Add more migration config options and remove skipping option (mihonapp/mihon#2193)

(cherry picked from commit 288f577a45a6835c34ad41caab95794f164b7a0b)

* Further tweak migration config screen sheet

(cherry picked from commit 019fc08da2392725c36e064ffadc4e645edafb63)

Co-authored-by: Cuong-Tran <16017808+cuong-tran@users.noreply.github.com>
This commit is contained in:
AntsyLich 2025-06-12 04:18:13 +06:00 committed by Cuong-Tran
parent 2236e94f50
commit 42a97bb918
8 changed files with 224 additions and 135 deletions

View file

@ -23,8 +23,6 @@ class SourcePreferences(
fun enabledLanguages() = preferenceStore.getStringSet("source_languages", LocaleHelper.getDefaultEnabledLanguages()) fun enabledLanguages() = preferenceStore.getStringSet("source_languages", LocaleHelper.getDefaultEnabledLanguages())
fun migrationSources() = preferenceStore.getLongArray("migration_sources", emptyList())
fun disabledSources() = preferenceStore.getStringSet("hidden_catalogues", emptySet()) fun disabledSources() = preferenceStore.getStringSet("hidden_catalogues", emptySet())
fun incognitoExtensions() = preferenceStore.getStringSet("incognito_extensions", emptySet()) fun incognitoExtensions() = preferenceStore.getStringSet("incognito_extensions", emptySet())
@ -71,14 +69,22 @@ class SourcePreferences(
false, false,
) )
fun migrationSources() = preferenceStore.getLongArray("migration_sources", emptyList())
fun migrationFlags() = preferenceStore.getObjectFromInt( fun migrationFlags() = preferenceStore.getObjectFromInt(
key = "migrate_flags", key = "migration_flags",
defaultValue = MigrationFlag.entries.toSet(), defaultValue = MigrationFlag.entries.toSet(),
serializer = { MigrationFlag.toBit(it) }, serializer = { MigrationFlag.toBit(it) },
deserializer = { value: Int -> MigrationFlag.fromBit(value) }, deserializer = { value: Int -> MigrationFlag.fromBit(value) },
) )
fun skipMigrationConfig() = preferenceStore.getBoolean(Preference.appStateKey("skip_migration_config"), false) fun migrationDeepSearchMode() = preferenceStore.getBoolean("migration_deep_search", false)
fun migrationPrioritizeByChapters() = preferenceStore.getBoolean("migration_prioritize_by_chapters", false)
fun migrationHideUnmatched() = preferenceStore.getBoolean("migration_hide_unmatched", false)
fun migrationHideWithoutUpdates() = preferenceStore.getBoolean("migration_hide_without_updates", false)
// KMK --> // KMK -->
fun globalSearchPinnedState() = preferenceStore.getEnum( fun globalSearchPinnedState() = preferenceStore.getEnum(
@ -122,14 +128,6 @@ class SourcePreferences(
WSRV_NL, WSRV_NL,
} }
fun smartMigration() = preferenceStore.getBoolean("smart_migrate", false)
fun useSourceWithMost() = preferenceStore.getBoolean("use_source_with_most", false)
fun hideNotFoundMigration() = preferenceStore.getBoolean("hide_not_found_migration", false)
fun showOnlyUpdatesMigration() = preferenceStore.getBoolean("show_only_updates_migration", false)
fun allowLocalSourceHiddenFolders() = preferenceStore.getBoolean("allow_local_source_hidden_folders", false) fun allowLocalSourceHiddenFolders() = preferenceStore.getBoolean("allow_local_source_hidden_folders", false)
fun preferredMangaDexId() = preferenceStore.getString("preferred_mangaDex_id", "0") fun preferredMangaDexId() = preferenceStore.getString("preferred_mangaDex_id", "0")

View file

@ -166,22 +166,6 @@ object SettingsBrowseScreen : SearchableSettings {
Preference.PreferenceItem.InfoPreference(stringResource(MR.strings.parental_controls_info)), 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),
),
),
) )
} }
} }

View file

