From 96e3c60923c65192dbd702292cdc418e5d8fad46 Mon Sep 17 00:00:00 2001 From: Andreas Date: Fri, 26 Aug 2022 08:37:37 +0200 Subject: [PATCH] Review changes --- .../eu/kanade/core/prefs/CheckboxState.kt | 55 +++++++++++++ .../components/ChangeCategoryDialog.kt | 78 +++---------------- .../components/DeleteLibraryMangaDialog.kt | 18 ++--- .../tachiyomi/ui/library/LibraryController.kt | 36 ++++----- .../tachiyomi/ui/library/LibraryPresenter.kt | 4 +- .../tachiyomi/ui/manga/MangaController.kt | 14 ++-- .../tachiyomi/ui/manga/MangaPresenter.kt | 12 ++- .../drawable/ic_chevron_left_black_24dp.xml | 9 --- .../ic_chevron_left_double_black_24dp.xml | 9 --- .../drawable/ic_chevron_right_black_24dp.xml | 9 --- .../ic_chevron_right_double_black_24dp.xml | 9 --- .../res/layout/download_custom_amount.xml | 47 ----------- 12 files changed, 113 insertions(+), 187 deletions(-) create mode 100644 app/src/main/java/eu/kanade/core/prefs/CheckboxState.kt delete mode 100644 app/src/main/res/drawable/ic_chevron_left_black_24dp.xml delete mode 100644 app/src/main/res/drawable/ic_chevron_left_double_black_24dp.xml delete mode 100644 app/src/main/res/drawable/ic_chevron_right_black_24dp.xml delete mode 100644 app/src/main/res/drawable/ic_chevron_right_double_black_24dp.xml delete mode 100644 app/src/main/res/layout/download_custom_amount.xml diff --git a/app/src/main/java/eu/kanade/core/prefs/CheckboxState.kt b/app/src/main/java/eu/kanade/core/prefs/CheckboxState.kt new file mode 100644 index 0000000000..64e1a5606a --- /dev/null +++ b/app/src/main/java/eu/kanade/core/prefs/CheckboxState.kt @@ -0,0 +1,55 @@ +package eu.kanade.core.prefs + +import androidx.compose.ui.state.ToggleableState + +sealed class CheckboxState(open val value: T) { + abstract fun next(): CheckboxState + + sealed class State(override val value: T) : CheckboxState(value) { + data class Checked(override val value: T) : State(value) + data class None(override val value: T) : State(value) + + val isChecked: Boolean + get() = this is Checked + + override fun next(): CheckboxState { + return when (this) { + is Checked -> None(value) + is None -> Checked(value) + } + } + } + sealed class TriState(override val value: T) : CheckboxState(value) { + data class Include(override val value: T) : TriState(value) + data class Exclude(override val value: T) : TriState(value) + data class None(override val value: T) : TriState(value) + + override fun next(): CheckboxState { + return when (this) { + is Exclude -> None(value) + is Include -> Exclude(value) + is None -> Include(value) + } + } + + fun asState(): ToggleableState { + return when (this) { + is Exclude -> ToggleableState.Indeterminate + is Include -> ToggleableState.On + is None -> ToggleableState.Off + } + } + } +} + +inline fun T.asCheckboxState(condition: (T) -> Boolean): CheckboxState.State { + return if (condition(this)) { + CheckboxState.State.Checked(this) + } else { + CheckboxState.State.None(this) + } +} + +inline fun List.mapAsCheckboxState(condition: (T) -> Boolean): List> { + return this.map { it.asCheckboxState(condition) } +} diff --git a/app/src/main/java/eu/kanade/presentation/components/ChangeCategoryDialog.kt b/app/src/main/java/eu/kanade/presentation/components/ChangeCategoryDialog.kt index 3aa9a5346e..6d90168dde 100644 --- a/app/src/main/java/eu/kanade/presentation/components/ChangeCategoryDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/components/ChangeCategoryDialog.kt @@ -16,78 +16,20 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource -import androidx.compose.ui.state.ToggleableState +import eu.kanade.core.prefs.CheckboxState import eu.kanade.domain.category.model.Category import eu.kanade.presentation.category.visualName import eu.kanade.presentation.util.horizontalPadding import eu.kanade.tachiyomi.R -sealed class Checkbox(open val value: T) { - abstract fun next(): Checkbox - - sealed class State(override val value: T) : Checkbox(value) { - data class Checked(override val value: T) : State(value) - data class None(override val value: T) : State(value) - - override fun next(): Checkbox { - return when (this) { - is Checked -> None(value) - is None -> Checked(value) - } - } - } - sealed class TriState(override val value: T) : Checkbox(value) { - data class Include(override val value: T) : TriState(value) - data class Exclude(override val value: T) : TriState(value) - data class None(override val value: T) : TriState(value) - - override fun next(): Checkbox { - return when (this) { - is Exclude -> None(value) - is Include -> Exclude(value) - is None -> Include(value) - } - } - - fun asState(): ToggleableState { - return when (this) { - is Exclude -> ToggleableState.Indeterminate - is Include -> ToggleableState.On - is None -> ToggleableState.Off - } - } - } -} - -@JvmName("ChangeCategoryDialogHelper") @Composable fun ChangeCategoryDialog( - categories: List, - initialSelection: List, - onDismissRequest: () -> Unit, - onEditCategories: () -> Unit, - onConfirm: (List) -> Unit, -) { - ChangeCategoryDialog( - categories = categories, - initialSelection = categories.map { - if (it.id in initialSelection) Checkbox.State.Checked(it) else Checkbox.State.None(it) - }, - onDismissRequest = onDismissRequest, - onEditCategories = onEditCategories, - onConfirm = { include, _ -> onConfirm(include.map { it }) }, - ) -} - -@Composable -fun ChangeCategoryDialog( - categories: List, - initialSelection: List>, + initialSelection: List>, onDismissRequest: () -> Unit, onEditCategories: () -> Unit, onConfirm: (List, List) -> Unit, ) { - if (categories.isEmpty()) { + if (initialSelection.isEmpty()) { AlertDialog( onDismissRequest = onDismissRequest, confirmButton = { @@ -128,12 +70,12 @@ fun ChangeCategoryDialog( onClick = { onDismissRequest() onConfirm( - selection.filter { it is Checkbox.State.Checked || it is Checkbox.TriState.Include }.map { it.value.id }, - selection.filter { it is Checkbox.TriState.Exclude }.map { it.value.id }, + selection.filter { it is CheckboxState.State.Checked || it is CheckboxState.TriState.Include }.map { it.value.id }, + selection.filter { it is CheckboxState.TriState.Exclude }.map { it.value.id }, ) }, ) { - Text(text = "Add") + Text(text = stringResource(id = R.string.action_add)) } } }, @@ -146,7 +88,7 @@ fun ChangeCategoryDialog( Row( verticalAlignment = Alignment.CenterVertically, ) { - val onCheckboxChange: (Checkbox) -> Unit = { + val onCheckboxChange: (CheckboxState) -> Unit = { val index = selection.indexOf(it) val mutableList = selection.toMutableList() mutableList.removeAt(index) @@ -154,15 +96,15 @@ fun ChangeCategoryDialog( selection = mutableList.toList() } when (checkbox) { - is Checkbox.TriState -> { + is CheckboxState.TriState -> { TriStateCheckbox( state = checkbox.asState(), onClick = { onCheckboxChange(checkbox) }, ) } - is Checkbox.State -> { + is CheckboxState.State -> { Checkbox( - checked = checkbox is Checkbox.State.Checked, + checked = checkbox.isChecked, onCheckedChange = { onCheckboxChange(checkbox) }, ) } diff --git a/app/src/main/java/eu/kanade/presentation/components/DeleteLibraryMangaDialog.kt b/app/src/main/java/eu/kanade/presentation/components/DeleteLibraryMangaDialog.kt index 1209cb21d0..946d619357 100644 --- a/app/src/main/java/eu/kanade/presentation/components/DeleteLibraryMangaDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/components/DeleteLibraryMangaDialog.kt @@ -13,7 +13,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.res.stringResource -import eu.kanade.presentation.components.Checkbox +import eu.kanade.core.prefs.CheckboxState import eu.kanade.tachiyomi.R @Composable @@ -24,10 +24,10 @@ fun DeleteLibraryMangaDialog( ) { var list by remember { mutableStateOf( - buildList> { - add(Checkbox.State.None(R.string.manga_from_library)) - if (containsLocalManga) { - add(Checkbox.State.None(R.string.downloaded_chapters)) + buildList> { + add(CheckboxState.State.None(R.string.manga_from_library)) + if (!containsLocalManga) { + add(CheckboxState.State.None(R.string.downloaded_chapters)) } }, ) @@ -44,8 +44,8 @@ fun DeleteLibraryMangaDialog( onClick = { onDismissRequest() onConfirm( - list[0] is Checkbox.State.Checked, - list.getOrElse(1) { Checkbox.State.None(0) } is Checkbox.State.Checked, + list[0].isChecked, + list.getOrElse(1) { CheckboxState.State.None(0) }.isChecked, ) }, ) { @@ -60,12 +60,12 @@ fun DeleteLibraryMangaDialog( list.forEach { state -> Row(verticalAlignment = Alignment.CenterVertically) { Checkbox( - checked = state is Checkbox.State.Checked, + checked = state.isChecked, onCheckedChange = { val index = list.indexOf(state) val mutableList = list.toMutableList() mutableList.removeAt(index) - mutableList.add(index, state.next() as Checkbox.State) + mutableList.add(index, state.next() as CheckboxState.State) list = mutableList.toList() }, ) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt index 25bda02580..ccc88f4426 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt @@ -8,10 +8,11 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.platform.LocalContext import com.bluelinelabs.conductor.ControllerChangeHandler import com.bluelinelabs.conductor.ControllerChangeType +import eu.kanade.core.prefs.CheckboxState +import eu.kanade.domain.manga.model.Manga import eu.kanade.domain.manga.model.isLocal import eu.kanade.domain.manga.model.toDbManga import eu.kanade.presentation.components.ChangeCategoryDialog -import eu.kanade.presentation.components.Checkbox import eu.kanade.presentation.library.LibraryScreen import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.models.toDomainManga @@ -67,22 +68,21 @@ class LibraryController( when (val dialog = presenter.dialog) { is LibraryPresenter.Dialog.ChangeCategory -> { ChangeCategoryDialog( - categories = dialog.categories, initialSelection = dialog.initialSelection, onDismissRequest = onDismissRequest, onEditCategories = { - router.popCurrentController() + presenter.clearSelection() router.pushController(CategoryController()) }, onConfirm = { include, exclude -> - presenter.setMangaCategories(dialog.manga, include, exclude) presenter.clearSelection() + presenter.setMangaCategories(dialog.manga, include, exclude) }, ) } is LibraryPresenter.Dialog.DeleteManga -> { DeleteLibraryMangaDialog( - containsLocalManga = dialog.manga.any { !it.isLocal() }, + containsLocalManga = dialog.manga.any(Manga::isLocal), onDismissRequest = onDismissRequest, onConfirm = { deleteManga, deleteChapter -> presenter.removeMangas(dialog.manga.map { it.toDbManga() }, deleteManga, deleteChapter) @@ -197,40 +197,40 @@ class LibraryController( private fun showMangaCategoriesDialog() { viewScope.launchIO { // Create a copy of selected manga - val manga = presenter.selection.mapNotNull { it.toDomainManga() }.toList() + val mangaList = presenter.selection.mapNotNull { it.toDomainManga() }.toList() // Hide the default category because it has a different behavior than the ones from db. val categories = presenter.categories.filter { it.id != 0L } // Get indexes of the common categories to preselect. - val common = presenter.getCommonCategories(manga) + val common = presenter.getCommonCategories(mangaList) // Get indexes of the mix categories to preselect. - val mix = presenter.getMixCategories(manga) + val mix = presenter.getMixCategories(mangaList) val preselected = categories.map { when (it) { - in common -> Checkbox.State.Checked(it) - in mix -> Checkbox.TriState.Exclude(it) - else -> Checkbox.State.None(it) + in common -> CheckboxState.State.Checked(it) + in mix -> CheckboxState.TriState.Exclude(it) + else -> CheckboxState.State.None(it) } } - presenter.dialog = LibraryPresenter.Dialog.ChangeCategory(manga, categories, preselected) + presenter.dialog = LibraryPresenter.Dialog.ChangeCategory(mangaList, preselected) } } private fun downloadUnreadChapters() { - val manga = presenter.selection.toList() - presenter.downloadUnreadChapters(manga.mapNotNull { it.toDomainManga() }) + val mangaList = presenter.selection.toList() + presenter.downloadUnreadChapters(mangaList.mapNotNull { it.toDomainManga() }) presenter.clearSelection() } private fun markReadStatus(read: Boolean) { - val manga = presenter.selection.toList() - presenter.markReadStatus(manga.mapNotNull { it.toDomainManga() }, read) + val mangaList = presenter.selection.toList() + presenter.markReadStatus(mangaList.mapNotNull { it.toDomainManga() }, read) presenter.clearSelection() } private fun showDeleteMangaDialog() { - val manga = presenter.selection.mapNotNull { it.toDomainManga() }.toList() - presenter.dialog = LibraryPresenter.Dialog.DeleteManga(manga) + val mangaList = presenter.selection.mapNotNull { it.toDomainManga() }.toList() + presenter.dialog = LibraryPresenter.Dialog.DeleteManga(mangaList) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt index 23b6dccbdd..c88ae23940 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt @@ -11,6 +11,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.res.stringResource import androidx.compose.ui.util.fastAny import com.jakewharton.rxrelay.BehaviorRelay +import eu.kanade.core.prefs.CheckboxState import eu.kanade.core.prefs.PreferenceMutableState import eu.kanade.core.util.asFlow import eu.kanade.core.util.asObservable @@ -28,7 +29,6 @@ import eu.kanade.domain.manga.model.MangaUpdate import eu.kanade.domain.manga.model.isLocal import eu.kanade.domain.track.interactor.GetTracks import eu.kanade.presentation.category.visualName -import eu.kanade.presentation.components.Checkbox import eu.kanade.presentation.library.LibraryState import eu.kanade.presentation.library.LibraryStateImpl import eu.kanade.presentation.library.components.LibraryToolbarTitle @@ -720,7 +720,7 @@ class LibraryPresenter( } sealed class Dialog { - data class ChangeCategory(val manga: List, val categories: List, val initialSelection: List>) : Dialog() + data class ChangeCategory(val manga: List, val initialSelection: List>) : Dialog() data class DeleteManga(val manga: List) : Dialog() } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt index 8b8f9a0257..694867de1c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt @@ -151,15 +151,13 @@ class MangaController : FullComposeController { when (val dialog = dialog) { is Dialog.ChangeCategory -> { ChangeCategoryDialog( - categories = dialog.categories, initialSelection = dialog.initialSelection, onDismissRequest = onDismissRequest, onEditCategories = { - router.popCurrentController() router.pushController(CategoryController()) }, - onConfirm = { - presenter.moveMangaToCategoriesAndAddToLibrary(dialog.manga, it) + onConfirm = { include, _ -> + presenter.moveMangaToCategoriesAndAddToLibrary(dialog.manga, include) }, ) } @@ -186,7 +184,13 @@ class MangaController : FullComposeController { is Dialog.DuplicateManga -> { DuplicateDialog( onDismissRequest = onDismissRequest, - onConfirm = { presenter.toggleFavorite({}, {}, false) }, + onConfirm = { + presenter.toggleFavorite( + onRemoved = {}, + onAdded = {}, + checkDuplicate = false, + ) + }, onOpenManga = { router.pushController(MangaController(dialog.duplicate.id)) }, duplicateFrom = presenter.getSourceOrStub(dialog.duplicate), ) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt index c6caa1eb0e..ab43f0bcb3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt @@ -4,6 +4,8 @@ import android.app.Application import android.content.Context import android.os.Bundle import androidx.compose.runtime.Immutable +import eu.kanade.core.prefs.CheckboxState +import eu.kanade.core.prefs.mapAsCheckboxState import eu.kanade.domain.category.interactor.GetCategories import eu.kanade.domain.category.interactor.SetMangaCategories import eu.kanade.domain.category.model.Category @@ -347,10 +349,16 @@ class MangaPresenter( val manga = state.manga presenterScope.launch { val categories = getCategories() + val selection = getMangaCategoryIds(manga) _state.update { state -> when (state) { MangaScreenState.Loading -> state - is MangaScreenState.Success -> state.copy(dialog = Dialog.ChangeCategory(manga, categories, getMangaCategoryIds(manga))) + is MangaScreenState.Success -> state.copy( + dialog = Dialog.ChangeCategory( + manga = manga, + initialSelection = categories.mapAsCheckboxState { it.id in selection }, + ), + ) } } } @@ -1026,7 +1034,7 @@ class MangaPresenter( } sealed class Dialog { - data class ChangeCategory(val manga: DomainManga, val categories: List, val initialSelection: List) : Dialog() + data class ChangeCategory(val manga: DomainManga, val initialSelection: List>) : Dialog() data class DeleteChapters(val chapters: List) : Dialog() data class DuplicateManga(val manga: DomainManga, val duplicate: DomainManga) : Dialog() data class DownloadCustomAmount(val max: Int) : Dialog() diff --git a/app/src/main/res/drawable/ic_chevron_left_black_24dp.xml b/app/src/main/res/drawable/ic_chevron_left_black_24dp.xml deleted file mode 100644 index 128189cdfc..0000000000 --- a/app/src/main/res/drawable/ic_chevron_left_black_24dp.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_chevron_left_double_black_24dp.xml b/app/src/main/res/drawable/ic_chevron_left_double_black_24dp.xml deleted file mode 100644 index 1543ca119e..0000000000 --- a/app/src/main/res/drawable/ic_chevron_left_double_black_24dp.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_chevron_right_black_24dp.xml b/app/src/main/res/drawable/ic_chevron_right_black_24dp.xml deleted file mode 100644 index edc833548d..0000000000 --- a/app/src/main/res/drawable/ic_chevron_right_black_24dp.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_chevron_right_double_black_24dp.xml b/app/src/main/res/drawable/ic_chevron_right_double_black_24dp.xml deleted file mode 100644 index f73270046d..0000000000 --- a/app/src/main/res/drawable/ic_chevron_right_double_black_24dp.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/layout/download_custom_amount.xml b/app/src/main/res/layout/download_custom_amount.xml deleted file mode 100644 index e147cf4f48..0000000000 --- a/app/src/main/res/layout/download_custom_amount.xml +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - -