Przeglądaj źródła

替换规则界面排序功能

HapeLee 1 rok temu
rodzic
commit
7c151e1b86

+ 49 - 0
app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt

@@ -22,6 +22,55 @@ interface ReplaceRuleDao {
     @Query("SELECT * FROM replace_rules ORDER BY sortOrder ASC")
     fun flowAll(): Flow<List<ReplaceRule>>
 
+    @Query("SELECT * FROM replace_rules ORDER BY sortOrder ASC")
+    fun flowAllAsc(): Flow<List<ReplaceRule>>
+
+    @Query("SELECT * FROM replace_rules ORDER BY sortOrder DESC")
+    fun flowAllDesc(): Flow<List<ReplaceRule>>
+
+    @Query("SELECT * FROM replace_rules ORDER BY name COLLATE NOCASE ASC")
+    fun flowAllNameAsc(): Flow<List<ReplaceRule>>
+
+    @Query("SELECT * FROM replace_rules ORDER BY name COLLATE NOCASE DESC")
+    fun flowAllNameDesc(): Flow<List<ReplaceRule>>
+
+    @Query("SELECT * FROM replace_rules WHERE `group` LIKE :key OR name LIKE :key ORDER BY sortOrder ASC")
+    fun flowSearchAsc(key: String): Flow<List<ReplaceRule>>
+
+    @Query("SELECT * FROM replace_rules WHERE `group` LIKE :key OR name LIKE :key ORDER BY sortOrder DESC")
+    fun flowSearchDesc(key: String): Flow<List<ReplaceRule>>
+
+    @Query("SELECT * FROM replace_rules WHERE `group` LIKE :key OR name LIKE :key ORDER BY name COLLATE NOCASE ASC")
+    fun flowSearchNameAsc(key: String): Flow<List<ReplaceRule>>
+
+    @Query("SELECT * FROM replace_rules WHERE `group` LIKE :key OR name LIKE :key ORDER BY name COLLATE NOCASE DESC")
+    fun flowSearchNameDesc(key: String): Flow<List<ReplaceRule>>
+
+    @Query("SELECT * FROM replace_rules WHERE `group` LIKE :key ORDER BY sortOrder ASC")
+    fun flowGroupSearchAsc(key: String): Flow<List<ReplaceRule>>
+
+    @Query("SELECT * FROM replace_rules WHERE `group` LIKE :key ORDER BY sortOrder DESC")
+    fun flowGroupSearchDesc(key: String): Flow<List<ReplaceRule>>
+
+    @Query("SELECT * FROM replace_rules WHERE `group` LIKE :key ORDER BY name COLLATE NOCASE ASC")
+    fun flowGroupSearchNameAsc(key: String): Flow<List<ReplaceRule>>
+
+    @Query("SELECT * FROM replace_rules WHERE `group` LIKE :key ORDER BY name COLLATE NOCASE DESC")
+    fun flowGroupSearchNameDesc(key: String): Flow<List<ReplaceRule>>
+
+    // === 未分组 ===
+    @Query("SELECT * FROM replace_rules WHERE `group` IS NULL OR trim(`group`) = '' OR trim(`group`) LIKE '%未分组%' ORDER BY sortOrder ASC")
+    fun flowNoGroupAsc(): Flow<List<ReplaceRule>>
+
+    @Query("SELECT * FROM replace_rules WHERE `group` IS NULL OR trim(`group`) = '' OR trim(`group`) LIKE '%未分组%' ORDER BY sortOrder DESC")
+    fun flowNoGroupDesc(): Flow<List<ReplaceRule>>
+
+    @Query("SELECT * FROM replace_rules WHERE `group` IS NULL OR trim(`group`) = '' OR trim(`group`) LIKE '%未分组%' ORDER BY name COLLATE NOCASE ASC")
+    fun flowNoGroupNameAsc(): Flow<List<ReplaceRule>>
+
+    @Query("SELECT * FROM replace_rules WHERE `group` IS NULL OR trim(`group`) = '' OR trim(`group`) LIKE '%未分组%' ORDER BY name COLLATE NOCASE DESC")
+    fun flowNoGroupNameDesc(): Flow<List<ReplaceRule>>
+
     @Query("SELECT * FROM replace_rules where `group` like :key or name like :key ORDER BY sortOrder ASC")
     fun flowSearch(key: String): Flow<List<ReplaceRule>>
 

+ 16 - 32
app/src/main/java/io/legado/app/ui/replace/ReplaceRuleActivity.kt

@@ -50,6 +50,7 @@ import kotlinx.coroutines.Dispatchers.IO
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.flow.catch
+import kotlinx.coroutines.flow.collectLatest
 import kotlinx.coroutines.flow.conflate
 import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.launch
@@ -71,8 +72,9 @@ class ReplaceRuleActivity : VMBaseActivity<ActivityReplaceRuleBinding, ReplaceRu
     }
     private var groups = arrayListOf<String>()
     private var groupMenu: SubMenu? = null
