mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-11-04 08:08:55 +01:00 
			
		
		
		
	Minor refactoring
This commit is contained in:
		@@ -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,
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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,
 | 
			
		||||
 
 | 
			
		||||
@@ -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()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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()
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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,
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -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)) },
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -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 {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user