mirror of
https://github.com/mihonapp/mihon.git
synced 2024-11-21 20:47:03 -05:00
More settings stuff (#8226)
* title size * move about screen to settings keeping shortcut inside more screen * more * shrink texts * scrollable create backup dialog choices * search back button * cleanups * delay changes that require activity recreate * lessen horizontal padding
This commit is contained in:
parent
ea092fa175
commit
f5bde3726a
28 changed files with 552 additions and 649 deletions
|
@ -13,16 +13,16 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.platform.LocalUriHandler
|
import androidx.compose.ui.platform.LocalUriHandler
|
||||||
import androidx.compose.ui.res.painterResource
|
|
||||||
import androidx.compose.ui.res.pluralStringResource
|
import androidx.compose.ui.res.pluralStringResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.res.vectorResource
|
||||||
import eu.kanade.presentation.components.AppStateBanners
|
import eu.kanade.presentation.components.AppStateBanners
|
||||||
import eu.kanade.presentation.components.Divider
|
import eu.kanade.presentation.components.Divider
|
||||||
import eu.kanade.presentation.components.PreferenceRow
|
|
||||||
import eu.kanade.presentation.components.ScrollbarLazyColumn
|
import eu.kanade.presentation.components.ScrollbarLazyColumn
|
||||||
import eu.kanade.presentation.components.SwitchPreference
|
import eu.kanade.presentation.more.settings.widget.SwitchPreferenceWidget
|
||||||
|
import eu.kanade.presentation.more.settings.widget.TextPreferenceWidget
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.ui.more.DownloadQueueState
|
import eu.kanade.tachiyomi.ui.more.DownloadQueueState
|
||||||
import eu.kanade.tachiyomi.ui.more.MoreController
|
import eu.kanade.tachiyomi.ui.more.MoreController
|
||||||
|
@ -57,26 +57,28 @@ fun MoreScreen(
|
||||||
}
|
}
|
||||||
|
|
||||||
item {
|
item {
|
||||||
SwitchPreference(
|
SwitchPreferenceWidget(
|
||||||
preference = presenter.downloadedOnly,
|
|
||||||
title = stringResource(R.string.label_downloaded_only),
|
title = stringResource(R.string.label_downloaded_only),
|
||||||
subtitle = stringResource(R.string.downloaded_only_summary),
|
subtitle = stringResource(R.string.downloaded_only_summary),
|
||||||
painter = rememberVectorPainter(Icons.Outlined.CloudOff),
|
icon = Icons.Outlined.CloudOff,
|
||||||
|
checked = presenter.downloadedOnly.value,
|
||||||
|
onCheckedChanged = { presenter.downloadedOnly.value = it },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
item {
|
item {
|
||||||
SwitchPreference(
|
SwitchPreferenceWidget(
|
||||||
preference = presenter.incognitoMode,
|
|
||||||
title = stringResource(R.string.pref_incognito_mode),
|
title = stringResource(R.string.pref_incognito_mode),
|
||||||
subtitle = stringResource(R.string.pref_incognito_mode_summary),
|
subtitle = stringResource(R.string.pref_incognito_mode_summary),
|
||||||
painter = painterResource(R.drawable.ic_glasses_24dp),
|
icon = ImageVector.vectorResource(R.drawable.ic_glasses_24dp),
|
||||||
|
checked = presenter.incognitoMode.value,
|
||||||
|
onCheckedChanged = { presenter.incognitoMode.value = it },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
item { Divider() }
|
item { Divider() }
|
||||||
|
|
||||||
item {
|
item {
|
||||||
PreferenceRow(
|
TextPreferenceWidget(
|
||||||
title = stringResource(R.string.label_download_queue),
|
title = stringResource(R.string.label_download_queue),
|
||||||
subtitle = when (downloadQueueState) {
|
subtitle = when (downloadQueueState) {
|
||||||
DownloadQueueState.Stopped -> null
|
DownloadQueueState.Stopped -> null
|
||||||
|
@ -99,46 +101,46 @@ fun MoreScreen(
|
||||||
pluralStringResource(id = R.plurals.download_queue_summary, count = pending, pending)
|
pluralStringResource(id = R.plurals.download_queue_summary, count = pending, pending)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
painter = rememberVectorPainter(Icons.Outlined.GetApp),
|
icon = Icons.Outlined.GetApp,
|
||||||
onClick = onClickDownloadQueue,
|
onPreferenceClick = onClickDownloadQueue,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
item {
|
item {
|
||||||
PreferenceRow(
|
TextPreferenceWidget(
|
||||||
title = stringResource(R.string.categories),
|
title = stringResource(R.string.categories),
|
||||||
painter = rememberVectorPainter(Icons.Outlined.Label),
|
icon = Icons.Outlined.Label,
|
||||||
onClick = onClickCategories,
|
onPreferenceClick = onClickCategories,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
item {
|
item {
|
||||||
PreferenceRow(
|
TextPreferenceWidget(
|
||||||
title = stringResource(R.string.label_backup),
|
title = stringResource(R.string.label_backup),
|
||||||
painter = rememberVectorPainter(Icons.Outlined.SettingsBackupRestore),
|
icon = Icons.Outlined.SettingsBackupRestore,
|
||||||
onClick = onClickBackupAndRestore,
|
onPreferenceClick = onClickBackupAndRestore,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
item { Divider() }
|
item { Divider() }
|
||||||
|
|
||||||
item {
|
item {
|
||||||
PreferenceRow(
|
TextPreferenceWidget(
|
||||||
title = stringResource(R.string.label_settings),
|
title = stringResource(R.string.label_settings),
|
||||||
painter = rememberVectorPainter(Icons.Outlined.Settings),
|
icon = Icons.Outlined.Settings,
|
||||||
onClick = onClickSettings,
|
onPreferenceClick = onClickSettings,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
item {
|
item {
|
||||||
PreferenceRow(
|
TextPreferenceWidget(
|
||||||
title = stringResource(R.string.pref_category_about),
|
title = stringResource(R.string.pref_category_about),
|
||||||
painter = rememberVectorPainter(Icons.Outlined.Info),
|
icon = Icons.Outlined.Info,
|
||||||
onClick = onClickAbout,
|
onPreferenceClick = onClickAbout,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
item {
|
item {
|
||||||
PreferenceRow(
|
TextPreferenceWidget(
|
||||||
title = stringResource(R.string.label_help),
|
title = stringResource(R.string.label_help),
|
||||||
painter = rememberVectorPainter(Icons.Outlined.HelpOutline),
|
icon = Icons.Outlined.HelpOutline,
|
||||||
onClick = { uriHandler.openUri(MoreController.URL_HELP) },
|
onPreferenceClick = { uriHandler.openUri(MoreController.URL_HELP) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,152 +0,0 @@
|
||||||
package eu.kanade.presentation.more.about
|
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.outlined.Public
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.ui.platform.LocalUriHandler
|
|
||||||
import androidx.compose.ui.res.painterResource
|
|
||||||
import androidx.compose.ui.res.stringResource
|
|
||||||
import eu.kanade.presentation.components.AppBar
|
|
||||||
import eu.kanade.presentation.components.LinkIcon
|
|
||||||
import eu.kanade.presentation.components.PreferenceRow
|
|
||||||
import eu.kanade.presentation.components.Scaffold
|
|
||||||
import eu.kanade.presentation.components.ScrollbarLazyColumn
|
|
||||||
import eu.kanade.presentation.more.LogoHeader
|
|
||||||
import eu.kanade.presentation.util.plus
|
|
||||||
import eu.kanade.tachiyomi.BuildConfig
|
|
||||||
import eu.kanade.tachiyomi.R
|
|
||||||
import eu.kanade.tachiyomi.data.updater.RELEASE_URL
|
|
||||||
import eu.kanade.tachiyomi.util.CrashLogUtil
|
|
||||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun AboutScreen(
|
|
||||||
navigateUp: () -> Unit,
|
|
||||||
checkVersion: () -> Unit,
|
|
||||||
getFormattedBuildTime: () -> String,
|
|
||||||
onClickLicenses: () -> Unit,
|
|
||||||
) {
|
|
||||||
val context = LocalContext.current
|
|
||||||
val uriHandler = LocalUriHandler.current
|
|
||||||
|
|
||||||
Scaffold(
|
|
||||||
topBar = { scrollBehavior ->
|
|
||||||
AppBar(
|
|
||||||
title = stringResource(R.string.pref_category_about),
|
|
||||||
navigateUp = navigateUp,
|
|
||||||
scrollBehavior = scrollBehavior,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
) { contentPadding ->
|
|
||||||
ScrollbarLazyColumn(
|
|
||||||
contentPadding = contentPadding,
|
|
||||||
) {
|
|
||||||
item {
|
|
||||||
LogoHeader()
|
|
||||||
}
|
|
||||||
|
|
||||||
item {
|
|
||||||
PreferenceRow(
|
|
||||||
title = stringResource(R.string.version),
|
|
||||||
subtitle = when {
|
|
||||||
BuildConfig.DEBUG -> {
|
|
||||||
"Debug ${BuildConfig.COMMIT_SHA} (${getFormattedBuildTime()})"
|
|
||||||
}
|
|
||||||
BuildConfig.PREVIEW -> {
|
|
||||||
"Preview r${BuildConfig.COMMIT_COUNT} (${BuildConfig.COMMIT_SHA}, ${getFormattedBuildTime()})"
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
"Stable ${BuildConfig.VERSION_NAME} (${getFormattedBuildTime()})"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onClick = {
|
|
||||||
val deviceInfo = CrashLogUtil(context).getDebugInfo()
|
|
||||||
context.copyToClipboard("Debug information", deviceInfo)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (BuildConfig.INCLUDE_UPDATER) {
|
|
||||||
item {
|
|
||||||
PreferenceRow(
|
|
||||||
title = stringResource(R.string.check_for_updates),
|
|
||||||
onClick = checkVersion,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!BuildConfig.DEBUG) {
|
|
||||||
item {
|
|
||||||
PreferenceRow(
|
|
||||||
title = stringResource(R.string.whats_new),
|
|
||||||
onClick = { uriHandler.openUri(RELEASE_URL) },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
item {
|
|
||||||
PreferenceRow(
|
|
||||||
title = stringResource(R.string.help_translate),
|
|
||||||
onClick = { uriHandler.openUri("https://tachiyomi.org/help/contribution/#translation") },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
item {
|
|
||||||
PreferenceRow(
|
|
||||||
title = stringResource(R.string.licenses),
|
|
||||||
onClick = onClickLicenses,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
item {
|
|
||||||
PreferenceRow(
|
|
||||||
title = stringResource(R.string.privacy_policy),
|
|
||||||
onClick = { uriHandler.openUri("https://tachiyomi.org/privacy") },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
item {
|
|
||||||
Row(
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
horizontalArrangement = Arrangement.Center,
|
|
||||||
) {
|
|
||||||
LinkIcon(
|
|
||||||
label = stringResource(R.string.website),
|
|
||||||
painter = rememberVectorPainter(Icons.Outlined.Public),
|
|
||||||
url = "https://tachiyomi.org",
|
|
||||||
)
|
|
||||||
LinkIcon(
|
|
||||||
label = "Discord",
|
|
||||||
painter = painterResource(R.drawable.ic_discord_24dp),
|
|
||||||
url = "https://discord.gg/tachiyomi",
|
|
||||||
)
|
|
||||||
LinkIcon(
|
|
||||||
label = "Twitter",
|
|
||||||
painter = painterResource(R.drawable.ic_twitter_24dp),
|
|
||||||
url = "https://twitter.com/tachiyomiorg",
|
|
||||||
)
|
|
||||||
LinkIcon(
|
|
||||||
label = "Facebook",
|
|
||||||
painter = painterResource(R.drawable.ic_facebook_24dp),
|
|
||||||
url = "https://facebook.com/tachiyomiorg",
|
|
||||||
)
|
|
||||||
LinkIcon(
|
|
||||||
label = "Reddit",
|
|
||||||
painter = painterResource(R.drawable.ic_reddit_24dp),
|
|
||||||
url = "https://www.reddit.com/r/Tachiyomi",
|
|
||||||
)
|
|
||||||
LinkIcon(
|
|
||||||
label = "GitHub",
|
|
||||||
painter = painterResource(R.drawable.ic_github_24dp),
|
|
||||||
url = "https://github.com/tachiyomiorg",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
package eu.kanade.presentation.more.about
|
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.res.stringResource
|
|
||||||
import com.mikepenz.aboutlibraries.ui.compose.LibrariesContainer
|
|
||||||
import com.mikepenz.aboutlibraries.ui.compose.LibraryDefaults
|
|
||||||
import eu.kanade.presentation.components.AppBar
|
|
||||||
import eu.kanade.presentation.components.Scaffold
|
|
||||||
import eu.kanade.tachiyomi.R
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun LicensesScreen(
|
|
||||||
navigateUp: () -> Unit,
|
|
||||||
) {
|
|
||||||
Scaffold(
|
|
||||||
topBar = { scrollBehavior ->
|
|
||||||
AppBar(
|
|
||||||
title = stringResource(R.string.licenses),
|
|
||||||
navigateUp = navigateUp,
|
|
||||||
scrollBehavior = scrollBehavior,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
) { contentPadding ->
|
|
||||||
LibrariesContainer(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize(),
|
|
||||||
contentPadding = contentPadding,
|
|
||||||
colors = LibraryDefaults.libraryColors(
|
|
||||||
backgroundColor = MaterialTheme.colorScheme.background,
|
|
||||||
contentColor = MaterialTheme.colorScheme.onBackground,
|
|
||||||
badgeBackgroundColor = MaterialTheme.colorScheme.primary,
|
|
||||||
badgeContentColor = MaterialTheme.colorScheme.onPrimary,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,7 +2,6 @@ package eu.kanade.presentation.more.settings
|
||||||
|
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.compose.foundation.layout.RowScope
|
import androidx.compose.foundation.layout.RowScope
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.ArrowBack
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
|
@ -10,9 +9,7 @@ import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TopAppBar
|
import androidx.compose.material3.TopAppBar
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import eu.kanade.presentation.components.Scaffold
|
import eu.kanade.presentation.components.Scaffold
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
|
|
||||||
|
@ -26,12 +23,7 @@ fun PreferenceScaffold(
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
title = {
|
title = { Text(text = stringResource(id = titleRes)) },
|
||||||
Text(
|
|
||||||
text = stringResource(id = titleRes),
|
|
||||||
modifier = Modifier.padding(start = 8.dp),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
navigationIcon = {
|
navigationIcon = {
|
||||||
if (onBackPressed != null) {
|
if (onBackPressed != null) {
|
||||||
IconButton(onClick = onBackPressed) {
|
IconButton(onClick = onBackPressed) {
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
package eu.kanade.presentation.more.settings.database
|
|
||||||
|
|
||||||
import androidx.compose.runtime.Stable
|
|
||||||
import androidx.compose.runtime.derivedStateOf
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import eu.kanade.domain.source.model.SourceWithCount
|
|
||||||
|
|
||||||
@Stable
|
|
||||||
interface ClearDatabaseState {
|
|
||||||
val items: List<SourceWithCount>
|
|
||||||
val selection: List<Long>
|
|
||||||
val isEmpty: Boolean
|
|
||||||
var dialog: Dialog?
|
|
||||||
}
|
|
||||||
|
|
||||||
fun ClearDatabaseState(): ClearDatabaseState {
|
|
||||||
return ClearDatabaseStateImpl()
|
|
||||||
}
|
|
||||||
|
|
||||||
class ClearDatabaseStateImpl : ClearDatabaseState {
|
|
||||||
override var items: List<SourceWithCount> by mutableStateOf(emptyList())
|
|
||||||
override var selection: List<Long> by mutableStateOf(emptyList())
|
|
||||||
override val isEmpty: Boolean by derivedStateOf { items.isEmpty() }
|
|
||||||
override var dialog: Dialog? by mutableStateOf(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class Dialog {
|
|
||||||
data class Delete(val sourceIds: List<Long>) : Dialog()
|
|
||||||
}
|
|
|
@ -1,73 +0,0 @@
|
||||||
package eu.kanade.presentation.more.settings.database.components
|
|
||||||
|
|
||||||
import androidx.compose.animation.Crossfade
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.lazy.items
|
|
||||||
import androidx.compose.material3.Button
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.res.stringResource
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import eu.kanade.domain.source.model.Source
|
|
||||||
import eu.kanade.presentation.components.Divider
|
|
||||||
import eu.kanade.presentation.components.EmptyScreen
|
|
||||||
import eu.kanade.presentation.components.FastScrollLazyColumn
|
|
||||||
import eu.kanade.presentation.more.settings.database.ClearDatabaseState
|
|
||||||
import eu.kanade.tachiyomi.R
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun ClearDatabaseContent(
|
|
||||||
state: ClearDatabaseState,
|
|
||||||
contentPadding: PaddingValues,
|
|
||||||
onClickSelection: (Source) -> Unit,
|
|
||||||
onClickDelete: () -> Unit,
|
|
||||||
) {
|
|
||||||
Crossfade(targetState = state.isEmpty.not()) { _state ->
|
|
||||||
when (_state) {
|
|
||||||
true -> {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(contentPadding)
|
|
||||||
.fillMaxSize(),
|
|
||||||
) {
|
|
||||||
FastScrollLazyColumn(
|
|
||||||
modifier = Modifier.weight(1f),
|
|
||||||
) {
|
|
||||||
items(state.items) { sourceWithCount ->
|
|
||||||
ClearDatabaseItem(
|
|
||||||
source = sourceWithCount.source,
|
|
||||||
count = sourceWithCount.count,
|
|
||||||
isSelected = state.selection.contains(sourceWithCount.id),
|
|
||||||
onClickSelect = { onClickSelection(sourceWithCount.source) },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Divider()
|
|
||||||
|
|
||||||
Button(
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(horizontal = 16.dp, vertical = 8.dp)
|
|
||||||
.fillMaxWidth(),
|
|
||||||
onClick = onClickDelete,
|
|
||||||
enabled = state.selection.isNotEmpty(),
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = stringResource(R.string.action_delete),
|
|
||||||
color = MaterialTheme.colorScheme.onPrimary,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false -> {
|
|
||||||
EmptyScreen(message = stringResource(R.string.database_clean))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
package eu.kanade.presentation.more.settings.database.components
|
|
||||||
|
|
||||||
import androidx.compose.material3.AlertDialog
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.material3.TextButton
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.ui.res.stringResource
|
|
||||||
import eu.kanade.tachiyomi.R
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun ClearDatabaseDeleteDialog(
|
|
||||||
onDismissRequest: () -> Unit,
|
|
||||||
onDelete: () -> Unit,
|
|
||||||
) {
|
|
||||||
AlertDialog(
|
|
||||||
onDismissRequest = onDismissRequest,
|
|
||||||
confirmButton = {
|
|
||||||
TextButton(onClick = onDelete) {
|
|
||||||
Text(text = stringResource(android.R.string.ok))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
dismissButton = {
|
|
||||||
TextButton(onClick = onDismissRequest) {
|
|
||||||
Text(text = stringResource(android.R.string.cancel))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
text = {
|
|
||||||
Text(text = stringResource(R.string.clear_database_confirmation))
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
package eu.kanade.presentation.more.settings.database.components
|
|
||||||
|
|
||||||
import androidx.compose.foundation.clickable
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.height
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.material3.Checkbox
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.res.stringResource
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import eu.kanade.domain.source.model.Source
|
|
||||||
import eu.kanade.presentation.browse.components.SourceIcon
|
|
||||||
import eu.kanade.presentation.util.selectedBackground
|
|
||||||
import eu.kanade.tachiyomi.R
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun ClearDatabaseItem(
|
|
||||||
source: Source,
|
|
||||||
count: Long,
|
|
||||||
isSelected: Boolean,
|
|
||||||
onClickSelect: () -> Unit,
|
|
||||||
) {
|
|
||||||
Row(
|
|
||||||
modifier = Modifier
|
|
||||||
.selectedBackground(isSelected)
|
|
||||||
.clickable(onClick = onClickSelect)
|
|
||||||
.padding(horizontal = 8.dp)
|
|
||||||
.height(56.dp),
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
) {
|
|
||||||
SourceIcon(source = source)
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(start = 8.dp)
|
|
||||||
.weight(1f),
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = source.visualName,
|
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
|
||||||
)
|
|
||||||
Text(text = stringResource(R.string.clear_database_source_item_count, count))
|
|
||||||
}
|
|
||||||
Checkbox(
|
|
||||||
checked = isSelected,
|
|
||||||
onCheckedChange = { onClickSelect() },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
package eu.kanade.presentation.more.settings.database.components
|
|
||||||
|
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.outlined.FlipToBack
|
|
||||||
import androidx.compose.material.icons.outlined.SelectAll
|
|
||||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.ui.res.stringResource
|
|
||||||
import eu.kanade.presentation.components.AppBar
|
|
||||||
import eu.kanade.presentation.components.AppBarActions
|
|
||||||
import eu.kanade.presentation.more.settings.database.ClearDatabaseState
|
|
||||||
import eu.kanade.tachiyomi.R
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun ClearDatabaseToolbar(
|
|
||||||
state: ClearDatabaseState,
|
|
||||||
navigateUp: () -> Unit,
|
|
||||||
onClickSelectAll: () -> Unit,
|
|
||||||
onClickInvertSelection: () -> Unit,
|
|
||||||
scrollBehavior: TopAppBarScrollBehavior,
|
|
||||||
) {
|
|
||||||
AppBar(
|
|
||||||
title = stringResource(R.string.pref_clear_database),
|
|
||||||
navigateUp = navigateUp,
|
|
||||||
actions = {
|
|
||||||
if (state.isEmpty.not()) {
|
|
||||||
AppBarActions(
|
|
||||||
actions = listOf(
|
|
||||||
AppBar.Action(
|
|
||||||
title = stringResource(R.string.action_select_all),
|
|
||||||
icon = Icons.Outlined.SelectAll,
|
|
||||||
onClick = onClickSelectAll,
|
|
||||||
),
|
|
||||||
AppBar.Action(
|
|
||||||
title = stringResource(R.string.action_select_all),
|
|
||||||
icon = Icons.Outlined.FlipToBack,
|
|
||||||
onClick = onClickInvertSelection,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
scrollBehavior = scrollBehavior,
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -0,0 +1,254 @@
|
||||||
|
package eu.kanade.presentation.more.settings.screen
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.outlined.Public
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.platform.LocalUriHandler
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import cafe.adriel.voyager.core.screen.Screen
|
||||||
|
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||||
|
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||||
|
import com.bluelinelabs.conductor.Router
|
||||||
|
import eu.kanade.domain.ui.UiPreferences
|
||||||
|
import eu.kanade.presentation.components.AppBar
|
||||||
|
import eu.kanade.presentation.components.LinkIcon
|
||||||
|
import eu.kanade.presentation.components.Scaffold
|
||||||
|
import eu.kanade.presentation.components.ScrollbarLazyColumn
|
||||||
|
import eu.kanade.presentation.more.LogoHeader
|
||||||
|
import eu.kanade.presentation.more.about.LicensesScreen
|
||||||
|
import eu.kanade.presentation.more.settings.widget.TextPreferenceWidget
|
||||||
|
import eu.kanade.presentation.util.LocalBackPress
|
||||||
|
import eu.kanade.presentation.util.LocalRouter
|
||||||
|
import eu.kanade.tachiyomi.BuildConfig
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.data.updater.AppUpdateChecker
|
||||||
|
import eu.kanade.tachiyomi.data.updater.AppUpdateResult
|
||||||
|
import eu.kanade.tachiyomi.data.updater.RELEASE_URL
|
||||||
|
import eu.kanade.tachiyomi.ui.more.NewUpdateDialogController
|
||||||
|
import eu.kanade.tachiyomi.util.CrashLogUtil
|
||||||
|
import eu.kanade.tachiyomi.util.lang.toDateTimestampString
|
||||||
|
import eu.kanade.tachiyomi.util.lang.withIOContext
|
||||||
|
import eu.kanade.tachiyomi.util.lang.withUIContext
|
||||||
|
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||||
|
import eu.kanade.tachiyomi.util.system.logcat
|
||||||
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import logcat.LogPriority
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
import java.text.DateFormat
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Locale
|
||||||
|
import java.util.TimeZone
|
||||||
|
|
||||||
|
class AboutScreen : Screen {
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
override fun Content() {
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
val context = LocalContext.current
|
||||||
|
val uriHandler = LocalUriHandler.current
|
||||||
|
val handleBack = LocalBackPress.current
|
||||||
|
val navigator = LocalNavigator.currentOrThrow
|
||||||
|
val router = LocalRouter.currentOrThrow
|
||||||
|
|
||||||
|
Scaffold(
|
||||||
|
topBar = { scrollBehavior ->
|
||||||
|
AppBar(
|
||||||
|
title = stringResource(R.string.pref_category_about),
|
||||||
|
navigateUp = if (handleBack != null) handleBack::invoke else null,
|
||||||
|
scrollBehavior = scrollBehavior,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
) { contentPadding ->
|
||||||
|
ScrollbarLazyColumn(
|
||||||
|
contentPadding = contentPadding,
|
||||||
|
) {
|
||||||
|
item {
|
||||||
|
LogoHeader()
|
||||||
|
}
|
||||||
|
|
||||||
|
item {
|
||||||
|
TextPreferenceWidget(
|
||||||
|
title = stringResource(R.string.version),
|
||||||
|
subtitle = getVersionName(withBuildDate = true),
|
||||||
|
onPreferenceClick = {
|
||||||
|
val deviceInfo = CrashLogUtil(context).getDebugInfo()
|
||||||
|
context.copyToClipboard("Debug information", deviceInfo)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BuildConfig.INCLUDE_UPDATER) {
|
||||||
|
item {
|
||||||
|
TextPreferenceWidget(
|
||||||
|
title = stringResource(R.string.check_for_updates),
|
||||||
|
onPreferenceClick = {
|
||||||
|
scope.launch {
|
||||||
|
checkVersion(context, router)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!BuildConfig.DEBUG) {
|
||||||
|
item {
|
||||||
|
TextPreferenceWidget(
|
||||||
|
title = stringResource(R.string.whats_new),
|
||||||
|
onPreferenceClick = { uriHandler.openUri(RELEASE_URL) },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
item {
|
||||||
|
TextPreferenceWidget(
|
||||||
|
title = stringResource(R.string.help_translate),
|
||||||
|
onPreferenceClick = { uriHandler.openUri("https://tachiyomi.org/help/contribution/#translation") },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
item {
|
||||||
|
TextPreferenceWidget(
|
||||||
|
title = stringResource(R.string.licenses),
|
||||||
|
onPreferenceClick = { navigator.push(LicensesScreen()) },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
item {
|
||||||
|
TextPreferenceWidget(
|
||||||
|
title = stringResource(R.string.privacy_policy),
|
||||||
|
onPreferenceClick = { uriHandler.openUri("https://tachiyomi.org/privacy") },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
item {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(vertical = 8.dp),
|
||||||
|
horizontalArrangement = Arrangement.Center,
|
||||||
|
) {
|
||||||
|
LinkIcon(
|
||||||
|
label = stringResource(R.string.website),
|
||||||
|
painter = rememberVectorPainter(Icons.Outlined.Public),
|
||||||
|
url = "https://tachiyomi.org",
|
||||||
|
)
|
||||||
|
LinkIcon(
|
||||||
|
label = "Discord",
|
||||||
|
painter = painterResource(R.drawable.ic_discord_24dp),
|
||||||
|
url = "https://discord.gg/tachiyomi",
|
||||||
|
)
|
||||||
|
LinkIcon(
|
||||||
|
label = "Twitter",
|
||||||
|
painter = painterResource(R.drawable.ic_twitter_24dp),
|
||||||
|
url = "https://twitter.com/tachiyomiorg",
|
||||||
|
)
|
||||||
|
LinkIcon(
|
||||||
|
label = "Facebook",
|
||||||
|
painter = painterResource(R.drawable.ic_facebook_24dp),
|
||||||
|
url = "https://facebook.com/tachiyomiorg",
|
||||||
|
)
|
||||||
|
LinkIcon(
|
||||||
|
label = "Reddit",
|
||||||
|
painter = painterResource(R.drawable.ic_reddit_24dp),
|
||||||
|
url = "https://www.reddit.com/r/Tachiyomi",
|
||||||
|
)
|
||||||
|
LinkIcon(
|
||||||
|
label = "GitHub",
|
||||||
|
painter = painterResource(R.drawable.ic_github_24dp),
|
||||||
|
url = "https://github.com/tachiyomiorg",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks version and shows a user prompt if an update is available.
|
||||||
|
*/
|
||||||
|
private suspend fun checkVersion(context: Context, router: Router) {
|
||||||
|
val updateChecker = AppUpdateChecker()
|
||||||
|
withUIContext {
|
||||||
|
context.toast(R.string.update_check_look_for_updates)
|
||||||
|
try {
|
||||||
|
when (val result = withIOContext { updateChecker.checkForUpdate(context, isUserPrompt = true) }) {
|
||||||
|
is AppUpdateResult.NewUpdate -> {
|
||||||
|
NewUpdateDialogController(result).showDialog(router)
|
||||||
|
}
|
||||||
|
is AppUpdateResult.NoNewUpdate -> {
|
||||||
|
context.toast(R.string.update_check_no_new_updates)
|
||||||
|
}
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
context.toast(e.message)
|
||||||
|
logcat(LogPriority.ERROR, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun getVersionName(withBuildDate: Boolean): String {
|
||||||
|
return when {
|
||||||
|
BuildConfig.DEBUG -> {
|
||||||
|
"Debug ${BuildConfig.COMMIT_SHA}".let {
|
||||||
|
if (withBuildDate) {
|
||||||
|
"$it (${getFormattedBuildTime()}"
|
||||||
|
} else {
|
||||||
|
it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BuildConfig.PREVIEW -> {
|
||||||
|
"Preview r${BuildConfig.COMMIT_COUNT}".let {
|
||||||
|
if (withBuildDate) {
|
||||||
|
"$it (${BuildConfig.COMMIT_SHA}, ${getFormattedBuildTime()})"
|
||||||
|
} else {
|
||||||
|
"$it (${BuildConfig.COMMIT_SHA})"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
"Stable ${BuildConfig.VERSION_NAME}".let {
|
||||||
|
if (withBuildDate) {
|
||||||
|
"$it (${getFormattedBuildTime()})"
|
||||||
|
} else {
|
||||||
|
it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getFormattedBuildTime(): String {
|
||||||
|
return try {
|
||||||
|
val inputDf = SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'", Locale.US)
|
||||||
|
inputDf.timeZone = TimeZone.getTimeZone("UTC")
|
||||||
|
val buildTime = inputDf.parse(BuildConfig.BUILD_TIME)
|
||||||
|
|
||||||
|
val outputDf = DateFormat.getDateTimeInstance(
|
||||||
|
DateFormat.MEDIUM,
|
||||||
|
DateFormat.SHORT,
|
||||||
|
Locale.getDefault(),
|
||||||
|
)
|
||||||
|
outputDf.timeZone = TimeZone.getDefault()
|
||||||
|
|
||||||
|
buildTime!!.toDateTimestampString(UiPreferences.dateFormat(Injekt.get<UiPreferences>().dateFormat().get()))
|
||||||
|
} catch (e: Exception) {
|
||||||
|
BuildConfig.BUILD_TIME
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,19 +1,26 @@
|
||||||
package eu.kanade.presentation.more.settings.screen
|
package eu.kanade.presentation.more.settings.screen
|
||||||
|
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.outlined.FlipToBack
|
import androidx.compose.material.icons.outlined.FlipToBack
|
||||||
import androidx.compose.material.icons.outlined.SelectAll
|
import androidx.compose.material.icons.outlined.SelectAll
|
||||||
|
import androidx.compose.material3.AlertDialog
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.Checkbox
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TextButton
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
@ -27,6 +34,7 @@ import cafe.adriel.voyager.navigator.currentOrThrow
|
||||||
import eu.kanade.domain.source.interactor.GetSourcesWithNonLibraryManga
|
import eu.kanade.domain.source.interactor.GetSourcesWithNonLibraryManga
|
||||||
import eu.kanade.domain.source.model.Source
|
import eu.kanade.domain.source.model.Source
|
||||||
import eu.kanade.domain.source.model.SourceWithCount
|
import eu.kanade.domain.source.model.SourceWithCount
|
||||||
|
import eu.kanade.presentation.browse.components.SourceIcon
|
||||||
import eu.kanade.presentation.components.AppBar
|
import eu.kanade.presentation.components.AppBar
|
||||||
import eu.kanade.presentation.components.AppBarActions
|
import eu.kanade.presentation.components.AppBarActions
|
||||||
import eu.kanade.presentation.components.Divider
|
import eu.kanade.presentation.components.Divider
|
||||||
|
@ -34,8 +42,7 @@ import eu.kanade.presentation.components.EmptyScreen
|
||||||
import eu.kanade.presentation.components.FastScrollLazyColumn
|
import eu.kanade.presentation.components.FastScrollLazyColumn
|
||||||
import eu.kanade.presentation.components.LoadingScreen
|
import eu.kanade.presentation.components.LoadingScreen
|
||||||
import eu.kanade.presentation.components.Scaffold
|
import eu.kanade.presentation.components.Scaffold
|
||||||
import eu.kanade.presentation.more.settings.database.components.ClearDatabaseDeleteDialog
|
import eu.kanade.presentation.util.selectedBackground
|
||||||
import eu.kanade.presentation.more.settings.database.components.ClearDatabaseItem
|
|
||||||
import eu.kanade.tachiyomi.Database
|
import eu.kanade.tachiyomi.Database
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||||
|
@ -58,14 +65,28 @@ class ClearDatabaseScreen : Screen {
|
||||||
is ClearDatabaseScreenModel.State.Loading -> LoadingScreen()
|
is ClearDatabaseScreenModel.State.Loading -> LoadingScreen()
|
||||||
is ClearDatabaseScreenModel.State.Ready -> {
|
is ClearDatabaseScreenModel.State.Ready -> {
|
||||||
if (s.showConfirmation) {
|
if (s.showConfirmation) {
|
||||||
ClearDatabaseDeleteDialog(
|
AlertDialog(
|
||||||
onDismissRequest = model::hideConfirmation,
|
onDismissRequest = model::hideConfirmation,
|
||||||
onDelete = {
|
confirmButton = {
|
||||||
|
TextButton(
|
||||||
|
onClick = {
|
||||||
model.removeMangaBySourceId()
|
model.removeMangaBySourceId()
|
||||||
model.clearSelection()
|
model.clearSelection()
|
||||||
model.hideConfirmation()
|
model.hideConfirmation()
|
||||||
context.toast(R.string.clear_database_completed)
|
context.toast(R.string.clear_database_completed)
|
||||||
},
|
},
|
||||||
|
) {
|
||||||
|
Text(text = stringResource(android.R.string.ok))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dismissButton = {
|
||||||
|
TextButton(onClick = model::hideConfirmation) {
|
||||||
|
Text(text = stringResource(android.R.string.cancel))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
text = {
|
||||||
|
Text(text = stringResource(R.string.clear_database_confirmation))
|
||||||
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,6 +161,40 @@ class ClearDatabaseScreen : Screen {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ClearDatabaseItem(
|
||||||
|
source: Source,
|
||||||
|
count: Long,
|
||||||
|
isSelected: Boolean,
|
||||||
|
onClickSelect: () -> Unit,
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.selectedBackground(isSelected)
|
||||||
|
.clickable(onClick = onClickSelect)
|
||||||
|
.padding(horizontal = 8.dp)
|
||||||
|
.height(56.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
SourceIcon(source = source)
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(start = 8.dp)
|
||||||
|
.weight(1f),
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = source.visualName,
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
)
|
||||||
|
Text(text = stringResource(R.string.clear_database_source_item_count, count))
|
||||||
|
}
|
||||||
|
Checkbox(
|
||||||
|
checked = isSelected,
|
||||||
|
onCheckedChange = { onClickSelect() },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ClearDatabaseScreenModel : StateScreenModel<ClearDatabaseScreenModel.State>(State.Loading) {
|
private class ClearDatabaseScreenModel : StateScreenModel<ClearDatabaseScreenModel.State>(State.Loading) {
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
package eu.kanade.presentation.more.about
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import cafe.adriel.voyager.core.screen.Screen
|
||||||
|
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||||
|
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||||
|
import com.mikepenz.aboutlibraries.ui.compose.LibrariesContainer
|
||||||
|
import com.mikepenz.aboutlibraries.ui.compose.LibraryDefaults
|
||||||
|
import eu.kanade.presentation.components.AppBar
|
||||||
|
import eu.kanade.presentation.components.Scaffold
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
|
||||||
|
class LicensesScreen : Screen {
|
||||||
|
@Composable
|
||||||
|
override fun Content() {
|
||||||
|
val navigator = LocalNavigator.currentOrThrow
|
||||||
|
Scaffold(
|
||||||
|
topBar = { scrollBehavior ->
|
||||||
|
AppBar(
|
||||||
|
title = stringResource(R.string.licenses),
|
||||||
|
navigateUp = navigator::pop,
|
||||||
|
scrollBehavior = scrollBehavior,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
) { contentPadding ->
|
||||||
|
LibrariesContainer(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize(),
|
||||||
|
contentPadding = contentPadding,
|
||||||
|
colors = LibraryDefaults.libraryColors(
|
||||||
|
backgroundColor = MaterialTheme.colorScheme.background,
|
||||||
|
contentColor = MaterialTheme.colorScheme.onBackground,
|
||||||
|
badgeBackgroundColor = MaterialTheme.colorScheme.primary,
|
||||||
|
badgeContentColor = MaterialTheme.colorScheme.onPrimary,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ import android.app.Activity
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.ReadOnlyComposable
|
import androidx.compose.runtime.ReadOnlyComposable
|
||||||
|
@ -19,6 +20,7 @@ import eu.kanade.presentation.util.collectAsState
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.util.system.isTablet
|
import eu.kanade.tachiyomi.util.system.isTablet
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
|
import kotlinx.coroutines.flow.debounce
|
||||||
import kotlinx.coroutines.flow.drop
|
import kotlinx.coroutines.flow.drop
|
||||||
import kotlinx.coroutines.flow.merge
|
import kotlinx.coroutines.flow.merge
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
|
@ -54,9 +56,25 @@ class SettingsAppearanceScreen : SearchableSettings {
|
||||||
val appThemePref = uiPreferences.appTheme()
|
val appThemePref = uiPreferences.appTheme()
|
||||||
val amoledPref = uiPreferences.themeDarkAmoled()
|
val amoledPref = uiPreferences.themeDarkAmoled()
|
||||||
|
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
themeModePref.changes()
|
||||||
|
.drop(1)
|
||||||
|
.debounce(1000)
|
||||||
|
.collectLatest {
|
||||||
|
AppCompatDelegate.setDefaultNightMode(
|
||||||
|
when (it) {
|
||||||
|
ThemeMode.LIGHT -> AppCompatDelegate.MODE_NIGHT_NO
|
||||||
|
ThemeMode.DARK -> AppCompatDelegate.MODE_NIGHT_YES
|
||||||
|
ThemeMode.SYSTEM -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
merge(appThemePref.changes(), amoledPref.changes())
|
merge(appThemePref.changes(), amoledPref.changes())
|
||||||
.drop(2)
|
.drop(2)
|
||||||
|
.debounce(1000)
|
||||||
.collectLatest { (context as? Activity)?.let { ActivityCompat.recreate(it) } }
|
.collectLatest { (context as? Activity)?.let { ActivityCompat.recreate(it) } }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,11 +8,12 @@ import androidx.activity.compose.rememberLauncherForActivityResult
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.heightIn
|
import androidx.compose.foundation.layout.heightIn
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.material3.AlertDialog
|
import androidx.compose.material3.AlertDialog
|
||||||
import androidx.compose.material3.Checkbox
|
import androidx.compose.material3.Checkbox
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
@ -39,8 +40,12 @@ import androidx.core.net.toUri
|
||||||
import com.google.accompanist.permissions.rememberPermissionState
|
import com.google.accompanist.permissions.rememberPermissionState
|
||||||
import com.hippo.unifile.UniFile
|
import com.hippo.unifile.UniFile
|
||||||
import eu.kanade.domain.backup.service.BackupPreferences
|
import eu.kanade.domain.backup.service.BackupPreferences
|
||||||
|
import eu.kanade.presentation.components.Divider
|
||||||
|
import eu.kanade.presentation.components.ScrollbarLazyColumn
|
||||||
import eu.kanade.presentation.more.settings.Preference
|
import eu.kanade.presentation.more.settings.Preference
|
||||||
import eu.kanade.presentation.util.collectAsState
|
import eu.kanade.presentation.util.collectAsState
|
||||||
|
import eu.kanade.presentation.util.isScrolledToEnd
|
||||||
|
import eu.kanade.presentation.util.isScrolledToStart
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.backup.BackupConst
|
import eu.kanade.tachiyomi.data.backup.BackupConst
|
||||||
import eu.kanade.tachiyomi.data.backup.BackupCreatorJob
|
import eu.kanade.tachiyomi.data.backup.BackupCreatorJob
|
||||||
|
@ -148,12 +153,17 @@ class SettingsBackupScreen : SearchableSettings {
|
||||||
onDismissRequest = onDismissRequest,
|
onDismissRequest = onDismissRequest,
|
||||||
title = { Text(text = stringResource(R.string.backup_choice)) },
|
title = { Text(text = stringResource(R.string.backup_choice)) },
|
||||||
text = {
|
text = {
|
||||||
Column {
|
Box {
|
||||||
|
val state = rememberLazyListState()
|
||||||
|
ScrollbarLazyColumn(state = state) {
|
||||||
|
item {
|
||||||
CreateBackupDialogItem(
|
CreateBackupDialogItem(
|
||||||
isSelected = true,
|
isSelected = true,
|
||||||
title = stringResource(R.string.manga),
|
title = stringResource(R.string.manga),
|
||||||
)
|
)
|
||||||
|
}
|
||||||
choices.forEach { (k, v) ->
|
choices.forEach { (k, v) ->
|
||||||
|
item {
|
||||||
val isSelected = flags.contains(k)
|
val isSelected = flags.contains(k)
|
||||||
CreateBackupDialogItem(
|
CreateBackupDialogItem(
|
||||||
isSelected = isSelected,
|
isSelected = isSelected,
|
||||||
|
@ -168,6 +178,10 @@ class SettingsBackupScreen : SearchableSettings {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (!state.isScrolledToStart()) Divider(modifier = Modifier.align(Alignment.TopCenter))
|
||||||
|
if (!state.isScrolledToEnd()) Divider(modifier = Modifier.align(Alignment.BottomCenter))
|
||||||
|
}
|
||||||
},
|
},
|
||||||
dismissButton = {
|
dismissButton = {
|
||||||
TextButton(onClick = onDismissRequest) {
|
TextButton(onClick = onDismissRequest) {
|
||||||
|
|
|
@ -9,6 +9,7 @@ import androidx.appcompat.app.AppCompatDelegate
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.ReadOnlyComposable
|
import androidx.compose.runtime.ReadOnlyComposable
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.core.os.LocaleListCompat
|
import androidx.core.os.LocaleListCompat
|
||||||
|
@ -17,6 +18,8 @@ import eu.kanade.domain.library.service.LibraryPreferences
|
||||||
import eu.kanade.presentation.more.settings.Preference
|
import eu.kanade.presentation.more.settings.Preference
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import org.xmlpull.v1.XmlPullParser
|
import org.xmlpull.v1.XmlPullParser
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
@ -30,6 +33,7 @@ class SettingsGeneralScreen : SearchableSettings {
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun getPreferences(): List<Preference> {
|
override fun getPreferences(): List<Preference> {
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
val prefs = remember { Injekt.get<BasePreferences>() }
|
val prefs = remember { Injekt.get<BasePreferences>() }
|
||||||
val libraryPrefs = remember { Injekt.get<LibraryPreferences>() }
|
val libraryPrefs = remember { Injekt.get<LibraryPreferences>() }
|
||||||
return mutableListOf<Preference>().apply {
|
return mutableListOf<Preference>().apply {
|
||||||
|
@ -71,12 +75,15 @@ class SettingsGeneralScreen : SearchableSettings {
|
||||||
subtitle = "%s",
|
subtitle = "%s",
|
||||||
entries = langs,
|
entries = langs,
|
||||||
onValueChanged = { newValue ->
|
onValueChanged = { newValue ->
|
||||||
|
scope.launch {
|
||||||
|
delay(1000)
|
||||||
val locale = if (newValue.isEmpty()) {
|
val locale = if (newValue.isEmpty()) {
|
||||||
LocaleListCompat.getEmptyLocaleList()
|
LocaleListCompat.getEmptyLocaleList()
|
||||||
} else {
|
} else {
|
||||||
LocaleListCompat.forLanguageTags(newValue)
|
LocaleListCompat.forLanguageTags(newValue)
|
||||||
}
|
}
|
||||||
AppCompatDelegate.setApplicationLocales(locale)
|
AppCompatDelegate.setApplicationLocales(locale)
|
||||||
|
}
|
||||||
true
|
true
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
|
@ -4,7 +4,8 @@ import androidx.annotation.StringRes
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.isSystemInDarkTheme
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.ArrowBack
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
|
@ -13,6 +14,7 @@ import androidx.compose.material.icons.outlined.Code
|
||||||
import androidx.compose.material.icons.outlined.CollectionsBookmark
|
import androidx.compose.material.icons.outlined.CollectionsBookmark
|
||||||
import androidx.compose.material.icons.outlined.Explore
|
import androidx.compose.material.icons.outlined.Explore
|
||||||
import androidx.compose.material.icons.outlined.GetApp
|
import androidx.compose.material.icons.outlined.GetApp
|
||||||
|
import androidx.compose.material.icons.outlined.Info
|
||||||
import androidx.compose.material.icons.outlined.Palette
|
import androidx.compose.material.icons.outlined.Palette
|
||||||
import androidx.compose.material.icons.outlined.Search
|
import androidx.compose.material.icons.outlined.Search
|
||||||
import androidx.compose.material.icons.outlined.Security
|
import androidx.compose.material.icons.outlined.Security
|
||||||
|
@ -25,8 +27,11 @@ import androidx.compose.material3.LocalContentColor
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TopAppBar
|
import androidx.compose.material3.TopAppBar
|
||||||
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
|
import androidx.compose.material3.rememberTopAppBarState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.CompositionLocalProvider
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
|
@ -35,7 +40,6 @@ import androidx.compose.ui.graphics.toArgb
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.util.fastFirstOrNull
|
|
||||||
import androidx.core.graphics.ColorUtils
|
import androidx.core.graphics.ColorUtils
|
||||||
import cafe.adriel.voyager.core.screen.Screen
|
import cafe.adriel.voyager.core.screen.Screen
|
||||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||||
|
@ -76,7 +80,9 @@ object SettingsMainScreen : Screen {
|
||||||
val navigator = LocalNavigator.currentOrThrow
|
val navigator = LocalNavigator.currentOrThrow
|
||||||
val backPress = LocalBackPress.currentOrThrow
|
val backPress = LocalBackPress.currentOrThrow
|
||||||
val containerColor = if (twoPane) getPalerSurface() else MaterialTheme.colorScheme.surface
|
val containerColor = if (twoPane) getPalerSurface() else MaterialTheme.colorScheme.surface
|
||||||
|
val topBarState = rememberTopAppBarState()
|
||||||
Scaffold(
|
Scaffold(
|
||||||
|
topBarScrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(topBarState),
|
||||||
topBar = { scrollBehavior ->
|
topBar = { scrollBehavior ->
|
||||||
// https://issuetracker.google.com/issues/249688556
|
// https://issuetracker.google.com/issues/249688556
|
||||||
MaterialTheme(
|
MaterialTheme(
|
||||||
|
@ -114,15 +120,34 @@ object SettingsMainScreen : Screen {
|
||||||
},
|
},
|
||||||
containerColor = containerColor,
|
containerColor = containerColor,
|
||||||
content = { contentPadding ->
|
content = { contentPadding ->
|
||||||
LazyColumn(contentPadding = contentPadding) {
|
val state = rememberLazyListState()
|
||||||
items(
|
val indexSelected = if (twoPane) {
|
||||||
|
items.indexOfFirst { it.screen::class == navigator.items.first()::class }
|
||||||
|
.also {
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
state.animateScrollToItem(it)
|
||||||
|
if (it > 0) {
|
||||||
|
// Lift scroll
|
||||||
|
topBarState.contentOffset = topBarState.heightOffsetLimit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
LazyColumn(
|
||||||
|
state = state,
|
||||||
|
contentPadding = contentPadding,
|
||||||
|
) {
|
||||||
|
itemsIndexed(
|
||||||
items = items,
|
items = items,
|
||||||
key = { it.hashCode() },
|
key = { _, item -> item.hashCode() },
|
||||||
) { item ->
|
) { index, item ->
|
||||||
|
val selected = indexSelected == index
|
||||||
var modifier: Modifier = Modifier
|
var modifier: Modifier = Modifier
|
||||||
var contentColor = LocalContentColor.current
|
var contentColor = LocalContentColor.current
|
||||||
if (twoPane) {
|
if (twoPane) {
|
||||||
val selected = navigator.items.fastFirstOrNull { it::class == item.screen::class } != null
|
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(horizontal = 8.dp)
|
.padding(horizontal = 8.dp)
|
||||||
.clip(RoundedCornerShape(24.dp))
|
.clip(RoundedCornerShape(24.dp))
|
||||||
|
@ -141,7 +166,7 @@ object SettingsMainScreen : Screen {
|
||||||
TextPreferenceWidget(
|
TextPreferenceWidget(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
title = stringResource(item.titleRes),
|
title = stringResource(item.titleRes),
|
||||||
subtitle = stringResource(item.subtitleRes),
|
subtitle = item.formatSubtitle(),
|
||||||
icon = item.icon,
|
icon = item.icon,
|
||||||
onPreferenceClick = { navigator.navigate(item.screen, twoPane) },
|
onPreferenceClick = { navigator.navigate(item.screen, twoPane) },
|
||||||
)
|
)
|
||||||
|
@ -160,6 +185,7 @@ object SettingsMainScreen : Screen {
|
||||||
private data class Item(
|
private data class Item(
|
||||||
@StringRes val titleRes: Int,
|
@StringRes val titleRes: Int,
|
||||||
@StringRes val subtitleRes: Int,
|
@StringRes val subtitleRes: Int,
|
||||||
|
val formatSubtitle: @Composable () -> String = { stringResource(subtitleRes) },
|
||||||
val icon: ImageVector,
|
val icon: ImageVector,
|
||||||
val screen: Screen,
|
val screen: Screen,
|
||||||
)
|
)
|
||||||
|
@ -225,4 +251,13 @@ private val items = listOf(
|
||||||
icon = Icons.Outlined.Code,
|
icon = Icons.Outlined.Code,
|
||||||
screen = SettingsAdvancedScreen(),
|
screen = SettingsAdvancedScreen(),
|
||||||
),
|
),
|
||||||
|
Item(
|
||||||
|
titleRes = R.string.pref_category_about,
|
||||||
|
subtitleRes = 0,
|
||||||
|
formatSubtitle = {
|
||||||
|
"${stringResource(R.string.app_name)} ${AboutScreen.getVersionName(withBuildDate = false)}"
|
||||||
|
},
|
||||||
|
icon = Icons.Outlined.Info,
|
||||||
|
screen = AboutScreen(),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
|
@ -91,6 +91,8 @@ class SettingsSearchScreen : Screen {
|
||||||
Column {
|
Column {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
navigationIcon = {
|
navigationIcon = {
|
||||||
|
val canPop = remember { navigator.canPop }
|
||||||
|
if (canPop) {
|
||||||
IconButton(onClick = navigator::pop) {
|
IconButton(onClick = navigator::pop) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.ArrowBack,
|
imageVector = Icons.Default.ArrowBack,
|
||||||
|
@ -98,6 +100,7 @@ class SettingsSearchScreen : Screen {
|
||||||
tint = MaterialTheme.colorScheme.onSurfaceVariant,
|
tint = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
title = {
|
title = {
|
||||||
BasicTextField(
|
BasicTextField(
|
||||||
|
|
|
@ -78,7 +78,7 @@ private fun AppThemesList(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.animateContentSize()
|
.animateContentSize()
|
||||||
.padding(vertical = 8.dp),
|
.padding(vertical = 8.dp),
|
||||||
contentPadding = PaddingValues(horizontal = HorizontalPadding),
|
contentPadding = PaddingValues(horizontal = PrefsHorizontalPadding),
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
) {
|
) {
|
||||||
items(
|
items(
|
||||||
|
|
|
@ -53,30 +53,30 @@ internal fun BasePreferenceWidget(
|
||||||
) {
|
) {
|
||||||
if (icon != null) {
|
if (icon != null) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier.padding(start = HorizontalPadding),
|
modifier = Modifier.padding(start = PrefsHorizontalPadding, end = 8.dp),
|
||||||
content = { icon() },
|
content = { icon() },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
.padding(vertical = 16.dp),
|
.padding(vertical = PrefsVerticalPadding),
|
||||||
) {
|
) {
|
||||||
if (!title.isNullOrBlank()) {
|
if (!title.isNullOrBlank()) {
|
||||||
Text(
|
Text(
|
||||||
modifier = Modifier.padding(horizontal = HorizontalPadding),
|
modifier = Modifier.padding(horizontal = PrefsHorizontalPadding),
|
||||||
text = title,
|
text = title,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
maxLines = 2,
|
maxLines = 2,
|
||||||
style = MaterialTheme.typography.titleLarge,
|
style = MaterialTheme.typography.titleLarge,
|
||||||
fontSize = 20.sp,
|
fontSize = TitleFontSize,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
subcomponent?.invoke(this)
|
subcomponent?.invoke(this)
|
||||||
}
|
}
|
||||||
if (widget != null) {
|
if (widget != null) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier.padding(end = HorizontalPadding),
|
modifier = Modifier.padding(end = PrefsHorizontalPadding),
|
||||||
content = { widget() },
|
content = { widget() },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -117,4 +117,6 @@ internal fun Modifier.highlightBackground(highlighted: Boolean): Modifier = comp
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val TrailingWidgetBuffer = 16.dp
|
internal val TrailingWidgetBuffer = 16.dp
|
||||||
internal val HorizontalPadding = 24.dp
|
internal val PrefsHorizontalPadding = 16.dp
|
||||||
|
internal val PrefsVerticalPadding = 16.dp
|
||||||
|
internal val TitleFontSize = 16.sp
|
||||||
|
|
|
@ -23,7 +23,7 @@ import eu.kanade.tachiyomi.R
|
||||||
internal fun InfoWidget(text: String) {
|
internal fun InfoWidget(text: String) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(horizontal = HorizontalPadding, vertical = 16.dp)
|
.padding(horizontal = PrefsHorizontalPadding, vertical = 16.dp)
|
||||||
.secondaryItemAlpha(),
|
.secondaryItemAlpha(),
|
||||||
verticalArrangement = Arrangement.spacedBy(16.dp),
|
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||||
) {
|
) {
|
||||||
|
@ -33,7 +33,7 @@ internal fun InfoWidget(text: String) {
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = text,
|
text = text,
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
style = MaterialTheme.typography.bodySmall,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ fun PreferenceGroupHeader(title: String) {
|
||||||
Text(
|
Text(
|
||||||
text = title,
|
text = title,
|
||||||
color = MaterialTheme.colorScheme.secondary,
|
color = MaterialTheme.colorScheme.secondary,
|
||||||
modifier = Modifier.padding(horizontal = 24.dp),
|
modifier = Modifier.padding(horizontal = PrefsHorizontalPadding),
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,9 +33,9 @@ fun TextPreferenceWidget(
|
||||||
Text(
|
Text(
|
||||||
text = subtitle,
|
text = subtitle,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(horizontal = HorizontalPadding)
|
.padding(horizontal = PrefsHorizontalPadding)
|
||||||
.secondaryItemAlpha(),
|
.secondaryItemAlpha(),
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
style = MaterialTheme.typography.bodySmall,
|
||||||
maxLines = 10,
|
maxLines = 10,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,6 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
|
||||||
import eu.kanade.presentation.more.settings.LocalPreferenceHighlighted
|
import eu.kanade.presentation.more.settings.LocalPreferenceHighlighted
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
@ -40,7 +39,7 @@ fun TrackingPreferenceWidget(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.clickable(enabled = onClick != null, onClick = { onClick?.invoke() })
|
.clickable(enabled = onClick != null, onClick = { onClick?.invoke() })
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = HorizontalPadding, vertical = 8.dp),
|
.padding(horizontal = PrefsHorizontalPadding, vertical = 8.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
|
@ -62,7 +61,7 @@ fun TrackingPreferenceWidget(
|
||||||
.padding(horizontal = 16.dp),
|
.padding(horizontal = 16.dp),
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
style = MaterialTheme.typography.titleLarge,
|
style = MaterialTheme.typography.titleLarge,
|
||||||
fontSize = 20.sp,
|
fontSize = TitleFontSize,
|
||||||
)
|
)
|
||||||
if (checked) {
|
if (checked) {
|
||||||
Icon(
|
Icon(
|
||||||
|
|
|
@ -11,7 +11,6 @@ import android.content.IntentFilter
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.webkit.WebView
|
import android.webkit.WebView
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
|
||||||
import androidx.core.app.NotificationManagerCompat
|
import androidx.core.app.NotificationManagerCompat
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import androidx.glance.appwidget.GlanceAppWidgetManager
|
import androidx.glance.appwidget.GlanceAppWidgetManager
|
||||||
|
@ -28,8 +27,6 @@ import coil.util.DebugLogger
|
||||||
import eu.kanade.data.DatabaseHandler
|
import eu.kanade.data.DatabaseHandler
|
||||||
import eu.kanade.domain.DomainModule
|
import eu.kanade.domain.DomainModule
|
||||||
import eu.kanade.domain.base.BasePreferences
|
import eu.kanade.domain.base.BasePreferences
|
||||||
import eu.kanade.domain.ui.UiPreferences
|
|
||||||
import eu.kanade.domain.ui.model.ThemeMode
|
|
||||||
import eu.kanade.tachiyomi.crash.CrashActivity
|
import eu.kanade.tachiyomi.crash.CrashActivity
|
||||||
import eu.kanade.tachiyomi.crash.GlobalExceptionHandler
|
import eu.kanade.tachiyomi.crash.GlobalExceptionHandler
|
||||||
import eu.kanade.tachiyomi.data.coil.DomainMangaKeyer
|
import eu.kanade.tachiyomi.data.coil.DomainMangaKeyer
|
||||||
|
@ -42,7 +39,6 @@ import eu.kanade.tachiyomi.glance.UpdatesGridGlanceWidget
|
||||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||||
import eu.kanade.tachiyomi.network.NetworkPreferences
|
import eu.kanade.tachiyomi.network.NetworkPreferences
|
||||||
import eu.kanade.tachiyomi.ui.base.delegate.SecureActivityDelegate
|
import eu.kanade.tachiyomi.ui.base.delegate.SecureActivityDelegate
|
||||||
import eu.kanade.tachiyomi.util.preference.asHotFlow
|
|
||||||
import eu.kanade.tachiyomi.util.system.WebViewUtil
|
import eu.kanade.tachiyomi.util.system.WebViewUtil
|
||||||
import eu.kanade.tachiyomi.util.system.animatorDurationScale
|
import eu.kanade.tachiyomi.util.system.animatorDurationScale
|
||||||
import eu.kanade.tachiyomi.util.system.isDevFlavor
|
import eu.kanade.tachiyomi.util.system.isDevFlavor
|
||||||
|
@ -67,7 +63,6 @@ import java.security.Security
|
||||||
class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
|
class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
|
||||||
|
|
||||||
private val basePreferences: BasePreferences by injectLazy()
|
private val basePreferences: BasePreferences by injectLazy()
|
||||||
private val uiPreferences: UiPreferences by injectLazy()
|
|
||||||
private val networkPreferences: NetworkPreferences by injectLazy()
|
private val networkPreferences: NetworkPreferences by injectLazy()
|
||||||
|
|
||||||
private val disableIncognitoReceiver = DisableIncognitoReceiver()
|
private val disableIncognitoReceiver = DisableIncognitoReceiver()
|
||||||
|
@ -126,17 +121,6 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
|
||||||
}
|
}
|
||||||
.launchIn(ProcessLifecycleOwner.get().lifecycleScope)
|
.launchIn(ProcessLifecycleOwner.get().lifecycleScope)
|
||||||
|
|
||||||
uiPreferences.themeMode()
|
|
||||||
.asHotFlow {
|
|
||||||
AppCompatDelegate.setDefaultNightMode(
|
|
||||||
when (it) {
|
|
||||||
ThemeMode.LIGHT -> AppCompatDelegate.MODE_NIGHT_NO
|
|
||||||
ThemeMode.DARK -> AppCompatDelegate.MODE_NIGHT_YES
|
|
||||||
ThemeMode.SYSTEM -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}.launchIn(ProcessLifecycleOwner.get().lifecycleScope)
|
|
||||||
|
|
||||||
// Updates widget update
|
// Updates widget update
|
||||||
Injekt.get<DatabaseHandler>()
|
Injekt.get<DatabaseHandler>()
|
||||||
.subscribeToList { updatesViewQueries.updates(after = UpdatesGridGlanceWidget.DateLimit.timeInMillis) }
|
.subscribeToList { updatesViewQueries.updates(after = UpdatesGridGlanceWidget.DateLimit.timeInMillis) }
|
||||||
|
|
|
@ -1,86 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.ui.more
|
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import eu.kanade.domain.ui.UiPreferences
|
|
||||||
import eu.kanade.presentation.more.about.AboutScreen
|
|
||||||
import eu.kanade.tachiyomi.BuildConfig
|
|
||||||
import eu.kanade.tachiyomi.R
|
|
||||||
import eu.kanade.tachiyomi.data.updater.AppUpdateChecker
|
|
||||||
import eu.kanade.tachiyomi.data.updater.AppUpdateResult
|
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.BasicFullComposeController
|
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.pushController
|
|
||||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
|
||||||
import eu.kanade.tachiyomi.util.lang.toDateTimestampString
|
|
||||||
import eu.kanade.tachiyomi.util.lang.withUIContext
|
|
||||||
import eu.kanade.tachiyomi.util.system.logcat
|
|
||||||
import eu.kanade.tachiyomi.util.system.toast
|
|
||||||
import logcat.LogPriority
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
import java.text.DateFormat
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.Locale
|
|
||||||
import java.util.TimeZone
|
|
||||||
|
|
||||||
class AboutController : BasicFullComposeController() {
|
|
||||||
|
|
||||||
private val preferences: UiPreferences by injectLazy()
|
|
||||||
private val updateChecker by lazy { AppUpdateChecker() }
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
override fun ComposeContent() {
|
|
||||||
AboutScreen(
|
|
||||||
navigateUp = router::popCurrentController,
|
|
||||||
checkVersion = this::checkVersion,
|
|
||||||
getFormattedBuildTime = this::getFormattedBuildTime,
|
|
||||||
onClickLicenses = { router.pushController(LicensesController()) },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks version and shows a user prompt if an update is available.
|
|
||||||
*/
|
|
||||||
private fun checkVersion() {
|
|
||||||
if (activity == null) return
|
|
||||||
|
|
||||||
activity!!.toast(R.string.update_check_look_for_updates)
|
|
||||||
|
|
||||||
viewScope.launchIO {
|
|
||||||
try {
|
|
||||||
val result = updateChecker.checkForUpdate(activity!!, isUserPrompt = true)
|
|
||||||
withUIContext {
|
|
||||||
when (result) {
|
|
||||||
is AppUpdateResult.NewUpdate -> {
|
|
||||||
NewUpdateDialogController(result).showDialog(router)
|
|
||||||
}
|
|
||||||
is AppUpdateResult.NoNewUpdate -> {
|
|
||||||
activity?.toast(R.string.update_check_no_new_updates)
|
|
||||||
}
|
|
||||||
else -> {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
withUIContext { activity?.toast(e.message) }
|
|
||||||
logcat(LogPriority.ERROR, e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getFormattedBuildTime(): String {
|
|
||||||
return try {
|
|
||||||
val inputDf = SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'", Locale.US)
|
|
||||||
inputDf.timeZone = TimeZone.getTimeZone("UTC")
|
|
||||||
val buildTime = inputDf.parse(BuildConfig.BUILD_TIME)
|
|
||||||
|
|
||||||
val outputDf = DateFormat.getDateTimeInstance(
|
|
||||||
DateFormat.MEDIUM,
|
|
||||||
DateFormat.SHORT,
|
|
||||||
Locale.getDefault(),
|
|
||||||
)
|
|
||||||
outputDf.timeZone = TimeZone.getDefault()
|
|
||||||
|
|
||||||
buildTime!!.toDateTimestampString(UiPreferences.dateFormat(preferences.dateFormat().get()))
|
|
||||||
} catch (e: Exception) {
|
|
||||||
BuildConfig.BUILD_TIME
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.ui.more
|
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import eu.kanade.presentation.more.about.LicensesScreen
|
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.BasicFullComposeController
|
|
||||||
|
|
||||||
class LicensesController : BasicFullComposeController() {
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
override fun ComposeContent() {
|
|
||||||
LicensesScreen(
|
|
||||||
navigateUp = router::popCurrentController,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -21,9 +21,9 @@ class MoreController :
|
||||||
presenter = presenter,
|
presenter = presenter,
|
||||||
onClickDownloadQueue = { router.pushController(DownloadController()) },
|
onClickDownloadQueue = { router.pushController(DownloadController()) },
|
||||||
onClickCategories = { router.pushController(CategoryController()) },
|
onClickCategories = { router.pushController(CategoryController()) },
|
||||||
onClickBackupAndRestore = { router.pushController(SettingsMainController(toBackupScreen = true)) },
|
onClickBackupAndRestore = { router.pushController(SettingsMainController.toBackupScreen()) },
|
||||||
onClickSettings = { router.pushController(SettingsMainController()) },
|
onClickSettings = { router.pushController(SettingsMainController()) },
|
||||||
onClickAbout = { router.pushController(AboutController()) },
|
onClickAbout = { router.pushController(SettingsMainController.toAboutScreen()) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ import cafe.adriel.voyager.core.stack.StackEvent
|
||||||
import cafe.adriel.voyager.navigator.Navigator
|
import cafe.adriel.voyager.navigator.Navigator
|
||||||
import cafe.adriel.voyager.transitions.ScreenTransition
|
import cafe.adriel.voyager.transitions.ScreenTransition
|
||||||
import eu.kanade.presentation.components.TwoPanelBox
|
import eu.kanade.presentation.components.TwoPanelBox
|
||||||
|
import eu.kanade.presentation.more.settings.screen.AboutScreen
|
||||||
import eu.kanade.presentation.more.settings.screen.SettingsBackupScreen
|
import eu.kanade.presentation.more.settings.screen.SettingsBackupScreen
|
||||||
import eu.kanade.presentation.more.settings.screen.SettingsGeneralScreen
|
import eu.kanade.presentation.more.settings.screen.SettingsGeneralScreen
|
||||||
import eu.kanade.presentation.more.settings.screen.SettingsMainScreen
|
import eu.kanade.presentation.more.settings.screen.SettingsMainScreen
|
||||||
|
@ -19,14 +20,10 @@ import eu.kanade.tachiyomi.ui.base.controller.BasicFullComposeController
|
||||||
import soup.compose.material.motion.animation.materialSharedAxisX
|
import soup.compose.material.motion.animation.materialSharedAxisX
|
||||||
import soup.compose.material.motion.animation.rememberSlideDistance
|
import soup.compose.material.motion.animation.rememberSlideDistance
|
||||||
|
|
||||||
class SettingsMainController : BasicFullComposeController {
|
class SettingsMainController(bundle: Bundle = bundleOf()) : BasicFullComposeController(bundle) {
|
||||||
|
|
||||||
@Suppress("unused")
|
|
||||||
constructor(bundle: Bundle) : this(bundle.getBoolean(TO_BACKUP_SCREEN))
|
|
||||||
|
|
||||||
constructor(toBackupScreen: Boolean = false) : super(bundleOf(TO_BACKUP_SCREEN to toBackupScreen))
|
|
||||||
|
|
||||||
private val toBackupScreen = args.getBoolean(TO_BACKUP_SCREEN)
|
private val toBackupScreen = args.getBoolean(TO_BACKUP_SCREEN)
|
||||||
|
private val toAboutScreen = args.getBoolean(TO_ABOUT_SCREEN)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun ComposeContent() {
|
override fun ComposeContent() {
|
||||||
|
@ -34,7 +31,13 @@ class SettingsMainController : BasicFullComposeController {
|
||||||
val widthSizeClass = calculateWindowWidthSizeClass()
|
val widthSizeClass = calculateWindowWidthSizeClass()
|
||||||
if (widthSizeClass == WindowWidthSizeClass.Compact) {
|
if (widthSizeClass == WindowWidthSizeClass.Compact) {
|
||||||
Navigator(
|
Navigator(
|
||||||
screen = if (toBackupScreen) SettingsBackupScreen() else SettingsMainScreen,
|
screen = if (toBackupScreen) {
|
||||||
|
SettingsBackupScreen()
|
||||||
|
} else if (toAboutScreen) {
|
||||||
|
AboutScreen()
|
||||||
|
} else {
|
||||||
|
SettingsMainScreen
|
||||||
|
},
|
||||||
content = {
|
content = {
|
||||||
CompositionLocalProvider(LocalBackPress provides this::back) {
|
CompositionLocalProvider(LocalBackPress provides this::back) {
|
||||||
val slideDistance = rememberSlideDistance()
|
val slideDistance = rememberSlideDistance()
|
||||||
|
@ -52,7 +55,13 @@ class SettingsMainController : BasicFullComposeController {
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Navigator(
|
Navigator(
|
||||||
screen = if (toBackupScreen) SettingsBackupScreen() else SettingsGeneralScreen(),
|
screen = if (toBackupScreen) {
|
||||||
|
SettingsBackupScreen()
|
||||||
|
} else if (toAboutScreen) {
|
||||||
|
AboutScreen()
|
||||||
|
} else {
|
||||||
|
SettingsGeneralScreen()
|
||||||
|
},
|
||||||
) {
|
) {
|
||||||
TwoPanelBox(
|
TwoPanelBox(
|
||||||
startContent = {
|
startContent = {
|
||||||
|
@ -81,6 +90,17 @@ class SettingsMainController : BasicFullComposeController {
|
||||||
private fun back() {
|
private fun back() {
|
||||||
activity?.onBackPressed()
|
activity?.onBackPressed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun toBackupScreen(): SettingsMainController {
|
||||||
|
return SettingsMainController(bundleOf(TO_BACKUP_SCREEN to true))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toAboutScreen(): SettingsMainController {
|
||||||
|
return SettingsMainController(bundleOf(TO_ABOUT_SCREEN to true))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private const val TO_BACKUP_SCREEN = "to_backup_screen"
|
private const val TO_BACKUP_SCREEN = "to_backup_screen"
|
||||||
|
private const val TO_ABOUT_SCREEN = "to_about_screen"
|
||||||
|
|
Loading…
Reference in a new issue