mirror of
https://github.com/aniyomiorg/aniyomi.git
synced 2024-11-21 20:27:06 +03:00
parent
370212c677
commit
a439045319
112 changed files with 758 additions and 867 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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,9 +72,9 @@ class SetSeenStatus(
|
|||
suspend fun await(anime: Anime, seen: Boolean) =
|
||||
await(anime.id, seen)
|
||||
|
||||
sealed class Result {
|
||||
data object Success : Result()
|
||||
data object NoEpisodes : Result()
|
||||
data class InternalError(val error: Throwable) : Result()
|
||||
sealed interface Result {
|
||||
data object Success : Result
|
||||
data object NoEpisodes : Result
|
||||
data class InternalError(val error: Throwable) : Result
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,12 +22,14 @@ import androidx.compose.material.icons.outlined.HelpOutline
|
|||
import androidx.compose.material.icons.outlined.History
|
||||
import androidx.compose.material.icons.outlined.Settings
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.VerticalDivider
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
|
@ -52,11 +54,9 @@ import eu.kanade.presentation.more.settings.widget.TrailingWidgetBuffer
|
|||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
|
||||
import eu.kanade.tachiyomi.extension.anime.model.AnimeExtension
|
||||
import eu.kanade.tachiyomi.ui.browse.anime.extension.details.AnimeExtensionDetailsState
|
||||
import eu.kanade.tachiyomi.ui.browse.anime.extension.details.AnimeExtensionDetailsScreenModel
|
||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||
import tachiyomi.presentation.core.components.ScrollbarLazyColumn
|
||||
import tachiyomi.presentation.core.components.material.DIVIDER_ALPHA
|
||||
import tachiyomi.presentation.core.components.material.Divider
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.presentation.core.screens.EmptyScreen
|
||||
|
@ -64,7 +64,7 @@ import tachiyomi.presentation.core.screens.EmptyScreen
|
|||
@Composable
|
||||
fun AnimeExtensionDetailsScreen(
|
||||
navigateUp: () -> Unit,
|
||||
state: AnimeExtensionDetailsState,
|
||||
state: AnimeExtensionDetailsScreenModel.State,
|
||||
onClickSourcePreferences: (sourceId: Long) -> Unit,
|
||||
onClickWhatsNew: () -> Unit,
|
||||
onClickReadme: () -> Unit,
|
||||
|
@ -313,7 +313,7 @@ private fun DetailsHeader(
|
|||
}
|
||||
}
|
||||
|
||||
Divider()
|
||||
HorizontalDivider()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -355,11 +355,8 @@ private fun InfoText(
|
|||
|
||||
@Composable
|
||||
private fun InfoDivider() {
|
||||
Divider(
|
||||
modifier = Modifier
|
||||
.height(20.dp)
|
||||
.width(1.dp),
|
||||
color = MaterialTheme.colorScheme.onSurface.copy(alpha = DIVIDER_ALPHA),
|
||||
VerticalDivider(
|
||||
modifier = Modifier.height(20.dp),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ import eu.kanade.tachiyomi.R
|
|||
import eu.kanade.tachiyomi.extension.InstallStep
|
||||
import eu.kanade.tachiyomi.extension.anime.model.AnimeExtension
|
||||
import eu.kanade.tachiyomi.ui.browse.anime.extension.AnimeExtensionUiModel
|
||||
import eu.kanade.tachiyomi.ui.browse.anime.extension.AnimeExtensionsState
|
||||
import eu.kanade.tachiyomi.ui.browse.anime.extension.AnimeExtensionsScreenModel
|
||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||
import tachiyomi.presentation.core.components.FastScrollLazyColumn
|
||||
import tachiyomi.presentation.core.components.material.PullRefresh
|
||||
|
@ -56,7 +56,7 @@ import tachiyomi.presentation.core.util.secondaryItemAlpha
|
|||
|
||||
@Composable
|
||||
fun AnimeExtensionScreen(
|
||||
state: AnimeExtensionsState,
|
||||
state: AnimeExtensionsScreenModel.State,
|
||||
contentPadding: PaddingValues,
|
||||
searchQuery: String?,
|
||||
onLongClickItem: (AnimeExtension) -> Unit,
|
||||
|
@ -107,7 +107,7 @@ fun AnimeExtensionScreen(
|
|||
|
||||
@Composable
|
||||
private fun AnimeExtensionContent(
|
||||
state: AnimeExtensionsState,
|
||||
state: AnimeExtensionsScreenModel.State,
|
||||
contentPadding: PaddingValues,
|
||||
onLongClickItem: (AnimeExtension) -> Unit,
|
||||
onClickItemCancel: (AnimeExtension) -> Unit,
|
||||
|
|
|
@ -12,7 +12,7 @@ import eu.kanade.presentation.browse.anime.components.BaseAnimeSourceItem
|
|||
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.anime.source.AnimeSourcesFilterState
|
||||
import eu.kanade.tachiyomi.ui.browse.anime.source.AnimeSourcesFilterScreenModel
|
||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||
import tachiyomi.domain.source.anime.model.AnimeSource
|
||||
import tachiyomi.presentation.core.components.FastScrollLazyColumn
|
||||
|
@ -22,7 +22,7 @@ import tachiyomi.presentation.core.screens.EmptyScreen
|
|||
@Composable
|
||||
fun AnimeSourcesFilterScreen(
|
||||
navigateUp: () -> Unit,
|
||||
state: AnimeSourcesFilterState.Success,
|
||||
state: AnimeSourcesFilterScreenModel.State.Success,
|
||||
onClickLanguage: (String) -> Unit,
|
||||
onClickSource: (AnimeSource) -> Unit,
|
||||
) {
|
||||
|
@ -54,7 +54,7 @@ fun AnimeSourcesFilterScreen(
|
|||
@Composable
|
||||
private fun AnimeSourcesFilterContent(
|
||||
contentPadding: PaddingValues,
|
||||
state: AnimeSourcesFilterState.Success,
|
||||
state: AnimeSourcesFilterScreenModel.State.Success,
|
||||
onClickLanguage: (String) -> Unit,
|
||||
onClickSource: (AnimeSource) -> Unit,
|
||||
) {
|
||||
|
|
|
@ -192,7 +192,7 @@ fun AnimeSourceOptionsDialog(
|
|||
)
|
||||
}
|
||||
|
||||
sealed class AnimeSourceUiModel {
|
||||
data class Item(val source: AnimeSource) : AnimeSourceUiModel()
|
||||
data class Header(val language: String) : AnimeSourceUiModel()
|
||||
sealed interface AnimeSourceUiModel {
|
||||
data class Item(val source: AnimeSource) : AnimeSourceUiModel
|
||||
data class Header(val language: String) : AnimeSourceUiModel
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import androidx.compose.ui.Modifier
|
|||
import eu.kanade.presentation.components.AppBar
|
||||
import eu.kanade.presentation.entries.anime.components.BaseAnimeListItem
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.browse.anime.migration.anime.MigrateAnimeState
|
||||
import eu.kanade.tachiyomi.ui.browse.anime.migration.anime.MigrateAnimeScreenModel
|
||||
import tachiyomi.domain.entries.anime.model.Anime
|
||||
import tachiyomi.presentation.core.components.FastScrollLazyColumn
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
|
@ -18,7 +18,7 @@ import tachiyomi.presentation.core.screens.EmptyScreen
|
|||
fun MigrateAnimeScreen(
|
||||
navigateUp: () -> Unit,
|
||||
title: String?,
|
||||
state: MigrateAnimeState,
|
||||
state: MigrateAnimeScreenModel.State,
|
||||
onClickItem: (Anime) -> Unit,
|
||||
onClickCover: (Anime) -> Unit,
|
||||
) {
|
||||
|
@ -51,7 +51,7 @@ fun MigrateAnimeScreen(
|
|||
@Composable
|
||||
private fun MigrateAnimeContent(
|
||||
contentPadding: PaddingValues,
|
||||
state: MigrateAnimeState,
|
||||
state: MigrateAnimeScreenModel.State,
|
||||
onClickItem: (Anime) -> Unit,
|
||||
onClickCover: (Anime) -> Unit,
|
||||
) {
|
||||
|
|
|
@ -26,7 +26,7 @@ import eu.kanade.domain.source.service.SetMigrateSorting
|
|||
import eu.kanade.presentation.browse.anime.components.AnimeSourceIcon
|
||||
import eu.kanade.presentation.browse.anime.components.BaseAnimeSourceItem
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.browse.anime.migration.sources.MigrateAnimeSourceState
|
||||
import eu.kanade.tachiyomi.ui.browse.anime.migration.sources.MigrateAnimeSourceScreenModel
|
||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||
import tachiyomi.domain.source.anime.model.AnimeSource
|
||||
import tachiyomi.presentation.core.components.Badge
|
||||
|
@ -43,7 +43,7 @@ import tachiyomi.presentation.core.util.secondaryItemAlpha
|
|||
|
||||
@Composable
|
||||
fun MigrateAnimeSourceScreen(
|
||||
state: MigrateAnimeSourceState,
|
||||
state: MigrateAnimeSourceScreenModel.State,
|
||||
contentPadding: PaddingValues,
|
||||
onClickItem: (AnimeSource) -> Unit,
|
||||
onToggleSortingDirection: () -> Unit,
|
||||
|
|
|
@ -14,14 +14,15 @@ import androidx.compose.material.icons.Icons
|
|||
import androidx.compose.material.icons.outlined.DoneAll
|
||||
import androidx.compose.material.icons.outlined.FilterList
|
||||
import androidx.compose.material.icons.outlined.PushPin
|
||||
import androidx.compose.material3.Divider
|
||||
import androidx.compose.material3.FilterChip
|
||||
import androidx.compose.material3.FilterChipDefaults
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.LinearProgressIndicator
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||
import androidx.compose.material3.VerticalDivider
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
@ -29,7 +30,6 @@ import androidx.compose.ui.res.stringResource
|
|||
import eu.kanade.presentation.components.SearchToolbar
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.browse.anime.source.globalsearch.AnimeSourceFilter
|
||||
import tachiyomi.presentation.core.components.material.VerticalDivider
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
|
||||
@Composable
|
||||
|
@ -123,6 +123,6 @@ fun GlobalAnimeSearchToolbar(
|
|||
)
|
||||
}
|
||||
|
||||
Divider()
|
||||
HorizontalDivider()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import androidx.compose.material.icons.outlined.History
|
|||
import androidx.compose.material.icons.outlined.Settings
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
|
@ -30,6 +31,7 @@ import androidx.compose.material3.OutlinedButton
|
|||
import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.VerticalDivider
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
|
@ -53,11 +55,9 @@ import eu.kanade.presentation.more.settings.widget.TrailingWidgetBuffer
|
|||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.extension.manga.model.MangaExtension
|
||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||
import eu.kanade.tachiyomi.ui.browse.manga.extension.details.MangaExtensionDetailsState
|
||||
import eu.kanade.tachiyomi.ui.browse.manga.extension.details.MangaExtensionDetailsScreenModel
|
||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||
import tachiyomi.presentation.core.components.ScrollbarLazyColumn
|
||||
import tachiyomi.presentation.core.components.material.DIVIDER_ALPHA
|
||||
import tachiyomi.presentation.core.components.material.Divider
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.presentation.core.screens.EmptyScreen
|
||||
|
@ -65,7 +65,7 @@ import tachiyomi.presentation.core.screens.EmptyScreen
|
|||
@Composable
|
||||
fun ExtensionDetailsScreen(
|
||||
navigateUp: () -> Unit,
|
||||
state: MangaExtensionDetailsState,
|
||||
state: MangaExtensionDetailsScreenModel.State,
|
||||
onClickSourcePreferences: (sourceId: Long) -> Unit,
|
||||
onClickWhatsNew: () -> Unit,
|
||||
onClickReadme: () -> Unit,
|
||||
|
@ -314,7 +314,7 @@ private fun DetailsHeader(
|
|||
}
|
||||
}
|
||||
|
||||
Divider()
|
||||
HorizontalDivider()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -356,11 +356,8 @@ private fun InfoText(
|
|||
|
||||
@Composable
|
||||
private fun InfoDivider() {
|
||||
Divider(
|
||||
modifier = Modifier
|
||||
.height(20.dp)
|
||||
.width(1.dp),
|
||||
color = MaterialTheme.colorScheme.onSurface.copy(alpha = DIVIDER_ALPHA),
|
||||
VerticalDivider(
|
||||
modifier = Modifier.height(20.dp),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ import eu.kanade.tachiyomi.R
|
|||
import eu.kanade.tachiyomi.extension.InstallStep
|
||||
import eu.kanade.tachiyomi.extension.manga.model.MangaExtension
|
||||
import eu.kanade.tachiyomi.ui.browse.manga.extension.MangaExtensionUiModel
|
||||
import eu.kanade.tachiyomi.ui.browse.manga.extension.MangaExtensionsState
|
||||
import eu.kanade.tachiyomi.ui.browse.manga.extension.MangaExtensionsScreenModel
|
||||
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 MangaExtensionScreen(
|
||||
state: MangaExtensionsState,
|
||||
state: MangaExtensionsScreenModel.State,
|
||||
contentPadding: PaddingValues,
|
||||
searchQuery: String?,
|
||||
onLongClickItem: (MangaExtension) -> Unit,
|
||||
|
@ -108,7 +108,7 @@ fun MangaExtensionScreen(
|
|||
|
||||
@Composable
|
||||
private fun ExtensionContent(
|
||||
state: MangaExtensionsState,
|
||||
state: MangaExtensionsScreenModel.State,
|
||||
contentPadding: PaddingValues,
|
||||
onLongClickItem: (MangaExtension) -> Unit,
|
||||
onClickItemCancel: (MangaExtension) -> Unit,
|
||||
|
|
|
@ -12,7 +12,7 @@ import eu.kanade.presentation.browse.manga.components.BaseMangaSourceItem
|
|||
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.manga.source.MangaSourcesFilterState
|
||||
import eu.kanade.tachiyomi.ui.browse.manga.source.SourcesFilterScreenModel
|
||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||
import tachiyomi.domain.source.manga.model.Source
|
||||
import tachiyomi.presentation.core.components.FastScrollLazyColumn
|
||||
|
@ -22,7 +22,7 @@ import tachiyomi.presentation.core.screens.EmptyScreen
|
|||
@Composable
|
||||
fun MangaSourcesFilterScreen(
|
||||
navigateUp: () -> Unit,
|
||||
state: MangaSourcesFilterState.Success,
|
||||
state: SourcesFilterScreenModel.State.Success,
|
||||
onClickLanguage: (String) -> Unit,
|
||||
onClickSource: (Source) -> Unit,
|
||||
) {
|
||||
|
@ -54,7 +54,7 @@ fun MangaSourcesFilterScreen(
|
|||
@Composable
|
||||
private fun SourcesFilterContent(
|
||||
contentPadding: PaddingValues,
|
||||
state: MangaSourcesFilterState.Success,
|
||||
state: SourcesFilterScreenModel.State.Success,
|
||||
onClickLanguage: (String) -> Unit,
|
||||
onClickSource: (Source) -> Unit,
|
||||
) {
|
||||
|
|
|
@ -210,7 +210,7 @@ fun MangaSourceOptionsDialog(
|
|||
)
|
||||
}
|
||||
|
||||
sealed class MangaSourceUiModel {
|
||||
data class Item(val source: Source) : MangaSourceUiModel()
|
||||
data class Header(val language: String) : MangaSourceUiModel()
|
||||
sealed interface MangaSourceUiModel {
|
||||
data class Item(val source: Source) : MangaSourceUiModel
|
||||
data class Header(val language: String) : MangaSourceUiModel
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import androidx.compose.ui.Modifier
|
|||
import eu.kanade.presentation.components.AppBar
|
||||
import eu.kanade.presentation.entries.manga.components.BaseMangaListItem
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.browse.manga.migration.manga.MigrateMangaState
|
||||
import eu.kanade.tachiyomi.ui.browse.manga.migration.manga.MigrateMangaScreenModel
|
||||
import tachiyomi.domain.entries.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.service.SetMigrateSorting
|
|||
import eu.kanade.presentation.browse.manga.components.BaseMangaSourceItem
|
||||
import eu.kanade.presentation.browse.manga.components.MangaSourceIcon
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.browse.manga.migration.sources.MigrateMangaSourceState
|
||||
import eu.kanade.tachiyomi.ui.browse.manga.migration.sources.MigrateSourceScreenModel
|
||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||
import tachiyomi.domain.source.manga.model.Source
|
||||
import tachiyomi.presentation.core.components.Badge
|
||||
|
@ -43,7 +43,7 @@ import tachiyomi.presentation.core.util.secondaryItemAlpha
|
|||
|
||||
@Composable
|
||||
fun MigrateMangaSourceScreen(
|
||||
state: MigrateMangaSourceState,
|
||||
state: MigrateSourceScreenModel.State,
|
||||
contentPadding: PaddingValues,
|
||||
onClickItem: (Source) -> Unit,
|
||||
onToggleSortingDirection: () -> Unit,
|
||||
|
|
|
@ -14,14 +14,15 @@ import androidx.compose.material.icons.Icons
|
|||
import androidx.compose.material.icons.outlined.DoneAll
|
||||
import androidx.compose.material.icons.outlined.FilterList
|
||||
import androidx.compose.material.icons.outlined.PushPin
|
||||
import androidx.compose.material3.Divider
|
||||
import androidx.compose.material3.FilterChip
|
||||
import androidx.compose.material3.FilterChipDefaults
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.LinearProgressIndicator
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||
import androidx.compose.material3.VerticalDivider
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
@ -29,7 +30,6 @@ import androidx.compose.ui.res.stringResource
|
|||
import eu.kanade.presentation.components.SearchToolbar
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.browse.manga.source.globalsearch.MangaSourceFilter
|
||||
import tachiyomi.presentation.core.components.material.VerticalDivider
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
|
||||
@Composable
|
||||
|
@ -123,6 +123,6 @@ fun GlobalMangaSearchToolbar(
|
|||
)
|
||||
}
|
||||
|
||||
Divider()
|
||||
HorizontalDivider()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import androidx.compose.foundation.pager.PagerState
|
|||
import androidx.compose.foundation.pager.rememberPagerState
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.MoreVert
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
|
@ -31,7 +32,6 @@ import androidx.compose.ui.util.fastForEachIndexed
|
|||
import eu.kanade.tachiyomi.R
|
||||
import kotlinx.coroutines.launch
|
||||
import tachiyomi.presentation.core.components.HorizontalPager
|
||||
import tachiyomi.presentation.core.components.material.Divider
|
||||
import tachiyomi.presentation.core.components.material.TabIndicator
|
||||
|
||||
object TabbedDialogPaddings {
|
||||
|
@ -87,7 +87,7 @@ fun TabbedDialog(
|
|||
|
||||
MoreMenu(onOverflowMenuClicked, tabOverflowMenuContent, overflowIcon)
|
||||
}
|
||||
Divider()
|
||||
HorizontalDivider()
|
||||
|
||||
HorizontalPager(
|
||||
modifier = Modifier.animateContentSize(),
|
||||
|
|
|
@ -72,7 +72,7 @@ import eu.kanade.tachiyomi.animesource.model.SAnime
|
|||
import eu.kanade.tachiyomi.data.download.anime.model.AnimeDownload
|
||||
import eu.kanade.tachiyomi.source.anime.getNameForAnimeInfo
|
||||
import eu.kanade.tachiyomi.ui.browse.anime.extension.details.SourcePreferencesScreen
|
||||
import eu.kanade.tachiyomi.ui.entries.anime.AnimeScreenState
|
||||
import eu.kanade.tachiyomi.ui.entries.anime.AnimeScreenModel
|
||||
import eu.kanade.tachiyomi.ui.entries.anime.EpisodeItem
|
||||
import eu.kanade.tachiyomi.util.lang.toRelativeString
|
||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||
|
@ -95,7 +95,7 @@ import java.util.concurrent.TimeUnit
|
|||
|
||||
@Composable
|
||||
fun AnimeScreen(
|
||||
state: AnimeScreenState.Success,
|
||||
state: AnimeScreenModel.State.Success,
|
||||
snackbarHostState: SnackbarHostState,
|
||||
dateRelativeTime: Int,
|
||||
dateFormat: DateFormat,
|
||||
|
@ -240,7 +240,7 @@ fun AnimeScreen(
|
|||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun AnimeScreenSmallImpl(
|
||||
state: AnimeScreenState.Success,
|
||||
state: AnimeScreenModel.State.Success,
|
||||
snackbarHostState: SnackbarHostState,
|
||||
dateRelativeTime: Int,
|
||||
dateFormat: DateFormat,
|
||||
|
@ -506,7 +506,7 @@ private fun AnimeScreenSmallImpl(
|
|||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun AnimeScreenLargeImpl(
|
||||
state: AnimeScreenState.Success,
|
||||
state: AnimeScreenModel.State.Success,
|
||||
snackbarHostState: SnackbarHostState,
|
||||
dateRelativeTime: Int,
|
||||
dateFormat: DateFormat,
|
||||
|
|
|
@ -68,7 +68,7 @@ import eu.kanade.tachiyomi.source.ConfigurableSource
|
|||
import eu.kanade.tachiyomi.source.manga.getNameForMangaInfo
|
||||
import eu.kanade.tachiyomi.ui.browse.manga.extension.details.MangaSourcePreferencesScreen
|
||||
import eu.kanade.tachiyomi.ui.entries.manga.ChapterItem
|
||||
import eu.kanade.tachiyomi.ui.entries.manga.MangaScreenState
|
||||
import eu.kanade.tachiyomi.ui.entries.manga.MangaScreenModel
|
||||
import eu.kanade.tachiyomi.util.lang.toRelativeString
|
||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||
import tachiyomi.domain.entries.manga.model.Manga
|
||||
|
@ -88,7 +88,7 @@ import java.util.Date
|
|||
|
||||
@Composable
|
||||
fun MangaScreen(
|
||||
state: MangaScreenState.Success,
|
||||
state: MangaScreenModel.State.Success,
|
||||
snackbarHostState: SnackbarHostState,
|
||||
dateRelativeTime: Int,
|
||||
dateFormat: DateFormat,
|
||||
|
@ -223,7 +223,7 @@ fun MangaScreen(
|
|||
|
||||
@Composable
|
||||
private fun MangaScreenSmallImpl(
|
||||
state: MangaScreenState.Success,
|
||||
state: MangaScreenModel.State.Success,
|
||||
snackbarHostState: SnackbarHostState,
|
||||
dateRelativeTime: Int,
|
||||
dateFormat: DateFormat,
|
||||
|
@ -454,7 +454,7 @@ private fun MangaScreenSmallImpl(
|
|||
|
||||
@Composable
|
||||
fun MangaScreenLargeImpl(
|
||||
state: MangaScreenState.Success,
|
||||
state: MangaScreenModel.State.Success,
|
||||
snackbarHostState: SnackbarHostState,
|
||||
dateRelativeTime: Int,
|
||||
dateFormat: DateFormat,
|
||||
|
|
|
@ -9,7 +9,6 @@ import androidx.compose.ui.Modifier
|
|||
import eu.kanade.presentation.animehistory.components.AnimeHistoryContent
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.history.anime.AnimeHistoryScreenModel
|
||||
import eu.kanade.tachiyomi.ui.history.anime.AnimeHistoryState
|
||||
import tachiyomi.domain.history.anime.model.AnimeHistoryWithRelations
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.screens.EmptyScreen
|
||||
|
@ -18,7 +17,7 @@ import java.util.Date
|
|||
|
||||
@Composable
|
||||
fun AnimeHistoryScreen(
|
||||
state: AnimeHistoryState,
|
||||
state: AnimeHistoryScreenModel.State,
|
||||
contentPadding: PaddingValues,
|
||||
searchQuery: String? = null,
|
||||
snackbarHostState: SnackbarHostState,
|
||||
|
@ -55,7 +54,7 @@ fun AnimeHistoryScreen(
|
|||
}
|
||||
}
|
||||
|
||||
sealed class AnimeHistoryUiModel {
|
||||
data class Header(val date: Date) : AnimeHistoryUiModel()
|
||||
data class Item(val item: AnimeHistoryWithRelations) : AnimeHistoryUiModel()
|
||||
sealed interface AnimeHistoryUiModel {
|
||||
data class Header(val date: Date) : AnimeHistoryUiModel
|
||||
data class Item(val item: AnimeHistoryWithRelations) : AnimeHistoryUiModel
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ import androidx.compose.material3.SnackbarHostState
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.history.manga.HistoryState
|
||||
import eu.kanade.tachiyomi.ui.history.manga.MangaHistoryScreenModel
|
||||
import tachiyomi.domain.history.manga.model.MangaHistoryWithRelations
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
|
@ -17,7 +16,7 @@ import java.util.Date
|
|||
|
||||
@Composable
|
||||
fun MangaHistoryScreen(
|
||||
state: HistoryState,
|
||||
state: MangaHistoryScreenModel.State,
|
||||
contentPadding: PaddingValues,
|
||||
searchQuery: String? = null,
|
||||
snackbarHostState: SnackbarHostState,
|
||||
|
@ -54,7 +53,7 @@ fun MangaHistoryScreen(
|
|||
}
|
||||
}
|
||||
|
||||
sealed class MangaHistoryUiModel {
|
||||
data class Header(val date: Date) : MangaHistoryUiModel()
|
||||
data class Item(val item: MangaHistoryWithRelations) : MangaHistoryUiModel()
|
||||
sealed interface MangaHistoryUiModel {
|
||||
data class Header(val date: Date) : MangaHistoryUiModel
|
||||
data class Item(val item: MangaHistoryWithRelations) : MangaHistoryUiModel
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package eu.kanade.presentation.library
|
|||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.pager.PagerState
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.ScrollableTabRow
|
||||
import androidx.compose.material3.Tab
|
||||
|
@ -9,7 +10,6 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.presentation.category.visualName
|
||||
import tachiyomi.domain.category.model.Category
|
||||
import tachiyomi.presentation.core.components.material.Divider
|
||||
import tachiyomi.presentation.core.components.material.TabIndicator
|
||||
import tachiyomi.presentation.core.components.material.TabText
|
||||
|
||||
|
@ -44,6 +44,6 @@ fun LibraryTabs(
|
|||
}
|
||||
}
|
||||
|
||||
Divider()
|
||||
HorizontalDivider()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import androidx.compose.foundation.layout.Column
|
|||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
|
@ -12,7 +13,6 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.tachiyomi.R
|
||||
import tachiyomi.presentation.core.components.material.Divider
|
||||
|
||||
@Composable
|
||||
fun LogoHeader() {
|
||||
|
@ -29,6 +29,6 @@ fun LogoHeader() {
|
|||
.size(64.dp),
|
||||
)
|
||||
|
||||
Divider()
|
||||
HorizontalDivider()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import androidx.compose.material.icons.outlined.QueryStats
|
|||
import androidx.compose.material.icons.outlined.Settings
|
||||
import androidx.compose.material.icons.outlined.SettingsBackupRestore
|
||||
import androidx.compose.material.icons.outlined.Storage
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
|
@ -35,7 +36,6 @@ import eu.kanade.tachiyomi.core.Constants
|
|||
import eu.kanade.tachiyomi.ui.more.DownloadQueueState
|
||||
import tachiyomi.domain.library.service.LibraryPreferences
|
||||
import tachiyomi.presentation.core.components.ScrollbarLazyColumn
|
||||
import tachiyomi.presentation.core.components.material.Divider
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
|
@ -101,7 +101,7 @@ fun MoreScreen(
|
|||
)
|
||||
}
|
||||
|
||||
item { Divider() }
|
||||
item { HorizontalDivider() }
|
||||
|
||||
val libraryPreferences: LibraryPreferences by injectLazy()
|
||||
|
||||
|
@ -182,7 +182,7 @@ fun MoreScreen(
|
|||
)
|
||||
}
|
||||
|
||||
item { Divider() }
|
||||
item { HorizontalDivider() }
|
||||
|
||||
item {
|
||||
TextPreferenceWidget(
|
||||
|
|
|
@ -13,8 +13,6 @@ import androidx.compose.runtime.rememberCoroutineScope
|
|||
import androidx.compose.runtime.structuralEqualityPolicy
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.domain.track.service.TrackPreferences
|
||||
import eu.kanade.domain.ui.UiPreferences
|
||||
import eu.kanade.presentation.more.settings.widget.AppThemePreferenceWidget
|
||||
import eu.kanade.presentation.more.settings.widget.EditTextPreferenceWidget
|
||||
import eu.kanade.presentation.more.settings.widget.InfoWidget
|
||||
import eu.kanade.presentation.more.settings.widget.ListPreferenceWidget
|
||||
|
@ -173,16 +171,6 @@ internal fun PreferenceItem(
|
|||
singleLine = false,
|
||||
)
|
||||
}
|
||||
is Preference.PreferenceItem.AppThemePreference -> {
|
||||
val value by item.pref.collectAsState()
|
||||
val amoled by Injekt.get<UiPreferences>().themeDarkAmoled().collectAsState()
|
||||
AppThemePreferenceWidget(
|
||||
title = item.title,
|
||||
value = value,
|
||||
amoled = amoled,
|
||||
onItemClick = { scope.launch { item.pref.set(it) } },
|
||||
)
|
||||
}
|
||||
is Preference.PreferenceItem.TrackingPreference -> {
|
||||
val uName by Injekt.get<PreferenceStore>()
|
||||
.getString(TrackPreferences.trackUsername(item.service.id))
|
||||
|
@ -198,6 +186,9 @@ internal fun PreferenceItem(
|
|||
is Preference.PreferenceItem.InfoPreference -> {
|
||||
InfoWidget(text = item.title)
|
||||
}
|
||||
is Preference.PreferenceItem.CustomPreference -> {
|
||||
item.content(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import eu.kanade.domain.ui.model.AppTheme
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.track.TrackService
|
||||
import tachiyomi.core.preference.Preference as PreferenceData
|
||||
|
@ -144,19 +143,6 @@ sealed class Preference {
|
|||
override val onValueChanged: suspend (newValue: String) -> Boolean = { true },
|
||||
) : PreferenceItem<String>()
|
||||
|
||||
/**
|
||||
* A [PreferenceItem] that shows previews of [AppTheme] selection.
|
||||
*/
|
||||
data class AppThemePreference(
|
||||
val pref: PreferenceData<AppTheme>,
|
||||
override val title: String,
|
||||
) : PreferenceItem<AppTheme>() {
|
||||
override val enabled: Boolean = true
|
||||
override val subtitle: String? = null
|
||||
override val icon: ImageVector? = null
|
||||
override val onValueChanged: suspend (newValue: AppTheme) -> Boolean = { true }
|
||||
}
|
||||
|
||||
/**
|
||||
* A [PreferenceItem] for individual tracking service.
|
||||
*/
|
||||
|
@ -180,6 +166,16 @@ sealed class Preference {
|
|||
override val icon: ImageVector? = null
|
||||
override val onValueChanged: suspend (newValue: String) -> Boolean = { true }
|
||||
}
|
||||
|
||||
data class CustomPreference(
|
||||
override val title: String,
|
||||
val content: @Composable (PreferenceItem<String>) -> Unit,
|
||||
) : PreferenceItem<String>() {
|
||||
override val enabled: Boolean = true
|
||||
override val subtitle: String? = null
|
||||
override val icon: ImageVector? = null
|
||||
override val onValueChanged: suspend (newValue: String) -> Boolean = { true }
|
||||
}
|
||||
}
|
||||
|
||||
data class PreferenceGroup(
|
||||
|
|
|
@ -21,6 +21,7 @@ import eu.kanade.domain.ui.model.TabletUiMode
|
|||
import eu.kanade.domain.ui.model.ThemeMode
|
||||
import eu.kanade.domain.ui.model.setAppCompatDelegateThemeMode
|
||||
import eu.kanade.presentation.more.settings.Preference
|
||||
import eu.kanade.presentation.more.settings.widget.AppThemePreferenceWidget
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.home.HomeScreen
|
||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||
|
@ -61,8 +62,11 @@ object SettingsAppearanceScreen : SearchableSettings {
|
|||
): Preference.PreferenceGroup {
|
||||
val themeModePref = uiPreferences.themeMode()
|
||||
val themeMode by themeModePref.collectAsState()
|
||||
|
||||
val appThemePref = uiPreferences.appTheme()
|
||||
|
||||
val amoledPref = uiPreferences.themeDarkAmoled()
|
||||
val amoled by amoledPref.collectAsState()
|
||||
|
||||
LaunchedEffect(themeMode) {
|
||||
setAppCompatDelegateThemeMode(themeMode)
|
||||
|
@ -93,10 +97,17 @@ object SettingsAppearanceScreen : SearchableSettings {
|
|||
)
|
||||
},
|
||||
),
|
||||
Preference.PreferenceItem.AppThemePreference(
|
||||
Preference.PreferenceItem.CustomPreference(
|
||||
title = stringResource(R.string.pref_app_theme),
|
||||
pref = appThemePref,
|
||||
),
|
||||
) { item ->
|
||||
val value by appThemePref.collectAsState()
|
||||
AppThemePreferenceWidget(
|
||||
title = item.title,
|
||||
value = value,
|
||||
amoled = amoled,
|
||||
onItemClick = { appThemePref.set(it) },
|
||||
)
|
||||
},
|
||||
Preference.PreferenceItem.SwitchPreference(
|
||||
pref = amoledPref,
|
||||
title = stringResource(R.string.pref_dark_theme_pure_black),
|
||||
|
|
|
@ -20,6 +20,7 @@ import androidx.compose.foundation.rememberScrollState
|
|||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Checkbox
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
|
@ -62,7 +63,6 @@ import tachiyomi.domain.backup.service.FLAG_HISTORY
|
|||
import tachiyomi.domain.backup.service.FLAG_SETTINGS
|
||||
import tachiyomi.domain.backup.service.FLAG_TRACK
|
||||
import tachiyomi.presentation.core.components.ScrollbarLazyColumn
|
||||
import tachiyomi.presentation.core.components.material.Divider
|
||||
import tachiyomi.presentation.core.util.collectAsState
|
||||
import tachiyomi.presentation.core.util.isScrolledToEnd
|
||||
import tachiyomi.presentation.core.util.isScrolledToStart
|
||||
|
@ -197,8 +197,8 @@ object SettingsBackupScreen : SearchableSettings {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (!state.isScrolledToStart()) Divider(modifier = Modifier.align(Alignment.TopCenter))
|
||||
if (!state.isScrolledToEnd()) Divider(modifier = Modifier.align(Alignment.BottomCenter))
|
||||
if (!state.isScrolledToStart()) HorizontalDivider(modifier = Modifier.align(Alignment.TopCenter))
|
||||
if (!state.isScrolledToEnd()) HorizontalDivider(modifier = Modifier.align(Alignment.BottomCenter))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
|
|
|
@ -17,6 +17,7 @@ import androidx.compose.foundation.text.KeyboardActions
|
|||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.Close
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
|
@ -53,7 +54,6 @@ import eu.kanade.presentation.components.UpIcon
|
|||
import eu.kanade.presentation.more.settings.Preference
|
||||
import eu.kanade.presentation.util.Screen
|
||||
import eu.kanade.tachiyomi.R
|
||||
import tachiyomi.presentation.core.components.material.Divider
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.screens.EmptyScreen
|
||||
import tachiyomi.presentation.core.util.runOnEnterKeyPressed
|
||||
|
@ -138,7 +138,7 @@ class SettingsSearchScreen : Screen() {
|
|||
}
|
||||
},
|
||||
)
|
||||
Divider()
|
||||
HorizontalDivider()
|
||||
}
|
||||
},
|
||||
) { contentPadding ->
|
||||
|
|
|
@ -15,10 +15,12 @@ import androidx.compose.material.icons.outlined.SelectAll
|
|||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Checkbox
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
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
|
||||
|
@ -48,7 +50,6 @@ import tachiyomi.domain.source.anime.interactor.GetAnimeSourcesWithNonLibraryAni
|
|||
import tachiyomi.domain.source.anime.model.AnimeSource
|
||||
import tachiyomi.domain.source.anime.model.AnimeSourceWithCount
|
||||
import tachiyomi.mi.data.AnimeDatabase
|
||||
import tachiyomi.presentation.core.components.material.Divider
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.screens.EmptyScreen
|
||||
import tachiyomi.presentation.core.screens.LoadingScreen
|
||||
|
@ -148,7 +149,7 @@ class ClearAnimeDatabaseScreen : Screen() {
|
|||
}
|
||||
}
|
||||
|
||||
Divider()
|
||||
HorizontalDivider()
|
||||
|
||||
Button(
|
||||
modifier = Modifier
|
||||
|
@ -269,12 +270,15 @@ private class ClearAnimeDatabaseScreenModel : StateScreenModel<ClearAnimeDatabas
|
|||
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<AnimeSourceWithCount>,
|
||||
val selection: List<Long> = emptyList(),
|
||||
val showConfirmation: Boolean = false,
|
||||
) : State()
|
||||
) : State
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,10 +15,12 @@ import androidx.compose.material.icons.outlined.SelectAll
|
|||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Checkbox
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
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
|
||||
|
@ -48,7 +50,6 @@ import tachiyomi.data.Database
|
|||
import tachiyomi.domain.source.manga.interactor.GetMangaSourcesWithNonLibraryManga
|
||||
import tachiyomi.domain.source.manga.model.MangaSourceWithCount
|
||||
import tachiyomi.domain.source.manga.model.Source
|
||||
import tachiyomi.presentation.core.components.material.Divider
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.screens.EmptyScreen
|
||||
import tachiyomi.presentation.core.screens.LoadingScreen
|
||||
|
@ -148,7 +149,7 @@ class ClearDatabaseScreen : Screen() {
|
|||
}
|
||||
}
|
||||
|
||||
Divider()
|
||||
HorizontalDivider()
|
||||
|
||||
Button(
|
||||
modifier = Modifier
|
||||
|
@ -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<MangaSourceWithCount>,
|
||||
val selection: List<Long> = emptyList(),
|
||||
val showConfirmation: Boolean = false,
|
||||
) : State()
|
||||
) : State
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import androidx.compose.foundation.shape.CircleShape
|
|||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.CheckCircle
|
||||
import androidx.compose.material3.DividerDefaults
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
|
@ -44,7 +45,6 @@ import eu.kanade.presentation.theme.TachiyomiTheme
|
|||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
||||
import eu.kanade.tachiyomi.util.system.isDynamicColorAvailable
|
||||
import tachiyomi.presentation.core.components.material.DIVIDER_ALPHA
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.presentation.core.util.ThemePreviews
|
||||
import tachiyomi.presentation.core.util.secondaryItemAlpha
|
||||
|
@ -123,7 +123,6 @@ fun AppThemePreviewItem(
|
|||
selected: Boolean,
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
val dividerColor = MaterialTheme.colorScheme.onSurface.copy(alpha = DIVIDER_ALPHA)
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
|
@ -133,7 +132,7 @@ fun AppThemePreviewItem(
|
|||
color = if (selected) {
|
||||
MaterialTheme.colorScheme.primary
|
||||
} else {
|
||||
dividerColor
|
||||
DividerDefaults.color
|
||||
},
|
||||
shape = RoundedCornerShape(17.dp),
|
||||
)
|
||||
|
@ -180,7 +179,7 @@ fun AppThemePreviewItem(
|
|||
modifier = Modifier
|
||||
.padding(start = 8.dp, top = 2.dp)
|
||||
.background(
|
||||
color = dividerColor,
|
||||
color = DividerDefaults.color,
|
||||
shape = MaterialTheme.shapes.small,
|
||||
)
|
||||
.fillMaxWidth(0.5f)
|
||||
|
|
|
@ -8,6 +8,7 @@ import androidx.compose.foundation.lazy.rememberLazyListState
|
|||
import androidx.compose.foundation.selection.selectable
|
||||
import androidx.compose.material.minimumInteractiveComponentSize
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.RadioButton
|
||||
import androidx.compose.material3.Text
|
||||
|
@ -25,7 +26,6 @@ import androidx.compose.ui.res.stringResource
|
|||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.tachiyomi.R
|
||||
import tachiyomi.presentation.core.components.ScrollbarLazyColumn
|
||||
import tachiyomi.presentation.core.components.material.Divider
|
||||
import tachiyomi.presentation.core.util.isScrolledToEnd
|
||||
import tachiyomi.presentation.core.util.isScrolledToStart
|
||||
|
||||
|
@ -69,8 +69,8 @@ fun <T> ListPreferenceWidget(
|
|||
}
|
||||
}
|
||||
}
|
||||
if (!state.isScrolledToStart()) Divider(modifier = Modifier.align(Alignment.TopCenter))
|
||||
if (!state.isScrolledToEnd()) Divider(modifier = Modifier.align(Alignment.BottomCenter))
|
||||
if (!state.isScrolledToStart()) HorizontalDivider(modifier = Modifier.align(Alignment.TopCenter))
|
||||
if (!state.isScrolledToEnd()) HorizontalDivider(modifier = Modifier.align(Alignment.BottomCenter))
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
|
|
|
@ -15,6 +15,7 @@ import androidx.compose.material.icons.rounded.CheckBox
|
|||
import androidx.compose.material.icons.rounded.CheckBoxOutlineBlank
|
||||
import androidx.compose.material.icons.rounded.DisabledByDefault
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
|
@ -29,7 +30,6 @@ import androidx.compose.ui.draw.clip
|
|||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.tachiyomi.R
|
||||
import tachiyomi.presentation.core.components.material.Divider
|
||||
import tachiyomi.presentation.core.util.isScrolledToEnd
|
||||
import tachiyomi.presentation.core.util.isScrolledToStart
|
||||
|
||||
|
@ -115,8 +115,8 @@ fun <T> TriStateListDialog(
|
|||
}
|
||||
}
|
||||
|
||||
if (!listState.isScrolledToStart()) Divider(modifier = Modifier.align(Alignment.TopCenter))
|
||||
if (!listState.isScrolledToEnd()) Divider(modifier = Modifier.align(Alignment.BottomCenter))
|
||||
if (!listState.isScrolledToStart()) HorizontalDivider(modifier = Modifier.align(Alignment.TopCenter))
|
||||
if (!listState.isScrolledToEnd()) HorizontalDivider(modifier = Modifier.align(Alignment.BottomCenter))
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -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 SuccessManga(
|
||||
|
@ -13,7 +13,7 @@ sealed class StatsScreenState {
|
|||
val titles: StatsData.MangaTitles,
|
||||
val chapters: StatsData.Chapters,
|
||||
val trackers: StatsData.Trackers,
|
||||
) : StatsScreenState()
|
||||
) : StatsScreenState
|
||||
|
||||
@Immutable
|
||||
data class SuccessAnime(
|
||||
|
@ -21,5 +21,5 @@ sealed class StatsScreenState {
|
|||
val titles: StatsData.AnimeTitles,
|
||||
val episodes: StatsData.Episodes,
|
||||
val trackers: StatsData.Trackers,
|
||||
) : StatsScreenState()
|
||||
) : StatsScreenState
|
||||
}
|
||||
|
|
|
@ -1,46 +1,46 @@
|
|||
package eu.kanade.presentation.more.stats.data
|
||||
|
||||
sealed class StatsData {
|
||||
sealed interface StatsData {
|
||||
|
||||
data class MangaOverview(
|
||||
val libraryMangaCount: Int,
|
||||
val completedMangaCount: Int,
|
||||
val totalReadDuration: Long,
|
||||
) : StatsData()
|
||||
) : StatsData
|
||||
|
||||
data class AnimeOverview(
|
||||
val libraryAnimeCount: Int,
|
||||
val completedAnimeCount: Int,
|
||||
val totalSeenDuration: Long,
|
||||
) : StatsData()
|
||||
) : StatsData
|
||||
|
||||
data class MangaTitles(
|
||||
val globalUpdateItemCount: Int,
|
||||
val startedMangaCount: Int,
|
||||
val localMangaCount: Int,
|
||||
) : StatsData()
|
||||
) : StatsData
|
||||
|
||||
data class AnimeTitles(
|
||||
val globalUpdateItemCount: Int,
|
||||
val startedAnimeCount: Int,
|
||||
val localAnimeCount: Int,
|
||||
) : StatsData()
|
||||
) : StatsData
|
||||
|
||||
data class Chapters(
|
||||
val totalChapterCount: Int,
|
||||
val readChapterCount: Int,
|
||||
val downloadCount: Int,
|
||||
) : StatsData()
|
||||
) : StatsData
|
||||
|
||||
data class Episodes(
|
||||
val totalEpisodeCount: Int,
|
||||
val readEpisodeCount: Int,
|
||||
val downloadCount: Int,
|
||||
) : StatsData()
|
||||
) : StatsData
|
||||
|
||||
data class Trackers(
|
||||
val trackedTitleCount: Int,
|
||||
val meanScore: Double,
|
||||
val trackerCount: Int,
|
||||
) : StatsData()
|
||||
) : StatsData
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import androidx.compose.foundation.selection.selectable
|
|||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.minimumInteractiveComponentSize
|
||||
import androidx.compose.material3.DatePicker
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.RadioButton
|
||||
import androidx.compose.material3.SelectableDates
|
||||
|
@ -36,7 +37,6 @@ import tachiyomi.presentation.core.components.ScrollbarLazyColumn
|
|||
import tachiyomi.presentation.core.components.WheelNumberPicker
|
||||
import tachiyomi.presentation.core.components.WheelTextPicker
|
||||
import tachiyomi.presentation.core.components.material.AlertDialogContent
|
||||
import tachiyomi.presentation.core.components.material.Divider
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.presentation.core.util.isScrolledToEnd
|
||||
import tachiyomi.presentation.core.util.isScrolledToStart
|
||||
|
@ -81,8 +81,8 @@ fun TrackStatusSelector(
|
|||
}
|
||||
}
|
||||
}
|
||||
if (!state.isScrolledToStart()) Divider(modifier = Modifier.align(Alignment.TopCenter))
|
||||
if (!state.isScrolledToEnd()) Divider(modifier = Modifier.align(Alignment.BottomCenter))
|
||||
if (!state.isScrolledToStart()) HorizontalDivider(modifier = Modifier.align(Alignment.TopCenter))
|
||||
if (!state.isScrolledToEnd()) HorizontalDivider(modifier = Modifier.align(Alignment.BottomCenter))
|
||||
},
|
||||
onConfirm = onConfirm,
|
||||
onDismissRequest = onDismissRequest,
|
||||
|
|
|
@ -18,9 +18,11 @@ import androidx.compose.foundation.layout.windowInsetsPadding
|
|||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.VerticalDivider
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
|
@ -39,8 +41,6 @@ import eu.kanade.tachiyomi.R
|
|||
import eu.kanade.tachiyomi.data.track.TrackService
|
||||
import eu.kanade.tachiyomi.ui.entries.anime.track.AnimeTrackItem
|
||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||
import tachiyomi.presentation.core.components.material.Divider
|
||||
import tachiyomi.presentation.core.components.material.VerticalDivider
|
||||
import java.text.DateFormat
|
||||
|
||||
private const val UnsetStatusTextAlpha = 0.5F
|
||||
|
@ -200,7 +200,7 @@ private fun TrackInfoItem(
|
|||
}
|
||||
|
||||
if (onStartDateClick != null && onEndDateClick != null) {
|
||||
Divider()
|
||||
HorizontalDivider()
|
||||
Row(modifier = Modifier.height(IntrinsicSize.Min)) {
|
||||
TrackDetailsItem(
|
||||
modifier = Modifier.weight(1F),
|
||||
|
|
|
@ -22,6 +22,7 @@ import androidx.compose.material.icons.filled.ArrowBack
|
|||
import androidx.compose.material.icons.filled.Close
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
|
@ -45,7 +46,6 @@ import eu.kanade.presentation.track.manga.SearchResultItem
|
|||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.track.model.AnimeTrackSearch
|
||||
import tachiyomi.presentation.core.components.ScrollbarLazyColumn
|
||||
import tachiyomi.presentation.core.components.material.Divider
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.screens.EmptyScreen
|
||||
import tachiyomi.presentation.core.screens.LoadingScreen
|
||||
|
@ -126,7 +126,7 @@ fun AnimeTrackServiceSearch(
|
|||
}
|
||||
},
|
||||
)
|
||||
Divider()
|
||||
HorizontalDivider()
|
||||
}
|
||||
},
|
||||
bottomBar = {
|
||||
|
|
|
@ -24,11 +24,13 @@ import androidx.compose.foundation.verticalScroll
|
|||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.MoreVert
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.VerticalDivider
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
|
@ -50,8 +52,6 @@ import eu.kanade.tachiyomi.R
|
|||
import eu.kanade.tachiyomi.data.track.TrackService
|
||||
import eu.kanade.tachiyomi.ui.entries.manga.track.MangaTrackItem
|
||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||
import tachiyomi.presentation.core.components.material.Divider
|
||||
import tachiyomi.presentation.core.components.material.VerticalDivider
|
||||
import java.text.DateFormat
|
||||
|
||||
private const val UnsetStatusTextAlpha = 0.5F
|
||||
|
@ -211,7 +211,7 @@ private fun TrackInfoItem(
|
|||
}
|
||||
|
||||
if (onStartDateClick != null && onEndDateClick != null) {
|
||||
Divider()
|
||||
HorizontalDivider()
|
||||
Row(modifier = Modifier.height(IntrinsicSize.Min)) {
|
||||
TrackDetailsItem(
|
||||
modifier = Modifier.weight(1F),
|
||||
|
|
|
@ -33,6 +33,7 @@ import androidx.compose.material.icons.filled.CheckCircle
|
|||
import androidx.compose.material.icons.filled.Close
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
|
@ -60,7 +61,6 @@ import eu.kanade.presentation.entries.ItemCover
|
|||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.track.model.MangaTrackSearch
|
||||
import tachiyomi.presentation.core.components.ScrollbarLazyColumn
|
||||
import tachiyomi.presentation.core.components.material.Divider
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.presentation.core.screens.EmptyScreen
|
||||
|
@ -143,7 +143,7 @@ fun MangaTrackServiceSearch(
|
|||
}
|
||||
},
|
||||
)
|
||||
Divider()
|
||||
HorizontalDivider()
|
||||
}
|
||||
},
|
||||
bottomBar = {
|
||||
|
|
|
@ -22,7 +22,7 @@ import eu.kanade.tachiyomi.R
|
|||
import eu.kanade.tachiyomi.data.download.anime.model.AnimeDownload
|
||||
import eu.kanade.tachiyomi.ui.player.settings.PlayerPreferences
|
||||
import eu.kanade.tachiyomi.ui.updates.anime.AnimeUpdatesItem
|
||||
import eu.kanade.tachiyomi.ui.updates.anime.AnimeUpdatesState
|
||||
import eu.kanade.tachiyomi.ui.updates.anime.AnimeUpdatesScreenModel
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import tachiyomi.presentation.core.components.FastScrollLazyColumn
|
||||
|
@ -36,7 +36,7 @@ import kotlin.time.Duration.Companion.seconds
|
|||
|
||||
@Composable
|
||||
fun AnimeUpdateScreen(
|
||||
state: AnimeUpdatesState,
|
||||
state: AnimeUpdatesScreenModel.State,
|
||||
snackbarHostState: SnackbarHostState,
|
||||
contentPadding: PaddingValues,
|
||||
lastUpdated: Long,
|
||||
|
@ -158,7 +158,7 @@ private fun AnimeUpdatesBottomBar(
|
|||
)
|
||||
}
|
||||
|
||||
sealed class AnimeUpdatesUiModel {
|
||||
data class Header(val date: String) : AnimeUpdatesUiModel()
|
||||
data class Item(val item: AnimeUpdatesItem) : AnimeUpdatesUiModel()
|
||||
sealed interface AnimeUpdatesUiModel {
|
||||
data class Header(val date: String) : AnimeUpdatesUiModel
|
||||
data class Item(val item: AnimeUpdatesItem) : AnimeUpdatesUiModel
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ import eu.kanade.presentation.entries.manga.components.ChapterDownloadAction
|
|||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.download.manga.model.MangaDownload
|
||||
import eu.kanade.tachiyomi.ui.updates.manga.MangaUpdatesItem
|
||||
import eu.kanade.tachiyomi.ui.updates.manga.UpdatesState
|
||||
import eu.kanade.tachiyomi.ui.updates.manga.MangaUpdatesScreenModel
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import tachiyomi.presentation.core.components.FastScrollLazyColumn
|
||||
|
@ -33,7 +33,7 @@ import kotlin.time.Duration.Companion.seconds
|
|||
|
||||
@Composable
|
||||
fun MangaUpdateScreen(
|
||||
state: UpdatesState,
|
||||
state: MangaUpdatesScreenModel.State,
|
||||
snackbarHostState: SnackbarHostState,
|
||||
contentPadding: PaddingValues,
|
||||
lastUpdated: Long,
|
||||
|
@ -147,7 +147,7 @@ private fun MangaUpdatesBottomBar(
|
|||
)
|
||||
}
|
||||
|
||||
sealed class MangaUpdatesUiModel {
|
||||
data class Header(val date: String) : MangaUpdatesUiModel()
|
||||
data class Item(val item: MangaUpdatesItem) : MangaUpdatesUiModel()
|
||||
sealed interface MangaUpdatesUiModel {
|
||||
data class Header(val date: String) : MangaUpdatesUiModel
|
||||
data class Item(val item: MangaUpdatesItem) : MangaUpdatesUiModel
|
||||
}
|
||||
|
|
|
@ -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.anime.model
|
||||
|
||||
sealed class AnimeLoadResult {
|
||||
data class Success(val extension: AnimeExtension.Installed) : AnimeLoadResult()
|
||||
data class Untrusted(val extension: AnimeExtension.Untrusted) : AnimeLoadResult()
|
||||
data object Error : AnimeLoadResult()
|
||||
sealed interface AnimeLoadResult {
|
||||
data class Success(val extension: AnimeExtension.Installed) : AnimeLoadResult
|
||||
data class Untrusted(val extension: AnimeExtension.Untrusted) : AnimeLoadResult
|
||||
data object Error : AnimeLoadResult
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package eu.kanade.tachiyomi.extension.manga.model
|
||||
|
||||
sealed class MangaLoadResult {
|
||||
data class Success(val extension: MangaExtension.Installed) : MangaLoadResult()
|
||||
data class Untrusted(val extension: MangaExtension.Untrusted) : MangaLoadResult()
|
||||
data object Error : MangaLoadResult()
|
||||
sealed interface MangaLoadResult {
|
||||
data class Success(val extension: MangaExtension.Installed) : MangaLoadResult
|
||||
data class Untrusted(val extension: MangaExtension.Untrusted) : MangaLoadResult
|
||||
data object Error : MangaLoadResult
|
||||
}
|
||||
|
|
|
@ -54,20 +54,20 @@ class AnimeExtensionFilterScreenModel(
|
|||
}
|
||||
}
|
||||
|
||||
sealed class AnimeExtensionFilterEvent {
|
||||
data object FailedFetchingLanguages : AnimeExtensionFilterEvent()
|
||||
sealed interface AnimeExtensionFilterEvent {
|
||||
data object FailedFetchingLanguages : AnimeExtensionFilterEvent
|
||||
}
|
||||
|
||||
sealed class AnimeExtensionFilterState {
|
||||
sealed interface AnimeExtensionFilterState {
|
||||
|
||||
@Immutable
|
||||
data object Loading : AnimeExtensionFilterState()
|
||||
data object Loading : AnimeExtensionFilterState
|
||||
|
||||
@Immutable
|
||||
data class Success(
|
||||
val languages: List<String>,
|
||||
val enabledLanguages: Set<String> = emptySet(),
|
||||
) : AnimeExtensionFilterState() {
|
||||
) : AnimeExtensionFilterState {
|
||||
|
||||
val isEmpty: Boolean
|
||||
get() = languages.isEmpty()
|
||||
|
|
|
@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.browse.anime.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.anime.interactor.GetAnimeExtensionsByType
|
||||
|
@ -35,7 +36,7 @@ class AnimeExtensionsScreenModel(
|
|||
preferences: SourcePreferences = Injekt.get(),
|
||||
private val extensionManager: AnimeExtensionManager = Injekt.get(),
|
||||
private val getExtensions: GetAnimeExtensionsByType = Injekt.get(),
|
||||
) : StateScreenModel<AnimeExtensionsState>(AnimeExtensionsState()) {
|
||||
) : StateScreenModel<AnimeExtensionsScreenModel.State>(State()) {
|
||||
|
||||
private var _currentDownloads = MutableStateFlow<Map<String, InstallStep>>(hashMapOf())
|
||||
|
||||
|
@ -189,16 +190,17 @@ class AnimeExtensionsScreenModel(
|
|||
fun trustSignature(signatureHash: String) {
|
||||
extensionManager.trustSignature(signatureHash)
|
||||
}
|
||||
}
|
||||
|
||||
data class AnimeExtensionsState(
|
||||
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<AnimeExtensionUiModel.Header, List<AnimeExtensionUiModel.Item>>
|
||||
|
|
|
@ -38,7 +38,7 @@ class AnimeExtensionDetailsScreenModel(
|
|||
private val extensionManager: AnimeExtensionManager = Injekt.get(),
|
||||
private val getExtensionSources: GetAnimeExtensionSources = Injekt.get(),
|
||||
private val toggleSource: ToggleAnimeSource = Injekt.get(),
|
||||
) : StateScreenModel<AnimeExtensionDetailsState>(AnimeExtensionDetailsState()) {
|
||||
) : StateScreenModel<AnimeExtensionDetailsScreenModel.State>(State()) {
|
||||
|
||||
private val _events: Channel<AnimeExtensionDetailsEvent> = Channel()
|
||||
val events: Flow<AnimeExtensionDetailsEvent> = _events.receiveAsFlow()
|
||||
|
@ -160,21 +160,21 @@ class AnimeExtensionDetailsScreenModel(
|
|||
url + "/src/" + pkgName.replace(".", "/") + path
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
data class State(
|
||||
val extension: AnimeExtension.Installed? = null,
|
||||
private val _sources: List<AnimeExtensionSourceItem>? = null,
|
||||
) {
|
||||
|
||||
val sources: List<AnimeExtensionSourceItem>
|
||||
get() = _sources.orEmpty()
|
||||
|
||||
val isLoading: Boolean
|
||||
get() = extension == null || _sources == null
|
||||
}
|
||||
}
|
||||
|
||||
sealed class AnimeExtensionDetailsEvent {
|
||||
data object Uninstalled : AnimeExtensionDetailsEvent()
|
||||
}
|
||||
|
||||
@Immutable
|
||||
data class AnimeExtensionDetailsState(
|
||||
val extension: AnimeExtension.Installed? = null,
|
||||
private val _sources: List<AnimeExtensionSourceItem>? = null,
|
||||
) {
|
||||
|
||||
val sources: List<AnimeExtensionSourceItem>
|
||||
get() = _sources.orEmpty()
|
||||
|
||||
val isLoading: Boolean
|
||||
get() = extension == null || _sources == null
|
||||
sealed interface AnimeExtensionDetailsEvent {
|
||||
data object Uninstalled : AnimeExtensionDetailsEvent
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ import eu.kanade.tachiyomi.util.system.toast
|
|||
import kotlinx.coroutines.flow.collectLatest
|
||||
import tachiyomi.presentation.core.screens.LoadingScreen
|
||||
|
||||
data class MigrationAnimeScreen(
|
||||
data class MigrateAnimeScreen(
|
||||
private val sourceId: Long,
|
||||
) : Screen() {
|
||||
|
||||
|
@ -25,7 +25,7 @@ data class MigrationAnimeScreen(
|
|||
override fun Content() {
|
||||
val context = LocalContext.current
|
||||
val navigator = LocalNavigator.currentOrThrow
|
||||
val screenModel = rememberScreenModel { MigrationAnimeScreenModel(sourceId) }
|
||||
val screenModel = rememberScreenModel { MigrateAnimeScreenModel(sourceId) }
|
||||
|
||||
val state by screenModel.state.collectAsState()
|
||||
|
|
@ -20,11 +20,11 @@ import tachiyomi.domain.source.anime.service.AnimeSourceManager
|
|||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class MigrationAnimeScreenModel(
|
||||
class MigrateAnimeScreenModel(
|
||||
private val sourceId: Long,
|
||||
private val sourceManager: AnimeSourceManager = Injekt.get(),
|
||||
private val getFavorites: GetAnimeFavorites = Injekt.get(),
|
||||
) : StateScreenModel<MigrateAnimeState>(MigrateAnimeState()) {
|
||||
) : StateScreenModel<MigrateAnimeScreenModel.State>(State()) {
|
||||
|
||||
private val _events: Channel<MigrationAnimeEvent> = Channel()
|
||||
val events: Flow<MigrationAnimeEvent> = _events.receiveAsFlow()
|
||||
|
@ -51,24 +51,24 @@ class MigrationAnimeScreenModel(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
data class State(
|
||||
val source: AnimeSource? = null,
|
||||
private val titleList: List<Anime>? = null,
|
||||
) {
|
||||
|
||||
val titles: List<Anime>
|
||||
get() = titleList.orEmpty()
|
||||
|
||||
val isLoading: Boolean
|
||||
get() = source == null || titleList == null
|
||||
|
||||
val isEmpty: Boolean
|
||||
get() = titles.isEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
sealed class MigrationAnimeEvent {
|
||||
data object FailedFetchingFavorites : MigrationAnimeEvent()
|
||||
}
|
||||
|
||||
@Immutable
|
||||
data class MigrateAnimeState(
|
||||
val source: AnimeSource? = null,
|
||||
private val titleList: List<Anime>? = null,
|
||||
) {
|
||||
|
||||
val titles: List<Anime>
|
||||
get() = titleList.orEmpty()
|
||||
|
||||
val isLoading: Boolean
|
||||
get() = source == null || titleList == null
|
||||
|
||||
val isEmpty: Boolean
|
||||
get() = titles.isEmpty()
|
||||
sealed interface MigrationAnimeEvent {
|
||||
data object FailedFetchingFavorites : MigrationAnimeEvent
|
||||
}
|
|
@ -37,7 +37,7 @@ class AnimeMigrateSearchScreenDialogScreenModel(
|
|||
val dialog: Dialog? = null,
|
||||
)
|
||||
|
||||
sealed class Dialog {
|
||||
data class Migrate(val anime: Anime) : Dialog()
|
||||
sealed interface Dialog {
|
||||
data class Migrate(val anime: Anime) : Dialog
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package eu.kanade.tachiyomi.ui.browse.anime.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.anime.interactor.GetAnimeSourcesWithFavoriteCount
|
||||
|
@ -23,7 +24,7 @@ class MigrateAnimeSourceScreenModel(
|
|||
preferences: SourcePreferences = Injekt.get(),
|
||||
private val getSourcesWithFavoriteCount: GetAnimeSourcesWithFavoriteCount = Injekt.get(),
|
||||
private val setMigrateSorting: SetMigrateSorting = Injekt.get(),
|
||||
) : StateScreenModel<MigrateAnimeSourceState>(MigrateAnimeSourceState()) {
|
||||
) : StateScreenModel<MigrateAnimeSourceScreenModel.State>(State()) {
|
||||
|
||||
private val _channel = Channel<Event>(Int.MAX_VALUE)
|
||||
val channel = _channel.receiveAsFlow()
|
||||
|
@ -76,16 +77,17 @@ class MigrateAnimeSourceScreenModel(
|
|||
}
|
||||
}
|
||||
|
||||
sealed class Event {
|
||||
data object FailedFetchingSourcesWithCount : Event()
|
||||
@Immutable
|
||||
data class State(
|
||||
val isLoading: Boolean = true,
|
||||
val items: List<Pair<AnimeSource, 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 MigrateAnimeSourceState(
|
||||
val isLoading: Boolean = true,
|
||||
val items: List<Pair<AnimeSource, 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.anime.MigrateAnimeSourceScreen
|
|||
import eu.kanade.presentation.components.AppBar
|
||||
import eu.kanade.presentation.components.TabContent
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.browse.anime.migration.anime.MigrationAnimeScreen
|
||||
import eu.kanade.tachiyomi.ui.browse.anime.migration.anime.MigrateAnimeScreen
|
||||
|
||||
@Composable
|
||||
fun Screen.migrateAnimeSourceTab(): TabContent {
|
||||
|
@ -39,7 +39,9 @@ fun Screen.migrateAnimeSourceTab(): TabContent {
|
|||
MigrateAnimeSourceScreen(
|
||||
state = state,
|
||||
contentPadding = contentPadding,
|
||||
onClickItem = { source -> navigator.push(MigrationAnimeScreen(source.id)) },
|
||||
onClickItem = { source ->
|
||||
navigator.push(MigrateAnimeScreen(source.id))
|
||||
},
|
||||
onToggleSortingDirection = screenModel::toggleSortingDirection,
|
||||
onToggleSortingMode = screenModel::toggleSortingMode,
|
||||
)
|
||||
|
|
|
@ -22,12 +22,12 @@ class AnimeSourcesFilterScreen : Screen() {
|
|||
val screenModel = rememberScreenModel { AnimeSourcesFilterScreenModel() }
|
||||
val state by screenModel.state.collectAsState()
|
||||
|
||||
if (state is AnimeSourcesFilterState.Loading) {
|
||||
if (state is AnimeSourcesFilterScreenModel.State.Loading) {
|
||||
LoadingScreen()
|
||||
return
|
||||
}
|
||||
|
||||
if (state is AnimeSourcesFilterState.Error) {
|
||||
if (state is AnimeSourcesFilterScreenModel.State.Error) {
|
||||
val context = LocalContext.current
|
||||
LaunchedEffect(Unit) {
|
||||
context.toast(R.string.internal_error)
|
||||
|
@ -36,7 +36,7 @@ class AnimeSourcesFilterScreen : Screen() {
|
|||
return
|
||||
}
|
||||
|
||||
val successState = state as AnimeSourcesFilterState.Success
|
||||
val successState = state as AnimeSourcesFilterScreenModel.State.Success
|
||||
|
||||
AnimeSourcesFilterScreen(
|
||||
navigateUp = navigator::pop,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package eu.kanade.tachiyomi.ui.browse.anime.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.anime.interactor.GetLanguagesWithAnimeSources
|
||||
|
@ -21,7 +22,7 @@ class AnimeSourcesFilterScreenModel(
|
|||
private val getLanguagesWithSources: GetLanguagesWithAnimeSources = Injekt.get(),
|
||||
private val toggleSource: ToggleAnimeSource = Injekt.get(),
|
||||
private val toggleLanguage: ToggleLanguage = Injekt.get(),
|
||||
) : StateScreenModel<AnimeSourcesFilterState>(AnimeSourcesFilterState.Loading) {
|
||||
) : StateScreenModel<AnimeSourcesFilterScreenModel.State>(State.Loading) {
|
||||
|
||||
init {
|
||||
coroutineScope.launch {
|
||||
|
@ -32,14 +33,14 @@ class AnimeSourcesFilterScreenModel(
|
|||
) { a, b, c -> Triple(a, b, c) }
|
||||
.catch { throwable ->
|
||||
mutableState.update {
|
||||
AnimeSourcesFilterState.Error(
|
||||
State.Error(
|
||||
throwable = throwable,
|
||||
)
|
||||
}
|
||||
}
|
||||
.collectLatest { (languagesWithSources, enabledLanguages, disabledSources) ->
|
||||
mutableState.update {
|
||||
AnimeSourcesFilterState.Success(
|
||||
State.Success(
|
||||
items = languagesWithSources,
|
||||
enabledLanguages = enabledLanguages,
|
||||
disabledSources = disabledSources,
|
||||
|
@ -56,23 +57,26 @@ class AnimeSourcesFilterScreenModel(
|
|||
fun toggleLanguage(language: String) {
|
||||
toggleLanguage.await(language)
|
||||
}
|
||||
}
|
||||
|
||||
sealed class AnimeSourcesFilterState {
|
||||
sealed interface State {
|
||||
|
||||
object Loading : AnimeSourcesFilterState()
|
||||
@Immutable
|
||||
data object Loading : State
|
||||
|
||||
data class Error(
|
||||
val throwable: Throwable,
|
||||
) : AnimeSourcesFilterState()
|
||||
@Immutable
|
||||
data class Error(
|
||||
val throwable: Throwable,
|
||||
) : State
|
||||
|
||||
data class Success(
|
||||
val items: SortedMap<String, List<AnimeSource>>,
|
||||
val enabledLanguages: Set<String>,
|
||||
val disabledSources: Set<String>,
|
||||
) : AnimeSourcesFilterState() {
|
||||
@Immutable
|
||||
data class Success(
|
||||
val items: SortedMap<String, List<AnimeSource>>,
|
||||
val enabledLanguages: Set<String>,
|
||||
val disabledSources: Set<String>,
|
||||
) : State {
|
||||
|
||||
val isEmpty: Boolean
|
||||
get() = items.isEmpty()
|
||||
val isEmpty: Boolean
|
||||
get() = items.isEmpty()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,8 +99,8 @@ class AnimeSourcesScreenModel(
|
|||
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: AnimeSource)
|
||||
|
|
|
@ -14,6 +14,7 @@ import androidx.compose.material.icons.outlined.FilterList
|
|||
import androidx.compose.material.icons.outlined.NewReleases
|
||||
import androidx.compose.material3.FilterChip
|
||||
import androidx.compose.material3.FilterChipDefaults
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
|
@ -57,7 +58,6 @@ import kotlinx.coroutines.flow.collectLatest
|
|||
import kotlinx.coroutines.flow.receiveAsFlow
|
||||
import tachiyomi.core.util.lang.launchIO
|
||||
import tachiyomi.domain.source.anime.model.StubAnimeSource
|
||||
import tachiyomi.presentation.core.components.material.Divider
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.source.local.entries.anime.LocalAnimeSource
|
||||
|
@ -192,7 +192,7 @@ data class BrowseAnimeSourceScreen(
|
|||
}
|
||||
}
|
||||
|
||||
Divider()
|
||||
HorizontalDivider()
|
||||
}
|
||||
},
|
||||
snackbarHost = { SnackbarHost(hostState = snackbarHostState) },
|
||||
|
|
|
@ -373,15 +373,15 @@ class BrowseAnimeSourceScreenModel(
|
|||
}
|
||||
}
|
||||
|
||||
sealed class Dialog {
|
||||
data object Filter : Dialog()
|
||||
data class RemoveAnime(val anime: Anime) : Dialog()
|
||||
data class AddDuplicateAnime(val anime: Anime, val duplicate: Anime) : Dialog()
|
||||
sealed interface Dialog {
|
||||
data object Filter : Dialog
|
||||
data class RemoveAnime(val anime: Anime) : Dialog
|
||||
data class AddDuplicateAnime(val anime: Anime, val duplicate: Anime) : Dialog
|
||||
data class ChangeAnimeCategory(
|
||||
val anime: Anime,
|
||||
val initialSelection: List<CheckboxState.State<Category>>,
|
||||
) : Dialog()
|
||||
data class Migrate(val newAnime: Anime) : Dialog()
|
||||
) : Dialog
|
||||
data class Migrate(val newAnime: Anime) : Dialog
|
||||
}
|
||||
|
||||
@Immutable
|
||||
|
|
|
@ -8,7 +8,7 @@ import androidx.compose.foundation.layout.padding
|
|||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Divider
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.LocalTextStyle
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
|
@ -68,7 +68,7 @@ fun SourceFilterAnimeDialog(
|
|||
Text(stringResource(R.string.action_filter))
|
||||
}
|
||||
}
|
||||
Divider()
|
||||
HorizontalDivider()
|
||||
}
|
||||
|
||||
items(filters) {
|
||||
|
@ -85,7 +85,7 @@ private fun FilterItem(filter: AnimeFilter<*>, onUpdate: () -> Unit) {
|
|||
HeadingItem(filter.name)
|
||||
}
|
||||
is AnimeFilter.Separator -> {
|
||||
Divider()
|
||||
HorizontalDivider()
|
||||
}
|
||||
is AnimeFilter.CheckBox -> {
|
||||
CheckboxItem(
|
||||
|
|
|
@ -186,16 +186,16 @@ enum class AnimeSourceFilter {
|
|||
PinnedOnly,
|
||||
}
|
||||
|
||||
sealed class AnimeSearchItemResult {
|
||||
data object Loading : AnimeSearchItemResult()
|
||||
sealed interface AnimeSearchItemResult {
|
||||
data object Loading : AnimeSearchItemResult
|
||||
|
||||
data class Error(
|
||||
val throwable: Throwable,
|
||||
) : AnimeSearchItemResult()
|
||||
) : AnimeSearchItemResult
|
||||
|
||||
data class Success(
|
||||
val result: List<Anime>,
|
||||
) : AnimeSearchItemResult() {
|
||||
) : AnimeSearchItemResult {
|
||||
val isEmpty: Boolean
|
||||
get() = result.isEmpty()
|
||||
}
|
||||
|
|
|
@ -54,20 +54,20 @@ class MangaExtensionFilterScreenModel(
|
|||
}
|
||||
}
|
||||
|
||||
sealed class MangaExtensionFilterEvent {
|
||||
data object FailedFetchingLanguages : MangaExtensionFilterEvent()
|
||||
sealed interface MangaExtensionFilterEvent {
|
||||
data object FailedFetchingLanguages : MangaExtensionFilterEvent
|
||||
}
|
||||
|
||||
sealed class MangaExtensionFilterState {
|
||||
sealed interface MangaExtensionFilterState {
|
||||
|
||||
@Immutable
|
||||
data object Loading : MangaExtensionFilterState()
|
||||
data object Loading : MangaExtensionFilterState
|
||||
|
||||
@Immutable
|
||||
data class Success(
|
||||
val languages: List<String>,
|
||||
val enabledLanguages: Set<String> = emptySet(),
|
||||
) : MangaExtensionFilterState() {
|
||||
) : MangaExtensionFilterState {
|
||||
|
||||
val isEmpty: Boolean
|
||||
get() = languages.isEmpty()
|
||||
|
|
|
@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.browse.manga.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.manga.interactor.GetMangaExtensionsByType
|
||||
|
@ -35,7 +36,7 @@ class MangaExtensionsScreenModel(
|
|||
preferences: SourcePreferences = Injekt.get(),
|
||||
private val extensionManager: MangaExtensionManager = Injekt.get(),
|
||||
private val getExtensions: GetMangaExtensionsByType = Injekt.get(),
|
||||
) : StateScreenModel<MangaExtensionsState>(MangaExtensionsState()) {
|
||||
) : StateScreenModel<MangaExtensionsScreenModel.State>(State()) {
|
||||
|
||||
private var _currentDownloads = MutableStateFlow<Map<String, InstallStep>>(hashMapOf())
|
||||
|
||||
|
@ -191,16 +192,17 @@ class MangaExtensionsScreenModel(
|
|||
fun trustSignature(signatureHash: String) {
|
||||
extensionManager.trustSignature(signatureHash)
|
||||
}
|
||||
}
|
||||
|
||||
data class MangaExtensionsState(
|
||||
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<MangaExtensionUiModel.Header, List<MangaExtensionUiModel.Item>>
|
||||
|
|
|
@ -38,7 +38,7 @@ class MangaExtensionDetailsScreenModel(
|
|||
private val extensionManager: MangaExtensionManager = Injekt.get(),
|
||||
private val getExtensionSources: GetExtensionSources = Injekt.get(),
|
||||
private val toggleSource: ToggleMangaSource = Injekt.get(),
|
||||
) : StateScreenModel<MangaExtensionDetailsState>(MangaExtensionDetailsState()) {
|
||||
) : StateScreenModel<MangaExtensionDetailsScreenModel.State>(State()) {
|
||||
|
||||
private val _events: Channel<MangaExtensionDetailsEvent> = Channel()
|
||||
val events: Flow<MangaExtensionDetailsEvent> = _events.receiveAsFlow()
|
||||
|
@ -160,21 +160,21 @@ class MangaExtensionDetailsScreenModel(
|
|||
url + "/src/" + pkgName.replace(".", "/") + path
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
data class State(
|
||||
val extension: MangaExtension.Installed? = null,
|
||||
private val _sources: List<MangaExtensionSourceItem>? = null,
|
||||
) {
|
||||
|
||||
val sources: List<MangaExtensionSourceItem>
|
||||
get() = _sources.orEmpty()
|
||||
|
||||
val isLoading: Boolean
|
||||
get() = extension == null || _sources == null
|
||||
}
|
||||
}
|
||||
|
||||
sealed class MangaExtensionDetailsEvent {
|
||||
data object Uninstalled : MangaExtensionDetailsEvent()
|
||||
}
|
||||
|
||||
@Immutable
|
||||
data class MangaExtensionDetailsState(
|
||||
val extension: MangaExtension.Installed? = null,
|
||||
private val _sources: List<MangaExtensionSourceItem>? = null,
|
||||
) {
|
||||
|
||||
val sources: List<MangaExtensionSourceItem>
|
||||
get() = _sources.orEmpty()
|
||||
|
||||
val isLoading: Boolean
|
||||
get() = extension == null || _sources == null
|
||||
sealed interface MangaExtensionDetailsEvent {
|
||||
data object Uninstalled : MangaExtensionDetailsEvent
|
||||
}
|
||||
|
|
|
@ -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.manga.service.MangaSourceManager
|
|||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class MigrationMangaScreenModel(
|
||||
class MigrateMangaScreenModel(
|
||||
private val sourceId: Long,
|
||||
private val sourceManager: MangaSourceManager = Injekt.get(),
|
||||
private val getFavorites: GetMangaFavorites = 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: MangaSource? = 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: MangaSource? = 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 MangaMigrateSearchScreenDialogScreenModel(
|
|||
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.manga.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.manga.interactor.GetMangaSourcesWithFavoriteCount
|
||||
|
@ -23,7 +24,7 @@ class MigrateSourceScreenModel(
|
|||
preferences: SourcePreferences = Injekt.get(),
|
||||
private val getSourcesWithFavoriteCount: GetMangaSourcesWithFavoriteCount = Injekt.get(),
|
||||
private val setMigrateSorting: SetMigrateSorting = Injekt.get(),
|
||||
) : StateScreenModel<MigrateMangaSourceState>(MigrateMangaSourceState()) {
|
||||
) : 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 MigrateMangaSourceState(
|
||||
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.manga.MigrateMangaSourceScreen
|
|||
import eu.kanade.presentation.components.AppBar
|
||||
import eu.kanade.presentation.components.TabContent
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.browse.manga.migration.manga.MigrationMangaScreen
|
||||
import eu.kanade.tachiyomi.ui.browse.manga.migration.manga.MigrateMangaScreen
|
||||
|
||||
@Composable
|
||||
fun Screen.migrateMangaSourceTab(): TabContent {
|
||||
|
@ -40,7 +40,7 @@ fun Screen.migrateMangaSourceTab(): 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 MangaSourcesFilterScreen : Screen() {
|
|||
val screenModel = rememberScreenModel { SourcesFilterScreenModel() }
|
||||
val state by screenModel.state.collectAsState()
|
||||
|
||||
if (state is MangaSourcesFilterState.Loading) {
|
||||
if (state is SourcesFilterScreenModel.State.Loading) {
|
||||
LoadingScreen()
|
||||
return
|
||||
}
|
||||
|
||||
if (state is MangaSourcesFilterState.Error) {
|
||||
if (state is SourcesFilterScreenModel.State.Error) {
|
||||
val context = LocalContext.current
|
||||
LaunchedEffect(Unit) {
|
||||
context.toast(R.string.internal_error)
|
||||
|
@ -36,7 +36,7 @@ class MangaSourcesFilterScreen : Screen() {
|
|||
return
|
||||
}
|
||||
|
||||
val successState = state as MangaSourcesFilterState.Success
|
||||
val successState = state as SourcesFilterScreenModel.State.Success
|
||||
|
||||
MangaSourcesFilterScreen(
|
||||
navigateUp = navigator::pop,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package eu.kanade.tachiyomi.ui.browse.manga.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.manga.interactor.GetLanguagesWithMangaSources
|
||||
|
@ -21,7 +22,7 @@ class SourcesFilterScreenModel(
|
|||
private val getLanguagesWithSources: GetLanguagesWithMangaSources = Injekt.get(),
|
||||
private val toggleSource: ToggleMangaSource = Injekt.get(),
|
||||
private val toggleLanguage: ToggleLanguage = Injekt.get(),
|
||||
) : StateScreenModel<MangaSourcesFilterState>(MangaSourcesFilterState.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 {
|
||||
MangaSourcesFilterState.Error(
|
||||
State.Error(
|
||||
throwable = throwable,
|
||||
)
|
||||
}
|
||||
}
|
||||
.collectLatest { (languagesWithSources, enabledLanguages, disabledSources) ->
|
||||
mutableState.update {
|
||||
MangaSourcesFilterState.Success(
|
||||
State.Success(
|
||||
items = languagesWithSources,
|
||||
enabledLanguages = enabledLanguages,
|
||||
disabledSources = disabledSources,
|
||||
|
@ -56,23 +57,26 @@ class SourcesFilterScreenModel(
|
|||
fun toggleLanguage(language: String) {
|
||||
toggleLanguage.await(language)
|
||||
}
|
||||
}
|
||||
|
||||
sealed class MangaSourcesFilterState {
|
||||
sealed interface State {
|
||||
|
||||
object Loading : MangaSourcesFilterState()
|
||||
@Immutable
|
||||
data object Loading : State
|
||||
|
||||
data class Error(
|
||||
val throwable: Throwable,
|
||||
) : MangaSourcesFilterState()
|
||||
@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>,
|
||||
) : MangaSourcesFilterState() {
|
||||
@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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -123,8 +123,8 @@ class MangaSourcesScreenModel(
|
|||
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)
|
||||
|
|
|
@ -14,6 +14,7 @@ import androidx.compose.material.icons.outlined.FilterList
|
|||
import androidx.compose.material.icons.outlined.NewReleases
|
||||
import androidx.compose.material3.FilterChip
|
||||
import androidx.compose.material3.FilterChipDefaults
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
|
@ -57,7 +58,6 @@ import kotlinx.coroutines.flow.collectLatest
|
|||
import kotlinx.coroutines.flow.receiveAsFlow
|
||||
import tachiyomi.core.util.lang.launchIO
|
||||
import tachiyomi.domain.source.manga.model.StubMangaSource
|
||||
import tachiyomi.presentation.core.components.material.Divider
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.source.local.entries.manga.LocalMangaSource
|
||||
|
@ -192,7 +192,7 @@ data class BrowseMangaSourceScreen(
|
|||
}
|
||||
}
|
||||
|
||||
Divider()
|
||||
HorizontalDivider()
|
||||
}
|
||||
},
|
||||
snackbarHost = { SnackbarHost(hostState = snackbarHostState) },
|
||||
|
|
|
@ -367,15 +367,15 @@ class BrowseMangaSourceScreenModel(
|
|||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.Spacer
|
|||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.LocalTextStyle
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
|
@ -28,7 +29,6 @@ import tachiyomi.presentation.core.components.SortItem
|
|||
import tachiyomi.presentation.core.components.TextItem
|
||||
import tachiyomi.presentation.core.components.TriStateItem
|
||||
import tachiyomi.presentation.core.components.material.Button
|
||||
import tachiyomi.presentation.core.components.material.Divider
|
||||
|
||||
@Composable
|
||||
fun SourceFilterMangaDialog(
|
||||
|
@ -68,7 +68,7 @@ fun SourceFilterMangaDialog(
|
|||
Text(stringResource(R.string.action_filter))
|
||||
}
|
||||
}
|
||||
Divider()
|
||||
HorizontalDivider()
|
||||
}
|
||||
|
||||
items(filters) {
|
||||
|
@ -85,7 +85,7 @@ private fun FilterItem(filter: Filter<*>, onUpdate: () -> Unit) {
|
|||
HeadingItem(filter.name)
|
||||
}
|
||||
is Filter.Separator -> {
|
||||
Divider()
|
||||
HorizontalDivider()
|
||||
}
|
||||
is Filter.CheckBox -> {
|
||||
CheckboxItem(
|
||||
|
|
|
@ -186,16 +186,16 @@ enum class MangaSourceFilter {
|
|||
PinnedOnly,
|
||||
}
|
||||
|
||||
sealed class MangaSearchItemResult {
|
||||
data object Loading : MangaSearchItemResult()
|
||||
sealed interface MangaSearchItemResult {
|
||||
data object Loading : MangaSearchItemResult
|
||||
|
||||
data class Error(
|
||||
val throwable: Throwable,
|
||||
) : MangaSearchItemResult()
|
||||
) : MangaSearchItemResult
|
||||
|
||||
data class Success(
|
||||
val result: List<Manga>,
|
||||
) : MangaSearchItemResult() {
|
||||
) : MangaSearchItemResult {
|
||||
val isEmpty: Boolean
|
||||
get() = result.isEmpty()
|
||||
}
|
||||
|
|
|
@ -130,27 +130,27 @@ class AnimeCategoryScreenModel(
|
|||
}
|
||||
}
|
||||
|
||||
sealed class AnimeCategoryDialog {
|
||||
data object Create : AnimeCategoryDialog()
|
||||
data class Rename(val category: Category) : AnimeCategoryDialog()
|
||||
data class Delete(val category: Category) : AnimeCategoryDialog()
|
||||
sealed interface AnimeCategoryDialog {
|
||||
data object Create : AnimeCategoryDialog
|
||||
data class Rename(val category: Category) : AnimeCategoryDialog
|
||||
data class Delete(val category: Category) : AnimeCategoryDialog
|
||||
}
|
||||
|
||||
sealed class AnimeCategoryEvent {
|
||||
sealed class LocalizedMessage(@StringRes val stringRes: Int) : AnimeCategoryEvent()
|
||||
sealed interface AnimeCategoryEvent {
|
||||
sealed class LocalizedMessage(@StringRes val stringRes: Int) : AnimeCategoryEvent
|
||||
data object InternalError : LocalizedMessage(R.string.internal_error)
|
||||
}
|
||||
|
||||
sealed class AnimeCategoryScreenState {
|
||||
sealed interface AnimeCategoryScreenState {
|
||||
|
||||
@Immutable
|
||||
data object Loading : AnimeCategoryScreenState()
|
||||
data object Loading : AnimeCategoryScreenState
|
||||
|
||||
@Immutable
|
||||
data class Success(
|
||||
val categories: List<Category>,
|
||||
val dialog: AnimeCategoryDialog? = null,
|
||||
) : AnimeCategoryScreenState() {
|
||||
) : AnimeCategoryScreenState {
|
||||
|
||||
val isEmpty: Boolean
|
||||
get() = categories.isEmpty()
|
||||
|
|
|
@ -130,27 +130,27 @@ class MangaCategoryScreenModel(
|
|||
}
|
||||
}
|
||||
|
||||
sealed class MangaCategoryDialog {
|
||||
data object Create : MangaCategoryDialog()
|
||||
data class Rename(val category: Category) : MangaCategoryDialog()
|
||||
data class Delete(val category: Category) : MangaCategoryDialog()
|
||||
sealed interface MangaCategoryDialog {
|
||||
data object Create : MangaCategoryDialog
|
||||
data class Rename(val category: Category) : MangaCategoryDialog
|
||||
data class Delete(val category: Category) : MangaCategoryDialog
|
||||
}
|
||||
|
||||
sealed class MangaCategoryEvent {
|
||||
sealed class LocalizedMessage(@StringRes val stringRes: Int) : MangaCategoryEvent()
|
||||
sealed interface MangaCategoryEvent {
|
||||
sealed class LocalizedMessage(@StringRes val stringRes: Int) : MangaCategoryEvent
|
||||
data object InternalError : LocalizedMessage(R.string.internal_error)
|
||||
}
|
||||
|
||||
sealed class MangaCategoryScreenState {
|
||||
sealed interface MangaCategoryScreenState {
|
||||
|
||||
@Immutable
|
||||
data object Loading : MangaCategoryScreenState()
|
||||
data object Loading : MangaCategoryScreenState
|
||||
|
||||
@Immutable
|
||||
data class Success(
|
||||
val categories: List<Category>,
|
||||
val dialog: MangaCategoryDialog? = null,
|
||||
) : MangaCategoryScreenState() {
|
||||
) : MangaCategoryScreenState {
|
||||
|
||||
val isEmpty: Boolean
|
||||
get() = categories.isEmpty()
|
||||
|
|
|
@ -81,12 +81,12 @@ class AnimeScreen(
|
|||
|
||||
val state by screenModel.state.collectAsState()
|
||||
|
||||
if (state is AnimeScreenState.Loading) {
|
||||
if (state is AnimeScreenModel.State.Loading) {
|
||||
LoadingScreen()
|
||||
return
|
||||
}
|
||||
|
||||
val successState = state as AnimeScreenState.Success
|
||||
val successState = state as AnimeScreenModel.State.Success
|
||||
val isAnimeHttpSource = remember { successState.source is AnimeHttpSource }
|
||||
|
||||
LaunchedEffect(successState.anime, screenModel.source) {
|
||||
|
|
|
@ -105,10 +105,10 @@ class AnimeScreenModel(
|
|||
private val setAnimeCategories: SetAnimeCategories = Injekt.get(),
|
||||
internal val setAnimeViewerFlags: SetAnimeViewerFlags = Injekt.get(),
|
||||
val snackbarHostState: SnackbarHostState = SnackbarHostState(),
|
||||
) : StateScreenModel<AnimeScreenState>(AnimeScreenState.Loading) {
|
||||
) : StateScreenModel<AnimeScreenModel.State>(State.Loading) {
|
||||
|
||||
private val successState: AnimeScreenState.Success?
|
||||
get() = state.value as? AnimeScreenState.Success
|
||||
private val successState: State.Success?
|
||||
get() = state.value as? State.Success
|
||||
|
||||
private val loggedServices by lazy { trackManager.services.filter { it.isLogged && it is AnimeTrackService } }
|
||||
|
||||
|
@ -145,11 +145,11 @@ class AnimeScreenModel(
|
|||
/**
|
||||
* Helper function to update the UI state only if it's currently in success state
|
||||
*/
|
||||
private inline fun updateSuccessState(func: (AnimeScreenState.Success) -> AnimeScreenState.Success) {
|
||||
private inline fun updateSuccessState(func: (State.Success) -> State.Success) {
|
||||
mutableState.update {
|
||||
when (it) {
|
||||
AnimeScreenState.Loading -> it
|
||||
is AnimeScreenState.Success -> func(it)
|
||||
State.Loading -> it
|
||||
is State.Success -> func(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -187,7 +187,7 @@ class AnimeScreenModel(
|
|||
|
||||
// Show what we have earlier
|
||||
mutableState.update {
|
||||
AnimeScreenState.Success(
|
||||
State.Success(
|
||||
anime = anime,
|
||||
source = Injekt.get<AnimeSourceManager>().getOrStub(anime.source),
|
||||
isFromSource = isFromSource,
|
||||
|
@ -351,8 +351,7 @@ class AnimeScreenModel(
|
|||
}
|
||||
|
||||
fun promptChangeCategories() {
|
||||
val state = successState ?: return
|
||||
val anime = state.anime
|
||||
val anime = successState?.anime ?: return
|
||||
coroutineScope.launch {
|
||||
val categories = getCategories()
|
||||
val selection = getAnimeCategoryIds(anime)
|
||||
|
@ -685,9 +684,9 @@ class AnimeScreenModel(
|
|||
}
|
||||
|
||||
fun markPreviousEpisodeSeen(pointer: Episode) {
|
||||
val successState = successState ?: return
|
||||
val anime = successState?.anime ?: return
|
||||
val episodes = processedEpisodes.orEmpty().map { it.episode }.toList()
|
||||
val prevEpisodes = if (successState.anime.sortDescending()) episodes.asReversed() else episodes
|
||||
val prevEpisodes = if (anime.sortDescending()) episodes.asReversed() else episodes
|
||||
val pointerPos = prevEpisodes.indexOf(pointer)
|
||||
if (pointerPos != -1) markEpisodesSeen(prevEpisodes.take(pointerPos), true)
|
||||
}
|
||||
|
@ -969,15 +968,15 @@ class AnimeScreenModel(
|
|||
|
||||
// Track sheet - end
|
||||
|
||||
sealed class Dialog {
|
||||
data class ChangeCategory(val anime: Anime, val initialSelection: List<CheckboxState<Category>>) : Dialog()
|
||||
data class DeleteEpisodes(val episodes: List<Episode>) : Dialog()
|
||||
data class DuplicateAnime(val anime: Anime, val duplicate: Anime) : Dialog()
|
||||
data class ShowQualities(val episode: Episode, val anime: Anime, val source: AnimeSource) : Dialog()
|
||||
data object ChangeAnimeSkipIntro : Dialog()
|
||||
data object SettingsSheet : Dialog()
|
||||
data object TrackSheet : Dialog()
|
||||
data object FullCover : Dialog()
|
||||
sealed interface Dialog {
|
||||
data class ChangeCategory(val anime: Anime, val initialSelection: List<CheckboxState<Category>>) : Dialog
|
||||
data class DeleteEpisodes(val episodes: List<Episode>) : Dialog
|
||||
data class DuplicateAnime(val anime: Anime, val duplicate: Anime) : Dialog
|
||||
data class ShowQualities(val episode: Episode, val anime: Anime, val source: AnimeSource) : Dialog
|
||||
data object ChangeAnimeSkipIntro : Dialog
|
||||
data object SettingsSheet : Dialog
|
||||
data object TrackSheet : Dialog
|
||||
data object FullCover : Dialog
|
||||
}
|
||||
|
||||
fun dismissDialog() {
|
||||
|
@ -1007,55 +1006,60 @@ class AnimeScreenModel(
|
|||
private fun showQualitiesDialog(episode: Episode) {
|
||||
updateSuccessState { it.copy(dialog = Dialog.ShowQualities(episode, it.anime, it.source)) }
|
||||
}
|
||||
}
|
||||
|
||||
sealed class AnimeScreenState {
|
||||
@Immutable
|
||||
object Loading : AnimeScreenState()
|
||||
sealed interface State {
|
||||
@Immutable
|
||||
object Loading : State
|
||||
|
||||
@Immutable
|
||||
data class Success(
|
||||
val anime: Anime,
|
||||
val source: AnimeSource,
|
||||
val isFromSource: Boolean,
|
||||
val episodes: List<EpisodeItem>,
|
||||
val trackItems: List<AnimeTrackItem> = emptyList(),
|
||||
val isRefreshingData: Boolean = false,
|
||||
val dialog: AnimeScreenModel.Dialog? = null,
|
||||
val hasPromptedToAddBefore: Boolean = false,
|
||||
val nextAiringEpisode: Pair<Int, Long> = Pair(anime.nextEpisodeToAir, anime.nextEpisodeAiringAt),
|
||||
) : AnimeScreenState() {
|
||||
@Immutable
|
||||
data class Success(
|
||||
val anime: Anime,
|
||||
val source: AnimeSource,
|
||||
val isFromSource: Boolean,
|
||||
val episodes: List<EpisodeItem>,
|
||||
val trackItems: List<AnimeTrackItem> = emptyList(),
|
||||
val isRefreshingData: Boolean = false,
|
||||
val dialog: Dialog? = null,
|
||||
val hasPromptedToAddBefore: Boolean = false,
|
||||
val nextAiringEpisode: Pair<Int, Long> = Pair(anime.nextEpisodeToAir, anime.nextEpisodeAiringAt),
|
||||
) : State {
|
||||
|
||||
val processedEpisodes by lazy {
|
||||
episodes.applyFilters(anime).toList()
|
||||
}
|
||||
val processedEpisodes by lazy {
|
||||
episodes.applyFilters(anime).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 }
|
||||
|
||||
val airingEpisodeNumber: Double
|
||||
get() = nextAiringEpisode.first.toDouble()
|
||||
val airingEpisodeNumber: Double
|
||||
get() = nextAiringEpisode.first.toDouble()
|
||||
|
||||
val airingTime: Long
|
||||
get() = nextAiringEpisode.second.times(1000L).minus(Calendar.getInstance().timeInMillis)
|
||||
val airingTime: Long
|
||||
get() = nextAiringEpisode.second.times(1000L).minus(Calendar.getInstance().timeInMillis)
|
||||
|
||||
/**
|
||||
* Applies the view filters to the list of episodes obtained from the database.
|
||||
* @return an observable of the list of episodes filtered and sorted.
|
||||
*/
|
||||
private fun List<EpisodeItem>.applyFilters(anime: Anime): Sequence<EpisodeItem> {
|
||||
val isLocalAnime = anime.isLocal()
|
||||
val unseenFilter = anime.unseenFilter
|
||||
val downloadedFilter = anime.downloadedFilter
|
||||
val bookmarkedFilter = anime.bookmarkedFilter
|
||||
return asSequence()
|
||||
.filter { (episode) -> applyFilter(unseenFilter) { !episode.seen } }
|
||||
.filter { (episode) -> applyFilter(bookmarkedFilter) { episode.bookmark } }
|
||||
.filter { applyFilter(downloadedFilter) { it.isDownloaded || isLocalAnime } }
|
||||
.sortedWith { (episode1), (episode2) -> getEpisodeSort(anime).invoke(episode1, episode2) }
|
||||
/**
|
||||
* Applies the view filters to the list of episodes obtained from the database.
|
||||
* @return an observable of the list of episodes filtered and sorted.
|
||||
*/
|
||||
private fun List<EpisodeItem>.applyFilters(anime: Anime): Sequence<EpisodeItem> {
|
||||
val isLocalAnime = anime.isLocal()
|
||||
val unseenFilter = anime.unseenFilter
|
||||
val downloadedFilter = anime.downloadedFilter
|
||||
val bookmarkedFilter = anime.bookmarkedFilter
|
||||
return asSequence()
|
||||
.filter { (episode) -> applyFilter(unseenFilter) { !episode.seen } }
|
||||
.filter { (episode) -> applyFilter(bookmarkedFilter) { episode.bookmark } }
|
||||
.filter { applyFilter(downloadedFilter) { it.isDownloaded || isLocalAnime } }
|
||||
.sortedWith { (episode1), (episode2) ->
|
||||
getEpisodeSort(anime).invoke(
|
||||
episode1,
|
||||
episode2,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,12 +76,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) {
|
||||
|
|
|
@ -100,10 +100,10 @@ class MangaScreenModel(
|
|||
private val getTracks: GetMangaTracks = 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 && it is MangaTrackService } }
|
||||
|
||||
|
@ -140,11 +140,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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -182,7 +182,7 @@ class MangaScreenModel(
|
|||
|
||||
// Show what we have earlier
|
||||
mutableState.update {
|
||||
MangaScreenState.Success(
|
||||
State.Success(
|
||||
manga = manga,
|
||||
source = Injekt.get<MangaSourceManager>().getOrStub(manga.source),
|
||||
isFromSource = isFromSource,
|
||||
|
@ -347,8 +347,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)
|
||||
|
@ -675,9 +674,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)
|
||||
}
|
||||
|
@ -953,13 +952,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() {
|
||||
|
@ -981,48 +980,53 @@ 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: MangaSource,
|
||||
val isFromSource: Boolean,
|
||||
val chapters: List<ChapterItem>,
|
||||
val trackItems: List<MangaTrackItem> = emptyList(),
|
||||
val isRefreshingData: Boolean = false,
|
||||
val dialog: MangaScreenModel.Dialog? = null,
|
||||
val hasPromptedToAddBefore: Boolean = false,
|
||||
) : MangaScreenState() {
|
||||
@Immutable
|
||||
data class Success(
|
||||
val manga: Manga,
|
||||
val source: MangaSource,
|
||||
val isFromSource: Boolean,
|
||||
val chapters: List<ChapterItem>,
|
||||
val trackItems: List<MangaTrackItem> = 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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ class AnimeHistoryScreenModel(
|
|||
private val getHistory: GetAnimeHistory = Injekt.get(),
|
||||
private val getNextEpisodes: GetNextEpisodes = Injekt.get(),
|
||||
private val removeHistory: RemoveAnimeHistory = Injekt.get(),
|
||||
) : StateScreenModel<AnimeHistoryState>(AnimeHistoryState()) {
|
||||
) : StateScreenModel<AnimeHistoryScreenModel.State>(State()) {
|
||||
|
||||
private val _events: Channel<Event> = Channel(Channel.UNLIMITED)
|
||||
val events: Flow<Event> = _events.receiveAsFlow()
|
||||
|
@ -119,20 +119,21 @@ class AnimeHistoryScreenModel(
|
|||
mutableState.update { it.copy(dialog = dialog) }
|
||||
}
|
||||
|
||||
sealed class Dialog {
|
||||
data object DeleteAll : Dialog()
|
||||
data class Delete(val history: AnimeHistoryWithRelations) : Dialog()
|
||||
@Immutable
|
||||
data class State(
|
||||
val searchQuery: String? = null,
|
||||
val list: List<AnimeHistoryUiModel>? = null,
|
||||
val dialog: Dialog? = null,
|
||||
)
|
||||
|
||||
sealed interface Dialog {
|
||||
data object DeleteAll : Dialog
|
||||
data class Delete(val history: AnimeHistoryWithRelations) : Dialog
|
||||
}
|
||||
|
||||
sealed class Event {
|
||||
data class OpenEpisode(val episode: Episode?) : Event()
|
||||
data object InternalError : Event()
|
||||
data object HistoryCleared : Event()
|
||||
sealed interface Event {
|
||||
data class OpenEpisode(val episode: Episode?) : Event
|
||||
data object InternalError : Event
|
||||
data object HistoryCleared : Event
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
data class AnimeHistoryState(
|
||||
val list: List<AnimeHistoryUiModel>? = null,
|
||||
val dialog: AnimeHistoryScreenModel.Dialog? = null,
|
||||
)
|
||||
|
|
|
@ -37,7 +37,7 @@ class MangaHistoryScreenModel(
|
|||
private val getHistory: GetMangaHistory = Injekt.get(),
|
||||
private val getNextChapters: GetNextChapters = Injekt.get(),
|
||||
private val removeHistory: RemoveMangaHistory = Injekt.get(),
|
||||
) : StateScreenModel<HistoryState>(HistoryState()) {
|
||||
) : StateScreenModel<MangaHistoryScreenModel.State>(State()) {
|
||||
|
||||
private val _events: Channel<Event> = Channel(Channel.UNLIMITED)
|
||||
val events: Flow<Event> = _events.receiveAsFlow()
|
||||
|
@ -119,20 +119,21 @@ class MangaHistoryScreenModel(
|
|||
mutableState.update { it.copy(dialog = dialog) }
|
||||
}
|
||||
|
||||
sealed class Dialog {
|
||||
data object DeleteAll : Dialog()
|
||||
data class Delete(val history: MangaHistoryWithRelations) : Dialog()
|
||||
@Immutable
|
||||
data class State(
|
||||
val searchQuery: String? = null,
|
||||
val list: List<MangaHistoryUiModel>? = null,
|
||||
val dialog: Dialog? = null,
|
||||
)
|
||||
|
||||
sealed interface Dialog {
|
||||
data object DeleteAll : Dialog
|
||||
data class Delete(val history: MangaHistoryWithRelations) : 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 list: List<MangaHistoryUiModel>? = null,
|
||||
val dialog: MangaHistoryScreenModel.Dialog? = null,
|
||||
)
|
||||
|
|
|
@ -336,12 +336,12 @@ object HomeScreen : Screen() {
|
|||
showBottomNavEvent.send(show)
|
||||
}
|
||||
|
||||
sealed class Tab {
|
||||
data class Animelib(val animeIdToOpen: Long? = null) : 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 Animelib(val animeIdToOpen: Long? = null) : 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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -664,10 +664,10 @@ class AnimeLibraryScreenModel(
|
|||
mutableState.update { it.copy(dialog = null) }
|
||||
}
|
||||
|
||||
sealed class Dialog {
|
||||
data object SettingsSheet : Dialog()
|
||||
data class ChangeCategory(val anime: List<Anime>, val initialSelection: List<CheckboxState<Category>>) : Dialog()
|
||||
data class DeleteAnime(val anime: List<Anime>) : Dialog()
|
||||
sealed interface Dialog {
|
||||
data object SettingsSheet : Dialog
|
||||
data class ChangeCategory(val anime: List<Anime>, val initialSelection: List<CheckboxState<Category>>) : Dialog
|
||||
data class DeleteAnime(val anime: List<Anime>) : Dialog
|
||||
}
|
||||
|
||||
@Immutable
|
||||
|
|
|
@ -658,10 +658,10 @@ class MangaLibraryScreenModel(
|
|||
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
|
||||
|
|
|
@ -134,8 +134,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
|
||||
}
|
||||
|
|
|
@ -815,9 +815,9 @@ class ReaderViewModel @JvmOverloads constructor(
|
|||
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
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -907,18 +907,18 @@ class ReaderViewModel @JvmOverloads constructor(
|
|||
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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ class AnimeUpdatesScreenModel(
|
|||
val snackbarHostState: SnackbarHostState = SnackbarHostState(),
|
||||
downloadPreferences: DownloadPreferences = Injekt.get(),
|
||||
uiPreferences: UiPreferences = Injekt.get(),
|
||||
) : StateScreenModel<AnimeUpdatesState>(AnimeUpdatesState()) {
|
||||
) : StateScreenModel<AnimeUpdatesScreenModel.State>(State()) {
|
||||
|
||||
private val _events: Channel<Event> = Channel(Int.MAX_VALUE)
|
||||
val events: Flow<Event> = _events.receiveAsFlow()
|
||||
|
@ -378,47 +378,47 @@ class AnimeUpdatesScreenModel(
|
|||
libraryPreferences.newAnimeUpdatesCount().set(0)
|
||||
}
|
||||
|
||||
sealed class Dialog {
|
||||
data class DeleteConfirmation(val toDelete: List<AnimeUpdatesItem>) : Dialog()
|
||||
data class ShowQualities(val episodeTitle: String, val episodeId: Long, val animeId: Long, val sourceId: Long) : Dialog()
|
||||
}
|
||||
@Immutable
|
||||
data class State(
|
||||
val isLoading: Boolean = true,
|
||||
val items: List<AnimeUpdatesItem> = emptyList(),
|
||||
val dialog: AnimeUpdatesScreenModel.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<AnimeUpdatesUiModel> {
|
||||
val dateFormat by mutableStateOf(UiPreferences.dateFormat(Injekt.get<UiPreferences>().dateFormat().get()))
|
||||
|
||||
@Immutable
|
||||
data class AnimeUpdatesState(
|
||||
val isLoading: Boolean = true,
|
||||
val items: List<AnimeUpdatesItem> = emptyList(),
|
||||
val dialog: AnimeUpdatesScreenModel.Dialog? = null,
|
||||
) {
|
||||
val selected = items.filter { it.selected }
|
||||
val selectionMode = selected.isNotEmpty()
|
||||
|
||||
fun getUiModel(context: Context, relativeTime: Int): List<AnimeUpdatesUiModel> {
|
||||
val dateFormat by mutableStateOf(UiPreferences.dateFormat(Injekt.get<UiPreferences>().dateFormat().get()))
|
||||
|
||||
return items
|
||||
.map { AnimeUpdatesUiModel.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,
|
||||
)
|
||||
AnimeUpdatesUiModel.Header(text)
|
||||
return items
|
||||
.map { AnimeUpdatesUiModel.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,
|
||||
)
|
||||
AnimeUpdatesUiModel.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<AnimeUpdatesItem>) : Dialog
|
||||
data class ShowQualities(val episodeTitle: String, val episodeId: Long, val animeId: Long, val sourceId: Long) : Dialog
|
||||
}
|
||||
|
||||
sealed interface Event {
|
||||
data object InternalError : Event
|
||||
data class LibraryUpdateTriggered(val started: Boolean) : Event
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ class MangaUpdatesScreenModel(
|
|||
private val libraryPreferences: LibraryPreferences = Injekt.get(),
|
||||
val snackbarHostState: SnackbarHostState = SnackbarHostState(),
|
||||
uiPreferences: UiPreferences = Injekt.get(),
|
||||
) : StateScreenModel<UpdatesState>(UpdatesState()) {
|
||||
) : StateScreenModel<MangaUpdatesScreenModel.State>(State()) {
|
||||
|
||||
private val _events: Channel<Event> = Channel(Int.MAX_VALUE)
|
||||
val events: Flow<Event> = _events.receiveAsFlow()
|
||||
|
@ -366,46 +366,46 @@ class MangaUpdatesScreenModel(
|
|||
libraryPreferences.newMangaUpdatesCount().set(0)
|
||||
}
|
||||
|
||||
sealed class Dialog {
|
||||
data class DeleteConfirmation(val toDelete: List<MangaUpdatesItem>) : Dialog()
|
||||
}
|
||||
@Immutable
|
||||
data class State(
|
||||
val isLoading: Boolean = true,
|
||||
val items: List<MangaUpdatesItem> = emptyList(),
|
||||
val dialog: MangaUpdatesScreenModel.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<MangaUpdatesUiModel> {
|
||||
val dateFormat by mutableStateOf(UiPreferences.dateFormat(Injekt.get<UiPreferences>().dateFormat().get()))
|
||||
|
||||
@Immutable
|
||||
data class UpdatesState(
|
||||
val isLoading: Boolean = true,
|
||||
val items: List<MangaUpdatesItem> = emptyList(),
|
||||
val dialog: MangaUpdatesScreenModel.Dialog? = null,
|
||||
) {
|
||||
val selected = items.filter { it.selected }
|
||||
val selectionMode = selected.isNotEmpty()
|
||||
|
||||
fun getUiModel(context: Context, relativeTime: Int): List<MangaUpdatesUiModel> {
|
||||
val dateFormat by mutableStateOf(UiPreferences.dateFormat(Injekt.get<UiPreferences>().dateFormat().get()))
|
||||
|
||||
return items
|
||||
.map { MangaUpdatesUiModel.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,
|
||||
)
|
||||
MangaUpdatesUiModel.Header(text)
|
||||
return items
|
||||
.map { MangaUpdatesUiModel.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,
|
||||
)
|
||||
MangaUpdatesUiModel.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<MangaUpdatesItem>) : Dialog
|
||||
}
|
||||
|
||||
sealed interface Event {
|
||||
data object InternalError : Event
|
||||
data class LibraryUpdateTriggered(val started: Boolean) : Event
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,8 +38,8 @@ class CreateAnimeCategoryWithName(
|
|||
}
|
||||
}
|
||||
|
||||
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 DeleteAnimeCategory(
|
|||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ class HideAnimeCategory(
|
|||
}
|
||||
|
||||
sealed class Result {
|
||||
object Success : Result()
|
||||
data object Success : Result()
|
||||
data class InternalError(val error: Throwable) : Result()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,8 +28,8 @@ class RenameAnimeCategory(
|
|||
|
||||
suspend fun await(category: Category, name: String) = await(category.id, name)
|
||||
|
||||
sealed class Result {
|
||||
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 ReorderAnimeCategory(
|
|||
}
|
||||
}
|
||||
|
||||
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 UpdateAnimeCategory(
|
|||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,8 +38,8 @@ class CreateMangaCategoryWithName(
|
|||
}
|
||||
}
|
||||
|
||||
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 DeleteMangaCategory(
|
|||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue