diff --git a/app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt b/app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt index 663c504db..5f88b0454 100644 --- a/app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt +++ b/app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt @@ -66,4 +66,6 @@ class SourcePreferences( serializer = { MigrationFlag.toBit(it) }, deserializer = { value: Int -> MigrationFlag.fromBit(value) }, ) + + fun skipMigrationConfig() = preferenceStore.getBoolean(Preference.appStateKey("skip_migration_config"), false) } diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBrowseScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBrowseScreen.kt index 6baeda597..6677b39a4 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBrowseScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBrowseScreen.kt @@ -71,6 +71,22 @@ object SettingsBrowseScreen : SearchableSettings { Preference.PreferenceItem.InfoPreference(stringResource(MR.strings.parental_controls_info)), ), ), + getMigrationCategory(sourcePreferences), + ) + } + + @Composable + fun getMigrationCategory(sourcePreferences: SourcePreferences): Preference.PreferenceGroup { + return Preference.PreferenceGroup( + stringResource(MR.strings.browseSettingsScreen_migrationCategoryHeader), + enabled = sourcePreferences.skipMigrationConfig().isSet(), + preferenceItems = persistentListOf( + Preference.PreferenceItem.SwitchPreference( + preference = sourcePreferences.skipMigrationConfig(), + title = stringResource(MR.strings.browseSettingsScreen_skipMigrationConfigTitle), + subtitle = stringResource(MR.strings.browseSettingsScreen_skipMigrationConfigSubtitle), + ), + ), ) } } diff --git a/app/src/main/java/mihon/feature/migration/config/MigrationConfigScreen.kt b/app/src/main/java/mihon/feature/migration/config/MigrationConfigScreen.kt index 8c2f5e9f8..689be9cd1 100644 --- a/app/src/main/java/mihon/feature/migration/config/MigrationConfigScreen.kt +++ b/app/src/main/java/mihon/feature/migration/config/MigrationConfigScreen.kt @@ -22,10 +22,14 @@ import androidx.compose.material3.ListItemDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -61,6 +65,7 @@ import tachiyomi.presentation.core.components.material.ExtendedFloatingActionBut import tachiyomi.presentation.core.components.material.Scaffold import tachiyomi.presentation.core.components.material.padding import tachiyomi.presentation.core.i18n.stringResource +import tachiyomi.presentation.core.screens.LoadingScreen import tachiyomi.presentation.core.util.shouldExpandFAB import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get @@ -70,8 +75,28 @@ class MigrationConfigScreen(private val mangaId: Long) : Screen() { @Composable override fun Content() { val navigator = LocalNavigator.currentOrThrow + val screenModel = rememberScreenModel { ScreenModel() } val state by screenModel.state.collectAsState() + + var migrationSheetOpen by rememberSaveable { mutableStateOf(false) } + + fun continueMigration(openSheet: Boolean) { + if (openSheet) { + migrationSheetOpen = true + return + } + navigator.replace(MigrateSearchScreen(mangaId)) + } + + if (state.isLoading) { + LaunchedEffect(state.skipMigrationConfig) { + if (state.skipMigrationConfig) continueMigration(openSheet = false) + } + LoadingScreen() + return + } + val (selectedSources, availableSources) = state.sources.partition { it.isSelected } val showLanguage by remember(state) { derivedStateOf { @@ -118,7 +143,7 @@ class MigrationConfigScreen(private val mangaId: Long) : Screen() { icon = { Icon(imageVector = Icons.AutoMirrored.Outlined.ArrowForward, contentDescription = null) }, onClick = { screenModel.saveSources() - navigator.replace(MigrateSearchScreen(mangaId)) + continueMigration(openSheet = true) }, expanded = lazyListState.shouldExpandFAB(), ) @@ -174,6 +199,17 @@ class MigrationConfigScreen(private val mangaId: Long) : Screen() { } } } + + if (migrationSheetOpen) { + MigrationConfigScreenSheet( + preferences = screenModel.sourcePreferences, + onDismissRequest = { migrationSheetOpen = false }, + onStartMigration = { + migrationSheetOpen = false + continueMigration(openSheet = false) + }, + ) + } } @Composable @@ -270,13 +306,17 @@ class MigrationConfigScreen(private val mangaId: Long) : Screen() { } private class ScreenModel( + val sourcePreferences: SourcePreferences = Injekt.get(), private val sourceManager: SourceManager = Injekt.get(), - private val sourcePreferences: SourcePreferences = Injekt.get(), ) : StateScreenModel(State()) { init { screenModelScope.launchIO { + val skipMigrationConfig = sourcePreferences.skipMigrationConfig().get() + mutableState.update { it.copy(skipMigrationConfig = skipMigrationConfig) } + if (skipMigrationConfig) return@launchIO initSources() + mutableState.update { it.copy(isLoading = false) } } } @@ -373,6 +413,8 @@ class MigrationConfigScreen(private val mangaId: Long) : Screen() { } data class State( + val isLoading: Boolean = true, + val skipMigrationConfig: Boolean = false, val sources: List = emptyList(), ) diff --git a/app/src/main/java/mihon/feature/migration/config/MigrationConfigScreenSheet.kt b/app/src/main/java/mihon/feature/migration/config/MigrationConfigScreenSheet.kt new file mode 100644 index 000000000..a53aa56d3 --- /dev/null +++ b/app/src/main/java/mihon/feature/migration/config/MigrationConfigScreenSheet.kt @@ -0,0 +1,87 @@ +package mihon.feature.migration.config + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.ListItem +import androidx.compose.material3.ListItemDefaults +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Switch +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import eu.kanade.domain.source.service.SourcePreferences +import eu.kanade.presentation.components.AdaptiveSheet +import tachiyomi.core.common.preference.toggle +import tachiyomi.i18n.MR +import tachiyomi.presentation.core.components.material.Button +import tachiyomi.presentation.core.components.material.padding +import tachiyomi.presentation.core.i18n.stringResource +import tachiyomi.presentation.core.util.collectAsState + +@Composable +fun MigrationConfigScreenSheet( + preferences: SourcePreferences, + onDismissRequest: () -> Unit, + onStartMigration: () -> Unit, +) { + val skipMigrationConfig by preferences.skipMigrationConfig().collectAsState() + AdaptiveSheet(onDismissRequest = onDismissRequest) { + Column(modifier = Modifier.fillMaxWidth()) { + Column( + modifier = Modifier + .fillMaxWidth() + .verticalScroll(rememberScrollState()), + verticalArrangement = Arrangement.spacedBy(8.dp), + ) { + MigrationSheetItem( + title = stringResource(MR.strings.migrationConfigScreen_skipMigrationConfigTitle), + subtitle = stringResource(MR.strings.migrationConfigScreen_skipMigrationConfigSubtitle), + action = { + Switch( + checked = skipMigrationConfig, + onCheckedChange = null, + ) + }, + onClick = { preferences.skipMigrationConfig().toggle() }, + ) + } + HorizontalDivider() + Button( + onClick = onStartMigration, + modifier = Modifier + .fillMaxWidth() + .padding( + horizontal = MaterialTheme.padding.medium, + vertical = MaterialTheme.padding.small, + ), + ) { + Text(text = stringResource(MR.strings.migrationConfigScreen_continueButtonText)) + } + } + } +} + +@Composable +private fun MigrationSheetItem( + title: String, + subtitle: String?, + action: @Composable () -> Unit, + onClick: () -> Unit, +) { + ListItem( + headlineContent = { Text(text = title) }, + supportingContent = subtitle?.let { { Text(text = subtitle) } }, + trailingContent = action, + colors = ListItemDefaults.colors(containerColor = Color.Transparent), + modifier = Modifier.clickable(onClick = onClick), + ) +} diff --git a/i18n/src/commonMain/moko-resources/base/strings.xml b/i18n/src/commonMain/moko-resources/base/strings.xml index bfe36a045..34f5860e6 100644 --- a/i18n/src/commonMain/moko-resources/base/strings.xml +++ b/i18n/src/commonMain/moko-resources/base/strings.xml @@ -1004,4 +1004,10 @@ Select enabled sources Select pinned sources Continue + Skip migration config + To show this screen again in the future, disable skipping in Settings → Browse + + Migration + Skip migration config + Use last used sources and preferences for migration