diff --git a/.github/workflows/lock.yml b/.github/workflows/lock.yml index a86486b92..869c1140a 100644 --- a/.github/workflows/lock.yml +++ b/.github/workflows/lock.yml @@ -12,7 +12,7 @@ jobs: lock: runs-on: ubuntu-latest steps: - - uses: dessant/lock-threads@v4 + - uses: dessant/lock-threads@v5 with: github-token: ${{ github.token }} issue-inactive-days: '2' diff --git a/app/build.gradle.kts b/app/build.gradle.kts index c82161ddd..8b39d56ec 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -174,6 +174,7 @@ dependencies { implementation(compose.accompanist.permissions) implementation(compose.accompanist.themeadapter) implementation(compose.accompanist.systemuicontroller) + lintChecks(compose.lintchecks) implementation(androidx.paging.runtime) implementation(androidx.paging.compose) @@ -181,6 +182,7 @@ dependencies { implementation(libs.bundles.sqlite) implementation(kotlinx.reflect) + implementation(kotlinx.immutables) implementation(platform(kotlinx.coroutines.bom)) implementation(kotlinx.bundles.coroutines) diff --git a/app/src/main/java/eu/kanade/presentation/browse/GlobalSearchResultItems.kt b/app/src/main/java/eu/kanade/presentation/browse/GlobalSearchResultItems.kt index f00605983..3f61d0c3b 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/GlobalSearchResultItems.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/GlobalSearchResultItems.kt @@ -11,6 +11,7 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.outlined.ArrowForward import androidx.compose.material.icons.outlined.ArrowForward import androidx.compose.material.icons.outlined.Error import androidx.compose.material3.CircularProgressIndicator @@ -54,7 +55,7 @@ fun GlobalSearchResultItem( Text(text = subtitle) } IconButton(onClick = onClick) { - Icon(imageVector = Icons.Outlined.ArrowForward, contentDescription = null) + Icon(imageVector = Icons.AutoMirrored.Outlined.ArrowForward, contentDescription = null) } } content() diff --git a/app/src/main/java/eu/kanade/presentation/browse/anime/AnimeExtensionDetailsScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/anime/AnimeExtensionDetailsScreen.kt index 9a446ad7e..428326e2c 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/anime/AnimeExtensionDetailsScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/anime/AnimeExtensionDetailsScreen.kt @@ -16,6 +16,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.items import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.outlined.HelpOutline import androidx.compose.material.icons.outlined.HelpOutline import androidx.compose.material.icons.outlined.History import androidx.compose.material.icons.outlined.Settings @@ -54,6 +55,7 @@ import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource import eu.kanade.tachiyomi.extension.anime.model.AnimeExtension import eu.kanade.tachiyomi.ui.browse.anime.extension.details.AnimeExtensionDetailsScreenModel import eu.kanade.tachiyomi.util.system.LocaleHelper +import kotlinx.collections.immutable.persistentListOf import tachiyomi.presentation.core.components.ScrollbarLazyColumn import tachiyomi.presentation.core.components.material.Scaffold import tachiyomi.presentation.core.components.material.padding @@ -79,40 +81,42 @@ fun AnimeExtensionDetailsScreen( navigateUp = navigateUp, actions = { AppBarActions( - actions = buildList { - if (state.extension?.isUnofficial == false) { - add( - AppBar.Action( - title = stringResource(R.string.whats_new), - icon = Icons.Outlined.History, - onClick = onClickWhatsNew, - ), - ) - add( - AppBar.Action( - title = stringResource(R.string.action_faq_and_guides), - icon = Icons.Outlined.HelpOutline, - onClick = onClickReadme, + actions = persistentListOf().builder() + .apply { + if (state.extension?.isUnofficial == false) { + add( + AppBar.Action( + title = stringResource(R.string.whats_new), + icon = Icons.Outlined.History, + onClick = onClickWhatsNew, + ), + ) + add( + AppBar.Action( + title = stringResource(R.string.action_faq_and_guides), + icon = Icons.AutoMirrored.Outlined.HelpOutline, + onClick = onClickReadme, + ), + ) + } + addAll( + listOf( + AppBar.OverflowAction( + title = stringResource(R.string.action_enable_all), + onClick = onClickEnableAll, + ), + AppBar.OverflowAction( + title = stringResource(R.string.action_disable_all), + onClick = onClickDisableAll, + ), + AppBar.OverflowAction( + title = stringResource(R.string.pref_clear_cookies), + onClick = onClickClearCookies, + ), ), ) } - addAll( - listOf( - AppBar.OverflowAction( - title = stringResource(R.string.action_enable_all), - onClick = onClickEnableAll, - ), - AppBar.OverflowAction( - title = stringResource(R.string.action_disable_all), - onClick = onClickDisableAll, - ), - AppBar.OverflowAction( - title = stringResource(R.string.pref_clear_cookies), - onClick = onClickClearCookies, - ), - ), - ) - }, + .build(), ) }, scrollBehavior = scrollBehavior, @@ -186,7 +190,6 @@ private fun AnimeExtensionDetails( key = { it.source.id }, ) { source -> SourceSwitchPreference( - modifier = Modifier.animateItemPlacement(), source = source, onClickSourcePreferences = onClickSourcePreferences, onClickSource = onClickSource, @@ -321,10 +324,10 @@ private fun DetailsHeader( @Composable private fun InfoText( - modifier: Modifier, primaryText: String, - primaryTextStyle: TextStyle = MaterialTheme.typography.bodyLarge, secondaryText: String, + modifier: Modifier = Modifier, + primaryTextStyle: TextStyle = MaterialTheme.typography.bodyLarge, onClick: (() -> Unit)? = null, ) { val interactionSource = remember { MutableInteractionSource() } @@ -364,10 +367,10 @@ private fun InfoDivider() { @Composable private fun SourceSwitchPreference( - modifier: Modifier = Modifier, source: AnimeExtensionSourceItem, onClickSourcePreferences: (sourceId: Long) -> Unit, onClickSource: (sourceId: Long) -> Unit, + modifier: Modifier = Modifier, ) { val context = LocalContext.current diff --git a/app/src/main/java/eu/kanade/presentation/browse/anime/AnimeExtensionFilterScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/anime/AnimeExtensionFilterScreen.kt index ec8eac285..51c9d7d85 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/anime/AnimeExtensionFilterScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/anime/AnimeExtensionFilterScreen.kt @@ -58,7 +58,6 @@ private fun AnimeExtensionFilterContent( ) { items(state.languages) { language -> SwitchPreferenceWidget( - modifier = Modifier.animateItemPlacement(), title = LocaleHelper.getSourceDisplayName(language, context), checked = language in state.enabledLanguages, onCheckedChanged = { onClickLang(language) }, diff --git a/app/src/main/java/eu/kanade/presentation/browse/anime/AnimeExtensionsScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/anime/AnimeExtensionsScreen.kt index 77498b3fd..45097800a 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/anime/AnimeExtensionsScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/anime/AnimeExtensionsScreen.kt @@ -147,14 +147,13 @@ private fun AnimeExtensionContent( } ExtensionHeader( textRes = header.textRes, - modifier = Modifier.animateItemPlacement(), action = action, ) } is AnimeExtensionUiModel.Header.Text -> { ExtensionHeader( text = header.text, - modifier = Modifier.animateItemPlacement(), + ) } } @@ -166,7 +165,7 @@ private fun AnimeExtensionContent( key = { "extension-${it.hashCode()}" }, ) { item -> AnimeExtensionItem( - modifier = Modifier.animateItemPlacement(), + item = item, onClickItem = { when (it) { @@ -216,12 +215,12 @@ private fun AnimeExtensionContent( @Composable private fun AnimeExtensionItem( - modifier: Modifier = Modifier, item: AnimeExtensionUiModel.Item, onClickItem: (AnimeExtension) -> Unit, onLongClickItem: (AnimeExtension) -> Unit, onClickItemCancel: (AnimeExtension) -> Unit, onClickItemAction: (AnimeExtension) -> Unit, + modifier: Modifier = Modifier, ) { val (extension, installStep) = item BaseBrowseItem( diff --git a/app/src/main/java/eu/kanade/presentation/browse/anime/AnimeSourcesFilterScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/anime/AnimeSourcesFilterScreen.kt index bc911027d..d995f941c 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/anime/AnimeSourcesFilterScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/anime/AnimeSourcesFilterScreen.kt @@ -68,7 +68,7 @@ private fun AnimeSourcesFilterContent( contentType = "source-filter-header", ) { AnimeSourcesFilterHeader( - modifier = Modifier.animateItemPlacement(), + language = language, enabled = enabled, onClickItem = onClickLanguage, @@ -81,7 +81,7 @@ private fun AnimeSourcesFilterContent( contentType = { "source-filter-item" }, ) { source -> AnimeSourcesFilterItem( - modifier = Modifier.animateItemPlacement(), + source = source, isEnabled = "${source.id}" !in state.disabledSources, onClickItem = onClickSource, @@ -94,10 +94,10 @@ private fun AnimeSourcesFilterContent( @Composable fun AnimeSourcesFilterHeader( - modifier: Modifier, language: String, enabled: Boolean, onClickItem: (String) -> Unit, + modifier: Modifier = Modifier, ) { SwitchPreferenceWidget( modifier = modifier, @@ -109,10 +109,10 @@ fun AnimeSourcesFilterHeader( @Composable private fun AnimeSourcesFilterItem( - modifier: Modifier, source: AnimeSource, isEnabled: Boolean, onClickItem: (AnimeSource) -> Unit, + modifier: Modifier = Modifier, ) { BaseAnimeSourceItem( modifier = modifier, diff --git a/app/src/main/java/eu/kanade/presentation/browse/anime/AnimeSourcesScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/anime/AnimeSourcesScreen.kt index bb9d82081..5748f2621 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/anime/AnimeSourcesScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/anime/AnimeSourcesScreen.kt @@ -74,12 +74,12 @@ fun AnimeSourcesScreen( when (model) { is AnimeSourceUiModel.Header -> { AnimeSourceHeader( - modifier = Modifier.animateItemPlacement(), + language = model.language, ) } is AnimeSourceUiModel.Item -> AnimeSourceItem( - modifier = Modifier.animateItemPlacement(), + source = model.source, onClickItem = onClickItem, onLongClickItem = onLongClickItem, @@ -94,8 +94,8 @@ fun AnimeSourcesScreen( @Composable private fun AnimeSourceHeader( - modifier: Modifier = Modifier, language: String, + modifier: Modifier = Modifier, ) { val context = LocalContext.current Text( @@ -111,11 +111,11 @@ private fun AnimeSourceHeader( @Composable private fun AnimeSourceItem( - modifier: Modifier = Modifier, source: AnimeSource, onClickItem: (AnimeSource, Listing) -> Unit, onLongClickItem: (AnimeSource) -> Unit, onClickPin: (AnimeSource) -> Unit, + modifier: Modifier = Modifier, ) { BaseAnimeSourceItem( modifier = modifier, diff --git a/app/src/main/java/eu/kanade/presentation/browse/anime/BrowseAnimeSourceScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/anime/BrowseAnimeSourceScreen.kt index 0e844d434..1e9351b40 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/anime/BrowseAnimeSourceScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/anime/BrowseAnimeSourceScreen.kt @@ -4,6 +4,7 @@ import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.outlined.HelpOutline import androidx.compose.material.icons.outlined.HelpOutline import androidx.compose.material.icons.outlined.Public import androidx.compose.material.icons.outlined.Refresh @@ -24,6 +25,7 @@ import eu.kanade.presentation.components.AppBar import eu.kanade.presentation.util.formattedMessage import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.animesource.AnimeSource +import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.flow.StateFlow import tachiyomi.domain.entries.anime.model.Anime import tachiyomi.domain.library.model.LibraryDisplayMode @@ -76,15 +78,15 @@ fun BrowseAnimeSourceContent( modifier = Modifier.padding(contentPadding), message = getErrorMessage(errorState), actions = if (source is LocalAnimeSource) { - listOf( + persistentListOf( EmptyScreenAction( stringResId = R.string.local_source_help_guide, - icon = Icons.Outlined.HelpOutline, + icon = Icons.AutoMirrored.Outlined.HelpOutline, onClick = onLocalAnimeSourceHelpClick, ), ) } else { - listOf( + persistentListOf( EmptyScreenAction( stringResId = R.string.action_retry, icon = Icons.Outlined.Refresh, @@ -97,7 +99,7 @@ fun BrowseAnimeSourceContent( ), EmptyScreenAction( stringResId = R.string.label_help, - icon = Icons.Outlined.HelpOutline, + icon = Icons.AutoMirrored.Outlined.HelpOutline, onClick = onHelpClick, ), ) @@ -145,7 +147,7 @@ fun BrowseAnimeSourceContent( } @Composable -fun MissingSourceScreen( +internal fun MissingSourceScreen( source: StubAnimeSource, navigateUp: () -> Unit, ) { diff --git a/app/src/main/java/eu/kanade/presentation/browse/anime/GlobalAnimeSearchScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/anime/GlobalAnimeSearchScreen.kt index ed64044f4..0b48e11f8 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/anime/GlobalAnimeSearchScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/anime/GlobalAnimeSearchScreen.kt @@ -60,13 +60,13 @@ fun GlobalAnimeSearchScreen( @Composable internal fun GlobalSearchContent( - fromSourceId: Long? = null, items: Map, contentPadding: PaddingValues, getAnime: @Composable (Anime) -> State, onClickSource: (AnimeCatalogueSource) -> Unit, onClickItem: (Anime) -> Unit, onLongClickItem: (Anime) -> Unit, + fromSourceId: Long? = null, ) { LazyColumn( contentPadding = contentPadding, diff --git a/app/src/main/java/eu/kanade/presentation/browse/anime/MigrateAnimeScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/anime/MigrateAnimeScreen.kt index c2e5de943..d71a6144e 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/anime/MigrateAnimeScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/anime/MigrateAnimeScreen.kt @@ -70,10 +70,10 @@ private fun MigrateAnimeContent( @Composable private fun MigrateAnimeItem( - modifier: Modifier = Modifier, anime: Anime, onClickItem: (Anime) -> Unit, onClickCover: (Anime) -> Unit, + modifier: Modifier = Modifier, ) { BaseAnimeListItem( modifier = modifier, diff --git a/app/src/main/java/eu/kanade/presentation/browse/anime/MigrateAnimeSourceScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/anime/MigrateAnimeSourceScreen.kt index fc77766b1..f9612d294 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/anime/MigrateAnimeSourceScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/anime/MigrateAnimeSourceScreen.kt @@ -132,7 +132,7 @@ private fun MigrateAnimeSourceList( key = { (source, _) -> "migrate-${source.id}" }, ) { (source, count) -> MigrateAnimeSourceItem( - modifier = Modifier.animateItemPlacement(), + source = source, count = count, onClickItem = { onClickItem(source) }, @@ -144,11 +144,11 @@ private fun MigrateAnimeSourceList( @Composable private fun MigrateAnimeSourceItem( - modifier: Modifier = Modifier, source: AnimeSource, count: Long, onClickItem: () -> Unit, onLongClickItem: () -> Unit, + modifier: Modifier = Modifier, ) { BaseAnimeSourceItem( modifier = modifier, diff --git a/app/src/main/java/eu/kanade/presentation/browse/anime/components/BaseAnimeSourceItem.kt b/app/src/main/java/eu/kanade/presentation/browse/anime/components/BaseAnimeSourceItem.kt index 5cc886fc3..1008fc0c9 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/anime/components/BaseAnimeSourceItem.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/anime/components/BaseAnimeSourceItem.kt @@ -17,8 +17,8 @@ import tachiyomi.presentation.core.util.secondaryItemAlpha @Composable fun BaseAnimeSourceItem( - modifier: Modifier = Modifier, source: AnimeSource, + modifier: Modifier = Modifier, showLanguageInContent: Boolean = true, onClickItem: () -> Unit = {}, onLongClickItem: () -> Unit = {}, diff --git a/app/src/main/java/eu/kanade/presentation/browse/anime/components/BrowseAnimeSourceToolbar.kt b/app/src/main/java/eu/kanade/presentation/browse/anime/components/BrowseAnimeSourceToolbar.kt index d588babb4..887c482c8 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/anime/components/BrowseAnimeSourceToolbar.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/anime/components/BrowseAnimeSourceToolbar.kt @@ -1,6 +1,7 @@ package eu.kanade.presentation.browse.anime.components import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ViewList import androidx.compose.material.icons.filled.ViewList import androidx.compose.material.icons.filled.ViewModule import androidx.compose.material3.Text @@ -20,6 +21,7 @@ import eu.kanade.presentation.components.SearchToolbar import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.animesource.AnimeSource import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource +import kotlinx.collections.immutable.persistentListOf import tachiyomi.domain.library.model.LibraryDisplayMode import tachiyomi.source.local.entries.anime.LocalAnimeSource @@ -53,32 +55,44 @@ fun BrowseAnimeSourceToolbar( onClickCloseSearch = navigateUp, actions = { AppBarActions( - actions = listOfNotNull( - AppBar.Action( - title = stringResource(R.string.action_display_mode), - icon = if (displayMode == LibraryDisplayMode.List) { - Icons.Filled.ViewList + actions = persistentListOf().builder() + .apply { + add( + AppBar.Action( + title = stringResource(R.string.action_display_mode), + icon = if (displayMode == LibraryDisplayMode.List) { + Icons.AutoMirrored.Filled.ViewList + } else { + Icons.Filled.ViewModule + }, + onClick = { selectingDisplayMode = true }, + ), + ) + if (isLocalSource) { + add( + AppBar.OverflowAction( + title = stringResource(R.string.label_help), + onClick = onHelpClick, + ), + ) } else { - Icons.Filled.ViewModule - }, - onClick = { selectingDisplayMode = true }, - ), - if (isLocalSource) { - AppBar.OverflowAction( - title = stringResource(R.string.label_help), - onClick = onHelpClick, - ) - } else { - AppBar.OverflowAction( - title = stringResource(R.string.action_open_in_web_view), - onClick = onWebViewClick, - ) - }, - AppBar.OverflowAction( - title = stringResource(R.string.action_settings), - onClick = onSettingsClick, - ).takeIf { isConfigurableSource }, - ), + add( + AppBar.OverflowAction( + title = stringResource(R.string.action_open_in_web_view), + onClick = onWebViewClick, + ), + ) + } + if (isConfigurableSource) { + add( + AppBar.OverflowAction( + title = stringResource(R.string.action_settings), + onClick = onSettingsClick, + ), + ) + } + } + .build(), ) DropdownMenu( diff --git a/app/src/main/java/eu/kanade/presentation/browse/anime/components/GlobalAnimeSearchToolbar.kt b/app/src/main/java/eu/kanade/presentation/browse/anime/components/GlobalAnimeSearchToolbar.kt index da5d66404..fdfc5c987 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/anime/components/GlobalAnimeSearchToolbar.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/anime/components/GlobalAnimeSearchToolbar.kt @@ -58,7 +58,7 @@ fun GlobalAnimeSearchToolbar( ) if (progress in 1.. Unit, ) { diff --git a/app/src/main/java/eu/kanade/presentation/browse/manga/GlobalMangaSearchScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/manga/GlobalMangaSearchScreen.kt index c27856b0e..4cca90355 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/manga/GlobalMangaSearchScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/manga/GlobalMangaSearchScreen.kt @@ -60,13 +60,13 @@ fun GlobalMangaSearchScreen( @Composable internal fun GlobalSearchContent( - fromSourceId: Long? = null, items: Map, contentPadding: PaddingValues, getManga: @Composable (Manga) -> State, onClickSource: (CatalogueSource) -> Unit, onClickItem: (Manga) -> Unit, onLongClickItem: (Manga) -> Unit, + fromSourceId: Long? = null, ) { LazyColumn( contentPadding = contentPadding, diff --git a/app/src/main/java/eu/kanade/presentation/browse/manga/MangaExtensionDetailsScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/manga/MangaExtensionDetailsScreen.kt index 9bd22b61d..567663cfb 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/manga/MangaExtensionDetailsScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/manga/MangaExtensionDetailsScreen.kt @@ -16,6 +16,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.items import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.outlined.HelpOutline import androidx.compose.material.icons.outlined.HelpOutline import androidx.compose.material.icons.outlined.History import androidx.compose.material.icons.outlined.Settings @@ -55,6 +56,7 @@ import eu.kanade.tachiyomi.extension.manga.model.MangaExtension import eu.kanade.tachiyomi.source.ConfigurableSource import eu.kanade.tachiyomi.ui.browse.manga.extension.details.MangaExtensionDetailsScreenModel import eu.kanade.tachiyomi.util.system.LocaleHelper +import kotlinx.collections.immutable.persistentListOf import tachiyomi.presentation.core.components.ScrollbarLazyColumn import tachiyomi.presentation.core.components.material.Scaffold import tachiyomi.presentation.core.components.material.padding @@ -80,40 +82,42 @@ fun ExtensionDetailsScreen( navigateUp = navigateUp, actions = { AppBarActions( - actions = buildList { - if (state.extension?.isUnofficial == false) { - add( - AppBar.Action( - title = stringResource(R.string.whats_new), - icon = Icons.Outlined.History, - onClick = onClickWhatsNew, - ), - ) - add( - AppBar.Action( - title = stringResource(R.string.action_faq_and_guides), - icon = Icons.Outlined.HelpOutline, - onClick = onClickReadme, + actions = persistentListOf().builder() + .apply { + if (state.extension?.isUnofficial == false) { + add( + AppBar.Action( + title = stringResource(R.string.whats_new), + icon = Icons.Outlined.History, + onClick = onClickWhatsNew, + ), + ) + add( + AppBar.Action( + title = stringResource(R.string.action_faq_and_guides), + icon = Icons.AutoMirrored.Outlined.HelpOutline, + onClick = onClickReadme, + ), + ) + } + addAll( + listOf( + AppBar.OverflowAction( + title = stringResource(R.string.action_enable_all), + onClick = onClickEnableAll, + ), + AppBar.OverflowAction( + title = stringResource(R.string.action_disable_all), + onClick = onClickDisableAll, + ), + AppBar.OverflowAction( + title = stringResource(R.string.pref_clear_cookies), + onClick = onClickClearCookies, + ), ), ) } - addAll( - listOf( - AppBar.OverflowAction( - title = stringResource(R.string.action_enable_all), - onClick = onClickEnableAll, - ), - AppBar.OverflowAction( - title = stringResource(R.string.action_disable_all), - onClick = onClickDisableAll, - ), - AppBar.OverflowAction( - title = stringResource(R.string.pref_clear_cookies), - onClick = onClickClearCookies, - ), - ), - ) - }, + .build(), ) }, scrollBehavior = scrollBehavior, @@ -187,7 +191,7 @@ private fun ExtensionDetails( key = { it.source.id }, ) { source -> SourceSwitchPreference( - modifier = Modifier.animateItemPlacement(), + source = source, onClickSourcePreferences = onClickSourcePreferences, onClickSource = onClickSource, @@ -320,10 +324,10 @@ private fun DetailsHeader( @Composable private fun InfoText( - modifier: Modifier, primaryText: String, - primaryTextStyle: TextStyle = MaterialTheme.typography.bodyLarge, secondaryText: String, + modifier: Modifier = Modifier, + primaryTextStyle: TextStyle = MaterialTheme.typography.bodyLarge, onClick: (() -> Unit)? = null, ) { val interactionSource = remember { MutableInteractionSource() } @@ -363,10 +367,10 @@ private fun InfoDivider() { @Composable private fun SourceSwitchPreference( - modifier: Modifier = Modifier, source: MangaExtensionSourceItem, onClickSourcePreferences: (sourceId: Long) -> Unit, onClickSource: (sourceId: Long) -> Unit, + modifier: Modifier = Modifier, ) { val context = LocalContext.current diff --git a/app/src/main/java/eu/kanade/presentation/browse/manga/MangaExtensionFilterScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/manga/MangaExtensionFilterScreen.kt index 875aaa2a7..500b71aa5 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/manga/MangaExtensionFilterScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/manga/MangaExtensionFilterScreen.kt @@ -58,7 +58,7 @@ private fun ExtensionFilterContent( ) { items(state.languages) { language -> SwitchPreferenceWidget( - modifier = Modifier.animateItemPlacement(), + title = LocaleHelper.getSourceDisplayName(language, context), checked = language in state.enabledLanguages, onCheckedChanged = { onClickLang(language) }, diff --git a/app/src/main/java/eu/kanade/presentation/browse/manga/MangaExtensionsScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/manga/MangaExtensionsScreen.kt index 10f142613..bebc75b91 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/manga/MangaExtensionsScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/manga/MangaExtensionsScreen.kt @@ -148,14 +148,14 @@ private fun ExtensionContent( } ExtensionHeader( textRes = header.textRes, - modifier = Modifier.animateItemPlacement(), + action = action, ) } is MangaExtensionUiModel.Header.Text -> { ExtensionHeader( text = header.text, - modifier = Modifier.animateItemPlacement(), + ) } } @@ -167,7 +167,7 @@ private fun ExtensionContent( key = { "extension-${it.hashCode()}" }, ) { item -> ExtensionItem( - modifier = Modifier.animateItemPlacement(), + item = item, onClickItem = { when (it) { @@ -217,12 +217,12 @@ private fun ExtensionContent( @Composable private fun ExtensionItem( - modifier: Modifier = Modifier, item: MangaExtensionUiModel.Item, onClickItem: (MangaExtension) -> Unit, onLongClickItem: (MangaExtension) -> Unit, onClickItemCancel: (MangaExtension) -> Unit, onClickItemAction: (MangaExtension) -> Unit, + modifier: Modifier = Modifier, ) { val (extension, installStep) = item BaseBrowseItem( diff --git a/app/src/main/java/eu/kanade/presentation/browse/manga/MangaSourcesFilterScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/manga/MangaSourcesFilterScreen.kt index d2c75d5cd..596c56106 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/manga/MangaSourcesFilterScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/manga/MangaSourcesFilterScreen.kt @@ -68,7 +68,7 @@ private fun SourcesFilterContent( contentType = "source-filter-header", ) { SourcesFilterHeader( - modifier = Modifier.animateItemPlacement(), + language = language, enabled = enabled, onClickItem = onClickLanguage, @@ -81,7 +81,7 @@ private fun SourcesFilterContent( contentType = { "source-filter-item" }, ) { source -> SourcesFilterItem( - modifier = Modifier.animateItemPlacement(), + source = source, enabled = "${source.id}" !in state.disabledSources, onClickItem = onClickSource, @@ -94,10 +94,11 @@ private fun SourcesFilterContent( @Composable private fun SourcesFilterHeader( - modifier: Modifier, language: String, enabled: Boolean, onClickItem: (String) -> Unit, + modifier: Modifier = Modifier, + ) { SwitchPreferenceWidget( modifier = modifier, @@ -109,10 +110,10 @@ private fun SourcesFilterHeader( @Composable private fun SourcesFilterItem( - modifier: Modifier, source: Source, enabled: Boolean, onClickItem: (Source) -> Unit, + modifier: Modifier = Modifier, ) { BaseMangaSourceItem( modifier = modifier, diff --git a/app/src/main/java/eu/kanade/presentation/browse/manga/MangaSourcesScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/manga/MangaSourcesScreen.kt index f23d6ed46..4661fccc2 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/manga/MangaSourcesScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/manga/MangaSourcesScreen.kt @@ -74,12 +74,12 @@ fun MangaSourcesScreen( when (model) { is MangaSourceUiModel.Header -> { SourceHeader( - modifier = Modifier.animateItemPlacement(), + language = model.language, ) } is MangaSourceUiModel.Item -> SourceItem( - modifier = Modifier.animateItemPlacement(), + source = model.source, onClickItem = onClickItem, onLongClickItem = onLongClickItem, @@ -94,8 +94,8 @@ fun MangaSourcesScreen( @Composable private fun SourceHeader( - modifier: Modifier = Modifier, language: String, + modifier: Modifier = Modifier, ) { val context = LocalContext.current Text( @@ -111,11 +111,11 @@ private fun SourceHeader( @Composable private fun SourceItem( - modifier: Modifier = Modifier, source: Source, onClickItem: (Source, Listing) -> Unit, onLongClickItem: (Source) -> Unit, onClickPin: (Source) -> Unit, + modifier: Modifier = Modifier, ) { BaseMangaSourceItem( modifier = modifier, diff --git a/app/src/main/java/eu/kanade/presentation/browse/manga/MigrateMangaScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/manga/MigrateMangaScreen.kt index dd2d5faa7..e332d0b5d 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/manga/MigrateMangaScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/manga/MigrateMangaScreen.kt @@ -70,10 +70,10 @@ private fun MigrateMangaContent( @Composable private fun MigrateMangaItem( - modifier: Modifier = Modifier, manga: Manga, onClickItem: (Manga) -> Unit, onClickCover: (Manga) -> Unit, + modifier: Modifier = Modifier, ) { BaseMangaListItem( modifier = modifier, diff --git a/app/src/main/java/eu/kanade/presentation/browse/manga/MigrateMangaSourceScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/manga/MigrateMangaSourceScreen.kt index a150d8729..02f122e77 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/manga/MigrateMangaSourceScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/manga/MigrateMangaSourceScreen.kt @@ -132,7 +132,7 @@ private fun MigrateSourceList( key = { (source, _) -> "migrate-${source.id}" }, ) { (source, count) -> MigrateSourceItem( - modifier = Modifier.animateItemPlacement(), + source = source, count = count, onClickItem = { onClickItem(source) }, @@ -144,11 +144,11 @@ private fun MigrateSourceList( @Composable private fun MigrateSourceItem( - modifier: Modifier = Modifier, source: Source, count: Long, onClickItem: () -> Unit, onLongClickItem: () -> Unit, + modifier: Modifier = Modifier, ) { BaseMangaSourceItem( modifier = modifier, diff --git a/app/src/main/java/eu/kanade/presentation/browse/manga/components/BaseMangaSourceItem.kt b/app/src/main/java/eu/kanade/presentation/browse/manga/components/BaseMangaSourceItem.kt index 247e19f45..c5bcf1eae 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/manga/components/BaseMangaSourceItem.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/manga/components/BaseMangaSourceItem.kt @@ -17,8 +17,8 @@ import tachiyomi.presentation.core.util.secondaryItemAlpha @Composable fun BaseMangaSourceItem( - modifier: Modifier = Modifier, source: Source, + modifier: Modifier = Modifier, showLanguageInContent: Boolean = true, onClickItem: () -> Unit = {}, onLongClickItem: () -> Unit = {}, diff --git a/app/src/main/java/eu/kanade/presentation/browse/manga/components/BrowseMangaSourceToolbar.kt b/app/src/main/java/eu/kanade/presentation/browse/manga/components/BrowseMangaSourceToolbar.kt index a55ac164d..dc5b390ed 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/manga/components/BrowseMangaSourceToolbar.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/manga/components/BrowseMangaSourceToolbar.kt @@ -1,6 +1,7 @@ package eu.kanade.presentation.browse.manga.components import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ViewList import androidx.compose.material.icons.filled.ViewList import androidx.compose.material.icons.filled.ViewModule import androidx.compose.material3.Text @@ -20,6 +21,7 @@ import eu.kanade.presentation.components.SearchToolbar import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.source.ConfigurableSource import eu.kanade.tachiyomi.source.MangaSource +import kotlinx.collections.immutable.persistentListOf import tachiyomi.domain.library.model.LibraryDisplayMode import tachiyomi.source.local.entries.manga.LocalMangaSource @@ -53,32 +55,44 @@ fun BrowseMangaSourceToolbar( onClickCloseSearch = navigateUp, actions = { AppBarActions( - actions = listOfNotNull( - AppBar.Action( - title = stringResource(R.string.action_display_mode), - icon = if (displayMode == LibraryDisplayMode.List) { - Icons.Filled.ViewList + actions = persistentListOf().builder() + .apply { + add( + AppBar.Action( + title = stringResource(R.string.action_display_mode), + icon = if (displayMode == LibraryDisplayMode.List) { + Icons.AutoMirrored.Filled.ViewList + } else { + Icons.Filled.ViewModule + }, + onClick = { selectingDisplayMode = true }, + ), + ) + if (isLocalSource) { + add( + AppBar.OverflowAction( + title = stringResource(R.string.label_help), + onClick = onHelpClick, + ), + ) } else { - Icons.Filled.ViewModule - }, - onClick = { selectingDisplayMode = true }, - ), - if (isLocalSource) { - AppBar.OverflowAction( - title = stringResource(R.string.label_help), - onClick = onHelpClick, - ) - } else { - AppBar.OverflowAction( - title = stringResource(R.string.action_open_in_web_view), - onClick = onWebViewClick, - ) - }, - AppBar.OverflowAction( - title = stringResource(R.string.action_settings), - onClick = onSettingsClick, - ).takeIf { isConfigurableSource }, - ), + add( + AppBar.OverflowAction( + title = stringResource(R.string.action_open_in_web_view), + onClick = onWebViewClick, + ), + ) + } + if (isConfigurableSource) { + add( + AppBar.OverflowAction( + title = stringResource(R.string.action_settings), + onClick = onSettingsClick, + ), + ) + } + } + .build(), ) DropdownMenu( diff --git a/app/src/main/java/eu/kanade/presentation/category/components/CategoryContent.kt b/app/src/main/java/eu/kanade/presentation/category/components/CategoryContent.kt index 43053e5ef..cd8855a2a 100644 --- a/app/src/main/java/eu/kanade/presentation/category/components/CategoryContent.kt +++ b/app/src/main/java/eu/kanade/presentation/category/components/CategoryContent.kt @@ -7,7 +7,6 @@ import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier import tachiyomi.domain.category.model.Category import tachiyomi.presentation.core.components.material.padding @@ -32,7 +31,7 @@ fun CategoryContent( key = { _, category -> "category-${category.id}" }, ) { index, category -> CategoryListItem( - modifier = Modifier.animateItemPlacement(), + category = category, canMoveUp = index != 0, canMoveDown = index != categories.lastIndex, diff --git a/app/src/main/java/eu/kanade/presentation/category/components/CategoryListItem.kt b/app/src/main/java/eu/kanade/presentation/category/components/CategoryListItem.kt index bbacc9141..2cf8ae448 100644 --- a/app/src/main/java/eu/kanade/presentation/category/components/CategoryListItem.kt +++ b/app/src/main/java/eu/kanade/presentation/category/components/CategoryListItem.kt @@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.outlined.Label import androidx.compose.material.icons.outlined.ArrowDropDown import androidx.compose.material.icons.outlined.ArrowDropUp import androidx.compose.material.icons.outlined.Delete @@ -28,7 +29,6 @@ import tachiyomi.presentation.core.components.material.padding @Composable fun CategoryListItem( - modifier: Modifier = Modifier, category: Category, canMoveUp: Boolean, canMoveDown: Boolean, @@ -37,6 +37,7 @@ fun CategoryListItem( onRename: () -> Unit, onHide: () -> Unit, onDelete: () -> Unit, + modifier: Modifier = Modifier, ) { ElevatedCard( modifier = modifier, @@ -52,7 +53,7 @@ fun CategoryListItem( ), verticalAlignment = Alignment.CenterVertically, ) { - Icon(imageVector = Icons.Outlined.Label, contentDescription = "") + Icon(imageVector = Icons.AutoMirrored.Outlined.Label, contentDescription = "") Text( text = category.name, modifier = Modifier diff --git a/app/src/main/java/eu/kanade/presentation/components/AdaptiveSheet.kt b/app/src/main/java/eu/kanade/presentation/components/AdaptiveSheet.kt index 856d50fe3..0d11854aa 100644 --- a/app/src/main/java/eu/kanade/presentation/components/AdaptiveSheet.kt +++ b/app/src/main/java/eu/kanade/presentation/components/AdaptiveSheet.kt @@ -73,11 +73,11 @@ fun NavigatorAdaptiveSheet( */ @Composable fun AdaptiveSheet( + onDismissRequest: () -> Unit, modifier: Modifier = Modifier, hideSystemBars: Boolean = false, tonalElevation: Dp = 1.dp, enableSwipeDismiss: Boolean = true, - onDismissRequest: () -> Unit, content: @Composable () -> Unit, ) { val isTabletUi = isTabletUi() diff --git a/app/src/main/java/eu/kanade/presentation/components/AppBar.kt b/app/src/main/java/eu/kanade/presentation/components/AppBar.kt index 6fb733ebb..7a077216b 100644 --- a/app/src/main/java/eu/kanade/presentation/components/AppBar.kt +++ b/app/src/main/java/eu/kanade/presentation/components/AppBar.kt @@ -13,7 +13,7 @@ import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.TextFieldDefaults import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.outlined.ArrowBack +import androidx.compose.material.icons.automirrored.outlined.ArrowBack import androidx.compose.material.icons.outlined.Close import androidx.compose.material.icons.outlined.MoreVert import androidx.compose.material.icons.outlined.Search @@ -22,11 +22,14 @@ import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.LocalContentColor import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.PlainTooltipBox +import androidx.compose.material3.PlainTooltip import androidx.compose.material3.Text +import androidx.compose.material3.TooltipBox +import androidx.compose.material3.TooltipDefaults import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarScrollBehavior +import androidx.compose.material3.rememberTooltipState import androidx.compose.material3.surfaceColorAtElevation import androidx.compose.runtime.Composable import androidx.compose.runtime.derivedStateOf @@ -52,6 +55,7 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import eu.kanade.tachiyomi.R +import kotlinx.collections.immutable.ImmutableList import tachiyomi.presentation.core.components.Pill import tachiyomi.presentation.core.util.clearFocusOnSoftKeyboardHide import tachiyomi.presentation.core.util.runOnEnterKeyPressed @@ -205,18 +209,23 @@ fun AppBarTitle( @Composable fun AppBarActions( - actions: List, + actions: ImmutableList, ) { var showMenu by remember { mutableStateOf(false) } actions.filterIsInstance().map { - PlainTooltipBox( - tooltip = { Text(it.title) }, + TooltipBox( + positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(), + tooltip = { + PlainTooltip { + Text(it.title) + } + }, + state = rememberTooltipState(), ) { IconButton( onClick = it.onClick, enabled = it.enabled, - modifier = Modifier.tooltipTrigger(), ) { Icon( imageVector = it.icon, @@ -229,12 +238,17 @@ fun AppBarActions( val overflowActions = actions.filterIsInstance() if (overflowActions.isNotEmpty()) { - PlainTooltipBox( - tooltip = { Text(stringResource(R.string.abc_action_menu_overflow_description)) }, + TooltipBox( + positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(), + tooltip = { + PlainTooltip { + Text(stringResource(R.string.abc_action_menu_overflow_description)) + } + }, + state = rememberTooltipState(), ) { IconButton( onClick = { showMenu = !showMenu }, - modifier = Modifier.tooltipTrigger(), ) { Icon( Icons.Outlined.MoreVert, @@ -356,12 +370,17 @@ fun SearchToolbar( if (!searchEnabled) { // Don't show search action } else if (searchQuery == null) { - PlainTooltipBox( - tooltip = { Text(stringResource(R.string.action_search)) }, + TooltipBox( + positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(), + tooltip = { + PlainTooltip { + Text(stringResource(R.string.action_search)) + } + }, + state = rememberTooltipState(), ) { IconButton( onClick = onClick, - modifier = Modifier.tooltipTrigger(), ) { Icon( Icons.Outlined.Search, @@ -370,15 +389,20 @@ fun SearchToolbar( } } } else if (searchQuery.isNotEmpty()) { - PlainTooltipBox( - tooltip = { Text(stringResource(R.string.action_reset)) }, + TooltipBox( + positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(), + tooltip = { + PlainTooltip { + Text(stringResource(R.string.action_reset)) + } + }, + state = rememberTooltipState(), ) { IconButton( onClick = { onClick() focusRequester.requestFocus() }, - modifier = Modifier.tooltipTrigger(), ) { Icon( Icons.Outlined.Close, @@ -400,7 +424,7 @@ fun SearchToolbar( @Composable fun UpIcon(navigationIcon: ImageVector? = null) { val icon = navigationIcon - ?: Icons.Outlined.ArrowBack + ?: Icons.AutoMirrored.Outlined.ArrowBack Icon( imageVector = icon, contentDescription = stringResource(R.string.abc_action_bar_up_description), diff --git a/app/src/main/java/eu/kanade/presentation/components/DropdownMenu.kt b/app/src/main/java/eu/kanade/presentation/components/DropdownMenu.kt index 69d7f5682..d67ad26e2 100644 --- a/app/src/main/java/eu/kanade/presentation/components/DropdownMenu.kt +++ b/app/src/main/java/eu/kanade/presentation/components/DropdownMenu.kt @@ -3,7 +3,7 @@ package eu.kanade.presentation.components import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.sizeIn import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.outlined.ArrowLeft +import androidx.compose.material.icons.automirrored.outlined.ArrowRight import androidx.compose.material.icons.outlined.ArrowRight import androidx.compose.material.icons.outlined.RadioButtonChecked import androidx.compose.material.icons.outlined.RadioButtonUnchecked @@ -84,7 +84,7 @@ fun NestedMenuItem( onClick = { nestedExpanded = true }, trailingIcon = { Icon( - imageVector = if (isLtr) Icons.Outlined.ArrowRight else Icons.Outlined.ArrowLeft, + imageVector = Icons.AutoMirrored.Outlined.ArrowRight, contentDescription = null, ) }, diff --git a/app/src/main/java/eu/kanade/presentation/components/EmptyScreen.kt b/app/src/main/java/eu/kanade/presentation/components/EmptyScreen.kt index def969a39..47efe2aba 100644 --- a/app/src/main/java/eu/kanade/presentation/components/EmptyScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/components/EmptyScreen.kt @@ -1,6 +1,7 @@ package eu.kanade.presentation.components import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.outlined.HelpOutline import androidx.compose.material.icons.outlined.HelpOutline import androidx.compose.material.icons.outlined.Refresh import androidx.compose.material3.Surface @@ -8,6 +9,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.tooling.preview.PreviewLightDark import eu.kanade.presentation.theme.TachiyomiTheme import eu.kanade.tachiyomi.R +import kotlinx.collections.immutable.persistentListOf import tachiyomi.presentation.core.screens.EmptyScreen import tachiyomi.presentation.core.screens.EmptyScreenAction @@ -30,7 +32,7 @@ private fun WithActionPreview() { Surface { EmptyScreen( textResource = R.string.empty_screen, - actions = listOf( + actions = persistentListOf( EmptyScreenAction( stringResId = R.string.action_retry, icon = Icons.Outlined.Refresh, @@ -38,7 +40,7 @@ private fun WithActionPreview() { ), EmptyScreenAction( stringResId = R.string.getting_started_guide, - icon = Icons.Outlined.HelpOutline, + icon = Icons.AutoMirrored.Outlined.HelpOutline, onClick = {}, ), ), diff --git a/app/src/main/java/eu/kanade/presentation/components/RelativeDateHeader.kt b/app/src/main/java/eu/kanade/presentation/components/RelativeDateHeader.kt index 2466e2eed..c291890e3 100644 --- a/app/src/main/java/eu/kanade/presentation/components/RelativeDateHeader.kt +++ b/app/src/main/java/eu/kanade/presentation/components/RelativeDateHeader.kt @@ -11,10 +11,10 @@ import java.util.Date @Composable fun RelativeDateHeader( - modifier: Modifier = Modifier, date: Date, relativeTime: Boolean, dateFormat: DateFormat, + modifier: Modifier = Modifier, ) { val context = LocalContext.current ListGroupHeader( diff --git a/app/src/main/java/eu/kanade/presentation/components/TabbedDialog.kt b/app/src/main/java/eu/kanade/presentation/components/TabbedDialog.kt index c6e1818b9..7e5905715 100644 --- a/app/src/main/java/eu/kanade/presentation/components/TabbedDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/components/TabbedDialog.kt @@ -14,8 +14,8 @@ import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.PrimaryTabRow import androidx.compose.material3.Tab -import androidx.compose.material3.TabRow import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -29,9 +29,9 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.compose.ui.util.fastForEachIndexed import eu.kanade.tachiyomi.R +import kotlinx.collections.immutable.ImmutableList import kotlinx.coroutines.launch import tachiyomi.presentation.core.components.HorizontalPager -import tachiyomi.presentation.core.components.material.TabIndicator import tachiyomi.presentation.core.components.material.TabText object TabbedDialogPaddings { @@ -41,9 +41,9 @@ object TabbedDialogPaddings { @Composable fun TabbedDialog( - modifier: Modifier = Modifier, onDismissRequest: () -> Unit, - tabTitles: List, + tabTitles: ImmutableList, + modifier: Modifier = Modifier, tabOverflowMenuContent: (@Composable ColumnScope.(() -> Unit) -> Unit)? = null, onOverflowMenuClicked: (() -> Unit)? = null, overflowIcon: ImageVector? = null, @@ -60,15 +60,9 @@ fun TabbedDialog( Column { Row { - TabRow( + PrimaryTabRow( modifier = Modifier.weight(1f), selectedTabIndex = pagerState.currentPage, - indicator = { - TabIndicator( - it[pagerState.currentPage], - pagerState.currentPageOffsetFraction, - ) - }, divider = {}, ) { tabTitles.fastForEachIndexed { index, tab -> diff --git a/app/src/main/java/eu/kanade/presentation/components/TabbedScreen.kt b/app/src/main/java/eu/kanade/presentation/components/TabbedScreen.kt index e3bdb9201..79ae00f44 100644 --- a/app/src/main/java/eu/kanade/presentation/components/TabbedScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/components/TabbedScreen.kt @@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.pager.PagerState import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.PrimaryTabRow import androidx.compose.material3.ScrollableTabRow import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState @@ -25,16 +26,17 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.launch import tachiyomi.presentation.core.components.HorizontalPager import tachiyomi.presentation.core.components.material.Scaffold -import tachiyomi.presentation.core.components.material.TabIndicator import tachiyomi.presentation.core.components.material.TabText @Composable fun TabbedScreen( @StringRes titleRes: Int?, - tabs: List, + tabs: ImmutableList, startIndex: Int? = null, mangaSearchQuery: String? = null, onChangeMangaSearchQuery: (String?) -> Unit = {}, @@ -89,10 +91,8 @@ fun TabbedScreen( end = contentPadding.calculateEndPadding(LocalLayoutDirection.current), ), ) { - FlexibleTabRow( - scrollable = scrollable, + PrimaryTabRow( selectedTabIndex = state.currentPage, - indicator = { TabIndicator(it[state.currentPage], state.currentPageOffsetFraction) }, ) { tabs.forEachIndexed { index, tab -> Tab( @@ -127,7 +127,7 @@ data class TabContent( @StringRes val titleRes: Int, val badgeNumber: Int? = null, val searchEnabled: Boolean = false, - val actions: List = emptyList(), + val actions: ImmutableList = persistentListOf(), val content: @Composable (contentPadding: PaddingValues, snackbarHostState: SnackbarHostState) -> Unit, val numberTitle: Int = 0, val cancelAction: () -> Unit = {}, diff --git a/app/src/main/java/eu/kanade/presentation/entries/EntryBottomActionMenu.kt b/app/src/main/java/eu/kanade/presentation/entries/EntryBottomActionMenu.kt index 41784efe3..0b8de9b04 100644 --- a/app/src/main/java/eu/kanade/presentation/entries/EntryBottomActionMenu.kt +++ b/app/src/main/java/eu/kanade/presentation/entries/EntryBottomActionMenu.kt @@ -23,6 +23,7 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.shape.ZeroCornerSize import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.outlined.Label import androidx.compose.material.icons.outlined.BookmarkAdd import androidx.compose.material.icons.outlined.BookmarkRemove import androidx.compose.material.icons.outlined.Delete @@ -304,7 +305,7 @@ fun LibraryBottomActionMenu( ) { Button( title = stringResource(R.string.action_move_category), - icon = Icons.Outlined.Label, + icon = Icons.AutoMirrored.Outlined.Label, toConfirm = confirm[0], onLongClick = { onLongClickItem(0) }, onClick = onChangeCategoryClicked, diff --git a/app/src/main/java/eu/kanade/presentation/entries/EntryToolbar.kt b/app/src/main/java/eu/kanade/presentation/entries/EntryToolbar.kt index 06fa7ab11..f561f85b5 100644 --- a/app/src/main/java/eu/kanade/presentation/entries/EntryToolbar.kt +++ b/app/src/main/java/eu/kanade/presentation/entries/EntryToolbar.kt @@ -29,6 +29,7 @@ import eu.kanade.presentation.components.AppBarActions import eu.kanade.presentation.components.EntryDownloadDropdownMenu import eu.kanade.presentation.components.UpIcon import eu.kanade.tachiyomi.R +import kotlinx.collections.immutable.persistentListOf import tachiyomi.presentation.core.theme.active @Composable @@ -75,7 +76,7 @@ fun EntryToolbar( actions = { if (isActionMode) { AppBarActions( - listOf( + persistentListOf( AppBar.Action( title = stringResource(R.string.action_select_all), icon = Icons.Outlined.SelectAll, @@ -102,71 +103,65 @@ fun EntryToolbar( val filterTint = if (hasFilters) MaterialTheme.colorScheme.active else LocalContentColor.current AppBarActions( - actions = buildList { - if (onClickDownload != null) { + actions = persistentListOf().builder() + .apply { + if (onClickDownload != null) { + add( + AppBar.Action( + title = stringResource(R.string.manga_download), + icon = Icons.Outlined.Download, + onClick = { downloadExpanded = !downloadExpanded }, + ), + ) + } add( AppBar.Action( - title = stringResource(R.string.manga_download), - icon = Icons.Outlined.Download, - onClick = { downloadExpanded = !downloadExpanded }, + title = stringResource(R.string.action_filter), + icon = Icons.Outlined.FilterList, + iconTint = filterTint, + onClick = onClickFilter, ), ) - } - add( - AppBar.Action( - title = stringResource(R.string.action_filter), - icon = Icons.Outlined.FilterList, - iconTint = filterTint, - onClick = onClickFilter, - ), - ) - add( - AppBar.OverflowAction( - title = stringResource(R.string.action_webview_refresh), - onClick = onClickRefresh, - ), - ) - if (onClickEditCategory != null) { + if (changeAnimeSkipIntro != null) { + add( + AppBar.OverflowAction( + title = stringResource(R.string.action_change_intro_length), + onClick = changeAnimeSkipIntro, + ), + ) + } add( AppBar.OverflowAction( - title = stringResource(R.string.action_edit_categories), - onClick = onClickEditCategory, + title = stringResource(R.string.action_webview_refresh), + onClick = onClickRefresh, ), ) + if (onClickEditCategory != null) { + add( + AppBar.OverflowAction( + title = stringResource(R.string.action_edit_categories), + onClick = onClickEditCategory, + ), + ) + } + if (onClickMigrate != null) { + add( + AppBar.OverflowAction( + title = stringResource(R.string.action_migrate), + onClick = onClickMigrate, + ), + ) + } + if (onClickShare != null) { + add( + AppBar.OverflowAction( + title = stringResource(R.string.action_share), + onClick = onClickShare, + ), + ) + } } - if (onClickMigrate != null) { - add( - AppBar.OverflowAction( - title = stringResource(R.string.action_migrate), - onClick = onClickMigrate, - ), - ) - } - if (changeAnimeSkipIntro != null) { - add( - AppBar.OverflowAction( - title = stringResource(R.string.action_change_intro_length), - onClick = changeAnimeSkipIntro, - ), - ) - } - if (onClickSettings != null) { - add( - AppBar.OverflowAction( - title = stringResource(R.string.settings), - onClick = onClickSettings, - ), - ) - } - if (onClickShare != null) { - add( - AppBar.OverflowAction( - title = stringResource(R.string.action_share), - onClick = onClickShare, - ), - ) - } - }, + .build(), ) } }, diff --git a/app/src/main/java/eu/kanade/presentation/entries/ItemsDialogs.kt b/app/src/main/java/eu/kanade/presentation/entries/ItemsDialogs.kt index c92058d3b..6cbce5cb2 100644 --- a/app/src/main/java/eu/kanade/presentation/entries/ItemsDialogs.kt +++ b/app/src/main/java/eu/kanade/presentation/entries/ItemsDialogs.kt @@ -16,6 +16,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp import eu.kanade.tachiyomi.R +import kotlinx.collections.immutable.toImmutableList import tachiyomi.presentation.core.components.WheelTextPicker @Composable @@ -68,16 +69,18 @@ fun SetIntervalDialog( contentAlignment = Alignment.Center, ) { val size = DpSize(width = maxWidth / 2, height = 128.dp) - val items = (0..28).map { - if (it == 0) { - stringResource(R.string.label_default) - } else { - it.toString() + val items = (0..28) + .map { + if (it == 0) { + stringResource(R.string.label_default) + } else { + it.toString() + } } - } + .toImmutableList() WheelTextPicker( - size = size, items = items, + size = size, startIndex = selectedInterval, onSelectionChanged = { selectedInterval = it }, ) diff --git a/app/src/main/java/eu/kanade/presentation/entries/anime/AnimeScreen.kt b/app/src/main/java/eu/kanade/presentation/entries/anime/AnimeScreen.kt index 97dc07593..c9cbfece6 100644 --- a/app/src/main/java/eu/kanade/presentation/entries/anime/AnimeScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/entries/anime/AnimeScreen.kt @@ -88,7 +88,6 @@ import tachiyomi.presentation.core.components.VerticalFastScroller import tachiyomi.presentation.core.components.material.ExtendedFloatingActionButton import tachiyomi.presentation.core.components.material.PullRefresh import tachiyomi.presentation.core.components.material.Scaffold -import tachiyomi.presentation.core.components.material.padding import tachiyomi.presentation.core.util.isScrolledToEnd import tachiyomi.presentation.core.util.isScrollingUp import java.text.DateFormat @@ -350,12 +349,12 @@ private fun AnimeScreenSmallImpl( onClickEditCategory = onEditCategoryClicked, onClickRefresh = onRefresh, onClickMigrate = onMigrateClicked, + onClickSettings = onSettingsClicked, changeAnimeSkipIntro = changeAnimeSkipIntro, actionModeCounter = selectedEpisodeCount, onSelectAll = { onAllEpisodeSelected(true) }, onInvertSelection = { onInvertSelection() }, isManga = false, - onClickSettings = onSettingsClicked, ) }, bottomBar = { @@ -647,12 +646,12 @@ fun AnimeScreenLargeImpl( onClickEditCategory = onEditCategoryClicked, onClickRefresh = onRefresh, onClickMigrate = onMigrateClicked, + onClickSettings = onSettingsClicked, changeAnimeSkipIntro = changeAnimeSkipIntro, actionModeCounter = selectedEpisodeCount, onSelectAll = { onAllEpisodeSelected(true) }, onInvertSelection = { onInvertSelection() }, isManga = false, - onClickSettings = onSettingsClicked, ) }, bottomBar = { diff --git a/app/src/main/java/eu/kanade/presentation/entries/anime/EpisodeSettingsDialog.kt b/app/src/main/java/eu/kanade/presentation/entries/anime/EpisodeSettingsDialog.kt index bafc6243f..b5193955c 100644 --- a/app/src/main/java/eu/kanade/presentation/entries/anime/EpisodeSettingsDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/entries/anime/EpisodeSettingsDialog.kt @@ -22,6 +22,7 @@ import eu.kanade.domain.entries.anime.model.forceDownloaded import eu.kanade.presentation.components.TabbedDialog import eu.kanade.presentation.components.TabbedDialogPaddings import eu.kanade.tachiyomi.R +import kotlinx.collections.immutable.persistentListOf import tachiyomi.core.preference.TriState import tachiyomi.domain.entries.anime.model.Anime import tachiyomi.presentation.core.components.LabeledCheckbox @@ -50,7 +51,7 @@ fun EpisodeSettingsDialog( TabbedDialog( onDismissRequest = onDismissRequest, - tabTitles = listOf( + tabTitles = persistentListOf( stringResource(R.string.action_filter), stringResource(R.string.action_sort), stringResource(R.string.action_display), diff --git a/app/src/main/java/eu/kanade/presentation/entries/anime/components/AnimeCoverDialog.kt b/app/src/main/java/eu/kanade/presentation/entries/anime/components/AnimeCoverDialog.kt index 3b1e8b1cd..1e71e72fe 100644 --- a/app/src/main/java/eu/kanade/presentation/entries/anime/components/AnimeCoverDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/entries/anime/components/AnimeCoverDialog.kt @@ -49,6 +49,7 @@ import eu.kanade.presentation.components.DropdownMenu import eu.kanade.presentation.entries.EditCoverAction import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.reader.viewer.ReaderPageImageView +import kotlinx.collections.immutable.persistentListOf import tachiyomi.domain.entries.anime.model.Anime import tachiyomi.presentation.core.components.material.Scaffold import tachiyomi.presentation.core.util.clickableNoIndication @@ -91,22 +92,18 @@ fun AnimeCoverDialog( Spacer(modifier = Modifier.weight(1f)) ActionsPill { AppBarActions( - actions = buildList { - add( - AppBar.Action( - title = stringResource(R.string.action_share), - icon = Icons.Outlined.Share, - onClick = onShareClick, - ), - ) - add( - AppBar.Action( - title = stringResource(R.string.action_save), - icon = Icons.Outlined.Save, - onClick = onSaveClick, - ), - ) - }, + actions = persistentListOf( + AppBar.Action( + title = stringResource(R.string.action_share), + icon = Icons.Outlined.Share, + onClick = onShareClick, + ), + AppBar.Action( + title = stringResource(R.string.action_save), + icon = Icons.Outlined.Save, + onClick = onSaveClick, + ), + ), ) if (onEditClick != null) { Box { diff --git a/app/src/main/java/eu/kanade/presentation/entries/anime/components/EpisodeDownloadIndicator.kt b/app/src/main/java/eu/kanade/presentation/entries/anime/components/EpisodeDownloadIndicator.kt index e484c0f8c..15a66cea4 100644 --- a/app/src/main/java/eu/kanade/presentation/entries/anime/components/EpisodeDownloadIndicator.kt +++ b/app/src/main/java/eu/kanade/presentation/entries/anime/components/EpisodeDownloadIndicator.kt @@ -145,7 +145,7 @@ private fun DownloadingIndicator( MaterialTheme.colorScheme.background } CircularProgressIndicator( - progress = animatedProgress, + progress = { animatedProgress }, modifier = IndicatorModifier, color = strokeColor, strokeWidth = IndicatorSize / 2, diff --git a/app/src/main/java/eu/kanade/presentation/entries/manga/ChapterSettingsDialog.kt b/app/src/main/java/eu/kanade/presentation/entries/manga/ChapterSettingsDialog.kt index 98189c53f..3a866b29b 100644 --- a/app/src/main/java/eu/kanade/presentation/entries/manga/ChapterSettingsDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/entries/manga/ChapterSettingsDialog.kt @@ -31,6 +31,7 @@ import eu.kanade.domain.entries.manga.model.forceDownloaded import eu.kanade.presentation.components.TabbedDialog import eu.kanade.presentation.components.TabbedDialogPaddings import eu.kanade.tachiyomi.R +import kotlinx.collections.immutable.persistentListOf import tachiyomi.core.preference.TriState import tachiyomi.domain.entries.manga.model.Manga import tachiyomi.presentation.core.components.LabeledCheckbox @@ -63,7 +64,7 @@ fun ChapterSettingsDialog( TabbedDialog( onDismissRequest = onDismissRequest, - tabTitles = listOf( + tabTitles = persistentListOf( stringResource(R.string.action_filter), stringResource(R.string.action_sort), stringResource(R.string.action_display), diff --git a/app/src/main/java/eu/kanade/presentation/entries/manga/MangaScreen.kt b/app/src/main/java/eu/kanade/presentation/entries/manga/MangaScreen.kt index 85acde186..36e807bc5 100644 --- a/app/src/main/java/eu/kanade/presentation/entries/manga/MangaScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/entries/manga/MangaScreen.kt @@ -81,7 +81,6 @@ import tachiyomi.presentation.core.components.VerticalFastScroller import tachiyomi.presentation.core.components.material.ExtendedFloatingActionButton import tachiyomi.presentation.core.components.material.PullRefresh import tachiyomi.presentation.core.components.material.Scaffold -import tachiyomi.presentation.core.components.material.padding import tachiyomi.presentation.core.util.isScrolledToEnd import tachiyomi.presentation.core.util.isScrollingUp import java.text.DateFormat @@ -330,12 +329,12 @@ private fun MangaScreenSmallImpl( onClickEditCategory = onEditCategoryClicked, onClickRefresh = onRefresh, onClickMigrate = onMigrateClicked, + onClickSettings = onSettingsClicked, changeAnimeSkipIntro = null, actionModeCounter = selectedChapterCount, onSelectAll = { onAllChapterSelected(true) }, onInvertSelection = { onInvertSelection() }, isManga = true, - onClickSettings = onSettingsClicked, ) }, bottomBar = { @@ -588,12 +587,12 @@ fun MangaScreenLargeImpl( onClickEditCategory = onEditCategoryClicked, onClickRefresh = onRefresh, onClickMigrate = onMigrateClicked, + onClickSettings = onSettingsClicked, changeAnimeSkipIntro = null, actionModeCounter = selectedChapterCount, onSelectAll = { onAllChapterSelected(true) }, onInvertSelection = { onInvertSelection() }, isManga = true, - onClickSettings = onSettingsClicked, ) }, bottomBar = { diff --git a/app/src/main/java/eu/kanade/presentation/entries/manga/components/ChapterDownloadIndicator.kt b/app/src/main/java/eu/kanade/presentation/entries/manga/components/ChapterDownloadIndicator.kt index cf6e45217..60e4b4ed0 100644 --- a/app/src/main/java/eu/kanade/presentation/entries/manga/components/ChapterDownloadIndicator.kt +++ b/app/src/main/java/eu/kanade/presentation/entries/manga/components/ChapterDownloadIndicator.kt @@ -144,7 +144,7 @@ private fun DownloadingIndicator( MaterialTheme.colorScheme.background } CircularProgressIndicator( - progress = animatedProgress, + progress = { animatedProgress }, modifier = IndicatorModifier, color = strokeColor, strokeWidth = IndicatorSize / 2, diff --git a/app/src/main/java/eu/kanade/presentation/entries/manga/components/MangaCoverDialog.kt b/app/src/main/java/eu/kanade/presentation/entries/manga/components/MangaCoverDialog.kt index 64fe555bb..8f2cec71a 100644 --- a/app/src/main/java/eu/kanade/presentation/entries/manga/components/MangaCoverDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/entries/manga/components/MangaCoverDialog.kt @@ -49,6 +49,7 @@ import eu.kanade.presentation.components.DropdownMenu import eu.kanade.presentation.entries.EditCoverAction import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.reader.viewer.ReaderPageImageView +import kotlinx.collections.immutable.persistentListOf import tachiyomi.domain.entries.manga.model.Manga import tachiyomi.presentation.core.components.material.Scaffold import tachiyomi.presentation.core.util.clickableNoIndication @@ -91,22 +92,18 @@ fun MangaCoverDialog( Spacer(modifier = Modifier.weight(1f)) ActionsPill { AppBarActions( - actions = buildList { - add( - AppBar.Action( - title = stringResource(R.string.action_share), - icon = Icons.Outlined.Share, - onClick = onShareClick, - ), - ) - add( - AppBar.Action( - title = stringResource(R.string.action_save), - icon = Icons.Outlined.Save, - onClick = onSaveClick, - ), - ) - }, + actions = persistentListOf( + AppBar.Action( + title = stringResource(R.string.action_share), + icon = Icons.Outlined.Share, + onClick = onShareClick, + ), + AppBar.Action( + title = stringResource(R.string.action_save), + icon = Icons.Outlined.Save, + onClick = onSaveClick, + ), + ), ) if (onEditClick != null) { Box { diff --git a/app/src/main/java/eu/kanade/presentation/history/anime/AnimeHistoryContent.kt b/app/src/main/java/eu/kanade/presentation/history/anime/AnimeHistoryContent.kt index aa430891a..bbcdb55a4 100644 --- a/app/src/main/java/eu/kanade/presentation/history/anime/AnimeHistoryContent.kt +++ b/app/src/main/java/eu/kanade/presentation/history/anime/AnimeHistoryContent.kt @@ -4,7 +4,6 @@ import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.lazy.items import androidx.compose.runtime.Composable import androidx.compose.runtime.remember -import androidx.compose.ui.Modifier import eu.kanade.domain.ui.UiPreferences import eu.kanade.presentation.components.RelativeDateHeader import tachiyomi.domain.history.anime.model.AnimeHistoryWithRelations @@ -38,7 +37,7 @@ fun AnimeHistoryContent( when (item) { is AnimeHistoryUiModel.Header -> { RelativeDateHeader( - modifier = Modifier.animateItemPlacement(), + date = item.date, relativeTime = relativeTime, dateFormat = dateFormat, @@ -47,7 +46,7 @@ fun AnimeHistoryContent( is AnimeHistoryUiModel.Item -> { val value = item.item AnimeHistoryItem( - modifier = Modifier.animateItemPlacement(), + history = value, onClickCover = { onClickCover(value) }, onClickResume = { onClickResume(value) }, diff --git a/app/src/main/java/eu/kanade/presentation/history/anime/AnimeHistoryItem.kt b/app/src/main/java/eu/kanade/presentation/history/anime/AnimeHistoryItem.kt index 086f79c96..8762b0226 100644 --- a/app/src/main/java/eu/kanade/presentation/history/anime/AnimeHistoryItem.kt +++ b/app/src/main/java/eu/kanade/presentation/history/anime/AnimeHistoryItem.kt @@ -35,11 +35,11 @@ private val HistoryItemHeight = 96.dp @Composable fun AnimeHistoryItem( - modifier: Modifier = Modifier, history: AnimeHistoryWithRelations, onClickCover: () -> Unit, onClickResume: () -> Unit, onClickDelete: () -> Unit, + modifier: Modifier = Modifier, ) { Row( modifier = modifier diff --git a/app/src/main/java/eu/kanade/presentation/history/anime/AnimeHistoryUiModelProviders.kt b/app/src/main/java/eu/kanade/presentation/history/anime/AnimeHistoryUiModelProviders.kt deleted file mode 100644 index fffe681d3..000000000 --- a/app/src/main/java/eu/kanade/presentation/history/anime/AnimeHistoryUiModelProviders.kt +++ /dev/null @@ -1,13 +0,0 @@ -package eu.kanade.presentation.history.anime - -import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import java.time.Instant -import java.util.Date - -object AnimeHistoryUiModelProviders { - - class HeadNow : PreviewParameterProvider { - override val values: Sequence = - sequenceOf(AnimeHistoryUiModel.Header(Date.from(Instant.now()))) - } -} diff --git a/app/src/main/java/eu/kanade/presentation/history/manga/MangaHistoryContent.kt b/app/src/main/java/eu/kanade/presentation/history/manga/MangaHistoryContent.kt index f6d6b0384..01ee70a5f 100644 --- a/app/src/main/java/eu/kanade/presentation/history/manga/MangaHistoryContent.kt +++ b/app/src/main/java/eu/kanade/presentation/history/manga/MangaHistoryContent.kt @@ -4,7 +4,6 @@ import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.lazy.items import androidx.compose.runtime.Composable import androidx.compose.runtime.remember -import androidx.compose.ui.Modifier import eu.kanade.domain.ui.UiPreferences import eu.kanade.presentation.components.RelativeDateHeader import tachiyomi.domain.history.manga.model.MangaHistoryWithRelations @@ -39,7 +38,6 @@ fun MangaHistoryContent( when (item) { is MangaHistoryUiModel.Header -> { RelativeDateHeader( - modifier = Modifier.animateItemPlacement(), date = item.date, relativeTime = relativeTime, dateFormat = dateFormat, @@ -48,7 +46,6 @@ fun MangaHistoryContent( is MangaHistoryUiModel.Item -> { val value = item.item MangaHistoryItem( - modifier = Modifier.animateItemPlacement(), history = value, onClickCover = { onClickCover(value) }, onClickResume = { onClickResume(value) }, diff --git a/app/src/main/java/eu/kanade/presentation/history/manga/MangaHistoryItem.kt b/app/src/main/java/eu/kanade/presentation/history/manga/MangaHistoryItem.kt index f6a2eb9f0..2827415b6 100644 --- a/app/src/main/java/eu/kanade/presentation/history/manga/MangaHistoryItem.kt +++ b/app/src/main/java/eu/kanade/presentation/history/manga/MangaHistoryItem.kt @@ -35,11 +35,11 @@ private val HISTORY_ITEM_HEIGHT = 96.dp @Composable fun MangaHistoryItem( - modifier: Modifier = Modifier, history: MangaHistoryWithRelations, onClickCover: () -> Unit, onClickResume: () -> Unit, onClickDelete: () -> Unit, + modifier: Modifier = Modifier, ) { Row( modifier = modifier diff --git a/app/src/main/java/eu/kanade/presentation/history/manga/MangaHistoryUiModelProviders.kt b/app/src/main/java/eu/kanade/presentation/history/manga/MangaHistoryUiModelProviders.kt deleted file mode 100644 index 8806245f8..000000000 --- a/app/src/main/java/eu/kanade/presentation/history/manga/MangaHistoryUiModelProviders.kt +++ /dev/null @@ -1,13 +0,0 @@ -package eu.kanade.presentation.history.manga - -import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import java.time.Instant -import java.util.Date - -object MangaHistoryUiModelProviders { - - class HeadNow : PreviewParameterProvider { - override val values: Sequence = - sequenceOf(MangaHistoryUiModel.Header(Date.from(Instant.now()))) - } -} diff --git a/app/src/main/java/eu/kanade/presentation/library/CommonEntryItem.kt b/app/src/main/java/eu/kanade/presentation/library/CommonEntryItem.kt index 691486449..5a6083ed5 100644 --- a/app/src/main/java/eu/kanade/presentation/library/CommonEntryItem.kt +++ b/app/src/main/java/eu/kanade/presentation/library/CommonEntryItem.kt @@ -33,11 +33,13 @@ import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Shadow +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import eu.kanade.presentation.entries.ItemCover +import eu.kanade.tachiyomi.R import tachiyomi.domain.entries.EntryCover import tachiyomi.presentation.core.components.BadgeGroup import tachiyomi.presentation.core.util.selectedBackground @@ -377,7 +379,7 @@ private fun ContinueViewingButton( ) { Icon( imageVector = Icons.Filled.PlayArrow, - contentDescription = "", + contentDescription = stringResource(R.string.action_resume), modifier = Modifier.size(16.dp), ) } diff --git a/app/src/main/java/eu/kanade/presentation/library/LibraryTabs.kt b/app/src/main/java/eu/kanade/presentation/library/LibraryTabs.kt index 22ae43eda..c3fca9478 100644 --- a/app/src/main/java/eu/kanade/presentation/library/LibraryTabs.kt +++ b/app/src/main/java/eu/kanade/presentation/library/LibraryTabs.kt @@ -4,13 +4,12 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.pager.PagerState import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.ScrollableTabRow +import androidx.compose.material3.PrimaryScrollableTabRow import androidx.compose.material3.Tab import androidx.compose.runtime.Composable import androidx.compose.ui.unit.dp import eu.kanade.presentation.category.visualName import tachiyomi.domain.category.model.Category -import tachiyomi.presentation.core.components.material.TabIndicator import tachiyomi.presentation.core.components.material.TabText @Composable @@ -21,15 +20,9 @@ fun LibraryTabs( onTabItemClick: (Int) -> Unit, ) { Column { - ScrollableTabRow( + PrimaryScrollableTabRow( selectedTabIndex = pagerState.currentPage, edgePadding = 0.dp, - indicator = { - TabIndicator( - it[pagerState.currentPage], - pagerState.currentPageOffsetFraction, - ) - }, // TODO: use default when width is fixed upstream // https://issuetracker.google.com/issues/242879624 divider = {}, diff --git a/app/src/main/java/eu/kanade/presentation/library/LibraryToolbar.kt b/app/src/main/java/eu/kanade/presentation/library/LibraryToolbar.kt index 1bf1cc147..628dcaea6 100644 --- a/app/src/main/java/eu/kanade/presentation/library/LibraryToolbar.kt +++ b/app/src/main/java/eu/kanade/presentation/library/LibraryToolbar.kt @@ -21,6 +21,7 @@ import eu.kanade.presentation.components.AppBar import eu.kanade.presentation.components.AppBarActions import eu.kanade.presentation.components.SearchToolbar import eu.kanade.tachiyomi.R +import kotlinx.collections.immutable.persistentListOf import tachiyomi.presentation.core.components.Pill import tachiyomi.presentation.core.theme.active @@ -99,7 +100,7 @@ fun LibraryRegularToolbar( actions = { val filterTint = if (hasFilters) MaterialTheme.colorScheme.active else LocalContentColor.current AppBarActions( - listOf( + persistentListOf( AppBar.Action( title = stringResource(R.string.action_filter), icon = Icons.Outlined.FilterList, @@ -138,7 +139,7 @@ fun LibrarySelectionToolbar( titleContent = { Text(text = "$selectedCount") }, actions = { AppBarActions( - listOf( + persistentListOf( AppBar.Action( title = stringResource(R.string.action_select_all), icon = Icons.Outlined.SelectAll, diff --git a/app/src/main/java/eu/kanade/presentation/library/anime/AnimeLibrarySettingsDialog.kt b/app/src/main/java/eu/kanade/presentation/library/anime/AnimeLibrarySettingsDialog.kt index 7fa23b2c8..84a052c6d 100644 --- a/app/src/main/java/eu/kanade/presentation/library/anime/AnimeLibrarySettingsDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/library/anime/AnimeLibrarySettingsDialog.kt @@ -18,6 +18,7 @@ import eu.kanade.presentation.components.TabbedDialog import eu.kanade.presentation.components.TabbedDialogPaddings import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.library.anime.AnimeLibrarySettingsScreenModel +import kotlinx.collections.immutable.persistentListOf import tachiyomi.core.preference.TriState import tachiyomi.domain.category.model.Category import tachiyomi.domain.library.anime.model.AnimeLibrarySort @@ -40,7 +41,7 @@ fun AnimeLibrarySettingsDialog( ) { TabbedDialog( onDismissRequest = onDismissRequest, - tabTitles = listOf( + tabTitles = persistentListOf( stringResource(R.string.action_filter), stringResource(R.string.action_sort), stringResource(R.string.action_display), diff --git a/app/src/main/java/eu/kanade/presentation/library/manga/MangaLibrarySettingsDialog.kt b/app/src/main/java/eu/kanade/presentation/library/manga/MangaLibrarySettingsDialog.kt index c1cc35769..8a8777859 100644 --- a/app/src/main/java/eu/kanade/presentation/library/manga/MangaLibrarySettingsDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/library/manga/MangaLibrarySettingsDialog.kt @@ -18,6 +18,7 @@ import eu.kanade.presentation.components.TabbedDialog import eu.kanade.presentation.components.TabbedDialogPaddings import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.library.manga.MangaLibrarySettingsScreenModel +import kotlinx.collections.immutable.persistentListOf import tachiyomi.core.preference.TriState import tachiyomi.domain.category.model.Category import tachiyomi.domain.library.manga.model.MangaLibrarySort @@ -40,7 +41,7 @@ fun MangaLibrarySettingsDialog( ) { TabbedDialog( onDismissRequest = onDismissRequest, - tabTitles = listOf( + tabTitles = persistentListOf( stringResource(R.string.action_filter), stringResource(R.string.action_sort), stringResource(R.string.action_display), diff --git a/app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt b/app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt index 4e50d8a2c..63f5e34e9 100644 --- a/app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt @@ -9,13 +9,14 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.outlined.HelpOutline +import androidx.compose.material.icons.automirrored.outlined.Label import androidx.compose.material.icons.outlined.CloudOff import androidx.compose.material.icons.outlined.CollectionsBookmark import androidx.compose.material.icons.outlined.GetApp import androidx.compose.material.icons.outlined.HelpOutline import androidx.compose.material.icons.outlined.History import androidx.compose.material.icons.outlined.Info -import androidx.compose.material.icons.outlined.Label import androidx.compose.material.icons.outlined.QueryStats import androidx.compose.material.icons.outlined.Settings import androidx.compose.material.icons.outlined.Storage @@ -163,7 +164,7 @@ fun MoreScreen( item { TextPreferenceWidget( title = stringResource(R.string.general_categories), - icon = Icons.Outlined.Label, + icon = Icons.AutoMirrored.Outlined.Label, onPreferenceClick = onClickCategories, ) } @@ -208,7 +209,7 @@ fun MoreScreen( item { TextPreferenceWidget( title = stringResource(R.string.label_help), - icon = Icons.Outlined.HelpOutline, + icon = Icons.AutoMirrored.Outlined.HelpOutline, onPreferenceClick = { uriHandler.openUri(Constants.URL_HELP) }, ) } diff --git a/app/src/main/java/eu/kanade/presentation/more/NewUpdateScreen.kt b/app/src/main/java/eu/kanade/presentation/more/NewUpdateScreen.kt index d6dc9f94c..9d3f5c75f 100644 --- a/app/src/main/java/eu/kanade/presentation/more/NewUpdateScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/NewUpdateScreen.kt @@ -5,7 +5,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.OpenInNew +import androidx.compose.material.icons.automirrored.outlined.OpenInNew import androidx.compose.material.icons.outlined.NewReleases import androidx.compose.material.icons.outlined.OpenInNew import androidx.compose.material3.Icon @@ -61,7 +61,7 @@ fun NewUpdateScreen( ) { Text(text = stringResource(R.string.update_check_open)) Spacer(modifier = Modifier.width(MaterialTheme.padding.tiny)) - Icon(imageVector = Icons.Default.OpenInNew, contentDescription = null) + Icon(imageVector = Icons.AutoMirrored.Outlined.OpenInNew, contentDescription = null) } } } diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceScreen.kt index 236719024..26b4086b8 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceScreen.kt @@ -85,12 +85,11 @@ fun PreferenceScreen( private fun List.findHighlightedIndex(highlightKey: String): Int { return flatMap { if (it is Preference.PreferenceGroup) { - mutableListOf() - .apply { - add(null) // Header - addAll(it.preferenceItems.map { groupItem -> groupItem.title }) - add(null) // Spacer - } + buildList { + add(null) // Header + addAll(it.preferenceItems.map { groupItem -> groupItem.title }) + add(null) // Spacer + } } else { listOf(it.title) } diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt index 86d3c616e..3f8f197ca 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt @@ -1,6 +1,5 @@ package eu.kanade.presentation.more.settings.screen -import android.content.ActivityNotFoundException import android.content.Context import android.content.Intent import android.net.Uri @@ -13,44 +12,39 @@ import androidx.annotation.StringRes import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.AlertDialog -import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.ReadOnlyComposable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf -import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource +import cafe.adriel.voyager.navigator.LocalNavigator +import cafe.adriel.voyager.navigator.currentOrThrow import eu.kanade.presentation.more.settings.Preference +import eu.kanade.presentation.more.settings.screen.data.CreateBackupScreen import eu.kanade.presentation.more.settings.widget.BasePreferenceWidget import eu.kanade.presentation.more.settings.widget.PrefsHorizontalPadding import eu.kanade.presentation.permissions.PermissionRequestHelper import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.data.backup.BackupConst import eu.kanade.tachiyomi.data.backup.BackupCreateJob import eu.kanade.tachiyomi.data.backup.BackupFileValidator import eu.kanade.tachiyomi.data.backup.BackupRestoreJob -import eu.kanade.tachiyomi.data.backup.models.Backup import eu.kanade.tachiyomi.data.cache.ChapterCache import eu.kanade.tachiyomi.data.cache.EpisodeCache import eu.kanade.tachiyomi.util.storage.DiskUtil import eu.kanade.tachiyomi.util.system.DeviceUtil import eu.kanade.tachiyomi.util.system.copyToClipboard import eu.kanade.tachiyomi.util.system.toast -import kotlinx.coroutines.launch import logcat.LogPriority import tachiyomi.core.util.lang.launchNonCancellable import tachiyomi.core.util.lang.withUIContext @@ -64,11 +58,7 @@ import tachiyomi.domain.backup.service.FLAG_HISTORY import tachiyomi.domain.backup.service.FLAG_SETTINGS import tachiyomi.domain.backup.service.FLAG_TRACK import tachiyomi.domain.library.service.LibraryPreferences -import tachiyomi.presentation.core.components.LabeledCheckbox -import tachiyomi.presentation.core.components.ScrollbarLazyColumn import tachiyomi.presentation.core.util.collectAsState -import tachiyomi.presentation.core.util.isScrolledToEnd -import tachiyomi.presentation.core.util.isScrolledToStart import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get @@ -134,140 +124,11 @@ object SettingsDataScreen : SearchableSettings { @Composable private fun getCreateBackupPref(): Preference.PreferenceItem.TextPreference { - val scope = rememberCoroutineScope() - val context = LocalContext.current - - var flag by rememberSaveable { mutableIntStateOf(0) } - val chooseBackupDir = rememberLauncherForActivityResult( - contract = ActivityResultContracts.CreateDocument("application/*"), - ) { - if (it != null) { - context.contentResolver.takePersistableUriPermission( - it, - Intent.FLAG_GRANT_READ_URI_PERMISSION or - Intent.FLAG_GRANT_WRITE_URI_PERMISSION, - ) - BackupCreateJob.startNow(context, it, flag) - } - flag = 0 - } - var showCreateDialog by rememberSaveable { mutableStateOf(false) } - if (showCreateDialog) { - CreateBackupDialog( - onConfirm = { - showCreateDialog = false - flag = it - try { - chooseBackupDir.launch(Backup.getFilename()) - } catch (e: ActivityNotFoundException) { - flag = 0 - context.toast(R.string.file_picker_error) - } - }, - onDismissRequest = { showCreateDialog = false }, - ) - } - + val navigator = LocalNavigator.currentOrThrow return Preference.PreferenceItem.TextPreference( title = stringResource(R.string.pref_create_backup), subtitle = stringResource(R.string.pref_create_backup_summ), - onClick = { - scope.launch { - if (!BackupCreateJob.isManualJobRunning(context)) { - if (DeviceUtil.isMiui && DeviceUtil.isMiuiOptimizationDisabled()) { - context.toast(R.string.restore_miui_warning, Toast.LENGTH_LONG) - } - showCreateDialog = true - } else { - context.toast(R.string.backup_in_progress) - } - } - }, - ) - } - - @Composable - private fun CreateBackupDialog( - onConfirm: (flag: Int) -> Unit, - onDismissRequest: () -> Unit, - ) { - val choices = remember { - mapOf( - BackupConst.BACKUP_CATEGORY to R.string.general_categories, - BackupConst.BACKUP_CHAPTER to R.string.chapters_episodes, - BackupConst.BACKUP_TRACK to R.string.track, - BackupConst.BACKUP_HISTORY to R.string.history, - BackupConst.BACKUP_PREFS to R.string.settings, - BackupConst.BACKUP_EXT_PREFS to R.string.extension_settings, - BackupConst.BACKUP_EXTENSIONS to R.string.label_extensions, - ) - } - val flags = remember { - mutableStateListOf( - BackupConst.BACKUP_CATEGORY, - BackupConst.BACKUP_CHAPTER, - BackupConst.BACKUP_TRACK, - BackupConst.BACKUP_HISTORY, - ) - } - AlertDialog( - onDismissRequest = onDismissRequest, - title = { Text(text = stringResource(R.string.backup_choice)) }, - text = { - Box { - val state = rememberLazyListState() - ScrollbarLazyColumn(state = state) { - item { - LabeledCheckbox( - label = stringResource(R.string.entries), - checked = true, - onCheckedChange = {}, - ) - } - choices.forEach { (k, v) -> - item { - val isSelected = flags.contains(k) - LabeledCheckbox( - label = stringResource(v), - checked = isSelected, - onCheckedChange = { - if (it) { - flags.add(k) - } else { - flags.remove(k) - } - }, - ) - } - } - } - if (!state.isScrolledToStart()) { - HorizontalDivider( - modifier = Modifier.align(Alignment.TopCenter), - ) - } - if (!state.isScrolledToEnd()) { - HorizontalDivider( - modifier = Modifier.align(Alignment.BottomCenter), - ) - } - } - }, - dismissButton = { - TextButton(onClick = onDismissRequest) { - Text(text = stringResource(R.string.action_cancel)) - } - }, - confirmButton = { - TextButton( - onClick = { - val flag = flags.fold(initial = 0, operation = { a, b -> a or b }) - onConfirm(flag) - }, - ) { - Text(text = stringResource(R.string.action_ok)) - } - }, + onClick = { navigator.push(CreateBackupScreen()) }, ) } @@ -362,7 +223,7 @@ object SettingsDataScreen : SearchableSettings { }, ) { if (it == null) { - error = InvalidRestore(message = context.getString(R.string.file_null_uri_error)) + context.toast(R.string.file_null_uri_error) return@rememberLauncherForActivityResult } diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsMainScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsMainScreen.kt index be3e4954c..6d8b7f1ac 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsMainScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsMainScreen.kt @@ -9,6 +9,7 @@ import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.outlined.ChromeReaderMode import androidx.compose.material.icons.outlined.ChromeReaderMode import androidx.compose.material.icons.outlined.Code import androidx.compose.material.icons.outlined.CollectionsBookmark @@ -47,6 +48,7 @@ import eu.kanade.presentation.more.settings.widget.TextPreferenceWidget import eu.kanade.presentation.util.LocalBackPress import eu.kanade.presentation.util.Screen import eu.kanade.tachiyomi.R +import kotlinx.collections.immutable.persistentListOf import tachiyomi.presentation.core.components.material.Scaffold import cafe.adriel.voyager.core.screen.Screen as VoyagerScreen @@ -87,7 +89,7 @@ object SettingsMainScreen : Screen() { navigateUp = backPress::invoke, actions = { AppBarActions( - listOf( + persistentListOf( AppBar.Action( title = stringResource(R.string.action_search), icon = Icons.Outlined.Search, @@ -188,7 +190,7 @@ object SettingsMainScreen : Screen() { Item( titleRes = R.string.pref_category_reader, subtitleRes = R.string.pref_reader_summary, - icon = Icons.Outlined.ChromeReaderMode, + icon = Icons.AutoMirrored.Outlined.ChromeReaderMode, screen = SettingsReaderScreen, ), Item( diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsPlayerScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsPlayerScreen.kt index 0dd8f8f23..0f4679140 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsPlayerScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsPlayerScreen.kt @@ -36,6 +36,7 @@ import eu.kanade.tachiyomi.ui.player.VLC_PLAYER import eu.kanade.tachiyomi.ui.player.WEB_VIDEO_CASTER import eu.kanade.tachiyomi.ui.player.X_PLAYER import eu.kanade.tachiyomi.ui.player.settings.PlayerPreferences +import kotlinx.collections.immutable.toImmutableList import tachiyomi.presentation.core.components.WheelTextPicker import tachiyomi.presentation.core.util.collectAsState import uy.kohesive.injekt.Injekt @@ -395,7 +396,7 @@ object SettingsPlayerScreen : SearchableSettings { R.string.seconds_short, it, ) - }, + }.toImmutableList(), onSelectionChanged = { newLength = it }, diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/about/OpenSourceLibraryLicenseScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/about/OpenSourceLibraryLicenseScreen.kt index 964f503b0..9b0da494c 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/about/OpenSourceLibraryLicenseScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/about/OpenSourceLibraryLicenseScreen.kt @@ -20,6 +20,7 @@ import eu.kanade.presentation.components.AppBar import eu.kanade.presentation.components.AppBarActions import eu.kanade.presentation.util.Screen import eu.kanade.tachiyomi.R +import kotlinx.collections.immutable.persistentListOf import tachiyomi.presentation.core.components.material.Scaffold class OpenSourceLibraryLicenseScreen( @@ -41,7 +42,7 @@ class OpenSourceLibraryLicenseScreen( actions = { if (!website.isNullOrEmpty()) { AppBarActions( - listOf( + persistentListOf( AppBar.Action( title = stringResource(R.string.website), icon = Icons.Default.Public, diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/advanced/ClearAnimeDatabaseScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/advanced/ClearAnimeDatabaseScreen.kt index 5e746a8cc..5f7ad3843 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/advanced/ClearAnimeDatabaseScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/advanced/ClearAnimeDatabaseScreen.kt @@ -41,6 +41,7 @@ import eu.kanade.presentation.components.AppBarActions import eu.kanade.presentation.util.Screen import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.util.system.toast +import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.update import tachiyomi.core.util.lang.launchIO @@ -106,7 +107,7 @@ class ClearAnimeDatabaseScreen : Screen() { actions = { if (s.items.isNotEmpty()) { AppBarActions( - actions = listOf( + actions = persistentListOf( AppBar.Action( title = stringResource(R.string.action_select_all), icon = Icons.Outlined.SelectAll, diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/advanced/ClearDatabaseScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/advanced/ClearDatabaseScreen.kt index b1d8ca71f..943629ade 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/advanced/ClearDatabaseScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/advanced/ClearDatabaseScreen.kt @@ -41,6 +41,7 @@ import eu.kanade.presentation.components.AppBarActions import eu.kanade.presentation.util.Screen import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.util.system.toast +import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.update import tachiyomi.core.util.lang.launchIO @@ -106,7 +107,7 @@ class ClearDatabaseScreen : Screen() { actions = { if (s.items.isNotEmpty()) { AppBarActions( - actions = listOf( + actions = persistentListOf( AppBar.Action( title = stringResource(R.string.action_select_all), icon = Icons.Outlined.SelectAll, diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/CreateBackupScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/CreateBackupScreen.kt new file mode 100644 index 000000000..5b168fe77 --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/CreateBackupScreen.kt @@ -0,0 +1,173 @@ +package eu.kanade.presentation.more.settings.screen.data + +import android.content.ActivityNotFoundException +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.widget.Toast +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material3.Button +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Immutable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import cafe.adriel.voyager.core.model.StateScreenModel +import cafe.adriel.voyager.core.model.rememberScreenModel +import cafe.adriel.voyager.navigator.LocalNavigator +import cafe.adriel.voyager.navigator.currentOrThrow +import eu.kanade.presentation.components.AppBar +import eu.kanade.presentation.util.Screen +import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.data.backup.BackupCreateFlags +import eu.kanade.tachiyomi.data.backup.BackupCreateJob +import eu.kanade.tachiyomi.data.backup.models.Backup +import eu.kanade.tachiyomi.util.system.DeviceUtil +import eu.kanade.tachiyomi.util.system.toast +import kotlinx.collections.immutable.PersistentSet +import kotlinx.collections.immutable.minus +import kotlinx.collections.immutable.plus +import kotlinx.collections.immutable.toPersistentSet +import kotlinx.coroutines.flow.update +import tachiyomi.presentation.core.components.LabeledCheckbox +import tachiyomi.presentation.core.components.material.Scaffold +import tachiyomi.presentation.core.components.material.padding + +class CreateBackupScreen : Screen() { + + @Composable + override fun Content() { + val context = LocalContext.current + val navigator = LocalNavigator.currentOrThrow + val model = rememberScreenModel { CreateBackupScreenModel() } + val state by model.state.collectAsState() + + val chooseBackupDir = rememberLauncherForActivityResult( + contract = ActivityResultContracts.CreateDocument("application/*"), + ) { + if (it != null) { + context.contentResolver.takePersistableUriPermission( + it, + Intent.FLAG_GRANT_READ_URI_PERMISSION or + Intent.FLAG_GRANT_WRITE_URI_PERMISSION, + ) + model.createBackup(context, it) + navigator.pop() + } + } + + Scaffold( + topBar = { + AppBar( + title = stringResource(R.string.pref_create_backup), + navigateUp = navigator::pop, + scrollBehavior = it, + ) + }, + ) { contentPadding -> + Column( + modifier = Modifier + .padding(contentPadding) + .fillMaxSize(), + ) { + LazyColumn( + modifier = Modifier + .weight(1f) + .padding(horizontal = MaterialTheme.padding.medium), + ) { + item { + LabeledCheckbox( + label = stringResource(R.string.entries), + checked = true, + onCheckedChange = {}, + enabled = false, + ) + } + BackupChoices.forEach { (k, v) -> + item { + LabeledCheckbox( + label = stringResource(v), + checked = state.flags.contains(k), + onCheckedChange = { + model.toggleFlag(k) + }, + ) + } + } + } + + HorizontalDivider() + + Button( + modifier = Modifier + .padding(horizontal = 16.dp, vertical = 8.dp) + .fillMaxWidth(), + onClick = { + if (!BackupCreateJob.isManualJobRunning(context)) { + if (DeviceUtil.isMiui && DeviceUtil.isMiuiOptimizationDisabled()) { + context.toast(R.string.restore_miui_warning, Toast.LENGTH_LONG) + } + try { + chooseBackupDir.launch(Backup.getFilename()) + } catch (e: ActivityNotFoundException) { + context.toast(R.string.file_picker_error) + } + } else { + context.toast(R.string.backup_in_progress) + } + }, + ) { + Text( + text = stringResource(R.string.action_create), + color = MaterialTheme.colorScheme.onPrimary, + ) + } + } + } + } +} + +private class CreateBackupScreenModel : StateScreenModel(State()) { + + fun toggleFlag(flag: Int) { + mutableState.update { + if (it.flags.contains(flag)) { + it.copy(flags = it.flags - flag) + } else { + it.copy(flags = it.flags + flag) + } + } + } + + fun createBackup(context: Context, uri: Uri) { + val flags = state.value.flags.fold(initial = 0, operation = { a, b -> a or b }) + BackupCreateJob.startNow(context, uri, flags) + } + + @Immutable + data class State( + val flags: PersistentSet = BackupChoices.keys.toPersistentSet(), + ) +} + +private val BackupChoices = mapOf( + BackupCreateFlags.BACKUP_CATEGORY to R.string.general_categories, + BackupCreateFlags.BACKUP_CHAPTER to R.string.chapters_episodes, + BackupCreateFlags.BACKUP_TRACK to R.string.track, + BackupCreateFlags.BACKUP_HISTORY to R.string.history, + BackupCreateFlags.BACKUP_PREFS to R.string.settings, + BackupCreateFlags.BACKUP_EXT_PREFS to R.string.extension_settings, + BackupCreateFlags.BACKUP_EXTENSIONS to R.string.label_extensions, +) diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/BackupSchemaScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/BackupSchemaScreen.kt index 3684804b5..61bc6c66e 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/BackupSchemaScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/BackupSchemaScreen.kt @@ -21,6 +21,7 @@ import eu.kanade.presentation.util.Screen import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.backup.models.Backup import eu.kanade.tachiyomi.util.system.copyToClipboard +import kotlinx.collections.immutable.persistentListOf import kotlinx.serialization.protobuf.schema.ProtoBufSchemaGenerator import tachiyomi.presentation.core.components.material.Scaffold @@ -48,7 +49,7 @@ class BackupSchemaScreen : Screen() { navigateUp = navigator::pop, actions = { AppBarActions( - listOf( + persistentListOf( AppBar.Action( title = stringResource(R.string.action_copy_to_clipboard), icon = Icons.Default.ContentCopy, diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/WorkerInfoScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/WorkerInfoScreen.kt index ba6f82ede..a7c557ca8 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/WorkerInfoScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/WorkerInfoScreen.kt @@ -33,6 +33,7 @@ import eu.kanade.presentation.util.ioCoroutineScope import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.util.system.copyToClipboard import eu.kanade.tachiyomi.util.system.workManager +import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn @@ -62,7 +63,7 @@ class WorkerInfoScreen : Screen() { navigateUp = navigator::pop, actions = { AppBarActions( - listOf( + persistentListOf( AppBar.Action( title = stringResource(R.string.action_copy_to_clipboard), icon = Icons.Default.ContentCopy, diff --git a/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt b/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt index aff4c8c3f..a57d63cc9 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt @@ -29,6 +29,7 @@ import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode import eu.kanade.tachiyomi.ui.reader.viewer.Viewer import eu.kanade.tachiyomi.ui.reader.viewer.pager.R2LPagerViewer +import kotlinx.collections.immutable.persistentListOf private val animationSpec = tween(200) @@ -98,27 +99,43 @@ fun ReaderAppBars( navigateUp = navigateUp, actions = { AppBarActions( - listOfNotNull( - AppBar.Action( - title = stringResource( - if (bookmarked) R.string.action_remove_bookmark else R.string.action_bookmark, - ), - icon = if (bookmarked) Icons.Outlined.Bookmark else Icons.Outlined.BookmarkBorder, - onClick = onToggleBookmarked, - ), - onOpenInWebView?.let { - AppBar.OverflowAction( - title = stringResource(R.string.action_open_in_web_view), - onClick = it, + actions = persistentListOf().builder() + .apply { + add( + AppBar.Action( + title = stringResource( + if (bookmarked) { + R.string.action_remove_bookmark + } else { + R.string.action_bookmark + }, + ), + icon = if (bookmarked) { + Icons.Outlined.Bookmark + } else { + Icons.Outlined.BookmarkBorder + }, + onClick = onToggleBookmarked, + ), ) - }, - onShare?.let { - AppBar.OverflowAction( - title = stringResource(R.string.action_share), - onClick = it, - ) - }, - ), + onOpenInWebView?.let { + add( + AppBar.OverflowAction( + title = stringResource(R.string.action_open_in_web_view), + onClick = it, + ), + ) + } + onShare?.let { + add( + AppBar.OverflowAction( + title = stringResource(R.string.action_share), + onClick = it, + ), + ) + } + } + .build(), ) }, ) diff --git a/app/src/main/java/eu/kanade/presentation/reader/settings/ReaderSettingsDialog.kt b/app/src/main/java/eu/kanade/presentation/reader/settings/ReaderSettingsDialog.kt index 583708d98..08dc5ae5e 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/settings/ReaderSettingsDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/settings/ReaderSettingsDialog.kt @@ -17,6 +17,7 @@ import eu.kanade.presentation.components.TabbedDialog import eu.kanade.presentation.components.TabbedDialogPaddings import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel +import kotlinx.collections.immutable.persistentListOf @Composable fun ReaderSettingsDialog( @@ -25,7 +26,7 @@ fun ReaderSettingsDialog( onHideMenus: () -> Unit, screenModel: ReaderSettingsScreenModel, ) { - val tabTitles = listOf( + val tabTitles = persistentListOf( stringResource(R.string.pref_category_reading_mode), stringResource(R.string.pref_category_general), stringResource(R.string.custom_filter), diff --git a/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogSelector.kt b/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogSelector.kt index 98b749312..f167b20ca 100644 --- a/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogSelector.kt +++ b/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogSelector.kt @@ -36,6 +36,8 @@ import androidx.compose.ui.tooling.preview.PreviewLightDark import androidx.compose.ui.unit.dp import eu.kanade.presentation.theme.TachiyomiTheme import eu.kanade.tachiyomi.R +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toImmutableList import tachiyomi.presentation.core.components.ScrollbarLazyColumn import tachiyomi.presentation.core.components.WheelNumberPicker import tachiyomi.presentation.core.components.WheelTextPicker @@ -114,9 +116,9 @@ fun TrackItemSelector( title = stringResource(titleText), content = { WheelNumberPicker( + items = range.toImmutableList(), modifier = Modifier.align(Alignment.Center), startIndex = selection, - items = range.toList(), onSelectionChanged = { onSelectionChange(it) }, ) }, @@ -129,7 +131,7 @@ fun TrackItemSelector( fun TrackScoreSelector( selection: String, onSelectionChange: (String) -> Unit, - selections: List, + selections: ImmutableList, onConfirm: () -> Unit, onDismissRequest: () -> Unit, ) { @@ -137,9 +139,9 @@ fun TrackScoreSelector( title = stringResource(R.string.score), content = { WheelTextPicker( + items = selections, modifier = Modifier.align(Alignment.Center), startIndex = selections.indexOf(selection).takeIf { it > 0 } ?: (selections.size / 2), - items = selections, onSelectionChanged = { onSelectionChange(selections[it]) }, ) }, @@ -203,9 +205,9 @@ fun TrackDateSelector( fun BaseSelector( title: String, content: @Composable BoxScope.() -> Unit, - thirdButton: @Composable (RowScope.() -> Unit)? = null, onConfirm: () -> Unit, onDismissRequest: () -> Unit, + thirdButton: @Composable (RowScope.() -> Unit)? = null, ) { AlertDialogContent( modifier = Modifier.windowInsetsPadding(WindowInsets.systemBars), diff --git a/app/src/main/java/eu/kanade/presentation/track/anime/AnimeTrackInfoDialogHomePreviewProvider.kt b/app/src/main/java/eu/kanade/presentation/track/anime/AnimeTrackInfoDialogHomePreviewProvider.kt index b71dcd30b..50b1aa82c 100644 --- a/app/src/main/java/eu/kanade/presentation/track/anime/AnimeTrackInfoDialogHomePreviewProvider.kt +++ b/app/src/main/java/eu/kanade/presentation/track/anime/AnimeTrackInfoDialogHomePreviewProvider.kt @@ -2,8 +2,8 @@ package eu.kanade.presentation.track.anime import androidx.compose.runtime.Composable import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import eu.kanade.tachiyomi.dev.preview.DummyTracker import eu.kanade.tachiyomi.ui.entries.anime.track.AnimeTrackItem +import eu.kanade.test.DummyTracker import tachiyomi.domain.track.anime.model.AnimeTrack import java.text.DateFormat diff --git a/app/src/main/java/eu/kanade/presentation/track/anime/AnimeTrackerSearch.kt b/app/src/main/java/eu/kanade/presentation/track/anime/AnimeTrackerSearch.kt index 00b27868a..1fbfb38db 100644 --- a/app/src/main/java/eu/kanade/presentation/track/anime/AnimeTrackerSearch.kt +++ b/app/src/main/java/eu/kanade/presentation/track/anime/AnimeTrackerSearch.kt @@ -18,7 +18,7 @@ import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.automirrored.outlined.ArrowBack import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.outlined.ArrowBack import androidx.compose.material3.Button @@ -81,7 +81,7 @@ fun AnimeTrackerSearch( navigationIcon = { IconButton(onClick = onDismissRequest) { Icon( - imageVector = Icons.Default.ArrowBack, + imageVector = Icons.AutoMirrored.Outlined.ArrowBack, contentDescription = null, tint = MaterialTheme.colorScheme.onSurfaceVariant, ) diff --git a/app/src/main/java/eu/kanade/presentation/track/components/TrackLogoIconPreviewProvider.kt b/app/src/main/java/eu/kanade/presentation/track/components/TrackLogoIconPreviewProvider.kt index aeaa577a1..3f5e4b840 100644 --- a/app/src/main/java/eu/kanade/presentation/track/components/TrackLogoIconPreviewProvider.kt +++ b/app/src/main/java/eu/kanade/presentation/track/components/TrackLogoIconPreviewProvider.kt @@ -4,7 +4,7 @@ import android.graphics.Color import androidx.compose.ui.tooling.preview.PreviewParameterProvider import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.track.Tracker -import eu.kanade.tachiyomi.dev.preview.DummyTracker +import eu.kanade.test.DummyTracker internal class TrackLogoIconPreviewProvider : PreviewParameterProvider { diff --git a/app/src/main/java/eu/kanade/presentation/track/manga/MangaTrackInfoDialogHome.kt b/app/src/main/java/eu/kanade/presentation/track/manga/MangaTrackInfoDialogHome.kt index 84f889305..78f1925e4 100644 --- a/app/src/main/java/eu/kanade/presentation/track/manga/MangaTrackInfoDialogHome.kt +++ b/app/src/main/java/eu/kanade/presentation/track/manga/MangaTrackInfoDialogHome.kt @@ -243,10 +243,10 @@ private fun TrackInfoItem( @Composable fun TrackDetailsItem( - modifier: Modifier = Modifier, text: String?, - placeholder: String = "", onClick: () -> Unit, + modifier: Modifier = Modifier, + placeholder: String = "", ) { Box( modifier = modifier diff --git a/app/src/main/java/eu/kanade/presentation/track/manga/MangaTrackInfoDialogHomePreviewProvider.kt b/app/src/main/java/eu/kanade/presentation/track/manga/MangaTrackInfoDialogHomePreviewProvider.kt index c487640fc..d65acf805 100644 --- a/app/src/main/java/eu/kanade/presentation/track/manga/MangaTrackInfoDialogHomePreviewProvider.kt +++ b/app/src/main/java/eu/kanade/presentation/track/manga/MangaTrackInfoDialogHomePreviewProvider.kt @@ -2,8 +2,8 @@ package eu.kanade.presentation.track.manga import androidx.compose.runtime.Composable import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import eu.kanade.tachiyomi.dev.preview.DummyTracker import eu.kanade.tachiyomi.ui.entries.manga.track.MangaTrackItem +import eu.kanade.test.DummyTracker import tachiyomi.domain.track.manga.model.MangaTrack import java.text.DateFormat diff --git a/app/src/main/java/eu/kanade/presentation/track/manga/MangaTrackerSearch.kt b/app/src/main/java/eu/kanade/presentation/track/manga/MangaTrackerSearch.kt index 61548517e..1338c32d4 100644 --- a/app/src/main/java/eu/kanade/presentation/track/manga/MangaTrackerSearch.kt +++ b/app/src/main/java/eu/kanade/presentation/track/manga/MangaTrackerSearch.kt @@ -28,10 +28,9 @@ import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.automirrored.outlined.ArrowBack import androidx.compose.material.icons.filled.CheckCircle import androidx.compose.material.icons.filled.Close -import androidx.compose.material.icons.outlined.ArrowBack import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.HorizontalDivider @@ -99,7 +98,7 @@ fun MangaTrackerSearch( navigationIcon = { IconButton(onClick = onDismissRequest) { Icon( - imageVector = Icons.Default.ArrowBack, + imageVector = Icons.AutoMirrored.Outlined.ArrowBack, contentDescription = null, tint = MaterialTheme.colorScheme.onSurfaceVariant, ) diff --git a/app/src/main/java/eu/kanade/presentation/updates/anime/AnimeUpdatesUiItem.kt b/app/src/main/java/eu/kanade/presentation/updates/anime/AnimeUpdatesUiItem.kt index e51bad177..d957ce794 100644 --- a/app/src/main/java/eu/kanade/presentation/updates/anime/AnimeUpdatesUiItem.kt +++ b/app/src/main/java/eu/kanade/presentation/updates/anime/AnimeUpdatesUiItem.kt @@ -98,14 +98,14 @@ fun LazyListScope.animeUpdatesUiItems( when (item) { is AnimeUpdatesUiModel.Header -> { ListGroupHeader( - modifier = Modifier.animateItemPlacement(), + text = item.date, ) } is AnimeUpdatesUiModel.Item -> { val updatesItem = item.item AnimeUpdatesUiItem( - modifier = Modifier.animateItemPlacement(), + update = updatesItem.update, selected = updatesItem.selected, watchProgress = updatesItem.update.lastSecondSeen @@ -146,7 +146,6 @@ fun LazyListScope.animeUpdatesUiItems( @OptIn(ExperimentalFoundationApi::class) @Composable fun AnimeUpdatesUiItem( - modifier: Modifier, update: AnimeUpdatesWithRelations, selected: Boolean, watchProgress: String?, @@ -157,6 +156,7 @@ fun AnimeUpdatesUiItem( // Download Indicator downloadStateProvider: () -> AnimeDownload.State, downloadProgressProvider: () -> Int, + modifier: Modifier = Modifier, ) { val haptic = LocalHapticFeedback.current val textAlpha = if (update.seen) ReadItemAlpha else 1f diff --git a/app/src/main/java/eu/kanade/presentation/updates/manga/MangaUpdatesUiItem.kt b/app/src/main/java/eu/kanade/presentation/updates/manga/MangaUpdatesUiItem.kt index 7516df9dd..b2fadf3d1 100644 --- a/app/src/main/java/eu/kanade/presentation/updates/manga/MangaUpdatesUiItem.kt +++ b/app/src/main/java/eu/kanade/presentation/updates/manga/MangaUpdatesUiItem.kt @@ -97,14 +97,14 @@ fun LazyListScope.mangaUpdatesUiItems( when (item) { is MangaUpdatesUiModel.Header -> { ListGroupHeader( - modifier = Modifier.animateItemPlacement(), + text = item.date, ) } is MangaUpdatesUiModel.Item -> { val updatesItem = item.item MangaUpdatesUiItem( - modifier = Modifier.animateItemPlacement(), + update = updatesItem.update, selected = updatesItem.selected, readProgress = updatesItem.update.lastPageRead @@ -144,7 +144,6 @@ fun LazyListScope.mangaUpdatesUiItems( @OptIn(ExperimentalFoundationApi::class) @Composable fun MangaUpdatesUiItem( - modifier: Modifier, update: MangaUpdatesWithRelations, selected: Boolean, readProgress: String?, @@ -155,6 +154,7 @@ fun MangaUpdatesUiItem( // Download Indicator downloadStateProvider: () -> MangaDownload.State, downloadProgressProvider: () -> Int, + modifier: Modifier = Modifier, ) { val haptic = LocalHapticFeedback.current val textAlpha = if (update.read) ReadItemAlpha else 1f diff --git a/app/src/main/java/eu/kanade/presentation/util/Navigator.kt b/app/src/main/java/eu/kanade/presentation/util/Navigator.kt index ca1afc986..54596dd90 100644 --- a/app/src/main/java/eu/kanade/presentation/util/Navigator.kt +++ b/app/src/main/java/eu/kanade/presentation/util/Navigator.kt @@ -1,5 +1,6 @@ package eu.kanade.presentation.util +import android.annotation.SuppressLint import androidx.compose.animation.AnimatedContent import androidx.compose.animation.AnimatedContentTransitionScope import androidx.compose.animation.ContentTransform @@ -27,6 +28,7 @@ import soup.compose.material.motion.animation.rememberSlideDistance /** * For invoking back press to the parent activity */ +@SuppressLint("ComposeCompositionLocalUsage") val LocalBackPress: ProvidableCompositionLocal<(() -> Unit)?> = staticCompositionLocalOf { null } abstract class Tab : cafe.adriel.voyager.navigator.tab.Tab { @@ -81,7 +83,7 @@ fun ScreenTransition( targetState = navigator.lastItem, transitionSpec = transition, modifier = modifier, - label = "", + label = "transition", ) { screen -> navigator.saveableState("transition", screen) { content(screen) diff --git a/app/src/main/java/eu/kanade/presentation/webview/WebViewScreenContent.kt b/app/src/main/java/eu/kanade/presentation/webview/WebViewScreenContent.kt index 750b05d6b..0d6e3cc88 100644 --- a/app/src/main/java/eu/kanade/presentation/webview/WebViewScreenContent.kt +++ b/app/src/main/java/eu/kanade/presentation/webview/WebViewScreenContent.kt @@ -41,6 +41,7 @@ import eu.kanade.tachiyomi.BuildConfig import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.util.system.getHtml import eu.kanade.tachiyomi.util.system.setDefaultSettings +import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.launch import tachiyomi.presentation.core.components.material.Scaffold @@ -49,11 +50,11 @@ fun WebViewScreenContent( onNavigateUp: () -> Unit, initialTitle: String?, url: String, - headers: Map = emptyMap(), - onUrlChange: (String) -> Unit = {}, onShare: (String) -> Unit, onOpenInBrowser: (String) -> Unit, onClearCookies: (String) -> Unit, + headers: Map = emptyMap(), + onUrlChange: (String) -> Unit = {}, ) { val state = rememberWebViewState(url = url, additionalHttpHeaders = headers) val navigator = rememberWebViewNavigator() @@ -116,7 +117,7 @@ fun WebViewScreenContent( navigationIcon = Icons.Outlined.Close, actions = { AppBarActions( - listOf( + persistentListOf( AppBar.Action( title = stringResource(R.string.action_webview_back), icon = Icons.Outlined.ArrowBack, @@ -182,7 +183,7 @@ fun WebViewScreenContent( .align(Alignment.BottomCenter), ) is LoadingState.Loading -> LinearProgressIndicator( - progress = (loadingState as? LoadingState.Loading)?.progress ?: 1f, + progress = { (loadingState as? LoadingState.Loading)?.progress ?: 1f }, modifier = Modifier .fillMaxWidth() .align(Alignment.BottomCenter), diff --git a/app/src/main/java/eu/kanade/tachiyomi/App.kt b/app/src/main/java/eu/kanade/tachiyomi/App.kt index 14c6e0f16..471034489 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/App.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/App.kt @@ -38,6 +38,8 @@ import eu.kanade.tachiyomi.data.coil.MangaCoverKeyer import eu.kanade.tachiyomi.data.coil.MangaKeyer import eu.kanade.tachiyomi.data.coil.TachiyomiImageDecoder import eu.kanade.tachiyomi.data.notification.Notifications +import eu.kanade.tachiyomi.di.AppModule +import eu.kanade.tachiyomi.di.PreferenceModule import eu.kanade.tachiyomi.network.NetworkHelper import eu.kanade.tachiyomi.network.NetworkPreferences import eu.kanade.tachiyomi.ui.base.delegate.SecureActivityDelegate @@ -59,8 +61,8 @@ import org.acra.ktx.initAcra import org.acra.sender.HttpSender import org.conscrypt.Conscrypt import tachiyomi.core.util.system.logcat -import tachiyomi.presentation.widget.entries.anime.TachiyomiAnimeWidgetManager -import tachiyomi.presentation.widget.entries.manga.TachiyomiMangaWidgetManager +import tachiyomi.presentation.widget.entries.anime.AnimeWidgetManager +import tachiyomi.presentation.widget.entries.manga.MangaWidgetManager import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import uy.kohesive.injekt.injectLazy @@ -134,11 +136,11 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory { setAppCompatDelegateThemeMode(Injekt.get().themeMode().get()) // Updates widget update - with(TachiyomiMangaWidgetManager(Injekt.get(), Injekt.get())) { + with(MangaWidgetManager(Injekt.get(), Injekt.get())) { init(ProcessLifecycleOwner.get().lifecycleScope) } - with(TachiyomiAnimeWidgetManager(Injekt.get(), Injekt.get())) { + with(AnimeWidgetManager(Injekt.get(), Injekt.get())) { init(ProcessLifecycleOwner.get().lifecycleScope) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupConst.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupConst.kt deleted file mode 100644 index c67de94fe..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupConst.kt +++ /dev/null @@ -1,27 +0,0 @@ -package eu.kanade.tachiyomi.data.backup - -// Filter options -internal object BackupConst { - const val BACKUP_CATEGORY = 0x1 - const val BACKUP_CATEGORY_MASK = 0x1 - - const val BACKUP_CHAPTER = 0x2 - const val BACKUP_CHAPTER_MASK = 0x2 - - const val BACKUP_HISTORY = 0x4 - const val BACKUP_HISTORY_MASK = 0x4 - - const val BACKUP_TRACK = 0x8 - const val BACKUP_TRACK_MASK = 0x8 - - const val BACKUP_PREFS = 0x10 - const val BACKUP_PREFS_MASK = 0x10 - - const val BACKUP_EXT_PREFS = 0x20 - const val BACKUP_EXT_PREFS_MASK = 0x20 - - const val BACKUP_EXTENSIONS = 0x40 - const val BACKUP_EXTENSIONS_MASK = 0x40 - - const val BACKUP_ALL = 0x7F -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreateFlags.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreateFlags.kt new file mode 100644 index 000000000..cd58627eb --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreateFlags.kt @@ -0,0 +1,18 @@ +package eu.kanade.tachiyomi.data.backup + +internal object BackupCreateFlags { + const val BACKUP_CATEGORY = 0x1 + const val BACKUP_CHAPTER = 0x2 + const val BACKUP_HISTORY = 0x4 + const val BACKUP_TRACK = 0x8 + const val BACKUP_PREFS = 0x10 + const val BACKUP_EXT_PREFS = 0x20 + const val BACKUP_EXTENSIONS = 0x40 + + const val AutomaticDefaults = BACKUP_CATEGORY or + BACKUP_CHAPTER or + BACKUP_HISTORY or + BACKUP_TRACK or + BACKUP_PREFS or + BACKUP_EXT_PREFS +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreateJob.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreateJob.kt index 2f22972c1..7ac4f72c6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreateJob.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreateJob.kt @@ -40,7 +40,7 @@ class BackupCreateJob(private val context: Context, workerParams: WorkerParamete val backupPreferences = Injekt.get() val uri = inputData.getString(LOCATION_URI_KEY)?.toUri() ?: backupPreferences.backupsDirectory().get().toUri() - val flags = inputData.getInt(BACKUP_FLAGS_KEY, BackupConst.BACKUP_ALL) + val flags = inputData.getInt(BACKUP_FLAGS_KEY, BackupCreateFlags.AutomaticDefaults) try { setForeground(getForegroundInfo()) } catch (e: IllegalStateException) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreator.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreator.kt index bf0daf0ab..09eec5db3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreator.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreator.kt @@ -8,6 +8,13 @@ import android.net.Uri import androidx.preference.PreferenceManager import com.hippo.unifile.UniFile import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.data.backup.BackupCreateFlags.BACKUP_CATEGORY +import eu.kanade.tachiyomi.data.backup.BackupCreateFlags.BACKUP_CHAPTER +import eu.kanade.tachiyomi.data.backup.BackupCreateFlags.BACKUP_EXTENSIONS +import eu.kanade.tachiyomi.data.backup.BackupCreateFlags.BACKUP_EXT_PREFS +import eu.kanade.tachiyomi.data.backup.BackupCreateFlags.BACKUP_HISTORY +import eu.kanade.tachiyomi.data.backup.BackupCreateFlags.BACKUP_PREFS +import eu.kanade.tachiyomi.data.backup.BackupCreateFlags.BACKUP_TRACK import eu.kanade.tachiyomi.data.backup.models.Backup import eu.kanade.tachiyomi.data.backup.models.BackupAnime import eu.kanade.tachiyomi.data.backup.models.BackupAnimeHistory @@ -190,7 +197,7 @@ class BackupCreator( */ private suspend fun backupCategories(options: Int): List { // Check if user wants category information in backup - return if (options and BackupConst.BACKUP_CATEGORY_MASK == BackupConst.BACKUP_CATEGORY) { + return if (options and BACKUP_CATEGORY == BACKUP_CATEGORY) { getMangaCategories.await() .filterNot(Category::isSystemCategory) .map(backupCategoryMapper) @@ -206,7 +213,7 @@ class BackupCreator( */ private suspend fun backupAnimeCategories(options: Int): List { // Check if user wants category information in backup - return if (options and BackupConst.BACKUP_CATEGORY_MASK == BackupConst.BACKUP_CATEGORY) { + return if (options and BACKUP_CATEGORY == BACKUP_CATEGORY) { getAnimeCategories.await() .filterNot(Category::isSystemCategory) .map(backupCategoryMapper) @@ -239,7 +246,7 @@ class BackupCreator( val mangaObject = BackupManga.copyFrom(manga) // Check if user wants chapter information in backup - if (options and BackupConst.BACKUP_CHAPTER_MASK == BackupConst.BACKUP_CHAPTER) { + if (options and BACKUP_CHAPTER == BACKUP_CHAPTER) { // Backup all the chapters mangaHandler.awaitList { chaptersQueries.getChaptersByMangaId( @@ -253,7 +260,7 @@ class BackupCreator( } // Check if user wants category information in backup - if (options and BackupConst.BACKUP_CATEGORY_MASK == BackupConst.BACKUP_CATEGORY) { + if (options and BACKUP_CATEGORY == BACKUP_CATEGORY) { // Backup categories for this manga val categoriesForManga = getMangaCategories.await(manga.id) if (categoriesForManga.isNotEmpty()) { @@ -262,7 +269,7 @@ class BackupCreator( } // Check if user wants track information in backup - if (options and BackupConst.BACKUP_TRACK_MASK == BackupConst.BACKUP_TRACK) { + if (options and BACKUP_TRACK == BACKUP_TRACK) { val tracks = mangaHandler.awaitList { manga_syncQueries.getTracksByMangaId( manga.id, @@ -275,7 +282,7 @@ class BackupCreator( } // Check if user wants history information in backup - if (options and BackupConst.BACKUP_HISTORY_MASK == BackupConst.BACKUP_HISTORY) { + if (options and BACKUP_HISTORY == BACKUP_HISTORY) { val historyByMangaId = getMangaHistory.await(manga.id) if (historyByMangaId.isNotEmpty()) { val history = historyByMangaId.map { history -> @@ -307,7 +314,7 @@ class BackupCreator( val animeObject = BackupAnime.copyFrom(anime) // Check if user wants chapter information in backup - if (options and BackupConst.BACKUP_CHAPTER_MASK == BackupConst.BACKUP_CHAPTER) { + if (options and BACKUP_CHAPTER == BACKUP_CHAPTER) { // Backup all the chapters val episodes = animeHandler.awaitList { episodesQueries.getEpisodesByAnimeId( @@ -321,7 +328,7 @@ class BackupCreator( } // Check if user wants category information in backup - if (options and BackupConst.BACKUP_CATEGORY_MASK == BackupConst.BACKUP_CATEGORY) { + if (options and BACKUP_CATEGORY == BACKUP_CATEGORY) { // Backup categories for this manga val categoriesForAnime = getAnimeCategories.await(anime.id) if (categoriesForAnime.isNotEmpty()) { @@ -330,7 +337,7 @@ class BackupCreator( } // Check if user wants track information in backup - if (options and BackupConst.BACKUP_TRACK_MASK == BackupConst.BACKUP_TRACK) { + if (options and BACKUP_TRACK == BACKUP_TRACK) { val tracks = animeHandler.awaitList { anime_syncQueries.getTracksByAnimeId( anime.id, @@ -343,7 +350,7 @@ class BackupCreator( } // Check if user wants history information in backup - if (options and BackupConst.BACKUP_HISTORY_MASK == BackupConst.BACKUP_HISTORY) { + if (options and BACKUP_HISTORY == BACKUP_HISTORY) { val historyByAnimeId = getAnimeHistory.await(anime.id) if (historyByAnimeId.isNotEmpty()) { val history = historyByAnimeId.map { history -> @@ -364,7 +371,7 @@ class BackupCreator( } private fun backupExtensionPreferences(flags: Int): List { - if (flags and BackupConst.BACKUP_EXT_PREFS_MASK != BackupConst.BACKUP_EXT_PREFS) return emptyList() + if (flags and BACKUP_EXT_PREFS != BACKUP_EXT_PREFS) return emptyList() val prefs = mutableListOf>() Injekt.get().getCatalogueSources().forEach { val name = it.getPreferenceKey() @@ -377,14 +384,14 @@ class BackupCreator( return prefs.map { BackupExtensionPreferences( it.first, - backupPreferences(it.second, BackupConst.BACKUP_PREFS), + backupPreferences(it.second, BACKUP_PREFS), ) } } @Suppress("DEPRECATION") private fun backupExtensions(flags: Int): List { - if (flags and BackupConst.BACKUP_EXTENSIONS_MASK != BackupConst.BACKUP_EXTENSIONS) return emptyList() + if (flags and BACKUP_EXTENSIONS != BACKUP_EXTENSIONS) return emptyList() val installedExtensions = mutableListOf() Injekt.get().installedExtensionsFlow.value.forEach { val packageName = it.pkgName @@ -416,7 +423,7 @@ class BackupCreator( } private fun backupPreferences(prefs: SharedPreferences, flags: Int): List { - if (flags and BackupConst.BACKUP_PREFS_MASK != BackupConst.BACKUP_PREFS) return emptyList() + if (flags and BACKUP_PREFS != BACKUP_PREFS) return emptyList() val backupPreferences = mutableListOf() for (pref in prefs.all) { val toAdd = when (pref.value) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/AnimeTracker.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/AnimeTracker.kt index ac5678d57..a5bd6c60a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/AnimeTracker.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/AnimeTracker.kt @@ -6,6 +6,7 @@ import eu.kanade.domain.track.anime.model.toDomainTrack import eu.kanade.tachiyomi.data.database.models.anime.AnimeTrack import eu.kanade.tachiyomi.data.track.model.AnimeTrackSearch import eu.kanade.tachiyomi.util.system.toast +import kotlinx.collections.immutable.ImmutableList import logcat.LogPriority import tachiyomi.core.util.lang.withIOContext import tachiyomi.core.util.lang.withUIContext @@ -24,7 +25,7 @@ interface AnimeTracker { // Common functions fun getCompletionStatus(): Int - fun getScoreList(): List + fun getScoreList(): ImmutableList fun indexToScore(index: Int): Float { return index.toFloat() diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/MangaTracker.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/MangaTracker.kt index da5830b07..5fbed0ebf 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/MangaTracker.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/MangaTracker.kt @@ -6,6 +6,7 @@ import eu.kanade.domain.track.manga.model.toDomainTrack import eu.kanade.tachiyomi.data.database.models.manga.MangaTrack import eu.kanade.tachiyomi.data.track.model.MangaTrackSearch import eu.kanade.tachiyomi.util.system.toast +import kotlinx.collections.immutable.ImmutableList import logcat.LogPriority import tachiyomi.core.util.lang.withIOContext import tachiyomi.core.util.lang.withUIContext @@ -24,7 +25,7 @@ interface MangaTracker { // Common functions fun getCompletionStatus(): Int - fun getScoreList(): List + fun getScoreList(): ImmutableList fun indexToScore(index: Int): Float { return index.toFloat() diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/Tracker.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/Tracker.kt index 214e673a7..c9763ecd6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/Tracker.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/Tracker.kt @@ -4,6 +4,7 @@ import androidx.annotation.CallSuper import androidx.annotation.ColorInt import androidx.annotation.DrawableRes import androidx.annotation.StringRes +import kotlinx.collections.immutable.ImmutableList import okhttp3.OkHttpClient interface Tracker { @@ -25,8 +26,11 @@ interface Tracker { @StringRes fun getStatus(status: Int): Int? + fun getCompletionStatus(): Int - fun getScoreList(): List + + fun getScoreList(): ImmutableList + suspend fun login(username: String, password: String) @CallSuper diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/Anilist.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/Anilist.kt index 7e7a165ee..c27f44793 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/Anilist.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/Anilist.kt @@ -12,6 +12,9 @@ import eu.kanade.tachiyomi.data.track.DeletableMangaTracker import eu.kanade.tachiyomi.data.track.MangaTracker import eu.kanade.tachiyomi.data.track.model.AnimeTrackSearch import eu.kanade.tachiyomi.data.track.model.MangaTrackSearch +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toImmutableList import kotlinx.serialization.decodeFromString import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json @@ -103,18 +106,18 @@ class Anilist(id: Long) : override fun getCompletionStatus(): Int = COMPLETED - override fun getScoreList(): List { + override fun getScoreList(): ImmutableList { return when (scorePreference.get()) { // 10 point - POINT_10 -> IntRange(0, 10).map(Int::toString) + POINT_10 -> IntRange(0, 10).map(Int::toString).toImmutableList() // 100 point - POINT_100 -> IntRange(0, 100).map(Int::toString) + POINT_100 -> IntRange(0, 100).map(Int::toString).toImmutableList() // 5 stars - POINT_5 -> IntRange(0, 5).map { "$it ★" } + POINT_5 -> IntRange(0, 5).map { "$it ★" }.toImmutableList() // Smiley - POINT_3 -> listOf("-", "😦", "😐", "😊") + POINT_3 -> persistentListOf("-", "😦", "😐", "😊") // 10 point decimal - POINT_10_DECIMAL -> IntRange(0, 100).map { (it / 10f).toString() } + POINT_10_DECIMAL -> IntRange(0, 100).map { (it / 10f).toString() }.toImmutableList() else -> throw Exception("Unknown score type") } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/Bangumi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/Bangumi.kt index e260c3690..8724b9011 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/Bangumi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/Bangumi.kt @@ -10,6 +10,8 @@ import eu.kanade.tachiyomi.data.track.BaseTracker import eu.kanade.tachiyomi.data.track.MangaTracker import eu.kanade.tachiyomi.data.track.model.AnimeTrackSearch import eu.kanade.tachiyomi.data.track.model.MangaTrackSearch +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toImmutableList import kotlinx.serialization.decodeFromString import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json @@ -23,9 +25,7 @@ class Bangumi(id: Long) : BaseTracker(id, "Bangumi"), MangaTracker, AnimeTracker private val api by lazy { BangumiApi(id, client, interceptor) } - override fun getScoreList(): List { - return IntRange(0, 10).map(Int::toString) - } + override fun getScoreList(): ImmutableList = SCORE_LIST override fun indexToScore(index: Int): Float { return index.toFloat() @@ -218,5 +218,9 @@ class Bangumi(id: Long) : BaseTracker(id, "Bangumi"), MangaTracker, AnimeTracker const val ON_HOLD = 4 const val DROPPED = 5 const val PLAN_TO_READ = 1 + + private val SCORE_LIST = IntRange(0, 10) + .map(Int::toString) + .toImmutableList() } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/Kavita.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/Kavita.kt index e1ed12c0f..98ac46a82 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/Kavita.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/Kavita.kt @@ -12,6 +12,8 @@ import eu.kanade.tachiyomi.data.track.model.MangaTrackSearch import eu.kanade.tachiyomi.source.ConfigurableSource import eu.kanade.tachiyomi.source.MangaSource import eu.kanade.tachiyomi.source.sourcePreferences +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf import tachiyomi.domain.entries.manga.model.Manga import tachiyomi.domain.source.manga.service.MangaSourceManager import uy.kohesive.injekt.injectLazy @@ -53,7 +55,7 @@ class Kavita(id: Long) : BaseTracker(id, "Kavita"), EnhancedMangaTracker, MangaT override fun getCompletionStatus(): Int = COMPLETED - override fun getScoreList(): List = emptyList() + override fun getScoreList(): ImmutableList = persistentListOf() override fun displayScore(track: MangaTrack): String = "" diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/Kitsu.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/Kitsu.kt index 5c49d4569..76d4bf91f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/Kitsu.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/Kitsu.kt @@ -12,6 +12,8 @@ import eu.kanade.tachiyomi.data.track.DeletableMangaTracker import eu.kanade.tachiyomi.data.track.MangaTracker import eu.kanade.tachiyomi.data.track.model.AnimeTrackSearch import eu.kanade.tachiyomi.data.track.model.MangaTrackSearch +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toImmutableList import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import uy.kohesive.injekt.injectLazy @@ -79,9 +81,9 @@ class Kitsu(id: Long) : override fun getCompletionStatus(): Int = COMPLETED - override fun getScoreList(): List { + override fun getScoreList(): ImmutableList { val df = DecimalFormat("0.#") - return listOf("0") + IntRange(2, 20).map { df.format(it / 2f) } + return (listOf("0") + IntRange(2, 20).map { df.format(it / 2f) }).toImmutableList() } override fun indexToScore(index: Int): Float { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/komga/Komga.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/komga/Komga.kt index e1a428049..d60a94376 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/komga/Komga.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/komga/Komga.kt @@ -9,6 +9,8 @@ import eu.kanade.tachiyomi.data.track.EnhancedMangaTracker import eu.kanade.tachiyomi.data.track.MangaTracker import eu.kanade.tachiyomi.data.track.model.MangaTrackSearch import eu.kanade.tachiyomi.source.MangaSource +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf import okhttp3.Dns import okhttp3.OkHttpClient import tachiyomi.domain.entries.manga.model.Manga @@ -51,7 +53,7 @@ class Komga(id: Long) : BaseTracker(id, "Komga"), EnhancedMangaTracker, MangaTra override fun getCompletionStatus(): Int = COMPLETED - override fun getScoreList(): List = emptyList() + override fun getScoreList(): ImmutableList = persistentListOf() override suspend fun update(track: MangaTrack, didReadChapter: Boolean): MangaTrack { if (track.status != COMPLETED) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/MangaUpdates.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/MangaUpdates.kt index 304180d59..156a5d53d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/MangaUpdates.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/MangaUpdates.kt @@ -10,6 +10,8 @@ import eu.kanade.tachiyomi.data.track.MangaTracker import eu.kanade.tachiyomi.data.track.mangaupdates.dto.copyTo import eu.kanade.tachiyomi.data.track.mangaupdates.dto.toTrackSearch import eu.kanade.tachiyomi.data.track.model.MangaTrackSearch +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toImmutableList class MangaUpdates(id: Long) : BaseTracker(id, "MangaUpdates"), MangaTracker, DeletableMangaTracker { @@ -19,6 +21,12 @@ class MangaUpdates(id: Long) : BaseTracker(id, "MangaUpdates"), MangaTracker, De const val COMPLETE_LIST = 2 const val UNFINISHED_LIST = 3 const val ON_HOLD_LIST = 4 + + private val SCORE_LIST = ( + (0..9) + .flatMap { i -> (0..9).map { j -> "$i.$j" } } + listOf("10.0") + ) + .toImmutableList() } private val interceptor by lazy { MangaUpdatesInterceptor(this) } @@ -49,11 +57,9 @@ class MangaUpdates(id: Long) : BaseTracker(id, "MangaUpdates"), MangaTracker, De override fun getCompletionStatus(): Int = COMPLETE_LIST - private val _scoreList = (0..9).flatMap { i -> (0..9).map { j -> "$i.$j" } } + listOf("10.0") + override fun getScoreList(): ImmutableList = SCORE_LIST - override fun getScoreList(): List = _scoreList - - override fun indexToScore(index: Int): Float = _scoreList[index].toFloat() + override fun indexToScore(index: Int): Float = SCORE_LIST[index].toFloat() override fun displayScore(track: MangaTrack): String = track.score.toString() diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeList.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeList.kt index 45d16b76a..5a161f784 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeList.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeList.kt @@ -12,6 +12,8 @@ import eu.kanade.tachiyomi.data.track.DeletableMangaTracker import eu.kanade.tachiyomi.data.track.MangaTracker import eu.kanade.tachiyomi.data.track.model.AnimeTrackSearch import eu.kanade.tachiyomi.data.track.model.MangaTrackSearch +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toImmutableList import kotlinx.serialization.decodeFromString import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json @@ -40,6 +42,10 @@ class MyAnimeList(id: Long) : private const val SEARCH_ID_PREFIX = "id:" private const val SEARCH_LIST_PREFIX = "my:" + + private val SCORE_LIST = IntRange(0, 10) + .map(Int::toString) + .toImmutableList() } private val json: Json by injectLazy() @@ -85,9 +91,7 @@ class MyAnimeList(id: Long) : override fun getCompletionStatus(): Int = COMPLETED - override fun getScoreList(): List { - return IntRange(0, 10).map(Int::toString) - } + override fun getScoreList(): ImmutableList = SCORE_LIST override fun indexToScore(index: Int): Float { return index.toFloat() diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/Shikimori.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/Shikimori.kt index 073fb00ad..0f582dd7e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/Shikimori.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/Shikimori.kt @@ -12,6 +12,8 @@ import eu.kanade.tachiyomi.data.track.DeletableMangaTracker import eu.kanade.tachiyomi.data.track.MangaTracker import eu.kanade.tachiyomi.data.track.model.AnimeTrackSearch import eu.kanade.tachiyomi.data.track.model.MangaTrackSearch +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toImmutableList import kotlinx.serialization.decodeFromString import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json @@ -34,6 +36,10 @@ class Shikimori(id: Long) : const val DROPPED = 4 const val PLAN_TO_READ = 5 const val REREADING = 6 + + private val SCORE_LIST = IntRange(0, 10) + .map(Int::toString) + .toImmutableList() } private val json: Json by injectLazy() @@ -42,9 +48,7 @@ class Shikimori(id: Long) : private val api by lazy { ShikimoriApi(id, client, interceptor) } - override fun getScoreList(): List { - return IntRange(0, 10).map(Int::toString) - } + override fun getScoreList(): ImmutableList = SCORE_LIST override fun indexToScore(index: Int): Float { return index.toFloat() diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/simkl/Simkl.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/simkl/Simkl.kt index a440b0b76..970a60d8f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/simkl/Simkl.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/simkl/Simkl.kt @@ -7,6 +7,8 @@ import eu.kanade.tachiyomi.data.database.models.anime.AnimeTrack import eu.kanade.tachiyomi.data.track.AnimeTracker import eu.kanade.tachiyomi.data.track.BaseTracker import eu.kanade.tachiyomi.data.track.model.AnimeTrackSearch +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toImmutableList import kotlinx.serialization.decodeFromString import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json @@ -20,6 +22,10 @@ class Simkl(id: Long) : BaseTracker(id, "Simkl"), AnimeTracker { const val ON_HOLD = 3 const val NOT_INTERESTING = 4 const val PLAN_TO_WATCH = 5 + + private val SCORE_LIST = IntRange(0, 10) + .map(Int::toString) + .toImmutableList() } private val json: Json by injectLazy() @@ -28,9 +34,7 @@ class Simkl(id: Long) : BaseTracker(id, "Simkl"), AnimeTracker { private val api by lazy { SimklApi(client, interceptor) } - override fun getScoreList(): List { - return IntRange(0, 10).map(Int::toString) - } + override fun getScoreList(): ImmutableList = SCORE_LIST override fun displayScore(track: AnimeTrack): String { return track.score.toInt().toString() diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/Suwayomi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/Suwayomi.kt index c4835635c..7f2e24ce5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/Suwayomi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/Suwayomi.kt @@ -9,6 +9,8 @@ import eu.kanade.tachiyomi.data.track.EnhancedMangaTracker import eu.kanade.tachiyomi.data.track.MangaTracker import eu.kanade.tachiyomi.data.track.model.MangaTrackSearch import eu.kanade.tachiyomi.source.MangaSource +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf import tachiyomi.domain.entries.manga.model.Manga as DomainManga import tachiyomi.domain.track.manga.model.MangaTrack as DomainTrack @@ -42,7 +44,7 @@ class Suwayomi(id: Long) : BaseTracker(id, "Suwayomi"), EnhancedMangaTracker, Ma override fun getCompletionStatus(): Int = COMPLETED - override fun getScoreList(): List = emptyList() + override fun getScoreList(): ImmutableList = persistentListOf() override fun displayScore(track: MangaTrack): String = "" diff --git a/app/src/main/java/eu/kanade/tachiyomi/AppModule.kt b/app/src/main/java/eu/kanade/tachiyomi/di/AppModule.kt similarity index 77% rename from app/src/main/java/eu/kanade/tachiyomi/AppModule.kt rename to app/src/main/java/eu/kanade/tachiyomi/di/AppModule.kt index e7a98ebe6..246edfb18 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/AppModule.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/di/AppModule.kt @@ -1,4 +1,4 @@ -package eu.kanade.tachiyomi +package eu.kanade.tachiyomi.di import android.app.Application import android.os.Build @@ -10,14 +10,9 @@ import data.History import data.Mangas import dataanime.Animehistory import dataanime.Animes -import eu.kanade.domain.base.BasePreferences -import eu.kanade.domain.source.service.SourcePreferences import eu.kanade.domain.track.anime.store.DelayedAnimeTrackingStore import eu.kanade.domain.track.manga.store.DelayedMangaTrackingStore -import eu.kanade.domain.track.service.TrackPreferences -import eu.kanade.domain.ui.UiPreferences -import eu.kanade.tachiyomi.core.preference.AndroidPreferenceStore -import eu.kanade.tachiyomi.core.security.SecurityPreferences +import eu.kanade.tachiyomi.BuildConfig import eu.kanade.tachiyomi.data.cache.AnimeCoverCache import eu.kanade.tachiyomi.data.cache.ChapterCache import eu.kanade.tachiyomi.data.cache.EpisodeCache @@ -34,21 +29,14 @@ import eu.kanade.tachiyomi.extension.anime.AnimeExtensionManager import eu.kanade.tachiyomi.extension.manga.MangaExtensionManager import eu.kanade.tachiyomi.network.JavaScriptEngine import eu.kanade.tachiyomi.network.NetworkHelper -import eu.kanade.tachiyomi.network.NetworkPreferences import eu.kanade.tachiyomi.source.anime.AndroidAnimeSourceManager import eu.kanade.tachiyomi.source.manga.AndroidMangaSourceManager import eu.kanade.tachiyomi.ui.player.ExternalIntents -import eu.kanade.tachiyomi.ui.player.settings.PlayerPreferences -import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences -import eu.kanade.tachiyomi.util.system.isDevFlavor import io.requery.android.database.sqlite.RequerySQLiteOpenHelperFactory import kotlinx.serialization.json.Json import nl.adaptivity.xmlutil.XmlDeclMode import nl.adaptivity.xmlutil.core.XmlVersion import nl.adaptivity.xmlutil.serialization.XML -import tachiyomi.core.preference.PreferenceStore -import tachiyomi.core.provider.AndroidBackupFolderProvider -import tachiyomi.core.provider.AndroidDownloadFolderProvider import tachiyomi.data.Database import tachiyomi.data.DateColumnAdapter import tachiyomi.data.StringListColumnAdapter @@ -57,9 +45,6 @@ import tachiyomi.data.handlers.anime.AndroidAnimeDatabaseHandler import tachiyomi.data.handlers.anime.AnimeDatabaseHandler import tachiyomi.data.handlers.manga.AndroidMangaDatabaseHandler import tachiyomi.data.handlers.manga.MangaDatabaseHandler -import tachiyomi.domain.backup.service.BackupPreferences -import tachiyomi.domain.download.service.DownloadPreferences -import tachiyomi.domain.library.service.LibraryPreferences import tachiyomi.domain.source.anime.service.AnimeSourceManager import tachiyomi.domain.source.manga.service.MangaSourceManager import tachiyomi.mi.data.AnimeDatabase @@ -238,59 +223,3 @@ class AppModule(val app: Application) : InjektModule { } } } - -class PreferenceModule(val application: Application) : InjektModule { - override fun InjektRegistrar.registerInjectables() { - addSingletonFactory { - AndroidPreferenceStore(application) - } - addSingletonFactory { - NetworkPreferences( - preferenceStore = get(), - verboseLogging = isDevFlavor, - ) - } - addSingletonFactory { - SourcePreferences(get()) - } - addSingletonFactory { - SecurityPreferences(get()) - } - addSingletonFactory { - LibraryPreferences(get()) - } - addSingletonFactory { - ReaderPreferences(get()) - } - addSingletonFactory { - PlayerPreferences(get()) - } - addSingletonFactory { - TrackPreferences(get()) - } - addSingletonFactory { - AndroidDownloadFolderProvider(application) - } - addSingletonFactory { - DownloadPreferences( - folderProvider = get(), - preferenceStore = get(), - ) - } - addSingletonFactory { - AndroidBackupFolderProvider(application) - } - addSingletonFactory { - BackupPreferences( - folderProvider = get(), - preferenceStore = get(), - ) - } - addSingletonFactory { - UiPreferences(get()) - } - addSingletonFactory { - BasePreferences(application, get()) - } - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/di/PreferenceModule.kt b/app/src/main/java/eu/kanade/tachiyomi/di/PreferenceModule.kt new file mode 100644 index 000000000..e77f40b2f --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/di/PreferenceModule.kt @@ -0,0 +1,79 @@ +package eu.kanade.tachiyomi.di + +import android.app.Application +import eu.kanade.domain.base.BasePreferences +import eu.kanade.domain.source.service.SourcePreferences +import eu.kanade.domain.track.service.TrackPreferences +import eu.kanade.domain.ui.UiPreferences +import eu.kanade.tachiyomi.core.preference.AndroidPreferenceStore +import eu.kanade.tachiyomi.core.security.SecurityPreferences +import eu.kanade.tachiyomi.network.NetworkPreferences +import eu.kanade.tachiyomi.ui.player.settings.PlayerPreferences +import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences +import eu.kanade.tachiyomi.util.system.isDevFlavor +import tachiyomi.core.preference.PreferenceStore +import tachiyomi.core.provider.AndroidBackupFolderProvider +import tachiyomi.core.provider.AndroidDownloadFolderProvider +import tachiyomi.domain.backup.service.BackupPreferences +import tachiyomi.domain.download.service.DownloadPreferences +import tachiyomi.domain.library.service.LibraryPreferences +import uy.kohesive.injekt.api.InjektModule +import uy.kohesive.injekt.api.InjektRegistrar +import uy.kohesive.injekt.api.addSingletonFactory +import uy.kohesive.injekt.api.get + +class PreferenceModule(val application: Application) : InjektModule { + override fun InjektRegistrar.registerInjectables() { + addSingletonFactory { + AndroidPreferenceStore(application) + } + addSingletonFactory { + NetworkPreferences( + preferenceStore = get(), + verboseLogging = isDevFlavor, + ) + } + addSingletonFactory { + SourcePreferences(get()) + } + addSingletonFactory { + SecurityPreferences(get()) + } + addSingletonFactory { + LibraryPreferences(get()) + } + addSingletonFactory { + ReaderPreferences(get()) + } + addSingletonFactory { + PlayerPreferences(get()) + } + addSingletonFactory { + TrackPreferences(get()) + } + addSingletonFactory { + AndroidDownloadFolderProvider(application) + } + addSingletonFactory { + DownloadPreferences( + folderProvider = get(), + preferenceStore = get(), + ) + } + addSingletonFactory { + AndroidBackupFolderProvider(application) + } + addSingletonFactory { + BackupPreferences( + folderProvider = get(), + preferenceStore = get(), + ) + } + addSingletonFactory { + UiPreferences(get()) + } + addSingletonFactory { + BasePreferences(application, get()) + } + } +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/anime/AndroidAnimeSourceManager.kt b/app/src/main/java/eu/kanade/tachiyomi/source/anime/AndroidAnimeSourceManager.kt index 94478377a..6d3e11960 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/anime/AndroidAnimeSourceManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/anime/AndroidAnimeSourceManager.kt @@ -57,7 +57,7 @@ class AndroidAnimeSourceManager( extensions.forEach { extension -> extension.sources.forEach { mutableMap[it.id] = it - registerStubSource(it.toStubSource()) + registerStubSource(StubAnimeSource.from(it)) } } sourcesMapFlow.value = mutableMap diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/anime/model/SAnimeExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/source/anime/model/SAnimeExtensions.kt index b50aebfba..bafeac839 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/anime/model/SAnimeExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/anime/model/SAnimeExtensions.kt @@ -1,59 +1,15 @@ package eu.kanade.tachiyomi.source.anime.model import dataanime.Animes -import eu.kanade.tachiyomi.animesource.model.SAnime import tachiyomi.domain.entries.anime.model.Anime -fun SAnime.copyFrom(other: Animes) { - if (other.author != null) { - author = other.author - } - - if (other.artist != null) { - artist = other.artist - } - - if (other.description != null) { - description = other.description - } - - if (other.genre != null) { - genre = other.genre!!.joinToString(separator = ", ") - } - - if (other.thumbnail_url != null) { - thumbnail_url = other.thumbnail_url - } - - status = other.status.toInt() - - if (!initialized) { - initialized = other.initialized - } -} - fun Anime.copyFrom(other: Animes): Anime { var anime = this - if (other.author != null) { - anime = anime.copy(author = other.author) - } - - if (other.artist != null) { - anime = anime.copy(artist = other.artist) - } - - if (other.description != null) { - anime = anime.copy(description = other.description) - } - - if (other.genre != null) { - anime = anime.copy(genre = other.genre) - } - - if (other.thumbnail_url != null) { - anime = anime.copy(thumbnailUrl = other.thumbnail_url) - } - + other.author?.let { anime = anime.copy(author = it) } + other.artist?.let { anime = anime.copy(artist = it) } + other.description?.let { anime = anime.copy(description = it) } + other.genre?.let { anime = anime.copy(genre = it) } + other.thumbnail_url?.let { anime = anime.copy(thumbnailUrl = it) } anime = anime.copy(status = other.status) if (!initialized) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/anime/model/SEpisodeExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/source/anime/model/SEpisodeExtensions.kt deleted file mode 100644 index 5a5e84a5c..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/source/anime/model/SEpisodeExtensions.kt +++ /dev/null @@ -1,12 +0,0 @@ -package eu.kanade.tachiyomi.source.anime.model - -import dataanime.Episodes -import eu.kanade.tachiyomi.animesource.model.SEpisode - -fun SEpisode.copyFrom(other: Episodes) { - name = other.name - url = other.url - date_upload = other.date_upload - episode_number = other.episode_number.toFloat() - scanlator = other.scanlator -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/manga/AndroidMangaSourceManager.kt b/app/src/main/java/eu/kanade/tachiyomi/source/manga/AndroidMangaSourceManager.kt index 5afe14548..c66e32f2a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/manga/AndroidMangaSourceManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/manga/AndroidMangaSourceManager.kt @@ -57,7 +57,7 @@ class AndroidMangaSourceManager( extensions.forEach { extension -> extension.sources.forEach { mutableMap[it.id] = it - registerStubSource(it.toStubSource()) + registerStubSource(StubMangaSource.from(it)) } } sourcesMapFlow.value = mutableMap diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/manga/model/SChapterExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/source/manga/model/SChapterExtensions.kt deleted file mode 100644 index 47e5b4e64..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/source/manga/model/SChapterExtensions.kt +++ /dev/null @@ -1,12 +0,0 @@ -package eu.kanade.tachiyomi.source.manga.model - -import data.Chapters -import eu.kanade.tachiyomi.source.model.SChapter - -fun SChapter.copyFrom(other: Chapters) { - name = other.name - url = other.url - date_upload = other.date_upload - chapter_number = other.chapter_number.toFloat() - scanlator = other.scanlator -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/manga/model/SMangaExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/source/manga/model/SMangaExtensions.kt index 876b2738e..53de4c03a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/manga/model/SMangaExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/manga/model/SMangaExtensions.kt @@ -1,61 +1,16 @@ package eu.kanade.tachiyomi.source.manga.model import data.Mangas -import eu.kanade.tachiyomi.source.model.SManga import tachiyomi.domain.entries.manga.model.Manga -fun SManga.copyFrom(other: Mangas) { - if (other.author != null) { - author = other.author - } - - if (other.artist != null) { - artist = other.artist - } - - if (other.description != null) { - description = other.description - } - - if (other.genre != null) { - genre = other.genre!!.joinToString(separator = ", ") - } - - if (other.thumbnail_url != null) { - thumbnail_url = other.thumbnail_url - } - - status = other.status.toInt() - - if (!initialized) { - initialized = other.initialized - } -} - fun Manga.copyFrom(other: Mangas): Manga { var manga = this - if (other.author != null) { - manga = manga.copy(author = other.author) - } - - if (other.artist != null) { - manga = manga.copy(artist = other.artist) - } - - if (other.description != null) { - manga = manga.copy(description = other.description) - } - - if (other.genre != null) { - manga = manga.copy(genre = other.genre) - } - - if (other.thumbnail_url != null) { - manga = manga.copy(thumbnailUrl = other.thumbnail_url) - } - + other.author?.let { manga = manga.copy(author = it) } + other.artist?.let { manga = manga.copy(artist = it) } + other.description?.let { manga = manga.copy(description = it) } + other.genre?.let { manga = manga.copy(genre = it) } + other.thumbnail_url?.let { manga = manga.copy(thumbnailUrl = it) } manga = manga.copy(status = other.status) - if (!initialized) { manga = manga.copy(initialized = other.initialized) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/BrowseTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/BrowseTab.kt index f35bc5a28..5b3037c01 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/BrowseTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/BrowseTab.kt @@ -27,6 +27,7 @@ import eu.kanade.tachiyomi.ui.browse.manga.extension.mangaExtensionsTab import eu.kanade.tachiyomi.ui.browse.manga.migration.sources.migrateMangaSourceTab import eu.kanade.tachiyomi.ui.browse.manga.source.mangaSourcesTab import eu.kanade.tachiyomi.ui.main.MainActivity +import kotlinx.collections.immutable.persistentListOf data class BrowseTab( private val toExtensions: Boolean = false, @@ -62,7 +63,7 @@ data class BrowseTab( TabbedScreen( titleRes = R.string.browse, - tabs = listOf( + tabs = persistentListOf( animeSourcesTab(), mangaSourcesTab(), animeExtensionsTab(animeExtensionsScreenModel), diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/extension/AnimeExtensionFilterScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/extension/AnimeExtensionFilterScreenModel.kt index 068a22794..c7a417b18 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/extension/AnimeExtensionFilterScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/extension/AnimeExtensionFilterScreenModel.kt @@ -6,6 +6,11 @@ import cafe.adriel.voyager.core.model.screenModelScope import eu.kanade.domain.extension.anime.interactor.GetAnimeExtensionLanguages import eu.kanade.domain.source.service.SourcePreferences import eu.kanade.domain.source.service.ToggleLanguage +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.ImmutableSet +import kotlinx.collections.immutable.persistentSetOf +import kotlinx.collections.immutable.toImmutableList +import kotlinx.collections.immutable.toImmutableSet import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch @@ -41,8 +46,8 @@ class AnimeExtensionFilterScreenModel( .collectLatest { (extensionLanguages, enabledLanguages) -> mutableState.update { AnimeExtensionFilterState.Success( - languages = extensionLanguages, - enabledLanguages = enabledLanguages, + languages = extensionLanguages.toImmutableList(), + enabledLanguages = enabledLanguages.toImmutableSet(), ) } } @@ -65,8 +70,8 @@ sealed interface AnimeExtensionFilterState { @Immutable data class Success( - val languages: List, - val enabledLanguages: Set = emptySet(), + val languages: ImmutableList, + val enabledLanguages: ImmutableSet = persistentSetOf(), ) : AnimeExtensionFilterState { val isEmpty: Boolean diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/extension/AnimeExtensionsTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/extension/AnimeExtensionsTab.kt index f6cacb54a..635264824 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/extension/AnimeExtensionsTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/extension/AnimeExtensionsTab.kt @@ -14,6 +14,7 @@ import eu.kanade.presentation.components.TabContent import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.extension.anime.model.AnimeExtension import eu.kanade.tachiyomi.ui.browse.anime.extension.details.AnimeExtensionDetailsScreen +import kotlinx.collections.immutable.persistentListOf @Composable fun animeExtensionsTab( @@ -26,7 +27,7 @@ fun animeExtensionsTab( titleRes = R.string.label_anime_extensions, badgeNumber = state.updates.takeIf { it > 0 }, searchEnabled = true, - actions = listOf( + actions = persistentListOf( AppBar.Action( title = stringResource(R.string.action_filter), icon = Icons.Outlined.Translate, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/extension/details/AnimeExtensionDetailsScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/extension/details/AnimeExtensionDetailsScreenModel.kt index 5d9a5e68f..2d3727864 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/extension/details/AnimeExtensionDetailsScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/extension/details/AnimeExtensionDetailsScreenModel.kt @@ -12,6 +12,9 @@ import eu.kanade.tachiyomi.extension.anime.model.AnimeExtension import eu.kanade.tachiyomi.network.NetworkHelper import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.util.system.LocaleHelper +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch @@ -78,10 +81,10 @@ class AnimeExtensionDetailsScreenModel( } .catch { throwable -> logcat(LogPriority.ERROR, throwable) - mutableState.update { it.copy(_sources = emptyList()) } + mutableState.update { it.copy(_sources = persistentListOf()) } } .collectLatest { sources -> - mutableState.update { it.copy(_sources = sources) } + mutableState.update { it.copy(_sources = sources.toImmutableList()) } } } } @@ -167,11 +170,11 @@ class AnimeExtensionDetailsScreenModel( @Immutable data class State( val extension: AnimeExtension.Installed? = null, - private val _sources: List? = null, + private val _sources: ImmutableList? = null, ) { - val sources: List - get() = _sources.orEmpty() + val sources: ImmutableList + get() = _sources ?: persistentListOf() val isLoading: Boolean get() = extension == null || _sources == null diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/migration/anime/MigrateAnimeScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/migration/anime/MigrateAnimeScreenModel.kt index d408a6df9..3c7eaaae1 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/migration/anime/MigrateAnimeScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/migration/anime/MigrateAnimeScreenModel.kt @@ -4,6 +4,9 @@ import androidx.compose.runtime.Immutable import cafe.adriel.voyager.core.model.StateScreenModel import cafe.adriel.voyager.core.model.screenModelScope import eu.kanade.tachiyomi.animesource.AnimeSource +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch @@ -40,11 +43,13 @@ class MigrateAnimeScreenModel( logcat(LogPriority.ERROR, it) _events.send(MigrationAnimeEvent.FailedFetchingFavorites) mutableState.update { state -> - state.copy(titleList = emptyList()) + state.copy(titleList = persistentListOf()) } } .map { anime -> - anime.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER) { it.title }) + anime + .sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER) { it.title }) + .toImmutableList() } .collectLatest { list -> mutableState.update { it.copy(titleList = list) } @@ -55,11 +60,11 @@ class MigrateAnimeScreenModel( @Immutable data class State( val source: AnimeSource? = null, - private val titleList: List? = null, + private val titleList: ImmutableList? = null, ) { - val titles: List - get() = titleList.orEmpty() + val titles: ImmutableList + get() = titleList ?: persistentListOf() val isLoading: Boolean get() = source == null || titleList == null diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/migration/sources/MigrateAnimeSourceScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/migration/sources/MigrateAnimeSourceScreenModel.kt index 4088003f0..a4bee67b5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/migration/sources/MigrateAnimeSourceScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/migration/sources/MigrateAnimeSourceScreenModel.kt @@ -6,6 +6,9 @@ import cafe.adriel.voyager.core.model.screenModelScope import eu.kanade.domain.source.anime.interactor.GetAnimeSourcesWithFavoriteCount import eu.kanade.domain.source.service.SetMigrateSorting import eu.kanade.domain.source.service.SourcePreferences +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.collectLatest @@ -40,7 +43,7 @@ class MigrateAnimeSourceScreenModel( mutableState.update { it.copy( isLoading = false, - items = sources, + items = sources.toImmutableList(), ) } } @@ -80,7 +83,7 @@ class MigrateAnimeSourceScreenModel( @Immutable data class State( val isLoading: Boolean = true, - val items: List> = emptyList(), + val items: ImmutableList> = persistentListOf(), val sortingMode: SetMigrateSorting.Mode = SetMigrateSorting.Mode.ALPHABETICAL, val sortingDirection: SetMigrateSorting.Direction = SetMigrateSorting.Direction.ASCENDING, ) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/migration/sources/MigrateAnimeSourceTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/migration/sources/MigrateAnimeSourceTab.kt index bf59b9135..e47449e56 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/migration/sources/MigrateAnimeSourceTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/migration/sources/MigrateAnimeSourceTab.kt @@ -1,6 +1,7 @@ package eu.kanade.tachiyomi.ui.browse.anime.migration.sources import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.outlined.HelpOutline import androidx.compose.material.icons.outlined.HelpOutline import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState @@ -16,6 +17,7 @@ import eu.kanade.presentation.components.AppBar import eu.kanade.presentation.components.TabContent import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.browse.anime.migration.anime.MigrateAnimeScreen +import kotlinx.collections.immutable.persistentListOf @Composable fun Screen.migrateAnimeSourceTab(): TabContent { @@ -26,10 +28,10 @@ fun Screen.migrateAnimeSourceTab(): TabContent { return TabContent( titleRes = R.string.label_migration_anime, - actions = listOf( + actions = persistentListOf( AppBar.Action( title = stringResource(R.string.migration_help_guide), - icon = Icons.Outlined.HelpOutline, + icon = Icons.AutoMirrored.Outlined.HelpOutline, onClick = { uriHandler.openUri("https://aniyomi.org/help/guides/source-migration/") }, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/source/AnimeSourcesScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/source/AnimeSourcesScreenModel.kt index 6900bc7f1..da6c995a8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/source/AnimeSourcesScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/source/AnimeSourcesScreenModel.kt @@ -11,6 +11,9 @@ import eu.kanade.domain.source.service.SourcePreferences import eu.kanade.presentation.browse.anime.AnimeSourceUiModel import eu.kanade.tachiyomi.util.system.LAST_USED_KEY import eu.kanade.tachiyomi.util.system.PINNED_KEY +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.collectLatest @@ -71,14 +74,16 @@ class AnimeSourcesScreenModel( state.copy( isLoading = false, - items = byLang.flatMap { - listOf( - AnimeSourceUiModel.Header(it.key), - *it.value.map { source -> - AnimeSourceUiModel.Item(source) - }.toTypedArray(), - ) - }, + items = byLang + .flatMap { + listOf( + AnimeSourceUiModel.Header(it.key), + *it.value.map { source -> + AnimeSourceUiModel.Item(source) + }.toTypedArray(), + ) + } + .toImmutableList(), ) } } @@ -109,7 +114,7 @@ class AnimeSourcesScreenModel( data class State( val dialog: Dialog? = null, val isLoading: Boolean = true, - val items: List = emptyList(), + val items: ImmutableList = persistentListOf(), ) { val isEmpty = items.isEmpty() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/source/AnimeSourcesTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/source/AnimeSourcesTab.kt index 53a34d18c..3ef680a1e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/source/AnimeSourcesTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/source/AnimeSourcesTab.kt @@ -19,6 +19,7 @@ import eu.kanade.presentation.components.TabContent import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.browse.anime.source.browse.BrowseAnimeSourceScreen import eu.kanade.tachiyomi.ui.browse.anime.source.globalsearch.GlobalAnimeSearchScreen +import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch @@ -30,7 +31,7 @@ fun Screen.animeSourcesTab(): TabContent { return TabContent( titleRes = R.string.label_anime_sources, - actions = listOf( + actions = persistentListOf( AppBar.Action( title = stringResource(R.string.action_global_search), icon = Icons.Outlined.TravelExplore, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/source/browse/BrowseAnimeSourceScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/source/browse/BrowseAnimeSourceScreen.kt index 8e33de43c..e76d428b1 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/source/browse/BrowseAnimeSourceScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/source/browse/BrowseAnimeSourceScreen.kt @@ -146,7 +146,7 @@ data class BrowseAnimeSourceScreen( leadingIcon = { Icon( imageVector = Icons.Outlined.Favorite, - contentDescription = "", + contentDescription = null, modifier = Modifier .size(FilterChipDefaults.IconSize), ) @@ -165,7 +165,7 @@ data class BrowseAnimeSourceScreen( leadingIcon = { Icon( imageVector = Icons.Outlined.NewReleases, - contentDescription = "", + contentDescription = null, modifier = Modifier .size(FilterChipDefaults.IconSize), ) @@ -182,7 +182,7 @@ data class BrowseAnimeSourceScreen( leadingIcon = { Icon( imageVector = Icons.Outlined.FilterList, - contentDescription = "", + contentDescription = null, modifier = Modifier .size(FilterChipDefaults.IconSize), ) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/source/globalsearch/AnimeSearchScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/source/globalsearch/AnimeSearchScreenModel.kt index 9223f6f20..08d12f51a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/source/globalsearch/AnimeSearchScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/anime/source/globalsearch/AnimeSearchScreenModel.kt @@ -9,6 +9,10 @@ import eu.kanade.domain.source.service.SourcePreferences import eu.kanade.presentation.util.ioCoroutineScope import eu.kanade.tachiyomi.animesource.AnimeCatalogueSource import eu.kanade.tachiyomi.extension.anime.AnimeExtensionManager +import kotlinx.collections.immutable.PersistentMap +import kotlinx.collections.immutable.mutate +import kotlinx.collections.immutable.persistentMapOf +import kotlinx.collections.immutable.toPersistentMap import kotlinx.coroutines.Job import kotlinx.coroutines.asCoroutineDispatcher import kotlinx.coroutines.async @@ -124,10 +128,16 @@ abstract class AnimeSearchScreenModel( if (sameQuery) { val existingResults = state.value.items updateItems( - sources.associateWith { existingResults[it] ?: AnimeSearchItemResult.Loading }, + sources + .associateWith { existingResults[it] ?: AnimeSearchItemResult.Loading } + .toPersistentMap(), ) } else { - updateItems(sources.associateWith { AnimeSearchItemResult.Loading }) + updateItems( + sources + .associateWith { AnimeSearchItemResult.Loading } + .toPersistentMap(), + ) } searchJob = ioCoroutineScope.launch { @@ -159,14 +169,21 @@ abstract class AnimeSearchScreenModel( } } - private fun updateItems(items: Map) { - mutableState.update { it.copy(items = items.toSortedMap(sortComparator(items))) } + private fun updateItems(items: PersistentMap) { + mutableState.update { + it.copy( + items = items + .toSortedMap(sortComparator(items)) + .toPersistentMap(), + ) + } } private fun updateItem(source: AnimeCatalogueSource, result: AnimeSearchItemResult) { - val mutableItems = state.value.items.toMutableMap() - mutableItems[source] = result - updateItems(mutableItems) + val newItems = state.value.items.mutate { + it[source] = result + } + updateItems(newItems) } @Immutable @@ -175,7 +192,7 @@ abstract class AnimeSearchScreenModel( val searchQuery: String? = null, val sourceFilter: AnimeSourceFilter = AnimeSourceFilter.PinnedOnly, val onlyShowHasResults: Boolean = false, - val items: Map = emptyMap(), + val items: PersistentMap = persistentMapOf(), ) { val progress: Int = items.count { it.value !is AnimeSearchItemResult.Loading } val total: Int = items.size diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/extension/MangaExtensionFilterScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/extension/MangaExtensionFilterScreenModel.kt index 2eeeb956a..c4192d35d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/extension/MangaExtensionFilterScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/extension/MangaExtensionFilterScreenModel.kt @@ -6,6 +6,11 @@ import cafe.adriel.voyager.core.model.screenModelScope import eu.kanade.domain.extension.manga.interactor.GetMangaExtensionLanguages import eu.kanade.domain.source.service.SourcePreferences import eu.kanade.domain.source.service.ToggleLanguage +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.ImmutableSet +import kotlinx.collections.immutable.persistentSetOf +import kotlinx.collections.immutable.toImmutableList +import kotlinx.collections.immutable.toImmutableSet import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch @@ -41,8 +46,8 @@ class MangaExtensionFilterScreenModel( .collectLatest { (extensionLanguages, enabledLanguages) -> mutableState.update { MangaExtensionFilterState.Success( - languages = extensionLanguages, - enabledLanguages = enabledLanguages, + languages = extensionLanguages.toImmutableList(), + enabledLanguages = enabledLanguages.toImmutableSet(), ) } } @@ -65,8 +70,8 @@ sealed interface MangaExtensionFilterState { @Immutable data class Success( - val languages: List, - val enabledLanguages: Set = emptySet(), + val languages: ImmutableList, + val enabledLanguages: ImmutableSet = persistentSetOf(), ) : MangaExtensionFilterState { val isEmpty: Boolean diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/extension/MangaExtensionsTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/extension/MangaExtensionsTab.kt index 1ca971b10..c5ac91faf 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/extension/MangaExtensionsTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/extension/MangaExtensionsTab.kt @@ -14,6 +14,7 @@ import eu.kanade.presentation.components.TabContent import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.extension.manga.model.MangaExtension import eu.kanade.tachiyomi.ui.browse.manga.extension.details.MangaExtensionDetailsScreen +import kotlinx.collections.immutable.persistentListOf @Composable fun mangaExtensionsTab( @@ -26,7 +27,7 @@ fun mangaExtensionsTab( titleRes = R.string.label_manga_extensions, badgeNumber = state.updates.takeIf { it > 0 }, searchEnabled = true, - actions = listOf( + actions = persistentListOf( AppBar.Action( title = stringResource(R.string.action_filter), icon = Icons.Outlined.Translate, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/extension/details/MangaExtensionDetailsScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/extension/details/MangaExtensionDetailsScreenModel.kt index 77d0f04ed..921f39eb1 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/extension/details/MangaExtensionDetailsScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/extension/details/MangaExtensionDetailsScreenModel.kt @@ -12,6 +12,9 @@ import eu.kanade.tachiyomi.extension.manga.model.MangaExtension import eu.kanade.tachiyomi.network.NetworkHelper import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.util.system.LocaleHelper +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch @@ -78,10 +81,10 @@ class MangaExtensionDetailsScreenModel( } .catch { throwable -> logcat(LogPriority.ERROR, throwable) - mutableState.update { it.copy(_sources = emptyList()) } + mutableState.update { it.copy(_sources = persistentListOf()) } } .collectLatest { sources -> - mutableState.update { it.copy(_sources = sources) } + mutableState.update { it.copy(_sources = sources.toImmutableList()) } } } } @@ -167,11 +170,11 @@ class MangaExtensionDetailsScreenModel( @Immutable data class State( val extension: MangaExtension.Installed? = null, - private val _sources: List? = null, + private val _sources: ImmutableList? = null, ) { - val sources: List - get() = _sources.orEmpty() + val sources: ImmutableList + get() = _sources ?: persistentListOf() val isLoading: Boolean get() = extension == null || _sources == null diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/migration/manga/MigrateMangaScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/migration/manga/MigrateMangaScreenModel.kt index 2be87fd13..30c78bd16 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/migration/manga/MigrateMangaScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/migration/manga/MigrateMangaScreenModel.kt @@ -4,6 +4,9 @@ import androidx.compose.runtime.Immutable import cafe.adriel.voyager.core.model.StateScreenModel import cafe.adriel.voyager.core.model.screenModelScope import eu.kanade.tachiyomi.source.MangaSource +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch @@ -40,11 +43,13 @@ class MigrateMangaScreenModel( logcat(LogPriority.ERROR, it) _events.send(MigrationMangaEvent.FailedFetchingFavorites) mutableState.update { state -> - state.copy(titleList = emptyList()) + state.copy(titleList = persistentListOf()) } } .map { manga -> - manga.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER) { it.title }) + manga + .sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER) { it.title }) + .toImmutableList() } .collectLatest { list -> mutableState.update { it.copy(titleList = list) } @@ -55,11 +60,11 @@ class MigrateMangaScreenModel( @Immutable data class State( val source: MangaSource? = null, - private val titleList: List? = null, + private val titleList: ImmutableList? = null, ) { - val titles: List - get() = titleList.orEmpty() + val titles: ImmutableList + get() = titleList ?: persistentListOf() val isLoading: Boolean get() = source == null || titleList == null diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/migration/sources/MigrateMangaSourceScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/migration/sources/MigrateMangaSourceScreenModel.kt index 03bfc4082..4dc52f3ed 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/migration/sources/MigrateMangaSourceScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/migration/sources/MigrateMangaSourceScreenModel.kt @@ -6,6 +6,9 @@ import cafe.adriel.voyager.core.model.screenModelScope import eu.kanade.domain.source.manga.interactor.GetMangaSourcesWithFavoriteCount import eu.kanade.domain.source.service.SetMigrateSorting import eu.kanade.domain.source.service.SourcePreferences +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.collectLatest @@ -40,7 +43,7 @@ class MigrateMangaSourceScreenModel( mutableState.update { it.copy( isLoading = false, - items = sources, + items = sources.toImmutableList(), ) } } @@ -80,7 +83,7 @@ class MigrateMangaSourceScreenModel( @Immutable data class State( val isLoading: Boolean = true, - val items: List> = emptyList(), + val items: ImmutableList> = persistentListOf(), val sortingMode: SetMigrateSorting.Mode = SetMigrateSorting.Mode.ALPHABETICAL, val sortingDirection: SetMigrateSorting.Direction = SetMigrateSorting.Direction.ASCENDING, ) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/migration/sources/MigrateMangaSourceTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/migration/sources/MigrateMangaSourceTab.kt index 2b652f823..0d68c5b8f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/migration/sources/MigrateMangaSourceTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/migration/sources/MigrateMangaSourceTab.kt @@ -1,6 +1,7 @@ package eu.kanade.tachiyomi.ui.browse.manga.migration.sources import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.outlined.HelpOutline import androidx.compose.material.icons.outlined.HelpOutline import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState @@ -16,6 +17,7 @@ import eu.kanade.presentation.components.AppBar import eu.kanade.presentation.components.TabContent import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.browse.manga.migration.manga.MigrateMangaScreen +import kotlinx.collections.immutable.persistentListOf @Composable fun Screen.migrateMangaSourceTab(): TabContent { @@ -26,10 +28,10 @@ fun Screen.migrateMangaSourceTab(): TabContent { return TabContent( titleRes = R.string.label_migration, - actions = listOf( + actions = persistentListOf( AppBar.Action( title = stringResource(R.string.migration_help_guide), - icon = Icons.Outlined.HelpOutline, + icon = Icons.AutoMirrored.Outlined.HelpOutline, onClick = { uriHandler.openUri("https://aniyomi.org/help/guides/source-migration/") }, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/source/MangaSourcesScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/source/MangaSourcesScreenModel.kt index 2774b8a58..c5ebd2b46 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/source/MangaSourcesScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/source/MangaSourcesScreenModel.kt @@ -13,6 +13,9 @@ import eu.kanade.domain.source.service.SourcePreferences.DataSaver import eu.kanade.presentation.browse.manga.MangaSourceUiModel import eu.kanade.tachiyomi.util.system.LAST_USED_KEY import eu.kanade.tachiyomi.util.system.PINNED_KEY +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.collectLatest @@ -89,14 +92,16 @@ class MangaSourcesScreenModel( state.copy( isLoading = false, - items = byLang.flatMap { - listOf( - MangaSourceUiModel.Header(it.key), - *it.value.map { source -> - MangaSourceUiModel.Item(source) - }.toTypedArray(), - ) - }, + items = byLang + .flatMap { + listOf( + MangaSourceUiModel.Header(it.key), + *it.value.map { source -> + MangaSourceUiModel.Item(source) + }.toTypedArray(), + ) + } + .toImmutableList(), ) } } @@ -133,7 +138,7 @@ class MangaSourcesScreenModel( data class State( val dialog: Dialog? = null, val isLoading: Boolean = true, - val items: List = emptyList(), + val items: ImmutableList = persistentListOf(), // SY --> val dataSaverEnabled: Boolean = false, // SY <-- diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/source/MangaSourcesTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/source/MangaSourcesTab.kt index 53d11ff44..2ae21ddf4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/source/MangaSourcesTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/source/MangaSourcesTab.kt @@ -19,6 +19,7 @@ import eu.kanade.presentation.components.TabContent import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.browse.manga.source.browse.BrowseMangaSourceScreen import eu.kanade.tachiyomi.ui.browse.manga.source.globalsearch.GlobalMangaSearchScreen +import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch @@ -30,7 +31,7 @@ fun Screen.mangaSourcesTab(): TabContent { return TabContent( titleRes = R.string.label_manga_sources, - actions = listOf( + actions = persistentListOf( AppBar.Action( title = stringResource(R.string.action_global_search), icon = Icons.Outlined.TravelExplore, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/source/browse/BrowseMangaSourceScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/source/browse/BrowseMangaSourceScreen.kt index 6034f83fe..d96aee45e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/source/browse/BrowseMangaSourceScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/source/browse/BrowseMangaSourceScreen.kt @@ -146,7 +146,7 @@ data class BrowseMangaSourceScreen( leadingIcon = { Icon( imageVector = Icons.Outlined.Favorite, - contentDescription = "", + contentDescription = null, modifier = Modifier .size(FilterChipDefaults.IconSize), ) @@ -165,7 +165,7 @@ data class BrowseMangaSourceScreen( leadingIcon = { Icon( imageVector = Icons.Outlined.NewReleases, - contentDescription = "", + contentDescription = null, modifier = Modifier .size(FilterChipDefaults.IconSize), ) @@ -182,7 +182,7 @@ data class BrowseMangaSourceScreen( leadingIcon = { Icon( imageVector = Icons.Outlined.FilterList, - contentDescription = "", + contentDescription = null, modifier = Modifier .size(FilterChipDefaults.IconSize), ) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/source/globalsearch/MangaSearchScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/source/globalsearch/MangaSearchScreenModel.kt index 85980f98a..d3ad08469 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/source/globalsearch/MangaSearchScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/manga/source/globalsearch/MangaSearchScreenModel.kt @@ -9,6 +9,10 @@ import eu.kanade.domain.source.service.SourcePreferences import eu.kanade.presentation.util.ioCoroutineScope import eu.kanade.tachiyomi.extension.manga.MangaExtensionManager import eu.kanade.tachiyomi.source.CatalogueSource +import kotlinx.collections.immutable.PersistentMap +import kotlinx.collections.immutable.mutate +import kotlinx.collections.immutable.persistentMapOf +import kotlinx.collections.immutable.toPersistentMap import kotlinx.coroutines.Job import kotlinx.coroutines.asCoroutineDispatcher import kotlinx.coroutines.async @@ -124,10 +128,16 @@ abstract class MangaSearchScreenModel( if (sameQuery) { val existingResults = state.value.items updateItems( - sources.associateWith { existingResults[it] ?: MangaSearchItemResult.Loading }, + sources + .associateWith { existingResults[it] ?: MangaSearchItemResult.Loading } + .toPersistentMap(), ) } else { - updateItems(sources.associateWith { MangaSearchItemResult.Loading }) + updateItems( + sources + .associateWith { MangaSearchItemResult.Loading } + .toPersistentMap(), + ) } searchJob = ioCoroutineScope.launch { sources.map { source -> @@ -158,14 +168,21 @@ abstract class MangaSearchScreenModel( } } - private fun updateItems(items: Map) { - mutableState.update { it.copy(items = items.toSortedMap(sortComparator(items))) } + private fun updateItems(items: PersistentMap) { + mutableState.update { + it.copy( + items = items + .toSortedMap(sortComparator(items)) + .toPersistentMap(), + ) + } } private fun updateItem(source: CatalogueSource, result: MangaSearchItemResult) { - val mutableItems = state.value.items.toMutableMap() - mutableItems[source] = result - updateItems(mutableItems) + val newItems = state.value.items.mutate { + it[source] = result + } + updateItems(newItems) } @Immutable @@ -174,7 +191,7 @@ abstract class MangaSearchScreenModel( val searchQuery: String? = null, val sourceFilter: MangaSourceFilter = MangaSourceFilter.PinnedOnly, val onlyShowHasResults: Boolean = false, - val items: Map = emptyMap(), + val items: PersistentMap = persistentMapOf(), ) { val progress: Int = items.count { it.value !is MangaSearchItemResult.Loading } val total: Int = items.size diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoriesTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoriesTab.kt index cae0d617d..fe845bc16 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoriesTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoriesTab.kt @@ -21,6 +21,7 @@ import eu.kanade.tachiyomi.ui.category.manga.MangaCategoryScreenModel import eu.kanade.tachiyomi.ui.category.manga.mangaCategoryTab import eu.kanade.tachiyomi.ui.main.MainActivity import eu.kanade.tachiyomi.util.system.toast +import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.flow.collectLatest data class CategoriesTab( @@ -48,7 +49,7 @@ data class CategoriesTab( TabbedScreen( titleRes = R.string.general_categories, - tabs = listOf( + tabs = persistentListOf( animeCategoryTab(), mangaCategoryTab(), ), diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/category/anime/AnimeCategoryScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/category/anime/AnimeCategoryScreenModel.kt index 7743bdfb6..28760ae4e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/category/anime/AnimeCategoryScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/category/anime/AnimeCategoryScreenModel.kt @@ -5,6 +5,8 @@ import androidx.compose.runtime.Immutable import cafe.adriel.voyager.core.model.StateScreenModel import cafe.adriel.voyager.core.model.screenModelScope import eu.kanade.tachiyomi.R +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.receiveAsFlow @@ -47,7 +49,9 @@ class AnimeCategoryScreenModel( allCategories.collectLatest { categories -> mutableState.update { AnimeCategoryScreenState.Success( - categories = categories.filterNot(Category::isSystemCategory), + categories = categories + .filterNot(Category::isSystemCategory) + .toImmutableList(), ) } } @@ -168,7 +172,7 @@ sealed interface AnimeCategoryScreenState { @Immutable data class Success( - val categories: List, + val categories: ImmutableList, val dialog: AnimeCategoryDialog? = null, ) : AnimeCategoryScreenState { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/category/anime/AnimeCategoryTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/category/anime/AnimeCategoryTab.kt index 103770e07..45b94fabe 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/category/anime/AnimeCategoryTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/category/anime/AnimeCategoryTab.kt @@ -18,6 +18,7 @@ import eu.kanade.presentation.category.components.CategorySortAlphabeticallyDial import eu.kanade.presentation.components.AppBar import eu.kanade.presentation.components.TabContent import eu.kanade.tachiyomi.R +import kotlinx.collections.immutable.persistentListOf import tachiyomi.presentation.core.screens.LoadingScreen @Composable @@ -31,7 +32,7 @@ fun Screen.animeCategoryTab(): TabContent { titleRes = R.string.label_anime, searchEnabled = false, actions = - listOf( + persistentListOf( AppBar.Action( title = stringResource(R.string.action_sort), icon = Icons.Outlined.SortByAlpha, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/category/manga/MangaCategoryScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/category/manga/MangaCategoryScreenModel.kt index fee4f6b90..32929e833 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/category/manga/MangaCategoryScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/category/manga/MangaCategoryScreenModel.kt @@ -5,6 +5,8 @@ import androidx.compose.runtime.Immutable import cafe.adriel.voyager.core.model.StateScreenModel import cafe.adriel.voyager.core.model.screenModelScope import eu.kanade.tachiyomi.R +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.receiveAsFlow @@ -47,7 +49,9 @@ class MangaCategoryScreenModel( allCategories.collectLatest { categories -> mutableState.update { MangaCategoryScreenState.Success( - categories = categories.filterNot(Category::isSystemCategory), + categories = categories + .filterNot(Category::isSystemCategory) + .toImmutableList(), ) } } @@ -168,7 +172,7 @@ sealed interface MangaCategoryScreenState { @Immutable data class Success( - val categories: List, + val categories: ImmutableList, val dialog: MangaCategoryDialog? = null, ) : MangaCategoryScreenState { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/category/manga/MangaCategoryTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/category/manga/MangaCategoryTab.kt index af43a20c6..0c527a8ec 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/category/manga/MangaCategoryTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/category/manga/MangaCategoryTab.kt @@ -18,6 +18,7 @@ import eu.kanade.presentation.category.components.CategorySortAlphabeticallyDial import eu.kanade.presentation.components.AppBar import eu.kanade.presentation.components.TabContent import eu.kanade.tachiyomi.R +import kotlinx.collections.immutable.persistentListOf import tachiyomi.presentation.core.screens.LoadingScreen @Composable @@ -30,7 +31,7 @@ fun Screen.mangaCategoryTab(): TabContent { return TabContent( titleRes = R.string.label_manga, searchEnabled = false, - actions = listOf( + actions = persistentListOf( AppBar.Action( title = stringResource(R.string.action_sort), icon = Icons.Outlined.SortByAlpha, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadsTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadsTab.kt index d256cf4a9..4e174a3e3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadsTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadsTab.kt @@ -16,6 +16,7 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.download.anime.animeDownloadTab import eu.kanade.tachiyomi.ui.download.manga.mangaDownloadTab import eu.kanade.tachiyomi.ui.main.MainActivity +import kotlinx.collections.immutable.persistentListOf data class DownloadsTab( private val isManga: Boolean = false, @@ -39,7 +40,7 @@ data class DownloadsTab( TabbedScreen( titleRes = R.string.label_download_queue, - tabs = listOf( + tabs = persistentListOf( animeDownloadTab(), mangaDownloadTab(), ), diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/entries/anime/track/AnimeTrackInfoDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/entries/anime/track/AnimeTrackInfoDialog.kt index 32b62588c..239e5e5cc 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/entries/anime/track/AnimeTrackInfoDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/entries/anime/track/AnimeTrackInfoDialog.kt @@ -59,6 +59,7 @@ import eu.kanade.tachiyomi.data.track.model.AnimeTrackSearch import eu.kanade.tachiyomi.util.lang.convertEpochMillisZone import eu.kanade.tachiyomi.util.system.openInBrowser import eu.kanade.tachiyomi.util.system.toast +import kotlinx.collections.immutable.ImmutableList import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.distinctUntilChanged @@ -415,7 +416,7 @@ private data class TrackScoreSelectorScreen( private val tracker: Tracker, ) : StateScreenModel(State(tracker.animeService.displayScore(track.toDbTrack()))) { - fun getSelections(): List { + fun getSelections(): ImmutableList { return tracker.animeService.getScoreList() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/entries/manga/track/MangaTrackInfoDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/entries/manga/track/MangaTrackInfoDialog.kt index 7a9fb5efe..6f2f99c1f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/entries/manga/track/MangaTrackInfoDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/entries/manga/track/MangaTrackInfoDialog.kt @@ -59,6 +59,7 @@ import eu.kanade.tachiyomi.data.track.model.MangaTrackSearch import eu.kanade.tachiyomi.util.lang.convertEpochMillisZone import eu.kanade.tachiyomi.util.system.openInBrowser import eu.kanade.tachiyomi.util.system.toast +import kotlinx.collections.immutable.ImmutableList import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.distinctUntilChanged @@ -415,7 +416,7 @@ private data class TrackScoreSelectorScreen( private val tracker: Tracker, ) : StateScreenModel(State(tracker.mangaService.displayScore(track.toDbTrack()))) { - fun getSelections(): List { + fun getSelections(): ImmutableList { return tracker.mangaService.getScoreList() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/history/HistoriesTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/history/HistoriesTab.kt index 3306fbd0a..e78808a6b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/history/HistoriesTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/history/HistoriesTab.kt @@ -24,6 +24,7 @@ import eu.kanade.tachiyomi.ui.history.anime.resumeLastEpisodeSeenEvent import eu.kanade.tachiyomi.ui.history.manga.MangaHistoryScreenModel import eu.kanade.tachiyomi.ui.history.manga.mangaHistoryTab import eu.kanade.tachiyomi.ui.main.MainActivity +import kotlinx.collections.immutable.persistentListOf data class HistoriesTab( private val fromMore: Boolean, @@ -59,7 +60,7 @@ data class HistoriesTab( TabbedScreen( titleRes = R.string.label_recent_manga, - tabs = listOf( + tabs = persistentListOf( animeHistoryTab(context, fromMore, preferences), mangaHistoryTab(context, fromMore, preferences), ), diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/history/anime/AnimeHistoryTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/history/anime/AnimeHistoryTab.kt index 78cb9dbcb..509d1ba45 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/history/anime/AnimeHistoryTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/history/anime/AnimeHistoryTab.kt @@ -23,6 +23,7 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.entries.anime.AnimeScreen import eu.kanade.tachiyomi.ui.main.MainActivity import eu.kanade.tachiyomi.ui.player.settings.PlayerPreferences +import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.receiveAsFlow @@ -127,7 +128,7 @@ fun Screen.animeHistoryTab( } }, actions = - listOf( + persistentListOf( AppBar.Action( title = stringResource(R.string.pref_clear_history), icon = Icons.Outlined.DeleteSweep, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/history/manga/MangaHistoryTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/history/manga/MangaHistoryTab.kt index 0e629b27b..100c587fa 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/history/manga/MangaHistoryTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/history/manga/MangaHistoryTab.kt @@ -24,6 +24,7 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.entries.manga.MangaScreen import eu.kanade.tachiyomi.ui.main.MainActivity import eu.kanade.tachiyomi.ui.reader.ReaderActivity +import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.receiveAsFlow @@ -126,7 +127,7 @@ fun Screen.mangaHistoryTab( } }, actions = - listOf( + persistentListOf( AppBar.Action( title = stringResource(R.string.pref_clear_history), icon = Icons.Outlined.DeleteSweep, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/anime/AnimeLibraryScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/anime/AnimeLibraryScreenModel.kt index a1423d332..7275088a4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/anime/AnimeLibraryScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/anime/AnimeLibraryScreenModel.kt @@ -28,6 +28,9 @@ import eu.kanade.tachiyomi.data.download.anime.AnimeDownloadManager import eu.kanade.tachiyomi.data.track.TrackerManager import eu.kanade.tachiyomi.util.episode.getNextUnseen import eu.kanade.tachiyomi.util.removeCovers +import kotlinx.collections.immutable.PersistentList +import kotlinx.collections.immutable.mutate +import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.combine @@ -584,16 +587,16 @@ class AnimeLibraryScreenModel( } fun clearSelection() { - mutableState.update { it.copy(selection = emptyList()) } + mutableState.update { it.copy(selection = persistentListOf()) } } fun toggleSelection(anime: LibraryAnime) { mutableState.update { state -> - val newSelection = state.selection.toMutableList().apply { - if (fastAny { it.id == anime.id }) { - removeAll { it.id == anime.id } + val newSelection = state.selection.mutate { list -> + if (list.fastAny { it.id == anime.id }) { + list.removeAll { it.id == anime.id } } else { - add(anime) + list.add(anime) } } state.copy(selection = newSelection) @@ -606,11 +609,11 @@ class AnimeLibraryScreenModel( */ fun toggleRangeSelection(anime: LibraryAnime) { mutableState.update { state -> - val newSelection = state.selection.toMutableList().apply { - val lastSelected = lastOrNull() + val newSelection = state.selection.mutate { list -> + val lastSelected = list.lastOrNull() if (lastSelected?.category != anime.category) { - add(anime) - return@apply + list.add(anime) + return@mutate } val items = state.getAnimelibItemsByCategoryId(anime.category) @@ -618,17 +621,17 @@ class AnimeLibraryScreenModel( val lastAnimeIndex = items.indexOf(lastSelected) val curAnimeIndex = items.indexOf(anime) - val selectedIds = fastMap { it.id } + val selectedIds = list.fastMap { it.id } val selectionRange = when { lastAnimeIndex < curAnimeIndex -> IntRange(lastAnimeIndex, curAnimeIndex) curAnimeIndex < lastAnimeIndex -> IntRange(curAnimeIndex, lastAnimeIndex) // We shouldn't reach this point - else -> return@apply + else -> return@mutate } val newSelections = selectionRange.mapNotNull { index -> items[index].takeUnless { it.id in selectedIds } } - addAll(newSelections) + list.addAll(newSelections) } state.copy(selection = newSelection) } @@ -636,14 +639,14 @@ class AnimeLibraryScreenModel( fun selectAll(index: Int) { mutableState.update { state -> - val newSelection = state.selection.toMutableList().apply { + val newSelection = state.selection.mutate { list -> val categoryId = state.categories.getOrNull(index)?.id ?: -1 - val selectedIds = fastMap { it.id } + val selectedIds = list.fastMap { it.id } state.getAnimelibItemsByCategoryId(categoryId) ?.fastMapNotNull { item -> item.libraryAnime.takeUnless { it.id in selectedIds } } - ?.let { addAll(it) } + ?.let { list.addAll(it) } } state.copy(selection = newSelection) } @@ -651,14 +654,14 @@ class AnimeLibraryScreenModel( fun invertSelection(index: Int) { mutableState.update { state -> - val newSelection = state.selection.toMutableList().apply { + val newSelection = state.selection.mutate { list -> val categoryId = state.categories[index].id val items = state.getAnimelibItemsByCategoryId(categoryId)?.fastMap { it.libraryAnime }.orEmpty() - val selectedIds = fastMap { it.id } + val selectedIds = list.fastMap { it.id } val (toRemove, toAdd) = items.fastPartition { it.id in selectedIds } val toRemoveIds = toRemove.fastMap { it.id } - removeAll { it.id in toRemoveIds } - addAll(toAdd) + list.removeAll { it.id in toRemoveIds } + list.addAll(toAdd) } state.copy(selection = newSelection) } @@ -728,7 +731,7 @@ class AnimeLibraryScreenModel( val isLoading: Boolean = true, val library: AnimeLibraryMap = emptyMap(), val searchQuery: String? = null, - val selection: List = emptyList(), + val selection: PersistentList = persistentListOf(), val hasActiveFilters: Boolean = false, val showCategoryTabs: Boolean = false, val showAnimeCount: Boolean = false, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/anime/AnimeLibraryTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/anime/AnimeLibraryTab.kt index 912de9071..45d00fe67 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/anime/AnimeLibraryTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/anime/AnimeLibraryTab.kt @@ -7,6 +7,7 @@ import androidx.compose.animation.graphics.res.rememberAnimatedVectorPainter import androidx.compose.animation.graphics.vector.AnimatedImageVector import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.outlined.HelpOutline import androidx.compose.material.icons.outlined.HelpOutline import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.SnackbarHost @@ -45,6 +46,7 @@ import eu.kanade.tachiyomi.ui.entries.anime.AnimeScreen import eu.kanade.tachiyomi.ui.home.HomeScreen import eu.kanade.tachiyomi.ui.main.MainActivity import eu.kanade.tachiyomi.ui.player.settings.PlayerPreferences +import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.receiveAsFlow @@ -192,10 +194,10 @@ object AnimeLibraryTab : Tab() { EmptyScreen( textResource = R.string.information_empty_library, modifier = Modifier.padding(contentPadding), - actions = listOf( + actions = persistentListOf( EmptyScreenAction( stringResId = R.string.getting_started_guide, - icon = Icons.Outlined.HelpOutline, + icon = Icons.AutoMirrored.Outlined.HelpOutline, onClick = { handler.openUri( "https://aniyomi.org/docs/guides/getting-started", diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/manga/MangaLibraryScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/manga/MangaLibraryScreenModel.kt index c16842f87..33eb633ea 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/manga/MangaLibraryScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/manga/MangaLibraryScreenModel.kt @@ -28,6 +28,9 @@ import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.util.chapter.getNextUnread import eu.kanade.tachiyomi.util.removeCovers +import kotlinx.collections.immutable.PersistentList +import kotlinx.collections.immutable.mutate +import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.combine @@ -575,16 +578,16 @@ class MangaLibraryScreenModel( } fun clearSelection() { - mutableState.update { it.copy(selection = emptyList()) } + mutableState.update { it.copy(selection = persistentListOf()) } } fun toggleSelection(manga: LibraryManga) { mutableState.update { state -> - val newSelection = state.selection.toMutableList().apply { - if (fastAny { it.id == manga.id }) { - removeAll { it.id == manga.id } + val newSelection = state.selection.mutate { list -> + if (list.fastAny { it.id == manga.id }) { + list.removeAll { it.id == manga.id } } else { - add(manga) + list.add(manga) } } state.copy(selection = newSelection) @@ -597,11 +600,11 @@ class MangaLibraryScreenModel( */ fun toggleRangeSelection(manga: LibraryManga) { mutableState.update { state -> - val newSelection = state.selection.toMutableList().apply { - val lastSelected = lastOrNull() + val newSelection = state.selection.mutate { list -> + val lastSelected = list.lastOrNull() if (lastSelected?.category != manga.category) { - add(manga) - return@apply + list.add(manga) + return@mutate } val items = state.getLibraryItemsByCategoryId(manga.category) @@ -609,17 +612,17 @@ class MangaLibraryScreenModel( val lastMangaIndex = items.indexOf(lastSelected) val curMangaIndex = items.indexOf(manga) - val selectedIds = fastMap { it.id } + val selectedIds = list.fastMap { it.id } val selectionRange = when { lastMangaIndex < curMangaIndex -> IntRange(lastMangaIndex, curMangaIndex) curMangaIndex < lastMangaIndex -> IntRange(curMangaIndex, lastMangaIndex) // We shouldn't reach this point - else -> return@apply + else -> return@mutate } val newSelections = selectionRange.mapNotNull { index -> items[index].takeUnless { it.id in selectedIds } } - addAll(newSelections) + list.addAll(newSelections) } state.copy(selection = newSelection) } @@ -627,14 +630,14 @@ class MangaLibraryScreenModel( fun selectAll(index: Int) { mutableState.update { state -> - val newSelection = state.selection.toMutableList().apply { + val newSelection = state.selection.mutate { list -> val categoryId = state.categories.getOrNull(index)?.id ?: -1 - val selectedIds = fastMap { it.id } + val selectedIds = list.fastMap { it.id } state.getLibraryItemsByCategoryId(categoryId) ?.fastMapNotNull { item -> item.libraryManga.takeUnless { it.id in selectedIds } } - ?.let { addAll(it) } + ?.let { list.addAll(it) } } state.copy(selection = newSelection) } @@ -642,14 +645,14 @@ class MangaLibraryScreenModel( fun invertSelection(index: Int) { mutableState.update { state -> - val newSelection = state.selection.toMutableList().apply { + val newSelection = state.selection.mutate { list -> val categoryId = state.categories[index].id val items = state.getLibraryItemsByCategoryId(categoryId)?.fastMap { it.libraryManga }.orEmpty() - val selectedIds = fastMap { it.id } + val selectedIds = list.fastMap { it.id } val (toRemove, toAdd) = items.fastPartition { it.id in selectedIds } val toRemoveIds = toRemove.fastMap { it.id } - removeAll { it.id in toRemoveIds } - addAll(toAdd) + list.removeAll { it.id in toRemoveIds } + list.addAll(toAdd) } state.copy(selection = newSelection) } @@ -719,7 +722,7 @@ class MangaLibraryScreenModel( val isLoading: Boolean = true, val library: MangaLibraryMap = emptyMap(), val searchQuery: String? = null, - val selection: List = emptyList(), + val selection: PersistentList = persistentListOf(), val hasActiveFilters: Boolean = false, val showCategoryTabs: Boolean = false, val showMangaCount: Boolean = false, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/manga/MangaLibraryTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/manga/MangaLibraryTab.kt index 2236dfd01..5a12c9114 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/manga/MangaLibraryTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/manga/MangaLibraryTab.kt @@ -7,6 +7,7 @@ import androidx.compose.animation.graphics.res.rememberAnimatedVectorPainter import androidx.compose.animation.graphics.vector.AnimatedImageVector import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.outlined.HelpOutline import androidx.compose.material.icons.outlined.HelpOutline import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.SnackbarHost @@ -45,6 +46,7 @@ import eu.kanade.tachiyomi.ui.entries.manga.MangaScreen import eu.kanade.tachiyomi.ui.home.HomeScreen import eu.kanade.tachiyomi.ui.main.MainActivity import eu.kanade.tachiyomi.ui.reader.ReaderActivity +import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.receiveAsFlow @@ -187,10 +189,10 @@ object MangaLibraryTab : Tab() { EmptyScreen( textResource = R.string.information_empty_library, modifier = Modifier.padding(contentPadding), - actions = listOf( + actions = persistentListOf( EmptyScreenAction( stringResId = R.string.getting_started_guide, - icon = Icons.Outlined.HelpOutline, + icon = Icons.AutoMirrored.Outlined.HelpOutline, onClick = { handler.openUri( "https://aniyomi.org/docs/guides/getting-started", diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/player/settings/dialogs/SkipIntroLengthDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/player/settings/dialogs/SkipIntroLengthDialog.kt index f0acde26f..a4538a95a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/player/settings/dialogs/SkipIntroLengthDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/player/settings/dialogs/SkipIntroLengthDialog.kt @@ -8,6 +8,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import eu.kanade.tachiyomi.R +import kotlinx.collections.immutable.toImmutableList import tachiyomi.presentation.core.components.WheelTextPicker @Composable @@ -35,7 +36,7 @@ fun SkipIntroLengthDialog( content = { WheelTextPicker( modifier = Modifier.align(Alignment.Center), - items = remember { 1..255 }.map { stringResource(R.string.seconds_short, it) }, + items = remember { 1..255 }.map { stringResource(R.string.seconds_short, it) }.toImmutableList(), onSelectionChanged = { newLength = it + 1 }, startIndex = if (currentSkipIntroLength > 0) { currentSkipIntroLength - 1 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/player/settings/sheets/StreamsCatalogSheet.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/player/settings/sheets/StreamsCatalogSheet.kt index 6b68906c7..f8605a074 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/player/settings/sheets/StreamsCatalogSheet.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/player/settings/sheets/StreamsCatalogSheet.kt @@ -36,6 +36,7 @@ import eu.kanade.tachiyomi.animesource.model.Track import eu.kanade.tachiyomi.ui.player.PlayerViewModel import eu.kanade.tachiyomi.ui.player.settings.sheetDialogPadding import `is`.xyz.mpv.MPVLib +import kotlinx.collections.immutable.persistentListOf import tachiyomi.presentation.core.components.material.padding import java.io.File @@ -50,7 +51,7 @@ fun StreamsCatalogSheet( onSettingsClicked: () -> Unit, onDismissRequest: () -> Unit, ) { - val tabTitles = mutableListOf( + val tabTitles = persistentListOf( stringResource(id = R.string.subtitle_dialog_header), stringResource(id = R.string.audio_dialog_header), ) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/player/settings/sheets/subtitle/SubtitleSettingsSheet.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/player/settings/sheets/subtitle/SubtitleSettingsSheet.kt index b41a6002d..3c9e84bba 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/player/settings/sheets/subtitle/SubtitleSettingsSheet.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/player/settings/sheets/subtitle/SubtitleSettingsSheet.kt @@ -39,6 +39,7 @@ import eu.kanade.presentation.components.TabbedDialog import eu.kanade.presentation.components.TabbedDialogPaddings import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.player.settings.PlayerSettingsScreenModel +import kotlinx.collections.immutable.persistentListOf import tachiyomi.presentation.core.components.material.padding import java.io.File @@ -49,7 +50,7 @@ fun SubtitleSettingsSheet( ) { TabbedDialog( onDismissRequest = onDismissRequest, - tabTitles = listOf( + tabTitles = persistentListOf( stringResource(id = R.string.player_subtitle_settings_delay_tab), stringResource(id = R.string.player_subtitle_settings_font_tab), stringResource(id = R.string.player_subtitle_settings_color_tab), diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderProgressIndicator.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderProgressIndicator.kt index 4ea011c04..c1404e026 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderProgressIndicator.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderProgressIndicator.kt @@ -40,7 +40,7 @@ class ReaderProgressIndicator @JvmOverloads constructor( @Composable override fun Content() { TachiyomiTheme { - CombinedCircularProgressIndicator(progress = progress) + CombinedCircularProgressIndicator(progress = { progress }) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/stats/StatsTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/stats/StatsTab.kt index 610c44bf5..44b54740a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/stats/StatsTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/stats/StatsTab.kt @@ -15,6 +15,7 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.main.MainActivity import eu.kanade.tachiyomi.ui.stats.anime.animeStatsTab import eu.kanade.tachiyomi.ui.stats.manga.mangaStatsTab +import kotlinx.collections.immutable.persistentListOf data class StatsTab( private val isManga: Boolean = false, @@ -38,7 +39,7 @@ data class StatsTab( TabbedScreen( titleRes = R.string.label_stats, - tabs = listOf( + tabs = persistentListOf( animeStatsTab(), mangaStatsTab(), ), diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/storage/StorageTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/storage/StorageTab.kt index e6f2716be..8cd411133 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/storage/StorageTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/storage/StorageTab.kt @@ -15,6 +15,7 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.main.MainActivity import eu.kanade.tachiyomi.ui.storage.anime.animeStorageTab import eu.kanade.tachiyomi.ui.storage.manga.mangaStorageTab +import kotlinx.collections.immutable.persistentListOf data class StorageTab( private val isManga: Boolean = false, @@ -38,7 +39,7 @@ data class StorageTab( TabbedScreen( titleRes = R.string.label_storage, - tabs = listOf( + tabs = persistentListOf( animeStorageTab(), mangaStorageTab(), ), diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/updates/UpdatesTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/updates/UpdatesTab.kt index 013303252..b1ad1ed1e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/updates/UpdatesTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/updates/UpdatesTab.kt @@ -17,6 +17,7 @@ import eu.kanade.tachiyomi.ui.download.DownloadsTab import eu.kanade.tachiyomi.ui.main.MainActivity import eu.kanade.tachiyomi.ui.updates.anime.animeUpdatesTab import eu.kanade.tachiyomi.ui.updates.manga.mangaUpdatesTab +import kotlinx.collections.immutable.persistentListOf data class UpdatesTab( private val fromMore: Boolean, @@ -45,7 +46,7 @@ data class UpdatesTab( TabbedScreen( titleRes = R.string.label_recent_updates, - tabs = listOf( + tabs = persistentListOf( animeUpdatesTab(context, fromMore), mangaUpdatesTab(context, fromMore), ), diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/updates/anime/AnimeUpdatesScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/updates/anime/AnimeUpdatesScreenModel.kt index 80c98e577..092932dd0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/updates/anime/AnimeUpdatesScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/updates/anime/AnimeUpdatesScreenModel.kt @@ -21,6 +21,10 @@ import eu.kanade.tachiyomi.data.download.anime.model.AnimeDownload import eu.kanade.tachiyomi.data.library.anime.AnimeLibraryUpdateJob import eu.kanade.tachiyomi.util.lang.toDateKey import eu.kanade.tachiyomi.util.lang.toRelativeString +import kotlinx.collections.immutable.PersistentList +import kotlinx.collections.immutable.mutate +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toPersistentList import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch @@ -110,27 +114,29 @@ class AnimeUpdatesScreenModel( } } - private fun List.toUpdateItems(): List { - return this.map { update -> - val activeDownload = downloadManager.getQueuedDownloadOrNull(update.episodeId) - val downloaded = downloadManager.isEpisodeDownloaded( - update.episodeName, - update.scanlator, - update.animeTitle, - update.sourceId, - ) - val downloadState = when { - activeDownload != null -> activeDownload.status - downloaded -> AnimeDownload.State.DOWNLOADED - else -> AnimeDownload.State.NOT_DOWNLOADED + private fun List.toUpdateItems(): PersistentList { + return this + .map { update -> + val activeDownload = downloadManager.getQueuedDownloadOrNull(update.episodeId) + val downloaded = downloadManager.isEpisodeDownloaded( + update.episodeName, + update.scanlator, + update.animeTitle, + update.sourceId, + ) + val downloadState = when { + activeDownload != null -> activeDownload.status + downloaded -> AnimeDownload.State.DOWNLOADED + else -> AnimeDownload.State.NOT_DOWNLOADED + } + AnimeUpdatesItem( + update = update, + downloadStateProvider = { downloadState }, + downloadProgressProvider = { activeDownload?.progress ?: 0 }, + selected = update.episodeId in selectedEpisodeIds, + ) } - AnimeUpdatesItem( - update = update, - downloadStateProvider = { downloadState }, - downloadProgressProvider = { activeDownload?.progress ?: 0 }, - selected = update.episodeId in selectedEpisodeIds, - ) - } + .toPersistentList() } fun updateLibrary(): Boolean { @@ -148,17 +154,14 @@ class AnimeUpdatesScreenModel( */ private fun updateDownloadState(download: AnimeDownload) { mutableState.update { state -> - val newItems = state.items.toMutableList().apply { - val modifiedIndex = indexOfFirst { it.update.episodeId == download.episode.id } - if (modifiedIndex < 0) return@apply + val newItems = state.items.mutate { list -> + val modifiedIndex = list.indexOfFirst { it.update.episodeId == download.episode.id } + if (modifiedIndex < 0) return@mutate - val item = get(modifiedIndex) - set( - modifiedIndex, - item.copy( - downloadStateProvider = { download.status }, - downloadProgressProvider = { download.progress }, - ), + val item = list[modifiedIndex] + list[modifiedIndex] = item.copy( + downloadStateProvider = { download.status }, + downloadProgressProvider = { download.progress }, ) } state.copy(items = newItems) @@ -349,7 +352,7 @@ class AnimeUpdatesScreenModel( } } } - state.copy(items = newItems) + state.copy(items = newItems.toPersistentList()) } } @@ -359,7 +362,7 @@ class AnimeUpdatesScreenModel( selectedEpisodeIds.addOrRemove(it.update.episodeId, selected) it.copy(selected = selected) } - state.copy(items = newItems) + state.copy(items = newItems.toPersistentList()) } selectedPositions[0] = -1 @@ -372,7 +375,7 @@ class AnimeUpdatesScreenModel( selectedEpisodeIds.addOrRemove(it.update.episodeId, !it.selected) it.copy(selected = !it.selected) } - state.copy(items = newItems) + state.copy(items = newItems.toPersistentList()) } selectedPositions[0] = -1 selectedPositions[1] = -1 @@ -389,7 +392,7 @@ class AnimeUpdatesScreenModel( @Immutable data class State( val isLoading: Boolean = true, - val items: List = emptyList(), + val items: PersistentList = persistentListOf(), val dialog: Dialog? = null, ) { val selected = items.filter { it.selected } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/updates/anime/AnimeUpdatesTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/updates/anime/AnimeUpdatesTab.kt index ff77c7be4..003bc09cf 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/updates/anime/AnimeUpdatesTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/updates/anime/AnimeUpdatesTab.kt @@ -27,6 +27,7 @@ import eu.kanade.tachiyomi.ui.entries.anime.AnimeScreen import eu.kanade.tachiyomi.ui.home.HomeScreen import eu.kanade.tachiyomi.ui.main.MainActivity import eu.kanade.tachiyomi.ui.player.settings.PlayerPreferences +import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.flow.collectLatest import tachiyomi.core.util.lang.launchIO import uy.kohesive.injekt.injectLazy @@ -141,7 +142,7 @@ fun Screen.animeUpdatesTab( }, actions = if (screenModel.state.collectAsState().value.selected.isNotEmpty()) { - listOf( + persistentListOf( AppBar.Action( title = stringResource(R.string.action_select_all), icon = Icons.Outlined.SelectAll, @@ -154,7 +155,7 @@ fun Screen.animeUpdatesTab( ), ) } else { - listOf( + persistentListOf( AppBar.Action( title = stringResource(R.string.action_update_library), icon = Icons.Outlined.Refresh, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/updates/manga/MangaUpdatesScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/updates/manga/MangaUpdatesScreenModel.kt index 8ce3e0b23..5a6291f67 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/updates/manga/MangaUpdatesScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/updates/manga/MangaUpdatesScreenModel.kt @@ -21,6 +21,10 @@ import eu.kanade.tachiyomi.data.download.manga.model.MangaDownload import eu.kanade.tachiyomi.data.library.manga.MangaLibraryUpdateJob import eu.kanade.tachiyomi.util.lang.toDateKey import eu.kanade.tachiyomi.util.lang.toRelativeString +import kotlinx.collections.immutable.PersistentList +import kotlinx.collections.immutable.mutate +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toPersistentList import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch @@ -106,27 +110,29 @@ class MangaUpdatesScreenModel( } } - private fun List.toUpdateItems(): List { - return this.map { update -> - val activeDownload = downloadManager.getQueuedDownloadOrNull(update.chapterId) - val downloaded = downloadManager.isChapterDownloaded( - update.chapterName, - update.scanlator, - update.mangaTitle, - update.sourceId, - ) - val downloadState = when { - activeDownload != null -> activeDownload.status - downloaded -> MangaDownload.State.DOWNLOADED - else -> MangaDownload.State.NOT_DOWNLOADED + private fun List.toUpdateItems(): PersistentList { + return this + .map { update -> + val activeDownload = downloadManager.getQueuedDownloadOrNull(update.chapterId) + val downloaded = downloadManager.isChapterDownloaded( + update.chapterName, + update.scanlator, + update.mangaTitle, + update.sourceId, + ) + val downloadState = when { + activeDownload != null -> activeDownload.status + downloaded -> MangaDownload.State.DOWNLOADED + else -> MangaDownload.State.NOT_DOWNLOADED + } + MangaUpdatesItem( + update = update, + downloadStateProvider = { downloadState }, + downloadProgressProvider = { activeDownload?.progress ?: 0 }, + selected = update.chapterId in selectedChapterIds, + ) } - MangaUpdatesItem( - update = update, - downloadStateProvider = { downloadState }, - downloadProgressProvider = { activeDownload?.progress ?: 0 }, - selected = update.chapterId in selectedChapterIds, - ) - } + .toPersistentList() } fun updateLibrary(): Boolean { @@ -144,17 +150,14 @@ class MangaUpdatesScreenModel( */ private fun updateDownloadState(download: MangaDownload) { mutableState.update { state -> - val newItems = state.items.toMutableList().apply { - val modifiedIndex = indexOfFirst { it.update.chapterId == download.chapter.id } - if (modifiedIndex < 0) return@apply + val newItems = state.items.mutate { list -> + val modifiedIndex = list.indexOfFirst { it.update.chapterId == download.chapter.id } + if (modifiedIndex < 0) return@mutate - val item = get(modifiedIndex) - set( - modifiedIndex, - item.copy( - downloadStateProvider = { download.status }, - downloadProgressProvider = { download.progress }, - ), + val item = list[modifiedIndex] + list[modifiedIndex] = item.copy( + downloadStateProvider = { download.status }, + downloadProgressProvider = { download.progress }, ) } state.copy(items = newItems) @@ -330,7 +333,7 @@ class MangaUpdatesScreenModel( } } } - state.copy(items = newItems) + state.copy(items = newItems.toPersistentList()) } } @@ -340,7 +343,7 @@ class MangaUpdatesScreenModel( selectedChapterIds.addOrRemove(it.update.chapterId, selected) it.copy(selected = selected) } - state.copy(items = newItems) + state.copy(items = newItems.toPersistentList()) } selectedPositions[0] = -1 @@ -353,7 +356,7 @@ class MangaUpdatesScreenModel( selectedChapterIds.addOrRemove(it.update.chapterId, !it.selected) it.copy(selected = !it.selected) } - state.copy(items = newItems) + state.copy(items = newItems.toPersistentList()) } selectedPositions[0] = -1 selectedPositions[1] = -1 @@ -370,7 +373,7 @@ class MangaUpdatesScreenModel( @Immutable data class State( val isLoading: Boolean = true, - val items: List = emptyList(), + val items: PersistentList = persistentListOf(), val dialog: Dialog? = null, ) { val selected = items.filter { it.selected } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/updates/manga/MangaUpdatesTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/updates/manga/MangaUpdatesTab.kt index a458a0ffd..97fc588b6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/updates/manga/MangaUpdatesTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/updates/manga/MangaUpdatesTab.kt @@ -24,6 +24,7 @@ import eu.kanade.tachiyomi.ui.entries.manga.MangaScreen import eu.kanade.tachiyomi.ui.home.HomeScreen import eu.kanade.tachiyomi.ui.main.MainActivity import eu.kanade.tachiyomi.ui.reader.ReaderActivity +import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.flow.collectLatest @Composable @@ -114,7 +115,7 @@ fun Screen.mangaUpdatesTab( }, actions = if (screenModel.state.collectAsState().value.selected.isNotEmpty()) { - listOf( + persistentListOf( AppBar.Action( title = stringResource(R.string.action_select_all), icon = Icons.Outlined.SelectAll, @@ -127,7 +128,7 @@ fun Screen.mangaUpdatesTab( ), ) } else { - listOf( + persistentListOf( AppBar.Action( title = stringResource(R.string.action_update_library), icon = Icons.Outlined.Refresh, diff --git a/app/src/main/java/eu/kanade/tachiyomi/dev/preview/DummyTracker.kt b/app/src/main/java/eu/kanade/test/DummyTracker.kt similarity index 85% rename from app/src/main/java/eu/kanade/tachiyomi/dev/preview/DummyTracker.kt rename to app/src/main/java/eu/kanade/test/DummyTracker.kt index 3c6404dc4..5b1d41145 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/dev/preview/DummyTracker.kt +++ b/app/src/main/java/eu/kanade/test/DummyTracker.kt @@ -1,10 +1,12 @@ -package eu.kanade.tachiyomi.dev.preview +package eu.kanade.test import android.graphics.Color import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.track.Tracker import eu.kanade.tachiyomi.data.track.model.AnimeTrackSearch import eu.kanade.tachiyomi.data.track.model.MangaTrackSearch +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toImmutableList import okhttp3.OkHttpClient data class DummyTracker( @@ -16,7 +18,7 @@ data class DummyTracker( val valLogo: Int = R.drawable.ic_tracker_anilist, val valStatuses: List = (1..6).toList(), val valCompletionStatus: Int = 2, - val valScoreList: List = (0..10).map(Int::toString), + val valScoreList: ImmutableList = (0..10).map(Int::toString).toImmutableList(), val val10PointScore: Double = 5.4, val valMangaSearchResults: List = listOf(), val valAnimeSearchResults: List = listOf(), @@ -43,7 +45,7 @@ data class DummyTracker( override fun getCompletionStatus(): Int = valCompletionStatus - override fun getScoreList(): List = valScoreList + override fun getScoreList(): ImmutableList = valScoreList override suspend fun login(username: String, password: String) = Unit diff --git a/core/src/main/java/eu/kanade/tachiyomi/util/storage/EpubFile.kt b/core/src/main/java/eu/kanade/tachiyomi/util/storage/EpubFile.kt index 8838a199c..a00ee69e7 100644 --- a/core/src/main/java/eu/kanade/tachiyomi/util/storage/EpubFile.kt +++ b/core/src/main/java/eu/kanade/tachiyomi/util/storage/EpubFile.kt @@ -80,7 +80,7 @@ class EpubFile(file: File) : Closeable { /** * Returns all the pages from the epub. */ - fun getPagesFromDocument(document: Document): List { + private fun getPagesFromDocument(document: Document): List { val pages = document.select("manifest > item") .filter { node -> "application/xhtml+xml" == node.attr("media-type") } .associateBy { it.attr("id") } @@ -102,10 +102,9 @@ class EpubFile(file: File) : Closeable { val imageBasePath = getParentDirectory(entryPath) document.allElements.forEach { - if (it.tagName() == "img") { - result.add(resolveZipPath(imageBasePath, it.attr("src"))) - } else if (it.tagName() == "image") { - result.add(resolveZipPath(imageBasePath, it.attr("xlink:href"))) + when (it.tagName()) { + "img" -> result.add(resolveZipPath(imageBasePath, it.attr("src"))) + "image" -> result.add(resolveZipPath(imageBasePath, it.attr("xlink:href"))) } } } diff --git a/domain/src/main/java/tachiyomi/domain/source/anime/model/StubAnimeSource.kt b/domain/src/main/java/tachiyomi/domain/source/anime/model/StubAnimeSource.kt index 51c997bba..5744c9968 100644 --- a/domain/src/main/java/tachiyomi/domain/source/anime/model/StubAnimeSource.kt +++ b/domain/src/main/java/tachiyomi/domain/source/anime/model/StubAnimeSource.kt @@ -25,5 +25,11 @@ class StubAnimeSource( override fun toString(): String = if (isInvalid.not()) "$name (${lang.uppercase()})" else id.toString() + + companion object { + fun from(source: AnimeSource): StubAnimeSource { + return StubAnimeSource(id = source.id, lang = source.lang, name = source.name) + } + } } class AnimeSourceNotInstalledException : Exception() diff --git a/domain/src/main/java/tachiyomi/domain/source/manga/model/StubMangaSource.kt b/domain/src/main/java/tachiyomi/domain/source/manga/model/StubMangaSource.kt index 06416d7c4..412ff6c6d 100644 --- a/domain/src/main/java/tachiyomi/domain/source/manga/model/StubMangaSource.kt +++ b/domain/src/main/java/tachiyomi/domain/source/manga/model/StubMangaSource.kt @@ -25,6 +25,12 @@ class StubMangaSource( override fun toString(): String = if (isInvalid.not()) "$name (${lang.uppercase()})" else id.toString() + + companion object { + fun from(source: MangaSource): StubMangaSource { + return StubMangaSource(id = source.id, lang = source.lang, name = source.name) + } + } } class SourceNotInstalledException : Exception() diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index 83aad11ca..6c5248989 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -1,5 +1,5 @@ [versions] -agp_version = "8.1.2" +agp_version = "8.1.3" lifecycle_version = "2.6.2" paging_version = "3.2.1" @@ -14,7 +14,6 @@ corektx = "androidx.core:core-ktx:1.12.0" splashscreen = "androidx.core:core-splashscreen:1.0.1" recyclerview = "androidx.recyclerview:recyclerview:1.3.2" viewpager = "androidx.viewpager:viewpager:1.1.0-alpha01" -glance = "androidx.glance:glance-appwidget:1.0.0" profileinstaller = "androidx.profileinstaller:profileinstaller:1.3.1" mediasession = "androidx.media:media:1.6.0" @@ -27,7 +26,7 @@ workmanager = "androidx.work:work-runtime-ktx:2.8.1" paging-runtime = { module = "androidx.paging:paging-runtime", version.ref = "paging_version" } paging-compose = { module = "androidx.paging:paging-compose", version.ref = "paging_version" } -benchmark-macro = "androidx.benchmark:benchmark-macro-junit4:1.2.0" +benchmark-macro = "androidx.benchmark:benchmark-macro-junit4:1.2.1" test-ext = "androidx.test.ext:junit-ktx:1.2.0-alpha01" test-espresso-core = "androidx.test.espresso:espresso-core:3.6.0-alpha01" test-uiautomator = "androidx.test.uiautomator:uiautomator:2.3.0-alpha05" diff --git a/gradle/compose.versions.toml b/gradle/compose.versions.toml index 26f0809d0..657e2e9e8 100644 --- a/gradle/compose.versions.toml +++ b/gradle/compose.versions.toml @@ -1,10 +1,10 @@ [versions] -compiler = "1.5.3" -compose-bom = "2023.09.00-alpha02" -accompanist = "0.33.1-alpha" +compiler = "1.5.4" +compose-bom = "2023.12.00-alpha01" +accompanist = "0.33.2-alpha" [libraries] -activity = "androidx.activity:activity-compose:1.8.0" +activity = "androidx.activity:activity-compose:1.8.1" bom = { group = "dev.chrisbanes.compose", name = "compose-bom", version.ref = "compose-bom" } foundation = { module = "androidx.compose.foundation:foundation" } animation = { module = "androidx.compose.animation:animation" } @@ -19,7 +19,11 @@ material-icons = { module = "androidx.compose.material:material-icons-extended" # Some components aren't available in Material3 material-core = { module = "androidx.compose.material:material" } +glance = "androidx.glance:glance-appwidget:1.0.0" + accompanist-webview = { module = "com.google.accompanist:accompanist-webview", version.ref = "accompanist" } accompanist-permissions = { module = "com.google.accompanist:accompanist-permissions", version.ref = "accompanist" } -accompanist-themeadapter = { module = "com.google.accompanist:accompanist-themeadapter-material3", version.ref = "accompanist" } +accompanist-themeadapter = { module = "com.google.accompanist:accompanist-themeadapter-material3", version.ref ="accompanist" } accompanist-systemuicontroller = { module = "com.google.accompanist:accompanist-systemuicontroller", version.ref = "accompanist" } + +lintchecks = { module = "com.slack.lint.compose:compose-lint-checks", version = "1.2.0" } diff --git a/gradle/kotlinx.versions.toml b/gradle/kotlinx.versions.toml index 3014a1fa7..54024e394 100644 --- a/gradle/kotlinx.versions.toml +++ b/gradle/kotlinx.versions.toml @@ -1,12 +1,14 @@ [versions] -kotlin_version = "1.9.10" -serialization_version = "1.6.0" +kotlin_version = "1.9.20" +serialization_version = "1.6.1" xml_serialization_version = "0.86.2" [libraries] reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin_version" } gradle = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin_version" } +immutables = { module = "org.jetbrains.kotlinx:kotlinx-collections-immutable", version = "0.3.6" } + coroutines-bom = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-bom", version = "1.7.3" } coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core" } coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android" } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0c0e3af22..adc97e9ea 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ shizuku_version = "12.2.0" sqlite = "2.4.0" sqldelight = "2.0.0" leakcanary = "2.12" -voyager = "1.0.0-rc09" +voyager = "1.0.0-rc10" richtext = "0.17.0" [libraries] diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index d811110a3..96ddf702a 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -480,6 +480,7 @@ Backup location Automatic backup frequency Maximum automatic backups + Create Backup created Invalid backup file Backup does not contain any library entries. @@ -861,7 +862,7 @@ Select cover image Select backup file No file picker app found - File picker failed to return file to app + No file selected Download diff --git a/presentation-core/build.gradle.kts b/presentation-core/build.gradle.kts index 9c87d7465..4727dbed8 100644 --- a/presentation-core/build.gradle.kts +++ b/presentation-core/build.gradle.kts @@ -35,6 +35,9 @@ dependencies { debugImplementation(compose.ui.tooling) implementation(compose.ui.tooling.preview) implementation(compose.ui.util) + lintChecks(compose.lintchecks) + + implementation(kotlinx.immutables) } tasks { diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/ActionButton.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/ActionButton.kt index 54cbd9cdd..4aa09cde5 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/ActionButton.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/ActionButton.kt @@ -14,10 +14,10 @@ import androidx.compose.ui.unit.dp @Composable fun ActionButton( - modifier: Modifier = Modifier, title: String, icon: ImageVector, onClick: () -> Unit, + modifier: Modifier = Modifier, ) { TextButton( modifier = modifier, diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/AdaptiveSheet.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/AdaptiveSheet.kt index de3871f2f..877db62f4 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/AdaptiveSheet.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/AdaptiveSheet.kt @@ -58,11 +58,11 @@ private val sheetAnimationSpec = tween(durationMillis = 350) @Composable fun AdaptiveSheet( - modifier: Modifier = Modifier, isTabletUi: Boolean, tonalElevation: Dp, enableSwipeDismiss: Boolean, onDismissRequest: () -> Unit, + modifier: Modifier = Modifier, content: @Composable () -> Unit, ) { val density = LocalDensity.current diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/Badges.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/Badges.kt index f2a004ba2..ee2a05dac 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/Badges.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/Badges.kt @@ -36,13 +36,14 @@ fun BadgeGroup( @Composable fun Badge( text: String, + modifier: Modifier = Modifier, color: Color = MaterialTheme.colorScheme.secondary, textColor: Color = MaterialTheme.colorScheme.onSecondary, shape: Shape = RectangleShape, ) { Text( text = text, - modifier = Modifier + modifier = modifier .clip(shape) .background(color) .padding(horizontal = 3.dp, vertical = 1.dp), @@ -56,6 +57,7 @@ fun Badge( @Composable fun Badge( imageVector: ImageVector, + modifier: Modifier = Modifier, color: Color = MaterialTheme.colorScheme.secondary, iconColor: Color = MaterialTheme.colorScheme.onSecondary, shape: Shape = RectangleShape, @@ -86,7 +88,7 @@ fun Badge( Text( text = text, inlineContent = inlineContent, - modifier = Modifier + modifier = modifier .clip(shape) .background(color) .padding(horizontal = 3.dp, vertical = 1.dp), diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/CircularProgressIndicator.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/CircularProgressIndicator.kt index dafe3237d..b123e26e5 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/CircularProgressIndicator.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/CircularProgressIndicator.kt @@ -38,17 +38,14 @@ import androidx.compose.ui.tooling.preview.Preview */ @Composable fun CombinedCircularProgressIndicator( - progress: Float, + progress: () -> Float, + modifier: Modifier = Modifier, ) { - val animatedProgress by animateFloatAsState( - targetValue = progress, - animationSpec = ProgressIndicatorDefaults.ProgressAnimationSpec, - label = "progress", - ) AnimatedContent( - targetState = progress == 0f, + targetState = progress() == 0f, transitionSpec = { fadeIn() togetherWith fadeOut() }, label = "progressState", + modifier = modifier, ) { indeterminate -> if (indeterminate) { // Indeterminate @@ -65,8 +62,13 @@ fun CombinedCircularProgressIndicator( ), label = "rotation", ) + val animatedProgress by animateFloatAsState( + targetValue = progress(), + animationSpec = ProgressIndicatorDefaults.ProgressAnimationSpec, + label = "progress", + ) CircularProgressIndicator( - progress = animatedProgress, + progress = { animatedProgress }, modifier = Modifier.rotate(rotation), ) } @@ -103,7 +105,7 @@ private fun CombinedCircularProgressIndicatorPreview() { .fillMaxSize() .padding(it), ) { - CombinedCircularProgressIndicator(progress = progress) + CombinedCircularProgressIndicator(progress = { progress }) } } } diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/LabeledCheckbox.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/LabeledCheckbox.kt index 0a72e4b0b..e40293841 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/LabeledCheckbox.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/LabeledCheckbox.kt @@ -17,10 +17,11 @@ import androidx.compose.ui.unit.dp @Composable fun LabeledCheckbox( - modifier: Modifier = Modifier, label: String, checked: Boolean, onCheckedChange: (Boolean) -> Unit, + modifier: Modifier = Modifier, + enabled: Boolean = true, ) { Row( modifier = modifier @@ -37,6 +38,7 @@ fun LabeledCheckbox( Checkbox( checked = checked, onCheckedChange = null, + enabled = enabled, ) Text(text = label) diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/LinkIcon.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/LinkIcon.kt index 17dc818ca..b1e1e8245 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/LinkIcon.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/LinkIcon.kt @@ -12,10 +12,10 @@ import androidx.compose.ui.unit.dp @Composable fun LinkIcon( - modifier: Modifier = Modifier, label: String, icon: ImageVector, url: String, + modifier: Modifier = Modifier, ) { val uriHandler = LocalUriHandler.current IconButton( diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/ListGroupHeader.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/ListGroupHeader.kt index c0ffb35d4..1aaba373e 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/ListGroupHeader.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/ListGroupHeader.kt @@ -10,8 +10,8 @@ import tachiyomi.presentation.core.components.material.padding @Composable fun ListGroupHeader( - modifier: Modifier = Modifier, text: String, + modifier: Modifier = Modifier, ) { Text( text = text, diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/SettingsItems.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/SettingsItems.kt index b98159d07..bcfab6217 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/SettingsItems.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/SettingsItems.kt @@ -191,11 +191,11 @@ fun RadioItem( @Composable fun SliderItem( label: String, - min: Int = 0, - max: Int, value: Int, valueText: String, onChange: (Int) -> Unit, + max: Int, + min: Int = 0, ) { val haptic = LocalHapticFeedback.current diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/TwoPanelBox.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/TwoPanelBox.kt index a3a97dcd1..8dbc88693 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/TwoPanelBox.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/TwoPanelBox.kt @@ -17,10 +17,10 @@ import androidx.compose.ui.unit.dp @Composable fun TwoPanelBox( - modifier: Modifier = Modifier, - contentWindowInsets: WindowInsets = WindowInsets(0), startContent: @Composable BoxScope.() -> Unit, endContent: @Composable BoxScope.() -> Unit, + modifier: Modifier = Modifier, + contentWindowInsets: WindowInsets = WindowInsets(0), ) { val direction = LocalLayoutDirection.current val padding = contentWindowInsets.asPaddingValues() diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/WheelPicker.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/WheelPicker.kt index ce0d497b4..4545d695d 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/WheelPicker.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/WheelPicker.kt @@ -41,6 +41,7 @@ import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp +import kotlinx.collections.immutable.ImmutableList import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.drop @@ -54,9 +55,9 @@ import kotlin.math.absoluteValue @Composable fun WheelNumberPicker( + items: ImmutableList, modifier: Modifier = Modifier, startIndex: Int = 0, - items: List, size: DpSize = DpSize(128.dp, 128.dp), onSelectionChanged: (index: Int) -> Unit = {}, backgroundContent: (@Composable (size: DpSize) -> Unit)? = { @@ -78,9 +79,9 @@ fun WheelNumberPicker( @Composable fun WheelTextPicker( + items: ImmutableList, modifier: Modifier = Modifier, startIndex: Int = 0, - items: List, size: DpSize = DpSize(128.dp, 128.dp), onSelectionChanged: (index: Int) -> Unit = {}, backgroundContent: (@Composable (size: DpSize) -> Unit)? = { @@ -101,9 +102,9 @@ fun WheelTextPicker( @Composable private fun WheelPicker( + items: ImmutableList, modifier: Modifier = Modifier, startIndex: Int = 0, - items: List, size: DpSize = DpSize(128.dp, 128.dp), onSelectionChanged: (index: Int) -> Unit = {}, manualInputType: KeyboardType? = null, diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/FloatingActionButton.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/FloatingActionButton.kt index 645e318f3..fd1fa8c4b 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/FloatingActionButton.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/FloatingActionButton.kt @@ -46,7 +46,10 @@ fun ExtendedFloatingActionButton( contentColor: Color = contentColorFor(containerColor), elevation: FloatingActionButtonElevation = FloatingActionButtonDefaults.elevation(), ) { - val minWidth by animateDpAsState(if (expanded) ExtendedFabMinimumWidth else FabContainerWidth) + val minWidth by animateDpAsState( + targetValue = if (expanded) ExtendedFabMinimumWidth else FabContainerWidth, + label = "minWidth", + ) FloatingActionButton( modifier = modifier.sizeIn(minWidth = minWidth), onClick = onClick, @@ -56,8 +59,14 @@ fun ExtendedFloatingActionButton( contentColor = contentColor, elevation = elevation, ) { - val startPadding by animateDpAsState(if (expanded) ExtendedFabIconSize / 2 else 0.dp) - val endPadding by animateDpAsState(if (expanded) ExtendedFabTextPadding else 0.dp) + val startPadding by animateDpAsState( + targetValue = if (expanded) ExtendedFabIconSize / 2 else 0.dp, + label = "startPadding", + ) + val endPadding by animateDpAsState( + targetValue = if (expanded) ExtendedFabTextPadding else 0.dp, + label = "endPadding", + ) Row( modifier = Modifier.padding(start = startPadding, end = endPadding), diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/IconToggleButton.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/IconToggleButton.kt index 2abcc4b39..d00cc8657 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/IconToggleButton.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/IconToggleButton.kt @@ -20,9 +20,9 @@ import androidx.compose.ui.unit.dp fun IconToggleButton( checked: Boolean, onCheckedChange: (Boolean) -> Unit, - modifier: Modifier = Modifier, imageVector: ImageVector, title: String, + modifier: Modifier = Modifier, ) { FilledIconToggleButton( checked = checked, diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Scaffold.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Scaffold.kt index cd14e2c0e..609e7933a 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Scaffold.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Scaffold.kt @@ -14,36 +14,39 @@ * limitations under the License. */ +@file:Suppress("KDocUnresolvedReference") + package tachiyomi.presentation.core.components.material -import androidx.compose.foundation.layout.MutableWindowInsets import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.asPaddingValues -import androidx.compose.foundation.layout.calculateEndPadding -import androidx.compose.foundation.layout.calculateStartPadding -import androidx.compose.foundation.layout.exclude -import androidx.compose.foundation.layout.onConsumedWindowInsetsChanged +import androidx.compose.foundation.layout.windowInsetsBottomHeight +import androidx.compose.foundation.layout.windowInsetsEndWidth +import androidx.compose.foundation.layout.windowInsetsStartWidth +import androidx.compose.foundation.layout.windowInsetsTopHeight import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.FabPosition import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ScaffoldDefaults import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.material3.contentColorFor -import androidx.compose.material3.rememberTopAppBarState import androidx.compose.runtime.Composable -import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.Immutable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.staticCompositionLocalOf +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.input.nestedscroll.nestedScroll -import androidx.compose.ui.layout.SubcomposeLayout +import androidx.compose.ui.layout.Layout import androidx.compose.ui.unit.Constraints +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.max +import androidx.compose.ui.unit.offset import androidx.compose.ui.util.fastForEach import androidx.compose.ui.util.fastMap import androidx.compose.ui.util.fastMaxBy @@ -70,8 +73,6 @@ import kotlin.math.max * * Pass scroll behavior to top bar by default * * Remove height constraint for expanded app bar * * Also take account of fab height when providing inner padding - * * Fixes for fab and snackbar horizontal placements when [contentWindowInsets] is used - * * Handle consumed window insets * * Add startBar slot for Navigation Rail * * @param modifier the [Modifier] to be applied to this scaffold @@ -99,9 +100,7 @@ import kotlin.math.max @Composable fun Scaffold( modifier: Modifier = Modifier, - topBarScrollBehavior: TopAppBarScrollBehavior = TopAppBarDefaults.pinnedScrollBehavior( - rememberTopAppBarState(), - ), + topBarScrollBehavior: TopAppBarScrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(), topBar: @Composable (TopAppBarScrollBehavior) -> Unit = {}, bottomBar: @Composable () -> Unit = {}, startBar: @Composable () -> Unit = {}, @@ -113,16 +112,9 @@ fun Scaffold( contentWindowInsets: WindowInsets = ScaffoldDefaults.contentWindowInsets, content: @Composable (PaddingValues) -> Unit, ) { - // Tachiyomi: Handle consumed window insets - val remainingWindowInsets = remember { MutableWindowInsets() } androidx.compose.material3.Surface( modifier = Modifier .nestedScroll(topBarScrollBehavior.nestedScrollConnection) - .onConsumedWindowInsetsChanged { - remainingWindowInsets.insets = contentWindowInsets.exclude( - it, - ) - } .then(modifier), color = containerColor, contentColor = contentColor, @@ -134,7 +126,7 @@ fun Scaffold( bottomBar = bottomBar, content = content, snackbar = snackbarHost, - contentWindowInsets = remainingWindowInsets, + contentWindowInsets = contentWindowInsets, fab = floatingActionButton, ) } @@ -152,7 +144,6 @@ fun Scaffold( * @param bottomBar the content to place at the bottom of the [Scaffold], on top of the * [content], typically a [NavigationBar]. */ -@OptIn(ExperimentalMaterial3Api::class) @Composable private fun ScaffoldLayout( fabPosition: FabPosition, @@ -164,7 +155,47 @@ private fun ScaffoldLayout( contentWindowInsets: WindowInsets, bottomBar: @Composable () -> Unit, ) { - SubcomposeLayout { constraints -> + // Create the backing values for the content padding + // These values will be updated during measurement, but before measuring and placing + // the body content + var topContentPadding by remember { mutableStateOf(0.dp) } + var startContentPadding by remember { mutableStateOf(0.dp) } + var endContentPadding by remember { mutableStateOf(0.dp) } + var bottomContentPadding by remember { mutableStateOf(0.dp) } + + val contentPadding = remember { + object : PaddingValues { + override fun calculateLeftPadding(layoutDirection: LayoutDirection): Dp = + when (layoutDirection) { + LayoutDirection.Ltr -> startContentPadding + LayoutDirection.Rtl -> endContentPadding + } + + override fun calculateTopPadding(): Dp = topContentPadding + + override fun calculateRightPadding(layoutDirection: LayoutDirection): Dp = + when (layoutDirection) { + LayoutDirection.Ltr -> endContentPadding + LayoutDirection.Rtl -> startContentPadding + } + + override fun calculateBottomPadding(): Dp = bottomContentPadding + } + } + Layout( + contents = listOf( + { Spacer(Modifier.windowInsetsTopHeight(contentWindowInsets)) }, + { Spacer(Modifier.windowInsetsBottomHeight(contentWindowInsets)) }, + { Spacer(Modifier.windowInsetsStartWidth(contentWindowInsets)) }, + { Spacer(Modifier.windowInsetsEndWidth(contentWindowInsets)) }, + startBar, + topBar, + snackbar, + fab, + bottomBar, + { content(contentPadding) }, + ), + ) { measurables, constraints -> val layoutWidth = constraints.maxWidth val layoutHeight = constraints.maxHeight @@ -175,117 +206,116 @@ private fun ScaffoldLayout( */ val topBarConstraints = looseConstraints.copy(maxHeight = Constraints.Infinity) - layout(layoutWidth, layoutHeight) { - val leftInset = contentWindowInsets.getLeft(this@SubcomposeLayout, layoutDirection) - val rightInset = contentWindowInsets.getRight(this@SubcomposeLayout, layoutDirection) - val bottomInset = contentWindowInsets.getBottom(this@SubcomposeLayout) + val topInsetsPlaceables = measurables[0].single() + .measure(looseConstraints) + val bottomInsetsPlaceables = measurables[1].single() + .measure(looseConstraints) + val startInsetsPlaceables = measurables[2].single() + .measure(looseConstraints) + val endInsetsPlaceables = measurables[3].single() + .measure(looseConstraints) - // Tachiyomi: Add startBar slot for Navigation Rail - val startBarPlaceables = subcompose(ScaffoldLayoutContent.StartBar, startBar).fastMap { - it.measure(looseConstraints) - } - val startBarWidth = startBarPlaceables.fastMaxBy { it.width }?.width ?: 0 + val startInsetsWidth = startInsetsPlaceables.width + val endInsetsWidth = endInsetsPlaceables.width - // Tachiyomi: layoutWidth after horizontal insets - val insetLayoutWidth = layoutWidth - leftInset - rightInset - startBarWidth + val topInsetsHeight = topInsetsPlaceables.height + val bottomInsetsHeight = bottomInsetsPlaceables.height - val topBarPlaceables = subcompose(ScaffoldLayoutContent.TopBar, topBar).fastMap { - it.measure(topBarConstraints) - } + // Tachiyomi: Add startBar slot for Navigation Rail + val startBarPlaceables = measurables[4] + .fastMap { it.measure(looseConstraints) } - val topBarHeight = topBarPlaceables.fastMaxBy { it.height }?.height ?: 0 + val startBarWidth = startBarPlaceables.fastMaxBy { it.width }?.width ?: 0 - val snackbarPlaceables = subcompose(ScaffoldLayoutContent.Snackbar, snackbar).fastMap { - it.measure(looseConstraints) - } + val topBarPlaceables = measurables[5] + .fastMap { it.measure(topBarConstraints) } - val snackbarHeight = snackbarPlaceables.fastMaxBy { it.height }?.height ?: 0 - val snackbarWidth = snackbarPlaceables.fastMaxBy { it.width }?.width ?: 0 + val topBarHeight = topBarPlaceables.fastMaxBy { it.height }?.height ?: 0 - // Tachiyomi: Calculate insets for snackbar placement offset - val snackbarLeft = if (snackbarPlaceables.isNotEmpty()) { - (insetLayoutWidth - snackbarWidth) / 2 + leftInset - } else { - 0 - } + val bottomPlaceablesConstraints = looseConstraints.offset( + -startInsetsWidth - endInsetsWidth, + -bottomInsetsHeight, + ) - val fabPlaceables = - subcompose(ScaffoldLayoutContent.Fab, fab).fastMap { measurable -> - measurable.measure(looseConstraints) - } + val snackbarPlaceables = measurables[6] + .fastMap { it.measure(bottomPlaceablesConstraints) } - val fabWidth = fabPlaceables.fastMaxBy { it.width }?.width ?: 0 - val fabHeight = fabPlaceables.fastMaxBy { it.height }?.height ?: 0 + val snackbarHeight = snackbarPlaceables.fastMaxBy { it.height }?.height ?: 0 + val snackbarWidth = snackbarPlaceables.fastMaxBy { it.width }?.width ?: 0 - val fabPlacement = if (fabPlaceables.isNotEmpty() && fabWidth != 0 && fabHeight != 0) { - // FAB distance from the left of the layout, taking into account LTR / RTL - // Tachiyomi: Calculate insets for fab placement offset - val fabLeftOffset = if (fabPosition == FabPosition.End) { + val fabPlaceables = measurables[7] + .fastMap { it.measure(bottomPlaceablesConstraints) } + + val fabWidth = fabPlaceables.fastMaxBy { it.width }?.width ?: 0 + val fabHeight = fabPlaceables.fastMaxBy { it.height }?.height ?: 0 + + val fabPlacement = if (fabWidth > 0 && fabHeight > 0) { + // FAB distance from the left of the layout, taking into account LTR / RTL + val fabLeftOffset = when (fabPosition) { + FabPosition.Start -> { if (layoutDirection == LayoutDirection.Ltr) { - layoutWidth - FabSpacing.roundToPx() - fabWidth - rightInset + FabSpacing.roundToPx() } else { - FabSpacing.roundToPx() + leftInset + layoutWidth - FabSpacing.roundToPx() - fabWidth } - } else { - leftInset + ((insetLayoutWidth - fabWidth) / 2) } - - FabPlacement( - left = fabLeftOffset, - width = fabWidth, - height = fabHeight, - ) - } else { - null - } - - val bottomBarPlaceables = subcompose(ScaffoldLayoutContent.BottomBar) { - CompositionLocalProvider( - LocalFabPlacement provides fabPlacement, - content = bottomBar, - ) - }.fastMap { it.measure(looseConstraints) } - - val bottomBarHeight = bottomBarPlaceables - .fastMaxBy { it.height } - ?.height - ?.takeIf { it != 0 } - val fabOffsetFromBottom = fabPlacement?.let { - max(bottomBarHeight ?: 0, bottomInset) + it.height + FabSpacing.roundToPx() - } - - val snackbarOffsetFromBottom = if (snackbarHeight != 0) { - snackbarHeight + (fabOffsetFromBottom ?: max(bottomBarHeight ?: 0, bottomInset)) - } else { - 0 - } - - val bodyContentPlaceables = subcompose(ScaffoldLayoutContent.MainContent) { - val insets = contentWindowInsets.asPaddingValues(this@SubcomposeLayout) - val fabOffsetDp = fabOffsetFromBottom?.toDp() ?: 0.dp - val bottomBarHeightPx = bottomBarHeight ?: 0 - val innerPadding = PaddingValues( - top = - if (topBarPlaceables.isEmpty()) { - insets.calculateTopPadding() + FabPosition.End, FabPosition.EndOverlay -> { + if (layoutDirection == LayoutDirection.Ltr) { + layoutWidth - FabSpacing.roundToPx() - fabWidth } else { - topBarHeight.toDp() - }, - bottom = // Tachiyomi: Also take account of fab height when providing inner padding - if (bottomBarPlaceables.isEmpty() || bottomBarHeightPx == 0) { - max(insets.calculateBottomPadding(), fabOffsetDp) - } else { - max(bottomBarHeightPx.toDp(), fabOffsetDp) - }, - start = max( - insets.calculateStartPadding((this@SubcomposeLayout).layoutDirection), - startBarWidth.toDp(), - ), - end = insets.calculateEndPadding((this@SubcomposeLayout).layoutDirection), - ) - content(innerPadding) - }.fastMap { it.measure(looseConstraints) } + FabSpacing.roundToPx() + } + } + else -> (layoutWidth - fabWidth) / 2 + } + FabPlacement( + left = fabLeftOffset, + width = fabWidth, + height = fabHeight, + ) + } else { + null + } + + val bottomBarPlaceables = measurables[8] + .fastMap { it.measure(looseConstraints) } + + val bottomBarHeight = bottomBarPlaceables.fastMaxBy { it.height }?.height ?: 0 + + val fabOffsetFromBottom = fabPlacement?.let { + if (fabPosition == FabPosition.EndOverlay) { + it.height + FabSpacing.roundToPx() + bottomInsetsHeight + } else { + // Total height is the bottom bar height + the FAB height + the padding + // between the FAB and bottom bar + max(bottomBarHeight, bottomInsetsHeight) + it.height + FabSpacing.roundToPx() + } + } + val snackbarOffsetFromBottom = if (snackbarHeight != 0) { + snackbarHeight + max( + fabOffsetFromBottom ?: 0, + max( + bottomBarHeight, + bottomInsetsHeight, + ), + ) + } else { + 0 + } + + // Update the backing value for the content padding of the body content + // We do this before measuring or placing the body content + topContentPadding = max(topBarHeight, topInsetsHeight).toDp() + bottomContentPadding = max(fabOffsetFromBottom ?: 0, max(bottomBarHeight, bottomInsetsHeight)).toDp() + startContentPadding = max(startBarWidth, startInsetsWidth).toDp() + endContentPadding = endInsetsWidth.toDp() + + val bodyContentPlaceables = measurables[9] + .fastMap { it.measure(looseConstraints) } + + layout(layoutWidth, layoutHeight) { + // Inset spacers are just for convenient measurement logic, no need to place them // Placing to control drawing order to match default elevation of each placeable bodyContentPlaceables.fastForEach { @@ -299,50 +329,27 @@ private fun ScaffoldLayout( } snackbarPlaceables.fastForEach { it.place( - snackbarLeft, + (layoutWidth - snackbarWidth) / 2 + when (layoutDirection) { + LayoutDirection.Ltr -> startInsetsWidth + LayoutDirection.Rtl -> endInsetsWidth + }, layoutHeight - snackbarOffsetFromBottom, ) } // The bottom bar is always at the bottom of the layout bottomBarPlaceables.fastForEach { - it.place(0, layoutHeight - (bottomBarHeight ?: 0)) + it.place(0, layoutHeight - bottomBarHeight) } // Explicitly not using placeRelative here as `leftOffset` already accounts for RTL - fabPlaceables.fastForEach { - it.place(fabPlacement?.left ?: 0, layoutHeight - (fabOffsetFromBottom ?: 0)) + fabPlacement?.let { placement -> + fabPlaceables.fastForEach { + it.place(placement.left, layoutHeight - fabOffsetFromBottom!!) + } } } } } -/** - * The possible positions for a [FloatingActionButton] attached to a [Scaffold]. - */ -@ExperimentalMaterial3Api -@JvmInline -value class FabPosition internal constructor(@Suppress("unused") private val value: Int) { - companion object { - /** - * Position FAB at the bottom of the screen in the center, above the [NavigationBar] (if it - * exists) - */ - val Center = FabPosition(0) - - /** - * Position FAB at the bottom of the screen at the end, above the [NavigationBar] (if it - * exists) - */ - val End = FabPosition(1) - } - - override fun toString(): String { - return when (this) { - Center -> "FabPosition.Center" - else -> "FabPosition.End" - } - } -} - /** * Placement information for a [FloatingActionButton] inside a [Scaffold]. * @@ -358,12 +365,5 @@ internal class FabPlacement( val height: Int, ) -/** - * CompositionLocal containing a [FabPlacement] that is used to calculate the FAB bottom offset. - */ -internal val LocalFabPlacement = staticCompositionLocalOf { null } - // FAB spacing above the bottom bar / bottom of the Scaffold private val FabSpacing = 16.dp - -private enum class ScaffoldLayoutContent { TopBar, MainContent, Snackbar, Fab, BottomBar, StartBar } diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Tabs.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Tabs.kt index 6ca213aa3..f74ff909c 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Tabs.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Tabs.kt @@ -1,65 +1,15 @@ package tachiyomi.presentation.core.components.material -import androidx.compose.animation.core.Spring -import androidx.compose.animation.core.animateDpAsState -import androidx.compose.animation.core.spring import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.offset -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.layout.wrapContentSize -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.TabPosition -import androidx.compose.material3.TabRowDefaults.SecondaryIndicator -import androidx.compose.material3.TabRowDefaults.tabIndicatorOffset import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.composed -import androidx.compose.ui.draw.clip import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.unit.IntOffset -import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import tachiyomi.presentation.core.components.Pill -private fun Modifier.tabIndicatorOffset( - currentTabPosition: TabPosition, - currentPageOffsetFraction: Float, -) = fillMaxWidth() - .wrapContentSize(Alignment.BottomStart) - .composed { - val currentTabWidth by animateDpAsState( - targetValue = currentTabPosition.width, - animationSpec = spring(stiffness = Spring.StiffnessMediumLow), - ) - val offset by animateDpAsState( - targetValue = currentTabPosition.left + (currentTabWidth * currentPageOffsetFraction), - animationSpec = spring(stiffness = Spring.StiffnessMediumLow), - ) - Modifier - .offset { IntOffset(x = offset.roundToPx(), y = 0) } - .width(currentTabWidth) - } - -@Composable -fun TabIndicator( - currentTabPosition: TabPosition, - currentPageOffsetFraction: Float, -) { - SecondaryIndicator( - modifier = Modifier - .tabIndicatorOffset(currentTabPosition, currentPageOffsetFraction) - .padding(horizontal = 8.dp) - .clip(RoundedCornerShape(topStart = 3.dp, topEnd = 3.dp)), - ) -} - @Composable fun TabText( text: String, diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/screens/EmptyScreen.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/screens/EmptyScreen.kt index c3a0cbe79..f7de6a931 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/screens/EmptyScreen.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/screens/EmptyScreen.kt @@ -12,14 +12,18 @@ import androidx.compose.foundation.verticalScroll import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import androidx.compose.ui.util.fastForEach +import kotlinx.collections.immutable.ImmutableList import tachiyomi.presentation.core.components.ActionButton import tachiyomi.presentation.core.components.material.padding import tachiyomi.presentation.core.util.secondaryItemAlpha @@ -35,7 +39,7 @@ data class EmptyScreenAction( fun EmptyScreen( @StringRes textResource: Int, modifier: Modifier = Modifier, - actions: List? = null, + actions: ImmutableList? = null, ) { EmptyScreen( message = stringResource(textResource), @@ -48,7 +52,7 @@ fun EmptyScreen( fun EmptyScreen( message: String, modifier: Modifier = Modifier, - actions: List? = null, + actions: ImmutableList? = null, ) { val face = remember { getRandomErrorFace() } Column( @@ -59,11 +63,13 @@ fun EmptyScreen( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, ) { - Text( - text = face, - modifier = Modifier.secondaryItemAlpha(), - style = MaterialTheme.typography.displayMedium, - ) + CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) { + Text( + text = face, + modifier = Modifier.secondaryItemAlpha(), + style = MaterialTheme.typography.displayMedium, + ) + } Text( text = message, @@ -93,7 +99,7 @@ fun EmptyScreen( } } -private val ERROR_FACES = listOf( +private val ErrorFaces = listOf( "(・o・;)", "Σ(ಠ_ಠ)", "ಥ_ಥ", @@ -103,5 +109,5 @@ private val ERROR_FACES = listOf( ) private fun getRandomErrorFace(): String { - return ERROR_FACES[Random.nextInt(ERROR_FACES.size)] + return ErrorFaces[Random.nextInt(ErrorFaces.size)] } diff --git a/presentation-widget/build.gradle.kts b/presentation-widget/build.gradle.kts index 9c5c0ec65..e41d7be3d 100644 --- a/presentation-widget/build.gradle.kts +++ b/presentation-widget/build.gradle.kts @@ -25,7 +25,10 @@ dependencies { implementation(project(":domain")) implementation(project(":presentation-core")) - implementation(androidx.glance) + implementation(compose.glance) + lintChecks(compose.lintchecks) + + implementation(kotlinx.immutables) implementation(platform(libs.coil.bom)) implementation(libs.coil.core) diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/anime/UpdatesAnimeCover.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/anime/UpdatesAnimeCover.kt index a6dc4537b..5bbb401ef 100644 --- a/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/anime/UpdatesAnimeCover.kt +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/anime/UpdatesAnimeCover.kt @@ -18,8 +18,8 @@ val CoverHeight = 87.dp @Composable fun UpdatesAnimeCover( - modifier: GlanceModifier = GlanceModifier, cover: Bitmap?, + modifier: GlanceModifier = GlanceModifier, ) { Box( modifier = modifier diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/anime/UpdatesAnimeWidget.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/anime/UpdatesAnimeWidget.kt index 5a806fb7a..85c78a512 100644 --- a/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/anime/UpdatesAnimeWidget.kt +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/anime/UpdatesAnimeWidget.kt @@ -22,17 +22,18 @@ import androidx.glance.text.Text import androidx.glance.text.TextStyle import androidx.glance.unit.ColorProvider import eu.kanade.tachiyomi.core.Constants +import kotlinx.collections.immutable.ImmutableList import tachiyomi.presentation.widget.R import tachiyomi.presentation.widget.util.calculateRowAndColumnCount import tachiyomi.presentation.widget.util.stringResource @Composable fun UpdatesAnimeWidget( - data: List>?, - modifier: GlanceModifier = GlanceModifier, + data: ImmutableList>?, contentColor: ColorProvider, topPadding: Dp, bottomPadding: Dp, + modifier: GlanceModifier = GlanceModifier, ) { Box( contentAlignment = Alignment.Center, @@ -83,8 +84,8 @@ fun UpdatesAnimeWidget( addCategory(animeId.toString()) } UpdatesAnimeCover( - modifier = GlanceModifier.clickable(actionStartActivity(intent)), cover = cover, + modifier = GlanceModifier.clickable(actionStartActivity(intent)), ) } } diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/manga/UpdatesMangaCover.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/manga/UpdatesMangaCover.kt index 5b36312ee..2eeecbdc4 100644 --- a/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/manga/UpdatesMangaCover.kt +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/manga/UpdatesMangaCover.kt @@ -18,8 +18,8 @@ val CoverHeight = 87.dp @Composable fun UpdatesMangaCover( - modifier: GlanceModifier = GlanceModifier, cover: Bitmap?, + modifier: GlanceModifier = GlanceModifier, ) { Box( modifier = modifier diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/manga/UpdatesMangaWidget.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/manga/UpdatesMangaWidget.kt index d8d420965..2d167c95c 100644 --- a/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/manga/UpdatesMangaWidget.kt +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/manga/UpdatesMangaWidget.kt @@ -22,17 +22,18 @@ import androidx.glance.text.Text import androidx.glance.text.TextStyle import androidx.glance.unit.ColorProvider import eu.kanade.tachiyomi.core.Constants +import kotlinx.collections.immutable.ImmutableList import tachiyomi.presentation.widget.R import tachiyomi.presentation.widget.util.calculateRowAndColumnCount import tachiyomi.presentation.widget.util.stringResource @Composable fun UpdatesMangaWidget( - data: List>?, - modifier: GlanceModifier = GlanceModifier, + data: ImmutableList>?, contentColor: ColorProvider, topPadding: Dp, bottomPadding: Dp, + modifier: GlanceModifier = GlanceModifier, ) { Box( contentAlignment = Alignment.Center, @@ -83,8 +84,8 @@ fun UpdatesMangaWidget( addCategory(mangaId.toString()) } UpdatesMangaCover( - modifier = GlanceModifier.clickable(actionStartActivity(intent)), cover = cover, + modifier = GlanceModifier.clickable(actionStartActivity(intent)), ) } } diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/entries/anime/TachiyomiAnimeWidgetManager.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/entries/anime/AnimeWidgetManager.kt similarity index 97% rename from presentation-widget/src/main/java/tachiyomi/presentation/widget/entries/anime/TachiyomiAnimeWidgetManager.kt rename to presentation-widget/src/main/java/tachiyomi/presentation/widget/entries/anime/AnimeWidgetManager.kt index 20dd36534..83bcd7555 100644 --- a/presentation-widget/src/main/java/tachiyomi/presentation/widget/entries/anime/TachiyomiAnimeWidgetManager.kt +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/entries/anime/AnimeWidgetManager.kt @@ -13,7 +13,7 @@ import logcat.LogPriority import tachiyomi.core.util.system.logcat import tachiyomi.domain.updates.anime.interactor.GetAnimeUpdates -class TachiyomiAnimeWidgetManager( +class AnimeWidgetManager( private val getUpdates: GetAnimeUpdates, private val securityPreferences: SecurityPreferences, ) { diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/entries/anime/BaseAnimeUpdatesGridGlanceWidget.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/entries/anime/BaseAnimeUpdatesGridGlanceWidget.kt index 6d2f4d11e..971d899fb 100644 --- a/presentation-widget/src/main/java/tachiyomi/presentation/widget/entries/anime/BaseAnimeUpdatesGridGlanceWidget.kt +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/entries/anime/BaseAnimeUpdatesGridGlanceWidget.kt @@ -30,6 +30,8 @@ import coil.size.Scale import coil.transform.RoundedCornersTransformation import eu.kanade.tachiyomi.core.security.SecurityPreferences import eu.kanade.tachiyomi.util.system.dpToPx +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.flow.map import tachiyomi.core.util.lang.withIOContext import tachiyomi.domain.entries.anime.model.AnimeCover @@ -96,10 +98,10 @@ abstract class BaseAnimeUpdatesGridGlanceWidget( val data by flow.collectAsState(initial = null) UpdatesAnimeWidget( data = data, - modifier = containerModifier, contentColor = foreground, topPadding = topPadding, bottomPadding = bottomPadding, + modifier = containerModifier, ) } } @@ -107,7 +109,7 @@ abstract class BaseAnimeUpdatesGridGlanceWidget( private suspend fun List.prepareData( rowCount: Int, columnCount: Int, - ): List> { + ): ImmutableList> { // Resize to cover size val widthPx = CoverWidth.value.toInt().dpToPx val heightPx = CoverHeight.value.toInt().dpToPx @@ -141,6 +143,7 @@ abstract class BaseAnimeUpdatesGridGlanceWidget( .build() Pair(updatesView.animeId, context.imageLoader.executeBlocking(request).drawable?.toBitmap()) } + .toImmutableList() } } diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/entries/manga/BaseMangaUpdatesGridGlanceWidget.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/entries/manga/BaseMangaUpdatesGridGlanceWidget.kt index 243cdba8d..ad8fc4edc 100644 --- a/presentation-widget/src/main/java/tachiyomi/presentation/widget/entries/manga/BaseMangaUpdatesGridGlanceWidget.kt +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/entries/manga/BaseMangaUpdatesGridGlanceWidget.kt @@ -30,6 +30,8 @@ import coil.size.Scale import coil.transform.RoundedCornersTransformation import eu.kanade.tachiyomi.core.security.SecurityPreferences import eu.kanade.tachiyomi.util.system.dpToPx +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.flow.map import tachiyomi.core.util.lang.withIOContext import tachiyomi.domain.entries.manga.model.MangaCover @@ -96,10 +98,10 @@ abstract class BaseMangaUpdatesGridGlanceWidget( val data by flow.collectAsState(initial = null) UpdatesMangaWidget( data = data, - modifier = containerModifier, contentColor = foreground, topPadding = topPadding, bottomPadding = bottomPadding, + modifier = containerModifier, ) } } @@ -107,7 +109,7 @@ abstract class BaseMangaUpdatesGridGlanceWidget( private suspend fun List.prepareData( rowCount: Int, columnCount: Int, - ): List> { + ): ImmutableList> { // Resize to cover size val widthPx = CoverWidth.value.toInt().dpToPx val heightPx = CoverHeight.value.toInt().dpToPx @@ -141,6 +143,7 @@ abstract class BaseMangaUpdatesGridGlanceWidget( .build() Pair(updatesView.mangaId, context.imageLoader.executeBlocking(request).drawable?.toBitmap()) } + .toImmutableList() } } diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/entries/manga/TachiyomiMangaWidgetManager.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/entries/manga/MangaWidgetManager.kt similarity index 97% rename from presentation-widget/src/main/java/tachiyomi/presentation/widget/entries/manga/TachiyomiMangaWidgetManager.kt rename to presentation-widget/src/main/java/tachiyomi/presentation/widget/entries/manga/MangaWidgetManager.kt index 2fb1f5824..9bd1829ad 100644 --- a/presentation-widget/src/main/java/tachiyomi/presentation/widget/entries/manga/TachiyomiMangaWidgetManager.kt +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/entries/manga/MangaWidgetManager.kt @@ -13,7 +13,7 @@ import logcat.LogPriority import tachiyomi.core.util.system.logcat import tachiyomi.domain.updates.manga.interactor.GetMangaUpdates -class TachiyomiMangaWidgetManager( +class MangaWidgetManager( private val getUpdates: GetMangaUpdates, private val securityPreferences: SecurityPreferences, ) {