mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-11-04 08:08:55 +01:00 
			
		
		
		
	Unify layout for new update and crash screens
This commit is contained in:
		@@ -0,0 +1,141 @@
 | 
			
		||||
package eu.kanade.presentation.components
 | 
			
		||||
 | 
			
		||||
import androidx.compose.foundation.background
 | 
			
		||||
import androidx.compose.foundation.layout.Box
 | 
			
		||||
import androidx.compose.foundation.layout.Column
 | 
			
		||||
import androidx.compose.foundation.layout.ColumnScope
 | 
			
		||||
import androidx.compose.foundation.layout.fillMaxWidth
 | 
			
		||||
import androidx.compose.foundation.layout.height
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
import androidx.compose.foundation.layout.size
 | 
			
		||||
import androidx.compose.foundation.layout.width
 | 
			
		||||
import androidx.compose.foundation.layout.windowInsetsPadding
 | 
			
		||||
import androidx.compose.foundation.rememberScrollState
 | 
			
		||||
import androidx.compose.foundation.verticalScroll
 | 
			
		||||
import androidx.compose.material.icons.Icons
 | 
			
		||||
import androidx.compose.material.icons.outlined.Newspaper
 | 
			
		||||
import androidx.compose.material3.Icon
 | 
			
		||||
import androidx.compose.material3.MaterialTheme
 | 
			
		||||
import androidx.compose.material3.NavigationBarDefaults
 | 
			
		||||
import androidx.compose.material3.OutlinedButton
 | 
			
		||||
import androidx.compose.material3.Text
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.draw.drawBehind
 | 
			
		||||
import androidx.compose.ui.geometry.Offset
 | 
			
		||||
import androidx.compose.ui.graphics.vector.ImageVector
 | 
			
		||||
import androidx.compose.ui.unit.Dp
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
import androidx.compose.ui.zIndex
 | 
			
		||||
import eu.kanade.presentation.theme.TachiyomiTheme
 | 
			
		||||
import eu.kanade.presentation.util.ThemePreviews
 | 
			
		||||
import eu.kanade.presentation.util.padding
 | 
			
		||||
import eu.kanade.presentation.util.secondaryItemAlpha
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
fun InfoScaffold(
 | 
			
		||||
    icon: ImageVector,
 | 
			
		||||
    headingText: String,
 | 
			
		||||
    subtitleText: String,
 | 
			
		||||
    acceptText: String,
 | 
			
		||||
    onAcceptClick: () -> Unit,
 | 
			
		||||
    rejectText: String,
 | 
			
		||||
    onRejectClick: () -> Unit,
 | 
			
		||||
    content: @Composable ColumnScope.() -> Unit,
 | 
			
		||||
) {
 | 
			
		||||
    Scaffold(
 | 
			
		||||
        bottomBar = {
 | 
			
		||||
            val strokeWidth = Dp.Hairline
 | 
			
		||||
            val borderColor = MaterialTheme.colorScheme.outline
 | 
			
		||||
            Column(
 | 
			
		||||
                modifier = Modifier
 | 
			
		||||
                    .background(MaterialTheme.colorScheme.background)
 | 
			
		||||
                    .drawBehind {
 | 
			
		||||
                        drawLine(
 | 
			
		||||
                            borderColor,
 | 
			
		||||
                            Offset(0f, 0f),
 | 
			
		||||
                            Offset(size.width, 0f),
 | 
			
		||||
                            strokeWidth.value,
 | 
			
		||||
                        )
 | 
			
		||||
                    }
 | 
			
		||||
                    .windowInsetsPadding(NavigationBarDefaults.windowInsets)
 | 
			
		||||
                    .padding(
 | 
			
		||||
                        horizontal = MaterialTheme.padding.medium,
 | 
			
		||||
                        vertical = MaterialTheme.padding.small,
 | 
			
		||||
                    ),
 | 
			
		||||
            ) {
 | 
			
		||||
                androidx.compose.material3.Button(
 | 
			
		||||
                    modifier = Modifier.fillMaxWidth(),
 | 
			
		||||
                    onClick = onAcceptClick,
 | 
			
		||||
                ) {
 | 
			
		||||
                    Text(text = acceptText)
 | 
			
		||||
                }
 | 
			
		||||
                OutlinedButton(
 | 
			
		||||
                    modifier = Modifier.fillMaxWidth(),
 | 
			
		||||
                    onClick = onRejectClick,
 | 
			
		||||
                ) {
 | 
			
		||||
                    Text(text = rejectText)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
    ) { paddingValues ->
 | 
			
		||||
        // Status bar scrim
 | 
			
		||||
        Box(
 | 
			
		||||
            modifier = Modifier
 | 
			
		||||
                .zIndex(2f)
 | 
			
		||||
                .secondaryItemAlpha()
 | 
			
		||||
                .background(MaterialTheme.colorScheme.background)
 | 
			
		||||
                .fillMaxWidth()
 | 
			
		||||
                .height(paddingValues.calculateTopPadding()),
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        Column(
 | 
			
		||||
            modifier = Modifier
 | 
			
		||||
                .verticalScroll(rememberScrollState())
 | 
			
		||||
                .fillMaxWidth()
 | 
			
		||||
                .padding(paddingValues)
 | 
			
		||||
                .padding(top = 48.dp)
 | 
			
		||||
                .padding(horizontal = MaterialTheme.padding.medium),
 | 
			
		||||
        ) {
 | 
			
		||||
            Icon(
 | 
			
		||||
                imageVector = icon,
 | 
			
		||||
                contentDescription = null,
 | 
			
		||||
                modifier = Modifier
 | 
			
		||||
                    .padding(bottom = MaterialTheme.padding.small)
 | 
			
		||||
                    .size(48.dp),
 | 
			
		||||
                tint = MaterialTheme.colorScheme.primary,
 | 
			
		||||
            )
 | 
			
		||||
            Text(
 | 
			
		||||
                text = headingText,
 | 
			
		||||
                style = MaterialTheme.typography.headlineLarge,
 | 
			
		||||
            )
 | 
			
		||||
            Text(
 | 
			
		||||
                text = subtitleText,
 | 
			
		||||
                modifier = Modifier
 | 
			
		||||
                    .secondaryItemAlpha()
 | 
			
		||||
                    .padding(vertical = MaterialTheme.padding.small),
 | 
			
		||||
                style = MaterialTheme.typography.titleSmall,
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            content()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ThemePreviews
 | 
			
		||||
@Composable
 | 
			
		||||
private fun InfoScaffoldPreview() {
 | 
			
		||||
    TachiyomiTheme {
 | 
			
		||||
        InfoScaffold(
 | 
			
		||||
            icon = Icons.Outlined.Newspaper,
 | 
			
		||||
            headingText = "Heading",
 | 
			
		||||
            subtitleText = "Subtitle",
 | 
			
		||||
            acceptText = "Accept",
 | 
			
		||||
            onAcceptClick = {},
 | 
			
		||||
            rejectText = "Reject",
 | 
			
		||||
            onRejectClick = {},
 | 
			
		||||
        ) {
 | 
			
		||||
            Text("Hello world")
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,37 +1,22 @@
 | 
			
		||||
package eu.kanade.presentation.crash
 | 
			
		||||
 | 
			
		||||
import androidx.compose.foundation.background
 | 
			
		||||
import androidx.compose.foundation.layout.Arrangement
 | 
			
		||||
import androidx.compose.foundation.layout.Box
 | 
			
		||||
import androidx.compose.foundation.layout.Column
 | 
			
		||||
import androidx.compose.foundation.layout.WindowInsets
 | 
			
		||||
import androidx.compose.foundation.layout.asPaddingValues
 | 
			
		||||
import androidx.compose.foundation.layout.fillMaxWidth
 | 
			
		||||
import androidx.compose.foundation.layout.navigationBars
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
import androidx.compose.foundation.layout.size
 | 
			
		||||
import androidx.compose.foundation.layout.systemBars
 | 
			
		||||
import androidx.compose.foundation.rememberScrollState
 | 
			
		||||
import androidx.compose.foundation.verticalScroll
 | 
			
		||||
import androidx.compose.material.icons.Icons
 | 
			
		||||
import androidx.compose.material.icons.outlined.BugReport
 | 
			
		||||
import androidx.compose.material3.Button
 | 
			
		||||
import androidx.compose.material3.Icon
 | 
			
		||||
import androidx.compose.material3.MaterialTheme
 | 
			
		||||
import androidx.compose.material3.OutlinedButton
 | 
			
		||||
import androidx.compose.material3.Scaffold
 | 
			
		||||
import androidx.compose.material3.Text
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.runtime.rememberCoroutineScope
 | 
			
		||||
import androidx.compose.ui.Alignment
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.draw.clip
 | 
			
		||||
import androidx.compose.ui.draw.drawBehind
 | 
			
		||||
import androidx.compose.ui.geometry.Offset
 | 
			
		||||
import androidx.compose.ui.platform.LocalContext
 | 
			
		||||
import androidx.compose.ui.res.stringResource
 | 
			
		||||
import androidx.compose.ui.unit.Dp
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
import eu.kanade.presentation.components.InfoScaffold
 | 
			
		||||
import eu.kanade.presentation.theme.TachiyomiTheme
 | 
			
		||||
import eu.kanade.presentation.util.ThemePreviews
 | 
			
		||||
import eu.kanade.presentation.util.padding
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.util.CrashLogUtil
 | 
			
		||||
@@ -44,82 +29,41 @@ fun CrashScreen(
 | 
			
		||||
) {
 | 
			
		||||
    val scope = rememberCoroutineScope()
 | 
			
		||||
    val context = LocalContext.current
 | 
			
		||||
    Scaffold(
 | 
			
		||||
        contentWindowInsets = WindowInsets.systemBars,
 | 
			
		||||
        bottomBar = {
 | 
			
		||||
            val strokeWidth = Dp.Hairline
 | 
			
		||||
            val borderColor = MaterialTheme.colorScheme.outline
 | 
			
		||||
            Column(
 | 
			
		||||
                modifier = Modifier
 | 
			
		||||
                    .background(MaterialTheme.colorScheme.surface)
 | 
			
		||||
                    .drawBehind {
 | 
			
		||||
                        drawLine(
 | 
			
		||||
                            borderColor,
 | 
			
		||||
                            Offset(0f, 0f),
 | 
			
		||||
                            Offset(size.width, 0f),
 | 
			
		||||
                            strokeWidth.value,
 | 
			
		||||
                        )
 | 
			
		||||
                    }
 | 
			
		||||
                    .padding(WindowInsets.navigationBars.asPaddingValues())
 | 
			
		||||
                    .padding(horizontal = MaterialTheme.padding.medium, vertical = MaterialTheme.padding.small),
 | 
			
		||||
                verticalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small),
 | 
			
		||||
            ) {
 | 
			
		||||
                Button(
 | 
			
		||||
                    onClick = {
 | 
			
		||||
                        scope.launch {
 | 
			
		||||
                            CrashLogUtil(context).dumpLogs()
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    modifier = Modifier.fillMaxWidth(),
 | 
			
		||||
                ) {
 | 
			
		||||
                    Text(text = stringResource(R.string.pref_dump_crash_logs))
 | 
			
		||||
                }
 | 
			
		||||
                OutlinedButton(
 | 
			
		||||
                    onClick = onRestartClick,
 | 
			
		||||
                    modifier = Modifier.fillMaxWidth(),
 | 
			
		||||
                ) {
 | 
			
		||||
                    Text(text = stringResource(R.string.crash_screen_restart_application))
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
    InfoScaffold(
 | 
			
		||||
        icon = Icons.Outlined.BugReport,
 | 
			
		||||
        headingText = stringResource(R.string.crash_screen_title),
 | 
			
		||||
        subtitleText = stringResource(R.string.crash_screen_description, stringResource(R.string.app_name)),
 | 
			
		||||
        acceptText = stringResource(R.string.pref_dump_crash_logs),
 | 
			
		||||
        onAcceptClick = {
 | 
			
		||||
            scope.launch {
 | 
			
		||||
                CrashLogUtil(context).dumpLogs()
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
    ) { paddingValues ->
 | 
			
		||||
        Column(
 | 
			
		||||
        rejectText = stringResource(R.string.crash_screen_restart_application),
 | 
			
		||||
        onRejectClick = onRestartClick,
 | 
			
		||||
    ) {
 | 
			
		||||
        Box(
 | 
			
		||||
            modifier = Modifier
 | 
			
		||||
                .verticalScroll(rememberScrollState())
 | 
			
		||||
                .padding(paddingValues)
 | 
			
		||||
                .padding(top = 56.dp)
 | 
			
		||||
                .padding(horizontal = MaterialTheme.padding.medium),
 | 
			
		||||
            horizontalAlignment = Alignment.CenterHorizontally,
 | 
			
		||||
                .padding(vertical = MaterialTheme.padding.small)
 | 
			
		||||
                .clip(MaterialTheme.shapes.small)
 | 
			
		||||
                .fillMaxWidth()
 | 
			
		||||
                .background(MaterialTheme.colorScheme.surfaceVariant),
 | 
			
		||||
        ) {
 | 
			
		||||
            Icon(
 | 
			
		||||
                imageVector = Icons.Outlined.BugReport,
 | 
			
		||||
                contentDescription = null,
 | 
			
		||||
                modifier = Modifier
 | 
			
		||||
                    .size(64.dp),
 | 
			
		||||
            )
 | 
			
		||||
            Text(
 | 
			
		||||
                text = stringResource(R.string.crash_screen_title),
 | 
			
		||||
                style = MaterialTheme.typography.titleLarge,
 | 
			
		||||
            )
 | 
			
		||||
            Text(
 | 
			
		||||
                text = stringResource(R.string.crash_screen_description, stringResource(R.string.app_name)),
 | 
			
		||||
                text = exception.toString(),
 | 
			
		||||
                modifier = Modifier
 | 
			
		||||
                    .padding(vertical = MaterialTheme.padding.small),
 | 
			
		||||
                    .padding(all = MaterialTheme.padding.small),
 | 
			
		||||
                color = MaterialTheme.colorScheme.onSurfaceVariant,
 | 
			
		||||
            )
 | 
			
		||||
            Box(
 | 
			
		||||
                modifier = Modifier
 | 
			
		||||
                    .padding(vertical = MaterialTheme.padding.small)
 | 
			
		||||
                    .clip(MaterialTheme.shapes.small)
 | 
			
		||||
                    .fillMaxWidth()
 | 
			
		||||
                    .background(MaterialTheme.colorScheme.surfaceVariant),
 | 
			
		||||
            ) {
 | 
			
		||||
                Text(
 | 
			
		||||
                    text = exception.toString(),
 | 
			
		||||
                    modifier = Modifier
 | 
			
		||||
                        .padding(all = MaterialTheme.padding.small),
 | 
			
		||||
                    color = MaterialTheme.colorScheme.onSurfaceVariant,
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ThemePreviews
 | 
			
		||||
@Composable
 | 
			
		||||
private fun CrashScreenPreview() {
 | 
			
		||||
    TachiyomiTheme {
 | 
			
		||||
        CrashScreen(exception = RuntimeException("Dummy")) {}
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -39,6 +39,7 @@ import androidx.compose.ui.draw.alpha
 | 
			
		||||
import androidx.compose.ui.draw.clip
 | 
			
		||||
import androidx.compose.ui.platform.LocalContext
 | 
			
		||||
import androidx.compose.ui.res.stringResource
 | 
			
		||||
import androidx.compose.ui.text.style.TextAlign
 | 
			
		||||
import androidx.compose.ui.text.style.TextOverflow
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
import eu.kanade.presentation.components.Divider
 | 
			
		||||
@@ -250,6 +251,7 @@ private fun TrackDetailsItem(
 | 
			
		||||
            maxLines = 2,
 | 
			
		||||
            overflow = TextOverflow.Ellipsis,
 | 
			
		||||
            style = MaterialTheme.typography.bodyMedium,
 | 
			
		||||
            textAlign = TextAlign.Center,
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,41 +1,28 @@
 | 
			
		||||
package eu.kanade.presentation.more
 | 
			
		||||
 | 
			
		||||
import androidx.compose.foundation.background
 | 
			
		||||
import androidx.compose.foundation.layout.Box
 | 
			
		||||
import androidx.compose.foundation.layout.Column
 | 
			
		||||
import androidx.compose.foundation.layout.Spacer
 | 
			
		||||
import androidx.compose.foundation.layout.fillMaxWidth
 | 
			
		||||
import androidx.compose.foundation.layout.height
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
import androidx.compose.foundation.layout.size
 | 
			
		||||
import androidx.compose.foundation.layout.width
 | 
			
		||||
import androidx.compose.foundation.layout.windowInsetsPadding
 | 
			
		||||
import androidx.compose.foundation.rememberScrollState
 | 
			
		||||
import androidx.compose.foundation.verticalScroll
 | 
			
		||||
import androidx.compose.material.icons.Icons
 | 
			
		||||
import androidx.compose.material.icons.filled.OpenInNew
 | 
			
		||||
import androidx.compose.material.icons.outlined.NewReleases
 | 
			
		||||
import androidx.compose.material3.Icon
 | 
			
		||||
import androidx.compose.material3.MaterialTheme
 | 
			
		||||
import androidx.compose.material3.NavigationBarDefaults
 | 
			
		||||
import androidx.compose.material3.Text
 | 
			
		||||
import androidx.compose.material3.TextButton
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.draw.drawBehind
 | 
			
		||||
import androidx.compose.ui.geometry.Offset
 | 
			
		||||
import androidx.compose.ui.res.stringResource
 | 
			
		||||
import androidx.compose.ui.text.SpanStyle
 | 
			
		||||
import androidx.compose.ui.unit.Dp
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
import androidx.compose.ui.zIndex
 | 
			
		||||
import com.halilibo.richtext.markdown.Markdown
 | 
			
		||||
import com.halilibo.richtext.ui.RichTextStyle
 | 
			
		||||
import com.halilibo.richtext.ui.material3.Material3RichText
 | 
			
		||||
import com.halilibo.richtext.ui.string.RichTextStringStyle
 | 
			
		||||
import eu.kanade.presentation.components.Scaffold
 | 
			
		||||
import eu.kanade.presentation.components.InfoScaffold
 | 
			
		||||
import eu.kanade.presentation.theme.TachiyomiTheme
 | 
			
		||||
import eu.kanade.presentation.util.ThemePreviews
 | 
			
		||||
import eu.kanade.presentation.util.padding
 | 
			
		||||
import eu.kanade.presentation.util.secondaryItemAlpha
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
@@ -46,98 +33,56 @@ fun NewUpdateScreen(
 | 
			
		||||
    onRejectUpdate: () -> Unit,
 | 
			
		||||
    onAcceptUpdate: () -> Unit,
 | 
			
		||||
) {
 | 
			
		||||
    Scaffold(
 | 
			
		||||
        bottomBar = {
 | 
			
		||||
            val strokeWidth = Dp.Hairline
 | 
			
		||||
            val borderColor = MaterialTheme.colorScheme.outline
 | 
			
		||||
            Column(
 | 
			
		||||
                modifier = Modifier
 | 
			
		||||
                    .background(MaterialTheme.colorScheme.background)
 | 
			
		||||
                    .drawBehind {
 | 
			
		||||
                        drawLine(
 | 
			
		||||
                            borderColor,
 | 
			
		||||
                            Offset(0f, 0f),
 | 
			
		||||
                            Offset(size.width, 0f),
 | 
			
		||||
                            strokeWidth.value,
 | 
			
		||||
                        )
 | 
			
		||||
                    }
 | 
			
		||||
                    .windowInsetsPadding(NavigationBarDefaults.windowInsets)
 | 
			
		||||
                    .padding(
 | 
			
		||||
                        horizontal = MaterialTheme.padding.medium,
 | 
			
		||||
                        vertical = MaterialTheme.padding.small,
 | 
			
		||||
                    ),
 | 
			
		||||
            ) {
 | 
			
		||||
                TextButton(
 | 
			
		||||
                    modifier = Modifier.fillMaxWidth(),
 | 
			
		||||
                    onClick = onAcceptUpdate,
 | 
			
		||||
                ) {
 | 
			
		||||
                    Text(text = stringResource(id = R.string.update_check_confirm))
 | 
			
		||||
                }
 | 
			
		||||
                TextButton(
 | 
			
		||||
                    modifier = Modifier.fillMaxWidth(),
 | 
			
		||||
                    onClick = onRejectUpdate,
 | 
			
		||||
                ) {
 | 
			
		||||
                    Text(text = stringResource(R.string.action_not_now))
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
    ) { paddingValues ->
 | 
			
		||||
        // Status bar scrim
 | 
			
		||||
        Box(
 | 
			
		||||
    InfoScaffold(
 | 
			
		||||
        icon = Icons.Outlined.NewReleases,
 | 
			
		||||
        headingText = stringResource(R.string.update_check_notification_update_available),
 | 
			
		||||
        subtitleText = versionName,
 | 
			
		||||
        acceptText = stringResource(id = R.string.update_check_confirm),
 | 
			
		||||
        onAcceptClick = onAcceptUpdate,
 | 
			
		||||
        rejectText = stringResource(R.string.action_not_now),
 | 
			
		||||
        onRejectClick = onRejectUpdate,
 | 
			
		||||
    ) {
 | 
			
		||||
        Material3RichText(
 | 
			
		||||
            modifier = Modifier
 | 
			
		||||
                .zIndex(2f)
 | 
			
		||||
                .secondaryItemAlpha()
 | 
			
		||||
                .background(MaterialTheme.colorScheme.background)
 | 
			
		||||
                .fillMaxWidth()
 | 
			
		||||
                .height(paddingValues.calculateTopPadding()),
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        Column(
 | 
			
		||||
            modifier = Modifier
 | 
			
		||||
                .verticalScroll(rememberScrollState())
 | 
			
		||||
                .padding(paddingValues)
 | 
			
		||||
                .padding(top = 48.dp)
 | 
			
		||||
                .padding(horizontal = MaterialTheme.padding.medium),
 | 
			
		||||
        ) {
 | 
			
		||||
            Icon(
 | 
			
		||||
                imageVector = Icons.Outlined.NewReleases,
 | 
			
		||||
                contentDescription = null,
 | 
			
		||||
                modifier = Modifier
 | 
			
		||||
                    .padding(bottom = MaterialTheme.padding.small)
 | 
			
		||||
                    .size(48.dp),
 | 
			
		||||
                tint = MaterialTheme.colorScheme.primary,
 | 
			
		||||
            )
 | 
			
		||||
            Text(
 | 
			
		||||
                text = stringResource(R.string.update_check_notification_update_available),
 | 
			
		||||
                style = MaterialTheme.typography.headlineLarge,
 | 
			
		||||
            )
 | 
			
		||||
            Text(
 | 
			
		||||
                text = versionName,
 | 
			
		||||
                modifier = Modifier.secondaryItemAlpha(),
 | 
			
		||||
                style = MaterialTheme.typography.titleSmall,
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            Material3RichText(
 | 
			
		||||
                modifier = Modifier
 | 
			
		||||
                    .fillMaxWidth()
 | 
			
		||||
                    .padding(vertical = MaterialTheme.padding.large),
 | 
			
		||||
                style = RichTextStyle(
 | 
			
		||||
                    stringStyle = RichTextStringStyle(
 | 
			
		||||
                        linkStyle = SpanStyle(color = MaterialTheme.colorScheme.primary),
 | 
			
		||||
                    ),
 | 
			
		||||
                .padding(vertical = MaterialTheme.padding.large),
 | 
			
		||||
            style = RichTextStyle(
 | 
			
		||||
                stringStyle = RichTextStringStyle(
 | 
			
		||||
                    linkStyle = SpanStyle(color = MaterialTheme.colorScheme.primary),
 | 
			
		||||
                ),
 | 
			
		||||
            ) {
 | 
			
		||||
                Markdown(content = changelogInfo)
 | 
			
		||||
            ),
 | 
			
		||||
        ) {
 | 
			
		||||
            Markdown(content = changelogInfo)
 | 
			
		||||
 | 
			
		||||
                TextButton(
 | 
			
		||||
                    onClick = onOpenInBrowser,
 | 
			
		||||
                    modifier = Modifier.padding(top = MaterialTheme.padding.small),
 | 
			
		||||
                ) {
 | 
			
		||||
                    Text(text = stringResource(R.string.update_check_open))
 | 
			
		||||
                    Spacer(modifier = Modifier.width(MaterialTheme.padding.tiny))
 | 
			
		||||
                    Icon(imageVector = Icons.Default.OpenInNew, contentDescription = null)
 | 
			
		||||
                }
 | 
			
		||||
            TextButton(
 | 
			
		||||
                onClick = onOpenInBrowser,
 | 
			
		||||
                modifier = Modifier.padding(top = MaterialTheme.padding.small),
 | 
			
		||||
            ) {
 | 
			
		||||
                Text(text = stringResource(R.string.update_check_open))
 | 
			
		||||
                Spacer(modifier = Modifier.width(MaterialTheme.padding.tiny))
 | 
			
		||||
                Icon(imageVector = Icons.Default.OpenInNew, contentDescription = null)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ThemePreviews
 | 
			
		||||
@Composable
 | 
			
		||||
private fun NewUpdateScreenPreview() {
 | 
			
		||||
    TachiyomiTheme {
 | 
			
		||||
        NewUpdateScreen(
 | 
			
		||||
            versionName = "v0.99.9",
 | 
			
		||||
            changelogInfo = """
 | 
			
		||||
                ## Yay
 | 
			
		||||
                Foobar
 | 
			
		||||
                
 | 
			
		||||
                ### More info
 | 
			
		||||
                - Hello
 | 
			
		||||
                - World
 | 
			
		||||
            """.trimIndent(),
 | 
			
		||||
            onOpenInBrowser = {},
 | 
			
		||||
            onRejectUpdate = {},
 | 
			
		||||
            onAcceptUpdate = {},
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -377,14 +377,13 @@ class Downloader(
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val digitCount = (download.pages?.size ?: 0).toString().length.coerceAtLeast(3)
 | 
			
		||||
 | 
			
		||||
        val filename = String.format("%0${digitCount}d", page.number)
 | 
			
		||||
        val tmpFile = tmpDir.findFile("$filename.tmp")
 | 
			
		||||
 | 
			
		||||
        // Delete temp file if it exists.
 | 
			
		||||
        // Delete temp file if it exists
 | 
			
		||||
        tmpFile?.delete()
 | 
			
		||||
 | 
			
		||||
        // Try to find the image file.
 | 
			
		||||
        // Try to find the image file
 | 
			
		||||
        val imageFile = tmpDir.listFiles()?.firstOrNull { it.name!!.startsWith("$filename.") || it.name!!.startsWith("${filename}__001") }
 | 
			
		||||
 | 
			
		||||
        // If the image is already downloaded, do nothing. Otherwise download from network
 | 
			
		||||
@@ -492,7 +491,7 @@ class Downloader(
 | 
			
		||||
        val imageFile = tmpDir.listFiles()?.firstOrNull { it.name.orEmpty().startsWith(filenamePrefix) }
 | 
			
		||||
            ?: throw Error(context.getString(R.string.download_notifier_split_page_not_found, page.number))
 | 
			
		||||
 | 
			
		||||
        // Check if the original page was previously splitted before then skip.
 | 
			
		||||
        // If the original page was previously split, then skip
 | 
			
		||||
        if (imageFile.name.orEmpty().startsWith("${filenamePrefix}__")) return true
 | 
			
		||||
 | 
			
		||||
        return try {
 | 
			
		||||
@@ -521,7 +520,7 @@ class Downloader(
 | 
			
		||||
        val downloadPageCount = download.pages?.size ?: return
 | 
			
		||||
        // Ensure that all pages has been downloaded
 | 
			
		||||
        if (download.downloadedImages < downloadPageCount) return
 | 
			
		||||
        // Ensure that the chapter folder has all the pages.
 | 
			
		||||
        // Ensure that the chapter folder has all the pages
 | 
			
		||||
        val downloadedImagesCount = tmpDir.listFiles().orEmpty().count {
 | 
			
		||||
            val fileName = it.name.orEmpty()
 | 
			
		||||
            when {
 | 
			
		||||
@@ -542,7 +541,8 @@ class Downloader(
 | 
			
		||||
//                download.chapter.toDomainChapter()!!,
 | 
			
		||||
//                chapterUrl,
 | 
			
		||||
//            )
 | 
			
		||||
            // Only rename the directory if it's downloaded.
 | 
			
		||||
 | 
			
		||||
            // Only rename the directory if it's downloaded
 | 
			
		||||
            if (downloadPreferences.saveChaptersAsCBZ().get()) {
 | 
			
		||||
                archiveChapter(mangaDir, dirname, tmpDir)
 | 
			
		||||
            } else {
 | 
			
		||||
@@ -621,7 +621,7 @@ class Downloader(
 | 
			
		||||
    private fun completeDownload(download: Download) {
 | 
			
		||||
        // Delete successful downloads from queue
 | 
			
		||||
        if (download.status == Download.State.DOWNLOADED) {
 | 
			
		||||
            // remove downloaded chapter from queue
 | 
			
		||||
            // Remove downloaded chapter from queue
 | 
			
		||||
            queue.remove(download)
 | 
			
		||||
        }
 | 
			
		||||
        if (areAllDownloadsFinished()) {
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,7 @@ class NewUpdateScreen(
 | 
			
		||||
    private val releaseLink: String,
 | 
			
		||||
    private val downloadLink: String,
 | 
			
		||||
) : Screen {
 | 
			
		||||
 | 
			
		||||
    @Composable
 | 
			
		||||
    override fun Content() {
 | 
			
		||||
        val navigator = LocalNavigator.currentOrThrow
 | 
			
		||||
@@ -23,6 +24,7 @@ class NewUpdateScreen(
 | 
			
		||||
        val changelogInfoNoChecksum = remember {
 | 
			
		||||
            changelogInfo.replace("""---(\R|.)*Checksums(\R|.)*""".toRegex(), "")
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        NewUpdateScreen(
 | 
			
		||||
            versionName = versionName,
 | 
			
		||||
            changelogInfo = changelogInfoNoChecksum,
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user