feat(migration): Allow skipping smart search for single entry migration (#1496)
* feat(migration): Allow skipping smart search for single entry migration Introduces a "Smart search" setting when migrating a single manga, allowing users to choose between an automated best-match search or manual selection directly. * ensure manual migration is only triggered once * Add UI toggle * refactor pref
This commit is contained in:
parent
36c1c642ca
commit
fe7b10f941
6 changed files with 70 additions and 15 deletions
|
|
@ -87,6 +87,8 @@ class SourcePreferences(
|
||||||
fun migrationHideWithoutUpdates() = preferenceStore.getBoolean("migration_hide_without_updates", false)
|
fun migrationHideWithoutUpdates() = preferenceStore.getBoolean("migration_hide_without_updates", false)
|
||||||
|
|
||||||
// KMK -->
|
// KMK -->
|
||||||
|
fun migrationSmartSearchSingleEntry() = preferenceStore.getBoolean("migration_smart_search_single_entry", false)
|
||||||
|
|
||||||
fun globalSearchPinnedState() = preferenceStore.getEnum(
|
fun globalSearchPinnedState() = preferenceStore.getEnum(
|
||||||
Preference.appStateKey("global_search_pinned_toggle_state"),
|
Preference.appStateKey("global_search_pinned_toggle_state"),
|
||||||
SourceFilter.PinnedOnly,
|
SourceFilter.PinnedOnly,
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,7 @@ class MigrationConfigScreen(private val mangaIds: Collection<Long>) : Screen() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val screen = // KMK --> if (mangaId == null) {
|
val screen = // KMK --> if (mangaId == null) {
|
||||||
MigrationListScreen(mangaIds, extraSearchQuery)
|
MigrationListScreen(mangaIds, extraSearchQuery, screenModel.sourcePreferences.migrationSmartSearchSingleEntry().get())
|
||||||
// KMK -->
|
// KMK -->
|
||||||
// } else {
|
// } else {
|
||||||
// MigrateSearchScreen(mangaId)
|
// MigrateSearchScreen(mangaId)
|
||||||
|
|
@ -297,6 +297,9 @@ class MigrationConfigScreen(private val mangaIds: Collection<Long>) : Screen() {
|
||||||
migrationSheetOpen = false
|
migrationSheetOpen = false
|
||||||
continueMigration(openSheet = false, extraSearchQuery = extraSearchQuery)
|
continueMigration(openSheet = false, extraSearchQuery = extraSearchQuery)
|
||||||
},
|
},
|
||||||
|
// KMK -->
|
||||||
|
isSingleEntry = mangaIds.size == 1,
|
||||||
|
// KMK <--
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ import tachiyomi.core.common.preference.Preference
|
||||||
import tachiyomi.core.common.preference.getAndSet
|
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.i18n.kmk.KMR
|
||||||
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
|
||||||
|
|
@ -53,6 +54,7 @@ fun MigrationConfigScreenSheet(
|
||||||
onStartMigration: (extraSearchQuery: String?) -> Unit,
|
onStartMigration: (extraSearchQuery: String?) -> Unit,
|
||||||
// KMK -->
|
// KMK -->
|
||||||
fullSettings: Boolean = true,
|
fullSettings: Boolean = true,
|
||||||
|
isSingleEntry: Boolean = false,
|
||||||
// KMK <--
|
// KMK <--
|
||||||
) {
|
) {
|
||||||
var extraSearchQuery by rememberSaveable { mutableStateOf("") }
|
var extraSearchQuery by rememberSaveable { mutableStateOf("") }
|
||||||
|
|
@ -160,17 +162,30 @@ fun MigrationConfigScreenSheet(
|
||||||
if (fullSettings) {
|
if (fullSettings) {
|
||||||
// KMK <--
|
// KMK <--
|
||||||
MigrationSheetDividerItem()
|
MigrationSheetDividerItem()
|
||||||
MigrationSheetWarningItem(stringResource(MR.strings.migrationConfigScreen_enhancedOptionsWarning))
|
// KMK -->
|
||||||
MigrationSheetSwitchItem(
|
val migrationSmartSearchSingleEntryPref = preferences.migrationSmartSearchSingleEntry()
|
||||||
title = stringResource(MR.strings.migrationConfigScreen_deepSearchModeTitle),
|
val isSmartSearchSingleEntry by migrationSmartSearchSingleEntryPref.collectAsState()
|
||||||
subtitle = stringResource(MR.strings.migrationConfigScreen_deepSearchModeSubtitle),
|
if (isSingleEntry) {
|
||||||
preference = preferences.migrationDeepSearchMode(),
|
MigrationSheetSwitchItem(
|
||||||
)
|
title = stringResource(KMR.strings.migrationConfigScreen_smartSearchSingleEntryTitle),
|
||||||
MigrationSheetSwitchItem(
|
subtitle = stringResource(KMR.strings.migrationConfigScreen_smartSearchSingleEntrySubtitle),
|
||||||
title = stringResource(MR.strings.migrationConfigScreen_prioritizeByChaptersTitle),
|
preference = migrationSmartSearchSingleEntryPref,
|
||||||
subtitle = stringResource(MR.strings.migrationConfigScreen_prioritizeByChaptersSubtitle),
|
)
|
||||||
preference = preferences.migrationPrioritizeByChapters(),
|
}
|
||||||
)
|
if (!isSingleEntry || isSmartSearchSingleEntry) {
|
||||||
|
// KMK <--
|
||||||
|
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()
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,9 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
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.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import cafe.adriel.voyager.core.model.rememberScreenModel
|
import cafe.adriel.voyager.core.model.rememberScreenModel
|
||||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||||
|
|
@ -25,7 +28,13 @@ import tachiyomi.i18n.MR
|
||||||
/**
|
/**
|
||||||
* Screen showing a list of pair of current-target manga entries being migrated.
|
* Screen showing a list of pair of current-target manga entries being migrated.
|
||||||
*/
|
*/
|
||||||
class MigrationListScreen(private val mangaIds: Collection<Long>, private val extraSearchQuery: String?) : Screen() {
|
class MigrationListScreen(
|
||||||
|
private val mangaIds: Collection<Long>,
|
||||||
|
private val extraSearchQuery: String?,
|
||||||
|
// KMK -->
|
||||||
|
private val isSmartSearchSingleEntry: Boolean = false,
|
||||||
|
// KMK <--
|
||||||
|
) : Screen() {
|
||||||
|
|
||||||
private var matchOverride: Pair<Long, Long>? = null
|
private var matchOverride: Pair<Long, Long>? = null
|
||||||
|
|
||||||
|
|
@ -36,10 +45,24 @@ class MigrationListScreen(private val mangaIds: Collection<Long>, private val ex
|
||||||
@Composable
|
@Composable
|
||||||
override fun Content() {
|
override fun Content() {
|
||||||
val navigator = LocalNavigator.currentOrThrow
|
val navigator = LocalNavigator.currentOrThrow
|
||||||
val screenModel = rememberScreenModel { MigrationListScreenModel(mangaIds, extraSearchQuery) }
|
// KMK -->
|
||||||
|
val singleEntryNoSmartSearch = mangaIds.size == 1 && !isSmartSearchSingleEntry
|
||||||
|
// KMK <--
|
||||||
|
val screenModel = rememberScreenModel { MigrationListScreenModel(mangaIds, extraSearchQuery, /* KMK --> */ singleEntryNoSmartSearch /* KMK <-- */) }
|
||||||
val state by screenModel.state.collectAsState()
|
val state by screenModel.state.collectAsState()
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
|
// KMK -->
|
||||||
|
var hasPushedManual by rememberSaveable(mangaIds) { mutableStateOf(false) }
|
||||||
|
LaunchedEffect(mangaIds) {
|
||||||
|
if (singleEntryNoSmartSearch && !hasPushedManual) {
|
||||||
|
@Suppress("AssignedValueIsNeverRead")
|
||||||
|
hasPushedManual = true
|
||||||
|
navigator.push(MigrateSearchScreen(mangaIds.single()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// KMK <--
|
||||||
|
|
||||||
LaunchedEffect(matchOverride) {
|
LaunchedEffect(matchOverride) {
|
||||||
val (current, target) = matchOverride ?: return@LaunchedEffect
|
val (current, target) = matchOverride ?: return@LaunchedEffect
|
||||||
screenModel.useMangaForMigration(
|
screenModel.useMangaForMigration(
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,9 @@ import uy.kohesive.injekt.api.get
|
||||||
class MigrationListScreenModel(
|
class MigrationListScreenModel(
|
||||||
mangaIds: Collection<Long>,
|
mangaIds: Collection<Long>,
|
||||||
extraSearchQuery: String?,
|
extraSearchQuery: String?,
|
||||||
|
// KMK -->
|
||||||
|
runManually: Boolean = false,
|
||||||
|
// KMK <--
|
||||||
val preferences: SourcePreferences = Injekt.get(),
|
val preferences: SourcePreferences = Injekt.get(),
|
||||||
private val sourceManager: SourceManager = Injekt.get(),
|
private val sourceManager: SourceManager = Injekt.get(),
|
||||||
private val getManga: GetManga = Injekt.get(),
|
private val getManga: GetManga = Injekt.get(),
|
||||||
|
|
@ -100,12 +103,19 @@ class MigrationListScreenModel(
|
||||||
// KMK <--
|
// KMK <--
|
||||||
),
|
),
|
||||||
parentContext = screenModelScope.coroutineContext,
|
parentContext = screenModelScope.coroutineContext,
|
||||||
)
|
// KMK -->
|
||||||
|
).apply {
|
||||||
|
if (runManually) searchResult.value = SearchResult.NotFound
|
||||||
|
// KMK <--
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.awaitAll()
|
.awaitAll()
|
||||||
.filterNotNull()
|
.filterNotNull()
|
||||||
mutableState.update { it.copy(items = manga.toImmutableList()) }
|
mutableState.update { it.copy(items = manga.toImmutableList()) }
|
||||||
|
// KMK -->
|
||||||
|
if (runManually) return@launchIO
|
||||||
|
// KMK <--
|
||||||
runMigrations(manga)
|
runMigrations(manga)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -183,6 +183,8 @@
|
||||||
<string name="sort_feed_confirmation">Would you like to sort the feeds alphabetically?</string>
|
<string name="sort_feed_confirmation">Would you like to sort the feeds alphabetically?</string>
|
||||||
<!-- Migration -->
|
<!-- Migration -->
|
||||||
<string name="current_">Current: %1$s</string>
|
<string name="current_">Current: %1$s</string>
|
||||||
|
<string name="migrationConfigScreen_smartSearchSingleEntryTitle">Use smart search</string>
|
||||||
|
<string name="migrationConfigScreen_smartSearchSingleEntrySubtitle">If enabled, automatically picks the best match result. Otherwise, shows all search results for manual selection.</string>
|
||||||
<!-- Misc -->
|
<!-- Misc -->
|
||||||
<string name="job_failed_schedule_update_check">Failed to schedule automatic library update: %s</string>
|
<string name="job_failed_schedule_update_check">Failed to schedule automatic library update: %s</string>
|
||||||
<string name="job_failed_schedule_backup_check">Failed to schedule automatic backup: %s</string>
|
<string name="job_failed_schedule_backup_check">Failed to schedule automatic backup: %s</string>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue