MangaScreen: Save selection state (#7560)

This commit is contained in:
Ivan Iskandar 2022-07-19 03:42:46 +07:00 committed by GitHub
parent 473dc688f0
commit 00519e3b93
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 145 additions and 120 deletions

View File

@ -38,8 +38,6 @@ import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.snapshots.SnapshotStateList
import androidx.compose.runtime.toMutableStateList
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.hapticfeedback.HapticFeedbackType import androidx.compose.ui.hapticfeedback.HapticFeedbackType
@ -106,6 +104,11 @@ fun MangaScreen(
onMultiMarkAsReadClicked: (List<Chapter>, markAsRead: Boolean) -> Unit, onMultiMarkAsReadClicked: (List<Chapter>, markAsRead: Boolean) -> Unit,
onMarkPreviousAsReadClicked: (Chapter) -> Unit, onMarkPreviousAsReadClicked: (Chapter) -> Unit,
onMultiDeleteClicked: (List<Chapter>) -> Unit, onMultiDeleteClicked: (List<Chapter>) -> Unit,
// Chapter selection
onChapterSelected: (ChapterItem, Boolean, Boolean, Boolean) -> Unit,
onAllChapterSelected: (Boolean) -> Unit,
onInvertSelection: () -> Unit,
) { ) {
if (windowWidthSizeClass == WindowWidthSizeClass.Compact) { if (windowWidthSizeClass == WindowWidthSizeClass.Compact) {
MangaScreenSmallImpl( MangaScreenSmallImpl(
@ -131,6 +134,9 @@ fun MangaScreen(
onMultiMarkAsReadClicked = onMultiMarkAsReadClicked, onMultiMarkAsReadClicked = onMultiMarkAsReadClicked,
onMarkPreviousAsReadClicked = onMarkPreviousAsReadClicked, onMarkPreviousAsReadClicked = onMarkPreviousAsReadClicked,
onMultiDeleteClicked = onMultiDeleteClicked, onMultiDeleteClicked = onMultiDeleteClicked,
onChapterSelected = onChapterSelected,
onAllChapterSelected = onAllChapterSelected,
onInvertSelection = onInvertSelection,
) )
} else { } else {
MangaScreenLargeImpl( MangaScreenLargeImpl(
@ -157,6 +163,9 @@ fun MangaScreen(
onMultiMarkAsReadClicked = onMultiMarkAsReadClicked, onMultiMarkAsReadClicked = onMultiMarkAsReadClicked,
onMarkPreviousAsReadClicked = onMarkPreviousAsReadClicked, onMarkPreviousAsReadClicked = onMarkPreviousAsReadClicked,
onMultiDeleteClicked = onMultiDeleteClicked, onMultiDeleteClicked = onMultiDeleteClicked,
onChapterSelected = onChapterSelected,
onAllChapterSelected = onAllChapterSelected,
onInvertSelection = onInvertSelection,
) )
} }
} }
@ -191,18 +200,21 @@ private fun MangaScreenSmallImpl(
onMultiMarkAsReadClicked: (List<Chapter>, markAsRead: Boolean) -> Unit, onMultiMarkAsReadClicked: (List<Chapter>, markAsRead: Boolean) -> Unit,
onMarkPreviousAsReadClicked: (Chapter) -> Unit, onMarkPreviousAsReadClicked: (Chapter) -> Unit,
onMultiDeleteClicked: (List<Chapter>) -> Unit, onMultiDeleteClicked: (List<Chapter>) -> Unit,
// Chapter selection
onChapterSelected: (ChapterItem, Boolean, Boolean, Boolean) -> Unit,
onAllChapterSelected: (Boolean) -> Unit,
onInvertSelection: () -> Unit,
) { ) {
val layoutDirection = LocalLayoutDirection.current val layoutDirection = LocalLayoutDirection.current
val chapterListState = rememberLazyListState() val chapterListState = rememberLazyListState()
val insetPadding = WindowInsets.systemBars.only(WindowInsetsSides.Horizontal).asPaddingValues() val insetPadding = WindowInsets.systemBars.only(WindowInsetsSides.Horizontal).asPaddingValues()
val chapters = remember(state) { state.processedChapters.toList() } val chapters = remember(state) { state.processedChapters.toList() }
val selected = remember(chapters) { emptyList<ChapterItem>().toMutableStateList() }
val selectedPositions = remember(chapters) { arrayOf(-1, -1) } // first and last selected index in list
val internalOnBackPressed = { val internalOnBackPressed = {
if (selected.isNotEmpty()) { if (chapters.any { it.selected }) {
selected.clear() onAllChapterSelected(false)
} else { } else {
onBackClicked() onBackClicked()
} }
@ -236,21 +248,14 @@ private fun MangaScreenSmallImpl(
onDownloadClicked = onDownloadActionClicked, onDownloadClicked = onDownloadActionClicked,
onEditCategoryClicked = onEditCategoryClicked, onEditCategoryClicked = onEditCategoryClicked,
onMigrateClicked = onMigrateClicked, onMigrateClicked = onMigrateClicked,
actionModeCounter = selected.size, actionModeCounter = chapters.count { it.selected },
onSelectAll = { onSelectAll = { onAllChapterSelected(true) },
selected.clear() onInvertSelection = { onInvertSelection() },
selected.addAll(chapters)
},
onInvertSelection = {
val toSelect = chapters - selected
selected.clear()
selected.addAll(toSelect)
},
) )
}, },
bottomBar = { bottomBar = {
SharedMangaBottomActionMenu( SharedMangaBottomActionMenu(
selected = selected, selected = chapters.filter { it.selected },
onMultiBookmarkClicked = onMultiBookmarkClicked, onMultiBookmarkClicked = onMultiBookmarkClicked,
onMultiMarkAsReadClicked = onMultiMarkAsReadClicked, onMultiMarkAsReadClicked = onMultiMarkAsReadClicked,
onMarkPreviousAsReadClicked = onMarkPreviousAsReadClicked, onMarkPreviousAsReadClicked = onMarkPreviousAsReadClicked,
@ -262,7 +267,7 @@ private fun MangaScreenSmallImpl(
snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, snackbarHost = { SnackbarHost(hostState = snackbarHostState) },
floatingActionButton = { floatingActionButton = {
AnimatedVisibility( AnimatedVisibility(
visible = chapters.any { !it.chapter.read } && selected.isEmpty(), visible = chapters.any { !it.chapter.read } && chapters.none { it.selected },
enter = fadeIn(), enter = fadeIn(),
exit = fadeOut(), exit = fadeOut(),
) { ) {
@ -370,10 +375,9 @@ private fun MangaScreenSmallImpl(
sharedChapterItems( sharedChapterItems(
chapters = chapters, chapters = chapters,
selected = selected,
selectedPositions = selectedPositions,
onChapterClicked = onChapterClicked, onChapterClicked = onChapterClicked,
onDownloadChapter = onDownloadChapter, onDownloadChapter = onDownloadChapter,
onChapterSelected = onChapterSelected,
) )
} }
} }
@ -412,6 +416,11 @@ fun MangaScreenLargeImpl(
onMultiMarkAsReadClicked: (List<Chapter>, markAsRead: Boolean) -> Unit, onMultiMarkAsReadClicked: (List<Chapter>, markAsRead: Boolean) -> Unit,
onMarkPreviousAsReadClicked: (Chapter) -> Unit, onMarkPreviousAsReadClicked: (Chapter) -> Unit,
onMultiDeleteClicked: (List<Chapter>) -> Unit, onMultiDeleteClicked: (List<Chapter>) -> Unit,
// Chapter selection
onChapterSelected: (ChapterItem, Boolean, Boolean, Boolean) -> Unit,
onAllChapterSelected: (Boolean) -> Unit,
onInvertSelection: () -> Unit,
) { ) {
val layoutDirection = LocalLayoutDirection.current val layoutDirection = LocalLayoutDirection.current
val density = LocalDensity.current val density = LocalDensity.current
@ -436,12 +445,10 @@ fun MangaScreenLargeImpl(
) { ) {
val chapterListState = rememberLazyListState() val chapterListState = rememberLazyListState()
val chapters = remember(state) { state.processedChapters.toList() } val chapters = remember(state) { state.processedChapters.toList() }
val selected = remember(chapters) { emptyList<ChapterItem>().toMutableStateList() }
val selectedPositions = remember(chapters) { arrayOf(-1, -1) } // first and last selected index in list
val internalOnBackPressed = { val internalOnBackPressed = {
if (selected.isNotEmpty()) { if (chapters.any { it.selected }) {
selected.clear() onAllChapterSelected(false)
} else { } else {
onBackClicked() onBackClicked()
} }
@ -454,7 +461,7 @@ fun MangaScreenLargeImpl(
MangaSmallAppBar( MangaSmallAppBar(
modifier = Modifier.onSizeChanged { onTopBarHeightChanged(it.height) }, modifier = Modifier.onSizeChanged { onTopBarHeightChanged(it.height) },
title = state.manga.title, title = state.manga.title,
titleAlphaProvider = { if (selected.isEmpty()) 0f else 1f }, titleAlphaProvider = { if (chapters.any { it.selected }) 1f else 0f },
backgroundAlphaProvider = { 1f }, backgroundAlphaProvider = { 1f },
incognitoMode = state.isIncognitoMode, incognitoMode = state.isIncognitoMode,
downloadedOnlyMode = state.isDownloadedOnlyMode, downloadedOnlyMode = state.isDownloadedOnlyMode,
@ -463,16 +470,9 @@ fun MangaScreenLargeImpl(
onDownloadClicked = onDownloadActionClicked, onDownloadClicked = onDownloadActionClicked,
onEditCategoryClicked = onEditCategoryClicked, onEditCategoryClicked = onEditCategoryClicked,
onMigrateClicked = onMigrateClicked, onMigrateClicked = onMigrateClicked,
actionModeCounter = selected.size, actionModeCounter = chapters.count { it.selected },
onSelectAll = { onSelectAll = { onAllChapterSelected(true) },
selected.clear() onInvertSelection = { onInvertSelection() },
selected.addAll(chapters)
},
onInvertSelection = {
val toSelect = chapters - selected
selected.clear()
selected.addAll(toSelect)
},
) )
}, },
bottomBar = { bottomBar = {
@ -481,7 +481,7 @@ fun MangaScreenLargeImpl(
contentAlignment = Alignment.BottomEnd, contentAlignment = Alignment.BottomEnd,
) { ) {
SharedMangaBottomActionMenu( SharedMangaBottomActionMenu(
selected = selected, selected = chapters.filter { it.selected },
onMultiBookmarkClicked = onMultiBookmarkClicked, onMultiBookmarkClicked = onMultiBookmarkClicked,
onMultiMarkAsReadClicked = onMultiMarkAsReadClicked, onMultiMarkAsReadClicked = onMultiMarkAsReadClicked,
onMarkPreviousAsReadClicked = onMarkPreviousAsReadClicked, onMarkPreviousAsReadClicked = onMarkPreviousAsReadClicked,
@ -494,7 +494,7 @@ fun MangaScreenLargeImpl(
snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, snackbarHost = { SnackbarHost(hostState = snackbarHostState) },
floatingActionButton = { floatingActionButton = {
AnimatedVisibility( AnimatedVisibility(
visible = chapters.any { !it.chapter.read } && selected.isEmpty(), visible = chapters.any { !it.chapter.read } && chapters.none { it.selected },
enter = fadeIn(), enter = fadeIn(),
exit = fadeOut(), exit = fadeOut(),
) { ) {
@ -578,10 +578,9 @@ fun MangaScreenLargeImpl(
sharedChapterItems( sharedChapterItems(
chapters = chapters, chapters = chapters,
selected = selected,
selectedPositions = selectedPositions,
onChapterClicked = onChapterClicked, onChapterClicked = onChapterClicked,
onDownloadChapter = onDownloadChapter, onDownloadChapter = onDownloadChapter,
onChapterSelected = onChapterSelected,
) )
} }
} }
@ -592,7 +591,7 @@ fun MangaScreenLargeImpl(
@Composable @Composable
private fun SharedMangaBottomActionMenu( private fun SharedMangaBottomActionMenu(
selected: SnapshotStateList<ChapterItem>, selected: List<ChapterItem>,
onMultiBookmarkClicked: (List<Chapter>, bookmarked: Boolean) -> Unit, onMultiBookmarkClicked: (List<Chapter>, bookmarked: Boolean) -> Unit,
onMultiMarkAsReadClicked: (List<Chapter>, markAsRead: Boolean) -> Unit, onMultiMarkAsReadClicked: (List<Chapter>, markAsRead: Boolean) -> Unit,
onMarkPreviousAsReadClicked: (Chapter) -> Unit, onMarkPreviousAsReadClicked: (Chapter) -> Unit,
@ -605,33 +604,26 @@ private fun SharedMangaBottomActionMenu(
modifier = Modifier.fillMaxWidth(fillFraction), modifier = Modifier.fillMaxWidth(fillFraction),
onBookmarkClicked = { onBookmarkClicked = {
onMultiBookmarkClicked.invoke(selected.map { it.chapter }, true) onMultiBookmarkClicked.invoke(selected.map { it.chapter }, true)
selected.clear()
}.takeIf { selected.any { !it.chapter.bookmark } }, }.takeIf { selected.any { !it.chapter.bookmark } },
onRemoveBookmarkClicked = { onRemoveBookmarkClicked = {
onMultiBookmarkClicked.invoke(selected.map { it.chapter }, false) onMultiBookmarkClicked.invoke(selected.map { it.chapter }, false)
selected.clear()
}.takeIf { selected.all { it.chapter.bookmark } }, }.takeIf { selected.all { it.chapter.bookmark } },
onMarkAsReadClicked = { onMarkAsReadClicked = {
onMultiMarkAsReadClicked(selected.map { it.chapter }, true) onMultiMarkAsReadClicked(selected.map { it.chapter }, true)
selected.clear()
}.takeIf { selected.any { !it.chapter.read } }, }.takeIf { selected.any { !it.chapter.read } },
onMarkAsUnreadClicked = { onMarkAsUnreadClicked = {
onMultiMarkAsReadClicked(selected.map { it.chapter }, false) onMultiMarkAsReadClicked(selected.map { it.chapter }, false)
selected.clear()
}.takeIf { selected.any { it.chapter.read } }, }.takeIf { selected.any { it.chapter.read } },
onMarkPreviousAsReadClicked = { onMarkPreviousAsReadClicked = {
onMarkPreviousAsReadClicked(selected[0].chapter) onMarkPreviousAsReadClicked(selected[0].chapter)
selected.clear()
}.takeIf { selected.size == 1 }, }.takeIf { selected.size == 1 },
onDownloadClicked = { onDownloadClicked = {
onDownloadChapter!!(selected.toList(), ChapterDownloadAction.START) onDownloadChapter!!(selected.toList(), ChapterDownloadAction.START)
selected.clear()
}.takeIf { }.takeIf {
onDownloadChapter != null && selected.any { it.downloadState != Download.State.DOWNLOADED } onDownloadChapter != null && selected.any { it.downloadState != Download.State.DOWNLOADED }
}, },
onDeleteClicked = { onDeleteClicked = {
onMultiDeleteClicked(selected.map { it.chapter }) onMultiDeleteClicked(selected.map { it.chapter })
selected.clear()
}.takeIf { }.takeIf {
onDownloadChapter != null && selected.any { it.downloadState == Download.State.DOWNLOADED } onDownloadChapter != null && selected.any { it.downloadState == Download.State.DOWNLOADED }
}, },
@ -640,10 +632,9 @@ private fun SharedMangaBottomActionMenu(
private fun LazyListScope.sharedChapterItems( private fun LazyListScope.sharedChapterItems(
chapters: List<ChapterItem>, chapters: List<ChapterItem>,
selected: SnapshotStateList<ChapterItem>,
selectedPositions: Array<Int>,
onChapterClicked: (Chapter) -> Unit, onChapterClicked: (Chapter) -> Unit,
onDownloadChapter: ((List<ChapterItem>, ChapterDownloadAction) -> Unit)?, onDownloadChapter: ((List<ChapterItem>, ChapterDownloadAction) -> Unit)?,
onChapterSelected: (ChapterItem, Boolean, Boolean, Boolean) -> Unit,
) { ) {
items( items(
items = chapters, items = chapters,
@ -658,24 +649,18 @@ private fun LazyListScope.sharedChapterItems(
scanlator = chapterItem.chapter.scanlator.takeIf { !it.isNullOrBlank() }, scanlator = chapterItem.chapter.scanlator.takeIf { !it.isNullOrBlank() },
read = chapterItem.chapter.read, read = chapterItem.chapter.read,
bookmark = chapterItem.chapter.bookmark, bookmark = chapterItem.chapter.bookmark,
selected = selected.contains(chapterItem), selected = chapterItem.selected,
downloadStateProvider = { chapterItem.downloadState }, downloadStateProvider = { chapterItem.downloadState },
downloadProgressProvider = { chapterItem.downloadProgress }, downloadProgressProvider = { chapterItem.downloadProgress },
onLongClick = { onLongClick = {
val dispatched = onChapterItemLongClick( onChapterSelected(chapterItem, !chapterItem.selected, true, true)
chapterItem = chapterItem, haptic.performHapticFeedback(HapticFeedbackType.LongPress)
selected = selected,
chapters = chapters,
selectedPositions = selectedPositions,
)
if (dispatched) haptic.performHapticFeedback(HapticFeedbackType.LongPress)
}, },
onClick = { onClick = {
onChapterItemClick( onChapterItemClick(
chapterItem = chapterItem, chapterItem = chapterItem,
selected = selected,
chapters = chapters, chapters = chapters,
selectedPositions = selectedPositions, onToggleSelection = { onChapterSelected(chapterItem, !chapterItem.selected, true, false) },
onChapterClicked = onChapterClicked, onChapterClicked = onChapterClicked,
) )
}, },
@ -686,72 +671,15 @@ private fun LazyListScope.sharedChapterItems(
} }
} }
private fun onChapterItemLongClick(
chapterItem: ChapterItem,
selected: MutableList<ChapterItem>,
chapters: List<ChapterItem>,
selectedPositions: Array<Int>,
): Boolean {
if (!selected.contains(chapterItem)) {
val selectedIndex = chapters.indexOf(chapterItem)
if (selected.isEmpty()) {
selected.add(chapterItem)
selectedPositions[0] = selectedIndex
selectedPositions[1] = selectedIndex
return true
}
// Try to select the items in-between when possible
val range: IntRange
if (selectedIndex < selectedPositions[0]) {
range = selectedIndex until selectedPositions[0]
selectedPositions[0] = selectedIndex
} else if (selectedIndex > selectedPositions[1]) {
range = (selectedPositions[1] + 1)..selectedIndex
selectedPositions[1] = selectedIndex
} else {
// Just select itself
range = selectedIndex..selectedIndex
}
range.forEach {
val toAdd = chapters[it]
if (!selected.contains(toAdd)) {
selected.add(toAdd)
}
}
return true
}
return false
}
private fun onChapterItemClick( private fun onChapterItemClick(
chapterItem: ChapterItem, chapterItem: ChapterItem,
selected: MutableList<ChapterItem>,
chapters: List<ChapterItem>, chapters: List<ChapterItem>,
selectedPositions: Array<Int>, onToggleSelection: (Boolean) -> Unit,
onChapterClicked: (Chapter) -> Unit, onChapterClicked: (Chapter) -> Unit,
) { ) {
val selectedIndex = chapters.indexOf(chapterItem)
when { when {
selected.contains(chapterItem) -> { chapterItem.selected -> onToggleSelection(false)
val removedIndex = chapters.indexOf(chapterItem) chapters.any { it.selected } -> onToggleSelection(true)
selected.remove(chapterItem)
if (removedIndex == selectedPositions[0]) {
selectedPositions[0] = chapters.indexOfFirst { selected.contains(it) }
} else if (removedIndex == selectedPositions[1]) {
selectedPositions[1] = chapters.indexOfLast { selected.contains(it) }
}
}
selected.isNotEmpty() -> {
if (selectedIndex < selectedPositions[0]) {
selectedPositions[0] = selectedIndex
} else if (selectedIndex > selectedPositions[1]) {
selectedPositions[1] = selectedIndex
}
selected.add(chapterItem)
}
else -> onChapterClicked(chapterItem.chapter) else -> onChapterClicked(chapterItem.chapter)
} }
} }

View File

@ -142,6 +142,9 @@ class MangaController :
onMultiMarkAsReadClicked = presenter::markChaptersRead, onMultiMarkAsReadClicked = presenter::markChaptersRead,
onMarkPreviousAsReadClicked = presenter::markPreviousChapterRead, onMarkPreviousAsReadClicked = presenter::markPreviousChapterRead,
onMultiDeleteClicked = this::deleteChaptersWithConfirmation, onMultiDeleteClicked = this::deleteChaptersWithConfirmation,
onChapterSelected = presenter::toggleSelection,
onAllChapterSelected = presenter::toggleAllSelection,
onInvertSelection = presenter::invertSelection,
) )
} else { } else {
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {

View File

@ -140,6 +140,8 @@ class MangaPresenter(
val processedChapters: Sequence<ChapterItem>? val processedChapters: Sequence<ChapterItem>?
get() = successState?.processedChapters get() = successState?.processedChapters
private val selectedPositions: Array<Int> = arrayOf(-1, -1) // first and last selected index in list
/** /**
* Helper function to update the UI state only if it's currently in success state * Helper function to update the UI state only if it's currently in success state
*/ */
@ -583,6 +585,7 @@ class MangaPresenter(
values = chapters.toTypedArray(), values = chapters.toTypedArray(),
) )
} }
toggleAllSelection(false)
} }
/** /**
@ -592,6 +595,7 @@ class MangaPresenter(
fun downloadChapters(chapters: List<DomainChapter>) { fun downloadChapters(chapters: List<DomainChapter>) {
val manga = successState?.manga ?: return val manga = successState?.manga ?: return
downloadManager.downloadChapters(manga, chapters.map { it.toDbChapter() }) downloadManager.downloadChapters(manga, chapters.map { it.toDbChapter() })
toggleAllSelection(false)
} }
/** /**
@ -605,6 +609,7 @@ class MangaPresenter(
.map { ChapterUpdate(id = it.id, bookmark = bookmarked) } .map { ChapterUpdate(id = it.id, bookmark = bookmarked) }
.let { updateChapter.awaitAll(it) } .let { updateChapter.awaitAll(it) }
} }
toggleAllSelection(false)
} }
/** /**
@ -627,12 +632,16 @@ class MangaPresenter(
deletedChapters.forEach { deletedChapters.forEach {
val index = indexOf(it) val index = indexOf(it)
val toAdd = removeAt(index) val toAdd = removeAt(index)
.copy(downloadState = Download.State.NOT_DOWNLOADED, downloadProgress = 0) .copy(
downloadState = Download.State.NOT_DOWNLOADED,
downloadProgress = 0,
)
add(index, toAdd) add(index, toAdd)
} }
} }
successState.copy(chapters = newChapters) successState.copy(chapters = newChapters)
} }
toggleAllSelection(false)
} catch (e: Throwable) { } catch (e: Throwable) {
logcat(LogPriority.ERROR, e) logcat(LogPriority.ERROR, e)
} }
@ -725,6 +734,89 @@ class MangaPresenter(
} }
} }
fun toggleSelection(
item: ChapterItem,
selected: Boolean,
userSelected: Boolean = false,
fromLongPress: Boolean = false,
) {
updateSuccessState { successState ->
val modifiedIndex = successState.chapters.indexOfFirst { it.chapter.id == item.chapter.id }
if (modifiedIndex < 0) return@updateSuccessState successState
val oldItem = successState.chapters[modifiedIndex]
if ((oldItem.selected && selected) || (!oldItem.selected && !selected)) return@updateSuccessState successState
val newChapters = successState.chapters.toMutableList().apply {
val firstSelection = none { it.selected }
var newItem = removeAt(modifiedIndex)
add(modifiedIndex, newItem.copy(selected = selected))
if (selected && userSelected && fromLongPress) {
if (firstSelection) {
selectedPositions[0] = modifiedIndex
selectedPositions[1] = modifiedIndex
} else {
// Try to select the items in-between when possible
val range: IntRange
if (modifiedIndex < selectedPositions[0]) {
range = modifiedIndex + 1 until selectedPositions[0]
selectedPositions[0] = modifiedIndex
} else if (modifiedIndex > selectedPositions[1]) {
range = (selectedPositions[1] + 1) until modifiedIndex
selectedPositions[1] = modifiedIndex
} else {
// Just select itself
range = IntRange.EMPTY
}
range.forEach {
newItem = removeAt(it)
add(it, newItem.copy(selected = true))
}
}
} else if (userSelected && !fromLongPress) {
if (!selected) {
if (modifiedIndex == selectedPositions[0]) {
selectedPositions[0] = indexOfFirst { it.selected }
} else if (modifiedIndex == selectedPositions[1]) {
selectedPositions[1] = indexOfLast { it.selected }
}
} else {
if (modifiedIndex < selectedPositions[0]) {
selectedPositions[0] = modifiedIndex
} else if (modifiedIndex > selectedPositions[1]) {
selectedPositions[1] = modifiedIndex
}
}
}
}
successState.copy(chapters = newChapters)
}
}
fun toggleAllSelection(selected: Boolean) {
updateSuccessState { successState ->
val newChapters = successState.chapters.map {
it.copy(selected = selected)
}
selectedPositions[0] = -1
selectedPositions[1] = -1
successState.copy(chapters = newChapters)
}
}
fun invertSelection() {
updateSuccessState { successState ->
val newChapters = successState.chapters.map {
it.copy(selected = !it.selected)
}
selectedPositions[0] = -1
selectedPositions[1] = -1
successState.copy(chapters = newChapters)
}
}
// Chapters list - end // Chapters list - end
// Track sheet - start // Track sheet - start
@ -962,6 +1054,8 @@ data class ChapterItem(
val chapterTitleString: String, val chapterTitleString: String,
val dateUploadString: String?, val dateUploadString: String?,
val readProgressString: String?, val readProgressString: String?,
val selected: Boolean = false,
) { ) {
val isDownloaded = downloadState == Download.State.DOWNLOADED val isDownloaded = downloadState == Download.State.DOWNLOADED
} }