@ -4,7 +4,6 @@ import android.view.LayoutInflater
import android.widget.CompoundButton import android.widget.CompoundButton
import android.widget.RadioButton import android.widget.RadioButton
import android.widget.RadioGroup import android.widget.RadioGroup
import android.widget.Toast
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
@ -21,13 +20,11 @@ import eu.kanade.domain.source.service.SourcePreferences
import eu.kanade.presentation.components.AdaptiveSheet import eu.kanade.presentation.components.AdaptiveSheet
import eu.kanade.presentation.theme.colorscheme.AndroidViewColorScheme import eu.kanade.presentation.theme.colorscheme.AndroidViewColorScheme
import eu.kanade.tachiyomi.databinding.MigrationBottomSheetBinding import eu.kanade.tachiyomi.databinding.MigrationBottomSheetBinding
import eu.kanade.tachiyomi.util.system.toast
import mihon.domain.migration.models.MigrationFlag import mihon.domain.migration.models.MigrationFlag
import tachiyomi.core.common.i18n.stringResource import tachiyomi.core.common.i18n.stringResource
import tachiyomi.core.common.preference.Preference import tachiyomi.core.common.preference.Preference
import tachiyomi.core.common.util.lang.toLong import tachiyomi.core.common.util.lang.toLong
import tachiyomi.i18n.MR import tachiyomi.i18n.MR
import tachiyomi.i18n.sy.SYMR
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
@Composable @Composable
@ -85,7 +82,6 @@ fun MigrationBottomSheetDialog(
listOf( listOf(
useSmartSearch, useSmartSearch,
extraSearchParam, extraSearchParam,
skipStep,
hideNotFoundManga, hideNotFoundManga,
onlyShowUpdates, onlyShowUpdates,
).forEach { ).forEach {
@ -137,29 +133,19 @@ class MigrationBottomSheetDialogState(
checkBox.setOnCheckedChangeListener { _, _ -> setFlags(binding) } checkBox.setOnCheckedChangeListener { _, _ -> setFlags(binding) }
} }
useSmartSearch.bindToPreference(preferences.smartMigration()) useSmartSearch.bindToPreference(preferences.migrationDeepSearchMode())
extraSearchParamInputLayout.isVisible = false extraSearchParamInputLayout.isVisible = false
extraSearchParam.setOnCheckedChangeListener { _, isChecked -> extraSearchParam.setOnCheckedChangeListener { _, isChecked ->
extraSearchParamInputLayout.isVisible = isChecked extraSearchParamInputLayout.isVisible = isChecked
} }
sourceGroup.bindToPreference(preferences.useSourceWithMost()) sourceGroup.bindToPreference(preferences.migrationPrioritizeByChapters())
skipStep.isChecked = preferences.skipMigrationConfig().get() hideNotFoundManga.isChecked = preferences.migrationHideUnmatched().get()
hideNotFoundManga.isChecked = preferences.hideNotFoundMigration().get() onlyShowUpdates.isChecked = preferences.migrationHideWithoutUpdates().get()
onlyShowUpdates.isChecked = preferences.showOnlyUpdatesMigration().get()
skipStep.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) {
root.context.toast(
SYMR.strings.pre_migration_skip_toast,
Toast.LENGTH_LONG,
)
}
}
migrateBtn.setOnClickListener { migrateBtn.setOnClickListener {
preferences.skipMigrationConfig().set(skipStep.isChecked) preferences.migrationHideUnmatched().set(hideNotFoundManga.isChecked)
preferences.hideNotFoundMigration().set(hideNotFoundManga.isChecked) preferences.migrationHideWithoutUpdates().set(onlyShowUpdates.isChecked)
preferences.showOnlyUpdatesMigration().set(onlyShowUpdates.isChecked)
onStartMigration.value( onStartMigration.value(
if (useSmartSearch.isChecked && !extraSearchParamText.text.isNullOrBlank()) { if (useSmartSearch.isChecked && !extraSearchParamText.text.isNullOrBlank()) {
extraSearchParamText.text.toString() extraSearchParamText.text.toString()
@ -175,7 +161,6 @@ class MigrationBottomSheetDialogState(
extraSearchParam.isVisible = false extraSearchParam.isVisible = false
extraSearchParamInputLayout.isVisible = false extraSearchParamInputLayout.isVisible = false
sourceGroup.isVisible = false sourceGroup.isVisible = false
skipStep.isVisible = false
migrateBtn.text = root.context.stringResource(MR.strings.action_save) migrateBtn.text = root.context.stringResource(MR.strings.action_save)
} }
// KMK <-- // KMK <--

View file

@ -69,10 +69,10 @@ class MigrationListScreenModel(
val manualMigrations = MutableStateFlow(0) val manualMigrations = MutableStateFlow(0)
var hideNotFound = preferences.hideNotFoundMigration().get() var hideNotFound = preferences.migrationHideUnmatched().get()
private var showOnlyUpdates = preferences.showOnlyUpdatesMigration().get() private var showOnlyUpdates = preferences.migrationHideWithoutUpdates().get()
private var useSourceWithMost = preferences.useSourceWithMost().get() private var useSourceWithMost = preferences.migrationPrioritizeByChapters().get()
private var useSmartSearch = preferences.smartMigration().get() private var useSmartSearch = preferences.migrationDeepSearchMode().get()
val navigateOut = MutableSharedFlow<Unit>() val navigateOut = MutableSharedFlow<Unit>()
@ -498,10 +498,10 @@ class MigrationListScreenModel(
} }
fun updateOptions() { fun updateOptions() {
hideNotFound = preferences.hideNotFoundMigration().get() hideNotFound = preferences.migrationHideUnmatched().get()
showOnlyUpdates = preferences.showOnlyUpdatesMigration().get() showOnlyUpdates = preferences.migrationHideWithoutUpdates().get()
useSourceWithMost = preferences.useSourceWithMost().get() useSourceWithMost = preferences.migrationPrioritizeByChapters().get()
useSmartSearch = preferences.smartMigration().get() useSmartSearch = preferences.migrationDeepSearchMode().get()
} }
// KMK <-- // KMK <--

View file

@ -30,7 +30,6 @@ 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
@ -59,7 +58,6 @@ import eu.kanade.presentation.components.AppBarActions
import eu.kanade.presentation.components.SOURCE_SEARCH_BOX_HEIGHT import eu.kanade.presentation.components.SOURCE_SEARCH_BOX_HEIGHT
import eu.kanade.presentation.util.Screen import eu.kanade.presentation.util.Screen
import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.ui.browse.migration.advanced.design.MigrationBottomSheetDialog
import eu.kanade.tachiyomi.ui.browse.migration.advanced.process.MigrationListScreen import eu.kanade.tachiyomi.ui.browse.migration.advanced.process.MigrationListScreen
import eu.kanade.tachiyomi.ui.browse.migration.advanced.process.MigrationProcedureConfig import eu.kanade.tachiyomi.ui.browse.migration.advanced.process.MigrationProcedureConfig
import eu.kanade.tachiyomi.ui.browse.migration.advanced.process.MigrationType import eu.kanade.tachiyomi.ui.browse.migration.advanced.process.MigrationType
@ -111,38 +109,24 @@ class MigrationConfigScreen(private val mangaIds: List<Long>) : Screen() {
val state by screenModel.state.collectAsState() val state by screenModel.state.collectAsState()
var migrationSheetOpen by rememberSaveable { mutableStateOf(false) } var migrationSheetOpen by rememberSaveable { mutableStateOf(false) }
// KMK -->
var migrationBottomSheetDialog by rememberSaveable { mutableStateOf(false) }
fun continueMigrationBottom(openSheet: Boolean, extraParam: String? = null) { fun continueMigration(openSheet: Boolean, extraSearchQuery: String?) {
if (openSheet) {
migrationBottomSheetDialog = true
return
}
navigator.replace(
// KMK -->
MigrationListScreen(
MigrationProcedureConfig(MigrationType.MangaList(mangaIds), extraParam),
),
// KMK <--
)
}
// KMK <--
fun continueMigration(openSheet: Boolean) {
if (openSheet) { if (openSheet) {
migrationSheetOpen = true migrationSheetOpen = true
return return
} }
// KMK -->
continueMigrationBottom(true) navigator.replace(
// KMK <-- // KMK -->
// MigrateSearchScreen(mangaId)
MigrationListScreen(
MigrationProcedureConfig(MigrationType.MangaList(mangaIds), extraSearchQuery),
),
// KMK <--
)
} }
if (state.isLoading) { if (state.isLoading) {
LaunchedEffect(state.skipMigrationConfig) {
if (state.skipMigrationConfig) continueMigration(openSheet = false)
}
LoadingScreen() LoadingScreen()
return return
} }
@ -213,7 +197,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()
continueMigration(openSheet = true) continueMigration(openSheet = true, extraSearchQuery = null)
}, },
expanded = lazyListState.shouldExpandFAB(), expanded = lazyListState.shouldExpandFAB(),
) )
@ -305,24 +289,12 @@ class MigrationConfigScreen(private val mangaIds: List<Long>) : Screen() {
MigrationConfigScreenSheet( MigrationConfigScreenSheet(
preferences = screenModel.sourcePreferences, preferences = screenModel.sourcePreferences,
onDismissRequest = { migrationSheetOpen = false }, onDismissRequest = { migrationSheetOpen = false },
onStartMigration = { onStartMigration = { extraSearchQuery ->
migrationSheetOpen = false migrationSheetOpen = false
continueMigration(openSheet = false) continueMigration(openSheet = false, extraSearchQuery = extraSearchQuery)
}, },
) )
} }
// KMK -->
if (migrationBottomSheetDialog) {
MigrationBottomSheetDialog(
onDismissRequest = { migrationBottomSheetDialog = false },
onStartMigration = { extraParam ->
migrationBottomSheetDialog = false
continueMigrationBottom(openSheet = false, extraParam)
},
)
}
// KMK <--
} }
@Composable @Composable
@ -432,9 +404,6 @@ 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) } mutableState.update { it.copy(isLoading = false) }
} }
@ -543,7 +512,6 @@ class MigrationConfigScreen(private val mangaIds: List<Long>) : Screen() {
data class State( data class State(
val isLoading: Boolean = true, val isLoading: Boolean = true,
val skipMigrationConfig: Boolean = false,
val sources: List<MigrationSource> = emptyList(), val sources: List<MigrationSource> = emptyList(),
) )

View file

@ -3,60 +3,171 @@ package mihon.feature.migration.config
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.Spacer
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.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Check
import androidx.compose.material.icons.outlined.Warning
import androidx.compose.material3.FilterChip
import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.ListItem import androidx.compose.material3.ListItem
import androidx.compose.material3.ListItemDefaults import androidx.compose.material3.ListItemDefaults
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Switch import androidx.compose.material3.Switch
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp import androidx.compose.ui.util.fastForEach
import eu.kanade.core.util.fastFilterNot
import eu.kanade.domain.source.service.SourcePreferences import eu.kanade.domain.source.service.SourcePreferences
import eu.kanade.presentation.components.AdaptiveSheet import eu.kanade.presentation.components.AdaptiveSheet
import mihon.domain.migration.models.MigrationFlag
import mihon.feature.common.utils.getLabel
import tachiyomi.core.common.preference.Preference
import tachiyomi.core.common.preference.getAndSet
import tachiyomi.core.common.preference.toggle import tachiyomi.core.common.preference.toggle
import tachiyomi.i18n.MR import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.Button import tachiyomi.presentation.core.components.material.Button
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.theme.active
import tachiyomi.presentation.core.theme.header
import tachiyomi.presentation.core.util.collectAsState import tachiyomi.presentation.core.util.collectAsState
@Composable @Composable
fun MigrationConfigScreenSheet( fun MigrationConfigScreenSheet(
preferences: SourcePreferences, preferences: SourcePreferences,
onDismissRequest: () -> Unit, onDismissRequest: () -> Unit,
onStartMigration: () -> Unit, onStartMigration: (extraSearchQuery: String?) -> Unit,
) { ) {
val skipMigrationConfig by preferences.skipMigrationConfig().collectAsState() var extraSearchQuery by rememberSaveable { mutableStateOf("") }
val migrationFlags by preferences.migrationFlags().collectAsState()
AdaptiveSheet(onDismissRequest = onDismissRequest) { AdaptiveSheet(onDismissRequest = onDismissRequest) {
Column(modifier = Modifier.fillMaxWidth()) { Column(modifier = Modifier.fillMaxWidth()) {
Column( Column(
modifier = Modifier modifier = Modifier
.weight(1f, fill = false)
.fillMaxWidth() .fillMaxWidth()
.verticalScroll(rememberScrollState()), .verticalScroll(rememberScrollState())
verticalArrangement = Arrangement.spacedBy(8.dp), .padding(top = MaterialTheme.padding.medium),
) { ) {
MigrationSheetItem( Text(
title = stringResource(MR.strings.migrationConfigScreen_skipMigrationConfigTitle), text = stringResource(MR.strings.migrationConfigScreen_dataToMigrateHeader),
subtitle = stringResource(MR.strings.migrationConfigScreen_skipMigrationConfigSubtitle), style = MaterialTheme.typography.header,
action = { modifier = Modifier
Switch( .fillMaxWidth()
checked = skipMigrationConfig, .padding(top = MaterialTheme.padding.extraSmall)
onCheckedChange = null, .padding(horizontal = MaterialTheme.padding.medium),
) )
Spacer(modifier = Modifier.height(MaterialTheme.padding.extraSmall))
FlowRow(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = MaterialTheme.padding.medium)
.padding(bottom = MaterialTheme.padding.extraSmall),
horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small),
) {
MigrationFlag.entries
.fastFilterNot { it == MigrationFlag.REMOVE_DOWNLOAD }
.fastForEach { flag ->
val selected = flag in migrationFlags
FilterChip(
selected = selected,
onClick = {
preferences.migrationFlags().getAndSet { currentFlags ->
if (flag in currentFlags) {
currentFlags - flag
} else {
currentFlags + flag
}
}
},
label = { Text(stringResource(flag.getLabel())) },
leadingIcon = {
if (selected) {
Icon(
imageVector = Icons.Outlined.Check,
contentDescription = null,
)
}
},
)
}
}
val removeDownloads = MigrationFlag.REMOVE_DOWNLOAD in migrationFlags
MigrationSheetSwitchItem(
title = stringResource(MR.strings.migrationConfigScreen_removeDownloadsTitle),
subtitle = null,
checked = removeDownloads,
onClick = {
preferences.migrationFlags().getAndSet {
// KMK -->
if (MigrationFlag.REMOVE_DOWNLOAD in it) {
// KMK <--
it - MigrationFlag.REMOVE_DOWNLOAD
} else {
it + MigrationFlag.REMOVE_DOWNLOAD
}
}
}, },
onClick = { preferences.skipMigrationConfig().toggle() }, )
MigrationSheetDividerItem()
OutlinedTextField(
value = extraSearchQuery,
onValueChange = { extraSearchQuery = it },
label = { Text(stringResource(MR.strings.migrationConfigScreen_additionalSearchQueryLabel)) },
supportingText = {
Text(stringResource(MR.strings.migrationConfigScreen_additionalSearchQuerySupportingText))
},
singleLine = true,
modifier = Modifier
.fillMaxWidth()
.padding(
horizontal = MaterialTheme.padding.medium,
vertical = MaterialTheme.padding.extraSmall,
),
)
MigrationSheetSwitchItem(
title = stringResource(MR.strings.migrationConfigScreen_hideUnmatchedTitle),
subtitle = null,
preference = preferences.migrationHideUnmatched(),
)
MigrationSheetSwitchItem(
title = stringResource(MR.strings.migrationConfigScreen_hideWithoutUpdatesTitle),
subtitle = stringResource(MR.strings.migrationConfigScreen_hideWithoutUpdatesSubtitle),
preference = preferences.migrationHideWithoutUpdates(),
)
MigrationSheetDividerItem()
MigrationSheetWarningItem(stringResource(MR.strings.migrationConfigScreen_enhancedOptionsWarning))
MigrationSheetSwitchItem(
title = stringResource(MR.strings.migrationConfigScreen_deepSearchModeTitle),
subtitle = stringResource(MR.strings.migrationConfigScreen_deepSearchModeSubtitle),
preference = preferences.migrationDeepSearchMode(),
)
MigrationSheetSwitchItem(
title = stringResource(MR.strings.migrationConfigScreen_prioritizeByChaptersTitle),
subtitle = stringResource(MR.strings.migrationConfigScreen_prioritizeByChaptersSubtitle),
preference = preferences.migrationPrioritizeByChapters(),
) )
} }
HorizontalDivider() HorizontalDivider()
Button( Button(
onClick = onStartMigration, onClick = {
val cleanedExtraSearchQuery = extraSearchQuery.trim().ifBlank { null }
onStartMigration(cleanedExtraSearchQuery)
},
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding( .padding(
@ -71,17 +182,63 @@ fun MigrationConfigScreenSheet(
} }
@Composable @Composable
private fun MigrationSheetItem( private fun MigrationSheetSwitchItem(
title: String, title: String,
subtitle: String?, subtitle: String?,
action: @Composable () -> Unit, preference: Preference<Boolean>,
) {
MigrationSheetSwitchItem(
title = title,
subtitle = subtitle,
checked = preference.collectAsState().value,
onClick = { preference.toggle() },
)
}
@Composable
private fun MigrationSheetSwitchItem(
title: String,
subtitle: String?,
checked: Boolean,
onClick: () -> Unit, onClick: () -> Unit,
) { ) {
ListItem( ListItem(
headlineContent = { Text(text = title) }, headlineContent = { Text(text = title) },
supportingContent = subtitle?.let { { Text(text = subtitle) } }, supportingContent = subtitle?.let { { Text(text = subtitle) } },
trailingContent = action, trailingContent = {
Switch(
checked = checked,
onCheckedChange = null,
)
},
colors = ListItemDefaults.colors(containerColor = Color.Transparent), colors = ListItemDefaults.colors(containerColor = Color.Transparent),
modifier = Modifier.clickable(onClick = onClick), modifier = Modifier.clickable(onClick = onClick),
) )
} }
@Composable
private fun MigrationSheetDividerItem() {
HorizontalDivider(modifier = Modifier.padding(vertical = MaterialTheme.padding.extraSmall))
}
@Composable
private fun MigrationSheetWarningItem(
text: String,
) {
ListItem(
leadingContent = {
Icon(
imageVector = Icons.Outlined.Warning,
contentDescription = null,
tint = MaterialTheme.colorScheme.active,
)
},
headlineContent = {
Text(
text = text,
color = MaterialTheme.colorScheme.error,
)
},
colors = ListItemDefaults.colors(containerColor = Color.Transparent),
)
}

View file

@ -189,15 +189,6 @@
android:textSize="14sp"/> android:textSize="14sp"/>
</com.google.android.material.textfield.TextInputLayout> </com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.materialswitch.MaterialSwitch
android:id="@+id/skip_step"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:paddingHorizontal="16dp"
android:paddingVertical="16dp"
android:text="@string/skip_this_step_next_time" />
<com.google.android.material.materialswitch.MaterialSwitch <com.google.android.material.materialswitch.MaterialSwitch
android:id="@+id/hide_not_found_manga" android:id="@+id/hide_not_found_manga"
android:layout_width="match_parent" android:layout_width="match_parent"

View file

@ -1015,10 +1015,16 @@
<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.dataToMigrateHeader">Data to migrate</string>
<string name="migrationConfigScreen.skipMigrationConfigSubtitle">To show this screen again in the future, disable skipping in Settings → Browse</string> <string name="migrationConfigScreen.removeDownloadsTitle">Delete downloads of current entry after migration</string>
<string name="migrationConfigScreen.additionalSearchQueryLabel">Additional keywords (optional)</string>
<string name="browseSettingsScreen.migrationCategoryHeader">Migration</string> <string name="migrationConfigScreen.additionalSearchQuerySupportingText">Helps narrow down search results by adding additional keywords</string>
<string name="browseSettingsScreen.skipMigrationConfigTitle">Skip migration config</string> <string name="migrationConfigScreen.hideUnmatchedTitle">Hide entries without a match</string>
<string name="browseSettingsScreen.skipMigrationConfigSubtitle">Use last used sources and preferences for migration</string> <string name="migrationConfigScreen.hideWithoutUpdatesTitle">Hide entries without newer chapters</string>
<string name="migrationConfigScreen.hideWithoutUpdatesSubtitle">Only show entry if the match has additional chapters</string>
<string name="migrationConfigScreen.enhancedOptionsWarning">These options are slow and dangerous and may lead to restrictions from sources</string>
<string name="migrationConfigScreen.deepSearchModeTitle">Advanced search mode</string>
<string name="migrationConfigScreen.deepSearchModeSubtitle">Breaks down the title into keywords for a wider search</string>
<string name="migrationConfigScreen.prioritizeByChaptersTitle">Match based on chapter number</string>
<string name="migrationConfigScreen.prioritizeByChaptersSubtitle">If enabled, chooses the match furthest ahead. Otherwise, picks the first match by source priority.</string>
</resources> </resources>