mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-12-21 11:41:48 +01:00
parent
c54d77333f
commit
2df0236669
@ -0,0 +1,304 @@
|
||||
package eu.kanade.tachiyomi.ui.browse.migration.search
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Checkbox
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.util.fastForEachIndexed
|
||||
import cafe.adriel.voyager.core.model.StateScreenModel
|
||||
import eu.kanade.domain.category.interactor.GetCategories
|
||||
import eu.kanade.domain.category.interactor.SetMangaCategories
|
||||
import eu.kanade.domain.chapter.interactor.GetChapterByMangaId
|
||||
import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource
|
||||
import eu.kanade.domain.chapter.interactor.UpdateChapter
|
||||
import eu.kanade.domain.chapter.model.toChapterUpdate
|
||||
import eu.kanade.domain.manga.interactor.UpdateManga
|
||||
import eu.kanade.domain.manga.model.Manga
|
||||
import eu.kanade.domain.manga.model.MangaUpdate
|
||||
import eu.kanade.domain.manga.model.hasCustomCover
|
||||
import eu.kanade.domain.track.interactor.GetTracks
|
||||
import eu.kanade.domain.track.interactor.InsertTrack
|
||||
import eu.kanade.presentation.components.LoadingScreen
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.core.preference.Preference
|
||||
import eu.kanade.tachiyomi.core.preference.PreferenceStore
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
import eu.kanade.tachiyomi.data.track.EnhancedTrackService
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.MigrationFlags
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import eu.kanade.tachiyomi.util.lang.withUIContext
|
||||
import kotlinx.coroutines.flow.update
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.util.Date
|
||||
|
||||
@Composable
|
||||
internal fun MigrateDialog(
|
||||
oldManga: Manga,
|
||||
newManga: Manga,
|
||||
screenModel: MigrateDialogScreenModel,
|
||||
onDismissRequest: () -> Unit,
|
||||
onClickTitle: () -> Unit,
|
||||
onPopScreen: () -> Unit,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val scope = rememberCoroutineScope()
|
||||
val state by screenModel.state.collectAsState()
|
||||
|
||||
val activeFlags = remember { MigrationFlags.getEnabledFlagsPositions(screenModel.migrateFlags.get()) }
|
||||
val items = remember {
|
||||
MigrationFlags.titles(oldManga)
|
||||
.map { context.getString(it) }
|
||||
.toList()
|
||||
}
|
||||
val selected = remember {
|
||||
mutableStateListOf(*List(items.size) { i -> activeFlags.contains(i) }.toTypedArray())
|
||||
}
|
||||
|
||||
if (state.isMigrating) {
|
||||
LoadingScreen(
|
||||
modifier = Modifier
|
||||
.background(MaterialTheme.colorScheme.background.copy(alpha = 0.7f)),
|
||||
)
|
||||
} else {
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
title = {
|
||||
Text(text = stringResource(R.string.migration_dialog_what_to_include))
|
||||
},
|
||||
text = {
|
||||
Column(
|
||||
modifier = Modifier.verticalScroll(rememberScrollState()),
|
||||
) {
|
||||
items.forEachIndexed { index, title ->
|
||||
val onChange: () -> Unit = {
|
||||
selected[index] = !selected[index]
|
||||
}
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable(onClick = onChange),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Checkbox(checked = selected[index], onCheckedChange = { onChange() })
|
||||
Text(text = title)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
Row {
|
||||
TextButton(
|
||||
onClick = {
|
||||
onClickTitle()
|
||||
onDismissRequest()
|
||||
},
|
||||
) {
|
||||
Text(text = stringResource(R.string.action_show_manga))
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
TextButton(
|
||||
onClick = {
|
||||
scope.launchIO {
|
||||
screenModel.migrateManga(oldManga, newManga, false)
|
||||
withUIContext { onPopScreen() }
|
||||
}
|
||||
},
|
||||
) {
|
||||
Text(text = stringResource(R.string.copy))
|
||||
}
|
||||
TextButton(
|
||||
onClick = {
|
||||
scope.launchIO {
|
||||
val selectedIndices = mutableListOf<Int>()
|
||||
selected.fastForEachIndexed { i, b -> if (b) selectedIndices.add(i) }
|
||||
val newValue =
|
||||
MigrationFlags.getFlagsFromPositions(selectedIndices.toTypedArray())
|
||||
screenModel.migrateFlags.set(newValue)
|
||||
screenModel.migrateManga(oldManga, newManga, true)
|
||||
withUIContext { onPopScreen() }
|
||||
}
|
||||
},
|
||||
) {
|
||||
Text(text = stringResource(R.string.migrate))
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
internal class MigrateDialogScreenModel(
|
||||
private val sourceManager: SourceManager = Injekt.get(),
|
||||
private val updateManga: UpdateManga = Injekt.get(),
|
||||
private val getChapterByMangaId: GetChapterByMangaId = Injekt.get(),
|
||||
private val syncChaptersWithSource: SyncChaptersWithSource = Injekt.get(),
|
||||
private val updateChapter: UpdateChapter = 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(),
|
||||
private val coverCache: CoverCache = Injekt.get(),
|
||||
private val preferenceStore: PreferenceStore = Injekt.get(),
|
||||
) : StateScreenModel<MigrateDialogScreenModel.State>(State()) {
|
||||
|
||||
val migrateFlags: Preference<Int> by lazy {
|
||||
preferenceStore.getInt("migrate_flags", Int.MAX_VALUE)
|
||||
}
|
||||
|
||||
private val enhancedServices by lazy {
|
||||
Injekt.get<TrackManager>().services.filterIsInstance<EnhancedTrackService>()
|
||||
}
|
||||
|
||||
suspend fun migrateManga(oldManga: Manga, newManga: Manga, replace: Boolean) {
|
||||
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,
|
||||
)
|
||||
} catch (_: Throwable) {
|
||||
// Explicitly stop if an error occurred; the dialog normally gets popped at the end
|
||||
// anyway
|
||||
mutableState.update { it.copy(isMigrating = false) }
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun migrateMangaInternal(
|
||||
oldSource: Source?,
|
||||
newSource: Source,
|
||||
oldManga: Manga,
|
||||
newManga: Manga,
|
||||
sourceChapters: List<SChapter>,
|
||||
replace: Boolean,
|
||||
) {
|
||||
val flags = migrateFlags.get()
|
||||
|
||||
val migrateChapters = MigrationFlags.hasChapters(flags)
|
||||
val migrateCategories = MigrationFlags.hasCategories(flags)
|
||||
val migrateTracks = MigrationFlags.hasTracks(flags)
|
||||
val migrateCustomCover = MigrationFlags.hasCustomCover(flags)
|
||||
|
||||
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 = getChapterByMangaId.await(oldManga.id)
|
||||
val mangaChapters = getChapterByMangaId.await(newManga.id)
|
||||
|
||||
val maxChapterRead = prevMangaChapters
|
||||
.filter { it.read }
|
||||
.maxOfOrNull { it.chapterNumber }
|
||||
|
||||
val updatedMangaChapters = mangaChapters.map { mangaChapter ->
|
||||
var updatedChapter = mangaChapter
|
||||
if (updatedChapter.isRecognizedNumber) {
|
||||
val prevChapter = prevMangaChapters
|
||||
.find { it.isRecognizedNumber && it.chapterNumber == updatedChapter.chapterNumber }
|
||||
|
||||
if (prevChapter != null) {
|
||||
updatedChapter = updatedChapter.copy(
|
||||
dateFetch = prevChapter.dateFetch,
|
||||
bookmark = prevChapter.bookmark,
|
||||
)
|
||||
}
|
||||
|
||||
if (maxChapterRead != null && updatedChapter.chapterNumber <= maxChapterRead) {
|
||||
updatedChapter = updatedChapter.copy(read = true)
|
||||
}
|
||||
}
|
||||
|
||||
updatedChapter
|
||||
}
|
||||
|
||||
val chapterUpdates = updatedMangaChapters.map { it.toChapterUpdate() }
|
||||
updateChapter.awaitAll(chapterUpdates)
|
||||
}
|
||||
|
||||
// Update categories
|
||||
if (migrateCategories) {
|
||||
val categoryIds = getCategories.await(oldManga.id).map { it.id }
|
||||
setMangaCategories.await(newManga.id, categoryIds)
|
||||
}
|
||||
|
||||
// Update track
|
||||
if (migrateTracks) {
|
||||
val tracks = getTracks.await(oldManga.id).mapNotNull { track ->
|
||||
val updatedTrack = track.copy(mangaId = newManga.id)
|
||||
|
||||
val service = enhancedServices
|
||||
.firstOrNull { it.isTrackFrom(updatedTrack, oldManga, oldSource) }
|
||||
|
||||
if (service != null) {
|
||||
service.migrateTrack(updatedTrack, newManga, newSource)
|
||||
} else {
|
||||
updatedTrack
|
||||
}
|
||||
}
|
||||
insertTrack.awaitAll(tracks)
|
||||
}
|
||||
|
||||
if (replace) {
|
||||
updateManga.await(MangaUpdate(oldManga.id, favorite = false, dateAdded = 0))
|
||||
}
|
||||
|
||||
// Update custom cover (recheck if custom cover exists)
|
||||
if (migrateCustomCover && oldManga.hasCustomCover()) {
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
coverCache.setCustomCoverToCache(newManga, coverCache.getCustomCoverFile(oldManga.id).inputStream())
|
||||
}
|
||||
|
||||
updateManga.await(
|
||||
MangaUpdate(
|
||||
id = newManga.id,
|
||||
favorite = true,
|
||||
chapterFlags = oldManga.chapterFlags,
|
||||
viewerFlags = oldManga.viewerFlags,
|
||||
dateAdded = if (replace) oldManga.dateAdded else Date().time,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
data class State(
|
||||
val isMigrating: Boolean = false,
|
||||
)
|
||||
}
|
@ -1,67 +1,21 @@
|
||||
package eu.kanade.tachiyomi.ui.browse.migration.search
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Checkbox
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.util.fastForEachIndexed
|
||||
import cafe.adriel.voyager.core.model.ScreenModel
|
||||
import cafe.adriel.voyager.core.model.rememberScreenModel
|
||||
import cafe.adriel.voyager.core.screen.Screen
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import eu.kanade.domain.category.interactor.GetCategories
|
||||
import eu.kanade.domain.category.interactor.SetMangaCategories
|
||||
import eu.kanade.domain.chapter.interactor.GetChapterByMangaId
|
||||
import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource
|
||||
import eu.kanade.domain.chapter.interactor.UpdateChapter
|
||||
import eu.kanade.domain.chapter.model.toChapterUpdate
|
||||
import eu.kanade.domain.manga.interactor.UpdateManga
|
||||
import eu.kanade.domain.manga.model.Manga
|
||||
import eu.kanade.domain.manga.model.MangaUpdate
|
||||
import eu.kanade.domain.manga.model.hasCustomCover
|
||||
import eu.kanade.domain.track.interactor.GetTracks
|
||||
import eu.kanade.domain.track.interactor.InsertTrack
|
||||
import eu.kanade.presentation.browse.MigrateSearchScreen
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.core.preference.Preference
|
||||
import eu.kanade.tachiyomi.core.preference.PreferenceStore
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
import eu.kanade.tachiyomi.data.track.EnhancedTrackService
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.MigrationFlags
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaScreen
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import eu.kanade.tachiyomi.util.lang.launchUI
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.util.Date
|
||||
|
||||
class MigrateSearchScreen(private val mangaId: Long) : Screen {
|
||||
|
||||
@Composable
|
||||
override fun Content() {
|
||||
val navigator = LocalNavigator.currentOrThrow
|
||||
|
||||
val screenModel = rememberScreenModel { MigrateSearchScreenModel(mangaId = mangaId) }
|
||||
val state by screenModel.state.collectAsState()
|
||||
|
||||
@ -84,7 +38,6 @@ class MigrateSearchScreen(private val mangaId: Long) : Screen {
|
||||
)
|
||||
|
||||
when (val dialog = state.dialog) {
|
||||
null -> {}
|
||||
is MigrateSearchDialog.Migrate -> {
|
||||
MigrateDialog(
|
||||
oldManga = state.manga!!,
|
||||
@ -105,228 +58,7 @@ class MigrateSearchScreen(private val mangaId: Long) : Screen {
|
||||
},
|
||||
)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MigrateDialog(
|
||||
oldManga: Manga,
|
||||
newManga: Manga,
|
||||
screenModel: MigrateDialogScreenModel,
|
||||
onDismissRequest: () -> Unit,
|
||||
onClickTitle: () -> Unit,
|
||||
onPopScreen: () -> Unit,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val scope = rememberCoroutineScope()
|
||||
val activeFlags = remember { MigrationFlags.getEnabledFlagsPositions(screenModel.migrateFlags.get()) }
|
||||
val items = remember {
|
||||
MigrationFlags.titles(oldManga)
|
||||
.map { context.getString(it) }
|
||||
.toList()
|
||||
}
|
||||
val selected = remember {
|
||||
mutableStateListOf(*List(items.size) { i -> activeFlags.contains(i) }.toTypedArray())
|
||||
}
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
title = {
|
||||
Text(text = stringResource(R.string.migration_dialog_what_to_include))
|
||||
},
|
||||
text = {
|
||||
Column(
|
||||
modifier = Modifier.verticalScroll(rememberScrollState()),
|
||||
) {
|
||||
items.forEachIndexed { index, title ->
|
||||
val onChange: () -> Unit = {
|
||||
selected[index] = !selected[index]
|
||||
}
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable(onClick = onChange),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Checkbox(checked = selected[index], onCheckedChange = { onChange() })
|
||||
Text(text = title)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
Row {
|
||||
TextButton(onClick = {
|
||||
onClickTitle()
|
||||
onDismissRequest()
|
||||
},) {
|
||||
Text(text = stringResource(R.string.action_show_manga))
|
||||
}
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
TextButton(onClick = {
|
||||
scope.launchIO {
|
||||
screenModel.migrateManga(oldManga, newManga, false)
|
||||
launchUI {
|
||||
onPopScreen()
|
||||
}
|
||||
}
|
||||
},) {
|
||||
Text(text = stringResource(R.string.copy))
|
||||
}
|
||||
TextButton(onClick = {
|
||||
scope.launchIO {
|
||||
val selectedIndices = mutableListOf<Int>()
|
||||
selected.fastForEachIndexed { i, b -> if (b) selectedIndices.add(i) }
|
||||
val newValue = MigrationFlags.getFlagsFromPositions(selectedIndices.toTypedArray())
|
||||
screenModel.migrateFlags.set(newValue)
|
||||
screenModel.migrateManga(oldManga, newManga, true)
|
||||
launchUI {
|
||||
onPopScreen()
|
||||
}
|
||||
}
|
||||
},) {
|
||||
Text(text = stringResource(R.string.migrate))
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
class MigrateDialogScreenModel(
|
||||
private val sourceManager: SourceManager = Injekt.get(),
|
||||
private val updateManga: UpdateManga = Injekt.get(),
|
||||
private val getChapterByMangaId: GetChapterByMangaId = Injekt.get(),
|
||||
private val syncChaptersWithSource: SyncChaptersWithSource = Injekt.get(),
|
||||
private val updateChapter: UpdateChapter = 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(),
|
||||
private val coverCache: CoverCache = Injekt.get(),
|
||||
private val preferenceStore: PreferenceStore = Injekt.get(),
|
||||
) : ScreenModel {
|
||||
|
||||
val migrateFlags: Preference<Int> by lazy {
|
||||
preferenceStore.getInt("migrate_flags", Int.MAX_VALUE)
|
||||
}
|
||||
|
||||
private val enhancedServices by lazy { Injekt.get<TrackManager>().services.filterIsInstance<EnhancedTrackService>() }
|
||||
|
||||
suspend fun migrateManga(oldManga: Manga, newManga: Manga, replace: Boolean) {
|
||||
val source = sourceManager.get(newManga.source) ?: return
|
||||
val prevSource = sourceManager.get(oldManga.source)
|
||||
|
||||
try {
|
||||
val chapters = source.getChapterList(newManga.toSManga())
|
||||
|
||||
migrateMangaInternal(
|
||||
oldSource = prevSource,
|
||||
newSource = source,
|
||||
oldManga = oldManga,
|
||||
newManga = newManga,
|
||||
sourceChapters = chapters,
|
||||
replace = replace,
|
||||
)
|
||||
} catch (e: Throwable) {
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun migrateMangaInternal(
|
||||
oldSource: Source?,
|
||||
newSource: Source,
|
||||
oldManga: Manga,
|
||||
newManga: Manga,
|
||||
sourceChapters: List<SChapter>,
|
||||
replace: Boolean,
|
||||
) {
|
||||
val flags = migrateFlags.get()
|
||||
|
||||
val migrateChapters = MigrationFlags.hasChapters(flags)
|
||||
val migrateCategories = MigrationFlags.hasCategories(flags)
|
||||
val migrateTracks = MigrationFlags.hasTracks(flags)
|
||||
val migrateCustomCover = MigrationFlags.hasCustomCover(flags)
|
||||
|
||||
try {
|
||||
syncChaptersWithSource.await(sourceChapters, newManga, newSource)
|
||||
} catch (e: Exception) {
|
||||
// Worst case, chapters won't be synced
|
||||
}
|
||||
|
||||
// Update chapters read, bookmark and dateFetch
|
||||
if (migrateChapters) {
|
||||
val prevMangaChapters = getChapterByMangaId.await(oldManga.id)
|
||||
val mangaChapters = getChapterByMangaId.await(newManga.id)
|
||||
|
||||
val maxChapterRead = prevMangaChapters
|
||||
.filter { it.read }
|
||||
.maxOfOrNull { it.chapterNumber }
|
||||
|
||||
val updatedMangaChapters = mangaChapters.map { mangaChapter ->
|
||||
var updatedChapter = mangaChapter
|
||||
if (updatedChapter.isRecognizedNumber) {
|
||||
val prevChapter = prevMangaChapters
|
||||
.find { it.isRecognizedNumber && it.chapterNumber == updatedChapter.chapterNumber }
|
||||
|
||||
if (prevChapter != null) {
|
||||
updatedChapter = updatedChapter.copy(
|
||||
dateFetch = prevChapter.dateFetch,
|
||||
bookmark = prevChapter.bookmark,
|
||||
)
|
||||
}
|
||||
|
||||
if (maxChapterRead != null && updatedChapter.chapterNumber <= maxChapterRead) {
|
||||
updatedChapter = updatedChapter.copy(read = true)
|
||||
}
|
||||
}
|
||||
|
||||
updatedChapter
|
||||
}
|
||||
|
||||
val chapterUpdates = updatedMangaChapters.map { it.toChapterUpdate() }
|
||||
updateChapter.awaitAll(chapterUpdates)
|
||||
}
|
||||
|
||||
// Update categories
|
||||
if (migrateCategories) {
|
||||
val categoryIds = getCategories.await(oldManga.id).map { it.id }
|
||||
setMangaCategories.await(newManga.id, categoryIds)
|
||||
}
|
||||
|
||||
// Update track
|
||||
if (migrateTracks) {
|
||||
val tracks = getTracks.await(oldManga.id).mapNotNull { track ->
|
||||
val updatedTrack = track.copy(mangaId = newManga.id)
|
||||
|
||||
val service = enhancedServices
|
||||
.firstOrNull { it.isTrackFrom(updatedTrack, oldManga, oldSource) }
|
||||
|
||||
if (service != null) {
|
||||
service.migrateTrack(updatedTrack, newManga, newSource)
|
||||
} else {
|
||||
updatedTrack
|
||||
}
|
||||
}
|
||||
insertTrack.awaitAll(tracks)
|
||||
}
|
||||
|
||||
if (replace) {
|
||||
updateManga.await(MangaUpdate(oldManga.id, favorite = false, dateAdded = 0))
|
||||
}
|
||||
|
||||
// Update custom cover (recheck if custom cover exists)
|
||||
if (migrateCustomCover && oldManga.hasCustomCover()) {
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
coverCache.setCustomCoverToCache(newManga, coverCache.getCustomCoverFile(oldManga.id).inputStream())
|
||||
}
|
||||
|
||||
updateManga.await(
|
||||
MangaUpdate(
|
||||
id = newManga.id,
|
||||
favorite = true,
|
||||
chapterFlags = oldManga.chapterFlags,
|
||||
viewerFlags = oldManga.viewerFlags,
|
||||
dateAdded = if (replace) oldManga.dateAdded else Date().time,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user