mirror of
https://github.com/mihonapp/mihon.git
synced 2025-11-15 13:37:29 +01:00
Minor cleanup
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user