From 9276382c12c5a9acc40fbb38ef07eada50915f59 Mon Sep 17 00:00:00 2001 From: Ahmad Ansori Palembani Date: Sun, 1 Dec 2024 08:11:33 +0700 Subject: [PATCH] refactor(library): Some adjustments - fetchLibrary -> forceUpdateEvent - getLibrary -> updateLibrary - updateManga -> updateLibrary - Add some todo notes - Remove old todo notes - Update UI on categories collapsed instead of relying on forceUpdateEvent - Remove unnecessary force UI update --- .../tachiyomi/ui/library/LibraryController.kt | 20 ++--- .../tachiyomi/ui/library/LibraryPresenter.kt | 86 ++++++++++--------- .../ui/library/display/LibraryCategoryView.kt | 10 +-- .../ui/library/filter/FilterBottomSheet.kt | 6 +- 4 files changed, 64 insertions(+), 58 deletions(-) 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 77a468109c..56092ddddd 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 @@ -558,7 +558,7 @@ open class LibraryController( } presenter.groupType = item shouldScrollToTop = true - presenter.getLibrary() + presenter.updateLibrary() true }.show() } @@ -1055,7 +1055,7 @@ open class LibraryController( if (type.isEnter) { binding.filterBottomSheet.filterBottomSheet.isVisible = true if (type == ControllerChangeType.POP_ENTER) { - presenter.getLibrary() + presenter.updateLibrary() isPoppingIn = true } DownloadJob.callListeners() @@ -1095,7 +1095,7 @@ open class LibraryController( if (!isBindingInitialized) return updateFilterSheetY() if (observeLater) { - presenter.getLibrary() + presenter.updateLibrary() } } @@ -1408,7 +1408,7 @@ open class LibraryController( private fun onRefresh() { showCategories(false) - presenter.getLibrary() + presenter.updateLibrary() destroyActionModeIfNeeded() } @@ -1432,14 +1432,14 @@ open class LibraryController( val isShowAllCategoriesSet = preferences.showAllCategories().get() if (!query.isNullOrBlank() && this.query.isBlank() && !isShowAllCategoriesSet) { presenter.forceShowAllCategories = preferences.showAllCategoriesWhenSearchingSingleCategory().get() - presenter.getLibrary() + presenter.updateLibrary() } else if (query.isNullOrBlank() && this.query.isNotBlank() && !isShowAllCategoriesSet) { if (!isSubClass) { preferences.showAllCategoriesWhenSearchingSingleCategory() .set(presenter.forceShowAllCategories) } presenter.forceShowAllCategories = false - presenter.getLibrary() + presenter.updateLibrary() } if (query != this.query && !query.isNullOrBlank()) { @@ -1641,7 +1641,7 @@ open class LibraryController( if (mangaId == null) { adapter.getHeaderPositions().forEach { adapter.notifyItemChanged(it) } } else { - presenter.updateManga() + presenter.updateLibrary() } } @@ -1820,7 +1820,7 @@ open class LibraryController( val category = (adapter.getItem(position) as? LibraryHeaderItem)?.category ?: return if (!category.isDynamic) { ManageCategoryDialog(category) { - presenter.getLibrary() + presenter.updateLibrary() }.showDialog(router) } } @@ -1913,7 +1913,7 @@ open class LibraryController( isGone = true setOnClickListener { presenter.forceShowAllCategories = !presenter.forceShowAllCategories - presenter.getLibrary() + presenter.updateLibrary() isSelected = presenter.forceShowAllCategories } val pad = 12.dpToPx @@ -2192,7 +2192,7 @@ open class LibraryController( private fun showChangeMangaCategoriesSheet() { val activity = activity ?: return selectedMangas.toList().moveCategories(activity) { - presenter.getLibrary() + presenter.updateLibrary() destroyActionModeIfNeeded() } } 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 b024ac77ad..c166f991e1 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 @@ -54,13 +54,11 @@ import kotlin.random.Random import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.receiveAsFlow -import kotlinx.coroutines.flow.shareIn import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext @@ -105,10 +103,7 @@ class LibraryPresenter( private val getTrack: GetTrack by injectLazy() private val getHistory: GetHistory by injectLazy() - private val _fetchLibrary: Channel = Channel(Channel.UNLIMITED) - val fetchLibrary = _fetchLibrary.receiveAsFlow() - .onStart { emit(Unit) } - .shareIn(presenterScope, SharingStarted.Lazily, 1) + private val forceUpdateEvent: Channel = Channel(Channel.UNLIMITED) private val context = preferences.context private val viewContext @@ -131,6 +126,8 @@ class LibraryPresenter( private var allCategories: List = emptyList() /** List of all manga to update the */ + // TODO: Store sectioned before flattening it out for "show all categories" + private var currentLibrary: Map> = mapOf() var libraryItems: List = emptyList() private var sectionedLibraryItems: MutableMap> = mutableMapOf() var currentCategory = -1 @@ -235,7 +232,7 @@ class LibraryPresenter( combine( getLibraryFlow(), - fetchLibrary, + emptyFlow(), // Placeholder flow for later usage ) { data, _ -> categories = data.categories allCategories = data.allCategories @@ -263,13 +260,6 @@ class LibraryPresenter( } } - /** Get favorited manga for library and sort and filter it */ - fun getLibrary() { - presenterScope.launch { - _fetchLibrary.send(Unit) - } - } - private suspend fun reorderCategories(categories: List) { val sortedCategories = categories.sortedBy { it.order } sortedCategories.forEachIndexed { i, category -> category.order = i } @@ -323,8 +313,7 @@ class LibraryPresenter( private suspend fun sectionLibrary(items: List, freshStart: Boolean = false) { libraryItems = items - val showAll = showAllCategories || !libraryIsGrouped || - categories.size <= 1 + val showAll = showAllCategories || !libraryIsGrouped || categories.size <= 1 sectionedLibraryItems = items.groupBy { it.header.category.id ?: 0 }.toMutableMap() if (!showAll && currentCategory == -1) { currentCategory = categories.find { @@ -760,6 +749,9 @@ class LibraryPresenter( preferences.librarySortingMode().changes(), preferences.librarySortingAscending().changes(), + + preferences.collapsedCategories().changes(), + preferences.collapsedDynamicCategories().changes(), ) { ItemPreferences( filterDownloaded = it[0] as Int, @@ -773,6 +765,8 @@ class LibraryPresenter( showAllCategories = it[8] as Boolean, sortingMode = it[9] as Int, sortAscending = it[10] as Boolean, + collapsedCategories = it[11] as Set, + collapsedDynamicCategories = it[12] as Set, ) } @@ -810,22 +804,24 @@ class LibraryPresenter( * If category id '-1' is not empty, it means the library not grouped by categories */ private fun getLibraryFlow(): Flow { - return combine( + val libraryItemFlow = combine( getCategories.subscribe(), getLibraryManga.subscribe(), getPreferencesFlow(), - preferences.removeArticles().changes(), - fetchLibrary - ) { allCategories, libraryMangaList, prefs, removeArticles, _ -> - groupType = prefs.groupType + forceUpdateEvent.receiveAsFlow(), + ) { allCategories, libraryMangaList, prefs, _ -> + this.groupType = prefs.groupType + this.allCategories = allCategories - val (items, categories, hiddenItems) = if (groupType <= BY_DEFAULT || !libraryIsGrouped) { + // FIXME: Should return Map where Int is category id + if (groupType <= BY_DEFAULT || !libraryIsGrouped) { getLibraryItems( - allCategories, + allCategories, // FIXME: Don't depends on allCategories libraryMangaList, prefs.sortingMode, prefs.sortAscending, prefs.showAllCategories, + prefs.collapsedCategories, ) } else { getDynamicLibraryItems( @@ -833,8 +829,16 @@ class LibraryPresenter( prefs.sortingMode, prefs.sortAscending, groupType, + prefs.collapsedDynamicCategories, ) } + } + + return combine( + libraryItemFlow, + preferences.removeArticles().changes(), + ) { libraryItems, removeArticles -> + val (items, categories, hiddenItems) = libraryItems LibraryData( categories = categories, @@ -852,6 +856,7 @@ class LibraryPresenter( sortingMode: Int, isAscending: Boolean, showAll: Boolean, + collapsedCategories: Set, ): Triple, List, List> { val categories = allCategories.toMutableList() val hiddenItems = mutableListOf() @@ -874,6 +879,11 @@ class LibraryPresenter( } + (-1 to catItemAll) + (0 to LibraryHeaderItem({ categories.getOrDefault(0) }, 0)) ).toMap() + // TODO + val map = libraryManga.groupBy { + categories.getOrDefault(it.category) + } + val items = if (libraryIsGrouped) { libraryManga } else { @@ -893,16 +903,14 @@ class LibraryPresenter( val categoriesHidden = if (forceShowAllCategories || controllerIsSubClass) { emptySet() } else { - preferences.collapsedCategories().get().mapNotNull { it.toIntOrNull() }.toSet() + collapsedCategories.mapNotNull { it.toIntOrNull() }.toSet() } if (categorySet.contains(0)) categories.add(0, createDefaultCategory()) if (libraryIsGrouped) { categories.forEach { category -> val catId = category.id ?: return@forEach - if (catId > 0 && !categorySet.contains(catId) && - (catId !in categoriesHidden || !showAll) - ) { + if (catId > 0 && !categorySet.contains(catId) && (catId !in categoriesHidden || !showAll)) { val headerItem = headerItems[catId] if (headerItem != null) { items.add( @@ -955,6 +963,7 @@ class LibraryPresenter( sortingMode: Int, isAscending: Boolean, groupType: Int, + collapsedDynamicCategories: Set, ): Triple, List, List> { val tagItems: MutableMap = mutableMapOf() @@ -1057,7 +1066,7 @@ class LibraryPresenter( val hiddenDynamics = if (controllerIsSubClass) { emptySet() } else { - preferences.collapsedDynamicCategories().get() + collapsedDynamicCategories } val headers = tagItems.map { item -> Category.createCustom( @@ -1213,7 +1222,6 @@ class LibraryPresenter( .mapNotNull { if (it.id != null) MangaUpdate(it.id!!, favorite = false) else null } withIOContext { updateManga.awaitAll(mangaToDelete) } - getLibrary() } } @@ -1236,8 +1244,11 @@ class LibraryPresenter( } } - /** Called when Library Service updates a manga, update the item as well */ - fun updateManga() = getLibrary() + /** Force update the library */ + fun updateLibrary() = presenterScope.launch { + forceUpdateEvent.send(Unit) + } + /** Undo the removal of the manga once in library */ fun reAddMangas(mangas: List) { @@ -1247,12 +1258,12 @@ class LibraryPresenter( withIOContext { updateManga.awaitAll(mangaToAdd) } (view as? FilteredLibraryController)?.updateStatsPage() - getLibrary() } } /** Returns first unread chapter of a manga */ fun getFirstUnread(manga: Manga): Chapter? { + // FIXME: Don't do blocking val chapters = runBlocking { getChapter.awaitAll(manga) } return ChapterSort(manga, chapterFilter, preferences).getNextUnreadChapter(chapters, false) } @@ -1304,7 +1315,6 @@ class LibraryPresenter( } } - // TODO: Use SQLDelight /** Shift a manga's category via drag & drop */ fun moveMangaToCategory( manga: LibraryManga, @@ -1350,7 +1360,6 @@ class LibraryPresenter( ) } } - getLibrary() } } @@ -1385,7 +1394,6 @@ class LibraryPresenter( } preferences.collapsedDynamicCategories().set(categoriesHidden) } - getLibrary() } private fun getDynamicCategoryName(category: Category): String = @@ -1416,7 +1424,6 @@ class LibraryPresenter( } } } - getLibrary() } fun allCategoriesExpanded(): Boolean { @@ -1458,7 +1465,6 @@ class LibraryPresenter( mapMangaChapters[manga] = chapters } - getLibrary() } return mapMangaChapters } @@ -1474,7 +1480,6 @@ class LibraryPresenter( } }.flatten() updateChapter.awaitAll(updates) - getLibrary() } } @@ -1654,6 +1659,9 @@ class LibraryPresenter( val sortingMode: Int, val sortAscending: Boolean, + + val collapsedCategories: Set, + val collapsedDynamicCategories: Set, ) data class LibraryData( diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/display/LibraryCategoryView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/display/LibraryCategoryView.kt index b409856977..0dc927b9e0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/display/LibraryCategoryView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/display/LibraryCategoryView.kt @@ -2,16 +2,14 @@ package eu.kanade.tachiyomi.ui.library.display import android.content.Context import android.util.AttributeSet -import eu.kanade.tachiyomi.R -import yokai.i18n.MR -import yokai.util.lang.getString -import dev.icerock.moko.resources.compose.stringResource import eu.kanade.tachiyomi.databinding.LibraryCategoryLayoutBinding import eu.kanade.tachiyomi.util.bindToPreference import eu.kanade.tachiyomi.util.lang.withSubtitle import eu.kanade.tachiyomi.util.system.toInt import eu.kanade.tachiyomi.widget.BaseLibraryDisplayView import kotlin.math.min +import yokai.i18n.MR +import yokai.util.lang.getString class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : BaseLibraryDisplayView(context, attrs) { @@ -20,7 +18,7 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att override fun initGeneralPreferences() { with(binding) { showAll.bindToPreference(preferences.showAllCategories()) { - controller?.presenter?.getLibrary() + controller?.presenter?.updateLibrary() binding.categoryShow.isEnabled = it } categoryShow.isEnabled = showAll.isChecked @@ -30,7 +28,7 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att dynamicToBottom.text = context.getString(MR.strings.move_dynamic_to_bottom) .withSubtitle(context, MR.strings.when_grouping_by_sources_tags) dynamicToBottom.bindToPreference(preferences.collapsedDynamicAtBottom()) { - controller?.presenter?.getLibrary() + controller?.presenter?.updateLibrary() } showEmptyCatsFiltering.bindToPreference(preferences.showEmptyCategoriesWhileFiltering()) { controller?.presenter?.requestFilterUpdate() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/filter/FilterBottomSheet.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/filter/FilterBottomSheet.kt index dbf17c3c49..9950858541 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/filter/FilterBottomSheet.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/filter/FilterBottomSheet.kt @@ -36,6 +36,8 @@ import eu.kanade.tachiyomi.util.view.isCollapsed import eu.kanade.tachiyomi.util.view.isExpanded import eu.kanade.tachiyomi.util.view.isHidden import eu.kanade.tachiyomi.util.view.setText +import kotlin.math.max +import kotlin.math.roundToInt import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.flow.drop @@ -48,8 +50,6 @@ import uy.kohesive.injekt.api.get import uy.kohesive.injekt.injectLazy import yokai.i18n.MR import yokai.util.lang.getString -import kotlin.math.max -import kotlin.math.roundToInt class FilterBottomSheet @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : LinearLayout(context, attrs), @@ -637,7 +637,7 @@ class FilterBottomSheet @JvmOverloads constructor(context: Context, attrs: Attri SeriesType('m', MR.strings.series_type), Bookmarked('b', MR.strings.bookmarked), Tracked('t', MR.strings.tracking), - ContentType('s', MR.strings.content_type); + ContentType('s', MR.strings.content_type) ; companion object {