Minor refactoring
This commit is contained in:
parent
dd3ca0c131
commit
ef7b285151
23 changed files with 78 additions and 114 deletions
|
@ -23,7 +23,7 @@ import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import eu.kanade.presentation.browse.components.BaseSourceItem
|
import eu.kanade.presentation.browse.components.BaseSourceItem
|
||||||
import eu.kanade.tachiyomi.R
|
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.ui.browse.source.browse.BrowseSourceScreenModel.Listing
|
||||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||||
import tachiyomi.domain.source.model.Pin
|
import tachiyomi.domain.source.model.Pin
|
||||||
|
@ -40,7 +40,7 @@ import tachiyomi.source.local.isLocal
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SourcesScreen(
|
fun SourcesScreen(
|
||||||
state: SourcesState,
|
state: SourcesScreenModel.State,
|
||||||
contentPadding: PaddingValues,
|
contentPadding: PaddingValues,
|
||||||
onClickItem: (Source, Listing) -> Unit,
|
onClickItem: (Source, Listing) -> Unit,
|
||||||
onClickPin: (Source) -> Unit,
|
onClickPin: (Source) -> Unit,
|
||||||
|
|
|
@ -1,20 +1,14 @@
|
||||||
package eu.kanade.tachiyomi.data.backup
|
package eu.kanade.tachiyomi.data.backup
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID
|
// Filter options
|
||||||
|
internal object BackupConst {
|
||||||
object BackupConst {
|
const val BACKUP_CATEGORY = 0x1
|
||||||
|
const val BACKUP_CATEGORY_MASK = 0x1
|
||||||
private const val NAME = "BackupRestoreServices"
|
const val BACKUP_CHAPTER = 0x2
|
||||||
const val EXTRA_URI = "$ID.$NAME.EXTRA_URI"
|
const val BACKUP_CHAPTER_MASK = 0x2
|
||||||
|
const val BACKUP_HISTORY = 0x4
|
||||||
// Filter options
|
const val BACKUP_HISTORY_MASK = 0x4
|
||||||
internal const val BACKUP_CATEGORY = 0x1
|
const val BACKUP_TRACK = 0x8
|
||||||
internal const val BACKUP_CATEGORY_MASK = 0x1
|
const val BACKUP_TRACK_MASK = 0x8
|
||||||
internal const val BACKUP_CHAPTER = 0x2
|
const val BACKUP_ALL = 0xF
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import com.hippo.unifile.UniFile
|
import com.hippo.unifile.UniFile
|
||||||
import eu.kanade.domain.chapter.model.copyFrom
|
import eu.kanade.domain.chapter.model.copyFrom
|
||||||
import eu.kanade.domain.manga.model.copyFrom
|
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CATEGORY
|
import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CATEGORY
|
||||||
import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CATEGORY_MASK
|
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.source.model.Page
|
||||||
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||||
import eu.kanade.tachiyomi.util.storage.saveTo
|
import eu.kanade.tachiyomi.util.storage.saveTo
|
||||||
import kotlinx.serialization.decodeFromString
|
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
|
|
|
@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.data.download
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.decodeFromString
|
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import tachiyomi.domain.chapter.model.Chapter
|
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 eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.decodeFromString
|
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import tachiyomi.domain.chapter.interactor.GetChapter
|
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.DeletableTrackService
|
||||||
import eu.kanade.tachiyomi.data.track.TrackService
|
import eu.kanade.tachiyomi.data.track.TrackService
|
||||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||||
import kotlinx.serialization.decodeFromString
|
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import uy.kohesive.injekt.injectLazy
|
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.database.models.Track
|
||||||
import eu.kanade.tachiyomi.data.track.TrackService
|
import eu.kanade.tachiyomi.data.track.TrackService
|
||||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||||
import kotlinx.serialization.decodeFromString
|
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import uy.kohesive.injekt.injectLazy
|
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.POST
|
||||||
import eu.kanade.tachiyomi.network.awaitSuccess
|
import eu.kanade.tachiyomi.network.awaitSuccess
|
||||||
import eu.kanade.tachiyomi.network.parseAs
|
import eu.kanade.tachiyomi.network.parseAs
|
||||||
import kotlinx.serialization.decodeFromString
|
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import kotlinx.serialization.json.JsonObject
|
import kotlinx.serialization.json.JsonObject
|
||||||
import kotlinx.serialization.json.contentOrNull
|
import kotlinx.serialization.json.contentOrNull
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package eu.kanade.tachiyomi.data.track.bangumi
|
package eu.kanade.tachiyomi.data.track.bangumi
|
||||||
|
|
||||||
import kotlinx.serialization.decodeFromString
|
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import okhttp3.FormBody
|
import okhttp3.FormBody
|
||||||
import okhttp3.Interceptor
|
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.DeletableTrackService
|
||||||
import eu.kanade.tachiyomi.data.track.TrackService
|
import eu.kanade.tachiyomi.data.track.TrackService
|
||||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||||
import kotlinx.serialization.decodeFromString
|
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package eu.kanade.tachiyomi.data.track.kitsu
|
package eu.kanade.tachiyomi.data.track.kitsu
|
||||||
|
|
||||||
import kotlinx.serialization.decodeFromString
|
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import okhttp3.Interceptor
|
import okhttp3.Interceptor
|
||||||
import okhttp3.Response
|
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.DeletableTrackService
|
||||||
import eu.kanade.tachiyomi.data.track.TrackService
|
import eu.kanade.tachiyomi.data.track.TrackService
|
||||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||||
import kotlinx.serialization.decodeFromString
|
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import uy.kohesive.injekt.injectLazy
|
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.DeletableTrackService
|
||||||
import eu.kanade.tachiyomi.data.track.TrackService
|
import eu.kanade.tachiyomi.data.track.TrackService
|
||||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||||
import kotlinx.serialization.decodeFromString
|
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package eu.kanade.tachiyomi.data.track.shikimori
|
package eu.kanade.tachiyomi.data.track.shikimori
|
||||||
|
|
||||||
import kotlinx.serialization.decodeFromString
|
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import okhttp3.Interceptor
|
import okhttp3.Interceptor
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
|
|
|
@ -29,17 +29,14 @@ class MigrateSearchScreen(private val mangaId: Long) : Screen() {
|
||||||
onChangeSearchFilter = screenModel::setSourceFilter,
|
onChangeSearchFilter = screenModel::setSourceFilter,
|
||||||
onToggleResults = screenModel::toggleFilterResults,
|
onToggleResults = screenModel::toggleFilterResults,
|
||||||
onClickSource = {
|
onClickSource = {
|
||||||
if (!screenModel.incognitoMode.get()) {
|
|
||||||
screenModel.lastUsedSourceId.set(it.id)
|
|
||||||
}
|
|
||||||
navigator.push(SourceSearchScreen(state.manga!!, it.id, state.searchQuery))
|
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)) },
|
onLongClickItem = { navigator.push(MangaScreen(it.id, true)) },
|
||||||
)
|
)
|
||||||
|
|
||||||
when (val dialog = state.dialog) {
|
when (val dialog = state.dialog) {
|
||||||
is MigrateSearchDialog.Migrate -> {
|
is MigrateSearchScreenModel.Dialog.Migrate -> {
|
||||||
MigrateDialog(
|
MigrateDialog(
|
||||||
oldManga = state.manga!!,
|
oldManga = state.manga!!,
|
||||||
newManga = dialog.manga,
|
newManga = dialog.manga,
|
||||||
|
|
|
@ -2,8 +2,6 @@ package eu.kanade.tachiyomi.ui.browse.migration.search
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import cafe.adriel.voyager.core.model.coroutineScope
|
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.source.CatalogueSource
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SearchItemResult
|
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SearchItemResult
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SearchScreenModel
|
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SearchScreenModel
|
||||||
|
@ -12,21 +10,14 @@ import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import tachiyomi.domain.manga.interactor.GetManga
|
import tachiyomi.domain.manga.interactor.GetManga
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.source.service.SourceManager
|
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
class MigrateSearchScreenModel(
|
class MigrateSearchScreenModel(
|
||||||
val mangaId: Long,
|
val mangaId: Long,
|
||||||
preferences: BasePreferences = Injekt.get(),
|
getManga: GetManga = Injekt.get(),
|
||||||
private val sourcePreferences: SourcePreferences = Injekt.get(),
|
|
||||||
private val sourceManager: SourceManager = Injekt.get(),
|
|
||||||
private val getManga: GetManga = Injekt.get(),
|
|
||||||
) : SearchScreenModel<MigrateSearchScreenModel.State>(State()) {
|
) : SearchScreenModel<MigrateSearchScreenModel.State>(State()) {
|
||||||
|
|
||||||
val incognitoMode = preferences.incognitoMode()
|
|
||||||
val lastUsedSourceId = sourcePreferences.lastUsedSource()
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
val manga = getManga.await(mangaId)!!
|
val manga = getManga.await(mangaId)!!
|
||||||
|
@ -40,16 +31,15 @@ class MigrateSearchScreenModel(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getEnabledSources(): List<CatalogueSource> {
|
override fun getEnabledSources(): List<CatalogueSource> {
|
||||||
val enabledLanguages = sourcePreferences.enabledLanguages().get()
|
return super.getEnabledSources()
|
||||||
val disabledSources = sourcePreferences.disabledSources().get()
|
|
||||||
val pinnedSources = sourcePreferences.pinnedSources().get()
|
|
||||||
|
|
||||||
return sourceManager.getCatalogueSources()
|
|
||||||
.filter { mutableState.value.sourceFilter != SourceFilter.PinnedOnly || "${it.id}" in pinnedSources }
|
.filter { mutableState.value.sourceFilter != SourceFilter.PinnedOnly || "${it.id}" in pinnedSources }
|
||||||
.filter { it.lang in enabledLanguages }
|
.sortedWith(
|
||||||
.filterNot { "${it.id}" in disabledSources }
|
compareBy(
|
||||||
.sortedWith(compareBy({ "${it.id}" !in pinnedSources }, { "${it.name.lowercase()} (${it.lang})" }))
|
{ it.id != state.value.manga!!.source },
|
||||||
.sortedByDescending { it.id == state.value.manga!!.source }
|
{ "${it.id}" !in pinnedSources },
|
||||||
|
{ "${it.name.lowercase()} (${it.lang})" },
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateSearchQuery(query: String?) {
|
override fun updateSearchQuery(query: String?) {
|
||||||
|
@ -68,17 +58,17 @@ class MigrateSearchScreenModel(
|
||||||
return mutableState.value.items
|
return mutableState.value.items
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setSourceFilter(filter: SourceFilter) {
|
override fun setSourceFilter(filter: SourceFilter) {
|
||||||
mutableState.update { it.copy(sourceFilter = filter) }
|
mutableState.update { it.copy(sourceFilter = filter) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toggleFilterResults() {
|
override fun toggleFilterResults() {
|
||||||
mutableState.update {
|
mutableState.update {
|
||||||
it.copy(onlyShowHasResults = !it.onlyShowHasResults)
|
it.copy(onlyShowHasResults = !it.onlyShowHasResults)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setDialog(dialog: MigrateSearchDialog?) {
|
fun setDialog(dialog: Dialog?) {
|
||||||
mutableState.update {
|
mutableState.update {
|
||||||
it.copy(dialog = dialog)
|
it.copy(dialog = dialog)
|
||||||
}
|
}
|
||||||
|
@ -87,7 +77,7 @@ class MigrateSearchScreenModel(
|
||||||
@Immutable
|
@Immutable
|
||||||
data class State(
|
data class State(
|
||||||
val manga: Manga? = null,
|
val manga: Manga? = null,
|
||||||
val dialog: MigrateSearchDialog? = null,
|
val dialog: Dialog? = null,
|
||||||
|
|
||||||
val searchQuery: String? = null,
|
val searchQuery: String? = null,
|
||||||
val sourceFilter: SourceFilter = SourceFilter.PinnedOnly,
|
val sourceFilter: SourceFilter = SourceFilter.PinnedOnly,
|
||||||
|
@ -98,8 +88,8 @@ class MigrateSearchScreenModel(
|
||||||
val total: Int = items.size
|
val total: Int = items.size
|
||||||
val filteredItems = items.filter { (_, result) -> result.isVisible(onlyShowHasResults) }
|
val filteredItems = items.filter { (_, result) -> result.isVisible(onlyShowHasResults) }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
sealed class MigrateSearchDialog {
|
sealed class Dialog {
|
||||||
data class Migrate(val manga: Manga) : MigrateSearchDialog()
|
data class Migrate(val manga: Manga) : Dialog()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,11 +3,9 @@ package eu.kanade.tachiyomi.ui.browse.source
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import cafe.adriel.voyager.core.model.StateScreenModel
|
import cafe.adriel.voyager.core.model.StateScreenModel
|
||||||
import cafe.adriel.voyager.core.model.coroutineScope
|
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.GetEnabledSources
|
||||||
import eu.kanade.domain.source.interactor.ToggleSource
|
import eu.kanade.domain.source.interactor.ToggleSource
|
||||||
import eu.kanade.domain.source.interactor.ToggleSourcePin
|
import eu.kanade.domain.source.interactor.ToggleSourcePin
|
||||||
import eu.kanade.domain.source.service.SourcePreferences
|
|
||||||
import eu.kanade.presentation.browse.SourceUiModel
|
import eu.kanade.presentation.browse.SourceUiModel
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.catch
|
||||||
|
@ -24,12 +22,10 @@ import uy.kohesive.injekt.api.get
|
||||||
import java.util.TreeMap
|
import java.util.TreeMap
|
||||||
|
|
||||||
class SourcesScreenModel(
|
class SourcesScreenModel(
|
||||||
private val preferences: BasePreferences = Injekt.get(),
|
|
||||||
private val sourcePreferences: SourcePreferences = Injekt.get(),
|
|
||||||
private val getEnabledSources: GetEnabledSources = Injekt.get(),
|
private val getEnabledSources: GetEnabledSources = Injekt.get(),
|
||||||
private val toggleSource: ToggleSource = Injekt.get(),
|
private val toggleSource: ToggleSource = Injekt.get(),
|
||||||
private val toggleSourcePin: ToggleSourcePin = Injekt.get(),
|
private val toggleSourcePin: ToggleSourcePin = Injekt.get(),
|
||||||
) : StateScreenModel<SourcesState>(SourcesState()) {
|
) : StateScreenModel<SourcesScreenModel.State>(State()) {
|
||||||
|
|
||||||
private val _events = Channel<Event>(Int.MAX_VALUE)
|
private val _events = Channel<Event>(Int.MAX_VALUE)
|
||||||
val events = _events.receiveAsFlow()
|
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) {
|
fun toggleSource(source: Source) {
|
||||||
toggleSource.await(source)
|
toggleSource.await(source)
|
||||||
}
|
}
|
||||||
|
@ -109,17 +99,17 @@ class SourcesScreenModel(
|
||||||
|
|
||||||
data class Dialog(val source: Source)
|
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 {
|
companion object {
|
||||||
const val PINNED_KEY = "pinned"
|
const val PINNED_KEY = "pinned"
|
||||||
const val LAST_USED_KEY = "last_used"
|
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,
|
state = state,
|
||||||
contentPadding = contentPadding,
|
contentPadding = contentPadding,
|
||||||
onClickItem = { source, listing ->
|
onClickItem = { source, listing ->
|
||||||
screenModel.onOpenSource(source)
|
|
||||||
navigator.push(BrowseSourceScreen(source.id, listing.query))
|
navigator.push(BrowseSourceScreen(source.id, listing.query))
|
||||||
},
|
},
|
||||||
onClickPin = screenModel::togglePin,
|
onClickPin = screenModel::togglePin,
|
||||||
|
|
|
@ -13,6 +13,7 @@ import androidx.paging.map
|
||||||
import cafe.adriel.voyager.core.model.StateScreenModel
|
import cafe.adriel.voyager.core.model.StateScreenModel
|
||||||
import cafe.adriel.voyager.core.model.coroutineScope
|
import cafe.adriel.voyager.core.model.coroutineScope
|
||||||
import eu.kanade.core.preference.asState
|
import eu.kanade.core.preference.asState
|
||||||
|
import eu.kanade.domain.base.BasePreferences
|
||||||
import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay
|
import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay
|
||||||
import eu.kanade.domain.manga.interactor.UpdateManga
|
import eu.kanade.domain.manga.interactor.UpdateManga
|
||||||
import eu.kanade.domain.manga.model.toDomainManga
|
import eu.kanade.domain.manga.model.toDomainManga
|
||||||
|
@ -65,6 +66,7 @@ class BrowseSourceScreenModel(
|
||||||
listingQuery: String?,
|
listingQuery: String?,
|
||||||
sourceManager: SourceManager = Injekt.get(),
|
sourceManager: SourceManager = Injekt.get(),
|
||||||
sourcePreferences: SourcePreferences = Injekt.get(),
|
sourcePreferences: SourcePreferences = Injekt.get(),
|
||||||
|
basePreferences: BasePreferences = Injekt.get(),
|
||||||
private val libraryPreferences: LibraryPreferences = Injekt.get(),
|
private val libraryPreferences: LibraryPreferences = Injekt.get(),
|
||||||
private val coverCache: CoverCache = Injekt.get(),
|
private val coverCache: CoverCache = Injekt.get(),
|
||||||
private val getRemoteManga: GetRemoteManga = 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,
|
onChangeSearchFilter = screenModel::setSourceFilter,
|
||||||
onToggleResults = screenModel::toggleFilterResults,
|
onToggleResults = screenModel::toggleFilterResults,
|
||||||
onClickSource = {
|
onClickSource = {
|
||||||
if (!screenModel.incognitoMode.get()) {
|
|
||||||
screenModel.lastUsedSourceId.set(it.id)
|
|
||||||
}
|
|
||||||
navigator.push(BrowseSourceScreen(it.id, state.searchQuery))
|
navigator.push(BrowseSourceScreen(it.id, state.searchQuery))
|
||||||
},
|
},
|
||||||
onClickItem = { navigator.push(MangaScreen(it.id, true)) },
|
onClickItem = { navigator.push(MangaScreen(it.id, true)) },
|
||||||
|
|
|
@ -1,25 +1,14 @@
|
||||||
package eu.kanade.tachiyomi.ui.browse.source.globalsearch
|
package eu.kanade.tachiyomi.ui.browse.source.globalsearch
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
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 eu.kanade.tachiyomi.source.CatalogueSource
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import tachiyomi.domain.source.service.SourceManager
|
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
class GlobalSearchScreenModel(
|
class GlobalSearchScreenModel(
|
||||||
initialQuery: String = "",
|
initialQuery: String = "",
|
||||||
initialExtensionFilter: String? = null,
|
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)) {
|
) : SearchScreenModel<GlobalSearchScreenModel.State>(State(searchQuery = initialQuery)) {
|
||||||
|
|
||||||
val incognitoMode = preferences.incognitoMode()
|
|
||||||
val lastUsedSourceId = sourcePreferences.lastUsedSource()
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
extensionFilter = initialExtensionFilter
|
extensionFilter = initialExtensionFilter
|
||||||
if (initialQuery.isNotBlank() || !initialExtensionFilter.isNullOrBlank()) {
|
if (initialQuery.isNotBlank() || !initialExtensionFilter.isNullOrBlank()) {
|
||||||
|
@ -28,15 +17,8 @@ class GlobalSearchScreenModel(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getEnabledSources(): List<CatalogueSource> {
|
override fun getEnabledSources(): List<CatalogueSource> {
|
||||||
val enabledLanguages = sourcePreferences.enabledLanguages().get()
|
return super.getEnabledSources()
|
||||||
val disabledSources = sourcePreferences.disabledSources().get()
|
|
||||||
val pinnedSources = sourcePreferences.pinnedSources().get()
|
|
||||||
|
|
||||||
return sourceManager.getCatalogueSources()
|
|
||||||
.filter { mutableState.value.sourceFilter != SourceFilter.PinnedOnly || "${it.id}" in pinnedSources }
|
.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?) {
|
override fun updateSearchQuery(query: String?) {
|
||||||
|
@ -55,11 +37,11 @@ class GlobalSearchScreenModel(
|
||||||
return mutableState.value.items
|
return mutableState.value.items
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setSourceFilter(filter: SourceFilter) {
|
override fun setSourceFilter(filter: SourceFilter) {
|
||||||
mutableState.update { it.copy(sourceFilter = filter) }
|
mutableState.update { it.copy(sourceFilter = filter) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toggleFilterResults() {
|
override fun toggleFilterResults() {
|
||||||
mutableState.update {
|
mutableState.update {
|
||||||
it.copy(onlyShowHasResults = !it.onlyShowHasResults)
|
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.presentation.util.ioCoroutineScope
|
||||||
import eu.kanade.tachiyomi.extension.ExtensionManager
|
import eu.kanade.tachiyomi.extension.ExtensionManager
|
||||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.asCoroutineDispatcher
|
import kotlinx.coroutines.asCoroutineDispatcher
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.awaitAll
|
import kotlinx.coroutines.awaitAll
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
|
import kotlinx.coroutines.flow.filterNotNull
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import tachiyomi.core.util.lang.awaitSingle
|
import tachiyomi.core.util.lang.awaitSingle
|
||||||
import tachiyomi.domain.manga.interactor.GetManga
|
import tachiyomi.domain.manga.interactor.GetManga
|
||||||
import tachiyomi.domain.manga.interactor.NetworkToLocalManga
|
import tachiyomi.domain.manga.interactor.NetworkToLocalManga
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
|
import tachiyomi.domain.source.service.SourceManager
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
|
@ -27,6 +30,7 @@ import java.util.concurrent.Executors
|
||||||
abstract class SearchScreenModel<T>(
|
abstract class SearchScreenModel<T>(
|
||||||
initialState: T,
|
initialState: T,
|
||||||
private val sourcePreferences: SourcePreferences = Injekt.get(),
|
private val sourcePreferences: SourcePreferences = Injekt.get(),
|
||||||
|
private val sourceManager: SourceManager = Injekt.get(),
|
||||||
private val extensionManager: ExtensionManager = Injekt.get(),
|
private val extensionManager: ExtensionManager = Injekt.get(),
|
||||||
private val networkToLocalManga: NetworkToLocalManga = Injekt.get(),
|
private val networkToLocalManga: NetworkToLocalManga = Injekt.get(),
|
||||||
private val getManga: GetManga = Injekt.get(),
|
private val getManga: GetManga = Injekt.get(),
|
||||||
|
@ -34,12 +38,13 @@ abstract class SearchScreenModel<T>(
|
||||||
) : StateScreenModel<T>(initialState) {
|
) : StateScreenModel<T>(initialState) {
|
||||||
|
|
||||||
private val coroutineDispatcher = Executors.newFixedThreadPool(5).asCoroutineDispatcher()
|
private val coroutineDispatcher = Executors.newFixedThreadPool(5).asCoroutineDispatcher()
|
||||||
|
private var searchJob: Job? = null
|
||||||
|
|
||||||
protected var query: String? = null
|
protected var query: String? = null
|
||||||
protected var extensionFilter: String? = null
|
protected var extensionFilter: String? = null
|
||||||
|
|
||||||
private val sources by lazy { getSelectedSources() }
|
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> ->
|
private val sortComparator = { map: Map<CatalogueSource, SearchItemResult> ->
|
||||||
compareBy<CatalogueSource>(
|
compareBy<CatalogueSource>(
|
||||||
|
@ -53,14 +58,27 @@ abstract class SearchScreenModel<T>(
|
||||||
fun getManga(initialManga: Manga): State<Manga> {
|
fun getManga(initialManga: Manga): State<Manga> {
|
||||||
return produceState(initialValue = initialManga) {
|
return produceState(initialValue = initialManga) {
|
||||||
getManga.subscribe(initialManga.url, initialManga.source)
|
getManga.subscribe(initialManga.url, initialManga.source)
|
||||||
|
.filterNotNull()
|
||||||
.collectLatest { manga ->
|
.collectLatest { manga ->
|
||||||
if (manga == null) return@collectLatest
|
|
||||||
value = manga
|
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> {
|
private fun getSelectedSources(): List<CatalogueSource> {
|
||||||
val enabledSources = getEnabledSources()
|
val enabledSources = getEnabledSources()
|
||||||
|
@ -73,8 +91,8 @@ abstract class SearchScreenModel<T>(
|
||||||
return extensionManager.installedExtensionsFlow.value
|
return extensionManager.installedExtensionsFlow.value
|
||||||
.filter { it.pkgName == filter }
|
.filter { it.pkgName == filter }
|
||||||
.flatMap { it.sources }
|
.flatMap { it.sources }
|
||||||
.filter { it in enabledSources }
|
|
||||||
.filterIsInstance<CatalogueSource>()
|
.filterIsInstance<CatalogueSource>()
|
||||||
|
.filter { it in enabledSources }
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract fun updateSearchQuery(query: String?)
|
abstract fun updateSearchQuery(query: String?)
|
||||||
|
@ -87,15 +105,19 @@ abstract class SearchScreenModel<T>(
|
||||||
updateItems(function(getItems()))
|
updateItems(function(getItems()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract fun setSourceFilter(filter: SourceFilter)
|
||||||
|
|
||||||
|
abstract fun toggleFilterResults()
|
||||||
|
|
||||||
fun search(query: String) {
|
fun search(query: String) {
|
||||||
if (this.query == query) return
|
if (this.query == query) return
|
||||||
|
|
||||||
this.query = query
|
this.query = query
|
||||||
|
|
||||||
|
searchJob?.cancel()
|
||||||
val initialItems = getSelectedSources().associateWith { SearchItemResult.Loading }
|
val initialItems = getSelectedSources().associateWith { SearchItemResult.Loading }
|
||||||
updateItems(initialItems)
|
updateItems(initialItems)
|
||||||
|
searchJob = ioCoroutineScope.launch {
|
||||||
ioCoroutineScope.launch {
|
|
||||||
sources
|
sources
|
||||||
.map { source ->
|
.map { source ->
|
||||||
async {
|
async {
|
||||||
|
|
Reference in a new issue