Explorar el Código

refactor: 清零 RSS DAO 直连

5151561 hace 3 meses
padre
commit
2804025596

+ 33 - 0
app/src/main/java/io/legado/app/data/repository/RssArticleRepository.kt

@@ -0,0 +1,33 @@
+package io.legado.app.data.repository
+
+import io.legado.app.data.dao.RssArticleDao
+import io.legado.app.data.entities.RssArticle
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+
+class RssArticleRepository(
+    private val dao: RssArticleDao,
+) {
+
+    suspend fun findByLink(origin: String, link: String): RssArticle? =
+        withContext(Dispatchers.IO) {
+            dao.getByLink(origin, link)
+        }
+
+    suspend fun insert(vararg articles: RssArticle) = withContext(Dispatchers.IO) {
+        dao.insert(*articles)
+    }
+
+    suspend fun append(vararg articles: RssArticle) = withContext(Dispatchers.IO) {
+        dao.append(*articles)
+    }
+
+    suspend fun clearOld(origin: String, sort: String, order: Long) =
+        withContext(Dispatchers.IO) {
+            dao.clearOld(origin, sort, order)
+        }
+
+    suspend fun deleteByOrigin(origin: String) = withContext(Dispatchers.IO) {
+        dao.delete(origin)
+    }
+}

+ 6 - 0
app/src/main/java/io/legado/app/data/repository/RssFavoriteRepository.kt

@@ -2,12 +2,18 @@ package io.legado.app.data.repository
 
 
 import io.legado.app.data.dao.RssStarDao
 import io.legado.app.data.dao.RssStarDao
 import io.legado.app.data.entities.RssStar
 import io.legado.app.data.entities.RssStar
