Bring back original Mihon's migration dialog (#823)
This commit is contained in:
parent
d89180fb10
commit
271680bd03
11 changed files with 551 additions and 257 deletions
|
|
@ -24,7 +24,6 @@ import eu.kanade.presentation.history.components.HistoryItem
|
|||
import eu.kanade.presentation.theme.TachiyomiPreviewTheme
|
||||
import eu.kanade.presentation.util.animateItemFastScroll
|
||||
import eu.kanade.tachiyomi.ui.history.HistoryScreenModel
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import tachiyomi.domain.history.model.HistoryWithRelations
|
||||
import tachiyomi.i18n.MR
|
||||
|
|
@ -126,7 +125,7 @@ fun HistoryScreen(
|
|||
|
||||
@Composable
|
||||
private fun HistoryScreenContent(
|
||||
history: ImmutableList<HistoryUiModel>,
|
||||
history: List<HistoryUiModel>,
|
||||
contentPadding: PaddingValues,
|
||||
onClickCover: (HistoryWithRelations) -> Unit,
|
||||
onClickResume: (HistoryWithRelations) -> Unit,
|
||||
|
|
|
|||
|
|
@ -1,13 +1,48 @@
|
|||
package eu.kanade.tachiyomi.ui.browse.migration
|
||||
|
||||
import dev.icerock.moko.resources.StringResource
|
||||
import eu.kanade.domain.manga.model.hasCustomCover
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
import eu.kanade.tachiyomi.data.download.DownloadCache
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.i18n.sy.SYMR
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
data class MigrationFlag(
|
||||
val flag: Int,
|
||||
val isDefaultSelected: Boolean,
|
||||
val titleId: StringResource,
|
||||
) {
|
||||
companion object {
|
||||
fun create(flag: Int, defaultSelectionMap: Int, titleId: StringResource): MigrationFlag {
|
||||
return MigrationFlag(
|
||||
flag = flag,
|
||||
isDefaultSelected = defaultSelectionMap and flag != 0,
|
||||
titleId = titleId,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object MigrationFlags {
|
||||
|
||||
const val CHAPTERS = 0b00001
|
||||
const val CATEGORIES = 0b00010
|
||||
|
||||
// KMK -->
|
||||
const val TRACK = 0b00100
|
||||
// KMK <--
|
||||
|
||||
const val CUSTOM_COVER = 0b01000
|
||||
const val DELETE_DOWNLOADED = 0b10000
|
||||
|
||||
// KMK -->
|
||||
const val EXTRA = 0b1000000
|
||||
// KMK <--
|
||||
|
||||
private val coverCache: CoverCache by injectLazy()
|
||||
private val downloadCache: DownloadCache by injectLazy()
|
||||
|
||||
fun hasChapters(value: Int): Boolean {
|
||||
return value and CHAPTERS != 0
|
||||
|
|
@ -17,19 +52,61 @@ object MigrationFlags {
|
|||
return value and CATEGORIES != 0
|
||||
}
|
||||
|
||||
// KMK -->
|
||||
fun hasTracks(value: Int): Boolean {
|
||||
return value and TRACK != 0
|
||||
}
|
||||
// KMK <--
|
||||
|
||||
fun hasCustomCover(value: Int): Boolean {
|
||||
return value and CUSTOM_COVER != 0
|
||||
}
|
||||
|
||||
fun hasExtra(value: Int): Boolean {
|
||||
return value and EXTRA != 0
|
||||
}
|
||||
|
||||
fun hasDeleteDownloaded(value: Int): Boolean {
|
||||
return value and DELETE_DOWNLOADED != 0
|
||||
}
|
||||
|
||||
// KMK -->
|
||||
/** Returns true if the manga has extra info, include notes. */
|
||||
fun hasExtra(value: Int): Boolean {
|
||||
return value and EXTRA != 0
|
||||
}
|
||||
// KMK <--
|
||||
|
||||
/** Returns information about applicable flags with default selections. */
|
||||
fun getFlags(manga: Manga?, defaultSelectedBitMap: Int): List<MigrationFlag> {
|
||||
val flags = mutableListOf<MigrationFlag>()
|
||||
flags += MigrationFlag.create(CHAPTERS, defaultSelectedBitMap, MR.strings.chapters)
|
||||
flags += MigrationFlag.create(CATEGORIES, defaultSelectedBitMap, MR.strings.categories)
|
||||
// KMK -->
|
||||
flags += MigrationFlag.create(TRACK, defaultSelectedBitMap, MR.strings.track)
|
||||
// KMK <--
|
||||
|
||||
if (manga != null) {
|
||||
if (manga.hasCustomCover(coverCache)) {
|
||||
flags += MigrationFlag.create(CUSTOM_COVER, defaultSelectedBitMap, MR.strings.custom_cover)
|
||||
}
|
||||
if (downloadCache.getDownloadCount(manga) > 0) {
|
||||
flags += MigrationFlag.create(DELETE_DOWNLOADED, defaultSelectedBitMap, MR.strings.delete_downloaded)
|
||||
}
|
||||
}
|
||||
|
||||
// KMK -->
|
||||
flags += MigrationFlag.create(EXTRA, defaultSelectedBitMap, SYMR.strings.log_extra)
|
||||
// KMK <--
|
||||
|
||||
return flags
|
||||
}
|
||||
|
||||
/** Returns a bit map of selected flags. */
|
||||
fun getSelectedFlagsBitMap(
|
||||
selectedFlags: List<Boolean>,
|
||||
flags: List<MigrationFlag>,
|
||||
): Int {
|
||||
return selectedFlags
|
||||
.zip(flags)
|
||||
.filter { (isSelected, _) -> isSelected }
|
||||
.map { (_, flag) -> flag.flag }
|
||||
.reduceOrNull { acc, mask -> acc or mask } ?: 0
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -391,6 +391,7 @@ class PreMigrationScreen(val migration: MigrationType) : Screen() {
|
|||
)
|
||||
}
|
||||
|
||||
/* All usages have been replaced by original Mihon's migration dialog */
|
||||
fun navigateToMigration(skipPre: Boolean, navigator: Navigator, fromMangaId: Long, toManga: Long?) {
|
||||
navigator.push(
|
||||
if (skipPre) {
|
||||
|
|
|
|||
|
|
@ -6,20 +6,13 @@ import cafe.adriel.voyager.core.model.ScreenModel
|
|||
import cafe.adriel.voyager.core.model.screenModelScope
|
||||
import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource
|
||||
import eu.kanade.domain.manga.interactor.UpdateManga
|
||||
import eu.kanade.domain.manga.model.hasCustomCover
|
||||
import eu.kanade.domain.manga.model.toSManga
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||
import eu.kanade.tachiyomi.data.track.EnhancedTracker
|
||||
import eu.kanade.tachiyomi.data.track.TrackerManager
|
||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.getNameForMangaInfo
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.online.all.EHentai
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.MigrationFlags
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.advanced.design.MigrationType
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.advanced.process.MigratingManga.SearchResult
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.search.MigrateDialogScreenModel.Companion.migrateMangaInternal
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import exh.eh.EHentaiThrottleManager
|
||||
import exh.smartsearch.SmartSearchEngine
|
||||
|
|
@ -43,54 +36,30 @@ import tachiyomi.core.common.util.lang.launchIO
|
|||
import tachiyomi.core.common.util.lang.withUIContext
|
||||
import tachiyomi.core.common.util.system.logcat
|
||||
import tachiyomi.domain.UnsortedPreferences
|
||||
import tachiyomi.domain.category.interactor.GetCategories
|
||||
import tachiyomi.domain.category.interactor.SetMangaCategories
|
||||
import tachiyomi.domain.chapter.interactor.GetChaptersByMangaId
|
||||
import tachiyomi.domain.chapter.interactor.UpdateChapter
|
||||
import tachiyomi.domain.chapter.model.ChapterUpdate
|
||||
import tachiyomi.domain.history.interactor.GetHistoryByMangaId
|
||||
import tachiyomi.domain.history.interactor.UpsertHistory
|
||||
import tachiyomi.domain.history.model.HistoryUpdate
|
||||
import tachiyomi.domain.manga.interactor.GetManga
|
||||
import tachiyomi.domain.manga.interactor.GetMergedReferencesById
|
||||
import tachiyomi.domain.manga.interactor.NetworkToLocalManga
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.domain.manga.model.MangaUpdate
|
||||
import tachiyomi.domain.source.service.SourceManager
|
||||
import tachiyomi.domain.track.interactor.GetTracks
|
||||
import tachiyomi.domain.track.interactor.InsertTrack
|
||||
import tachiyomi.i18n.sy.SYMR
|
||||
import timber.log.Timber
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.time.Instant
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
class MigrationListScreenModel(
|
||||
private val config: MigrationProcedureConfig,
|
||||
private val preferences: UnsortedPreferences = Injekt.get(),
|
||||
private val sourceManager: SourceManager = Injekt.get(),
|
||||
private val downloadManager: DownloadManager = Injekt.get(),
|
||||
private val coverCache: CoverCache = Injekt.get(),
|
||||
private val getManga: GetManga = Injekt.get(),
|
||||
private val networkToLocalManga: NetworkToLocalManga = Injekt.get(),
|
||||
private val updateManga: UpdateManga = Injekt.get(),
|
||||
private val syncChaptersWithSource: SyncChaptersWithSource = Injekt.get(),
|
||||
private val updateChapter: UpdateChapter = Injekt.get(),
|
||||
private val getChaptersByMangaId: GetChaptersByMangaId = Injekt.get(),
|
||||
private val getMergedReferencesById: GetMergedReferencesById = Injekt.get(),
|
||||
private val getHistoryByMangaId: GetHistoryByMangaId = Injekt.get(),
|
||||
private val upsertHistory: UpsertHistory = Injekt.get(),
|
||||
private val getCategories: GetCategories = Injekt.get(),
|
||||
private val setMangaCategories: SetMangaCategories = Injekt.get(),
|
||||
private val getTracks: GetTracks = Injekt.get(),
|
||||
private val insertTrack: InsertTrack = Injekt.get(),
|
||||
) : ScreenModel {
|
||||
|
||||
private val enhancedServices by lazy {
|
||||
Injekt.get<TrackerManager>().trackers.filterIsInstance<EnhancedTracker>()
|
||||
}
|
||||
|
||||
private val smartSearchEngine = SmartSearchEngine(config.extraSearchParams)
|
||||
private val throttleManager = EHentaiThrottleManager()
|
||||
|
||||
|
|
@ -359,153 +328,6 @@ class MigrationListScreenModel(
|
|||
|
||||
private fun mangasSkipped() = migratingItems.value.orEmpty().count { it.searchResult.value == SearchResult.NotFound }
|
||||
|
||||
private suspend fun migrateMangaInternal(
|
||||
oldSource: Source?,
|
||||
newSource: Source,
|
||||
oldManga: Manga,
|
||||
newManga: Manga,
|
||||
sourceChapters: List<SChapter>,
|
||||
replace: Boolean,
|
||||
) {
|
||||
if (oldManga.id == newManga.id) return // Nothing to migrate
|
||||
|
||||
val flags = preferences.migrateFlags().get()
|
||||
val migrateChapters = MigrationFlags.hasChapters(flags)
|
||||
val migrateCategories = MigrationFlags.hasCategories(flags)
|
||||
val migrateCustomCover = MigrationFlags.hasCustomCover(flags)
|
||||
val deleteDownloaded = MigrationFlags.hasDeleteDownloaded(flags)
|
||||
val migrateTracks = MigrationFlags.hasTracks(flags)
|
||||
val migrateExtra = MigrationFlags.hasExtra(flags)
|
||||
|
||||
// Update newManga's chapters first to ensure it has latest chapter list
|
||||
try {
|
||||
syncChaptersWithSource.await(sourceChapters, newManga, newSource)
|
||||
} catch (_: Exception) {
|
||||
// Worst case, chapters won't be synced
|
||||
}
|
||||
|
||||
// Update chapters read, bookmark and dateFetch
|
||||
if (migrateChapters) {
|
||||
val prevMangaChapters = getChaptersByMangaId.await(oldManga.id)
|
||||
val mangaChapters = getChaptersByMangaId.await(newManga.id)
|
||||
|
||||
val maxChapterRead = prevMangaChapters
|
||||
.filter { it.read }
|
||||
.maxOfOrNull { it.chapterNumber }
|
||||
|
||||
val prevHistoryList = getHistoryByMangaId.await(oldManga.id)
|
||||
// KMK -->
|
||||
.associateBy { it.chapterId }
|
||||
// KMK <--
|
||||
|
||||
val chapterUpdates = mutableListOf<ChapterUpdate>()
|
||||
val historyUpdates = mutableListOf<HistoryUpdate>()
|
||||
|
||||
mangaChapters.forEach { updateChapter ->
|
||||
if (updateChapter.isRecognizedNumber) {
|
||||
val prevChapter = prevMangaChapters
|
||||
.find { it.isRecognizedNumber && it.chapterNumber == updateChapter.chapterNumber }
|
||||
|
||||
if (prevChapter != null) {
|
||||
// SY -->
|
||||
// If chapters match then mark new manga's chapters read/unread as old one
|
||||
chapterUpdates += ChapterUpdate(
|
||||
id = updateChapter.id,
|
||||
// Also migrate read status
|
||||
read = prevChapter.read,
|
||||
// SY <--
|
||||
dateFetch = prevChapter.dateFetch,
|
||||
bookmark = prevChapter.bookmark,
|
||||
)
|
||||
// SY -->
|
||||
// KMK -->
|
||||
prevHistoryList[prevChapter.id]?.let { prevHistory ->
|
||||
// KMK <--
|
||||
historyUpdates += HistoryUpdate(
|
||||
updateChapter.id,
|
||||
prevHistory.readAt ?: return@let,
|
||||
prevHistory.readDuration,
|
||||
)
|
||||
}
|
||||
// SY <--
|
||||
} else if (maxChapterRead != null && updateChapter.chapterNumber <= maxChapterRead) {
|
||||
// SY -->
|
||||
// If chapters which only present on new manga then mark read up to latest read chapter number
|
||||
chapterUpdates += ChapterUpdate(
|
||||
id = updateChapter.id,
|
||||
// SY <--
|
||||
read = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateChapter.awaitAll(chapterUpdates)
|
||||
upsertHistory.awaitAll(historyUpdates)
|
||||
}
|
||||
|
||||
// Update categories
|
||||
if (migrateCategories) {
|
||||
val categoryIds = getCategories.await(oldManga.id).map { it.id }
|
||||
setMangaCategories.await(newManga.id, categoryIds)
|
||||
}
|
||||
|
||||
// Update track
|
||||
if (migrateTracks) {
|
||||
getTracks.await(oldManga.id).mapNotNull { track ->
|
||||
val updatedTrack = track.copy(mangaId = newManga.id)
|
||||
|
||||
// Kavita, Komga, Suwayomi
|
||||
val service = enhancedServices
|
||||
.firstOrNull { it.isTrackFrom(updatedTrack, oldManga, oldSource) }
|
||||
|
||||
if (service != null) {
|
||||
service.migrateTrack(updatedTrack, newManga, newSource)
|
||||
} else {
|
||||
updatedTrack
|
||||
}
|
||||
}
|
||||
.takeIf { it.isNotEmpty() }
|
||||
?.let { insertTrack.awaitAll(it) }
|
||||
}
|
||||
|
||||
// Delete downloaded
|
||||
if (deleteDownloaded) {
|
||||
if (oldSource != null) {
|
||||
downloadManager.deleteManga(oldManga, oldSource)
|
||||
}
|
||||
}
|
||||
|
||||
if (replace) {
|
||||
updateManga.awaitUpdateFavorite(oldManga.id, favorite = false)
|
||||
}
|
||||
|
||||
// Update custom cover (recheck if custom cover exists)
|
||||
if (migrateCustomCover && oldManga.hasCustomCover()) {
|
||||
coverCache.setCustomCoverToCache(newManga, coverCache.getCustomCoverFile(oldManga.id).inputStream())
|
||||
}
|
||||
|
||||
updateManga.await(
|
||||
MangaUpdate(
|
||||
id = newManga.id,
|
||||
favorite = true,
|
||||
chapterFlags = oldManga.chapterFlags
|
||||
// KMK -->
|
||||
.takeIf { migrateExtra },
|
||||
// KMK <--
|
||||
viewerFlags = oldManga.viewerFlags
|
||||
// KMK -->
|
||||
.takeIf { migrateExtra },
|
||||
// KMK <--
|
||||
dateAdded = if (replace) oldManga.dateAdded else Instant.now().toEpochMilli(),
|
||||
notes = oldManga.notes
|
||||
// KMK -->
|
||||
.takeIf { migrateExtra },
|
||||
// KMK <--
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
/** Set a manga picked from manual search to be used as migration target */
|
||||
fun useMangaForMigration(context: Context, newMangaId: Long, selectedMangaId: Long) {
|
||||
val migratingManga = migratingItems.value.orEmpty().find { it.manga.id == selectedMangaId }
|
||||
|
|
@ -578,14 +400,14 @@ class MigrationListScreenModel(
|
|||
val prevSource = sourceManager.get(oldManga.manga.source)
|
||||
|
||||
try {
|
||||
val newSourceChapters = source.getChapterList(newManga.toSManga())
|
||||
val chapters = source.getChapterList(newManga.toSManga())
|
||||
|
||||
migrateMangaInternal(
|
||||
oldSource = prevSource,
|
||||
newSource = source,
|
||||
oldManga = oldManga.manga,
|
||||
newManga = newManga,
|
||||
sourceChapters = newSourceChapters,
|
||||
sourceChapters = chapters,
|
||||
replace = replace,
|
||||
)
|
||||
} catch (_: Throwable) {
|
||||
|
|
@ -628,14 +450,14 @@ class MigrationListScreenModel(
|
|||
val prevSource = sourceManager.get(oldManga.manga.source)
|
||||
|
||||
try {
|
||||
val newSourceChapters = source.getChapterList(newManga.toSManga())
|
||||
val chapters = source.getChapterList(newManga.toSManga())
|
||||
|
||||
migrateMangaInternal(
|
||||
oldSource = prevSource,
|
||||
newSource = source,
|
||||
oldManga = oldManga.manga,
|
||||
newManga = newManga,
|
||||
sourceChapters = newSourceChapters,
|
||||
sourceChapters = chapters,
|
||||
replace = replace,
|
||||
)
|
||||
} catch (_: Throwable) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,380 @@
|
|||
package eu.kanade.tachiyomi.ui.browse.migration.search
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.FlowRow
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.toMutableStateList
|
||||
import androidx.compose.ui.Modifier
|
||||
import cafe.adriel.voyager.core.model.StateScreenModel
|
||||
import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource
|
||||
import eu.kanade.domain.manga.interactor.UpdateManga
|
||||
import eu.kanade.domain.manga.model.hasCustomCover
|
||||
import eu.kanade.domain.manga.model.toSManga
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||
import eu.kanade.tachiyomi.data.track.EnhancedTracker
|
||||
import eu.kanade.tachiyomi.data.track.TrackerManager
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.MigrationFlags
|
||||
import kotlinx.coroutines.flow.update
|
||||
import tachiyomi.core.common.preference.Preference
|
||||
import tachiyomi.core.common.util.lang.launchIO
|
||||
import tachiyomi.core.common.util.lang.withUIContext
|
||||
import tachiyomi.domain.UnsortedPreferences
|
||||
import tachiyomi.domain.category.interactor.GetCategories
|
||||
import tachiyomi.domain.category.interactor.SetMangaCategories
|
||||
import tachiyomi.domain.chapter.interactor.GetChaptersByMangaId
|
||||
import tachiyomi.domain.chapter.interactor.UpdateChapter
|
||||
import tachiyomi.domain.chapter.model.ChapterUpdate
|
||||
import tachiyomi.domain.history.interactor.GetHistoryByMangaId
|
||||
import tachiyomi.domain.history.interactor.UpsertHistory
|
||||
import tachiyomi.domain.history.model.HistoryUpdate
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.domain.manga.model.MangaUpdate
|
||||
import tachiyomi.domain.source.service.SourceManager
|
||||
import tachiyomi.domain.track.interactor.GetTracks
|
||||
import tachiyomi.domain.track.interactor.InsertTrack
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.components.LabeledCheckbox
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.presentation.core.i18n.stringResource
|
||||
import tachiyomi.presentation.core.screens.LoadingScreen
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.time.Instant
|
||||
|
||||
@Composable
|
||||
internal fun MigrateDialog(
|
||||
oldManga: Manga,
|
||||
newManga: Manga,
|
||||
screenModel: MigrateDialogScreenModel,
|
||||
onDismissRequest: () -> Unit,
|
||||
onClickTitle: () -> Unit,
|
||||
onPopScreen: () -> Unit,
|
||||
) {
|
||||
val scope = rememberCoroutineScope()
|
||||
val state by screenModel.state.collectAsState()
|
||||
|
||||
val flags = remember { MigrationFlags.getFlags(oldManga, screenModel.migrateFlags.get()) }
|
||||
val selectedFlags = remember { flags.map { it.isDefaultSelected }.toMutableStateList() }
|
||||
|
||||
if (state.isMigrating) {
|
||||
LoadingScreen(
|
||||
modifier = Modifier
|
||||
.background(MaterialTheme.colorScheme.background.copy(alpha = 0.7f)),
|
||||
)
|
||||
} else {
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
title = {
|
||||
Text(text = stringResource(MR.strings.migration_dialog_what_to_include))
|
||||
},
|
||||
text = {
|
||||
Column(
|
||||
modifier = Modifier.verticalScroll(rememberScrollState()),
|
||||
) {
|
||||
flags.forEachIndexed { index, flag ->
|
||||
LabeledCheckbox(
|
||||
label = stringResource(flag.titleId),
|
||||
checked = selectedFlags[index],
|
||||
onCheckedChange = { selectedFlags[index] = it },
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
FlowRow(
|
||||
horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.extraSmall),
|
||||
) {
|
||||
TextButton(
|
||||
onClick = {
|
||||
onDismissRequest()
|
||||
onClickTitle()
|
||||
},
|
||||
) {
|
||||
Text(text = stringResource(MR.strings.action_show_manga))
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
TextButton(
|
||||
onClick = {
|
||||
scope.launchIO {
|
||||
screenModel.migrateManga(
|
||||
oldManga,
|
||||
newManga,
|
||||
false,
|
||||
MigrationFlags.getSelectedFlagsBitMap(selectedFlags, flags),
|
||||
)
|
||||
withUIContext { onPopScreen() }
|
||||
}
|
||||
},
|
||||
) {
|
||||
Text(text = stringResource(MR.strings.copy))
|
||||
}
|
||||
TextButton(
|
||||
onClick = {
|
||||
scope.launchIO {
|
||||
screenModel.migrateManga(
|
||||
oldManga,
|
||||
newManga,
|
||||
true,
|
||||
MigrationFlags.getSelectedFlagsBitMap(selectedFlags, flags),
|
||||
)
|
||||
|
||||
withUIContext { onPopScreen() }
|
||||
}
|
||||
},
|
||||
) {
|
||||
Text(text = stringResource(MR.strings.migrate))
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
internal class MigrateDialogScreenModel(
|
||||
private val sourceManager: SourceManager = Injekt.get(),
|
||||
// KMK -->
|
||||
preferences: UnsortedPreferences = Injekt.get(),
|
||||
// KMK <--
|
||||
) : StateScreenModel<MigrateDialogScreenModel.State>(State()) {
|
||||
|
||||
val migrateFlags: Preference<Int> by lazy {
|
||||
// KMK -->
|
||||
preferences.migrateFlags()
|
||||
// KMK <--
|
||||
}
|
||||
|
||||
suspend fun migrateManga(
|
||||
oldManga: Manga,
|
||||
newManga: Manga,
|
||||
replace: Boolean,
|
||||
flags: Int,
|
||||
) {
|
||||
migrateFlags.set(flags)
|
||||
val source = sourceManager.get(newManga.source) ?: return
|
||||
val prevSource = sourceManager.get(oldManga.source)
|
||||
|
||||
mutableState.update { it.copy(isMigrating = true) }
|
||||
|
||||
try {
|
||||
val chapters = source.getChapterList(newManga.toSManga())
|
||||
|
||||
migrateMangaInternal(
|
||||
oldSource = prevSource,
|
||||
newSource = source,
|
||||
oldManga = oldManga,
|
||||
newManga = newManga,
|
||||
sourceChapters = chapters,
|
||||
replace = replace,
|
||||
presetFlags = flags,
|
||||
)
|
||||
} catch (_: Throwable) {
|
||||
// Explicitly stop if an error occurred; the dialog normally gets popped at the end
|
||||
// anyway
|
||||
mutableState.update { it.copy(isMigrating = false) }
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
suspend fun migrateMangaInternal(
|
||||
oldSource: Source?,
|
||||
newSource: Source,
|
||||
oldManga: Manga,
|
||||
newManga: Manga,
|
||||
sourceChapters: List<SChapter>,
|
||||
replace: Boolean,
|
||||
// KMK -->
|
||||
presetFlags: Int? = null,
|
||||
// KMK <--
|
||||
) {
|
||||
// KMK -->
|
||||
if (oldManga.id == newManga.id) return // Nothing to migrate
|
||||
|
||||
val preferences: UnsortedPreferences = Injekt.get()
|
||||
val downloadManager: DownloadManager = Injekt.get()
|
||||
val coverCache: CoverCache = Injekt.get()
|
||||
val updateManga: UpdateManga = Injekt.get()
|
||||
val syncChaptersWithSource: SyncChaptersWithSource = Injekt.get()
|
||||
val updateChapter: UpdateChapter = Injekt.get()
|
||||
val getChaptersByMangaId: GetChaptersByMangaId = Injekt.get()
|
||||
val getHistoryByMangaId: GetHistoryByMangaId = Injekt.get()
|
||||
val upsertHistory: UpsertHistory = Injekt.get()
|
||||
val getCategories: GetCategories = Injekt.get()
|
||||
val setMangaCategories: SetMangaCategories = Injekt.get()
|
||||
val getTracks: GetTracks = Injekt.get()
|
||||
val insertTrack: InsertTrack = Injekt.get()
|
||||
val enhancedServices by lazy {
|
||||
Injekt.get<TrackerManager>().trackers.filterIsInstance<EnhancedTracker>()
|
||||
}
|
||||
|
||||
val flags = presetFlags ?: preferences.migrateFlags().get()
|
||||
// KMK <--
|
||||
|
||||
val migrateChapters = MigrationFlags.hasChapters(flags)
|
||||
val migrateCategories = MigrationFlags.hasCategories(flags)
|
||||
val migrateCustomCover = MigrationFlags.hasCustomCover(flags)
|
||||
val deleteDownloaded = MigrationFlags.hasDeleteDownloaded(flags)
|
||||
// KMK -->
|
||||
val migrateTracks = MigrationFlags.hasTracks(flags)
|
||||
val migrateExtra = MigrationFlags.hasExtra(flags)
|
||||
// KMK <--
|
||||
|
||||
// Update newManga's chapters first to ensure it has latest chapter list
|
||||
try {
|
||||
syncChaptersWithSource.await(sourceChapters, newManga, newSource)
|
||||
} catch (_: Exception) {
|
||||
// Worst case, chapters won't be synced
|
||||
}
|
||||
|
||||
// Update chapters read, bookmark and dateFetch
|
||||
if (migrateChapters) {
|
||||
val prevMangaChapters = getChaptersByMangaId.await(oldManga.id)
|
||||
val mangaChapters = getChaptersByMangaId.await(newManga.id)
|
||||
|
||||
val maxChapterRead = prevMangaChapters
|
||||
.filter { it.read }
|
||||
.maxOfOrNull { it.chapterNumber }
|
||||
|
||||
// SY -->
|
||||
val prevHistoryList = getHistoryByMangaId.await(oldManga.id)
|
||||
// KMK -->
|
||||
.associateBy { it.chapterId }
|
||||
// KMK <--
|
||||
|
||||
val chapterUpdates = mutableListOf<ChapterUpdate>()
|
||||
val historyUpdates = mutableListOf<HistoryUpdate>()
|
||||
|
||||
mangaChapters.forEach { updatedChapter ->
|
||||
// SY <--
|
||||
if (updatedChapter.isRecognizedNumber) {
|
||||
val prevChapter = prevMangaChapters
|
||||
.find { it.isRecognizedNumber && it.chapterNumber == updatedChapter.chapterNumber }
|
||||
|
||||
if (prevChapter != null) {
|
||||
// SY -->
|
||||
// If chapters match then mark new manga's chapters read/unread as old one
|
||||
chapterUpdates += ChapterUpdate(
|
||||
id = updatedChapter.id,
|
||||
// Also migrate read status
|
||||
read = prevChapter.read,
|
||||
// SY <--
|
||||
dateFetch = prevChapter.dateFetch,
|
||||
bookmark = prevChapter.bookmark,
|
||||
)
|
||||
// SY -->
|
||||
// KMK -->
|
||||
prevHistoryList[prevChapter.id]?.let { prevHistory ->
|
||||
// KMK <--
|
||||
historyUpdates += HistoryUpdate(
|
||||
updatedChapter.id,
|
||||
prevHistory.readAt ?: return@let,
|
||||
prevHistory.readDuration,
|
||||
)
|
||||
}
|
||||
// SY <--
|
||||
} else if (maxChapterRead != null && updatedChapter.chapterNumber <= maxChapterRead) {
|
||||
// SY -->
|
||||
// If chapters which only present on new manga then mark read up to latest read chapter number
|
||||
chapterUpdates += ChapterUpdate(
|
||||
id = updatedChapter.id,
|
||||
// SY <--
|
||||
read = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateChapter.awaitAll(chapterUpdates)
|
||||
// SY -->
|
||||
upsertHistory.awaitAll(historyUpdates)
|
||||
// SY <--
|
||||
}
|
||||
|
||||
// Update categories
|
||||
if (migrateCategories) {
|
||||
val categoryIds = getCategories.await(oldManga.id).map { it.id }
|
||||
setMangaCategories.await(newManga.id, categoryIds)
|
||||
}
|
||||
|
||||
// Update track
|
||||
// SY -->
|
||||
if (migrateTracks) {
|
||||
// SY <--
|
||||
getTracks.await(oldManga.id).mapNotNull { track ->
|
||||
val updatedTrack = track.copy(mangaId = newManga.id)
|
||||
|
||||
// Kavita, Komga, Suwayomi
|
||||
val service = enhancedServices
|
||||
.firstOrNull { it.isTrackFrom(updatedTrack, oldManga, oldSource) }
|
||||
|
||||
if (service != null) {
|
||||
service.migrateTrack(updatedTrack, newManga, newSource)
|
||||
} else {
|
||||
updatedTrack
|
||||
}
|
||||
}
|
||||
.takeIf { it.isNotEmpty() }
|
||||
?.let { insertTrack.awaitAll(it) }
|
||||
}
|
||||
|
||||
// Delete downloaded
|
||||
if (deleteDownloaded) {
|
||||
if (oldSource != null) {
|
||||
downloadManager.deleteManga(oldManga, oldSource)
|
||||
}
|
||||
}
|
||||
|
||||
if (replace) {
|
||||
updateManga.awaitUpdateFavorite(oldManga.id, favorite = false)
|
||||
}
|
||||
|
||||
// Update custom cover (recheck if custom cover exists)
|
||||
if (migrateCustomCover && oldManga.hasCustomCover()) {
|
||||
coverCache.setCustomCoverToCache(newManga, coverCache.getCustomCoverFile(oldManga.id).inputStream())
|
||||
}
|
||||
|
||||
updateManga.await(
|
||||
MangaUpdate(
|
||||
id = newManga.id,
|
||||
favorite = true,
|
||||
chapterFlags = oldManga.chapterFlags
|
||||
// KMK -->
|
||||
.takeIf { migrateExtra },
|
||||
// KMK <--
|
||||
viewerFlags = oldManga.viewerFlags
|
||||
// KMK -->
|
||||
.takeIf { migrateExtra },
|
||||
// KMK <--
|
||||
dateAdded = if (replace) oldManga.dateAdded else Instant.now().toEpochMilli(),
|
||||
notes = oldManga.notes
|
||||
// KMK -->
|
||||
.takeIf { migrateExtra },
|
||||
// KMK <--
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
data class State(
|
||||
val isMigrating: Boolean = false,
|
||||
)
|
||||
}
|
||||
|
|
@ -55,7 +55,8 @@ import eu.kanade.tachiyomi.source.online.HttpSource
|
|||
import eu.kanade.tachiyomi.ui.browse.BulkFavoriteDialogs
|
||||
import eu.kanade.tachiyomi.ui.browse.BulkFavoriteScreenModel
|
||||
import eu.kanade.tachiyomi.ui.browse.extension.details.SourcePreferencesScreen
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.advanced.design.PreMigrationScreen
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.search.MigrateDialog
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.search.MigrateDialogScreenModel
|
||||
import eu.kanade.tachiyomi.ui.browse.source.SourcesScreen
|
||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreenModel.Listing
|
||||
import eu.kanade.tachiyomi.ui.category.CategoryScreen
|
||||
|
|
@ -434,7 +435,10 @@ data class BrowseSourceScreen(
|
|||
},
|
||||
openMangaDexFollows = if (screenModel.source.isMdBasedSource()) {
|
||||
{
|
||||
navigator.replace(MangaDexFollowsScreen(sourceId))
|
||||
// KMK -->
|
||||
// navigator.replace(MangaDexFollowsScreen(sourceId))
|
||||
navigator.push(MangaDexFollowsScreen(sourceId))
|
||||
// KMK <--
|
||||
}
|
||||
} else {
|
||||
null
|
||||
|
|
@ -448,15 +452,19 @@ data class BrowseSourceScreen(
|
|||
onDismissRequest = onDismissRequest,
|
||||
onConfirm = { screenModel.addFavorite(dialog.manga) },
|
||||
onOpenManga = { navigator.push(MangaScreen(it.id)) },
|
||||
onMigrate = {
|
||||
// SY -->
|
||||
PreMigrationScreen.navigateToMigration(
|
||||
Injekt.get<UnsortedPreferences>().skipPreMigration().get(),
|
||||
navigator,
|
||||
it.id,
|
||||
dialog.manga.id,
|
||||
)
|
||||
// SY <--
|
||||
onMigrate = { screenModel.setDialog(BrowseSourceScreenModel.Dialog.Migrate(dialog.manga, it)) },
|
||||
)
|
||||
}
|
||||
|
||||
is BrowseSourceScreenModel.Dialog.Migrate -> {
|
||||
MigrateDialog(
|
||||
oldManga = dialog.oldManga,
|
||||
newManga = dialog.newManga,
|
||||
screenModel = MigrateDialogScreenModel(),
|
||||
onDismissRequest = onDismissRequest,
|
||||
onClickTitle = { navigator.push(MangaScreen(dialog.oldManga.id)) },
|
||||
onPopScreen = {
|
||||
onDismissRequest()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ class HistoryScreenModel(
|
|||
logcat(LogPriority.ERROR, error)
|
||||
_events.send(Event.InternalError)
|
||||
}
|
||||
.map { it.toHistoryUiModels().toImmutableList() }
|
||||
.map { it.toHistoryUiModels() }
|
||||
.flowOn(Dispatchers.IO)
|
||||
}
|
||||
.collect { newList -> mutableState.update { it.copy(list = newList) } }
|
||||
|
|
@ -215,6 +215,12 @@ class HistoryScreenModel(
|
|||
}
|
||||
}
|
||||
|
||||
fun showMigrateDialog(currentManga: Manga, duplicate: Manga) {
|
||||
mutableState.update { currentState ->
|
||||
currentState.copy(dialog = Dialog.Migrate(newManga = currentManga, oldManga = duplicate))
|
||||
}
|
||||
}
|
||||
|
||||
private fun showChangeCategoryDialog(manga: Manga) {
|
||||
screenModelScope.launch {
|
||||
val categories = getCategories()
|
||||
|
|
@ -233,7 +239,7 @@ class HistoryScreenModel(
|
|||
@Immutable
|
||||
data class State(
|
||||
val searchQuery: String? = null,
|
||||
val list: ImmutableList<HistoryUiModel>? = null,
|
||||
val list: List<HistoryUiModel>? = null,
|
||||
val dialog: Dialog? = null,
|
||||
)
|
||||
|
||||
|
|
@ -245,6 +251,7 @@ class HistoryScreenModel(
|
|||
val manga: Manga,
|
||||
val initialSelection: ImmutableList<CheckboxState<Category>>,
|
||||
) : Dialog
|
||||
data class Migrate(val newManga: Manga, val oldManga: Manga) : Dialog
|
||||
}
|
||||
|
||||
sealed interface Event {
|
||||
|
|
|
|||
|
|
@ -27,7 +27,8 @@ import eu.kanade.presentation.history.components.HistoryDeleteDialog
|
|||
import eu.kanade.presentation.manga.DuplicateMangaDialog
|
||||
import eu.kanade.presentation.util.Tab
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.advanced.design.PreMigrationScreen
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.search.MigrateDialog
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.search.MigrateDialogScreenModel
|
||||
import eu.kanade.tachiyomi.ui.category.CategoryScreen
|
||||
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaScreen
|
||||
|
|
@ -36,7 +37,6 @@ import kotlinx.coroutines.channels.Channel
|
|||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.receiveAsFlow
|
||||
import tachiyomi.core.common.i18n.stringResource
|
||||
import tachiyomi.domain.UnsortedPreferences
|
||||
import tachiyomi.domain.chapter.model.Chapter
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.i18n.stringResource
|
||||
|
|
@ -121,16 +121,7 @@ data object HistoryTab : Tab {
|
|||
screenModel.addFavorite(dialog.manga)
|
||||
},
|
||||
onOpenManga = { navigator.push(MangaScreen(it.id)) },
|
||||
onMigrate = {
|
||||
// KMK -->
|
||||
PreMigrationScreen.navigateToMigration(
|
||||
Injekt.get<UnsortedPreferences>().skipPreMigration().get(),
|
||||
navigator,
|
||||
it.id,
|
||||
dialog.manga.id,
|
||||
)
|
||||
// KMK <--
|
||||
},
|
||||
onMigrate = { screenModel.showMigrateDialog(dialog.manga, it) },
|
||||
)
|
||||
}
|
||||
is HistoryScreenModel.Dialog.ChangeCategory -> {
|
||||
|
|
@ -143,6 +134,16 @@ data object HistoryTab : Tab {
|
|||
},
|
||||
)
|
||||
}
|
||||
is HistoryScreenModel.Dialog.Migrate -> {
|
||||
MigrateDialog(
|
||||
oldManga = dialog.oldManga,
|
||||
newManga = dialog.newManga,
|
||||
screenModel = MigrateDialogScreenModel(),
|
||||
onDismissRequest = onDismissRequest,
|
||||
onClickTitle = { navigator.push(MangaScreen(dialog.oldManga.id)) },
|
||||
onPopScreen = { navigator.replace(MangaScreen(dialog.newManga.id)) },
|
||||
)
|
||||
}
|
||||
null -> {}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -68,6 +68,8 @@ import eu.kanade.tachiyomi.ui.browse.BulkFavoriteScreenModel
|
|||
import eu.kanade.tachiyomi.ui.browse.extension.ExtensionsScreen
|
||||
import eu.kanade.tachiyomi.ui.browse.extension.details.SourcePreferencesScreen
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.advanced.design.PreMigrationScreen
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.search.MigrateDialog
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.search.MigrateDialogScreenModel
|
||||
import eu.kanade.tachiyomi.ui.browse.source.SourcesScreen
|
||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreen
|
||||
import eu.kanade.tachiyomi.ui.browse.source.feed.SourceFeedScreen
|
||||
|
|
@ -327,9 +329,17 @@ class MangaScreen(
|
|||
onEditFetchIntervalClicked = screenModel::showSetFetchIntervalDialog.takeIf {
|
||||
successState.manga.favorite
|
||||
},
|
||||
previewsRowCount = successState.previewsRowCount,
|
||||
onMigrateClicked = {
|
||||
// SY -->
|
||||
PreMigrationScreen.navigateToMigration(
|
||||
Injekt.get<UnsortedPreferences>().skipPreMigration().get(),
|
||||
navigator,
|
||||
listOfNotNull(successState.manga.id),
|
||||
)
|
||||
// SY <--
|
||||
}.takeIf { successState.manga.favorite },
|
||||
// SY -->
|
||||
onMigrateClicked = { migrateManga(navigator, screenModel.manga!!) }.takeIf { successState.manga.favorite },
|
||||
previewsRowCount = successState.previewsRowCount,
|
||||
onMetadataViewerClicked = {
|
||||
openMetadataViewer(
|
||||
navigator,
|
||||
|
|
@ -433,7 +443,6 @@ class MangaScreen(
|
|||
},
|
||||
)
|
||||
}
|
||||
|
||||
is MangaScreenModel.Dialog.DeleteChapters -> {
|
||||
DeleteChaptersDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
|
|
@ -450,14 +459,20 @@ class MangaScreen(
|
|||
onDismissRequest = onDismissRequest,
|
||||
onConfirm = { screenModel.toggleFavorite(onRemoved = {}, checkDuplicate = false) },
|
||||
onOpenManga = { navigator.push(MangaScreen(it.id)) },
|
||||
onMigrate = {
|
||||
// SY -->
|
||||
migrateManga(navigator, it, screenModel.manga!!.id)
|
||||
// SY <--
|
||||
},
|
||||
onMigrate = { screenModel.showMigrateDialog(it) },
|
||||
)
|
||||
}
|
||||
|
||||
is MangaScreenModel.Dialog.Migrate -> {
|
||||
MigrateDialog(
|
||||
oldManga = dialog.oldManga,
|
||||
newManga = dialog.newManga,
|
||||
screenModel = MigrateDialogScreenModel(),
|
||||
onDismissRequest = onDismissRequest,
|
||||
onClickTitle = { navigator.push(MangaScreen(dialog.oldManga.id)) },
|
||||
onPopScreen = { navigator.replace(MangaScreen(dialog.newManga.id)) },
|
||||
)
|
||||
}
|
||||
MangaScreenModel.Dialog.SettingsSheet -> ChapterSettingsDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
manga = successState.manga,
|
||||
|
|
@ -471,7 +486,6 @@ class MangaScreen(
|
|||
scanlatorFilterActive = successState.scanlatorFilterActive,
|
||||
onScanlatorFilterClicked = { showScanlatorsDialog = true },
|
||||
)
|
||||
|
||||
MangaScreenModel.Dialog.TrackSheet -> {
|
||||
NavigatorAdaptiveSheet(
|
||||
screen = TrackInfoDialogHomeScreen(
|
||||
|
|
@ -483,7 +497,6 @@ class MangaScreen(
|
|||
onDismissRequest = onDismissRequest,
|
||||
)
|
||||
}
|
||||
|
||||
MangaScreenModel.Dialog.FullCover -> {
|
||||
val sm = rememberScreenModel { MangaCoverScreenModel(successState.manga.id) }
|
||||
val manga by sm.state.collectAsState()
|
||||
|
|
@ -540,7 +553,6 @@ class MangaScreen(
|
|||
LoadingScreen(Modifier.systemBarsPadding())
|
||||
}
|
||||
}
|
||||
|
||||
is MangaScreenModel.Dialog.SetFetchInterval -> {
|
||||
SetIntervalDialog(
|
||||
interval = dialog.manga.fetchInterval,
|
||||
|
|
@ -739,21 +751,6 @@ class MangaScreen(
|
|||
context.copyToClipboard(url, url)
|
||||
}
|
||||
|
||||
// SY -->
|
||||
/**
|
||||
* Initiates source migration for the specific manga.
|
||||
*/
|
||||
private fun migrateManga(navigator: Navigator, manga: Manga, toMangaId: Long? = null) {
|
||||
// SY -->
|
||||
PreMigrationScreen.navigateToMigration(
|
||||
Injekt.get<UnsortedPreferences>().skipPreMigration().get(),
|
||||
navigator,
|
||||
manga.id,
|
||||
toMangaId,
|
||||
)
|
||||
// SY <--
|
||||
}
|
||||
|
||||
private fun openMetadataViewer(
|
||||
navigator: Navigator,
|
||||
manga: Manga,
|
||||
|
|
|
|||
|
|
@ -1738,10 +1738,7 @@ class MangaScreenModel(
|
|||
) : Dialog
|
||||
data class DeleteChapters(val chapters: List<Chapter>) : Dialog
|
||||
data class DuplicateManga(val manga: Manga, val duplicates: List<Manga>) : Dialog
|
||||
|
||||
/* SY -->
|
||||
data class Migrate(val newManga: Manga, val oldManga: Manga) : Dialog
|
||||
SY <-- */
|
||||
data class SetFetchInterval(val manga: Manga) : Dialog
|
||||
|
||||
// SY -->
|
||||
|
|
@ -1774,11 +1771,10 @@ class MangaScreenModel(
|
|||
updateSuccessState { it.copy(dialog = Dialog.FullCover) }
|
||||
}
|
||||
|
||||
/* SY -->
|
||||
fun showMigrateDialog(duplicate: Manga) {
|
||||
val manga = successState?.manga ?: return
|
||||
updateSuccessState { it.copy(dialog = Dialog.Migrate(newManga = manga, oldManga = duplicate)) }
|
||||
} SY <-- */
|
||||
}
|
||||
|
||||
fun setExcludedScanlators(excludedScanlators: Set<String>) {
|
||||
screenModelScope.launchIO {
|
||||
|
|
|
|||
|
|
@ -24,19 +24,17 @@ import eu.kanade.presentation.manga.DuplicateMangaDialog
|
|||
import eu.kanade.presentation.util.Screen
|
||||
import eu.kanade.tachiyomi.ui.browse.BulkFavoriteDialogs
|
||||
import eu.kanade.tachiyomi.ui.browse.BulkFavoriteScreenModel
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.advanced.design.PreMigrationScreen
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.search.MigrateDialog
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.search.MigrateDialogScreenModel
|
||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreenModel
|
||||
import eu.kanade.tachiyomi.ui.category.CategoryScreen
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaScreen
|
||||
import mihon.presentation.core.util.collectAsLazyPagingItems
|
||||
import tachiyomi.core.common.util.lang.launchIO
|
||||
import tachiyomi.domain.UnsortedPreferences
|
||||
import tachiyomi.i18n.sy.SYMR
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.i18n.stringResource
|
||||
import tachiyomi.presentation.core.screens.LoadingScreen
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class MangaDexFollowsScreen(private val sourceId: Long) : Screen() {
|
||||
|
||||
|
|
@ -158,23 +156,31 @@ class MangaDexFollowsScreen(private val sourceId: Long) : Screen() {
|
|||
|
||||
val onDismissRequest = { screenModel.setDialog(null) }
|
||||
when (val dialog = state.dialog) {
|
||||
is BrowseSourceScreenModel.Dialog.Migrate -> {}
|
||||
is BrowseSourceScreenModel.Dialog.AddDuplicateManga -> {
|
||||
DuplicateMangaDialog(
|
||||
duplicates = dialog.duplicates,
|
||||
onDismissRequest = onDismissRequest,
|
||||
onConfirm = { screenModel.addFavorite(dialog.manga) },
|
||||
onOpenManga = { navigator.push(MangaScreen(it.id)) },
|
||||
onMigrate = {
|
||||
PreMigrationScreen.navigateToMigration(
|
||||
Injekt.get<UnsortedPreferences>().skipPreMigration().get(),
|
||||
navigator,
|
||||
it.id,
|
||||
dialog.manga.id,
|
||||
)
|
||||
// KMK -->
|
||||
onMigrate = { screenModel.setDialog(BrowseSourceScreenModel.Dialog.Migrate(dialog.manga, it)) },
|
||||
// KMK <--
|
||||
)
|
||||
}
|
||||
// KMK -->
|
||||
is BrowseSourceScreenModel.Dialog.Migrate -> {
|
||||
MigrateDialog(
|
||||
oldManga = dialog.oldManga,
|
||||
newManga = dialog.newManga,
|
||||
screenModel = MigrateDialogScreenModel(),
|
||||
onDismissRequest = onDismissRequest,
|
||||
onClickTitle = { navigator.push(MangaScreen(dialog.oldManga.id)) },
|
||||
onPopScreen = {
|
||||
onDismissRequest()
|
||||
},
|
||||
)
|
||||
}
|
||||
// KMK <--
|
||||
is BrowseSourceScreenModel.Dialog.RemoveManga -> {
|
||||
RemoveMangaDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
|
|
|
|||
Loading…
Reference in a new issue