Minor cleanup
This commit is contained in:
parent
2556e9f08c
commit
abae9bf37d
46 changed files with 341 additions and 331 deletions
|
@ -72,9 +72,9 @@ class SetReadStatus(
|
|||
suspend fun await(manga: Manga, read: Boolean) =
|
||||
await(manga.id, read)
|
||||
|
||||
sealed class Result {
|
||||
data object Success : Result()
|
||||
data object NoChapters : Result()
|
||||
data class InternalError(val error: Throwable) : Result()
|
||||
sealed interface Result {
|
||||
data object Success : Result
|
||||
data object NoChapters : Result
|
||||
data class InternalError(val error: Throwable) : Result
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ import eu.kanade.presentation.more.settings.widget.TrailingWidgetBuffer
|
|||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.extension.model.Extension
|
||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||
import eu.kanade.tachiyomi.ui.browse.extension.details.ExtensionDetailsState
|
||||
import eu.kanade.tachiyomi.ui.browse.extension.details.ExtensionDetailsScreenModel
|
||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||
import tachiyomi.presentation.core.components.ScrollbarLazyColumn
|
||||
import tachiyomi.presentation.core.components.material.DIVIDER_ALPHA
|
||||
|
@ -65,7 +65,7 @@ import tachiyomi.presentation.core.screens.EmptyScreen
|
|||
@Composable
|
||||
fun ExtensionDetailsScreen(
|
||||
navigateUp: () -> Unit,
|
||||
state: ExtensionDetailsState,
|
||||
state: ExtensionDetailsScreenModel.State,
|
||||
onClickSourcePreferences: (sourceId: Long) -> Unit,
|
||||
onClickWhatsNew: () -> Unit,
|
||||
onClickReadme: () -> Unit,
|
||||
|
|
|
@ -43,7 +43,7 @@ import eu.kanade.tachiyomi.R
|
|||
import eu.kanade.tachiyomi.extension.model.Extension
|
||||
import eu.kanade.tachiyomi.extension.model.InstallStep
|
||||
import eu.kanade.tachiyomi.ui.browse.extension.ExtensionUiModel
|
||||
import eu.kanade.tachiyomi.ui.browse.extension.ExtensionsState
|
||||
import eu.kanade.tachiyomi.ui.browse.extension.ExtensionsScreenModel
|
||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||
import tachiyomi.presentation.core.components.FastScrollLazyColumn
|
||||
import tachiyomi.presentation.core.components.material.PullRefresh
|
||||
|
@ -57,7 +57,7 @@ import tachiyomi.presentation.core.util.secondaryItemAlpha
|
|||
|
||||
@Composable
|
||||
fun ExtensionScreen(
|
||||
state: ExtensionsState,
|
||||
state: ExtensionsScreenModel.State,
|
||||
contentPadding: PaddingValues,
|
||||
searchQuery: String?,
|
||||
onLongClickItem: (Extension) -> Unit,
|
||||
|
@ -108,7 +108,7 @@ fun ExtensionScreen(
|
|||
|
||||
@Composable
|
||||
private fun ExtensionContent(
|
||||
state: ExtensionsState,
|
||||
state: ExtensionsScreenModel.State,
|
||||
contentPadding: PaddingValues,
|
||||
onLongClickItem: (Extension) -> Unit,
|
||||
onClickItemCancel: (Extension) -> Unit,
|
||||
|
|
|
@ -8,7 +8,7 @@ import androidx.compose.ui.Modifier
|
|||
import eu.kanade.presentation.components.AppBar
|
||||
import eu.kanade.presentation.manga.components.BaseMangaListItem
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.manga.MigrateMangaState
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.manga.MigrateMangaScreenModel
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.presentation.core.components.FastScrollLazyColumn
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
|
@ -18,7 +18,7 @@ import tachiyomi.presentation.core.screens.EmptyScreen
|
|||
fun MigrateMangaScreen(
|
||||
navigateUp: () -> Unit,
|
||||
title: String?,
|
||||
state: MigrateMangaState,
|
||||
state: MigrateMangaScreenModel.State,
|
||||
onClickItem: (Manga) -> Unit,
|
||||
onClickCover: (Manga) -> Unit,
|
||||
) {
|
||||
|
@ -51,7 +51,7 @@ fun MigrateMangaScreen(
|
|||
@Composable
|
||||
private fun MigrateMangaContent(
|
||||
contentPadding: PaddingValues,
|
||||
state: MigrateMangaState,
|
||||
state: MigrateMangaScreenModel.State,
|
||||
onClickItem: (Manga) -> Unit,
|
||||
onClickCover: (Manga) -> Unit,
|
||||
) {
|
||||
|
|
|
@ -26,7 +26,7 @@ import eu.kanade.domain.source.interactor.SetMigrateSorting
|
|||
import eu.kanade.presentation.browse.components.BaseSourceItem
|
||||
import eu.kanade.presentation.browse.components.SourceIcon
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.sources.MigrateSourceState
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.sources.MigrateSourceScreenModel
|
||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||
import tachiyomi.domain.source.model.Source
|
||||
import tachiyomi.presentation.core.components.Badge
|
||||
|
@ -43,7 +43,7 @@ import tachiyomi.presentation.core.util.secondaryItemAlpha
|
|||
|
||||
@Composable
|
||||
fun MigrateSourceScreen(
|
||||
state: MigrateSourceState,
|
||||
state: MigrateSourceScreenModel.State,
|
||||
contentPadding: PaddingValues,
|
||||
onClickItem: (Source) -> Unit,
|
||||
onToggleSortingDirection: () -> Unit,
|
||||
|
|
|
@ -12,7 +12,7 @@ import eu.kanade.presentation.browse.components.BaseSourceItem
|
|||
import eu.kanade.presentation.components.AppBar
|
||||
import eu.kanade.presentation.more.settings.widget.SwitchPreferenceWidget
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.browse.source.SourcesFilterState
|
||||
import eu.kanade.tachiyomi.ui.browse.source.SourcesFilterScreenModel
|
||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||
import tachiyomi.domain.source.model.Source
|
||||
import tachiyomi.presentation.core.components.FastScrollLazyColumn
|
||||
|
@ -22,7 +22,7 @@ import tachiyomi.presentation.core.screens.EmptyScreen
|
|||
@Composable
|
||||
fun SourcesFilterScreen(
|
||||
navigateUp: () -> Unit,
|
||||
state: SourcesFilterState.Success,
|
||||
state: SourcesFilterScreenModel.State.Success,
|
||||
onClickLanguage: (String) -> Unit,
|
||||
onClickSource: (Source) -> Unit,
|
||||
) {
|
||||
|
@ -54,7 +54,7 @@ fun SourcesFilterScreen(
|
|||
@Composable
|
||||
private fun SourcesFilterContent(
|
||||
contentPadding: PaddingValues,
|
||||
state: SourcesFilterState.Success,
|
||||
state: SourcesFilterScreenModel.State.Success,
|
||||
onClickLanguage: (String) -> Unit,
|
||||
onClickSource: (Source) -> Unit,
|
||||
) {
|
||||
|
|
|
@ -192,7 +192,7 @@ fun SourceOptionsDialog(
|
|||
)
|
||||
}
|
||||
|
||||
sealed class SourceUiModel {
|
||||
data class Item(val source: Source) : SourceUiModel()
|
||||
data class Header(val language: String) : SourceUiModel()
|
||||
sealed interface SourceUiModel {
|
||||
data class Item(val source: Source) : SourceUiModel
|
||||
data class Header(val language: String) : SourceUiModel
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ import eu.kanade.presentation.components.SearchToolbar
|
|||
import eu.kanade.presentation.history.components.HistoryItem
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.history.HistoryScreenModel
|
||||
import eu.kanade.tachiyomi.ui.history.HistoryState
|
||||
import tachiyomi.domain.history.model.HistoryWithRelations
|
||||
import tachiyomi.presentation.core.components.FastScrollLazyColumn
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
|
@ -33,7 +32,7 @@ import java.util.Date
|
|||
|
||||
@Composable
|
||||
fun HistoryScreen(
|
||||
state: HistoryState,
|
||||
state: HistoryScreenModel.State,
|
||||
snackbarHostState: SnackbarHostState,
|
||||
onSearchQueryChange: (String?) -> Unit,
|
||||
onClickCover: (mangaId: Long) -> Unit,
|
||||
|
@ -139,7 +138,7 @@ private fun HistoryScreenContent(
|
|||
}
|
||||
}
|
||||
|
||||
sealed class HistoryUiModel {
|
||||
data class Header(val date: Date) : HistoryUiModel()
|
||||
data class Item(val item: HistoryWithRelations) : HistoryUiModel()
|
||||
sealed interface HistoryUiModel {
|
||||
data class Header(val date: Date) : HistoryUiModel
|
||||
data class Item(val item: HistoryWithRelations) : HistoryUiModel
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ import eu.kanade.tachiyomi.R
|
|||
import eu.kanade.tachiyomi.data.download.model.Download
|
||||
import eu.kanade.tachiyomi.source.getNameForMangaInfo
|
||||
import eu.kanade.tachiyomi.ui.manga.ChapterItem
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenModel
|
||||
import eu.kanade.tachiyomi.util.lang.toRelativeString
|
||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||
import tachiyomi.domain.chapter.model.Chapter
|
||||
|
@ -82,7 +82,7 @@ import java.util.Date
|
|||
|
||||
@Composable
|
||||
fun MangaScreen(
|
||||
state: MangaScreenState.Success,
|
||||
state: MangaScreenModel.State.Success,
|
||||
snackbarHostState: SnackbarHostState,
|
||||
dateRelativeTime: Int,
|
||||
dateFormat: DateFormat,
|
||||
|
@ -210,7 +210,7 @@ fun MangaScreen(
|
|||
|
||||
@Composable
|
||||
private fun MangaScreenSmallImpl(
|
||||
state: MangaScreenState.Success,
|
||||
state: MangaScreenModel.State.Success,
|
||||
snackbarHostState: SnackbarHostState,
|
||||
dateRelativeTime: Int,
|
||||
dateFormat: DateFormat,
|
||||
|
@ -436,7 +436,7 @@ private fun MangaScreenSmallImpl(
|
|||
|
||||
@Composable
|
||||
fun MangaScreenLargeImpl(
|
||||
state: MangaScreenState.Success,
|
||||
state: MangaScreenModel.State.Success,
|
||||
snackbarHostState: SnackbarHostState,
|
||||
dateRelativeTime: Int,
|
||||
dateFormat: DateFormat,
|
||||
|
|
|
@ -19,6 +19,7 @@ import androidx.compose.material3.MaterialTheme
|
|||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
|
@ -269,12 +270,15 @@ private class ClearDatabaseScreenModel : StateScreenModel<ClearDatabaseScreenMod
|
|||
state.copy(showConfirmation = false)
|
||||
}
|
||||
|
||||
sealed class State {
|
||||
data object Loading : State()
|
||||
sealed interface State {
|
||||
@Immutable
|
||||
data object Loading : State
|
||||
|
||||
@Immutable
|
||||
data class Ready(
|
||||
val items: List<SourceWithCount>,
|
||||
val selection: List<Long> = emptyList(),
|
||||
val showConfirmation: Boolean = false,
|
||||
) : State()
|
||||
) : State
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,9 +3,9 @@ package eu.kanade.presentation.more.stats
|
|||
import androidx.compose.runtime.Immutable
|
||||
import eu.kanade.presentation.more.stats.data.StatsData
|
||||
|
||||
sealed class StatsScreenState {
|
||||
sealed interface StatsScreenState {
|
||||
@Immutable
|
||||
data object Loading : StatsScreenState()
|
||||
data object Loading : StatsScreenState
|
||||
|
||||
@Immutable
|
||||
data class Success(
|
||||
|
@ -13,5 +13,5 @@ sealed class StatsScreenState {
|
|||
val titles: StatsData.Titles,
|
||||
val chapters: StatsData.Chapters,
|
||||
val trackers: StatsData.Trackers,
|
||||
) : StatsScreenState()
|
||||
) : StatsScreenState
|
||||
}
|
||||
|
|
|
@ -1,28 +1,28 @@
|
|||
package eu.kanade.presentation.more.stats.data
|
||||
|
||||
sealed class StatsData {
|
||||
sealed interface StatsData {
|
||||
|
||||
data class Overview(
|
||||
val libraryMangaCount: Int,
|
||||
val completedMangaCount: Int,
|
||||
val totalReadDuration: Long,
|
||||
) : StatsData()
|
||||
) : StatsData
|
||||
|
||||
data class Titles(
|
||||
val globalUpdateItemCount: Int,
|
||||
val startedMangaCount: Int,
|
||||
val localMangaCount: Int,
|
||||
) : StatsData()
|
||||
) : StatsData
|
||||
|
||||
data class Chapters(
|
||||
val totalChapterCount: Int,
|
||||
val readChapterCount: Int,
|
||||
val downloadCount: Int,
|
||||
) : StatsData()
|
||||
) : StatsData
|
||||
|
||||
data class Trackers(
|
||||
val trackedTitleCount: Int,
|
||||
val meanScore: Double,
|
||||
val trackerCount: Int,
|
||||
) : StatsData()
|
||||
) : StatsData
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ import eu.kanade.presentation.manga.components.MangaBottomActionMenu
|
|||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.download.model.Download
|
||||
import eu.kanade.tachiyomi.ui.updates.UpdatesItem
|
||||
import eu.kanade.tachiyomi.ui.updates.UpdatesState
|
||||
import eu.kanade.tachiyomi.ui.updates.UpdatesScreenModel
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import tachiyomi.presentation.core.components.FastScrollLazyColumn
|
||||
|
@ -40,7 +40,7 @@ import kotlin.time.Duration.Companion.seconds
|
|||
|
||||
@Composable
|
||||
fun UpdateScreen(
|
||||
state: UpdatesState,
|
||||
state: UpdatesScreenModel.State,
|
||||
snackbarHostState: SnackbarHostState,
|
||||
lastUpdated: Long,
|
||||
relativeTime: Int,
|
||||
|
@ -209,7 +209,7 @@ private fun UpdatesBottomBar(
|
|||
)
|
||||
}
|
||||
|
||||
sealed class UpdatesUiModel {
|
||||
data class Header(val date: String) : UpdatesUiModel()
|
||||
data class Item(val item: UpdatesItem) : UpdatesUiModel()
|
||||
sealed interface UpdatesUiModel {
|
||||
data class Header(val date: String) : UpdatesUiModel
|
||||
data class Item(val item: UpdatesItem) : UpdatesUiModel
|
||||
}
|
||||
|
|
|
@ -152,8 +152,8 @@ sealed class Image(
|
|||
}
|
||||
}
|
||||
|
||||
sealed class Location {
|
||||
data class Pictures private constructor(val relativePath: String) : Location() {
|
||||
sealed interface Location {
|
||||
data class Pictures private constructor(val relativePath: String) : Location {
|
||||
companion object {
|
||||
fun create(relativePath: String = ""): Pictures {
|
||||
return Pictures(relativePath)
|
||||
|
@ -161,7 +161,7 @@ sealed class Location {
|
|||
}
|
||||
}
|
||||
|
||||
data object Cache : Location()
|
||||
data object Cache : Location
|
||||
|
||||
fun directory(context: Context): File {
|
||||
return when (this) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package eu.kanade.tachiyomi.extension.model
|
||||
|
||||
sealed class LoadResult {
|
||||
data class Success(val extension: Extension.Installed) : LoadResult()
|
||||
data class Untrusted(val extension: Extension.Untrusted) : LoadResult()
|
||||
data object Error : LoadResult()
|
||||
sealed interface LoadResult {
|
||||
data class Success(val extension: Extension.Installed) : LoadResult
|
||||
data class Untrusted(val extension: Extension.Untrusted) : LoadResult
|
||||
data object Error : LoadResult
|
||||
}
|
||||
|
|
|
@ -54,20 +54,20 @@ class ExtensionFilterScreenModel(
|
|||
}
|
||||
}
|
||||
|
||||
sealed class ExtensionFilterEvent {
|
||||
data object FailedFetchingLanguages : ExtensionFilterEvent()
|
||||
sealed interface ExtensionFilterEvent {
|
||||
data object FailedFetchingLanguages : ExtensionFilterEvent
|
||||
}
|
||||
|
||||
sealed class ExtensionFilterState {
|
||||
sealed interface ExtensionFilterState {
|
||||
|
||||
@Immutable
|
||||
data object Loading : ExtensionFilterState()
|
||||
data object Loading : ExtensionFilterState
|
||||
|
||||
@Immutable
|
||||
data class Success(
|
||||
val languages: List<String>,
|
||||
val enabledLanguages: Set<String> = emptySet(),
|
||||
) : ExtensionFilterState() {
|
||||
) : ExtensionFilterState {
|
||||
|
||||
val isEmpty: Boolean
|
||||
get() = languages.isEmpty()
|
||||
|
|
|
@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.browse.extension
|
|||
|
||||
import android.app.Application
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.runtime.Immutable
|
||||
import cafe.adriel.voyager.core.model.StateScreenModel
|
||||
import cafe.adriel.voyager.core.model.coroutineScope
|
||||
import eu.kanade.domain.extension.interactor.GetExtensionsByType
|
||||
|
@ -35,7 +36,7 @@ class ExtensionsScreenModel(
|
|||
preferences: SourcePreferences = Injekt.get(),
|
||||
private val extensionManager: ExtensionManager = Injekt.get(),
|
||||
private val getExtensions: GetExtensionsByType = Injekt.get(),
|
||||
) : StateScreenModel<ExtensionsState>(ExtensionsState()) {
|
||||
) : StateScreenModel<ExtensionsScreenModel.State>(State()) {
|
||||
|
||||
private var _currentDownloads = MutableStateFlow<Map<String, InstallStep>>(hashMapOf())
|
||||
|
||||
|
@ -190,16 +191,17 @@ class ExtensionsScreenModel(
|
|||
fun trustSignature(signatureHash: String) {
|
||||
extensionManager.trustSignature(signatureHash)
|
||||
}
|
||||
}
|
||||
|
||||
data class ExtensionsState(
|
||||
val isLoading: Boolean = true,
|
||||
val isRefreshing: Boolean = false,
|
||||
val items: ItemGroups = mutableMapOf(),
|
||||
val updates: Int = 0,
|
||||
val searchQuery: String? = null,
|
||||
) {
|
||||
val isEmpty = items.isEmpty()
|
||||
@Immutable
|
||||
data class State(
|
||||
val isLoading: Boolean = true,
|
||||
val isRefreshing: Boolean = false,
|
||||
val items: ItemGroups = mutableMapOf(),
|
||||
val updates: Int = 0,
|
||||
val searchQuery: String? = null,
|
||||
) {
|
||||
val isEmpty = items.isEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
typealias ItemGroups = MutableMap<ExtensionUiModel.Header, List<ExtensionUiModel.Item>>
|
||||
|
|
|
@ -38,7 +38,7 @@ class ExtensionDetailsScreenModel(
|
|||
private val extensionManager: ExtensionManager = Injekt.get(),
|
||||
private val getExtensionSources: GetExtensionSources = Injekt.get(),
|
||||
private val toggleSource: ToggleSource = Injekt.get(),
|
||||
) : StateScreenModel<ExtensionDetailsState>(ExtensionDetailsState()) {
|
||||
) : StateScreenModel<ExtensionDetailsScreenModel.State>(State()) {
|
||||
|
||||
private val _events: Channel<ExtensionDetailsEvent> = Channel()
|
||||
val events: Flow<ExtensionDetailsEvent> = _events.receiveAsFlow()
|
||||
|
@ -160,21 +160,21 @@ class ExtensionDetailsScreenModel(
|
|||
url + "/src/" + pkgName.replace(".", "/") + path
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
data class State(
|
||||
val extension: Extension.Installed? = null,
|
||||
private val _sources: List<ExtensionSourceItem>? = null,
|
||||
) {
|
||||
|
||||
val sources: List<ExtensionSourceItem>
|
||||
get() = _sources.orEmpty()
|
||||
|
||||
val isLoading: Boolean
|
||||
get() = extension == null || _sources == null
|
||||
}
|
||||
}
|
||||
|
||||
sealed class ExtensionDetailsEvent {
|
||||
data object Uninstalled : ExtensionDetailsEvent()
|
||||
}
|
||||
|
||||
@Immutable
|
||||
data class ExtensionDetailsState(
|
||||
val extension: Extension.Installed? = null,
|
||||
private val _sources: List<ExtensionSourceItem>? = null,
|
||||
) {
|
||||
|
||||
val sources: List<ExtensionSourceItem>
|
||||
get() = _sources.orEmpty()
|
||||
|
||||
val isLoading: Boolean
|
||||
get() = extension == null || _sources == null
|
||||
sealed interface ExtensionDetailsEvent {
|
||||
data object Uninstalled : ExtensionDetailsEvent
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ import eu.kanade.tachiyomi.util.system.toast
|
|||
import kotlinx.coroutines.flow.collectLatest
|
||||
import tachiyomi.presentation.core.screens.LoadingScreen
|
||||
|
||||
data class MigrationMangaScreen(
|
||||
data class MigrateMangaScreen(
|
||||
private val sourceId: Long,
|
||||
) : Screen() {
|
||||
|
||||
|
@ -25,7 +25,7 @@ data class MigrationMangaScreen(
|
|||
override fun Content() {
|
||||
val context = LocalContext.current
|
||||
val navigator = LocalNavigator.currentOrThrow
|
||||
val screenModel = rememberScreenModel { MigrationMangaScreenModel(sourceId) }
|
||||
val screenModel = rememberScreenModel { MigrateMangaScreenModel(sourceId) }
|
||||
|
||||
val state by screenModel.state.collectAsState()
|
||||
|
|
@ -20,11 +20,11 @@ import tachiyomi.domain.source.service.SourceManager
|
|||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class MigrationMangaScreenModel(
|
||||
class MigrateMangaScreenModel(
|
||||
private val sourceId: Long,
|
||||
private val sourceManager: SourceManager = Injekt.get(),
|
||||
private val getFavorites: GetFavorites = Injekt.get(),
|
||||
) : StateScreenModel<MigrateMangaState>(MigrateMangaState()) {
|
||||
) : StateScreenModel<MigrateMangaScreenModel.State>(State()) {
|
||||
|
||||
private val _events: Channel<MigrationMangaEvent> = Channel()
|
||||
val events: Flow<MigrationMangaEvent> = _events.receiveAsFlow()
|
||||
|
@ -51,24 +51,24 @@ class MigrationMangaScreenModel(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
data class State(
|
||||
val source: Source? = null,
|
||||
private val titleList: List<Manga>? = null,
|
||||
) {
|
||||
|
||||
val titles: List<Manga>
|
||||
get() = titleList.orEmpty()
|
||||
|
||||
val isLoading: Boolean
|
||||
get() = source == null || titleList == null
|
||||
|
||||
val isEmpty: Boolean
|
||||
get() = titles.isEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
sealed class MigrationMangaEvent {
|
||||
data object FailedFetchingFavorites : MigrationMangaEvent()
|
||||
}
|
||||
|
||||
@Immutable
|
||||
data class MigrateMangaState(
|
||||
val source: Source? = null,
|
||||
private val titleList: List<Manga>? = null,
|
||||
) {
|
||||
|
||||
val titles: List<Manga>
|
||||
get() = titleList.orEmpty()
|
||||
|
||||
val isLoading: Boolean
|
||||
get() = source == null || titleList == null
|
||||
|
||||
val isEmpty: Boolean
|
||||
get() = titles.isEmpty()
|
||||
sealed interface MigrationMangaEvent {
|
||||
data object FailedFetchingFavorites : MigrationMangaEvent
|
||||
}
|
|
@ -37,7 +37,7 @@ class MigrateSearchScreenDialogScreenModel(
|
|||
val dialog: Dialog? = null,
|
||||
)
|
||||
|
||||
sealed class Dialog {
|
||||
data class Migrate(val manga: Manga) : Dialog()
|
||||
sealed interface Dialog {
|
||||
data class Migrate(val manga: Manga) : Dialog
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package eu.kanade.tachiyomi.ui.browse.migration.sources
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import cafe.adriel.voyager.core.model.StateScreenModel
|
||||
import cafe.adriel.voyager.core.model.coroutineScope
|
||||
import eu.kanade.domain.source.interactor.GetSourcesWithFavoriteCount
|
||||
|
@ -23,7 +24,7 @@ class MigrateSourceScreenModel(
|
|||
preferences: SourcePreferences = Injekt.get(),
|
||||
private val getSourcesWithFavoriteCount: GetSourcesWithFavoriteCount = Injekt.get(),
|
||||
private val setMigrateSorting: SetMigrateSorting = Injekt.get(),
|
||||
) : StateScreenModel<MigrateSourceState>(MigrateSourceState()) {
|
||||
) : StateScreenModel<MigrateSourceScreenModel.State>(State()) {
|
||||
|
||||
private val _channel = Channel<Event>(Int.MAX_VALUE)
|
||||
val channel = _channel.receiveAsFlow()
|
||||
|
@ -76,16 +77,17 @@ class MigrateSourceScreenModel(
|
|||
}
|
||||
}
|
||||
|
||||
sealed class Event {
|
||||
data object FailedFetchingSourcesWithCount : Event()
|
||||
@Immutable
|
||||
data class State(
|
||||
val isLoading: Boolean = true,
|
||||
val items: List<Pair<Source, Long>> = emptyList(),
|
||||
val sortingMode: SetMigrateSorting.Mode = SetMigrateSorting.Mode.ALPHABETICAL,
|
||||
val sortingDirection: SetMigrateSorting.Direction = SetMigrateSorting.Direction.ASCENDING,
|
||||
) {
|
||||
val isEmpty = items.isEmpty()
|
||||
}
|
||||
|
||||
sealed interface Event {
|
||||
data object FailedFetchingSourcesWithCount : Event
|
||||
}
|
||||
}
|
||||
|
||||
data class MigrateSourceState(
|
||||
val isLoading: Boolean = true,
|
||||
val items: List<Pair<Source, Long>> = emptyList(),
|
||||
val sortingMode: SetMigrateSorting.Mode = SetMigrateSorting.Mode.ALPHABETICAL,
|
||||
val sortingDirection: SetMigrateSorting.Direction = SetMigrateSorting.Direction.ASCENDING,
|
||||
) {
|
||||
val isEmpty = items.isEmpty()
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ import eu.kanade.presentation.browse.MigrateSourceScreen
|
|||
import eu.kanade.presentation.components.AppBar
|
||||
import eu.kanade.presentation.components.TabContent
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.manga.MigrationMangaScreen
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.manga.MigrateMangaScreen
|
||||
|
||||
@Composable
|
||||
fun Screen.migrateSourceTab(): TabContent {
|
||||
|
@ -40,7 +40,7 @@ fun Screen.migrateSourceTab(): TabContent {
|
|||
state = state,
|
||||
contentPadding = contentPadding,
|
||||
onClickItem = { source ->
|
||||
navigator.push(MigrationMangaScreen(source.id))
|
||||
navigator.push(MigrateMangaScreen(source.id))
|
||||
},
|
||||
onToggleSortingDirection = screenModel::toggleSortingDirection,
|
||||
onToggleSortingMode = screenModel::toggleSortingMode,
|
||||
|
|
|
@ -22,12 +22,12 @@ class SourcesFilterScreen : Screen() {
|
|||
val screenModel = rememberScreenModel { SourcesFilterScreenModel() }
|
||||
val state by screenModel.state.collectAsState()
|
||||
|
||||
if (state is SourcesFilterState.Loading) {
|
||||
if (state is SourcesFilterScreenModel.State.Loading) {
|
||||
LoadingScreen()
|
||||
return
|
||||
}
|
||||
|
||||
if (state is SourcesFilterState.Error) {
|
||||
if (state is SourcesFilterScreenModel.State.Error) {
|
||||
val context = LocalContext.current
|
||||
LaunchedEffect(Unit) {
|
||||
context.toast(R.string.internal_error)
|
||||
|
@ -36,7 +36,7 @@ class SourcesFilterScreen : Screen() {
|
|||
return
|
||||
}
|
||||
|
||||
val successState = state as SourcesFilterState.Success
|
||||
val successState = state as SourcesFilterScreenModel.State.Success
|
||||
|
||||
SourcesFilterScreen(
|
||||
navigateUp = navigator::pop,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
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.source.interactor.GetLanguagesWithSources
|
||||
|
@ -21,7 +22,7 @@ class SourcesFilterScreenModel(
|
|||
private val getLanguagesWithSources: GetLanguagesWithSources = Injekt.get(),
|
||||
private val toggleSource: ToggleSource = Injekt.get(),
|
||||
private val toggleLanguage: ToggleLanguage = Injekt.get(),
|
||||
) : StateScreenModel<SourcesFilterState>(SourcesFilterState.Loading) {
|
||||
) : StateScreenModel<SourcesFilterScreenModel.State>(State.Loading) {
|
||||
|
||||
init {
|
||||
coroutineScope.launch {
|
||||
|
@ -32,14 +33,14 @@ class SourcesFilterScreenModel(
|
|||
) { a, b, c -> Triple(a, b, c) }
|
||||
.catch { throwable ->
|
||||
mutableState.update {
|
||||
SourcesFilterState.Error(
|
||||
State.Error(
|
||||
throwable = throwable,
|
||||
)
|
||||
}
|
||||
}
|
||||
.collectLatest { (languagesWithSources, enabledLanguages, disabledSources) ->
|
||||
mutableState.update {
|
||||
SourcesFilterState.Success(
|
||||
State.Success(
|
||||
items = languagesWithSources,
|
||||
enabledLanguages = enabledLanguages,
|
||||
disabledSources = disabledSources,
|
||||
|
@ -56,23 +57,26 @@ class SourcesFilterScreenModel(
|
|||
fun toggleLanguage(language: String) {
|
||||
toggleLanguage.await(language)
|
||||
}
|
||||
}
|
||||
|
||||
sealed class SourcesFilterState {
|
||||
sealed interface State {
|
||||
|
||||
data object Loading : SourcesFilterState()
|
||||
@Immutable
|
||||
data object Loading : State
|
||||
|
||||
data class Error(
|
||||
val throwable: Throwable,
|
||||
) : SourcesFilterState()
|
||||
@Immutable
|
||||
data class Error(
|
||||
val throwable: Throwable,
|
||||
) : State
|
||||
|
||||
data class Success(
|
||||
val items: SortedMap<String, List<Source>>,
|
||||
val enabledLanguages: Set<String>,
|
||||
val disabledSources: Set<String>,
|
||||
) : SourcesFilterState() {
|
||||
@Immutable
|
||||
data class Success(
|
||||
val items: SortedMap<String, List<Source>>,
|
||||
val enabledLanguages: Set<String>,
|
||||
val disabledSources: Set<String>,
|
||||
) : State {
|
||||
|
||||
val isEmpty: Boolean
|
||||
get() = items.isEmpty()
|
||||
val isEmpty: Boolean
|
||||
get() = items.isEmpty()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,8 +93,8 @@ class SourcesScreenModel(
|
|||
mutableState.update { it.copy(dialog = null) }
|
||||
}
|
||||
|
||||
sealed class Event {
|
||||
data object FailedFetchingSources : Event()
|
||||
sealed interface Event {
|
||||
data object FailedFetchingSources : Event
|
||||
}
|
||||
|
||||
data class Dialog(val source: Source)
|
||||
|
|
|
@ -365,15 +365,15 @@ class BrowseSourceScreenModel(
|
|||
}
|
||||
}
|
||||
|
||||
sealed class Dialog {
|
||||
data object Filter : Dialog()
|
||||
data class RemoveManga(val manga: Manga) : Dialog()
|
||||
data class AddDuplicateManga(val manga: Manga, val duplicate: Manga) : Dialog()
|
||||
sealed interface Dialog {
|
||||
data object Filter : Dialog
|
||||
data class RemoveManga(val manga: Manga) : Dialog
|
||||
data class AddDuplicateManga(val manga: Manga, val duplicate: Manga) : Dialog
|
||||
data class ChangeMangaCategory(
|
||||
val manga: Manga,
|
||||
val initialSelection: List<CheckboxState.State<Category>>,
|
||||
) : Dialog()
|
||||
data class Migrate(val newManga: Manga) : Dialog()
|
||||
) : Dialog
|
||||
data class Migrate(val newManga: Manga) : Dialog
|
||||
}
|
||||
|
||||
@Immutable
|
||||
|
|
|
@ -190,16 +190,16 @@ enum class SourceFilter {
|
|||
PinnedOnly,
|
||||
}
|
||||
|
||||
sealed class SearchItemResult {
|
||||
data object Loading : SearchItemResult()
|
||||
sealed interface SearchItemResult {
|
||||
data object Loading : SearchItemResult
|
||||
|
||||
data class Error(
|
||||
val throwable: Throwable,
|
||||
) : SearchItemResult()
|
||||
) : SearchItemResult
|
||||
|
||||
data class Success(
|
||||
val result: List<Manga>,
|
||||
) : SearchItemResult() {
|
||||
) : SearchItemResult {
|
||||
val isEmpty: Boolean
|
||||
get() = result.isEmpty()
|
||||
}
|
||||
|
|
|
@ -107,27 +107,27 @@ class CategoryScreenModel(
|
|||
}
|
||||
}
|
||||
|
||||
sealed class CategoryDialog {
|
||||
data object Create : CategoryDialog()
|
||||
data class Rename(val category: Category) : CategoryDialog()
|
||||
data class Delete(val category: Category) : CategoryDialog()
|
||||
sealed interface CategoryDialog {
|
||||
data object Create : CategoryDialog
|
||||
data class Rename(val category: Category) : CategoryDialog
|
||||
data class Delete(val category: Category) : CategoryDialog
|
||||
}
|
||||
|
||||
sealed class CategoryEvent {
|
||||
sealed class LocalizedMessage(@StringRes val stringRes: Int) : CategoryEvent()
|
||||
sealed interface CategoryEvent {
|
||||
sealed class LocalizedMessage(@StringRes val stringRes: Int) : CategoryEvent
|
||||
data object InternalError : LocalizedMessage(R.string.internal_error)
|
||||
}
|
||||
|
||||
sealed class CategoryScreenState {
|
||||
sealed interface CategoryScreenState {
|
||||
|
||||
@Immutable
|
||||
data object Loading : CategoryScreenState()
|
||||
data object Loading : CategoryScreenState
|
||||
|
||||
@Immutable
|
||||
data class Success(
|
||||
val categories: List<Category>,
|
||||
val dialog: CategoryDialog? = null,
|
||||
) : CategoryScreenState() {
|
||||
) : CategoryScreenState {
|
||||
|
||||
val isEmpty: Boolean
|
||||
get() = categories.isEmpty()
|
||||
|
|
|
@ -34,7 +34,7 @@ class HistoryScreenModel(
|
|||
private val getHistory: GetHistory = Injekt.get(),
|
||||
private val getNextChapters: GetNextChapters = Injekt.get(),
|
||||
private val removeHistory: RemoveHistory = Injekt.get(),
|
||||
) : StateScreenModel<HistoryState>(HistoryState()) {
|
||||
) : StateScreenModel<HistoryScreenModel.State>(State()) {
|
||||
|
||||
private val _events: Channel<Event> = Channel(Channel.UNLIMITED)
|
||||
val events: Flow<Event> = _events.receiveAsFlow()
|
||||
|
@ -113,21 +113,21 @@ class HistoryScreenModel(
|
|||
mutableState.update { it.copy(dialog = dialog) }
|
||||
}
|
||||
|
||||
sealed class Dialog {
|
||||
data object DeleteAll : Dialog()
|
||||
data class Delete(val history: HistoryWithRelations) : Dialog()
|
||||
@Immutable
|
||||
data class State(
|
||||
val searchQuery: String? = null,
|
||||
val list: List<HistoryUiModel>? = null,
|
||||
val dialog: Dialog? = null,
|
||||
)
|
||||
|
||||
sealed interface Dialog {
|
||||
data object DeleteAll : Dialog
|
||||
data class Delete(val history: HistoryWithRelations) : Dialog
|
||||
}
|
||||
|
||||
sealed class Event {
|
||||
data class OpenChapter(val chapter: Chapter?) : Event()
|
||||
data object InternalError : Event()
|
||||
data object HistoryCleared : Event()
|
||||
sealed interface Event {
|
||||
data class OpenChapter(val chapter: Chapter?) : Event
|
||||
data object InternalError : Event
|
||||
data object HistoryCleared : Event
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
data class HistoryState(
|
||||
val searchQuery: String? = null,
|
||||
val list: List<HistoryUiModel>? = null,
|
||||
val dialog: HistoryScreenModel.Dialog? = null,
|
||||
)
|
||||
|
|
|
@ -291,11 +291,11 @@ object HomeScreen : Screen() {
|
|||
showBottomNavEvent.send(show)
|
||||
}
|
||||
|
||||
sealed class Tab {
|
||||
data class Library(val mangaIdToOpen: Long? = null) : Tab()
|
||||
data object Updates : Tab()
|
||||
data object History : Tab()
|
||||
data class Browse(val toExtensions: Boolean = false) : Tab()
|
||||
data class More(val toDownloads: Boolean) : Tab()
|
||||
sealed interface Tab {
|
||||
data class Library(val mangaIdToOpen: Long? = null) : Tab
|
||||
data object Updates : Tab
|
||||
data object History : Tab
|
||||
data class Browse(val toExtensions: Boolean = false) : Tab
|
||||
data class More(val toDownloads: Boolean) : Tab
|
||||
}
|
||||
}
|
||||
|
|
|
@ -657,10 +657,10 @@ class LibraryScreenModel(
|
|||
mutableState.update { it.copy(dialog = null) }
|
||||
}
|
||||
|
||||
sealed class Dialog {
|
||||
data object SettingsSheet : Dialog()
|
||||
data class ChangeCategory(val manga: List<Manga>, val initialSelection: List<CheckboxState<Category>>) : Dialog()
|
||||
data class DeleteManga(val manga: List<Manga>) : Dialog()
|
||||
sealed interface Dialog {
|
||||
data object SettingsSheet : Dialog
|
||||
data class ChangeCategory(val manga: List<Manga>, val initialSelection: List<CheckboxState<Category>>) : Dialog
|
||||
data class DeleteManga(val manga: List<Manga>) : Dialog
|
||||
}
|
||||
|
||||
@Immutable
|
||||
|
|
|
@ -75,12 +75,12 @@ class MangaScreen(
|
|||
|
||||
val state by screenModel.state.collectAsState()
|
||||
|
||||
if (state is MangaScreenState.Loading) {
|
||||
if (state is MangaScreenModel.State.Loading) {
|
||||
LoadingScreen()
|
||||
return
|
||||
}
|
||||
|
||||
val successState = state as MangaScreenState.Success
|
||||
val successState = state as MangaScreenModel.State.Success
|
||||
val isHttpSource = remember { successState.source is HttpSource }
|
||||
|
||||
LaunchedEffect(successState.manga, screenModel.source) {
|
||||
|
|
|
@ -98,10 +98,10 @@ class MangaScreenModel(
|
|||
private val getTracks: GetTracks = Injekt.get(),
|
||||
private val setMangaCategories: SetMangaCategories = Injekt.get(),
|
||||
val snackbarHostState: SnackbarHostState = SnackbarHostState(),
|
||||
) : StateScreenModel<MangaScreenState>(MangaScreenState.Loading) {
|
||||
) : StateScreenModel<MangaScreenModel.State>(State.Loading) {
|
||||
|
||||
private val successState: MangaScreenState.Success?
|
||||
get() = state.value as? MangaScreenState.Success
|
||||
private val successState: State.Success?
|
||||
get() = state.value as? State.Success
|
||||
|
||||
private val loggedServices by lazy { trackManager.services.filter { it.isLogged } }
|
||||
|
||||
|
@ -133,11 +133,11 @@ class MangaScreenModel(
|
|||
/**
|
||||
* Helper function to update the UI state only if it's currently in success state
|
||||
*/
|
||||
private inline fun updateSuccessState(func: (MangaScreenState.Success) -> MangaScreenState.Success) {
|
||||
private inline fun updateSuccessState(func: (State.Success) -> State.Success) {
|
||||
mutableState.update {
|
||||
when (it) {
|
||||
MangaScreenState.Loading -> it
|
||||
is MangaScreenState.Success -> func(it)
|
||||
State.Loading -> it
|
||||
is State.Success -> func(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -175,7 +175,7 @@ class MangaScreenModel(
|
|||
|
||||
// Show what we have earlier
|
||||
mutableState.update {
|
||||
MangaScreenState.Success(
|
||||
State.Success(
|
||||
manga = manga,
|
||||
source = Injekt.get<SourceManager>().getOrStub(manga.source),
|
||||
isFromSource = isFromSource,
|
||||
|
@ -334,8 +334,7 @@ class MangaScreenModel(
|
|||
}
|
||||
|
||||
fun promptChangeCategories() {
|
||||
val state = successState ?: return
|
||||
val manga = state.manga
|
||||
val manga = successState?.manga ?: return
|
||||
coroutineScope.launch {
|
||||
val categories = getCategories()
|
||||
val selection = getMangaCategoryIds(manga)
|
||||
|
@ -662,9 +661,9 @@ class MangaScreenModel(
|
|||
}
|
||||
|
||||
fun markPreviousChapterRead(pointer: Chapter) {
|
||||
val successState = successState ?: return
|
||||
val manga = successState?.manga ?: return
|
||||
val chapters = filteredChapters.orEmpty().map { it.chapter }
|
||||
val prevChapters = if (successState.manga.sortDescending()) chapters.asReversed() else chapters
|
||||
val prevChapters = if (manga.sortDescending()) chapters.asReversed() else chapters
|
||||
val pointerPos = prevChapters.indexOf(pointer)
|
||||
if (pointerPos != -1) markChaptersRead(prevChapters.take(pointerPos), true)
|
||||
}
|
||||
|
@ -940,13 +939,13 @@ class MangaScreenModel(
|
|||
|
||||
// Track sheet - end
|
||||
|
||||
sealed class Dialog {
|
||||
data class ChangeCategory(val manga: Manga, val initialSelection: List<CheckboxState<Category>>) : Dialog()
|
||||
data class DeleteChapters(val chapters: List<Chapter>) : Dialog()
|
||||
data class DuplicateManga(val manga: Manga, val duplicate: Manga) : Dialog()
|
||||
data object SettingsSheet : Dialog()
|
||||
data object TrackSheet : Dialog()
|
||||
data object FullCover : Dialog()
|
||||
sealed interface Dialog {
|
||||
data class ChangeCategory(val manga: Manga, val initialSelection: List<CheckboxState<Category>>) : Dialog
|
||||
data class DeleteChapters(val chapters: List<Chapter>) : Dialog
|
||||
data class DuplicateManga(val manga: Manga, val duplicate: Manga) : Dialog
|
||||
data object SettingsSheet : Dialog
|
||||
data object TrackSheet : Dialog
|
||||
data object FullCover : Dialog
|
||||
}
|
||||
|
||||
fun dismissDialog() {
|
||||
|
@ -968,48 +967,48 @@ class MangaScreenModel(
|
|||
fun showCoverDialog() {
|
||||
updateSuccessState { it.copy(dialog = Dialog.FullCover) }
|
||||
}
|
||||
}
|
||||
|
||||
sealed class MangaScreenState {
|
||||
@Immutable
|
||||
object Loading : MangaScreenState()
|
||||
sealed interface State {
|
||||
@Immutable
|
||||
object Loading : State
|
||||
|
||||
@Immutable
|
||||
data class Success(
|
||||
val manga: Manga,
|
||||
val source: Source,
|
||||
val isFromSource: Boolean,
|
||||
val chapters: List<ChapterItem>,
|
||||
val trackItems: List<TrackItem> = emptyList(),
|
||||
val isRefreshingData: Boolean = false,
|
||||
val dialog: MangaScreenModel.Dialog? = null,
|
||||
val hasPromptedToAddBefore: Boolean = false,
|
||||
) : MangaScreenState() {
|
||||
@Immutable
|
||||
data class Success(
|
||||
val manga: Manga,
|
||||
val source: Source,
|
||||
val isFromSource: Boolean,
|
||||
val chapters: List<ChapterItem>,
|
||||
val trackItems: List<TrackItem> = emptyList(),
|
||||
val isRefreshingData: Boolean = false,
|
||||
val dialog: Dialog? = null,
|
||||
val hasPromptedToAddBefore: Boolean = false,
|
||||
) : State {
|
||||
|
||||
val processedChapters by lazy {
|
||||
chapters.applyFilters(manga).toList()
|
||||
}
|
||||
val processedChapters by lazy {
|
||||
chapters.applyFilters(manga).toList()
|
||||
}
|
||||
|
||||
val trackingAvailable: Boolean
|
||||
get() = trackItems.isNotEmpty()
|
||||
val trackingAvailable: Boolean
|
||||
get() = trackItems.isNotEmpty()
|
||||
|
||||
val trackingCount: Int
|
||||
get() = trackItems.count { it.track != null }
|
||||
val trackingCount: Int
|
||||
get() = trackItems.count { it.track != null }
|
||||
|
||||
/**
|
||||
* Applies the view filters to the list of chapters obtained from the database.
|
||||
* @return an observable of the list of chapters filtered and sorted.
|
||||
*/
|
||||
private fun List<ChapterItem>.applyFilters(manga: Manga): Sequence<ChapterItem> {
|
||||
val isLocalManga = manga.isLocal()
|
||||
val unreadFilter = manga.unreadFilter
|
||||
val downloadedFilter = manga.downloadedFilter
|
||||
val bookmarkedFilter = manga.bookmarkedFilter
|
||||
return asSequence()
|
||||
.filter { (chapter) -> applyFilter(unreadFilter) { !chapter.read } }
|
||||
.filter { (chapter) -> applyFilter(bookmarkedFilter) { chapter.bookmark } }
|
||||
.filter { applyFilter(downloadedFilter) { it.isDownloaded || isLocalManga } }
|
||||
.sortedWith { (chapter1), (chapter2) -> getChapterSort(manga).invoke(chapter1, chapter2) }
|
||||
/**
|
||||
* Applies the view filters to the list of chapters obtained from the database.
|
||||
* @return an observable of the list of chapters filtered and sorted.
|
||||
*/
|
||||
private fun List<ChapterItem>.applyFilters(manga: Manga): Sequence<ChapterItem> {
|
||||
val isLocalManga = manga.isLocal()
|
||||
val unreadFilter = manga.unreadFilter
|
||||
val downloadedFilter = manga.downloadedFilter
|
||||
val bookmarkedFilter = manga.bookmarkedFilter
|
||||
return asSequence()
|
||||
.filter { (chapter) -> applyFilter(unreadFilter) { !chapter.read } }
|
||||
.filter { (chapter) -> applyFilter(bookmarkedFilter) { chapter.bookmark } }
|
||||
.filter { applyFilter(downloadedFilter) { it.isDownloaded || isLocalManga } }
|
||||
.sortedWith { (chapter1), (chapter2) -> getChapterSort(manga).invoke(chapter1, chapter2) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -108,8 +108,8 @@ private class MoreScreenModel(
|
|||
}
|
||||
}
|
||||
|
||||
sealed class DownloadQueueState {
|
||||
data object Stopped : DownloadQueueState()
|
||||
data class Paused(val pending: Int) : DownloadQueueState()
|
||||
data class Downloading(val pending: Int) : DownloadQueueState()
|
||||
sealed interface DownloadQueueState {
|
||||
data object Stopped : DownloadQueueState
|
||||
data class Paused(val pending: Int) : DownloadQueueState
|
||||
data class Downloading(val pending: Int) : DownloadQueueState
|
||||
}
|
||||
|
|
|
@ -798,9 +798,9 @@ class ReaderViewModel(
|
|||
Error,
|
||||
}
|
||||
|
||||
sealed class SaveImageResult {
|
||||
class Success(val uri: Uri) : SaveImageResult()
|
||||
class Error(val error: Throwable) : SaveImageResult()
|
||||
sealed interface SaveImageResult {
|
||||
class Success(val uri: Uri) : SaveImageResult
|
||||
class Error(val error: Throwable) : SaveImageResult
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -860,18 +860,18 @@ class ReaderViewModel(
|
|||
get() = viewerChapters?.currChapter?.pages?.size ?: -1
|
||||
}
|
||||
|
||||
sealed class Dialog {
|
||||
data object Loading : Dialog()
|
||||
data object Settings : Dialog()
|
||||
data class PageActions(val page: ReaderPage) : Dialog()
|
||||
sealed interface Dialog {
|
||||
data object Loading : Dialog
|
||||
data object Settings : Dialog
|
||||
data class PageActions(val page: ReaderPage) : Dialog
|
||||
}
|
||||
|
||||
sealed class Event {
|
||||
data object ReloadViewerChapters : Event()
|
||||
data class SetOrientation(val orientation: Int) : Event()
|
||||
data class SetCoverResult(val result: SetAsCoverResult) : Event()
|
||||
sealed interface Event {
|
||||
data object ReloadViewerChapters : Event
|
||||
data class SetOrientation(val orientation: Int) : Event
|
||||
data class SetCoverResult(val result: SetAsCoverResult) : Event
|
||||
|
||||
data class SavedImage(val result: SaveImageResult) : Event()
|
||||
data class ShareImage(val uri: Uri, val page: ReaderPage) : Event()
|
||||
data class SavedImage(val result: SaveImageResult) : Event
|
||||
data class ShareImage(val uri: Uri, val page: ReaderPage) : Event
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,10 +39,10 @@ data class ReaderChapter(val chapter: Chapter) {
|
|||
}
|
||||
}
|
||||
|
||||
sealed class State {
|
||||
data object Wait : State()
|
||||
data object Loading : State()
|
||||
data class Error(val error: Throwable) : State()
|
||||
data class Loaded(val pages: List<ReaderPage>) : State()
|
||||
sealed interface State {
|
||||
data object Wait : State
|
||||
data object Loading : State
|
||||
data class Error(val error: Throwable) : State
|
||||
data class Loaded(val pages: List<ReaderPage>) : State
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ class UpdatesScreenModel(
|
|||
private val libraryPreferences: LibraryPreferences = Injekt.get(),
|
||||
val snackbarHostState: SnackbarHostState = SnackbarHostState(),
|
||||
uiPreferences: UiPreferences = Injekt.get(),
|
||||
) : StateScreenModel<UpdatesState>(UpdatesState()) {
|
||||
) : StateScreenModel<UpdatesScreenModel.State>(State()) {
|
||||
|
||||
private val _events: Channel<Event> = Channel(Int.MAX_VALUE)
|
||||
val events: Flow<Event> = _events.receiveAsFlow()
|
||||
|
@ -366,46 +366,46 @@ class UpdatesScreenModel(
|
|||
libraryPreferences.newUpdatesCount().set(0)
|
||||
}
|
||||
|
||||
sealed class Dialog {
|
||||
data class DeleteConfirmation(val toDelete: List<UpdatesItem>) : Dialog()
|
||||
}
|
||||
@Immutable
|
||||
data class State(
|
||||
val isLoading: Boolean = true,
|
||||
val items: List<UpdatesItem> = emptyList(),
|
||||
val dialog: UpdatesScreenModel.Dialog? = null,
|
||||
) {
|
||||
val selected = items.filter { it.selected }
|
||||
val selectionMode = selected.isNotEmpty()
|
||||
|
||||
sealed class Event {
|
||||
data object InternalError : Event()
|
||||
data class LibraryUpdateTriggered(val started: Boolean) : Event()
|
||||
}
|
||||
}
|
||||
fun getUiModel(context: Context, relativeTime: Int): List<UpdatesUiModel> {
|
||||
val dateFormat by mutableStateOf(UiPreferences.dateFormat(Injekt.get<UiPreferences>().dateFormat().get()))
|
||||
|
||||
@Immutable
|
||||
data class UpdatesState(
|
||||
val isLoading: Boolean = true,
|
||||
val items: List<UpdatesItem> = emptyList(),
|
||||
val dialog: UpdatesScreenModel.Dialog? = null,
|
||||
) {
|
||||
val selected = items.filter { it.selected }
|
||||
val selectionMode = selected.isNotEmpty()
|
||||
|
||||
fun getUiModel(context: Context, relativeTime: Int): List<UpdatesUiModel> {
|
||||
val dateFormat by mutableStateOf(UiPreferences.dateFormat(Injekt.get<UiPreferences>().dateFormat().get()))
|
||||
|
||||
return items
|
||||
.map { UpdatesUiModel.Item(it) }
|
||||
.insertSeparators { before, after ->
|
||||
val beforeDate = before?.item?.update?.dateFetch?.toDateKey() ?: Date(0)
|
||||
val afterDate = after?.item?.update?.dateFetch?.toDateKey() ?: Date(0)
|
||||
when {
|
||||
beforeDate.time != afterDate.time && afterDate.time != 0L -> {
|
||||
val text = afterDate.toRelativeString(
|
||||
context = context,
|
||||
range = relativeTime,
|
||||
dateFormat = dateFormat,
|
||||
)
|
||||
UpdatesUiModel.Header(text)
|
||||
return items
|
||||
.map { UpdatesUiModel.Item(it) }
|
||||
.insertSeparators { before, after ->
|
||||
val beforeDate = before?.item?.update?.dateFetch?.toDateKey() ?: Date(0)
|
||||
val afterDate = after?.item?.update?.dateFetch?.toDateKey() ?: Date(0)
|
||||
when {
|
||||
beforeDate.time != afterDate.time && afterDate.time != 0L -> {
|
||||
val text = afterDate.toRelativeString(
|
||||
context = context,
|
||||
range = relativeTime,
|
||||
dateFormat = dateFormat,
|
||||
)
|
||||
UpdatesUiModel.Header(text)
|
||||
}
|
||||
// Return null to avoid adding a separator between two items.
|
||||
else -> null
|
||||
}
|
||||
// Return null to avoid adding a separator between two items.
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed interface Dialog {
|
||||
data class DeleteConfirmation(val toDelete: List<UpdatesItem>) : Dialog
|
||||
}
|
||||
|
||||
sealed interface Event {
|
||||
data object InternalError : Event
|
||||
data class LibraryUpdateTriggered(val started: Boolean) : Event
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,8 +37,8 @@ class CreateCategoryWithName(
|
|||
}
|
||||
}
|
||||
|
||||
sealed class Result {
|
||||
data object Success : Result()
|
||||
data class InternalError(val error: Throwable) : Result()
|
||||
sealed interface Result {
|
||||
data object Success : Result
|
||||
data class InternalError(val error: Throwable) : Result
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,8 +35,8 @@ class DeleteCategory(
|
|||
}
|
||||
}
|
||||
|
||||
sealed class Result {
|
||||
data object Success : Result()
|
||||
data class InternalError(val error: Throwable) : Result()
|
||||
sealed interface Result {
|
||||
data object Success : Result
|
||||
data class InternalError(val error: Throwable) : Result
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,8 +28,8 @@ class RenameCategory(
|
|||
|
||||
suspend fun await(category: Category, name: String) = await(category.id, name)
|
||||
|
||||
sealed class Result {
|
||||
data object Success : Result()
|
||||
data class InternalError(val error: Throwable) : Result()
|
||||
sealed interface Result {
|
||||
data object Success : Result
|
||||
data class InternalError(val error: Throwable) : Result
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,10 +57,10 @@ class ReorderCategory(
|
|||
}
|
||||
}
|
||||
|
||||
sealed class Result {
|
||||
data object Success : Result()
|
||||
data object Unchanged : Result()
|
||||
data class InternalError(val error: Throwable) : Result()
|
||||
sealed interface Result {
|
||||
data object Success : Result
|
||||
data object Unchanged : Result
|
||||
data class InternalError(val error: Throwable) : Result
|
||||
}
|
||||
|
||||
private enum class MoveTo {
|
||||
|
|
|
@ -17,8 +17,8 @@ class UpdateCategory(
|
|||
}
|
||||
}
|
||||
|
||||
sealed class Result {
|
||||
data object Success : Result()
|
||||
data class Error(val error: Exception) : Result()
|
||||
sealed interface Result {
|
||||
data object Success : Result
|
||||
data class Error(val error: Exception) : Result
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
package tachiyomi.domain.library.model
|
||||
|
||||
sealed class LibraryDisplayMode {
|
||||
sealed interface LibraryDisplayMode {
|
||||
|
||||
data object CompactGrid : LibraryDisplayMode()
|
||||
data object ComfortableGrid : LibraryDisplayMode()
|
||||
data object List : LibraryDisplayMode()
|
||||
data object CoverOnlyGrid : LibraryDisplayMode()
|
||||
data object CompactGrid : LibraryDisplayMode
|
||||
data object ComfortableGrid : LibraryDisplayMode
|
||||
data object List : LibraryDisplayMode
|
||||
data object CoverOnlyGrid : LibraryDisplayMode
|
||||
|
||||
object Serializer {
|
||||
fun deserialize(serialized: String): LibraryDisplayMode {
|
||||
|
|
|
@ -71,9 +71,9 @@ class GetApplicationRelease(
|
|||
val forceCheck: Boolean = false,
|
||||
)
|
||||
|
||||
sealed class Result {
|
||||
data class NewUpdate(val release: Release) : Result()
|
||||
data object NoNewUpdate : Result()
|
||||
data object ThirdPartyInstallation : Result()
|
||||
sealed interface Result {
|
||||
data class NewUpdate(val release: Release) : Result
|
||||
data object NoNewUpdate : Result
|
||||
data object ThirdPartyInstallation : Result
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,11 +2,11 @@ package tachiyomi.source.local.io
|
|||
|
||||
import java.io.File
|
||||
|
||||
sealed class Format {
|
||||
data class Directory(val file: File) : Format()
|
||||
data class Zip(val file: File) : Format()
|
||||
data class Rar(val file: File) : Format()
|
||||
data class Epub(val file: File) : Format()
|
||||
sealed interface Format {
|
||||
data class Directory(val file: File) : Format
|
||||
data class Zip(val file: File) : Format
|
||||
data class Rar(val file: File) : Format
|
||||
data class Epub(val file: File) : Format
|
||||
|
||||
class UnknownFormatException : Exception()
|
||||
|
||||
|
|
Reference in a new issue