Introduce DownloadsFilterState (#769)

* Fix default download list not updating on label delete

* Fix unexpected behavior after renaming label
This commit is contained in:
FooIbar authored and GitHub committed 2024-02-24 12:51:11 +08:00
1 parent dd0776758f
commit 1eeb5a51f6
3 files changed
+53 -24

No files matched your search

@@ -15,7 +15,6 @@
*/
package com.hippo.ehviewer.client.data
import com.hippo.ehviewer.util.containsIgnoreCase
import java.util.regex.Pattern
import moe.tarsin.kt.unreachable
@@ -147,6 +146,3 @@ fun GalleryInfo.findBaseInfo(): BaseGalleryInfo {
fun GalleryInfo.asGalleryDetail(): GalleryDetail? {
return this as? GalleryDetail
}
operator fun GalleryInfo.contains(keyword: String): Boolean =
arrayOf(title, titleJpn, uploader).any { it.containsIgnoreCase(keyword) }
@@ -0,0 +1,17 @@
package com.hippo.ehviewer.ui.screen
import android.os.Parcelable
import com.hippo.ehviewer.dao.DownloadInfo
import com.hippo.ehviewer.util.containsIgnoreCase
import kotlinx.parcelize.Parcelize
@Parcelize
data class DownloadsFilterState(
val label: String?,
val state: Int = -1,
val keyword: String = "",
) : Parcelable
fun DownloadsFilterState.take(info: DownloadInfo) =
(label == "" || info.label == label) && (state == -1 || info.state == state) &&
with(info) { title.containsIgnoreCase(keyword) || titleJpn.containsIgnoreCase(keyword) }
@@ -83,7 +83,6 @@ import com.hippo.ehviewer.EhDB
import com.hippo.ehviewer.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.asMutableState
import com.hippo.ehviewer.client.data.contains
import com.hippo.ehviewer.collectAsState
import com.hippo.ehviewer.dao.DownloadInfo
import com.hippo.ehviewer.download.DownloadManager
@@ -128,12 +127,13 @@ import sh.calvin.reorderable.rememberReorderableLazyColumnState
@Destination
@Composable
fun DownloadsScreen(navigator: DestinationsNavigator) {
var label by Settings.recentDownloadLabel.asMutableState()
var gridView by Settings.gridView.asMutableState()
var sortMode by Settings.downloadSortMode.asMutableState()
var keyword by rememberSaveable { mutableStateOf<String?>(null) }
var filterType by rememberSaveable { mutableIntStateOf(-1) }
var searchBarOffsetY by remember(label) { mutableIntStateOf(0) }
var filterState by rememberSaveable {
mutableStateOf(DownloadsFilterState(Settings.recentDownloadLabel.value))
}
var invalidateKey by rememberSaveable { mutableStateOf(false) }
var searchBarOffsetY by remember(filterState.label) { mutableIntStateOf(0) }
val searchFieldState = rememberTextFieldState()
var fabExpanded by remember { mutableStateOf(false) }
@@ -150,14 +150,16 @@ fun DownloadsScreen(navigator: DestinationsNavigator) {
val view = LocalView.current
val allName = stringResource(R.string.download_all)
val defaultName = stringResource(R.string.default_download_label_name)
val title = stringResource(R.string.scene_download_title, if (label == "") allName else label ?: defaultName)
val title = stringResource(
R.string.scene_download_title,
with(filterState) { if (label == "") allName else label ?: defaultName },
)
val hint = stringResource(R.string.search_bar_hint, title)
val sortModes = stringArrayResource(id = R.array.download_sort_modes)
val downloadStates = stringArrayResource(id = R.array.download_state)
val list = remember(label, filterType, keyword, sortMode) {
val list = remember(filterState, invalidateKey) {
DownloadManager.downloadInfoList.filterTo(mutableStateListOf()) { info ->
(label == "" || info.label == label) && (filterType == -1 || info.state == filterType) &&
keyword.orEmpty() in info
filterState.take(info)
}
}
@@ -169,6 +171,12 @@ fun DownloadsScreen(navigator: DestinationsNavigator) {
val labelExists = stringResource(R.string.label_text_exist)
val downloadsCount by rememberInVM { EhDB.downloadsCount }.collectAsState(emptyMap())
val totalCount = remember(downloadsCount) { downloadsCount.values.sum() }
fun switchLabel(label: String?) {
Settings.recentDownloadLabel.value = label
filterState = filterState.copy(label = label)
}
with(activity) {
ProvideSideSheetContent { drawerState ->
fun closeSheet() = coroutineScope.launch { drawerState.close() }
@@ -236,7 +244,7 @@ fun DownloadsScreen(navigator: DestinationsNavigator) {
stickyHeader {
ListItem(
modifier = Modifier.clickable {
label = ""
switchLabel("")
closeSheet()
},
tonalElevation = 1.dp,
@@ -249,7 +257,7 @@ fun DownloadsScreen(navigator: DestinationsNavigator) {
stickyHeader {
ListItem(
modifier = Modifier.clickable {
label = null
switchLabel(null)
closeSheet()
},
tonalElevation = 1.dp,
@@ -265,8 +273,9 @@ fun DownloadsScreen(navigator: DestinationsNavigator) {
if (it == SwipeToDismissBoxValue.EndToStart) {
coroutineScope.launch {
DownloadManager.deleteLabel(item)
if (label == item) {
label = ""
when (filterState.label) {
item -> switchLabel("")
null -> invalidateKey = !invalidateKey
}
}
}
@@ -288,7 +297,7 @@ fun DownloadsScreen(navigator: DestinationsNavigator) {
)
ListItem(
modifier = Modifier.clickable {
label = item
switchLabel(item)
closeSheet()
},
tonalElevation = 1.dp,
@@ -310,7 +319,9 @@ fun DownloadsScreen(navigator: DestinationsNavigator) {
}
}
DownloadManager.renameLabel(item, new)
label = new
if (filterState.label == item) {
switchLabel(new)
}
}
},
) {
@@ -348,7 +359,7 @@ fun DownloadsScreen(navigator: DestinationsNavigator) {
title = title,
searchFieldState = searchFieldState,
searchFieldHint = hint,
onApplySearch = { keyword = it.takeUnless { it.isBlank() } },
onApplySearch = { filterState = filterState.copy(keyword = it) },
onSearchExpanded = {
checkedInfoMap.clear()
fabHidden = true
@@ -450,6 +461,7 @@ fun DownloadsScreen(navigator: DestinationsNavigator) {
}
}
}
fun onItemClick(info: DownloadInfo) {
coroutineScope.launchIO {
EhDB.putHistoryInfo(info.galleryInfo)
@@ -578,13 +590,15 @@ fun DownloadsScreen(navigator: DestinationsNavigator) {
val mode = SortMode.All[selected]
DownloadManager.sortDownloads(mode)
sortMode = mode.flag
invalidateKey = !invalidateKey
}
onClick(Icons.Default.FilterList) {
filterType = dialogState.showSingleChoice(
val state = dialogState.showSingleChoice(
downloadStates.toList(),
filterType + 1,
filterState.state + 1,
R.string.download_filter,
) - 1
filterState = filterState.copy(state = state)
}
} else {
onClick(Icons.Default.DoneAll) {
@@ -613,8 +627,10 @@ fun DownloadsScreen(navigator: DestinationsNavigator) {
onClick(Icons.AutoMirrored.Default.DriveFileMove) {
val infoList = checkedInfoMap.run { toMap().values.also { clear() } }
val toLabel = dialogState.showMoveDownloadLabelList(infoList)
if (label != "" && label != toLabel) {
list.removeAll(infoList)
with(filterState) {
if (label != "" && label != toLabel) {
list.removeAll(infoList)
}
}
}
}