Fix categories and sources reordering

pull/478/head
Koitharu 3 years ago
parent f9609edea5
commit fff9df9609
Signed by: Koitharu
GPG Key ID: 676DEE768C17A9D7

@ -67,7 +67,7 @@ class FavouriteCategoriesActivity :
attachToRecyclerView(viewBinding.recyclerView) attachToRecyclerView(viewBinding.recyclerView)
} }
viewModel.categories.observe(this, ::onCategoriesChanged) viewModel.content.observe(this, ::onCategoriesChanged)
viewModel.onError.observeEvent(this, SnackbarErrorObserver(viewBinding.recyclerView, null)) viewModel.onError.observeEvent(this, SnackbarErrorObserver(viewBinding.recyclerView, null))
} }

@ -1,21 +1,20 @@
package org.koitharu.kotatsu.favourites.ui.categories package org.koitharu.kotatsu.favourites.ui.categories
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.plus
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.FavouriteCategory import org.koitharu.kotatsu.core.model.FavouriteCategory
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.ui.BaseViewModel import org.koitharu.kotatsu.core.ui.BaseViewModel
import org.koitharu.kotatsu.core.util.ext.requireValue import org.koitharu.kotatsu.core.util.ext.requireValue
import org.koitharu.kotatsu.favourites.domain.FavouritesRepository import org.koitharu.kotatsu.favourites.domain.FavouritesRepository
import org.koitharu.kotatsu.favourites.domain.model.Cover
import org.koitharu.kotatsu.favourites.ui.categories.adapter.CategoryListModel import org.koitharu.kotatsu.favourites.ui.categories.adapter.CategoryListModel
import org.koitharu.kotatsu.list.ui.model.EmptyState import org.koitharu.kotatsu.list.ui.model.EmptyState
import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.list.ui.model.LoadingState import org.koitharu.kotatsu.list.ui.model.LoadingState
import org.koitharu.kotatsu.parsers.util.move import org.koitharu.kotatsu.parsers.util.move
import javax.inject.Inject import javax.inject.Inject
@ -28,26 +27,17 @@ class FavouritesCategoriesViewModel @Inject constructor(
private var reorderJob: Job? = null private var reorderJob: Job? = null
val categories = repository.observeCategoriesWithCovers() val content = MutableStateFlow<List<ListModel>>(listOf(LoadingState))
.map { list ->
list.map { (category, covers) -> init {
CategoryListModel( launchJob(Dispatchers.Default) {
mangaCount = covers.size, repository.observeCategoriesWithCovers()
covers = covers.take(3), .collectLatest {
category = category, reorderJob?.join()
isTrackerEnabled = settings.isTrackerEnabled && AppSettings.TRACK_FAVOURITES in settings.trackSources, updateContent(it)
) }
}.ifEmpty { }
listOf(
EmptyState(
icon = R.drawable.ic_empty_favourites,
textPrimary = R.string.text_empty_holder_primary,
textSecondary = R.string.empty_favourite_categories,
actionStringRes = 0,
),
)
} }
}.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, listOf(LoadingState))
fun deleteCategories(ids: Set<Long>) { fun deleteCategories(ids: Set<Long>) {
launchJob(Dispatchers.Default) { launchJob(Dispatchers.Default) {
@ -59,14 +49,15 @@ class FavouritesCategoriesViewModel @Inject constructor(
settings.isAllFavouritesVisible = isVisible settings.isAllFavouritesVisible = isVisible
} }
fun isEmpty(): Boolean = categories.value.none { it is CategoryListModel } fun isEmpty(): Boolean = content.value.none { it is CategoryListModel }
fun reorderCategories(oldPos: Int, newPos: Int) { fun reorderCategories(oldPos: Int, newPos: Int) {
val prevJob = reorderJob val prevJob = reorderJob
reorderJob = launchJob(Dispatchers.Default) { reorderJob = launchJob(Dispatchers.Default) {
prevJob?.join() prevJob?.join()
val snapshot = categories.requireValue().toMutableList() val snapshot = content.requireValue().toMutableList()
snapshot.move(oldPos, newPos) snapshot.move(oldPos, newPos)
content.value = snapshot
val ids = snapshot.mapNotNullTo(ArrayList(snapshot.size)) { val ids = snapshot.mapNotNullTo(ArrayList(snapshot.size)) {
(it as? CategoryListModel)?.category?.id (it as? CategoryListModel)?.category?.id
} }
@ -83,9 +74,29 @@ class FavouritesCategoriesViewModel @Inject constructor(
} }
fun getCategories(ids: Set<Long>): ArrayList<FavouriteCategory> { fun getCategories(ids: Set<Long>): ArrayList<FavouriteCategory> {
val items = categories.requireValue() val items = content.requireValue()
return items.mapNotNullTo(ArrayList(ids.size)) { item -> return items.mapNotNullTo(ArrayList(ids.size)) { item ->
(item as? CategoryListModel)?.category?.takeIf { it.id in ids } (item as? CategoryListModel)?.category?.takeIf { it.id in ids }
} }
} }
private fun updateContent(categories: Map<FavouriteCategory, List<Cover>>) {
content.value = categories.map { (category, covers) ->
CategoryListModel(
mangaCount = covers.size,
covers = covers.take(3),
category = category,
isTrackerEnabled = settings.isTrackerEnabled && AppSettings.TRACK_FAVOURITES in settings.trackSources,
)
}.ifEmpty {
listOf(
EmptyState(
icon = R.drawable.ic_empty_favourites,
textPrimary = R.string.text_empty_holder_primary,
textSecondary = R.string.empty_favourite_categories,
actionStringRes = 0,
),
)
}
}
} }

@ -2,17 +2,12 @@ package org.koitharu.kotatsu.settings.sources
import androidx.annotation.CheckResult import androidx.annotation.CheckResult
import androidx.core.os.LocaleListCompat import androidx.core.os.LocaleListCompat
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.cancelAndJoin
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.plus
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.getLocaleTitle import org.koitharu.kotatsu.core.model.getLocaleTitle
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
@ -46,8 +41,12 @@ class SourcesManageViewModel @Inject constructor(
private val expandedGroups = MutableStateFlow(emptySet<String?>()) private val expandedGroups = MutableStateFlow(emptySet<String?>())
private var searchQuery = MutableStateFlow<String?>(null) private var searchQuery = MutableStateFlow<String?>(null)
private var reorderJob: Job? = null private var reorderJob: Job? = null
val content = MutableStateFlow<List<SourceConfigItem>>(emptyList())
val onActionDone = MutableEventFlow<ReversibleAction>()
val content = combine( init {
launchJob(Dispatchers.Default) {
combine(
repository.observeEnabledSources(), repository.observeEnabledSources(),
expandedGroups, expandedGroups,
searchQuery, searchQuery,
@ -55,23 +54,26 @@ class SourcesManageViewModel @Inject constructor(
settings.observeAsFlow(AppSettings.KEY_DISABLE_NSFW) { isNsfwContentDisabled }, settings.observeAsFlow(AppSettings.KEY_DISABLE_NSFW) { isNsfwContentDisabled },
) { sources, groups, query, tip, noNsfw -> ) { sources, groups, query, tip, noNsfw ->
buildList(sources, groups, query, tip, noNsfw) buildList(sources, groups, query, tip, noNsfw)
}.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, emptyList()) }.collectLatest {
reorderJob?.join()
val onActionDone = MutableEventFlow<ReversibleAction>() content.value = it
}
}
}
fun reorderSources(oldPos: Int, newPos: Int) { fun reorderSources(oldPos: Int, newPos: Int) {
val snapshot = content.value.toMutableList() val snapshot = content.value.toMutableList()
val prevJob = reorderJob val prevJob = reorderJob
reorderJob = launchJob(Dispatchers.Default) { reorderJob = launchJob(Dispatchers.Default) {
prevJob?.cancelAndJoin()
if ((snapshot[oldPos] as? SourceConfigItem.SourceItem)?.isDraggable != true) { if ((snapshot[oldPos] as? SourceConfigItem.SourceItem)?.isDraggable != true) {
return@launchJob return@launchJob
} }
if ((snapshot[newPos] as? SourceConfigItem.SourceItem)?.isDraggable != true) { if ((snapshot[newPos] as? SourceConfigItem.SourceItem)?.isDraggable != true) {
return@launchJob return@launchJob
} }
delay(100)
snapshot.move(oldPos, newPos) snapshot.move(oldPos, newPos)
content.value = snapshot
prevJob?.join()
val newSourcesList = snapshot.mapNotNull { x -> val newSourcesList = snapshot.mapNotNull { x ->
if (x is SourceConfigItem.SourceItem && x.isDraggable) { if (x is SourceConfigItem.SourceItem && x.isDraggable) {
x.source x.source

Loading…
Cancel
Save