From cb67f1de526e6120db363f67035966f365467912 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 11 Nov 2023 18:13:44 -0500 Subject: [PATCH 1/7] Add Compose lint checks Still need to address most of them though. --- app/build.gradle.kts | 1 + .../presentation/manga/components/MangaDialogs.kt | 2 +- .../presentation/track/TrackInfoDialogSelector.kt | 4 ++-- gradle/androidx.versions.toml | 1 - gradle/compose.versions.toml | 4 ++++ presentation-core/build.gradle.kts | 1 + .../presentation/core/components/ActionButton.kt | 2 +- .../presentation/core/components/AdaptiveSheet.kt | 2 +- .../core/components/CollapsibleBox.kt | 5 ++++- .../core/components/LabeledCheckbox.kt | 2 +- .../presentation/core/components/LinkIcon.kt | 7 ++++++- .../core/components/ListGroupHeader.kt | 5 ++++- .../presentation/core/components/SettingsItems.kt | 4 ++-- .../presentation/core/components/TwoPanelBox.kt | 4 ++-- .../presentation/core/components/WheelPicker.kt | 6 +++--- .../components/material/FloatingActionButton.kt | 15 ++++++++++++--- .../core/components/material/IconToggleButton.kt | 2 +- .../presentation/core/components/material/Tabs.kt | 2 ++ presentation-widget/build.gradle.kts | 3 ++- .../widget/BaseUpdatesGridGlanceWidget.kt | 2 +- .../widget/components/UpdatesMangaCover.kt | 5 ++++- .../widget/components/UpdatesWidget.kt | 4 ++-- 22 files changed, 57 insertions(+), 26 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 943d88031..13b7d3caa 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -167,6 +167,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) diff --git a/app/src/main/java/eu/kanade/presentation/manga/components/MangaDialogs.kt b/app/src/main/java/eu/kanade/presentation/manga/components/MangaDialogs.kt index 94f34eec2..1fd1dd021 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/components/MangaDialogs.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/components/MangaDialogs.kt @@ -75,8 +75,8 @@ fun SetIntervalDialog( } } WheelTextPicker( - size = size, items = items, + size = size, startIndex = selectedInterval, onSelectionChanged = { selectedInterval = it }, ) 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 012fc0466..a4faba194 100644 --- a/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogSelector.kt +++ b/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogSelector.kt @@ -102,9 +102,9 @@ fun TrackChapterSelector( title = stringResource(R.string.chapters), content = { WheelNumberPicker( + items = range.toList(), modifier = Modifier.align(Alignment.Center), startIndex = selection, - items = range.toList(), onSelectionChanged = { onSelectionChange(it) }, ) }, @@ -125,9 +125,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]) }, ) }, diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index c3df15095..2fd9332a4 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -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" lifecycle-common = { module = "androidx.lifecycle:lifecycle-common", version.ref = "lifecycle_version" } diff --git a/gradle/compose.versions.toml b/gradle/compose.versions.toml index 492bc2c38..fbac9ac7f 100644 --- a/gradle/compose.versions.toml +++ b/gradle/compose.versions.toml @@ -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-systemuicontroller = { module = "com.google.accompanist:accompanist-systemuicontroller", version.ref = "accompanist" } + +lintchecks = { module = "com.slack.lint.compose:compose-lint-checks", version = "1.2.0" } \ No newline at end of file diff --git a/presentation-core/build.gradle.kts b/presentation-core/build.gradle.kts index 9c87d7465..b578de913 100644 --- a/presentation-core/build.gradle.kts +++ b/presentation-core/build.gradle.kts @@ -35,6 +35,7 @@ dependencies { debugImplementation(compose.ui.tooling) implementation(compose.ui.tooling.preview) implementation(compose.ui.util) + lintChecks(compose.lintchecks) } 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 51fb672ee..51089cf52 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 @@ -56,11 +56,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/CollapsibleBox.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/CollapsibleBox.kt index ffd4b84e9..b70cb2705 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/CollapsibleBox.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/CollapsibleBox.kt @@ -23,7 +23,10 @@ import androidx.compose.ui.unit.dp import tachiyomi.presentation.core.theme.header @Composable -fun CollapsibleBox(heading: String, content: @Composable () -> Unit) { +fun CollapsibleBox( + heading: String, + content: @Composable () -> Unit, +) { var expanded by remember { mutableStateOf(false) } Column { 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 f2039cd36..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,10 @@ 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( 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 86d1225b5..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 @@ -11,7 +11,12 @@ import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.unit.dp @Composable -fun LinkIcon(modifier: Modifier = Modifier, label: String, icon: ImageVector, url: String) { +fun LinkIcon( + label: String, + icon: ImageVector, + url: String, + modifier: Modifier = Modifier, +) { val uriHandler = LocalUriHandler.current IconButton( modifier = modifier.padding(4.dp), 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 2fe128746..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 @@ -9,7 +9,10 @@ import androidx.compose.ui.text.font.FontWeight import tachiyomi.presentation.core.components.material.padding @Composable -fun ListGroupHeader(modifier: Modifier = Modifier, text: String) { +fun ListGroupHeader( + text: String, + modifier: Modifier = Modifier, +) { Text( text = text, modifier = modifier 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 4f339dc49..c949fa7ce 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 @@ -156,11 +156,11 @@ fun RadioItem(label: String, selected: Boolean, onClick: () -> Unit) { @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 6d24aa545..d13b96a7b 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 @@ -54,9 +54,9 @@ import kotlin.math.absoluteValue @Composable fun WheelNumberPicker( + items: List, 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 +78,9 @@ fun WheelNumberPicker( @Composable fun WheelTextPicker( + items: List, 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 +101,9 @@ fun WheelTextPicker( @Composable private fun WheelPicker( + items: List, 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/Tabs.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Tabs.kt index 0770d577a..23d65d07f 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 @@ -36,10 +36,12 @@ private fun Modifier.tabIndicatorOffset( val currentTabWidth by animateDpAsState( targetValue = currentTabPosition.width, animationSpec = spring(stiffness = Spring.StiffnessMediumLow), + label = "currentTabWidth", ) val offset by animateDpAsState( targetValue = currentTabPosition.left + (currentTabWidth * currentPageOffsetFraction), animationSpec = spring(stiffness = Spring.StiffnessMediumLow), + label = "offset", ) Modifier .offset { IntOffset(x = offset.roundToPx(), y = 0) } diff --git a/presentation-widget/build.gradle.kts b/presentation-widget/build.gradle.kts index 9c5c0ec65..95777e4a4 100644 --- a/presentation-widget/build.gradle.kts +++ b/presentation-widget/build.gradle.kts @@ -25,7 +25,8 @@ dependencies { implementation(project(":domain")) implementation(project(":presentation-core")) - implementation(androidx.glance) + implementation(compose.glance) + lintChecks(compose.lintchecks) implementation(platform(libs.coil.bom)) implementation(libs.coil.core) diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/BaseUpdatesGridGlanceWidget.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/BaseUpdatesGridGlanceWidget.kt index 26e1cd918..c28f818a6 100644 --- a/presentation-widget/src/main/java/tachiyomi/presentation/widget/BaseUpdatesGridGlanceWidget.kt +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/BaseUpdatesGridGlanceWidget.kt @@ -95,10 +95,10 @@ abstract class BaseUpdatesGridGlanceWidget( val data by flow.collectAsState(initial = null) UpdatesWidget( data = data, - modifier = containerModifier, contentColor = foreground, topPadding = topPadding, bottomPadding = bottomPadding, + modifier = containerModifier, ) } } diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesMangaCover.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesMangaCover.kt index 5b537f45d..076d25d74 100644 --- a/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesMangaCover.kt +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesMangaCover.kt @@ -17,7 +17,10 @@ val CoverWidth = 58.dp val CoverHeight = 87.dp @Composable -fun UpdatesMangaCover(modifier: GlanceModifier = GlanceModifier, cover: Bitmap?) { +fun UpdatesMangaCover( + cover: Bitmap?, + modifier: GlanceModifier = GlanceModifier, +) { Box( modifier = modifier .size(width = CoverWidth, height = CoverHeight) diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesWidget.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesWidget.kt index 46f8d26e6..53ebadfa9 100644 --- a/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesWidget.kt +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesWidget.kt @@ -29,10 +29,10 @@ import tachiyomi.presentation.widget.util.stringResource @Composable fun UpdatesWidget( data: List>?, - modifier: GlanceModifier = GlanceModifier, contentColor: ColorProvider, topPadding: Dp, bottomPadding: Dp, + modifier: GlanceModifier = GlanceModifier, ) { Box( contentAlignment = Alignment.Center, @@ -83,8 +83,8 @@ fun UpdatesWidget( addCategory(mangaId.toString()) } UpdatesMangaCover( - modifier = GlanceModifier.clickable(actionStartActivity(intent)), cover = cover, + modifier = GlanceModifier.clickable(actionStartActivity(intent)), ) } } From 4a6571d310ecf2bf77e86a303f1788aaaab3df25 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 11 Nov 2023 18:25:27 -0500 Subject: [PATCH 2/7] Minor cleanup --- .../TrackInfoDialogHomePreviewProvider.kt | 2 +- .../TrackLogoIconPreviewProvider.kt | 2 +- app/src/main/java/eu/kanade/tachiyomi/App.kt | 2 + .../eu/kanade/tachiyomi/{ => di}/AppModule.kt | 71 +---------------- .../kanade/tachiyomi/di/PreferenceModule.kt | 76 +++++++++++++++++++ .../tachiyomi/source/AndroidSourceManager.kt | 2 +- .../tachiyomi/source/SourceExtensions.kt | 6 -- .../source/model/SChapterExtensions.kt | 11 --- .../source/model/SMangaExtensions.kt | 54 ++----------- .../dev/preview => test}/DummyTracker.kt | 2 +- .../domain/source/model/StubSource.kt | 6 ++ 11 files changed, 95 insertions(+), 139 deletions(-) rename app/src/main/java/eu/kanade/tachiyomi/{ => di}/AppModule.kt (68%) create mode 100644 app/src/main/java/eu/kanade/tachiyomi/di/PreferenceModule.kt delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/source/model/SChapterExtensions.kt rename app/src/main/java/eu/kanade/{tachiyomi/dev/preview => test}/DummyTracker.kt (98%) diff --git a/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHomePreviewProvider.kt b/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHomePreviewProvider.kt index 00ef15ff1..e2733b7bf 100644 --- a/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHomePreviewProvider.kt +++ b/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHomePreviewProvider.kt @@ -2,8 +2,8 @@ package eu.kanade.presentation.track import androidx.compose.runtime.Composable import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import eu.kanade.tachiyomi.dev.preview.DummyTracker import eu.kanade.tachiyomi.ui.manga.track.TrackItem +import eu.kanade.test.DummyTracker import tachiyomi.domain.track.model.Track import java.text.DateFormat 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/tachiyomi/App.kt b/app/src/main/java/eu/kanade/tachiyomi/App.kt index 8459c8073..bc0e4aa47 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/App.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/App.kt @@ -34,6 +34,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 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 68% rename from app/src/main/java/eu/kanade/tachiyomi/AppModule.kt rename to app/src/main/java/eu/kanade/tachiyomi/di/AppModule.kt index 51bd28098..6aab7c7bc 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 @@ -7,12 +7,8 @@ import androidx.sqlite.db.SupportSQLiteDatabase import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory import app.cash.sqldelight.db.SqlDriver import app.cash.sqldelight.driver.android.AndroidSqliteDriver -import eu.kanade.domain.base.BasePreferences -import eu.kanade.domain.source.service.SourcePreferences -import eu.kanade.domain.track.service.TrackPreferences import eu.kanade.domain.track.store.DelayedTrackingStore -import eu.kanade.domain.ui.UiPreferences -import eu.kanade.tachiyomi.core.security.SecurityPreferences +import eu.kanade.tachiyomi.BuildConfig import eu.kanade.tachiyomi.data.cache.ChapterCache import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.download.DownloadCache @@ -23,19 +19,12 @@ import eu.kanade.tachiyomi.data.track.TrackerManager import eu.kanade.tachiyomi.extension.ExtensionManager import eu.kanade.tachiyomi.network.JavaScriptEngine import eu.kanade.tachiyomi.network.NetworkHelper -import eu.kanade.tachiyomi.network.NetworkPreferences import eu.kanade.tachiyomi.source.AndroidSourceManager -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.AndroidPreferenceStore -import tachiyomi.core.preference.PreferenceStore -import tachiyomi.core.provider.AndroidBackupFolderProvider -import tachiyomi.core.provider.AndroidDownloadFolderProvider import tachiyomi.data.AndroidDatabaseHandler import tachiyomi.data.Database import tachiyomi.data.DatabaseHandler @@ -44,9 +33,6 @@ import tachiyomi.data.History import tachiyomi.data.Mangas import tachiyomi.data.StringListColumnAdapter import tachiyomi.data.UpdateStrategyColumnAdapter -import tachiyomi.domain.backup.service.BackupPreferences -import tachiyomi.domain.download.service.DownloadPreferences -import tachiyomi.domain.library.service.LibraryPreferences import tachiyomi.domain.source.service.SourceManager import tachiyomi.source.local.image.LocalCoverManager import tachiyomi.source.local.io.LocalSourceFileSystem @@ -152,56 +138,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 { - 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..c7051cd47 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/di/PreferenceModule.kt @@ -0,0 +1,76 @@ +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.security.SecurityPreferences +import eu.kanade.tachiyomi.network.NetworkPreferences +import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences +import eu.kanade.tachiyomi.util.system.isDevFlavor +import tachiyomi.core.preference.AndroidPreferenceStore +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 app: Application) : InjektModule { + + override fun InjektRegistrar.registerInjectables() { + addSingletonFactory { + AndroidPreferenceStore(app) + } + addSingletonFactory { + NetworkPreferences( + preferenceStore = get(), + verboseLogging = isDevFlavor, + ) + } + addSingletonFactory { + SourcePreferences(get()) + } + addSingletonFactory { + SecurityPreferences(get()) + } + addSingletonFactory { + LibraryPreferences(get()) + } + addSingletonFactory { + ReaderPreferences(get()) + } + addSingletonFactory { + TrackPreferences(get()) + } + addSingletonFactory { + AndroidDownloadFolderProvider(app) + } + addSingletonFactory { + DownloadPreferences( + folderProvider = get(), + preferenceStore = get(), + ) + } + addSingletonFactory { + AndroidBackupFolderProvider(app) + } + addSingletonFactory { + BackupPreferences( + folderProvider = get(), + preferenceStore = get(), + ) + } + addSingletonFactory { + UiPreferences(get()) + } + addSingletonFactory { + BasePreferences(app, get()) + } + } +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/AndroidSourceManager.kt b/app/src/main/java/eu/kanade/tachiyomi/source/AndroidSourceManager.kt index dcbae8b4d..a7618bd8c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/AndroidSourceManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/AndroidSourceManager.kt @@ -56,7 +56,7 @@ class AndroidSourceManager( extensions.forEach { extension -> extension.sources.forEach { mutableMap[it.id] = it - registerStubSource(it.toStubSource()) + registerStubSource(StubSource.from(it)) } } sourcesMapFlow.value = mutableMap diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/SourceExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/source/SourceExtensions.kt index 7be9c4d20..bac6ed5cd 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/SourceExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/SourceExtensions.kt @@ -1,17 +1,11 @@ package eu.kanade.tachiyomi.source -import android.graphics.drawable.Drawable import eu.kanade.domain.source.service.SourcePreferences -import eu.kanade.tachiyomi.extension.ExtensionManager import tachiyomi.domain.source.model.StubSource import tachiyomi.source.local.isLocal import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get -fun Source.icon(): Drawable? = Injekt.get().getAppIconForSource(this.id) - -fun Source.toStubSource(): StubSource = StubSource(id = id, lang = lang, name = name) - fun Source.getNameForMangaInfo(): String { val preferences = Injekt.get() val enabledLanguages = preferences.enabledLanguages().get() diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/model/SChapterExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/source/model/SChapterExtensions.kt deleted file mode 100644 index 0fd2f860f..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/source/model/SChapterExtensions.kt +++ /dev/null @@ -1,11 +0,0 @@ -package eu.kanade.tachiyomi.source.model - -import tachiyomi.data.Chapters - -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/model/SMangaExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/source/model/SMangaExtensions.kt index 7147db9de..812c6110f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/model/SMangaExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/model/SMangaExtensions.kt @@ -3,58 +3,14 @@ package eu.kanade.tachiyomi.source.model import tachiyomi.data.Mangas import tachiyomi.domain.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/dev/preview/DummyTracker.kt b/app/src/main/java/eu/kanade/test/DummyTracker.kt similarity index 98% 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 2315912ba..c9e53f9f5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/dev/preview/DummyTracker.kt +++ b/app/src/main/java/eu/kanade/test/DummyTracker.kt @@ -1,4 +1,4 @@ -package eu.kanade.tachiyomi.dev.preview +package eu.kanade.test import android.graphics.Color import eu.kanade.tachiyomi.R diff --git a/domain/src/main/java/tachiyomi/domain/source/model/StubSource.kt b/domain/src/main/java/tachiyomi/domain/source/model/StubSource.kt index 8b5f67ef5..544326a4c 100644 --- a/domain/src/main/java/tachiyomi/domain/source/model/StubSource.kt +++ b/domain/src/main/java/tachiyomi/domain/source/model/StubSource.kt @@ -23,6 +23,12 @@ class StubSource( override fun toString(): String = if (isInvalid.not()) "$name (${lang.uppercase()})" else id.toString() + + companion object { + fun from(source: Source): StubSource { + return StubSource(id = source.id, lang = source.lang, name = source.name) + } + } } class SourceNotInstalledException : Exception() From 3c3b09209c7ea5729c29b9c3ad414c09b2bb9636 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 11 Nov 2023 18:31:27 -0500 Subject: [PATCH 3/7] Use immutable collections in presentation-widget module --- app/src/main/java/eu/kanade/tachiyomi/App.kt | 4 ++-- gradle/kotlinx.versions.toml | 2 ++ presentation-widget/build.gradle.kts | 2 ++ .../presentation/widget/BaseUpdatesGridGlanceWidget.kt | 5 ++++- .../widget/{TachiyomiWidgetManager.kt => WidgetManager.kt} | 2 +- .../presentation/widget/components/UpdatesWidget.kt | 3 ++- 6 files changed, 13 insertions(+), 5 deletions(-) rename presentation-widget/src/main/java/tachiyomi/presentation/widget/{TachiyomiWidgetManager.kt => WidgetManager.kt} (97%) diff --git a/app/src/main/java/eu/kanade/tachiyomi/App.kt b/app/src/main/java/eu/kanade/tachiyomi/App.kt index bc0e4aa47..2619a073b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/App.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/App.kt @@ -56,7 +56,7 @@ import org.acra.ktx.initAcra import org.acra.sender.HttpSender import org.conscrypt.Conscrypt import tachiyomi.core.util.system.logcat -import tachiyomi.presentation.widget.TachiyomiWidgetManager +import tachiyomi.presentation.widget.WidgetManager import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import uy.kohesive.injekt.injectLazy @@ -127,7 +127,7 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory { setAppCompatDelegateThemeMode(Injekt.get().themeMode().get()) // Updates widget update - with(TachiyomiWidgetManager(Injekt.get(), Injekt.get())) { + with(WidgetManager(Injekt.get(), Injekt.get())) { init(ProcessLifecycleOwner.get().lifecycleScope) } diff --git a/gradle/kotlinx.versions.toml b/gradle/kotlinx.versions.toml index fb63cc85e..5212c2fd0 100644 --- a/gradle/kotlinx.versions.toml +++ b/gradle/kotlinx.versions.toml @@ -7,6 +7,8 @@ xml_serialization_version = "0.86.2" 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/presentation-widget/build.gradle.kts b/presentation-widget/build.gradle.kts index 95777e4a4..e41d7be3d 100644 --- a/presentation-widget/build.gradle.kts +++ b/presentation-widget/build.gradle.kts @@ -28,6 +28,8 @@ dependencies { 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/BaseUpdatesGridGlanceWidget.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/BaseUpdatesGridGlanceWidget.kt index c28f818a6..1b2e83cae 100644 --- a/presentation-widget/src/main/java/tachiyomi/presentation/widget/BaseUpdatesGridGlanceWidget.kt +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/BaseUpdatesGridGlanceWidget.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.manga.model.MangaCover @@ -106,7 +108,7 @@ abstract class BaseUpdatesGridGlanceWidget( 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 @@ -140,6 +142,7 @@ abstract class BaseUpdatesGridGlanceWidget( .build() Pair(updatesView.mangaId, context.imageLoader.executeBlocking(request).drawable?.toBitmap()) } + .toImmutableList() } } diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/TachiyomiWidgetManager.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/WidgetManager.kt similarity index 97% rename from presentation-widget/src/main/java/tachiyomi/presentation/widget/TachiyomiWidgetManager.kt rename to presentation-widget/src/main/java/tachiyomi/presentation/widget/WidgetManager.kt index 8227c6c51..2ddcbcc38 100644 --- a/presentation-widget/src/main/java/tachiyomi/presentation/widget/TachiyomiWidgetManager.kt +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/WidgetManager.kt @@ -12,7 +12,7 @@ import logcat.LogPriority import tachiyomi.core.util.system.logcat import tachiyomi.domain.updates.interactor.GetUpdates -class TachiyomiWidgetManager( +class WidgetManager( private val getUpdates: GetUpdates, private val securityPreferences: SecurityPreferences, ) { diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesWidget.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesWidget.kt index 53ebadfa9..95beae786 100644 --- a/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesWidget.kt +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesWidget.kt @@ -21,6 +21,7 @@ import androidx.glance.layout.padding import androidx.glance.text.Text import androidx.glance.text.TextStyle import androidx.glance.unit.ColorProvider +import kotlinx.collections.immutable.ImmutableList import tachiyomi.core.Constants import tachiyomi.presentation.widget.R import tachiyomi.presentation.widget.util.calculateRowAndColumnCount @@ -28,7 +29,7 @@ import tachiyomi.presentation.widget.util.stringResource @Composable fun UpdatesWidget( - data: List>?, + data: ImmutableList>?, contentColor: ColorProvider, topPadding: Dp, bottomPadding: Dp, From dd998be1e762b0cc4774ca0efbbccbf9d6e4ca9c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 11 Nov 2023 22:44:05 -0500 Subject: [PATCH 4/7] Update voyager to v1.0.0-rc10 (#10127) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d5f12a1da..934797ad0 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] From 336221a972187c8e35d733d2f9d1d1a99e7b6f1b Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 11 Nov 2023 22:43:50 -0500 Subject: [PATCH 5/7] Use immutable collections in more places --- app/build.gradle.kts | 1 + .../presentation/browse/BrowseSourceScreen.kt | 5 +- .../presentation/browse/SourcesScreen.kt | 4 +- .../presentation/components/EmptyScreen.kt | 3 +- .../manga/components/MangaDialogs.kt | 15 ++-- .../more/settings/PreferenceScreen.kt | 11 ++- .../screen/data/CreateBackupScreen.kt | 6 +- .../track/TrackInfoDialogSelector.kt | 6 +- .../eu/kanade/tachiyomi/data/track/Tracker.kt | 3 +- .../tachiyomi/data/track/anilist/Anilist.kt | 15 ++-- .../tachiyomi/data/track/bangumi/Bangumi.kt | 10 ++- .../tachiyomi/data/track/kavita/Kavita.kt | 4 +- .../tachiyomi/data/track/kitsu/Kitsu.kt | 6 +- .../tachiyomi/data/track/komga/Komga.kt | 4 +- .../data/track/mangaupdates/MangaUpdates.kt | 14 ++-- .../data/track/myanimelist/MyAnimeList.kt | 10 ++- .../data/track/shikimori/Shikimori.kt | 10 ++- .../tachiyomi/data/track/suwayomi/Suwayomi.kt | 4 +- .../extension/ExtensionFilterScreenModel.kt | 13 ++-- .../details/ExtensionDetailsScreenModel.kt | 13 ++-- .../manga/MigrateMangaScreenModel.kt | 15 ++-- .../sources/MigrateSourceScreenModel.kt | 7 +- .../ui/browse/source/SourcesScreenModel.kt | 23 +++--- .../source/globalsearch/SearchScreenModel.kt | 35 ++++++--- .../ui/category/CategoryScreenModel.kt | 8 ++- .../ui/library/LibraryScreenModel.kt | 43 +++++------ .../kanade/tachiyomi/ui/library/LibraryTab.kt | 3 +- .../ui/manga/track/TrackInfoDialog.kt | 3 +- .../ui/updates/UpdatesScreenModel.kt | 71 ++++++++++--------- .../main/java/eu/kanade/test/DummyTracker.kt | 6 +- .../kanade/tachiyomi/util/storage/EpubFile.kt | 9 ++- presentation-core/build.gradle.kts | 2 + .../presentation/core/components/Badges.kt | 6 +- .../core/components/WheelPicker.kt | 7 +- .../presentation/core/screens/EmptyScreen.kt | 9 +-- 35 files changed, 252 insertions(+), 152 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 13b7d3caa..5db3ca582 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -175,6 +175,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/BrowseSourceScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/BrowseSourceScreen.kt index 833e4bf79..6d01f85b8 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/BrowseSourceScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/BrowseSourceScreen.kt @@ -24,6 +24,7 @@ import eu.kanade.presentation.components.AppBar import eu.kanade.presentation.util.formattedMessage import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.source.Source +import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.flow.StateFlow import tachiyomi.domain.library.model.LibraryDisplayMode import tachiyomi.domain.manga.model.Manga @@ -76,7 +77,7 @@ fun BrowseSourceContent( modifier = Modifier.padding(contentPadding), message = getErrorMessage(errorState), actions = if (source is LocalSource) { - listOf( + persistentListOf( EmptyScreenAction( stringResId = R.string.local_source_help_guide, icon = Icons.Outlined.HelpOutline, @@ -84,7 +85,7 @@ fun BrowseSourceContent( ), ) } else { - listOf( + persistentListOf( EmptyScreenAction( stringResId = R.string.action_retry, icon = Icons.Outlined.Refresh, diff --git a/app/src/main/java/eu/kanade/presentation/browse/SourcesScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/SourcesScreen.kt index d6a8c7186..377bcb031 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/SourcesScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/SourcesScreen.kt @@ -94,8 +94,8 @@ fun SourcesScreen( @Composable private fun SourceHeader( - modifier: Modifier = Modifier, language: String, + modifier: Modifier = Modifier, ) { val context = LocalContext.current Text( @@ -108,11 +108,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, ) { BaseSourceItem( modifier = modifier, 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..cc2a56ec7 100644 --- a/app/src/main/java/eu/kanade/presentation/components/EmptyScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/components/EmptyScreen.kt @@ -8,6 +8,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 +31,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, diff --git a/app/src/main/java/eu/kanade/presentation/manga/components/MangaDialogs.kt b/app/src/main/java/eu/kanade/presentation/manga/components/MangaDialogs.kt index 1fd1dd021..30817579c 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/components/MangaDialogs.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/components/MangaDialogs.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.domain.manga.interactor.FetchInterval import tachiyomi.presentation.core.components.WheelTextPicker @@ -67,13 +68,15 @@ fun SetIntervalDialog( contentAlignment = Alignment.Center, ) { val size = DpSize(width = maxWidth / 2, height = 128.dp) - val items = (0..FetchInterval.MAX_INTERVAL).map { - if (it == 0) { - stringResource(R.string.label_default) - } else { - it.toString() + val items = (0..FetchInterval.MAX_INTERVAL) + .map { + if (it == 0) { + stringResource(R.string.label_default) + } else { + it.toString() + } } - } + .toImmutableList() WheelTextPicker( items = items, size = size, 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/data/CreateBackupScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/CreateBackupScreen.kt index 571a7bda8..b1a5d9502 100644 --- 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 @@ -36,6 +36,10 @@ 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 @@ -154,7 +158,7 @@ private class CreateBackupScreenModel : StateScreenModel = BackupChoices.keys, + val flags: PersistentSet = BackupChoices.keys.toPersistentSet(), ) } 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 a4faba194..2f4ecf11d 100644 --- a/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogSelector.kt +++ b/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogSelector.kt @@ -34,6 +34,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 @@ -102,7 +104,7 @@ fun TrackChapterSelector( title = stringResource(R.string.chapters), content = { WheelNumberPicker( - items = range.toList(), + items = range.toImmutableList(), modifier = Modifier.align(Alignment.Center), startIndex = selection, onSelectionChanged = { onSelectionChange(it) }, @@ -117,7 +119,7 @@ fun TrackChapterSelector( fun TrackScoreSelector( selection: String, onSelectionChange: (String) -> Unit, - selections: List, + selections: ImmutableList, onConfirm: () -> Unit, onDismissRequest: () -> Unit, ) { 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 af51d7b80..732b25cac 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 @@ -6,6 +6,7 @@ import androidx.annotation.DrawableRes import androidx.annotation.StringRes import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.track.model.TrackSearch +import kotlinx.collections.immutable.ImmutableList import okhttp3.OkHttpClient interface Tracker { @@ -36,7 +37,7 @@ interface Tracker { fun getCompletionStatus(): Int - fun getScoreList(): List + fun getScoreList(): ImmutableList // TODO: Store all scores as 10 point in the future maybe? fun get10PointScore(track: tachiyomi.domain.track.model.Track): Double 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 19227efea..6fef751d6 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 @@ -7,6 +7,9 @@ import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.track.BaseTracker import eu.kanade.tachiyomi.data.track.DeletableTracker import eu.kanade.tachiyomi.data.track.model.TrackSearch +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toImmutableList import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import uy.kohesive.injekt.injectLazy @@ -74,18 +77,18 @@ class Anilist(id: Long) : BaseTracker(id, "AniList"), DeletableTracker { 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 ca4ddbc66..8434b3db6 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 @@ -6,6 +6,8 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.track.BaseTracker import eu.kanade.tachiyomi.data.track.model.TrackSearch +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toImmutableList import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import uy.kohesive.injekt.injectLazy @@ -18,9 +20,7 @@ class Bangumi(id: Long) : BaseTracker(id, "Bangumi") { 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 displayScore(track: Track): String { return track.score.toInt().toString() @@ -141,5 +141,9 @@ class Bangumi(id: Long) : BaseTracker(id, "Bangumi") { 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 e9de55925..bee854afd 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 @@ -10,6 +10,8 @@ import eu.kanade.tachiyomi.data.track.model.TrackSearch import eu.kanade.tachiyomi.source.ConfigurableSource import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.sourcePreferences +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.source.service.SourceManager import uy.kohesive.injekt.injectLazy @@ -51,7 +53,7 @@ class Kavita(id: Long) : BaseTracker(id, "Kavita"), EnhancedTracker { override fun getCompletionStatus(): Int = COMPLETED - override fun getScoreList(): List = emptyList() + override fun getScoreList(): ImmutableList = persistentListOf() override fun displayScore(track: Track): 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 7c1fd34ff..5763b735e 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 @@ -7,6 +7,8 @@ import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.track.BaseTracker import eu.kanade.tachiyomi.data.track.DeletableTracker import eu.kanade.tachiyomi.data.track.model.TrackSearch +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toImmutableList import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import uy.kohesive.injekt.injectLazy @@ -54,9 +56,9 @@ class Kitsu(id: Long) : BaseTracker(id, "Kitsu"), DeletableTracker { 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 a2071c785..5c9d3e6d2 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 @@ -8,6 +8,8 @@ import eu.kanade.tachiyomi.data.track.BaseTracker import eu.kanade.tachiyomi.data.track.EnhancedTracker import eu.kanade.tachiyomi.data.track.model.TrackSearch import eu.kanade.tachiyomi.source.Source +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf import okhttp3.Dns import okhttp3.OkHttpClient import tachiyomi.domain.manga.model.Manga @@ -48,7 +50,7 @@ class Komga(id: Long) : BaseTracker(id, "Komga"), EnhancedTracker { override fun getCompletionStatus(): Int = COMPLETED - override fun getScoreList(): List = emptyList() + override fun getScoreList(): ImmutableList = persistentListOf() override fun displayScore(track: Track): String = "" 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 14095f420..86826bb07 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 @@ -9,6 +9,8 @@ import eu.kanade.tachiyomi.data.track.DeletableTracker 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.TrackSearch +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toImmutableList class MangaUpdates(id: Long) : BaseTracker(id, "MangaUpdates"), DeletableTracker { @@ -18,6 +20,12 @@ class MangaUpdates(id: Long) : BaseTracker(id, "MangaUpdates"), DeletableTracker 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) } @@ -48,11 +56,9 @@ class MangaUpdates(id: Long) : BaseTracker(id, "MangaUpdates"), DeletableTracker 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: Track): 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 d7141099a..bce0e1d0b 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 @@ -7,6 +7,8 @@ import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.track.BaseTracker import eu.kanade.tachiyomi.data.track.DeletableTracker import eu.kanade.tachiyomi.data.track.model.TrackSearch +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toImmutableList import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import uy.kohesive.injekt.injectLazy @@ -23,6 +25,10 @@ class MyAnimeList(id: Long) : BaseTracker(id, "MyAnimeList"), DeletableTracker { 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() @@ -57,9 +63,7 @@ class MyAnimeList(id: Long) : BaseTracker(id, "MyAnimeList"), DeletableTracker { override fun getCompletionStatus(): Int = COMPLETED - override fun getScoreList(): List { - return IntRange(0, 10).map(Int::toString) - } + override fun getScoreList(): ImmutableList = SCORE_LIST override fun displayScore(track: Track): String { return track.score.toInt().toString() 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 2f39a9504..6a589511c 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 @@ -7,6 +7,8 @@ import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.track.BaseTracker import eu.kanade.tachiyomi.data.track.DeletableTracker import eu.kanade.tachiyomi.data.track.model.TrackSearch +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toImmutableList import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import uy.kohesive.injekt.injectLazy @@ -20,6 +22,10 @@ class Shikimori(id: Long) : BaseTracker(id, "Shikimori"), DeletableTracker { 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() @@ -28,9 +34,7 @@ class Shikimori(id: Long) : BaseTracker(id, "Shikimori"), DeletableTracker { 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 displayScore(track: Track): 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 4f3670929..6e4539ff7 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 @@ -8,6 +8,8 @@ import eu.kanade.tachiyomi.data.track.BaseTracker import eu.kanade.tachiyomi.data.track.EnhancedTracker import eu.kanade.tachiyomi.data.track.model.TrackSearch import eu.kanade.tachiyomi.source.Source +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf import tachiyomi.domain.manga.model.Manga as DomainManga import tachiyomi.domain.track.model.Track as DomainTrack @@ -41,7 +43,7 @@ class Suwayomi(id: Long) : BaseTracker(id, "Suwayomi"), EnhancedTracker { override fun getCompletionStatus(): Int = COMPLETED - override fun getScoreList(): List = emptyList() + override fun getScoreList(): ImmutableList = persistentListOf() override fun displayScore(track: Track): String = "" diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionFilterScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionFilterScreenModel.kt index c50a3d9e9..acfeafa04 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionFilterScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionFilterScreenModel.kt @@ -6,6 +6,11 @@ import cafe.adriel.voyager.core.model.screenModelScope import eu.kanade.domain.extension.interactor.GetExtensionLanguages import eu.kanade.domain.source.interactor.ToggleLanguage import eu.kanade.domain.source.service.SourcePreferences +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 ExtensionFilterScreenModel( .collectLatest { (extensionLanguages, enabledLanguages) -> mutableState.update { ExtensionFilterState.Success( - languages = extensionLanguages, - enabledLanguages = enabledLanguages, + languages = extensionLanguages.toImmutableList(), + enabledLanguages = enabledLanguages.toImmutableSet(), ) } } @@ -65,8 +70,8 @@ sealed interface ExtensionFilterState { @Immutable data class Success( - val languages: List, - val enabledLanguages: Set = emptySet(), + val languages: ImmutableList, + val enabledLanguages: ImmutableSet = persistentSetOf(), ) : ExtensionFilterState { val isEmpty: Boolean diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsScreenModel.kt index a3d9b2432..a0ed5495b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsScreenModel.kt @@ -12,6 +12,9 @@ import eu.kanade.tachiyomi.extension.model.Extension 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 @@ -75,10 +78,10 @@ class ExtensionDetailsScreenModel( } .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()) } } } } @@ -164,11 +167,11 @@ class ExtensionDetailsScreenModel( @Immutable data class State( val extension: Extension.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/migration/manga/MigrateMangaScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/manga/MigrateMangaScreenModel.kt index 2eb4085d6..e5d886f85 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/manga/MigrateMangaScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/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.Source +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: Source? = 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/migration/sources/MigrateSourceScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/sources/MigrateSourceScreenModel.kt index 2fd7e1c27..f7659b3e0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/sources/MigrateSourceScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/sources/MigrateSourceScreenModel.kt @@ -6,6 +6,9 @@ import cafe.adriel.voyager.core.model.screenModelScope import eu.kanade.domain.source.interactor.GetSourcesWithFavoriteCount import eu.kanade.domain.source.interactor.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 MigrateSourceScreenModel( mutableState.update { it.copy( isLoading = false, - items = sources, + items = sources.toImmutableList(), ) } } @@ -80,7 +83,7 @@ class MigrateSourceScreenModel( @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/source/SourcesScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcesScreenModel.kt index 1435eea3c..ce98bf629 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcesScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcesScreenModel.kt @@ -7,6 +7,9 @@ import eu.kanade.domain.source.interactor.GetEnabledSources import eu.kanade.domain.source.interactor.ToggleSource import eu.kanade.domain.source.interactor.ToggleSourcePin import eu.kanade.presentation.browse.SourceUiModel +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 @@ -65,14 +68,16 @@ class SourcesScreenModel( state.copy( isLoading = false, - items = byLang.flatMap { - listOf( - SourceUiModel.Header(it.key), - *it.value.map { source -> - SourceUiModel.Item(source) - }.toTypedArray(), - ) - }, + items = byLang + .flatMap { + listOf( + SourceUiModel.Header(it.key), + *it.value.map { source -> + SourceUiModel.Item(source) + }.toTypedArray(), + ) + } + .toImmutableList(), ) } } @@ -103,7 +108,7 @@ class SourcesScreenModel( 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/source/globalsearch/SearchScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/SearchScreenModel.kt index 276af54ee..3f7438b7c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/SearchScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/SearchScreenModel.kt @@ -9,6 +9,10 @@ import eu.kanade.domain.source.service.SourcePreferences import eu.kanade.presentation.util.ioCoroutineScope import eu.kanade.tachiyomi.extension.ExtensionManager 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 @@ -125,9 +129,17 @@ abstract class SearchScreenModel( // Reuse previous results if possible if (sameQuery) { val existingResults = state.value.items - updateItems(sources.associateWith { existingResults[it] ?: SearchItemResult.Loading }) + updateItems( + sources + .associateWith { existingResults[it] ?: SearchItemResult.Loading } + .toPersistentMap(), + ) } else { - updateItems(sources.associateWith { SearchItemResult.Loading }) + updateItems( + sources + .associateWith { SearchItemResult.Loading } + .toPersistentMap(), + ) } searchJob = ioCoroutineScope.launch { @@ -160,14 +172,21 @@ abstract class SearchScreenModel( } } - 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: SearchItemResult) { - val mutableItems = state.value.items.toMutableMap() - mutableItems[source] = result - updateItems(mutableItems) + val newItems = state.value.items.mutate { + it[source] = result + } + updateItems(newItems) } @Immutable @@ -176,7 +195,7 @@ abstract class SearchScreenModel( val searchQuery: String? = null, val sourceFilter: SourceFilter = SourceFilter.PinnedOnly, val onlyShowHasResults: Boolean = false, - val items: Map = emptyMap(), + val items: PersistentMap = persistentMapOf(), ) { val progress: Int = items.count { it.value !is SearchItemResult.Loading } val total: Int = items.size diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryScreenModel.kt index a4a4fe309..33b7ea148 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryScreenModel.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 @@ -36,7 +38,9 @@ class CategoryScreenModel( .collectLatest { categories -> mutableState.update { CategoryScreenState.Success( - categories = categories.filterNot(Category::isSystemCategory), + categories = categories + .filterNot(Category::isSystemCategory) + .toImmutableList(), ) } } @@ -135,7 +139,7 @@ sealed interface CategoryScreenState { @Immutable data class Success( - val categories: List, + val categories: ImmutableList, val dialog: CategoryDialog? = null, ) : CategoryScreenState { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt index c33b6cd12..72fa1cc6c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.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 @@ -562,16 +565,16 @@ class LibraryScreenModel( } 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) @@ -584,11 +587,11 @@ class LibraryScreenModel( */ 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) @@ -596,17 +599,17 @@ class LibraryScreenModel( 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) } @@ -614,14 +617,14 @@ class LibraryScreenModel( 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) } @@ -629,14 +632,14 @@ class LibraryScreenModel( 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) } @@ -703,7 +706,7 @@ class LibraryScreenModel( val isLoading: Boolean = true, val library: LibraryMap = 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/LibraryTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryTab.kt index aff6a2fdd..12e8f4974 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryTab.kt @@ -43,6 +43,7 @@ import eu.kanade.tachiyomi.ui.home.HomeScreen import eu.kanade.tachiyomi.ui.main.MainActivity import eu.kanade.tachiyomi.ui.manga.MangaScreen 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 @@ -154,7 +155,7 @@ object LibraryTab : 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, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt index 6eb8a0d74..3f33b9651 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt @@ -58,6 +58,7 @@ import eu.kanade.tachiyomi.data.track.model.TrackSearch 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 @@ -398,7 +399,7 @@ private data class TrackScoreSelectorScreen( private val tracker: Tracker, ) : StateScreenModel(State(tracker.displayScore(track.toDbTrack()))) { - fun getSelections(): List { + fun getSelections(): ImmutableList { return tracker.getScoreList() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/updates/UpdatesScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/updates/UpdatesScreenModel.kt index 5dcd140b3..d4a340ff3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/updates/UpdatesScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/updates/UpdatesScreenModel.kt @@ -21,6 +21,10 @@ import eu.kanade.tachiyomi.data.download.model.Download import eu.kanade.tachiyomi.data.library.LibraryUpdateJob 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 UpdatesScreenModel( } } - 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 -> Download.State.DOWNLOADED - else -> Download.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 -> Download.State.DOWNLOADED + else -> Download.State.NOT_DOWNLOADED + } + UpdatesItem( + update = update, + downloadStateProvider = { downloadState }, + downloadProgressProvider = { activeDownload?.progress ?: 0 }, + selected = update.chapterId in selectedChapterIds, + ) } - UpdatesItem( - update = update, - downloadStateProvider = { downloadState }, - downloadProgressProvider = { activeDownload?.progress ?: 0 }, - selected = update.chapterId in selectedChapterIds, - ) - } + .toPersistentList() } fun updateLibrary(): Boolean { @@ -144,17 +150,14 @@ class UpdatesScreenModel( */ private fun updateDownloadState(download: Download) { 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 UpdatesScreenModel( } } } - state.copy(items = newItems) + state.copy(items = newItems.toPersistentList()) } } @@ -340,7 +343,7 @@ class UpdatesScreenModel( 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 UpdatesScreenModel( 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 UpdatesScreenModel( @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/test/DummyTracker.kt b/app/src/main/java/eu/kanade/test/DummyTracker.kt index c9e53f9f5..2e20ebb4d 100644 --- a/app/src/main/java/eu/kanade/test/DummyTracker.kt +++ b/app/src/main/java/eu/kanade/test/DummyTracker.kt @@ -4,6 +4,8 @@ import android.graphics.Color import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.track.Tracker import eu.kanade.tachiyomi.data.track.model.TrackSearch +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toImmutableList import okhttp3.OkHttpClient import tachiyomi.domain.track.model.Track @@ -18,7 +20,7 @@ data class DummyTracker( val valReadingStatus: Int = 1, val valRereadingStatus: Int = 1, 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 valSearchResults: List = listOf(), ) : Tracker { @@ -48,7 +50,7 @@ data class DummyTracker( override fun getCompletionStatus(): Int = valCompletionStatus - override fun getScoreList(): List = valScoreList + override fun getScoreList(): ImmutableList = valScoreList override fun get10PointScore(track: Track): Double = val10PointScore 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/presentation-core/build.gradle.kts b/presentation-core/build.gradle.kts index b578de913..4727dbed8 100644 --- a/presentation-core/build.gradle.kts +++ b/presentation-core/build.gradle.kts @@ -36,6 +36,8 @@ dependencies { 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/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/WheelPicker.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/WheelPicker.kt index d13b96a7b..636e1ebac 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,7 +55,7 @@ import kotlin.math.absoluteValue @Composable fun WheelNumberPicker( - items: List, + items: ImmutableList, modifier: Modifier = Modifier, startIndex: Int = 0, size: DpSize = DpSize(128.dp, 128.dp), @@ -78,7 +79,7 @@ fun WheelNumberPicker( @Composable fun WheelTextPicker( - items: List, + items: ImmutableList, modifier: Modifier = Modifier, startIndex: Int = 0, size: DpSize = DpSize(128.dp, 128.dp), @@ -101,7 +102,7 @@ fun WheelTextPicker( @Composable private fun WheelPicker( - items: List, + items: ImmutableList, modifier: Modifier = Modifier, startIndex: Int = 0, size: DpSize = DpSize(128.dp, 128.dp), 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 23eaa436c..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 @@ -23,6 +23,7 @@ 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 @@ -38,7 +39,7 @@ data class EmptyScreenAction( fun EmptyScreen( @StringRes textResource: Int, modifier: Modifier = Modifier, - actions: List? = null, + actions: ImmutableList? = null, ) { EmptyScreen( message = stringResource(textResource), @@ -51,7 +52,7 @@ fun EmptyScreen( fun EmptyScreen( message: String, modifier: Modifier = Modifier, - actions: List? = null, + actions: ImmutableList? = null, ) { val face = remember { getRandomErrorFace() } Column( @@ -98,7 +99,7 @@ fun EmptyScreen( } } -private val ERROR_FACES = listOf( +private val ErrorFaces = listOf( "(・o・;)", "Σ(ಠ_ಠ)", "ಥ_ಥ", @@ -108,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)] } From d9e2317e62236119b62b3aa5c83d0fa7bc3e12fe Mon Sep 17 00:00:00 2001 From: "Weblate (bot)" Date: Mon, 13 Nov 2023 04:23:59 +0100 Subject: [PATCH 6/7] Translations update from Hosted Weblate (#10102) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Weblate translations Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ar/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ca/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/el/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es_419/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fil/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/hr/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/id/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ja/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ru/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/th/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/tr/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/uk/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hans/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hant/ Translation: Tachiyomi/Tachiyomi 0.x Co-authored-by: Alessandro Jean <14254807+alessandrojean@users.noreply.github.com> Co-authored-by: Ali Aljishi Co-authored-by: Dexroneum Co-authored-by: Eduard Ereza Martínez Co-authored-by: Hiroshi Co-authored-by: InfinityDouki56 Co-authored-by: La prière Co-authored-by: Lzmxya Co-authored-by: Milo Ivir Co-authored-by: Pitpe11 Co-authored-by: TheKingTermux Co-authored-by: Uzuki Shimamura Co-authored-by: Zero O Co-authored-by: altinat Co-authored-by: bapeey Co-authored-by: gallegonovato Co-authored-by: orkan gökçe alaz aşina Co-authored-by: winver --- i18n/src/main/res/values-ar/strings.xml | 13 ++++++-- i18n/src/main/res/values-b+es+419/strings.xml | 27 +++++++++++---- i18n/src/main/res/values-ca/strings.xml | 21 +++++++++--- i18n/src/main/res/values-el/strings.xml | 21 +++++++++--- i18n/src/main/res/values-es/strings.xml | 13 ++++++-- i18n/src/main/res/values-fil/strings.xml | 33 +++++++++++-------- i18n/src/main/res/values-hr/strings.xml | 12 +++++-- i18n/src/main/res/values-in/strings.xml | 25 ++++++++++---- i18n/src/main/res/values-ja/strings.xml | 9 ++++- i18n/src/main/res/values-pt-rBR/strings.xml | 12 ++++++- i18n/src/main/res/values-ru/strings.xml | 9 ++++- i18n/src/main/res/values-th/strings.xml | 15 ++++++--- i18n/src/main/res/values-tr/strings.xml | 24 ++++++++++---- i18n/src/main/res/values-uk/strings.xml | 7 ++++ i18n/src/main/res/values-zh-rCN/strings.xml | 25 +++++++++----- i18n/src/main/res/values-zh-rTW/strings.xml | 15 ++++++--- 16 files changed, 213 insertions(+), 68 deletions(-) diff --git a/i18n/src/main/res/values-ar/strings.xml b/i18n/src/main/res/values-ar/strings.xml index 30e6fdae3..fc0fb15b6 100644 --- a/i18n/src/main/res/values-ar/strings.xml +++ b/i18n/src/main/res/values-ar/strings.xml @@ -566,8 +566,8 @@ رأسي التدوير تلقائيًّا - إنشاء مجلدات وفقا لعنوان الإدخالات - حفظ الصفحات في مجلدات منفصلة + يُنشِئ مجلدات وفقًا لعناوين المدخلات + احفظ الصفحات في مجلدات منفصلة الإجراءات تدرج رمادي إستثناء: %s @@ -882,11 +882,18 @@ أتريد ترتيب الفئات حسب الحروف؟ إعدادات المصادر إعدادات التطبيق - ما استطاع محدِّد الملفات من إدخال الملف في التطبيق + لا ملفات حُدِّدت البيانات والتخزين أبدًا يخفِّف الحرق في شاشات الحبر آخر احتياط تلقائي: %s أشرق الشاشة بِيضًا إذا تغيرت الصفحة التخزين + نقاط المتتبع + أنشئ + نفِّذ + صفِّر + لم يُعثَر على مترجمين + المترجم + احجب بعض المترجمين \ No newline at end of file diff --git a/i18n/src/main/res/values-b+es+419/strings.xml b/i18n/src/main/res/values-b+es+419/strings.xml index a34bc4886..6c46a1970 100644 --- a/i18n/src/main/res/values-b+es+419/strings.xml +++ b/i18n/src/main/res/values-b+es+419/strings.xml @@ -271,7 +271,7 @@ Iniciar Reintentar Borrar cookies - Red + Redes Se canceló la restauración La restauración de la copia de seguridad falló Restaurando copia de seguridad @@ -291,8 +291,8 @@ La copia de seguridad no contiene ningún manga. Archivo de copia de seguridad invalido Copia de seguridad creada - Máximo de copias de seguridad - Frecuencia de respaldo + Máximo de copias de seguridad automáticas + Frecuencia de respaldo automático Directorio de copia de seguridad Restaurar biblioteca desde archivo de copia de seguridad Caché borrada. %1$d archivos se han eliminado @@ -523,7 +523,7 @@ Rotación Derecha Izquierda - Crea carpetas según el título del manga + Crear carpetas según el título del manga Escala de grises Está versión de Android ya no está soportada Falló al copiar en el portapapeles @@ -708,7 +708,7 @@ Modo lectura, apariencia, navegación Descargas automáticas y por adelantado Fuentes, extensiones, búsqueda global - Respaldo manual y automático + Respaldo manual y automático, espacio de almacenamiento Bloqueo de aplicación, pantalla de seguridad Guardar registros de fallo, optimizaciones de bateria Sincronización de progreso unidireccional, sincronización mejorada @@ -747,7 +747,7 @@ Título desconocido Comprobando descargas Ubicación incorrecta: %s - Reestablecer el nombre del navegador + Restablecer el nombre del navegador Una actualización está actualmente en curso ¿Estás seguro\? Manga @@ -834,5 +834,18 @@ ¿Quieres ordenar las categorías de forma alfabética\? Configuraciónes de fuente Configuraciones - El selector de archivos no pudo devolver el archivo a la aplicación + Ningún archivo seleccionado + Crear + Nunca + Reducir el ghosting en pantallas de tinta electrónica + Aplicar + Restablecer configuración predeterminada + Última copia de seguridad automática: %s + No se encontraron scanlators + Scanlator + Destello blanco al cambiar de página + Uso de almacenamiento + Puntuación del rastreador + Datos y almacenamiento + Excluir scanlators \ No newline at end of file diff --git a/i18n/src/main/res/values-ca/strings.xml b/i18n/src/main/res/values-ca/strings.xml index 835229167..2f2206d76 100644 --- a/i18n/src/main/res/values-ca/strings.xml +++ b/i18n/src/main/res/values-ca/strings.xml @@ -162,8 +162,8 @@ Restaura una còpia de seguretat Restaura la biblioteca del fitxer de còpia de seguretat Ubicació de la còpia de seguretat - Freqüència de la còpia de seguretat - Màxim de còpies de seguretat + Freqüència de la còpia de seguretat automàtica + Màxim de còpies de seguretat automàtiques S’ha creat la còpia de seguretat S’ha completat la restauració De què voleu fer una còpia de seguretat\? @@ -696,7 +696,7 @@ No s’han concedit permisos d’emmagatzematge Populars - Còpies de seguretat automàtiques i manuals + Còpies de seguretat automàtiques i manuals i espai d’emmagatzematge Mode de lectura, visualització i navegació Baixades automàtiques i per avançat Múltiples @@ -818,5 +818,18 @@ Voleu ordenar les categories alfabèticament\? Configuració de la font Configuració de l’aplicació - El selector de fitxers no ha retornat cap fitxer a l’aplicació + No s’ha seleccionat cap fitxer + Crea + Mai + Redueix l’efecte fantasma en pantalles de tinta electrònica + Aplica + Torna a la configuració per defecte + Darrera còpia de seguretat automàtica: %s + No s’ha trobat cap scanlator + Scanlator + Centelleig blanc en canviar de pàgina + Ús de l’emmagatzematge + Puntuació del servei de seguiment + Dades i emmagatzematge + Exclou scanlators \ No newline at end of file diff --git a/i18n/src/main/res/values-el/strings.xml b/i18n/src/main/res/values-el/strings.xml index 3efbebd71..1c1663b0a 100644 --- a/i18n/src/main/res/values-el/strings.xml +++ b/i18n/src/main/res/values-el/strings.xml @@ -162,8 +162,8 @@ Επαναφορά αντιγράφου ασφαλείας Επαναφορά βιβλιοθήκης από αρχείο αντιγράφου ασφαλείας Τοποθεσία αντιγράφων ασφαλείας - Συχνότητα αντίγραφου ασφάλειας - Μέγιστα αντίγραφα ασφαλείας + Συχνότητα αυτόματων αντιγράφων ασφαλείας + Μέγιστα αυτόματα αντίγραφα ασφαλείας Δημιουργήθηκε αντίγραφο ασφαλείας Η επαναφορά ολοκληρώθηκε Τι αντίγραφο ασφαλείας θέλετε να δημιουργήσετε; @@ -703,7 +703,7 @@ Κατηγορίες, καθολική ενημέρωση, σύρσιμο κεφαλαίου Λειτουργία ανάγνωσης, οθόνη, πλοήγηση Μονόδρομος συγχρονισμός προόδου, ενισχυμένος συγχρονισμός - Χειροκίνητα & αυτόματα αντίγραφα ασφαλείας + Χειροκίνητα & αυτόματα αντίγραφα ασφαλείας, χώρος αποθήκευσης Κλείδωμα εφαρμογής, ασφαλής οθόνη Επανεκκίνηση της εφαρμογής Αυτόματη λήψη, λήψη εκ των προτέρων @@ -818,5 +818,18 @@ Ενημέρωση βιβλιοθήκης… (%s) Θέλετε να ταξινομήσετε τις κατηγορίες αλφαβητικά; Ρυθμίσεις πηγών - Το πρόγραμμα επιλογής αρχείων απέτυχε να επιστρέψει το αρχείο στην εφαρμογή + Δεν έχει επιλεγεί αρχείο + Ποτέ + Μειώνει το ghosting σε οθόνες e-ink + Τελευταία αυτόματη δημιουργία αντιγράφων ασφαλείας: %s + Λευκό φλας κατά την αλλαγή σελίδας + Χρήση αποθηκευτικού χώρου + Σκορ tracker + Δεδομένα και χώρος αποθήκευσης + Δημιουργία + Υποβολή + Επαναφορά προεπιλογής + Δε βρέθηκαν scanlators + Scanlator + Εξαίρεση scanlator \ No newline at end of file diff --git a/i18n/src/main/res/values-es/strings.xml b/i18n/src/main/res/values-es/strings.xml index 3c99d7c7e..7f17ec314 100644 --- a/i18n/src/main/res/values-es/strings.xml +++ b/i18n/src/main/res/values-es/strings.xml @@ -572,8 +572,8 @@ Mostrar el número de elementos Fecha de obtención del capítulo Tipo de rotación - Crea carpetas según el título de los elementos - Guardar páginas en carpetas separadas + Crea carpetas según el título de las entradas + Guardar las páginas en carpetas independientes Acciones Escala de grises Es posible que las funciones de copia de respaldo y restauración no funcionen correctamente si la opción «Optimización de MIUI» está desactivada. @@ -865,11 +865,18 @@ Ajustes de la aplicación Ordenar categorías ¿Quieres ordenar las categorías de forma alfabética\? - La pantalla de selección de archivos no ha devuelto ningún archivo + Ningún archivo seleccionado Nunca Reducir el ghosting en las pantallas de tinta electrónica Última copia de seguridad automática: %s Parpadeo en blanco al cambiar de página Datos y almacenamiento Almacenamiento utilizado + Puntuación del rastreador + Aplicar + Volver a la configuración predeterminada + Crear + Sin ningún scanlators + Scanlator + Omitir a los scanlators \ No newline at end of file diff --git a/i18n/src/main/res/values-fil/strings.xml b/i18n/src/main/res/values-fil/strings.xml index a61be47a9..26157d64a 100644 --- a/i18n/src/main/res/values-fil/strings.xml +++ b/i18n/src/main/res/values-fil/strings.xml @@ -15,8 +15,8 @@ Pinakaluma Pinakabago Ayusin - Ikansela lahat - Ikansela + Kanselahin lahat + Kanselahin I-unpin I-pin Isara @@ -380,7 +380,7 @@ Di alam ang may-akda Di alam Patuloy - Gabay sa Lokal na Source + Gabay sa Lokal na source Maghanap Pinakabago Hinanap ang \"%1$s\" sa lahat @@ -388,7 +388,7 @@ Naka-pin Huling ginamit Iba pa - Lokal na Source + Lokal na source Walang nakitang resulta Wala na\'ng resulta Mga Tab @@ -453,7 +453,7 @@ %d tracker %d na mga tracker - Wala kang naka-pin na pinagkukunan + Wala kang naka-pin na source Tapos na Mga error Takbo @@ -482,11 +482,11 @@ Linisin ang nakaraan Nalinis na ang nakaraan Sigurado ka ba talaga\? Mawawala ang buong nakaraan. - Gabay sa Paglipat ng Source + Gabay sa Paglipat ng source Abante Balik Walang nakitang app para makapili - Ipakita sa mga source at extension + Ipakita sa mga listahan ng source at extension Mga source na NSFW (18+) Mag-login muli po sa MAL Natapos basahin @@ -504,7 +504,7 @@ Sinundan Kaliwa at Kanan Hatiin ang mga malalapad na pahina - Ipakita ang dami + Ipakita ang bilang ng mga item Kung sakaling hindi sumasakto sa direksyon ng pagbabasa ang paghahati sa malalapad na pahina Baligtarin ang paghahati sa pahina Ire-restore ang mga datos mula sa backup file. @@ -535,8 +535,8 @@ Pag-ikot Maabo Isara ang incognito - Kusa - Ikansela lahat para sa seryeng ito + Awto + Kanselahin lahat para sa seryeng ito Ayusin ayon sa Restriksyon: %s Walang nahanap na kapares @@ -608,7 +608,7 @@ Babala: maaaring humantong sa pagbagal at/o pagharang ng mga source sa Tachiyomi ang mga malalaking maramihang pag-download. I-tap para matuto pa. Mga update sa app I-update lahat - %1$d na entry sa database na wala sa Aklatan + %1$d na entry sa database na wala sa aklatan Linisin ang cache ng kabanata sa paglulunsad ng app Walang malilinis Bigong makuha ang listahan ng mga extension @@ -780,7 +780,7 @@ Ipasadya ang fetch interval Huling 10+ pagsusuri Susunod na inaasahang update - Nawala\? or Nahulog\? (depending on the context, \"Nahulog\" means dropped or dropped something, and \"Nawala\" means Gone/Vanished) Nahuling 20+ at 2 buwan + Itinigil\? Huli ng 20+ at 2 buwan Lumipas ang check period Kunin kada buwan (kada ika-28 na araw) @@ -816,7 +816,7 @@ Mag-ayos ng kategorya Nag-a-update ang aklatan... (%s) Gusto mo bang mag-ayos ng kategorya ayon sa alpabeto\? - Mga setting ng pinagmula + Mga setting ng source Mga setting ng app Ang file picker ay nabigo na ibalik ang file sa app Data at storage @@ -825,4 +825,11 @@ Hindi kailanman Huling awtomatikong na-back up: %s Paggamit ng storage + Iskor sa tracker + Gamitin + Ibalik sa default + Walang scanlator ang nahanap + Scanlator + Ibukod ang mga scanlator + Lumikha \ No newline at end of file diff --git a/i18n/src/main/res/values-hr/strings.xml b/i18n/src/main/res/values-hr/strings.xml index 47c8f888b..bcdf28a68 100644 --- a/i18n/src/main/res/values-hr/strings.xml +++ b/i18n/src/main/res/values-hr/strings.xml @@ -544,7 +544,7 @@ Deaktiviraj anonimni modus Okretanje Automatski - Stvara mape prema naslovu unosa + Stvara mape na osnovi naslova unosa Spremi stranice u zasebne mape Radnje Prekini sve za ovu seriju @@ -832,7 +832,7 @@ Razvrstaj kategorije Aktualiziranje biblioteke … (%s) Želiš li razvrstati kategorije po abecedi\? - Program za biranje datoteka nije uspio vratiti datoteku u aplikaciju + Nije odabrana nijedna datoteka Postavke izvora Postavke aplikacije Podaci i spremište @@ -840,4 +840,12 @@ Smanjuje artefakte na ekranima s e-tintom Zadnja automatska sigurnosna kopija: %s Zabljesni prilikom mijenjanja stranice + Stvori + Primijeni + Obnovi standardne vrijednosti + Nije pronađen nijedan amaterski prevoditelj + Amaterski prevoditelj + Korištenje memorije + Rezultat tragača + Isključi amaterske prevoditelje \ No newline at end of file diff --git a/i18n/src/main/res/values-in/strings.xml b/i18n/src/main/res/values-in/strings.xml index fde4d03ef..e3e72bc57 100644 --- a/i18n/src/main/res/values-in/strings.xml +++ b/i18n/src/main/res/values-in/strings.xml @@ -135,8 +135,8 @@ Pulihkan cadangan Pulihkan isi pustaka dari berkas cadangan Tempat pencadangan - Frekuensi cadangan dibuat - Jumlah maksimum cadangan + Frekuensi pencadangan otomatis + Jumlah maksimum pencadangan otomatis Cadangan dibuat Pemulihan selesai Apa saja yang ingin Anda cadangkan\? @@ -499,8 +499,8 @@ Lanjut Sblm Otomatis - Simpan halaman di folder terpisah - Membuat folder sesuai dengan judul entri + Menyimpan halaman ke dalam folder terpisah + Membuat folder menurut judul entri Kecuali: %s Termasuk: %s Membagi halaman lebar @@ -692,7 +692,7 @@ Kunci aplikasi, layar aman Tema, format tanggal & waktu Kategori, pembaruan global, geser chapter - Pencadangan manual & otomatis + Pencadangan manual & otomatis, ruang penyimpanan Buat log kerusakan, pengoptimalan baterai Aduh! Mulai ulang aplikasi @@ -800,7 +800,20 @@ Mengurutkan kategori Memperbarui pustaka... (%s) Apakah Anda ingin mengurutkan kategori menurut abjad\? - Pemilih file gagal mengembalikan file ke aplikasi + Tidak ada file yang dipilih Pengaturan sumber Pengaturan aplikasi + Buat + Tidak pernah + Mengurangi ghosting pada tampilan e-ink + Terapkan + Kembalikan ke default + Terakhir dicadangkan secara otomatis: %s + Tidak ditemukan pemindai + Pemindai + Berkedip putih pada perubahan halaman + Penggunaan penyimpanan + Skor pelacak + Data dan penyimpanan + Kecualikan pemindai \ No newline at end of file diff --git a/i18n/src/main/res/values-ja/strings.xml b/i18n/src/main/res/values-ja/strings.xml index 353d4fabd..22c76b21f 100644 --- a/i18n/src/main/res/values-ja/strings.xml +++ b/i18n/src/main/res/values-ja/strings.xml @@ -802,11 +802,18 @@ カテゴリをアルファベット順で並べ替えますか? ソース設定 アプリ設定 - ファイルピッカーはアプリにファイルを返せませんでした + 選択したファイルがありません なし Eインク画面の焼き付きを軽減 前回の自動バックアップ: %s ページめくりの時、画面を点滅させる 使用中のストレージ領域 データとストレージ + トラッカーの評価点数 + 作成 + 適用 + デフォルトに戻す + スキャンレーターが見つかりませんでした + スキャンレーター + スキャンレーターを除外 \ No newline at end of file diff --git a/i18n/src/main/res/values-pt-rBR/strings.xml b/i18n/src/main/res/values-pt-rBR/strings.xml index dc62600a4..1aeba797d 100644 --- a/i18n/src/main/res/values-pt-rBR/strings.xml +++ b/i18n/src/main/res/values-pt-rBR/strings.xml @@ -834,8 +834,18 @@ Configurações das fontes Ordenar as categorias Você deseja ordenar as categorias alfabeticamente\? - O seletor de arquivos não retornou o arquivo para o aplicativo + Nenhum arquivo selecionado Dados e armazenamento Reduz o efeito fantasma em telas e-ink Flash branco ao mudar de página + Avaliação no monitorador + Nunca + Último backup automático feito em: %s + Uso de armazenamento + Aplicar + Reverter para o padrão + Nenhum scanlator encontrado + Scanlator + Excluir scanlators + Criar \ No newline at end of file diff --git a/i18n/src/main/res/values-ru/strings.xml b/i18n/src/main/res/values-ru/strings.xml index ca1b8495f..e6cd72ba1 100644 --- a/i18n/src/main/res/values-ru/strings.xml +++ b/i18n/src/main/res/values-ru/strings.xml @@ -850,11 +850,18 @@ Обновление библиотеки... (%s) Сортировать категории Хотите ли вы сортировать категории по алфавиту\? - Приложению для выбора файлов не удалось вернуть путь файла в Tachiyomi + Файл не выбран Данные и хранение Никогда Уменьшает артефакты у экранов e-ink Последнее автоматическое резервное копирование: %s Мигать экраном при смене страницы Использование хранилища + Оценка сервиса отслеживания + Создать + Применить + Сбросить настройки + Переводчики не найдены + Переводчик + Исключить переводчиков \ No newline at end of file diff --git a/i18n/src/main/res/values-th/strings.xml b/i18n/src/main/res/values-th/strings.xml index f3d2e6e89..058815f11 100644 --- a/i18n/src/main/res/values-th/strings.xml +++ b/i18n/src/main/res/values-th/strings.xml @@ -301,8 +301,8 @@ รูปตัว L อัตโนมัติ เทา - สร้างโฟลเดอร์ตามชื่อเรื่อง - บันทึกหน้าลงในโฟลเดอร์ที่แยกต่างหาก + สร้างโฟลเดอร์ตามชื่อเรื่องของรายการ + บันทึกแต่ละหน้าลงในโฟลเดอร์ที่แยกต่างหาก การกระทำ ทั้งสอง แนวตั้ง @@ -564,7 +564,7 @@ ตัวติดตามขั้นสูง ควรเก็บสำเนาของข้อมูลสำรองไว้ที่อื่นด้วยเช่นกัน การสำรองข้อมูลอาจมีข้อมูลที่ละเอียดอ่อนรวมถึงรหัสผ่านที่เก็บไว้ ควรระวังหากแบ่งปันสำเนา บันทึกบันทึกอย่างละเอียดไปยังบันทึกของระบบ (ลดประสิทธิภาพของแอป) - ช่วยแปล + แปลเป็นภาษาไทยโดย altqx รูปแบบตอนไม่ถูกต้อง ปก ยังไม่ได้อ่าน @@ -802,11 +802,18 @@ ต้องการจัดเรียงหมวดหมู่ตามตัวอักษรหรือไม่\? การตั้งค่าแหล่งที่มา การตั้งค่าแอป - เครื่องมือเลือกไฟล์ไม่สามารถส่งต่อไฟล์ไปยังแอปได้ + ไม่มีไฟล์ถูกเลือกไว้ ไม่เลย ลดภาพซ้อนบนจอแสดงผล E-Ink สำรองข้อมูลอัตโนมัติครั้งล่าสุด: %s แฟลชสีขาวเมื่อเปลี่ยนหน้า การใช้พื้นที่เก็บข้อมูล ข้อมูลและการจัดเก็บข้อมูล + สร้าง + นำไปใช้ + ย้อนกลับไปเป็นค่าเริ่มต้น + ไม่พบผู้แปล + ผู้แปล + คะแนนจากตัวติดตาม + ผู้แปลที่เว้นไว้ \ No newline at end of file diff --git a/i18n/src/main/res/values-tr/strings.xml b/i18n/src/main/res/values-tr/strings.xml index 0fc6713e0..df630c2b9 100644 --- a/i18n/src/main/res/values-tr/strings.xml +++ b/i18n/src/main/res/values-tr/strings.xml @@ -162,8 +162,8 @@ Yedeği geri yükle Kitaplığı yedek dosyasından geri yükle Yedekleme konumu - Yedekleme sıklığı - Maksimum yedek + Kendiliğinden yedekleme sıklığı + En fazla kendiliğinden yedek Yedek oluşturuldu Geri yükleme tamamlandı Neyi yedeklemek istiyorsunuz? @@ -375,7 +375,7 @@ Daha az Daha fazla Web sitesi - Web Görünümü, uygulamanın işlevselliği için gereklidir + WebView, uygulamanın işlevselliği için gereklidir Açık kaynak lisansları Yalnızca indirilen Böl. %1$s - %2$s @@ -434,7 +434,7 @@ %1$s bölüm Etkili olması için uygulamanın yeniden başlatılmasını gerektirir - + Ağ oluşturma Yok Dokunma bölgelerini ters çevir İkisi de @@ -697,7 +697,7 @@ Depolama izinleri verilmedi Dizi güncelleme gerektirmediği için atlandı Ara… - Elle ve kendiliğinden yedeklemeler + Elle ve kendiliğinden yedeklemeler, depolama alanı Uygulama kilidi, güvenli ekran Çökme günlükleri dökümü, pil iyileştirmeleri Kategoriler, genel güncelleme, bölüm kaydırma @@ -806,7 +806,7 @@ %s verisine erişilemedi İzleyici girişi Kitaplık eşleşmesi tamamlandı - HTTP %d, siteyi Web Görünümünde denetle + HTTP %d, siteyi WebView\'de denetle Genel ağ bağlantısı yok Kitaplık eşleştiriliyor Aç: %s @@ -819,4 +819,16 @@ Uygulama ayarları Göreli zaman damgaları \"%1$s\" yerine \"%2$s + Asla + E-ink görüntülerinde gölgelenmeyi azaltır + Uygula + Varsayılana dön + En son şu tarihte kendi yedekledi: %s + Tareviriler bulunamadı + Tareviri + Sayfa değişiminde beyaz ışık çak + Depolama kullanımı + İzleyici notu + Veri ve depolama + Tarevirileri hariç tut \ No newline at end of file diff --git a/i18n/src/main/res/values-uk/strings.xml b/i18n/src/main/res/values-uk/strings.xml index ea3386d7d..64cbb567f 100644 --- a/i18n/src/main/res/values-uk/strings.xml +++ b/i18n/src/main/res/values-uk/strings.xml @@ -846,4 +846,11 @@ \"%1$s\" замість \"%2$s\" Налаштування джерела Налаштування застосунку + Застосувати + Повернути за замовчуванням + Сортувати категорії + Сканлейтор + Оцінка трекера + Дані та сховище + Ви хочете сортувати категорії алфавітно? \ No newline at end of file diff --git a/i18n/src/main/res/values-zh-rCN/strings.xml b/i18n/src/main/res/values-zh-rCN/strings.xml index 72c351e4c..37ce0c277 100644 --- a/i18n/src/main/res/values-zh-rCN/strings.xml +++ b/i18n/src/main/res/values-zh-rCN/strings.xml @@ -156,14 +156,14 @@ 倒数第四已读章节 倒数第五已读章节 自动下载新章节 - 平台 + 记录平台 创建备份 可用于还原当前书架数据 还原备份 从备份文件中还原 备份路径 - 备份频率 - 最大备份数 + 自动备份频率 + 最大自动备份数 已创建备份 还原完毕 需要备份什么? @@ -365,7 +365,7 @@ 条漫(页间有空隙) 反选 添加进度记录 - Tachiyomi 依赖于 WebView + app依赖WebView实现其功能 收起 展开 开源许可证 @@ -556,7 +556,7 @@ 青苹果 应用主题 为特定图源提供增强功能。作品在添加到书架时会自动同步进度。 - 增强平台 + 增强型记录平台 动态 后台活动 最低 @@ -589,7 +589,7 @@ 详细日志记录 警告 语言 - 你应该将备份数据保存到多个地方。 + 你应该将备份数据保存到多个地方。备份可能存有包括所有已存储密码在内的敏感数据;请谨慎分享。 大量更新会损害图源,并可能导致更新变慢、耗电增加。点击了解详情。 仅连接至 Wi-Fi 时 每 3 天 @@ -769,7 +769,7 @@ 删除已下载章节 自定义更新间隔 设定间隔 - 放弃\? 延迟 20+ 和 2个月 + 放弃?延迟 20+ 和 2个月 通过检查期 下次预期更新 每月更新(28天) @@ -781,7 +781,7 @@ 估计每个 设定更新为每 自定义间隔 - 跳过、今天预期没有新发布 + 跳过,因为预计今天没有新发布 有结果 正在同步书架 书架同步完成 @@ -800,7 +800,7 @@ 将作品移到底部 书架更新中…(%s) 是否按字母顺序对分类进行排序? - 文件选择器无法将文件恢复至应用 + 没有文件被选中 相对时间戳 以\"%1$s\" 表示 \"%2$s\" 从不 @@ -809,4 +809,11 @@ 切页时闪烁白屏 数据与存储 存储占用 + 创建 + 应用 + 恢复默认 + 未找到扫译者 + 扫译者 + 记录平台评分 + 排除的扫译者 \ No newline at end of file diff --git a/i18n/src/main/res/values-zh-rTW/strings.xml b/i18n/src/main/res/values-zh-rTW/strings.xml index 8a26a92e7..05de0e56a 100644 --- a/i18n/src/main/res/values-zh-rTW/strings.xml +++ b/i18n/src/main/res/values-zh-rTW/strings.xml @@ -400,7 +400,7 @@ %d 個類別 需要重新啟動應用程式以套用 - 網路設定 + 網路 全部 垂直 水平 @@ -639,7 +639,7 @@ 用以改善閱讀器效能 找不到第 %d 頁的檔案路徑 重設個別閱讀器設定 - 將所有作品的閱讀模式和螢幕方向恢復為預設值 + 將所有作品的閱讀模式和螢幕方向還原為預設值 已重設所有閱讀器設定 無法重設閱讀器設定 呃…尷尬了 @@ -802,11 +802,18 @@ 正在更新書櫃… (%s) 欲依照字母順序排列類別嗎? 來源設定 - 無法將選定的檔案傳回給應用程式 + 未選擇檔案 永不 減少電子墨水螢幕上的殘影 最後一次自動備份:%s 頁面轉換時閃白 資料與儲存空間 - 儲存空間佔用 + 儲存空間使用情形 + 歷程平台評分 + 套用 + 還原為預設值 + 沒有掃譯者 + 掃譯者 + 排除掃譯者 + 建立 \ No newline at end of file From 45d8411f98d831cd8c734089ea20a6ef06ef948f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduard=20Ereza=20Mart=C3=ADnez?= Date: Mon, 13 Nov 2023 04:26:09 +0100 Subject: [PATCH 7/7] Fix Catalan plurals manually (#10133) Co-authored-by: arkon --- i18n/src/main/res/values-ca/strings.xml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/i18n/src/main/res/values-ca/strings.xml b/i18n/src/main/res/values-ca/strings.xml index 2f2206d76..1751957c2 100644 --- a/i18n/src/main/res/values-ca/strings.xml +++ b/i18n/src/main/res/values-ca/strings.xml @@ -317,6 +317,7 @@ Mai Després d’%1$s minut + Després de %1$s minuts Després de %1$s minuts Mode discret @@ -329,6 +330,7 @@ Visualització %1$d capítol nou + %1$d capítols nous %1$d capítols nous Capítol %1$s @@ -336,6 +338,7 @@ Capítols %1$s Capítols %1$s i 1 més + Capítols %1$s i %2$d més Capítols %1$s i %2$d més Amaga el contingut de les notificacions @@ -347,6 +350,7 @@ Mostra sempre la transició de capítol Per a %d element + Per a %d elements Per a %d elements Menú @@ -356,6 +360,7 @@ Mou a sota de tot Hi ha una actualització d’una extensió + Hi ha actualitzacions de %d extensions Hi ha actualitzacions de %d extensions Actualitzacions d’extensions @@ -391,6 +396,7 @@ Filtra tots els elements de la vostra biblioteca En resta %1$s + En resten %1$s En resten %1$s Gris @@ -399,11 +405,13 @@ No s’ha pogut obrir la configuració del dispositiu Fet en %1$s amb %2$s error + Fet en %1$s amb %2$s errors Fet en %1$s amb %2$s errors Redueix les bandes de colors, però pot afectar el rendiment %d categoria + %d categories %d categories La sincronització és unidireccional per a actualitzar el progrés dels capítols als serveis de seguiment externs. Configureu el seguiment d’elements individuals al seu botó de seguiment. @@ -433,6 +441,7 @@ No s’ha trobat la font %1$s capítol + %1$s capítols %1$s capítols Estat desconegut @@ -451,6 +460,7 @@ Data d’incorporació %d servei de seguiment + %d serveis de seguiment %d serveis de seguiment No teniu cap origen fixat @@ -465,6 +475,7 @@ Això no evita que les extensions no oficials o possiblement mal etiquetades puguin mostrar contingut NSFW (+18) a l’aplicació. S’ha omès %d capítol. És possible que manqui a la font o que hagi estat filtrat + S’han omès %d capítols. És possible que manquin a la font o que hagin estat filtrats S’han omès %d capítols. És possible que manquin a la font o que hagin estat filtrats No s’ha trobat cap capítol @@ -563,6 +574,7 @@ Serveis de seguiment millorats Ahir + Fa %1$d dies Fa %1$d dies Avui @@ -692,6 +704,7 @@ S’ha produït un error inesperat al %s. Us suggerim que compartiu el registre d’errors al nostre canal d’assistència al Discord. El següent capítol no llegit + Els següents %d capítols no llegits Els següents %d capítols no llegits No s’han concedit permisos d’emmagatzematge @@ -750,6 +763,7 @@ *obligatori El següent capítol + Els següents %d capítols Els següents %d capítols La categoria és buida @@ -773,6 +787,7 @@ Rota les pàgines amples perquè s’ajustin a la pantalla Manca %1$s capítol + Manquen %1$s capítols Manquen %1$s capítols Informació de depuració @@ -781,6 +796,7 @@ Pròxima actualització prevista 1 dia + %d dies %d dies Obtén mensualment (28 dies)