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
@ -13,16 +13,16 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
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.res.painterResource
|
||||
import androidx.compose.ui.res.pluralStringResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import eu.kanade.presentation.components.AppStateBanners
|
||||
import eu.kanade.presentation.components.Divider
|
||||
import eu.kanade.presentation.components.PreferenceRow
|
||||
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.ui.more.DownloadQueueState
|
||||
import eu.kanade.tachiyomi.ui.more.MoreController
|
||||
@ -57,26 +57,28 @@ fun MoreScreen(
|
||||
}
|
||||
|
||||
item {
|
||||
SwitchPreference(
|
||||
preference = presenter.downloadedOnly,
|
||||
SwitchPreferenceWidget(
|
||||
title = stringResource(R.string.label_downloaded_only),
|
||||
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 {
|
||||
SwitchPreference(
|
||||
preference = presenter.incognitoMode,
|
||||
SwitchPreferenceWidget(
|
||||
title = stringResource(R.string.pref_incognito_mode),
|
||||
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 {
|
||||
PreferenceRow(
|
||||
TextPreferenceWidget(
|
||||
title = stringResource(R.string.label_download_queue),
|
||||
subtitle = when (downloadQueueState) {
|
||||
DownloadQueueState.Stopped -> null
|
||||
@ -99,46 +101,46 @@ fun MoreScreen(
|
||||
pluralStringResource(id = R.plurals.download_queue_summary, count = pending, pending)
|
||||
}
|
||||
},
|
||||
painter = rememberVectorPainter(Icons.Outlined.GetApp),
|
||||
onClick = onClickDownloadQueue,
|
||||
icon = Icons.Outlined.GetApp,
|
||||
onPreferenceClick = onClickDownloadQueue,
|
||||
)
|
||||
}
|
||||
item {
|
||||
PreferenceRow(
|
||||
TextPreferenceWidget(
|
||||
title = stringResource(R.string.categories),
|
||||
painter = rememberVectorPainter(Icons.Outlined.Label),
|
||||
onClick = onClickCategories,
|
||||
icon = Icons.Outlined.Label,
|
||||
onPreferenceClick = onClickCategories,
|
||||
)
|
||||
}
|
||||
item {
|
||||
PreferenceRow(
|
||||
TextPreferenceWidget(
|
||||
title = stringResource(R.string.label_backup),
|
||||
painter = rememberVectorPainter(Icons.Outlined.SettingsBackupRestore),
|
||||
onClick = onClickBackupAndRestore,
|
||||
icon = Icons.Outlined.SettingsBackupRestore,
|
||||
onPreferenceClick = onClickBackupAndRestore,
|
||||
)
|
||||
}
|
||||
|
||||
item { Divider() }
|
||||
|
||||
item {
|
||||
PreferenceRow(
|
||||
TextPreferenceWidget(
|
||||
title = stringResource(R.string.label_settings),
|
||||
painter = rememberVectorPainter(Icons.Outlined.Settings),
|
||||
onClick = onClickSettings,
|
||||
icon = Icons.Outlined.Settings,
|
||||
onPreferenceClick = onClickSettings,
|
||||
)
|
||||
}
|
||||
item {
|
||||
PreferenceRow(
|
||||
TextPreferenceWidget(
|
||||
title = stringResource(R.string.pref_category_about),
|
||||
painter = rememberVectorPainter(Icons.Outlined.Info),
|
||||
onClick = onClickAbout,
|
||||
icon = Icons.Outlined.Info,
|
||||
onPreferenceClick = onClickAbout,
|
||||
)
|
||||
}
|
||||
item {
|
||||
PreferenceRow(
|
||||
TextPreferenceWidget(
|
||||
title = stringResource(R.string.label_help),
|
||||
painter = rememberVectorPainter(Icons.Outlined.HelpOutline),
|
||||
onClick = { uriHandler.openUri(MoreController.URL_HELP) },
|
||||
icon = Icons.Outlined.HelpOutline,
|
||||
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.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material3.Icon
|
||||
@ -10,9 +9,7 @@ import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
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.presentation.components.Scaffold
|
||||
import eu.kanade.tachiyomi.R
|
||||
|
||||
@ -26,12 +23,7 @@ fun PreferenceScaffold(
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = {
|
||||
Text(
|
||||
text = stringResource(id = titleRes),
|
||||
modifier = Modifier.padding(start = 8.dp),
|
||||
)
|
||||
},
|
||||
title = { Text(text = stringResource(id = titleRes)) },
|
||||
navigationIcon = {
|
||||
if (onBackPressed != null) {
|
||||
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
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.FlipToBack
|
||||
import androidx.compose.material.icons.outlined.SelectAll
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Checkbox
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
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.model.Source
|
||||
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.AppBarActions
|
||||
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.LoadingScreen
|
||||
import eu.kanade.presentation.components.Scaffold
|
||||
import eu.kanade.presentation.more.settings.database.components.ClearDatabaseDeleteDialog
|
||||
import eu.kanade.presentation.more.settings.database.components.ClearDatabaseItem
|
||||
import eu.kanade.presentation.util.selectedBackground
|
||||
import eu.kanade.tachiyomi.Database
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
@ -58,13 +65,27 @@ class ClearDatabaseScreen : Screen {
|
||||
is ClearDatabaseScreenModel.State.Loading -> LoadingScreen()
|
||||
is ClearDatabaseScreenModel.State.Ready -> {
|
||||
if (s.showConfirmation) {
|
||||
ClearDatabaseDeleteDialog(
|
||||
AlertDialog(
|
||||
onDismissRequest = model::hideConfirmation,
|
||||
onDelete = {
|
||||
model.removeMangaBySourceId()
|
||||
model.clearSelection()
|
||||
model.hideConfirmation()
|
||||
context.toast(R.string.clear_database_completed)
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
model.removeMangaBySourceId()
|
||||
model.clearSelection()
|
||||
model.hideConfirmation()
|
||||
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) {
|
||||
|
@ -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.os.Build
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.ReadOnlyComposable
|
||||
@ -19,6 +20,7 @@ import eu.kanade.presentation.util.collectAsState
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.util.system.isTablet
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.debounce
|
||||
import kotlinx.coroutines.flow.drop
|
||||
import kotlinx.coroutines.flow.merge
|
||||
import uy.kohesive.injekt.Injekt
|
||||
@ -54,9 +56,25 @@ class SettingsAppearanceScreen : SearchableSettings {
|
||||
val appThemePref = uiPreferences.appTheme()
|
||||
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) {
|
||||
merge(appThemePref.changes(), amoledPref.changes())
|
||||
.drop(2)
|
||||
.debounce(1000)
|
||||
.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.annotation.StringRes
|
||||
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.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Checkbox
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
@ -39,8 +40,12 @@ import androidx.core.net.toUri
|
||||
import com.google.accompanist.permissions.rememberPermissionState
|
||||
import com.hippo.unifile.UniFile
|
||||
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.util.collectAsState
|
||||
import eu.kanade.presentation.util.isScrolledToEnd
|
||||
import eu.kanade.presentation.util.isScrolledToStart
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.backup.BackupConst
|
||||
import eu.kanade.tachiyomi.data.backup.BackupCreatorJob
|
||||
@ -148,25 +153,34 @@ class SettingsBackupScreen : SearchableSettings {
|
||||
onDismissRequest = onDismissRequest,
|
||||
title = { Text(text = stringResource(R.string.backup_choice)) },
|
||||
text = {
|
||||
Column {
|
||||
CreateBackupDialogItem(
|
||||
isSelected = true,
|
||||
title = stringResource(R.string.manga),
|
||||
)
|
||||
choices.forEach { (k, v) ->
|
||||
val isSelected = flags.contains(k)
|
||||
CreateBackupDialogItem(
|
||||
isSelected = isSelected,
|
||||
title = stringResource(v),
|
||||
modifier = Modifier.clickable {
|
||||
if (isSelected) {
|
||||
flags.remove(k)
|
||||
} else {
|
||||
flags.add(k)
|
||||
}
|
||||
},
|
||||
)
|
||||
Box {
|
||||
val state = rememberLazyListState()
|
||||
ScrollbarLazyColumn(state = state) {
|
||||
item {
|
||||
CreateBackupDialogItem(
|
||||
isSelected = true,
|
||||
title = stringResource(R.string.manga),
|
||||
)
|
||||
}
|
||||
choices.forEach { (k, v) ->
|
||||
item {
|
||||
val isSelected = flags.contains(k)
|
||||
CreateBackupDialogItem(
|
||||
isSelected = isSelected,
|
||||
title = stringResource(v),
|
||||
modifier = Modifier.clickable {
|
||||
if (isSelected) {
|
||||
flags.remove(k)
|
||||
} else {
|
||||
flags.add(k)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!state.isScrolledToStart()) Divider(modifier = Modifier.align(Alignment.TopCenter))
|
||||
if (!state.isScrolledToEnd()) Divider(modifier = Modifier.align(Alignment.BottomCenter))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
|
@ -9,6 +9,7 @@ import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.ReadOnlyComposable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
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.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import org.xmlpull.v1.XmlPullParser
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
@ -30,6 +33,7 @@ class SettingsGeneralScreen : SearchableSettings {
|
||||
|
||||
@Composable
|
||||
override fun getPreferences(): List<Preference> {
|
||||
val scope = rememberCoroutineScope()
|
||||
val prefs = remember { Injekt.get<BasePreferences>() }
|
||||
val libraryPrefs = remember { Injekt.get<LibraryPreferences>() }
|
||||
return mutableListOf<Preference>().apply {
|
||||
@ -71,12 +75,15 @@ class SettingsGeneralScreen : SearchableSettings {
|
||||
subtitle = "%s",
|
||||
entries = langs,
|
||||
onValueChanged = { newValue ->
|
||||
val locale = if (newValue.isEmpty()) {
|
||||
LocaleListCompat.getEmptyLocaleList()
|
||||
} else {
|
||||
LocaleListCompat.forLanguageTags(newValue)
|
||||
scope.launch {
|
||||
delay(1000)
|
||||
val locale = if (newValue.isEmpty()) {
|
||||
LocaleListCompat.getEmptyLocaleList()
|
||||
} else {
|
||||
LocaleListCompat.forLanguageTags(newValue)
|
||||
}
|
||||
AppCompatDelegate.setApplicationLocales(locale)
|
||||
}
|
||||
AppCompatDelegate.setApplicationLocales(locale)
|
||||
true
|
||||
},
|
||||
),
|
||||
|
@ -4,7 +4,8 @@ import androidx.annotation.StringRes
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
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.material.icons.Icons
|
||||
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.Explore
|
||||
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.Search
|
||||
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.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.rememberTopAppBarState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
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.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.util.fastFirstOrNull
|
||||
import androidx.core.graphics.ColorUtils
|
||||
import cafe.adriel.voyager.core.screen.Screen
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
@ -76,7 +80,9 @@ object SettingsMainScreen : Screen {
|
||||
val navigator = LocalNavigator.currentOrThrow
|
||||
val backPress = LocalBackPress.currentOrThrow
|
||||
val containerColor = if (twoPane) getPalerSurface() else MaterialTheme.colorScheme.surface
|
||||
val topBarState = rememberTopAppBarState()
|
||||
Scaffold(
|
||||
topBarScrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(topBarState),
|
||||
topBar = { scrollBehavior ->
|
||||
// https://issuetracker.google.com/issues/249688556
|
||||
MaterialTheme(
|
||||
@ -114,15 +120,34 @@ object SettingsMainScreen : Screen {
|
||||
},
|
||||
containerColor = containerColor,
|
||||
content = { contentPadding ->
|
||||
LazyColumn(contentPadding = contentPadding) {
|
||||
items(
|
||||
val state = rememberLazyListState()
|
||||
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,
|
||||
key = { it.hashCode() },
|
||||
) { item ->
|
||||
key = { _, item -> item.hashCode() },
|
||||
) { index, item ->
|
||||
val selected = indexSelected == index
|
||||
var modifier: Modifier = Modifier
|
||||
var contentColor = LocalContentColor.current
|
||||
if (twoPane) {
|
||||
val selected = navigator.items.fastFirstOrNull { it::class == item.screen::class } != null
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 8.dp)
|
||||
.clip(RoundedCornerShape(24.dp))
|
||||
@ -141,7 +166,7 @@ object SettingsMainScreen : Screen {
|
||||
TextPreferenceWidget(
|
||||
modifier = modifier,
|
||||
title = stringResource(item.titleRes),
|
||||
subtitle = stringResource(item.subtitleRes),
|
||||
subtitle = item.formatSubtitle(),
|
||||
icon = item.icon,
|
||||
onPreferenceClick = { navigator.navigate(item.screen, twoPane) },
|
||||
)
|
||||
@ -160,6 +185,7 @@ object SettingsMainScreen : Screen {
|
||||
private data class Item(
|
||||
@StringRes val titleRes: Int,
|
||||
@StringRes val subtitleRes: Int,
|
||||
val formatSubtitle: @Composable () -> String = { stringResource(subtitleRes) },
|
||||
val icon: ImageVector,
|
||||
val screen: Screen,
|
||||
)
|
||||
@ -225,4 +251,13 @@ private val items = listOf(
|
||||
icon = Icons.Outlined.Code,
|
||||
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,12 +91,15 @@ class SettingsSearchScreen : Screen {
|
||||
Column {
|
||||
TopAppBar(
|
||||
navigationIcon = {
|
||||
IconButton(onClick = navigator::pop) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.ArrowBack,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
val canPop = remember { navigator.canPop }
|
||||
if (canPop) {
|
||||
IconButton(onClick = navigator::pop) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.ArrowBack,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
title = {
|
||||
|
@ -78,7 +78,7 @@ private fun AppThemesList(
|
||||
modifier = Modifier
|
||||
.animateContentSize()
|
||||
.padding(vertical = 8.dp),
|
||||
contentPadding = PaddingValues(horizontal = HorizontalPadding),
|
||||
contentPadding = PaddingValues(horizontal = PrefsHorizontalPadding),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
items(
|
||||
|
@ -53,30 +53,30 @@ internal fun BasePreferenceWidget(
|
||||
) {
|
||||
if (icon != null) {
|
||||
Box(
|
||||
modifier = Modifier.padding(start = HorizontalPadding),
|
||||
modifier = Modifier.padding(start = PrefsHorizontalPadding, end = 8.dp),
|
||||
content = { icon() },
|
||||
)
|
||||
}
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(vertical = 16.dp),
|
||||
.padding(vertical = PrefsVerticalPadding),
|
||||
) {
|
||||
if (!title.isNullOrBlank()) {
|
||||
Text(
|
||||
modifier = Modifier.padding(horizontal = HorizontalPadding),
|
||||
modifier = Modifier.padding(horizontal = PrefsHorizontalPadding),
|
||||
text = title,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 2,
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
fontSize = 20.sp,
|
||||
fontSize = TitleFontSize,
|
||||
)
|
||||
}
|
||||
subcomponent?.invoke(this)
|
||||
}
|
||||
if (widget != null) {
|
||||
Box(
|
||||
modifier = Modifier.padding(end = HorizontalPadding),
|
||||
modifier = Modifier.padding(end = PrefsHorizontalPadding),
|
||||
content = { widget() },
|
||||
)
|
||||
}
|
||||
@ -117,4 +117,6 @@ internal fun Modifier.highlightBackground(highlighted: Boolean): Modifier = comp
|
||||
}
|
||||
|
||||
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) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = HorizontalPadding, vertical = 16.dp)
|
||||
.padding(horizontal = PrefsHorizontalPadding, vertical = 16.dp)
|
||||
.secondaryItemAlpha(),
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||
) {
|
||||
@ -33,7 +33,7 @@ internal fun InfoWidget(text: String) {
|
||||
)
|
||||
Text(
|
||||
text = text,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ fun PreferenceGroupHeader(title: String) {
|
||||
Text(
|
||||
text = title,
|
||||
color = MaterialTheme.colorScheme.secondary,
|
||||
modifier = Modifier.padding(horizontal = 24.dp),
|
||||
modifier = Modifier.padding(horizontal = PrefsHorizontalPadding),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
)
|
||||
}
|
||||
|
@ -33,9 +33,9 @@ fun TextPreferenceWidget(
|
||||
Text(
|
||||
text = subtitle,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = HorizontalPadding)
|
||||
.padding(horizontal = PrefsHorizontalPadding)
|
||||
.secondaryItemAlpha(),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
maxLines = 10,
|
||||
)
|
||||
}
|
||||
|
@ -22,7 +22,6 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import eu.kanade.presentation.more.settings.LocalPreferenceHighlighted
|
||||
|
||||
@Composable
|
||||
@ -40,7 +39,7 @@ fun TrackingPreferenceWidget(
|
||||
modifier = modifier
|
||||
.clickable(enabled = onClick != null, onClick = { onClick?.invoke() })
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = HorizontalPadding, vertical = 8.dp),
|
||||
.padding(horizontal = PrefsHorizontalPadding, vertical = 8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Box(
|
||||
@ -62,7 +61,7 @@ fun TrackingPreferenceWidget(
|
||||
.padding(horizontal = 16.dp),
|
||||
maxLines = 1,
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
fontSize = 20.sp,
|
||||
fontSize = TitleFontSize,
|
||||
)
|
||||
if (checked) {
|
||||
Icon(
|
||||
|
@ -11,7 +11,6 @@ import android.content.IntentFilter
|
||||
import android.os.Build
|
||||
import android.os.Looper
|
||||
import android.webkit.WebView
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.glance.appwidget.GlanceAppWidgetManager
|
||||
@ -28,8 +27,6 @@ import coil.util.DebugLogger
|
||||
import eu.kanade.data.DatabaseHandler
|
||||
import eu.kanade.domain.DomainModule
|
||||
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.GlobalExceptionHandler
|
||||
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.NetworkPreferences
|
||||
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.animatorDurationScale
|
||||
import eu.kanade.tachiyomi.util.system.isDevFlavor
|
||||
@ -67,7 +63,6 @@ import java.security.Security
|
||||
class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
|
||||
|
||||
private val basePreferences: BasePreferences by injectLazy()
|
||||
private val uiPreferences: UiPreferences by injectLazy()
|
||||
private val networkPreferences: NetworkPreferences by injectLazy()
|
||||
|
||||
private val disableIncognitoReceiver = DisableIncognitoReceiver()
|
||||
@ -126,17 +121,6 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
|
||||
}
|
||||
.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
|
||||
Injekt.get<DatabaseHandler>()
|
||||
.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,
|
||||
onClickDownloadQueue = { router.pushController(DownloadController()) },
|
||||
onClickCategories = { router.pushController(CategoryController()) },
|
||||
onClickBackupAndRestore = { router.pushController(SettingsMainController(toBackupScreen = true)) },
|
||||
onClickBackupAndRestore = { router.pushController(SettingsMainController.toBackupScreen()) },
|
||||
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.transitions.ScreenTransition
|
||||
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.SettingsGeneralScreen
|
||||
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.rememberSlideDistance
|
||||
|
||||
class SettingsMainController : BasicFullComposeController {
|
||||
|
||||
@Suppress("unused")
|
||||
constructor(bundle: Bundle) : this(bundle.getBoolean(TO_BACKUP_SCREEN))
|
||||
|
||||
constructor(toBackupScreen: Boolean = false) : super(bundleOf(TO_BACKUP_SCREEN to toBackupScreen))
|
||||
class SettingsMainController(bundle: Bundle = bundleOf()) : BasicFullComposeController(bundle) {
|
||||
|
||||
private val toBackupScreen = args.getBoolean(TO_BACKUP_SCREEN)
|
||||
private val toAboutScreen = args.getBoolean(TO_ABOUT_SCREEN)
|
||||
|
||||
@Composable
|
||||
override fun ComposeContent() {
|
||||
@ -34,7 +31,13 @@ class SettingsMainController : BasicFullComposeController {
|
||||
val widthSizeClass = calculateWindowWidthSizeClass()
|
||||
if (widthSizeClass == WindowWidthSizeClass.Compact) {
|
||||
Navigator(
|
||||
screen = if (toBackupScreen) SettingsBackupScreen() else SettingsMainScreen,
|
||||
screen = if (toBackupScreen) {
|
||||
SettingsBackupScreen()
|
||||
} else if (toAboutScreen) {
|
||||
AboutScreen()
|
||||
} else {
|
||||
SettingsMainScreen
|
||||
},
|
||||
content = {
|
||||
CompositionLocalProvider(LocalBackPress provides this::back) {
|
||||
val slideDistance = rememberSlideDistance()
|
||||
@ -52,7 +55,13 @@ class SettingsMainController : BasicFullComposeController {
|
||||
)
|
||||
} else {
|
||||
Navigator(
|
||||
screen = if (toBackupScreen) SettingsBackupScreen() else SettingsGeneralScreen(),
|
||||
screen = if (toBackupScreen) {
|
||||
SettingsBackupScreen()
|
||||
} else if (toAboutScreen) {
|
||||
AboutScreen()
|
||||
} else {
|
||||
SettingsGeneralScreen()
|
||||
},
|
||||
) {
|
||||
TwoPanelBox(
|
||||
startContent = {
|
||||
@ -81,6 +90,17 @@ class SettingsMainController : BasicFullComposeController {
|
||||
private fun back() {
|
||||
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_ABOUT_SCREEN = "to_about_screen"
|
||||
|
Loading…
Reference in New Issue
Block a user