Add option to skip migration config

(cherry picked from commit 8714653a2f3b1a1f536494bcefbe66e7a7bbb4f7)

Co-authored-by: Cuong-Tran <16017808+cuong-tran@users.noreply.github.com>
This commit is contained in:
AntsyLich 2025-06-02 11:07:02 +06:00 committed by Cuong-Tran
parent 5ab24620ec
commit 2236e94f50
6 changed files with 168 additions and 37 deletions

View file

@ -78,6 +78,8 @@ class SourcePreferences(
deserializer = { value: Int -> MigrationFlag.fromBit(value) }, deserializer = { value: Int -> MigrationFlag.fromBit(value) },
) )
fun skipMigrationConfig() = preferenceStore.getBoolean(Preference.appStateKey("skip_migration_config"), false)
// KMK --> // KMK -->
fun globalSearchPinnedState() = preferenceStore.getEnum( fun globalSearchPinnedState() = preferenceStore.getEnum(
Preference.appStateKey("global_search_pinned_toggle_state"), Preference.appStateKey("global_search_pinned_toggle_state"),
@ -124,8 +126,6 @@ class SourcePreferences(
fun useSourceWithMost() = preferenceStore.getBoolean("use_source_with_most", false) fun useSourceWithMost() = preferenceStore.getBoolean("use_source_with_most", false)
fun skipPreMigration() = preferenceStore.getBoolean(Preference.appStateKey("skip_pre_migration"), false)
fun hideNotFoundMigration() = preferenceStore.getBoolean("hide_not_found_migration", false) fun hideNotFoundMigration() = preferenceStore.getBoolean("hide_not_found_migration", false)
fun showOnlyUpdatesMigration() = preferenceStore.getBoolean("show_only_updates_migration", false) fun showOnlyUpdatesMigration() = preferenceStore.getBoolean("show_only_updates_migration", false)

View file

@ -30,6 +30,7 @@ import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
object SettingsBrowseScreen : SearchableSettings { object SettingsBrowseScreen : SearchableSettings {
@Suppress("unused")
private fun readResolve(): Any = SettingsBrowseScreen private fun readResolve(): Any = SettingsBrowseScreen
@ReadOnlyComposable @ReadOnlyComposable
@ -171,16 +172,14 @@ object SettingsBrowseScreen : SearchableSettings {
@Composable @Composable
fun getMigrationCategory(sourcePreferences: SourcePreferences): Preference.PreferenceGroup { fun getMigrationCategory(sourcePreferences: SourcePreferences): Preference.PreferenceGroup {
val skipPreMigration by sourcePreferences.skipPreMigration().collectAsState()
val migrationSources by sourcePreferences.migrationSources().collectAsState()
return Preference.PreferenceGroup( return Preference.PreferenceGroup(
stringResource(SYMR.strings.migration), stringResource(MR.strings.browseSettingsScreen_migrationCategoryHeader),
enabled = skipPreMigration || migrationSources.isNotEmpty(), enabled = sourcePreferences.skipMigrationConfig().isSet(),
preferenceItems = persistentListOf( preferenceItems = persistentListOf(
Preference.PreferenceItem.SwitchPreference( Preference.PreferenceItem.SwitchPreference(
preference = sourcePreferences.skipPreMigration(), preference = sourcePreferences.skipMigrationConfig(),
title = stringResource(SYMR.strings.skip_pre_migration), title = stringResource(MR.strings.browseSettingsScreen_skipMigrationConfigTitle),
subtitle = stringResource(SYMR.strings.pref_skip_pre_migration_summary), subtitle = stringResource(MR.strings.browseSettingsScreen_skipMigrationConfigSubtitle),
), ),
), ),
) )

View file

@ -144,7 +144,7 @@ class MigrationBottomSheetDialogState(
} }
sourceGroup.bindToPreference(preferences.useSourceWithMost()) sourceGroup.bindToPreference(preferences.useSourceWithMost())
skipStep.isChecked = preferences.skipPreMigration().get() skipStep.isChecked = preferences.skipMigrationConfig().get()
hideNotFoundManga.isChecked = preferences.hideNotFoundMigration().get() hideNotFoundManga.isChecked = preferences.hideNotFoundMigration().get()
onlyShowUpdates.isChecked = preferences.showOnlyUpdatesMigration().get() onlyShowUpdates.isChecked = preferences.showOnlyUpdatesMigration().get()
skipStep.setOnCheckedChangeListener { _, isChecked -> skipStep.setOnCheckedChangeListener { _, isChecked ->
@ -157,7 +157,7 @@ class MigrationBottomSheetDialogState(
} }
migrateBtn.setOnClickListener { migrateBtn.setOnClickListener {
preferences.skipPreMigration().set(skipStep.isChecked) preferences.skipMigrationConfig().set(skipStep.isChecked)
preferences.hideNotFoundMigration().set(hideNotFoundManga.isChecked) preferences.hideNotFoundMigration().set(hideNotFoundManga.isChecked)
preferences.showOnlyUpdatesMigration().set(onlyShowUpdates.isChecked) preferences.showOnlyUpdatesMigration().set(onlyShowUpdates.isChecked)
onStartMigration.value( onStartMigration.value(

View file

@ -30,11 +30,13 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SmallExtendedFloatingActionButton import androidx.compose.material3.SmallExtendedFloatingActionButton
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@ -63,8 +65,6 @@ import eu.kanade.tachiyomi.ui.browse.migration.advanced.process.MigrationProcedu
import eu.kanade.tachiyomi.ui.browse.migration.advanced.process.MigrationType import eu.kanade.tachiyomi.ui.browse.migration.advanced.process.MigrationType
import eu.kanade.tachiyomi.util.system.LocaleHelper import eu.kanade.tachiyomi.util.system.LocaleHelper
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import sh.calvin.reorderable.ReorderableCollectionItemScope import sh.calvin.reorderable.ReorderableCollectionItemScope
import sh.calvin.reorderable.ReorderableItem import sh.calvin.reorderable.ReorderableItem
@ -82,6 +82,7 @@ import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.components.material.padding import tachiyomi.presentation.core.components.material.padding
import tachiyomi.presentation.core.i18n.stringResource import tachiyomi.presentation.core.i18n.stringResource
import tachiyomi.presentation.core.icons.FlagEmoji import tachiyomi.presentation.core.icons.FlagEmoji
import tachiyomi.presentation.core.screens.LoadingScreen
import tachiyomi.presentation.core.util.shouldExpandFAB import tachiyomi.presentation.core.util.shouldExpandFAB
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
@ -99,6 +100,7 @@ class MigrationConfigScreen(private val mangaIds: List<Long>) : Screen() {
@Composable @Composable
override fun Content() { override fun Content() {
val navigator = LocalNavigator.currentOrThrow val navigator = LocalNavigator.currentOrThrow
val screenModel = rememberScreenModel { ScreenModel() } val screenModel = rememberScreenModel { ScreenModel() }
// KMK --> // KMK -->
var searchQuery by remember { mutableStateOf("") } var searchQuery by remember { mutableStateOf("") }
@ -107,6 +109,44 @@ class MigrationConfigScreen(private val mangaIds: List<Long>) : Screen() {
} }
// KMK <-- // KMK <--
val state by screenModel.state.collectAsState() val state by screenModel.state.collectAsState()
var migrationSheetOpen by rememberSaveable { mutableStateOf(false) }
// KMK -->
var migrationBottomSheetDialog by rememberSaveable { mutableStateOf(false) }
fun continueMigrationBottom(openSheet: Boolean, extraParam: String? = null) {
if (openSheet) {
migrationBottomSheetDialog = true
return
}
navigator.replace(
// KMK -->
MigrationListScreen(
MigrationProcedureConfig(MigrationType.MangaList(mangaIds), extraParam),
),
// KMK <--
)
}
// KMK <--
fun continueMigration(openSheet: Boolean) {
if (openSheet) {
migrationSheetOpen = true
return
}
// KMK -->
continueMigrationBottom(true)
// KMK <--
}
if (state.isLoading) {
LaunchedEffect(state.skipMigrationConfig) {
if (state.skipMigrationConfig) continueMigration(openSheet = false)
}
LoadingScreen()
return
}
val (selectedSources, availableSources) = state.sources val (selectedSources, availableSources) = state.sources
// KMK --> // KMK -->
.filter { sources -> .filter { sources ->
@ -173,9 +213,7 @@ class MigrationConfigScreen(private val mangaIds: List<Long>) : Screen() {
icon = { Icon(imageVector = Icons.AutoMirrored.Outlined.ArrowForward, contentDescription = null) }, icon = { Icon(imageVector = Icons.AutoMirrored.Outlined.ArrowForward, contentDescription = null) },
onClick = { onClick = {
screenModel.saveSources() screenModel.saveSources()
// KMK --> continueMigration(openSheet = true)
screenModel.onMigrationSheet(true)
// KMK <--
}, },
expanded = lazyListState.shouldExpandFAB(), expanded = lazyListState.shouldExpandFAB(),
) )
@ -263,20 +301,24 @@ class MigrationConfigScreen(private val mangaIds: List<Long>) : Screen() {
} }
} }
// KMK -->
val migrationSheetOpen by screenModel.migrationSheetOpen.collectAsState()
if (migrationSheetOpen) { if (migrationSheetOpen) {
MigrationConfigScreenSheet(
preferences = screenModel.sourcePreferences,
onDismissRequest = { migrationSheetOpen = false },
onStartMigration = {
migrationSheetOpen = false
continueMigration(openSheet = false)
},
)
}
// KMK -->
if (migrationBottomSheetDialog) {
MigrationBottomSheetDialog( MigrationBottomSheetDialog(
onDismissRequest = { screenModel.onMigrationSheet(false) }, onDismissRequest = { migrationBottomSheetDialog = false },
onStartMigration = { extraParam -> onStartMigration = { extraParam ->
screenModel.onMigrationSheet(false) migrationBottomSheetDialog = false
navigator.replace( continueMigrationBottom(openSheet = false, extraParam)
// KMK -->
MigrationListScreen(
MigrationProcedureConfig(MigrationType.MangaList(mangaIds), extraParam),
),
// KMK <--
)
}, },
) )
} }
@ -379,8 +421,8 @@ class MigrationConfigScreen(private val mangaIds: List<Long>) : Screen() {
} }
private class ScreenModel( private class ScreenModel(
val sourcePreferences: SourcePreferences = Injekt.get(),
private val sourceManager: SourceManager = Injekt.get(), private val sourceManager: SourceManager = Injekt.get(),
private val sourcePreferences: SourcePreferences = Injekt.get(),
) : StateScreenModel<ScreenModel.State>(State()) { ) : StateScreenModel<ScreenModel.State>(State()) {
// KMK --> // KMK -->
@ -390,19 +432,14 @@ class MigrationConfigScreen(private val mangaIds: List<Long>) : Screen() {
init { init {
screenModelScope.launchIO { screenModelScope.launchIO {
val skipMigrationConfig = sourcePreferences.skipMigrationConfig().get()
mutableState.update { it.copy(skipMigrationConfig = skipMigrationConfig) }
if (skipMigrationConfig) return@launchIO
initSources() initSources()
mutableState.update { it.copy(isLoading = false) }
} }
} }
// KMK -->
private val _migrationSheetOpen = MutableStateFlow(false)
val migrationSheetOpen = _migrationSheetOpen.asStateFlow()
fun onMigrationSheet(isOpen: Boolean) {
_migrationSheetOpen.value = isOpen
}
// KMK <--
private val sourcesComparator = { includedSources: /* KMK --> */ Map<Long, Int> /* KMK <-- */ -> private val sourcesComparator = { includedSources: /* KMK --> */ Map<Long, Int> /* KMK <-- */ ->
compareBy<MigrationSource>( compareBy<MigrationSource>(
// KMK --> // KMK -->
@ -505,6 +542,8 @@ class MigrationConfigScreen(private val mangaIds: List<Long>) : Screen() {
} }
data class State( data class State(
val isLoading: Boolean = true,
val skipMigrationConfig: Boolean = false,
val sources: List<MigrationSource> = emptyList(), val sources: List<MigrationSource> = emptyList(),
) )

View file

@ -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),
)
}

View file

@ -1015,4 +1015,10 @@
<string name="migrationConfigScreen.selectEnabledLabel">Select enabled sources</string> <string name="migrationConfigScreen.selectEnabledLabel">Select enabled sources</string>
<string name="migrationConfigScreen.selectPinnedLabel">Select pinned sources</string> <string name="migrationConfigScreen.selectPinnedLabel">Select pinned sources</string>
<string name="migrationConfigScreen.continueButtonText">Continue</string> <string name="migrationConfigScreen.continueButtonText">Continue</string>
<string name="migrationConfigScreen.skipMigrationConfigTitle">Skip migration config</string>
<string name="migrationConfigScreen.skipMigrationConfigSubtitle">To show this screen again in the future, disable skipping in Settings → Browse</string>
<string name="browseSettingsScreen.migrationCategoryHeader">Migration</string>
<string name="browseSettingsScreen.skipMigrationConfigTitle">Skip migration config</string>
<string name="browseSettingsScreen.skipMigrationConfigSubtitle">Use last used sources and preferences for migration</string>
</resources> </resources>