From c0a888807b78891b28c6f6b9f16b719e24b03de1 Mon Sep 17 00:00:00 2001 From: Maddie Witman Date: Fri, 22 Mar 2024 09:04:43 -0400 Subject: [PATCH] Rework Duplicate Dialog and Allow Migration (#492) * (Mostly) Working Manga screen migration via duplicate dialog * Fully working migrate from Browse Search * Small tweaks for Antsy * Update app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt * Update app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt --------- Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com> --- .../manga/DuplicateMangaDialog.kt | 139 +++++++++++++----- .../migration/search/SourceSearchScreen.kt | 2 +- .../source/browse/BrowseSourceScreen.kt | 19 ++- .../source/browse/BrowseSourceScreenModel.kt | 2 +- .../kanade/tachiyomi/ui/manga/MangaScreen.kt | 29 +++- .../tachiyomi/ui/manga/MangaScreenModel.kt | 6 + .../commonMain/resources/MR/base/strings.xml | 2 + 7 files changed, 155 insertions(+), 44 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/manga/DuplicateMangaDialog.kt b/app/src/main/java/eu/kanade/presentation/manga/DuplicateMangaDialog.kt index e3ff20ad26..0707ac2bc6 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/DuplicateMangaDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/DuplicateMangaDialog.kt @@ -1,16 +1,33 @@ package eu.kanade.presentation.manga +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.FlowRow +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer -import androidx.compose.material3.AlertDialog +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.sizeIn +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.Add +import androidx.compose.material.icons.outlined.Book +import androidx.compose.material.icons.outlined.SwapVert +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedButton import androidx.compose.material3.Text -import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import eu.kanade.presentation.components.AdaptiveSheet +import eu.kanade.presentation.components.TabbedDialogPaddings +import eu.kanade.presentation.more.settings.LocalPreferenceMinHeight +import eu.kanade.presentation.more.settings.widget.TextPreferenceWidget import tachiyomi.i18n.MR -import tachiyomi.presentation.core.components.material.padding import tachiyomi.presentation.core.i18n.stringResource @Composable @@ -18,42 +35,92 @@ fun DuplicateMangaDialog( onDismissRequest: () -> Unit, onConfirm: () -> Unit, onOpenManga: () -> Unit, + onMigrate: () -> Unit, + modifier: Modifier = Modifier, ) { - AlertDialog( + val minHeight = LocalPreferenceMinHeight.current + + AdaptiveSheet( + modifier = modifier, onDismissRequest = onDismissRequest, - title = { - Text(text = stringResource(MR.strings.are_you_sure)) - }, - text = { - Text(text = stringResource(MR.strings.confirm_add_duplicate_manga)) - }, - confirmButton = { - FlowRow( - horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.extraSmall), - ) { - TextButton( - onClick = { - onDismissRequest() - onOpenManga() - }, - ) { - Text(text = stringResource(MR.strings.action_show_manga)) - } + ) { + Column( + modifier = Modifier + .padding( + vertical = TabbedDialogPaddings.Vertical, + horizontal = TabbedDialogPaddings.Horizontal, + ) + .fillMaxWidth(), + ) { + Text( + modifier = Modifier.padding(TitlePadding), + text = stringResource(MR.strings.are_you_sure), + style = MaterialTheme.typography.headlineMedium, + ) - Spacer(modifier = Modifier.weight(1f)) + Text( + text = stringResource(MR.strings.confirm_add_duplicate_manga), + style = MaterialTheme.typography.bodyMedium, + ) - TextButton(onClick = onDismissRequest) { - Text(text = stringResource(MR.strings.action_cancel)) - } - TextButton( - onClick = { - onDismissRequest() - onConfirm() - }, - ) { - Text(text = stringResource(MR.strings.action_add)) + Spacer(Modifier.height(PaddingSize)) + + TextPreferenceWidget( + title = stringResource(MR.strings.action_show_manga), + icon = Icons.Outlined.Book, + onPreferenceClick = { + onDismissRequest() + onOpenManga() + }, + ) + + HorizontalDivider() + + TextPreferenceWidget( + title = stringResource(MR.strings.action_migrate_duplicate), + icon = Icons.Outlined.SwapVert, + onPreferenceClick = { + onDismissRequest() + onMigrate() + }, + ) + + HorizontalDivider() + + TextPreferenceWidget( + title = stringResource(MR.strings.action_add_anyway), + icon = Icons.Outlined.Add, + onPreferenceClick = { + onDismissRequest() + onConfirm() + }, + ) + + Row( + modifier = Modifier + .sizeIn(minHeight = minHeight) + .clickable { onDismissRequest.invoke() } + .padding(ButtonPadding) + .fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center, + ) { + OutlinedButton(onClick = onDismissRequest, modifier = Modifier.fillMaxWidth()) { + Text( + modifier = Modifier + .padding(vertical = 8.dp), + text = stringResource(MR.strings.action_cancel), + color = MaterialTheme.colorScheme.primary, + style = MaterialTheme.typography.titleLarge, + fontSize = 16.sp, + ) } } - }, - ) + } + } } + +private val PaddingSize = 16.dp + +private val ButtonPadding = PaddingValues(top = 16.dp, bottom = 16.dp) +private val TitlePadding = PaddingValues(bottom = 16.dp, top = 8.dp) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/SourceSearchScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/SourceSearchScreen.kt index 3a2adcc21f..533dbd3af3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/SourceSearchScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/SourceSearchScreen.kt @@ -83,7 +83,7 @@ data class SourceSearchScreen( ) { paddingValues -> val pagingFlow by screenModel.mangaPagerFlowFlow.collectAsState() val openMigrateDialog: (Manga) -> Unit = { - screenModel.setDialog(BrowseSourceScreenModel.Dialog.Migrate(it)) + screenModel.setDialog(BrowseSourceScreenModel.Dialog.Migrate(newManga = it, oldManga = oldManga)) } BrowseSourceContent( source = screenModel.source, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreen.kt index 61c30f604a..152b2adfee 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreen.kt @@ -47,6 +47,8 @@ import eu.kanade.presentation.util.Screen import eu.kanade.tachiyomi.source.CatalogueSource import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.ui.browse.extension.details.SourcePreferencesScreen +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.Listing import eu.kanade.tachiyomi.ui.category.CategoryScreen import eu.kanade.tachiyomi.ui.manga.MangaScreen @@ -252,6 +254,22 @@ data class BrowseSourceScreen( onDismissRequest = onDismissRequest, onConfirm = { screenModel.addFavorite(dialog.manga) }, onOpenManga = { navigator.push(MangaScreen(dialog.duplicate.id)) }, + onMigrate = { + screenModel.setDialog(BrowseSourceScreenModel.Dialog.Migrate(dialog.manga, dialog.duplicate)) + }, + ) + } + + is BrowseSourceScreenModel.Dialog.Migrate -> { + MigrateDialog( + oldManga = dialog.oldManga, + newManga = dialog.newManga, + screenModel = MigrateDialogScreenModel(), + onDismissRequest = onDismissRequest, + onClickTitle = { navigator.push(MangaScreen(dialog.oldManga.id)) }, + onPopScreen = { + onDismissRequest() + }, ) } is BrowseSourceScreenModel.Dialog.RemoveManga -> { @@ -274,7 +292,6 @@ data class BrowseSourceScreen( }, ) } - is BrowseSourceScreenModel.Dialog.Migrate -> {} else -> {} } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt index a7e8a26ea9..dff062503a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt @@ -345,7 +345,7 @@ class BrowseSourceScreenModel( val manga: Manga, val initialSelection: ImmutableList>, ) : Dialog - data class Migrate(val newManga: Manga) : Dialog + data class Migrate(val newManga: Manga, val oldManga: Manga) : Dialog } @Immutable diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt index d3578aff54..c2466ffd4f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt @@ -41,6 +41,8 @@ import eu.kanade.presentation.util.isTabletUi import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.isLocalOrStub import eu.kanade.tachiyomi.source.online.HttpSource +import eu.kanade.tachiyomi.ui.browse.migration.search.MigrateDialog +import eu.kanade.tachiyomi.ui.browse.migration.search.MigrateDialogScreenModel import eu.kanade.tachiyomi.ui.browse.migration.search.MigrateSearchScreen import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreen import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchScreen @@ -191,11 +193,28 @@ class MangaScreen( }, ) } - is MangaScreenModel.Dialog.DuplicateManga -> DuplicateMangaDialog( - onDismissRequest = onDismissRequest, - onConfirm = { screenModel.toggleFavorite(onRemoved = {}, checkDuplicate = false) }, - onOpenManga = { navigator.push(MangaScreen(dialog.duplicate.id)) }, - ) + + is MangaScreenModel.Dialog.DuplicateManga -> { + DuplicateMangaDialog( + onDismissRequest = onDismissRequest, + onConfirm = { screenModel.toggleFavorite(onRemoved = {}, checkDuplicate = false) }, + onOpenManga = { navigator.push(MangaScreen(dialog.duplicate.id)) }, + onMigrate = { + screenModel.showMigrateDialog(dialog.duplicate) + }, + ) + } + + 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, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt index 26ad3a7fc2..14cb037df2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt @@ -1003,6 +1003,7 @@ class MangaScreenModel( ) : Dialog data class DeleteChapters(val chapters: List) : Dialog data class DuplicateManga(val manga: Manga, val duplicate: Manga) : Dialog + data class Migrate(val newManga: Manga, val oldManga: Manga) : Dialog data class SetFetchInterval(val manga: Manga) : Dialog data object SettingsSheet : Dialog data object TrackSheet : Dialog @@ -1029,6 +1030,11 @@ class MangaScreenModel( updateSuccessState { it.copy(dialog = Dialog.FullCover) } } + fun showMigrateDialog(duplicate: Manga) { + val manga = successState?.manga ?: return + updateSuccessState { it.copy(dialog = Dialog.Migrate(newManga = manga, oldManga = duplicate)) } + } + fun setExcludedScanlators(excludedScanlators: Set) { screenModelScope.launchIO { setExcludedScanlators.await(mangaId, excludedScanlators) diff --git a/i18n/src/commonMain/resources/MR/base/strings.xml b/i18n/src/commonMain/resources/MR/base/strings.xml index 119e82ecdd..7fc1832cab 100644 --- a/i18n/src/commonMain/resources/MR/base/strings.xml +++ b/i18n/src/commonMain/resources/MR/base/strings.xml @@ -160,6 +160,8 @@ Refresh Start downloading now Not now + Add anyway + Migrate existing entry Loading…