From 8d19dffa01ebf8484a51f156a0c29b256e2b81c1 Mon Sep 17 00:00:00 2001 From: tarsin Date: Sat, 1 Jul 2023 12:07:23 +0800 Subject: [PATCH] Ensure Filter DB modification never on main thread --- .../com/hippo/ehviewer/client/EhFilter.kt | 19 +++++++++++----- .../ehviewer/ui/settings/FilterScreen.kt | 22 +++++++------------ 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/com/hippo/ehviewer/client/EhFilter.kt b/app/src/main/java/com/hippo/ehviewer/client/EhFilter.kt index 6bf2cab4e..bceaa1a52 100644 --- a/app/src/main/java/com/hippo/ehviewer/client/EhFilter.kt +++ b/app/src/main/java/com/hippo/ehviewer/client/EhFilter.kt @@ -20,6 +20,9 @@ import arrow.core.memoize import com.hippo.ehviewer.EhDB import com.hippo.ehviewer.client.data.GalleryInfo import com.hippo.ehviewer.dao.Filter +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch private val regex = { p: Filter -> Regex(p.text) }.memoize() private inline fun List.anyActive(predicate: (Filter) -> Boolean) = any { it.enable && predicate(it) } @@ -31,10 +34,16 @@ object EhFilter { val tagNamespaceFilterList = mutableStateListOf() val commenterFilterList = mutableStateListOf() val commentFilterList = mutableStateListOf() - - fun Filter.remember() = EhDB.addFilter(this).also { if (it) memorizeFilter(this) } - fun Filter.trigger() = EhDB.triggerFilter(this) - fun Filter.forget() { + private val opScope = CoroutineScope(Dispatchers.IO.limitedParallelism(1)) + private fun Filter.launchOps(callback: ((R) -> Unit)? = null, ops: Filter.() -> R) = opScope.launch { + val r = ops() + callback?.invoke(r) + } + fun Filter.remember(callback: ((Boolean) -> Unit)? = null) = launchOps(callback) { + EhDB.addFilter(this).also { if (it) memorizeFilter(this) } + } + fun Filter.trigger(callback: ((Unit) -> Unit)? = null) = launchOps(callback) { EhDB.triggerFilter(this) } + fun Filter.forget() = launchOps { EhDB.deleteFilter(this) when (mode) { MODE_TITLE -> titleFilterList.remove(this) @@ -43,7 +52,7 @@ object EhFilter { MODE_UPLOADER -> uploaderFilterList.remove(this) MODE_COMMENTER -> commenterFilterList.remove(this) MODE_COMMENT -> commentFilterList.remove(this) - else -> error("Unknown mode: " + mode) + else -> error("Unknown mode: $mode") } } diff --git a/app/src/main/java/com/hippo/ehviewer/ui/settings/FilterScreen.kt b/app/src/main/java/com/hippo/ehviewer/ui/settings/FilterScreen.kt index 59bf241c4..b530d8edc 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/settings/FilterScreen.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/settings/FilterScreen.kt @@ -48,7 +48,6 @@ import com.hippo.ehviewer.databinding.DialogAddFilterBinding import com.hippo.ehviewer.ui.LocalNavController import com.hippo.ehviewer.ui.legacy.BaseDialogBuilder import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch @Composable fun FilterScreen() { @@ -83,14 +82,14 @@ fun FilterScreen() { } } binding.textInputLayout.run { - if (!Filter(mArray.indexOf(text1), text!!).remember()) { - error = context.getString(R.string.label_text_exist) - return - } else { - error = null + Filter(mArray.indexOf(text1), text!!).remember { + if (it) { + post { dialog.dismiss() } + } else { + post { error = context.getString(R.string.label_text_exist) } + } } } - dialog.dismiss() } } @@ -139,17 +138,12 @@ fun FilterScreen() { val filterCheckBoxRecomposeScope = currentRecomposeScope Checkbox( checked = filter.enable, - onCheckedChange = { - coroutineScope.launch { - filter.trigger() - filterCheckBoxRecomposeScope.invalidate() - } - }, + 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) { coroutineScope.launch { filter.forget() } } }.setNegativeButton(android.R.string.cancel, null).show() }, + 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) }