-    private var replaceRuleFlowJob: Job? = null
-    private var dataInit = false
+
+    private var sortMode = "desc"
+    private var searchKey: String? = null
     private val qrCodeResult = registerForActivityResult(QrCodeResult()) {
         it ?: return@registerForActivityResult
         showDialogFragment(
@@ -197,35 +199,10 @@ class ReplaceRuleActivity : VMBaseActivity<ActivityReplaceRuleBinding, ReplaceRu
         binding.selectActionBar.setCallBack(this)
     }
 
-    private fun observeReplaceRuleData(searchKey: String? = null) {
-        dataInit = false
-        replaceRuleFlowJob?.cancel()
-        replaceRuleFlowJob = lifecycleScope.launch {
-            when {
-                searchKey.isNullOrEmpty() -> {
-                    appDb.replaceRuleDao.flowAll()
-                }
-
-                searchKey == getString(R.string.no_group) -> {
-                    appDb.replaceRuleDao.flowNoGroup()
-                }
-
-                searchKey.startsWith("group:") -> {
-                    val key = searchKey.substringAfter("group:")
-                    appDb.replaceRuleDao.flowGroupSearch("%$key%")
-                }
-                else -> {
-                    appDb.replaceRuleDao.flowSearch("%$searchKey%")
-                }
-            }.catch {
-                AppLog.put("替换规则管理界面更新数据出错", it)
-            }.flowOn(IO).conflate().collect {
-                if (dataInit) {
-                    setResult(RESULT_OK)
-                }
-                adapter.setItems(it, adapter.diffItemCallBack)
-                dataInit = true
-                delay(100)
+    private fun observeReplaceRuleData() {
+        lifecycleScope.launch {
+            viewModel.rulesFlow.collectLatest { rules ->
+                adapter.setItems(rules, adapter.diffItemCallBack)
             }
         }
     }
@@ -256,10 +233,16 @@ class ReplaceRuleActivity : VMBaseActivity<ActivityReplaceRuleBinding, ReplaceRu
             R.id.menu_group_null -> {
                 searchView.setQuery(getString(R.string.no_group), true)
             }
+            R.id.sort_order_asc -> viewModel.setSortMode("asc")
+            R.id.sort_order_desc -> viewModel.setSortMode("desc")
+            R.id.sort_name_asc -> viewModel.setSortMode("name_asc")
+            R.id.sort_name_desc -> viewModel.setSortMode("name_desc")
             else -> if (item.groupId == R.id.replace_group) {
                 searchView.setQuery("group:${item.title}", true)
+                viewModel.setSearchKey("group:${item.title}")
             }
         }
+        observeReplaceRuleData()
         return super.onCompatOptionsItemSelected(item)
     }
 
@@ -322,7 +305,8 @@ class ReplaceRuleActivity : VMBaseActivity<ActivityReplaceRuleBinding, ReplaceRu
     }
 
     override fun onQueryTextChange(newText: String?): Boolean {
-        observeReplaceRuleData(newText)
+        searchKey = newText
+        viewModel.setSearchKey(newText)
         return false
     }
 

+ 64 - 0
app/src/main/java/io/legado/app/ui/replace/ReplaceRuleViewModel.kt

@@ -2,10 +2,22 @@ package io.legado.app.ui.replace
 
 import android.app.Application
 import android.text.TextUtils
+import io.legado.app.R
 import io.legado.app.base.BaseViewModel
+import io.legado.app.constant.AppLog
 import io.legado.app.data.appDb
 import io.legado.app.data.entities.ReplaceRule
 import io.legado.app.utils.splitNotBlank
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.catch
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOn
+import splitties.init.appCtx
 
 /**
  * 替换规则数据修改
@@ -13,6 +25,58 @@ import io.legado.app.utils.splitNotBlank
  */
 class ReplaceRuleViewModel(application: Application) : BaseViewModel(application) {
 
+    private val _sortMode = MutableStateFlow("desc")
+    private val _searchKey = MutableStateFlow<String?>(null)
+
+    val sortMode: StateFlow<String> = _sortMode
+    val searchKey: StateFlow<String?> = _searchKey
+
+    fun setSortMode(mode: String) {
+        _sortMode.value = mode
+    }
+
+    fun setSearchKey(key: String?) {
+        _searchKey.value = key
+    }
+
+    @OptIn(ExperimentalCoroutinesApi::class)
+    val rulesFlow = combine(_searchKey, _sortMode) { search, sort ->
+        Pair(search, sort)
+    }.flatMapLatest { (searchKey, sortMode) ->
+        when {
+            searchKey.isNullOrEmpty() -> when (sortMode) {
+                "asc" -> appDb.replaceRuleDao.flowAllAsc()
+                "name_asc" -> appDb.replaceRuleDao.flowAllNameAsc()
+                "name_desc" -> appDb.replaceRuleDao.flowAllNameDesc()
+                else -> appDb.replaceRuleDao.flowAllDesc()
+            }
+
+            searchKey == appCtx.getString(R.string.no_group) -> when (sortMode) {
+                "asc" -> appDb.replaceRuleDao.flowNoGroupAsc()
+                "name_asc" -> appDb.replaceRuleDao.flowNoGroupNameAsc()
+                "name_desc" -> appDb.replaceRuleDao.flowNoGroupNameDesc()
+                else -> appDb.replaceRuleDao.flowNoGroupDesc()
+            }
+
+            searchKey.startsWith("group:") -> {
+                val key = searchKey.substringAfter("group:")
+                when (sortMode) {
+                    "asc" -> appDb.replaceRuleDao.flowGroupSearchAsc("%$key%")
+                    "name_asc" -> appDb.replaceRuleDao.flowGroupSearchNameAsc("%$key%")
+                    "name_desc" -> appDb.replaceRuleDao.flowGroupSearchNameDesc("%$key%")
+                    else -> appDb.replaceRuleDao.flowGroupSearchDesc("%$key%")
+                }
+            }
+
+            else -> when (sortMode) {
+                "asc" -> appDb.replaceRuleDao.flowSearchAsc("%$searchKey%")
+                "name_asc" -> appDb.replaceRuleDao.flowSearchNameAsc("%$searchKey%")
+                "name_desc" -> appDb.replaceRuleDao.flowSearchNameDesc("%$searchKey%")
+                else -> appDb.replaceRuleDao.flowSearchDesc("%$searchKey%")
+            }
+        }
+    }.flowOn(Dispatchers.IO)
+
     fun update(vararg rule: ReplaceRule) {
         execute {
             appDb.replaceRuleDao.update(*rule)

+ 18 - 0
app/src/main/res/menu/replace_rule.xml

@@ -28,6 +28,24 @@
 
     </item>
 
+    <item
+        android:id="@+id/menu_sort"
+        android:title="@string/sort"
+        android:icon="@drawable/ic_sort"
+        app:showAsAction="always">
+        <menu>
+            <item android:id="@+id/sort_order_asc" android:title="@string/sort_old_to_new" />
+
+            <item android:id="@+id/sort_order_desc" android:title="@string/sort_new_to_old" />
+
+            <item android:id="@+id/sort_name_asc" android:title="@string/sort_name_asc" />
+
+            <item android:id="@+id/sort_name_desc" android:title="@string/sort_name_desc" />
+
+        </menu>
+    </item>
+
+
     <item
         android:id="@+id/menu_add_replace_rule"
         android:icon="@drawable/ic_add"

+ 4 - 0
app/src/main/res/values-zh/strings.xml

@@ -1321,4 +1321,8 @@
     <string name="redirect_block_all">阻止所有重定向</string>
     <string name="redirect_ask_same_domain_block_cross">域内询问且域外阻止</string>
     <string name="show_status">显示状态栏</string>
+    <string name="sort_old_to_new">从旧到新</string>
+    <string name="sort_new_to_old">从新到旧</string>
+    <string name="sort_name_asc">名称升序</string>
+    <string name="sort_name_desc">名称降序</string>
 </resources>

+ 4 - 0
app/src/main/res/values/strings.xml

@@ -1322,4 +1322,8 @@
     <string name="redirect_block_all">阻止所有重定向</string>
     <string name="redirect_ask_same_domain_block_cross">域内询问且域外阻止</string>
     <string name="show_status">显示状态栏</string>
+    <string name="sort_old_to_new">从旧到新</string>
+    <string name="sort_new_to_old">从新到旧</string>
+    <string name="sort_name_asc">名称升序</string>
+    <string name="sort_name_desc">名称降序</string>
 </resources>