arkon 1 год назад
Родитель
Сommit
ef7b285151
23 измененных файлов с 78 добавлено и 114 удалено
  1. 2 2
      app/src/main/java/eu/kanade/presentation/browse/SourcesScreen.kt
  2. 11 17
      app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupConst.kt
  3. 0 1
      app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt
  4. 0 1
      app/src/main/java/eu/kanade/tachiyomi/data/cache/ChapterCache.kt
  5. 0 1
      app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadPendingDeleter.kt
  6. 0 1
      app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadStore.kt
  7. 0 1
      app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/Anilist.kt
  8. 0 1
      app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/Bangumi.kt
  9. 0 1
      app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiApi.kt
  10. 0 1
      app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiInterceptor.kt
  11. 0 1
      app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/Kitsu.kt
  12. 0 1
      app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuInterceptor.kt
  13. 0 1
      app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeList.kt
  14. 0 1
      app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/Shikimori.kt
  15. 0 1
      app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriInterceptor.kt
  16. 2 5
      app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreen.kt
  17. 16 26
      app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreenModel.kt
  18. 10 20
      app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcesScreenModel.kt
  19. 0 1
      app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcesTab.kt
  20. 6 0
      app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt
  21. 0 3
      app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreen.kt
  22. 3 21
      app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreenModel.kt
  23. 28 6
      app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/SearchScreenModel.kt

+ 2 - 2
app/src/main/java/eu/kanade/presentation/browse/SourcesScreen.kt

@@ -23,7 +23,7 @@ import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.unit.dp
 import eu.kanade.presentation.browse.components.BaseSourceItem
 import eu.kanade.tachiyomi.R
-import eu.kanade.tachiyomi.ui.browse.source.SourcesState
+import eu.kanade.tachiyomi.ui.browse.source.SourcesScreenModel
 import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreenModel.Listing
 import eu.kanade.tachiyomi.util.system.LocaleHelper
 import tachiyomi.domain.source.model.Pin
