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