+import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.withContext
 
 
 class RssFavoriteRepository(private val dao: RssStarDao) {
 class RssFavoriteRepository(private val dao: RssStarDao) {
     fun observeGroups(): Flow<List<String>> = dao.flowGroups()
     fun observeGroups(): Flow<List<String>> = dao.flowGroups()
     fun observeAll(): Flow<List<RssStar>> = dao.liveAll()
     fun observeAll(): Flow<List<RssStar>> = dao.liveAll()
     fun observeGroup(group: String): Flow<List<RssStar>> = dao.flowByGroup(group)
     fun observeGroup(group: String): Flow<List<RssStar>> = dao.flowByGroup(group)
+    suspend fun find(origin: String, link: String): RssStar? = withContext(Dispatchers.IO) {
+        dao.get(origin, link)
+    }
+    suspend fun insert(star: RssStar) = withContext(Dispatchers.IO) { dao.insert(star) }
     suspend fun update(star: RssStar) = dao.update(star)
     suspend fun update(star: RssStar) = dao.update(star)
     suspend fun delete(star: RssStar) = dao.delete(star.origin, star.link)
     suspend fun delete(star: RssStar) = dao.delete(star.origin, star.link)
     suspend fun deleteGroup(group: String) = dao.deleteByGroup(group)
     suspend fun deleteGroup(group: String) = dao.deleteByGroup(group)

+ 23 - 0
app/src/main/java/io/legado/app/data/repository/RssReadRecordRepository.kt

@@ -0,0 +1,23 @@
+package io.legado.app.data.repository
+
+import io.legado.app.data.dao.RssReadRecordDao
+import io.legado.app.data.entities.RssReadRecord
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+
+class RssReadRecordRepository(
+    private val dao: RssReadRecordDao,
+) {
+
+    suspend fun insert(record: RssReadRecord) = withContext(Dispatchers.IO) {
+        dao.insertRecord(record)
+    }
+
+    fun getAll(): List<RssReadRecord> = dao.getRecords()
+
+    fun count(): Int = dao.countRecords
+
+    suspend fun deleteAll() = withContext(Dispatchers.IO) {
+        dao.deleteAllRecord()
+    }
+}

+ 80 - 5
app/src/main/java/io/legado/app/data/repository/RssRepository.kt

@@ -28,15 +28,28 @@ class RssRepository(
 
 
     fun getEnabledGroups(): Flow<List<String>> = dao.flowEnabledGroups()
     fun getEnabledGroups(): Flow<List<String>> = dao.flowEnabledGroups()
 
 
+    fun flowAll(): Flow<List<RssSource>> = dao.flowAll()
+
+    fun flowGroups(): Flow<List<String>> = dao.flowGroups()
+
     suspend fun getByKey(sourceUrl: String): RssSource? = withContext(Dispatchers.IO) {
     suspend fun getByKey(sourceUrl: String): RssSource? = withContext(Dispatchers.IO) {
         dao.getByKey(sourceUrl)
         dao.getByKey(sourceUrl)
     }
     }
 
 
-    suspend fun updateSources(vararg sources: RssSource) {
+    suspend fun insertSources(vararg sources: RssSource) = withContext(Dispatchers.IO) {
+        dao.insert(*sources)
+    }
+
+    suspend fun updateSources(vararg sources: RssSource) = withContext(Dispatchers.IO) {
         dao.update(*sources)
         dao.update(*sources)
     }
     }
 
 
-    suspend fun topSources(vararg sources: RssSource) {
+    suspend fun updateRedirectPolicy(sourceUrl: String, redirectPolicy: String) =
+        withContext(Dispatchers.IO) {
+            dao.updateRedirectPolicy(sourceUrl, redirectPolicy)
+        }
+
+    suspend fun topSources(vararg sources: RssSource) = withContext(Dispatchers.IO) {
         val minOrder = dao.minOrder - 1
         val minOrder = dao.minOrder - 1
         val sortedSources = sources.sortedBy { it.customOrder }
         val sortedSources = sources.sortedBy { it.customOrder }
         val updates = Array(sortedSources.size) { index ->
         val updates = Array(sortedSources.size) { index ->
@@ -45,7 +58,7 @@ class RssRepository(
         dao.update(*updates)
         dao.update(*updates)
     }
     }
 
 
-    suspend fun bottomSources(vararg sources: RssSource) {
+    suspend fun bottomSources(vararg sources: RssSource) = withContext(Dispatchers.IO) {
         val maxOrder = dao.maxOrder + 1
         val maxOrder = dao.maxOrder + 1
         val sortedSources = sources.sortedBy { it.customOrder }
         val sortedSources = sources.sortedBy { it.customOrder }
         val updates = Array(sortedSources.size) { index ->
         val updates = Array(sortedSources.size) { index ->
@@ -54,12 +67,74 @@ class RssRepository(
         dao.update(*updates)
         dao.update(*updates)
     }
     }
 
 
-    suspend fun disableSource(source: RssSource) {
+    suspend fun disableSource(source: RssSource) = withContext(Dispatchers.IO) {
         dao.update(source.copy(enabled = false))
         dao.update(source.copy(enabled = false))
     }
     }
 
 
     suspend fun deleteSources(sources: List<RssSource>) {
     suspend fun deleteSources(sources: List<RssSource>) {
-        SourceHelp.deleteRssSources(sources)
+        withContext(Dispatchers.IO) {
+            SourceHelp.deleteRssSources(sources)
+        }
+    }
+
+    suspend fun deleteByIds(ids: Set<String>) = withContext(Dispatchers.IO) {
+        if (ids.isEmpty()) return@withContext
+        SourceHelp.deleteRssSources(dao.getRssSources(*ids.toTypedArray()))
+    }
+
+    suspend fun saveOrder(sources: List<RssSource>) = withContext(Dispatchers.IO) {
+        val updated = sources.mapIndexed { index, source ->
+            source.copy(customOrder = index + 1)
+        }
+        dao.update(*updated.toTypedArray())
+    }
+
+    suspend fun normalizeOrder() = withContext(Dispatchers.IO) {
+        val updated = dao.all.mapIndexed { index, source ->
+            source.copy(customOrder = index + 1)
+        }
+        dao.update(*updated.toTypedArray())
+    }
+
+    suspend fun setEnabled(ids: Set<String>, enabled: Boolean) = withContext(Dispatchers.IO) {
+        if (ids.isEmpty()) return@withContext
+        val updated = dao.getRssSources(*ids.toTypedArray()).map { it.copy(enabled = enabled) }
+        dao.update(*updated.toTypedArray())
+    }
+
+    suspend fun addGroup(ids: Set<String>, group: String) = withContext(Dispatchers.IO) {
+        if (ids.isEmpty()) return@withContext
+        val updated = dao.getRssSources(*ids.toTypedArray()).map { it.copy().addGroup(group) }
+        dao.update(*updated.toTypedArray())
+    }
+
+    suspend fun removeGroup(ids: Set<String>, group: String) = withContext(Dispatchers.IO) {
+        if (ids.isEmpty()) return@withContext
+        val updated = dao.getRssSources(*ids.toTypedArray()).map { it.copy().removeGroup(group) }
+        dao.update(*updated.toTypedArray())
+    }
+
+    suspend fun renameGroup(oldGroup: String, newGroup: String) = withContext(Dispatchers.IO) {
+        val sources = dao.getByGroup(oldGroup)
+        sources.forEach { source ->
+            source.sourceGroup?.split(",")?.toHashSet()?.let { groups ->
+                groups.remove(oldGroup)
+                if (newGroup.isNotEmpty()) groups.add(newGroup)
+                source.sourceGroup = groups.joinToString(",")
+            }
+        }
+        dao.update(*sources.toTypedArray())
+    }
+
+    suspend fun deleteGroup(group: String) = withContext(Dispatchers.IO) {
+        val sources = dao.getByGroup(group)
+        sources.forEach { source ->
+            source.sourceGroup?.split(",")?.toHashSet()?.let { groups ->
+                groups.remove(group)
+                source.sourceGroup = groups.joinToString(",")
+            }
+        }
+        dao.update(*sources.toTypedArray())
     }
     }
 
 
     fun getMinOrder(): Int = dao.minOrder
     fun getMinOrder(): Int = dao.minOrder

+ 34 - 0
app/src/main/java/io/legado/app/data/repository/RssSourceEditRepository.kt

@@ -0,0 +1,34 @@
+package io.legado.app.data.repository
+
+import io.legado.app.data.dao.CacheDao
+import io.legado.app.data.dao.RssArticleDao
+import io.legado.app.data.dao.RssSourceDao
+import io.legado.app.data.dao.RssStarDao
+import io.legado.app.data.entities.RssSource
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+
+class RssSourceEditRepository(
+    private val sourceDao: RssSourceDao,
+    private val starDao: RssStarDao,
+    private val articleDao: RssArticleDao,
+    private val cacheDao: CacheDao,
+) {
+
+    suspend fun findByUrl(sourceUrl: String): RssSource? = withContext(Dispatchers.IO) {
+        sourceDao.getByKey(sourceUrl)
+    }
+
+    suspend fun save(oldSource: RssSource?, source: RssSource): Boolean =
+        withContext(Dispatchers.IO) {
+            val originChanged = oldSource != null && oldSource.sourceUrl != source.sourceUrl
+            oldSource?.let { sourceDao.delete(it) }
+            if (originChanged) {
+                starDao.updateOrigin(source.sourceUrl, oldSource.sourceUrl)
+                articleDao.updateOrigin(source.sourceUrl, oldSource.sourceUrl)
+                cacheDao.deleteSourceVariables(oldSource.sourceUrl)
+            }
+            sourceDao.insert(source)
+            originChanged
+        }
+}

+ 6 - 0
app/src/main/java/io/legado/app/di/appModule.kt

@@ -69,8 +69,11 @@ import io.legado.app.data.repository.ReadSettingsRepository
 import io.legado.app.data.repository.ReadStyleRepository
 import io.legado.app.data.repository.ReadStyleRepository
 import io.legado.app.data.repository.RemoteBookRepository
 import io.legado.app.data.repository.RemoteBookRepository
 import io.legado.app.data.repository.ReplaceRuleRepository
 import io.legado.app.data.repository.ReplaceRuleRepository
+import io.legado.app.data.repository.RssArticleRepository
 import io.legado.app.data.repository.RssFavoriteRepository
 import io.legado.app.data.repository.RssFavoriteRepository
+import io.legado.app.data.repository.RssReadRecordRepository
 import io.legado.app.data.repository.RssRepository
 import io.legado.app.data.repository.RssRepository
+import io.legado.app.data.repository.RssSourceEditRepository
 import io.legado.app.data.repository.RuleSubscriptionRepository
 import io.legado.app.data.repository.RuleSubscriptionRepository
 import io.legado.app.data.repository.SearchContentRepository
 import io.legado.app.data.repository.SearchContentRepository
 import io.legado.app.data.repository.SearchRepository
 import io.legado.app.data.repository.SearchRepository
@@ -422,6 +425,9 @@ val appModule = module {
     single<ExploreBooksGateway> { get<ExploreRepositoryImpl>() }
     single<ExploreBooksGateway> { get<ExploreRepositoryImpl>() }
     singleOf(::RssRepository)
     singleOf(::RssRepository)
     singleOf(::RssFavoriteRepository)
     singleOf(::RssFavoriteRepository)
+    singleOf(::RssArticleRepository)
+    singleOf(::RssReadRecordRepository)
+    singleOf(::RssSourceEditRepository)
     singleOf(::RuleSubscriptionRepository)
     singleOf(::RuleSubscriptionRepository)
     single {
     single {
         SearchRepositoryImpl(get())
         SearchRepositoryImpl(get())

+ 11 - 8
app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt

@@ -5,9 +5,9 @@ import android.os.Bundle
 import androidx.lifecycle.viewModelScope
 import androidx.lifecycle.viewModelScope
 import io.legado.app.base.BaseViewModel
 import io.legado.app.base.BaseViewModel
 import io.legado.app.constant.AppLog
 import io.legado.app.constant.AppLog
-import io.legado.app.data.appDb
 import io.legado.app.data.entities.RssArticle
 import io.legado.app.data.entities.RssArticle
 import io.legado.app.data.entities.RssSource
 import io.legado.app.data.entities.RssSource
+import io.legado.app.data.repository.RssArticleRepository
 import io.legado.app.model.rss.Rss
 import io.legado.app.model.rss.Rss
 import io.legado.app.utils.stackTraceStr
 import io.legado.app.utils.stackTraceStr
 import kotlinx.coroutines.Dispatchers.IO
 import kotlinx.coroutines.Dispatchers.IO
@@ -15,7 +15,10 @@ import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.asStateFlow
 import kotlinx.coroutines.flow.asStateFlow
 
 
-class RssArticlesViewModel(application: Application) : BaseViewModel(application) {
+class RssArticlesViewModel(
+    application: Application,
+    private val repository: RssArticleRepository,
+) : BaseViewModel(application) {
 
 
     private val _loadState = MutableStateFlow(RssArticlesLoadState())
     private val _loadState = MutableStateFlow(RssArticlesLoadState())
     val loadState: StateFlow<RssArticlesLoadState> = _loadState.asStateFlow()
     val loadState: StateFlow<RssArticlesLoadState> = _loadState.asStateFlow()
@@ -62,9 +65,9 @@ class RssArticlesViewModel(application: Application) : BaseViewModel(application
             articles.forEach { rssArticle ->
             articles.forEach { rssArticle ->
                 rssArticle.order = order--
                 rssArticle.order = order--
             }
             }
-            appDb.rssArticleDao.insert(*articles.toTypedArray())
+            repository.insert(*articles.toTypedArray())
             if (!rssSource.ruleNextPage.isNullOrEmpty()) {
             if (!rssSource.ruleNextPage.isNullOrEmpty()) {
-                appDb.rssArticleDao.clearOld(rssSource.sourceUrl, sortName, order)
+                repository.clearOld(rssSource.sourceUrl, sortName, order)
             }
             }
             val hasMore = articles.isNotEmpty() && !rssSource.ruleNextPage.isNullOrEmpty()
             val hasMore = articles.isNotEmpty() && !rssSource.ruleNextPage.isNullOrEmpty()
             _loadState.value = _loadState.value.copy(
             _loadState.value = _loadState.value.copy(
@@ -112,7 +115,7 @@ class RssArticlesViewModel(application: Application) : BaseViewModel(application
         }
         }
     }
     }
 
 
-    private fun loadMoreSuccess(articles: MutableList<RssArticle>) {
+    private suspend fun loadMoreSuccess(articles: MutableList<RssArticle>) {
         if (articles.isEmpty()) {
         if (articles.isEmpty()) {
             _loadState.value = _loadState.value.copy(
             _loadState.value = _loadState.value.copy(
                 isLoadingMore = false,
                 isLoadingMore = false,
@@ -121,9 +124,9 @@ class RssArticlesViewModel(application: Application) : BaseViewModel(application
             return
             return
         }
         }
         val firstArticle = articles.first()
         val firstArticle = articles.first()
-        val dbFirstArticle = appDb.rssArticleDao.getByLink(firstArticle.origin, firstArticle.link)
+        val dbFirstArticle = repository.findByLink(firstArticle.origin, firstArticle.link)
         val lastArticle = articles.last()
         val lastArticle = articles.last()
-        val dbLastArticle = appDb.rssArticleDao.getByLink(lastArticle.origin, lastArticle.link)
+        val dbLastArticle = repository.findByLink(lastArticle.origin, lastArticle.link)
 
 
         val shouldStop = dbFirstArticle != null && dbLastArticle != null
         val shouldStop = dbFirstArticle != null && dbLastArticle != null
         if (shouldStop) {
         if (shouldStop) {
@@ -137,7 +140,7 @@ class RssArticlesViewModel(application: Application) : BaseViewModel(application
         articles.forEach {
         articles.forEach {
             it.order = order--
             it.order = order--
         }
         }
-        appDb.rssArticleDao.append(*articles.toTypedArray())
+        repository.append(*articles.toTypedArray())
 
 
         _loadState.value = _loadState.value.copy(
         _loadState.value = _loadState.value.copy(
             isLoadingMore = false,
             isLoadingMore = false,

+ 15 - 10
app/src/main/java/io/legado/app/ui/rss/article/RssSortViewModel.kt

@@ -3,10 +3,12 @@ package io.legado.app.ui.rss.article
 import android.app.Application
 import android.app.Application
 import androidx.lifecycle.MutableLiveData
 import androidx.lifecycle.MutableLiveData
 import io.legado.app.base.BaseViewModel
 import io.legado.app.base.BaseViewModel
-import io.legado.app.data.appDb
 import io.legado.app.data.entities.RssArticle
 import io.legado.app.data.entities.RssArticle
 import io.legado.app.data.entities.RssReadRecord
 import io.legado.app.data.entities.RssReadRecord
 import io.legado.app.data.entities.RssSource
 import io.legado.app.data.entities.RssSource
+import io.legado.app.data.repository.RssArticleRepository
+import io.legado.app.data.repository.RssReadRecordRepository
+import io.legado.app.data.repository.RssRepository
 import io.legado.app.domain.gateway.BookshelfSettingsGateway
 import io.legado.app.domain.gateway.BookshelfSettingsGateway
 import io.legado.app.help.source.removeSortCache
 import io.legado.app.help.source.removeSortCache
 import io.legado.app.help.source.sortUrls
 import io.legado.app.help.source.sortUrls
@@ -23,6 +25,9 @@ import kotlinx.coroutines.flow.stateIn
 class RssSortViewModel(
 class RssSortViewModel(
     application: Application,
     application: Application,
     bookshelfSettingsGateway: BookshelfSettingsGateway,
     bookshelfSettingsGateway: BookshelfSettingsGateway,
+    private val rssRepository: RssRepository,
+    private val articleRepository: RssArticleRepository,
+    private val readRecordRepository: RssReadRecordRepository,
 ) : BaseViewModel(application) {
 ) : BaseViewModel(application) {
     val shouldShowExpandButton = bookshelfSettingsGateway.settings
     val shouldShowExpandButton = bookshelfSettingsGateway.settings
         .map { it.shouldShowExpandButton }
         .map { it.shouldShowExpandButton }
@@ -34,10 +39,10 @@ class RssSortViewModel(
     val isGridLayout get() = rssSource?.articleStyle == 2
     val isGridLayout get() = rssSource?.articleStyle == 2
     val isWaterLayout get() = rssSource?.articleStyle == 3
     val isWaterLayout get() = rssSource?.articleStyle == 3
 
 
-    fun initDataSource(sourceUrl: String?) {
+    suspend fun initDataSource(sourceUrl: String?) {
         url = sourceUrl
         url = sourceUrl
         url?.let { src ->
         url?.let { src ->
-            rssSource = appDb.rssSourceDao.getByKey(src)
+            rssSource = rssRepository.getByKey(src)
             rssSource?.let {
             rssSource?.let {
                 titleLiveData.postValue(it.sourceName)
                 titleLiveData.postValue(it.sourceName)
             } ?: run {
             } ?: run {
@@ -82,7 +87,7 @@ class RssSortViewModel(
                 it.articleStyle = 0
                 it.articleStyle = 0
             }
             }
             execute {
             execute {
-                appDb.rssSourceDao.update(it)
+                rssRepository.updateSources(it)
             }
             }
         }
         }
     }
     }
@@ -94,14 +99,14 @@ class RssSortViewModel(
                 title = rssArticle.title,
                 title = rssArticle.title,
                 readTime = System.currentTimeMillis()
                 readTime = System.currentTimeMillis()
             )
             )
-            appDb.rssReadRecordDao.insertRecord(rssReadRecord)
+            readRecordRepository.insert(rssReadRecord)
         }
         }
     }
     }
 
 
     fun clearArticles() {
     fun clearArticles() {
         execute {
         execute {
             url?.let {
             url?.let {
-                appDb.rssArticleDao.delete(it)
+                articleRepository.deleteByOrigin(it)
             }
             }
             order = System.currentTimeMillis()
             order = System.currentTimeMillis()
         }
         }
@@ -116,22 +121,22 @@ class RssSortViewModel(
     }
     }
 
 
     fun getRecords(): List<RssReadRecord> {
     fun getRecords(): List<RssReadRecord> {
-        return appDb.rssReadRecordDao.getRecords()
+        return readRecordRepository.getAll()
     }
     }
 
 
     fun countRecords(): Int {
     fun countRecords(): Int {
-        return appDb.rssReadRecordDao.countRecords
+        return readRecordRepository.count()
     }
     }
 
 
     fun deleteAllRecord() {
     fun deleteAllRecord() {
         execute {
         execute {
-            appDb.rssReadRecordDao.deleteAllRecord()
+            readRecordRepository.deleteAll()
         }
         }
     }
     }
 
 
     fun updateRssSourceRedirectPolicy(sourceUrl: String, redirectPolicy: String) {
     fun updateRssSourceRedirectPolicy(sourceUrl: String, redirectPolicy: String) {
         execute {
         execute {
-            appDb.rssSourceDao.updateRedirectPolicy(sourceUrl, redirectPolicy)
+            rssRepository.updateRedirectPolicy(sourceUrl, redirectPolicy)
             rssSource?.redirectPolicy = redirectPolicy
             rssSource?.redirectPolicy = redirectPolicy
         }.onError {
         }.onError {
             appCtx.toastOnUi("保存失败: ${it.localizedMessage}")
             appCtx.toastOnUi("保存失败: ${it.localizedMessage}")

+ 16 - 10
app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt

@@ -7,11 +7,13 @@ import android.webkit.URLUtil
 import androidx.lifecycle.viewModelScope
 import androidx.lifecycle.viewModelScope
 import com.script.rhino.runScriptWithContext
 import com.script.rhino.runScriptWithContext
 import io.legado.app.base.BaseViewModel
 import io.legado.app.base.BaseViewModel
-import io.legado.app.data.appDb
 import io.legado.app.data.entities.RssArticle
 import io.legado.app.data.entities.RssArticle
 import io.legado.app.data.entities.RssSource
 import io.legado.app.data.entities.RssSource
 import io.legado.app.help.config.AppConfig
 import io.legado.app.help.config.AppConfig
 import io.legado.app.data.entities.RssStar
 import io.legado.app.data.entities.RssStar
+import io.legado.app.data.repository.RssArticleRepository
+import io.legado.app.data.repository.RssFavoriteRepository
+import io.legado.app.data.repository.RssRepository
 import io.legado.app.domain.gateway.AppShellSettingsGateway
 import io.legado.app.domain.gateway.AppShellSettingsGateway
 import io.legado.app.domain.gateway.DownloadCacheSettingsGateway
 import io.legado.app.domain.gateway.DownloadCacheSettingsGateway
 import io.legado.app.exception.NoStackTraceException
 import io.legado.app.exception.NoStackTraceException
@@ -50,6 +52,9 @@ class ReadRssViewModel(
     application: Application,
     application: Application,
     appShellSettingsGateway: AppShellSettingsGateway,
     appShellSettingsGateway: AppShellSettingsGateway,
     downloadCacheSettingsGateway: DownloadCacheSettingsGateway,
     downloadCacheSettingsGateway: DownloadCacheSettingsGateway,
+    private val rssRepository: RssRepository,
+    private val articleRepository: RssArticleRepository,
+    private val favoriteRepository: RssFavoriteRepository,
 ) : BaseViewModel(application) {
 ) : BaseViewModel(application) {
     val settings = combine(
     val settings = combine(
         appShellSettingsGateway.settings,
         appShellSettingsGateway.settings,
@@ -92,7 +97,7 @@ class ReadRssViewModel(
 
 
     fun initData(args: ReadRssArgs) {
     fun initData(args: ReadRssArgs) {
         execute {
         execute {
-            rssSource = appDb.rssSourceDao.getByKey(args.origin)
+            rssSource = rssRepository.getByKey(args.origin)
             headerMap = runScriptWithContext {
             headerMap = runScriptWithContext {
                 rssSource?.getHeaderMap(AppConfig.userAgent) ?: emptyMap()
                 rssSource?.getHeaderMap(AppConfig.userAgent) ?: emptyMap()
             }
             }
@@ -104,8 +109,9 @@ class ReadRssViewModel(
 
 
             val link = args.link
             val link = args.link
             if (!link.isNullOrBlank()) {
             if (!link.isNullOrBlank()) {
-                _rssStarState.value = appDb.rssStarDao.get(args.origin, link)
-                rssArticle = _rssStarState.value?.toRssArticle() ?: appDb.rssArticleDao.getByLink(args.origin, link)
+                _rssStarState.value = favoriteRepository.find(args.origin, link)
+                rssArticle = _rssStarState.value?.toRssArticle()
+                    ?: articleRepository.findByLink(args.origin, link)
                 val article = rssArticle ?: return@execute
                 val article = rssArticle ?: return@execute
                 if (!article.description.isNullOrBlank()) {
                 if (!article.description.isNullOrBlank()) {
                     _contentState.value = article.description!!
                     _contentState.value = article.description!!
@@ -177,10 +183,10 @@ class ReadRssViewModel(
         Rss.getContent(viewModelScope, rssArticle, ruleContent, source)
         Rss.getContent(viewModelScope, rssArticle, ruleContent, source)
             .onSuccess(IO) { body ->
             .onSuccess(IO) { body ->
                 rssArticle.description = body
                 rssArticle.description = body
-                appDb.rssArticleDao.insert(rssArticle)
+                articleRepository.insert(rssArticle)
                 _rssStarState.value?.let {
                 _rssStarState.value?.let {
                     it.description = body
                     it.description = body
-                    appDb.rssStarDao.insert(it)
+                    favoriteRepository.insert(it)
                 }
                 }
                 _contentState.value = body
                 _contentState.value = body
             }.onError {
             }.onError {
@@ -207,7 +213,7 @@ class ReadRssViewModel(
     fun addFavorite() {
     fun addFavorite() {
         execute {
         execute {
             _rssStarState.value ?: rssArticle?.toStar()?.let {
             _rssStarState.value ?: rssArticle?.toStar()?.let {
-                appDb.rssStarDao.insert(it)
+                favoriteRepository.insert(it)
                 _rssStarState.value = it
                 _rssStarState.value = it
             }
             }
         }
         }
@@ -224,7 +230,7 @@ class ReadRssViewModel(
         }
         }
         execute {
         execute {
             rssArticle?.toStar()?.let {
             rssArticle?.toStar()?.let {
-                appDb.rssStarDao.update(it)
+                favoriteRepository.update(it)
                 _rssStarState.value = it
                 _rssStarState.value = it
             }
             }
         }
         }
@@ -233,7 +239,7 @@ class ReadRssViewModel(
     fun delFavorite() {
     fun delFavorite() {
         execute {
         execute {
             _rssStarState.value?.let {
             _rssStarState.value?.let {
-                appDb.rssStarDao.delete(it.origin, it.link)
+                favoriteRepository.delete(it)
                 _rssStarState.value = null
                 _rssStarState.value = null
             }
             }
         }
         }
@@ -357,7 +363,7 @@ class ReadRssViewModel(
 
 
     fun updateRssSourceRedirectPolicy(sourceUrl: String, redirectPolicy: String) {
     fun updateRssSourceRedirectPolicy(sourceUrl: String, redirectPolicy: String) {
         execute {
         execute {
-            appDb.rssSourceDao.updateRedirectPolicy(sourceUrl, redirectPolicy)
+            rssRepository.updateRedirectPolicy(sourceUrl, redirectPolicy)
             rssSource?.redirectPolicy = redirectPolicy
             rssSource?.redirectPolicy = redirectPolicy
         }.onError {
         }.onError {
             appCtx.toastOnUi("保存失败: ${it.localizedMessage}")
             appCtx.toastOnUi("保存失败: ${it.localizedMessage}")

+ 7 - 4
app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt

@@ -6,8 +6,8 @@ import androidx.lifecycle.viewModelScope
 import com.google.gson.JsonObject
 import com.google.gson.JsonObject
 import com.google.gson.JsonParser
 import com.google.gson.JsonParser
 import io.legado.app.R
 import io.legado.app.R
-import io.legado.app.data.appDb
 import io.legado.app.data.entities.RssSource
 import io.legado.app.data.entities.RssSource
+import io.legado.app.data.repository.RssSourceEditRepository
 import io.legado.app.exception.NoStackTraceException
 import io.legado.app.exception.NoStackTraceException
 import io.legado.app.help.AppCacheManager
 import io.legado.app.help.AppCacheManager
 import io.legado.app.help.RuleComplete
 import io.legado.app.help.RuleComplete
@@ -26,7 +26,10 @@ import kotlinx.coroutines.flow.asStateFlow
 import kotlinx.coroutines.flow.update
 import kotlinx.coroutines.flow.update
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.launch
 
 
-class RssSourceEditViewModel(app: Application) : AndroidViewModel(app) {
+class RssSourceEditViewModel(
+    app: Application,
+    private val repository: RssSourceEditRepository,
+) : AndroidViewModel(app) {
     private val _uiState = MutableStateFlow(RssSourceEditUiState()); val uiState = _uiState.asStateFlow()
     private val _uiState = MutableStateFlow(RssSourceEditUiState()); val uiState = _uiState.asStateFlow()
     private val _effects = MutableSharedFlow<RssSourceEditEffect>(extraBufferCapacity = 16); val effects = _effects.asSharedFlow()
     private val _effects = MutableSharedFlow<RssSourceEditEffect>(extraBufferCapacity = 16); val effects = _effects.asSharedFlow()
     private var original: RssSource? = null; private var json = JsonObject(); private var baseline = ""
     private var original: RssSource? = null; private var json = JsonObject(); private var baseline = ""
@@ -53,7 +56,7 @@ class RssSourceEditViewModel(app: Application) : AndroidViewModel(app) {
             )
             )
         }; RssSourceEditIntent.Back -> _effects.tryEmit(RssSourceEditEffect.Finish(""))
         }; RssSourceEditIntent.Back -> _effects.tryEmit(RssSourceEditEffect.Finish(""))
     } }
     } }
-    private fun load(url:String?)=viewModelScope.launch(Dispatchers.IO){ apply(url?.let{appDb.rssSourceDao.getByKey(it)}?:RssSource(),true) }
+    private fun load(url:String?)=viewModelScope.launch(Dispatchers.IO){ apply(url?.let{repository.findByUrl(it)}?:RssSource(),true) }
     private fun showHelp() = viewModelScope.launch(Dispatchers.IO) {
     private fun showHelp() = viewModelScope.launch(Dispatchers.IO) {
         val content =
         val content =
             getApplication<Application>().assets.open("web/help/md/ruleHelp.md").bufferedReader()
             getApplication<Application>().assets.open("web/help/md/ruleHelp.md").bufferedReader()
@@ -69,7 +72,7 @@ class RssSourceEditViewModel(app: Application) : AndroidViewModel(app) {
     private fun update(k:String,v:String){ if(v.isBlank())json.remove(k) else json.addProperty(k,v);_uiState.update{st->st.copy(fields=st.fields.mapValues{(_,fs)->fs.map{if(it.path==k)it.copy(value=v)else it}.toImmutableList()}.toImmutableMap(),dirty=true)} }
     private fun update(k:String,v:String){ if(v.isBlank())json.remove(k) else json.addProperty(k,v);_uiState.update{st->st.copy(fields=st.fields.mapValues{(_,fs)->fs.map{if(it.path==k)it.copy(value=v)else it}.toImmutableList()}.toImmutableMap(),dirty=true)} }
     private fun flag(f:RssSourceEditUiState.()->RssSourceEditUiState)=_uiState.update{f(it).copy(dirty=true)}
     private fun flag(f:RssSourceEditUiState.()->RssSourceEditUiState)=_uiState.update{f(it).copy(dirty=true)}
     private fun current():RssSource=GSON.fromJson(json,RssSource::class.java).apply{val s=_uiState.value;enabled=s.enabled;singleUrl=s.singleUrl;enabledCookieJar=s.cookieJar;preload=s.preload;type=s.type;articleStyle=s.articleStyle;if(s.autoComplete){ruleNextPage=RuleComplete.autoComplete(ruleNextPage,ruleArticles,2);ruleTitle=RuleComplete.autoComplete(ruleTitle,ruleArticles);rulePubDate=RuleComplete.autoComplete(rulePubDate,ruleArticles);ruleDescription=RuleComplete.autoComplete(ruleDescription,ruleArticles);ruleImage=RuleComplete.autoComplete(ruleImage,ruleArticles,3);ruleLink=RuleComplete.autoComplete(ruleLink,ruleArticles);ruleContent=RuleComplete.autoComplete(ruleContent,ruleArticles)}}
     private fun current():RssSource=GSON.fromJson(json,RssSource::class.java).apply{val s=_uiState.value;enabled=s.enabled;singleUrl=s.singleUrl;enabledCookieJar=s.cookieJar;preload=s.preload;type=s.type;articleStyle=s.articleStyle;if(s.autoComplete){ruleNextPage=RuleComplete.autoComplete(ruleNextPage,ruleArticles,2);ruleTitle=RuleComplete.autoComplete(ruleTitle,ruleArticles);rulePubDate=RuleComplete.autoComplete(rulePubDate,ruleArticles);ruleDescription=RuleComplete.autoComplete(ruleDescription,ruleArticles);ruleImage=RuleComplete.autoComplete(ruleImage,ruleArticles,3);ruleLink=RuleComplete.autoComplete(ruleLink,ruleArticles);ruleContent=RuleComplete.autoComplete(ruleContent,ruleArticles)}}
-    private fun save(effect:(String)->RssSourceEditEffect)=viewModelScope.launch(Dispatchers.IO){runCatching{val s=current();if(s.sourceName.isBlank()||s.sourceUrl.isBlank())throw NoStackTraceException(getApplication<Application>().getString(R.string.non_null_name_url));val old=original?:RssSource();if(!s.equal(old)){s.lastUpdateTime=System.currentTimeMillis();if(old.sortUrl!=s.sortUrl)old.removeSortCache();if(old.jsLib!=s.jsLib)SharedJsScope.remove(old.jsLib)};original?.let{appDb.rssSourceDao.delete(it);if(it.sourceUrl!=s.sourceUrl){appDb.rssStarDao.updateOrigin(s.sourceUrl,it.sourceUrl);appDb.rssArticleDao.updateOrigin(s.sourceUrl,it.sourceUrl);appDb.cacheDao.deleteSourceVariables(it.sourceUrl);AppCacheManager.clearSourceVariables()}};appDb.rssSourceDao.insert(s);original=s;baseline=GSON.toJson(s);s.sourceUrl}.onSuccess{_uiState.update{s->s.copy(dirty=false)};_effects.emit(effect(it))}.onFailure{_effects.emit(RssSourceEditEffect.Message(it.localizedMessage?:"Error"))}}
+    private fun save(effect:(String)->RssSourceEditEffect)=viewModelScope.launch(Dispatchers.IO){runCatching{val s=current();if(s.sourceName.isBlank()||s.sourceUrl.isBlank())throw NoStackTraceException(getApplication<Application>().getString(R.string.non_null_name_url));val old=original?:RssSource();if(!s.equal(old)){s.lastUpdateTime=System.currentTimeMillis();if(old.sortUrl!=s.sortUrl)old.removeSortCache();if(old.jsLib!=s.jsLib)SharedJsScope.remove(old.jsLib)};if(repository.save(original,s))AppCacheManager.clearSourceVariables();original=s;baseline=GSON.toJson(s);s.sourceUrl}.onSuccess{_uiState.update{s->s.copy(dirty=false)};_effects.emit(effect(it))}.onFailure{_effects.emit(RssSourceEditEffect.Message(it.localizedMessage?:"Error"))}}
     private fun import(text:String)=runCatching{GSON.fromJson(text,RssSource::class.java)}.onSuccess{apply(it);_uiState.update{s->s.copy(dirty=true)}}.onFailure{_effects.tryEmit(RssSourceEditEffect.Message(it.localizedMessage?:"格式不对"))}
     private fun import(text:String)=runCatching{GSON.fromJson(text,RssSource::class.java)}.onSuccess{apply(it);_uiState.update{s->s.copy(dirty=true)}}.onFailure{_effects.tryEmit(RssSourceEditEffect.Message(it.localizedMessage?:"格式不对"))}
     private data class F(val k:String,val r:Int?=null,val l:String?=null)
     private data class F(val k:String,val r:Int?=null,val l:String?=null)
     private fun groups()=SPECS.mapValues{(_,v)->v.map{BookSourceEditFieldUi(it.k,it.r,it.l,json.get(it.k)?.takeUnless{e->e.isJsonNull}?.asString.orEmpty())}.toImmutableList()}.toImmutableMap()
     private fun groups()=SPECS.mapValues{(_,v)->v.map{BookSourceEditFieldUi(it.k,it.r,it.l,json.get(it.k)?.takeUnless{e->e.isJsonNull}?.asString.orEmpty())}.toImmutableList()}.toImmutableMap()

+ 20 - 61
app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt

@@ -8,11 +8,10 @@ import androidx.lifecycle.viewModelScope
 import io.legado.app.R
 import io.legado.app.R
 import io.legado.app.base.BaseRuleViewModel
 import io.legado.app.base.BaseRuleViewModel
 import io.legado.app.base.BaseRuleEvent
 import io.legado.app.base.BaseRuleEvent
-import io.legado.app.data.appDb
 import io.legado.app.data.entities.RssSource
 import io.legado.app.data.entities.RssSource
+import io.legado.app.data.repository.RssRepository
 import io.legado.app.data.repository.UploadRepository
 import io.legado.app.data.repository.UploadRepository
 import io.legado.app.help.DefaultData
 import io.legado.app.help.DefaultData
-import io.legado.app.help.source.SourceHelp
 import io.legado.app.ui.widget.components.importComponents.BaseImportUiState
 import io.legado.app.ui.widget.components.importComponents.BaseImportUiState
 import io.legado.app.ui.widget.components.list.InteractionState
 import io.legado.app.ui.widget.components.list.InteractionState
 import io.legado.app.ui.widget.components.list.ListUiState
 import io.legado.app.ui.widget.components.list.ListUiState
@@ -107,7 +106,8 @@ sealed interface RssSourceEffect {
 
 
 class RssSourceViewModel(
 class RssSourceViewModel(
     application: Application,
     application: Application,
-    uploadRepository: UploadRepository
+    uploadRepository: UploadRepository,
+    private val repository: RssRepository,
 ) : BaseRuleViewModel<RssSourceItemUi, RssSource, String, RssSourceUiState>(
 ) : BaseRuleViewModel<RssSourceItemUi, RssSource, String, RssSourceUiState>(
     application,
     application,
     RssSourceUiState(interaction = InteractionState(isLoading = true)),
     RssSourceUiState(interaction = InteractionState(isLoading = true)),
@@ -121,11 +121,9 @@ class RssSourceViewModel(
         const val PREFIX_GROUP = "group:"
         const val PREFIX_GROUP = "group:"
     }
     }
 
 
-    private val dao = appDb.rssSourceDao
+    override val rawDataFlow: Flow<List<RssSource>> = repository.flowAll()
 
 
-    override val rawDataFlow: Flow<List<RssSource>> = dao.flowAll()
-
-    val groupsFlow: StateFlow<List<String>> = dao.flowGroups()
+    val groupsFlow: StateFlow<List<String>> = repository.flowGroups()
         .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList())
         .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList())
 
 
     private val _groupFilterName = MutableStateFlow<String?>(null)
     private val _groupFilterName = MutableStateFlow<String?>(null)
@@ -254,7 +252,7 @@ class RssSourceViewModel(
     }
     }
 
 
     override suspend fun findOldRule(newRule: RssSource): RssSource? {
     override suspend fun findOldRule(newRule: RssSource): RssSource? {
-        return withContext(Dispatchers.IO) { dao.getByKey(newRule.sourceUrl) }
+        return repository.getByKey(newRule.sourceUrl)
     }
     }
 
 
     override fun saveImportedRules() {
     override fun saveImportedRules() {
@@ -263,7 +261,7 @@ class RssSourceViewModel(
             val rulesToSave = state.items
             val rulesToSave = state.items
                 .filter { it.isSelected }
                 .filter { it.isSelected }
                 .map { it.data }
                 .map { it.data }
-            dao.insert(*rulesToSave.toTypedArray())
+            repository.insertSources(*rulesToSave.toTypedArray())
             withContext(Dispatchers.Main) {
             withContext(Dispatchers.Main) {
                 _importState.value = BaseImportUiState.Idle
                 _importState.value = BaseImportUiState.Idle
             }
             }
@@ -304,10 +302,7 @@ class RssSourceViewModel(
     fun saveSortOrder() {
     fun saveSortOrder() {
         val currentLocal = _localItems.value ?: return
         val currentLocal = _localItems.value ?: return
         viewModelScope.launch(Dispatchers.IO) {
         viewModelScope.launch(Dispatchers.IO) {
-            val sources = currentLocal.mapIndexed { index, item ->
-                item.source.copy(customOrder = index + 1)
-            }
-            dao.update(*sources.toTypedArray())
+            repository.saveOrder(currentLocal.map { it.source })
             withContext(Dispatchers.Main) {
             withContext(Dispatchers.Main) {
                 _localItems.value = null
                 _localItems.value = null
             }
             }
@@ -316,65 +311,48 @@ class RssSourceViewModel(
 
 
     fun topSource(vararg sources: RssSource) {
     fun topSource(vararg sources: RssSource) {
         viewModelScope.launch(Dispatchers.IO) {
         viewModelScope.launch(Dispatchers.IO) {
-            val minOrder = dao.minOrder - 1
-            val updated = sources.sortedBy { it.customOrder }.mapIndexed { index, source ->
-                source.copy(customOrder = minOrder - index)
-            }
-            dao.update(*updated.toTypedArray())
+            repository.topSources(*sources)
         }
         }
     }
     }
 
 
     fun bottomSource(vararg sources: RssSource) {
     fun bottomSource(vararg sources: RssSource) {
         viewModelScope.launch(Dispatchers.IO) {
         viewModelScope.launch(Dispatchers.IO) {
-            val maxOrder = dao.maxOrder + 1
-            val updated = sources.sortedBy { it.customOrder }.mapIndexed { index, source ->
-                source.copy(customOrder = maxOrder + index)
-            }
-            dao.update(*updated.toTypedArray())
+            repository.bottomSources(*sources)
         }
         }
     }
     }
 
 
     fun del(vararg rssSource: RssSource) {
     fun del(vararg rssSource: RssSource) {
         viewModelScope.launch(Dispatchers.IO) {
         viewModelScope.launch(Dispatchers.IO) {
-            SourceHelp.deleteRssSources(rssSource.toList())
+            repository.deleteSources(rssSource.toList())
         }
         }
     }
     }
 
 
     fun delSelectionByIds(ids: Set<String>) {
     fun delSelectionByIds(ids: Set<String>) {
         viewModelScope.launch(Dispatchers.IO) {
         viewModelScope.launch(Dispatchers.IO) {
-            val sources = dao.getRssSources(*ids.toTypedArray())
-            SourceHelp.deleteRssSources(sources)
+            repository.deleteByIds(ids)
             _selectedIds.update { it - ids }
             _selectedIds.update { it - ids }
         }
         }
     }
     }
 
 
     fun update(vararg rssSource: RssSource) {
     fun update(vararg rssSource: RssSource) {
-        viewModelScope.launch(Dispatchers.IO) { dao.update(*rssSource) }
+        viewModelScope.launch(Dispatchers.IO) { repository.updateSources(*rssSource) }
     }
     }
 
 
     fun upOrder() {
     fun upOrder() {
         viewModelScope.launch(Dispatchers.IO) {
         viewModelScope.launch(Dispatchers.IO) {
-            val sources = dao.all
-            for ((index: Int, source: RssSource) in sources.withIndex()) {
-                source.customOrder = index + 1
-            }
-            dao.update(*sources.toTypedArray())
+            repository.normalizeOrder()
         }
         }
     }
     }
 
 
     fun enableSelectionByIds(ids: Set<String>) {
     fun enableSelectionByIds(ids: Set<String>) {
         viewModelScope.launch(Dispatchers.IO) {
         viewModelScope.launch(Dispatchers.IO) {
-            val sources = dao.getRssSources(*ids.toTypedArray())
-            val updated = sources.map { it.copy(enabled = true) }
-            dao.update(*updated.toTypedArray())
+            repository.setEnabled(ids, true)
         }
         }
     }
     }
 
 
     fun disableSelectionByIds(ids: Set<String>) {
     fun disableSelectionByIds(ids: Set<String>) {
         viewModelScope.launch(Dispatchers.IO) {
         viewModelScope.launch(Dispatchers.IO) {
-            val sources = dao.getRssSources(*ids.toTypedArray())
-            val updated = sources.map { it.copy(enabled = false) }
-            dao.update(*updated.toTypedArray())
+            repository.setEnabled(ids, false)
         }
         }
     }
     }
 
 
@@ -394,44 +372,25 @@ class RssSourceViewModel(
 
 
     fun selectionAddToGroups(ids: Set<String>, groups: String) {
     fun selectionAddToGroups(ids: Set<String>, groups: String) {
         viewModelScope.launch(Dispatchers.IO) {
         viewModelScope.launch(Dispatchers.IO) {
-            val sources = dao.getRssSources(*ids.toTypedArray())
-            val updated = sources.map { it.copy().addGroup(groups) }
-            dao.update(*updated.toTypedArray())
+            repository.addGroup(ids, groups)
         }
         }
     }
     }
 
 
     fun selectionRemoveFromGroups(ids: Set<String>, groups: String) {
     fun selectionRemoveFromGroups(ids: Set<String>, groups: String) {
         viewModelScope.launch(Dispatchers.IO) {
         viewModelScope.launch(Dispatchers.IO) {
-            val sources = dao.getRssSources(*ids.toTypedArray())
-            val updated = sources.map { it.copy().removeGroup(groups) }
-            dao.update(*updated.toTypedArray())
+            repository.removeGroup(ids, groups)
         }
         }
     }
     }
 
 
     fun upGroup(oldGroup: String, newGroup: String) {
     fun upGroup(oldGroup: String, newGroup: String) {
         viewModelScope.launch(Dispatchers.IO) {
         viewModelScope.launch(Dispatchers.IO) {
-            val sources = dao.getByGroup(oldGroup)
-            sources.forEach { source ->
-                source.sourceGroup?.split(",")?.toHashSet()?.let {
-                    it.remove(oldGroup)
-                    if (newGroup.isNotEmpty()) it.add(newGroup)
-                    source.sourceGroup = it.joinToString(",")
-                }
-            }
-            dao.update(*sources.toTypedArray())
+            repository.renameGroup(oldGroup, newGroup)
         }
         }
     }
     }
 
 
     fun delGroup(group: String) {
     fun delGroup(group: String) {
         viewModelScope.launch(Dispatchers.IO) {
         viewModelScope.launch(Dispatchers.IO) {
-            val sources = dao.getByGroup(group)
-            sources.forEach { source ->
-                source.sourceGroup?.split(",")?.toHashSet()?.let {
-                    it.remove(group)
-                    source.sourceGroup = it.joinToString(",")
-                }
-            }
-            dao.update(*sources.toTypedArray())
+            repository.deleteGroup(group)
         }
         }
     }
     }
 
 

+ 0 - 5
build.gradle.kts

@@ -215,11 +215,6 @@ val verifyConfigArchitecture = tasks.register<VerifyConfigArchitectureTask>(
             "io/legado/app/ui/book/toc/rule/preview/TxtTocRulePreviewViewModel.kt" to 2,
             "io/legado/app/ui/book/toc/rule/preview/TxtTocRulePreviewViewModel.kt" to 2,
             "io/legado/app/ui/browser/WebViewModel.kt" to 1,
             "io/legado/app/ui/browser/WebViewModel.kt" to 1,
             "io/legado/app/ui/login/SourceLoginViewModel.kt" to 6,
             "io/legado/app/ui/login/SourceLoginViewModel.kt" to 6,
-            "io/legado/app/ui/rss/article/RssArticlesViewModel.kt" to 5,
-            "io/legado/app/ui/rss/article/RssSortViewModel.kt" to 8,
-            "io/legado/app/ui/rss/read/ReadRssViewModel.kt" to 9,
-            "io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt" to 6,
-            "io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt" to 1,
             "io/legado/app/ui/tagGroupRule/TagGroupRuleViewModel.kt" to 4,
             "io/legado/app/ui/tagGroupRule/TagGroupRuleViewModel.kt" to 4,
         )
         )
     )
     )