@@ -40,7 +40,7 @@ import tachiyomi.source.local.isLocal
 
 @Composable
 fun SourcesScreen(
-    state: SourcesState,
+    state: SourcesScreenModel.State,
     contentPadding: PaddingValues,
     onClickItem: (Source, Listing) -> Unit,
     onClickPin: (Source) -> Unit,

+ 11 - 17
app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupConst.kt

@@ -1,20 +1,14 @@
 package eu.kanade.tachiyomi.data.backup
 
-import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID
-
-object BackupConst {
-
-    private const val NAME = "BackupRestoreServices"
-    const val EXTRA_URI = "$ID.$NAME.EXTRA_URI"
-
-    // Filter options
-    internal const val BACKUP_CATEGORY = 0x1
-    internal const val BACKUP_CATEGORY_MASK = 0x1
-    internal const val BACKUP_CHAPTER = 0x2
-    internal const val BACKUP_CHAPTER_MASK = 0x2
-    internal const val BACKUP_HISTORY = 0x4
-    internal const val BACKUP_HISTORY_MASK = 0x4
-    internal const val BACKUP_TRACK = 0x8
-    internal const val BACKUP_TRACK_MASK = 0x8
-    internal const val BACKUP_ALL = 0xF
+// Filter options
+internal object BackupConst {
+    const val BACKUP_CATEGORY = 0x1
+    const val BACKUP_CATEGORY_MASK = 0x1
+    const val BACKUP_CHAPTER = 0x2
+    const val BACKUP_CHAPTER_MASK = 0x2
+    const val BACKUP_HISTORY = 0x4
+    const val BACKUP_HISTORY_MASK = 0x4
+    const val BACKUP_TRACK = 0x8
+    const val BACKUP_TRACK_MASK = 0x8
+    const val BACKUP_ALL = 0xF
 }

+ 0 - 1
app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt

@@ -5,7 +5,6 @@ import android.content.Context
 import android.net.Uri
 import com.hippo.unifile.UniFile
 import eu.kanade.domain.chapter.model.copyFrom
-import eu.kanade.domain.manga.model.copyFrom
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CATEGORY
 import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CATEGORY_MASK

+ 0 - 1
app/src/main/java/eu/kanade/tachiyomi/data/cache/ChapterCache.kt

@@ -6,7 +6,6 @@ import com.jakewharton.disklrucache.DiskLruCache
 import eu.kanade.tachiyomi.source.model.Page
 import eu.kanade.tachiyomi.util.storage.DiskUtil
 import eu.kanade.tachiyomi.util.storage.saveTo
-import kotlinx.serialization.decodeFromString
 import kotlinx.serialization.encodeToString
 import kotlinx.serialization.json.Json
 import okhttp3.Response

+ 0 - 1
app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadPendingDeleter.kt

@@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.data.download
 import android.content.Context
 import androidx.core.content.edit
 import kotlinx.serialization.Serializable
-import kotlinx.serialization.decodeFromString
 import kotlinx.serialization.encodeToString
 import kotlinx.serialization.json.Json
 import tachiyomi.domain.chapter.model.Chapter

+ 0 - 1
app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadStore.kt

@@ -6,7 +6,6 @@ import eu.kanade.tachiyomi.data.download.model.Download
 import eu.kanade.tachiyomi.source.online.HttpSource
 import kotlinx.coroutines.runBlocking
 import kotlinx.serialization.Serializable
-import kotlinx.serialization.decodeFromString
 import kotlinx.serialization.encodeToString
 import kotlinx.serialization.json.Json
 import tachiyomi.domain.chapter.interactor.GetChapter

+ 0 - 1
app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/Anilist.kt

@@ -7,7 +7,6 @@ import eu.kanade.tachiyomi.data.database.models.Track
 import eu.kanade.tachiyomi.data.track.DeletableTrackService
 import eu.kanade.tachiyomi.data.track.TrackService
 import eu.kanade.tachiyomi.data.track.model.TrackSearch
-import kotlinx.serialization.decodeFromString
 import kotlinx.serialization.encodeToString
 import kotlinx.serialization.json.Json
 import uy.kohesive.injekt.injectLazy

+ 0 - 1
app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/Bangumi.kt

@@ -6,7 +6,6 @@ import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.database.models.Track
 import eu.kanade.tachiyomi.data.track.TrackService
 import eu.kanade.tachiyomi.data.track.model.TrackSearch
-import kotlinx.serialization.decodeFromString
 import kotlinx.serialization.encodeToString
 import kotlinx.serialization.json.Json
 import uy.kohesive.injekt.injectLazy

+ 0 - 1
app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiApi.kt

@@ -9,7 +9,6 @@ import eu.kanade.tachiyomi.network.GET
 import eu.kanade.tachiyomi.network.POST
 import eu.kanade.tachiyomi.network.awaitSuccess
 import eu.kanade.tachiyomi.network.parseAs
-import kotlinx.serialization.decodeFromString
 import kotlinx.serialization.json.Json
 import kotlinx.serialization.json.JsonObject
 import kotlinx.serialization.json.contentOrNull

+ 0 - 1
app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiInterceptor.kt

@@ -1,6 +1,5 @@
 package eu.kanade.tachiyomi.data.track.bangumi
 
-import kotlinx.serialization.decodeFromString
 import kotlinx.serialization.json.Json
 import okhttp3.FormBody
 import okhttp3.Interceptor

+ 0 - 1
app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/Kitsu.kt

@@ -7,7 +7,6 @@ import eu.kanade.tachiyomi.data.database.models.Track
 import eu.kanade.tachiyomi.data.track.DeletableTrackService
 import eu.kanade.tachiyomi.data.track.TrackService
 import eu.kanade.tachiyomi.data.track.model.TrackSearch
-import kotlinx.serialization.decodeFromString
 import kotlinx.serialization.encodeToString
 import kotlinx.serialization.json.Json
 import uy.kohesive.injekt.injectLazy

+ 0 - 1
app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuInterceptor.kt

@@ -1,6 +1,5 @@
 package eu.kanade.tachiyomi.data.track.kitsu
 
-import kotlinx.serialization.decodeFromString
 import kotlinx.serialization.json.Json
 import okhttp3.Interceptor
 import okhttp3.Response

+ 0 - 1
app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeList.kt

@@ -7,7 +7,6 @@ import eu.kanade.tachiyomi.data.database.models.Track
 import eu.kanade.tachiyomi.data.track.DeletableTrackService
 import eu.kanade.tachiyomi.data.track.TrackService
 import eu.kanade.tachiyomi.data.track.model.TrackSearch
-import kotlinx.serialization.decodeFromString
 import kotlinx.serialization.encodeToString
 import kotlinx.serialization.json.Json
 import uy.kohesive.injekt.injectLazy

+ 0 - 1
app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/Shikimori.kt

@@ -7,7 +7,6 @@ import eu.kanade.tachiyomi.data.database.models.Track
 import eu.kanade.tachiyomi.data.track.DeletableTrackService
 import eu.kanade.tachiyomi.data.track.TrackService
 import eu.kanade.tachiyomi.data.track.model.TrackSearch
-import kotlinx.serialization.decodeFromString
 import kotlinx.serialization.encodeToString
 import kotlinx.serialization.json.Json
 import uy.kohesive.injekt.injectLazy

+ 0 - 1
app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriInterceptor.kt

@@ -1,6 +1,5 @@
 package eu.kanade.tachiyomi.data.track.shikimori
 
-import kotlinx.serialization.decodeFromString
 import kotlinx.serialization.json.Json
 import okhttp3.Interceptor
 import okhttp3.Response

+ 2 - 5
app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreen.kt

@@ -29,17 +29,14 @@ class MigrateSearchScreen(private val mangaId: Long) : Screen() {
             onChangeSearchFilter = screenModel::setSourceFilter,
             onToggleResults = screenModel::toggleFilterResults,
             onClickSource = {
-                if (!screenModel.incognitoMode.get()) {
-                    screenModel.lastUsedSourceId.set(it.id)
-                }
                 navigator.push(SourceSearchScreen(state.manga!!, it.id, state.searchQuery))
             },
-            onClickItem = { screenModel.setDialog(MigrateSearchDialog.Migrate(it)) },
+            onClickItem = { screenModel.setDialog(MigrateSearchScreenModel.Dialog.Migrate(it)) },
             onLongClickItem = { navigator.push(MangaScreen(it.id, true)) },
         )
 
         when (val dialog = state.dialog) {
-            is MigrateSearchDialog.Migrate -> {
+            is MigrateSearchScreenModel.Dialog.Migrate -> {
                 MigrateDialog(
                     oldManga = state.manga!!,
                     newManga = dialog.manga,

+ 16 - 26
app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreenModel.kt

@@ -2,8 +2,6 @@ package eu.kanade.tachiyomi.ui.browse.migration.search
 
 import androidx.compose.runtime.Immutable
 import cafe.adriel.voyager.core.model.coroutineScope
-import eu.kanade.domain.base.BasePreferences
-import eu.kanade.domain.source.service.SourcePreferences
 import eu.kanade.tachiyomi.source.CatalogueSource
 import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SearchItemResult
 import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SearchScreenModel
@@ -12,21 +10,14 @@ import kotlinx.coroutines.flow.update
 import kotlinx.coroutines.launch
 import tachiyomi.domain.manga.interactor.GetManga
 import tachiyomi.domain.manga.model.Manga
-import tachiyomi.domain.source.service.SourceManager
 import uy.kohesive.injekt.Injekt
 import uy.kohesive.injekt.api.get
 
 class MigrateSearchScreenModel(
     val mangaId: Long,
-    preferences: BasePreferences = Injekt.get(),
-    private val sourcePreferences: SourcePreferences = Injekt.get(),
-    private val sourceManager: SourceManager = Injekt.get(),
-    private val getManga: GetManga = Injekt.get(),
+    getManga: GetManga = Injekt.get(),
 ) : SearchScreenModel<MigrateSearchScreenModel.State>(State()) {
 
-    val incognitoMode = preferences.incognitoMode()
-    val lastUsedSourceId = sourcePreferences.lastUsedSource()
-
     init {
         coroutineScope.launch {
             val manga = getManga.await(mangaId)!!
@@ -40,16 +31,15 @@ class MigrateSearchScreenModel(
     }
 
     override fun getEnabledSources(): List<CatalogueSource> {
-        val enabledLanguages = sourcePreferences.enabledLanguages().get()
-        val disabledSources = sourcePreferences.disabledSources().get()
-        val pinnedSources = sourcePreferences.pinnedSources().get()
-
-        return sourceManager.getCatalogueSources()
+        return super.getEnabledSources()
             .filter { mutableState.value.sourceFilter != SourceFilter.PinnedOnly || "${it.id}" in pinnedSources }
-            .filter { it.lang in enabledLanguages }
-            .filterNot { "${it.id}" in disabledSources }
-            .sortedWith(compareBy({ "${it.id}" !in pinnedSources }, { "${it.name.lowercase()} (${it.lang})" }))
-            .sortedByDescending { it.id == state.value.manga!!.source }
+            .sortedWith(
+                compareBy(
+                    { it.id != state.value.manga!!.source },
+                    { "${it.id}" !in pinnedSources },
+                    { "${it.name.lowercase()} (${it.lang})" },
+                ),
+            )
     }
 
     override fun updateSearchQuery(query: String?) {
@@ -68,17 +58,17 @@ class MigrateSearchScreenModel(
         return mutableState.value.items
     }
 
-    fun setSourceFilter(filter: SourceFilter) {
+    override fun setSourceFilter(filter: SourceFilter) {
         mutableState.update { it.copy(sourceFilter = filter) }
     }
 
-    fun toggleFilterResults() {
+    override fun toggleFilterResults() {
         mutableState.update {
             it.copy(onlyShowHasResults = !it.onlyShowHasResults)
         }
     }
 
-    fun setDialog(dialog: MigrateSearchDialog?) {
+    fun setDialog(dialog: Dialog?) {
         mutableState.update {
             it.copy(dialog = dialog)
         }
@@ -87,7 +77,7 @@ class MigrateSearchScreenModel(
     @Immutable
     data class State(
         val manga: Manga? = null,
-        val dialog: MigrateSearchDialog? = null,
+        val dialog: Dialog? = null,
 
         val searchQuery: String? = null,
         val sourceFilter: SourceFilter = SourceFilter.PinnedOnly,
@@ -98,8 +88,8 @@ class MigrateSearchScreenModel(
         val total: Int = items.size
         val filteredItems = items.filter { (_, result) -> result.isVisible(onlyShowHasResults) }
     }
-}
 
-sealed class MigrateSearchDialog {
-    data class Migrate(val manga: Manga) : MigrateSearchDialog()
+    sealed class Dialog {
+        data class Migrate(val manga: Manga) : Dialog()
+    }
 }

+ 10 - 20
app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcesScreenModel.kt

@@ -3,11 +3,9 @@ package eu.kanade.tachiyomi.ui.browse.source
 import androidx.compose.runtime.Immutable
 import cafe.adriel.voyager.core.model.StateScreenModel
 import cafe.adriel.voyager.core.model.coroutineScope
-import eu.kanade.domain.base.BasePreferences
 import eu.kanade.domain.source.interactor.GetEnabledSources
 import eu.kanade.domain.source.interactor.ToggleSource
 import eu.kanade.domain.source.interactor.ToggleSourcePin
-import eu.kanade.domain.source.service.SourcePreferences
 import eu.kanade.presentation.browse.SourceUiModel
 import kotlinx.coroutines.channels.Channel
 import kotlinx.coroutines.flow.catch
@@ -24,12 +22,10 @@ import uy.kohesive.injekt.api.get
 import java.util.TreeMap
 
 class SourcesScreenModel(
-    private val preferences: BasePreferences = Injekt.get(),
-    private val sourcePreferences: SourcePreferences = Injekt.get(),
     private val getEnabledSources: GetEnabledSources = Injekt.get(),
     private val toggleSource: ToggleSource = Injekt.get(),
     private val toggleSourcePin: ToggleSourcePin = Injekt.get(),
-) : StateScreenModel<SourcesState>(SourcesState()) {
+) : StateScreenModel<SourcesScreenModel.State>(State()) {
 
     private val _events = Channel<Event>(Int.MAX_VALUE)
     val events = _events.receiveAsFlow()
@@ -81,12 +77,6 @@ class SourcesScreenModel(
         }
     }
 
-    fun onOpenSource(source: Source) {
-        if (!preferences.incognitoMode().get()) {
-            sourcePreferences.lastUsedSource().set(source.id)
-        }
-    }
-
     fun toggleSource(source: Source) {
         toggleSource.await(source)
     }
@@ -109,17 +99,17 @@ class SourcesScreenModel(
 
     data class Dialog(val source: Source)
 
+    @Immutable
+    data class State(
+        val dialog: Dialog? = null,
+        val isLoading: Boolean = true,
+        val items: List<SourceUiModel> = emptyList(),
+    ) {
+        val isEmpty = items.isEmpty()
+    }
+
     companion object {
         const val PINNED_KEY = "pinned"
         const val LAST_USED_KEY = "last_used"
     }
 }
-
-@Immutable
-data class SourcesState(
-    val dialog: SourcesScreenModel.Dialog? = null,
-    val isLoading: Boolean = true,
-    val items: List<SourceUiModel> = emptyList(),
-) {
-    val isEmpty = items.isEmpty()
-}

+ 0 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcesTab.kt

@@ -47,7 +47,6 @@ fun Screen.sourcesTab(): TabContent {
                 state = state,
                 contentPadding = contentPadding,
                 onClickItem = { source, listing ->
-                    screenModel.onOpenSource(source)
                     navigator.push(BrowseSourceScreen(source.id, listing.query))
                 },
                 onClickPin = screenModel::togglePin,

+ 6 - 0
app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt

@@ -13,6 +13,7 @@ import androidx.paging.map
 import cafe.adriel.voyager.core.model.StateScreenModel
 import cafe.adriel.voyager.core.model.coroutineScope
 import eu.kanade.core.preference.asState
+import eu.kanade.domain.base.BasePreferences
 import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay
 import eu.kanade.domain.manga.interactor.UpdateManga
 import eu.kanade.domain.manga.model.toDomainManga
@@ -65,6 +66,7 @@ class BrowseSourceScreenModel(
     listingQuery: String?,
     sourceManager: SourceManager = Injekt.get(),
     sourcePreferences: SourcePreferences = Injekt.get(),
+    basePreferences: BasePreferences = Injekt.get(),
     private val libraryPreferences: LibraryPreferences = Injekt.get(),
     private val coverCache: CoverCache = Injekt.get(),
     private val getRemoteManga: GetRemoteManga = Injekt.get(),
@@ -104,6 +106,10 @@ class BrowseSourceScreenModel(
                 )
             }
         }
+
+        if (!basePreferences.incognitoMode().get()) {
+            sourcePreferences.lastUsedSource().set(source.id)
+        }
     }
 
     /**

+ 0 - 3
app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreen.kt

@@ -64,9 +64,6 @@ class GlobalSearchScreen(
                 onChangeSearchFilter = screenModel::setSourceFilter,
                 onToggleResults = screenModel::toggleFilterResults,
                 onClickSource = {
-                    if (!screenModel.incognitoMode.get()) {
-                        screenModel.lastUsedSourceId.set(it.id)
-                    }
                     navigator.push(BrowseSourceScreen(it.id, state.searchQuery))
                 },
                 onClickItem = { navigator.push(MangaScreen(it.id, true)) },

+ 3 - 21
app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreenModel.kt

@@ -1,25 +1,14 @@
 package eu.kanade.tachiyomi.ui.browse.source.globalsearch
 
 import androidx.compose.runtime.Immutable
-import eu.kanade.domain.base.BasePreferences
-import eu.kanade.domain.source.service.SourcePreferences
 import eu.kanade.tachiyomi.source.CatalogueSource
 import kotlinx.coroutines.flow.update
-import tachiyomi.domain.source.service.SourceManager
-import uy.kohesive.injekt.Injekt
-import uy.kohesive.injekt.api.get
 
 class GlobalSearchScreenModel(
     initialQuery: String = "",
     initialExtensionFilter: String? = null,
-    preferences: BasePreferences = Injekt.get(),
-    private val sourcePreferences: SourcePreferences = Injekt.get(),
-    private val sourceManager: SourceManager = Injekt.get(),
 ) : SearchScreenModel<GlobalSearchScreenModel.State>(State(searchQuery = initialQuery)) {
 
-    val incognitoMode = preferences.incognitoMode()
-    val lastUsedSourceId = sourcePreferences.lastUsedSource()
-
     init {
         extensionFilter = initialExtensionFilter
         if (initialQuery.isNotBlank() || !initialExtensionFilter.isNullOrBlank()) {
@@ -28,15 +17,8 @@ class GlobalSearchScreenModel(
     }
 
     override fun getEnabledSources(): List<CatalogueSource> {
-        val enabledLanguages = sourcePreferences.enabledLanguages().get()
-        val disabledSources = sourcePreferences.disabledSources().get()
-        val pinnedSources = sourcePreferences.pinnedSources().get()
-
-        return sourceManager.getCatalogueSources()
+        return super.getEnabledSources()
             .filter { mutableState.value.sourceFilter != SourceFilter.PinnedOnly || "${it.id}" in pinnedSources }
-            .filter { it.lang in enabledLanguages }
-            .filterNot { "${it.id}" in disabledSources }
-            .sortedWith(compareBy({ "${it.id}" !in pinnedSources }, { "${it.name.lowercase()} (${it.lang})" }))
     }
 
     override fun updateSearchQuery(query: String?) {
@@ -55,11 +37,11 @@ class GlobalSearchScreenModel(
         return mutableState.value.items
     }
 
-    fun setSourceFilter(filter: SourceFilter) {
+    override fun setSourceFilter(filter: SourceFilter) {
         mutableState.update { it.copy(sourceFilter = filter) }
     }
 
-    fun toggleFilterResults() {
+    override fun toggleFilterResults() {
         mutableState.update {
             it.copy(onlyShowHasResults = !it.onlyShowHasResults)
         }

+ 28 - 6
app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/SearchScreenModel.kt

@@ -10,16 +10,19 @@ import eu.kanade.domain.source.service.SourcePreferences
 import eu.kanade.presentation.util.ioCoroutineScope
 import eu.kanade.tachiyomi.extension.ExtensionManager
 import eu.kanade.tachiyomi.source.CatalogueSource
+import kotlinx.coroutines.Job
 import kotlinx.coroutines.asCoroutineDispatcher
 import kotlinx.coroutines.async
 import kotlinx.coroutines.awaitAll
 import kotlinx.coroutines.flow.collectLatest
+import kotlinx.coroutines.flow.filterNotNull
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
 import tachiyomi.core.util.lang.awaitSingle
 import tachiyomi.domain.manga.interactor.GetManga
 import tachiyomi.domain.manga.interactor.NetworkToLocalManga
 import tachiyomi.domain.manga.model.Manga
+import tachiyomi.domain.source.service.SourceManager
 import uy.kohesive.injekt.Injekt
 import uy.kohesive.injekt.api.get
 import java.util.concurrent.Executors
@@ -27,6 +30,7 @@ import java.util.concurrent.Executors
 abstract class SearchScreenModel<T>(
     initialState: T,
     private val sourcePreferences: SourcePreferences = Injekt.get(),
+    private val sourceManager: SourceManager = Injekt.get(),
     private val extensionManager: ExtensionManager = Injekt.get(),
     private val networkToLocalManga: NetworkToLocalManga = Injekt.get(),
     private val getManga: GetManga = Injekt.get(),
@@ -34,12 +38,13 @@ abstract class SearchScreenModel<T>(
 ) : StateScreenModel<T>(initialState) {
 
     private val coroutineDispatcher = Executors.newFixedThreadPool(5).asCoroutineDispatcher()
+    private var searchJob: Job? = null
 
     protected var query: String? = null
     protected var extensionFilter: String? = null
 
     private val sources by lazy { getSelectedSources() }
-    private val pinnedSources by lazy { sourcePreferences.pinnedSources().get() }
+    protected val pinnedSources = sourcePreferences.pinnedSources().get()
 
     private val sortComparator = { map: Map<CatalogueSource, SearchItemResult> ->
         compareBy<CatalogueSource>(
@@ -53,14 +58,27 @@ abstract class SearchScreenModel<T>(
     fun getManga(initialManga: Manga): State<Manga> {
         return produceState(initialValue = initialManga) {
             getManga.subscribe(initialManga.url, initialManga.source)
+                .filterNotNull()
                 .collectLatest { manga ->
-                    if (manga == null) return@collectLatest
                     value = manga
                 }
         }
     }
 
-    abstract fun getEnabledSources(): List<CatalogueSource>
+    open fun getEnabledSources(): List<CatalogueSource> {
+        val enabledLanguages = sourcePreferences.enabledLanguages().get()
+        val disabledSources = sourcePreferences.disabledSources().get()
+        val pinnedSources = sourcePreferences.pinnedSources().get()
+
+        return sourceManager.getCatalogueSources()
+            .filter { it.lang in enabledLanguages && "${it.id}" !in disabledSources }
+            .sortedWith(
+                compareBy(
+                    { "${it.id}" !in pinnedSources },
+                    { "${it.name.lowercase()} (${it.lang})" },
+                ),
+            )
+    }
 
     private fun getSelectedSources(): List<CatalogueSource> {
         val enabledSources = getEnabledSources()
@@ -73,8 +91,8 @@ abstract class SearchScreenModel<T>(
         return extensionManager.installedExtensionsFlow.value
             .filter { it.pkgName == filter }
             .flatMap { it.sources }
-            .filter { it in enabledSources }
             .filterIsInstance<CatalogueSource>()
+            .filter { it in enabledSources }
     }
 
     abstract fun updateSearchQuery(query: String?)
@@ -87,15 +105,19 @@ abstract class SearchScreenModel<T>(
         updateItems(function(getItems()))
     }
 
+    abstract fun setSourceFilter(filter: SourceFilter)
+
+    abstract fun toggleFilterResults()
+
     fun search(query: String) {
         if (this.query == query) return
 
         this.query = query
 
+        searchJob?.cancel()
         val initialItems = getSelectedSources().associateWith { SearchItemResult.Loading }
         updateItems(initialItems)
-
-        ioCoroutineScope.launch {
+        searchJob = ioCoroutineScope.launch {
             sources
                 .map { source ->
                     async {