Fixup! Refactor EhFilter to fix concurrency modification
This commit is contained in:
1 parent
1c74a422bc
commit
80d75661c1
3 files changed
+43
-52
No files matched your search
@@ -24,7 +24,7 @@ object EhFilter : CoroutineScope {
|
||||
EhDB.addFilter(this).also { if (it) filters.await().add(this) }
|
||||
}
|
||||
fun Filter.trigger(callback: ((Unit) -> Unit)? = null) = launchOps(callback) { EhDB.triggerFilter(this) }
|
||||
fun Filter.forget() = launchOps {
|
||||
fun Filter.forget(callback: ((Unit) -> Unit)? = null) = launchOps(callback) {
|
||||
EhDB.deleteFilter(this)
|
||||
filters.await().remove(this)
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.hippo.ehviewer.ui.settings
|
||||
|
||||
import android.content.DialogInterface
|
||||
import android.view.View
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@@ -31,8 +30,10 @@ import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.currentRecomposeScope
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.snapshots.SnapshotStateList
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
@@ -52,7 +53,6 @@ import com.hippo.ehviewer.ui.legacy.BaseDialogBuilder
|
||||
import com.hippo.ehviewer.ui.tools.Deferred
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import moe.tarsin.coroutines.groupByToObserved
|
||||
|
||||
@Composable
|
||||
fun FilterScreen() {
|
||||
@@ -62,7 +62,10 @@ fun FilterScreen() {
|
||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
|
||||
val allFilterMap = remember {
|
||||
scope.async {
|
||||
EhFilter.filters.await().groupByToObserved { it.mode }
|
||||
LinkedHashMap<FilterMode, SnapshotStateList<Filter>>().also { dest ->
|
||||
FilterMode.entries.forEach { dest[it] = mutableStateListOf() }
|
||||
EhFilter.filters.await().forEach { requireNotNull(dest[it.mode]).add(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
class AddFilterDialogHelper(private val dialog: AlertDialog) : View.OnClickListener {
|
||||
@@ -92,9 +95,12 @@ fun FilterScreen() {
|
||||
}
|
||||
}
|
||||
binding.textInputLayout.run {
|
||||
Filter(FilterMode.entries[mArray.indexOf(text1)], text!!).remember {
|
||||
val mode = FilterMode.entries[mArray.indexOf(text1)]
|
||||
val filter = Filter(mode, text!!)
|
||||
filter.remember {
|
||||
if (it) {
|
||||
post { dialog.dismiss() }
|
||||
requireNotNull(allFilterMap.getCompleted()[mode]).add(filter)
|
||||
} else {
|
||||
post { error = context.getString(R.string.label_text_exist) }
|
||||
}
|
||||
@@ -126,43 +132,13 @@ fun FilterScreen() {
|
||||
}
|
||||
},
|
||||
) { paddingValues ->
|
||||
Deferred({ allFilterMap.await() }) { filter ->
|
||||
Deferred({ allFilterMap.await() }) { filters ->
|
||||
LazyColumn(
|
||||
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||
contentPadding = paddingValues,
|
||||
) {
|
||||
var showTip = true
|
||||
fun filterType(list: List<Filter>, @StringRes title: Int) = list.takeIf { it.isNotEmpty() }?.let {
|
||||
stickyHeader {
|
||||
Text(
|
||||
text = stringResource(id = title),
|
||||
modifier = Modifier.padding(horizontal = 24.dp, vertical = 8.dp),
|
||||
color = MaterialTheme.colorScheme.tertiary,
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
)
|
||||
}
|
||||
items(list) { filter ->
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
val filterCheckBoxRecomposeScope = currentRecomposeScope
|
||||
Checkbox(
|
||||
checked = filter.enable,
|
||||
onCheckedChange = { filter.trigger { filterCheckBoxRecomposeScope.invalidate() } },
|
||||
)
|
||||
Text(text = filter.text)
|
||||
Spacer(modifier = Modifier.weight(1F))
|
||||
IconButton(
|
||||
onClick = { BaseDialogBuilder(context).setMessage(context.getString(R.string.delete_filter, filter.text)).setPositiveButton(R.string.delete) { _, which -> if (DialogInterface.BUTTON_POSITIVE == which) { filter.forget() } }.setNegativeButton(android.R.string.cancel, null).show() },
|
||||
) {
|
||||
Icon(imageVector = Icons.Default.Delete, contentDescription = null)
|
||||
}
|
||||
}
|
||||
}
|
||||
showTip = false
|
||||
}
|
||||
filter.forEach { (filterMode, filters) ->
|
||||
filters.forEach { (filterMode, filters) ->
|
||||
val title = when (filterMode) {
|
||||
FilterMode.TITLE -> R.string.filter_title
|
||||
FilterMode.UPLOADER -> R.string.filter_uploader
|
||||
@@ -171,7 +147,36 @@ fun FilterScreen() {
|
||||
FilterMode.COMMENTER -> R.string.filter_commenter
|
||||
FilterMode.COMMENT -> R.string.filter_comment
|
||||
}
|
||||
filterType(filters, title)
|
||||
if (filters.isNotEmpty()) {
|
||||
stickyHeader {
|
||||
Text(
|
||||
text = stringResource(id = title),
|
||||
modifier = Modifier.padding(horizontal = 24.dp, vertical = 8.dp),
|
||||
color = MaterialTheme.colorScheme.tertiary,
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
)
|
||||
}
|
||||
items(filters) { filter ->
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
val filterCheckBoxRecomposeScope = currentRecomposeScope
|
||||
Checkbox(
|
||||
checked = filter.enable,
|
||||
onCheckedChange = { filter.trigger { filterCheckBoxRecomposeScope.invalidate() } },
|
||||
)
|
||||
Text(text = filter.text)
|
||||
Spacer(modifier = Modifier.weight(1F))
|
||||
IconButton(
|
||||
onClick = { BaseDialogBuilder(context).setMessage(context.getString(R.string.delete_filter, filter.text)).setPositiveButton(R.string.delete) { _, which -> if (DialogInterface.BUTTON_POSITIVE == which) { filter.forget { filters.remove(filter) } } }.setNegativeButton(android.R.string.cancel, null).show() },
|
||||
) {
|
||||
Icon(imageVector = Icons.Default.Delete, contentDescription = null)
|
||||
}
|
||||
}
|
||||
}
|
||||
showTip = false
|
||||
}
|
||||
}
|
||||
if (showTip) {
|
||||
item {
|
||||
|
||||
Reference in new issue
Block a user