chore: Refactor selection state management and improve performance across various screens (#1607)
* chore: Refactor selection state management and improve performance across various screens * **MigrateMangaScreen**: Refactor state management to use a `Set<Long>` of IDs for selection instead of a list of wrapper items. * **LibraryUpdateErrorScreen**: Simplify `onErrorSelected` signature by removing the unused `userSelected` parameter and clean up related UI components. * **Performance**: Use `remember(state.selection)` in `MigrateMangaScreen` for efficient selection status lookups. * **Code Quality**: Fix minor typos (e.g., `inbetweenItem` to `inBetweenItem`) and optimize imports. * Refactor selection logic to prevent redundant state updates * Move early exit checks for item selection status outside or to the beginning of state update blocks to avoid unnecessary recompositions. * Improve safety and correctness of item selection by returning early from state updates when an item index is not found. * Standardize selection checks across `HistoryScreenModel`, `LibraryUpdateErrorScreenModel`, `MigrateMangaScreenModel`, `UpdatesScreenModel`, and `MangaScreenModel`. * update selection when migration list got updated * Update state management to reset selection and loading status on fetch failure
This commit is contained in:
parent
bdf81596e9
commit
4c21f019c0
8 changed files with 141 additions and 140 deletions
|
|
@ -67,7 +67,7 @@ fun LibraryUpdateErrorScreen(
|
||||||
onInvertSelection: () -> Unit,
|
onInvertSelection: () -> Unit,
|
||||||
onErrorsDelete: () -> Unit,
|
onErrorsDelete: () -> Unit,
|
||||||
onErrorDelete: (Long) -> Unit,
|
onErrorDelete: (Long) -> Unit,
|
||||||
onErrorSelected: (LibraryUpdateErrorItem, Boolean, Boolean, Boolean) -> Unit,
|
onErrorSelected: (LibraryUpdateErrorItem, Boolean, Boolean) -> Unit,
|
||||||
navigateUp: () -> Unit,
|
navigateUp: () -> Unit,
|
||||||
) {
|
) {
|
||||||
BackHandler(enabled = state.selectionMode, onBack = { onSelectAll(false) })
|
BackHandler(enabled = state.selectionMode, onBack = { onSelectAll(false) })
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ import tachiyomi.presentation.core.util.selectedBackground
|
||||||
internal fun LazyListScope.libraryUpdateErrorUiItems(
|
internal fun LazyListScope.libraryUpdateErrorUiItems(
|
||||||
uiModels: List<LibraryUpdateErrorUiModel>,
|
uiModels: List<LibraryUpdateErrorUiModel>,
|
||||||
selectionMode: Boolean,
|
selectionMode: Boolean,
|
||||||
onErrorSelected: (LibraryUpdateErrorItem, Boolean, Boolean, Boolean) -> Unit,
|
onErrorSelected: (LibraryUpdateErrorItem, Boolean, Boolean) -> Unit,
|
||||||
onClick: (LibraryUpdateErrorItem) -> Unit,
|
onClick: (LibraryUpdateErrorItem) -> Unit,
|
||||||
onClickCover: (LibraryUpdateErrorItem) -> Unit,
|
onClickCover: (LibraryUpdateErrorItem) -> Unit,
|
||||||
onDelete: (Long) -> Unit,
|
onDelete: (Long) -> Unit,
|
||||||
|
|
@ -81,7 +81,6 @@ internal fun LazyListScope.libraryUpdateErrorUiItems(
|
||||||
selectionMode -> onErrorSelected(
|
selectionMode -> onErrorSelected(
|
||||||
libraryUpdateErrorItem,
|
libraryUpdateErrorItem,
|
||||||
!libraryUpdateErrorItem.selected,
|
!libraryUpdateErrorItem.selected,
|
||||||
true,
|
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -93,7 +92,6 @@ internal fun LazyListScope.libraryUpdateErrorUiItems(
|
||||||
libraryUpdateErrorItem,
|
libraryUpdateErrorItem,
|
||||||
!libraryUpdateErrorItem.selected,
|
!libraryUpdateErrorItem.selected,
|
||||||
true,
|
true,
|
||||||
true,
|
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
onClickCover = { onClickCover(libraryUpdateErrorItem) }.takeIf { !selectionMode },
|
onClickCover = { onClickCover(libraryUpdateErrorItem) }.takeIf { !selectionMode },
|
||||||
|
|
|
||||||
|
|
@ -128,11 +128,9 @@ data class MigrateMangaScreen(
|
||||||
// KMK -->
|
// KMK -->
|
||||||
bottomBar = {
|
bottomBar = {
|
||||||
MigrateMangaBottomBar(
|
MigrateMangaBottomBar(
|
||||||
selected = state.selection,
|
selectionMode = state.selectionMode,
|
||||||
onMultiMigrateClicked = {
|
onMultiMigrateClicked = {
|
||||||
val selection = state.selection
|
navigator.push(MigrationConfigScreen(state.selection))
|
||||||
.map { it.manga.id }
|
|
||||||
navigator.push(MigrationConfigScreen(selection))
|
|
||||||
},
|
},
|
||||||
enableScrollToTop = enableScrollToTop,
|
enableScrollToTop = enableScrollToTop,
|
||||||
enableScrollToBottom = enableScrollToBottom,
|
enableScrollToBottom = enableScrollToBottom,
|
||||||
|
|
@ -187,7 +185,7 @@ data class MigrateMangaScreen(
|
||||||
contentPadding: PaddingValues,
|
contentPadding: PaddingValues,
|
||||||
state: MigrateMangaScreenModel.State,
|
state: MigrateMangaScreenModel.State,
|
||||||
// KMK -->
|
// KMK -->
|
||||||
onMangaSelected: (MigrateMangaItem, Boolean, Boolean, Boolean) -> Unit,
|
onMangaSelected: (Manga, Boolean, Boolean) -> Unit,
|
||||||
// KMK <--
|
// KMK <--
|
||||||
onClickItem: (Manga) -> Unit,
|
onClickItem: (Manga) -> Unit,
|
||||||
onClickCover: (Manga) -> Unit,
|
onClickCover: (Manga) -> Unit,
|
||||||
|
|
@ -197,20 +195,23 @@ data class MigrateMangaScreen(
|
||||||
contentPadding = contentPadding,
|
contentPadding = contentPadding,
|
||||||
) {
|
) {
|
||||||
items(items = state.titles) { manga ->
|
items(items = state.titles) { manga ->
|
||||||
|
// KMK -->
|
||||||
|
val isSelected = manga.id in state.selection
|
||||||
|
// KMK <--
|
||||||
MigrateMangaItem(
|
MigrateMangaItem(
|
||||||
manga = manga.manga,
|
manga = manga,
|
||||||
isSelected = manga.selected,
|
isSelected = isSelected,
|
||||||
onClickItem = {
|
onClickItem = {
|
||||||
// KMK -->
|
// KMK -->
|
||||||
when {
|
when {
|
||||||
state.selectionMode -> onMangaSelected(manga, !manga.selected, true, false)
|
state.selectionMode -> onMangaSelected(manga, !isSelected, false)
|
||||||
// KMK <--
|
// KMK <--
|
||||||
else -> onClickItem(it)
|
else -> onClickItem(it)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onClickCover = onClickCover,
|
onClickCover = onClickCover,
|
||||||
// KMK -->
|
// KMK -->
|
||||||
onLongClick = { onMangaSelected(manga, !manga.selected, true, true) },
|
onLongClick = { onMangaSelected(manga, !isSelected, true) },
|
||||||
modifier = Modifier.animateItemFastScroll(),
|
modifier = Modifier.animateItemFastScroll(),
|
||||||
// KMK <--
|
// KMK <--
|
||||||
)
|
)
|
||||||
|
|
@ -293,7 +294,7 @@ data class MigrateMangaScreen(
|
||||||
@Composable
|
@Composable
|
||||||
private fun MigrateMangaBottomBar(
|
private fun MigrateMangaBottomBar(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
selected: List<MigrateMangaItem>,
|
selectionMode: Boolean,
|
||||||
onMultiMigrateClicked: () -> Unit,
|
onMultiMigrateClicked: () -> Unit,
|
||||||
enableScrollToTop: Boolean,
|
enableScrollToTop: Boolean,
|
||||||
enableScrollToBottom: Boolean,
|
enableScrollToBottom: Boolean,
|
||||||
|
|
@ -302,7 +303,7 @@ data class MigrateMangaScreen(
|
||||||
) {
|
) {
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
val animatedElevation by animateDpAsState(
|
val animatedElevation by animateDpAsState(
|
||||||
targetValue = if (selected.isNotEmpty()) 3.dp else 0.dp,
|
targetValue = if (selectionMode) 3.dp else 0.dp,
|
||||||
label = "elevation",
|
label = "elevation",
|
||||||
)
|
)
|
||||||
Surface(
|
Surface(
|
||||||
|
|
@ -350,7 +351,7 @@ data class MigrateMangaScreen(
|
||||||
toConfirm = confirm[1],
|
toConfirm = confirm[1],
|
||||||
onLongClick = { onLongClickItem(1) },
|
onLongClick = { onLongClickItem(1) },
|
||||||
onClick = onMultiMigrateClicked,
|
onClick = onMultiMigrateClicked,
|
||||||
enabled = selected.isNotEmpty(),
|
enabled = selectionMode,
|
||||||
)
|
)
|
||||||
Button(
|
Button(
|
||||||
title = stringResource(KMR.strings.action_scroll_to_bottom),
|
title = stringResource(KMR.strings.action_scroll_to_bottom),
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.ui.browse.migration.manga
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import cafe.adriel.voyager.core.model.StateScreenModel
|
import cafe.adriel.voyager.core.model.StateScreenModel
|
||||||
import cafe.adriel.voyager.core.model.screenModelScope
|
import cafe.adriel.voyager.core.model.screenModelScope
|
||||||
import eu.kanade.core.util.addOrRemove
|
|
||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
|
|
@ -17,6 +16,7 @@ import kotlinx.coroutines.flow.receiveAsFlow
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
|
import mihon.core.common.utils.mutate
|
||||||
import tachiyomi.core.common.util.system.logcat
|
import tachiyomi.core.common.util.system.logcat
|
||||||
import tachiyomi.domain.manga.interactor.GetFavorites
|
import tachiyomi.domain.manga.interactor.GetFavorites
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
|
|
@ -36,7 +36,6 @@ class MigrateMangaScreenModel(
|
||||||
// KMK -->
|
// KMK -->
|
||||||
// First and last selected index in list
|
// First and last selected index in list
|
||||||
private val selectedPositions: Array<Int> = arrayOf(-1, -1)
|
private val selectedPositions: Array<Int> = arrayOf(-1, -1)
|
||||||
private val selectedMangaIds: HashSet<Long> = HashSet()
|
|
||||||
// KMK <--
|
// KMK <--
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
|
@ -50,120 +49,133 @@ class MigrateMangaScreenModel(
|
||||||
logcat(LogPriority.ERROR, it)
|
logcat(LogPriority.ERROR, it)
|
||||||
_events.send(MigrationMangaEvent.FailedFetchingFavorites)
|
_events.send(MigrationMangaEvent.FailedFetchingFavorites)
|
||||||
mutableState.update { state ->
|
mutableState.update { state ->
|
||||||
state.copy(titleList = persistentListOf())
|
state.copy(
|
||||||
|
titleList = persistentListOf(),
|
||||||
|
// KMK -->
|
||||||
|
selection = emptySet(),
|
||||||
|
// KMK <--
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// KMK -->
|
|
||||||
.map { manga ->
|
|
||||||
toMigrationMangaScreenItems(manga)
|
|
||||||
}
|
|
||||||
// KMK <--
|
|
||||||
.map { manga ->
|
.map { manga ->
|
||||||
manga
|
manga
|
||||||
.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER) { it.manga.title })
|
.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER) { it.title })
|
||||||
.toImmutableList()
|
.toImmutableList()
|
||||||
}
|
}
|
||||||
.collectLatest { list ->
|
.collectLatest { list ->
|
||||||
mutableState.update { it.copy(titleList = list) }
|
// KMK -->
|
||||||
|
mutableState.update { state ->
|
||||||
|
val titleIds = list.map { it.id }.toSet()
|
||||||
|
val selection = state.selection.intersect(titleIds).toMutableSet()
|
||||||
|
updateSelectedPositions(list, selection)
|
||||||
|
state.copy(
|
||||||
|
titleList = list,
|
||||||
|
selection = selection,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// KMK <--
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// KMK -->
|
|
||||||
private fun toMigrationMangaScreenItems(mangas: List<Manga>): List<MigrateMangaItem> {
|
|
||||||
return mangas.map { manga ->
|
|
||||||
MigrateMangaItem(
|
|
||||||
manga = manga,
|
|
||||||
selected = manga.id in selectedMangaIds,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun toggleSelection(
|
fun toggleSelection(
|
||||||
item: MigrateMangaItem,
|
item: Manga,
|
||||||
|
// KMK -->
|
||||||
selected: Boolean,
|
selected: Boolean,
|
||||||
userSelected: Boolean = false,
|
|
||||||
fromLongPress: Boolean = false,
|
fromLongPress: Boolean = false,
|
||||||
) {
|
) {
|
||||||
mutableState.update { state ->
|
mutableState.update { state ->
|
||||||
val newItems = state.titles.toMutableList().apply {
|
if (item.id in state.selection == selected) return@update state
|
||||||
val selectedIndex = indexOfFirst { it.manga.id == item.manga.id }
|
val selectedIndex = state.titles.indexOfFirst { it.id == item.id }
|
||||||
if (selectedIndex < 0) return@apply
|
if (selectedIndex < 0) return@update state
|
||||||
|
|
||||||
val selectedItem = get(selectedIndex)
|
val selection = state.selection.mutate { list ->
|
||||||
if (selectedItem.selected == selected) return@apply
|
state.titles.run {
|
||||||
|
val firstSelection = list.isEmpty()
|
||||||
|
if (selected) list.add(item.id) else list.remove(item.id)
|
||||||
|
|
||||||
val firstSelection = none { it.selected }
|
if (selected && fromLongPress) {
|
||||||
set(selectedIndex, selectedItem.copy(selected = selected))
|
if (firstSelection) {
|
||||||
selectedMangaIds.addOrRemove(item.manga.id, selected)
|
|
||||||
|
|
||||||
if (selected && userSelected && fromLongPress) {
|
|
||||||
if (firstSelection) {
|
|
||||||
selectedPositions[0] = selectedIndex
|
|
||||||
selectedPositions[1] = selectedIndex
|
|
||||||
} else {
|
|
||||||
// Try to select the items in-between when possible
|
|
||||||
val range: IntRange
|
|
||||||
if (selectedIndex < selectedPositions[0]) {
|
|
||||||
range = selectedIndex + 1 until selectedPositions[0]
|
|
||||||
selectedPositions[0] = selectedIndex
|
selectedPositions[0] = selectedIndex
|
||||||
} else if (selectedIndex > selectedPositions[1]) {
|
|
||||||
range = (selectedPositions[1] + 1) until selectedIndex
|
|
||||||
selectedPositions[1] = selectedIndex
|
selectedPositions[1] = selectedIndex
|
||||||
} else {
|
} else {
|
||||||
// Just select itself
|
// Try to select the items in-between when possible
|
||||||
range = IntRange.EMPTY
|
val range: IntRange
|
||||||
}
|
if (selectedIndex < selectedPositions[0]) {
|
||||||
|
range = selectedIndex + 1 until selectedPositions[0]
|
||||||
|
selectedPositions[0] = selectedIndex
|
||||||
|
} else if (selectedIndex > selectedPositions[1]) {
|
||||||
|
range = (selectedPositions[1] + 1) until selectedIndex
|
||||||
|
selectedPositions[1] = selectedIndex
|
||||||
|
} else {
|
||||||
|
// Just select itself
|
||||||
|
range = IntRange.EMPTY
|
||||||
|
}
|
||||||
|
|
||||||
range.forEach {
|
range.forEach {
|
||||||
val inBetweenItem = get(it)
|
val inBetweenItem = get(it)
|
||||||
if (!inBetweenItem.selected) {
|
if (inBetweenItem.id !in list) {
|
||||||
selectedMangaIds.add(inBetweenItem.manga.id)
|
list.add(inBetweenItem.id)
|
||||||
set(it, inBetweenItem.copy(selected = true))
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else if (!fromLongPress) {
|
||||||
} else if (userSelected && !fromLongPress) {
|
if (!selected) {
|
||||||
if (!selected) {
|
if (selectedIndex == selectedPositions[0]) {
|
||||||
if (selectedIndex == selectedPositions[0]) {
|
selectedPositions[0] = indexOfFirst { it.id in list }
|
||||||
selectedPositions[0] = indexOfFirst { it.selected }
|
} else if (selectedIndex == selectedPositions[1]) {
|
||||||
} else if (selectedIndex == selectedPositions[1]) {
|
selectedPositions[1] = indexOfLast { it.id in list }
|
||||||
selectedPositions[1] = indexOfLast { it.selected }
|
}
|
||||||
}
|
} else {
|
||||||
} else {
|
if (selectedIndex < selectedPositions[0]) {
|
||||||
if (selectedIndex < selectedPositions[0]) {
|
selectedPositions[0] = selectedIndex
|
||||||
selectedPositions[0] = selectedIndex
|
} else if (selectedIndex > selectedPositions[1]) {
|
||||||
} else if (selectedIndex > selectedPositions[1]) {
|
selectedPositions[1] = selectedIndex
|
||||||
selectedPositions[1] = selectedIndex
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
state.copy(titleList = newItems.toImmutableList())
|
// KMK <--
|
||||||
|
state.copy(selection = selection)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// KMK -->
|
||||||
|
private fun updateSelectedPositions(titles: List<Manga>, selection: Set<Long>) {
|
||||||
|
if (selection.isEmpty()) {
|
||||||
|
selectedPositions[0] = -1
|
||||||
|
selectedPositions[1] = -1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedPositions[0] = titles.indexOfFirst { it.id in selection }
|
||||||
|
selectedPositions[1] = titles.indexOfLast { it.id in selection }
|
||||||
|
}
|
||||||
|
|
||||||
fun toggleAllSelection(selected: Boolean = true) {
|
fun toggleAllSelection(selected: Boolean = true) {
|
||||||
mutableState.update { state ->
|
mutableState.update { state ->
|
||||||
val newItems = state.titles.map {
|
val selection = if (selected) {
|
||||||
selectedMangaIds.addOrRemove(it.manga.id, selected)
|
state.titles.mapTo(mutableSetOf()) { it.id }
|
||||||
it.copy(selected = selected)
|
} else {
|
||||||
|
emptySet()
|
||||||
}
|
}
|
||||||
selectedPositions[0] = -1
|
selectedPositions[0] = -1
|
||||||
selectedPositions[1] = -1
|
selectedPositions[1] = -1
|
||||||
state.copy(titleList = newItems.toImmutableList())
|
state.copy(selection = selection)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun invertSelection() {
|
fun invertSelection() {
|
||||||
mutableState.update { state ->
|
mutableState.update { state ->
|
||||||
val newItems = state.titles.map {
|
val selection = state.selection.mutate { list ->
|
||||||
selectedMangaIds.addOrRemove(it.manga.id, !it.selected)
|
state.titles.forEach { item ->
|
||||||
it.copy(selected = !it.selected)
|
if (!list.remove(item.id)) list.add(item.id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
selectedPositions[0] = -1
|
selectedPositions[0] = -1
|
||||||
selectedPositions[1] = -1
|
selectedPositions[1] = -1
|
||||||
state.copy(titleList = newItems.toImmutableList())
|
state.copy(selection = selection)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// KMK <--
|
// KMK <--
|
||||||
|
|
@ -177,13 +189,11 @@ class MigrateMangaScreenModel(
|
||||||
@Immutable
|
@Immutable
|
||||||
data class State(
|
data class State(
|
||||||
val source: Source? = null,
|
val source: Source? = null,
|
||||||
private val titleList: ImmutableList<MigrateMangaItem>? = null,
|
val selection: Set<Long> = emptySet(),
|
||||||
|
private val titleList: ImmutableList<Manga>? = null,
|
||||||
) {
|
) {
|
||||||
// KMK -->
|
|
||||||
val selection = titles.filter { it.selected }
|
|
||||||
// KMK <--
|
|
||||||
|
|
||||||
val titles: ImmutableList<MigrateMangaItem>
|
val titles: ImmutableList<Manga>
|
||||||
get() = titleList ?: persistentListOf()
|
get() = titleList ?: persistentListOf()
|
||||||
|
|
||||||
val isLoading: Boolean
|
val isLoading: Boolean
|
||||||
|
|
@ -199,11 +209,3 @@ class MigrateMangaScreenModel(
|
||||||
sealed interface MigrationMangaEvent {
|
sealed interface MigrationMangaEvent {
|
||||||
data object FailedFetchingFavorites : MigrationMangaEvent
|
data object FailedFetchingFavorites : MigrationMangaEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
// KMK -->
|
|
||||||
@Immutable
|
|
||||||
data class MigrateMangaItem(
|
|
||||||
val manga: Manga,
|
|
||||||
val selected: Boolean,
|
|
||||||
)
|
|
||||||
// KMK <--
|
|
||||||
|
|
|
||||||
|
|
@ -298,14 +298,14 @@ class HistoryScreenModel(
|
||||||
selectionOptions: HistorySelectionOptions,
|
selectionOptions: HistorySelectionOptions,
|
||||||
) {
|
) {
|
||||||
val (selected, fromLongPress) = selectionOptions
|
val (selected, fromLongPress) = selectionOptions
|
||||||
if (item.chapterId in state.value.selection == selected) return
|
|
||||||
|
|
||||||
mutableState.update { state ->
|
mutableState.update { state ->
|
||||||
|
if (item.chapterId in state.selection == selected) return@update state
|
||||||
|
val selectedIndex = state.list.indexOfFirst { it.chapterId == item.chapterId }
|
||||||
|
if (selectedIndex < 0) return@update state
|
||||||
|
|
||||||
val selection = state.selection.mutate { list ->
|
val selection = state.selection.mutate { list ->
|
||||||
state.list.run {
|
state.list.run {
|
||||||
val selectedIndex = indexOfFirst { it.chapterId == item.chapterId }
|
|
||||||
if (selectedIndex < 0) return@run
|
|
||||||
|
|
||||||
val firstSelection = list.isEmpty()
|
val firstSelection = list.isEmpty()
|
||||||
if (selected) list.add(item.chapterId) else list.remove(item.chapterId)
|
if (selected) list.add(item.chapterId) else list.remove(item.chapterId)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -62,22 +62,20 @@ class LibraryUpdateErrorScreenModel(
|
||||||
fun toggleSelection(
|
fun toggleSelection(
|
||||||
item: LibraryUpdateErrorItem,
|
item: LibraryUpdateErrorItem,
|
||||||
selected: Boolean,
|
selected: Boolean,
|
||||||
userSelected: Boolean = false,
|
|
||||||
fromLongPress: Boolean = false,
|
fromLongPress: Boolean = false,
|
||||||
) {
|
) {
|
||||||
mutableState.update { state ->
|
mutableState.update { state ->
|
||||||
|
val selectedIndex = state.items.indexOfFirst { it.error.errorId == item.error.errorId }
|
||||||
|
if (selectedIndex < 0) return@update state
|
||||||
|
val selectedItem = state.items[selectedIndex]
|
||||||
|
if (selectedItem.selected == selected) return@update state
|
||||||
|
|
||||||
val newItems = state.items.toMutableList().apply {
|
val newItems = state.items.toMutableList().apply {
|
||||||
val selectedIndex = indexOfFirst { it.error.errorId == item.error.errorId }
|
|
||||||
if (selectedIndex < 0) return@apply
|
|
||||||
|
|
||||||
val selectedItem = get(selectedIndex)
|
|
||||||
if (selectedItem.selected == selected) return@apply
|
|
||||||
|
|
||||||
val firstSelection = none { it.selected }
|
val firstSelection = none { it.selected }
|
||||||
set(selectedIndex, selectedItem.copy(selected = selected))
|
set(selectedIndex, selectedItem.copy(selected = selected))
|
||||||
selectedErrorIds.addOrRemove(item.error.errorId, selected)
|
selectedErrorIds.addOrRemove(item.error.errorId, selected)
|
||||||
|
|
||||||
if (selected && userSelected && fromLongPress) {
|
if (selected && fromLongPress) {
|
||||||
if (firstSelection) {
|
if (firstSelection) {
|
||||||
selectedPositions[0] = selectedIndex
|
selectedPositions[0] = selectedIndex
|
||||||
selectedPositions[1] = selectedIndex
|
selectedPositions[1] = selectedIndex
|
||||||
|
|
@ -96,14 +94,14 @@ class LibraryUpdateErrorScreenModel(
|
||||||
}
|
}
|
||||||
|
|
||||||
range.forEach {
|
range.forEach {
|
||||||
val inbetweenItem = get(it)
|
val inBetweenItem = get(it)
|
||||||
if (!inbetweenItem.selected) {
|
if (!inBetweenItem.selected) {
|
||||||
selectedErrorIds.add(inbetweenItem.error.errorId)
|
selectedErrorIds.add(inBetweenItem.error.errorId)
|
||||||
set(it, inbetweenItem.copy(selected = true))
|
set(it, inBetweenItem.copy(selected = true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (userSelected && !fromLongPress) {
|
} else if (!fromLongPress) {
|
||||||
if (!selected) {
|
if (!selected) {
|
||||||
if (selectedIndex == selectedPositions[0]) {
|
if (selectedIndex == selectedPositions[0]) {
|
||||||
selectedPositions[0] = indexOfFirst { it.selected }
|
selectedPositions[0] = indexOfFirst { it.selected }
|
||||||
|
|
|
||||||
|
|
@ -555,8 +555,8 @@ class MangaScreenModel(
|
||||||
}
|
}
|
||||||
val vibrantColor = it.getBestColor() ?: return@launchIO
|
val vibrantColor = it.getBestColor() ?: return@launchIO
|
||||||
mangaCover.vibrantCoverColor = vibrantColor
|
mangaCover.vibrantCoverColor = vibrantColor
|
||||||
updateSuccessState {
|
updateSuccessState { state ->
|
||||||
it.copy(seedColor = Color(vibrantColor))
|
state.copy(seedColor = Color(vibrantColor))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1729,13 +1729,14 @@ class MangaScreenModel(
|
||||||
fromLongPress: Boolean = false,
|
fromLongPress: Boolean = false,
|
||||||
) {
|
) {
|
||||||
updateSuccessState { successState ->
|
updateSuccessState { successState ->
|
||||||
|
// KMK -->
|
||||||
|
val selectedIndex = successState.processedChapters.indexOfFirst { it.id == item.chapter.id }
|
||||||
|
if (selectedIndex < 0) return@updateSuccessState successState
|
||||||
|
val selectedItem = successState.processedChapters[selectedIndex]
|
||||||
|
if (selectedItem.selected == selected) return@updateSuccessState successState
|
||||||
|
// KMK <--
|
||||||
|
|
||||||
val newChapters = successState.processedChapters.toMutableList().apply {
|
val newChapters = successState.processedChapters.toMutableList().apply {
|
||||||
val selectedIndex = successState.processedChapters.indexOfFirst { it.id == item.chapter.id }
|
|
||||||
if (selectedIndex < 0) return@apply
|
|
||||||
|
|
||||||
val selectedItem = get(selectedIndex)
|
|
||||||
if ((selectedItem.selected && selected) || (!selectedItem.selected && !selected)) return@apply
|
|
||||||
|
|
||||||
val firstSelection = none { it.selected }
|
val firstSelection = none { it.selected }
|
||||||
set(selectedIndex, selectedItem.copy(selected = selected))
|
set(selectedIndex, selectedItem.copy(selected = selected))
|
||||||
selectedChapterIds.addOrRemove(item.id, selected)
|
selectedChapterIds.addOrRemove(item.id, selected)
|
||||||
|
|
@ -1759,10 +1760,10 @@ class MangaScreenModel(
|
||||||
}
|
}
|
||||||
|
|
||||||
range.forEach {
|
range.forEach {
|
||||||
val inbetweenItem = get(it)
|
val inBetweenItem = get(it)
|
||||||
if (!inbetweenItem.selected) {
|
if (!inBetweenItem.selected) {
|
||||||
selectedChapterIds.add(inbetweenItem.id)
|
selectedChapterIds.add(inBetweenItem.id)
|
||||||
set(it, inbetweenItem.copy(selected = true))
|
set(it, inBetweenItem.copy(selected = true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -379,13 +379,14 @@ class UpdatesScreenModel(
|
||||||
val (selected, userSelected, fromLongPress, isGroup, isExpanded) = selectionOptions
|
val (selected, userSelected, fromLongPress, isGroup, isExpanded) = selectionOptions
|
||||||
// KMK <--
|
// KMK <--
|
||||||
mutableState.update { state ->
|
mutableState.update { state ->
|
||||||
|
// KMK -->
|
||||||
|
val selectedIndex = state.items.indexOfFirst { it.update.chapterId == item.update.chapterId }
|
||||||
|
if (selectedIndex < 0) return@update state
|
||||||
|
val selectedItem = state.items[selectedIndex]
|
||||||
|
if (selectedItem.selected == selected) return@update state
|
||||||
|
// KMK <--
|
||||||
|
|
||||||
val newItems = state.items.toMutableList().apply {
|
val newItems = state.items.toMutableList().apply {
|
||||||
val selectedIndex = indexOfFirst { it.update.chapterId == item.update.chapterId }
|
|
||||||
if (selectedIndex < 0) return@apply
|
|
||||||
|
|
||||||
val selectedItem = get(selectedIndex)
|
|
||||||
if (selectedItem.selected == selected) return@apply
|
|
||||||
|
|
||||||
val firstSelection = none { it.selected }
|
val firstSelection = none { it.selected }
|
||||||
set(selectedIndex, selectedItem.copy(selected = selected))
|
set(selectedIndex, selectedItem.copy(selected = selected))
|
||||||
selectedChapterIds.addOrRemove(item.update.chapterId, selected)
|
selectedChapterIds.addOrRemove(item.update.chapterId, selected)
|
||||||
|
|
@ -428,10 +429,10 @@ class UpdatesScreenModel(
|
||||||
}
|
}
|
||||||
|
|
||||||
range.forEach {
|
range.forEach {
|
||||||
val inbetweenItem = get(it)
|
val inBetweenItem = get(it)
|
||||||
if (!inbetweenItem.selected) {
|
if (!inBetweenItem.selected) {
|
||||||
selectedChapterIds.add(inbetweenItem.update.chapterId)
|
selectedChapterIds.add(inBetweenItem.update.chapterId)
|
||||||
set(it, inbetweenItem.copy(selected = true))
|
set(it, inBetweenItem.copy(selected = true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue