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
This commit is contained in:
Ahmad Ansori Palembani 2024-12-01 08:11:33 +07:00
parent 598c4918f1
commit 9276382c12
Signed by: null2264
GPG key ID: BA64F8B60AF3EFB6
4 changed files with 64 additions and 58 deletions

View file

@ -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()
}
}

View file

@ -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<Unit> = Channel(Channel.UNLIMITED)
val fetchLibrary = _fetchLibrary.receiveAsFlow()
.onStart { emit(Unit) }
.shareIn(presenterScope, SharingStarted.Lazily, 1)
private val forceUpdateEvent: Channel<Unit> = Channel(Channel.UNLIMITED)
private val context = preferences.context
private val viewContext
@ -131,6 +126,8 @@ class LibraryPresenter(
private var allCategories: List<Category> = emptyList()
/** List of all manga to update the */
// TODO: Store sectioned before flattening it out for "show all categories"
private var currentLibrary: Map<Category, List<LibraryItem>> = mapOf()
var libraryItems: List<LibraryItem> = emptyList()
private var sectionedLibraryItems: MutableMap<Int, List<LibraryItem>> = mutableMapOf()
var currentCategory = -1
@ -235,7 +232,7 @@ class LibraryPresenter(
combine(
getLibraryFlow(),
fetchLibrary,
emptyFlow<Unit>(), // 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<Category>) {
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<LibraryItem>, 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<String>,
collapsedDynamicCategories = it[12] as Set<String>,
)
}
@ -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<LibraryData> {
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<Int, LibraryItem> 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<String>,
): Triple<List<LibraryItem>, List<Category>, List<LibraryItem>> {
val categories = allCategories.toMutableList()
val hiddenItems = mutableListOf<LibraryItem>()
@ -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<String>,
): Triple<List<LibraryItem>, List<Category>, List<LibraryItem>> {
val tagItems: MutableMap<String, LibraryHeaderItem> = 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<Manga>) {
@ -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<String>,
val collapsedDynamicCategories: Set<String>,
)
data class LibraryData(

View file

@ -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<LibraryCategoryLayoutBinding>(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()

View file

@ -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 {