From ca7391bbf3d49428f6321aa6baa03b0d2b5abff9 Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Tue, 7 May 2024 15:03:32 +0600 Subject: [PATCH 001/297] Fix search bar style --- .../main/java/eu/kanade/presentation/components/AppBar.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/components/AppBar.kt b/app/src/main/java/eu/kanade/presentation/components/AppBar.kt index e7338c13e..01dcb575c 100644 --- a/app/src/main/java/eu/kanade/presentation/components/AppBar.kt +++ b/app/src/main/java/eu/kanade/presentation/components/AppBar.kt @@ -8,7 +8,6 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions -import androidx.compose.material.TextFieldDefaults import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.outlined.ArrowBack import androidx.compose.material.icons.outlined.Close @@ -21,6 +20,7 @@ import androidx.compose.material3.LocalContentColor import androidx.compose.material3.MaterialTheme import androidx.compose.material3.PlainTooltip import androidx.compose.material3.Text +import androidx.compose.material3.TextFieldDefaults import androidx.compose.material3.TooltipBox import androidx.compose.material3.TooltipDefaults import androidx.compose.material3.TopAppBar @@ -312,7 +312,7 @@ fun SearchToolbar( visualTransformation = visualTransformation, interactionSource = interactionSource, decorationBox = { innerTextField -> - TextFieldDefaults.TextFieldDecorationBox( + TextFieldDefaults.DecorationBox( value = searchQuery, innerTextField = innerTextField, enabled = true, @@ -331,6 +331,7 @@ fun SearchToolbar( ), ) }, + container = {}, ) }, ) From 1df87eabf2b301cf6fc60cfa5f9391756984b790 Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Sun, 5 May 2024 01:53:45 +0600 Subject: [PATCH 002/297] Use new SurfaceContainer color roles Non-dynamic themes need to be updated Co-authored-by: Ivan Iskandar <12537387+ivaniskandar@users.noreply.github.com> --- .../eu/kanade/presentation/components/AdaptiveSheet.kt | 6 ------ .../java/eu/kanade/presentation/components/TabbedDialog.kt | 1 + .../presentation/manga/components/MangaBottomActionMenu.kt | 4 ++-- .../more/settings/widget/AppThemePreferenceWidget.kt | 3 +-- .../kanade/presentation/reader/ReaderPageActionsDialog.kt | 4 +--- .../eu/kanade/presentation/track/TrackInfoDialogHome.kt | 2 +- .../ui/browse/source/browse/SourceFilterDialog.kt | 4 +--- .../presentation/core/components/AdaptiveSheet.kt | 6 ++---- .../java/tachiyomi/presentation/core/components/Pill.kt | 7 ++----- .../presentation/core/components/material/Button.kt | 2 -- 10 files changed, 11 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/components/AdaptiveSheet.kt b/app/src/main/java/eu/kanade/presentation/components/AdaptiveSheet.kt index 2712d9a27..15d05a6ec 100644 --- a/app/src/main/java/eu/kanade/presentation/components/AdaptiveSheet.kt +++ b/app/src/main/java/eu/kanade/presentation/components/AdaptiveSheet.kt @@ -7,8 +7,6 @@ import androidx.compose.animation.fadeOut import androidx.compose.animation.togetherWith import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import cafe.adriel.voyager.core.annotation.InternalVoyagerApi @@ -23,7 +21,6 @@ import tachiyomi.presentation.core.components.AdaptiveSheet as AdaptiveSheetImpl @Composable fun NavigatorAdaptiveSheet( screen: Screen, - tonalElevation: Dp = 1.dp, enableSwipeDismiss: (Navigator) -> Boolean = { true }, onDismissRequest: () -> Unit, ) { @@ -31,7 +28,6 @@ fun NavigatorAdaptiveSheet( screen = screen, content = { sheetNavigator -> AdaptiveSheet( - tonalElevation = tonalElevation, enableSwipeDismiss = enableSwipeDismiss(sheetNavigator), onDismissRequest = onDismissRequest, ) { @@ -73,7 +69,6 @@ fun NavigatorAdaptiveSheet( fun AdaptiveSheet( onDismissRequest: () -> Unit, modifier: Modifier = Modifier, - tonalElevation: Dp = 1.dp, enableSwipeDismiss: Boolean = true, content: @Composable () -> Unit, ) { @@ -86,7 +81,6 @@ fun AdaptiveSheet( AdaptiveSheetImpl( modifier = modifier, isTabletUi = isTabletUi, - tonalElevation = tonalElevation, enableSwipeDismiss = enableSwipeDismiss, onDismissRequest = onDismissRequest, ) { diff --git a/app/src/main/java/eu/kanade/presentation/components/TabbedDialog.kt b/app/src/main/java/eu/kanade/presentation/components/TabbedDialog.kt index 4ef2e9771..b651060f7 100644 --- a/app/src/main/java/eu/kanade/presentation/components/TabbedDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/components/TabbedDialog.kt @@ -58,6 +58,7 @@ fun TabbedDialog( PrimaryTabRow( modifier = Modifier.weight(1f), selectedTabIndex = pagerState.currentPage, + containerColor = MaterialTheme.colorScheme.surfaceContainerHigh, divider = {}, ) { tabTitles.fastForEachIndexed { index, tab -> diff --git a/app/src/main/java/eu/kanade/presentation/manga/components/MangaBottomActionMenu.kt b/app/src/main/java/eu/kanade/presentation/manga/components/MangaBottomActionMenu.kt index a78383590..93b8c1843 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/components/MangaBottomActionMenu.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/components/MangaBottomActionMenu.kt @@ -81,7 +81,7 @@ fun MangaBottomActionMenu( Surface( modifier = modifier, shape = MaterialTheme.shapes.large.copy(bottomEnd = ZeroCornerSize, bottomStart = ZeroCornerSize), - tonalElevation = 3.dp, + color = MaterialTheme.colorScheme.surfaceContainerHigh, ) { val haptic = LocalHapticFeedback.current val confirm = remember { mutableStateListOf(false, false, false, false, false, false, false) } @@ -237,7 +237,7 @@ fun LibraryBottomActionMenu( Surface( modifier = modifier, shape = MaterialTheme.shapes.large.copy(bottomEnd = ZeroCornerSize, bottomStart = ZeroCornerSize), - tonalElevation = 3.dp, + color = MaterialTheme.colorScheme.surfaceContainerHigh, ) { val haptic = LocalHapticFeedback.current val confirm = remember { mutableStateListOf(false, false, false, false, false) } diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/widget/AppThemePreferenceWidget.kt b/app/src/main/java/eu/kanade/presentation/more/settings/widget/AppThemePreferenceWidget.kt index db0842d08..5e3f76efe 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/widget/AppThemePreferenceWidget.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/widget/AppThemePreferenceWidget.kt @@ -223,13 +223,12 @@ fun AppThemePreviewItem( contentAlignment = Alignment.BottomCenter, ) { Surface( - tonalElevation = 3.dp, + color = MaterialTheme.colorScheme.surfaceContainer, ) { Row( modifier = Modifier .height(32.dp) .fillMaxWidth() - .background(MaterialTheme.colorScheme.surfaceVariant) .padding(horizontal = 8.dp), verticalAlignment = Alignment.CenterVertically, ) { diff --git a/app/src/main/java/eu/kanade/presentation/reader/ReaderPageActionsDialog.kt b/app/src/main/java/eu/kanade/presentation/reader/ReaderPageActionsDialog.kt index 70cc58f20..b83e8d6ad 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/ReaderPageActionsDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/ReaderPageActionsDialog.kt @@ -33,9 +33,7 @@ fun ReaderPageActionsDialog( ) { var showSetCoverDialog by remember { mutableStateOf(false) } - AdaptiveSheet( - onDismissRequest = onDismissRequest, - ) { + AdaptiveSheet(onDismissRequest = onDismissRequest) { Row( modifier = Modifier.padding(vertical = 16.dp), horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small), diff --git a/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHome.kt b/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHome.kt index 993532180..7ed6b3cc0 100644 --- a/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHome.kt +++ b/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHome.kt @@ -186,7 +186,7 @@ private fun TrackInfoItem( modifier = Modifier .padding(top = 12.dp) .clip(MaterialTheme.shapes.medium) - .background(MaterialTheme.colorScheme.surface) + .background(MaterialTheme.colorScheme.surfaceContainerHighest) .padding(8.dp) .clip(RoundedCornerShape(6.dp)), ) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/SourceFilterDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/SourceFilterDialog.kt index 017af7479..42355c504 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/SourceFilterDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/SourceFilterDialog.kt @@ -40,9 +40,7 @@ fun SourceFilterDialog( ) { val updateFilters = { onUpdate(filters) } - AdaptiveSheet( - onDismissRequest = onDismissRequest, - ) { + AdaptiveSheet(onDismissRequest = onDismissRequest) { LazyColumn { stickyHeader { Row( 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 54d2ad700..bb9ed8e85 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 @@ -38,7 +38,6 @@ import androidx.compose.ui.input.nestedscroll.NestedScrollSource import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.Velocity import androidx.compose.ui.unit.dp @@ -53,7 +52,6 @@ private val sheetAnimationSpec = tween(durationMillis = 350) @Composable fun AdaptiveSheet( isTabletUi: Boolean, - tonalElevation: Dp, enableSwipeDismiss: Boolean, onDismissRequest: () -> Unit, modifier: Modifier = Modifier, @@ -97,7 +95,7 @@ fun AdaptiveSheet( .padding(vertical = 16.dp) .then(modifier), shape = MaterialTheme.shapes.extraLarge, - tonalElevation = tonalElevation, + color = MaterialTheme.colorScheme.surfaceContainerHigh, content = { BackHandler(enabled = alpha > 0f, onBack = internalOnDismissRequest) content() @@ -180,7 +178,7 @@ fun AdaptiveSheet( .navigationBarsPadding() .statusBarsPadding(), shape = MaterialTheme.shapes.extraLarge, - tonalElevation = tonalElevation, + color = MaterialTheme.colorScheme.surfaceContainerHigh, content = { BackHandler( enabled = anchoredDraggableState.targetValue == 0, diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/Pill.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/Pill.kt index 4389fb482..1d8cf2d5f 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/Pill.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/Pill.kt @@ -10,7 +10,6 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.TextUnit import androidx.compose.ui.unit.dp @@ -18,9 +17,8 @@ import androidx.compose.ui.unit.dp fun Pill( text: String, modifier: Modifier = Modifier, - color: Color = MaterialTheme.colorScheme.background, - contentColor: Color = MaterialTheme.colorScheme.onBackground, - elevation: Dp = 1.dp, + color: Color = MaterialTheme.colorScheme.surfaceContainerHigh, + contentColor: Color = MaterialTheme.colorScheme.onSurface, fontSize: TextUnit = LocalTextStyle.current.fontSize, ) { Surface( @@ -29,7 +27,6 @@ fun Pill( shape = MaterialTheme.shapes.extraLarge, color = color, contentColor = contentColor, - tonalElevation = elevation, ) { Box( modifier = Modifier diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Button.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Button.kt index 6a645ed6a..5e65c89a2 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Button.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Button.kt @@ -100,7 +100,6 @@ fun Button( val containerColor = colors.containerColor(enabled).value val contentColor = colors.contentColor(enabled).value val shadowElevation = elevation?.shadowElevation(enabled, interactionSource)?.value ?: 0.dp - val tonalElevation = elevation?.tonalElevation(enabled, interactionSource)?.value ?: 0.dp Surface( onClick = onClick, @@ -109,7 +108,6 @@ fun Button( shape = shape, color = containerColor, contentColor = contentColor, - tonalElevation = tonalElevation, shadowElevation = shadowElevation, border = border, interactionSource = interactionSource, From 8e9396a9cfe5f5e87e4e5f2093421a3fa24d43db Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Tue, 7 May 2024 17:13:43 +0800 Subject: [PATCH 003/297] Fix tap control area shifting after zooming out (#767) --- .../tachiyomi/ui/reader/viewer/webtoon/WebtoonRecyclerView.kt | 3 ++- .../kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonRecyclerView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonRecyclerView.kt index 20c18c622..fe232fe87 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonRecyclerView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonRecyclerView.kt @@ -28,7 +28,8 @@ class WebtoonRecyclerView @JvmOverloads constructor( private var atFirstPosition = false private var halfWidth = 0 private var halfHeight = 0 - private var originalHeight = 0 + var originalHeight = 0 + private set private var heightSet = false private var firstVisibleItemPosition = 0 private var lastVisibleItemPosition = 0 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt index 1e370a8c7..a965631fc 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt @@ -117,7 +117,7 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr recycler.getLocationInWindow(viewPositionRelativeToWindow) val pos = PointF( (event.rawX - viewPosition[0] + viewPositionRelativeToWindow[0]) / recycler.width, - (event.rawY - viewPosition[1] + viewPositionRelativeToWindow[1]) / recycler.height, + (event.rawY - viewPosition[1] + viewPositionRelativeToWindow[1]) / recycler.originalHeight, ) when (config.navigator.getAction(pos)) { NavigationRegion.MENU -> activity.toggleMenu() From fb9423028eb017c110cb805f2d0601e5b02e50f9 Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Tue, 7 May 2024 15:53:26 +0600 Subject: [PATCH 004/297] Remove dependency on compose material 2 components --- app/build.gradle.kts | 1 - gradle/compose.versions.toml | 3 --- presentation-core/build.gradle.kts | 1 - .../presentation/core/components/SettingsItems.kt | 7 ++++--- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 5a16ab034..f7f9a78a3 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -151,7 +151,6 @@ dependencies { implementation(compose.activity) implementation(compose.foundation) implementation(compose.material3.core) - implementation(compose.material.core) implementation(compose.material.icons) implementation(compose.animation) implementation(compose.animation.graphics) diff --git a/gradle/compose.versions.toml b/gradle/compose.versions.toml index 1249e384f..77a87adf1 100644 --- a/gradle/compose.versions.toml +++ b/gradle/compose.versions.toml @@ -18,9 +18,6 @@ ui-util = { module = "androidx.compose.ui:ui-util" } material3-core = { module = "androidx.compose.material3:material3" } 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-systemuicontroller = { module = "com.google.accompanist:accompanist-systemuicontroller", version.ref = "accompanist" } diff --git a/presentation-core/build.gradle.kts b/presentation-core/build.gradle.kts index c7b64ad42..8fca92019 100644 --- a/presentation-core/build.gradle.kts +++ b/presentation-core/build.gradle.kts @@ -21,7 +21,6 @@ dependencies { implementation(compose.activity) implementation(compose.foundation) implementation(compose.material3.core) - implementation(compose.material.core) implementation(compose.material.icons) implementation(compose.animation) implementation(compose.animation.graphics) 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 abdf61c9f..4fd4b7571 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 @@ -14,7 +14,6 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.LazyGridScope import androidx.compose.foundation.lazy.grid.LazyVerticalGrid -import androidx.compose.material.ContentAlpha import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowDownward import androidx.compose.material.icons.filled.ArrowUpward @@ -56,6 +55,8 @@ object SettingsItemsPaddings { val Vertical = 10.dp } +private const val DisabledContentAlpha = 0.38f + @Composable fun HeadingItem(labelRes: StringResource) { HeadingItem(stringResource(labelRes)) @@ -278,7 +279,7 @@ fun TriStateItem( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.large), ) { - val stateAlpha = if (enabled && onClick != null) 1f else ContentAlpha.disabled + val stateAlpha = if (enabled && onClick != null) 1f else DisabledContentAlpha Icon( imageVector = when (state) { @@ -291,7 +292,7 @@ fun TriStateItem( MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = stateAlpha) } else { when (onClick) { - null -> MaterialTheme.colorScheme.onSurface.copy(alpha = ContentAlpha.disabled) + null -> MaterialTheme.colorScheme.onSurface.copy(alpha = DisabledContentAlpha) else -> MaterialTheme.colorScheme.primary } }, From 5955c9c3116c4d40e448c708a32057c6fd697fc4 Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Wed, 8 May 2024 23:06:35 +0600 Subject: [PATCH 005/297] Update project icon --- .idea/icon.png | Bin 26887 -> 63677 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/.idea/icon.png b/.idea/icon.png index cd287a6c46643f4747b4039cd86e0a551bd78860..465a5c55e8aa80f63d0fa72742100a91a9db72f0 100644 GIT binary patch literal 63677 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 RA_u@c>dHDw)e5%Z{|7!{J!}8~ literal 26887 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 Date: Fri, 10 May 2024 12:52:05 +0600 Subject: [PATCH 006/297] chore(deps): update actions/checkout action to v4.1.5 (#771) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/build_pull_request.yml | 2 +- .github/workflows/build_push.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_pull_request.yml b/.github/workflows/build_pull_request.yml index be47b2425..d9942cf0a 100644 --- a/.github/workflows/build_pull_request.yml +++ b/.github/workflows/build_pull_request.yml @@ -20,7 +20,7 @@ jobs: steps: - name: Clone repo - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5 - name: Validate Gradle Wrapper uses: gradle/wrapper-validation-action@216d1ad2b3710bf005dc39237337b9673fd8fcd5 # v3.3.2 diff --git a/.github/workflows/build_push.yml b/.github/workflows/build_push.yml index 0686e1889..e2ee5a7aa 100644 --- a/.github/workflows/build_push.yml +++ b/.github/workflows/build_push.yml @@ -17,7 +17,7 @@ jobs: steps: - name: Clone repo - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5 - name: Validate Gradle Wrapper uses: gradle/wrapper-validation-action@216d1ad2b3710bf005dc39237337b9673fd8fcd5 # v3.3.2 From aebb86794aa6391335cc8a4ab61bce2b9141ac1e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 10 May 2024 12:52:18 +0600 Subject: [PATCH 007/297] chore(deps): update softprops/action-gh-release action to v2.0.5 (#773) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/build_push.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_push.yml b/.github/workflows/build_push.yml index e2ee5a7aa..246f6e37c 100644 --- a/.github/workflows/build_push.yml +++ b/.github/workflows/build_push.yml @@ -83,7 +83,7 @@ jobs: - name: Create Release if: startsWith(github.ref, 'refs/tags/') && github.repository == 'mihonapp/mihon' - uses: softprops/action-gh-release@9d7c94cfd0a1f3ed45544c887983e9fa900f0564 # v2.0.4 + uses: softprops/action-gh-release@69320dbe05506a9a39fc8ae11030b214ec2d1f87 # v2.0.5 with: tag_name: ${{ env.VERSION_TAG }} name: Mihon ${{ env.VERSION_TAG }} From d3306e8cfe9e3e373a9fd688bdcd0d91fc5f4277 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 10 May 2024 12:52:40 +0600 Subject: [PATCH 008/297] fix(deps): update dependency io.kotest:kotest-assertions-core to v5.9.0 (#774) 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 b6776f997..1c287986e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -91,7 +91,7 @@ sqldelight-dialects-sql = { module = "app.cash.sqldelight:sqlite-3-38-dialect", sqldelight-gradle = { module = "app.cash.sqldelight:gradle-plugin", version.ref = "sqldelight" } junit = "org.junit.jupiter:junit-jupiter:5.10.2" -kotest-assertions = "io.kotest:kotest-assertions-core:5.8.1" +kotest-assertions = "io.kotest:kotest-assertions-core:5.9.0" mockk = "io.mockk:mockk:1.13.10" voyager-navigator = { module = "cafe.adriel.voyager:voyager-navigator", version.ref = "voyager" } From ab546e08843bc71ec059c5dd44031116fdac781f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 10 May 2024 20:25:59 +0600 Subject: [PATCH 009/297] fix(deps): update dependency org.jetbrains.kotlinx:kotlinx-coroutines-bom to v1.8.1 (#778) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/kotlinx.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/kotlinx.versions.toml b/gradle/kotlinx.versions.toml index 4c8871cd9..f86682ec5 100644 --- a/gradle/kotlinx.versions.toml +++ b/gradle/kotlinx.versions.toml @@ -9,7 +9,7 @@ gradle = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = " immutables = { module = "org.jetbrains.kotlinx:kotlinx-collections-immutable", version = "0.3.7" } -coroutines-bom = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-bom", version = "1.8.0" } +coroutines-bom = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-bom", version = "1.8.1" } coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core" } coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android" } coroutines-guava = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-guava" } From f603db3f3fac72954997bfa0c2cd77a0b92cd7f0 Mon Sep 17 00:00:00 2001 From: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com> Date: Sat, 11 May 2024 14:15:02 +0500 Subject: [PATCH 010/297] update r8 rules for `MultipartBody.Builder` in extensions (#783) --- app/proguard-rules.pro | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index c6471bea7..f4451efda 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -44,6 +44,10 @@ -dontnote rx.internal.util.PlatformDependent ##---------------End: proguard configuration for RxJava 1.x ---------- +##---------------Begin: proguard configuration for okhttp ---------- +-keepclasseswithmembers class okhttp3.MultipartBody$Builder { *; } +##---------------End: proguard configuration for okhttp ---------- + ##---------------Begin: proguard configuration for kotlinx.serialization ---------- -keepattributes *Annotation*, InnerClasses -dontnote kotlinx.serialization.** # core serialization annotations From 16392adcbba4027cbed0a44e2fc62df330af6385 Mon Sep 17 00:00:00 2001 From: CrepeTF <70870719+CrepeTF@users.noreply.github.com> Date: Mon, 13 May 2024 21:44:40 +0100 Subject: [PATCH 011/297] Update themes to follow new compose update changes (#766) * Update Green Apple theme * Add some Green Apple theme comments * Update Lavender theme * Update Midnight Dusk theme * Update Nord theme * Update Strawberry Daiquiri theme * Update Tako theme * Update Teal & Turquoise theme * Update Lavender secondaryContainer and onSecondaryContainer colour * Update M.Dusk secondaryContainer and onSecondaryContainer colour * Update Tako secondaryContainer and onSecondaryContainer colour * Comments * Update Tidal Wave theme * Update Yin Yang theme * Update Yotsuba theme * Fix navbar tinted background on pure black * Add surfaceContainer levels to Lavender theme * Resolve detekt issues * Add surfaceContainer levels to Midnight Dusk theme * Add surfaceContainer levels to Nord theme * Add surfaceContainer levels to Tako theme * Add surfaceContainer levels to Teal & Turquoise theme * Add surfaceContainer levels to Tidal Wave theme * Add surfaceContainer levels to Yin Yang theme * Add surfaceContainer levels to Yotsuba theme * Add dark theme surfaceContainer levels to Yotsuba theme * surfaceContainer tweaks to Yotsuba theme * surfaceContainer tweaks to Strawberry Daiquiri theme * surfaceContainer tweaks to Nord theme * surfaceContainer tweaks to Lavender theme * Update Tachiyomi theme * Update Pure Black theme * Resolve detekt issues * Oopsie --- .../theme/colorscheme/BaseColorScheme.kt | 12 ++ .../colorscheme/GreenAppleColorScheme.kt | 110 +++++++++++------- .../theme/colorscheme/LavenderColorScheme.kt | 102 +++++++++------- .../colorscheme/MidnightDuskColorScheme.kt | 38 +++--- .../theme/colorscheme/NordColorScheme.kt | 40 ++++--- .../colorscheme/StrawberryColorScheme.kt | 110 +++++++++++------- .../theme/colorscheme/TachiyomiColorScheme.kt | 38 +++--- .../theme/colorscheme/TakoColorScheme.kt | 38 +++--- .../colorscheme/TealTurqoiseColorScheme.kt | 38 +++--- .../theme/colorscheme/TidalWaveColorScheme.kt | 38 +++--- .../theme/colorscheme/YinYangColorScheme.kt | 38 +++--- .../theme/colorscheme/YotsubaColorScheme.kt | 38 +++--- 12 files changed, 402 insertions(+), 238 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/BaseColorScheme.kt b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/BaseColorScheme.kt index 97455fd9e..22dd9a0a7 100644 --- a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/BaseColorScheme.kt +++ b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/BaseColorScheme.kt @@ -8,6 +8,12 @@ internal abstract class BaseColorScheme { abstract val darkScheme: ColorScheme abstract val lightScheme: ColorScheme + // Cannot be pure black as there's content scrolling behind it + // https://m3.material.io/components/navigation-bar/guidelines#90615a71-607e-485e-9e09-778bfc080563 + private val surfaceContainer = Color(0xFF0C0C0C) + private val surfaceContainerHigh = Color(0xFF131313) + private val surfaceContainerHighest = Color(0xFF1B1B1B) + fun getColorScheme(isDark: Boolean, isAmoled: Boolean): ColorScheme { if (!isDark) return lightScheme @@ -18,6 +24,12 @@ internal abstract class BaseColorScheme { onBackground = Color.White, surface = Color.Black, onSurface = Color.White, + surfaceVariant = surfaceContainer, // Navigation bar background (ThemePrefWidget) + surfaceContainerLowest = surfaceContainer, + surfaceContainerLow = surfaceContainer, + surfaceContainer = surfaceContainer, // Navigation bar background + surfaceContainerHigh = surfaceContainerHigh, + surfaceContainerHighest = surfaceContainerHighest, ) } } diff --git a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/GreenAppleColorScheme.kt b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/GreenAppleColorScheme.kt index 354faed5f..566cce91b 100644 --- a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/GreenAppleColorScheme.kt +++ b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/GreenAppleColorScheme.kt @@ -19,53 +19,77 @@ internal object GreenAppleColorScheme : BaseColorScheme() { override val darkScheme = darkColorScheme( primary = Color(0xFF7ADB8F), - onPrimary = Color(0xFF003915), - primaryContainer = Color(0xFF005322), - onPrimaryContainer = Color(0xFF96F8A9), - inversePrimary = Color(0xFF006D2F), - secondary = Color(0xFF7ADB8F), - onSecondary = Color(0xFF003915), - secondaryContainer = Color(0xFF005322), - onSecondaryContainer = Color(0xFF96F8A9), - tertiary = Color(0xFFFFB3AA), - onTertiary = Color(0xFF680006), - tertiaryContainer = Color(0xFF93000D), - onTertiaryContainer = Color(0xFFFFDAD5), - background = Color(0xFF1A1C19), - onBackground = Color(0xFFE1E3DD), - surface = Color(0xFF1A1C19), - onSurface = Color(0xFFE1E3DD), - surfaceVariant = Color(0xFF414941), - onSurfaceVariant = Color(0xFFC1C8BE), - surfaceTint = Color(0xFF7ADB8F), - inverseSurface = Color(0xFFE1E3DD), - inverseOnSurface = Color(0xFF1A1C19), - outline = Color(0xFF8B9389), + onPrimary = Color(0xFF003917), + primaryContainer = Color(0xFF017737), + onPrimaryContainer = Color(0xFFFFFFFF), + secondary = Color(0xFF7ADB8F), // Unread badge + onSecondary = Color(0xFF003917), // Unread badge text + secondaryContainer = Color(0xFF017737), // Navigation bar selector pill & progress indicator (remaining) + onSecondaryContainer = Color(0xFFFFFFFF), // Navigation bar selected icon + tertiary = Color(0xFFFFB3AC), // Downloaded badge + onTertiary = Color(0xFF680008), // Downloaded badge text + tertiaryContainer = Color(0xFFC7282A), + onTertiaryContainer = Color(0xFFFFFFFF), + error = Color(0xFFFFB4AB), + onError = Color(0xFF690005), + errorContainer = Color(0xFF93000A), + onErrorContainer = Color(0xFFFFDAD6), + background = Color(0xFF0F1510), + onBackground = Color(0xFFDFE4DB), + surface = Color(0xFF0F1510), + onSurface = Color(0xFFDFE4DB), + surfaceVariant = Color(0xFF3F493F), // Navigation bar background (ThemePrefWidget) + onSurfaceVariant = Color(0xFFBECABC), + outline = Color(0xFF889487), + outlineVariant = Color(0xFF3F493F), + scrim = Color(0xFF000000), + inverseSurface = Color(0xFFDFE4DB), + inverseOnSurface = Color(0xFF2C322C), + inversePrimary = Color(0xFF006D32), + surfaceDim = Color(0xFF0F1510), + surfaceBright = Color(0xFF353B35), + surfaceContainerLowest = Color(0xFF0A0F0B), + surfaceContainerLow = Color(0xFF181D18), + surfaceContainer = Color(0xFF1C211C), // Navigation bar background + surfaceContainerHigh = Color(0xFF262B26), + surfaceContainerHighest = Color(0xFF313630), ) override val lightScheme = lightColorScheme( - primary = Color(0xFF006D2F), + primary = Color(0xFF005927), onPrimary = Color(0xFFFFFFFF), - primaryContainer = Color(0xFF96F8A9), - onPrimaryContainer = Color(0xFF002109), + primaryContainer = Color(0xFF188140), + onPrimaryContainer = Color(0xFFFFFFFF), + secondary = Color(0xFF005927), // Unread badge + onSecondary = Color(0xFFFFFFFF), // Unread badge text + secondaryContainer = Color(0xFF97f7a9), // Navigation bar selector pill & progress indicator (remaining) + onSecondaryContainer = Color(0xFF000000), // Navigation bar selected icon + tertiary = Color(0xFF9D0012), // Downloaded badge + onTertiary = Color(0xFFFFFFFF), // Downloaded badge text + tertiaryContainer = Color(0xFFD33131), + onTertiaryContainer = Color(0xFFFFFFFF), + error = Color(0xFFBA1A1A), + onError = Color(0xFFFFFFFF), + errorContainer = Color(0xFFFFDAD6), + onErrorContainer = Color(0xFF410002), + background = Color(0xFFF6FBF2), + onBackground = Color(0xFF181D18), + surface = Color(0xFFF6FBF2), + onSurface = Color(0xFF181D18), + surfaceVariant = Color(0xFFDAE6D7), // Navigation bar background (ThemePrefWidget) + onSurfaceVariant = Color(0xFF3F493F), + outline = Color(0xFF6F7A6E), + outlineVariant = Color(0xFFBECABC), + scrim = Color(0xFF000000), + inverseSurface = Color(0xFF2C322C), + inverseOnSurface = Color(0xFFEDF2E9), inversePrimary = Color(0xFF7ADB8F), - secondary = Color(0xFF006D2F), - onSecondary = Color(0xFFFFFFFF), - secondaryContainer = Color(0xFF96F8A9), - onSecondaryContainer = Color(0xFF002109), - tertiary = Color(0xFFB91D22), - onTertiary = Color(0xFFFFFFFF), - tertiaryContainer = Color(0xFFFFDAD5), - onTertiaryContainer = Color(0xFF410003), - background = Color(0xFFFBFDF7), - onBackground = Color(0xFF1A1C19), - surface = Color(0xFFFBFDF7), - onSurface = Color(0xFF1A1C19), - surfaceVariant = Color(0xFFDDE5DA), - onSurfaceVariant = Color(0xFF414941), - surfaceTint = Color(0xFF006D2F), - inverseSurface = Color(0xFF2F312E), - inverseOnSurface = Color(0xFFF0F2EC), - outline = Color(0xFF717970), + surfaceDim = Color(0xFFD6DCD3), + surfaceBright = Color(0xFFF6FBF2), + surfaceContainerLowest = Color(0xFFFFFFFF), + surfaceContainerLow = Color(0xFFF0F5EC), + surfaceContainer = Color(0xFFEAEFE6), // Navigation bar background + surfaceContainerHigh = Color(0xFFE4EAE1), + surfaceContainerHighest = Color(0xFFDFE4DB), ) } diff --git a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/LavenderColorScheme.kt b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/LavenderColorScheme.kt index 70a9bd196..e1bb6b3ee 100644 --- a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/LavenderColorScheme.kt +++ b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/LavenderColorScheme.kt @@ -18,53 +18,77 @@ internal object LavenderColorScheme : BaseColorScheme() { override val darkScheme = darkColorScheme( primary = Color(0xFFA177FF), - onPrimary = Color(0xFF111129), + onPrimary = Color(0xFF3D0090), primaryContainer = Color(0xFFA177FF), - onPrimaryContainer = Color(0xFF111129), - inversePrimary = Color(0xFF006D2F), - secondary = Color(0xFFA177FF), - onSecondary = Color(0xFF111129), - secondaryContainer = Color(0xFFA177FF), - onSecondaryContainer = Color(0xFF111129), - tertiary = Color(0xFF5E25E1), - onTertiary = Color(0xFFE8E8E8), - tertiaryContainer = Color(0xFF111129), - onTertiaryContainer = Color(0xFFDEE8FF), + onPrimaryContainer = Color(0xFFFFFFFF), + secondary = Color(0xFFA177FF), // Unread badge + onSecondary = Color(0xFFFFFFFF), // Unread badge text + secondaryContainer = Color(0xFF423271), // Navigation bar selector pill & progress indicator (remaining) + onSecondaryContainer = Color(0xFFA177FF), // Navigation bar selected icon + tertiary = Color(0xFFCDBDFF), // Downloaded badge + onTertiary = Color(0xFF360096), // Downloaded badge text + tertiaryContainer = Color(0xFF5512D8), + onTertiaryContainer = Color(0xFFEFE6FF), + error = Color(0xFFFFB4AB), + onError = Color(0xFF690005), + errorContainer = Color(0xFF93000A), + onErrorContainer = Color(0xFFFFDAD6), background = Color(0xFF111129), - onBackground = Color(0xFFDEE8FF), + onBackground = Color(0xFFE7E0EC), surface = Color(0xFF111129), - onSurface = Color(0xFFDEE8FF), - surfaceVariant = Color(0x2CB6B6B6), - onSurfaceVariant = Color(0xFFE8E8E8), - surfaceTint = Color(0xFFA177FF), - inverseSurface = Color(0xFF221247), - inverseOnSurface = Color(0xFFDEE8FF), - outline = Color(0xA8905FFF), + onSurface = Color(0xFFE7E0EC), + surfaceVariant = Color(0xFF3D2F6B), // Navigation bar background (ThemePrefWidget) + onSurfaceVariant = Color(0xFFCBC3D6), + outline = Color(0xFF958E9F), + outlineVariant = Color(0xFF4A4453), + scrim = Color(0xFF000000), + inverseSurface = Color(0xFFE7E0EC), + inverseOnSurface = Color(0xFF322F38), + inversePrimary = Color(0xFF6D41C8), + surfaceDim = Color(0xFF111129), + surfaceBright = Color(0xFF3B3841), + surfaceContainerLowest = Color(0xFF15132d), + surfaceContainerLow = Color(0xFF171531), + surfaceContainer = Color(0xFF1D193B), // Navigation bar background + surfaceContainerHigh = Color(0xFF241f41), + surfaceContainerHighest = Color(0xFF282446), ) override val lightScheme = lightColorScheme( - primary = Color(0xFF7B46AF), - onPrimary = Color(0xFFEDE2FF), + primary = Color(0xFF6D41C8), + onPrimary = Color(0xFFFFFFFF), primaryContainer = Color(0xFF7B46AF), - onPrimaryContainer = Color(0xFFEDE2FF), - inversePrimary = Color(0xFFD6BAFF), - secondary = Color(0xFF7B46AF), - onSecondary = Color(0xFFEDE2FF), - secondaryContainer = Color(0xFF7B46AF), - onSecondaryContainer = Color(0xFFEDE2FF), - tertiary = Color(0xFFEDE2FF), - onTertiary = Color(0xFF7B46AF), - tertiaryContainer = Color(0xFFEDE2FF), - onTertiaryContainer = Color(0xFF7B46AF), + onPrimaryContainer = Color(0xFF130038), + secondary = Color(0xFF7B46AF), // Unread badge + onSecondary = Color(0xFFEDE2FF), // Unread badge text + secondaryContainer = Color(0xFFC9B0E6), // Navigation bar selector pill & progress indicator (remaining) + onSecondaryContainer = Color(0xFF7B46AF), // Navigation bar selector icon + tertiary = Color(0xFFEDE2FF), // Downloaded badge + onTertiary = Color(0xFF7B46AF), // Downloaded badge text + tertiaryContainer = Color(0xFF6D3BF0), + onTertiaryContainer = Color(0xFFFFFFFF), + error = Color(0xFFBA1A1A), + onError = Color(0xFFFFFFFF), + errorContainer = Color(0xFFFFDAD6), + onErrorContainer = Color(0xFF410002), background = Color(0xFFEDE2FF), - onBackground = Color(0xFF1B1B22), + onBackground = Color(0xFF1D1A22), surface = Color(0xFFEDE2FF), - onSurface = Color(0xFF1B1B22), - surfaceVariant = Color(0xFFB9B0CC), - onSurfaceVariant = Color(0xD849454E), - surfaceTint = Color(0xFF7B46AF), - inverseSurface = Color(0xFF313033), - inverseOnSurface = Color(0xFFF3EFF4), - outline = Color(0xFF7B46AF), + onSurface = Color(0xFF1D1A22), + surfaceVariant = Color(0xFFE4D5F8), // Navigation bar background (ThemePrefWidget) + onSurfaceVariant = Color(0xFF4A4453), + outline = Color(0xFF7B7485), + outlineVariant = Color(0xFFCBC3D6), + scrim = Color(0xFF000000), + inverseSurface = Color(0xFF322F38), + inverseOnSurface = Color(0xFFF5EEFA), + inversePrimary = Color(0xFFA177FF), + surfaceDim = Color(0xFFDED7E3), + surfaceBright = Color(0xFFEDE2FF), + surfaceContainerLowest = Color(0xFFDACCEC), + surfaceContainerLow = Color(0xFFDED0F1), + surfaceContainer = Color(0xFFE4D5F8), // Navigation bar background + surfaceContainerHigh = Color(0xFFEADCFD), + surfaceContainerHighest = Color(0xFFEEE2FF), ) } diff --git a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/MidnightDuskColorScheme.kt b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/MidnightDuskColorScheme.kt index 7feaae333..5ae86aa34 100644 --- a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/MidnightDuskColorScheme.kt +++ b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/MidnightDuskColorScheme.kt @@ -23,24 +23,29 @@ internal object MidnightDuskColorScheme : BaseColorScheme() { primaryContainer = Color(0xFFBD1C5C), onPrimaryContainer = Color(0xFFFFFFFF), inversePrimary = Color(0xFFF02475), - secondary = Color(0xFFF02475), - onSecondary = Color(0xFFFFFFFF), - secondaryContainer = Color(0xFFF02475), - onSecondaryContainer = Color(0xFFFFFFFF), - tertiary = Color(0xFF55971C), - onTertiary = Color(0xFFFFFFFF), + secondary = Color(0xFFF02475), // Unread badge + onSecondary = Color(0xFF16151D), // Unread badge text + secondaryContainer = Color(0xFF66183C), // Navigation bar selector pill & progress indicator (remaining) + onSecondaryContainer = Color(0xFFF02475), // Navigation bar selector icon + tertiary = Color(0xFF55971C), // Downloaded badge + onTertiary = Color(0xFF16151D), // Downloaded badge text tertiaryContainer = Color(0xFF386412), onTertiaryContainer = Color(0xFFE5E1E5), background = Color(0xFF16151D), onBackground = Color(0xFFE5E1E5), surface = Color(0xFF16151D), onSurface = Color(0xFFE5E1E5), - surfaceVariant = Color(0xFF524346), + surfaceVariant = Color(0xFF281624), // Navigation bar background (ThemePrefWidget) onSurfaceVariant = Color(0xFFD6C1C4), surfaceTint = Color(0xFFF02475), inverseSurface = Color(0xFF333043), inverseOnSurface = Color(0xFFFFFFFF), outline = Color(0xFF9F8C8F), + surfaceContainerLowest = Color(0xFF221320), + surfaceContainerLow = Color(0xFF251522), + surfaceContainer = Color(0xFF281624), // Navigation bar background + surfaceContainerHigh = Color(0xFF2D1C2A), + surfaceContainerHighest = Color(0xFF2F1F2C), ) override val lightScheme = lightColorScheme( @@ -49,23 +54,28 @@ internal object MidnightDuskColorScheme : BaseColorScheme() { primaryContainer = Color(0xFFFFD9E1), onPrimaryContainer = Color(0xFF3F0017), inversePrimary = Color(0xFFFFB1C4), - secondary = Color(0xFFBB0054), - onSecondary = Color(0xFFFFFFFF), - secondaryContainer = Color(0xFFFFD9E1), - onSecondaryContainer = Color(0xFF3F0017), - tertiary = Color(0xFF006638), - onTertiary = Color(0xFFFFFFFF), + secondary = Color(0xFFBB0054), // Unread badge + onSecondary = Color(0xFFFFFFFF), // Unread badge text + secondaryContainer = Color(0xFFEFBAD4), // Navigation bar selector pill & progress indicator (remaining) + onSecondaryContainer = Color(0xFFD1377C), // Navigation bar selector icon + tertiary = Color(0xFF006638), // Downloaded badge + onTertiary = Color(0xFFFFFFFF), // Downloaded badge text tertiaryContainer = Color(0xFF00894b), onTertiaryContainer = Color(0xFF2D1600), background = Color(0xFFFFFBFF), onBackground = Color(0xFF1C1B1F), surface = Color(0xFFFFFBFF), onSurface = Color(0xFF1C1B1F), - surfaceVariant = Color(0xFFF3DDE0), + surfaceVariant = Color(0xFFF9E6F1), // Navigation bar background (ThemePrefWidget) onSurfaceVariant = Color(0xFF524346), surfaceTint = Color(0xFFBB0054), inverseSurface = Color(0xFF313033), inverseOnSurface = Color(0xFFF4F0F4), outline = Color(0xFF847376), + surfaceContainerLowest = Color(0xFFDAC0CD), + surfaceContainerLow = Color(0xFFE8D1DD), + surfaceContainer = Color(0xFFF9E6F1), // Navigation bar background + surfaceContainerHigh = Color(0xFFFCF3F8), + surfaceContainerHighest = Color(0xFFFEF9FC), ) } diff --git a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/NordColorScheme.kt b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/NordColorScheme.kt index d493e2d62..2e89b9ea4 100644 --- a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/NordColorScheme.kt +++ b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/NordColorScheme.kt @@ -17,19 +17,19 @@ internal object NordColorScheme : BaseColorScheme() { primaryContainer = Color(0xFF88C0D0), onPrimaryContainer = Color(0xFF2E3440), inversePrimary = Color(0xFF397E91), - secondary = Color(0xFF81A1C1), - onSecondary = Color(0xFF2E3440), - secondaryContainer = Color(0xFF81A1C1), - onSecondaryContainer = Color(0xFF2E3440), - tertiary = Color(0xFF5E81AC), - onTertiary = Color(0xFF000000), + secondary = Color(0xFF81A1C1), // Unread badge + onSecondary = Color(0xFF2E3440), // Unread badge text + secondaryContainer = Color(0xFF81A1C1), // Navigation bar selector pill & progress indicator (remaining) + onSecondaryContainer = Color(0xFF2E3440), // Navigation bar selector icon + tertiary = Color(0xFF5E81AC), // Downloaded badge + onTertiary = Color(0xFF000000), // Downloaded badge text tertiaryContainer = Color(0xFF5E81AC), onTertiaryContainer = Color(0xFF000000), background = Color(0xFF2E3440), onBackground = Color(0xFFECEFF4), - surface = Color(0xFF3B4252), + surface = Color(0xFF2E3440), onSurface = Color(0xFFECEFF4), - surfaceVariant = Color(0xFF2E3440), + surfaceVariant = Color(0xFF414C5C), // Navigation bar background (ThemePrefWidget) onSurfaceVariant = Color(0xFFECEFF4), surfaceTint = Color(0xFF88C0D0), inverseSurface = Color(0xFFD8DEE9), @@ -39,6 +39,11 @@ internal object NordColorScheme : BaseColorScheme() { onError = Color(0xFF2E3440), errorContainer = Color(0xFFBF616A), onErrorContainer = Color(0xFF000000), + surfaceContainerLowest = Color(0xFF373F4D), + surfaceContainerLow = Color(0xFF3E4756), + surfaceContainer = Color(0xFF414C5C), + surfaceContainerHigh = Color(0xFF4E5766), + surfaceContainerHighest = Color(0xFF505968), // Navigation bar background ) override val lightScheme = lightColorScheme( @@ -47,19 +52,19 @@ internal object NordColorScheme : BaseColorScheme() { primaryContainer = Color(0xFF5E81AC), onPrimaryContainer = Color(0xFF000000), inversePrimary = Color(0xFF8CA8CD), - secondary = Color(0xFF81A1C1), - onSecondary = Color(0xFF2E3440), - secondaryContainer = Color(0xFF81A1C1), - onSecondaryContainer = Color(0xFF2E3440), - tertiary = Color(0xFF88C0D0), - onTertiary = Color(0xFF2E3440), + secondary = Color(0xFF81A1C1), // Unread badge + onSecondary = Color(0xFF2E3440), // Unread badge text + secondaryContainer = Color(0xFF81A1C1), // Navigation bar selector pill & progress indicator (remaining) + onSecondaryContainer = Color(0xFF2E3440), // Navigation bar selector icon + tertiary = Color(0xFF88C0D0), // Downloaded badge + onTertiary = Color(0xFF2E3440), // Downloaded badge text tertiaryContainer = Color(0xFF88C0D0), onTertiaryContainer = Color(0xFF2E3440), background = Color(0xFFECEFF4), onBackground = Color(0xFF2E3440), surface = Color(0xFFE5E9F0), onSurface = Color(0xFF2E3440), - surfaceVariant = Color(0xFFffffff), + surfaceVariant = Color(0xFFDAE0EA), // Navigation bar background (ThemePrefWidget) onSurfaceVariant = Color(0xFF2E3440), surfaceTint = Color(0xFF5E81AC), inverseSurface = Color(0xFF3B4252), @@ -68,5 +73,10 @@ internal object NordColorScheme : BaseColorScheme() { onError = Color(0xFFECEFF4), errorContainer = Color(0xFFBF616A), onErrorContainer = Color(0xFF000000), + surfaceContainerLowest = Color(0xFFD1D7E0), + surfaceContainerLow = Color(0xFFD6DCE6), + surfaceContainer = Color(0xFFDAE0EA), // Navigation bar background + surfaceContainerHigh = Color(0xFFE9EDF3), + surfaceContainerHighest = Color(0xFFF2F4F8), ) } diff --git a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/StrawberryColorScheme.kt b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/StrawberryColorScheme.kt index 98417e336..e1b096e25 100644 --- a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/StrawberryColorScheme.kt +++ b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/StrawberryColorScheme.kt @@ -18,54 +18,78 @@ import androidx.compose.ui.graphics.Color internal object StrawberryColorScheme : BaseColorScheme() { override val darkScheme = darkColorScheme( - primary = Color(0xFFFFB2B9), - onPrimary = Color(0xFF67001B), - primaryContainer = Color(0xFF91002A), - onPrimaryContainer = Color(0xFFFFDADD), - inversePrimary = Color(0xFFB61E40), - secondary = Color(0xFFFFB2B9), - onSecondary = Color(0xFF67001B), - secondaryContainer = Color(0xFF91002A), - onSecondaryContainer = Color(0xFFFFDADD), - tertiary = Color(0xFFE8C08E), - onTertiary = Color(0xFF432C06), - tertiaryContainer = Color(0xFF5D421B), - onTertiaryContainer = Color(0xFFFFDDB1), + primary = Color(0xFFFFB2B8), + onPrimary = Color(0xFF67001D), + primaryContainer = Color(0xFFD53855), + onPrimaryContainer = Color(0xFFFFFFFF), + secondary = Color(0xFFED4A65), // Unread badge + onSecondary = Color(0xFF201A1A), // Unread badge text + secondaryContainer = Color(0xFF91002A), // Navigation bar selector pill & progress indicator (remaining) + onSecondaryContainer = Color(0xFFFFFFFF), // Navigation bar selector icon + tertiary = Color(0xFFE8C08E), // Downloaded badge + onTertiary = Color(0xFF201A1A), // Downloaded badge text + tertiaryContainer = Color(0xFF775930), + onTertiaryContainer = Color(0xFFFFF7F1), + error = Color(0xFFFFB4AB), + onError = Color(0xFF690005), + errorContainer = Color(0xFF93000A), + onErrorContainer = Color(0xFFFFDAD6), background = Color(0xFF201A1A), - onBackground = Color(0xFFECDFDF), + onBackground = Color(0xFFF7DCDD), surface = Color(0xFF201A1A), - onSurface = Color(0xFFECDFDF), - surfaceVariant = Color(0xFF534344), - onSurfaceVariant = Color(0xFFD7C1C2), - surfaceTint = Color(0xFFFFB2B9), - inverseSurface = Color(0xFFECDFDF), - inverseOnSurface = Color(0xFF201A1A), - outline = Color(0xFFA08C8D), + onSurface = Color(0xFFF7DCDD), + surfaceVariant = Color(0xFF322727), // Navigation bar background (ThemePrefWidget) + onSurfaceVariant = Color(0xFFE1BEC0), + outline = Color(0xFFA9898B), + outlineVariant = Color(0xFF594042), + scrim = Color(0xFF000000), + inverseSurface = Color(0xFFF7DCDD), + inverseOnSurface = Color(0xFF3D2C2D), + inversePrimary = Color(0xFFB61F40), + surfaceDim = Color(0xFF1D1011), + surfaceBright = Color(0xFF463536), + surfaceContainerLowest = Color(0xFF2C2222), + surfaceContainerLow = Color(0xFF302525), + surfaceContainer = Color(0xFF322727), // Navigation bar background + surfaceContainerHigh = Color(0xFF3C2F2F), + surfaceContainerHighest = Color(0xFF463737), ) override val lightScheme = lightColorScheme( - primary = Color(0xFFB61E40), + primary = Color(0xFFA10833), onPrimary = Color(0xFFFFFFFF), - primaryContainer = Color(0xFFFFDADD), - onPrimaryContainer = Color(0xFF40000D), - inversePrimary = Color(0xFFFFB2B9), - secondary = Color(0xFFB61E40), - onSecondary = Color(0xFFFFFFFF), - secondaryContainer = Color(0xFFFFDADD), - onSecondaryContainer = Color(0xFF40000D), - tertiary = Color(0xFF775930), - onTertiary = Color(0xFFFFFFFF), - tertiaryContainer = Color(0xFFFFDDB1), - onTertiaryContainer = Color(0xFF2A1800), - background = Color(0xFFFCFCFC), - onBackground = Color(0xFF201A1A), - surface = Color(0xFFFCFCFC), - onSurface = Color(0xFF201A1A), - surfaceVariant = Color(0xFFF4DDDD), - onSurfaceVariant = Color(0xFF534344), - surfaceTint = Color(0xFFB61E40), - inverseSurface = Color(0xFF362F2F), - inverseOnSurface = Color(0xFFFBEDED), - outline = Color(0xFF857374), + primaryContainer = Color(0xFFD53855), + onPrimaryContainer = Color(0xFFFFFFFF), + secondary = Color(0xFFA10833), // Unread badge + onSecondary = Color(0xFFFFFFFF), // Unread badge text + secondaryContainer = Color(0xFFD53855), // Navigation bar selector pill & progress indicator (remaining) + onSecondaryContainer = Color(0xFFF6EAED), // Navigation bar selector icon + tertiary = Color(0xFF5F441D), // Downloaded badge + onTertiary = Color(0xFFFFFFFF), // Downloaded badge text + tertiaryContainer = Color(0xFF87683D), + onTertiaryContainer = Color(0xFFFFFFFF), + error = Color(0xFFBA1A1A), + onError = Color(0xFFFFFFFF), + errorContainer = Color(0xFFFFDAD6), + onErrorContainer = Color(0xFF410002), + background = Color(0xFFFAFAFA), + onBackground = Color(0xFF261819), + surface = Color(0xFFFAFAFA), + onSurface = Color(0xFF261819), + surfaceVariant = Color(0xFFF6EAED), // Navigation bar background (ThemePrefWidget) + onSurfaceVariant = Color(0xFF594042), + outline = Color(0xFF8D7071), + outlineVariant = Color(0xFFE1BEC0), + scrim = Color(0xFF000000), + inverseSurface = Color(0xFF3D2C2D), + inverseOnSurface = Color(0xFFFFECED), + inversePrimary = Color(0xFFFFB2B8), + surfaceDim = Color(0xFFEED4D5), + surfaceBright = Color(0xFFFFF8F7), + surfaceContainerLowest = Color(0xFFF7DCDD), + surfaceContainerLow = Color(0xFFFDE2E3), + surfaceContainer = Color(0xFFF6EAED), // Navigation bar background + surfaceContainerHigh = Color(0xFFFFF0F0), + surfaceContainerHighest = Color(0xFFFFFFFF), ) } diff --git a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/TachiyomiColorScheme.kt b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/TachiyomiColorScheme.kt index 974d5f22d..5faeb7df0 100644 --- a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/TachiyomiColorScheme.kt +++ b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/TachiyomiColorScheme.kt @@ -22,19 +22,19 @@ internal object TachiyomiColorScheme : BaseColorScheme() { primaryContainer = Color(0xFF00429B), onPrimaryContainer = Color(0xFFD9E2FF), inversePrimary = Color(0xFF0058CA), - secondary = Color(0xFFB0C6FF), - onSecondary = Color(0xFF002D6E), - secondaryContainer = Color(0xFF00429B), - onSecondaryContainer = Color(0xFFD9E2FF), - tertiary = Color(0xFF7ADC77), - onTertiary = Color(0xFF003909), + secondary = Color(0xFFB0C6FF), // Unread badge + onSecondary = Color(0xFF002D6E), // Unread badge text + secondaryContainer = Color(0xFF00429B), // Navigation bar selector pill & pro + onSecondaryContainer = Color(0xFFD9E2FF), // Navigation bar selector icon + tertiary = Color(0xFF7ADC77), // Downloaded badge + onTertiary = Color(0xFF003909), // Downloaded badge text tertiaryContainer = Color(0xFF005312), onTertiaryContainer = Color(0xFF95F990), background = Color(0xFF1B1B1F), onBackground = Color(0xFFE3E2E6), surface = Color(0xFF1B1B1F), onSurface = Color(0xFFE3E2E6), - surfaceVariant = Color(0xFF44464F), + surfaceVariant = Color(0xFF211F26), // Navigation bar background (ThemePrefWidget) onSurfaceVariant = Color(0xFFC5C6D0), surfaceTint = Color(0xFFB0C6FF), inverseSurface = Color(0xFFE3E2E6), @@ -45,6 +45,11 @@ internal object TachiyomiColorScheme : BaseColorScheme() { onErrorContainer = Color(0xFFFFDAD6), outline = Color(0xFF8F9099), outlineVariant = Color(0xFF44464F), + surfaceContainerLowest = Color(0xFF1A181D), + surfaceContainerLow = Color(0xFF1E1C22), + surfaceContainer = Color(0xFF211F26), // Navigation bar background + surfaceContainerHigh = Color(0xFF292730), + surfaceContainerHighest = Color(0xFF302E38), ) override val lightScheme = lightColorScheme( @@ -53,19 +58,19 @@ internal object TachiyomiColorScheme : BaseColorScheme() { primaryContainer = Color(0xFFD9E2FF), onPrimaryContainer = Color(0xFF001945), inversePrimary = Color(0xFFB0C6FF), - secondary = Color(0xFF0058CA), - onSecondary = Color(0xFFFFFFFF), - secondaryContainer = Color(0xFFD9E2FF), - onSecondaryContainer = Color(0xFF001945), - tertiary = Color(0xFF006E1B), - onTertiary = Color(0xFFFFFFFF), + secondary = Color(0xFF0058CA), // Unread badge + onSecondary = Color(0xFFFFFFFF), // Unread badge text + secondaryContainer = Color(0xFFD9E2FF), // Navigation bar selector pill & progress indicator (remaining) + onSecondaryContainer = Color(0xFF001945), // Navigation bar selector icon + tertiary = Color(0xFF006E1B), // Downloaded badge + onTertiary = Color(0xFFFFFFFF), // Downloaded badge text tertiaryContainer = Color(0xFF95F990), onTertiaryContainer = Color(0xFF002203), background = Color(0xFFFEFBFF), onBackground = Color(0xFF1B1B1F), surface = Color(0xFFFEFBFF), onSurface = Color(0xFF1B1B1F), - surfaceVariant = Color(0xFFE1E2EC), + surfaceVariant = Color(0xFFF3EDF7), // Navigation bar background (ThemePrefWidget) onSurfaceVariant = Color(0xFF44464F), surfaceTint = Color(0xFF0058CA), inverseSurface = Color(0xFF303034), @@ -76,5 +81,10 @@ internal object TachiyomiColorScheme : BaseColorScheme() { onErrorContainer = Color(0xFF410002), outline = Color(0xFF757780), outlineVariant = Color(0xFFC5C6D0), + surfaceContainerLowest = Color(0xFFF5F1F8), + surfaceContainerLow = Color(0xFFF7F2FA), + surfaceContainer = Color(0xFFF3EDF7), // Navigation bar background + surfaceContainerHigh = Color(0xFFFCF7FF), + surfaceContainerHighest = Color(0xFFFCF7FF), ) } diff --git a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/TakoColorScheme.kt b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/TakoColorScheme.kt index 244e769d4..798812963 100644 --- a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/TakoColorScheme.kt +++ b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/TakoColorScheme.kt @@ -23,24 +23,29 @@ internal object TakoColorScheme : BaseColorScheme() { primaryContainer = Color(0xFFF3B375), onPrimaryContainer = Color(0xFF38294E), inversePrimary = Color(0xFF84531E), - secondary = Color(0xFFF3B375), - onSecondary = Color(0xFF38294E), - secondaryContainer = Color(0xFFF3B375), - onSecondaryContainer = Color(0xFF38294E), - tertiary = Color(0xFF66577E), - onTertiary = Color(0xFFF3B375), + secondary = Color(0xFFF3B375), // Unread badge + onSecondary = Color(0xFF38294E), // Unread badge text + secondaryContainer = Color(0xFF5C4D4B), // Navigation bar selector pill & progress indicator (remaining) + onSecondaryContainer = Color(0xFFF3B375), // Navigation bar selector icon + tertiary = Color(0xFF66577E), // Downloaded badge + onTertiary = Color(0xFFF3B375), // Downloaded badge text tertiaryContainer = Color(0xFF4E4065), onTertiaryContainer = Color(0xFFEDDCFF), background = Color(0xFF21212E), onBackground = Color(0xFFE3E0F2), surface = Color(0xFF21212E), onSurface = Color(0xFFE3E0F2), - surfaceVariant = Color(0xFF49454E), + surfaceVariant = Color(0xFF2A2A3C), // Navigation bar background (ThemePrefWidget) onSurfaceVariant = Color(0xFFCBC4CE), surfaceTint = Color(0xFF66577E), inverseSurface = Color(0xFFE5E1E6), inverseOnSurface = Color(0xFF1B1B1E), outline = Color(0xFF958F99), + surfaceContainerLowest = Color(0xFF20202E), + surfaceContainerLow = Color(0xFF262636), + surfaceContainer = Color(0xFF2A2A3C), // Navigation bar background + surfaceContainerHigh = Color(0xFF303044), + surfaceContainerHighest = Color(0xFF36364D), ) override val lightScheme = lightColorScheme( @@ -49,23 +54,28 @@ internal object TakoColorScheme : BaseColorScheme() { primaryContainer = Color(0xFF66577E), onPrimaryContainer = Color(0xFFF3B375), inversePrimary = Color(0xFFD6BAFF), - secondary = Color(0xFF66577E), - onSecondary = Color(0xFFF3B375), - secondaryContainer = Color(0xFF66577E), - onSecondaryContainer = Color(0xFFF3B375), - tertiary = Color(0xFFF3B375), - onTertiary = Color(0xFF574360), + secondary = Color(0xFF66577E), // Unread badge + onSecondary = Color(0xFFF3B375), // Unread badge text + secondaryContainer = Color(0xFFC8BED0), // Navigation bar selector pill & progress indicator (remaining) + onSecondaryContainer = Color(0xFF66577E), // Navigation bar selector icon + tertiary = Color(0xFFF3B375), // Downloaded badge + onTertiary = Color(0xFF574360), // Downloaded badge text tertiaryContainer = Color(0xFFFDD6B0), onTertiaryContainer = Color(0xFF221437), background = Color(0xFFF7F5FF), onBackground = Color(0xFF1B1B22), surface = Color(0xFFF7F5FF), onSurface = Color(0xFF1B1B22), - surfaceVariant = Color(0xFFE8E0EB), + surfaceVariant = Color(0xFFE8E0EB), // Navigation bar background (ThemePrefWidget) onSurfaceVariant = Color(0xFF49454E), surfaceTint = Color(0xFF66577E), inverseSurface = Color(0xFF313033), inverseOnSurface = Color(0xFFF3EFF4), outline = Color(0xFF7A757E), + surfaceContainerLowest = Color(0xFFD7D0DA), + surfaceContainerLow = Color(0xFFDFD8E2), + surfaceContainer = Color(0xFFE8E0EB), // Navigation bar background + surfaceContainerHigh = Color(0xFFEEE6F1), + surfaceContainerHighest = Color(0xFFF7EEFA), ) } diff --git a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/TealTurqoiseColorScheme.kt b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/TealTurqoiseColorScheme.kt index e914b49fc..28811fa6a 100644 --- a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/TealTurqoiseColorScheme.kt +++ b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/TealTurqoiseColorScheme.kt @@ -15,24 +15,29 @@ internal object TealTurqoiseColorScheme : BaseColorScheme() { primaryContainer = Color(0xFF40E0D0), onPrimaryContainer = Color(0xFF000000), inversePrimary = Color(0xFF008080), - secondary = Color(0xFF40E0D0), - onSecondary = Color(0xFF000000), - secondaryContainer = Color(0xFF18544E), - onSecondaryContainer = Color(0xFF40E0D0), - tertiary = Color(0xFFBF1F2F), - onTertiary = Color(0xFFFFFFFF), + secondary = Color(0xFF40E0D0), // Unread badge + onSecondary = Color(0xFF000000), // Unread badge text + secondaryContainer = Color(0xFF18544E), // Navigation bar selector pill & progress indicator (remaining) + onSecondaryContainer = Color(0xFF40E0D0), // Navigation bar selector icon + tertiary = Color(0xFFBF1F2F), // Downloaded badge + onTertiary = Color(0xFFFFFFFF), // Downloaded badge text tertiaryContainer = Color(0xFF200508), onTertiaryContainer = Color(0xFFBF1F2F), background = Color(0xFF202125), onBackground = Color(0xFFDFDEDA), surface = Color(0xFF202125), onSurface = Color(0xFFDFDEDA), - surfaceVariant = Color(0xFF3F4947), + surfaceVariant = Color(0xFF233133), // Navigation bar background (ThemePrefWidget) onSurfaceVariant = Color(0xFFDFDEDA), surfaceTint = Color(0xFF40E0D0), inverseSurface = Color(0xFFDFDEDA), inverseOnSurface = Color(0xFF202125), outline = Color(0xFF899391), + surfaceContainerLowest = Color(0xFF202C2E), + surfaceContainerLow = Color(0xFF222F31), + surfaceContainer = Color(0xFF233133), // Navigation bar background + surfaceContainerHigh = Color(0xFF28383A), + surfaceContainerHighest = Color(0xFF2F4244), ) override val lightScheme = lightColorScheme( @@ -41,23 +46,28 @@ internal object TealTurqoiseColorScheme : BaseColorScheme() { primaryContainer = Color(0xFF008080), onPrimaryContainer = Color(0xFFFFFFFF), inversePrimary = Color(0xFF40E0D0), - secondary = Color(0xFF008080), - onSecondary = Color(0xFFFFFFFF), - secondaryContainer = Color(0xFFBFDFDF), - onSecondaryContainer = Color(0xFF008080), - tertiary = Color(0xFFFF7F7F), - onTertiary = Color(0xFF000000), + secondary = Color(0xFF008080), // Unread badge text + onSecondary = Color(0xFFFFFFFF), // Unread badge text + secondaryContainer = Color(0xFFCFE5E4), // Navigation bar selector pill & progress indicator (remaining) + onSecondaryContainer = Color(0xFF008080), // Navigation bar selector icon + tertiary = Color(0xFFFF7F7F), // Downloaded badge + onTertiary = Color(0xFF000000), // Downloaded badge text tertiaryContainer = Color(0xFF2A1616), onTertiaryContainer = Color(0xFFFF7F7F), background = Color(0xFFFAFAFA), onBackground = Color(0xFF050505), surface = Color(0xFFFAFAFA), onSurface = Color(0xFF050505), - surfaceVariant = Color(0xFFDAE5E2), + surfaceVariant = Color(0xFFEBF3F1), // Navigation bar background (ThemePrefWidget) onSurfaceVariant = Color(0xFF050505), surfaceTint = Color(0xFFBFDFDF), inverseSurface = Color(0xFF050505), inverseOnSurface = Color(0xFFFAFAFA), outline = Color(0xFF6F7977), + surfaceContainerLowest = Color(0xFFE1E9E7), + surfaceContainerLow = Color(0xFFE6EEEC), + surfaceContainer = Color(0xFFEBF3F1), // Navigation bar background + surfaceContainerHigh = Color(0xFFF0F8F6), + surfaceContainerHighest = Color(0xFFF7FFFD), ) } diff --git a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/TidalWaveColorScheme.kt b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/TidalWaveColorScheme.kt index c56a1fa57..09dc248c0 100644 --- a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/TidalWaveColorScheme.kt +++ b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/TidalWaveColorScheme.kt @@ -22,24 +22,29 @@ internal object TidalWaveColorScheme : BaseColorScheme() { primaryContainer = Color(0xFF004d61), onPrimaryContainer = Color(0xFFb8eaff), inversePrimary = Color(0xFFa12b03), - secondary = Color(0xFF5ed4fc), - onSecondary = Color(0xFF003544), - secondaryContainer = Color(0xFF004d61), - onSecondaryContainer = Color(0xFFb8eaff), - tertiary = Color(0xFF92f7bc), - onTertiary = Color(0xFF001c3b), + secondary = Color(0xFF5ed4fc), // Unread badge + onSecondary = Color(0xFF003544), // Unread badge text + secondaryContainer = Color(0xFF004d61), // Navigation bar selector pill & progress indicator (remaining) + onSecondaryContainer = Color(0xFFb8eaff), // Navigation bar selector icon + tertiary = Color(0xFF92f7bc), // Downloaded badge + onTertiary = Color(0xFF001c3b), // Downloaded badge text tertiaryContainer = Color(0xFFc3fada), onTertiaryContainer = Color(0xFF78ffd6), background = Color(0xFF001c3b), onBackground = Color(0xFFd5e3ff), surface = Color(0xFF001c3b), onSurface = Color(0xFFd5e3ff), - surfaceVariant = Color(0xFF40484c), + surfaceVariant = Color(0xFF082b4b), // Navigation bar background (ThemePrefWidget) onSurfaceVariant = Color(0xFFbfc8cc), surfaceTint = Color(0xFF5ed4fc), inverseSurface = Color(0xFFffe3c4), inverseOnSurface = Color(0xFF001c3b), outline = Color(0xFF8a9296), + surfaceContainerLowest = Color(0xFF072642), + surfaceContainerLow = Color(0xFF072947), + surfaceContainer = Color(0xFF082b4b), // Navigation bar background + surfaceContainerHigh = Color(0xFF093257), + surfaceContainerHighest = Color(0xFF0A3861), ) override val lightScheme = lightColorScheme( @@ -48,23 +53,28 @@ internal object TidalWaveColorScheme : BaseColorScheme() { primaryContainer = Color(0xFFB4D4DF), onPrimaryContainer = Color(0xFF001f28), inversePrimary = Color(0xFFff987f), - secondary = Color(0xFF006780), - onSecondary = Color(0xFFffffff), - secondaryContainer = Color(0xFFb8eaff), - onSecondaryContainer = Color(0xFF001f28), - tertiary = Color(0xFF92f7bc), - onTertiary = Color(0xFF001c3b), + secondary = Color(0xFF006780), // Unread badge + onSecondary = Color(0xFFffffff), // Unread badge text + secondaryContainer = Color(0xFF9AE1FF), // Navigation bar selector pill & progress indicator (remaining) + onSecondaryContainer = Color(0xFF001f28), // Navigation bar selector icon + tertiary = Color(0xFF92f7bc), // Downloaded badge + onTertiary = Color(0xFF001c3b), // Downloaded badge text tertiaryContainer = Color(0xFFc3fada), onTertiaryContainer = Color(0xFF78ffd6), background = Color(0xFFfdfbff), onBackground = Color(0xFF001c3b), surface = Color(0xFFfdfbff), onSurface = Color(0xFF001c3b), - surfaceVariant = Color(0xFFdce4e8), + surfaceVariant = Color(0xFFe8eff5), // Navigation bar background (ThemePrefWidget) onSurfaceVariant = Color(0xFF40484c), surfaceTint = Color(0xFF006780), inverseSurface = Color(0xFF020400), inverseOnSurface = Color(0xFFffe3c4), outline = Color(0xFF70787c), + surfaceContainerLowest = Color(0xFFe2e8ec), + surfaceContainerLow = Color(0xFFe5ecf1), + surfaceContainer = Color(0xFFe8eff5), // Navigation bar background + surfaceContainerHigh = Color(0xFFedf4fA), + surfaceContainerHighest = Color(0xFFf5faff), ) } diff --git a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/YinYangColorScheme.kt b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/YinYangColorScheme.kt index da9dee424..1e9b12978 100644 --- a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/YinYangColorScheme.kt +++ b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/YinYangColorScheme.kt @@ -17,24 +17,29 @@ internal object YinYangColorScheme : BaseColorScheme() { primaryContainer = Color(0xFFFFFFFF), onPrimaryContainer = Color(0xFF000000), inversePrimary = Color(0xFFCECECE), - secondary = Color(0xFFFFFFFF), - onSecondary = Color(0xFF5A5A5A), - secondaryContainer = Color(0xFF717171), - onSecondaryContainer = Color(0xFFE4E4E4), - tertiary = Color(0xFF000000), - onTertiary = Color(0xFFFFFFFF), + secondary = Color(0xFFFFFFFF), // Unread badge + onSecondary = Color(0xFF5A5A5A), // Unread badge text + secondaryContainer = Color(0xFF717171), // Navigation bar selector pill & progress indicator (remaining) + onSecondaryContainer = Color(0xFFE4E4E4), // Navigation bar selector icon + tertiary = Color(0xFF000000), // Downloaded badge + onTertiary = Color(0xFFFFFFFF), // Downloaded badge text tertiaryContainer = Color(0xFF00419E), onTertiaryContainer = Color(0xFFD8E2FF), background = Color(0xFF1E1E1E), onBackground = Color(0xFFE6E6E6), surface = Color(0xFF1E1E1E), onSurface = Color(0xFFE6E6E6), - surfaceVariant = Color(0xFF4E4E4E), + surfaceVariant = Color(0xFF313131), // Navigation bar background (ThemePrefWidget) onSurfaceVariant = Color(0xFFD1D1D1), surfaceTint = Color(0xFFFFFFFF), inverseSurface = Color(0xFFE6E6E6), inverseOnSurface = Color(0xFF1E1E1E), outline = Color(0xFF999999), + surfaceContainerLowest = Color(0xFF2A2A2A), + surfaceContainerLow = Color(0xFF2D2D2D), + surfaceContainer = Color(0xFF313131), // Navigation bar background + surfaceContainerHigh = Color(0xFF383838), + surfaceContainerHighest = Color(0xFF3F3F3F), ) override val lightScheme = lightColorScheme( @@ -43,23 +48,28 @@ internal object YinYangColorScheme : BaseColorScheme() { primaryContainer = Color(0xFF000000), onPrimaryContainer = Color(0xFFFFFFFF), inversePrimary = Color(0xFFA6A6A6), - secondary = Color(0xFF000000), - onSecondary = Color(0xFFFFFFFF), - secondaryContainer = Color(0xFFDDDDDD), - onSecondaryContainer = Color(0xFF0C0C0C), - tertiary = Color(0xFFFFFFFF), - onTertiary = Color(0xFF000000), + secondary = Color(0xFF000000), // Unread badge + onSecondary = Color(0xFFFFFFFF), // Unread badge text + secondaryContainer = Color(0xFFDDDDDD), // Navigation bar selector pill & progress indicator (remaining) + onSecondaryContainer = Color(0xFF0C0C0C), // Navigation bar selector icon + tertiary = Color(0xFFFFFFFF), // Downloaded badge + onTertiary = Color(0xFF000000), // Downloaded badge text tertiaryContainer = Color(0xFFD8E2FF), onTertiaryContainer = Color(0xFF001947), background = Color(0xFFFDFDFD), onBackground = Color(0xFF222222), surface = Color(0xFFFDFDFD), onSurface = Color(0xFF222222), - surfaceVariant = Color(0xFFEDEDED), + surfaceVariant = Color(0xFFE8E8E8), // Navigation bar background (ThemePrefWidget) onSurfaceVariant = Color(0xFF515151), surfaceTint = Color(0xFF000000), inverseSurface = Color(0xFF333333), inverseOnSurface = Color(0xFFF4F4F4), outline = Color(0xFF838383), + surfaceContainerLowest = Color(0xFFCFCFCF), + surfaceContainerLow = Color(0xFFDADADA), + surfaceContainer = Color(0xFFE8E8E8), // Navigation bar background + surfaceContainerHigh = Color(0xFFECECEC), + surfaceContainerHighest = Color(0xFFEFEFEF), ) } diff --git a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/YotsubaColorScheme.kt b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/YotsubaColorScheme.kt index fdda6b7dc..58007a680 100644 --- a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/YotsubaColorScheme.kt +++ b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/YotsubaColorScheme.kt @@ -23,24 +23,29 @@ internal object YotsubaColorScheme : BaseColorScheme() { primaryContainer = Color(0xFF862200), onPrimaryContainer = Color(0xFFFFDBCF), inversePrimary = Color(0xFFAE3200), - secondary = Color(0xFFFFB59D), - onSecondary = Color(0xFF5F1600), - secondaryContainer = Color(0xFF862200), - onSecondaryContainer = Color(0xFFFFDBCF), - tertiary = Color(0xFFD7C68D), - onTertiary = Color(0xFF3A2F05), + secondary = Color(0xFFFFB59D), // Unread badge + onSecondary = Color(0xFF5F1600), // Unread badge text + secondaryContainer = Color(0xFF862200), // Navigation bar selector pill & progress indicator (remaining) + onSecondaryContainer = Color(0xFFFFDBCF), // Navigation bar selector icon + tertiary = Color(0xFFD7C68D), // Downloaded badge + onTertiary = Color(0xFF3A2F05), // Downloaded badge text tertiaryContainer = Color(0xFF524619), onTertiaryContainer = Color(0xFFF5E2A7), background = Color(0xFF211A18), onBackground = Color(0xFFEDE0DD), surface = Color(0xFF211A18), onSurface = Color(0xFFEDE0DD), - surfaceVariant = Color(0xFF53433F), + surfaceVariant = Color(0xFF332723), // Navigation bar background (ThemePrefWidget) onSurfaceVariant = Color(0xFFD8C2BC), surfaceTint = Color(0xFFFFB59D), inverseSurface = Color(0xFFEDE0DD), inverseOnSurface = Color(0xFF211A18), outline = Color(0xFFA08C87), + surfaceContainerLowest = Color(0xFF2E221F), + surfaceContainerLow = Color(0xFF312521), + surfaceContainer = Color(0xFF332723), // Navigation bar background + surfaceContainerHigh = Color(0xFF413531), + surfaceContainerHighest = Color(0xFF4C403D), ) override val lightScheme = lightColorScheme( @@ -49,23 +54,28 @@ internal object YotsubaColorScheme : BaseColorScheme() { primaryContainer = Color(0xFFFFDBCF), onPrimaryContainer = Color(0xFF3B0A00), inversePrimary = Color(0xFFFFB59D), - secondary = Color(0xFFAE3200), - onSecondary = Color(0xFFFFFFFF), - secondaryContainer = Color(0xFFFFDBCF), - onSecondaryContainer = Color(0xFF3B0A00), - tertiary = Color(0xFF6B5E2F), - onTertiary = Color(0xFFFFFFFF), + secondary = Color(0xFFAE3200), // Unread badge + onSecondary = Color(0xFFFFFFFF), // Unread badge text + secondaryContainer = Color(0xFFEBCDC2), // Navigation bar selector pill & progress indicator (remaining) + onSecondaryContainer = Color(0xFF3B0A00), // Navigation bar selector icon + tertiary = Color(0xFF6B5E2F), // Downloaded badge + onTertiary = Color(0xFFFFFFFF), // Downloaded badge text tertiaryContainer = Color(0xFFF5E2A7), onTertiaryContainer = Color(0xFF231B00), background = Color(0xFFFCFCFC), onBackground = Color(0xFF211A18), surface = Color(0xFFFCFCFC), onSurface = Color(0xFF211A18), - surfaceVariant = Color(0xFFF5DED8), + surfaceVariant = Color(0xFFF6EBE7), // Navigation bar background (ThemePrefWidget) onSurfaceVariant = Color(0xFF53433F), surfaceTint = Color(0xFFAE3200), inverseSurface = Color(0xFF362F2D), inverseOnSurface = Color(0xFFFBEEEB), outline = Color(0xFF85736E), + surfaceContainerLowest = Color(0xFFECE3E0), + surfaceContainerLow = Color(0xFFF1E7E4), + surfaceContainer = Color(0xFFF6EBE7), // Navigation bar background + surfaceContainerHigh = Color(0xFFFAF4F2), + surfaceContainerHighest = Color(0xFFFBF6F4), ) } From 0392ef0d1878be01633b8119cbc8d1b263737307 Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Fri, 17 May 2024 16:06:23 +0600 Subject: [PATCH 012/297] Update renovate config --- .github/renovate.json5 | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 751500ef3..0c0785f22 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -1,25 +1,20 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": [ - "config:base" - ], - "schedule": ["every friday"], + "extends": ["config:base"], "labels": ["Dependencies"], "packageRules": [ { - "groupName": "Compose BOM", + "groupName": "Compose BOM (Alpha)", "matchPackageNames": [ "dev.chrisbanes.compose:compose-bom" ], "ignoreUnstable": false }, { - // Compiler plugins are tightly coupled to Kotlin version - "groupName": "Kotlin", + "groupName": "Kotlin and Compose Compiler", "matchPackagePrefixes": [ "androidx.compose.compiler", "org.jetbrains.kotlin.", - "org.jetbrains.kotlin:" ], } ] From 84ea5166dee476db771e8b5b38839a34a80de976 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 17 May 2024 16:09:21 +0600 Subject: [PATCH 013/297] chore(deps): update actions/checkout action to v4.1.6 (#796) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/build_pull_request.yml | 2 +- .github/workflows/build_push.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_pull_request.yml b/.github/workflows/build_pull_request.yml index d9942cf0a..06dd2e7e8 100644 --- a/.github/workflows/build_pull_request.yml +++ b/.github/workflows/build_pull_request.yml @@ -20,7 +20,7 @@ jobs: steps: - name: Clone repo - uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5 + uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - name: Validate Gradle Wrapper uses: gradle/wrapper-validation-action@216d1ad2b3710bf005dc39237337b9673fd8fcd5 # v3.3.2 diff --git a/.github/workflows/build_push.yml b/.github/workflows/build_push.yml index 246f6e37c..90eee2c09 100644 --- a/.github/workflows/build_push.yml +++ b/.github/workflows/build_push.yml @@ -17,7 +17,7 @@ jobs: steps: - name: Clone repo - uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5 + uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - name: Validate Gradle Wrapper uses: gradle/wrapper-validation-action@216d1ad2b3710bf005dc39237337b9673fd8fcd5 # v3.3.2 From ce497003e38d838e846b6e4ce88aafe4610d522b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 17 May 2024 16:09:36 +0600 Subject: [PATCH 014/297] fix(deps): update dependency androidx.test.espresso:espresso-core to v3.6.0-beta01 (#797) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/androidx.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index 247035a9f..8341cfdaf 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -27,7 +27,7 @@ paging-compose = { module = "androidx.paging:paging-compose", version.ref = "pag benchmark-macro = "androidx.benchmark:benchmark-macro-junit4:1.2.4" test-ext = "androidx.test.ext:junit-ktx:1.2.0-alpha04" -test-espresso-core = "androidx.test.espresso:espresso-core:3.6.0-alpha04" +test-espresso-core = "androidx.test.espresso:espresso-core:3.6.0-beta01" test-uiautomator = "androidx.test.uiautomator:uiautomator:2.3.0" [bundles] From fffa6a462d9c2c8473d4fdabad775f0c5849775b Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Sat, 18 May 2024 23:00:17 +0600 Subject: [PATCH 015/297] Fix renovate config --- .github/renovate.json5 | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 0c0785f22..cc1468ce2 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -15,6 +15,7 @@ "matchPackagePrefixes": [ "androidx.compose.compiler", "org.jetbrains.kotlin.", + "org.jetbrains.kotlin:", ], } ] From 1dca9363a46aa310623d057113c68de89c31ee43 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 18 May 2024 23:02:46 +0600 Subject: [PATCH 016/297] fix(deps): update dependency dev.chrisbanes.compose:compose-bom to v2024.05.00-alpha02 (#802) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/compose.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/compose.versions.toml b/gradle/compose.versions.toml index 77a87adf1..cc57c27ff 100644 --- a/gradle/compose.versions.toml +++ b/gradle/compose.versions.toml @@ -1,6 +1,6 @@ [versions] compiler = "1.5.12" -compose-bom = "2024.05.00-alpha01" +compose-bom = "2024.05.00-alpha02" accompanist = "0.35.0-alpha" [libraries] From 653d5d3e252ff2508b100b0f291fdcfaf2a98097 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 18 May 2024 23:03:05 +0600 Subject: [PATCH 017/297] fix(deps): update dependency com.google.android.material:material to v1.12.0 (#754) 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 1c287986e..87e1f3e03 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -57,7 +57,7 @@ natural-comparator = "com.github.gpanther:java-nat-sort:natural-comparator-1.1" richtext-commonmark = { module = "com.halilibo.compose-richtext:richtext-commonmark", version.ref = "richtext" } richtext-m3 = { module = "com.halilibo.compose-richtext:richtext-ui-material3", version.ref = "richtext" } -material = "com.google.android.material:material:1.11.0" +material = "com.google.android.material:material:1.12.0" flexible-adapter-core = "com.github.arkon.FlexibleAdapter:flexible-adapter:c8013533" photoview = "com.github.chrisbanes:PhotoView:2.3.0" directionalviewpager = "com.github.tachiyomiorg:DirectionalViewPager:1.0.0" From 8d187f786594356dd47899dad660d602b52099ef Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 18 May 2024 23:03:38 +0600 Subject: [PATCH 018/297] fix(deps): update dependency androidx.test.ext:junit-ktx to v1.2.0-beta01 (#801) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/androidx.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index 8341cfdaf..1c901b069 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -26,7 +26,7 @@ paging-runtime = { module = "androidx.paging:paging-runtime", version.ref = "pag paging-compose = { module = "androidx.paging:paging-compose", version.ref = "paging_version" } benchmark-macro = "androidx.benchmark:benchmark-macro-junit4:1.2.4" -test-ext = "androidx.test.ext:junit-ktx:1.2.0-alpha04" +test-ext = "androidx.test.ext:junit-ktx:1.2.0-beta01" test-espresso-core = "androidx.test.espresso:espresso-core:3.6.0-beta01" test-uiautomator = "androidx.test.uiautomator:uiautomator:2.3.0" From 99b550ae0d9eaf530d644f7755162d9705c302f4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 18 May 2024 23:03:52 +0600 Subject: [PATCH 019/297] fix(deps): update dependency io.mockk:mockk to v1.13.11 (#803) 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 87e1f3e03..d4b58651d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -92,7 +92,7 @@ sqldelight-gradle = { module = "app.cash.sqldelight:gradle-plugin", version.ref junit = "org.junit.jupiter:junit-jupiter:5.10.2" kotest-assertions = "io.kotest:kotest-assertions-core:5.9.0" -mockk = "io.mockk:mockk:1.13.10" +mockk = "io.mockk:mockk:1.13.11" voyager-navigator = { module = "cafe.adriel.voyager:voyager-navigator", version.ref = "voyager" } voyager-screenmodel = { module = "cafe.adriel.voyager:voyager-screenmodel", version.ref = "voyager" } From 5912d6b08f3624a385f820582e49f1dde1b55864 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 18 May 2024 23:12:16 +0600 Subject: [PATCH 020/297] fix(deps): update dependency androidx.annotation:annotation to v1.8.0 (#808) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/androidx.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index 1c901b069..eb6cdc61e 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -6,7 +6,7 @@ paging_version = "3.2.1" [libraries] gradle = { module = "com.android.tools.build:gradle", version.ref = "agp_version" } -annotation = "androidx.annotation:annotation:1.7.1" +annotation = "androidx.annotation:annotation:1.8.0" appcompat = "androidx.appcompat:appcompat:1.6.1" biometricktx = "androidx.biometric:biometric-ktx:1.2.0-alpha05" constraintlayout = "androidx.constraintlayout:constraintlayout:2.1.4" From d2e5c78074829ca7c7bace3e5bfee25ea430e44c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 18 May 2024 23:12:27 +0600 Subject: [PATCH 021/297] fix(deps): update lifecycle.version to v2.8.0 (#809) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/androidx.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index eb6cdc61e..70768b424 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -1,6 +1,6 @@ [versions] agp_version = "8.4.0" -lifecycle_version = "2.7.0" +lifecycle_version = "2.8.0" paging_version = "3.2.1" [libraries] From 2f243fae11e48799437b1672ec1a8571552caacb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 18 May 2024 23:14:12 +0600 Subject: [PATCH 022/297] chore(deps): update kotlin and compose compiler (#800) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/compose.versions.toml | 2 +- gradle/kotlinx.versions.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/compose.versions.toml b/gradle/compose.versions.toml index cc57c27ff..3f1d253e1 100644 --- a/gradle/compose.versions.toml +++ b/gradle/compose.versions.toml @@ -1,5 +1,5 @@ [versions] -compiler = "1.5.12" +compiler = "1.5.14" compose-bom = "2024.05.00-alpha02" accompanist = "0.35.0-alpha" diff --git a/gradle/kotlinx.versions.toml b/gradle/kotlinx.versions.toml index f86682ec5..66e69752a 100644 --- a/gradle/kotlinx.versions.toml +++ b/gradle/kotlinx.versions.toml @@ -1,5 +1,5 @@ [versions] -kotlin_version = "1.9.23" +kotlin_version = "1.9.24" serialization_version = "1.6.3" xml_serialization_version = "0.86.3" From 0cb1794a445c8c7f4e9c163bd850f1681cdbef6a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 22 May 2024 13:45:53 +0600 Subject: [PATCH 023/297] fix(deps): update dependency com.android.tools.build:gradle to v8.4.1 (#818) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/androidx.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index 70768b424..94cb08052 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -1,5 +1,5 @@ [versions] -agp_version = "8.4.0" +agp_version = "8.4.1" lifecycle_version = "2.8.0" paging_version = "3.2.1" From 9b944092c75046b68ac38e2d9d3a5e49033d7588 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 27 May 2024 02:05:26 +0600 Subject: [PATCH 024/297] fix(deps): update aboutlib.version to v11.2.0 (#823) 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 d4b58651d..0dc2137fd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -aboutlib_version = "11.1.4" +aboutlib_version = "11.2.0" leakcanary = "2.14" moko = "0.23.0" okhttp_version = "5.0.0-alpha.12" From de5a64aa73c8a2229fa87e9baba9981197474f51 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 27 May 2024 02:05:40 +0600 Subject: [PATCH 025/297] fix(deps): update dependency org.apache.commons:commons-compress to v1.26.2 (#826) 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 0dc2137fd..8cb3ec05f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -32,7 +32,7 @@ jsoup = "org.jsoup:jsoup:1.17.2" disklrucache = "com.jakewharton:disklrucache:2.0.2" unifile = "com.github.tachiyomiorg:unifile:e0def6b3dc" -common-compress = "org.apache.commons:commons-compress:1.26.1" +common-compress = "org.apache.commons:commons-compress:1.26.2" junrar = "com.github.junrar:junrar:7.5.5" sqlite-framework = { module = "androidx.sqlite:sqlite-framework", version.ref = "sqlite" } From af8696cb9060e652f41220ea4a6074568df8bc3d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 27 May 2024 02:05:53 +0600 Subject: [PATCH 026/297] fix(deps): update paging.version to v3.3.0 (#810) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/androidx.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index 94cb08052..87533a374 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -1,7 +1,7 @@ [versions] agp_version = "8.4.1" lifecycle_version = "2.8.0" -paging_version = "3.2.1" +paging_version = "3.3.0" [libraries] gradle = { module = "com.android.tools.build:gradle", version.ref = "agp_version" } From b9da98b527e3d9ac56e263f7b595768239fa718e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 30 May 2024 05:07:08 +0600 Subject: [PATCH 027/297] fix(deps): update lifecycle.version to v2.8.1 (#844) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/androidx.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index 87533a374..fd2c6c767 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -1,6 +1,6 @@ [versions] agp_version = "8.4.1" -lifecycle_version = "2.8.0" +lifecycle_version = "2.8.1" paging_version = "3.3.0" [libraries] From 095da924b9a1d724e6a228cb4abcc4dfe948db7d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 30 May 2024 05:07:22 +0600 Subject: [PATCH 028/297] fix(deps): update dependency androidx.appcompat:appcompat to v1.7.0 (#845) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/androidx.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index fd2c6c767..6154d7ed1 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -7,7 +7,7 @@ paging_version = "3.3.0" gradle = { module = "com.android.tools.build:gradle", version.ref = "agp_version" } annotation = "androidx.annotation:annotation:1.8.0" -appcompat = "androidx.appcompat:appcompat:1.6.1" +appcompat = "androidx.appcompat:appcompat:1.7.0" biometricktx = "androidx.biometric:biometric-ktx:1.2.0-alpha05" constraintlayout = "androidx.constraintlayout:constraintlayout:2.1.4" corektx = "androidx.core:core-ktx:1.13.1" From e567250b17c231abee151541fea1f97b269b516a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 1 Jun 2024 22:02:54 +0600 Subject: [PATCH 029/297] fix(deps): update dependency androidx.test.espresso:espresso-core to v3.6.0-rc01 (#851) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/androidx.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index 6154d7ed1..30322329f 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -27,7 +27,7 @@ paging-compose = { module = "androidx.paging:paging-compose", version.ref = "pag benchmark-macro = "androidx.benchmark:benchmark-macro-junit4:1.2.4" test-ext = "androidx.test.ext:junit-ktx:1.2.0-beta01" -test-espresso-core = "androidx.test.espresso:espresso-core:3.6.0-beta01" +test-espresso-core = "androidx.test.espresso:espresso-core:3.6.0-rc01" test-uiautomator = "androidx.test.uiautomator:uiautomator:2.3.0" [bundles] From 7ab7f5ac37e8c102ca259144f136616b59172e6d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 1 Jun 2024 22:03:03 +0600 Subject: [PATCH 030/297] fix(deps): update dependency com.google.gms:google-services to v4.4.2 (#849) 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 8cb3ec05f..4c4fe977a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ detektCompose = "0.3.12" [libraries] desugar = "com.android.tools:desugar_jdk_libs:2.0.4" android-shortcut-gradle = "com.github.zellius:android-shortcut-gradle-plugin:0.1.2" -google-services-gradle = "com.google.gms:google-services:4.4.1" +google-services-gradle = "com.google.gms:google-services:4.4.2" rxjava = "io.reactivex:rxjava:1.3.8" From 1f286f1a357a6c0f8cf2a7274b11b175315de4ea Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 1 Jun 2024 22:03:10 +0600 Subject: [PATCH 031/297] fix(deps): update dependency com.google.firebase:firebase-analytics to v22.0.1 (#848) 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 4c4fe977a..2962a56ba 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -73,7 +73,7 @@ moko-gradle = { module = "dev.icerock.moko:resources-generator", version.ref = " logcat = "com.squareup.logcat:logcat:0.1" -firebase-analytics = "com.google.firebase:firebase-analytics:22.0.0" +firebase-analytics = "com.google.firebase:firebase-analytics:22.0.1" aboutLibraries-gradle = { module = "com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin", version.ref = "aboutlib_version" } aboutLibraries-compose = { module = "com.mikepenz:aboutlibraries-compose-m3", version.ref = "aboutlib_version" } From 9f5db70572cee99243c850d2da55fe0a10d52809 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 1 Jun 2024 22:03:20 +0600 Subject: [PATCH 032/297] fix(deps): update aboutlib.version to v11.2.1 (#846) 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 2962a56ba..2fe0f076b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -aboutlib_version = "11.2.0" +aboutlib_version = "11.2.1" leakcanary = "2.14" moko = "0.23.0" okhttp_version = "5.0.0-alpha.12" From 098f925519502a99aef9eb33c9b88b1280351a73 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 2 Jun 2024 01:23:31 +0600 Subject: [PATCH 033/297] fix(deps): update dependency androidx.test.ext:junit-ktx to v1.2.0-rc01 (#855) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/androidx.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index 30322329f..ff0416cb7 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -26,7 +26,7 @@ paging-runtime = { module = "androidx.paging:paging-runtime", version.ref = "pag paging-compose = { module = "androidx.paging:paging-compose", version.ref = "paging_version" } benchmark-macro = "androidx.benchmark:benchmark-macro-junit4:1.2.4" -test-ext = "androidx.test.ext:junit-ktx:1.2.0-beta01" +test-ext = "androidx.test.ext:junit-ktx:1.2.0-rc01" test-espresso-core = "androidx.test.espresso:espresso-core:3.6.0-rc01" test-uiautomator = "androidx.test.uiautomator:uiautomator:2.3.0" From 116579d38c08c203fe2c4996419e277c7bf9c165 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 2 Jun 2024 01:23:39 +0600 Subject: [PATCH 034/297] chore(deps): update dependency gradle to v8.8 (#856) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b82aa23a4..a4413138c 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 1aa94a426..b740cf133 100755 --- a/gradlew +++ b/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. From 8632ba85ee1ed080d7baa70050d460807c8edfcf Mon Sep 17 00:00:00 2001 From: Sven Date: Sat, 1 Jun 2024 21:25:58 +0200 Subject: [PATCH 035/297] fix: storage permission request for non-conforming devices (#726) * fix: storage permission request for non-conforming devices * fix: catch more specific exception * chore: add toast message to indicate missing persistent permissions * chore: correct newly introduced translaction string * Change error toast message --------- Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com> --- .../more/settings/screen/SettingsDataScreen.kt | 12 +++++++++++- i18n/src/commonMain/resources/MR/base/strings.xml | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt index 91de2993f..ecfd2ec75 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt @@ -111,7 +111,17 @@ object SettingsDataScreen : SearchableSettings { val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION - context.contentResolver.takePersistableUriPermission(uri, flags) + // For some reason InkBook devices do not implement the SAF properly. Persistable URI grants do not + // work. However, simply retrieving the URI and using it works fine for these devices. Access is not + // revoked after the app is closed or the device is restarted. + // This also holds for some Samsung devices. Thus, we simply execute inside of a try-catch block and + // ignore the exception if it is thrown. + try { + context.contentResolver.takePersistableUriPermission(uri, flags) + } catch (e: SecurityException) { + logcat(LogPriority.ERROR, e) + context.toast(MR.strings.file_picker_uri_permission_unsupported) + } UniFile.fromUri(context, uri)?.let { storageDirPref.set(it.uri.toString()) diff --git a/i18n/src/commonMain/resources/MR/base/strings.xml b/i18n/src/commonMain/resources/MR/base/strings.xml index bd30e2900..b0a397b1d 100644 --- a/i18n/src/commonMain/resources/MR/base/strings.xml +++ b/i18n/src/commonMain/resources/MR/base/strings.xml @@ -869,6 +869,7 @@ Select cover image Select backup file No file picker app found + Failed to acquire persistent folder access. The app may behave unexpectedly. No file selected From 0870cffba121c0cc7db9c79f83f770a43d9c32e7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 2 Jun 2024 15:20:56 +0600 Subject: [PATCH 036/297] fix(deps): update dependency io.github.fornewid:material-motion-compose-core to v1.2.1 (#858) 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 2fe0f076b..085533d04 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -62,7 +62,7 @@ flexible-adapter-core = "com.github.arkon.FlexibleAdapter:flexible-adapter:c8013 photoview = "com.github.chrisbanes:PhotoView:2.3.0" directionalviewpager = "com.github.tachiyomiorg:DirectionalViewPager:1.0.0" insetter = "dev.chrisbanes.insetter:insetter:0.6.1" -compose-materialmotion = "io.github.fornewid:material-motion-compose-core:1.2.0" +compose-materialmotion = "io.github.fornewid:material-motion-compose-core:1.2.1" compose-webview = "io.github.kevinnzou:compose-webview:0.33.6" compose-grid = "io.woong.compose.grid:grid:1.2.2" From da62c7a21a81f513988fa64df6253376f85228ef Mon Sep 17 00:00:00 2001 From: "Cuong M. Tran" Date: Fri, 7 Jun 2024 04:35:26 +0700 Subject: [PATCH 037/297] Fix MigratorTest after update to io.mockk v1.13.11 (#814) * Fix MigratorTest after update to io.mockk v1.13.11 Causing error: io.mockk.MockKException: was not can only be called on a mocked object * remove import --- app/src/test/java/mihon/core/migration/MigratorTest.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/src/test/java/mihon/core/migration/MigratorTest.kt b/app/src/test/java/mihon/core/migration/MigratorTest.kt index e0feff3fd..47c4bc7c2 100644 --- a/app/src/test/java/mihon/core/migration/MigratorTest.kt +++ b/app/src/test/java/mihon/core/migration/MigratorTest.kt @@ -1,6 +1,5 @@ package mihon.core.migration -import io.mockk.Called import io.mockk.slot import io.mockk.spyk import io.mockk.verify @@ -59,7 +58,7 @@ class MigratorTest { val result = execute.await() assertFalse(result) - verify { migrationJobFactory.create(any()) wasNot Called } + verify(exactly = 0) { migrationJobFactory.create(any()) } } @Test @@ -72,7 +71,7 @@ class MigratorTest { val result = execute.await() assertFalse(result) - verify { migrationJobFactory.create(any()) wasNot Called } + verify(exactly = 0) { migrationJobFactory.create(any()) } } @Test From 1f7574bd4fc0471b7f974cffdf166c2551b2749b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 7 Jun 2024 03:35:38 +0600 Subject: [PATCH 038/297] fix(deps): update dependency io.kotest:kotest-assertions-core to v5.9.1 (#869) 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 085533d04..ad58e9e7b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -91,7 +91,7 @@ sqldelight-dialects-sql = { module = "app.cash.sqldelight:sqlite-3-38-dialect", sqldelight-gradle = { module = "app.cash.sqldelight:gradle-plugin", version.ref = "sqldelight" } junit = "org.junit.jupiter:junit-jupiter:5.10.2" -kotest-assertions = "io.kotest:kotest-assertions-core:5.9.0" +kotest-assertions = "io.kotest:kotest-assertions-core:5.9.1" mockk = "io.mockk:mockk:1.13.11" voyager-navigator = { module = "cafe.adriel.voyager:voyager-navigator", version.ref = "voyager" } From e8fdfaad648ac70ed296e470cac2d07150c239b1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 7 Jun 2024 03:35:50 +0600 Subject: [PATCH 039/297] chore(deps): update actions/dependency-review-action action to v4.3.3 (#867) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/build_pull_request.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_pull_request.yml b/.github/workflows/build_pull_request.yml index 06dd2e7e8..ff697921b 100644 --- a/.github/workflows/build_pull_request.yml +++ b/.github/workflows/build_pull_request.yml @@ -26,7 +26,7 @@ jobs: uses: gradle/wrapper-validation-action@216d1ad2b3710bf005dc39237337b9673fd8fcd5 # v3.3.2 - name: Dependency Review - uses: actions/dependency-review-action@0c155c5e8556a497adf53f2c18edabf945ed8e70 # v4.3.2 + uses: actions/dependency-review-action@72eb03d02c7872a771aacd928f3123ac62ad6d3a # v4.3.3 - name: Set up JDK uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9 # v4.2.1 From 46003ec25139319079abc9fde89b3afd344a1a11 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 7 Jun 2024 03:48:35 +0600 Subject: [PATCH 040/297] chore(deps): update kotlin and compose compiler to v2 (major) (#819) * chore(deps): update kotlin and compose compiler to v2 * Update .gitignore * Fix build --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com> --- .github/renovate.json5 | 8 --- .gitignore | 1 + app/build.gradle.kts | 2 +- buildSrc/build.gradle.kts | 10 +-- ...hon.android.application.compose.gradle.kts | 1 - .../kotlin/mihon/buildlogic/AndroidConfig.kt | 4 ++ .../mihon/buildlogic/ProjectExtensions.kt | 70 +++++++++---------- data/build.gradle.kts | 2 +- domain/build.gradle.kts | 2 +- gradle/compose.versions.toml | 3 - gradle/kotlinx.versions.toml | 4 +- i18n/build.gradle.kts | 2 +- presentation-core/build.gradle.kts | 2 +- source-api/build.gradle.kts | 2 +- source-local/build.gradle.kts | 2 +- .../tachiyomi/source/local/LocalSource.kt | 13 ++-- 16 files changed, 61 insertions(+), 67 deletions(-) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index cc1468ce2..c01f918f5 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -9,14 +9,6 @@ "dev.chrisbanes.compose:compose-bom" ], "ignoreUnstable": false - }, - { - "groupName": "Kotlin and Compose Compiler", - "matchPackagePrefixes": [ - "androidx.compose.compiler", - "org.jetbrains.kotlin.", - "org.jetbrains.kotlin:", - ], } ] } diff --git a/.gitignore b/.gitignore index 6abb1d29e..70e152f0a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .gradle +.kotlin /local.properties /.idea/workspace.xml .DS_Store diff --git a/app/build.gradle.kts b/app/build.gradle.kts index f7f9a78a3..622715259 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -274,7 +274,7 @@ androidComponents { tasks { // See https://kotlinlang.org/docs/reference/experimental.html#experimental-status-of-experimental-api(-markers) withType { - kotlinOptions.freeCompilerArgs += listOf( + compilerOptions.freeCompilerArgs.addAll( "-Xcontext-receivers", "-opt-in=androidx.compose.foundation.layout.ExperimentalLayoutApi", "-opt-in=androidx.compose.material.ExperimentalMaterialApi", diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 0ce5d68de..b72b8a98b 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -3,14 +3,16 @@ plugins { } dependencies { + implementation(androidx.gradle) + implementation(kotlinx.gradle) + implementation(kotlinx.compose.compiler.gradle) + implementation(libs.detekt.gradlePlugin) + implementation(gradleApi()) + implementation(files(libs.javaClass.superclass.protectionDomain.codeSource.location)) implementation(files(androidx.javaClass.superclass.protectionDomain.codeSource.location)) implementation(files(compose.javaClass.superclass.protectionDomain.codeSource.location)) implementation(files(kotlinx.javaClass.superclass.protectionDomain.codeSource.location)) - implementation(androidx.gradle) - implementation(kotlinx.gradle) - implementation(libs.detekt.gradlePlugin) - implementation(gradleApi()) } repositories { diff --git a/buildSrc/src/main/kotlin/mihon.android.application.compose.gradle.kts b/buildSrc/src/main/kotlin/mihon.android.application.compose.gradle.kts index eda5fb22e..6b330b1d9 100644 --- a/buildSrc/src/main/kotlin/mihon.android.application.compose.gradle.kts +++ b/buildSrc/src/main/kotlin/mihon.android.application.compose.gradle.kts @@ -1,4 +1,3 @@ -import mihon.buildlogic.AndroidConfig import mihon.buildlogic.configureCompose plugins { diff --git a/buildSrc/src/main/kotlin/mihon/buildlogic/AndroidConfig.kt b/buildSrc/src/main/kotlin/mihon/buildlogic/AndroidConfig.kt index afea120de..23f0d2b9a 100644 --- a/buildSrc/src/main/kotlin/mihon/buildlogic/AndroidConfig.kt +++ b/buildSrc/src/main/kotlin/mihon/buildlogic/AndroidConfig.kt @@ -1,11 +1,15 @@ package mihon.buildlogic import org.gradle.api.JavaVersion as GradleJavaVersion +import org.jetbrains.kotlin.gradle.dsl.JvmTarget as KotlinJvmTarget object AndroidConfig { const val COMPILE_SDK = 34 const val TARGET_SDK = 34 const val MIN_SDK = 26 const val NDK = "26.1.10909125" + + // https://youtrack.jetbrains.com/issue/KT-66995/JvmTarget-and-JavaVersion-compatibility-for-easier-JVM-version-setup val JavaVersion = GradleJavaVersion.VERSION_17 + val JvmTarget = KotlinJvmTarget.JVM_17 } diff --git a/buildSrc/src/main/kotlin/mihon/buildlogic/ProjectExtensions.kt b/buildSrc/src/main/kotlin/mihon/buildlogic/ProjectExtensions.kt index 874e556a2..4b9e762b9 100644 --- a/buildSrc/src/main/kotlin/mihon/buildlogic/ProjectExtensions.kt +++ b/buildSrc/src/main/kotlin/mihon/buildlogic/ProjectExtensions.kt @@ -8,9 +8,12 @@ import org.gradle.accessors.dm.LibrariesForLibs import org.gradle.api.Project import org.gradle.api.tasks.testing.Test import org.gradle.api.tasks.testing.logging.TestLogEvent +import org.gradle.kotlin.dsl.configure import org.gradle.kotlin.dsl.dependencies +import org.gradle.kotlin.dsl.provideDelegate import org.gradle.kotlin.dsl.the import org.gradle.kotlin.dsl.withType +import org.jetbrains.kotlin.compose.compiler.gradle.ComposeCompilerGradlePluginExtension import org.jetbrains.kotlin.gradle.tasks.KotlinCompile val Project.androidx get() = the() @@ -37,15 +40,18 @@ internal fun Project.configureAndroid(commonExtension: CommonExtension<*, *, *, } tasks.withType().configureEach { - kotlinOptions { - jvmTarget = AndroidConfig.JavaVersion.toString() - // freeCompilerArgs += "-opt-in=kotlin.RequiresOptIn" - // freeCompilerArgs += "-Xcontext-receivers" + compilerOptions { + jvmTarget.set(AndroidConfig.JvmTarget) + freeCompilerArgs.addAll( + "-opt-in=kotlin.RequiresOptIn", + "-Xcontext-receivers", + ) // Treat all Kotlin warnings as errors (disabled by default) // Override by setting warningsAsErrors=true in your ~/.gradle/gradle.properties - // val warningsAsErrors: String? by project - // allWarningsAsErrors = warningsAsErrors.toBoolean() + val warningsAsErrors: String? by project + allWarningsAsErrors.set(warningsAsErrors.toBoolean()) + } } @@ -55,51 +61,41 @@ internal fun Project.configureAndroid(commonExtension: CommonExtension<*, *, *, } internal fun Project.configureCompose(commonExtension: CommonExtension<*, *, *, *, *, *>) { + pluginManager.apply(kotlinx.plugins.compose.compiler.get().pluginId) + commonExtension.apply { buildFeatures { compose = true } - composeOptions { - kotlinCompilerExtensionVersion = compose.versions.compiler.get() - } - dependencies { "implementation"(platform(compose.bom)) } } - tasks.withType().configureEach { - kotlinOptions { - freeCompilerArgs += buildComposeMetricsParameters() + extensions.configure { + // Enable strong skipping mode + enableStrongSkippingMode.set(true) - // Enable experimental compiler opts - // https://developer.android.com/jetpack/androidx/releases/compose-compiler#1.5.9 - freeCompilerArgs += listOf( - "-P", - "plugin:androidx.compose.compiler.plugins.kotlin:nonSkippingGroupOptimization=true", - ) + // Enable experimental compiler opts + // https://developer.android.com/jetpack/androidx/releases/compose-compiler#1.5.9 + enableNonSkippingGroupOptimization.set(true) + + val enableMetrics = project.providers.gradleProperty("enableComposeCompilerMetrics").orNull.toBoolean() + val enableReports = project.providers.gradleProperty("enableComposeCompilerReports").orNull.toBoolean() + + val rootProjectDir = rootProject.layout.buildDirectory.asFile.get() + val relativePath = projectDir.relativeTo(rootDir) + if (enableMetrics) { + val buildDirPath = rootProjectDir.resolve("compose-metrics").resolve(relativePath) + metricsDestination.set(buildDirPath) + } + if (enableReports) { + val buildDirPath = rootProjectDir.resolve("compose-reports").resolve(relativePath) + reportsDestination.set(buildDirPath) } } -} -private fun Project.buildComposeMetricsParameters(): List { - val rootProjectDir = rootProject.layout.buildDirectory.asFile.get() - val relativePath = projectDir.relativeTo(rootDir) - - val enableMetrics = project.providers.gradleProperty("enableComposeCompilerMetrics").orNull.toBoolean() - val enableReports = project.providers.gradleProperty("enableComposeCompilerReports").orNull.toBoolean() - - return listOfNotNull( - ("metricsDestination" to "compose-metrics").takeIf { enableMetrics }, - ("reportsDestination" to "compose-reports").takeIf { enableReports }, - ).flatMap { (flag, dirName) -> - val buildDirPath = rootProjectDir.resolve(dirName).resolve(relativePath).absolutePath - listOf( - "-P", - "plugin:androidx.compose.compiler.plugins.kotlin:$flag=$buildDirPath" - ) - } } internal fun Project.configureTest() { diff --git a/data/build.gradle.kts b/data/build.gradle.kts index e3f9d9004..2fded2043 100644 --- a/data/build.gradle.kts +++ b/data/build.gradle.kts @@ -33,7 +33,7 @@ dependencies { tasks { withType { - kotlinOptions.freeCompilerArgs += listOf( + compilerOptions.freeCompilerArgs.addAll( "-Xcontext-receivers", "-opt-in=kotlinx.serialization.ExperimentalSerializationApi", ) diff --git a/domain/build.gradle.kts b/domain/build.gradle.kts index c49c5bc51..5e2357181 100644 --- a/domain/build.gradle.kts +++ b/domain/build.gradle.kts @@ -31,7 +31,7 @@ dependencies { tasks { withType { - kotlinOptions.freeCompilerArgs += listOf( + compilerOptions.freeCompilerArgs.addAll( "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi", "-Xcontext-receivers", ) diff --git a/gradle/compose.versions.toml b/gradle/compose.versions.toml index 3f1d253e1..ea04b45ff 100644 --- a/gradle/compose.versions.toml +++ b/gradle/compose.versions.toml @@ -1,11 +1,8 @@ [versions] -compiler = "1.5.14" compose-bom = "2024.05.00-alpha02" accompanist = "0.35.0-alpha" [libraries] -compiler = { module = "androidx.compose.compiler:compiler", version.ref = "compiler" } - activity = "androidx.activity:activity-compose:1.9.0" bom = { group = "dev.chrisbanes.compose", name = "compose-bom", version.ref = "compose-bom" } foundation = { module = "androidx.compose.foundation:foundation" } diff --git a/gradle/kotlinx.versions.toml b/gradle/kotlinx.versions.toml index 66e69752a..6cfb1bdd9 100644 --- a/gradle/kotlinx.versions.toml +++ b/gradle/kotlinx.versions.toml @@ -1,11 +1,12 @@ [versions] -kotlin_version = "1.9.24" +kotlin_version = "2.0.0" serialization_version = "1.6.3" xml_serialization_version = "0.86.3" [libraries] reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin_version" } gradle = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin_version" } +compose-compiler-gradle = { module = "org.jetbrains.kotlin:compose-compiler-gradle-plugin", version.ref = "kotlin_version" } immutables = { module = "org.jetbrains.kotlinx:kotlinx-collections-immutable", version = "0.3.7" } @@ -28,4 +29,5 @@ serialization = ["serialization-json", "serialization-json-okio", "serialization [plugins] android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin_version" } +compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin_version" } serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin_version" } \ No newline at end of file diff --git a/i18n/build.gradle.kts b/i18n/build.gradle.kts index c782eac0f..bdfe09b97 100644 --- a/i18n/build.gradle.kts +++ b/i18n/build.gradle.kts @@ -50,7 +50,7 @@ tasks { } withType { - kotlinOptions.freeCompilerArgs += listOf( + compilerOptions.freeCompilerArgs.addAll( "-Xexpect-actual-classes", ) } diff --git a/presentation-core/build.gradle.kts b/presentation-core/build.gradle.kts index 8fca92019..c6e5c0b65 100644 --- a/presentation-core/build.gradle.kts +++ b/presentation-core/build.gradle.kts @@ -34,7 +34,7 @@ dependencies { tasks { // See https://kotlinlang.org/docs/reference/experimental.html#experimental-status-of-experimental-api(-markers) withType { - kotlinOptions.freeCompilerArgs += listOf( + compilerOptions.freeCompilerArgs.addAll( "-opt-in=androidx.compose.foundation.layout.ExperimentalLayoutApi", "-opt-in=androidx.compose.material.ExperimentalMaterialApi", "-opt-in=androidx.compose.material3.ExperimentalMaterial3Api", diff --git a/source-api/build.gradle.kts b/source-api/build.gradle.kts index ae28caa14..7ac4d6e2c 100644 --- a/source-api/build.gradle.kts +++ b/source-api/build.gradle.kts @@ -38,7 +38,7 @@ android { tasks { withType { - kotlinOptions.freeCompilerArgs += listOf( + compilerOptions.freeCompilerArgs.addAll( "-Xexpect-actual-classes", ) } diff --git a/source-local/build.gradle.kts b/source-local/build.gradle.kts index b63ae8fab..b0a720b97 100644 --- a/source-local/build.gradle.kts +++ b/source-local/build.gradle.kts @@ -40,7 +40,7 @@ android { tasks { withType { - kotlinOptions.freeCompilerArgs += listOf( + compilerOptions.freeCompilerArgs.addAll( "-Xexpect-actual-classes", "-opt-in=kotlinx.serialization.ExperimentalSerializationApi", ) diff --git a/source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt b/source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt index 06ed4551d..8efea5fd2 100644 --- a/source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt +++ b/source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt @@ -7,6 +7,7 @@ import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.UnmeteredSource import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.MangasPage +import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.util.lang.compareToCaseInsensitiveNaturalOrder @@ -20,17 +21,17 @@ import mihon.core.common.extensions.toZipFile import nl.adaptivity.xmlutil.AndroidXmlReader import nl.adaptivity.xmlutil.serialization.XML import tachiyomi.core.common.i18n.stringResource -import tachiyomi.core.metadata.comicinfo.COMIC_INFO_FILE -import tachiyomi.core.metadata.comicinfo.ComicInfo -import tachiyomi.core.metadata.comicinfo.copyFromComicInfo -import tachiyomi.core.metadata.comicinfo.getComicInfo -import tachiyomi.core.metadata.tachiyomi.MangaDetails import tachiyomi.core.common.storage.extension import tachiyomi.core.common.storage.nameWithoutExtension import tachiyomi.core.common.storage.openReadOnlyChannel import tachiyomi.core.common.util.lang.withIOContext import tachiyomi.core.common.util.system.ImageUtil import tachiyomi.core.common.util.system.logcat +import tachiyomi.core.metadata.comicinfo.COMIC_INFO_FILE +import tachiyomi.core.metadata.comicinfo.ComicInfo +import tachiyomi.core.metadata.comicinfo.copyFromComicInfo +import tachiyomi.core.metadata.comicinfo.getComicInfo +import tachiyomi.core.metadata.tachiyomi.MangaDetails import tachiyomi.domain.chapter.service.ChapterRecognition import tachiyomi.domain.manga.model.Manga import tachiyomi.i18n.MR @@ -294,7 +295,7 @@ actual class LocalSource( override fun getFilterList() = FilterList(OrderBy.Popular(context)) // Unused stuff - override suspend fun getPageList(chapter: SChapter) = throw UnsupportedOperationException("Unused") + override suspend fun getPageList(chapter: SChapter): List = throw UnsupportedOperationException("Unused") fun getFormat(chapter: SChapter): Format { try { From 71b558cb34c4e2da435877f391e57b6d49c4ef4f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 7 Jun 2024 03:58:55 +0600 Subject: [PATCH 041/297] fix(deps): update serialization.version to v1.7.0 (#870) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/kotlinx.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/kotlinx.versions.toml b/gradle/kotlinx.versions.toml index 6cfb1bdd9..ee3c15715 100644 --- a/gradle/kotlinx.versions.toml +++ b/gradle/kotlinx.versions.toml @@ -1,6 +1,6 @@ [versions] kotlin_version = "2.0.0" -serialization_version = "1.6.3" +serialization_version = "1.7.0" xml_serialization_version = "0.86.3" [libraries] From 777a071f4a2f32efc3447d118afd8b48006b3919 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 7 Jun 2024 04:23:27 +0600 Subject: [PATCH 042/297] fix(deps): update dependency dev.chrisbanes.compose:compose-bom to v2024.05.00-alpha03 (#843) * fix(deps): update dependency dev.chrisbanes.compose:compose-bom to v2024.05.00-alpha03 * Fix build --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com> --- .../java/eu/kanade/presentation/browse/ExtensionsScreen.kt | 2 +- app/src/main/java/eu/kanade/presentation/components/AppBar.kt | 2 +- .../kanade/presentation/library/components/LibraryContent.kt | 2 +- app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt | 4 ++-- .../main/java/eu/kanade/presentation/updates/UpdatesScreen.kt | 2 +- gradle/compose.versions.toml | 4 ++-- .../presentation/core/components/material/PullRefresh.kt | 4 ++-- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/browse/ExtensionsScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/ExtensionsScreen.kt index a3cb94800..5849e8c9e 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/ExtensionsScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/ExtensionsScreen.kt @@ -90,7 +90,7 @@ fun ExtensionScreen( PullRefresh( refreshing = state.isRefreshing, onRefresh = onRefresh, - enabled = { !state.isLoading }, + enabled = !state.isLoading, ) { when { state.isLoading -> LoadingScreen(Modifier.padding(contentPadding)) diff --git a/app/src/main/java/eu/kanade/presentation/components/AppBar.kt b/app/src/main/java/eu/kanade/presentation/components/AppBar.kt index 01dcb575c..2315e0050 100644 --- a/app/src/main/java/eu/kanade/presentation/components/AppBar.kt +++ b/app/src/main/java/eu/kanade/presentation/components/AppBar.kt @@ -179,7 +179,7 @@ fun AppBarTitle( maxLines = 1, overflow = TextOverflow.Ellipsis, modifier = Modifier.basicMarquee( - delayMillis = 2_000, + repeatDelayMillis = 2_000, ), ) } diff --git a/app/src/main/java/eu/kanade/presentation/library/components/LibraryContent.kt b/app/src/main/java/eu/kanade/presentation/library/components/LibraryContent.kt index f0a63f597..61da10345 100644 --- a/app/src/main/java/eu/kanade/presentation/library/components/LibraryContent.kt +++ b/app/src/main/java/eu/kanade/presentation/library/components/LibraryContent.kt @@ -93,7 +93,7 @@ fun LibraryContent( isRefreshing = false } }, - enabled = { notSelectionMode }, + enabled = notSelectionMode, ) { LibraryPager( state = pagerState, diff --git a/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt b/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt index efe44ceb4..91546f57f 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt @@ -355,7 +355,7 @@ private fun MangaScreenSmallImpl( PullRefresh( refreshing = state.isRefreshingData, onRefresh = onRefresh, - enabled = { !isAnySelected }, + enabled = !isAnySelected, indicatorPadding = PaddingValues(top = topPadding), ) { val layoutDirection = LocalLayoutDirection.current @@ -601,7 +601,7 @@ fun MangaScreenLargeImpl( PullRefresh( refreshing = state.isRefreshingData, onRefresh = onRefresh, - enabled = { !isAnySelected }, + enabled = !isAnySelected, indicatorPadding = PaddingValues( start = insetPadding.calculateStartPadding(layoutDirection), top = with(density) { topBarHeight.toDp() }, diff --git a/app/src/main/java/eu/kanade/presentation/updates/UpdatesScreen.kt b/app/src/main/java/eu/kanade/presentation/updates/UpdatesScreen.kt index fa2bd53fe..5693185c0 100644 --- a/app/src/main/java/eu/kanade/presentation/updates/UpdatesScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/updates/UpdatesScreen.kt @@ -104,7 +104,7 @@ fun UpdateScreen( isRefreshing = false } }, - enabled = { !state.selectionMode }, + enabled = !state.selectionMode, indicatorPadding = contentPadding, ) { FastScrollLazyColumn( diff --git a/gradle/compose.versions.toml b/gradle/compose.versions.toml index ea04b45ff..85091b5d3 100644 --- a/gradle/compose.versions.toml +++ b/gradle/compose.versions.toml @@ -1,6 +1,6 @@ [versions] -compose-bom = "2024.05.00-alpha02" -accompanist = "0.35.0-alpha" +compose-bom = "2024.05.00-alpha03" +accompanist = "0.35.1-alpha" [libraries] activity = "androidx.activity:activity-compose:1.9.0" diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/PullRefresh.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/PullRefresh.kt index b1987185b..08b10cdaa 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/PullRefresh.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/PullRefresh.kt @@ -22,7 +22,7 @@ import androidx.compose.ui.unit.dp @Composable fun PullRefresh( refreshing: Boolean, - enabled: () -> Boolean, + enabled: Boolean, onRefresh: () -> Unit, modifier: Modifier = Modifier, indicatorPadding: PaddingValues = PaddingValues(0.dp), @@ -36,7 +36,7 @@ fun PullRefresh( state = state, enabled = enabled, onRefresh = onRefresh, - ) + ), ) { content() From 1edd55c981aa72faf49c06173f33bf0c2f99fe60 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 7 Jun 2024 04:26:25 +0600 Subject: [PATCH 043/297] fix(deps): update okhttp monorepo to v5.0.0-alpha.14 (#688) * fix(deps): update okhttp monorepo to v5.0.0-alpha.14 * Fix build --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com> --- .../java/eu/kanade/tachiyomi/data/coil/MangaCoverFetcher.kt | 3 ++- gradle/libs.versions.toml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/coil/MangaCoverFetcher.kt b/app/src/main/java/eu/kanade/tachiyomi/data/coil/MangaCoverFetcher.kt index 11ff6a277..65a142099 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/coil/MangaCoverFetcher.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/coil/MangaCoverFetcher.kt @@ -21,7 +21,6 @@ import okhttp3.CacheControl import okhttp3.Call import okhttp3.Request import okhttp3.Response -import okhttp3.internal.http.HTTP_NOT_MODIFIED import okio.FileSystem import okio.Path.Companion.toOkioPath import okio.Source @@ -348,5 +347,7 @@ class MangaCoverFetcher( private val CACHE_CONTROL_NO_STORE = CacheControl.Builder().noStore().build() private val CACHE_CONTROL_NO_NETWORK_NO_CACHE = CacheControl.Builder().noCache().onlyIfCached().build() + + private const val HTTP_NOT_MODIFIED = 304 } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ad58e9e7b..b2f303917 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,7 +2,7 @@ aboutlib_version = "11.2.1" leakcanary = "2.14" moko = "0.23.0" -okhttp_version = "5.0.0-alpha.12" +okhttp_version = "5.0.0-alpha.14" richtext = "0.20.0" shizuku_version = "12.2.0" sqldelight = "2.0.2" From 15d999229fcce865001d5fa77d0163e6e80e38db Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Fri, 7 Jun 2024 04:30:17 +0600 Subject: [PATCH 044/297] MangaChapterListItem: Don't use alpha modifier Possibly fixes #822 Co-authored-by: Ivan Iskandar <12537387+ivaniskandar@users.noreply.github.com> --- .../manga/components/MangaChapterListItem.kt | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/manga/components/MangaChapterListItem.kt b/app/src/main/java/eu/kanade/presentation/manga/components/MangaChapterListItem.kt index 12720957e..6f323993c 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/components/MangaChapterListItem.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/components/MangaChapterListItem.kt @@ -30,7 +30,6 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.clipToBounds import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector @@ -66,9 +65,6 @@ fun MangaChapterListItem( onChapterSwipe: (LibraryPreferences.ChapterSwipeAction) -> Unit, modifier: Modifier = Modifier, ) { - val textAlpha = if (read) ReadItemAlpha else 1f - val textSubtitleAlpha = if (read) ReadItemAlpha else SecondaryItemAlpha - val start = getSwipeAction( action = chapterSwipeStartAction, read = read, @@ -133,15 +129,20 @@ fun MangaChapterListItem( Text( text = title, style = MaterialTheme.typography.bodyMedium, - color = LocalContentColor.current.copy(alpha = textAlpha), maxLines = 1, overflow = TextOverflow.Ellipsis, onTextLayout = { textHeight = it.size.height }, + color = LocalContentColor.current.copy(alpha = if (read) ReadItemAlpha else 1f), ) } - Row(modifier = Modifier.alpha(textSubtitleAlpha)) { - ProvideTextStyle(value = MaterialTheme.typography.bodySmall) { + Row { + val subtitleStyle = MaterialTheme.typography.bodySmall + .merge( + color = LocalContentColor.current + .copy(alpha = if (read) ReadItemAlpha else SecondaryItemAlpha) + ) + ProvideTextStyle(value = subtitleStyle) { if (date != null) { Text( text = date, From bdce3c39f1475dc77dad300a0bf3702e85d32916 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 7 Jun 2024 14:58:19 +0600 Subject: [PATCH 045/297] fix(deps): update dependency io.github.fornewid:material-motion-compose-core to v2 (#873) 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 b2f303917..bdb58f6f4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -62,7 +62,7 @@ flexible-adapter-core = "com.github.arkon.FlexibleAdapter:flexible-adapter:c8013 photoview = "com.github.chrisbanes:PhotoView:2.3.0" directionalviewpager = "com.github.tachiyomiorg:DirectionalViewPager:1.0.0" insetter = "dev.chrisbanes.insetter:insetter:0.6.1" -compose-materialmotion = "io.github.fornewid:material-motion-compose-core:1.2.1" +compose-materialmotion = "io.github.fornewid:material-motion-compose-core:2.0.0" compose-webview = "io.github.kevinnzou:compose-webview:0.33.6" compose-grid = "io.woong.compose.grid:grid:1.2.2" From 87fe64468ca08466af5b9fcc7f9e17e9a23021e6 Mon Sep 17 00:00:00 2001 From: "Weblate (bot)" Date: Fri, 7 Jun 2024 15:30:00 +0200 Subject: [PATCH 046/297] Translations update from Hosted Weblate (#611) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Translated using Weblate (Malayalam) Currently translated at 12.9% (104 of 803 strings) Translated using Weblate (Malayalam) Currently translated at 94.4% (17 of 18 strings) Translated using Weblate (Malayalam) Currently translated at 11.8% (95 of 803 strings) Added translation using Weblate (Malayalam) Added translation using Weblate (Malayalam) Co-authored-by: Akhil Raj Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/ml/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ml/ Translation: Mihon/Mihon Translation: Mihon/Mihon Plurals * Translated using Weblate (Italian) Currently translated at 99.6% (800 of 803 strings) Co-authored-by: Federico Pierantoni Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/it/ Translation: Mihon/Mihon * Translated using Weblate (Hungarian) Currently translated at 100.0% (803 of 803 strings) Translated using Weblate (Hungarian) Currently translated at 100.0% (803 of 803 strings) Co-authored-by: B4LiN7 Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/hu/ Translation: Mihon/Mihon * Translated using Weblate (Javanese) Currently translated at 38.7% (311 of 803 strings) Translated using Weblate (Japanese) Currently translated at 100.0% (803 of 803 strings) Translated using Weblate (Indonesian) Currently translated at 98.7% (793 of 803 strings) Co-authored-by: TheKingTermux Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/id/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ja/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/jv/ Translation: Mihon/Mihon * Translated using Weblate (Greek) Currently translated at 100.0% (803 of 803 strings) Co-authored-by: Pitpe11 Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/el/ Translation: Mihon/Mihon * Translated using Weblate (Serbian) Currently translated at 99.2% (797 of 803 strings) Co-authored-by: Rikishaaa Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/sr/ Translation: Mihon/Mihon * Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (803 of 803 strings) Co-authored-by: Blackiezin Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/pt_BR/ Translation: Mihon/Mihon * Translated using Weblate (French) Currently translated at 100.0% (18 of 18 strings) Translated using Weblate (French) Currently translated at 99.0% (795 of 803 strings) Co-authored-by: LaQuiche426 Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/fr/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/fr/ Translation: Mihon/Mihon Translation: Mihon/Mihon Plurals * Translated using Weblate (Portuguese) Currently translated at 99.8% (802 of 803 strings) Co-authored-by: ssantos Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/pt/ Translation: Mihon/Mihon * Translated using Weblate (Vietnamese) Currently translated at 100.0% (18 of 18 strings) Translated using Weblate (Vietnamese) Currently translated at 96.8% (778 of 803 strings) Co-authored-by: Karuto Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/vi/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/vi/ Translation: Mihon/Mihon Translation: Mihon/Mihon Plurals * Translated using Weblate (Croatian) Currently translated at 99.5% (799 of 803 strings) Co-authored-by: Milo Ivir Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/hr/ Translation: Mihon/Mihon * Translated using Weblate (Indonesian) Currently translated at 100.0% (803 of 803 strings) Co-authored-by: Eji-san Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/id/ Translation: Mihon/Mihon * Translated using Weblate (Galician) Currently translated at 100.0% (803 of 803 strings) Co-authored-by: kevans Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/gl/ Translation: Mihon/Mihon * Translated using Weblate (Ukrainian) Currently translated at 99.8% (802 of 803 strings) Co-authored-by: Kodekiro Kodekihara Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/uk/ Translation: Mihon/Mihon * Translated using Weblate (Malay) Currently translated at 98.6% (792 of 803 strings) Co-authored-by: Farith Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ms/ Translation: Mihon/Mihon * Translated using Weblate (Nepali) Currently translated at 100.0% (18 of 18 strings) Translated using Weblate (Nepali) Currently translated at 100.0% (803 of 803 strings) Co-authored-by: FateXBlood Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/ne/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ne/ Translation: Mihon/Mihon Translation: Mihon/Mihon Plurals * Translated using Weblate (Vietnamese) Currently translated at 100.0% (803 of 803 strings) Translation: Mihon/Mihon Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/vi/ * Translated using Weblate (Croatian) Currently translated at 100.0% (803 of 803 strings) Translation: Mihon/Mihon Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/hr/ * Translated using Weblate (Spanish) Currently translated at 100.0% (18 of 18 strings) Translation: Mihon/Mihon Plurals Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/es/ * Translated using Weblate (Romanian) Currently translated at 99.6% (800 of 803 strings) Translation: Mihon/Mihon Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ro/ * Translated using Weblate (Romanian) Currently translated at 100.0% (18 of 18 strings) Translation: Mihon/Mihon Plurals Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/ro/ * Translated using Weblate (Italian) Currently translated at 100.0% (803 of 803 strings) Translation: Mihon/Mihon Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/it/ * Translated using Weblate (Polish) Currently translated at 99.5% (799 of 803 strings) Translation: Mihon/Mihon Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/pl/ * Translated using Weblate (Spanish) Currently translated at 100.0% (803 of 803 strings) Translation: Mihon/Mihon Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/es/ * Translated using Weblate (German) Currently translated at 100.0% (804 of 804 strings) Translation: Mihon/Mihon Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/de/ * Translated using Weblate (Russian) Currently translated at 100.0% (804 of 804 strings) Translation: Mihon/Mihon Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ru/ * Translated using Weblate (French) Currently translated at 99.5% (800 of 804 strings) Translation: Mihon/Mihon Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/fr/ * Translated using Weblate (Filipino) Currently translated at 99.8% (803 of 804 strings) Translation: Mihon/Mihon Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/fil/ * Translated using Weblate (Nepali) Currently translated at 100.0% (804 of 804 strings) Translation: Mihon/Mihon Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ne/ * Translated using Weblate (Catalan) Currently translated at 100.0% (804 of 804 strings) Translation: Mihon/Mihon Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ca/ * Translated using Weblate (Spanish) Currently translated at 100.0% (804 of 804 strings) Translation: Mihon/Mihon Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/es/ * Translated using Weblate (Catalan) Currently translated at 100.0% (18 of 18 strings) Translation: Mihon/Mihon Plurals Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/ca/ --------- Co-authored-by: Akhil Raj Co-authored-by: Federico Pierantoni Co-authored-by: B4LiN7 Co-authored-by: TheKingTermux Co-authored-by: Pitpe11 Co-authored-by: Rikishaaa Co-authored-by: Blackiezin Co-authored-by: LaQuiche426 Co-authored-by: ssantos Co-authored-by: Karuto Co-authored-by: Milo Ivir Co-authored-by: Eji-san Co-authored-by: kevans Co-authored-by: Kodekiro Kodekihara Co-authored-by: Farith Co-authored-by: FateXBlood Co-authored-by: Nguyễn Trung Đức Co-authored-by: Chrono Lux Co-authored-by: Saft Octavian Co-authored-by: Giorgio Sanna Co-authored-by: sebastians17 Co-authored-by: Tim Schneeberger Co-authored-by: Dexroneum Co-authored-by: Naga Co-authored-by: Infy's Tagalog Translations Co-authored-by: Eduard Ereza Martínez Co-authored-by: gallegonovato --- .../commonMain/resources/MR/ca/plurals.xml | 5 + .../commonMain/resources/MR/ca/strings.xml | 14 +++ .../commonMain/resources/MR/de/strings.xml | 1 + .../commonMain/resources/MR/el/strings.xml | 12 +++ .../commonMain/resources/MR/es/plurals.xml | 12 +-- .../commonMain/resources/MR/es/strings.xml | 17 +-- .../commonMain/resources/MR/fil/strings.xml | 1 + .../commonMain/resources/MR/fr/plurals.xml | 5 + .../commonMain/resources/MR/fr/strings.xml | 10 ++ .../commonMain/resources/MR/gl/strings.xml | 45 +++++++- .../commonMain/resources/MR/hr/strings.xml | 11 ++ .../commonMain/resources/MR/hu/strings.xml | 14 +-- .../commonMain/resources/MR/in/strings.xml | 12 +++ .../commonMain/resources/MR/it/strings.xml | 5 + .../commonMain/resources/MR/ja/strings.xml | 6 +- .../commonMain/resources/MR/jv/strings.xml | 3 + .../commonMain/resources/MR/ml/plurals.xml | 71 ++++++++++++ .../commonMain/resources/MR/ml/strings.xml | 102 ++++++++++++++++++ .../commonMain/resources/MR/ms/strings.xml | 1 + .../commonMain/resources/MR/ne/plurals.xml | 4 + .../commonMain/resources/MR/ne/strings.xml | 18 ++-- .../commonMain/resources/MR/pl/strings.xml | 7 ++ .../resources/MR/pt-rBR/strings.xml | 12 +++ .../commonMain/resources/MR/pt/strings.xml | 95 ++++++++++++++++ .../commonMain/resources/MR/ro/plurals.xml | 5 + .../commonMain/resources/MR/ro/strings.xml | 28 +++-- .../commonMain/resources/MR/ru/strings.xml | 1 + .../commonMain/resources/MR/sr/strings.xml | 5 + .../commonMain/resources/MR/uk/strings.xml | 14 ++- .../commonMain/resources/MR/vi/plurals.xml | 6 ++ .../commonMain/resources/MR/vi/strings.xml | 30 ++++++ 31 files changed, 529 insertions(+), 43 deletions(-) create mode 100644 i18n/src/commonMain/resources/MR/ml/plurals.xml create mode 100644 i18n/src/commonMain/resources/MR/ml/strings.xml diff --git a/i18n/src/commonMain/resources/MR/ca/plurals.xml b/i18n/src/commonMain/resources/MR/ca/plurals.xml index 89fd5c350..78d4572c3 100644 --- a/i18n/src/commonMain/resources/MR/ca/plurals.xml +++ b/i18n/src/commonMain/resources/MR/ca/plurals.xml @@ -85,4 +85,9 @@ %d repositoris %d repositoris + + Demà + D’aquí a %1$d dies + D’aquí a %1$d dies + \ No newline at end of file diff --git a/i18n/src/commonMain/resources/MR/ca/strings.xml b/i18n/src/commonMain/resources/MR/ca/strings.xml index bc63d1260..d54f800aa 100644 --- a/i18n/src/commonMain/resources/MR/ca/strings.xml +++ b/i18n/src/commonMain/resources/MR/ca/strings.xml @@ -796,4 +796,18 @@ Aviat Freqüència d’actualització personalitzada: Obre el repositori d’origen + No s’ha pogut obtenir accés persistent a la carpeta. És possible que l’aplicació es comporti de manera inesperada. + Pròxim + Guia de pròximes actualitzacions + Mes següent + Afegeix igualment + Migra l’element existent + Desactiva l’allunyament + Substitueix + L’empremta digital de la clau de xifratge ja existeix + La clau de xifratge del repositori %1$s té la mateixa empremta digital que %2$s. +\nSi espereu que sigui així, se substituirà %2$s. En cas contrari, contacteu amb el mantenidor del repositori. + Perfil de visualització personalitzat + Mostra les pròximes actualitzacions + Mes anterior \ No newline at end of file diff --git a/i18n/src/commonMain/resources/MR/de/strings.xml b/i18n/src/commonMain/resources/MR/de/strings.xml index 7978b5a8c..25893556d 100644 --- a/i18n/src/commonMain/resources/MR/de/strings.xml +++ b/i18n/src/commonMain/resources/MR/de/strings.xml @@ -809,4 +809,5 @@ Bevorstehend Bevorstehende Aktualisierungen ansehen Leitfaden für Bevorstehendes + Dauerhafter Ordnerzugriff konnte nicht erlangt werden. Die App kann sich unerwartet verhalten. \ No newline at end of file diff --git a/i18n/src/commonMain/resources/MR/el/strings.xml b/i18n/src/commonMain/resources/MR/el/strings.xml index 00fb56e96..54691d40c 100644 --- a/i18n/src/commonMain/resources/MR/el/strings.xml +++ b/i18n/src/commonMain/resources/MR/el/strings.xml @@ -797,4 +797,16 @@ Ανάκληση αξιόπιστων άγνωστων επεκτάσεων Αποθετήριο ανοικτού κώδικα Απενεργοποίηση σμίκρυνσης εικόνας + Προσθέστε ούτως ή άλλως + Το αποθετήριο %1$s έχει το ίδιο δακτυλικό αποτύπωμα κλειδιού υπογραφής με το %2$s. +\nΕάν αυτό είναι αναμενόμενο, το %2$s θα αντικατασταθεί, διαφορετικά επικοινωνήστε με τον συντηρητή του αποθετηρίου σας. + Ανερχόμενο + Μεταφορά υπάρχουσας καταχώρησης + Προσαρμοσμένο προφίλ εμφάνισης + Δείτε τις επερχόμενες ενημερώσεις + Αντικατάσταση + Το δακτυλικό αποτύπωμα κλειδιού υπογραφής υπάρχει ήδη + Οδηγός ανερχόμενων + Επόμενο μήνα + Προηγούμενο Μήνα \ No newline at end of file diff --git a/i18n/src/commonMain/resources/MR/es/plurals.xml b/i18n/src/commonMain/resources/MR/es/plurals.xml index 08f01feea..21cff773b 100644 --- a/i18n/src/commonMain/resources/MR/es/plurals.xml +++ b/i18n/src/commonMain/resources/MR/es/plurals.xml @@ -1,7 +1,7 @@ - Tras %1$s minuto + Tras %1$s minutos Tras %1$s minutos Tras %1$s minutos @@ -26,9 +26,9 @@ %d actualizaciones de extensiones disponibles - Queda %1$s - Quedan %1$s - Quedan %1$s + Restante %1$s + Restantes %1$s + Restantes %1$s %d categoría @@ -61,8 +61,8 @@ Hace %1$d días - El siguiente capítulo sin leer - Los siguientes %d capítulos sin leer + Siguiente capítulo sin leer + Siguientes %d capítulos sin leer Los siguientes %d capítulos sin leer diff --git a/i18n/src/commonMain/resources/MR/es/strings.xml b/i18n/src/commonMain/resources/MR/es/strings.xml index 7c5a558c1..4e6501b9b 100644 --- a/i18n/src/commonMain/resources/MR/es/strings.xml +++ b/i18n/src/commonMain/resources/MR/es/strings.xml @@ -158,7 +158,7 @@ No se ha podido descargar el capítulo debido a un error inesperado No estás conectado a ninguna red Wi-Fi Categorías - Títulos en la biblioteca + Entradas de biblioteca Seguimiento Historial Favoritos @@ -508,8 +508,8 @@ Servicios de seguimiento mejorados Guía de seguimiento Automático - No - + Apagado + Encendido Establecer el tipo de orden para cada categoría Actividad en segundo plano Seguir @@ -679,7 +679,7 @@ Ver número de capítulos por leer en el icono de actualizaciones Se ha copiado al portapapeles Saltarse los capítulos repetidos - Están disponibles, pero las fuentes todavía no se han instalado: %s + Disponible, pero fuente no instalada: %s Ya tienes un elemento en la biblioteca con este mismo nombre. \n \n¿Seguro que quieres continuar? @@ -710,7 +710,7 @@ ¿Quieres desvincular %s? Esto eliminará el seguimiento localmente. Quitar también de %s - Borrar los ya descargados + Eliminar descargados Con resultados La biblioteca se ha sincronizado correctamente Sincronizando la biblioteca @@ -740,15 +740,15 @@ Almacenamiento utilizado Puntuación del rastreador Aplicar - Restablecer vista + Restablecer valor predeterminado Crear No se ha encontrado ningún equipo de traducción Equipo de traducción Excluir equipo de traducción Seleccionado - Sin seleccionar + No seleccionado Más opciones - Subir un nivel + Navegar hacia arriba Ubicación del almacenamiento Se utiliza para las copias de seguridad automáticas, poder descargar capítulos y abrir los que ya tengas en tu dispositivo. Elige una carpeta @@ -809,4 +809,5 @@ Próxima guía Próximo mes Mes anterior + No se ha podido obtener acceso a la carpeta persistente. La aplicación puede comportarse de forma inesperada. \ No newline at end of file diff --git a/i18n/src/commonMain/resources/MR/fil/strings.xml b/i18n/src/commonMain/resources/MR/fil/strings.xml index 58c86182b..df8b126ad 100644 --- a/i18n/src/commonMain/resources/MR/fil/strings.xml +++ b/i18n/src/commonMain/resources/MR/fil/strings.xml @@ -809,4 +809,5 @@ Susunod na Buwan Nakaraang Buwan Tingnan ang mga Paparating na Update + Nabigong makakuha ng patuloy na pag-access ng folder. Ang app ay magkaroon ng di-inaasahang pagkilos. \ No newline at end of file diff --git a/i18n/src/commonMain/resources/MR/fr/plurals.xml b/i18n/src/commonMain/resources/MR/fr/plurals.xml index 21e4e5eab..8d007cf27 100644 --- a/i18n/src/commonMain/resources/MR/fr/plurals.xml +++ b/i18n/src/commonMain/resources/MR/fr/plurals.xml @@ -85,4 +85,9 @@ %d dépôts %d dépôts + + Demain + Dans %1$d jours + Dans %1$d jours + \ No newline at end of file diff --git a/i18n/src/commonMain/resources/MR/fr/strings.xml b/i18n/src/commonMain/resources/MR/fr/strings.xml index 06b70876d..2764a75ef 100644 --- a/i18n/src/commonMain/resources/MR/fr/strings.xml +++ b/i18n/src/commonMain/resources/MR/fr/strings.xml @@ -796,4 +796,14 @@ Impossible de créer un fichier de sauvegarde Dernière sauvegarde automatique : %s Paramètres sources + Ajouter tout de même + Migrer l’entrée existante + À venir + Remplacer + Profil d\'affichage personnalisé + Désactiver le zoom arrière + Afficher les mises à jour à venir + Guide à venir + Le mois prochain + Le mois précédent \ No newline at end of file diff --git a/i18n/src/commonMain/resources/MR/gl/strings.xml b/i18n/src/commonMain/resources/MR/gl/strings.xml index 3c0ee8dfe..81f69686e 100644 --- a/i18n/src/commonMain/resources/MR/gl/strings.xml +++ b/i18n/src/commonMain/resources/MR/gl/strings.xml @@ -78,9 +78,9 @@ As fontes desta extensión poden ter contido NSFW (+18) +18 Esta extensión xa non está dispoñible. Pode que non funcione ben e cause problemas na aplicación. Recoméndase desinstalala. - Unha extensión maliciosa podería ler calquera credencial de inicio de sesión gardado en Mihon ou executar código arbitrario. + Unha extensión maliciosa podería ler calquera credencial de inicio de sesión gardada en Mihon ou executar calquera tipo de código. \n -\nConfiando neste certificado aceptas estes riscos. +\nSe confías nesta extensión, aceptas estes riscos. Extensión non confiable Non confiable Desinstalar @@ -754,7 +754,7 @@ «%1$s» en lugar de «%2$s» Predicir cando sae o seguinte capítulo Preme aquí para conceder os permisos para instalar extensións. - Revogar as extensións de confianza de orixe descoñecido + Revogar as extensións de confianza de orixe descoñecida Repositorios de extensións Aínda non engadiches ningún repositorio. Dirección URL do repositorio @@ -770,4 +770,43 @@ Axustes da fonte Crear Erro completo: + Non se puido crear unha copia de seguridade + Almacenamento utilizado + Eliminar tamén de %s + Invalidouse o índice de descargas + Ten resultados + Engadir de todos modos + Migrar a entrada existente + Dispoñible: %1$s / Total: %2$s + Sincronizando a biblioteca + Nunca + Proximamente + Substituír + A impresión dixital da chave da firma xa existe + O repositorio %1$s ten a misma impresión dixital da chave da firma que %2$s. +\nSe isto é o comportamento agardado, %2$s substituirase. Se no é así, contacta con quen mantén o repositorio. + Perfil de visualización personalizado + Incluír configuracións sensibles, como as chaves de inicio de sesión en plataformas de seguemento + Navegar arriba + A biblioteca sincronizouse correctamente + Intervalos + Estimar cada + Prevese que o seguinte capítulo saia en %1$s, compróbase cada %2$s. + Frecuencia de actualización personalizada: + Queres deixar de seguir %s? + Actualizando a biblioteca… (%s) + Omitiuse porque hoxe non se esperaba ningunha publicación + Non se elixiu ningún arquivo + Última copia de seguridade automática: %s + Licenciado: sen capítulos que mostrar + Actualizar cada + Pronto + Excluír equipos de tradución + Non se atopou ningún equipo de tradución + Esto eliminará o seguimento local. + Ver as próximas actualizacións + Guía dos próximos lanzamenos + Mes seguinte + Mes anterior + Preme aquí para obter axuda con Cloudflare \ No newline at end of file diff --git a/i18n/src/commonMain/resources/MR/hr/strings.xml b/i18n/src/commonMain/resources/MR/hr/strings.xml index ea77daeec..48336a888 100644 --- a/i18n/src/commonMain/resources/MR/hr/strings.xml +++ b/i18n/src/commonMain/resources/MR/hr/strings.xml @@ -798,4 +798,15 @@ Dostupno: %1$s / Ukupno: %2$s Deaktiviraj smanjivanje zumiranja Prilagođeni profil prikaza + Predstojeći + Migriraj postojeći unos + Svejedno dodaj + Prethodni mjesec + Zamijeni + Sljedeći mjesec + Pogledaj nadolazeća aktualizirane verzije + Vodič za nadolazeće verzije + Digitalni otisak prsta za potpisivanje već postoji + Repozitorij %1$s ima isti digitalni otisak ključa za potpisivanje kao %2$s. +\nAko se to očekuje, %2$s će se zamijeniti, u suprotnom se obrati svom održavatelju repozitorija. \ No newline at end of file diff --git a/i18n/src/commonMain/resources/MR/hu/strings.xml b/i18n/src/commonMain/resources/MR/hu/strings.xml index 370d7bb77..51c00c3eb 100644 --- a/i18n/src/commonMain/resources/MR/hu/strings.xml +++ b/i18n/src/commonMain/resources/MR/hu/strings.xml @@ -69,7 +69,7 @@ Olvasatlan Szűrők eltávolítása Betűrendben - Összes fejezet + Fejezetek száma Legutóbb olvasott Globális keresés Olvasottnak jelölés @@ -431,11 +431,11 @@ Mit tartalmazzon a biztonsági mentés? Biztonsági mentés/helyreállítás nem biztos,hogy működik ha a MIUI Optimalizáció ki van kapcsolva. Helyreállítás folyamatban van - Felhasznált gyorsítótár: %1$s + Felhasznált: %1$s Adatbázis törlése Nem könyvtári elemek előzményeinek törlése %1$d nem könyvtári manga az adatbázisban - Fejezet gyorsítótár törlése kilépéskor + Fejezet gyorsítótárának törlése kilépéskor Helytelen fejezet formátum Hálózat Nem lehetett a fejezeteket letölteni. Próbálja újra a letöltések menüpontban @@ -458,7 +458,7 @@ Hibaüzenetetek törlése Sorozat beállításainak visszaállítása Néhány gyártónak extra korlátozása van arra, hogy kikapcsolja a háttér folyamatokat. Ezen a web oldalon több információt találsz, hogy hogyan oldható meg. - Olvasási előzmények megállítása + Olvasási előzmények rögzítésének szüneteltetése Fedlap Szüneteltetve Kategóriák törölve @@ -663,7 +663,7 @@ Biztos vagy benne? Kategória üres Ez eltávolítja az eddig kiválasztott befejezési dátumot a(z) %s szolgáltatásból - Olvasási idő + Olvasási időtartam Nem található elem ebben a kategóriában A/az \"%s\"-t elfogod távolítani a könyvtáradból Éppen most @@ -674,7 +674,7 @@ %s hibába ütközött. A hiba üzenetet kérünk oszd meg velünk a Discord szerverünkön. Dátum eltávolítása? Applikáció újrainditása - Globális frissités + Globális frissítésben *kötelező Fejezet csúsztatás Balra csúsztatási cselekmény @@ -721,7 +721,7 @@ Könyvtár frissítése ... (%s) Elemek Felnavigálás - Adat és tárolás + Adatok és tárolás Szeretnéd a kategóriákat betűrendbe rendezni? Átlépve, mert ma nem várható kiadás Nincs fájl kiválasztva diff --git a/i18n/src/commonMain/resources/MR/in/strings.xml b/i18n/src/commonMain/resources/MR/in/strings.xml index 286fe0752..fa8ba612c 100644 --- a/i18n/src/commonMain/resources/MR/in/strings.xml +++ b/i18n/src/commonMain/resources/MR/in/strings.xml @@ -797,4 +797,16 @@ Cabut izin ekstensi tidak dikenal yang tepercaya Repo sumber terbuka Menonaktifkan zoom out + Yang akan datang + Migrasikan entri yang ada + Repositori %1$s memiliki Signing Key Fingerprint yang sama dengan %2$s. +\nJika hal ini diharapkan, %2$s akan diganti, jika tidak, hubungi pengelola repo Anda. + Tambahkan saja + Profil tampilan khusus + Ganti + Signing Key Fingerprint sudah ada + Lihat Pembaruan Mendatang + Panduan Mendatang + Bulan Depan + Bulan Kemarin \ No newline at end of file diff --git a/i18n/src/commonMain/resources/MR/it/strings.xml b/i18n/src/commonMain/resources/MR/it/strings.xml index b147c58b4..32b150fa5 100644 --- a/i18n/src/commonMain/resources/MR/it/strings.xml +++ b/i18n/src/commonMain/resources/MR/it/strings.xml @@ -806,4 +806,9 @@ \nSe è quello che si desidera, %2$s verrà sostituita, altrimenti contatta il manutentore della repository. Sostituisci Disattiva zoom indietro + Prossimamente + Controlla i Prossimi Aggiornamenti + Guida in arrivo + Mese prossimo + Mese scorso \ No newline at end of file diff --git a/i18n/src/commonMain/resources/MR/ja/strings.xml b/i18n/src/commonMain/resources/MR/ja/strings.xml index 9add17edd..09d5268ca 100644 --- a/i18n/src/commonMain/resources/MR/ja/strings.xml +++ b/i18n/src/commonMain/resources/MR/ja/strings.xml @@ -799,7 +799,7 @@ ズームアウトを無効にする 追加 移行 - 置き換える + 交換 カスタムディスプレイプロファイル 前月 翌月 @@ -807,6 +807,6 @@ 今後のアップデート 署名キーのフィンガープリントはすでに存在します 今後のご案内 - リポジトリ %1$s は %2$s と同じ署名キーフィンガープリントを持っています。 -\nこれが予想される場合は %2$s が置き換えされますが、そうでない場合はリポジトリのメンテナーに連絡してください。 + リポジトリ %1$s は %2$s と同じ署名キー指紋を持っています。 +\nこれが予想される場合は %2$s が置換されますが、そうでない場合はリポジトリのメンテナーに連絡してください。 \ No newline at end of file diff --git a/i18n/src/commonMain/resources/MR/jv/strings.xml b/i18n/src/commonMain/resources/MR/jv/strings.xml index 852bedcf8..5eadb71b9 100644 --- a/i18n/src/commonMain/resources/MR/jv/strings.xml +++ b/i18n/src/commonMain/resources/MR/jv/strings.xml @@ -307,4 +307,7 @@ Ngehapus downloadan Dipilih Gak dipilih + Pilihan liane + Data lan penyimpanan + Bakal muncul \ No newline at end of file diff --git a/i18n/src/commonMain/resources/MR/ml/plurals.xml b/i18n/src/commonMain/resources/MR/ml/plurals.xml new file mode 100644 index 000000000..a3e67ba1c --- /dev/null +++ b/i18n/src/commonMain/resources/MR/ml/plurals.xml @@ -0,0 +1,71 @@ + + + + ഇന്നലെ + %1$d ദിവസം മുമ്പ് + + + നാളെ + %1$d ദിവസത്തിനുള്ളിൽ + + + %2$s പിശകോടെ %1$s-നുള്ളിൽ ചെയ്തു + %2$s പിശകുകളോടെ %1$s-നുള്ളിൽ ചെയ്തു + + + %d അധ്യായം ഒഴിവാക്കുന്നു, ഒന്നുകിൽ ഉറവിടം അത് കാണുന്നില്ല അല്ലെങ്കിൽ അത് ഫിൽട്ടർ ചെയ്തിരിക്കുന്നു + %d അധ്യായങ്ങൾ ഒഴിവാക്കുന്നു, ഒന്നുകിൽ ഉറവിടം കാണുന്നില്ല അല്ലെങ്കിൽ അവ ഫിൽട്ടർ ചെയ്തിരിക്കുന്നു + + + വിപുലീകരണ അപ്ഡേറ്റ് ലഭ്യമാണ് + %d വിപുലീകരണ അപ്‌ഡേറ്റുകൾ ലഭ്യമാണ് + + + അടുത്ത അധ്യായം + അടുത്ത %d അധ്യായങ്ങൾ + + + %1$s മിനിറ്റിന് ശേഷം + %1$s മിനിറ്റിന് ശേഷം + + + %d വിഭാഗം + %d വിഭാഗങ്ങൾ + + + അടുത്ത വായിക്കാത്ത അധ്യായം + അടുത്ത %d വായിക്കാത്ത അധ്യായങ്ങൾ + + + %1$s ശേഷിക്കുന്നു + %1$s ശേഷിക്കുന്നു + + + 1 ദിവസം + %d ദിവസം + + + %1$s അധ്യായം കാണുന്നില്ല + %1$s അധ്യായങ്ങൾ കാണുന്നില്ല + + + %1$s അധ്യായം + %1$s അധ്യായങ്ങൾ + + + %d ട്രാക്കർ + %d ട്രാക്കറുകൾ + + + %1$d പുതിയ അധ്യായം + %1$d പുതിയ അധ്യായങ്ങൾ + + + അധ്യായങ്ങൾ %1$s-ഉം 1-ഉം + %1$s-ഉം %2$d-ഉം അധ്യായങ്ങൾ + + + %d റിപ്പോ + %d റിപ്പോകൾ + + \ No newline at end of file diff --git a/i18n/src/commonMain/resources/MR/ml/strings.xml b/i18n/src/commonMain/resources/MR/ml/strings.xml new file mode 100644 index 000000000..7a6be0bfb --- /dev/null +++ b/i18n/src/commonMain/resources/MR/ml/strings.xml @@ -0,0 +1,102 @@ + + + ഡാറ്റാ ആന്റ് സ്റ്റോറേജ് + ചരിത്രം + തിരയുക + ആഗോള തിരയൽ + ബുക്ക്മാർക്ക് അധ്യായം + എല്ലാം പ്രവർത്തനക്ഷമമാക്കുക + വായിച്ചിട്ടില്ലെന്ന് അടയാളപ്പെടുത്തുക + എല്ലാം പ്രവർത്തനരഹിതമാക്കുക + തിരുത്തുക + ചേർക്കുക + വിഭാഗം അപ്ഡേറ്റ് ചെയ്യുക + ക്രമരഹിതമായ എൻട്രി തുറക്കുക + വിഭാഗം ചേർക്കുക + വിഭാഗങ്ങൾ അക്ഷരമാലാക്രമത്തിൽ അടുക്കാൻ നിങ്ങൾ ആഗ്രഹിക്കുന്നുണ്ടോ? + കവർ എഡിറ്റ് ചെയ്യുക + അധ്യായങ്ങൾ കാണുക + വിരാമം + വീണ്ടും ശ്രമിക്കുക + മുൻ അധ്യായം + അടുത്ത അധ്യായം + ഏറ്റവും പുതിയ അധ്യായം + ഓഫ് + തിരഞ്ഞെടുക്കപ്പെട്ട + മുകളിലേക്ക് നയിക്കുക + പേര് + വിഭാഗങ്ങൾ + അദ്ധ്യായങ്ങൾ + ട്രാക്കിംഗ് + ഡൗൺലോഡ് ചെയ്‌തത് ഇല്ലാതാക്കുക + ഇനിയും + ഡൗൺലോഡ് ക്യൂ + ലൈബ്രറി + അപ്ഡേറ്റുകൾ + അടുത്തതായി + ചരിത്രം + ഉൽഭവം + ബാക്കപ്പും റിസ്റ്റോറും + ലൈബ്രറി എൻട്രികൾ + സ്ഥിതിവിവരക്കണക്കുകൾ + മൈഗ്രേറ്റ് ചെയ്യുക + വിപുലീകരണങ്ങൾ + വിപുലീകരണ വിവരം + സഹായം + സ്ഥിരസ്ഥിതി + മുന്നറിയിപ്പ് + ആരംഭിച്ചു + പ്രാദേശികമായ + ഡൗൺലോഡ് ചെയ്തു + %s അൺലോക്ക് ചെയ്യുക + മാറ്റം സ്ഥിരീകരിക്കാൻ പ്രാമാണീകരിക്കുക + ക്രമീകരണങ്ങൾ + പട്ടിക + ഫിൽട്ടർ ചെയ്യുക + ഇടവേള സജ്ജമാക്കുക + ബുക്ക്‌മാർക്ക് ചെയ്തു + ട്രാക്ക് ചെയ്തു + വായിക്കാത്തത് + ഇഷ്‌ടാനുസൃതമാക്കിയ അപ്‌ഡേറ്റ് ആവൃത്തി + ഫിൽട്ടർ നീക്കം ചെയ്യുക + അക്ഷരമാലാക്രമത്തിൽ + ആകെ എൻട്രികൾ + ആകെ അധ്യായങ്ങൾ + അവസാനം വായിച്ചത് + അവസാന അപ്ഡേറ്റ് പരിശോധന + വായിക്കാത്ത എണ്ണം + അടുത്തതായി പ്രതീക്ഷിക്കുന്ന അപ്ഡേറ്റ് + അധ്യായം ലഭിച്ച തീയതി + തീയതി ചേർത്തു + ട്രാക്കർ സ്കോർ + തിരയുക… + തിരയൽ ക്രമീകരണങ്ങൾ + എല്ലാം തിരഞ്ഞെടുക്കുക + വിപരീതം തിരഞ്ഞെടുക്കുക + വായിച്ചതായി അടയാളപ്പെടുത്തുക + മുമ്പത്തേത് വായിച്ചതായി അടയാളപ്പെടുത്തുക + ഡൗൺലോഡ് + അൺബുക്ക്മാർക്ക് അധ്യായം + ഇല്ലാതാക്കുക + ലൈബ്രറി അപ്ഡേറ്റ് ചെയ്യുക + വിഭാഗങ്ങൾ എഡിറ്റ് ചെയ്യുക + വിഭാഗത്തിൻ്റെ പേരുമാറ്റുക + വിഭാഗങ്ങൾ സജ്ജമാക്കുക + \"%s\" എന്ന വിഭാഗം ഇല്ലാതാക്കാൻ നിങ്ങൾ ആഗ്രഹിക്കുന്നുണ്ടോ? + വിഭാഗം ഇല്ലാതാക്കുക + വിഭാഗങ്ങൾ അടുക്കുക + ഓൺ + കൂടുതൽ ഓപ്ഷനുകൾ + തിരഞ്ഞെടുത്തില്ല + സ്കാൻലേറ്റർ + ക്രമീകരണങ്ങൾ + നീക്കം ചെയ്യുക + എല്ലാം നീക്കം ചെയ്യുക + ആരംഭിക്കുക + പുനരാരംഭിക്കുക + ബ്രൗസറിൽ തുറക്കുക + ക്ലിപ്പ്ബോർഡിലേയ്ക്ക് പകർത്തുക + വെബ്‌വ്യൂവിൽ തുറക്കുക + മൈഗ്രേറ്റ് ചെയ്യുക + ഡിസ്പ്ലേ മോഡ് + \ No newline at end of file diff --git a/i18n/src/commonMain/resources/MR/ms/strings.xml b/i18n/src/commonMain/resources/MR/ms/strings.xml index eb4ffe5be..539d2d449 100644 --- a/i18n/src/commonMain/resources/MR/ms/strings.xml +++ b/i18n/src/commonMain/resources/MR/ms/strings.xml @@ -796,4 +796,5 @@ Mengurangkan kesan \'ghosting\' pada skrin e-ink Sandaran automatik terakhir:%s Mengemaskini pustaka… (%s) + Ganti \ No newline at end of file diff --git a/i18n/src/commonMain/resources/MR/ne/plurals.xml b/i18n/src/commonMain/resources/MR/ne/plurals.xml index dfe3035be..3f499cb5c 100644 --- a/i18n/src/commonMain/resources/MR/ne/plurals.xml +++ b/i18n/src/commonMain/resources/MR/ne/plurals.xml @@ -68,4 +68,8 @@ %d रेपो %d रेपोहरु + + भोलि + %1$d दिनमा + \ No newline at end of file diff --git a/i18n/src/commonMain/resources/MR/ne/strings.xml b/i18n/src/commonMain/resources/MR/ne/strings.xml index 7b110f49c..62f4f896e 100644 --- a/i18n/src/commonMain/resources/MR/ne/strings.xml +++ b/i18n/src/commonMain/resources/MR/ne/strings.xml @@ -92,7 +92,7 @@ तपाईंको पुस्तकालय खाली छ हालै केहि पढेको छैन हालैका कुनै अपडेट छैन - डाउनलोड लाम + डाउनलोड सूची कुनै डाउनलोडहरू छैन मद्दत एक्सटेन्शनको जानकारी @@ -351,7 +351,7 @@ कुनै Wi-Fi जडान उपलब्ध छैन डाउनलोडहरू रोकियो कुनै नेटवर्क जडान उपलब्ध छैन - बाह्य ट्र्याकर सेवाहरूमा अध्याय प्रगति अपडेट गर्न एक-तर्फी सिङ्क। तिनीहरूको ट्र्याकिङ बटनबाट व्यक्तिगत इन्ट्रीहरूको लागि ट्र्याकिङ सेट अप गर्नुहोस्। + बाह्य ट्र्याकर सेवाहरूमा अध्याय प्रगति अपडेट गर्न एकतर्फी सिंक। तिनीहरूको ट्र्याकिङ बटनबाट व्यक्तिगत इन्ट्रीहरूको लागि ट्र्याकिङ सेट अप गर्नुहोस्। ट्र्याकरहरूमा लगइन छैनन्: छुटेको स्रोतहरू: अध्याय क्यास खाली गर्नुहोस् @@ -540,7 +540,7 @@ डाउनलोड अघिल्लो अध्याय छैन थोरै जम्मा गर्ने ठाउँ भएको कारणले अध्याय डाउनलोड हुन सकिँदएन - सावधान: ठूलो हिस्सामा डाउनलोड गर्नाले स्रोत ढिलो चल्न अनि/वा ताचियोमीलाई अवरुद्घ गर्न सक्नेछ। थप जान्न ट्याप गर्नुहोस्। + सावधान: ठूलो हिस्सामा डाउनलोड गर्नाले स्रोत ढिलो चल्न अनि/वा Mihon लाई अवरुद्घ गर्न सक्नेछ। थप जान्न ट्याप गर्नुहोस्। ट्र्याकिङ ट्र्याक गर्नुहोस् पढ्दै @@ -616,7 +616,7 @@ %s एक अप्रत्याशित त्रुटिमा पर्यो। समर्थन को लागि हामी तपाईंलाई हाम्रो Discord को #support च्यानलमा क्र्यास लगहरू साझेदारी गर्न सुझाव दिन्छौं। GitHub मा खोल्नुहोस् डाउनलोड गरिएका अध्यायहरू पुन: जाँच गर्न एपलाई फोर्स गर्नुहोस् - एकतर्फी प्रगति सिङ्क, परिष्कृत सिङ्क + एकतर्फी प्रगति सिंक, परिष्कृत सिंक क्र्यास लग डम्प, ब्याट्री अप्टिमाइजेसन तस्वीर बचत गर्न त्रुटि भयो भर्खरै @@ -716,8 +716,8 @@ ठिक छ डाउनलोड गरिएको हटाउनुहोस् परिणामहरू भएको - पुस्तकालय सिङ्क सम्पन्न भयो - पुस्तकालय सिङ्क गर्दै + पुस्तकालय सिंक सम्पन्न भयो + पुस्तकालय सिंक गर्दै डाउनलोड इन्डेक्स अवैध भयो Cloudflare सम्बन्धित मद्दतको लागि यहाँ ट्याप गर्नुहोस् ट्र्याकर लगइन @@ -808,4 +808,10 @@ साइन गर्ने की फिंगरप्रिन्ट पहिले नै अवस्थित छ रिपो %1$s सँग %2$s जस्तै साइन गर्ने की फिंगरप्रिन्ट छ। \nयदि यो अपेक्षित छ भने, %2$s प्रतिस्थापन गरिनेछ, अन्यथा आफ्नो रिपो प्रबन्धकलाई सम्पर्क गर्नुहोस्। + आगामी + आगामी अपडेटहरू हेर्नुहोस् + आगामी गाइड + अर्को महिना + अघिल्लो महिना + लगातार फोल्डर पहुँच प्राप्त गर्न असफल। एपले अप्रत्याशित रूपमा व्यवहार गर्न सक्छ। \ No newline at end of file diff --git a/i18n/src/commonMain/resources/MR/pl/strings.xml b/i18n/src/commonMain/resources/MR/pl/strings.xml index 214d732c6..8fdff8642 100644 --- a/i18n/src/commonMain/resources/MR/pl/strings.xml +++ b/i18n/src/commonMain/resources/MR/pl/strings.xml @@ -801,4 +801,11 @@ Pominięto, ponieważ nie spodziewano się dzisiaj żadnej publikacji Wyklucz skanlatorów Wyłącz oddalenie + Dodaj mimo to + Zmigruj istniejący wpis + Zamień + Pokaż nadchodzące aktualizacje + Następny miesiąc + Poprzedni miesiąc + Nadchodzący \ No newline at end of file diff --git a/i18n/src/commonMain/resources/MR/pt-rBR/strings.xml b/i18n/src/commonMain/resources/MR/pt-rBR/strings.xml index 4a03ce56d..5a3ea0d86 100644 --- a/i18n/src/commonMain/resources/MR/pt-rBR/strings.xml +++ b/i18n/src/commonMain/resources/MR/pt-rBR/strings.xml @@ -797,4 +797,16 @@ Revogar a confiabilidade de extensões desconhecidas Abrir repositório da fonte Desativar redução de zoom + Adicionar de qualquer maneira + Substituir + Próximo + Migrar entrada existente + A impressão digital da chave de assinatura já existe + O repositório %1$s tem a mesma impressão digital da chave de assinatura que %2$s. +\nSe isso for esperado, %2$s será substituído, caso contrário, entre em contato com o mantenedor do repositório. + Perfil de exibição personalizado + Exibir as próximas atualizações + Guia de próximos lançamentos + Próximo mês + Mês anterior \ No newline at end of file diff --git a/i18n/src/commonMain/resources/MR/pt/strings.xml b/i18n/src/commonMain/resources/MR/pt/strings.xml index e447f8a33..70ddb44b2 100644 --- a/i18n/src/commonMain/resources/MR/pt/strings.xml +++ b/i18n/src/commonMain/resources/MR/pt/strings.xml @@ -717,4 +717,99 @@ Navegar para cima Desbloquear %s Dados e armazenamento + Uso de armazenamento + Disponível: %1$s / Total: %2$s + Índice de descargas invalidado + Não foi possível resolver %s + Frequência de atualização personalizada: + Remover o monitoramento do %s? + Nenhum ficheiro selecionado + Toque aqui para obter ajuda com o Cloudflare + Deletar repositório + Adicionar de qualquer maneira + Migrar entrada existente + Seja notificado para atualizações da biblioteca e mais. + A reinstalar o %s? + Datas relativas + Permissões são necessárias para instalar extensões. Toque aqui para conceder. + Não tem repositórios definidos. + Adicionar repositório + URL do repositório + Perfil de exibição personalizado + Sem conexão de internet + Substituir + A impressão digital da chave de assinatura já existe + Flash ao mudar de página + Local de armazenamento + Criar + Configurações da app + A sincronizar a biblioteca + A atualizar a biblioteca… (%s) + HTTP %d, verifique o site na WebView + Deseja ordenar as categorias alfabeticamente? + Avaliação no monitorador + Aplicar + OK + Reverter para o padrão + Bem-vindo(a)! + Pular + Selecionar uma pasta + Uma pasta deve ser selecionada + A atualizar de uma versão anterior e não tem certeza do que selecionar? Consulte o guia de armazenamento para mais informações. + Guia de armazenamento + Permissão de instalação de apps + Para instalar extensões de fontes. + Permissão de notificação + Uso de pilha em plano de fundo + Evite interrupções para tarefas longas como atualizações da biblioteca, descargas e restauração de backups. + Conceder + Novo no %s? Recomendamos dar uma olhada no guia de introdução. + Nord + \"%1$s\" ao invés de \"%2$s\" + Adiciona repositórios adicionais ao Mihon. Deve ser uma URL que termine com \"index.min.json\". + URL do repositório inválido + Deseja deletar o repositório \"%s\"? + Abrir repositório da fonte + O repositório %1$s tem a mesma impressão digital da chave de assinatura que %2$s. +\nSe isto for esperado, %2$s será substituído, caso contrário, entre em contato com o mantenedor do repositório. + Reduz o efeito fantasma em ecrãs de e-ink + Erro completo: + Configurações das fontes + Incluir configurações sensíveis (tokens de login dos monitoradores, por exemplo) + Não foi possível criar o ficheiro do backup + Licenciado - Nenhum capítulo para mostrar + Há resultados + Em breve + Nunca + Guia de próximos lançamentos + Próximo mês + Mês anterior + Também remover do %s + Vamos definir algumas coisas primeiro. Sempre pode fazer alterações nas configurações depois também. + Próximo + Começar + Escolha uma pasta onde o %1$s irá armazenar as descargas de capítulos, backups e mais. +\n +\nUma pasta dedicada é recomendada. +\n +\nPasta selecionada: %2$s + Apagar scanlators + Nenhum scanlator encontrado + Ordenar as categorias + Mover série para o final + Guia de introdução + Atualização inteligente + Revogar a confiabilidade de extensões desconhecidas + Repositórios de extensões + Este repositório já existe! + Local de armazenamento não definido + Login do monitorador + Usado para backups automáticos, descargas de capítulos e na fonte local. + Último backup automático feito em: %s + Sincronização da biblioteca finalizada + Novos capítulos com previsão de serem lançados em torno de %1$s, verificando em torno de cada %2$s. + Isto irá remover o monitoramento localmente. + Desativar redução de zoom + Exibir as próximas atualizações + A seguir \ No newline at end of file diff --git a/i18n/src/commonMain/resources/MR/ro/plurals.xml b/i18n/src/commonMain/resources/MR/ro/plurals.xml index 17e794c1c..2ba7c8dbe 100644 --- a/i18n/src/commonMain/resources/MR/ro/plurals.xml +++ b/i18n/src/commonMain/resources/MR/ro/plurals.xml @@ -85,4 +85,9 @@ %d repozitorii %d de repozitorii + + Mâine + În %1$d zile + În %1$d de zile + \ No newline at end of file diff --git a/i18n/src/commonMain/resources/MR/ro/strings.xml b/i18n/src/commonMain/resources/MR/ro/strings.xml index b4b2fdebf..d43caf5c5 100644 --- a/i18n/src/commonMain/resources/MR/ro/strings.xml +++ b/i18n/src/commonMain/resources/MR/ro/strings.xml @@ -95,11 +95,9 @@ Nesigură Dezinstalează Extensie nesigură - Extensia a fost semnată cu un certificat nesigur și nu a fost activată. + Extensiile rău intenționate pot citi orice credențiale de autentificare stocate sau pot executa cod arbitrar. \n -\nO extensie periculoasă ar putea citi orice date de logare stocate în Mihon sau executa cod periculos. -\n -\nPrin acordarea încrederii acestui certificat acceptați riscurile menționate. +\nAcordând încredere acestei extensii, acceptați aceste riscuri. Ecran complet Animați tranzițiile de pagini Capitole descărcate @@ -119,7 +117,7 @@ Mod de citire implicit De la stânga la dreapta De la dreapta la stânga - Vertical + Paginat (vertical) Benzi desenate web Setări pagini Tip de scalare @@ -376,7 +374,7 @@ Grilă confortabilă Migrează Date - Fișierul de rezerva este invalid + Fișier de rezervă invalid: Nu s-au găsit pagini Tab-uri Afișează filele categoriei @@ -460,9 +458,7 @@ În formă de L Data obținerii capitolului Urmărit - Datele din fișierul de rezervă vor fi restaurate. -\n -\nVa trebui să instalați toate extensiile lipsă și să vă conectați ulterior la serviciile de urmărire pentru a le utiliza. + Este posibil să fie necesar să instalați extensiile lipsă și să vă conectați ulterior la serviciile de urmărire pentru a le utiliza. Nu vor fi descărcate înscrierile din categoriile excluse, chiar dacă acestea se află și în categoriile incluse. Descărcare automată Dreapta @@ -797,4 +793,18 @@ Acest repozitoriu există deja! Șterge repozitoriu URL repozitoriu invalid + Viitoare + Nord + Repozitoriul %1$s are acceeași amprenta digitală a cheii de semnare ca și %2$s +\nÎn cazul în care asta este la ce vă așteptați, %2$s va fi înlocuit, altfel contatati întreținătorul repozitoriului. + Profil de afișare personalizat + Adăugați oricum + Migrați intrare existentă + Înlocuiți + Amprenta digitală a cheii de semnare există deja + Dezactivați funcția de zoom-out + Vizualizați actualizările viitoare + Ghidul viitor + Luna următoare + Luna anterioară \ No newline at end of file diff --git a/i18n/src/commonMain/resources/MR/ru/strings.xml b/i18n/src/commonMain/resources/MR/ru/strings.xml index bf0909033..1337da8d9 100644 --- a/i18n/src/commonMain/resources/MR/ru/strings.xml +++ b/i18n/src/commonMain/resources/MR/ru/strings.xml @@ -809,4 +809,5 @@ Предстоящее Предстоящее руководство Следующий месяц + Не удалось получить постоянный доступ к папке. Приложение может работать некорректно. \ No newline at end of file diff --git a/i18n/src/commonMain/resources/MR/sr/strings.xml b/i18n/src/commonMain/resources/MR/sr/strings.xml index 36eb985a0..aab9d56c0 100644 --- a/i18n/src/commonMain/resources/MR/sr/strings.xml +++ b/i18n/src/commonMain/resources/MR/sr/strings.xml @@ -801,4 +801,9 @@ Ни једна датотека није одабрана Примени Врати на подразумевано + Dodati svejedno + Predstojeći + Migrirajte postojeći unos + Zameniti + Otisak prsta za otključavanje već postoji \ No newline at end of file diff --git a/i18n/src/commonMain/resources/MR/uk/strings.xml b/i18n/src/commonMain/resources/MR/uk/strings.xml index d03c85884..276fd442d 100644 --- a/i18n/src/commonMain/resources/MR/uk/strings.xml +++ b/i18n/src/commonMain/resources/MR/uk/strings.xml @@ -78,7 +78,7 @@ Кожні 6 годин Кожні 12 годин Щодня - Кожні 2 дні + Що 2 дні Щонеділі Всі Обмеження пристрою для автоматичних оновлень @@ -796,4 +796,16 @@ Почнемо Давайте для початку налаштуємо дещо. Ви завжди зможете змінити ці налаштування потім. Гайд новачка + Додати у будь-якому разі + Відбиток пальця для підпису ключа вже існує + Репозиторій %1$s має такий самий відбиток ключа підпису, як і %2$s. +\nЯкщо це очікувано, %2$s буде замінено, в іншому випадку зверніться до вашого обслуговуючого репозиторію. + Переглянути майбутні оновлення + Попередній місяць + Перенести існуючий запис + Замінити + Власний профіль відображення + Вимкнути зменшення масштабу + Незабаром + Наступний місяць \ No newline at end of file diff --git a/i18n/src/commonMain/resources/MR/vi/plurals.xml b/i18n/src/commonMain/resources/MR/vi/plurals.xml index df9978d19..013eada7a 100644 --- a/i18n/src/commonMain/resources/MR/vi/plurals.xml +++ b/i18n/src/commonMain/resources/MR/vi/plurals.xml @@ -48,4 +48,10 @@ %d ngày + + %d kho + + + Trong %1$d ngày + \ No newline at end of file diff --git a/i18n/src/commonMain/resources/MR/vi/strings.xml b/i18n/src/commonMain/resources/MR/vi/strings.xml index ca4675d6e..31a3761cc 100644 --- a/i18n/src/commonMain/resources/MR/vi/strings.xml +++ b/i18n/src/commonMain/resources/MR/vi/strings.xml @@ -781,4 +781,34 @@ Mã lỗi đầy đủ: Cần phải cấp phép để cài đặt tiện ích mở rộng. Bấm đây để cấp. Bao gồm những cài đặt nhạy cảm (ví dụ như token đăng nhập tracker) + Luôn luôn thêm + Phương bắc + Cập nhật thông minh + Sắp tới + Chuyển vào các mục hiện có + Cập nhật từ phiên bản cũ hơn và không biết nên chọn gì? Tham khảo hướng dẫn để biết thêm thông tin. + Thêm nguồn bổ sung vào Mihon. Địa chỉ URL này cần phải kết thúc với \"index.min.json\". + Kho lưu trữ %1$s có Dấu vân tay Khóa ký giống hệt như %2$s. +\nNếu điều này là dự kiến, %2$s sẽ bị thay thế. Nếu không, vui lòng liên hệ với người quản lý kho lưu trữ của bạn. + Bạn chưa có nguồn nào. + Thu hồi quyền truy cập của tiện ích không xác định + Thêm nguồn + Nguồn đã có rồi! + Xóa nguồn + Hướng dẫn + Quản lý nguồn + URL nguồn không hợp lệ + URL nguồn + Bạn có muốn xóa nguồn \"%s\"? + Mở nguồn + Sớm + Tần suất cập nhật tùy chỉnh: + Tùy chỉnh hồ sơ màn hình + Tắt thu nhỏ + Xem các cập nhật sắp tới + Hướng dẫn sắp tới + Tháng tiếp theo + Tháng trước + Thay thế + Dấu vân tay cho khóa ký đã được tạo trước đó. \ No newline at end of file From 119bcbf8ed2415664922ea77fadf0da1165d1732 Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Sat, 8 Jun 2024 06:38:35 +0600 Subject: [PATCH 047/297] Check category order before restoring from backup Closes #632 Co-authored-by: Cologler <10906962+Cologler@users.noreply.github.com> --- .../restore/restorers/CategoriesRestorer.kt | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/CategoriesRestorer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/CategoriesRestorer.kt index f98af1045..23a2d47fa 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/CategoriesRestorer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/CategoriesRestorer.kt @@ -17,14 +17,20 @@ class CategoriesRestorer( if (backupCategories.isNotEmpty()) { val dbCategories = getCategories.await() val dbCategoriesByName = dbCategories.associateBy { it.name } + var nextOrder = dbCategories.maxOfOrNull { it.order }?.plus(1) ?: 0 - val categories = backupCategories.map { - dbCategoriesByName[it.name] - ?: handler.awaitOneExecutable { - categoriesQueries.insert(it.name, it.order, it.flags) + val categories = backupCategories + .sortedBy { it.order } + .map { + val dbCategory = dbCategoriesByName[it.name] + if (dbCategory != null) return@map dbCategory + val order = nextOrder++ + handler.awaitOneExecutable { + categoriesQueries.insert(it.name, order, it.flags) categoriesQueries.selectLastInsertedRowId() - }.let { id -> it.toCategory(id) } - } + } + .let { id -> it.toCategory(id).copy(order = order) } + } libraryPreferences.categorizedDisplaySettings().set( (dbCategories + categories) From 6a80305d6c572da6c08c0c69f5c25ff26ecf7383 Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Sat, 8 Jun 2024 07:07:47 +0600 Subject: [PATCH 048/297] Fix chapter number parsing when number is after unwanted tag Fixes #554 Co-authored-by: Naputt1 <94742489+Naputt1@users.noreply.github.com> --- .../chapter/service/ChapterRecognition.kt | 42 +++++++++++-------- .../chapter/service/ChapterRecognitionTest.kt | 11 +++++ 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/domain/src/main/java/tachiyomi/domain/chapter/service/ChapterRecognition.kt b/domain/src/main/java/tachiyomi/domain/chapter/service/ChapterRecognition.kt index b2c3f6b44..3190e0456 100644 --- a/domain/src/main/java/tachiyomi/domain/chapter/service/ChapterRecognition.kt +++ b/domain/src/main/java/tachiyomi/domain/chapter/service/ChapterRecognition.kt @@ -41,27 +41,35 @@ object ChapterRecognition { } // Get chapter title with lower case - var name = chapterName.lowercase() + val cleanChapterName = chapterName.lowercase() + // Remove manga title from chapter title. + .replace(mangaTitle.lowercase(), "").trim() + // Remove comma's or hyphens. + .replace(',', '.') + .replace('-', '.') + // Remove unwanted white spaces. + .replace(unwantedWhiteSpace, "") - // Remove manga title from chapter title. - name = name.replace(mangaTitle.lowercase(), "").trim() + val numberMatch = number.findAll(cleanChapterName) - // Remove comma's or hyphens. - name = name.replace(',', '.').replace('-', '.') + when { + numberMatch.none() -> { + return chapterNumber ?: -1.0 + } + numberMatch.count() > 1 -> { + // Remove unwanted tags. + unwanted.replace(cleanChapterName, "").let { name -> + // Check base case ch.xx + basic.find(name)?.let { return getChapterNumberFromMatch(it) } - // Remove unwanted white spaces. - name = unwantedWhiteSpace.replace(name, "") + // need to find again first number might already removed + number.find(name)?.let { return getChapterNumberFromMatch(it) } + } + } + } - // Remove unwanted tags. - name = unwanted.replace(name, "") - - // Check base case ch.xx - basic.find(name)?.let { return getChapterNumberFromMatch(it) } - - // Take the first number encountered. - number.find(name)?.let { return getChapterNumberFromMatch(it) } - - return chapterNumber ?: -1.0 + // return the first number encountered + return getChapterNumberFromMatch(numberMatch.first()) } /** diff --git a/domain/src/test/java/tachiyomi/domain/chapter/service/ChapterRecognitionTest.kt b/domain/src/test/java/tachiyomi/domain/chapter/service/ChapterRecognitionTest.kt index 90ee3a486..8369bfa5c 100644 --- a/domain/src/test/java/tachiyomi/domain/chapter/service/ChapterRecognitionTest.kt +++ b/domain/src/test/java/tachiyomi/domain/chapter/service/ChapterRecognitionTest.kt @@ -171,6 +171,17 @@ class ChapterRecognitionTest { assertChapter(mangaTitle, "Tokyo ESP 027: Part 002: Chapter 001", 027.0) } + /** + * Case where the chapter title contains the unwanted tag + * But follow by chapter number. + */ + @Test + fun `Number after unwanted tag`() { + val mangaTitle = "One-punch Man" + + assertChapter(mangaTitle, "Mag Version 195.5", 195.5) + } + @Test fun `Unparseable chapter`() { val mangaTitle = "random" From e9d69a83febccf8840dad03597e3ac2a6aa3f972 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 11 Jun 2024 14:51:28 +0600 Subject: [PATCH 049/297] fix(deps): update dependency com.android.tools.build:gradle to v8.4.2 (#883) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/androidx.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index ff0416cb7..74c1e268c 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -1,5 +1,5 @@ [versions] -agp_version = "8.4.1" +agp_version = "8.4.2" lifecycle_version = "2.8.1" paging_version = "3.3.0" From 8e8ee69bbacb2260d0ae52808c02684e567119b9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 13 Jun 2024 02:21:02 +0600 Subject: [PATCH 050/297] fix(deps): update lifecycle.version to v2.8.2 (#889) fix(deps): update dependency androidx.lifecycle:lifecycle-runtime-ktx to v2.8.2 Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/androidx.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index 74c1e268c..71b16058e 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -1,6 +1,6 @@ [versions] agp_version = "8.4.2" -lifecycle_version = "2.8.1" +lifecycle_version = "2.8.2" paging_version = "3.3.0" [libraries] From af57e124f2113f78028771f1579a356884d7ead7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 13 Jun 2024 02:21:15 +0600 Subject: [PATCH 051/297] fix(deps): update dependency androidx.glance:glance-appwidget to v1.1.0 (#890) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/compose.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/compose.versions.toml b/gradle/compose.versions.toml index 85091b5d3..b5e306abe 100644 --- a/gradle/compose.versions.toml +++ b/gradle/compose.versions.toml @@ -15,6 +15,6 @@ ui-util = { module = "androidx.compose.ui:ui-util" } material3-core = { module = "androidx.compose.material3:material3" } material-icons = { module = "androidx.compose.material:material-icons-extended" } -glance = "androidx.glance:glance-appwidget:1.0.0" +glance = "androidx.glance:glance-appwidget:1.1.0" accompanist-systemuicontroller = { module = "com.google.accompanist:accompanist-systemuicontroller", version.ref = "accompanist" } From 6d8cfd5f30753025434b203840a8a1b49b94ed95 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 13 Jun 2024 02:31:28 +0600 Subject: [PATCH 052/297] chore(deps): update actions/checkout action to v4.1.7 (#891) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/build_pull_request.yml | 2 +- .github/workflows/build_push.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_pull_request.yml b/.github/workflows/build_pull_request.yml index ff697921b..28b914927 100644 --- a/.github/workflows/build_pull_request.yml +++ b/.github/workflows/build_pull_request.yml @@ -20,7 +20,7 @@ jobs: steps: - name: Clone repo - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Validate Gradle Wrapper uses: gradle/wrapper-validation-action@216d1ad2b3710bf005dc39237337b9673fd8fcd5 # v3.3.2 diff --git a/.github/workflows/build_push.yml b/.github/workflows/build_push.yml index 90eee2c09..98e3a7013 100644 --- a/.github/workflows/build_push.yml +++ b/.github/workflows/build_push.yml @@ -17,7 +17,7 @@ jobs: steps: - name: Clone repo - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Validate Gradle Wrapper uses: gradle/wrapper-validation-action@216d1ad2b3710bf005dc39237337b9673fd8fcd5 # v3.3.2 From 9fa22f0b378084478d6e5fa1040a7fd8da62356a Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Thu, 13 Jun 2024 02:45:55 +0600 Subject: [PATCH 053/297] Migrate to `gradle/actions/wrapper-validation` (#892) --- .github/workflows/build_pull_request.yml | 2 +- .github/workflows/build_push.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_pull_request.yml b/.github/workflows/build_pull_request.yml index 28b914927..a767948ca 100644 --- a/.github/workflows/build_pull_request.yml +++ b/.github/workflows/build_pull_request.yml @@ -23,7 +23,7 @@ jobs: uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Validate Gradle Wrapper - uses: gradle/wrapper-validation-action@216d1ad2b3710bf005dc39237337b9673fd8fcd5 # v3.3.2 + uses: gradle/actions/wrapper-validation@db19848a5fa7950289d3668fb053140cf3028d43 # v3.3.2 - name: Dependency Review uses: actions/dependency-review-action@72eb03d02c7872a771aacd928f3123ac62ad6d3a # v4.3.3 diff --git a/.github/workflows/build_push.yml b/.github/workflows/build_push.yml index 98e3a7013..f1e10ee4d 100644 --- a/.github/workflows/build_push.yml +++ b/.github/workflows/build_push.yml @@ -20,7 +20,7 @@ jobs: uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Validate Gradle Wrapper - uses: gradle/wrapper-validation-action@216d1ad2b3710bf005dc39237337b9673fd8fcd5 # v3.3.2 + uses: gradle/actions/wrapper-validation@db19848a5fa7950289d3668fb053140cf3028d43 # v3.3.2 - name: Setup Android SDK run: | From f696f209c6b3efb3148e1d587af9e42c71d8dc6f Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Thu, 13 Jun 2024 03:13:57 +0600 Subject: [PATCH 054/297] Fix issue with creating and restoring backup Fixes #881 --- .../java/eu/kanade/tachiyomi/data/backup/BackupDecoder.kt | 3 +-- .../eu/kanade/tachiyomi/data/backup/create/BackupCreator.kt | 3 +-- .../java/eu/kanade/tachiyomi/data/backup/models/Backup.kt | 4 ---- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupDecoder.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupDecoder.kt index e33572caf..34f862548 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupDecoder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupDecoder.kt @@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.data.backup import android.content.Context import android.net.Uri import eu.kanade.tachiyomi.data.backup.models.Backup -import eu.kanade.tachiyomi.data.backup.models.BackupSerializer import kotlinx.serialization.protobuf.ProtoBuf import okio.buffer import okio.gzip @@ -33,7 +32,7 @@ class BackupDecoder( source }.use { it.readByteArray() } - parser.decodeFromByteArray(BackupSerializer, backupString) + parser.decodeFromByteArray(Backup.serializer(), backupString) } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreator.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreator.kt index 14d05e239..42c97ca9c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreator.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreator.kt @@ -13,7 +13,6 @@ import eu.kanade.tachiyomi.data.backup.models.Backup import eu.kanade.tachiyomi.data.backup.models.BackupCategory import eu.kanade.tachiyomi.data.backup.models.BackupManga import eu.kanade.tachiyomi.data.backup.models.BackupPreference -import eu.kanade.tachiyomi.data.backup.models.BackupSerializer import eu.kanade.tachiyomi.data.backup.models.BackupSource import eu.kanade.tachiyomi.data.backup.models.BackupSourcePreferences import kotlinx.serialization.protobuf.ProtoBuf @@ -84,7 +83,7 @@ class BackupCreator( backupSourcePreferences = backupSourcePreferences(options), ) - val byteArray = parser.encodeToByteArray(BackupSerializer, backup) + val byteArray = parser.encodeToByteArray(Backup.serializer(), backup) if (byteArray.isEmpty()) { throw IllegalStateException(context.stringResource(MR.strings.empty_backup_error)) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt index cdc5c4ad2..dcf3d1174 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt @@ -1,12 +1,8 @@ package eu.kanade.tachiyomi.data.backup.models import kotlinx.serialization.Serializable -import kotlinx.serialization.Serializer import kotlinx.serialization.protobuf.ProtoNumber -@Serializer(forClass = Backup::class) -object BackupSerializer - @Serializable data class Backup( @ProtoNumber(1) val backupManga: List, From aa1714b2acf0e5b16558ea703220f60d4ecd23e9 Mon Sep 17 00:00:00 2001 From: "Weblate (bot)" Date: Wed, 12 Jun 2024 23:34:04 +0200 Subject: [PATCH 055/297] Translations update from Hosted Weblate (#878) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (804 of 804 strings) Translation: Mihon/Mihon Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/zh_Hant/ * Translated using Weblate (Croatian) Currently translated at 100.0% (804 of 804 strings) Translation: Mihon/Mihon Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/hr/ * Translated using Weblate (Malayalam) Currently translated at 15.5% (125 of 804 strings) Translation: Mihon/Mihon Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ml/ * Translated using Weblate (Malayalam) Currently translated at 15.5% (125 of 804 strings) Translation: Mihon/Mihon Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ml/ * Translated using Weblate (Malayalam) Currently translated at 94.4% (17 of 18 strings) Translation: Mihon/Mihon Plurals Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/ml/ --------- Co-authored-by: ɴᴇᴋᴏ Co-authored-by: Milo Ivir Co-authored-by: Akhil Raj Co-authored-by: Animeboynz --- .../commonMain/resources/MR/hr/strings.xml | 1 + .../commonMain/resources/MR/ml/plurals.xml | 2 +- .../commonMain/resources/MR/ml/strings.xml | 21 +++++++++++++++++++ .../resources/MR/zh-rTW/strings.xml | 1 + 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/i18n/src/commonMain/resources/MR/hr/strings.xml b/i18n/src/commonMain/resources/MR/hr/strings.xml index 48336a888..aafcf3da6 100644 --- a/i18n/src/commonMain/resources/MR/hr/strings.xml +++ b/i18n/src/commonMain/resources/MR/hr/strings.xml @@ -809,4 +809,5 @@ Digitalni otisak prsta za potpisivanje već postoji Repozitorij %1$s ima isti digitalni otisak ključa za potpisivanje kao %2$s. \nAko se to očekuje, %2$s će se zamijeniti, u suprotnom se obrati svom održavatelju repozitorija. + Neuspjelo dobivanje trajnog pristupa mapi. Aplikacija se može ponašati neočekivano. \ No newline at end of file diff --git a/i18n/src/commonMain/resources/MR/ml/plurals.xml b/i18n/src/commonMain/resources/MR/ml/plurals.xml index a3e67ba1c..589be4b61 100644 --- a/i18n/src/commonMain/resources/MR/ml/plurals.xml +++ b/i18n/src/commonMain/resources/MR/ml/plurals.xml @@ -61,7 +61,7 @@ %1$d പുതിയ അധ്യായങ്ങൾ - അധ്യായങ്ങൾ %1$s-ഉം 1-ഉം + അധ്യായങ്ങൾ %1$s-ഉം പിന്നെ 1-ഉം %1$s-ഉം %2$d-ഉം അധ്യായങ്ങൾ diff --git a/i18n/src/commonMain/resources/MR/ml/strings.xml b/i18n/src/commonMain/resources/MR/ml/strings.xml index 7a6be0bfb..b9c9409dd 100644 --- a/i18n/src/commonMain/resources/MR/ml/strings.xml +++ b/i18n/src/commonMain/resources/MR/ml/strings.xml @@ -99,4 +99,25 @@ വെബ്‌വ്യൂവിൽ തുറക്കുക മൈഗ്രേറ്റ് ചെയ്യുക ഡിസ്പ്ലേ മോഡ് + ഏറ്റവും പഴയത് + റദ്ദാക്കുക + വായന തുടരുക ബട്ടൺ + ഭാഷ + എല്ലാം റദ്ദാക്കുക + ശരി + ഈ സീരീസിനായി എല്ലാം റദ്ദാക്കുക + മുകളിലേക്ക് നീങ്ങുക + അധ്യായ നമ്പർ പ്രകാരം + ഏറ്റവും പുതിയത് + എൻട്രി കാണിക്കുക + കോംപാക്റ്റ് ഗ്രിഡ് + സുഖപ്രദമായ ഗ്രിഡ് + ഡൌൺലോഡ് ചെയ്ത അധ്യായങ്ങൾ + ലോക്കൽ സോഴ്സ് + ഡിസേബിൾ + പിൻ ചെയ്യുക + അപ്ലൈ + സോർട് + ലിസ്റ്റ് + ചിത്രം മാത്രമുള്ള ഗ്രിഡ് \ No newline at end of file diff --git a/i18n/src/commonMain/resources/MR/zh-rTW/strings.xml b/i18n/src/commonMain/resources/MR/zh-rTW/strings.xml index d2ec23ffe..e4dfbc1f6 100644 --- a/i18n/src/commonMain/resources/MR/zh-rTW/strings.xml +++ b/i18n/src/commonMain/resources/MR/zh-rTW/strings.xml @@ -809,4 +809,5 @@ 上個月 預告 檢視新刊預告 + 無法取得永久性資料夾存取權,應用程式可能會表現異常。 \ No newline at end of file From a5838387b1bb661ff95a51dd961f07550ee6954e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 14 Jun 2024 05:05:57 +0600 Subject: [PATCH 056/297] chore(deps): update gradle/actions action to v3.4.0 (#902) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/build_pull_request.yml | 4 ++-- .github/workflows/build_push.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build_pull_request.yml b/.github/workflows/build_pull_request.yml index a767948ca..0d6f228e1 100644 --- a/.github/workflows/build_pull_request.yml +++ b/.github/workflows/build_pull_request.yml @@ -23,7 +23,7 @@ jobs: uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Validate Gradle Wrapper - uses: gradle/actions/wrapper-validation@db19848a5fa7950289d3668fb053140cf3028d43 # v3.3.2 + uses: gradle/actions/wrapper-validation@d9336dac04dea2507a617466bc058a3def92b18b # v3.4.0 - name: Dependency Review uses: actions/dependency-review-action@72eb03d02c7872a771aacd928f3123ac62ad6d3a # v4.3.3 @@ -35,7 +35,7 @@ jobs: distribution: adopt - name: Set up gradle - uses: gradle/actions/setup-gradle@db19848a5fa7950289d3668fb053140cf3028d43 # v3.3.2 + uses: gradle/actions/setup-gradle@d9336dac04dea2507a617466bc058a3def92b18b # v3.4.0 - name: Build app and run unit tests run: ./gradlew detekt assembleStandardRelease testReleaseUnitTest diff --git a/.github/workflows/build_push.yml b/.github/workflows/build_push.yml index f1e10ee4d..8d20c072d 100644 --- a/.github/workflows/build_push.yml +++ b/.github/workflows/build_push.yml @@ -20,7 +20,7 @@ jobs: uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Validate Gradle Wrapper - uses: gradle/actions/wrapper-validation@db19848a5fa7950289d3668fb053140cf3028d43 # v3.3.2 + uses: gradle/actions/wrapper-validation@d9336dac04dea2507a617466bc058a3def92b18b # v3.4.0 - name: Setup Android SDK run: | @@ -33,7 +33,7 @@ jobs: distribution: adopt - name: Set up gradle - uses: gradle/actions/setup-gradle@db19848a5fa7950289d3668fb053140cf3028d43 # v3.3.2 + uses: gradle/actions/setup-gradle@d9336dac04dea2507a617466bc058a3def92b18b # v3.4.0 - name: Build app and run unit tests run: ./gradlew detekt assembleStandardRelease testReleaseUnitTest From 2e78bceb30908aca8e585f91942849a6e4e7cb15 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 14 Jun 2024 05:06:11 +0600 Subject: [PATCH 057/297] fix(deps): update dependency com.android.tools.build:gradle to v8.5.0 (#901) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/androidx.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index 71b16058e..94c1c15b1 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -1,5 +1,5 @@ [versions] -agp_version = "8.4.2" +agp_version = "8.5.0" lifecycle_version = "2.8.2" paging_version = "3.3.0" From 30a6e3a6a11bf164a8bc7c9943368f7dcdf6230c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 16 Jun 2024 04:47:39 +0600 Subject: [PATCH 058/297] chore(deps): update gradle/actions action to v3.4.1 (#905) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/build_pull_request.yml | 4 ++-- .github/workflows/build_push.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build_pull_request.yml b/.github/workflows/build_pull_request.yml index 0d6f228e1..537dee9ee 100644 --- a/.github/workflows/build_pull_request.yml +++ b/.github/workflows/build_pull_request.yml @@ -23,7 +23,7 @@ jobs: uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Validate Gradle Wrapper - uses: gradle/actions/wrapper-validation@d9336dac04dea2507a617466bc058a3def92b18b # v3.4.0 + uses: gradle/actions/wrapper-validation@31ae3562f68c96d481c31bc1a8a55cc1be162f83 # v3.4.1 - name: Dependency Review uses: actions/dependency-review-action@72eb03d02c7872a771aacd928f3123ac62ad6d3a # v4.3.3 @@ -35,7 +35,7 @@ jobs: distribution: adopt - name: Set up gradle - uses: gradle/actions/setup-gradle@d9336dac04dea2507a617466bc058a3def92b18b # v3.4.0 + uses: gradle/actions/setup-gradle@31ae3562f68c96d481c31bc1a8a55cc1be162f83 # v3.4.1 - name: Build app and run unit tests run: ./gradlew detekt assembleStandardRelease testReleaseUnitTest diff --git a/.github/workflows/build_push.yml b/.github/workflows/build_push.yml index 8d20c072d..ddd4cff6d 100644 --- a/.github/workflows/build_push.yml +++ b/.github/workflows/build_push.yml @@ -20,7 +20,7 @@ jobs: uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Validate Gradle Wrapper - uses: gradle/actions/wrapper-validation@d9336dac04dea2507a617466bc058a3def92b18b # v3.4.0 + uses: gradle/actions/wrapper-validation@31ae3562f68c96d481c31bc1a8a55cc1be162f83 # v3.4.1 - name: Setup Android SDK run: | @@ -33,7 +33,7 @@ jobs: distribution: adopt - name: Set up gradle - uses: gradle/actions/setup-gradle@d9336dac04dea2507a617466bc058a3def92b18b # v3.4.0 + uses: gradle/actions/setup-gradle@31ae3562f68c96d481c31bc1a8a55cc1be162f83 # v3.4.1 - name: Build app and run unit tests run: ./gradlew detekt assembleStandardRelease testReleaseUnitTest From f3226fb278cab87422255e04e647c50095b61529 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Sun, 16 Jun 2024 16:48:02 +0800 Subject: [PATCH 059/297] Update R8 to fix `NoSuchMethodError` crash (#914) --- build.gradle.kts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/build.gradle.kts b/build.gradle.kts index 93146c0a6..c27e7d91d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,11 @@ buildscript { + // https://issuetracker.google.com/344363457 + // TODO: Remove when AGP's bundled R8 is updated + repositories { + maven("https://storage.googleapis.com/r8-releases/raw") + } dependencies { + classpath("com.android.tools:r8:8.5.21") classpath(libs.android.shortcut.gradle) classpath(libs.google.services.gradle) classpath(libs.aboutLibraries.gradle) From 4182ae89a036525c5575961a68371df249ce384f Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Mon, 17 Jun 2024 06:53:02 +0800 Subject: [PATCH 060/297] Fix R8 version configuration not working (#916) This reverts commit f3226fb278cab87422255e04e647c50095b61529. --- build.gradle.kts | 6 ------ settings.gradle.kts | 10 ++++++++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index c27e7d91d..93146c0a6 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,11 +1,5 @@ buildscript { - // https://issuetracker.google.com/344363457 - // TODO: Remove when AGP's bundled R8 is updated - repositories { - maven("https://storage.googleapis.com/r8-releases/raw") - } dependencies { - classpath("com.android.tools:r8:8.5.21") classpath(libs.android.shortcut.gradle) classpath(libs.google.services.gradle) classpath(libs.aboutLibraries.gradle) diff --git a/settings.gradle.kts b/settings.gradle.kts index b1a2a2dd5..76b88ed6e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -13,6 +13,16 @@ pluginManagement { mavenCentral() maven(url = "https://www.jitpack.io") } + // https://issuetracker.google.com/344363457 + // TODO: Remove when AGP's bundled R8 is updated + buildscript { + repositories { + maven("https://storage.googleapis.com/r8-releases/raw") + } + dependencies { + classpath("com.android.tools:r8:8.5.21") + } + } } dependencyResolutionManagement { From 3b8ed3059ad1e54aef597155b40f2e3fe1b25c4f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 18 Jun 2024 05:08:07 +0600 Subject: [PATCH 061/297] chore(deps): update gradle/actions action to v3.4.2 (#924) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/build_pull_request.yml | 4 ++-- .github/workflows/build_push.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build_pull_request.yml b/.github/workflows/build_pull_request.yml index 537dee9ee..ef49e0414 100644 --- a/.github/workflows/build_pull_request.yml +++ b/.github/workflows/build_pull_request.yml @@ -23,7 +23,7 @@ jobs: uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Validate Gradle Wrapper - uses: gradle/actions/wrapper-validation@31ae3562f68c96d481c31bc1a8a55cc1be162f83 # v3.4.1 + uses: gradle/actions/wrapper-validation@dbbdc275be76ac10734476cc723d82dfe7ec6eda # v3.4.2 - name: Dependency Review uses: actions/dependency-review-action@72eb03d02c7872a771aacd928f3123ac62ad6d3a # v4.3.3 @@ -35,7 +35,7 @@ jobs: distribution: adopt - name: Set up gradle - uses: gradle/actions/setup-gradle@31ae3562f68c96d481c31bc1a8a55cc1be162f83 # v3.4.1 + uses: gradle/actions/setup-gradle@dbbdc275be76ac10734476cc723d82dfe7ec6eda # v3.4.2 - name: Build app and run unit tests run: ./gradlew detekt assembleStandardRelease testReleaseUnitTest diff --git a/.github/workflows/build_push.yml b/.github/workflows/build_push.yml index ddd4cff6d..fd6862b3f 100644 --- a/.github/workflows/build_push.yml +++ b/.github/workflows/build_push.yml @@ -20,7 +20,7 @@ jobs: uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Validate Gradle Wrapper - uses: gradle/actions/wrapper-validation@31ae3562f68c96d481c31bc1a8a55cc1be162f83 # v3.4.1 + uses: gradle/actions/wrapper-validation@dbbdc275be76ac10734476cc723d82dfe7ec6eda # v3.4.2 - name: Setup Android SDK run: | @@ -33,7 +33,7 @@ jobs: distribution: adopt - name: Set up gradle - uses: gradle/actions/setup-gradle@31ae3562f68c96d481c31bc1a8a55cc1be162f83 # v3.4.1 + uses: gradle/actions/setup-gradle@dbbdc275be76ac10734476cc723d82dfe7ec6eda # v3.4.2 - name: Build app and run unit tests run: ./gradlew detekt assembleStandardRelease testReleaseUnitTest From 5e2a3ee92757f0ccf7f2b6edea814b92ad059996 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 21 Jun 2024 01:41:26 +0600 Subject: [PATCH 062/297] chore(deps): update softprops/action-gh-release action to v2.0.6 (#929) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/build_push.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_push.yml b/.github/workflows/build_push.yml index fd6862b3f..e85411cd2 100644 --- a/.github/workflows/build_push.yml +++ b/.github/workflows/build_push.yml @@ -83,7 +83,7 @@ jobs: - name: Create Release if: startsWith(github.ref, 'refs/tags/') && github.repository == 'mihonapp/mihon' - uses: softprops/action-gh-release@69320dbe05506a9a39fc8ae11030b214ec2d1f87 # v2.0.5 + uses: softprops/action-gh-release@a74c6b72af54cfa997e81df42d94703d6313a2d0 # v2.0.6 with: tag_name: ${{ env.VERSION_TAG }} name: Mihon ${{ env.VERSION_TAG }} From cf02119da55c431d0fb4c42ecfec3681d466ae43 Mon Sep 17 00:00:00 2001 From: "Weblate (bot)" Date: Thu, 20 Jun 2024 22:24:22 +0200 Subject: [PATCH 063/297] Translations update from Hosted Weblate (#904) * Translated using Weblate (Malayalam) Currently translated at 16.9% (136 of 804 strings) Translation: Mihon/Mihon Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ml/ * Translated using Weblate (Swedish) Currently translated at 99.1% (797 of 804 strings) Translation: Mihon/Mihon Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/sv/ * Translated using Weblate (Arabic) Currently translated at 99.5% (800 of 804 strings) Translation: Mihon/Mihon Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ar/ * Translated using Weblate (Swedish) Currently translated at 100.0% (804 of 804 strings) Translation: Mihon/Mihon Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/sv/ * Translated using Weblate (Swedish) Currently translated at 100.0% (18 of 18 strings) Translation: Mihon/Mihon Plurals Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/sv/ --------- Co-authored-by: Akhil Raj Co-authored-by: Norsze Co-authored-by: Duh051 Co-authored-by: bittin1ddc447d824349b2 --- i18n/src/commonMain/resources/MR/ar/strings.xml | 9 +++++++++ i18n/src/commonMain/resources/MR/ml/strings.xml | 11 +++++++++++ i18n/src/commonMain/resources/MR/sv/plurals.xml | 4 ++++ i18n/src/commonMain/resources/MR/sv/strings.xml | 14 ++++++++++++++ 4 files changed, 38 insertions(+) diff --git a/i18n/src/commonMain/resources/MR/ar/strings.xml b/i18n/src/commonMain/resources/MR/ar/strings.xml index 3f5ca8fd2..7ebedaeee 100644 --- a/i18n/src/commonMain/resources/MR/ar/strings.xml +++ b/i18n/src/commonMain/resources/MR/ar/strings.xml @@ -796,4 +796,13 @@ إضافة مستودع من المتوقع أن يتم إصدار فصول جديدة في حوالي 1%1$s، والتحقق من كل 2%2$s . متاح: %1$s / الكل: %2$s + الشهر السابق + الدليل القادم + الشهر القادم + القادم + عرض الثحديثات القادمة + أضف على أي حال + استبدل + بصمة مفتاح الانخراط موجودة من قبل + تعطيل التصغير \ No newline at end of file diff --git a/i18n/src/commonMain/resources/MR/ml/strings.xml b/i18n/src/commonMain/resources/MR/ml/strings.xml index b9c9409dd..7e6ad53a5 100644 --- a/i18n/src/commonMain/resources/MR/ml/strings.xml +++ b/i18n/src/commonMain/resources/MR/ml/strings.xml @@ -120,4 +120,15 @@ സോർട് ലിസ്റ്റ് ചിത്രം മാത്രമുള്ള ഗ്രിഡ് + പുനഃസജ്ജമാക്കുക + പരമ്പര മുകളിലേക്ക് നീക്കുക + വിഭാഗം ടാബുകൾ കാണിക്കുക + അൺപിൻ ചെയ്യുക + അപ്‌ലോഡ് തീയതി പ്രകാരം + ആരോഹണം + അവരോഹണം + ഇൻസ്റ്റാൾ + താഴേക്ക് നീക്കുക + പങ്കിടുക + പ്രദർശിപ്പിക്കുക \ No newline at end of file diff --git a/i18n/src/commonMain/resources/MR/sv/plurals.xml b/i18n/src/commonMain/resources/MR/sv/plurals.xml index 976b04004..83e463a38 100644 --- a/i18n/src/commonMain/resources/MR/sv/plurals.xml +++ b/i18n/src/commonMain/resources/MR/sv/plurals.xml @@ -68,4 +68,8 @@ %d förråd %d flera förråd + + Imorgon + Om %1$d dagar + \ No newline at end of file diff --git a/i18n/src/commonMain/resources/MR/sv/strings.xml b/i18n/src/commonMain/resources/MR/sv/strings.xml index 5231c7374..bce82c14c 100644 --- a/i18n/src/commonMain/resources/MR/sv/strings.xml +++ b/i18n/src/commonMain/resources/MR/sv/strings.xml @@ -796,4 +796,18 @@ Öppenkällkods förråd Snart Anpassad uppdateringsfrekvens: + Inaktivera utzoomning + Lägg till ändå + Ersätt + Anpassad skärmprofil + Kommande + Föregående månad + Nästa månad + Migrera existerande post + Signeringsnyckel-fingeravtryck finns redan + Förrådet %1$s har samma Signering av nyckelfingeravtryck som %2$s. +\nOm detta förväntas kommer %2$s att ersättas, annars kontakta den förråds-ansvarige. + Visa kommande uppdateringar + Kommande guide + Misslyckades med att skaffa beständig mappåtkomst. Appen kan bete sig oväntat. \ No newline at end of file From f58a05e91828a69c01d49d629e5bfa9ec7ae3ffc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 21 Jun 2024 02:43:48 +0600 Subject: [PATCH 064/297] fix(deps): update moko to v0.24.1 (#933) * fix(deps): update moko to v0.24.1 * Fix build --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com> --- .../kotlin/mihon/buildlogic/tasks/LocalesConfigPlugin.kt | 2 +- gradle/libs.versions.toml | 2 +- i18n/build.gradle.kts | 8 ++------ .../{resources/MR => moko-resources}/am/plurals.xml | 0 .../{resources/MR => moko-resources}/am/strings.xml | 0 .../{resources/MR => moko-resources}/ar/plurals.xml | 0 .../{resources/MR => moko-resources}/ar/strings.xml | 0 .../{resources/MR => moko-resources}/base/plurals.xml | 0 .../{resources/MR => moko-resources}/base/strings.xml | 0 .../{resources/MR => moko-resources}/be/plurals.xml | 0 .../{resources/MR => moko-resources}/be/strings.xml | 0 .../{resources/MR => moko-resources}/bg/plurals.xml | 0 .../{resources/MR => moko-resources}/bg/strings.xml | 0 .../{resources/MR => moko-resources}/bn/plurals.xml | 0 .../{resources/MR => moko-resources}/bn/strings.xml | 0 .../{resources/MR => moko-resources}/ca/plurals.xml | 0 .../{resources/MR => moko-resources}/ca/strings.xml | 0 .../{resources/MR => moko-resources}/ceb/plurals.xml | 0 .../{resources/MR => moko-resources}/ceb/strings.xml | 0 .../{resources/MR => moko-resources}/cs/plurals.xml | 0 .../{resources/MR => moko-resources}/cs/strings.xml | 0 .../{resources/MR => moko-resources}/cv/plurals.xml | 0 .../{resources/MR => moko-resources}/cv/strings.xml | 0 .../{resources/MR => moko-resources}/da/plurals.xml | 0 .../{resources/MR => moko-resources}/da/strings.xml | 0 .../{resources/MR => moko-resources}/de/plurals.xml | 0 .../{resources/MR => moko-resources}/de/strings.xml | 0 .../{resources/MR => moko-resources}/el/plurals.xml | 0 .../{resources/MR => moko-resources}/el/strings.xml | 0 .../{resources/MR => moko-resources}/eo/plurals.xml | 0 .../{resources/MR => moko-resources}/eo/strings.xml | 0 .../{resources/MR => moko-resources}/es/plurals.xml | 0 .../{resources/MR => moko-resources}/es/strings.xml | 0 .../{resources/MR => moko-resources}/eu/plurals.xml | 0 .../{resources/MR => moko-resources}/eu/strings.xml | 0 .../{resources/MR => moko-resources}/fa/plurals.xml | 0 .../{resources/MR => moko-resources}/fa/strings.xml | 0 .../{resources/MR => moko-resources}/fi/plurals.xml | 0 .../{resources/MR => moko-resources}/fi/strings.xml | 0 .../{resources/MR => moko-resources}/fil/plurals.xml | 0 .../{resources/MR => moko-resources}/fil/strings.xml | 0 .../{resources/MR => moko-resources}/fr/plurals.xml | 0 .../{resources/MR => moko-resources}/fr/strings.xml | 0 .../{resources/MR => moko-resources}/gl/plurals.xml | 0 .../{resources/MR => moko-resources}/gl/strings.xml | 0 .../{resources/MR => moko-resources}/he/plurals.xml | 0 .../{resources/MR => moko-resources}/he/strings.xml | 0 .../{resources/MR => moko-resources}/hi/plurals.xml | 0 .../{resources/MR => moko-resources}/hi/strings.xml | 0 .../{resources/MR => moko-resources}/hr/plurals.xml | 0 .../{resources/MR => moko-resources}/hr/strings.xml | 0 .../{resources/MR => moko-resources}/hu/plurals.xml | 0 .../{resources/MR => moko-resources}/hu/strings.xml | 0 .../{resources/MR => moko-resources}/in/plurals.xml | 0 .../{resources/MR => moko-resources}/in/strings.xml | 0 .../{resources/MR => moko-resources}/it/plurals.xml | 0 .../{resources/MR => moko-resources}/it/strings.xml | 0 .../{resources/MR => moko-resources}/ja/plurals.xml | 0 .../{resources/MR => moko-resources}/ja/strings.xml | 0 .../{resources/MR => moko-resources}/jv/plurals.xml | 0 .../{resources/MR => moko-resources}/jv/strings.xml | 0 .../{resources/MR => moko-resources}/ka-rGE/plurals.xml | 0 .../{resources/MR => moko-resources}/ka-rGE/strings.xml | 0 .../{resources/MR => moko-resources}/kk/plurals.xml | 0 .../{resources/MR => moko-resources}/kk/strings.xml | 0 .../{resources/MR => moko-resources}/km/plurals.xml | 0 .../{resources/MR => moko-resources}/km/strings.xml | 0 .../{resources/MR => moko-resources}/kn/plurals.xml | 0 .../{resources/MR => moko-resources}/kn/strings.xml | 0 .../{resources/MR => moko-resources}/ko/plurals.xml | 0 .../{resources/MR => moko-resources}/ko/strings.xml | 0 .../{resources/MR => moko-resources}/lt/plurals.xml | 0 .../{resources/MR => moko-resources}/lt/strings.xml | 0 .../{resources/MR => moko-resources}/lv/plurals.xml | 0 .../{resources/MR => moko-resources}/lv/strings.xml | 0 .../{resources/MR => moko-resources}/ml/plurals.xml | 0 .../{resources/MR => moko-resources}/ml/strings.xml | 0 .../{resources/MR => moko-resources}/mr/plurals.xml | 0 .../{resources/MR => moko-resources}/mr/strings.xml | 0 .../{resources/MR => moko-resources}/ms/plurals.xml | 0 .../{resources/MR => moko-resources}/ms/strings.xml | 0 .../{resources/MR => moko-resources}/nb-rNO/plurals.xml | 0 .../{resources/MR => moko-resources}/nb-rNO/strings.xml | 0 .../{resources/MR => moko-resources}/ne/plurals.xml | 0 .../{resources/MR => moko-resources}/ne/strings.xml | 0 .../{resources/MR => moko-resources}/nl/plurals.xml | 0 .../{resources/MR => moko-resources}/nl/strings.xml | 0 .../{resources/MR => moko-resources}/nn/plurals.xml | 0 .../{resources/MR => moko-resources}/nn/strings.xml | 0 .../{resources/MR => moko-resources}/pl/plurals.xml | 0 .../{resources/MR => moko-resources}/pl/strings.xml | 0 .../{resources/MR => moko-resources}/pt-rBR/plurals.xml | 0 .../{resources/MR => moko-resources}/pt-rBR/strings.xml | 0 .../{resources/MR => moko-resources}/pt/plurals.xml | 0 .../{resources/MR => moko-resources}/pt/strings.xml | 0 .../{resources/MR => moko-resources}/ro/plurals.xml | 0 .../{resources/MR => moko-resources}/ro/strings.xml | 0 .../{resources/MR => moko-resources}/ru/plurals.xml | 0 .../{resources/MR => moko-resources}/ru/strings.xml | 0 .../{resources/MR => moko-resources}/sa/plurals.xml | 0 .../{resources/MR => moko-resources}/sa/strings.xml | 0 .../{resources/MR => moko-resources}/sah/plurals.xml | 0 .../{resources/MR => moko-resources}/sah/strings.xml | 0 .../{resources/MR => moko-resources}/sc/plurals.xml | 0 .../{resources/MR => moko-resources}/sc/strings.xml | 0 .../{resources/MR => moko-resources}/sdh/plurals.xml | 0 .../{resources/MR => moko-resources}/sdh/strings.xml | 0 .../{resources/MR => moko-resources}/sk/plurals.xml | 0 .../{resources/MR => moko-resources}/sk/strings.xml | 0 .../{resources/MR => moko-resources}/sq/plurals.xml | 0 .../{resources/MR => moko-resources}/sq/strings.xml | 0 .../{resources/MR => moko-resources}/sr/plurals.xml | 0 .../{resources/MR => moko-resources}/sr/strings.xml | 0 .../{resources/MR => moko-resources}/sv/plurals.xml | 0 .../{resources/MR => moko-resources}/sv/strings.xml | 0 .../{resources/MR => moko-resources}/te/plurals.xml | 0 .../{resources/MR => moko-resources}/te/strings.xml | 0 .../{resources/MR => moko-resources}/th/plurals.xml | 0 .../{resources/MR => moko-resources}/th/strings.xml | 0 .../{resources/MR => moko-resources}/tr/plurals.xml | 0 .../{resources/MR => moko-resources}/tr/strings.xml | 0 .../{resources/MR => moko-resources}/uk/plurals.xml | 0 .../{resources/MR => moko-resources}/uk/strings.xml | 0 .../{resources/MR => moko-resources}/uz/plurals.xml | 0 .../{resources/MR => moko-resources}/uz/strings.xml | 0 .../{resources/MR => moko-resources}/vi/plurals.xml | 0 .../{resources/MR => moko-resources}/vi/strings.xml | 0 .../{resources/MR => moko-resources}/zh-rCN/plurals.xml | 0 .../{resources/MR => moko-resources}/zh-rCN/strings.xml | 0 .../{resources/MR => moko-resources}/zh-rTW/plurals.xml | 0 .../{resources/MR => moko-resources}/zh-rTW/strings.xml | 0 131 files changed, 4 insertions(+), 8 deletions(-) rename i18n/src/commonMain/{resources/MR => moko-resources}/am/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/am/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/ar/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/ar/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/base/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/base/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/be/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/be/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/bg/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/bg/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/bn/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/bn/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/ca/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/ca/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/ceb/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/ceb/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/cs/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/cs/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/cv/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/cv/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/da/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/da/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/de/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/de/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/el/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/el/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/eo/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/eo/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/es/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/es/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/eu/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/eu/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/fa/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/fa/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/fi/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/fi/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/fil/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/fil/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/fr/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/fr/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/gl/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/gl/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/he/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/he/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/hi/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/hi/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/hr/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/hr/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/hu/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/hu/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/in/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/in/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/it/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/it/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/ja/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/ja/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/jv/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/jv/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/ka-rGE/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/ka-rGE/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/kk/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/kk/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/km/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/km/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/kn/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/kn/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/ko/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/ko/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/lt/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/lt/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/lv/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/lv/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/ml/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/ml/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/mr/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/mr/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/ms/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/ms/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/nb-rNO/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/nb-rNO/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/ne/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/ne/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/nl/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/nl/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/nn/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/nn/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/pl/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/pl/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/pt-rBR/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/pt-rBR/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/pt/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/pt/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/ro/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/ro/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/ru/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/ru/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/sa/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/sa/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/sah/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/sah/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/sc/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/sc/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/sdh/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/sdh/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/sk/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/sk/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/sq/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/sq/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/sr/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/sr/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/sv/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/sv/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/te/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/te/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/th/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/th/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/tr/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/tr/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/uk/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/uk/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/uz/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/uz/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/vi/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/vi/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/zh-rCN/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/zh-rCN/strings.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/zh-rTW/plurals.xml (100%) rename i18n/src/commonMain/{resources/MR => moko-resources}/zh-rTW/strings.xml (100%) diff --git a/buildSrc/src/main/kotlin/mihon/buildlogic/tasks/LocalesConfigPlugin.kt b/buildSrc/src/main/kotlin/mihon/buildlogic/tasks/LocalesConfigPlugin.kt index 961a3b751..d84d2cb64 100644 --- a/buildSrc/src/main/kotlin/mihon/buildlogic/tasks/LocalesConfigPlugin.kt +++ b/buildSrc/src/main/kotlin/mihon/buildlogic/tasks/LocalesConfigPlugin.kt @@ -8,7 +8,7 @@ private val emptyResourcesElement = "\\s*|".t fun Project.getLocalesConfigTask(): TaskProvider { return tasks.register("generateLocalesConfig") { - val locales = fileTree("$projectDir/src/commonMain/resources/MR/") + val locales = fileTree("$projectDir/src/commonMain/moko-resources/") .matching { include("**/strings.xml") } .filterNot { it.readText().contains(emptyResourcesElement) } .map { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index bdb58f6f4..a3bfcec8f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] aboutlib_version = "11.2.1" leakcanary = "2.14" -moko = "0.23.0" +moko = "0.24.1" okhttp_version = "5.0.0-alpha.14" richtext = "0.20.0" shizuku_version = "12.2.0" diff --git a/i18n/build.gradle.kts b/i18n/build.gradle.kts index bdfe09b97..7c7256acc 100644 --- a/i18n/build.gradle.kts +++ b/i18n/build.gradle.kts @@ -13,15 +13,11 @@ kotlin { applyDefaultHierarchyTemplate() sourceSets { - val commonMain by getting { + commonMain { dependencies { api(libs.moko.core) } } - - androidMain { - dependsOn(commonMain) // https://github.com/icerockdev/moko-resources/issues/562 - } } } @@ -40,7 +36,7 @@ android { } multiplatformResources { - multiplatformResourcesPackage = "tachiyomi.i18n" + resourcesPackage.set("tachiyomi.i18n") } tasks { diff --git a/i18n/src/commonMain/resources/MR/am/plurals.xml b/i18n/src/commonMain/moko-resources/am/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/am/plurals.xml rename to i18n/src/commonMain/moko-resources/am/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/am/strings.xml b/i18n/src/commonMain/moko-resources/am/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/am/strings.xml rename to i18n/src/commonMain/moko-resources/am/strings.xml diff --git a/i18n/src/commonMain/resources/MR/ar/plurals.xml b/i18n/src/commonMain/moko-resources/ar/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/ar/plurals.xml rename to i18n/src/commonMain/moko-resources/ar/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/ar/strings.xml b/i18n/src/commonMain/moko-resources/ar/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/ar/strings.xml rename to i18n/src/commonMain/moko-resources/ar/strings.xml diff --git a/i18n/src/commonMain/resources/MR/base/plurals.xml b/i18n/src/commonMain/moko-resources/base/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/base/plurals.xml rename to i18n/src/commonMain/moko-resources/base/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/base/strings.xml b/i18n/src/commonMain/moko-resources/base/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/base/strings.xml rename to i18n/src/commonMain/moko-resources/base/strings.xml diff --git a/i18n/src/commonMain/resources/MR/be/plurals.xml b/i18n/src/commonMain/moko-resources/be/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/be/plurals.xml rename to i18n/src/commonMain/moko-resources/be/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/be/strings.xml b/i18n/src/commonMain/moko-resources/be/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/be/strings.xml rename to i18n/src/commonMain/moko-resources/be/strings.xml diff --git a/i18n/src/commonMain/resources/MR/bg/plurals.xml b/i18n/src/commonMain/moko-resources/bg/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/bg/plurals.xml rename to i18n/src/commonMain/moko-resources/bg/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/bg/strings.xml b/i18n/src/commonMain/moko-resources/bg/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/bg/strings.xml rename to i18n/src/commonMain/moko-resources/bg/strings.xml diff --git a/i18n/src/commonMain/resources/MR/bn/plurals.xml b/i18n/src/commonMain/moko-resources/bn/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/bn/plurals.xml rename to i18n/src/commonMain/moko-resources/bn/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/bn/strings.xml b/i18n/src/commonMain/moko-resources/bn/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/bn/strings.xml rename to i18n/src/commonMain/moko-resources/bn/strings.xml diff --git a/i18n/src/commonMain/resources/MR/ca/plurals.xml b/i18n/src/commonMain/moko-resources/ca/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/ca/plurals.xml rename to i18n/src/commonMain/moko-resources/ca/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/ca/strings.xml b/i18n/src/commonMain/moko-resources/ca/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/ca/strings.xml rename to i18n/src/commonMain/moko-resources/ca/strings.xml diff --git a/i18n/src/commonMain/resources/MR/ceb/plurals.xml b/i18n/src/commonMain/moko-resources/ceb/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/ceb/plurals.xml rename to i18n/src/commonMain/moko-resources/ceb/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/ceb/strings.xml b/i18n/src/commonMain/moko-resources/ceb/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/ceb/strings.xml rename to i18n/src/commonMain/moko-resources/ceb/strings.xml diff --git a/i18n/src/commonMain/resources/MR/cs/plurals.xml b/i18n/src/commonMain/moko-resources/cs/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/cs/plurals.xml rename to i18n/src/commonMain/moko-resources/cs/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/cs/strings.xml b/i18n/src/commonMain/moko-resources/cs/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/cs/strings.xml rename to i18n/src/commonMain/moko-resources/cs/strings.xml diff --git a/i18n/src/commonMain/resources/MR/cv/plurals.xml b/i18n/src/commonMain/moko-resources/cv/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/cv/plurals.xml rename to i18n/src/commonMain/moko-resources/cv/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/cv/strings.xml b/i18n/src/commonMain/moko-resources/cv/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/cv/strings.xml rename to i18n/src/commonMain/moko-resources/cv/strings.xml diff --git a/i18n/src/commonMain/resources/MR/da/plurals.xml b/i18n/src/commonMain/moko-resources/da/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/da/plurals.xml rename to i18n/src/commonMain/moko-resources/da/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/da/strings.xml b/i18n/src/commonMain/moko-resources/da/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/da/strings.xml rename to i18n/src/commonMain/moko-resources/da/strings.xml diff --git a/i18n/src/commonMain/resources/MR/de/plurals.xml b/i18n/src/commonMain/moko-resources/de/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/de/plurals.xml rename to i18n/src/commonMain/moko-resources/de/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/de/strings.xml b/i18n/src/commonMain/moko-resources/de/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/de/strings.xml rename to i18n/src/commonMain/moko-resources/de/strings.xml diff --git a/i18n/src/commonMain/resources/MR/el/plurals.xml b/i18n/src/commonMain/moko-resources/el/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/el/plurals.xml rename to i18n/src/commonMain/moko-resources/el/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/el/strings.xml b/i18n/src/commonMain/moko-resources/el/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/el/strings.xml rename to i18n/src/commonMain/moko-resources/el/strings.xml diff --git a/i18n/src/commonMain/resources/MR/eo/plurals.xml b/i18n/src/commonMain/moko-resources/eo/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/eo/plurals.xml rename to i18n/src/commonMain/moko-resources/eo/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/eo/strings.xml b/i18n/src/commonMain/moko-resources/eo/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/eo/strings.xml rename to i18n/src/commonMain/moko-resources/eo/strings.xml diff --git a/i18n/src/commonMain/resources/MR/es/plurals.xml b/i18n/src/commonMain/moko-resources/es/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/es/plurals.xml rename to i18n/src/commonMain/moko-resources/es/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/es/strings.xml b/i18n/src/commonMain/moko-resources/es/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/es/strings.xml rename to i18n/src/commonMain/moko-resources/es/strings.xml diff --git a/i18n/src/commonMain/resources/MR/eu/plurals.xml b/i18n/src/commonMain/moko-resources/eu/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/eu/plurals.xml rename to i18n/src/commonMain/moko-resources/eu/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/eu/strings.xml b/i18n/src/commonMain/moko-resources/eu/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/eu/strings.xml rename to i18n/src/commonMain/moko-resources/eu/strings.xml diff --git a/i18n/src/commonMain/resources/MR/fa/plurals.xml b/i18n/src/commonMain/moko-resources/fa/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/fa/plurals.xml rename to i18n/src/commonMain/moko-resources/fa/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/fa/strings.xml b/i18n/src/commonMain/moko-resources/fa/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/fa/strings.xml rename to i18n/src/commonMain/moko-resources/fa/strings.xml diff --git a/i18n/src/commonMain/resources/MR/fi/plurals.xml b/i18n/src/commonMain/moko-resources/fi/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/fi/plurals.xml rename to i18n/src/commonMain/moko-resources/fi/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/fi/strings.xml b/i18n/src/commonMain/moko-resources/fi/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/fi/strings.xml rename to i18n/src/commonMain/moko-resources/fi/strings.xml diff --git a/i18n/src/commonMain/resources/MR/fil/plurals.xml b/i18n/src/commonMain/moko-resources/fil/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/fil/plurals.xml rename to i18n/src/commonMain/moko-resources/fil/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/fil/strings.xml b/i18n/src/commonMain/moko-resources/fil/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/fil/strings.xml rename to i18n/src/commonMain/moko-resources/fil/strings.xml diff --git a/i18n/src/commonMain/resources/MR/fr/plurals.xml b/i18n/src/commonMain/moko-resources/fr/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/fr/plurals.xml rename to i18n/src/commonMain/moko-resources/fr/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/fr/strings.xml b/i18n/src/commonMain/moko-resources/fr/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/fr/strings.xml rename to i18n/src/commonMain/moko-resources/fr/strings.xml diff --git a/i18n/src/commonMain/resources/MR/gl/plurals.xml b/i18n/src/commonMain/moko-resources/gl/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/gl/plurals.xml rename to i18n/src/commonMain/moko-resources/gl/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/gl/strings.xml b/i18n/src/commonMain/moko-resources/gl/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/gl/strings.xml rename to i18n/src/commonMain/moko-resources/gl/strings.xml diff --git a/i18n/src/commonMain/resources/MR/he/plurals.xml b/i18n/src/commonMain/moko-resources/he/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/he/plurals.xml rename to i18n/src/commonMain/moko-resources/he/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/he/strings.xml b/i18n/src/commonMain/moko-resources/he/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/he/strings.xml rename to i18n/src/commonMain/moko-resources/he/strings.xml diff --git a/i18n/src/commonMain/resources/MR/hi/plurals.xml b/i18n/src/commonMain/moko-resources/hi/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/hi/plurals.xml rename to i18n/src/commonMain/moko-resources/hi/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/hi/strings.xml b/i18n/src/commonMain/moko-resources/hi/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/hi/strings.xml rename to i18n/src/commonMain/moko-resources/hi/strings.xml diff --git a/i18n/src/commonMain/resources/MR/hr/plurals.xml b/i18n/src/commonMain/moko-resources/hr/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/hr/plurals.xml rename to i18n/src/commonMain/moko-resources/hr/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/hr/strings.xml b/i18n/src/commonMain/moko-resources/hr/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/hr/strings.xml rename to i18n/src/commonMain/moko-resources/hr/strings.xml diff --git a/i18n/src/commonMain/resources/MR/hu/plurals.xml b/i18n/src/commonMain/moko-resources/hu/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/hu/plurals.xml rename to i18n/src/commonMain/moko-resources/hu/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/hu/strings.xml b/i18n/src/commonMain/moko-resources/hu/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/hu/strings.xml rename to i18n/src/commonMain/moko-resources/hu/strings.xml diff --git a/i18n/src/commonMain/resources/MR/in/plurals.xml b/i18n/src/commonMain/moko-resources/in/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/in/plurals.xml rename to i18n/src/commonMain/moko-resources/in/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/in/strings.xml b/i18n/src/commonMain/moko-resources/in/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/in/strings.xml rename to i18n/src/commonMain/moko-resources/in/strings.xml diff --git a/i18n/src/commonMain/resources/MR/it/plurals.xml b/i18n/src/commonMain/moko-resources/it/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/it/plurals.xml rename to i18n/src/commonMain/moko-resources/it/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/it/strings.xml b/i18n/src/commonMain/moko-resources/it/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/it/strings.xml rename to i18n/src/commonMain/moko-resources/it/strings.xml diff --git a/i18n/src/commonMain/resources/MR/ja/plurals.xml b/i18n/src/commonMain/moko-resources/ja/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/ja/plurals.xml rename to i18n/src/commonMain/moko-resources/ja/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/ja/strings.xml b/i18n/src/commonMain/moko-resources/ja/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/ja/strings.xml rename to i18n/src/commonMain/moko-resources/ja/strings.xml diff --git a/i18n/src/commonMain/resources/MR/jv/plurals.xml b/i18n/src/commonMain/moko-resources/jv/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/jv/plurals.xml rename to i18n/src/commonMain/moko-resources/jv/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/jv/strings.xml b/i18n/src/commonMain/moko-resources/jv/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/jv/strings.xml rename to i18n/src/commonMain/moko-resources/jv/strings.xml diff --git a/i18n/src/commonMain/resources/MR/ka-rGE/plurals.xml b/i18n/src/commonMain/moko-resources/ka-rGE/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/ka-rGE/plurals.xml rename to i18n/src/commonMain/moko-resources/ka-rGE/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/ka-rGE/strings.xml b/i18n/src/commonMain/moko-resources/ka-rGE/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/ka-rGE/strings.xml rename to i18n/src/commonMain/moko-resources/ka-rGE/strings.xml diff --git a/i18n/src/commonMain/resources/MR/kk/plurals.xml b/i18n/src/commonMain/moko-resources/kk/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/kk/plurals.xml rename to i18n/src/commonMain/moko-resources/kk/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/kk/strings.xml b/i18n/src/commonMain/moko-resources/kk/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/kk/strings.xml rename to i18n/src/commonMain/moko-resources/kk/strings.xml diff --git a/i18n/src/commonMain/resources/MR/km/plurals.xml b/i18n/src/commonMain/moko-resources/km/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/km/plurals.xml rename to i18n/src/commonMain/moko-resources/km/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/km/strings.xml b/i18n/src/commonMain/moko-resources/km/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/km/strings.xml rename to i18n/src/commonMain/moko-resources/km/strings.xml diff --git a/i18n/src/commonMain/resources/MR/kn/plurals.xml b/i18n/src/commonMain/moko-resources/kn/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/kn/plurals.xml rename to i18n/src/commonMain/moko-resources/kn/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/kn/strings.xml b/i18n/src/commonMain/moko-resources/kn/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/kn/strings.xml rename to i18n/src/commonMain/moko-resources/kn/strings.xml diff --git a/i18n/src/commonMain/resources/MR/ko/plurals.xml b/i18n/src/commonMain/moko-resources/ko/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/ko/plurals.xml rename to i18n/src/commonMain/moko-resources/ko/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/ko/strings.xml b/i18n/src/commonMain/moko-resources/ko/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/ko/strings.xml rename to i18n/src/commonMain/moko-resources/ko/strings.xml diff --git a/i18n/src/commonMain/resources/MR/lt/plurals.xml b/i18n/src/commonMain/moko-resources/lt/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/lt/plurals.xml rename to i18n/src/commonMain/moko-resources/lt/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/lt/strings.xml b/i18n/src/commonMain/moko-resources/lt/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/lt/strings.xml rename to i18n/src/commonMain/moko-resources/lt/strings.xml diff --git a/i18n/src/commonMain/resources/MR/lv/plurals.xml b/i18n/src/commonMain/moko-resources/lv/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/lv/plurals.xml rename to i18n/src/commonMain/moko-resources/lv/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/lv/strings.xml b/i18n/src/commonMain/moko-resources/lv/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/lv/strings.xml rename to i18n/src/commonMain/moko-resources/lv/strings.xml diff --git a/i18n/src/commonMain/resources/MR/ml/plurals.xml b/i18n/src/commonMain/moko-resources/ml/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/ml/plurals.xml rename to i18n/src/commonMain/moko-resources/ml/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/ml/strings.xml b/i18n/src/commonMain/moko-resources/ml/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/ml/strings.xml rename to i18n/src/commonMain/moko-resources/ml/strings.xml diff --git a/i18n/src/commonMain/resources/MR/mr/plurals.xml b/i18n/src/commonMain/moko-resources/mr/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/mr/plurals.xml rename to i18n/src/commonMain/moko-resources/mr/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/mr/strings.xml b/i18n/src/commonMain/moko-resources/mr/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/mr/strings.xml rename to i18n/src/commonMain/moko-resources/mr/strings.xml diff --git a/i18n/src/commonMain/resources/MR/ms/plurals.xml b/i18n/src/commonMain/moko-resources/ms/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/ms/plurals.xml rename to i18n/src/commonMain/moko-resources/ms/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/ms/strings.xml b/i18n/src/commonMain/moko-resources/ms/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/ms/strings.xml rename to i18n/src/commonMain/moko-resources/ms/strings.xml diff --git a/i18n/src/commonMain/resources/MR/nb-rNO/plurals.xml b/i18n/src/commonMain/moko-resources/nb-rNO/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/nb-rNO/plurals.xml rename to i18n/src/commonMain/moko-resources/nb-rNO/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/nb-rNO/strings.xml b/i18n/src/commonMain/moko-resources/nb-rNO/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/nb-rNO/strings.xml rename to i18n/src/commonMain/moko-resources/nb-rNO/strings.xml diff --git a/i18n/src/commonMain/resources/MR/ne/plurals.xml b/i18n/src/commonMain/moko-resources/ne/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/ne/plurals.xml rename to i18n/src/commonMain/moko-resources/ne/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/ne/strings.xml b/i18n/src/commonMain/moko-resources/ne/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/ne/strings.xml rename to i18n/src/commonMain/moko-resources/ne/strings.xml diff --git a/i18n/src/commonMain/resources/MR/nl/plurals.xml b/i18n/src/commonMain/moko-resources/nl/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/nl/plurals.xml rename to i18n/src/commonMain/moko-resources/nl/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/nl/strings.xml b/i18n/src/commonMain/moko-resources/nl/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/nl/strings.xml rename to i18n/src/commonMain/moko-resources/nl/strings.xml diff --git a/i18n/src/commonMain/resources/MR/nn/plurals.xml b/i18n/src/commonMain/moko-resources/nn/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/nn/plurals.xml rename to i18n/src/commonMain/moko-resources/nn/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/nn/strings.xml b/i18n/src/commonMain/moko-resources/nn/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/nn/strings.xml rename to i18n/src/commonMain/moko-resources/nn/strings.xml diff --git a/i18n/src/commonMain/resources/MR/pl/plurals.xml b/i18n/src/commonMain/moko-resources/pl/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/pl/plurals.xml rename to i18n/src/commonMain/moko-resources/pl/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/pl/strings.xml b/i18n/src/commonMain/moko-resources/pl/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/pl/strings.xml rename to i18n/src/commonMain/moko-resources/pl/strings.xml diff --git a/i18n/src/commonMain/resources/MR/pt-rBR/plurals.xml b/i18n/src/commonMain/moko-resources/pt-rBR/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/pt-rBR/plurals.xml rename to i18n/src/commonMain/moko-resources/pt-rBR/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/pt-rBR/strings.xml b/i18n/src/commonMain/moko-resources/pt-rBR/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/pt-rBR/strings.xml rename to i18n/src/commonMain/moko-resources/pt-rBR/strings.xml diff --git a/i18n/src/commonMain/resources/MR/pt/plurals.xml b/i18n/src/commonMain/moko-resources/pt/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/pt/plurals.xml rename to i18n/src/commonMain/moko-resources/pt/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/pt/strings.xml b/i18n/src/commonMain/moko-resources/pt/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/pt/strings.xml rename to i18n/src/commonMain/moko-resources/pt/strings.xml diff --git a/i18n/src/commonMain/resources/MR/ro/plurals.xml b/i18n/src/commonMain/moko-resources/ro/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/ro/plurals.xml rename to i18n/src/commonMain/moko-resources/ro/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/ro/strings.xml b/i18n/src/commonMain/moko-resources/ro/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/ro/strings.xml rename to i18n/src/commonMain/moko-resources/ro/strings.xml diff --git a/i18n/src/commonMain/resources/MR/ru/plurals.xml b/i18n/src/commonMain/moko-resources/ru/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/ru/plurals.xml rename to i18n/src/commonMain/moko-resources/ru/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/ru/strings.xml b/i18n/src/commonMain/moko-resources/ru/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/ru/strings.xml rename to i18n/src/commonMain/moko-resources/ru/strings.xml diff --git a/i18n/src/commonMain/resources/MR/sa/plurals.xml b/i18n/src/commonMain/moko-resources/sa/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/sa/plurals.xml rename to i18n/src/commonMain/moko-resources/sa/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/sa/strings.xml b/i18n/src/commonMain/moko-resources/sa/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/sa/strings.xml rename to i18n/src/commonMain/moko-resources/sa/strings.xml diff --git a/i18n/src/commonMain/resources/MR/sah/plurals.xml b/i18n/src/commonMain/moko-resources/sah/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/sah/plurals.xml rename to i18n/src/commonMain/moko-resources/sah/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/sah/strings.xml b/i18n/src/commonMain/moko-resources/sah/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/sah/strings.xml rename to i18n/src/commonMain/moko-resources/sah/strings.xml diff --git a/i18n/src/commonMain/resources/MR/sc/plurals.xml b/i18n/src/commonMain/moko-resources/sc/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/sc/plurals.xml rename to i18n/src/commonMain/moko-resources/sc/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/sc/strings.xml b/i18n/src/commonMain/moko-resources/sc/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/sc/strings.xml rename to i18n/src/commonMain/moko-resources/sc/strings.xml diff --git a/i18n/src/commonMain/resources/MR/sdh/plurals.xml b/i18n/src/commonMain/moko-resources/sdh/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/sdh/plurals.xml rename to i18n/src/commonMain/moko-resources/sdh/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/sdh/strings.xml b/i18n/src/commonMain/moko-resources/sdh/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/sdh/strings.xml rename to i18n/src/commonMain/moko-resources/sdh/strings.xml diff --git a/i18n/src/commonMain/resources/MR/sk/plurals.xml b/i18n/src/commonMain/moko-resources/sk/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/sk/plurals.xml rename to i18n/src/commonMain/moko-resources/sk/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/sk/strings.xml b/i18n/src/commonMain/moko-resources/sk/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/sk/strings.xml rename to i18n/src/commonMain/moko-resources/sk/strings.xml diff --git a/i18n/src/commonMain/resources/MR/sq/plurals.xml b/i18n/src/commonMain/moko-resources/sq/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/sq/plurals.xml rename to i18n/src/commonMain/moko-resources/sq/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/sq/strings.xml b/i18n/src/commonMain/moko-resources/sq/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/sq/strings.xml rename to i18n/src/commonMain/moko-resources/sq/strings.xml diff --git a/i18n/src/commonMain/resources/MR/sr/plurals.xml b/i18n/src/commonMain/moko-resources/sr/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/sr/plurals.xml rename to i18n/src/commonMain/moko-resources/sr/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/sr/strings.xml b/i18n/src/commonMain/moko-resources/sr/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/sr/strings.xml rename to i18n/src/commonMain/moko-resources/sr/strings.xml diff --git a/i18n/src/commonMain/resources/MR/sv/plurals.xml b/i18n/src/commonMain/moko-resources/sv/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/sv/plurals.xml rename to i18n/src/commonMain/moko-resources/sv/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/sv/strings.xml b/i18n/src/commonMain/moko-resources/sv/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/sv/strings.xml rename to i18n/src/commonMain/moko-resources/sv/strings.xml diff --git a/i18n/src/commonMain/resources/MR/te/plurals.xml b/i18n/src/commonMain/moko-resources/te/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/te/plurals.xml rename to i18n/src/commonMain/moko-resources/te/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/te/strings.xml b/i18n/src/commonMain/moko-resources/te/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/te/strings.xml rename to i18n/src/commonMain/moko-resources/te/strings.xml diff --git a/i18n/src/commonMain/resources/MR/th/plurals.xml b/i18n/src/commonMain/moko-resources/th/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/th/plurals.xml rename to i18n/src/commonMain/moko-resources/th/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/th/strings.xml b/i18n/src/commonMain/moko-resources/th/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/th/strings.xml rename to i18n/src/commonMain/moko-resources/th/strings.xml diff --git a/i18n/src/commonMain/resources/MR/tr/plurals.xml b/i18n/src/commonMain/moko-resources/tr/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/tr/plurals.xml rename to i18n/src/commonMain/moko-resources/tr/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/tr/strings.xml b/i18n/src/commonMain/moko-resources/tr/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/tr/strings.xml rename to i18n/src/commonMain/moko-resources/tr/strings.xml diff --git a/i18n/src/commonMain/resources/MR/uk/plurals.xml b/i18n/src/commonMain/moko-resources/uk/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/uk/plurals.xml rename to i18n/src/commonMain/moko-resources/uk/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/uk/strings.xml b/i18n/src/commonMain/moko-resources/uk/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/uk/strings.xml rename to i18n/src/commonMain/moko-resources/uk/strings.xml diff --git a/i18n/src/commonMain/resources/MR/uz/plurals.xml b/i18n/src/commonMain/moko-resources/uz/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/uz/plurals.xml rename to i18n/src/commonMain/moko-resources/uz/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/uz/strings.xml b/i18n/src/commonMain/moko-resources/uz/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/uz/strings.xml rename to i18n/src/commonMain/moko-resources/uz/strings.xml diff --git a/i18n/src/commonMain/resources/MR/vi/plurals.xml b/i18n/src/commonMain/moko-resources/vi/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/vi/plurals.xml rename to i18n/src/commonMain/moko-resources/vi/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/vi/strings.xml b/i18n/src/commonMain/moko-resources/vi/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/vi/strings.xml rename to i18n/src/commonMain/moko-resources/vi/strings.xml diff --git a/i18n/src/commonMain/resources/MR/zh-rCN/plurals.xml b/i18n/src/commonMain/moko-resources/zh-rCN/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/zh-rCN/plurals.xml rename to i18n/src/commonMain/moko-resources/zh-rCN/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/zh-rCN/strings.xml b/i18n/src/commonMain/moko-resources/zh-rCN/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/zh-rCN/strings.xml rename to i18n/src/commonMain/moko-resources/zh-rCN/strings.xml diff --git a/i18n/src/commonMain/resources/MR/zh-rTW/plurals.xml b/i18n/src/commonMain/moko-resources/zh-rTW/plurals.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/zh-rTW/plurals.xml rename to i18n/src/commonMain/moko-resources/zh-rTW/plurals.xml diff --git a/i18n/src/commonMain/resources/MR/zh-rTW/strings.xml b/i18n/src/commonMain/moko-resources/zh-rTW/strings.xml similarity index 100% rename from i18n/src/commonMain/resources/MR/zh-rTW/strings.xml rename to i18n/src/commonMain/moko-resources/zh-rTW/strings.xml From b37357f9097730edb1d72f1297461e580286856c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 21 Jun 2024 03:21:27 +0600 Subject: [PATCH 065/297] fix(deps): update dependency com.google.firebase:firebase-analytics to v22.0.2 (#936) 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 a3bfcec8f..d02410c83 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -73,7 +73,7 @@ moko-gradle = { module = "dev.icerock.moko:resources-generator", version.ref = " logcat = "com.squareup.logcat:logcat:0.1" -firebase-analytics = "com.google.firebase:firebase-analytics:22.0.1" +firebase-analytics = "com.google.firebase:firebase-analytics:22.0.2" aboutLibraries-gradle = { module = "com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin", version.ref = "aboutlib_version" } aboutLibraries-compose = { module = "com.mikepenz:aboutlibraries-compose-m3", version.ref = "aboutlib_version" } From f6ec53cdde32a17bc394e55b697a3b59bfd76e58 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 23 Jun 2024 03:35:12 +0600 Subject: [PATCH 066/297] fix(deps): update dependency io.github.fornewid:material-motion-compose-core to v2.0.1 (#945) 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 d02410c83..3942f468f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -62,7 +62,7 @@ flexible-adapter-core = "com.github.arkon.FlexibleAdapter:flexible-adapter:c8013 photoview = "com.github.chrisbanes:PhotoView:2.3.0" directionalviewpager = "com.github.tachiyomiorg:DirectionalViewPager:1.0.0" insetter = "dev.chrisbanes.insetter:insetter:0.6.1" -compose-materialmotion = "io.github.fornewid:material-motion-compose-core:2.0.0" +compose-materialmotion = "io.github.fornewid:material-motion-compose-core:2.0.1" compose-webview = "io.github.kevinnzou:compose-webview:0.33.6" compose-grid = "io.woong.compose.grid:grid:1.2.2" From 4ed2062cabde8127cfa822cfff193e02a34d8ddb Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Sun, 23 Jun 2024 03:40:17 +0600 Subject: [PATCH 067/297] Update `build_pull_request.yml` `paths-ignore` --- .github/workflows/build_pull_request.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_pull_request.yml b/.github/workflows/build_pull_request.yml index ef49e0414..2a031c279 100644 --- a/.github/workflows/build_pull_request.yml +++ b/.github/workflows/build_pull_request.yml @@ -3,8 +3,8 @@ on: pull_request: paths-ignore: - '**.md' - - 'i18n/src/commonMain/resources/**/strings.xml' - - 'i18n/src/commonMain/resources/**/plurals.xml' + - 'i18n/src/commonMain/moko-resources/**/strings.xml' + - 'i18n/src/commonMain/moko-resources/**/plurals.xml' concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number }} From 0ce1cf22cdbb7d82df3db1a901253b4973ab027f Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Sun, 23 Jun 2024 05:53:49 +0800 Subject: [PATCH 068/297] Fix unexpected skips in strong skipping mode (#940) --- gradle/compose.versions.toml | 1 + source-api/build.gradle.kts | 3 +++ .../kotlin/eu/kanade/tachiyomi/source/model/FilterList.kt | 3 +++ 3 files changed, 7 insertions(+) diff --git a/gradle/compose.versions.toml b/gradle/compose.versions.toml index b5e306abe..c36eb21cb 100644 --- a/gradle/compose.versions.toml +++ b/gradle/compose.versions.toml @@ -8,6 +8,7 @@ bom = { group = "dev.chrisbanes.compose", name = "compose-bom", version.ref = "c foundation = { module = "androidx.compose.foundation:foundation" } animation = { module = "androidx.compose.animation:animation" } animation-graphics = { module = "androidx.compose.animation:animation-graphics" } +runtime = { module = "androidx.compose.runtime:runtime" } ui-tooling = { module = "androidx.compose.ui:ui-tooling" } ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview" } ui-util = { module = "androidx.compose.ui:ui-util" } diff --git a/source-api/build.gradle.kts b/source-api/build.gradle.kts index 7ac4d6e2c..ad562dcd5 100644 --- a/source-api/build.gradle.kts +++ b/source-api/build.gradle.kts @@ -13,6 +13,9 @@ kotlin { api(libs.injekt.core) api(libs.rxjava) api(libs.jsoup) + + implementation(project.dependencies.platform(compose.bom)) + implementation(compose.runtime) } } val androidMain by getting { diff --git a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/model/FilterList.kt b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/model/FilterList.kt index 77f339b9d..6c9935266 100644 --- a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/model/FilterList.kt +++ b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/model/FilterList.kt @@ -1,5 +1,8 @@ package eu.kanade.tachiyomi.source.model +import androidx.compose.runtime.Stable + +@Stable data class FilterList(val list: List>) : List> by list { constructor(vararg fs: Filter<*>) : this(if (fs.isNotEmpty()) fs.asList() else emptyList()) From e57638a49c759d36d25b92f26633df5bdfb0d2b3 Mon Sep 17 00:00:00 2001 From: "Tran M. Cuong" Date: Sun, 23 Jun 2024 05:05:44 +0700 Subject: [PATCH 069/297] Fix Migrator test and also add the test to build script (#896) * Fix MigratorTest after update to Kotlin 2.0.0 * add main module's test to build script --- .github/workflows/build_pull_request.yml | 2 +- .github/workflows/build_push.yml | 2 +- app/src/test/java/mihon/core/migration/MigratorTest.kt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build_pull_request.yml b/.github/workflows/build_pull_request.yml index 2a031c279..334ce464a 100644 --- a/.github/workflows/build_pull_request.yml +++ b/.github/workflows/build_pull_request.yml @@ -38,4 +38,4 @@ jobs: uses: gradle/actions/setup-gradle@dbbdc275be76ac10734476cc723d82dfe7ec6eda # v3.4.2 - name: Build app and run unit tests - run: ./gradlew detekt assembleStandardRelease testReleaseUnitTest + run: ./gradlew detekt assembleStandardRelease testReleaseUnitTest testStandardReleaseUnitTest diff --git a/.github/workflows/build_push.yml b/.github/workflows/build_push.yml index e85411cd2..47e6fe275 100644 --- a/.github/workflows/build_push.yml +++ b/.github/workflows/build_push.yml @@ -36,7 +36,7 @@ jobs: uses: gradle/actions/setup-gradle@dbbdc275be76ac10734476cc723d82dfe7ec6eda # v3.4.2 - name: Build app and run unit tests - run: ./gradlew detekt assembleStandardRelease testReleaseUnitTest + run: ./gradlew detekt assembleStandardRelease testReleaseUnitTest testStandardReleaseUnitTest # Sign APK and create release for tags diff --git a/app/src/test/java/mihon/core/migration/MigratorTest.kt b/app/src/test/java/mihon/core/migration/MigratorTest.kt index 47c4bc7c2..a805b5630 100644 --- a/app/src/test/java/mihon/core/migration/MigratorTest.kt +++ b/app/src/test/java/mihon/core/migration/MigratorTest.kt @@ -29,7 +29,7 @@ class MigratorTest { fun initilize() { migrationContext = MigrationContext(false) migrationJobFactory = spyk(MigrationJobFactory(migrationContext, CoroutineScope(Dispatchers.Main + Job()))) - migrationCompletedListener = spyk<() -> Unit>({}) + migrationCompletedListener = spyk(block = {}) migrationStrategyFactory = spyk(MigrationStrategyFactory(migrationJobFactory, migrationCompletedListener)) } From e17f70f7226ea031fc1f962c9dfea3e404ba53ad Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Sun, 23 Jun 2024 04:34:49 +0600 Subject: [PATCH 070/297] Cleanup in `CommonMangaItem.kt` Closes #19 Co-authored-by: Roshan Varughese <40583749+Animeboynz@users.noreply.github.com> --- .../library/components/CommonMangaItem.kt | 46 +++++++++++++------ 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/library/components/CommonMangaItem.kt b/app/src/main/java/eu/kanade/presentation/library/components/CommonMangaItem.kt index 92957384a..b4a4c2cc0 100644 --- a/app/src/main/java/eu/kanade/presentation/library/components/CommonMangaItem.kt +++ b/app/src/main/java/eu/kanade/presentation/library/components/CommonMangaItem.kt @@ -35,6 +35,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Shadow import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import eu.kanade.presentation.manga.components.MangaCover @@ -42,15 +43,22 @@ import tachiyomi.i18n.MR import tachiyomi.presentation.core.components.BadgeGroup import tachiyomi.presentation.core.i18n.stringResource import tachiyomi.presentation.core.util.selectedBackground +import tachiyomi.domain.manga.model.MangaCover as MangaCoverModel object CommonMangaItemDefaults { val GridHorizontalSpacer = 4.dp val GridVerticalSpacer = 4.dp + @Suppress("ConstPropertyName") const val BrowseFavoriteCoverAlpha = 0.34f } -private val ContinueReadingButtonSize = 28.dp +private val ContinueReadingButtonSizeSmall = 28.dp +private val ContinueReadingButtonSizeLarge = 32.dp + +private val ContinueReadingButtonIconSizeSmall = 16.dp +private val ContinueReadingButtonIconSizeLarge = 20.dp + private val ContinueReadingButtonGridPadding = 6.dp private val ContinueReadingButtonListSpacing = 8.dp @@ -62,7 +70,7 @@ private const val GridSelectedCoverAlpha = 0.76f */ @Composable fun MangaCompactGridItem( - coverData: tachiyomi.domain.manga.model.MangaCover, + coverData: MangaCoverModel, onClick: () -> Unit, onLongClick: () -> Unit, isSelected: Boolean = false, @@ -96,10 +104,12 @@ fun MangaCompactGridItem( ) } else if (onClickContinueReading != null) { ContinueReadingButton( + size = ContinueReadingButtonSizeLarge, + iconSize = ContinueReadingButtonIconSizeLarge, + onClick = onClickContinueReading, modifier = Modifier .padding(ContinueReadingButtonGridPadding) .align(Alignment.BottomEnd), - onClickContinueReading = onClickContinueReading, ) } }, @@ -148,11 +158,13 @@ private fun BoxScope.CoverTextOverlay( ) if (onClickContinueReading != null) { ContinueReadingButton( + size = ContinueReadingButtonSizeSmall, + iconSize = ContinueReadingButtonIconSizeSmall, + onClick = onClickContinueReading, modifier = Modifier.padding( end = ContinueReadingButtonGridPadding, bottom = ContinueReadingButtonGridPadding, ), - onClickContinueReading = onClickContinueReading, ) } } @@ -163,7 +175,7 @@ private fun BoxScope.CoverTextOverlay( */ @Composable fun MangaComfortableGridItem( - coverData: tachiyomi.domain.manga.model.MangaCover, + coverData: MangaCoverModel, title: String, onClick: () -> Unit, onLongClick: () -> Unit, @@ -194,10 +206,12 @@ fun MangaComfortableGridItem( content = { if (onClickContinueReading != null) { ContinueReadingButton( + size = ContinueReadingButtonSizeLarge, + iconSize = ContinueReadingButtonIconSizeLarge, + onClick = onClickContinueReading, modifier = Modifier .padding(ContinueReadingButtonGridPadding) .align(Alignment.BottomEnd), - onClickContinueReading = onClickContinueReading, ) } }, @@ -309,14 +323,14 @@ private fun GridItemSelectable( private fun Modifier.selectedOutline( isSelected: Boolean, color: Color, -) = this then drawBehind { if (isSelected) drawRect(color = color) } +) = drawBehind { if (isSelected) drawRect(color = color) } /** * Layout of list item. */ @Composable fun MangaListItem( - coverData: tachiyomi.domain.manga.model.MangaCover, + coverData: MangaCoverModel, title: String, onClick: () -> Unit, onLongClick: () -> Unit, @@ -354,8 +368,10 @@ fun MangaListItem( BadgeGroup(content = badge) if (onClickContinueReading != null) { ContinueReadingButton( - modifier = Modifier.padding(start = ContinueReadingButtonListSpacing), - onClickContinueReading = onClickContinueReading, + size = ContinueReadingButtonSizeSmall, + iconSize = ContinueReadingButtonIconSizeSmall, + onClick = onClickContinueReading, + modifier = Modifier.padding(start = ContinueReadingButtonListSpacing) ) } } @@ -363,23 +379,25 @@ fun MangaListItem( @Composable private fun ContinueReadingButton( + size: Dp, + iconSize: Dp, + onClick: () -> Unit, modifier: Modifier = Modifier, - onClickContinueReading: () -> Unit, ) { Box(modifier = modifier) { FilledIconButton( - onClick = onClickContinueReading, - modifier = Modifier.size(ContinueReadingButtonSize), + onClick = onClick, shape = MaterialTheme.shapes.small, colors = IconButtonDefaults.filledIconButtonColors( containerColor = MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.9f), contentColor = contentColorFor(MaterialTheme.colorScheme.primaryContainer), ), + modifier = Modifier.size(size) ) { Icon( imageVector = Icons.Filled.PlayArrow, contentDescription = stringResource(MR.strings.action_resume), - modifier = Modifier.size(16.dp), + modifier = Modifier.size(iconSize), ) } } From 5c249dd79078c7531c8582fd53a79378200153f0 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Sun, 23 Jun 2024 10:04:30 +0800 Subject: [PATCH 071/297] Upload build artifacts (#941) To decode obfuscated stack traces and help debugging R8 issues. --- .github/workflows/build_pull_request.yml | 12 ++++++++++++ .github/workflows/build_push.yml | 12 ++++++++++++ 2 files changed, 24 insertions(+) diff --git a/.github/workflows/build_pull_request.yml b/.github/workflows/build_pull_request.yml index 334ce464a..f12ac59d0 100644 --- a/.github/workflows/build_pull_request.yml +++ b/.github/workflows/build_pull_request.yml @@ -39,3 +39,15 @@ jobs: - name: Build app and run unit tests run: ./gradlew detekt assembleStandardRelease testReleaseUnitTest testStandardReleaseUnitTest + + - name: Upload APK + uses: actions/upload-artifact@v4 + with: + name: arm64-v8a-${{ github.sha }} + path: app/build/outputs/apk/standard/release/app-standard-arm64-v8a-release-unsigned.apk + + - name: Upload mapping + uses: actions/upload-artifact@v4 + with: + name: mapping-${{ github.sha }} + path: app/build/outputs/mapping/standardRelease diff --git a/.github/workflows/build_push.yml b/.github/workflows/build_push.yml index 47e6fe275..bb91f0a4f 100644 --- a/.github/workflows/build_push.yml +++ b/.github/workflows/build_push.yml @@ -38,6 +38,18 @@ jobs: - name: Build app and run unit tests run: ./gradlew detekt assembleStandardRelease testReleaseUnitTest testStandardReleaseUnitTest + - name: Upload APK + uses: actions/upload-artifact@v4 + with: + name: arm64-v8a-${{ github.sha }} + path: app/build/outputs/apk/standard/release/app-standard-arm64-v8a-release-unsigned.apk + + - name: Upload mapping + uses: actions/upload-artifact@v4 + with: + name: mapping-${{ github.sha }} + path: app/build/outputs/mapping/standardRelease + # Sign APK and create release for tags - name: Get tag name From a41ea8a61d0630e6c26074569ca9c000c3952f1e Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Mon, 24 Jun 2024 19:28:25 +0600 Subject: [PATCH 072/297] [skip ci] remove unused github workflow --- .github/mergify.yml | 10 ------- .github/workflows/issue_moderator.yml | 41 --------------------------- 2 files changed, 51 deletions(-) delete mode 100644 .github/mergify.yml delete mode 100644 .github/workflows/issue_moderator.yml diff --git a/.github/mergify.yml b/.github/mergify.yml deleted file mode 100644 index c9ddf7602..000000000 --- a/.github/mergify.yml +++ /dev/null @@ -1,10 +0,0 @@ -#pull_request_rules: -# - name: Automatically merge translations -# conditions: -# - "author = weblate" -# - "-conflict" -# - "current-day-of-week = Sat" -# - "created-at < 1 day ago" -# actions: -# merge: -# method: squash \ No newline at end of file diff --git a/.github/workflows/issue_moderator.yml b/.github/workflows/issue_moderator.yml deleted file mode 100644 index 1a4fbe18f..000000000 --- a/.github/workflows/issue_moderator.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: Issue moderator - -on: - issues: - types: [opened, edited, reopened] - issue_comment: - types: [created] - -jobs: - moderate: - runs-on: ubuntu-latest - steps: - - name: Moderate issues - uses: keiyoushi/issue-moderator-action@a017be83547db6e107431ce7575f53c1dfa3296a - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - duplicate-label: Duplicate - - auto-close-rules: | - [ - { - "type": "both", - "regex": "^(?!.*myanimelist.*).*(aniyomi|anime).*$", - "ignoreCase": true, - "message": "Mihon does not support anime, and has no plans to support anime. In addition Mihon is not affiliated with Aniyomi https://github.com/jmir1/aniyomi" - }, - { - "type": "both", - "regex": ".*(?:fail(?:ed|ure|s)?|can\\s*(?:no|')?t|(?:not|un).*able|(? Date: Tue, 25 Jun 2024 07:05:44 +0600 Subject: [PATCH 073/297] fix(deps): update dependency androidx.test.espresso:espresso-core to v3.6.0 (#947) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/androidx.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index 94c1c15b1..96d9553c4 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -27,7 +27,7 @@ paging-compose = { module = "androidx.paging:paging-compose", version.ref = "pag benchmark-macro = "androidx.benchmark:benchmark-macro-junit4:1.2.4" test-ext = "androidx.test.ext:junit-ktx:1.2.0-rc01" -test-espresso-core = "androidx.test.espresso:espresso-core:3.6.0-rc01" +test-espresso-core = "androidx.test.espresso:espresso-core:3.6.0" test-uiautomator = "androidx.test.uiautomator:uiautomator:2.3.0" [bundles] From 36e40c099772d2cb53d4ec87b2b00f97fe455c98 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 25 Jun 2024 07:49:12 +0600 Subject: [PATCH 074/297] fix(deps): update dependency androidx.test.ext:junit-ktx to v1.2.0 (#948) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/androidx.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index 96d9553c4..762d2a3d4 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -26,7 +26,7 @@ paging-runtime = { module = "androidx.paging:paging-runtime", version.ref = "pag paging-compose = { module = "androidx.paging:paging-compose", version.ref = "paging_version" } benchmark-macro = "androidx.benchmark:benchmark-macro-junit4:1.2.4" -test-ext = "androidx.test.ext:junit-ktx:1.2.0-rc01" +test-ext = "androidx.test.ext:junit-ktx:1.2.0" test-espresso-core = "androidx.test.espresso:espresso-core:3.6.0" test-uiautomator = "androidx.test.uiautomator:uiautomator:2.3.0" From 239c38982c4fd55d4d86b37fd9c3c51c3b47d098 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Wed, 26 Jun 2024 22:54:25 +0800 Subject: [PATCH 075/297] Refactor archive support with libarchive (#949) * Refactor archive support with libarchive * Revert string resource changs * Only mark archive formats as supported Comic book archives should not be compressed. * Fixup * Remove epub from archive format list * Move to mihon package * Format * Cleanup --- app/build.gradle.kts | 1 - app/proguard-rules.pro | 3 - .../tachiyomi/data/download/Downloader.kt | 27 +------ ...{ZipPageLoader.kt => ArchivePageLoader.kt} | 20 ++--- .../ui/reader/loader/ChapterLoader.kt | 12 +-- .../ui/reader/loader/DownloadPageLoader.kt | 10 +-- .../ui/reader/loader/EpubPageLoader.kt | 8 +- .../ui/reader/loader/RarPageLoader.kt | 67 ----------------- core/common/build.gradle.kts | 2 +- .../kanade/tachiyomi/util/storage/EpubFile.kt | 42 +++-------- .../mihon/core/common/archive/ArchiveEntry.kt | 6 ++ .../core/common/archive/ArchiveInputStream.kt | 52 +++++++++++++ .../core/common/archive/ArchiveReader.kt | 42 +++++++++++ .../mihon/core/common/archive/ZipWriter.kt | 74 +++++++++++++++++++ .../common/extensions/SeekableByteChannel.kt | 8 -- .../core/common/storage/UniFileExtensions.kt | 6 +- gradle/libs.versions.toml | 4 +- .../moko-resources/base/strings.xml | 1 - source-local/build.gradle.kts | 1 - .../tachiyomi/source/local/LocalSource.kt | 65 +++++----------- .../tachiyomi/source/local/io/Archive.kt | 4 +- .../tachiyomi/source/local/io/Format.kt | 17 ++--- 22 files changed, 239 insertions(+), 233 deletions(-) rename app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/{ZipPageLoader.kt => ArchivePageLoader.kt} (57%) delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/RarPageLoader.kt create mode 100644 core/common/src/main/kotlin/mihon/core/common/archive/ArchiveEntry.kt create mode 100644 core/common/src/main/kotlin/mihon/core/common/archive/ArchiveInputStream.kt create mode 100644 core/common/src/main/kotlin/mihon/core/common/archive/ArchiveReader.kt create mode 100644 core/common/src/main/kotlin/mihon/core/common/archive/ZipWriter.kt delete mode 100644 core/common/src/main/kotlin/mihon/core/common/extensions/SeekableByteChannel.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 622715259..9ea8f6ccf 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -203,7 +203,6 @@ dependencies { // Disk implementation(libs.disklrucache) implementation(libs.unifile) - implementation(libs.bundles.archive) // Preferences implementation(libs.preferencektx) diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index f4451efda..b2971f1b7 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -77,9 +77,6 @@ # XmlUtil -keep public enum nl.adaptivity.xmlutil.EventType { *; } -# Apache Commons Compress --keep class * extends org.apache.commons.compress.archivers.zip.ZipExtraField { (); } - # Firebase -keep class com.google.firebase.installations.** { *; } -keep interface com.google.firebase.installations.** { *; } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt index 11bfe28d1..ebf9df65e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt @@ -38,6 +38,7 @@ import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import kotlinx.coroutines.supervisorScope import logcat.LogPriority +import mihon.core.common.archive.ZipWriter import nl.adaptivity.xmlutil.serialization.XML import okhttp3.Response import tachiyomi.core.common.i18n.stringResource @@ -58,12 +59,8 @@ import tachiyomi.domain.track.interactor.GetTracks import tachiyomi.i18n.MR import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get -import java.io.BufferedOutputStream import java.io.File import java.util.Locale -import java.util.zip.CRC32 -import java.util.zip.ZipEntry -import java.util.zip.ZipOutputStream /** * This class is the one in charge of downloading chapters. @@ -594,25 +591,9 @@ class Downloader( tmpDir: UniFile, ) { val zip = mangaDir.createFile("$dirname.cbz$TMP_DIR_SUFFIX")!! - ZipOutputStream(BufferedOutputStream(zip.openOutputStream())).use { zipOut -> - zipOut.setMethod(ZipEntry.STORED) - - tmpDir.listFiles()?.forEach { img -> - img.openInputStream().use { input -> - val data = input.readBytes() - val size = img.length() - val entry = ZipEntry(img.name).apply { - val crc = CRC32().apply { - update(data) - } - setCrc(crc.value) - - compressedSize = size - setSize(size) - } - zipOut.putNextEntry(entry) - zipOut.write(data) - } + ZipWriter(context, zip).use { writer -> + tmpDir.listFiles()?.forEach { file -> + writer.write(file) } } zip.renameTo("$dirname.cbz") diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ZipPageLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ArchivePageLoader.kt similarity index 57% rename from app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ZipPageLoader.kt rename to app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ArchivePageLoader.kt index 89856bf22..397ac51bc 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ZipPageLoader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ArchivePageLoader.kt @@ -3,26 +3,22 @@ package eu.kanade.tachiyomi.ui.reader.loader import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.ui.reader.model.ReaderPage import eu.kanade.tachiyomi.util.lang.compareToCaseInsensitiveNaturalOrder -import mihon.core.common.extensions.toZipFile +import mihon.core.common.archive.ArchiveReader import tachiyomi.core.common.util.system.ImageUtil -import java.nio.channels.SeekableByteChannel /** - * Loader used to load a chapter from a .zip or .cbz file. + * Loader used to load a chapter from an archive file. */ -internal class ZipPageLoader(channel: SeekableByteChannel) : PageLoader() { - - private val zip = channel.toZipFile() - +internal class ArchivePageLoader(private val reader: ArchiveReader) : PageLoader() { override var isLocal: Boolean = true - override suspend fun getPages(): List { - return zip.entries.asSequence() - .filter { !it.isDirectory && ImageUtil.isImage(it.name) { zip.getInputStream(it) } } + override suspend fun getPages(): List = reader.useEntries { entries -> + entries + .filter { it.isFile && ImageUtil.isImage(it.name) { reader.getInputStream(it.name)!! } } .sortedWith { f1, f2 -> f1.name.compareToCaseInsensitiveNaturalOrder(f2.name) } .mapIndexed { i, entry -> ReaderPage(i).apply { - stream = { zip.getInputStream(entry) } + stream = { reader.getInputStream(entry.name)!! } status = Page.State.READY } } @@ -35,6 +31,6 @@ internal class ZipPageLoader(channel: SeekableByteChannel) : PageLoader() { override fun recycle() { super.recycle() - zip.close() + reader.close() } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ChapterLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ChapterLoader.kt index 1cd18bceb..3c1b34d6c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ChapterLoader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ChapterLoader.kt @@ -1,14 +1,13 @@ package eu.kanade.tachiyomi.ui.reader.loader import android.content.Context -import com.github.junrar.exception.UnsupportedRarV5Exception import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.data.download.DownloadProvider import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter +import mihon.core.common.archive.archiveReader import tachiyomi.core.common.i18n.stringResource -import tachiyomi.core.common.storage.openReadOnlyChannel import tachiyomi.core.common.util.lang.withIOContext import tachiyomi.core.common.util.system.logcat import tachiyomi.domain.manga.model.Manga @@ -95,13 +94,8 @@ class ChapterLoader( source is LocalSource -> source.getFormat(chapter.chapter).let { format -> when (format) { is Format.Directory -> DirectoryPageLoader(format.file) - is Format.Zip -> ZipPageLoader(format.file.openReadOnlyChannel(context)) - is Format.Rar -> try { - RarPageLoader(format.file.openInputStream()) - } catch (e: UnsupportedRarV5Exception) { - error(context.stringResource(MR.strings.loader_rar5_error)) - } - is Format.Epub -> EpubPageLoader(format.file.openReadOnlyChannel(context)) + is Format.Archive -> ArchivePageLoader(format.file.archiveReader(context)) + is Format.Epub -> EpubPageLoader(format.file.archiveReader(context)) } } source is HttpSource -> HttpPageLoader(chapter, source) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/DownloadPageLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/DownloadPageLoader.kt index abef28540..7b0f5c36c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/DownloadPageLoader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/DownloadPageLoader.kt @@ -10,7 +10,7 @@ import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter import eu.kanade.tachiyomi.ui.reader.model.ReaderPage -import tachiyomi.core.common.storage.openReadOnlyChannel +import mihon.core.common.archive.archiveReader import tachiyomi.domain.manga.model.Manga import uy.kohesive.injekt.injectLazy @@ -27,7 +27,7 @@ internal class DownloadPageLoader( private val context: Application by injectLazy() - private var zipPageLoader: ZipPageLoader? = null + private var archivePageLoader: ArchivePageLoader? = null override var isLocal: Boolean = true @@ -43,11 +43,11 @@ internal class DownloadPageLoader( override fun recycle() { super.recycle() - zipPageLoader?.recycle() + archivePageLoader?.recycle() } private suspend fun getPagesFromArchive(file: UniFile): List { - val loader = ZipPageLoader(file.openReadOnlyChannel(context)).also { zipPageLoader = it } + val loader = ArchivePageLoader(file.archiveReader(context)).also { archivePageLoader = it } return loader.getPages() } @@ -63,6 +63,6 @@ internal class DownloadPageLoader( } override suspend fun loadPage(page: ReaderPage) { - zipPageLoader?.loadPage(page) + archivePageLoader?.loadPage(page) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/EpubPageLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/EpubPageLoader.kt index baf65324b..8ace2fdee 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/EpubPageLoader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/EpubPageLoader.kt @@ -3,21 +3,21 @@ package eu.kanade.tachiyomi.ui.reader.loader import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.ui.reader.model.ReaderPage import eu.kanade.tachiyomi.util.storage.EpubFile -import java.nio.channels.SeekableByteChannel +import mihon.core.common.archive.ArchiveReader /** * Loader used to load a chapter from a .epub file. */ -internal class EpubPageLoader(channel: SeekableByteChannel) : PageLoader() { +internal class EpubPageLoader(reader: ArchiveReader) : PageLoader() { - private val epub = EpubFile(channel) + private val epub = EpubFile(reader) override var isLocal: Boolean = true override suspend fun getPages(): List { return epub.getImagesFromPages() .mapIndexed { i, path -> - val streamFn = { epub.getInputStream(epub.getEntry(path)!!) } + val streamFn = { epub.getInputStream(path)!! } ReaderPage(i).apply { stream = streamFn status = Page.State.READY diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/RarPageLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/RarPageLoader.kt deleted file mode 100644 index b1db3300d..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/RarPageLoader.kt +++ /dev/null @@ -1,67 +0,0 @@ -package eu.kanade.tachiyomi.ui.reader.loader - -import com.github.junrar.Archive -import com.github.junrar.rarfile.FileHeader -import eu.kanade.tachiyomi.source.model.Page -import eu.kanade.tachiyomi.ui.reader.model.ReaderPage -import eu.kanade.tachiyomi.util.lang.compareToCaseInsensitiveNaturalOrder -import tachiyomi.core.common.util.system.ImageUtil -import java.io.InputStream -import java.io.PipedInputStream -import java.io.PipedOutputStream -import java.util.concurrent.Executors - -/** - * Loader used to load a chapter from a .rar or .cbr file. - */ -internal class RarPageLoader(inputStream: InputStream) : PageLoader() { - - private val rar = Archive(inputStream) - - override var isLocal: Boolean = true - - /** - * Pool for copying compressed files to an input stream. - */ - private val pool = Executors.newFixedThreadPool(1) - - override suspend fun getPages(): List { - return rar.fileHeaders.asSequence() - .filter { !it.isDirectory && ImageUtil.isImage(it.fileName) { rar.getInputStream(it) } } - .sortedWith { f1, f2 -> f1.fileName.compareToCaseInsensitiveNaturalOrder(f2.fileName) } - .mapIndexed { i, header -> - ReaderPage(i).apply { - stream = { getStream(header) } - status = Page.State.READY - } - } - .toList() - } - - override suspend fun loadPage(page: ReaderPage) { - check(!isRecycled) - } - - override fun recycle() { - super.recycle() - rar.close() - pool.shutdown() - } - - /** - * Returns an input stream for the given [header]. - */ - private fun getStream(header: FileHeader): InputStream { - val pipeIn = PipedInputStream() - val pipeOut = PipedOutputStream(pipeIn) - pool.execute { - try { - pipeOut.use { - rar.extractFile(header, it) - } - } catch (e: Exception) { - } - } - return pipeIn - } -} diff --git a/core/common/build.gradle.kts b/core/common/build.gradle.kts index e31015dc4..d00fec682 100644 --- a/core/common/build.gradle.kts +++ b/core/common/build.gradle.kts @@ -32,7 +32,7 @@ dependencies { implementation(libs.image.decoder) implementation(libs.unifile) - implementation(libs.bundles.archive) + implementation(libs.libarchive) api(kotlinx.coroutines.core) api(kotlinx.serialization.json) diff --git a/core/common/src/main/kotlin/eu/kanade/tachiyomi/util/storage/EpubFile.kt b/core/common/src/main/kotlin/eu/kanade/tachiyomi/util/storage/EpubFile.kt index 29cea5824..b194c5ee3 100644 --- a/core/common/src/main/kotlin/eu/kanade/tachiyomi/util/storage/EpubFile.kt +++ b/core/common/src/main/kotlin/eu/kanade/tachiyomi/util/storage/EpubFile.kt @@ -1,48 +1,27 @@ package eu.kanade.tachiyomi.util.storage -import mihon.core.common.extensions.toZipFile -import org.apache.commons.compress.archivers.zip.ZipArchiveEntry +import mihon.core.common.archive.ArchiveReader import org.jsoup.Jsoup import org.jsoup.nodes.Document import java.io.Closeable import java.io.File import java.io.InputStream -import java.nio.channels.SeekableByteChannel /** * Wrapper over ZipFile to load files in epub format. */ -class EpubFile(channel: SeekableByteChannel) : Closeable { - - /** - * Zip file of this epub. - */ - private val zip = channel.toZipFile() +class EpubFile(private val reader: ArchiveReader) : Closeable by reader { /** * Path separator used by this epub. */ private val pathSeparator = getPathSeparator() - /** - * Closes the underlying zip file. - */ - override fun close() { - zip.close() - } - /** * Returns an input stream for reading the contents of the specified zip file entry. */ - fun getInputStream(entry: ZipArchiveEntry): InputStream { - return zip.getInputStream(entry) - } - - /** - * Returns the zip file entry for the specified name, or null if not found. - */ - fun getEntry(name: String): ZipArchiveEntry? { - return zip.getEntry(name) + fun getInputStream(entryName: String): InputStream? { + return reader.getInputStream(entryName) } /** @@ -59,9 +38,9 @@ class EpubFile(channel: SeekableByteChannel) : Closeable { * Returns the path to the package document. */ fun getPackageHref(): String { - val meta = zip.getEntry(resolveZipPath("META-INF", "container.xml")) + val meta = getInputStream(resolveZipPath("META-INF", "container.xml")) if (meta != null) { - val metaDoc = zip.getInputStream(meta).use { Jsoup.parse(it, null, "") } + val metaDoc = meta.use { Jsoup.parse(it, null, "") } val path = metaDoc.getElementsByTag("rootfile").first()?.attr("full-path") if (path != null) { return path @@ -74,8 +53,7 @@ class EpubFile(channel: SeekableByteChannel) : Closeable { * Returns the package document where all the files are listed. */ fun getPackageDocument(ref: String): Document { - val entry = zip.getEntry(ref) - return zip.getInputStream(entry).use { Jsoup.parse(it, null, "") } + return getInputStream(ref)!!.use { Jsoup.parse(it, null, "") } } /** @@ -98,8 +76,7 @@ class EpubFile(channel: SeekableByteChannel) : Closeable { val basePath = getParentDirectory(packageHref) pages.forEach { page -> val entryPath = resolveZipPath(basePath, page) - val entry = zip.getEntry(entryPath) - val document = zip.getInputStream(entry).use { Jsoup.parse(it, null, "") } + val document = getInputStream(entryPath)!!.use { Jsoup.parse(it, null, "") } val imageBasePath = getParentDirectory(entryPath) document.allElements.forEach { @@ -117,8 +94,9 @@ class EpubFile(channel: SeekableByteChannel) : Closeable { * Returns the path separator used by the epub file. */ private fun getPathSeparator(): String { - val meta = zip.getEntry("META-INF\\container.xml") + val meta = getInputStream("META-INF\\container.xml") return if (meta != null) { + meta.close() "\\" } else { "/" diff --git a/core/common/src/main/kotlin/mihon/core/common/archive/ArchiveEntry.kt b/core/common/src/main/kotlin/mihon/core/common/archive/ArchiveEntry.kt new file mode 100644 index 000000000..26240de00 --- /dev/null +++ b/core/common/src/main/kotlin/mihon/core/common/archive/ArchiveEntry.kt @@ -0,0 +1,6 @@ +package mihon.core.common.archive + +class ArchiveEntry( + val name: String, + val isFile: Boolean, +) diff --git a/core/common/src/main/kotlin/mihon/core/common/archive/ArchiveInputStream.kt b/core/common/src/main/kotlin/mihon/core/common/archive/ArchiveInputStream.kt new file mode 100644 index 000000000..a9bb87879 --- /dev/null +++ b/core/common/src/main/kotlin/mihon/core/common/archive/ArchiveInputStream.kt @@ -0,0 +1,52 @@ +package mihon.core.common.archive + +import me.zhanghai.android.libarchive.Archive +import me.zhanghai.android.libarchive.ArchiveEntry +import me.zhanghai.android.libarchive.ArchiveException +import java.io.InputStream +import java.nio.ByteBuffer + +class ArchiveInputStream(buffer: Long, size: Long) : InputStream() { + private val archive = Archive.readNew() + + init { + try { + Archive.setCharset(archive, Charsets.UTF_8.name().toByteArray()) + Archive.readSupportFilterAll(archive) + Archive.readSupportFormatAll(archive) + Archive.readOpenMemoryUnsafe(archive, buffer, size) + } catch (e: ArchiveException) { + close() + throw e + } + } + + private val oneByteBuffer = ByteBuffer.allocateDirect(1) + + override fun read(): Int { + read(oneByteBuffer) + return if (oneByteBuffer.hasRemaining()) oneByteBuffer.get().toUByte().toInt() else -1 + } + + override fun read(b: ByteArray, off: Int, len: Int): Int { + val buffer = ByteBuffer.wrap(b, off, len) + read(buffer) + return if (buffer.hasRemaining()) buffer.remaining() else -1 + } + + private fun read(buffer: ByteBuffer) { + buffer.clear() + Archive.readData(archive, buffer) + buffer.flip() + } + + override fun close() { + Archive.readFree(archive) + } + + fun getNextEntry() = Archive.readNextHeader(archive).takeUnless { it == 0L }?.let { entry -> + val name = ArchiveEntry.pathnameUtf8(entry) ?: ArchiveEntry.pathname(entry)?.decodeToString() ?: return null + val isFile = ArchiveEntry.filetype(entry) == ArchiveEntry.AE_IFREG + ArchiveEntry(name, isFile) + } +} diff --git a/core/common/src/main/kotlin/mihon/core/common/archive/ArchiveReader.kt b/core/common/src/main/kotlin/mihon/core/common/archive/ArchiveReader.kt new file mode 100644 index 000000000..28467d0fe --- /dev/null +++ b/core/common/src/main/kotlin/mihon/core/common/archive/ArchiveReader.kt @@ -0,0 +1,42 @@ +package mihon.core.common.archive + +import android.content.Context +import android.os.ParcelFileDescriptor +import android.system.Os +import android.system.OsConstants +import com.hippo.unifile.UniFile +import me.zhanghai.android.libarchive.ArchiveException +import tachiyomi.core.common.storage.openFileDescriptor +import java.io.Closeable +import java.io.InputStream + +class ArchiveReader(pfd: ParcelFileDescriptor) : Closeable { + val size = pfd.statSize + val address = Os.mmap(0, size, OsConstants.PROT_READ, OsConstants.MAP_PRIVATE, pfd.fileDescriptor, 0) + + inline fun useEntries(block: (Sequence) -> T): T = + ArchiveInputStream(address, size).use { block(generateSequence { it.getNextEntry() }) } + + fun getInputStream(entryName: String): InputStream? { + val archive = ArchiveInputStream(address, size) + try { + while (true) { + val entry = archive.getNextEntry() ?: break + if (entry.name == entryName) { + return archive + } + } + } catch (e: ArchiveException) { + archive.close() + throw e + } + archive.close() + return null + } + + override fun close() { + Os.munmap(address, size) + } +} + +fun UniFile.archiveReader(context: Context) = openFileDescriptor(context, "r").use { ArchiveReader(it) } diff --git a/core/common/src/main/kotlin/mihon/core/common/archive/ZipWriter.kt b/core/common/src/main/kotlin/mihon/core/common/archive/ZipWriter.kt new file mode 100644 index 000000000..b5d201516 --- /dev/null +++ b/core/common/src/main/kotlin/mihon/core/common/archive/ZipWriter.kt @@ -0,0 +1,74 @@ +package mihon.core.common.archive + +import android.content.Context +import android.system.Os +import android.system.StructStat +import com.hippo.unifile.UniFile +import me.zhanghai.android.libarchive.Archive +import me.zhanghai.android.libarchive.ArchiveEntry +import me.zhanghai.android.libarchive.ArchiveException +import tachiyomi.core.common.storage.openFileDescriptor +import java.io.Closeable +import java.nio.ByteBuffer + +class ZipWriter(val context: Context, file: UniFile) : Closeable { + private val pfd = file.openFileDescriptor(context, "wt") + private val archive = Archive.writeNew() + private val entry = ArchiveEntry.new2(archive) + private val buffer = ByteBuffer.allocateDirect(8192) + + init { + try { + Archive.setCharset(archive, Charsets.UTF_8.name().toByteArray()) + Archive.writeSetFormatZip(archive) + Archive.writeZipSetCompressionStore(archive) + Archive.writeOpenFd(archive, pfd.fd) + } catch (e: ArchiveException) { + close() + throw e + } + } + + fun write(file: UniFile) { + file.openFileDescriptor(context, "r").use { + val fd = it.fileDescriptor + ArchiveEntry.clear(entry) + ArchiveEntry.setPathnameUtf8(entry, file.name) + val stat = Os.fstat(fd) + ArchiveEntry.setStat(entry, stat.toArchiveStat()) + Archive.writeHeader(archive, entry) + while (true) { + buffer.clear() + Os.read(fd, buffer) + if (buffer.position() == 0) break + buffer.flip() + Archive.writeData(archive, buffer) + } + Archive.writeFinishEntry(archive) + } + } + + override fun close() { + ArchiveEntry.free(entry) + Archive.writeFree(archive) + pfd.close() + } +} + +private fun StructStat.toArchiveStat() = ArchiveEntry.StructStat().apply { + stDev = st_dev + stMode = st_mode + stNlink = st_nlink.toInt() + stUid = st_uid + stGid = st_gid + stRdev = st_rdev + stSize = st_size + stBlksize = st_blksize + stBlocks = st_blocks + stAtim = timespec(st_atime) + stMtim = timespec(st_mtime) + stCtim = timespec(st_ctime) + stIno = st_ino +} + +private fun timespec(tvSec: Long) = ArchiveEntry.StructTimespec().also { it.tvSec = tvSec } diff --git a/core/common/src/main/kotlin/mihon/core/common/extensions/SeekableByteChannel.kt b/core/common/src/main/kotlin/mihon/core/common/extensions/SeekableByteChannel.kt deleted file mode 100644 index 69e2d7201..000000000 --- a/core/common/src/main/kotlin/mihon/core/common/extensions/SeekableByteChannel.kt +++ /dev/null @@ -1,8 +0,0 @@ -package mihon.core.common.extensions - -import org.apache.commons.compress.archivers.zip.ZipFile -import java.nio.channels.SeekableByteChannel - -fun SeekableByteChannel.toZipFile(): ZipFile { - return ZipFile.Builder().setSeekableByteChannel(this).get() -} diff --git a/core/common/src/main/kotlin/tachiyomi/core/common/storage/UniFileExtensions.kt b/core/common/src/main/kotlin/tachiyomi/core/common/storage/UniFileExtensions.kt index 257fe210d..4b04ff405 100644 --- a/core/common/src/main/kotlin/tachiyomi/core/common/storage/UniFileExtensions.kt +++ b/core/common/src/main/kotlin/tachiyomi/core/common/storage/UniFileExtensions.kt @@ -3,7 +3,6 @@ package tachiyomi.core.common.storage import android.content.Context import android.os.ParcelFileDescriptor import com.hippo.unifile.UniFile -import java.nio.channels.FileChannel val UniFile.extension: String? get() = name?.substringAfterLast('.') @@ -14,6 +13,5 @@ val UniFile.nameWithoutExtension: String? val UniFile.displayablePath: String get() = filePath ?: uri.toString() -fun UniFile.openReadOnlyChannel(context: Context): FileChannel { - return ParcelFileDescriptor.AutoCloseInputStream(context.contentResolver.openFileDescriptor(uri, "r")).channel -} +fun UniFile.openFileDescriptor(context: Context, mode: String): ParcelFileDescriptor = + context.contentResolver.openFileDescriptor(uri, mode) ?: error("Failed to open file descriptor: $displayablePath") diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3942f468f..36bf03900 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -32,8 +32,7 @@ jsoup = "org.jsoup:jsoup:1.17.2" disklrucache = "com.jakewharton:disklrucache:2.0.2" unifile = "com.github.tachiyomiorg:unifile:e0def6b3dc" -common-compress = "org.apache.commons:commons-compress:1.26.2" -junrar = "com.github.junrar:junrar:7.5.5" +libarchive = "me.zhanghai.android.libarchive:library:1.1.0" sqlite-framework = { module = "androidx.sqlite:sqlite-framework", version.ref = "sqlite" } sqlite-ktx = { module = "androidx.sqlite:sqlite-ktx", version.ref = "sqlite" } @@ -104,7 +103,6 @@ detekt-rules-formatting = { module = "io.gitlab.arturbosch.detekt:detekt-formatt detekt-rules-compose = { module = "io.nlopez.compose.rules:detekt", version.ref = "detektCompose" } [bundles] -archive = ["common-compress", "junrar"] okhttp = ["okhttp-core", "okhttp-logging", "okhttp-brotli", "okhttp-dnsoverhttps"] js-engine = ["quickjs-android"] sqlite = ["sqlite-framework", "sqlite-ktx", "sqlite-android"] diff --git a/i18n/src/commonMain/moko-resources/base/strings.xml b/i18n/src/commonMain/moko-resources/base/strings.xml index b0a397b1d..afbdf686c 100644 --- a/i18n/src/commonMain/moko-resources/base/strings.xml +++ b/i18n/src/commonMain/moko-resources/base/strings.xml @@ -781,7 +781,6 @@ Failed to load pages: %1$s No pages found Source not found - RARv5 format is not supported Updating library diff --git a/source-local/build.gradle.kts b/source-local/build.gradle.kts index b0a720b97..25c268a34 100644 --- a/source-local/build.gradle.kts +++ b/source-local/build.gradle.kts @@ -12,7 +12,6 @@ kotlin { api(projects.i18n) implementation(libs.unifile) - implementation(libs.bundles.archive) } } val androidMain by getting { diff --git a/source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt b/source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt index 8efea5fd2..2d9725ad8 100644 --- a/source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt +++ b/source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt @@ -17,13 +17,12 @@ import kotlinx.coroutines.awaitAll import kotlinx.serialization.json.Json import kotlinx.serialization.json.decodeFromStream import logcat.LogPriority -import mihon.core.common.extensions.toZipFile +import mihon.core.common.archive.archiveReader import nl.adaptivity.xmlutil.AndroidXmlReader import nl.adaptivity.xmlutil.serialization.XML import tachiyomi.core.common.i18n.stringResource import tachiyomi.core.common.storage.extension import tachiyomi.core.common.storage.nameWithoutExtension -import tachiyomi.core.common.storage.openReadOnlyChannel import tachiyomi.core.common.util.lang.withIOContext import tachiyomi.core.common.util.system.ImageUtil import tachiyomi.core.common.util.system.logcat @@ -45,7 +44,6 @@ import uy.kohesive.injekt.injectLazy import java.io.InputStream import java.nio.charset.StandardCharsets import kotlin.time.Duration.Companion.days -import com.github.junrar.Archive as JunrarArchive import tachiyomi.domain.source.model.Source as DomainSource actual class LocalSource( @@ -187,9 +185,7 @@ actual class LocalSource( // Copy ComicInfo.xml from chapter archive to top level if found noXmlFile == null -> { - val chapterArchives = mangaDirFiles - .filter(Archive::isSupported) - .toList() + val chapterArchives = mangaDirFiles.filter(Archive::isSupported) val copiedFile = copyComicInfoFileFromArchive(chapterArchives, mangaDir) if (copiedFile != null) { @@ -209,26 +205,10 @@ actual class LocalSource( private fun copyComicInfoFileFromArchive(chapterArchives: List, folder: UniFile): UniFile? { for (chapter in chapterArchives) { - when (Format.valueOf(chapter)) { - is Format.Zip -> { - chapter.openReadOnlyChannel(context).toZipFile().use { zip -> - zip.getEntry(COMIC_INFO_FILE)?.let { comicInfoFile -> - zip.getInputStream(comicInfoFile).buffered().use { stream -> - return copyComicInfoFile(stream, folder) - } - } - } + chapter.archiveReader(context).use { reader -> + reader.getInputStream(COMIC_INFO_FILE)?.use { stream -> + return copyComicInfoFile(stream, folder) } - is Format.Rar -> { - JunrarArchive(chapter.openInputStream()).use { rar -> - rar.fileHeaders.firstOrNull { it.fileName == COMIC_INFO_FILE }?.let { comicInfoFile -> - rar.getInputStream(comicInfoFile).buffered().use { stream -> - return copyComicInfoFile(stream, folder) - } - } - } - } - else -> {} } } return null @@ -254,7 +234,7 @@ actual class LocalSource( override suspend fun getChapterList(manga: SManga): List = withIOContext { val chapters = fileSystem.getFilesInMangaDirectory(manga.url) // Only keep supported formats - .filter { it.isDirectory || Archive.isSupported(it) } + .filter { it.isDirectory || Archive.isSupported(it) || it.extension.equals("epub", true) } .map { chapterFile -> SChapter.create().apply { url = "${manga.url}/${chapterFile.name}" @@ -270,7 +250,7 @@ actual class LocalSource( val format = Format.valueOf(chapterFile) if (format is Format.Epub) { - EpubFile(format.file.openReadOnlyChannel(context)).use { epub -> + EpubFile(format.file.archiveReader(context)).use { epub -> epub.fillMetadata(manga, this) } } @@ -328,31 +308,22 @@ actual class LocalSource( entry?.let { coverManager.update(manga, it.openInputStream()) } } - is Format.Zip -> { - format.file.openReadOnlyChannel(context).toZipFile().use { zip -> - val entry = zip.entries.toList() - .sortedWith { f1, f2 -> f1.name.compareToCaseInsensitiveNaturalOrder(f2.name) } - .find { !it.isDirectory && ImageUtil.isImage(it.name) { zip.getInputStream(it) } } + is Format.Archive -> { + format.file.archiveReader(context).use { reader -> + val entry = reader.useEntries { entries -> + entries + .sortedWith { f1, f2 -> f1.name.compareToCaseInsensitiveNaturalOrder(f2.name) } + .find { it.isFile && ImageUtil.isImage(it.name) { reader.getInputStream(it.name)!! } } + } - entry?.let { coverManager.update(manga, zip.getInputStream(it)) } - } - } - is Format.Rar -> { - JunrarArchive(format.file.openInputStream()).use { archive -> - val entry = archive.fileHeaders - .sortedWith { f1, f2 -> f1.fileName.compareToCaseInsensitiveNaturalOrder(f2.fileName) } - .find { !it.isDirectory && ImageUtil.isImage(it.fileName) { archive.getInputStream(it) } } - - entry?.let { coverManager.update(manga, archive.getInputStream(it)) } + entry?.let { coverManager.update(manga, reader.getInputStream(it.name)!!) } } } is Format.Epub -> { - EpubFile(format.file.openReadOnlyChannel(context)).use { epub -> - val entry = epub.getImagesFromPages() - .firstOrNull() - ?.let { epub.getEntry(it) } + EpubFile(format.file.archiveReader(context)).use { epub -> + val entry = epub.getImagesFromPages().firstOrNull() - entry?.let { coverManager.update(manga, epub.getInputStream(it)) } + entry?.let { coverManager.update(manga, epub.getInputStream(it)!!) } } } } diff --git a/source-local/src/commonMain/kotlin/tachiyomi/source/local/io/Archive.kt b/source-local/src/commonMain/kotlin/tachiyomi/source/local/io/Archive.kt index e968adc7d..ea18e9b53 100644 --- a/source-local/src/commonMain/kotlin/tachiyomi/source/local/io/Archive.kt +++ b/source-local/src/commonMain/kotlin/tachiyomi/source/local/io/Archive.kt @@ -5,9 +5,9 @@ import tachiyomi.core.common.storage.extension object Archive { - private val SUPPORTED_ARCHIVE_TYPES = listOf("zip", "cbz", "rar", "cbr", "epub") + private val SUPPORTED_ARCHIVE_TYPES = listOf("zip", "cbz", "rar", "cbr", "7z", "cb7", "tar", "cbt") fun isSupported(file: UniFile): Boolean { - return file.extension in SUPPORTED_ARCHIVE_TYPES + return file.extension?.lowercase() in SUPPORTED_ARCHIVE_TYPES } } diff --git a/source-local/src/commonMain/kotlin/tachiyomi/source/local/io/Format.kt b/source-local/src/commonMain/kotlin/tachiyomi/source/local/io/Format.kt index 5b22e41e2..ad53d407c 100644 --- a/source-local/src/commonMain/kotlin/tachiyomi/source/local/io/Format.kt +++ b/source-local/src/commonMain/kotlin/tachiyomi/source/local/io/Format.kt @@ -2,25 +2,22 @@ package tachiyomi.source.local.io import com.hippo.unifile.UniFile import tachiyomi.core.common.storage.extension +import tachiyomi.source.local.io.Archive.isSupported as isArchiveSupported sealed interface Format { data class Directory(val file: UniFile) : Format - data class Zip(val file: UniFile) : Format - data class Rar(val file: UniFile) : Format + data class Archive(val file: UniFile) : Format data class Epub(val file: UniFile) : Format class UnknownFormatException : Exception() companion object { - fun valueOf(file: UniFile) = with(file) { - when { - isDirectory -> Directory(this) - extension.equals("zip", true) || extension.equals("cbz", true) -> Zip(this) - extension.equals("rar", true) || extension.equals("cbr", true) -> Rar(this) - extension.equals("epub", true) -> Epub(this) - else -> throw UnknownFormatException() - } + fun valueOf(file: UniFile) = when { + file.isDirectory -> Directory(file) + file.extension.equals("epub", true) -> Epub(file) + isArchiveSupported(file) -> Archive(file) + else -> throw UnknownFormatException() } } } From 2f86f25d5b24c2054a604802dc65b8bc3a99c7c0 Mon Sep 17 00:00:00 2001 From: Maddie Witman Date: Wed, 26 Jun 2024 16:04:28 -0400 Subject: [PATCH 076/297] Added configuration options to e-ink page flashes (#625) * Recommit for e-ink pref changes * Fixed state holder for flash interval * Detekt * Refactor suggested by Antsy * inverted currentDisplayRefresh check for early exit --- .../settings/screen/SettingsReaderScreen.kt | 66 +++++++++++++++++-- .../presentation/reader/DisplayRefreshHost.kt | 60 ++++++++++++++--- .../reader/settings/GeneralSettingsPage.kt | 50 ++++++++++++++ .../ui/reader/setting/ReaderPreferences.kt | 14 ++++ .../moko-resources/base/plurals.xml | 5 ++ .../moko-resources/base/strings.xml | 7 ++ 6 files changed, 189 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsReaderScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsReaderScreen.kt index be685a780..7b5aa15f3 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsReaderScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsReaderScreen.kt @@ -14,6 +14,7 @@ import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentMapOf import kotlinx.collections.immutable.toImmutableMap import tachiyomi.i18n.MR +import tachiyomi.presentation.core.i18n.pluralStringResource import tachiyomi.presentation.core.i18n.stringResource import tachiyomi.presentation.core.util.collectAsState import uy.kohesive.injekt.Injekt @@ -61,12 +62,8 @@ object SettingsReaderScreen : SearchableSettings { pref = readerPref.pageTransitions(), title = stringResource(MR.strings.pref_page_transitions), ), - Preference.PreferenceItem.SwitchPreference( - pref = readerPref.flashOnPageChange(), - title = stringResource(MR.strings.pref_flash_page), - subtitle = stringResource(MR.strings.pref_flash_page_summ), - ), getDisplayGroup(readerPreferences = readerPref), + getEInkGroup(readerPreferences = readerPref), getReadingGroup(readerPreferences = readerPref), getPagedGroup(readerPreferences = readerPref), getWebtoonGroup(readerPreferences = readerPref), @@ -122,6 +119,65 @@ object SettingsReaderScreen : SearchableSettings { ) } + @Composable + private fun getEInkGroup(readerPreferences: ReaderPreferences): Preference.PreferenceGroup { + val flashPageState by readerPreferences.flashOnPageChange().collectAsState() + + val flashMillisPref = readerPreferences.flashDurationMillis() + val flashMillis by flashMillisPref.collectAsState() + + val flashIntervalPref = readerPreferences.flashPageInterval() + val flashInterval by flashIntervalPref.collectAsState() + + val flashColorPref = readerPreferences.flashColor() + + return Preference.PreferenceGroup( + title = "E-Ink", + preferenceItems = persistentListOf( + Preference.PreferenceItem.SwitchPreference( + pref = readerPreferences.flashOnPageChange(), + title = stringResource(MR.strings.pref_flash_page), + subtitle = stringResource(MR.strings.pref_flash_page_summ), + ), + Preference.PreferenceItem.SliderPreference( + value = flashMillis / ReaderPreferences.MILLI_CONVERSION, + min = 1, + max = 15, + title = stringResource(MR.strings.pref_flash_duration), + subtitle = stringResource(MR.strings.pref_flash_duration_summary, flashMillis), + onValueChanged = { + flashMillisPref.set(it * ReaderPreferences.MILLI_CONVERSION) + true + }, + enabled = flashPageState, + ), + Preference.PreferenceItem.SliderPreference( + value = flashInterval, + min = 1, + max = 10, + title = stringResource(MR.strings.pref_flash_page_interval), + subtitle = pluralStringResource(MR.plurals.pref_pages, flashInterval, flashInterval), + onValueChanged = { + flashIntervalPref.set(it) + true + }, + enabled = flashPageState, + ), + Preference.PreferenceItem.ListPreference( + pref = flashColorPref, + title = stringResource(MR.strings.pref_flash_with), + entries = persistentMapOf( + ReaderPreferences.FlashColor.BLACK to stringResource(MR.strings.pref_flash_style_black), + ReaderPreferences.FlashColor.WHITE to stringResource(MR.strings.pref_flash_style_white), + ReaderPreferences.FlashColor.WHITE_BLACK + to stringResource(MR.strings.pref_flash_style_white_black), + ), + enabled = flashPageState, + ), + ), + ) + } + @Composable private fun getReadingGroup(readerPreferences: ReaderPreferences): Preference.PreferenceGroup { return Preference.PreferenceGroup( diff --git a/app/src/main/java/eu/kanade/presentation/reader/DisplayRefreshHost.kt b/app/src/main/java/eu/kanade/presentation/reader/DisplayRefreshHost.kt index 82d3cad0f..ecf26119d 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/DisplayRefreshHost.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/DisplayRefreshHost.kt @@ -7,19 +7,42 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.Stable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences import kotlinx.coroutines.delay -import kotlin.time.Duration.Companion.seconds +import tachiyomi.presentation.core.util.collectAsState +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get +import kotlin.time.Duration.Companion.milliseconds @Stable class DisplayRefreshHost { internal var currentDisplayRefresh by mutableStateOf(false) + private val readerPreferences = Injekt.get() + + internal val flashMillis = readerPreferences.flashDurationMillis() + internal val flashMode = readerPreferences.flashColor() + + internal val flashIntervalPref = readerPreferences.flashPageInterval() + + // Internal State for Flash + private var flashInterval = flashIntervalPref.get() + private var timesCalled = 0 fun flash() { - currentDisplayRefresh = true + if (timesCalled % flashInterval == 0) { + currentDisplayRefresh = true + } + timesCalled += 1 + } + + fun setInterval(interval: Int) { + flashInterval = interval + timesCalled = 0 } } @@ -29,18 +52,39 @@ fun DisplayRefreshHost( modifier: Modifier = Modifier, ) { val currentDisplayRefresh = hostState.currentDisplayRefresh + val refreshDuration by hostState.flashMillis.collectAsState() + val flashMode by hostState.flashMode.collectAsState() + val flashInterval by hostState.flashIntervalPref.collectAsState() + + var currentColor by remember { mutableStateOf(null) } + LaunchedEffect(currentDisplayRefresh) { - if (currentDisplayRefresh) { - delay(1.5.seconds) - hostState.currentDisplayRefresh = false + if (!currentDisplayRefresh) { + currentColor = null + return@LaunchedEffect } + + val refreshDurationHalf = refreshDuration.milliseconds / 2 + currentColor = if (flashMode == ReaderPreferences.FlashColor.BLACK) { + Color.Black + } else { + Color.White + } + delay(refreshDurationHalf) + if (flashMode == ReaderPreferences.FlashColor.WHITE_BLACK) { + currentColor = Color.Black + } + delay(refreshDurationHalf) + hostState.currentDisplayRefresh = false + } + + LaunchedEffect(flashInterval) { + hostState.setInterval(flashInterval) } Canvas( modifier = modifier.fillMaxSize(), ) { - if (currentDisplayRefresh) { - drawRect(Color.Black) - } + currentColor?.let { drawRect(it) } } } diff --git a/app/src/main/java/eu/kanade/presentation/reader/settings/GeneralSettingsPage.kt b/app/src/main/java/eu/kanade/presentation/reader/settings/GeneralSettingsPage.kt index 2f2832feb..0bb2da6cc 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/settings/GeneralSettingsPage.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/settings/GeneralSettingsPage.kt @@ -5,10 +5,13 @@ import androidx.compose.material3.FilterChip import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue +import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel import tachiyomi.i18n.MR import tachiyomi.presentation.core.components.CheckboxItem import tachiyomi.presentation.core.components.SettingsChipRow +import tachiyomi.presentation.core.components.SliderItem +import tachiyomi.presentation.core.i18n.pluralStringResource import tachiyomi.presentation.core.i18n.stringResource import tachiyomi.presentation.core.util.collectAsState @@ -19,9 +22,27 @@ private val themes = listOf( MR.strings.automatic_background to 3, ) +private val flashColors = listOf( + MR.strings.pref_flash_style_black to ReaderPreferences.FlashColor.BLACK, + MR.strings.pref_flash_style_white to ReaderPreferences.FlashColor.WHITE, + MR.strings.pref_flash_style_white_black to ReaderPreferences.FlashColor.WHITE_BLACK, +) + @Composable internal fun ColumnScope.GeneralPage(screenModel: ReaderSettingsScreenModel) { val readerTheme by screenModel.preferences.readerTheme().collectAsState() + + val flashPageState by screenModel.preferences.flashOnPageChange().collectAsState() + + val flashMillisPref = screenModel.preferences.flashDurationMillis() + val flashMillis by flashMillisPref.collectAsState() + + val flashIntervalPref = screenModel.preferences.flashPageInterval() + val flashInterval by flashIntervalPref.collectAsState() + + val flashColorPref = screenModel.preferences.flashColor() + val flashColor by flashColorPref.collectAsState() + SettingsChipRow(MR.strings.pref_reader_theme) { themes.map { (labelRes, value) -> FilterChip( @@ -73,4 +94,33 @@ internal fun ColumnScope.GeneralPage(screenModel: ReaderSettingsScreenModel) { label = stringResource(MR.strings.pref_flash_page), pref = screenModel.preferences.flashOnPageChange(), ) + if (flashPageState) { + SliderItem( + value = flashMillis / ReaderPreferences.MILLI_CONVERSION, + label = stringResource(MR.strings.pref_flash_duration), + valueText = stringResource(MR.strings.pref_flash_duration_summary, flashMillis), + onChange = { flashMillisPref.set(it * ReaderPreferences.MILLI_CONVERSION) }, + min = 1, + max = 15, + ) + SliderItem( + value = flashInterval, + label = stringResource(MR.strings.pref_flash_page_interval), + valueText = pluralStringResource(MR.plurals.pref_pages, flashInterval, flashInterval), + onChange = { + flashIntervalPref.set(it) + }, + min = 1, + max = 10, + ) + SettingsChipRow(MR.strings.pref_flash_with) { + flashColors.map { (labelRes, value) -> + FilterChip( + selected = flashColor == value, + onClick = { flashColorPref.set(value) }, + label = { Text(stringResource(labelRes)) }, + ) + } + } + } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderPreferences.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderPreferences.kt index 63162788c..57def3c12 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderPreferences.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderPreferences.kt @@ -17,6 +17,12 @@ class ReaderPreferences( fun flashOnPageChange() = preferenceStore.getBoolean("pref_reader_flash", false) + fun flashDurationMillis() = preferenceStore.getInt("pref_reader_flash_duration", MILLI_CONVERSION) + + fun flashPageInterval() = preferenceStore.getInt("pref_reader_flash_interval", 1) + + fun flashColor() = preferenceStore.getEnum("pref_reader_flash_mode", FlashColor.BLACK) + fun doubleTapAnimSpeed() = preferenceStore.getInt("pref_double_tap_anim_speed", 500) fun showPageNumber() = preferenceStore.getBoolean("pref_show_page_number_key", true) @@ -133,6 +139,12 @@ class ReaderPreferences( // endregion + enum class FlashColor { + BLACK, + WHITE, + WHITE_BLACK + } + enum class TappingInvertMode( val titleRes: StringResource, val shouldInvertHorizontal: Boolean = false, @@ -155,6 +167,8 @@ class ReaderPreferences( const val WEBTOON_PADDING_MIN = 0 const val WEBTOON_PADDING_MAX = 25 + const val MILLI_CONVERSION = 100 + val TapZones = listOf( MR.strings.label_default, MR.strings.l_nav, diff --git a/i18n/src/commonMain/moko-resources/base/plurals.xml b/i18n/src/commonMain/moko-resources/base/plurals.xml index d9c958afc..e436a8cb5 100644 --- a/i18n/src/commonMain/moko-resources/base/plurals.xml +++ b/i18n/src/commonMain/moko-resources/base/plurals.xml @@ -40,6 +40,11 @@ %d days + + 1 page + %1$s pages + + Missing %1$s chapter diff --git a/i18n/src/commonMain/moko-resources/base/strings.xml b/i18n/src/commonMain/moko-resources/base/strings.xml index afbdf686c..a3e7c3afd 100644 --- a/i18n/src/commonMain/moko-resources/base/strings.xml +++ b/i18n/src/commonMain/moko-resources/base/strings.xml @@ -366,6 +366,13 @@ Animate page transitions Flash on page change Reduces ghosting on e-ink displays + Flash duration + %1$s ms + Flash every + Flash with + Black + White + White and Black Double tap animation speed Show page number Show reading mode From d8fe7d32ca6bacbb74e9e80173625a993621e4b2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 27 Jun 2024 03:30:34 +0600 Subject: [PATCH 077/297] fix(deps): update serialization.version to v1.7.1 (#951) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/kotlinx.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/kotlinx.versions.toml b/gradle/kotlinx.versions.toml index ee3c15715..03b23177d 100644 --- a/gradle/kotlinx.versions.toml +++ b/gradle/kotlinx.versions.toml @@ -1,6 +1,6 @@ [versions] kotlin_version = "2.0.0" -serialization_version = "1.7.0" +serialization_version = "1.7.1" xml_serialization_version = "0.86.3" [libraries] From 2d41bf5589a3f26e549ecc7ddd5adafc17d503f4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 27 Jun 2024 03:42:32 +0600 Subject: [PATCH 078/297] fix(deps): update dependency dev.chrisbanes.compose:compose-bom to v2024.06.00-alpha01 (#957) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/compose.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/compose.versions.toml b/gradle/compose.versions.toml index c36eb21cb..74ae656e9 100644 --- a/gradle/compose.versions.toml +++ b/gradle/compose.versions.toml @@ -1,5 +1,5 @@ [versions] -compose-bom = "2024.05.00-alpha03" +compose-bom = "2024.06.00-alpha01" accompanist = "0.35.1-alpha" [libraries] From 7823966ddf2289fee743feaa58b906ab9179a4ed Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 27 Jun 2024 11:48:58 +0600 Subject: [PATCH 079/297] fix(deps): update dependency androidx.test.ext:junit-ktx to v1.2.1 (#959) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/androidx.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index 762d2a3d4..7e878e781 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -26,7 +26,7 @@ paging-runtime = { module = "androidx.paging:paging-runtime", version.ref = "pag paging-compose = { module = "androidx.paging:paging-compose", version.ref = "paging_version" } benchmark-macro = "androidx.benchmark:benchmark-macro-junit4:1.2.4" -test-ext = "androidx.test.ext:junit-ktx:1.2.0" +test-ext = "androidx.test.ext:junit-ktx:1.2.1" test-espresso-core = "androidx.test.espresso:espresso-core:3.6.0" test-uiautomator = "androidx.test.uiautomator:uiautomator:2.3.0" From f34702d4fcc10f24953b21e883fb454778bbae77 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 27 Jun 2024 11:50:11 +0600 Subject: [PATCH 080/297] fix(deps): update dependency androidx.test.espresso:espresso-core to v3.6.1 (#958) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/androidx.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index 7e878e781..778ea000c 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -27,7 +27,7 @@ paging-compose = { module = "androidx.paging:paging-compose", version.ref = "pag benchmark-macro = "androidx.benchmark:benchmark-macro-junit4:1.2.4" test-ext = "androidx.test.ext:junit-ktx:1.2.1" -test-espresso-core = "androidx.test.espresso:espresso-core:3.6.0" +test-espresso-core = "androidx.test.espresso:espresso-core:3.6.1" test-uiautomator = "androidx.test.uiautomator:uiautomator:2.3.0" [bundles] From 2674b849746f20c051dab3fd6edfad1594e41b42 Mon Sep 17 00:00:00 2001 From: Caio Oliveira Date: Thu, 27 Jun 2024 02:50:30 -0300 Subject: [PATCH 081/297] buildSrc: Fix strange warning in ci build (#952) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * buildSrc: Fix strange warning ´Project accessors enabled, but root project name not explicitly set for 'buildSrc'. Checking out the project in different folders will impact the generated code and implicitly the buildscript classpath, breaking caching.´ * Update settings.gradle.kts --------- Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com> --- buildSrc/settings.gradle.kts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts index 1b058e0d8..e45d92988 100644 --- a/buildSrc/settings.gradle.kts +++ b/buildSrc/settings.gradle.kts @@ -14,3 +14,5 @@ dependencyResolutionManagement { } } } + +rootProject.name = "mihon-buildSrc" From e132cc405f23e18dd8d73626730821eae9051149 Mon Sep 17 00:00:00 2001 From: CrepeTF <70870719+CrepeTF@users.noreply.github.com> Date: Fri, 28 Jun 2024 12:59:32 +0100 Subject: [PATCH 082/297] Theme fixes (#963) * Fix theme issue with download progress indicator * Fix theme issue with download progress indicator + better contrast --- .../presentation/theme/colorscheme/NordColorScheme.kt | 6 +++--- .../src/main/res/values-night/colors_lavender.xml | 2 +- .../src/main/res/values-night/colors_midnightdusk.xml | 2 +- presentation-core/src/main/res/values-night/colors_nord.xml | 2 +- presentation-core/src/main/res/values-night/colors_tako.xml | 2 +- presentation-core/src/main/res/values/colors_lavender.xml | 2 +- presentation-core/src/main/res/values/colors_nord.xml | 2 +- presentation-core/src/main/res/values/colors_tako.xml | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/NordColorScheme.kt b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/NordColorScheme.kt index 2e89b9ea4..84fe7b49f 100644 --- a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/NordColorScheme.kt +++ b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/NordColorScheme.kt @@ -19,8 +19,8 @@ internal object NordColorScheme : BaseColorScheme() { inversePrimary = Color(0xFF397E91), secondary = Color(0xFF81A1C1), // Unread badge onSecondary = Color(0xFF2E3440), // Unread badge text - secondaryContainer = Color(0xFF81A1C1), // Navigation bar selector pill & progress indicator (remaining) - onSecondaryContainer = Color(0xFF2E3440), // Navigation bar selector icon + secondaryContainer = Color(0xFF506275), // Navigation bar selector pill & progress indicator (remaining) + onSecondaryContainer = Color(0xFF88C0D0), // Navigation bar selector icon tertiary = Color(0xFF5E81AC), // Downloaded badge onTertiary = Color(0xFF000000), // Downloaded badge text tertiaryContainer = Color(0xFF5E81AC), @@ -54,7 +54,7 @@ internal object NordColorScheme : BaseColorScheme() { inversePrimary = Color(0xFF8CA8CD), secondary = Color(0xFF81A1C1), // Unread badge onSecondary = Color(0xFF2E3440), // Unread badge text - secondaryContainer = Color(0xFF81A1C1), // Navigation bar selector pill & progress indicator (remaining) + secondaryContainer = Color(0xFF91B4D7), // Navigation bar selector pill & progress indicator (remaining) onSecondaryContainer = Color(0xFF2E3440), // Navigation bar selector icon tertiary = Color(0xFF88C0D0), // Downloaded badge onTertiary = Color(0xFF2E3440), // Downloaded badge text diff --git a/presentation-core/src/main/res/values-night/colors_lavender.xml b/presentation-core/src/main/res/values-night/colors_lavender.xml index d76e55486..f9d558025 100644 --- a/presentation-core/src/main/res/values-night/colors_lavender.xml +++ b/presentation-core/src/main/res/values-night/colors_lavender.xml @@ -17,7 +17,7 @@ #111129 #A177FF #111129 - #A177FF + #423271 #111129 #5E25E1 #E8E8E8 diff --git a/presentation-core/src/main/res/values-night/colors_midnightdusk.xml b/presentation-core/src/main/res/values-night/colors_midnightdusk.xml index d107312aa..f10e84662 100644 --- a/presentation-core/src/main/res/values-night/colors_midnightdusk.xml +++ b/presentation-core/src/main/res/values-night/colors_midnightdusk.xml @@ -17,7 +17,7 @@ #FFFFFF #F02475 #FFFFFF - #F02475 + #66183C #FFFFFF #55971C #FFFFFF diff --git a/presentation-core/src/main/res/values-night/colors_nord.xml b/presentation-core/src/main/res/values-night/colors_nord.xml index f9ab8ce50..058d52a4a 100644 --- a/presentation-core/src/main/res/values-night/colors_nord.xml +++ b/presentation-core/src/main/res/values-night/colors_nord.xml @@ -7,7 +7,7 @@ #2E3440 #81A1C1 #2E3440 - #81A1C1 + #506275 #2E3440 #5E81AC #000000 diff --git a/presentation-core/src/main/res/values-night/colors_tako.xml b/presentation-core/src/main/res/values-night/colors_tako.xml index 907486c60..85f898c32 100644 --- a/presentation-core/src/main/res/values-night/colors_tako.xml +++ b/presentation-core/src/main/res/values-night/colors_tako.xml @@ -15,7 +15,7 @@ #38294E #F3B375 #38294E - #F3B375 + #5C4D4B #38294E #F3B375 #38294E diff --git a/presentation-core/src/main/res/values/colors_lavender.xml b/presentation-core/src/main/res/values/colors_lavender.xml index f6cfda65c..02d6274e3 100644 --- a/presentation-core/src/main/res/values/colors_lavender.xml +++ b/presentation-core/src/main/res/values/colors_lavender.xml @@ -16,7 +16,7 @@ #EDE2FF #7B46AF #EDE2FF - #7B46AF + #C9B0E6 #EDE2FF #EDE2FF #7B46AF diff --git a/presentation-core/src/main/res/values/colors_nord.xml b/presentation-core/src/main/res/values/colors_nord.xml index 7aab3eb43..b04ae3eec 100644 --- a/presentation-core/src/main/res/values/colors_nord.xml +++ b/presentation-core/src/main/res/values/colors_nord.xml @@ -8,7 +8,7 @@ #000000 #81A1C1 #2E3440 - #81A1C1 + #91B4D7 #2E3440 #88C0D0 #2E3440 diff --git a/presentation-core/src/main/res/values/colors_tako.xml b/presentation-core/src/main/res/values/colors_tako.xml index 0976d1b14..6a002cd2c 100644 --- a/presentation-core/src/main/res/values/colors_tako.xml +++ b/presentation-core/src/main/res/values/colors_tako.xml @@ -17,7 +17,7 @@ #F3B375 #66577E #F3B375 - #66577E + #C8BED0 #F3B375 #F3B375 #574360 From 9e2f97eeb8a0f1d1b353dc3e77fb64d69b568674 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 28 Jun 2024 17:59:49 +0600 Subject: [PATCH 083/297] fix(deps): update dependency org.junit.jupiter:junit-jupiter to v5.10.3 (#962) 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 36bf03900..7cccc999b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -89,7 +89,7 @@ sqldelight-android-paging = { module = "app.cash.sqldelight:androidx-paging3-ext sqldelight-dialects-sql = { module = "app.cash.sqldelight:sqlite-3-38-dialect", version.ref = "sqldelight" } sqldelight-gradle = { module = "app.cash.sqldelight:gradle-plugin", version.ref = "sqldelight" } -junit = "org.junit.jupiter:junit-jupiter:5.10.2" +junit = "org.junit.jupiter:junit-jupiter:5.10.3" kotest-assertions = "io.kotest:kotest-assertions-core:5.9.1" mockk = "io.mockk:mockk:1.13.11" From 80cdebcdf467ed00e530651aeed2b36cc63b8356 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 29 Jun 2024 23:26:00 +0600 Subject: [PATCH 084/297] fix(deps): update aboutlib.version to v11.2.2 (#965) 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 7cccc999b..0aa5ac0eb 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -aboutlib_version = "11.2.1" +aboutlib_version = "11.2.2" leakcanary = "2.14" moko = "0.24.1" okhttp_version = "5.0.0-alpha.14" From c0f9de88e70ef1db97c521993462ae27550b5790 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 30 Jun 2024 01:44:17 +0600 Subject: [PATCH 085/297] fix(deps): update dependency io.coil-kt.coil3:coil-bom to v3.0.0-alpha07 (#960) * fix(deps): update dependency io.coil-kt.coil3:coil-bom to v3.0.0-alpha07 * Fix build --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com> --- app/build.gradle.kts | 2 ++ .../kanade/presentation/manga/components/MangaCoverDialog.kt | 1 + .../eu/kanade/tachiyomi/data/coil/TachiyomiImageDecoder.kt | 4 ++-- .../eu/kanade/tachiyomi/data/library/LibraryUpdateNotifier.kt | 1 + .../eu/kanade/tachiyomi/ui/manga/MangaCoverScreenModel.kt | 1 + .../java/eu/kanade/tachiyomi/ui/reader/SaveImageNotifier.kt | 1 + .../kanade/tachiyomi/ui/reader/viewer/ReaderPageImageView.kt | 1 + .../eu/kanade/tachiyomi/util/system/DrawableExtensions.kt | 2 +- gradle/androidx.versions.toml | 3 +++ gradle/libs.versions.toml | 2 +- .../presentation/widget/BaseUpdatesGridGlanceWidget.kt | 1 + 11 files changed, 15 insertions(+), 4 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 9ea8f6ccf..1dbee966e 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -158,6 +158,8 @@ dependencies { implementation(compose.ui.tooling.preview) implementation(compose.ui.util) implementation(compose.accompanist.systemuicontroller) + + implementation(androidx.interpolator) implementation(androidx.paging.runtime) implementation(androidx.paging.compose) diff --git a/app/src/main/java/eu/kanade/presentation/manga/components/MangaCoverDialog.kt b/app/src/main/java/eu/kanade/presentation/manga/components/MangaCoverDialog.kt index a70511326..87bad99c2 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/components/MangaCoverDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/components/MangaCoverDialog.kt @@ -37,6 +37,7 @@ import androidx.compose.ui.viewinterop.AndroidView import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import androidx.core.view.updatePadding +import coil3.asDrawable import coil3.imageLoader import coil3.request.CachePolicy import coil3.request.ImageRequest diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/coil/TachiyomiImageDecoder.kt b/app/src/main/java/eu/kanade/tachiyomi/data/coil/TachiyomiImageDecoder.kt index 2929f4da3..6403f760b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/coil/TachiyomiImageDecoder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/coil/TachiyomiImageDecoder.kt @@ -2,7 +2,7 @@ package eu.kanade.tachiyomi.data.coil import android.graphics.Bitmap import coil3.ImageLoader -import coil3.asCoilImage +import coil3.asImage import coil3.decode.DecodeResult import coil3.decode.DecodeUtils import coil3.decode.Decoder @@ -58,7 +58,7 @@ class TachiyomiImageDecoder(private val resources: ImageSource, private val opti } return DecodeResult( - image = bitmap.asCoilImage(), + image = bitmap.asImage(), isSampled = sampleSize > 1, ) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateNotifier.kt b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateNotifier.kt index e18bf76c4..f7d6c5dbc 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateNotifier.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateNotifier.kt @@ -9,6 +9,7 @@ import android.graphics.BitmapFactory import android.net.Uri import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat +import coil3.asDrawable import coil3.imageLoader import coil3.request.ImageRequest import coil3.request.transformations diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaCoverScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaCoverScreenModel.kt index 75a98c5df..de79d4d0d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaCoverScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaCoverScreenModel.kt @@ -5,6 +5,7 @@ import android.net.Uri import androidx.compose.material3.SnackbarHostState import cafe.adriel.voyager.core.model.StateScreenModel import cafe.adriel.voyager.core.model.screenModelScope +import coil3.asDrawable import coil3.imageLoader import coil3.request.ImageRequest import coil3.size.Size diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/SaveImageNotifier.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/SaveImageNotifier.kt index 373ed97a8..6b08dfeb3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/SaveImageNotifier.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/SaveImageNotifier.kt @@ -4,6 +4,7 @@ import android.content.Context import android.graphics.Bitmap import android.net.Uri import androidx.core.app.NotificationCompat +import coil3.asDrawable import coil3.imageLoader import coil3.request.CachePolicy import coil3.request.ImageRequest diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderPageImageView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderPageImageView.kt index 17b973a7e..61e78c161 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderPageImageView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderPageImageView.kt @@ -19,6 +19,7 @@ import androidx.appcompat.widget.AppCompatImageView import androidx.core.os.postDelayed import androidx.core.view.isVisible import coil3.BitmapImage +import coil3.asDrawable import coil3.dispose import coil3.imageLoader import coil3.request.CachePolicy diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/system/DrawableExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/system/DrawableExtensions.kt index 2877768af..872552ef9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/system/DrawableExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/system/DrawableExtensions.kt @@ -4,7 +4,7 @@ import android.graphics.Bitmap import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable import androidx.core.graphics.drawable.toBitmap -import coil3.gif.ScaleDrawable +import coil3.size.ScaleDrawable fun Drawable.getBitmapOrNull(): Bitmap? = when (this) { is BitmapDrawable -> bitmap diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index 778ea000c..73b2a6546 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -2,6 +2,7 @@ agp_version = "8.5.0" lifecycle_version = "2.8.2" paging_version = "3.3.0" +interpolator_version = "1.0.0" [libraries] gradle = { module = "com.android.tools.build:gradle", version.ref = "agp_version" } @@ -25,6 +26,8 @@ workmanager = "androidx.work:work-runtime:2.9.0" paging-runtime = { module = "androidx.paging:paging-runtime", version.ref = "paging_version" } paging-compose = { module = "androidx.paging:paging-compose", version.ref = "paging_version" } +interpolator = { group = "androidx.interpolator", name = "interpolator", version.ref = "interpolator_version" } + benchmark-macro = "androidx.benchmark:benchmark-macro-junit4:1.2.4" test-ext = "androidx.test.ext:junit-ktx:1.2.1" test-espresso-core = "androidx.test.espresso:espresso-core:3.6.1" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0aa5ac0eb..37f29e6bc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -42,7 +42,7 @@ preferencektx = "androidx.preference:preference-ktx:1.2.1" injekt-core = "com.github.inorichi.injekt:injekt-core:65b0440" -coil-bom = { module = "io.coil-kt.coil3:coil-bom", version = "3.0.0-alpha06" } +coil-bom = { module = "io.coil-kt.coil3:coil-bom", version = "3.0.0-alpha07" } coil-core = { module = "io.coil-kt.coil3:coil" } coil-gif = { module = "io.coil-kt.coil3:coil-gif" } coil-compose = { module = "io.coil-kt.coil3:coil-compose" } 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 4fa7850a8..bc9c08faf 100644 --- a/presentation-widget/src/main/java/tachiyomi/presentation/widget/BaseUpdatesGridGlanceWidget.kt +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/BaseUpdatesGridGlanceWidget.kt @@ -22,6 +22,7 @@ import androidx.glance.layout.fillMaxSize import androidx.glance.layout.padding import androidx.glance.unit.ColorProvider import coil3.annotation.ExperimentalCoilApi +import coil3.asDrawable import coil3.executeBlocking import coil3.imageLoader import coil3.request.CachePolicy From e620665dda9eb5cc39f09e6087ea4f60a3cbe150 Mon Sep 17 00:00:00 2001 From: Ahmad Ansori Palembani <46041660+null2264@users.noreply.github.com> Date: Sun, 30 Jun 2024 20:57:29 +0700 Subject: [PATCH 086/297] Add safeguard to prevent ArchiveInputStream from being closed twice (#967) * fix: Add safeguard to prevent ArchiveInputStream from being closed twice * detekt * lint: Make detekt happy --------- Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com> --- .../mihon/core/common/archive/ArchiveInputStream.kt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/core/common/src/main/kotlin/mihon/core/common/archive/ArchiveInputStream.kt b/core/common/src/main/kotlin/mihon/core/common/archive/ArchiveInputStream.kt index a9bb87879..1499867c8 100644 --- a/core/common/src/main/kotlin/mihon/core/common/archive/ArchiveInputStream.kt +++ b/core/common/src/main/kotlin/mihon/core/common/archive/ArchiveInputStream.kt @@ -5,8 +5,14 @@ import me.zhanghai.android.libarchive.ArchiveEntry import me.zhanghai.android.libarchive.ArchiveException import java.io.InputStream import java.nio.ByteBuffer +import kotlin.concurrent.Volatile class ArchiveInputStream(buffer: Long, size: Long) : InputStream() { + private val lock = Any() + + @Volatile + private var isClosed = false + private val archive = Archive.readNew() init { @@ -41,6 +47,11 @@ class ArchiveInputStream(buffer: Long, size: Long) : InputStream() { } override fun close() { + synchronized(lock) { + if (isClosed) return + isClosed = true + } + Archive.readFree(archive) } From bff6183cf3ef400d8ddcdccf7180e4139816cc09 Mon Sep 17 00:00:00 2001 From: WerctFourth <88225220+WerctFourth@users.noreply.github.com> Date: Mon, 1 Jul 2024 21:15:46 +0500 Subject: [PATCH 087/297] Update image-decoder revision (#971) --- 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 37f29e6bc..84e9797c5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -49,7 +49,7 @@ coil-compose = { module = "io.coil-kt.coil3:coil-compose" } coil-network-okhttp = { module = "io.coil-kt.coil3:coil-network-okhttp" } subsamplingscaleimageview = "com.github.tachiyomiorg:subsampling-scale-image-view:b8e1b0ed2b" -image-decoder = "com.github.tachiyomiorg:image-decoder:e08e9be535" +image-decoder = "com.github.tachiyomiorg:image-decoder:41c059e540" natural-comparator = "com.github.gpanther:java-nat-sort:natural-comparator-1.1" From 77db8873f6753cc9db8f67b39d53685563380cc6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 2 Jul 2024 01:58:48 +0600 Subject: [PATCH 088/297] fix(deps): update lifecycle.version to v2.8.3 (#972) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/androidx.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index 73b2a6546..f7aa3acb6 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -1,6 +1,6 @@ [versions] agp_version = "8.5.0" -lifecycle_version = "2.8.2" +lifecycle_version = "2.8.3" paging_version = "3.3.0" interpolator_version = "1.0.0" From 75b5d966018aa917f57adf37370088a51e4914b2 Mon Sep 17 00:00:00 2001 From: CrepeTF <70870719+CrepeTF@users.noreply.github.com> Date: Tue, 2 Jul 2024 11:52:55 +0100 Subject: [PATCH 089/297] Correct tako variable colours (#976) --- presentation-core/src/main/res/values-night/colors_tako.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/presentation-core/src/main/res/values-night/colors_tako.xml b/presentation-core/src/main/res/values-night/colors_tako.xml index 85f898c32..63c2db1ce 100644 --- a/presentation-core/src/main/res/values-night/colors_tako.xml +++ b/presentation-core/src/main/res/values-night/colors_tako.xml @@ -15,8 +15,8 @@ #38294E #F3B375 #38294E - #5C4D4B - #38294E + #F3B375 + #5C4D4B #F3B375 #38294E #66577E From ddba71df37359e6abbbcc96b18685435961710dc Mon Sep 17 00:00:00 2001 From: Roshan Varughese <40583749+Animeboynz@users.noreply.github.com> Date: Wed, 3 Jul 2024 00:08:33 +1200 Subject: [PATCH 090/297] Smart Update Dialog Tweak (#977) * Smart Update Dialog Fix * Build Fail Change 1 * Commit Suggested Change Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com> * Build Fail Change 2 --------- Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com> --- .../kanade/presentation/manga/components/MangaDialogs.kt | 7 +++++-- i18n/src/commonMain/moko-resources/base/strings.xml | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) 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 a6ef3f9a5..bee8a8844 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 @@ -102,9 +102,12 @@ fun SetIntervalDialog( ), ), ) - - Spacer(Modifier.height(MaterialTheme.padding.small)) + } else { + Text( + stringResource(MR.strings.manga_interval_expected_update_null), + ) } + Spacer(Modifier.height(MaterialTheme.padding.small)) if (onValueChanged != null && (isDevFlavor || isPreviewBuildType)) { Text(stringResource(MR.strings.manga_interval_custom_amount)) diff --git a/i18n/src/commonMain/moko-resources/base/strings.xml b/i18n/src/commonMain/moko-resources/base/strings.xml index a3e7c3afd..08bbe2d76 100644 --- a/i18n/src/commonMain/moko-resources/base/strings.xml +++ b/i18n/src/commonMain/moko-resources/base/strings.xml @@ -693,6 +693,7 @@ Set to update every New chapters predicted to be released in around %1$s, checking around every %2$s. + This manga is either completed, or there is no predicted release date. Soon Custom update frequency: Downloading (%1$d/%2$d) From 5a61ca5535fe0d9e8e7bcb9e665ba2f9cb0cf649 Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Wed, 3 Jul 2024 06:00:04 +0600 Subject: [PATCH 091/297] Make global search "Has result" sticky Closes #133 --- .../domain/source/service/SourcePreferences.kt | 5 +++++ .../browse/source/globalsearch/SearchScreenModel.kt | 13 ++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt b/app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt index d4d3989c0..72989891e 100644 --- a/app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt +++ b/app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt @@ -48,4 +48,9 @@ class SourcePreferences( Preference.appStateKey("trusted_extensions"), emptySet(), ) + + fun globalSearchFilterState() = preferenceStore.getBoolean( + Preference.appStateKey("has_filters_toggle_state"), + false, + ) } 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 3f7438b7c..1cb9ba3ff 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 @@ -4,6 +4,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.Immutable import androidx.compose.runtime.produceState import cafe.adriel.voyager.core.model.StateScreenModel +import cafe.adriel.voyager.core.model.screenModelScope import eu.kanade.domain.manga.model.toDomainManga import eu.kanade.domain.source.service.SourcePreferences import eu.kanade.presentation.util.ioCoroutineScope @@ -23,6 +24,7 @@ import kotlinx.coroutines.flow.update import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import tachiyomi.core.common.preference.toggle import tachiyomi.domain.manga.interactor.GetManga import tachiyomi.domain.manga.interactor.NetworkToLocalManga import tachiyomi.domain.manga.model.Manga @@ -38,6 +40,7 @@ abstract class SearchScreenModel( private val extensionManager: ExtensionManager = Injekt.get(), private val networkToLocalManga: NetworkToLocalManga = Injekt.get(), private val getManga: GetManga = Injekt.get(), + private val preferences: SourcePreferences = Injekt.get(), ) : StateScreenModel(initialState) { private val coroutineDispatcher = Executors.newFixedThreadPool(5).asCoroutineDispatcher() @@ -60,6 +63,14 @@ abstract class SearchScreenModel( ) } + init { + screenModelScope.launch { + preferences.globalSearchFilterState().changes().collectLatest { state -> + mutableState.update { it.copy(onlyShowHasResults = state) } + } + } + } + @Composable fun getManga(initialManga: Manga): androidx.compose.runtime.State { return produceState(initialValue = initialManga) { @@ -107,7 +118,7 @@ abstract class SearchScreenModel( } fun toggleFilterResults() { - mutableState.update { it.copy(onlyShowHasResults = !it.onlyShowHasResults) } + preferences.globalSearchFilterState().toggle() } fun search() { From 2092c81bad59fd745a8514af320e534ecf40a5da Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Sat, 6 Jul 2024 07:25:33 +0600 Subject: [PATCH 092/297] Observe tracker login state instead of fetching once (#987) * Observe tracker login state instead of fetching once * Review changes --- .../library/LibrarySettingsDialog.kt | 15 ++++---- .../more/settings/PreferenceItem.kt | 20 +++++------ .../tachiyomi/data/track/BaseTracker.kt | 11 ++++++ .../eu/kanade/tachiyomi/data/track/Tracker.kt | 3 ++ .../tachiyomi/data/track/TrackerManager.kt | 9 +++++ .../ui/library/LibraryScreenModel.kt | 35 ++++++++++--------- .../ui/library/LibrarySettingsScreenModel.kt | 13 +++++-- .../kanade/tachiyomi/ui/manga/MangaScreen.kt | 2 +- .../tachiyomi/ui/manga/MangaScreenModel.kt | 34 +++++++++++------- .../ui/manga/track/TrackInfoDialog.kt | 2 +- .../tachiyomi/ui/stats/StatsScreenModel.kt | 2 +- .../main/java/eu/kanade/test/DummyTracker.kt | 3 ++ 12 files changed, 96 insertions(+), 53 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt b/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt index ad0733606..bf5daae99 100644 --- a/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt @@ -9,6 +9,7 @@ import androidx.compose.foundation.verticalScroll import androidx.compose.material3.FilterChip import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Modifier @@ -125,7 +126,7 @@ private fun ColumnScope.FilterPage( ) } - val trackers = remember { screenModel.trackers } + val trackers by screenModel.trackersFlow.collectAsState() when (trackers.size) { 0 -> { // No trackers @@ -158,15 +159,15 @@ private fun ColumnScope.SortPage( category: Category?, screenModel: LibrarySettingsScreenModel, ) { + val trackers by screenModel.trackersFlow.collectAsState() val sortingMode = category.sort.type val sortDescending = !category.sort.isAscending - val trackerSortOption = - if (screenModel.trackers.isEmpty()) { - emptyList() - } else { - listOf(MR.strings.action_sort_tracker_score to LibrarySort.Type.TrackerMean) - } + val trackerSortOption = if (trackers.isEmpty()) { + emptyList() + } else { + listOf(MR.strings.action_sort_tracker_score to LibrarySort.Type.TrackerMean) + } listOf( MR.strings.action_sort_alpha to LibrarySort.Type.Alphabetical, diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceItem.kt b/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceItem.kt index b22e69323..5a3c9d53b 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceItem.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceItem.kt @@ -7,12 +7,12 @@ import androidx.compose.animation.fadeOut import androidx.compose.animation.shrinkVertically import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.compositionLocalOf import androidx.compose.runtime.getValue import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.structuralEqualityPolicy import androidx.compose.ui.unit.dp -import eu.kanade.domain.track.service.TrackPreferences import eu.kanade.presentation.more.settings.widget.EditTextPreferenceWidget import eu.kanade.presentation.more.settings.widget.InfoWidget import eu.kanade.presentation.more.settings.widget.ListPreferenceWidget @@ -23,8 +23,6 @@ import eu.kanade.presentation.more.settings.widget.TrackingPreferenceWidget import kotlinx.coroutines.launch import tachiyomi.presentation.core.components.SliderItem import tachiyomi.presentation.core.util.collectAsState -import uy.kohesive.injekt.Injekt -import uy.kohesive.injekt.api.get val LocalPreferenceHighlighted = compositionLocalOf(structuralEqualityPolicy()) { false } val LocalPreferenceMinHeight = compositionLocalOf(structuralEqualityPolicy()) { 56.dp } @@ -156,16 +154,14 @@ internal fun PreferenceItem( ) } is Preference.PreferenceItem.TrackerPreference -> { - val uName by Injekt.get() - .trackUsername(item.tracker) - .collectAsState() - item.tracker.run { - TrackingPreferenceWidget( - tracker = this, - checked = uName.isNotEmpty(), - onClick = { if (isLoggedIn) item.logout() else item.login() }, - ) + val isLoggedIn by item.tracker.let { tracker -> + tracker.isLoggedInFlow.collectAsState(tracker.isLoggedIn) } + TrackingPreferenceWidget( + tracker = item.tracker, + checked = isLoggedIn, + onClick = { if (isLoggedIn) item.logout() else item.login() }, + ) } is Preference.PreferenceItem.InfoPreference -> { InfoWidget(text = item.title) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/BaseTracker.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/BaseTracker.kt index 8f88f1051..33caf6555 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/BaseTracker.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/BaseTracker.kt @@ -8,6 +8,8 @@ import eu.kanade.domain.track.service.TrackPreferences import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.network.NetworkHelper import eu.kanade.tachiyomi.util.system.toast +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine import logcat.LogPriority import okhttp3.OkHttpClient import tachiyomi.core.common.util.lang.withIOContext @@ -53,6 +55,15 @@ abstract class BaseTracker( get() = getUsername().isNotEmpty() && getPassword().isNotEmpty() + override val isLoggedInFlow: Flow by lazy { + combine( + trackPreferences.trackUsername(this).changes(), + trackPreferences.trackPassword(this).changes(), + ) { username, password -> + username.isNotEmpty() && password.isNotEmpty() + } + } + override fun getUsername() = trackPreferences.trackUsername(this).get() override fun getPassword() = trackPreferences.trackPassword(this).get() 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 06644e932..fd3a9f45e 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 @@ -7,6 +7,7 @@ import dev.icerock.moko.resources.StringResource import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.track.model.TrackSearch import kotlinx.collections.immutable.ImmutableList +import kotlinx.coroutines.flow.Flow import okhttp3.OkHttpClient import tachiyomi.domain.track.model.Track as DomainTrack @@ -61,6 +62,8 @@ interface Tracker { val isLoggedIn: Boolean + val isLoggedInFlow: Flow + fun getUsername(): String fun getPassword(): String diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackerManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackerManager.kt index 598a0c06c..1071fa7ee 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackerManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackerManager.kt @@ -9,6 +9,7 @@ import eu.kanade.tachiyomi.data.track.mangaupdates.MangaUpdates import eu.kanade.tachiyomi.data.track.myanimelist.MyAnimeList import eu.kanade.tachiyomi.data.track.shikimori.Shikimori import eu.kanade.tachiyomi.data.track.suwayomi.Suwayomi +import kotlinx.coroutines.flow.combine class TrackerManager { @@ -32,5 +33,13 @@ class TrackerManager { fun loggedInTrackers() = trackers.filter { it.isLoggedIn } + fun loggedInTrackersFlow() = combine(trackers.map { it.isLoggedInFlow }) { + it.mapIndexedNotNull { index, isLoggedIn -> + if (isLoggedIn) trackers[index] else null + } + } + fun get(id: Long) = trackers.find { it.id == id } + + fun getAll(ids: Set) = trackers.filter { it.id in ids } } 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 b2771d4e2..e866c98c9 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 @@ -39,6 +39,7 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map @@ -106,10 +107,10 @@ class LibraryScreenModel( getTracksPerManga.subscribe(), getTrackingFilterFlow(), downloadCache.changes, - ) { searchQuery, library, tracks, loggedInTrackers, _ -> + ) { searchQuery, library, tracks, trackingFiler, _ -> library - .applyFilters(tracks, loggedInTrackers) - .applySort(tracks) + .applyFilters(tracks, trackingFiler) + .applySort(tracks, trackingFiler.keys) .mapValues { (_, value) -> if (searchQuery != null) { // Filter query @@ -173,9 +174,10 @@ class LibraryScreenModel( /** * Applies library filters to the given map of manga. */ + @Suppress("LongMethod", "CyclomaticComplexMethod") private suspend fun LibraryMap.applyFilters( trackMap: Map>, - loggedInTrackers: Map, + trackingFiler: Map, ): LibraryMap { val prefs = getLibraryItemPreferencesFlow().first() val downloadedOnly = prefs.globalFilterDownloaded @@ -187,10 +189,10 @@ class LibraryScreenModel( val filterCompleted = prefs.filterCompleted val filterIntervalCustom = prefs.filterIntervalCustom - val isNotLoggedInAnyTrack = loggedInTrackers.isEmpty() + val isNotLoggedInAnyTrack = trackingFiler.isEmpty() - val excludedTracks = loggedInTrackers.mapNotNull { if (it.value == TriState.ENABLED_NOT) it.key else null } - val includedTracks = loggedInTrackers.mapNotNull { if (it.value == TriState.ENABLED_IS) it.key else null } + val excludedTracks = trackingFiler.mapNotNull { if (it.value == TriState.ENABLED_NOT) it.key else null } + val includedTracks = trackingFiler.mapNotNull { if (it.value == TriState.ENABLED_IS) it.key else null } val trackFiltersIsIgnored = includedTracks.isEmpty() && excludedTracks.isEmpty() val filterFnDownloaded: (LibraryItem) -> Boolean = { @@ -254,9 +256,11 @@ class LibraryScreenModel( /** * Applies library sorting to the given map of manga. */ + @Suppress("LongMethod", "CyclomaticComplexMethod") private fun LibraryMap.applySort( // Map> trackMap: Map>, + loggedInTrackerIds: Set ): LibraryMap { val sortAlphabetically: (LibraryItem, LibraryItem) -> Int = { i1, i2 -> i1.libraryManga.manga.title.lowercase().compareToWithCollator(i2.libraryManga.manga.title.lowercase()) @@ -264,7 +268,7 @@ class LibraryScreenModel( val defaultTrackerScoreSortValue = -1.0 val trackerScores by lazy { - val trackerMap = trackerManager.loggedInTrackers().associateBy { e -> e.id } + val trackerMap = trackerManager.getAll(loggedInTrackerIds).associateBy { e -> e.id } trackMap.mapValues { entry -> when { entry.value.isEmpty() -> null @@ -405,18 +409,17 @@ class LibraryScreenModel( * @return map of track id with the filter value */ private fun getTrackingFilterFlow(): Flow> { - val loggedInTrackers = trackerManager.loggedInTrackers() - return if (loggedInTrackers.isNotEmpty()) { - val prefFlows = loggedInTrackers - .map { libraryPreferences.filterTracking(it.id.toInt()).changes() } - .toTypedArray() - combine(*prefFlows) { + return trackerManager.loggedInTrackersFlow().flatMapLatest { loggedInTrackers -> + if (loggedInTrackers.isEmpty()) return@flatMapLatest flowOf(emptyMap()) + + val prefFlows = loggedInTrackers.map { tracker -> + libraryPreferences.filterTracking(tracker.id.toInt()).changes() + } + combine(prefFlows) { loggedInTrackers .mapIndexed { index, tracker -> tracker.id to it[index] } .toMap() } - } else { - flowOf(emptyMap()) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsScreenModel.kt index f0856f830..bd5867797 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsScreenModel.kt @@ -4,6 +4,8 @@ import cafe.adriel.voyager.core.model.ScreenModel import cafe.adriel.voyager.core.model.screenModelScope import eu.kanade.domain.base.BasePreferences import eu.kanade.tachiyomi.data.track.TrackerManager +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.stateIn import tachiyomi.core.common.preference.Preference import tachiyomi.core.common.preference.TriState import tachiyomi.core.common.preference.getAndSet @@ -16,17 +18,22 @@ import tachiyomi.domain.library.model.LibrarySort import tachiyomi.domain.library.service.LibraryPreferences import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get +import kotlin.time.Duration.Companion.seconds class LibrarySettingsScreenModel( val preferences: BasePreferences = Injekt.get(), val libraryPreferences: LibraryPreferences = Injekt.get(), private val setDisplayMode: SetDisplayMode = Injekt.get(), private val setSortModeForCategory: SetSortModeForCategory = Injekt.get(), - private val trackerManager: TrackerManager = Injekt.get(), + trackerManager: TrackerManager = Injekt.get(), ) : ScreenModel { - val trackers - get() = trackerManager.trackers.filter { it.isLoggedIn } + val trackersFlow = trackerManager.loggedInTrackersFlow() + .stateIn( + scope = screenModelScope, + started = SharingStarted.WhileSubscribed(5.seconds.inWholeMilliseconds), + initialValue = trackerManager.loggedInTrackers() + ) fun toggleFilter(preference: (LibraryPreferences) -> Preference) { preference(libraryPreferences).getAndSet { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt index c2466ffd4..b4b82584e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt @@ -138,7 +138,7 @@ class MangaScreen( ) }.takeIf { isHttpSource }, onTrackingClicked = { - if (screenModel.loggedInTrackers.isEmpty()) { + if (successState.loggedInTracker.isEmpty()) { navigator.push(SettingsScreen(SettingsScreen.Destination.Tracking)) } else { screenModel.showTrackDialog() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt index 14cb037df..682c45fcd 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt @@ -28,6 +28,7 @@ import eu.kanade.tachiyomi.data.download.DownloadCache import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.data.download.model.Download import eu.kanade.tachiyomi.data.track.EnhancedTracker +import eu.kanade.tachiyomi.data.track.Tracker import eu.kanade.tachiyomi.data.track.TrackerManager import eu.kanade.tachiyomi.network.HttpException import eu.kanade.tachiyomi.source.Source @@ -45,7 +46,6 @@ import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter -import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.update import kotlinx.coroutines.isActive import kotlinx.coroutines.launch @@ -117,8 +117,6 @@ class MangaScreenModel( private val successState: State.Success? get() = state.value as? State.Success - val loggedInTrackers by lazy { trackerManager.trackers.filter { it.isLoggedIn } } - val manga: Manga? get() = successState?.manga @@ -194,6 +192,16 @@ class MangaScreenModel( } } + screenModelScope.launchIO { + trackerManager.loggedInTrackersFlow() + .distinctUntilChanged() + .collectLatest { trackers -> + updateSuccessState { + it.copy(loggedInTracker = trackers) + } + } + } + observeDownloads() screenModelScope.launchIO { @@ -978,15 +986,16 @@ class MangaScreenModel( val manga = successState?.manga ?: return screenModelScope.launchIO { - getTracks.subscribe(manga.id) - .catch { logcat(LogPriority.ERROR, it) } - .map { tracks -> - loggedInTrackers - // Map to TrackItem - .map { service -> TrackItem(tracks.find { it.trackerId == service.id }, service) } - // Show only if the service supports this manga's source - .filter { (it.tracker as? EnhancedTracker)?.accept(source!!) ?: true } - } + combine( + getTracks.subscribe(manga.id).catch { logcat(LogPriority.ERROR, it) }, + trackerManager.loggedInTrackersFlow(), + ) { mangaTracks, loggedInTrackers -> + loggedInTrackers + // Map to TrackItem + .map { service -> TrackItem(mangaTracks.find { it.trackerId == service.id }, service) } + // Show only if the service supports this manga's source + .filter { (it.tracker as? EnhancedTracker)?.accept(source!!) ?: true } + } .distinctUntilChanged() .collectLatest { trackItems -> updateSuccessState { it.copy(trackItems = trackItems) } @@ -1057,6 +1066,7 @@ class MangaScreenModel( val isRefreshingData: Boolean = false, val dialog: Dialog? = null, val hasPromptedToAddBefore: Boolean = false, + val loggedInTracker: List = emptyList(), ) : State { val processedChapters by lazy { chapters.applyFilters(manga).toList() 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 1ba697f24..4c66940c9 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 @@ -239,7 +239,7 @@ data class TrackInfoDialogHomeScreen( } private fun List.mapToTrackItem(): List { - val loggedInTrackers = Injekt.get().trackers.filter { it.isLoggedIn } + val loggedInTrackers = Injekt.get().loggedInTrackers() val source = Injekt.get().getOrStub(sourceId) return loggedInTrackers // Map to TrackItem diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/stats/StatsScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/stats/StatsScreenModel.kt index 0d553ab4b..174ac26dc 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/stats/StatsScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/stats/StatsScreenModel.kt @@ -36,7 +36,7 @@ class StatsScreenModel( private val trackerManager: TrackerManager = Injekt.get(), ) : StateScreenModel(StatsScreenState.Loading) { - private val loggedInTrackers by lazy { trackerManager.trackers.fastFilter { it.isLoggedIn } } + private val loggedInTrackers by lazy { trackerManager.loggedInTrackers() } init { screenModelScope.launchIO { diff --git a/app/src/main/java/eu/kanade/test/DummyTracker.kt b/app/src/main/java/eu/kanade/test/DummyTracker.kt index 56092b440..4c77e660d 100644 --- a/app/src/main/java/eu/kanade/test/DummyTracker.kt +++ b/app/src/main/java/eu/kanade/test/DummyTracker.kt @@ -7,6 +7,8 @@ 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 kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOf import okhttp3.OkHttpClient import tachiyomi.domain.track.model.Track import tachiyomi.i18n.MR @@ -16,6 +18,7 @@ data class DummyTracker( override val name: String, override val supportsReadingDates: Boolean = false, override val isLoggedIn: Boolean = false, + override val isLoggedInFlow: Flow = flowOf(false), val valLogoColor: Int = Color.rgb(18, 25, 35), val valLogo: Int = R.drawable.ic_tracker_anilist, val valStatuses: List = (1L..6L).toList(), From cbcd8bd6682023f728568f2b44da26124618aed7 Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Mon, 8 Jul 2024 09:20:02 +0600 Subject: [PATCH 093/297] Fix login prompts despite being logged in to trackers in Manga screen --- .../kanade/tachiyomi/ui/manga/MangaScreen.kt | 2 +- .../tachiyomi/ui/manga/MangaScreenModel.kt | 38 +++++++------------ 2 files changed, 15 insertions(+), 25 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt index b4b82584e..e500a04d3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt @@ -138,7 +138,7 @@ class MangaScreen( ) }.takeIf { isHttpSource }, onTrackingClicked = { - if (successState.loggedInTracker.isEmpty()) { + if (!successState.hasLoggedInTrackers) { navigator.push(SettingsScreen(SettingsScreen.Destination.Tracking)) } else { screenModel.showTrackDialog() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt index 682c45fcd..99a1b1612 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt @@ -28,11 +28,9 @@ import eu.kanade.tachiyomi.data.download.DownloadCache import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.data.download.model.Download import eu.kanade.tachiyomi.data.track.EnhancedTracker -import eu.kanade.tachiyomi.data.track.Tracker import eu.kanade.tachiyomi.data.track.TrackerManager import eu.kanade.tachiyomi.network.HttpException import eu.kanade.tachiyomi.source.Source -import eu.kanade.tachiyomi.ui.manga.track.TrackItem import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences import eu.kanade.tachiyomi.util.chapter.getNextUnread import eu.kanade.tachiyomi.util.removeCovers @@ -192,16 +190,6 @@ class MangaScreenModel( } } - screenModelScope.launchIO { - trackerManager.loggedInTrackersFlow() - .distinctUntilChanged() - .collectLatest { trackers -> - updateSuccessState { - it.copy(loggedInTracker = trackers) - } - } - } - observeDownloads() screenModelScope.launchIO { @@ -990,15 +978,20 @@ class MangaScreenModel( getTracks.subscribe(manga.id).catch { logcat(LogPriority.ERROR, it) }, trackerManager.loggedInTrackersFlow(), ) { mangaTracks, loggedInTrackers -> - loggedInTrackers - // Map to TrackItem - .map { service -> TrackItem(mangaTracks.find { it.trackerId == service.id }, service) } - // Show only if the service supports this manga's source - .filter { (it.tracker as? EnhancedTracker)?.accept(source!!) ?: true } + // Show only if the service supports this manga's source + val supportedTrackers = loggedInTrackers.filter { (it as? EnhancedTracker)?.accept(source!!) ?: true } + val supportedTrackerIds = supportedTrackers.map { it.id }.toHashSet() + val supportedTrackerTracks = mangaTracks.filter { it.trackerId in supportedTrackerIds } + supportedTrackerTracks.size to supportedTrackers.isNotEmpty() } .distinctUntilChanged() - .collectLatest { trackItems -> - updateSuccessState { it.copy(trackItems = trackItems) } + .collectLatest { (trackingCount, hasLoggedInTrackers) -> + updateSuccessState { + it.copy( + trackingCount = trackingCount, + hasLoggedInTrackers = hasLoggedInTrackers, + ) + } } } } @@ -1062,11 +1055,11 @@ class MangaScreenModel( val chapters: List, val availableScanlators: Set, val excludedScanlators: Set, - val trackItems: List = emptyList(), + val trackingCount: Int = 0, + val hasLoggedInTrackers: Boolean = false, val isRefreshingData: Boolean = false, val dialog: Dialog? = null, val hasPromptedToAddBefore: Boolean = false, - val loggedInTracker: List = emptyList(), ) : State { val processedChapters by lazy { chapters.applyFilters(manga).toList() @@ -1109,9 +1102,6 @@ class MangaScreenModel( val filterActive: Boolean get() = scanlatorFilterActive || manga.chaptersFiltered() - val trackingCount: Int - get() = trackItems.count { it.track != null } - /** * Applies the view filters to the list of chapters obtained from the database. * @return an observable of the list of chapters filtered and sorted. From daa47e049327c4d8b1fe4724ed1b84897d81fcf2 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Mon, 8 Jul 2024 18:02:50 +0800 Subject: [PATCH 094/297] Fix some issues when reading/saving images (#993) * Fix unsupported mime type error when saving images Avoid using platform mime type map to get extensions as it may not have all mime types we support. * Fix jxl images downloading/reading --- .../data/download/DownloadManager.kt | 3 ++- .../tachiyomi/data/download/Downloader.kt | 8 +------ .../kanade/tachiyomi/data/saver/ImageSaver.kt | 18 ++++++++++----- .../core/common/util/system/ImageUtil.kt | 23 ++++--------------- 4 files changed, 20 insertions(+), 32 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt index 01a342859..5fba899ca 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt @@ -17,6 +17,7 @@ import logcat.LogPriority import tachiyomi.core.common.i18n.stringResource import tachiyomi.core.common.storage.extension import tachiyomi.core.common.util.lang.launchIO +import tachiyomi.core.common.util.system.ImageUtil import tachiyomi.core.common.util.system.logcat import tachiyomi.domain.category.interactor.GetCategories import tachiyomi.domain.chapter.model.Chapter @@ -160,7 +161,7 @@ class DownloadManager( fun buildPageList(source: Source, manga: Manga, chapter: Chapter): List { val chapterDir = provider.findChapterDir(chapter.name, chapter.scanlator, manga.title, source) val files = chapterDir?.listFiles().orEmpty() - .filter { "image" in it.type.orEmpty() } + .filter { it.isFile && ImageUtil.isImage(it.name) { it.openInputStream() } } if (files.isEmpty()) { throw Exception(context.stringResource(MR.strings.page_list_empty_error)) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt index ebf9df65e..57c3a9824 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt @@ -523,14 +523,8 @@ class Downloader( * @param file the file where the image is already downloaded. */ private fun getImageExtension(response: Response, file: UniFile): String { - // Read content type if available. val mime = response.body.contentType()?.run { if (type == "image") "image/$subtype" else null } - // Else guess from the uri. - ?: context.contentResolver.getType(file.uri) - // Else read magic numbers. - ?: ImageUtil.findImageType { file.openInputStream() }?.mime - - return ImageUtil.getExtensionFromMimeType(mime) + return ImageUtil.getExtensionFromMimeType(mime) { file.openInputStream() } } private fun splitTallImageIfNeeded(page: Page, tmpDir: UniFile) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/saver/ImageSaver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/saver/ImageSaver.kt index b7b53d835..0cc0ebc04 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/saver/ImageSaver.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/saver/ImageSaver.kt @@ -7,6 +7,7 @@ import android.net.Uri import android.os.Build import android.os.Environment import android.provider.MediaStore +import android.webkit.MimeTypeMap import androidx.annotation.RequiresApi import androidx.core.content.contentValuesOf import androidx.core.net.toUri @@ -65,21 +66,26 @@ class ImageSaver( filename: String, data: () -> InputStream, ): Uri { - val pictureDir = + val isMimeTypeSupported = MimeTypeMap.getSingleton().hasMimeType(type.mime) + + val pictureDir = if (isMimeTypeSupported) { MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) + } else { + MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) + } val imageLocation = (image.location as Location.Pictures).relativePath val relativePath = listOf( - Environment.DIRECTORY_PICTURES, + if (isMimeTypeSupported) Environment.DIRECTORY_PICTURES else Environment.DIRECTORY_DOCUMENTS, context.stringResource(MR.strings.app_name), imageLocation, ).joinToString(File.separator) val contentValues = contentValuesOf( - MediaStore.Images.Media.RELATIVE_PATH to relativePath, - MediaStore.Images.Media.DISPLAY_NAME to image.name, - MediaStore.Images.Media.MIME_TYPE to type.mime, - MediaStore.Images.Media.DATE_MODIFIED to Instant.now().epochSecond, + MediaStore.MediaColumns.RELATIVE_PATH to relativePath, + MediaStore.MediaColumns.DISPLAY_NAME to if (isMimeTypeSupported) image.name else filename, + MediaStore.MediaColumns.MIME_TYPE to type.mime, + MediaStore.MediaColumns.DATE_MODIFIED to Instant.now().epochSecond, ) val picture = findUriOrDefault(relativePath, filename) { diff --git a/core/common/src/main/kotlin/tachiyomi/core/common/util/system/ImageUtil.kt b/core/common/src/main/kotlin/tachiyomi/core/common/util/system/ImageUtil.kt index f5e9a8098..2cdd2a306 100644 --- a/core/common/src/main/kotlin/tachiyomi/core/common/util/system/ImageUtil.kt +++ b/core/common/src/main/kotlin/tachiyomi/core/common/util/system/ImageUtil.kt @@ -13,7 +13,6 @@ import android.graphics.drawable.ColorDrawable import android.graphics.drawable.Drawable import android.graphics.drawable.GradientDrawable import android.os.Build -import android.webkit.MimeTypeMap import androidx.annotation.ColorInt import androidx.core.graphics.alpha import androidx.core.graphics.applyCanvas @@ -29,7 +28,6 @@ import okio.BufferedSource import tachiyomi.decoder.Format import tachiyomi.decoder.ImageDecoder import java.io.InputStream -import java.net.URLConnection import java.util.Locale import kotlin.math.abs import kotlin.math.max @@ -40,12 +38,8 @@ object ImageUtil { fun isImage(name: String?, openStream: (() -> InputStream)? = null): Boolean { if (name == null) return false - val contentType = try { - URLConnection.guessContentTypeFromName(name) - } catch (e: Exception) { - null - } ?: openStream?.let { findImageType(it)?.mime } - return contentType?.startsWith("image/") ?: false + val extension = name.substringAfterLast('.') + return ImageType.entries.any { it.extension == extension } || openStream?.let { findImageType(it) } != null } fun findImageType(openStream: () -> InputStream): ImageType? { @@ -69,10 +63,9 @@ object ImageUtil { } } - fun getExtensionFromMimeType(mime: String?): String { - return MimeTypeMap.getSingleton().getExtensionFromMimeType(mime) - ?: SUPPLEMENTARY_MIMETYPE_MAPPING[mime] - ?: "jpg" + fun getExtensionFromMimeType(mime: String?, openStream: () -> InputStream): String { + val type = mime?.let { ImageType.entries.find { it.mime == mime } } ?: findImageType(openStream) + return type?.extension ?: "jpg" } fun isAnimatedAndSupported(source: BufferedSource): Boolean { @@ -558,12 +551,6 @@ object ImageUtil { } private val optimalImageHeight = getDisplayMaxHeightInPx * 2 - - // Android doesn't include some mappings - private val SUPPLEMENTARY_MIMETYPE_MAPPING = mapOf( - // https://issuetracker.google.com/issues/182703810 - "image/jxl" to "jxl", - ) } val getDisplayMaxHeightInPx: Int From e65634cb427eafe9e3bd192f9e8bf71f2243ce6c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 9 Jul 2024 07:27:03 +0000 Subject: [PATCH 095/297] Bump coil version and some cleanup Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/src/main/java/eu/kanade/tachiyomi/App.kt | 21 +++++++++++++------- gradle/libs.versions.toml | 2 +- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/App.kt b/app/src/main/java/eu/kanade/tachiyomi/App.kt index 558ad213e..d0b77cec1 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/App.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/App.kt @@ -153,26 +153,33 @@ class App : Application(), DefaultLifecycleObserver, SingletonImageLoader.Factor ) } + @Suppress("MagicNumber") override fun newImageLoader(context: Context): ImageLoader { return ImageLoader.Builder(this).apply { val callFactoryLazy = lazy { Injekt.get().client } components { + // NetworkFetcher.Factory add(OkHttpNetworkFetcherFactory(callFactoryLazy::value)) + // Decoder.Factory add(TachiyomiImageDecoder.Factory()) - add(MangaCoverFetcher.MangaFactory(callFactoryLazy)) - add(MangaCoverFetcher.MangaCoverFactory(callFactoryLazy)) - add(MangaKeyer()) - add(MangaCoverKeyer()) + // Fetcher.Factory add(BufferedSourceFetcher.Factory()) + add(MangaCoverFetcher.MangaCoverFactory(callFactoryLazy)) + add(MangaCoverFetcher.MangaFactory(callFactoryLazy)) + // Keyer + add(MangaCoverKeyer()) + add(MangaKeyer()) } + crossfade((300 * this@App.animatorDurationScale).toInt()) allowRgb565(DeviceUtil.isLowRamDevice(this@App)) if (networkPreferences.verboseLogging().get()) logger(DebugLogger()) // Coil spawns a new thread for every image load by default - fetcherDispatcher(Dispatchers.IO.limitedParallelism(8)) - decoderDispatcher(Dispatchers.IO.limitedParallelism(2)) - }.build() + fetcherCoroutineContext(Dispatchers.IO.limitedParallelism(8)) + decoderCoroutineContext(Dispatchers.IO.limitedParallelism(3)) + } + .build() } override fun onStart(owner: LifecycleOwner) { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 84e9797c5..520933e40 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -42,7 +42,7 @@ preferencektx = "androidx.preference:preference-ktx:1.2.1" injekt-core = "com.github.inorichi.injekt:injekt-core:65b0440" -coil-bom = { module = "io.coil-kt.coil3:coil-bom", version = "3.0.0-alpha07" } +coil-bom = { module = "io.coil-kt.coil3:coil-bom", version = "3.0.0-alpha08" } coil-core = { module = "io.coil-kt.coil3:coil" } coil-gif = { module = "io.coil-kt.coil3:coil-gif" } coil-compose = { module = "io.coil-kt.coil3:coil-compose" } From 4a7613d515578a2fb05f4f2953cce410dc229a95 Mon Sep 17 00:00:00 2001 From: Roshan Varughese <40583749+Animeboynz@users.noreply.github.com> Date: Thu, 11 Jul 2024 03:30:12 +1200 Subject: [PATCH 096/297] A Minor Milestone (#1000) * Fixes README.md Alignment * Adds parameter to both --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b059b312c..d40550b03 100644 --- a/README.md +++ b/README.md @@ -49,8 +49,8 @@ Before reporting a new issue, take a look at the [FAQ](https://mihon.app/docs/fa ### Repositories -[![mihonapp/website - GitHub](https://github-readme-stats.vercel.app/api/pin/?username=mihonapp&repo=website&bg_color=161B22&text_color=c9d1d9&title_color=0877d2&icon_color=0877d2&border_radius=8&hide_border=true)](https://github.com/mihonapp/website/) -[![mihonapp/bitmap.kt - GitHub](https://github-readme-stats.vercel.app/api/pin/?username=mihonapp&repo=bitmap.kt&bg_color=161B22&text_color=c9d1d9&title_color=0877d2&icon_color=0877d2&border_radius=8&hide_border=true)](https://github.com/mihonapp/bitmap.kt/) +[![mihonapp/website - GitHub](https://github-readme-stats.vercel.app/api/pin/?username=mihonapp&repo=website&bg_color=161B22&text_color=c9d1d9&title_color=0877d2&icon_color=0877d2&border_radius=8&hide_border=true&description_lines_count=2)](https://github.com/mihonapp/website/) +[![mihonapp/bitmap.kt - GitHub](https://github-readme-stats.vercel.app/api/pin/?username=mihonapp&repo=bitmap.kt&bg_color=161B22&text_color=c9d1d9&title_color=0877d2&icon_color=0877d2&border_radius=8&hide_border=true&description_lines_count=2)](https://github.com/mihonapp/bitmap.kt/) ### Credits From 7a2ca4bf4d41764705637d61c6d86249f8815b7b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 12 Jul 2024 04:51:42 +0600 Subject: [PATCH 097/297] fix(deps): update dependency com.android.tools.build:gradle to v8.5.1 (#1010) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/androidx.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index f7aa3acb6..6cb627960 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -1,5 +1,5 @@ [versions] -agp_version = "8.5.0" +agp_version = "8.5.1" lifecycle_version = "2.8.3" paging_version = "3.3.0" interpolator_version = "1.0.0" From e94c8dac9425a1d3fbe6640a0c285e9f3a5f16a8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 12 Jul 2024 04:51:55 +0600 Subject: [PATCH 098/297] chore(deps): update actions/dependency-review-action action to v4.3.4 (#1009) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/build_pull_request.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_pull_request.yml b/.github/workflows/build_pull_request.yml index f12ac59d0..bdcacb4e2 100644 --- a/.github/workflows/build_pull_request.yml +++ b/.github/workflows/build_pull_request.yml @@ -26,7 +26,7 @@ jobs: uses: gradle/actions/wrapper-validation@dbbdc275be76ac10734476cc723d82dfe7ec6eda # v3.4.2 - name: Dependency Review - uses: actions/dependency-review-action@72eb03d02c7872a771aacd928f3123ac62ad6d3a # v4.3.3 + uses: actions/dependency-review-action@5a2ce3f5b92ee19cbb1541a4984c76d921601d7c # v4.3.4 - name: Set up JDK uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9 # v4.2.1 From 14d687c5cdff1071098b3580e8b010d7aa01f485 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 12 Jul 2024 04:52:08 +0600 Subject: [PATCH 099/297] fix(deps): update dependency dev.chrisbanes.compose:compose-bom to v2024.07.00-alpha01 (#1002) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/compose.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/compose.versions.toml b/gradle/compose.versions.toml index 74ae656e9..ea9e52efd 100644 --- a/gradle/compose.versions.toml +++ b/gradle/compose.versions.toml @@ -1,5 +1,5 @@ [versions] -compose-bom = "2024.06.00-alpha01" +compose-bom = "2024.07.00-alpha01" accompanist = "0.35.1-alpha" [libraries] From f3f2bd41c3974878bcf0e3a62d99ee89bf92fb41 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 12 Jul 2024 04:52:17 +0600 Subject: [PATCH 100/297] fix(deps): update dependency org.jsoup:jsoup to v1.18.1 (#999) 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 520933e40..8bf834d80 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -28,7 +28,7 @@ conscrypt-android = "org.conscrypt:conscrypt-android:2.5.2" quickjs-android = "app.cash.quickjs:quickjs-android:0.9.2" -jsoup = "org.jsoup:jsoup:1.17.2" +jsoup = "org.jsoup:jsoup:1.18.1" disklrucache = "com.jakewharton:disklrucache:2.0.2" unifile = "com.github.tachiyomiorg:unifile:e0def6b3dc" From f63e95091013320b27bfc3c7c975c4bdd4a983c5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 12 Jul 2024 06:04:57 +0600 Subject: [PATCH 101/297] chore(deps): update dependency gradle to v8.9 (#1007) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a4413138c..09523c0e5 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From 8c9d12a84050afe5f6930868461c16e56c03116d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 16 Jul 2024 16:19:14 +0600 Subject: [PATCH 102/297] chore(deps): update gradle/actions action to v3.5.0 (#1018) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/build_pull_request.yml | 4 ++-- .github/workflows/build_push.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build_pull_request.yml b/.github/workflows/build_pull_request.yml index bdcacb4e2..98907b52f 100644 --- a/.github/workflows/build_pull_request.yml +++ b/.github/workflows/build_pull_request.yml @@ -23,7 +23,7 @@ jobs: uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Validate Gradle Wrapper - uses: gradle/actions/wrapper-validation@dbbdc275be76ac10734476cc723d82dfe7ec6eda # v3.4.2 + uses: gradle/actions/wrapper-validation@d9c87d481d55275bb5441eef3fe0e46805f9ef70 # v3.5.0 - name: Dependency Review uses: actions/dependency-review-action@5a2ce3f5b92ee19cbb1541a4984c76d921601d7c # v4.3.4 @@ -35,7 +35,7 @@ jobs: distribution: adopt - name: Set up gradle - uses: gradle/actions/setup-gradle@dbbdc275be76ac10734476cc723d82dfe7ec6eda # v3.4.2 + uses: gradle/actions/setup-gradle@d9c87d481d55275bb5441eef3fe0e46805f9ef70 # v3.5.0 - name: Build app and run unit tests run: ./gradlew detekt assembleStandardRelease testReleaseUnitTest testStandardReleaseUnitTest diff --git a/.github/workflows/build_push.yml b/.github/workflows/build_push.yml index bb91f0a4f..1f04e4759 100644 --- a/.github/workflows/build_push.yml +++ b/.github/workflows/build_push.yml @@ -20,7 +20,7 @@ jobs: uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Validate Gradle Wrapper - uses: gradle/actions/wrapper-validation@dbbdc275be76ac10734476cc723d82dfe7ec6eda # v3.4.2 + uses: gradle/actions/wrapper-validation@d9c87d481d55275bb5441eef3fe0e46805f9ef70 # v3.5.0 - name: Setup Android SDK run: | @@ -33,7 +33,7 @@ jobs: distribution: adopt - name: Set up gradle - uses: gradle/actions/setup-gradle@dbbdc275be76ac10734476cc723d82dfe7ec6eda # v3.4.2 + uses: gradle/actions/setup-gradle@d9c87d481d55275bb5441eef3fe0e46805f9ef70 # v3.5.0 - name: Build app and run unit tests run: ./gradlew detekt assembleStandardRelease testReleaseUnitTest testStandardReleaseUnitTest From 4f61b2e4e89bc257cf5e629823904805907bf75c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 16 Jul 2024 16:19:27 +0600 Subject: [PATCH 103/297] fix(deps): update dependency io.mockk:mockk to v1.13.12 (#1016) 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 8bf834d80..398a2f89b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -91,7 +91,7 @@ sqldelight-gradle = { module = "app.cash.sqldelight:gradle-plugin", version.ref junit = "org.junit.jupiter:junit-jupiter:5.10.3" kotest-assertions = "io.kotest:kotest-assertions-core:5.9.1" -mockk = "io.mockk:mockk:1.13.11" +mockk = "io.mockk:mockk:1.13.12" voyager-navigator = { module = "cafe.adriel.voyager:voyager-navigator", version.ref = "voyager" } voyager-screenmodel = { module = "cafe.adriel.voyager:voyager-screenmodel", version.ref = "voyager" } From ca784cbe3267e94e652e4c54f91b7107cc53c307 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 24 Jul 2024 18:53:11 +0600 Subject: [PATCH 104/297] fix(deps): update dependency io.coil-kt.coil3:coil-bom to v3.0.0-alpha09 (#1039) 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 398a2f89b..f1e91d2f8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -42,7 +42,7 @@ preferencektx = "androidx.preference:preference-ktx:1.2.1" injekt-core = "com.github.inorichi.injekt:injekt-core:65b0440" -coil-bom = { module = "io.coil-kt.coil3:coil-bom", version = "3.0.0-alpha08" } +coil-bom = { module = "io.coil-kt.coil3:coil-bom", version = "3.0.0-alpha09" } coil-core = { module = "io.coil-kt.coil3:coil" } coil-gif = { module = "io.coil-kt.coil3:coil-gif" } coil-compose = { module = "io.coil-kt.coil3:coil-compose" } From 51b68cd25ff4bf556de88cb31525c55dd7eb7027 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Wed, 24 Jul 2024 21:09:29 +0800 Subject: [PATCH 105/297] Remove obsolete workaround (#1021) --- settings.gradle.kts | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/settings.gradle.kts b/settings.gradle.kts index 76b88ed6e..b1a2a2dd5 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -13,16 +13,6 @@ pluginManagement { mavenCentral() maven(url = "https://www.jitpack.io") } - // https://issuetracker.google.com/344363457 - // TODO: Remove when AGP's bundled R8 is updated - buildscript { - repositories { - maven("https://storage.googleapis.com/r8-releases/raw") - } - dependencies { - classpath("com.android.tools:r8:8.5.21") - } - } } dependencyResolutionManagement { From 6ace423e18f04e7a335c2840f8068828296d429c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 24 Jul 2024 19:09:53 +0600 Subject: [PATCH 106/297] chore(deps): update softprops/action-gh-release action to v2.0.8 (#1024) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/build_push.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_push.yml b/.github/workflows/build_push.yml index 1f04e4759..bbabee9c5 100644 --- a/.github/workflows/build_push.yml +++ b/.github/workflows/build_push.yml @@ -95,7 +95,7 @@ jobs: - name: Create Release if: startsWith(github.ref, 'refs/tags/') && github.repository == 'mihonapp/mihon' - uses: softprops/action-gh-release@a74c6b72af54cfa997e81df42d94703d6313a2d0 # v2.0.6 + uses: softprops/action-gh-release@c062e08bd532815e2082a85e87e3ef29c3e6d191 # v2.0.8 with: tag_name: ${{ env.VERSION_TAG }} name: Mihon ${{ env.VERSION_TAG }} From e48dbdbf2356c0e6e148313dc6610e865cd8e995 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 25 Jul 2024 01:14:44 +0600 Subject: [PATCH 107/297] fix(deps): update dependency androidx.activity:activity-compose to v1.9.1 (#1042) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/compose.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/compose.versions.toml b/gradle/compose.versions.toml index ea9e52efd..2e64c51b5 100644 --- a/gradle/compose.versions.toml +++ b/gradle/compose.versions.toml @@ -3,7 +3,7 @@ compose-bom = "2024.07.00-alpha01" accompanist = "0.35.1-alpha" [libraries] -activity = "androidx.activity:activity-compose:1.9.0" +activity = "androidx.activity:activity-compose:1.9.1" bom = { group = "dev.chrisbanes.compose", name = "compose-bom", version.ref = "compose-bom" } foundation = { module = "androidx.compose.foundation:foundation" } animation = { module = "androidx.compose.animation:animation" } From 602b58f364b95b83a3148be34cd4c90d95d7d405 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 25 Jul 2024 01:15:21 +0600 Subject: [PATCH 108/297] fix(deps): update dependency androidx.annotation:annotation to v1.8.1 (#1043) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/androidx.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index 6cb627960..aedf1fa6f 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -7,7 +7,7 @@ interpolator_version = "1.0.0" [libraries] gradle = { module = "com.android.tools.build:gradle", version.ref = "agp_version" } -annotation = "androidx.annotation:annotation:1.8.0" +annotation = "androidx.annotation:annotation:1.8.1" appcompat = "androidx.appcompat:appcompat:1.7.0" biometricktx = "androidx.biometric:biometric-ktx:1.2.0-alpha05" constraintlayout = "androidx.constraintlayout:constraintlayout:2.1.4" From b7849d714698900a25188bdbfd77bf24936f2dd7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 25 Jul 2024 21:35:38 +0600 Subject: [PATCH 109/297] fix(deps): update lifecycle.version to v2.8.4 (#1045) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/androidx.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index aedf1fa6f..3a82e7320 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -1,6 +1,6 @@ [versions] agp_version = "8.5.1" -lifecycle_version = "2.8.3" +lifecycle_version = "2.8.4" paging_version = "3.3.0" interpolator_version = "1.0.0" From 88efde8796b0e1cc8fba6cd987bdc487bd97f248 Mon Sep 17 00:00:00 2001 From: Roshan Varughese <40583749+Animeboynz@users.noreply.github.com> Date: Fri, 26 Jul 2024 04:00:06 +1200 Subject: [PATCH 110/297] Format Category String on Subtitle Display (#1030) * Fixes #1029 * Max Line Length Fix * Update SettingsLibraryScreen.kt No idea how this works. Co-authored-by: Foolbar <118464521+Foolbar@users.noreply.github.com> --------- Co-authored-by: Foolbar <118464521+Foolbar@users.noreply.github.com> --- .../more/settings/screen/SettingsLibraryScreen.kt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsLibraryScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsLibraryScreen.kt index 346a60b86..c3ef07d42 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsLibraryScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsLibraryScreen.kt @@ -71,9 +71,6 @@ object SettingsLibraryScreen : SearchableSettings { val scope = rememberCoroutineScope() val userCategoriesCount = allCategories.filterNot(Category::isSystemCategory).size - val defaultCategory by libraryPreferences.defaultCategory().collectAsState() - val selectedCategory = allCategories.find { it.id == defaultCategory.toLong() } - // For default category val ids = listOf(libraryPreferences.defaultCategory().defaultValue()) + allCategories.fastMap { it.id.toInt() } @@ -95,7 +92,6 @@ object SettingsLibraryScreen : SearchableSettings { Preference.PreferenceItem.ListPreference( pref = libraryPreferences.defaultCategory(), title = stringResource(MR.strings.default_category), - subtitle = selectedCategory?.visualName ?: stringResource(MR.strings.default_category_summary), entries = ids.zip(labels).toMap().toImmutableMap(), ), Preference.PreferenceItem.SwitchPreference( From 41e2dc7ae80250d9166fc637c1170667afdb0a9e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 25 Jul 2024 22:00:41 +0600 Subject: [PATCH 111/297] fix(deps): update paging.version to v3.3.1 (#1046) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/androidx.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index 3a82e7320..404729cf9 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -1,7 +1,7 @@ [versions] agp_version = "8.5.1" lifecycle_version = "2.8.4" -paging_version = "3.3.0" +paging_version = "3.3.1" interpolator_version = "1.0.0" [libraries] From 04aa5b36a5893ef9991312d61f84f830b83535f7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 26 Jul 2024 19:23:23 +0600 Subject: [PATCH 112/297] fix(deps): update dependency dev.chrisbanes.compose:compose-bom to v2024.07.00-alpha02 (#1051) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/compose.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/compose.versions.toml b/gradle/compose.versions.toml index 2e64c51b5..29dc3acf0 100644 --- a/gradle/compose.versions.toml +++ b/gradle/compose.versions.toml @@ -1,5 +1,5 @@ [versions] -compose-bom = "2024.07.00-alpha01" +compose-bom = "2024.07.00-alpha02" accompanist = "0.35.1-alpha" [libraries] From 913ff22132390a59a13c463645ce954c7cbc5c6b Mon Sep 17 00:00:00 2001 From: "Tran M. Cuong" Date: Sat, 27 Jul 2024 02:01:32 +0700 Subject: [PATCH 113/297] Fix disappearance items when fast scrolling (#1035) * Don't use animateItem's fade-in/fade-out in FastScrollLazyColumn * Move to extension function Avoid using animateItemPlacement name since it's shadowed by compose-bom's deprecated one --- .../eu/kanade/presentation/browse/ExtensionsScreen.kt | 7 ++++--- .../eu/kanade/presentation/browse/SourcesFilterScreen.kt | 5 +++-- .../java/eu/kanade/presentation/history/HistoryScreen.kt | 5 +++-- .../java/eu/kanade/presentation/updates/UpdatesUiItem.kt | 7 ++++--- .../eu/kanade/presentation/util/FastScrollAnimateItem.kt | 8 ++++++++ 5 files changed, 22 insertions(+), 10 deletions(-) create mode 100644 app/src/main/java/eu/kanade/presentation/util/FastScrollAnimateItem.kt diff --git a/app/src/main/java/eu/kanade/presentation/browse/ExtensionsScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/ExtensionsScreen.kt index 5849e8c9e..f5a6fedd4 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/ExtensionsScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/ExtensionsScreen.kt @@ -48,6 +48,7 @@ import eu.kanade.presentation.browse.components.ExtensionIcon import eu.kanade.presentation.components.WarningBanner import eu.kanade.presentation.manga.components.DotSeparatorNoSpaceText import eu.kanade.presentation.more.settings.screen.browse.ExtensionReposScreen +import eu.kanade.presentation.util.animateItemFastScroll import eu.kanade.presentation.util.rememberRequestPackageInstallsPermissionState import eu.kanade.tachiyomi.extension.model.Extension import eu.kanade.tachiyomi.extension.model.InstallStep @@ -187,14 +188,14 @@ private fun ExtensionContent( } ExtensionHeader( textRes = header.textRes, - modifier = Modifier.animateItem(), + modifier = Modifier.animateItemFastScroll(), action = action, ) } is ExtensionUiModel.Header.Text -> { ExtensionHeader( text = header.text, - modifier = Modifier.animateItem(), + modifier = Modifier.animateItemFastScroll(), ) } } @@ -212,7 +213,7 @@ private fun ExtensionContent( }, ) { item -> ExtensionItem( - modifier = Modifier.animateItem(), + modifier = Modifier.animateItemFastScroll(), item = item, onClickItem = { when (it) { diff --git a/app/src/main/java/eu/kanade/presentation/browse/SourcesFilterScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/SourcesFilterScreen.kt index 9f74c3799..2cfbb2c68 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/SourcesFilterScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/SourcesFilterScreen.kt @@ -10,6 +10,7 @@ import androidx.compose.ui.platform.LocalContext import eu.kanade.presentation.browse.components.BaseSourceItem import eu.kanade.presentation.components.AppBar import eu.kanade.presentation.more.settings.widget.SwitchPreferenceWidget +import eu.kanade.presentation.util.animateItemFastScroll import eu.kanade.tachiyomi.ui.browse.source.SourcesFilterScreenModel import eu.kanade.tachiyomi.util.system.LocaleHelper import tachiyomi.domain.source.model.Source @@ -68,7 +69,7 @@ private fun SourcesFilterContent( contentType = "source-filter-header", ) { SourcesFilterHeader( - modifier = Modifier.animateItem(), + modifier = Modifier.animateItemFastScroll(), language = language, enabled = enabled, onClickItem = onClickLanguage, @@ -81,7 +82,7 @@ private fun SourcesFilterContent( contentType = { "source-filter-item" }, ) { source -> SourcesFilterItem( - modifier = Modifier.animateItem(), + modifier = Modifier.animateItemFastScroll(), source = source, enabled = "${source.id}" !in state.disabledSources, onClickItem = onClickSource, diff --git a/app/src/main/java/eu/kanade/presentation/history/HistoryScreen.kt b/app/src/main/java/eu/kanade/presentation/history/HistoryScreen.kt index dba526b54..e1806237d 100644 --- a/app/src/main/java/eu/kanade/presentation/history/HistoryScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/history/HistoryScreen.kt @@ -18,6 +18,7 @@ import eu.kanade.presentation.components.SearchToolbar import eu.kanade.presentation.components.relativeDateText import eu.kanade.presentation.history.components.HistoryItem import eu.kanade.presentation.theme.TachiyomiPreviewTheme +import eu.kanade.presentation.util.animateItemFastScroll import eu.kanade.tachiyomi.ui.history.HistoryScreenModel import kotlinx.collections.immutable.persistentListOf import tachiyomi.domain.history.model.HistoryWithRelations @@ -113,14 +114,14 @@ private fun HistoryScreenContent( when (item) { is HistoryUiModel.Header -> { ListGroupHeader( - modifier = Modifier.animateItem(), + modifier = Modifier.animateItemFastScroll(), text = relativeDateText(item.date), ) } is HistoryUiModel.Item -> { val value = item.item HistoryItem( - modifier = Modifier.animateItem(), + modifier = Modifier.animateItemFastScroll(), history = value, onClickCover = { onClickCover(value) }, onClickResume = { onClickResume(value) }, diff --git a/app/src/main/java/eu/kanade/presentation/updates/UpdatesUiItem.kt b/app/src/main/java/eu/kanade/presentation/updates/UpdatesUiItem.kt index 9f5c92479..e0e60d4fb 100644 --- a/app/src/main/java/eu/kanade/presentation/updates/UpdatesUiItem.kt +++ b/app/src/main/java/eu/kanade/presentation/updates/UpdatesUiItem.kt @@ -37,6 +37,7 @@ import eu.kanade.presentation.manga.components.ChapterDownloadAction import eu.kanade.presentation.manga.components.ChapterDownloadIndicator import eu.kanade.presentation.manga.components.DotSeparatorText import eu.kanade.presentation.manga.components.MangaCover +import eu.kanade.presentation.util.animateItemFastScroll import eu.kanade.presentation.util.relativeTimeSpanString import eu.kanade.tachiyomi.data.download.model.Download import eu.kanade.tachiyomi.ui.updates.UpdatesItem @@ -54,7 +55,7 @@ internal fun LazyListScope.updatesLastUpdatedItem( item(key = "updates-lastUpdated") { Box( modifier = Modifier - .animateItem() + .animateItem(fadeInSpec = null, fadeOutSpec = null) .padding(horizontal = MaterialTheme.padding.medium, vertical = MaterialTheme.padding.small), ) { Text( @@ -91,14 +92,14 @@ internal fun LazyListScope.updatesUiItems( when (item) { is UpdatesUiModel.Header -> { ListGroupHeader( - modifier = Modifier.animateItem(), + modifier = Modifier.animateItemFastScroll(), text = relativeDateText(item.date), ) } is UpdatesUiModel.Item -> { val updatesItem = item.item UpdatesUiItem( - modifier = Modifier.animateItem(), + modifier = Modifier.animateItemFastScroll(), update = updatesItem.update, selected = updatesItem.selected, readProgress = updatesItem.update.lastPageRead diff --git a/app/src/main/java/eu/kanade/presentation/util/FastScrollAnimateItem.kt b/app/src/main/java/eu/kanade/presentation/util/FastScrollAnimateItem.kt new file mode 100644 index 000000000..a6c9f7019 --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/util/FastScrollAnimateItem.kt @@ -0,0 +1,8 @@ +package eu.kanade.presentation.util + +import androidx.compose.foundation.lazy.LazyItemScope +import androidx.compose.ui.Modifier + +// https://issuetracker.google.com/352584409 +context(LazyItemScope) +fun Modifier.animateItemFastScroll() = this.animateItem(fadeInSpec = null, fadeOutSpec = null) From 0af90999c8eed4b6c56a94418e5558833f273aa9 Mon Sep 17 00:00:00 2001 From: Roshan Varughese <40583749+Animeboynz@users.noreply.github.com> Date: Sat, 27 Jul 2024 08:59:59 +1200 Subject: [PATCH 114/297] Adds Option to Copy Panel to Clipboard (#1003) * Add Copy to Clipboard * Removing Unused Import * Reusing onShare function * Commit Suggestion * Early Return on null Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com> --------- Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com> --- .../presentation/reader/ReaderPageActionsDialog.kt | 14 ++++++++++++-- .../kanade/tachiyomi/ui/reader/ReaderActivity.kt | 12 ++++++++++++ .../kanade/tachiyomi/ui/reader/ReaderViewModel.kt | 5 +++-- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/reader/ReaderPageActionsDialog.kt b/app/src/main/java/eu/kanade/presentation/reader/ReaderPageActionsDialog.kt index b83e8d6ad..9e9afde8d 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/ReaderPageActionsDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/ReaderPageActionsDialog.kt @@ -4,6 +4,7 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.ContentCopy import androidx.compose.material.icons.outlined.Photo import androidx.compose.material.icons.outlined.Save import androidx.compose.material.icons.outlined.Share @@ -28,7 +29,7 @@ import tachiyomi.presentation.core.i18n.stringResource fun ReaderPageActionsDialog( onDismissRequest: () -> Unit, onSetAsCover: () -> Unit, - onShare: () -> Unit, + onShare: (Boolean) -> Unit, onSave: () -> Unit, ) { var showSetCoverDialog by remember { mutableStateOf(false) } @@ -44,12 +45,21 @@ fun ReaderPageActionsDialog( icon = Icons.Outlined.Photo, onClick = { showSetCoverDialog = true }, ) + ActionButton( + modifier = Modifier.weight(1f), + title = stringResource(MR.strings.action_copy_to_clipboard), + icon = Icons.Outlined.ContentCopy, + onClick = { + onShare(true) + onDismissRequest() + }, + ) ActionButton( modifier = Modifier.weight(1f), title = stringResource(MR.strings.action_share), icon = Icons.Outlined.Share, onClick = { - onShare() + onShare(false) onDismissRequest() }, ) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt index ae471a025..1a177e211 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt @@ -3,6 +3,8 @@ package eu.kanade.tachiyomi.ui.reader import android.annotation.SuppressLint import android.app.Activity import android.app.assist.AssistContent +import android.content.ClipData +import android.content.ClipboardManager import android.content.Context import android.content.Intent import android.graphics.Color @@ -28,6 +30,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.unit.dp +import androidx.core.content.getSystemService import androidx.core.graphics.ColorUtils import androidx.core.net.toUri import androidx.core.transition.doOnEnd @@ -223,6 +226,9 @@ class ReaderActivity : BaseActivity() { is ReaderViewModel.Event.ShareImage -> { onShareImageResult(event.uri, event.page) } + is ReaderViewModel.Event.CopyImage -> { + onCopyImageResult(event.uri) + } is ReaderViewModel.Event.SetCoverResult -> { onSetAsCoverResult(event.result) } @@ -721,6 +727,12 @@ class ReaderActivity : BaseActivity() { startActivity(Intent.createChooser(intent, stringResource(MR.strings.action_share))) } + private fun onCopyImageResult(uri: Uri) { + val clipboardManager = applicationContext.getSystemService() ?: return + val clipData = ClipData.newUri(applicationContext.contentResolver, "", uri) + clipboardManager.setPrimaryClip(clipData) + } + /** * Called from the presenter when a page is saved or fails. It shows a message or logs the * event depending on the [result]. diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt index 432eff749..259b45883 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt @@ -809,7 +809,7 @@ class ReaderViewModel @JvmOverloads constructor( * get a path to the file and it has to be decompressed somewhere first. Only the last shared * image will be kept so it won't be taking lots of internal disk space. */ - fun shareImage() { + fun shareImage(copyToClipboard: Boolean) { val page = (state.value.dialog as? Dialog.PageActions)?.page if (page?.status != Page.State.READY) return val manga = manga ?: return @@ -829,7 +829,7 @@ class ReaderViewModel @JvmOverloads constructor( location = Location.Cache, ), ) - eventChannel.send(Event.ShareImage(uri, page)) + eventChannel.send(if (copyToClipboard) Event.CopyImage(uri) else Event.ShareImage(uri, page)) } } catch (e: Throwable) { logcat(LogPriority.ERROR, e) @@ -949,5 +949,6 @@ class ReaderViewModel @JvmOverloads constructor( data class SavedImage(val result: SaveImageResult) : Event data class ShareImage(val uri: Uri, val page: ReaderPage) : Event + data class CopyImage(val uri: Uri) : Event } } From 56fb4f62a152e87a71892aa68c78cac51a2c8596 Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Tue, 30 Jul 2024 04:47:57 +0600 Subject: [PATCH 115/297] Fix library is backed up when disabled and make categories backup/restore independent --- .../screen/data/CreateBackupScreen.kt | 5 ++-- .../screen/data/RestoreBackupScreen.kt | 2 +- .../data/backup/create/BackupCreator.kt | 10 ++++---- .../data/backup/create/BackupOptions.kt | 13 +++++----- .../create/creators/SourcesBackupCreator.kt | 6 ++--- .../data/backup/restore/BackupRestorer.kt | 13 ++++++---- .../data/backup/restore/RestoreOptions.kt | 24 ++++++++++++------- 7 files changed, 42 insertions(+), 31 deletions(-) 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 a45fd374e..fdadafb43 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 @@ -6,7 +6,6 @@ import android.content.Intent import android.net.Uri import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts -import androidx.compose.foundation.layout.ColumnScope import androidx.compose.runtime.Composable import androidx.compose.runtime.Immutable import androidx.compose.runtime.collectAsState @@ -68,7 +67,7 @@ class CreateBackupScreen : Screen() { LazyColumnWithAction( contentPadding = contentPadding, actionLabel = stringResource(MR.strings.action_create), - actionEnabled = state.options.anyEnabled(), + actionEnabled = state.options.canCreate(), onClickAction = { if (!BackupCreateJob.isManualJobRunning(context)) { try { @@ -103,7 +102,7 @@ class CreateBackupScreen : Screen() { } @Composable - private fun ColumnScope.Options( + private fun Options( options: ImmutableList, state: CreateBackupScreenModel.State, model: CreateBackupScreenModel, diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/RestoreBackupScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/RestoreBackupScreen.kt index 1e5e36169..489ff96b4 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/RestoreBackupScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/RestoreBackupScreen.kt @@ -63,7 +63,7 @@ class RestoreBackupScreen( LazyColumnWithAction( contentPadding = contentPadding, actionLabel = stringResource(MR.strings.action_restore), - actionEnabled = state.canRestore && state.options.anyEnabled(), + actionEnabled = state.canRestore && state.options.canRestore(), onClickAction = { model.startRestore() navigator.pop() diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreator.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreator.kt index 42c97ca9c..406e3bac0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreator.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreator.kt @@ -74,11 +74,11 @@ class BackupCreator( throw IllegalStateException(context.stringResource(MR.strings.create_backup_file_error)) } - val databaseManga = getFavorites.await() + val backupManga = backupMangas(getFavorites.await(), options) val backup = Backup( - backupManga = backupMangas(databaseManga, options), + backupManga = backupManga, backupCategories = backupCategories(options), - backupSources = backupSources(databaseManga), + backupSources = backupSources(backupManga), backupPreferences = backupAppPreferences(options), backupSourcePreferences = backupSourcePreferences(options), ) @@ -120,10 +120,12 @@ class BackupCreator( } private suspend fun backupMangas(mangas: List, options: BackupOptions): List { + if (!options.libraryEntries) return emptyList() + return mangaBackupCreator.backupMangas(mangas, options) } - private fun backupSources(mangas: List): List { + private fun backupSources(mangas: List): List { return sourcesBackupCreator.backupSources(mangas) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupOptions.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupOptions.kt index 868458b8a..7130c25cf 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupOptions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupOptions.kt @@ -26,7 +26,7 @@ data class BackupOptions( privateSettings, ) - fun anyEnabled() = libraryEntries || appSettings || sourceSettings + fun canCreate() = libraryEntries || categories || appSettings || sourceSettings companion object { val libraryOptions = persistentListOf( @@ -35,12 +35,6 @@ data class BackupOptions( getter = BackupOptions::libraryEntries, setter = { options, enabled -> options.copy(libraryEntries = enabled) }, ), - Entry( - label = MR.strings.categories, - getter = BackupOptions::categories, - setter = { options, enabled -> options.copy(categories = enabled) }, - enabled = { it.libraryEntries }, - ), Entry( label = MR.strings.chapters, getter = BackupOptions::chapters, @@ -59,6 +53,11 @@ data class BackupOptions( setter = { options, enabled -> options.copy(history = enabled) }, enabled = { it.libraryEntries }, ), + Entry( + label = MR.strings.categories, + getter = BackupOptions::categories, + setter = { options, enabled -> options.copy(categories = enabled) }, + ), ) val settingsOptions = persistentListOf( diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/SourcesBackupCreator.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/SourcesBackupCreator.kt index 075e449a7..0052c2c93 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/SourcesBackupCreator.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/SourcesBackupCreator.kt @@ -1,8 +1,8 @@ package eu.kanade.tachiyomi.data.backup.create.creators +import eu.kanade.tachiyomi.data.backup.models.BackupManga import eu.kanade.tachiyomi.data.backup.models.BackupSource import eu.kanade.tachiyomi.source.Source -import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.source.service.SourceManager import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get @@ -11,10 +11,10 @@ class SourcesBackupCreator( private val sourceManager: SourceManager = Injekt.get(), ) { - fun backupSources(mangas: List): List { + fun backupSources(mangas: List): List { return mangas .asSequence() - .map(Manga::source) + .map(BackupManga::source) .distinct() .map(sourceManager::getOrStub) .map { it.toBackupSource() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestorer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestorer.kt index a17d33f43..1c5a3a2d2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestorer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestorer.kt @@ -67,8 +67,11 @@ class BackupRestorer( val backupMaps = backup.backupSources + backup.backupBrokenSources.map { it.toBackupSource() } sourceMapping = backupMaps.associate { it.sourceId to it.name } - if (options.library) { - restoreAmount += backup.backupManga.size + 1 // +1 for categories + if (options.libraryEntries) { + restoreAmount += backup.backupManga.size + } + if (options.categories) { + restoreAmount += 1 } if (options.appSettings) { restoreAmount += 1 @@ -78,7 +81,7 @@ class BackupRestorer( } coroutineScope { - if (options.library) { + if (options.categories) { restoreCategories(backup.backupCategories) } if (options.appSettings) { @@ -87,8 +90,8 @@ class BackupRestorer( if (options.sourceSettings) { restoreSourcePreferences(backup.backupSourcePreferences) } - if (options.library) { - restoreManga(backup.backupManga, backup.backupCategories) + if (options.libraryEntries) { + restoreManga(backup.backupManga, if (options.categories) backup.backupCategories else emptyList()) } // TODO: optionally trigger online library + tracker update diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/RestoreOptions.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/RestoreOptions.kt index c824cb3d4..30c34200d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/RestoreOptions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/RestoreOptions.kt @@ -5,25 +5,32 @@ import kotlinx.collections.immutable.persistentListOf import tachiyomi.i18n.MR data class RestoreOptions( - val library: Boolean = true, + val libraryEntries: Boolean = true, + val categories: Boolean = true, val appSettings: Boolean = true, val sourceSettings: Boolean = true, ) { fun asBooleanArray() = booleanArrayOf( - library, + libraryEntries, + categories, appSettings, sourceSettings, ) - fun anyEnabled() = library || appSettings || sourceSettings + fun canRestore() = libraryEntries || categories || appSettings || sourceSettings companion object { val options = persistentListOf( Entry( label = MR.strings.label_library, - getter = RestoreOptions::library, - setter = { options, enabled -> options.copy(library = enabled) }, + getter = RestoreOptions::libraryEntries, + setter = { options, enabled -> options.copy(libraryEntries = enabled) }, + ), + Entry( + label = MR.strings.categories, + getter = RestoreOptions::categories, + setter = { options, enabled -> options.copy(categories = enabled) }, ), Entry( label = MR.strings.app_settings, @@ -38,9 +45,10 @@ data class RestoreOptions( ) fun fromBooleanArray(array: BooleanArray) = RestoreOptions( - library = array[0], - appSettings = array[1], - sourceSettings = array[2], + libraryEntries = array[0], + categories = array[1], + appSettings = array[2], + sourceSettings = array[3], ) } From c201b341a716b90d378dcda4bd9b8ac4a343d4fc Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Tue, 30 Jul 2024 04:59:16 +0600 Subject: [PATCH 116/297] Cleanup backup/restore related code --- .../data/backup/create/BackupCreator.kt | 40 +++++++++---------- .../creators/CategoriesBackupCreator.kt | 2 +- .../create/creators/MangaBackupCreator.kt | 2 +- .../creators/PreferenceBackupCreator.kt | 4 +- .../create/creators/SourcesBackupCreator.kt | 2 +- .../data/backup/restore/BackupRestorer.kt | 8 ++-- .../restore/restorers/CategoriesRestorer.kt | 2 +- .../backup/restore/restorers/MangaRestorer.kt | 2 +- .../restore/restorers/PreferenceRestorer.kt | 4 +- 9 files changed, 32 insertions(+), 34 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreator.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreator.kt index 406e3bac0..3c12cecfe 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreator.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreator.kt @@ -51,24 +51,22 @@ class BackupCreator( suspend fun backup(uri: Uri, options: BackupOptions): String { var file: UniFile? = null try { - file = ( - if (isAutoBackup) { - // Get dir of file and create - val dir = UniFile.fromUri(context, uri) + file = if (isAutoBackup) { + // Get dir of file and create + val dir = UniFile.fromUri(context, uri) - // Delete older backups - dir?.listFiles { _, filename -> FILENAME_REGEX.matches(filename) } - .orEmpty() - .sortedByDescending { it.name } - .drop(MAX_AUTO_BACKUPS - 1) - .forEach { it.delete() } + // Delete older backups + dir?.listFiles { _, filename -> FILENAME_REGEX.matches(filename) } + .orEmpty() + .sortedByDescending { it.name } + .drop(MAX_AUTO_BACKUPS - 1) + .forEach { it.delete() } - // Create new file to place backup - dir?.createFile(getFilename()) - } else { - UniFile.fromUri(context, uri) - } - ) + // Create new file to place backup + dir?.createFile(getFilename()) + } else { + UniFile.fromUri(context, uri) + } if (file == null || !file.isFile) { throw IllegalStateException(context.stringResource(MR.strings.create_backup_file_error)) @@ -116,29 +114,29 @@ class BackupCreator( private suspend fun backupCategories(options: BackupOptions): List { if (!options.categories) return emptyList() - return categoriesBackupCreator.backupCategories() + return categoriesBackupCreator() } private suspend fun backupMangas(mangas: List, options: BackupOptions): List { if (!options.libraryEntries) return emptyList() - return mangaBackupCreator.backupMangas(mangas, options) + return mangaBackupCreator(mangas, options) } private fun backupSources(mangas: List): List { - return sourcesBackupCreator.backupSources(mangas) + return sourcesBackupCreator(mangas) } private fun backupAppPreferences(options: BackupOptions): List { if (!options.appSettings) return emptyList() - return preferenceBackupCreator.backupAppPreferences(includePrivatePreferences = options.privateSettings) + return preferenceBackupCreator.createApp(includePrivatePreferences = options.privateSettings) } private fun backupSourcePreferences(options: BackupOptions): List { if (!options.sourceSettings) return emptyList() - return preferenceBackupCreator.backupSourcePreferences(includePrivatePreferences = options.privateSettings) + return preferenceBackupCreator.createSource(includePrivatePreferences = options.privateSettings) } companion object { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/CategoriesBackupCreator.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/CategoriesBackupCreator.kt index e1ed56ee1..945f32d86 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/CategoriesBackupCreator.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/CategoriesBackupCreator.kt @@ -11,7 +11,7 @@ class CategoriesBackupCreator( private val getCategories: GetCategories = Injekt.get(), ) { - suspend fun backupCategories(): List { + suspend operator fun invoke(): List { return getCategories.await() .filterNot(Category::isSystemCategory) .map(backupCategoryMapper) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/MangaBackupCreator.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/MangaBackupCreator.kt index fd10293a9..040de931b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/MangaBackupCreator.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/MangaBackupCreator.kt @@ -20,7 +20,7 @@ class MangaBackupCreator( private val getHistory: GetHistory = Injekt.get(), ) { - suspend fun backupMangas(mangas: List, options: BackupOptions): List { + suspend operator fun invoke(mangas: List, options: BackupOptions): List { return mangas.map { backupManga(it, options) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/PreferenceBackupCreator.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/PreferenceBackupCreator.kt index d14cef230..5b72ce384 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/PreferenceBackupCreator.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/PreferenceBackupCreator.kt @@ -22,12 +22,12 @@ class PreferenceBackupCreator( private val preferenceStore: PreferenceStore = Injekt.get(), ) { - fun backupAppPreferences(includePrivatePreferences: Boolean): List { + fun createApp(includePrivatePreferences: Boolean): List { return preferenceStore.getAll().toBackupPreferences() .withPrivatePreferences(includePrivatePreferences) } - fun backupSourcePreferences(includePrivatePreferences: Boolean): List { + fun createSource(includePrivatePreferences: Boolean): List { return sourceManager.getCatalogueSources() .filterIsInstance() .map { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/SourcesBackupCreator.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/SourcesBackupCreator.kt index 0052c2c93..d3bc573a7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/SourcesBackupCreator.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/SourcesBackupCreator.kt @@ -11,7 +11,7 @@ class SourcesBackupCreator( private val sourceManager: SourceManager = Injekt.get(), ) { - fun backupSources(mangas: List): List { + operator fun invoke(mangas: List): List { return mangas .asSequence() .map(BackupManga::source) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestorer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestorer.kt index 1c5a3a2d2..4d56e925b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestorer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestorer.kt @@ -100,7 +100,7 @@ class BackupRestorer( private fun CoroutineScope.restoreCategories(backupCategories: List) = launch { ensureActive() - categoriesRestorer.restoreCategories(backupCategories) + categoriesRestorer(backupCategories) restoreProgress += 1 notifier.showRestoreProgress( @@ -120,7 +120,7 @@ class BackupRestorer( ensureActive() try { - mangaRestorer.restoreManga(it, backupCategories) + mangaRestorer.restore(it, backupCategories) } catch (e: Exception) { val sourceName = sourceMapping[it.source] ?: it.source.toString() errors.add(Date() to "${it.title} [$sourceName]: ${e.message}") @@ -133,7 +133,7 @@ class BackupRestorer( private fun CoroutineScope.restoreAppPreferences(preferences: List) = launch { ensureActive() - preferenceRestorer.restoreAppPreferences(preferences) + preferenceRestorer.restoreApp(preferences) restoreProgress += 1 notifier.showRestoreProgress( @@ -146,7 +146,7 @@ class BackupRestorer( private fun CoroutineScope.restoreSourcePreferences(preferences: List) = launch { ensureActive() - preferenceRestorer.restoreSourcePreferences(preferences) + preferenceRestorer.restoreSource(preferences) restoreProgress += 1 notifier.showRestoreProgress( diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/CategoriesRestorer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/CategoriesRestorer.kt index 23a2d47fa..15080f8ee 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/CategoriesRestorer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/CategoriesRestorer.kt @@ -13,7 +13,7 @@ class CategoriesRestorer( private val libraryPreferences: LibraryPreferences = Injekt.get(), ) { - suspend fun restoreCategories(backupCategories: List) { + suspend operator fun invoke(backupCategories: List) { if (backupCategories.isNotEmpty()) { val dbCategories = getCategories.await() val dbCategoriesByName = dbCategories.associateBy { it.name } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/MangaRestorer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/MangaRestorer.kt index b0c86e2ab..38d15bad1 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/MangaRestorer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/MangaRestorer.kt @@ -53,7 +53,7 @@ class MangaRestorer( ) } - suspend fun restoreManga( + suspend fun restore( backupManga: BackupManga, backupCategories: List, ) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/PreferenceRestorer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/PreferenceRestorer.kt index 4871e3949..b70280c55 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/PreferenceRestorer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/PreferenceRestorer.kt @@ -22,14 +22,14 @@ class PreferenceRestorer( private val preferenceStore: PreferenceStore = Injekt.get(), ) { - fun restoreAppPreferences(preferences: List) { + fun restoreApp(preferences: List) { restorePreferences(preferences, preferenceStore) LibraryUpdateJob.setupTask(context) BackupCreateJob.setupTask(context) } - fun restoreSourcePreferences(preferences: List) { + fun restoreSource(preferences: List) { preferences.forEach { val sourcePrefs = AndroidPreferenceStore(context, sourcePreferences(it.sourceKey)) restorePreferences(it.prefs, sourcePrefs) From 8160b47ff5fbbd9b32caeb462b5be881fabd3449 Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Tue, 30 Jul 2024 21:09:56 +0600 Subject: [PATCH 117/297] Bump default user agent string --- .../kotlin/eu/kanade/tachiyomi/network/NetworkPreferences.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/common/src/main/kotlin/eu/kanade/tachiyomi/network/NetworkPreferences.kt b/core/common/src/main/kotlin/eu/kanade/tachiyomi/network/NetworkPreferences.kt index c32864aec..23b02e315 100644 --- a/core/common/src/main/kotlin/eu/kanade/tachiyomi/network/NetworkPreferences.kt +++ b/core/common/src/main/kotlin/eu/kanade/tachiyomi/network/NetworkPreferences.kt @@ -19,7 +19,7 @@ class NetworkPreferences( fun defaultUserAgent(): Preference { return preferenceStore.getString( "default_user_agent", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:123.0) Gecko/20100101 Firefox/123.0", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0", ) } } From de8ef6dad7c89afb7041ccb489d68539a4849cb5 Mon Sep 17 00:00:00 2001 From: Vetle Ledaal Date: Wed, 31 Jul 2024 16:39:41 +0200 Subject: [PATCH 118/297] Improve error message if restoring from JSON file (#1056) * Improve error message if restoring from JSON file * Replace Exception with IOException * Use more generic error message if protobuf fails * fix lint --- .../tachiyomi/data/backup/BackupDecoder.kt | 27 ++++++++++++++----- .../moko-resources/base/strings.xml | 2 ++ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupDecoder.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupDecoder.kt index 34f862548..55553082f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupDecoder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupDecoder.kt @@ -3,18 +3,21 @@ package eu.kanade.tachiyomi.data.backup import android.content.Context import android.net.Uri import eu.kanade.tachiyomi.data.backup.models.Backup +import kotlinx.serialization.SerializationException import kotlinx.serialization.protobuf.ProtoBuf import okio.buffer import okio.gzip import okio.source +import tachiyomi.core.common.i18n.stringResource +import tachiyomi.i18n.MR import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get +import java.io.IOException class BackupDecoder( private val context: Context, private val parser: ProtoBuf = Injekt.get(), ) { - /** * Decode a potentially-gzipped backup. */ @@ -26,13 +29,25 @@ class BackupDecoder( require(2) } val id1id2 = peeked.readShort() - val backupString = if (id1id2.toInt() == 0x1f8b) { // 0x1f8b is gzip magic bytes - source.gzip().buffer() - } else { - source + val backupString = when (id1id2.toInt()) { + 0x1f8b -> source.gzip().buffer() // 0x1f8b is gzip magic bytes + MAGIC_JSON_SIGNATURE1, MAGIC_JSON_SIGNATURE2, MAGIC_JSON_SIGNATURE3 -> { + throw IOException(context.stringResource(MR.strings.invalid_backup_file_json)) + } + else -> source }.use { it.readByteArray() } - parser.decodeFromByteArray(Backup.serializer(), backupString) + try { + parser.decodeFromByteArray(Backup.serializer(), backupString) + } catch (_: SerializationException) { + throw IOException(context.stringResource(MR.strings.invalid_backup_file_unknown)) + } } } + + companion object { + private const val MAGIC_JSON_SIGNATURE1 = 0x7b7d // `{}` + private const val MAGIC_JSON_SIGNATURE2 = 0x7b22 // `{"` + private const val MAGIC_JSON_SIGNATURE3 = 0x7b0a // `{\n` + } } diff --git a/i18n/src/commonMain/moko-resources/base/strings.xml b/i18n/src/commonMain/moko-resources/base/strings.xml index 08bbe2d76..73f7d4a6e 100644 --- a/i18n/src/commonMain/moko-resources/base/strings.xml +++ b/i18n/src/commonMain/moko-resources/base/strings.xml @@ -518,6 +518,8 @@ Invalid backup file: Full error: Backup does not contain any library entries. + JSON backup not supported + Backup file is corrupted Missing sources: Trackers not logged into: You may need to install any missing extensions and log in to tracking services afterwards to use them. From a3dfd2efe6ace7a2a4d79bd09fb1a729989f1094 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Sun, 4 Aug 2024 23:45:11 +0800 Subject: [PATCH 119/297] Match extra layout space with scroll distance (#1076) And increase recycler item view cache size. --- .../reader/viewer/webtoon/WebtoonLayoutManager.kt | 8 ++------ .../ui/reader/viewer/webtoon/WebtoonViewer.kt | 15 +++++++++------ 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonLayoutManager.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonLayoutManager.kt index 852cd76e1..1948bcdf1 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonLayoutManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonLayoutManager.kt @@ -13,12 +13,7 @@ import androidx.recyclerview.widget.RecyclerView.NO_POSITION * This layout manager uses the same package name as the support library in order to use a package * protected method. */ -class WebtoonLayoutManager(context: Context) : LinearLayoutManager(context) { - - /** - * Extra layout space is set to half the screen height. - */ - private val extraLayoutSpace = context.resources.displayMetrics.heightPixels / 2 +class WebtoonLayoutManager(context: Context, private val extraLayoutSpace: Int) : LinearLayoutManager(context) { init { isItemPrefetchEnabled = false @@ -27,6 +22,7 @@ class WebtoonLayoutManager(context: Context) : LinearLayoutManager(context) { /** * Returns the custom extra layout space. */ + @Deprecated("Deprecated in Java") override fun getExtraLayoutSpace(state: RecyclerView.State): Int { return extraLayoutSpace } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt index a965631fc..ce1710cf0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt @@ -47,10 +47,15 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr */ private val frame = WebtoonFrame(activity) + /** + * Distance to scroll when the user taps on one side of the recycler view. + */ + private val scrollDistance = activity.resources.displayMetrics.heightPixels * 3 / 4 + /** * Layout manager of the recycler view. */ - private val layoutManager = WebtoonLayoutManager(activity) + private val layoutManager = WebtoonLayoutManager(activity, scrollDistance) /** * Configuration used by this viewer, like allow taps, or crop image borders. @@ -62,11 +67,6 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr */ private val adapter = WebtoonAdapter(this) - /** - * Distance to scroll when the user taps on one side of the recycler view. - */ - private var scrollDistance = activity.resources.displayMetrics.heightPixels * 3 / 4 - /** * Currently active item. It can be a chapter page or a chapter transition. */ @@ -79,6 +79,7 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr .threshold init { + recycler.setItemViewCacheSize(RecyclerViewCacheSize) recycler.isVisible = false // Don't let the recycler layout yet recycler.layoutParams = ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT) recycler.isFocusable = false @@ -359,3 +360,5 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr ) } } + +private const val RecyclerViewCacheSize = 4 From 3f6bd5f010532d292310c0c0f14bf11832277f2e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 6 Aug 2024 20:38:13 +0600 Subject: [PATCH 120/297] chore(deps): update actions/setup-java action to v4.2.2 (#1080) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/build_pull_request.yml | 2 +- .github/workflows/build_push.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_pull_request.yml b/.github/workflows/build_pull_request.yml index 98907b52f..cfca98a2a 100644 --- a/.github/workflows/build_pull_request.yml +++ b/.github/workflows/build_pull_request.yml @@ -29,7 +29,7 @@ jobs: uses: actions/dependency-review-action@5a2ce3f5b92ee19cbb1541a4984c76d921601d7c # v4.3.4 - name: Set up JDK - uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9 # v4.2.1 + uses: actions/setup-java@6a0805fcefea3d4657a47ac4c165951e33482018 # v4.2.2 with: java-version: 17 distribution: adopt diff --git a/.github/workflows/build_push.yml b/.github/workflows/build_push.yml index bbabee9c5..0c187ca33 100644 --- a/.github/workflows/build_push.yml +++ b/.github/workflows/build_push.yml @@ -27,7 +27,7 @@ jobs: ${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager "build-tools;29.0.3" - name: Set up JDK - uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9 # v4.2.1 + uses: actions/setup-java@6a0805fcefea3d4657a47ac4c165951e33482018 # v4.2.2 with: java-version: 17 distribution: adopt From 04db46fe75c2406fe9750e97da65774a6b268f27 Mon Sep 17 00:00:00 2001 From: "Tran M. Cuong" Date: Tue, 6 Aug 2024 21:38:56 +0700 Subject: [PATCH 121/297] fix: drawScrollbar crash on list with 0 item but only sticky header (#1083) --- .../main/java/tachiyomi/presentation/core/util/Scrollbar.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/util/Scrollbar.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/util/Scrollbar.kt index e0cd0a3e0..40bcb70b0 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/util/Scrollbar.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/util/Scrollbar.kt @@ -119,15 +119,15 @@ private fun Modifier.drawScrollbar( 0f } else { items - .fastFirstOrNull { (it.key as? String)?.startsWith(STICKY_HEADER_KEY_PREFIX)?.not() ?: true }!! - .run { + .fastFirstOrNull { (it.key as? String)?.startsWith(STICKY_HEADER_KEY_PREFIX)?.not() ?: true } + ?.run { val startPadding = if (reverseDirection) { layoutInfo.afterContentPadding } else { layoutInfo.beforeContentPadding } startPadding + ((estimatedItemSize * index - offset) / totalSize * viewportSize) - } + } ?: 0f } val drawScrollbar = onDrawScrollbar( orientation, reverseDirection, atEnd, showScrollbar, From 854474f85ffc41eccdc2b3a6cf105fa2805ebc3c Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Tue, 6 Aug 2024 22:39:49 +0800 Subject: [PATCH 122/297] Don't crash on ill-formed URLs (#1084) --- .../eu/kanade/tachiyomi/ui/webview/WebViewScreenModel.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/webview/WebViewScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/webview/WebViewScreenModel.kt index 331d62b59..833806db8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/webview/WebViewScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/webview/WebViewScreenModel.kt @@ -10,7 +10,7 @@ import eu.kanade.tachiyomi.util.system.openInBrowser import eu.kanade.tachiyomi.util.system.toShareIntent import eu.kanade.tachiyomi.util.system.toast import logcat.LogPriority -import okhttp3.HttpUrl.Companion.toHttpUrl +import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import tachiyomi.core.common.util.system.logcat import tachiyomi.domain.source.service.SourceManager import uy.kohesive.injekt.Injekt @@ -47,7 +47,9 @@ class WebViewScreenModel( } fun clearCookies(url: String) { - val cleared = network.cookieJar.remove(url.toHttpUrl()) - logcat { "Cleared $cleared cookies for: $url" } + url.toHttpUrlOrNull()?.let { + val cleared = network.cookieJar.remove(it) + logcat { "Cleared $cleared cookies for: $url" } + } } } From edb8201f74e516c296b62e04a13802e1bd9e0b6b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 6 Aug 2024 20:41:28 +0600 Subject: [PATCH 123/297] chore(deps): update kotlin monorepo to v2.0.10 (#1085) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/kotlinx.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/kotlinx.versions.toml b/gradle/kotlinx.versions.toml index 03b23177d..a9b03bcfd 100644 --- a/gradle/kotlinx.versions.toml +++ b/gradle/kotlinx.versions.toml @@ -1,5 +1,5 @@ [versions] -kotlin_version = "2.0.0" +kotlin_version = "2.0.10" serialization_version = "1.7.1" xml_serialization_version = "0.86.3" From 2858ef835fec8d7278b1d0cad1b5664104d1e4b0 Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Wed, 7 Aug 2024 12:02:49 +0600 Subject: [PATCH 124/297] Rename backup restore error log file --- .../eu/kanade/tachiyomi/data/backup/restore/BackupRestorer.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestorer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestorer.kt index 4d56e925b..29dc04533 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestorer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestorer.kt @@ -160,7 +160,7 @@ class BackupRestorer( private fun writeErrorLog(): File { try { if (errors.isNotEmpty()) { - val file = context.createFileInCacheDir("tachiyomi_restore.txt") + val file = context.createFileInCacheDir("mihon_restore_error.txt") val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.getDefault()) file.bufferedWriter().use { out -> From 31263084eca3ba98624d258a317d53094bba2256 Mon Sep 17 00:00:00 2001 From: Roshan Varughese <40583749+Animeboynz@users.noreply.github.com> Date: Wed, 7 Aug 2024 19:49:17 +1200 Subject: [PATCH 125/297] Add Backup and Restore of Extension Repos (#1057) * Backup/Restore Extension Repos * Refactor * Moving to Under App Settings * Sort by URL, Check existing by SHA and Error Logging Untested. Currently in a lecture and can't test if the changes really work. * Changes to logic * Don't ask me what's happening here * Renaming Variables * Fixing restoreAmount & changes to logic Co-Authored-By: AntsyLich <59261191+AntsyLich@users.noreply.github.com> --------- Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com> --- .../data/backup/create/BackupCreator.kt | 10 +++++ .../data/backup/create/BackupOptions.kt | 14 +++++-- .../creators/ExtensionRepoBackupCreator.kt | 17 ++++++++ .../tachiyomi/data/backup/models/Backup.kt | 2 + .../backup/models/BackupExtensionRepos.kt | 25 ++++++++++++ .../data/backup/restore/BackupRestorer.kt | 32 +++++++++++++++ .../data/backup/restore/RestoreOptions.kt | 16 ++++++-- .../restorers/ExtensionRepoRestorer.kt | 40 +++++++++++++++++++ .../moko-resources/base/strings.xml | 1 + 9 files changed, 150 insertions(+), 7 deletions(-) create mode 100644 app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/ExtensionRepoBackupCreator.kt create mode 100644 app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupExtensionRepos.kt create mode 100644 app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/ExtensionRepoRestorer.kt diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreator.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreator.kt index 3c12cecfe..fa06f55bb 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreator.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreator.kt @@ -6,11 +6,13 @@ import com.hippo.unifile.UniFile import eu.kanade.tachiyomi.BuildConfig import eu.kanade.tachiyomi.data.backup.BackupFileValidator import eu.kanade.tachiyomi.data.backup.create.creators.CategoriesBackupCreator +import eu.kanade.tachiyomi.data.backup.create.creators.ExtensionRepoBackupCreator import eu.kanade.tachiyomi.data.backup.create.creators.MangaBackupCreator import eu.kanade.tachiyomi.data.backup.create.creators.PreferenceBackupCreator import eu.kanade.tachiyomi.data.backup.create.creators.SourcesBackupCreator import eu.kanade.tachiyomi.data.backup.models.Backup import eu.kanade.tachiyomi.data.backup.models.BackupCategory +import eu.kanade.tachiyomi.data.backup.models.BackupExtensionRepos import eu.kanade.tachiyomi.data.backup.models.BackupManga import eu.kanade.tachiyomi.data.backup.models.BackupPreference import eu.kanade.tachiyomi.data.backup.models.BackupSource @@ -45,6 +47,7 @@ class BackupCreator( private val categoriesBackupCreator: CategoriesBackupCreator = CategoriesBackupCreator(), private val mangaBackupCreator: MangaBackupCreator = MangaBackupCreator(), private val preferenceBackupCreator: PreferenceBackupCreator = PreferenceBackupCreator(), + private val extensionRepoBackupCreator: ExtensionRepoBackupCreator = ExtensionRepoBackupCreator(), private val sourcesBackupCreator: SourcesBackupCreator = SourcesBackupCreator(), ) { @@ -78,6 +81,7 @@ class BackupCreator( backupCategories = backupCategories(options), backupSources = backupSources(backupManga), backupPreferences = backupAppPreferences(options), + backupExtensionRepo = backupExtensionRepos(options), backupSourcePreferences = backupSourcePreferences(options), ) @@ -133,6 +137,12 @@ class BackupCreator( return preferenceBackupCreator.createApp(includePrivatePreferences = options.privateSettings) } + private suspend fun backupExtensionRepos(options: BackupOptions): List { + if (!options.extensionRepoSettings) return emptyList() + + return extensionRepoBackupCreator() + } + private fun backupSourcePreferences(options: BackupOptions): List { if (!options.sourceSettings) return emptyList() diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupOptions.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupOptions.kt index 7130c25cf..daaecff8e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupOptions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupOptions.kt @@ -11,6 +11,7 @@ data class BackupOptions( val tracking: Boolean = true, val history: Boolean = true, val appSettings: Boolean = true, + val extensionRepoSettings: Boolean = true, val sourceSettings: Boolean = true, val privateSettings: Boolean = false, ) { @@ -22,11 +23,12 @@ data class BackupOptions( tracking, history, appSettings, + extensionRepoSettings, sourceSettings, privateSettings, ) - fun canCreate() = libraryEntries || categories || appSettings || sourceSettings + fun canCreate() = libraryEntries || categories || appSettings || extensionRepoSettings || sourceSettings companion object { val libraryOptions = persistentListOf( @@ -66,6 +68,11 @@ data class BackupOptions( getter = BackupOptions::appSettings, setter = { options, enabled -> options.copy(appSettings = enabled) }, ), + Entry( + label = MR.strings.extensionRepo_settings, + getter = BackupOptions::extensionRepoSettings, + setter = { options, enabled -> options.copy(extensionRepoSettings = enabled) }, + ), Entry( label = MR.strings.source_settings, getter = BackupOptions::sourceSettings, @@ -86,8 +93,9 @@ data class BackupOptions( tracking = array[3], history = array[4], appSettings = array[5], - sourceSettings = array[6], - privateSettings = array[7], + extensionRepoSettings = array[6], + sourceSettings = array[7], + privateSettings = array[8], ) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/ExtensionRepoBackupCreator.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/ExtensionRepoBackupCreator.kt new file mode 100644 index 000000000..2db6a6f06 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/ExtensionRepoBackupCreator.kt @@ -0,0 +1,17 @@ +package eu.kanade.tachiyomi.data.backup.create.creators + +import eu.kanade.tachiyomi.data.backup.models.BackupExtensionRepos +import eu.kanade.tachiyomi.data.backup.models.backupExtensionReposMapper +import mihon.domain.extensionrepo.interactor.GetExtensionRepo +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get + +class ExtensionRepoBackupCreator( + private val getExtensionRepos: GetExtensionRepo = Injekt.get(), +) { + + suspend operator fun invoke(): List { + return getExtensionRepos.getAll() + .map(backupExtensionReposMapper) + } +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt index dcf3d1174..75c75b6b5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt @@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.data.backup.models import kotlinx.serialization.Serializable import kotlinx.serialization.protobuf.ProtoNumber +@Suppress("MagicNumber") @Serializable data class Backup( @ProtoNumber(1) val backupManga: List, @@ -11,4 +12,5 @@ data class Backup( @ProtoNumber(101) var backupSources: List = emptyList(), @ProtoNumber(104) var backupPreferences: List = emptyList(), @ProtoNumber(105) var backupSourcePreferences: List = emptyList(), + @ProtoNumber(106) var backupExtensionRepo: List = emptyList(), ) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupExtensionRepos.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupExtensionRepos.kt new file mode 100644 index 000000000..fa9968667 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupExtensionRepos.kt @@ -0,0 +1,25 @@ +package eu.kanade.tachiyomi.data.backup.models + +import kotlinx.serialization.Serializable +import kotlinx.serialization.protobuf.ProtoNumber +import mihon.domain.extensionrepo.model.ExtensionRepo + +@Suppress("MagicNumber") +@Serializable +class BackupExtensionRepos( + @ProtoNumber(1) var baseUrl: String, + @ProtoNumber(2) var name: String, + @ProtoNumber(3) var shortName: String?, + @ProtoNumber(4) var website: String, + @ProtoNumber(5) var signingKeyFingerprint: String, +) + +val backupExtensionReposMapper = { repo: ExtensionRepo -> + BackupExtensionRepos( + baseUrl = repo.baseUrl, + name = repo.name, + shortName = repo.shortName, + website = repo.website, + signingKeyFingerprint = repo.signingKeyFingerprint, + ) +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestorer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestorer.kt index 29dc04533..c4275f96f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestorer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestorer.kt @@ -5,10 +5,12 @@ import android.net.Uri import eu.kanade.tachiyomi.data.backup.BackupDecoder import eu.kanade.tachiyomi.data.backup.BackupNotifier import eu.kanade.tachiyomi.data.backup.models.BackupCategory +import eu.kanade.tachiyomi.data.backup.models.BackupExtensionRepos import eu.kanade.tachiyomi.data.backup.models.BackupManga import eu.kanade.tachiyomi.data.backup.models.BackupPreference import eu.kanade.tachiyomi.data.backup.models.BackupSourcePreferences import eu.kanade.tachiyomi.data.backup.restore.restorers.CategoriesRestorer +import eu.kanade.tachiyomi.data.backup.restore.restorers.ExtensionRepoRestorer import eu.kanade.tachiyomi.data.backup.restore.restorers.MangaRestorer import eu.kanade.tachiyomi.data.backup.restore.restorers.PreferenceRestorer import eu.kanade.tachiyomi.util.system.createFileInCacheDir @@ -30,6 +32,7 @@ class BackupRestorer( private val categoriesRestorer: CategoriesRestorer = CategoriesRestorer(), private val preferenceRestorer: PreferenceRestorer = PreferenceRestorer(context), + private val extensionRepoRestorer: ExtensionRepoRestorer = ExtensionRepoRestorer(), private val mangaRestorer: MangaRestorer = MangaRestorer(), ) { @@ -76,6 +79,9 @@ class BackupRestorer( if (options.appSettings) { restoreAmount += 1 } + if (options.extensionRepoSettings) { + restoreAmount += backup.backupExtensionRepo.size + } if (options.sourceSettings) { restoreAmount += 1 } @@ -93,6 +99,9 @@ class BackupRestorer( if (options.libraryEntries) { restoreManga(backup.backupManga, if (options.categories) backup.backupCategories else emptyList()) } + if (options.extensionRepoSettings) { + restoreExtensionRepos(backup.backupExtensionRepo) + } // TODO: optionally trigger online library + tracker update } @@ -157,6 +166,29 @@ class BackupRestorer( ) } + private fun CoroutineScope.restoreExtensionRepos( + backupExtensionRepo: List + ) = launch { + backupExtensionRepo + .forEach { + ensureActive() + + try { + extensionRepoRestorer(it) + } catch (e: Exception) { + errors.add(Date() to "Error Adding Repo: ${it.name} : ${e.message}") + } + + restoreProgress += 1 + notifier.showRestoreProgress( + context.stringResource(MR.strings.extensionRepo_settings), + restoreProgress, + restoreAmount, + isSync, + ) + } + } + private fun writeErrorLog(): File { try { if (errors.isNotEmpty()) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/RestoreOptions.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/RestoreOptions.kt index 30c34200d..933bf0568 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/RestoreOptions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/RestoreOptions.kt @@ -8,17 +8,19 @@ data class RestoreOptions( val libraryEntries: Boolean = true, val categories: Boolean = true, val appSettings: Boolean = true, - val sourceSettings: Boolean = true, + val extensionRepoSettings: Boolean = true, + val sourceSettings: Boolean = true ) { fun asBooleanArray() = booleanArrayOf( libraryEntries, categories, appSettings, - sourceSettings, + extensionRepoSettings, + sourceSettings ) - fun canRestore() = libraryEntries || categories || appSettings || sourceSettings + fun canRestore() = libraryEntries || categories || appSettings || extensionRepoSettings || sourceSettings companion object { val options = persistentListOf( @@ -37,6 +39,11 @@ data class RestoreOptions( getter = RestoreOptions::appSettings, setter = { options, enabled -> options.copy(appSettings = enabled) }, ), + Entry( + label = MR.strings.extensionRepo_settings, + getter = RestoreOptions::extensionRepoSettings, + setter = { options, enabled -> options.copy(extensionRepoSettings = enabled) }, + ), Entry( label = MR.strings.source_settings, getter = RestoreOptions::sourceSettings, @@ -48,7 +55,8 @@ data class RestoreOptions( libraryEntries = array[0], categories = array[1], appSettings = array[2], - sourceSettings = array[3], + extensionRepoSettings = array[3], + sourceSettings = array[4], ) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/ExtensionRepoRestorer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/ExtensionRepoRestorer.kt new file mode 100644 index 000000000..1dd0da491 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/ExtensionRepoRestorer.kt @@ -0,0 +1,40 @@ +package eu.kanade.tachiyomi.data.backup.restore.restorers + +import eu.kanade.tachiyomi.data.backup.models.BackupExtensionRepos +import mihon.domain.extensionrepo.interactor.GetExtensionRepo +import tachiyomi.data.DatabaseHandler +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get + +class ExtensionRepoRestorer( + private val handler: DatabaseHandler = Injekt.get(), + private val getExtensionRepos: GetExtensionRepo = Injekt.get() +) { + + suspend operator fun invoke( + backupRepo: BackupExtensionRepos, + ) { + val dbRepos = getExtensionRepos.getAll() + val existingReposBySHA = dbRepos.associateBy { it.signingKeyFingerprint } + val existingReposByUrl = dbRepos.associateBy { it.baseUrl } + + val urlExists = existingReposByUrl[backupRepo.baseUrl] + val shaExists = existingReposBySHA[backupRepo.signingKeyFingerprint] + + if (urlExists != null && urlExists.signingKeyFingerprint != backupRepo.signingKeyFingerprint) { + error("Already Exists with different signing key fingerprint") + } else if (shaExists != null) { + error("${shaExists.name} has the same signing key fingerprint") + } else { + handler.await { + extension_reposQueries.insert( + backupRepo.baseUrl, + backupRepo.name, + backupRepo.shortName, + backupRepo.website, + backupRepo.signingKeyFingerprint + ) + } + } + } +} diff --git a/i18n/src/commonMain/moko-resources/base/strings.xml b/i18n/src/commonMain/moko-resources/base/strings.xml index 73f7d4a6e..90719fb92 100644 --- a/i18n/src/commonMain/moko-resources/base/strings.xml +++ b/i18n/src/commonMain/moko-resources/base/strings.xml @@ -529,6 +529,7 @@ What do you want to backup? App settings Source settings + Extension Repos Include sensitive settings (e.g., tracker login tokens) Creating backup Backup failed From 1c16fc79c2ac4c4be30308fed84ffb371dab5902 Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Wed, 7 Aug 2024 14:30:39 +0600 Subject: [PATCH 126/297] ExpandableMangaDescription: Adjust size transform anim spec Co-authored-by: ivan <12537387+ivaniskandar@users.noreply.github.com> --- .../kanade/presentation/manga/components/MangaInfoHeader.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/eu/kanade/presentation/manga/components/MangaInfoHeader.kt b/app/src/main/java/eu/kanade/presentation/manga/components/MangaInfoHeader.kt index f1b660626..f65525646 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/components/MangaInfoHeader.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/components/MangaInfoHeader.kt @@ -2,6 +2,7 @@ package eu.kanade.presentation.manga.components import androidx.compose.animation.animateContentSize import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.animation.core.spring import androidx.compose.animation.graphics.res.animatedVectorResource import androidx.compose.animation.graphics.res.rememberAnimatedVectorPainter import androidx.compose.animation.graphics.vector.AnimatedImageVector @@ -271,7 +272,8 @@ fun ExpandableMangaDescription( modifier = Modifier .padding(top = 8.dp) .padding(vertical = 12.dp) - .animateContentSize(), + .animateContentSize(animationSpec = spring()) + .fillMaxWidth(), ) { var showMenu by remember { mutableStateOf(false) } var tagSelected by remember { mutableStateOf("") } From 8e40146f96704c3dc98bbb4f9f89d470ffa32f69 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 9 Aug 2024 01:44:48 +0600 Subject: [PATCH 127/297] fix(deps): update paging.version to v3.3.2 (#1093) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/androidx.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index 404729cf9..90b8ab072 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -1,7 +1,7 @@ [versions] agp_version = "8.5.1" lifecycle_version = "2.8.4" -paging_version = "3.3.1" +paging_version = "3.3.2" interpolator_version = "1.0.0" [libraries] From fdc1423f3dd3730c01200c631bb64377e056ef3a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 9 Aug 2024 02:33:30 +0600 Subject: [PATCH 128/297] chore(deps): update gradle/actions action to v4 (#1095) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/build_pull_request.yml | 4 ++-- .github/workflows/build_push.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build_pull_request.yml b/.github/workflows/build_pull_request.yml index cfca98a2a..4ca360716 100644 --- a/.github/workflows/build_pull_request.yml +++ b/.github/workflows/build_pull_request.yml @@ -23,7 +23,7 @@ jobs: uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Validate Gradle Wrapper - uses: gradle/actions/wrapper-validation@d9c87d481d55275bb5441eef3fe0e46805f9ef70 # v3.5.0 + uses: gradle/actions/wrapper-validation@af1da67850ed9a4cedd57bfd976089dd991e2582 # v4.0.0 - name: Dependency Review uses: actions/dependency-review-action@5a2ce3f5b92ee19cbb1541a4984c76d921601d7c # v4.3.4 @@ -35,7 +35,7 @@ jobs: distribution: adopt - name: Set up gradle - uses: gradle/actions/setup-gradle@d9c87d481d55275bb5441eef3fe0e46805f9ef70 # v3.5.0 + uses: gradle/actions/setup-gradle@af1da67850ed9a4cedd57bfd976089dd991e2582 # v4.0.0 - name: Build app and run unit tests run: ./gradlew detekt assembleStandardRelease testReleaseUnitTest testStandardReleaseUnitTest diff --git a/.github/workflows/build_push.yml b/.github/workflows/build_push.yml index 0c187ca33..88fe57f46 100644 --- a/.github/workflows/build_push.yml +++ b/.github/workflows/build_push.yml @@ -20,7 +20,7 @@ jobs: uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Validate Gradle Wrapper - uses: gradle/actions/wrapper-validation@d9c87d481d55275bb5441eef3fe0e46805f9ef70 # v3.5.0 + uses: gradle/actions/wrapper-validation@af1da67850ed9a4cedd57bfd976089dd991e2582 # v4.0.0 - name: Setup Android SDK run: | @@ -33,7 +33,7 @@ jobs: distribution: adopt - name: Set up gradle - uses: gradle/actions/setup-gradle@d9c87d481d55275bb5441eef3fe0e46805f9ef70 # v3.5.0 + uses: gradle/actions/setup-gradle@af1da67850ed9a4cedd57bfd976089dd991e2582 # v4.0.0 - name: Build app and run unit tests run: ./gradlew detekt assembleStandardRelease testReleaseUnitTest testStandardReleaseUnitTest From 36b9caeea8baf15f0d0ed37abc12638d44194c09 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 9 Aug 2024 04:22:33 +0600 Subject: [PATCH 129/297] fix(deps): update dependency androidx.annotation:annotation to v1.8.2 (#1090) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/androidx.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index 90b8ab072..6d9690c6c 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -7,7 +7,7 @@ interpolator_version = "1.0.0" [libraries] gradle = { module = "com.android.tools.build:gradle", version.ref = "agp_version" } -annotation = "androidx.annotation:annotation:1.8.1" +annotation = "androidx.annotation:annotation:1.8.2" appcompat = "androidx.appcompat:appcompat:1.7.0" biometricktx = "androidx.biometric:biometric-ktx:1.2.0-alpha05" constraintlayout = "androidx.constraintlayout:constraintlayout:2.1.4" From af77083660000e7378587dbc8d44e44bd8b196ec Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 9 Aug 2024 04:23:36 +0600 Subject: [PATCH 130/297] fix(deps): update dependency androidx.work:work-runtime to v2.9.1 (#1091) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/androidx.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index 6d9690c6c..dfd863425 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -21,7 +21,7 @@ lifecycle-common = { module = "androidx.lifecycle:lifecycle-common", version.ref lifecycle-process = { module = "androidx.lifecycle:lifecycle-process", version.ref = "lifecycle_version" } lifecycle-runtimektx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "lifecycle_version" } -workmanager = "androidx.work:work-runtime:2.9.0" +workmanager = "androidx.work:work-runtime:2.9.1" paging-runtime = { module = "androidx.paging:paging-runtime", version.ref = "paging_version" } paging-compose = { module = "androidx.paging:paging-compose", version.ref = "paging_version" } From e8b7c3e24bb677d289554b972ef2496a976c79aa Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 9 Aug 2024 04:29:35 +0600 Subject: [PATCH 131/297] fix(deps): update dependency io.coil-kt.coil3:coil-bom to v3.0.0-alpha10 (#1092) 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 f1e91d2f8..3c4666c7e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -42,7 +42,7 @@ preferencektx = "androidx.preference:preference-ktx:1.2.1" injekt-core = "com.github.inorichi.injekt:injekt-core:65b0440" -coil-bom = { module = "io.coil-kt.coil3:coil-bom", version = "3.0.0-alpha09" } +coil-bom = { module = "io.coil-kt.coil3:coil-bom", version = "3.0.0-alpha10" } coil-core = { module = "io.coil-kt.coil3:coil" } coil-gif = { module = "io.coil-kt.coil3:coil-gif" } coil-compose = { module = "io.coil-kt.coil3:coil-compose" } From dca9bf105770890e015b8e2f9fbf22f05665e343 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 9 Aug 2024 04:31:56 +0600 Subject: [PATCH 132/297] fix(deps): update dependency dev.chrisbanes.compose:compose-bom to v2024.08.00-alpha01 (#1094) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/compose.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/compose.versions.toml b/gradle/compose.versions.toml index 29dc3acf0..35374b8d3 100644 --- a/gradle/compose.versions.toml +++ b/gradle/compose.versions.toml @@ -1,5 +1,5 @@ [versions] -compose-bom = "2024.07.00-alpha02" +compose-bom = "2024.08.00-alpha01" accompanist = "0.35.1-alpha" [libraries] From 4828c54245dd6532c0e7a2b6c8cf5d8a703d3376 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 9 Aug 2024 09:51:28 +0600 Subject: [PATCH 133/297] fix(deps): update dependency com.android.tools.build:gradle to v8.5.2 (#1099) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/androidx.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index dfd863425..2b88b09ba 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -1,5 +1,5 @@ [versions] -agp_version = "8.5.1" +agp_version = "8.5.2" lifecycle_version = "2.8.4" paging_version = "3.3.2" interpolator_version = "1.0.0" From 14ae57d78b31f0bb3b58d19c1d8cfcebcc8e2253 Mon Sep 17 00:00:00 2001 From: Catting <5874051+mm12@users.noreply.github.com> Date: Sat, 10 Aug 2024 16:58:02 -0500 Subject: [PATCH 134/297] Contributing: ktLintFormat -> detekt (#1102) * Contributing: ktLintFormat -> detekt update Contributing info to use detekt instead of ktLintFormat * Update CONTRIBUTING.md --------- Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com> --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6c1c74cfa..2315fd44d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -26,7 +26,7 @@ Before you start, please note that the ability to use following technologies is ## Linting -To auto-fix some linting errors, run the `ktlintFormat` Gradle task. +Run the `detekt` gradle task. If the build fails, a report of issues can be found in `app/build/reports/detekt/`. The report is availble in several formats and details each issue that needs attention. ## Getting help From 9240eceedc5e2b065dd680819c4180c1ae09512b Mon Sep 17 00:00:00 2001 From: MajorTanya <39014446+MajorTanya@users.noreply.github.com> Date: Sun, 11 Aug 2024 18:40:28 +0200 Subject: [PATCH 135/297] Change Kitsu to kitsu.app domain (#1106) cf. https://github.com/hummingbird-me/kitsu-server/commit/244fdccca9754d8579c049e738832843001b33b1 --- README.md | 2 +- .../java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index d40550b03..4088af5ff 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Discover and read manga, webtoons, comics, and more – easier than ever on your * Local reading of content. * A configurable reader with multiple viewers, reading directions and other settings. -* Tracker support: [MyAnimeList](https://myanimelist.net/), [AniList](https://anilist.co/), [Kitsu](https://kitsu.io/), [MangaUpdates](https://mangaupdates.com), [Shikimori](https://shikimori.one), and [Bangumi](https://bgm.tv/) support. +* Tracker support: [MyAnimeList](https://myanimelist.net/), [AniList](https://anilist.co/), [Kitsu](https://kitsu.app/), [MangaUpdates](https://mangaupdates.com), [Shikimori](https://shikimori.one), and [Bangumi](https://bgm.tv/) support. * Categories to organize your library. * Light and dark themes. * Schedule updating your library for new chapters. diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt index 3c9251eaf..cabdf87be 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt @@ -270,10 +270,10 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor) private const val clientSecret = "54d7307928f63414defd96399fc31ba847961ceaecef3a5fd93144e960c0e151" - private const val baseUrl = "https://kitsu.io/api/edge/" - private const val loginUrl = "https://kitsu.io/api/oauth/token" - private const val baseMangaUrl = "https://kitsu.io/manga/" - private const val algoliaKeyUrl = "https://kitsu.io/api/edge/algolia-keys/media/" + private const val baseUrl = "https://kitsu.app/api/edge/" + private const val loginUrl = "https://kitsu.app/api/oauth/token" + private const val baseMangaUrl = "https://kitsu.app/manga/" + private const val algoliaKeyUrl = "https://kitsu.app/api/edge/algolia-keys/media/" private const val algoliaUrl = "https://AWQO5J657S-dsn.algolia.net/1/indexes/production_media/query/" From 97c81fadb426d71ac99c9443ab0e89f4089046ef Mon Sep 17 00:00:00 2001 From: MajorTanya <39014446+MajorTanya@users.noreply.github.com> Date: Sun, 11 Aug 2024 18:55:13 +0200 Subject: [PATCH 136/297] Fix MAL search results not showing start dates (#1098) The previous approach would always throw an Exception because `SimpleDateFormat.format()` expects the input to be of type `Date` or `Number`, not `String`. --- .../tachiyomi/data/track/myanimelist/MyAnimeListApi.kt | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListApi.kt index 2aef56016..097e36a5d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListApi.kt @@ -129,12 +129,7 @@ class MyAnimeListApi( obj["status"]!!.jsonPrimitive.content.replace("_", " ") publishing_type = obj["media_type"]!!.jsonPrimitive.content.replace("_", " ") - start_date = try { - val outputDf = SimpleDateFormat("yyyy-MM-dd", Locale.US) - outputDf.format(obj["start_date"]!!) - } catch (e: Exception) { - "" - } + start_date = obj["start_date"]?.jsonPrimitive?.content ?: "" } } } From b1b15a93eec15a82e2e83650abf97c1b9f0c501c Mon Sep 17 00:00:00 2001 From: "Weblate (bot)" Date: Sun, 11 Aug 2024 18:55:47 +0200 Subject: [PATCH 137/297] Translations update from Hosted Weblate (#939) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/ar/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/ca/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/cs/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/de/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/es/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/fil/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/id/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/ja/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/ml/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/ru/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/sv/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/zh_Hant/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/am/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ar/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/be/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/bg/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/bn/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ca/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ceb/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/cs/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/cv/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/da/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/de/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/el/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/eo/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/es/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/eu/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/fa/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/fi/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/fil/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/fr/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/gl/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/he/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/hi/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/hr/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/hu/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/id/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/it/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ja/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/jv/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ka/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/kk/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/km/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/kn/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ko/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/lt/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/lv/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ml/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/mr/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ms/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/nb_NO/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ne/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/nl/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/nn/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/pl/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/pt/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/pt_BR/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ro/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ru/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/sa/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/sah/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/sc/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/sdh/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/sk/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/sq/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/sr/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/sv/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/te/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/th/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/tr/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/uk/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/uz/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/vi/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/zh_Hans/ Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/zh_Hant/ Translation: Mihon/Mihon Translation: Mihon/Mihon Plurals Co-authored-by: Ahmed seif al-nasr Co-authored-by: Ajeje Brazorf Co-authored-by: Akhil Raj Co-authored-by: Animeboynz <40583749+Animeboynz@users.noreply.github.com> Co-authored-by: David Katrinka Co-authored-by: Dexroneum Co-authored-by: Eduard Ereza Martínez Co-authored-by: Eji-san Co-authored-by: FateXBlood Co-authored-by: Giorgio Sanna Co-authored-by: Iker Lerones Co-authored-by: Infy's Tagalog Translations Co-authored-by: Lyfja <45209212+lyfja@users.noreply.github.com> Co-authored-by: Matyáš Caras Co-authored-by: Norsze Co-authored-by: Pitpe11 Co-authored-by: TheKingTermux Co-authored-by: abc0922001 Co-authored-by: bittin1ddc447d824349b2 Co-authored-by: gallegonovato Co-authored-by: gekka <1778962971@qq.com> Co-authored-by: sebastians17 Co-authored-by: vodkapmp Co-authored-by: ɴᴇᴋᴏ Co-authored-by: Артём Голуб --- .../commonMain/moko-resources/ar/plurals.xml | 24 +++++-- .../commonMain/moko-resources/ar/strings.xml | 40 +++++++---- .../commonMain/moko-resources/be/strings.xml | 15 ++++ .../commonMain/moko-resources/bg/strings.xml | 1 - .../commonMain/moko-resources/bn/strings.xml | 1 - .../commonMain/moko-resources/ca/plurals.xml | 5 ++ .../commonMain/moko-resources/ca/strings.xml | 14 +++- .../commonMain/moko-resources/cs/plurals.xml | 5 ++ .../commonMain/moko-resources/cs/strings.xml | 13 +++- .../commonMain/moko-resources/de/plurals.xml | 4 ++ .../commonMain/moko-resources/de/strings.xml | 11 ++- .../commonMain/moko-resources/el/strings.xml | 2 +- .../commonMain/moko-resources/es/plurals.xml | 7 +- .../commonMain/moko-resources/es/strings.xml | 12 +++- .../commonMain/moko-resources/eu/strings.xml | 5 ++ .../commonMain/moko-resources/fa/strings.xml | 1 - .../commonMain/moko-resources/fi/strings.xml | 1 - .../commonMain/moko-resources/fil/plurals.xml | 6 +- .../commonMain/moko-resources/fil/strings.xml | 32 ++++++--- .../commonMain/moko-resources/fr/strings.xml | 1 - .../commonMain/moko-resources/gl/strings.xml | 1 - .../commonMain/moko-resources/he/strings.xml | 1 - .../commonMain/moko-resources/hi/strings.xml | 1 - .../commonMain/moko-resources/hr/strings.xml | 1 - .../commonMain/moko-resources/hu/strings.xml | 1 - .../commonMain/moko-resources/in/plurals.xml | 3 + .../commonMain/moko-resources/in/strings.xml | 12 +++- .../commonMain/moko-resources/it/strings.xml | 9 ++- .../commonMain/moko-resources/ja/plurals.xml | 3 + .../commonMain/moko-resources/ja/strings.xml | 10 ++- .../commonMain/moko-resources/kk/strings.xml | 1 - .../commonMain/moko-resources/km/strings.xml | 1 - .../commonMain/moko-resources/ko/strings.xml | 1 - .../commonMain/moko-resources/lt/strings.xml | 1 - .../commonMain/moko-resources/lv/strings.xml | 1 - .../commonMain/moko-resources/ml/plurals.xml | 10 ++- .../commonMain/moko-resources/ml/strings.xml | 37 ++++++++++ .../commonMain/moko-resources/ms/strings.xml | 1 - .../moko-resources/nb-rNO/strings.xml | 5 +- .../commonMain/moko-resources/ne/strings.xml | 12 +++- .../commonMain/moko-resources/nl/strings.xml | 1 - .../commonMain/moko-resources/pl/strings.xml | 13 +++- .../moko-resources/pt-rBR/strings.xml | 1 - .../commonMain/moko-resources/pt/strings.xml | 1 - .../commonMain/moko-resources/ro/strings.xml | 1 - .../commonMain/moko-resources/ru/plurals.xml | 6 ++ .../commonMain/moko-resources/ru/strings.xml | 12 +++- .../commonMain/moko-resources/sc/strings.xml | 68 ++++++++++++++++++- .../commonMain/moko-resources/sk/strings.xml | 1 - .../commonMain/moko-resources/sq/strings.xml | 1 - .../commonMain/moko-resources/sr/strings.xml | 1 - .../commonMain/moko-resources/sv/plurals.xml | 6 +- .../commonMain/moko-resources/sv/strings.xml | 12 +++- .../commonMain/moko-resources/th/strings.xml | 1 - .../commonMain/moko-resources/tr/strings.xml | 1 - .../commonMain/moko-resources/uk/strings.xml | 1 - .../commonMain/moko-resources/vi/strings.xml | 1 - .../moko-resources/zh-rCN/strings.xml | 12 +++- .../moko-resources/zh-rTW/plurals.xml | 3 + .../moko-resources/zh-rTW/strings.xml | 14 +++- 60 files changed, 388 insertions(+), 81 deletions(-) diff --git a/i18n/src/commonMain/moko-resources/ar/plurals.xml b/i18n/src/commonMain/moko-resources/ar/plurals.xml index ff772f02d..087a71f09 100644 --- a/i18n/src/commonMain/moko-resources/ar/plurals.xml +++ b/i18n/src/commonMain/moko-resources/ar/plurals.xml @@ -90,8 +90,8 @@ الأمس - منذ %1$d أيام - منذ %1$d أيام + منذ يوم + منذ يومين منذ %1$d أيام منذ %1$d أيام منذ %1$d أيام @@ -129,11 +129,27 @@ %d يوم - %d + لا مستودعات مستودع مستودعان %d مستودعات %d مستودعات - + %d مستودعات + + + %1$s صفحات + صفحة + صفحتان + %1$s صفحات + %1$s صفحات + %1$s صفحات + + + اليوم + غداً + بعد غد + بعد %1$d أيام + بعد %1$d أيام + بعد %1$d أيام \ No newline at end of file diff --git a/i18n/src/commonMain/moko-resources/ar/strings.xml b/i18n/src/commonMain/moko-resources/ar/strings.xml index 7ebedaeee..c23312cc1 100644 --- a/i18n/src/commonMain/moko-resources/ar/strings.xml +++ b/i18n/src/commonMain/moko-resources/ar/strings.xml @@ -149,7 +149,7 @@ تم محو ملفات تعريف الارتباط محو قاعدة البيانات مسح سجلّ الإدخالات التي ليست محفوظة في مكتبتك - أمتأكِّد؟ إن فعلتَ خسرتَ الفصول المقروءة و التقدم فى العنوانين الغير محفوظة فى المكتبة + أمتأكِّد؟ إن فعلتَ سوف تخسر الفصول المقروءة و التقدم فى المدخلات الغير محفوظة فى المكتبة تم حذف المدخلات اﻹصدار إرسال تقارير الأعطال @@ -185,7 +185,7 @@ هل أنت متأكد من أنك تريد حذف الفصول المحددة؟ التتبع القراءة - تمَّت + مكتملة متروكة معلَّقة أنوي قراءتها @@ -259,7 +259,7 @@ الحالة النوع اختر بيانات لتضمينها - رحِّل + نقل نسخ ليست لديك أيّة فئات، اضغط زر اﻹضافة لإنشاء واحدة لتنظيم مكتبتك. تمَّ الانتهاء من: @@ -281,7 +281,7 @@ مراوغة / تفتيح حرق / تغميق لم يُعثر على أيِّ نتائج - اختيار مصدر للترحيل من + اختيار مصدر للنقل من عودة تقدم تحديث @@ -343,7 +343,7 @@ الفصل %1$s و%2$d فصول أخرى الفصل %1$s الفصل %1$s - %2$s - تُحدَّث المكتبة + تَحديثُ المكتبة وضع القراءة القسم الخاص بهذه السلسلة متوقِّفة @@ -428,7 +428,7 @@ مسح السجل الصفحة التالية الصفحة السابقة - دليل ترحيل المصدر + دليل نقل المصدر محتوى +18 اعرض في قوائم المصادر والامتدادات رجاء سجل دخولك في MAL مجدداً @@ -442,7 +442,7 @@ تاريخ انهاء القراءة تاريخ بدء القراءة يحفظ سجلات الأخطاء في ملف للمشاركة مع المطورين - شارك سجلَّات الانهيار + شارك سجلَّات الاعطال يميناً ويساراً إذا كان موضع تقسيم الصفحات العريضة لا يتطابق مع اتجاه القراءة عكس موضع تقسيم الصفحة @@ -490,7 +490,7 @@ فشلت مشاركة الغلاف خطأ في حفظ الغلاف حُفظ الغلاف - غطاء + غُلاف تنسيق الفصل غير صالح تعليمات التعقب إعدادات فرز كل صنف @@ -545,7 +545,7 @@ «Shizuku» لا يعمل انتهى النشر أُلغيت - منقطعة + متوقفة للحصول على المساعده في إصلاح أخطاء تحديث المكتبة، أنظر هنا%1$s احفظ كأرشيف CBZ سياسة الخصوصية @@ -562,15 +562,15 @@ تُخُطِّيت بسبب عدم وجود فصول قُرئت تُخُطِّيت لوجود فصول لم تُقرأ لم يبدأ هذا بعد - تُخُطِّيت لأنها تمِّت + تُخُطِّيت لأنها مكتملة حرِّك الصور الواسعة كبِّر الصور العريضة تلقائيًّا خطأ أثناء حفظ الصورة معطل رأسي بالعكس فشل %1$d تحديث أو تحديثات - اضغط لقراءة المزيد - نسخة جديدة متاحة من الإصدارات الرسمية. انقر لمعرفة كيفية التحويل من إصدارات F-Droid غير الرسمية. + اضغط لمعرفة المزيد + نسخة جديدة متاحة من الإصدارات الرسمية. انقر لمعرفة كيفية النقل من إصدارات F-Droid غير الرسمية. نقل سلسلة الفصول للأعلى لا توجد مدخلات في المكتبة لإجراء نسخة احتياطي‮‮ة اغلاق @@ -612,7 +612,6 @@ لا تتاح الأداة حال تمكين قفل التطبيق اطَّلع على ما حُدِّث مؤخَّرًا في مكتبتك حذف كل شيء - تنسيق RARv5 ليس مدعومًا موجة مد و جزر متعدد هنالك تحديث جارٍ بالفعل @@ -727,7 +726,7 @@ التوقيت النسبي «%1$s» بدلًا عن «%2$s» رتِّب الفئات - تُنعَش المكتبة… (%s) + تحديث المكتبة… (%s) أتريد ترتيب الفئات حسب الحروف؟ إعدادات المصادر إعدادات التطبيق @@ -805,4 +804,17 @@ استبدل بصمة مفتاح الانخراط موجودة من قبل تعطيل التصغير + المانجا اما منتهية او لا يوجد تاريخ اصدار متوقع. + أبيض وأسود + فشل في الحصول على الوصول المستمر إلى المجلد. قد يتصرف التطبيق بشكل غير متوقع. + %1$s ms + مدة الوميض + يومض كل(مدة) + أسود + أبيض + يومض مع + يحتوي المستودع %1$s على نفس بصمة مفتاح التوقيع الموجودة في %2$s. +\n إذا كان هذا متوقعًا، فسيتم استبدال %2$s، وإلا فاتصل بمشرف الرابطالخاص بك. + نقل مَدْخَل موجود + ملف تعريف عرض خاص \ No newline at end of file diff --git a/i18n/src/commonMain/moko-resources/be/strings.xml b/i18n/src/commonMain/moko-resources/be/strings.xml index b0e470588..9b082d59e 100644 --- a/i18n/src/commonMain/moko-resources/be/strings.xml +++ b/i18n/src/commonMain/moko-resources/be/strings.xml @@ -337,4 +337,19 @@ Выдаліць усё Кожныя 3 дні Толькі па Wi-Fi + Не выбрана + Перайсці ўверх + Разблакіраваць %s + Пачата + Выбрана + Другія опцыі + Выдаліць загружанае + Даныя і хаванне + Статыстыка + На ўстройстве + Задаць інтэрвал + Наладжвальная частата абнаўлення + Наступнае + Перакладчык + Загружана \ No newline at end of file diff --git a/i18n/src/commonMain/moko-resources/bg/strings.xml b/i18n/src/commonMain/moko-resources/bg/strings.xml index 817a229ef..7b7def8fe 100644 --- a/i18n/src/commonMain/moko-resources/bg/strings.xml +++ b/i18n/src/commonMain/moko-resources/bg/strings.xml @@ -626,7 +626,6 @@ Искате да премахнете \"%s\" от библиотеката си Затвори Всички настройки на четеца нулирани - Форматът RARv5 не се поддържа Тема, формат на датата и времето Категории, глобални обновления Режим на четене, показване, навигация diff --git a/i18n/src/commonMain/moko-resources/bn/strings.xml b/i18n/src/commonMain/moko-resources/bn/strings.xml index 31bb98cec..d14fd3ff4 100644 --- a/i18n/src/commonMain/moko-resources/bn/strings.xml +++ b/i18n/src/commonMain/moko-resources/bn/strings.xml @@ -589,7 +589,6 @@ পঠনের ধরন, ডিসপ্লে,নেভিগেশন ম্যানুয়াল ও সয়ংক্রিয় ব্যাকআপ অ্যাপ লক,নিরাপদ পর্দা - RARv5 ধরন সমর্থিত নয় অপঠিত অধ্যায় থাকায় এড়িয়ে যাওয়া হয়েছে স্থানীয় ক্লিপবোর্ডে কপি করুন diff --git a/i18n/src/commonMain/moko-resources/ca/plurals.xml b/i18n/src/commonMain/moko-resources/ca/plurals.xml index 78d4572c3..b37ec5f92 100644 --- a/i18n/src/commonMain/moko-resources/ca/plurals.xml +++ b/i18n/src/commonMain/moko-resources/ca/plurals.xml @@ -90,4 +90,9 @@ D’aquí a %1$d dies D’aquí a %1$d dies + + 1 pàgina + %1$s pàgines + %1$s pàgines + \ No newline at end of file diff --git a/i18n/src/commonMain/moko-resources/ca/strings.xml b/i18n/src/commonMain/moko-resources/ca/strings.xml index d54f800aa..42c67c295 100644 --- a/i18n/src/commonMain/moko-resources/ca/strings.xml +++ b/i18n/src/commonMain/moko-resources/ca/strings.xml @@ -610,7 +610,6 @@ Cadena d’agent d’usuari per defecte Restableix la cadena d’agent d’usuari per defecte El widget no està disponible quan hi ha activat el blocatge de l’aplicació - El format RARv5 no està suportat Vegeu els elements de la biblioteca actualitzats recentment Elimina-ho tot Ja s’està executant una actualització @@ -702,7 +701,7 @@ Freqüència d’actualització personalitzat Pròxima actualització prevista D’acord - Preveu el moment del pròxim llançament + Preveu el moment de la pròxima publicació Intervals Estima cada S’actualitzarà cada @@ -810,4 +809,15 @@ Perfil de visualització personalitzat Mostra les pròximes actualitzacions Mes anterior + Durada del flaix + Blanc + %1$s ms + Flaix amb + Negre + Flaix cada + Blanc i negre + Aquest manga està completat o bé no té cap data de publicació prevista. + Còpia de seguretat en JSON no suportada + El fitxer de còpia de seguretat és corrupte + Repositoris d’extensions \ No newline at end of file diff --git a/i18n/src/commonMain/moko-resources/cs/plurals.xml b/i18n/src/commonMain/moko-resources/cs/plurals.xml index 2716c07c0..3977db060 100644 --- a/i18n/src/commonMain/moko-resources/cs/plurals.xml +++ b/i18n/src/commonMain/moko-resources/cs/plurals.xml @@ -90,4 +90,9 @@ Za %1$d dny Za %1$d dnů + + 1 stránka + %1$s stránky + %1$s stránek + \ No newline at end of file diff --git a/i18n/src/commonMain/moko-resources/cs/strings.xml b/i18n/src/commonMain/moko-resources/cs/strings.xml index e0bf3524a..966c92551 100644 --- a/i18n/src/commonMain/moko-resources/cs/strings.xml +++ b/i18n/src/commonMain/moko-resources/cs/strings.xml @@ -610,7 +610,6 @@ Obnovit výchozí řetězec pro user agent Výchozí řetězec pro user agent Odstranit vše - Formát RARv5 není podporován Widget není k dispozici, když je povolen zámek aplikace Podívejte se na své nedávno aktualizované záznamy v knihovně Aktualizace již probíhá @@ -803,4 +802,16 @@ Otisk podepisovacího klíče již existuje Repozitář %1$s má stejný otisk podepisovacího klíče jako %2$s \nPokud to tak je správně, bude%2$s nahrazen, v opačném případě kontaktujte správce repozitáře. + %1$s ms + Bílou + Tato manga je buďto dokončená, nebo nemá přibližné datum vydání. + Nadcházející + Délka bliknutí + Bliknout každých + Bliknout + Černou + Bílou a Černou + Vlastní profil zobrazení + Zobrazit nadcházející aktualizace + Nepodařilo se získat trvalý přístup ke složce. Aplikace se může chovat zvláštně. \ No newline at end of file diff --git a/i18n/src/commonMain/moko-resources/de/plurals.xml b/i18n/src/commonMain/moko-resources/de/plurals.xml index 785b237c5..60cd2d491 100644 --- a/i18n/src/commonMain/moko-resources/de/plurals.xml +++ b/i18n/src/commonMain/moko-resources/de/plurals.xml @@ -72,4 +72,8 @@ Morgen In %1$d Tagen + + 1 Seite + %1$s Seiten + \ No newline at end of file diff --git a/i18n/src/commonMain/moko-resources/de/strings.xml b/i18n/src/commonMain/moko-resources/de/strings.xml index 25893556d..d53670e0b 100644 --- a/i18n/src/commonMain/moko-resources/de/strings.xml +++ b/i18n/src/commonMain/moko-resources/de/strings.xml @@ -610,7 +610,6 @@ Standard-User-Agent-Text Standard-User-Agent-Text zurücksetzen Alles entfernen - Das RARv5-Format wird nicht unterstützt Deine kürzlich aktualisierten Bibliothekseinträge ansehen Widget ist nicht verfügbar, wenn die App-Sperre aktiviert ist Eine Aktualisierung ist bereits im Gange @@ -637,7 +636,7 @@ Ups! Absturzprotokolle ausgeben, Akkuverbrauch-Optimierung Manuelle und automatische Datensicherungen, Speicherplatz - %s ist auf einen unerwarteten Fehler gestoßen. Wir empfehlen dir, die Absturzprotokolle in unserem Support-Kanal auf Discord zu teilen. + %s ist auf einen unerwarteten Fehler gestoßen. Wir empfehlen dir, die Absturzprotokolle in unseren Support-Kanal auf Discord zu teilen. App-Sperre, sicherer Bildschirm Unbekannter Titel Ungültiger Speicherort: %s @@ -810,4 +809,12 @@ Bevorstehende Aktualisierungen ansehen Leitfaden für Bevorstehendes Dauerhafter Ordnerzugriff konnte nicht erlangt werden. Die App kann sich unerwartet verhalten. + Dieser Manga ist entweder abgeschlossen, oder es existiert kein geschätztes Veröffentlichungsdatum. + Leuchte jede + Leuchte mit + Schwarz + Weiß + Weiß und Schwarz + Dauer des Leuchtens + %1$s ms \ No newline at end of file diff --git a/i18n/src/commonMain/moko-resources/el/strings.xml b/i18n/src/commonMain/moko-resources/el/strings.xml index 54691d40c..ad47edea5 100644 --- a/i18n/src/commonMain/moko-resources/el/strings.xml +++ b/i18n/src/commonMain/moko-resources/el/strings.xml @@ -610,7 +610,6 @@ Προεπιλεγμένη συμβολοσειρά πράκτορα χρήστη Επαναφορά προεπιλεγμένης συμβολοσειράς πράκτορα χρήστη Καταργήστε τα πάντα - Η μορφή RARv5 δεν υποστηρίζεται Δείτε τις πρόσφατα ενημερωμένες καταχωρήσεις της βιβλιοθήκης σας Το widget δεν είναι διαθέσιμο όταν είναι ενεργοποιημένο το κλείδωμα εφαρμογών Εκτελείται ήδη μια ενημέρωση @@ -809,4 +808,5 @@ Οδηγός ανερχόμενων Επόμενο μήνα Προηγούμενο Μήνα + Αποτυχία απόκτησης μόνιμης πρόσβασης φακέλου. Η εφαρμογή μπορεί να συμπεριφέρεται απροσδόκητα. \ No newline at end of file diff --git a/i18n/src/commonMain/moko-resources/es/plurals.xml b/i18n/src/commonMain/moko-resources/es/plurals.xml index 21cff773b..f24e81118 100644 --- a/i18n/src/commonMain/moko-resources/es/plurals.xml +++ b/i18n/src/commonMain/moko-resources/es/plurals.xml @@ -1,7 +1,7 @@ - Tras %1$s minutos + Tras %1$s minuto Tras %1$s minutos Tras %1$s minutos @@ -90,4 +90,9 @@ Dentro de %1$d días Dentro de %1$d días + + 1 página + %1$s páginas + %1$s páginas + \ No newline at end of file diff --git a/i18n/src/commonMain/moko-resources/es/strings.xml b/i18n/src/commonMain/moko-resources/es/strings.xml index 4e6501b9b..9e76f4a46 100644 --- a/i18n/src/commonMain/moko-resources/es/strings.xml +++ b/i18n/src/commonMain/moko-resources/es/strings.xml @@ -610,7 +610,6 @@ Identificarse como otro navegador web («user agent») Volver a la identificación de navegador («user agent») original Quitar todo - La aplicación no es capaz de leer el formato RARv5 Aquí aparecerá el contenido más reciente de tu biblioteca El widget no está disponible cuando el bloqueo de aplicación está activo Ya se está actualizando @@ -810,4 +809,15 @@ Próximo mes Mes anterior No se ha podido obtener acceso a la carpeta persistente. La aplicación puede comportarse de forma inesperada. + Flash cada + Flash con + Blanco + Blanco y negro + Negro + Duración del flash + %1$s ms + Este manga está terminado o no hay fecha de publicación prevista. + Copia de seguridad JSON no compatible + El archivo de la copia de seguridad está dañado + Repositorios de extensiones \ No newline at end of file diff --git a/i18n/src/commonMain/moko-resources/eu/strings.xml b/i18n/src/commonMain/moko-resources/eu/strings.xml index d3dabbfbd..939836136 100644 --- a/i18n/src/commonMain/moko-resources/eu/strings.xml +++ b/i18n/src/commonMain/moko-resources/eu/strings.xml @@ -600,4 +600,9 @@ Kategoriak alfabetikoki ordenatu nahi? Jarraitu irakurtzen botoia OK + Irakurketa zerrenda + Bukatu gabeko zerrenda + Ezarri denbora-bitartea + Datu eta memoria + Azkenengo egunearatze egiaztapena \ No newline at end of file diff --git a/i18n/src/commonMain/moko-resources/fa/strings.xml b/i18n/src/commonMain/moko-resources/fa/strings.xml index 6137d857d..0441e04e8 100644 --- a/i18n/src/commonMain/moko-resources/fa/strings.xml +++ b/i18n/src/commonMain/moko-resources/fa/strings.xml @@ -586,7 +586,6 @@ شما باید از پشتیبانی ها در جا های دیگر هم کپی داشته باشید. بروزرسانی دسته بندی کپی کردن به کلیپ‌برد - فرمت RARv5 پشتیبانی نشده متوقف شده باز گشایی %s پاک کردن قسمت های دانلود شده diff --git a/i18n/src/commonMain/moko-resources/fi/strings.xml b/i18n/src/commonMain/moko-resources/fi/strings.xml index 587de5deb..2d51f1a17 100644 --- a/i18n/src/commonMain/moko-resources/fi/strings.xml +++ b/i18n/src/commonMain/moko-resources/fi/strings.xml @@ -602,7 +602,6 @@ Yksityiskohtainen kirjaaminen Kansikuva tallennettu Virhe tallentaessa kansikuvaa - RARv5-muoto ei ole tuettu Ohitettu, koska sarjassa on luettomia lukuja Ohitettu, koska sarja ei vaadi päivityksiä Olet poistamassa \"%s\" kirjastostasi diff --git a/i18n/src/commonMain/moko-resources/fil/plurals.xml b/i18n/src/commonMain/moko-resources/fil/plurals.xml index 4d10091a1..70cab3bc8 100644 --- a/i18n/src/commonMain/moko-resources/fil/plurals.xml +++ b/i18n/src/commonMain/moko-resources/fil/plurals.xml @@ -70,6 +70,10 @@ Bukas - Sa loob ng %1$d araw + Sa loob ng %1$d na araw + + + 1 pahina + %1$s na mga pahina \ No newline at end of file diff --git a/i18n/src/commonMain/moko-resources/fil/strings.xml b/i18n/src/commonMain/moko-resources/fil/strings.xml index df8b126ad..8b5e43a90 100644 --- a/i18n/src/commonMain/moko-resources/fil/strings.xml +++ b/i18n/src/commonMain/moko-resources/fil/strings.xml @@ -77,12 +77,12 @@ Wala ka pang kategorya. Pindutin ang plus button para gumawa ng isa para sa pag-aayos ng iyong aklatan. Bakante ang Aklatan mo Walang binasa kamakailan - Walang kamakailang mga update + Walang kamakailang update Walang dina-download Tulong Tungkol sa extension Mga Extension - Lumipat + Maglipat Pag-backup at Pag-restore Mga Source Nakaraan @@ -98,7 +98,7 @@ Nangangailangang i-unlock Pamahalaan ang mga abiso Seguridad at privacy - Ayos ng petsa + Pormat ng petsa Madilim Maliwanag Sistema @@ -221,10 +221,10 @@ Imbalidong backup file: Nai-backup na Awtomatikong dalas ng pag-backup - I-restore ang Aklatan mula sa backup + I-restore ang aklatan mula sa backup file I-restore ang backup - Magagamit para ma-restore ang kasalukuyang Aklatan - Mag-backup + Magagamit para ma-restore ang kasalukuyang aklatan + Gumawa ng backup Isahang pagsabay (sync) para mai-update ang progress sa mga kabanata sa mga external na tracking service. Ayusin ang pagta-track para sa mga indibidwal na entry gamit ang button na Pagta-track. Mga Tracker I-update ang progress pagkatapos basahin @@ -248,7 +248,7 @@ Di ma-download ang kabanata dahil sa isang di-inaasahang error Nagka-error Taga-download - Paki-update po ang WebView app para sa mas maayos na paggana + Paki-update ang WebView app para sa mas mahusay na pagkakatugma Kinakailangan ng app ang WebView upang gumana ito Bigong ma-bypass ang Cloudflare May bagong bersyon! @@ -302,8 +302,8 @@ Estado Pamagat Iskor - Binabasa uli - Binabalak + Binabasa muli + Binabalak na basahin Hininto Tinigil Kumpleto @@ -610,7 +610,6 @@ I-reset ang default na string ng user agent Default na string ng user agent Burahin lahat - Di suportado ang format na RARv5 Tingnan ang mga kamakailang nai-update na entry sa iyong aklatan Di available ang widget kapag nakabukas ang lock May ina-update sa ngayon @@ -775,7 +774,7 @@ Maabisuhan para sa mga update sa aklatan at higit pa. Payagan Na magagamit: %1$s / Kabuuan: %2$s - Mga bagong kabanata na hinulaang ipapalabas sa humigit-kumulang %1$s, na tumitingin sa bawat %2$s. + Mga bagong kabanata na nahulaang ilalabas sa loob ng %1$s, na tumitingin sa bawat %2$s. Buong error: Kinakailangan ng permiso para mag-install ng mga extension. I-tap upang mapayagan ito. Kasali ang mga sensitibong setting (hal., mga tracker login token) @@ -810,4 +809,15 @@ Nakaraang Buwan Tingnan ang mga Paparating na Update Nabigong makakuha ng patuloy na pag-access ng folder. Ang app ay magkaroon ng di-inaasahang pagkilos. + Mag-flash kada + Puti at Itim + Tagal ng pag-flash + %1$s ms + Mag-flash na may + Itim + Puti + Ang manga na ito ay nakumpleto na, o walang nahulaang petsa ng paglabas. + Hindi suportado ang JSON backup + Nasira ang backup file + Mga Repo ng Extension \ No newline at end of file diff --git a/i18n/src/commonMain/moko-resources/fr/strings.xml b/i18n/src/commonMain/moko-resources/fr/strings.xml index 2764a75ef..a5fb72811 100644 --- a/i18n/src/commonMain/moko-resources/fr/strings.xml +++ b/i18n/src/commonMain/moko-resources/fr/strings.xml @@ -610,7 +610,6 @@ Réinitialiser la liste d\'agents utilisateurs Liste d\'agents utilisateurs par défaut Tout retirer - Le format RARv5 n\'est pas supporté Voir les entrées de votre bibliothèque récemment mises à jour Le Widget n\'est pas disponible lorsque l\'application est verrouillée La liste d\'agents utilisateurs ne peut être vide diff --git a/i18n/src/commonMain/moko-resources/gl/strings.xml b/i18n/src/commonMain/moko-resources/gl/strings.xml index 81f69686e..45e76dcf2 100644 --- a/i18n/src/commonMain/moko-resources/gl/strings.xml +++ b/i18n/src/commonMain/moko-resources/gl/strings.xml @@ -665,7 +665,6 @@ Xa hai unha categoría con este nome! Reiniciar tódolos capítulos deste elemento Modo de lectura - O formato RARv5 non está soportado Actualizando a biblioteca Última actualización da biblioteca: %s Cap. %1$s - %2$s diff --git a/i18n/src/commonMain/moko-resources/he/strings.xml b/i18n/src/commonMain/moko-resources/he/strings.xml index 283ad0a8e..adc52160d 100644 --- a/i18n/src/commonMain/moko-resources/he/strings.xml +++ b/i18n/src/commonMain/moko-resources/he/strings.xml @@ -563,7 +563,6 @@ אם המקום של העמוד המפוצל לא תואם לכיוון הקריאה כלום איזורי נגיעה - הפורמט RARv5 לא נתמך חיפוש… פתיחת פריט אקראי מדריך למתחיל diff --git a/i18n/src/commonMain/moko-resources/hi/strings.xml b/i18n/src/commonMain/moko-resources/hi/strings.xml index 75f62e210..c3dd4279d 100644 --- a/i18n/src/commonMain/moko-resources/hi/strings.xml +++ b/i18n/src/commonMain/moko-resources/hi/strings.xml @@ -608,7 +608,6 @@ खैर, यह अजीब है आंतरिक त्रुटि : अधिक जानकारी के लिए क्रैश लॉग की जाँच करें केवल अनमीटर्ड कनेक्शन पर - RARv5 प्रारूप समर्थित नहीं है पुस्तकालय पिछली बार अपडेट किया गया: %s अपनी हाल ही में अपडेट की गई पुस्तकालय एन्ट्री देखें केवल तभी काम करता है जब वर्तमान अध्याय + अगला पहले से ही डाउनलोड किया गया हो। diff --git a/i18n/src/commonMain/moko-resources/hr/strings.xml b/i18n/src/commonMain/moko-resources/hr/strings.xml index aafcf3da6..1c9d1a7bc 100644 --- a/i18n/src/commonMain/moko-resources/hr/strings.xml +++ b/i18n/src/commonMain/moko-resources/hr/strings.xml @@ -580,7 +580,6 @@ Na popisu čekanja Popis nedovršenih Stranica %d nije pronađena tijekom rastavljanja - RARv5 format nije podržan Radi samo ako je trenutačno i sljedeće poglavlje već preuzeto. Zadnja provjera aktualiziranja Samo na mrežom bez ograničenja diff --git a/i18n/src/commonMain/moko-resources/hu/strings.xml b/i18n/src/commonMain/moko-resources/hu/strings.xml index 51c00c3eb..d476b7dbe 100644 --- a/i18n/src/commonMain/moko-resources/hu/strings.xml +++ b/i18n/src/commonMain/moko-resources/hu/strings.xml @@ -610,7 +610,6 @@ Alap hálózati kliens szöveg Alap hálózati kliens szöveg visszaállítása Minden Eltávolitása - RARv5 formátum nem támogatót Lásd nemrég frissített mangádat Widget nem elérhető amikor az alkalmazás zárolva van Téma, dátum és idő formátuma diff --git a/i18n/src/commonMain/moko-resources/in/plurals.xml b/i18n/src/commonMain/moko-resources/in/plurals.xml index cb31ac13d..b3cff445b 100644 --- a/i18n/src/commonMain/moko-resources/in/plurals.xml +++ b/i18n/src/commonMain/moko-resources/in/plurals.xml @@ -54,4 +54,7 @@ Dalam %1$d hari + + %1$s halaman + \ No newline at end of file diff --git a/i18n/src/commonMain/moko-resources/in/strings.xml b/i18n/src/commonMain/moko-resources/in/strings.xml index fa8ba612c..3485996c2 100644 --- a/i18n/src/commonMain/moko-resources/in/strings.xml +++ b/i18n/src/commonMain/moko-resources/in/strings.xml @@ -610,7 +610,6 @@ String agen pengguna default Setel ulang string agen pengguna default Hapus semuanya - Format RARv5 tidak didukung Lihat entri pustaka Anda yang baru saja diperbarui Widget tidak tersedia saat kunci aplikasi diaktifkan Pembaruan sudah berjalan @@ -799,7 +798,7 @@ Menonaktifkan zoom out Yang akan datang Migrasikan entri yang ada - Repositori %1$s memiliki Signing Key Fingerprint yang sama dengan %2$s. + Repositori %1$s memiliki Signing Key Fingerprint yang sama dengan %2$s. \nJika hal ini diharapkan, %2$s akan diganti, jika tidak, hubungi pengelola repo Anda. Tambahkan saja Profil tampilan khusus @@ -809,4 +808,13 @@ Panduan Mendatang Bulan Depan Bulan Kemarin + Manga ini sudah selesai, atau belum ada tanggal rilis yang diperkirakan. + Gagal mendapatkan akses folder yang terus-menerus. Aplikasi mungkin berperilaku tak terduga. + Durasi lampu kilat + %1$s ms + Flash setiap + Flash dengan + Hitam + Putih + Hitam Putih \ No newline at end of file diff --git a/i18n/src/commonMain/moko-resources/it/strings.xml b/i18n/src/commonMain/moko-resources/it/strings.xml index 32b150fa5..e78206667 100644 --- a/i18n/src/commonMain/moko-resources/it/strings.xml +++ b/i18n/src/commonMain/moko-resources/it/strings.xml @@ -612,7 +612,6 @@ Ripristina la stringa «user agent» del browser Stringa «user agent» del browser Rimuovi tutto - Il formato RARv5 non è supportato Widget non disponibile quando il blocco app è attivo Vedi le voci aggiornate di recente È già in corso un aggiornamento @@ -811,4 +810,12 @@ Guida in arrivo Mese prossimo Mese scorso + Durata del flash + %1$s ms + Flash con + Nero + Bianco + Non si è potuto ottenere l\'accesso permanente alle cartella. L\'applicazione potrebbe comportarsi inaspettatamente. + Flash ogni + Bianco e Nero \ No newline at end of file diff --git a/i18n/src/commonMain/moko-resources/ja/plurals.xml b/i18n/src/commonMain/moko-resources/ja/plurals.xml index b94cb9d90..71826beef 100644 --- a/i18n/src/commonMain/moko-resources/ja/plurals.xml +++ b/i18n/src/commonMain/moko-resources/ja/plurals.xml @@ -54,4 +54,7 @@ %1$d 日後 + + %1$s ページ + \ No newline at end of file diff --git a/i18n/src/commonMain/moko-resources/ja/strings.xml b/i18n/src/commonMain/moko-resources/ja/strings.xml index 09d5268ca..ec9e5b326 100644 --- a/i18n/src/commonMain/moko-resources/ja/strings.xml +++ b/i18n/src/commonMain/moko-resources/ja/strings.xml @@ -610,7 +610,6 @@ デフォルトのユーザーエージェント文字列 デフォルトのユーザーエージェント文字列をリセットする 全て削除 - フォーマットRARv5は未対応です 最近更新されたライブラリの項目を見る アプリロックがONの時、ウィジェットは利用できません アップデートはすでに進行中です @@ -809,4 +808,13 @@ 今後のご案内 リポジトリ %1$s は %2$s と同じ署名キー指紋を持っています。 \nこれが予想される場合は %2$s が置換されますが、そうでない場合はリポジトリのメンテナーに連絡してください。 + 閃光時間 + %1$s ms + フラッシュ・エブリ + フラッシュ + ブラック + ホワイト + 白と黒 + このマンガは完結しているか、あるいは発売予定日が決まっていない。 + 永続フォルダアクセスの取得に失敗しました。 アプリが予期しない動作をする可能性があります。 \ No newline at end of file diff --git a/i18n/src/commonMain/moko-resources/kk/strings.xml b/i18n/src/commonMain/moko-resources/kk/strings.xml index eb5fa9e7d..7f8d392b5 100644 --- a/i18n/src/commonMain/moko-resources/kk/strings.xml +++ b/i18n/src/commonMain/moko-resources/kk/strings.xml @@ -503,7 +503,6 @@ Ақырғы оқылған тарау ашылмай тұр Кітапхананың ақырғы жаңаруы: %s Дереккөз табылмады - RARv5 пішімі қолжетімсіз MyAnimeList-ке қайтадан кіріңіз Ұқсастық табылмады Дереккөз қолжетімсіз diff --git a/i18n/src/commonMain/moko-resources/km/strings.xml b/i18n/src/commonMain/moko-resources/km/strings.xml index 04c81c222..435981fdb 100644 --- a/i18n/src/commonMain/moko-resources/km/strings.xml +++ b/i18n/src/commonMain/moko-resources/km/strings.xml @@ -177,7 +177,6 @@ ចេញផ្សាយចប់ហើយ កំពុងតែធ្វើបច្ចុប្បន្នភាពបណ្ណាល័យ មានឡាយសិន - ទម្រង់RARv5មិនត្រូវបានទទួលយកទេ ម​គ្គុ​ទេស​ក៍​ ស្វែងរក ទាំងអស់ diff --git a/i18n/src/commonMain/moko-resources/ko/strings.xml b/i18n/src/commonMain/moko-resources/ko/strings.xml index a01a42c1f..7acf6f649 100644 --- a/i18n/src/commonMain/moko-resources/ko/strings.xml +++ b/i18n/src/commonMain/moko-resources/ko/strings.xml @@ -611,7 +611,6 @@ 최근에 업데이트된 항목 보기 보류 목록 분리 중 페이지 %d을 찾을 수 없습니다 - RARv5 포맷은 지원되지 않습니다 앱 잠금 사용 중에는 위젯을 이용할 수 없습니다 파도 업데이트가 이미 실행 중입니다 diff --git a/i18n/src/commonMain/moko-resources/lt/strings.xml b/i18n/src/commonMain/moko-resources/lt/strings.xml index 056b4a1b7..0cbc2281a 100644 --- a/i18n/src/commonMain/moko-resources/lt/strings.xml +++ b/i18n/src/commonMain/moko-resources/lt/strings.xml @@ -615,7 +615,6 @@ Nepavyko atidaryti paskutinio skaityto skyriaus Puslapis: %1$d Kitas: - RARv5 formatas nepalaikomas Įdiegtų šaltinių nerasta Potvynio banga Ieškoti… diff --git a/i18n/src/commonMain/moko-resources/lv/strings.xml b/i18n/src/commonMain/moko-resources/lv/strings.xml index 9ddae7b85..abaa8977c 100644 --- a/i18n/src/commonMain/moko-resources/lv/strings.xml +++ b/i18n/src/commonMain/moko-resources/lv/strings.xml @@ -663,7 +663,6 @@ Kategorijas, globāli atjauninājumi, nodaļu vilkšana Rādīt nelasīto skaitu uz atjauninājumu ikonas Logrīks nav pieejams, ja ir iespējota lietotņu bloķēšana - RARv5 formāts netiek atbalstīts %dh InternalError: Par plašāku informāciju skatiet avārijas žurnālu Vai vēlaties dzēst kategoriju \"%s\"? diff --git a/i18n/src/commonMain/moko-resources/ml/plurals.xml b/i18n/src/commonMain/moko-resources/ml/plurals.xml index 589be4b61..6101ae600 100644 --- a/i18n/src/commonMain/moko-resources/ml/plurals.xml +++ b/i18n/src/commonMain/moko-resources/ml/plurals.xml @@ -62,10 +62,18 @@ അധ്യായങ്ങൾ %1$s-ഉം പിന്നെ 1-ഉം - %1$s-ഉം %2$d-ഉം അധ്യായങ്ങൾ + %1$s അധ്യായങ്ങളും പിന്നെ %2$d-ഉം %d റിപ്പോ %d റിപ്പോകൾ + + 1 പേജ് + %1$s പേജ് + + + %d എൻട്രിക്ക് + %d എൻട്രികൾക്കായി + \ No newline at end of file diff --git a/i18n/src/commonMain/moko-resources/ml/strings.xml b/i18n/src/commonMain/moko-resources/ml/strings.xml index 7e6ad53a5..4fd22be53 100644 --- a/i18n/src/commonMain/moko-resources/ml/strings.xml +++ b/i18n/src/commonMain/moko-resources/ml/strings.xml @@ -131,4 +131,41 @@ താഴേക്ക് നീക്കുക പങ്കിടുക പ്രദർശിപ്പിക്കുക + സേവ് + സ്വാഗതം! + ആപ്പ് ഇൻസ്റ്റാൾ ചെയ്യാനുള്ള അനുവാദം + ഡൌൺലോഡ് ചെയ്യാൻ തുടങ്ങുക + ഒരു ഫോൾഡർ സെലക്ട് ചെയുക + സ്റ്റോറേജ് ഗൈഡ് + നോട്ടിഫിക്കേഷൻ കാണിക്കാനുള്ള അനുവാദം + ലോഡിങ്ങ്… + ഒരു ഫോൾഡർ തിരഞ്ഞെടുക്കണം + വിശദാംശങ്ങൾ കാണാൻ ടാപ്പുചെയ്യുക + അടയ്ക്കുക + ഇനങ്ങളുടെ എണ്ണം കാണിക്കുക + സ്ഥിരസ്ഥിതിയിലേക്ക് മടങ്ങുക + അൻഡൂ + ലോഗ് തുറക്കുക + ഇൻസ്റ്റാൾ + വിശ്വസിക്കൂ + എല്ലാ 2 ദിവസവും + ആഴ്ചയിൽ ഒരിക്കൽ + എല്ലാ ദിവസവും + ഈ എക്സ്റ്റൻഷൻ ഇനി ലഭ്യമല്ല. ഇത് ശരിയായി പ്രവർത്തിച്ചേക്കില്ല, ആപ്പിൽ പ്രശ്നങ്ങൾ ഉണ്ടാക്കാം. ഇത് അൺഇൻസ്റ്റാൾ ചെയ്യാൻ റെകമെൻഡ് ചെയ്യുന്നു. + ചാർജ് ചെയ്യുമ്പോൾ + അപ്ഡേറ്റ് ചെയ്യരുത് + മുന്നോട്ട് + പുറകിലുള്ള + റിസ്റ്റോർ + ഓരോ 12 മണിക്കൂറിലും + ഓരോ 6 മണിക്കൂറിലും + ലാൻഡ്സ്കേപ്പ് + ഗ്രിഡ് വലിപ്പം + അപ്ഡേറ്റ് + എല്ലാം + എപ്പോഴും ചോദിക്കുക + ഡൗൺലോഡ് ചെയ്യുന്നു + അൺഇൻസ്റ്റാൾ + അവിശ്വസനീയം + ഇൻസ്റ്റാൾ ചെയ്യുന്നു \ No newline at end of file diff --git a/i18n/src/commonMain/moko-resources/ms/strings.xml b/i18n/src/commonMain/moko-resources/ms/strings.xml index 539d2d449..057d35a5e 100644 --- a/i18n/src/commonMain/moko-resources/ms/strings.xml +++ b/i18n/src/commonMain/moko-resources/ms/strings.xml @@ -610,7 +610,6 @@ Untaian ejen pengguna lalai Set semula untaian ejen pengguna lalai Buang semuanya - Format RARv5 tidak disokong Widget tidak tersedia apabila kekunci aplikasi digunakan Lihat kemas kini entri pustaka terkini anda Kemas kini sedang berjalan diff --git a/i18n/src/commonMain/moko-resources/nb-rNO/strings.xml b/i18n/src/commonMain/moko-resources/nb-rNO/strings.xml index 3221848f5..adae92711 100644 --- a/i18n/src/commonMain/moko-resources/nb-rNO/strings.xml +++ b/i18n/src/commonMain/moko-resources/nb-rNO/strings.xml @@ -592,7 +592,6 @@ Kunne ikke finne filbanen til side %d Applås, sikker skjerm Dump krasjlogger, batterioptimaliseringer - RARv5-formatet støttes ikke Lagringstilgang er ikke gitt Ugyldig streng for brukeragent Ønskeliste @@ -796,4 +795,8 @@ Snart Fjern tilliten til ukjente utvidelser Åpne pakkebrønnen + Kommende + Legg til likevel + Flytt eksisterende oppføring + Erstatt \ No newline at end of file diff --git a/i18n/src/commonMain/moko-resources/ne/strings.xml b/i18n/src/commonMain/moko-resources/ne/strings.xml index 62f4f896e..5eeb083fa 100644 --- a/i18n/src/commonMain/moko-resources/ne/strings.xml +++ b/i18n/src/commonMain/moko-resources/ne/strings.xml @@ -663,7 +663,6 @@ पृष्ठ विभाजन गर्दा %d फेला परेन वर्ग खाली छ आन्तरिक त्रुटि: थप जानकारीको लागि क्र्यास लगहरू जाँच गर्नुहोस् - RARv5 समर्थित छैन पढिसकेका इन्ट्रीहरू कुल पढेको @@ -814,4 +813,15 @@ अर्को महिना अघिल्लो महिना लगातार फोल्डर पहुँच प्राप्त गर्न असफल। एपले अप्रत्याशित रूपमा व्यवहार गर्न सक्छ। + फ्ल्यास अवधि + सेतो + सेतो र कालो + सँग फ्ल्यास + %1$s ms + फ्ल्यास हरेक + कालो + यो माङ्गा या त समाप्त भयो, वा त्यहाँ कुनै अनुमानित रिलीज मिति छैन। + एक्सटेन्शन रिपो + JSON ब्याकअप समर्थित छैन + ब्याकअप फाइल बिग्रिएको छ \ No newline at end of file diff --git a/i18n/src/commonMain/moko-resources/nl/strings.xml b/i18n/src/commonMain/moko-resources/nl/strings.xml index 9ad64c610..0b2219306 100644 --- a/i18n/src/commonMain/moko-resources/nl/strings.xml +++ b/i18n/src/commonMain/moko-resources/nl/strings.xml @@ -579,7 +579,6 @@ Download vooruit WebView-gegevens gewist WebView-gegevens wissen - RARv5-indeling wordt niet ondersteund Pagina %d niet gevonden tijdens het splitsen InternalError: Bekijk de crash logs voor meer informatie Lavendel diff --git a/i18n/src/commonMain/moko-resources/pl/strings.xml b/i18n/src/commonMain/moko-resources/pl/strings.xml index 8fdff8642..4b4a83733 100644 --- a/i18n/src/commonMain/moko-resources/pl/strings.xml +++ b/i18n/src/commonMain/moko-resources/pl/strings.xml @@ -614,7 +614,6 @@ Usuń kategorię InternalError: sprawdź log błędów po więcej informacji Usuń wszystko - Format RARv5 jest nieobsługiwany Pole user agent nie może być puste Aktualizacja już trwa Tsunami @@ -790,7 +789,7 @@ Pełny błąd: Login serwisu śledzącego Utwórz - Włącz przerwy między stronami + Miganie przy zmianie strony Dołącz wrażliwe ustawienia (np. tokeny serwisu śledzącego) Ostatnia automatyczna kopia zapasowa: %s Ma wyniki @@ -808,4 +807,14 @@ Następny miesiąc Poprzedni miesiąc Nadchodzący + Nie udało się uzyskać dostępu do folderu. Aplikacja może się zachowywać nieprzewidywalnie. + %1$s ms + Długość migania + Miganie na + Biały i czarny + Czarny + Biały + Ta manga jest zakończona lub nie ma przewidywanej daty wydania. + Migaj co + Niestandardowy profil \ No newline at end of file diff --git a/i18n/src/commonMain/moko-resources/pt-rBR/strings.xml b/i18n/src/commonMain/moko-resources/pt-rBR/strings.xml index 5a3ea0d86..cec31ada1 100644 --- a/i18n/src/commonMain/moko-resources/pt-rBR/strings.xml +++ b/i18n/src/commonMain/moko-resources/pt-rBR/strings.xml @@ -610,7 +610,6 @@ User Agent padrão Redefinir o User Agent padrão Remover tudo - O formato RARv5 não é suportado Veja seus itens da biblioteca atualizados recentemente Widget não disponível quando o bloqueio do aplicativo está habilitado Uma atualização já está em andamento diff --git a/i18n/src/commonMain/moko-resources/pt/strings.xml b/i18n/src/commonMain/moko-resources/pt/strings.xml index 70ddb44b2..76d41bd21 100644 --- a/i18n/src/commonMain/moko-resources/pt/strings.xml +++ b/i18n/src/commonMain/moko-resources/pt/strings.xml @@ -593,7 +593,6 @@ Repor as definições do leitor por série Repõe o modo de leitura e orientação de todas as séries Não foi possível encontrar o caminho do ficheiro da página %d - O formato RARv5 não é suportado Multi Transferência automática durante leitura Deseja apagar a categoria \"%s\"? diff --git a/i18n/src/commonMain/moko-resources/ro/strings.xml b/i18n/src/commonMain/moko-resources/ro/strings.xml index d43caf5c5..4448981f5 100644 --- a/i18n/src/commonMain/moko-resources/ro/strings.xml +++ b/i18n/src/commonMain/moko-resources/ro/strings.xml @@ -549,7 +549,6 @@ Este posibil să nu funcționeze corect backup/restaurare dacă MIUI Optimization este dezactivată. La fiecare 3 zile Doar prin Wi Fi - Formatul RARv5 nu este acceptat Oprit Informații despre aplicație Copertă personalizată diff --git a/i18n/src/commonMain/moko-resources/ru/plurals.xml b/i18n/src/commonMain/moko-resources/ru/plurals.xml index a4f625ebe..523bf01a4 100644 --- a/i18n/src/commonMain/moko-resources/ru/plurals.xml +++ b/i18n/src/commonMain/moko-resources/ru/plurals.xml @@ -108,4 +108,10 @@ В течении %1$d дней В течении %1$d дней + + 1 страница + %1$s страницы + %1$s страниц + %1$s страниц + \ No newline at end of file diff --git a/i18n/src/commonMain/moko-resources/ru/strings.xml b/i18n/src/commonMain/moko-resources/ru/strings.xml index 1337da8d9..80f692a32 100644 --- a/i18n/src/commonMain/moko-resources/ru/strings.xml +++ b/i18n/src/commonMain/moko-resources/ru/strings.xml @@ -610,7 +610,6 @@ User agent по умолчанию Сбросить user agent по умолчанию Удалить всё - Формат RARv5 не поддерживается Виджет недоступен при включённой блокировке биометрией Посмотреть недавно обновлённые серии в библиотеке Обновление уже запущено @@ -810,4 +809,15 @@ Предстоящее руководство Следующий месяц Не удалось получить постоянный доступ к папке. Приложение может работать некорректно. + Продолжительность вспышки + %1$s мс + Вспышка с + Чёрная + Белая + Белая и чёрная + Вспышка каждую + Эта серия либо завершена, либо дата ее выхода неизвестна. + Файл резервной копии поврежден + Резервное копирование в формате JSON не поддерживается + Репозитории расширений \ No newline at end of file diff --git a/i18n/src/commonMain/moko-resources/sc/strings.xml b/i18n/src/commonMain/moko-resources/sc/strings.xml index 9ec1b724c..b6a9de753 100644 --- a/i18n/src/commonMain/moko-resources/sc/strings.xml +++ b/i18n/src/commonMain/moko-resources/sc/strings.xml @@ -614,7 +614,6 @@ Istringa de agente de utente predefinida Reseta s\'istringa de agente de utente predefinida Boga totu - Su formadu RARv5 no est suportadu Su widget no est a disponimentu cando su blocu de s\'aplicatzione est abilitadu Pòmpia sos elementos de biblioteca tuos agiornados dae pagu B\'est giai un\'agiornamentu in cursu @@ -755,4 +754,71 @@ Impostatziones de sas fontes Impostatziones de s\'aplicatzione Esclude sos iscandutores (iscansidores+tradutores) + Custu manga est acabbadu o non b\'at una data de publicatzione previdida. + Non s\'est pòdidu otènnere s\'atzessu permanente a sa cartella. S\'aplicatzione si diat pòdere cumportare in manera no isetada. + B\'at bisòngiu de sos permissos pro installare estensiones. Toca inoghe pro los frunire. + Non tenes galu depòsitos impostados. + Custu depòsitu esistit giai! + Iscantzella su depòsitu + Boles iscantzellare su depòsitu \"%s\"? + Depòsitu a còdighe abertu + Perunu logu de archiviatzione isseberadu + Durada de su flash + %1$s ms + Flash cada + Flash cun + Nieddu + Biancu + Biancu e nieddu + Errore intreu: + Ghia a sas atualizatziones imbenientes + Ghia de introdutzione + Bene bènnidu! + Imbeniente + Incumintzemus + Brinca + Seletziona una cartella in ue %1$s at a archiviare sos capìtulos iscarrigados, sas còpias de seguresa e àteru. +\n +\nSi cussìgiat una cartella dedicada. +\n +\nCartella seletzionada: %2$s + Ses agiornende dae una versione betza e non ses seguru de ite seletzionare? Abbista·ti sa ghia a s\'archiviatzione pro àteras informatziones. + Ghia a s\'archiviatzione + Èvita interrutziones a agiornamentos longos de sa biblioteca, iscarrigamentos, e riprìstinos de còpias de seguresa. + Fruni + Nou in %s? Ti cussigiamus de t\'abbistare sa ghia de introdutzione. + Nord + Agiornamentu inteligente + Annanghe unu depòsitu + URL de su depòsitu + Annanghe depòsitos additzionales a Mihon. Custu diat dèpere èssere un\'URL chi acabbat cun \"index.min.json\". + Include impostatziones sensìbiles ( a es. getones de intrada a sos arrastadores) + Luego + Annanghe su matessi + Tràmuda s\'elementu esistente + Istuda sa ridutzione de ismanniada + In antis de totus tocat a cunfigurare una paja de cosas. L\'as a pòdere semper modificare a pustis dae sas impostatziones. + Seletziona una cartella + Depes seletzionare una cartella + Permissos pro installare s\'aplicatzione + Pro installare estensiones de fontes. + Permissu pro sas notìficas + Retzi notìficas pro agiornamentos de sa biblioteca e àteru. + Impreu de sa bateria in s\'isfundu + URL de su depòsitu non vàlidu + Si pensat chi sos capìtulos los pùblichent pagu prus o mancu cada%1$s, cun verìficas cada %2$s. + Frecuèntzia de agiornamentu personalizada: + Su mese chi intrat + Su mese coladu + Ses torrende a installare %s? + Rèvoca sas estensiones disconnotas afidàbiles + Depòsitos de estensiones + A disponimentu: %1$s / Totale: %2$s + Remplasa + S\'imprenta digitale de sa crae de firma esistit giai + Su depòsitu %1$s tenet sa matessi imprenta digitale de sa crae de firma de %2$s. +\nSi custu est su chi t\'isetas, %2$s s\'at a sostituire, si nono cuntata su mantenidore de su depòsitu tuo. + Profilu de visualizatzione predefinidu + Abbista·ti sos agiornamentos imbenientes + Imbeniente \ No newline at end of file diff --git a/i18n/src/commonMain/moko-resources/sk/strings.xml b/i18n/src/commonMain/moko-resources/sk/strings.xml index b1b3e461e..39f4a9b63 100644 --- a/i18n/src/commonMain/moko-resources/sk/strings.xml +++ b/i18n/src/commonMain/moko-resources/sk/strings.xml @@ -627,7 +627,6 @@ Preskočené, pretože séria je dokončená Preskočené, pretože obsahuje neprečítané kapitoly Preskočené, pretože neboli prečítané žiadne kapitoly - Formát RARv5 nie je podporovaný Lokálna Stiahnuté Štatistiky diff --git a/i18n/src/commonMain/moko-resources/sq/strings.xml b/i18n/src/commonMain/moko-resources/sq/strings.xml index b4e48e6d6..aca22b21a 100644 --- a/i18n/src/commonMain/moko-resources/sq/strings.xml +++ b/i18n/src/commonMain/moko-resources/sq/strings.xml @@ -433,7 +433,6 @@ Nuk u gjet asnjë rezultat Titulli i panjohur Shto gjurmimin - Formati RARv5 nuk mbështetet Zgjidhni të dhënat për të përfshirë Kapitujt nuk mund të shkarkoheshin. Mund të provoni përsëri në seksionin e shkarkimeve Përditësimet e mëdha dëmtojnë burimet dhe mund të çojnë në përditësime më të ngadalta dhe gjithashtu rritje të përdorimit të baterisë. Trokit për të mësuar më shumë. diff --git a/i18n/src/commonMain/moko-resources/sr/strings.xml b/i18n/src/commonMain/moko-resources/sr/strings.xml index aab9d56c0..68dcba68c 100644 --- a/i18n/src/commonMain/moko-resources/sr/strings.xml +++ b/i18n/src/commonMain/moko-resources/sr/strings.xml @@ -643,7 +643,6 @@ Више језика Језик Ресетуј режим читања и оријентацију свих серија - RARv5 формат није подржан Популарно Завршени наслови Побољшава перформансе читача diff --git a/i18n/src/commonMain/moko-resources/sv/plurals.xml b/i18n/src/commonMain/moko-resources/sv/plurals.xml index 83e463a38..105d279a3 100644 --- a/i18n/src/commonMain/moko-resources/sv/plurals.xml +++ b/i18n/src/commonMain/moko-resources/sv/plurals.xml @@ -66,10 +66,14 @@ %d förråd - %d flera förråd + %d förråd Imorgon Om %1$d dagar + + 1 sida + %1$s sidor + \ No newline at end of file diff --git a/i18n/src/commonMain/moko-resources/sv/strings.xml b/i18n/src/commonMain/moko-resources/sv/strings.xml index bce82c14c..eb0c19827 100644 --- a/i18n/src/commonMain/moko-resources/sv/strings.xml +++ b/i18n/src/commonMain/moko-resources/sv/strings.xml @@ -610,7 +610,6 @@ Standardsträng för användaragent Återställ standardsträngen för användaragent Ta bort allt - RARv5 formatet stöds inte Se dina nyligen uppdaterade biblioteket inlägg Widget är inte tillgänglig när applåset är aktiverat En uppdatering pågår redan @@ -810,4 +809,15 @@ Visa kommande uppdateringar Kommande guide Misslyckades med att skaffa beständig mappåtkomst. Appen kan bete sig oväntat. + Denna manga är antingen avslutad, eller så finns inget förutsebart publiceringsdatum. + Blink varaktighet + %1$s ms + Blinka var + Blinka med + Svart + Vitt + Svart och vitt + Säkerhetskopierings fil är korrupt + JSON säkerhetskopering stöds inte + Tilläggsförråd \ No newline at end of file diff --git a/i18n/src/commonMain/moko-resources/th/strings.xml b/i18n/src/commonMain/moko-resources/th/strings.xml index b2b3da3bf..1776b231a 100644 --- a/i18n/src/commonMain/moko-resources/th/strings.xml +++ b/i18n/src/commonMain/moko-resources/th/strings.xml @@ -610,7 +610,6 @@ ตัวแทนผู้ใช้เริ่มต้น รีเซ็ตตัวแทนผู้ใช้ นำทุกอย่างออก - ไม่รับรองรูปแบบ RARv5 แสดงรายการในคลังที่อัปเดตล่าสุดของคุณ วิดเจ็ตไม่พร้อมใช้งานขณะการล็อกแอปเปิดไว้ สตริงตัวแทนผู้ใช้ไม่สามารถทิ้งว่างเปล่าไว้ได้ diff --git a/i18n/src/commonMain/moko-resources/tr/strings.xml b/i18n/src/commonMain/moko-resources/tr/strings.xml index 1aae5877e..7d7048747 100644 --- a/i18n/src/commonMain/moko-resources/tr/strings.xml +++ b/i18n/src/commonMain/moko-resources/tr/strings.xml @@ -610,7 +610,6 @@ Öntanımlı kullanıcı aracısı dizgesi Öntanımlı kullanıcı aracısı dizgesini sıfırla Her şeyi kaldır - RARv5 biçimi desteklenmiyor Uygulama kilidi etkinleştirildiğinde widget kullanılamıyor Son güncellenen kitaplık girdilerinizi görün Bir güncelleme zaten çalışıyor diff --git a/i18n/src/commonMain/moko-resources/uk/strings.xml b/i18n/src/commonMain/moko-resources/uk/strings.xml index 276fd442d..42c2c55c8 100644 --- a/i18n/src/commonMain/moko-resources/uk/strings.xml +++ b/i18n/src/commonMain/moko-resources/uk/strings.xml @@ -612,7 +612,6 @@ Типовий user agent Видалити все Скинути типовий user agent - Формат RARv5 не підтримується Багатомовне Останнє оновлення бібліотеки: %s Доступ до файлової системи не надано diff --git a/i18n/src/commonMain/moko-resources/vi/strings.xml b/i18n/src/commonMain/moko-resources/vi/strings.xml index 31a3761cc..9546c1c7f 100644 --- a/i18n/src/commonMain/moko-resources/vi/strings.xml +++ b/i18n/src/commonMain/moko-resources/vi/strings.xml @@ -614,7 +614,6 @@ Tiện ích không còn khả dụng khi khóa ứng dụng đang bật Xem các bộ truyện được cập nhật gần đây Loại bỏ tất cả mọi thứ - Định dạng RARv5 không được hỗ trợ Có một cập nhật đang chạy sẵn Sóng Thủy Triều Chuỗi đại diện người dùng không thể bỏ trống diff --git a/i18n/src/commonMain/moko-resources/zh-rCN/strings.xml b/i18n/src/commonMain/moko-resources/zh-rCN/strings.xml index 21290a04d..7b2023b4d 100644 --- a/i18n/src/commonMain/moko-resources/zh-rCN/strings.xml +++ b/i18n/src/commonMain/moko-resources/zh-rCN/strings.xml @@ -610,7 +610,6 @@ 默认 User Agent 字符串 恢复默认 User Agent 字符串 全部删除 - 不支持 RARv5 格式 应用锁开启时,小部件不能使用 查看最近更新的作品 有其他更新尚未完成 @@ -809,4 +808,15 @@ 即将推出 下个月 上个月 + 此漫画或已完结,或无发行日期。 + %1$s 毫秒 + 闪烁时间 + + 闪烁于 + + 黑白 + 获取永久文件存储权限失败,应用程序可能会出现异常。 + 闪烁时间间隔 + 不支持 JSON 备份 + 备份文件已损坏 \ No newline at end of file diff --git a/i18n/src/commonMain/moko-resources/zh-rTW/plurals.xml b/i18n/src/commonMain/moko-resources/zh-rTW/plurals.xml index ee3847fac..5a2dc58fc 100644 --- a/i18n/src/commonMain/moko-resources/zh-rTW/plurals.xml +++ b/i18n/src/commonMain/moko-resources/zh-rTW/plurals.xml @@ -54,4 +54,7 @@ %1$d 天後 + + %1$s pages + \ No newline at end of file diff --git a/i18n/src/commonMain/moko-resources/zh-rTW/strings.xml b/i18n/src/commonMain/moko-resources/zh-rTW/strings.xml index e4dfbc1f6..57fb04917 100644 --- a/i18n/src/commonMain/moko-resources/zh-rTW/strings.xml +++ b/i18n/src/commonMain/moko-resources/zh-rTW/strings.xml @@ -610,7 +610,6 @@ 重設預設使用者代理字串 預設使用者代理字串 全部清除 - 不支援 RARv5 格式 當需要解鎖才能存取應用程式時,無法使用小工具 查看書櫃中近期更新的作品 已在進行更新 @@ -686,7 +685,7 @@ %1$s 發生錯誤:%2$s *必填 隱藏已在書櫃的作品 - 複製到剪貼簿 + 複製 更新類別 分割過高的圖片 封面附加元素 @@ -810,4 +809,15 @@ 預告 檢視新刊預告 無法取得永久性資料夾存取權,應用程式可能會表現異常。 + + 黑白 + 這部漫畫要麼已完結,又或是無預計發布日期。 + 閃爍時間 + %1$s 毫秒 + 閃爍間隔 + 閃爍於 + + 備份檔案已損壞 + 不支援 JSON 備份 + 擴充套件儲存庫 \ No newline at end of file From 200d39e023af79b02276554a1bef1d7d53e3b903 Mon Sep 17 00:00:00 2001 From: Catting <5874051+mm12@users.noreply.github.com> Date: Sun, 11 Aug 2024 12:10:36 -0500 Subject: [PATCH 138/297] Add Copy Tracker URL on icon long press (#1101) * Add Copy Tracker URL on icon long press Signed-off-by: Catt0s <5874051+mm12@users.noreply.github.com> * Add 'Copy To Clipboard' to tracker item menu Signed-off-by: Catt0s <5874051+mm12@users.noreply.github.com> * Add 'Copy link' to locales. Signed-off-by: Catt0s <5874051+mm12@users.noreply.github.com> * Implement code review suggestions > > Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Signed-off-by: Catt0s <5874051+mm12@users.noreply.github.com> * Update app/src/main/java/eu/kanade/presentation/track/components/TrackLogoIcon.kt --------- Signed-off-by: Catt0s <5874051+mm12@users.noreply.github.com> Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com> --- .../presentation/track/TrackInfoDialogHome.kt | 13 +++++++++++++ .../track/TrackInfoDialogHomePreviewProvider.kt | 2 ++ .../presentation/track/components/TrackLogoIcon.kt | 4 +++- .../tachiyomi/ui/manga/track/TrackInfoDialog.kt | 9 +++++++++ i18n/src/commonMain/moko-resources/base/strings.xml | 1 + 5 files changed, 28 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHome.kt b/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHome.kt index 7ed6b3cc0..4e146c60e 100644 --- a/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHome.kt +++ b/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHome.kt @@ -72,6 +72,7 @@ fun TrackInfoDialogHome( onNewSearch: (TrackItem) -> Unit, onOpenInBrowser: (TrackItem) -> Unit, onRemoved: (TrackItem) -> Unit, + onCopyLink: (TrackItem) -> Unit, ) { Column( modifier = Modifier @@ -116,6 +117,7 @@ fun TrackInfoDialogHome( onNewSearch = { onNewSearch(item) }, onOpenInBrowser = { onOpenInBrowser(item) }, onRemoved = { onRemoved(item) }, + onCopyLink = { onCopyLink(item) }, ) } else { TrackInfoItemEmpty( @@ -144,6 +146,7 @@ private fun TrackInfoItem( onNewSearch: () -> Unit, onOpenInBrowser: () -> Unit, onRemoved: () -> Unit, + onCopyLink: () -> Unit, ) { val context = LocalContext.current Column { @@ -153,6 +156,7 @@ private fun TrackInfoItem( TrackLogoIcon( tracker = tracker, onClick = onOpenInBrowser, + onLongClick = onCopyLink, ) Box( modifier = Modifier @@ -179,6 +183,7 @@ private fun TrackInfoItem( TrackInfoItemMenu( onOpenInBrowser = onOpenInBrowser, onRemoved = onRemoved, + onCopyLink = onCopyLink, ) } @@ -287,6 +292,7 @@ private fun TrackInfoItemEmpty( private fun TrackInfoItemMenu( onOpenInBrowser: () -> Unit, onRemoved: () -> Unit, + onCopyLink: () -> Unit, ) { var expanded by remember { mutableStateOf(false) } Box(modifier = Modifier.wrapContentSize(Alignment.TopStart)) { @@ -307,6 +313,13 @@ private fun TrackInfoItemMenu( expanded = false }, ) + DropdownMenuItem( + text = { Text(stringResource(MR.strings.action_copy_link)) }, + onClick = { + onCopyLink() + expanded = false + }, + ) DropdownMenuItem( text = { Text(stringResource(MR.strings.action_remove)) }, onClick = { 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 aa58403ea..3b60a9277 100644 --- a/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHomePreviewProvider.kt +++ b/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHomePreviewProvider.kt @@ -56,6 +56,7 @@ internal class TrackInfoDialogHomePreviewProvider : onNewSearch = {}, onOpenInBrowser = {}, onRemoved = {}, + onCopyLink = {}, ) } @@ -71,6 +72,7 @@ internal class TrackInfoDialogHomePreviewProvider : onNewSearch = {}, onOpenInBrowser = {}, onRemoved = {}, + onCopyLink = {}, ) } diff --git a/app/src/main/java/eu/kanade/presentation/track/components/TrackLogoIcon.kt b/app/src/main/java/eu/kanade/presentation/track/components/TrackLogoIcon.kt index 4dd03ecc7..7488d0da9 100644 --- a/app/src/main/java/eu/kanade/presentation/track/components/TrackLogoIcon.kt +++ b/app/src/main/java/eu/kanade/presentation/track/components/TrackLogoIcon.kt @@ -22,9 +22,10 @@ import tachiyomi.presentation.core.util.clickableNoIndication fun TrackLogoIcon( tracker: Tracker, onClick: (() -> Unit)? = null, + onLongClick: (() -> Unit)? = null, ) { val modifier = if (onClick != null) { - Modifier.clickableNoIndication(onClick = onClick) + Modifier.clickableNoIndication(onClick = onClick, onLongClick = onLongClick) } else { Modifier } @@ -53,6 +54,7 @@ private fun TrackLogoIconPreviews( TrackLogoIcon( tracker = tracker, onClick = null, + onLongClick = null, ) } } 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 4c66940c9..e8c919c9d 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 @@ -54,6 +54,7 @@ import eu.kanade.tachiyomi.data.track.Tracker import eu.kanade.tachiyomi.data.track.TrackerManager import eu.kanade.tachiyomi.data.track.model.TrackSearch import eu.kanade.tachiyomi.util.lang.convertEpochMillisZone +import eu.kanade.tachiyomi.util.system.copyToClipboard import eu.kanade.tachiyomi.util.system.openInBrowser import eu.kanade.tachiyomi.util.system.toast import kotlinx.collections.immutable.ImmutableList @@ -170,6 +171,7 @@ data class TrackInfoDialogHomeScreen( ), ) }, + onCopyLink = { context.copyTrackerLink(it) }, ) } @@ -183,6 +185,13 @@ data class TrackInfoDialogHomeScreen( } } + private fun Context.copyTrackerLink(trackItem: TrackItem) { + val url = trackItem.track?.remoteUrl ?: return + if (url.isNotBlank()) { + copyToClipboard(url, url) + } + } + private class Model( private val mangaId: Long, private val sourceId: Long, diff --git a/i18n/src/commonMain/moko-resources/base/strings.xml b/i18n/src/commonMain/moko-resources/base/strings.xml index 90719fb92..bdd75f70b 100644 --- a/i18n/src/commonMain/moko-resources/base/strings.xml +++ b/i18n/src/commonMain/moko-resources/base/strings.xml @@ -110,6 +110,7 @@ Open in browser Show entry Copy to clipboard + Copy link Open in WebView WebView From 84b2164787a795f3fd757c325cbfb6ef660ac3a3 Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Mon, 12 Aug 2024 02:50:45 +0600 Subject: [PATCH 139/297] Add a button to select all scanlators Resolves #943 Closes #1109 --- .../manga/components/ScanlatorFilterDialog.kt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/manga/components/ScanlatorFilterDialog.kt b/app/src/main/java/eu/kanade/presentation/manga/components/ScanlatorFilterDialog.kt index 747ac09e0..007dd8153 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/components/ScanlatorFilterDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/components/ScanlatorFilterDialog.kt @@ -108,8 +108,14 @@ fun ScanlatorFilterDialog( } } else { FlowRow { - TextButton(onClick = mutableExcludedScanlators::clear) { - Text(text = stringResource(MR.strings.action_reset)) + if (mutableExcludedScanlators.isEmpty()) { + TextButton(onClick = { mutableExcludedScanlators.addAll(availableScanlators) }) { + Text(text = stringResource(MR.strings.action_select_all)) + } + } else { + TextButton(onClick = mutableExcludedScanlators::clear) { + Text(text = stringResource(MR.strings.action_reset)) + } } Spacer(modifier = Modifier.weight(1f)) TextButton(onClick = onDismissRequest) { From 3f1d28c3833e6b868152149ed02b3fb8c54eccef Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Mon, 12 Aug 2024 03:21:17 +0600 Subject: [PATCH 140/297] Fix UI freeze after migration Fixes #938 --- .../java/mihon/core/migration/MigrationStrategyFactory.kt | 4 +--- app/src/main/java/mihon/core/migration/Migrator.kt | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/mihon/core/migration/MigrationStrategyFactory.kt b/app/src/main/java/mihon/core/migration/MigrationStrategyFactory.kt index 7e06fecb3..0905cc086 100644 --- a/app/src/main/java/mihon/core/migration/MigrationStrategyFactory.kt +++ b/app/src/main/java/mihon/core/migration/MigrationStrategyFactory.kt @@ -6,15 +6,13 @@ class MigrationStrategyFactory( ) { fun create(old: Int, new: Int): MigrationStrategy { - val versions = (old + 1)..new val strategy = when { old == 0 -> InitialMigrationStrategy( strategy = DefaultMigrationStrategy(factory, migrationCompletedListener, Migrator.scope), ) - old >= new -> NoopMigrationStrategy(false) else -> VersionRangeMigrationStrategy( - versions = versions, + versions = (old + 1)..new, strategy = DefaultMigrationStrategy(factory, migrationCompletedListener, Migrator.scope), ) } diff --git a/app/src/main/java/mihon/core/migration/Migrator.kt b/app/src/main/java/mihon/core/migration/Migrator.kt index 11f22a8c9..2296aa074 100644 --- a/app/src/main/java/mihon/core/migration/Migrator.kt +++ b/app/src/main/java/mihon/core/migration/Migrator.kt @@ -10,7 +10,7 @@ import kotlinx.coroutines.runBlocking object Migrator { private var result: Deferred? = null - val scope = CoroutineScope(Dispatchers.Main + Job()) + val scope = CoroutineScope(Dispatchers.IO + Job()) fun initialize( old: Int, From c5994e057b37484fec3a5300491946afe377a90a Mon Sep 17 00:00:00 2001 From: Catting <5874051+mm12@users.noreply.github.com> Date: Sun, 11 Aug 2024 16:52:47 -0500 Subject: [PATCH 141/297] Add an "open in browser" button to reader menu (#1110) * Add an "open in browser" button to reader menu Signed-off-by: Catting <5874051+mm12@users.noreply.github.com> * fixup! Add an "open in browser" button to reader menu Signed-off-by: Catting <5874051+mm12@users.noreply.github.com> --------- Signed-off-by: Catting <5874051+mm12@users.noreply.github.com> --- .../kanade/presentation/reader/appbars/ReaderAppBars.kt | 9 +++++++++ .../java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt | 8 ++++++++ 2 files changed, 17 insertions(+) diff --git a/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt b/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt index 964172483..124f3a6c3 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt @@ -45,6 +45,7 @@ fun ReaderAppBars( onClickTopAppBar: () -> Unit, bookmarked: Boolean, onToggleBookmarked: () -> Unit, + onOpenInBrowser: (() -> Unit)?, onOpenInWebView: (() -> Unit)?, onShare: (() -> Unit)?, @@ -119,6 +120,14 @@ fun ReaderAppBars( onClick = onToggleBookmarked, ), ) + onOpenInBrowser?.let { + add( + AppBar.OverflowAction( + title = stringResource(MR.strings.action_open_in_browser), + onClick = it, + ), + ) + } onOpenInWebView?.let { add( AppBar.OverflowAction( diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt index 1a177e211..7f0b3ab35 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt @@ -75,6 +75,7 @@ import eu.kanade.tachiyomi.ui.reader.viewer.ReaderProgressIndicator import eu.kanade.tachiyomi.ui.webview.WebViewActivity import eu.kanade.tachiyomi.util.system.hasDisplayCutout import eu.kanade.tachiyomi.util.system.isNightMode +import eu.kanade.tachiyomi.util.system.openInBrowser import eu.kanade.tachiyomi.util.system.toShareIntent import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.view.setComposeContent @@ -389,6 +390,7 @@ class ReaderActivity : BaseActivity() { onClickTopAppBar = ::openMangaScreen, bookmarked = state.bookmarked, onToggleBookmarked = viewModel::toggleChapterBookmark, + onOpenInBrowser = ::openChapterInBrowser.takeIf { isHttpSource }, onOpenInWebView = ::openChapterInWebView.takeIf { isHttpSource }, onShare = ::shareChapter.takeIf { isHttpSource }, @@ -563,6 +565,12 @@ class ReaderActivity : BaseActivity() { } } + private fun openChapterInBrowser() { + assistUrl?.let { + openInBrowser(it.toUri(), forceDefaultBrowser = false) + } + } + private fun openChapterInWebView() { val manga = viewModel.manga ?: return val source = viewModel.getSource() ?: return From fdb96179c6373eb0a8e7d6daea671a315d5ce5f0 Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Mon, 12 Aug 2024 05:22:56 +0600 Subject: [PATCH 142/297] Handle Android SDK 35 API collision --- .../java/eu/kanade/tachiyomi/extension/installer/Installer.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/installer/Installer.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/installer/Installer.kt index 0e1ee3684..495e82e91 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/installer/Installer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/installer/Installer.kt @@ -102,7 +102,7 @@ abstract class Installer(private val service: Service) { } val nextEntry = queue.first() if (waitingInstall.compareAndSet(null, nextEntry)) { - queue.removeFirst() + queue.removeAt(0) processEntry(nextEntry) } } From be124ebe86377ad77de5abd1594afd7aedf9050c Mon Sep 17 00:00:00 2001 From: MajorTanya <39014446+MajorTanya@users.noreply.github.com> Date: Mon, 12 Aug 2024 01:36:34 +0200 Subject: [PATCH 143/297] Fix some migrations never running (#1114) Both `SetupBackupCreateMigration` and `SetupLibraryUpdateMigration` were trying to get the `App` class from Injekt which is never provided via the `AppModule`. Using `Application` instead works since the `workManager` property used by the respective `setupTask` functions is an extension property on `Context`. Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com> --- .../core/migration/migrations/SetupBackupCreateMigration.kt | 4 ++-- .../core/migration/migrations/SetupLibraryUpdateMigration.kt | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/mihon/core/migration/migrations/SetupBackupCreateMigration.kt b/app/src/main/java/mihon/core/migration/migrations/SetupBackupCreateMigration.kt index 44c0b557c..aabd5935f 100644 --- a/app/src/main/java/mihon/core/migration/migrations/SetupBackupCreateMigration.kt +++ b/app/src/main/java/mihon/core/migration/migrations/SetupBackupCreateMigration.kt @@ -1,6 +1,6 @@ package mihon.core.migration.migrations -import eu.kanade.tachiyomi.App +import android.app.Application import eu.kanade.tachiyomi.data.backup.create.BackupCreateJob import mihon.core.migration.Migration import mihon.core.migration.MigrationContext @@ -9,7 +9,7 @@ class SetupBackupCreateMigration : Migration { override val version: Float = Migration.ALWAYS override suspend fun invoke(migrationContext: MigrationContext): Boolean { - val context = migrationContext.get() ?: return false + val context = migrationContext.get() ?: return false BackupCreateJob.setupTask(context) return true } diff --git a/app/src/main/java/mihon/core/migration/migrations/SetupLibraryUpdateMigration.kt b/app/src/main/java/mihon/core/migration/migrations/SetupLibraryUpdateMigration.kt index 65482cd89..08b84c9a0 100644 --- a/app/src/main/java/mihon/core/migration/migrations/SetupLibraryUpdateMigration.kt +++ b/app/src/main/java/mihon/core/migration/migrations/SetupLibraryUpdateMigration.kt @@ -1,6 +1,6 @@ package mihon.core.migration.migrations -import eu.kanade.tachiyomi.App +import android.app.Application import eu.kanade.tachiyomi.data.library.LibraryUpdateJob import mihon.core.migration.Migration import mihon.core.migration.MigrationContext @@ -9,7 +9,7 @@ class SetupLibraryUpdateMigration : Migration { override val version: Float = Migration.ALWAYS override suspend fun invoke(migrationContext: MigrationContext): Boolean { - val context = migrationContext.get() ?: return false + val context = migrationContext.get() ?: return false LibraryUpdateJob.setupTask(context) return true } From b404a71e26526844600a9918eb796219667be498 Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Mon, 12 Aug 2024 23:34:46 +0600 Subject: [PATCH 144/297] Create CHANGELOG.md --- CHANGELOG.md | 133 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..e60c54e3a --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,133 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] +### Added +- Option to disable reader zoom out (@Splintorien) +- Source name and tracker urls to app generated `ComicInfo.xml` file (@Shamicen) +- Option to migrate in Duplicate entry dialog (@sirlag) +- Upcoming screen to visualize expected update dates (@sirlag) +- Crash screen error message to the top of the crash log generated from that screen (@FooIbar) +- Support for 7Zip and RAR5 archives (@FooIbar, @null2264) +- Extra configuration options to e-ink page flashes (@sirlag) +- 8-bit+ AVIF image support (@WerctFourth) +- Smart update dialog message when no predicted released date exists (@Animeboynz) +- Save global search "Has result" choice (@AntsyLich) +- Option to copy reader panel to clipboard (@Animeboynz) +- Copy Tracker URL option to tracker sheet (@mm12) +- A button to exclude all scanlators in exclude scanlators dialog (@AntsyLich) +- Open in browser option to reader menu (@mm12) + +### Changed +- Read archive files from memory instead of extracting files to internal storage (@FooIbar) +- Try to get resource from Extension before checking in the app (@beer-psi) +- Default user agent (@AntsyLich) +- Wait for sources to be initialized before performing source related tasks (@jobobby04) +- Duplicate entry dialog UI (@sirlag) +- Extension trust system (@AntsyLich) +- Make category backup/restore not dependant on library backup (@AntsyLich) +- Kitsu domain to `kitsu.app` (@MajorTanya) + +### Improvement +- Long strip reader performance (@FooIbar, @wwww-wwww) +- Performance when looking up specific files (@raxod502) +- Chapter number parsing (@Naputt1) +- Error message on restoring if backup decoding fails (@vetleledaal) + +### Fixed +- Creating `ComicInfo.xml` file for local source (@FooIbar) +- Chapter download indicator (@ivaniskandar) +- Crash when trying to load some corrupt image (@az4521) +- Issues with shizuku in a multi user setup (@Redjard) +- Occasional black bar when scrolling in long strip reader (@FooIbar) +- Extension being marked as not installed instead of untrusted after updating with private installer (@AntsyLich) +- Extension update counter not updating due to extension being marked as untrusted (@AntsyLich) +- `Key "extension-XXX-YYY" was already used` crash (@AntsyLich) +- Navigation layout tap zones shifting after zooming out in webtoon readers (@FooIbar) +- Some extension not loading due to missing classes (@AwkwardPeak7) +- Theme colors in accordance to upstream changes (@CrepeTF) +- Crash when requesting folder access on non-conforming devices (@mainrs) +- Bugged color for Date/Scanlator in chapter list for read chapters (@ivaniskandar) +- Categories having same `order` after restoring backup (@Cologler) +- Filter by "Tracking" temporarily stuck after signing out of tracker (@AntsyLich) +- JXL image downloading and loading (@FooIbar) +- Crash when using `%` in category name (@Animeboynz, @FooIbar) +- Library is backed up while being disabled (@AntsyLich) +- Crash on list with 0 item but only sticky header (@cuong-tran) +- Crash when trying to clear cookies of some source (@FooIbar) +- MAL search results not showing start dates (@MajorTanya) +- Android SDK 35 API collision (@AntsyLich) + +## [v0.16.5] - 2024-04-09 +## Added +- Setting to install custom color profiles to get true colors (@wwww-wwww) + +## Changed +- Permanently enable 32-bit color mode (@wwww-wwww) + +## Fixed +- Fix wrong dates in Updates and History tab due to time zone issues (@sirlag) +- Fix app infinitely retries tracker update instead of failing after 3 tries (@MajorTanya) +- Fix crash on Pixel devices +- Fix crash when opening some heif/heic images (@az4521) +- Fix crash in track date selection dialog (@ivaniskandar) +- Fix dates for saved images on Samsung devices (@MajorTanya) +- Fix colors getting distorted when opening CMYK jpeg images (@wwww-wwww) + +## [v0.16.4] - 2024-02-26 +## Fixed +- Circumvent MAL block (@AntsyLich) + +## [v0.16.3] - 2024-01-30 +## Added +- Copy extension debug info when clicking logo or name in the extension details screen (@MajorTanya) + +## Changed +- Rename extension update error file to `mihon_update_errors.txt` (@m-jishnu) +- Hide display cutoff setting in reader settings sheet if fullscreen is off (@Riztard) + +## Fixed +- Fix bottom sheet display issues on non-Tablet UI (@theolm) +- Fix crash when switching screen while a list is scrolling (@theolm) +- Fix newly installed extensions not being recognized by Mihon (@AwkwardPeak7) +- Fix error handling when refreshing MAL OAuth token (@AntsyLich) + +## [v0.16.2] - 2024-01-28 +## Added +- Scanlator filter is now part of Backup (@jobobby04) + +## Changed +- Rename crash log filename to `mihon_crash_logs.txt` (@MajorTanya) + +## Fixed +- "Flash screen on page change" Making the screen goes blank (@AntsyLich) +- App icon scaling (@AntsyLich) +- Updating extension not reflecting correctly (@AntsyLich) +- Inconsistent button height with some languages in "Data and storage" (@theolm) +- Fix chapter not being marked as read in some cases with Enhanced Trackers (@Secozzi) +- And various tracker related fixes (@AntsyLich, @Secozzi) + +## [v0.16.1] - 2024-01-18 +## Fixed +- App Icon not filled (@AntsyLich) +- MangaUpdates default score being set to -1.0 (@AntsyLich) + +## [v0.16.0] - 2024-01-16 + +"The end of 立ち読み (Tachiyomi) is the beginning of みほん (Mihon)" +Credit to LinkCable, the icon designer, for this poetic quote. + +What's New? +Well, nothing, except you now you need Android 8+ to install the app. + +[unreleased]: https://github.com/mihonapp/mihon/compare/v0.16.5...HEAD +[v0.16.5]: https://github.com/mihonapp/mihon/compare/v0.16.4...v0.16.5 +[v0.16.4]: https://github.com/mihonapp/mihon/compare/v0.16.3...v0.16.4 +[v0.16.3]: https://github.com/mihonapp/mihon/compare/v0.16.2...v0.16.3 +[v0.16.2]: https://github.com/mihonapp/mihon/compare/v0.16.1...v0.16.2 +[v0.16.1]: https://github.com/mihonapp/mihon/compare/v0.16.0...v0.16.1 +[v0.16.0]: https://github.com/mihonapp/mihon/releases/tag/v0.16.0 From 124a787cdae215b59250f1a1365ad8ef9d53d8d6 Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Mon, 12 Aug 2024 23:51:56 +0600 Subject: [PATCH 145/297] Update CHANGELOG.md --- CHANGELOG.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e60c54e3a..b16c3a5ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -63,13 +63,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Android SDK 35 API collision (@AntsyLich) ## [v0.16.5] - 2024-04-09 -## Added +### Added - Setting to install custom color profiles to get true colors (@wwww-wwww) -## Changed +### Changed - Permanently enable 32-bit color mode (@wwww-wwww) -## Fixed +### Fixed - Fix wrong dates in Updates and History tab due to time zone issues (@sirlag) - Fix app infinitely retries tracker update instead of failing after 3 tries (@MajorTanya) - Fix crash on Pixel devices @@ -79,31 +79,31 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix colors getting distorted when opening CMYK jpeg images (@wwww-wwww) ## [v0.16.4] - 2024-02-26 -## Fixed +### Fixed - Circumvent MAL block (@AntsyLich) ## [v0.16.3] - 2024-01-30 -## Added +### Added - Copy extension debug info when clicking logo or name in the extension details screen (@MajorTanya) -## Changed +### Changed - Rename extension update error file to `mihon_update_errors.txt` (@m-jishnu) - Hide display cutoff setting in reader settings sheet if fullscreen is off (@Riztard) -## Fixed +### Fixed - Fix bottom sheet display issues on non-Tablet UI (@theolm) - Fix crash when switching screen while a list is scrolling (@theolm) - Fix newly installed extensions not being recognized by Mihon (@AwkwardPeak7) - Fix error handling when refreshing MAL OAuth token (@AntsyLich) ## [v0.16.2] - 2024-01-28 -## Added +### Added - Scanlator filter is now part of Backup (@jobobby04) -## Changed +### Changed - Rename crash log filename to `mihon_crash_logs.txt` (@MajorTanya) -## Fixed +### Fixed - "Flash screen on page change" Making the screen goes blank (@AntsyLich) - App icon scaling (@AntsyLich) - Updating extension not reflecting correctly (@AntsyLich) @@ -112,7 +112,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - And various tracker related fixes (@AntsyLich, @Secozzi) ## [v0.16.1] - 2024-01-18 -## Fixed +### Fixed - App Icon not filled (@AntsyLich) - MangaUpdates default score being set to -1.0 (@AntsyLich) From 9a34ace09c66274e6c2b3f9446058a0fa99d4bd0 Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Tue, 13 Aug 2024 12:42:32 +0600 Subject: [PATCH 146/297] Sync compose theme with MDC theme --- CHANGELOG.md | 2 +- app/src/main/res/values-night/themes.xml | 9 +- app/src/main/res/values/themes.xml | 172 +++++++++++++----- .../src/main/res/values-night/colors.xml | 5 - .../res/values-night/colors_greenapple.xml | 53 ++++-- .../main/res/values-night/colors_lavender.xml | 46 +++-- .../res/values-night/colors_midnightdusk.xml | 19 +- .../src/main/res/values-night/colors_nord.xml | 20 +- .../res/values-night/colors_strawberry.xml | 49 +++-- .../res/values-night/colors_tachiyomi.xml | 49 +++-- .../src/main/res/values-night/colors_tako.xml | 21 ++- .../res/values-night/colors_tealturqoise.xml | 16 +- .../res/values-night/colors_tidalwave.xml | 15 +- .../main/res/values-night/colors_yinyang.xml | 14 +- .../main/res/values-night/colors_yotsuba.xml | 14 +- .../src/main/res/values/colors.xml | 14 +- .../src/main/res/values/colors_greenapple.xml | 51 ++++-- .../src/main/res/values/colors_lavender.xml | 42 +++-- .../main/res/values/colors_midnightdusk.xml | 19 +- .../src/main/res/values/colors_nord.xml | 15 +- .../src/main/res/values/colors_strawberry.xml | 51 ++++-- .../src/main/res/values/colors_tachiyomi.xml | 45 +++-- .../src/main/res/values/colors_tako.xml | 15 +- .../main/res/values/colors_tealturqoise.xml | 18 +- .../src/main/res/values/colors_tidalwave.xml | 16 +- .../src/main/res/values/colors_yinyang.xml | 14 +- .../src/main/res/values/colors_yotsuba.xml | 16 +- 27 files changed, 537 insertions(+), 283 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b16c3a5ad..55d7c729a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,7 +49,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `Key "extension-XXX-YYY" was already used` crash (@AntsyLich) - Navigation layout tap zones shifting after zooming out in webtoon readers (@FooIbar) - Some extension not loading due to missing classes (@AwkwardPeak7) -- Theme colors in accordance to upstream changes (@CrepeTF) +- Theme colors in accordance to upstream changes (@CrepeTF, @AntsyLich) - Crash when requesting folder access on non-conforming devices (@mainrs) - Bugged color for Date/Scanlator in chapter list for read chapters (@ivaniskandar) - Categories having same `order` after restoring backup (@Cologler) diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml index 24200c407..c79fcf02a 100644 --- a/app/src/main/res/values-night/themes.xml +++ b/app/src/main/res/values-night/themes.xml @@ -4,8 +4,13 @@ diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 2e6458eca..d0fb6fca7 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -15,6 +15,7 @@ @color/tachiyomi_onPrimary @color/tachiyomi_primaryContainer @color/tachiyomi_onPrimaryContainer + @color/tachiyomi_inversePrimary @color/tachiyomi_secondary @color/tachiyomi_onSecondary @color/tachiyomi_secondaryContainer @@ -29,14 +30,20 @@ @color/tachiyomi_onSurface @color/tachiyomi_surfaceVariant @color/tachiyomi_onSurfaceVariant - @color/tachiyomi_outline - @color/tachiyomi_inverseOnSurface + @color/tachiyomi_surfaceTint @color/tachiyomi_inverseSurface - @color/tachiyomi_primaryInverse - @color/error - @color/onError - @color/errorContainer - @color/onErrorContainer + @color/tachiyomi_inverseOnSurface + @color/tachiyomi_error + @color/tachiyomi_onError + @color/tachiyomi_errorContainer + @color/tachiyomi_onErrorContainer + @color/tachiyomi_outline + @color/tachiyomi_outlineVariant + @color/tachiyomi_surfaceContainer + @color/tachiyomi_surfaceContainerHigh + @color/tachiyomi_surfaceContainerHighest + @color/tachiyomi_surfaceContainerLow + @color/tachiyomi_surfaceContainerLowest @color/divider_default @drawable/line_divider @@ -52,7 +59,7 @@ @bool/lightStatusBar @android:color/transparent - @color/surface_amoled + @color/amoled_surface @null false false @@ -91,6 +98,7 @@ @color/greenapple_onPrimary @color/greenapple_primaryContainer @color/greenapple_onPrimaryContainer + @color/greenapple_inversePrimary @color/greenapple_secondary @color/greenapple_onSecondary @color/greenapple_secondaryContainer @@ -105,10 +113,22 @@ @color/greenapple_onSurface @color/greenapple_surfaceVariant @color/greenapple_onSurfaceVariant - @color/greenapple_outline - @color/greenapple_inverseOnSurface @color/greenapple_inverseSurface - @color/greenapple_primaryInverse + @color/greenapple_inverseOnSurface + @color/greenapple_error + @color/greenapple_onError + @color/greenapple_errorContainer + @color/greenapple_onErrorContainer + @color/greenapple_outline + @color/greenapple_outlineVariant + @color/greenapple_scrim + @color/greenapple_surfaceBright + @color/greenapple_surfaceDim + @color/greenapple_surfaceContainer + @color/greenapple_surfaceContainerHigh + @color/greenapple_surfaceContainerHighest + @color/greenapple_surfaceContainerLow + @color/greenapple_surfaceContainerLowest @@ -118,6 +138,7 @@ @color/lavender_onPrimary @color/lavender_primaryContainer @color/lavender_onPrimaryContainer + @color/lavender_inversePrimary @color/lavender_secondary @color/lavender_onSecondary @color/lavender_secondaryContainer @@ -132,11 +153,22 @@ @color/lavender_onSurface @color/lavender_surfaceVariant @color/lavender_onSurfaceVariant - @color/lavender_outline - @color/lavender_inverseOnSurface @color/lavender_inverseSurface - @color/lavender_primaryInverse - @color/lavender_elevationOverlay + @color/lavender_inverseOnSurface + @color/lavender_error + @color/lavender_onError + @color/lavender_errorContainer + @color/lavender_onErrorContainer + @color/lavender_outline + @color/lavender_outlineVariant + @color/lavender_scrim + @color/lavender_surfaceBright + @color/lavender_surfaceDim + @color/lavender_surfaceContainer + @color/lavender_surfaceContainerHigh + @color/lavender_surfaceContainerHighest + @color/lavender_surfaceContainerLow + @color/lavender_surfaceContainerLowest @@ -146,6 +178,7 @@ @color/midnightdusk_onPrimary @color/midnightdusk_primaryContainer @color/midnightdusk_onPrimaryContainer + @color/midnightdusk_inversePrimary @color/midnightdusk_secondary @color/midnightdusk_onSecondary @color/midnightdusk_secondaryContainer @@ -160,11 +193,15 @@ @color/midnightdusk_onSurface @color/midnightdusk_surfaceVariant @color/midnightdusk_onSurfaceVariant - @color/midnightdusk_outline - @color/midnightdusk_inverseOnSurface + @color/midnightdusk_surfaceTint @color/midnightdusk_inverseSurface - @color/midnightdusk_primaryInverse - @color/midnightdusk_elevationOverlay + @color/midnightdusk_inverseOnSurface + @color/midnightdusk_outline + @color/midnightdusk_surfaceContainer + @color/midnightdusk_surfaceContainerHigh + @color/midnightdusk_surfaceContainerHighest + @color/midnightdusk_surfaceContainerLow + @color/midnightdusk_surfaceContainerLowest @@ -174,6 +211,7 @@ @color/strawberry_onPrimary @color/strawberry_primaryContainer @color/strawberry_onPrimaryContainer + @color/strawberry_inversePrimary @color/strawberry_secondary @color/strawberry_onSecondary @color/strawberry_secondaryContainer @@ -188,10 +226,22 @@ @color/strawberry_onSurface @color/strawberry_surfaceVariant @color/strawberry_onSurfaceVariant - @color/strawberry_outline - @color/strawberry_inverseOnSurface @color/strawberry_inverseSurface - @color/strawberry_primaryInverse + @color/strawberry_inverseOnSurface + @color/strawberry_error + @color/strawberry_onError + @color/strawberry_errorContainer + @color/strawberry_onErrorContainer + @color/strawberry_outline + @color/strawberry_outlineVariant + @color/strawberry_scrim + @color/strawberry_surfaceBright + @color/strawberry_surfaceDim + @color/strawberry_surfaceContainer + @color/strawberry_surfaceContainerHigh + @color/strawberry_surfaceContainerHighest + @color/strawberry_surfaceContainerLow + @color/strawberry_surfaceContainerLowest @@ -201,6 +251,7 @@ @color/tako_onPrimary @color/tako_primaryContainer @color/tako_onPrimaryContainer + @color/tako_inversePrimary @color/tako_secondary @color/tako_onSecondary @color/tako_secondaryContainer @@ -215,11 +266,15 @@ @color/tako_onSurface @color/tako_surfaceVariant @color/tako_onSurfaceVariant - @color/tako_outline - @color/tako_inverseOnSurface + @color/tako_surfaceTint @color/tako_inverseSurface - @color/tako_primaryInverse - @color/tako_elevationOverlay + @color/tako_inverseOnSurface + @color/tako_outline + @color/tako_surfaceContainer + @color/tako_surfaceContainerHigh + @color/tako_surfaceContainerHighest + @color/tako_surfaceContainerLow + @color/tako_surfaceContainerLowest @@ -229,6 +284,7 @@ @color/tealturquoise_onPrimary @color/tealturquoise_primaryContainer @color/tealturquoise_onPrimaryContainer + @color/tealturquoise_inversePrimary @color/tealturquoise_secondary @color/tealturquoise_onSecondary @color/tealturquoise_secondaryContainer @@ -243,13 +299,15 @@ @color/tealturquoise_onSurface @color/tealturquoise_surfaceVariant @color/tealturquoise_onSurfaceVariant - @color/tealturquoise_outline - @color/tealturquoise_inverseOnSurface + @color/tealturquoise_surfaceTint @color/tealturquoise_inverseSurface - @color/tealturquoise_primaryInverse - @color/tealturquoise_tertiary - @color/tealturquoise_onTertiary - @color/tealturquoise_elevationOverlay + @color/tealturquoise_inverseOnSurface + @color/tealturquoise_outline + @color/tealturquoise_surfaceContainer + @color/tealturquoise_surfaceContainerHigh + @color/tealturquoise_surfaceContainerHighest + @color/tealturquoise_surfaceContainerLow + @color/tealturquoise_surfaceContainerLowest @@ -259,6 +317,7 @@ @color/yinyang_onPrimary @color/yinyang_primaryContainer @color/yinyang_onPrimaryContainer + @color/yinyang_inversePrimary @color/yinyang_secondary @color/yinyang_onSecondary @color/yinyang_secondaryContainer @@ -273,10 +332,15 @@ @color/yinyang_onSurface @color/yinyang_surfaceVariant @color/yinyang_onSurfaceVariant - @color/yinyang_outline - @color/yinyang_inverseOnSurface + @color/yinyang_surfaceTint @color/yinyang_inverseSurface - @color/yinyang_primaryInverse + @color/yinyang_inverseOnSurface + @color/yinyang_outline + @color/yinyang_surfaceContainer + @color/yinyang_surfaceContainerHigh + @color/yinyang_surfaceContainerHighest + @color/yinyang_surfaceContainerLow + @color/yinyang_surfaceContainerLowest @@ -286,6 +350,7 @@ @color/yotsuba_onPrimary @color/yotsuba_primaryContainer @color/yotsuba_onPrimaryContainer + @color/yotsuba_inversePrimary @color/yotsuba_secondary @color/yotsuba_onSecondary @color/yotsuba_secondaryContainer @@ -300,10 +365,15 @@ @color/yotsuba_onSurface @color/yotsuba_surfaceVariant @color/yotsuba_onSurfaceVariant - @color/yotsuba_outline - @color/yotsuba_inverseOnSurface + @color/yotsuba_surfaceTint @color/yotsuba_inverseSurface - @color/yotsuba_primaryInverse + @color/yotsuba_inverseOnSurface + @color/yotsuba_outline + @color/yotsuba_surfaceContainer + @color/yotsuba_surfaceContainerHigh + @color/yotsuba_surfaceContainerHighest + @color/yotsuba_surfaceContainerLow + @color/yotsuba_surfaceContainerLowest @@ -313,6 +383,7 @@ @color/tidalwave_onPrimary @color/tidalwave_primaryContainer @color/tidalwave_onPrimaryContainer + @color/tidalwave_inversePrimary @color/tidalwave_secondary @color/tidalwave_onSecondary @color/tidalwave_secondaryContainer @@ -327,10 +398,15 @@ @color/tidalwave_onSurface @color/tidalwave_surfaceVariant @color/tidalwave_onSurfaceVariant - @color/tidalwave_outline - @color/tidalwave_inverseOnSurface + @color/tidalwave_surfaceTint @color/tidalwave_inverseSurface - @color/tidalwave_primaryInverse + @color/tidalwave_inverseOnSurface + @color/tidalwave_outline + @color/tidalwave_surfaceContainer + @color/tidalwave_surfaceContainerHigh + @color/tidalwave_surfaceContainerHighest + @color/tidalwave_surfaceContainerLow + @color/tidalwave_surfaceContainerLowest @@ -340,6 +416,7 @@ @color/nord_onPrimary @color/nord_primaryContainer @color/nord_onPrimaryContainer + @color/nord_inversePrimary @color/nord_secondary @color/nord_onSecondary @color/nord_secondaryContainer @@ -354,14 +431,19 @@ @color/nord_onSurface @color/nord_surfaceVariant @color/nord_onSurfaceVariant - @color/nord_outline - @color/nord_inverseOnSurface + @color/nord_surfaceTint @color/nord_inverseSurface - @color/nord_primaryInverse + @color/nord_inverseOnSurface @color/nord_onError @color/nord_errorContainer @color/nord_onErrorContainer - @color/nord_elevationOverlay + @color/nord_outline + @color/nord_outlineVariant + @color/nord_surfaceContainer + @color/nord_surfaceContainerHigh + @color/nord_surfaceContainerHighest + @color/nord_surfaceContainerLow + @color/nord_surfaceContainerLowest diff --git a/presentation-core/src/main/res/values-night/colors.xml b/presentation-core/src/main/res/values-night/colors.xml index 9d6a4a86a..5f79e77f6 100644 --- a/presentation-core/src/main/res/values-night/colors.xml +++ b/presentation-core/src/main/res/values-night/colors.xml @@ -2,11 +2,6 @@ #202125 - #FFB4A9 - #930006 - #680003 - #FFDAD4 - @color/md_white_1000_12 diff --git a/presentation-core/src/main/res/values-night/colors_greenapple.xml b/presentation-core/src/main/res/values-night/colors_greenapple.xml index ecc50b64b..2d83e66e2 100644 --- a/presentation-core/src/main/res/values-night/colors_greenapple.xml +++ b/presentation-core/src/main/res/values-night/colors_greenapple.xml @@ -12,25 +12,38 @@ --> #7ADB8F - #003915 - #005322 - #96F8A9 + #003917 + #017737 + #FFFFFF #7ADB8F - #003915 - #005322 - #96F8A9 - #FFB3AA - #680006 - #93000D - #FFDAD5 - #1A1C19 - #E1E3DD - #1A1C19 - #E1E3DD - #414941 - #C1C8BE - #8B9389 - #1A1C19 - #E1E3DD - #006D2F + #003917 + #017737 + #FFFFFF + #FFB3AC + #680008 + #C7282A + #FFFFFF + #FFB4AB + #690005 + #93000A + #FFDAD6 + #0F1510 + #DFE4DB + #0F1510 + #DFE4DB + #3F493F + #BECABC + #889487 + #3F493F + #000000 + #DFE4DB + #2C322C + #006D32 + #0F1510 + #353B35 + #0A0F0B + #181D18 + #1C211C + #262B26 + #313630 diff --git a/presentation-core/src/main/res/values-night/colors_lavender.xml b/presentation-core/src/main/res/values-night/colors_lavender.xml index f9d558025..54cdbd450 100644 --- a/presentation-core/src/main/res/values-night/colors_lavender.xml +++ b/presentation-core/src/main/res/values-night/colors_lavender.xml @@ -12,26 +12,38 @@ --> #A177FF - #111129 + #3D0090 #A177FF - #111129 + #FFFFFF #A177FF - #111129 + #FFFFFF #423271 - #111129 - #5E25E1 - #E8E8E8 - #111129 - #DEE8FF + #A177FF + #CDBDFF + #360096 + #5512D8 + #EFE6FF + #FFB4AB + #690005 + #93000A + #FFDAD6 #111129 - #DEE8FF + #E7E0EC #111129 - #DEE8FF - #2CB6B6B6 - #E8E8E8 - #A8905FFF - #DEE8FF - #221247 - #A177FF - @color/lavender_primary + #E7E0EC + #3D2F6B + #CBC3D6 + #958E9F + #4A4453 + #000000 + #E7E0EC + #322F38 + #6D41C8 + #111129 + #3B3841 + #15132d + #171531 + #1D193B + #241f41 + #282446 diff --git a/presentation-core/src/main/res/values-night/colors_midnightdusk.xml b/presentation-core/src/main/res/values-night/colors_midnightdusk.xml index f10e84662..b245b1e7a 100644 --- a/presentation-core/src/main/res/values-night/colors_midnightdusk.xml +++ b/presentation-core/src/main/res/values-night/colors_midnightdusk.xml @@ -15,23 +15,28 @@ #FFFFFF #BD1C5C #FFFFFF + #F02475 #F02475 - #FFFFFF + #16151D #66183C - #FFFFFF + #F02475 #55971C - #FFFFFF + #16151D #386412 #E5E1E5 #16151D #E5E1E5 #16151D #E5E1E5 - #524346 + #281624 #D6C1C4 - #9F8C8F + #F02475 #333043 #FFFFFF - #F02475 - #2C0013 + #9F8C8F + #221320 + #251522 + #281624 + #2D1C2A + #2F1F2C \ No newline at end of file diff --git a/presentation-core/src/main/res/values-night/colors_nord.xml b/presentation-core/src/main/res/values-night/colors_nord.xml index 058d52a4a..0aeb36cf9 100644 --- a/presentation-core/src/main/res/values-night/colors_nord.xml +++ b/presentation-core/src/main/res/values-night/colors_nord.xml @@ -5,26 +5,32 @@ #2E3440 #88C0D0 #2E3440 + #397E91 #81A1C1 #2E3440 #506275 - #2E3440 + #88C0D0 #5E81AC #000000 #5E81AC #000000 #2E3440 #ECEFF4 - #3B4252 + #2E3440 #ECEFF4 - #2E3440 + #414C5C #ECEFF4 - #D8DEE9 - #2E3440 + #88C0D0 #D8DEE9 - #397E91 - #434C5E + #2E3440 + #6d717b + #90939a #2E3440 #BF616A #000000 + #373F4D + #3E4756 + #414C5C + #4E5766 + #505968 diff --git a/presentation-core/src/main/res/values-night/colors_strawberry.xml b/presentation-core/src/main/res/values-night/colors_strawberry.xml index 79071bd14..f1a7b4b73 100644 --- a/presentation-core/src/main/res/values-night/colors_strawberry.xml +++ b/presentation-core/src/main/res/values-night/colors_strawberry.xml @@ -11,26 +11,39 @@ ~ Neutral #655C5C --> - #FFB2B9 - #67001B - #91002A - #FFDADD - #FFB2B9 - #67001B + #FFB2B8 + #67001D + #D53855 + #FFFFFF + #ED4A65 + #201A1A #91002A - #FFDADD + #FFFFFF #E8C08E - #432C06 - #5D421B - #FFDDB1 + #201A1A + #775930 + #FFF7F1 + #FFB4AB + #690005 + #93000A + #FFDAD6 #201A1A - #ECDFDF + #F7DCDD #201A1A - #ECDFDF - #534344 - #D7C1C2 - #A08C8D - #201A1A - #ECDFDF - #B61E40 + #F7DCDD + #322727 + #E1BEC0 + #A9898B + #594042 + #000000 + #F7DCDD + #3D2C2D + #B61F40 + #1D1011 + #463536 + #2C2222 + #302525 + #322727 + #3C2F2F + #463737 diff --git a/presentation-core/src/main/res/values-night/colors_tachiyomi.xml b/presentation-core/src/main/res/values-night/colors_tachiyomi.xml index 40f5befcc..6af256bed 100644 --- a/presentation-core/src/main/res/values-night/colors_tachiyomi.xml +++ b/presentation-core/src/main/res/values-night/colors_tachiyomi.xml @@ -10,26 +10,37 @@ ~ Neutral #5E5E62 --> - #AEC6FF - #002C71 - #00419E - #D8E2FF - #AEC6FF - #002C71 - #00419E - #D8E2FF + #B0C6FF + #002D6E + #00429B + #D9E2FF + #0058CA + #B0C6FF + #002D6E + #00429B + #D9E2FF #7ADC77 - #003907 - #00530D + #003909 + #005312 #95F990 - #1B1B1E - #E4E2E6 - #1B1B1E - #E4E2E6 - #44464E + #1B1B1F + #E3E2E6 + #1B1B1F + #E3E2E6 + #211F26 #C5C6D0 - #8E9099 - #1B1B1E - #E4E2E6 - #0057CE + #B0C6FF + #E3E2E6 + #1B1B1F + #FFB4AB + #690005 + #93000A + #FFDAD6 + #8F9099 + #44464F + #1A181D + #1E1C22 + #211F26 + #292730 + #302E38 diff --git a/presentation-core/src/main/res/values-night/colors_tako.xml b/presentation-core/src/main/res/values-night/colors_tako.xml index 63c2db1ce..0824df1af 100644 --- a/presentation-core/src/main/res/values-night/colors_tako.xml +++ b/presentation-core/src/main/res/values-night/colors_tako.xml @@ -15,10 +15,11 @@ #38294E #F3B375 #38294E + #84531E #F3B375 - #5C4D4B - #F3B375 - #38294E + #38294E + #5C4D4B + #F3B375 #66577E #F3B375 #4E4065 @@ -27,11 +28,15 @@ #E3E0F2 #21212E #E3E0F2 - #49454E + #2A2A3C #CBC4CE - #958F99 - #1B1B1E + #66577E #E5E1E6 - #84531E - @color/tako_tertiary + #1B1B1E + #958F99 + #20202E + #262636 + #2A2A3C + #303044 + #36364D diff --git a/presentation-core/src/main/res/values-night/colors_tealturqoise.xml b/presentation-core/src/main/res/values-night/colors_tealturqoise.xml index 69d3e4d4e..21bff2b26 100644 --- a/presentation-core/src/main/res/values-night/colors_tealturqoise.xml +++ b/presentation-core/src/main/res/values-night/colors_tealturqoise.xml @@ -1,10 +1,10 @@ - #40E0D0 #000000 #40E0D0 #000000 + #008080 #40E0D0 #000000 #18544E @@ -17,11 +17,15 @@ #DFDEDA #202125 #DFDEDA - #3F4947 + #233133 #DFDEDA - #899391 - #202125 + #40E0D0 #DFDEDA - #008080 - #18544E + #202125 + #899391 + #202C2E + #222F31 + #233133 + #28383A + #2F4244 diff --git a/presentation-core/src/main/res/values-night/colors_tidalwave.xml b/presentation-core/src/main/res/values-night/colors_tidalwave.xml index 7cf425d55..c2eb63436 100644 --- a/presentation-core/src/main/res/values-night/colors_tidalwave.xml +++ b/presentation-core/src/main/res/values-night/colors_tidalwave.xml @@ -14,6 +14,7 @@ #003544 #004d61 #b8eaff + #a12b03 #5ed4fc #003544 #004d61 @@ -26,11 +27,15 @@ #d5e3ff #001c3b #d5e3ff - #40484c + #082b4b #bfc8cc - #8a9296 - #001c3b + #5ed4fc #ffe3c4 - #a12b03 - + #001c3b + #8a9296 + #072642 + #072947 + #082b4b + #093257 + #0A3861 \ No newline at end of file diff --git a/presentation-core/src/main/res/values-night/colors_yinyang.xml b/presentation-core/src/main/res/values-night/colors_yinyang.xml index 0a34a2da6..1dccc74e3 100644 --- a/presentation-core/src/main/res/values-night/colors_yinyang.xml +++ b/presentation-core/src/main/res/values-night/colors_yinyang.xml @@ -9,6 +9,7 @@ #5A5A5A #FFFFFF #000000 + #CECECE #FFFFFF #5A5A5A #717171 @@ -21,10 +22,15 @@ #E6E6E6 #1E1E1E #E6E6E6 - #4E4E4E + #313131 #D1D1D1 - #999999 - #1E1E1E + #FFFFFF #E6E6E6 - #CECECE + #1E1E1E + #999999 + #2A2A2A + #2D2D2D + #313131 + #383838 + #3F3F3F diff --git a/presentation-core/src/main/res/values-night/colors_yotsuba.xml b/presentation-core/src/main/res/values-night/colors_yotsuba.xml index 4ca498a18..74ddae02d 100644 --- a/presentation-core/src/main/res/values-night/colors_yotsuba.xml +++ b/presentation-core/src/main/res/values-night/colors_yotsuba.xml @@ -15,6 +15,7 @@ #5F1600 #862200 #FFDBCF + #AE3200 #FFB59D #5F1600 #862200 @@ -27,10 +28,15 @@ #EDE0DD #211A18 #EDE0DD - #53433F + #332723 #D8C2BC - #A08C87 - #211A18 + #FFB59D #EDE0DD - #AE3200 + #211A18 + #A08C87 + #2E221F + #312521 + #332723 + #413531 + #4C403D diff --git a/presentation-core/src/main/res/values/colors.xml b/presentation-core/src/main/res/values/colors.xml index 551dcc0a7..f8acc3cf4 100644 --- a/presentation-core/src/main/res/values/colors.xml +++ b/presentation-core/src/main/res/values/colors.xml @@ -4,11 +4,6 @@ #1F888888 - #BA1B1B - #FFDAD4 - #FFFFFF - #410001 - @color/md_black_1000_12 @@ -16,8 +11,13 @@ #54759E - #000001 - #000000 + #000000 + #FFFFFF + #000000 + #FFFFFF + #0C0C0C + #131313 + #1B1B1B #1F000000 diff --git a/presentation-core/src/main/res/values/colors_greenapple.xml b/presentation-core/src/main/res/values/colors_greenapple.xml index 13dbf83dc..df06d61e5 100644 --- a/presentation-core/src/main/res/values/colors_greenapple.xml +++ b/presentation-core/src/main/res/values/colors_greenapple.xml @@ -11,26 +11,39 @@ ~ Neutral #5D5F5B --> - #006D2F + #005927 #FFFFFF - #96F8A9 - #002109 - #006D2F + #188140 + #FFFFFF + #005927 #FFFFFF - #96F8A9 - #002109 - #B91D22 + #97f7a9 + #000000 + #9D0012 #FFFFFF - #FFDAD5 - #410003 - #FBFDF7 - #1A1C19 - #FBFDF7 - #1A1C19 - #DDE5DA - #414941 - #717970 - #F0F2EC - #2F312E - #7ADB8F + #D33131 + #FFFFFF + #BA1A1A + #FFFFFF + #FFDAD6 + #410002 + #F6FBF2 + #181D18 + #F6FBF2 + #181D18 + #DAE6D7 + #3F493F + #6F7A6E + #BECABC + #000000 + #2C322C + #EDF2E9 + #7ADB8F + #D6DCD3 + #F6FBF2 + #FFFFFF + #F0F5EC + #EAEFE6 + #E4EAE1 + #DFE4DB diff --git a/presentation-core/src/main/res/values/colors_lavender.xml b/presentation-core/src/main/res/values/colors_lavender.xml index 02d6274e3..dd763c2eb 100644 --- a/presentation-core/src/main/res/values/colors_lavender.xml +++ b/presentation-core/src/main/res/values/colors_lavender.xml @@ -10,27 +10,39 @@ ~ Neutral #EDE2FF --> - #7B46AF - #EDE2FF + #6D41C8 + #FFFFFF #7B46AF - #EDE2FF + #130038 #7B46AF #EDE2FF #C9B0E6 - #EDE2FF + #7B46AF #EDE2FF #7B46AF - #EDE2FF - #7B46AF + #6D3BF0 + #FFFFFF + #BA1A1A + #FFFFFF + #FFDAD6 + #410002 #EDE2FF - #1B1B22 + #1D1A22 #EDE2FF - #1B1B22 - #B9B0CC - #D849454E - #7B46AF - #F3EFF4 - #313033 - #D6BAFF - @color/lavender_primary + #1D1A22 + #E4D5F8 + #4A4453 + #7B7485 + #CBC3D6 + #000000 + #322F38 + #F5EEFA + #A177FF + #DED7E3 + #EDE2FF + #DACCEC + #DED0F1 + #E4D5F8 + #EADCFD + #EEE2FF diff --git a/presentation-core/src/main/res/values/colors_midnightdusk.xml b/presentation-core/src/main/res/values/colors_midnightdusk.xml index f78b6849e..547406360 100644 --- a/presentation-core/src/main/res/values/colors_midnightdusk.xml +++ b/presentation-core/src/main/res/values/colors_midnightdusk.xml @@ -15,10 +15,11 @@ #FFFFFF #FFD9E1 #3F0017 + #FFB1C4 #BB0054 #FFFFFF - #FFD9E1 - #3F0017 + #EFBAD4 + #D1377C #006638 #FFFFFF #00894b @@ -27,11 +28,15 @@ #1C1B1F #FFFBFF #1C1B1F - #F3DDE0 + #F9E6F1 #524346 - #847376 - #F4F0F4 + #BB0054 #313033 - #FFB1C4 - @color/midnightdusk_primary + #F4F0F4 + #847376 + #DAC0CD + #E8D1DD + #F9E6F1 + #FCF3F8 + #FEF9FC diff --git a/presentation-core/src/main/res/values/colors_nord.xml b/presentation-core/src/main/res/values/colors_nord.xml index b04ae3eec..4cb1d411f 100644 --- a/presentation-core/src/main/res/values/colors_nord.xml +++ b/presentation-core/src/main/res/values/colors_nord.xml @@ -6,6 +6,7 @@ #000000 #5E81AC #000000 + #8CA8CD #81A1C1 #2E3440 #91B4D7 @@ -18,14 +19,18 @@ #2E3440 #E5E9F0 #2E3440 - #ffffff + #DAE0EA #2E3440 - #4C566A - #ECEFF4 + #5E81AC #3B4252 - #8CA8CD - #D8DEE9 + #ECEFF4 + #2E3440 #ECEFF4 #BF616A #000000 + #D1D7E0 + #D6DCE6 + #DAE0EA + #E9EDF3 + #F2F4F8 diff --git a/presentation-core/src/main/res/values/colors_strawberry.xml b/presentation-core/src/main/res/values/colors_strawberry.xml index 97e45ba77..2a430c453 100644 --- a/presentation-core/src/main/res/values/colors_strawberry.xml +++ b/presentation-core/src/main/res/values/colors_strawberry.xml @@ -11,26 +11,39 @@ ~ Neutral #655C5C --> - #B61E40 + #A10833 #FFFFFF - #FFDADD - #40000D - #B61E40 + #D53855 + #FFFFFF + #A10833 #FFFFFF - #FFDADD - #40000D - #775930 + #D53855 + #F6EAED + #5F441D #FFFFFF - #FFDDB1 - #2A1800 - #FCFCFC - #201A1A - #FCFCFC - #201A1A - #F4DDDD - #534344 - #857374 - #FBEDED - #362F2F - #FFB2B9 + #87683D + #FFFFFF + #BA1A1A + #FFFFFF + #FFDAD6 + #410002 + #FAFAFA + #261819 + #FAFAFA + #261819 + #F6EAED + #594042 + #8D7071 + #E1BEC0 + #000000 + #3D2C2D + #FFECED + #FFB2B8 + #EED4D5 + #FFF8F7 + #F7DCDD + #FDE2E3 + #F6EAED + #FFF0F0 + #FFFFFF diff --git a/presentation-core/src/main/res/values/colors_tachiyomi.xml b/presentation-core/src/main/res/values/colors_tachiyomi.xml index e5f4f5ed8..37f2a9ff0 100644 --- a/presentation-core/src/main/res/values/colors_tachiyomi.xml +++ b/presentation-core/src/main/res/values/colors_tachiyomi.xml @@ -10,26 +10,37 @@ ~ Neutral #5E5E62 --> - #0057CE + #0058CA #FFFFFF - #D8E2FF - #001947 - #0057CE + #D9E2FF + #001945 + #B0C6FF + #0058CA #FFFFFF - #D8E2FF - #001947 - #006E17 + #D9E2FF + #001945 + #006E1B #FFFFFF #95F990 - #002202 - #FDFBFF - #1B1B1E - #FDFBFF - #1B1B1E - #E1E2EC - #44464E - #757780 + #002203 + #FEFBFF + #1B1B1F + #FEFBFF + #1B1B1F + #F3EDF7 + #44464F + #0058CA + #303034 #F2F0F4 - #303033 - #AEC6FF + #BA1A1A + #FFFFFF + #FFDAD6 + #410002 + #757780 + #C5C6D0 + #F5F1F8 + #F7F2FA + #F3EDF7 + #FCF7FF + #FCF7FF diff --git a/presentation-core/src/main/res/values/colors_tako.xml b/presentation-core/src/main/res/values/colors_tako.xml index 6a002cd2c..373970a04 100644 --- a/presentation-core/src/main/res/values/colors_tako.xml +++ b/presentation-core/src/main/res/values/colors_tako.xml @@ -15,10 +15,11 @@ #F3B375 #66577E #F3B375 + #D6BAFF #66577E #F3B375 #C8BED0 - #F3B375 + #66577E #F3B375 #574360 #FDD6B0 @@ -29,9 +30,13 @@ #1B1B22 #E8E0EB #49454E - #7A757E - #F3EFF4 + #66577E #313033 - #D6BAFF - @color/tako_primary + #F3EFF4 + #7A757E + #D7D0DA + #DFD8E2 + #E8E0EB + #EEE6F1 + #F7EEFA diff --git a/presentation-core/src/main/res/values/colors_tealturqoise.xml b/presentation-core/src/main/res/values/colors_tealturqoise.xml index c9b1e0a9d..0bff8baaa 100644 --- a/presentation-core/src/main/res/values/colors_tealturqoise.xml +++ b/presentation-core/src/main/res/values/colors_tealturqoise.xml @@ -1,13 +1,13 @@ - #008080 #FFFFFF #008080 #FFFFFF + #40E0D0 #008080 #FFFFFF - #BFDFDF + #CFE5E4 #008080 #FF7F7F #000000 @@ -17,11 +17,15 @@ #050505 #FAFAFA #050505 - #DAE5E2 + #EBF3F1 #050505 - #6F7977 - #FAFAFA + #BFDFDF #050505 - #40E0D0 - #BFDFDF + #FAFAFA + #6F7977 + #E1E9E7 + #E6EEEC + #EBF3F1 + #F0F8F6 + #F7FFFD diff --git a/presentation-core/src/main/res/values/colors_tidalwave.xml b/presentation-core/src/main/res/values/colors_tidalwave.xml index 8ae6942d5..e66f7aed5 100644 --- a/presentation-core/src/main/res/values/colors_tidalwave.xml +++ b/presentation-core/src/main/res/values/colors_tidalwave.xml @@ -15,9 +15,10 @@ #ffffff #B4D4DF #001f28 + #ff987f #006780 #ffffff - #b8eaff + #9AE1FF #001f28 #92f7bc #001c3b @@ -27,10 +28,15 @@ #001c3b #fdfbff #001c3b - #dce4e8 + #e8eff5 #40484c - #70787c - #ffe3c4 + #006780 #020400 - #ff987f + #ffe3c4 + #70787c + #e2e8ec + #e5ecf1 + #e8eff5 + #edf4fA + #f5faff \ No newline at end of file diff --git a/presentation-core/src/main/res/values/colors_yinyang.xml b/presentation-core/src/main/res/values/colors_yinyang.xml index c6d2cefbd..e54ea0f6f 100644 --- a/presentation-core/src/main/res/values/colors_yinyang.xml +++ b/presentation-core/src/main/res/values/colors_yinyang.xml @@ -9,6 +9,7 @@ #FFFFFF #000000 #FFFFFF + #A6A6A6 #000000 #FFFFFF #DDDDDD @@ -21,10 +22,15 @@ #222222 #FDFDFD #222222 - #EDEDED + #E8E8E8 #515151 - #838383 - #F4F4F4 + #000000 #333333 - #A6A6A6 + #F4F4F4 + #838383 + #CFCFCF + #DADADA + #E8E8E8 + #ECECEC + #EFEFEF diff --git a/presentation-core/src/main/res/values/colors_yotsuba.xml b/presentation-core/src/main/res/values/colors_yotsuba.xml index 79c662f7f..81fd13611 100644 --- a/presentation-core/src/main/res/values/colors_yotsuba.xml +++ b/presentation-core/src/main/res/values/colors_yotsuba.xml @@ -15,9 +15,10 @@ #FFFFFF #FFDBCF #3B0A00 + #FFB59D #AE3200 #FFFFFF - #FFDBCF + #EBCDC2 #3B0A00 #6B5E2F #FFFFFF @@ -27,10 +28,15 @@ #211A18 #FCFCFC #211A18 - #F5DED8 + #F6EBE7 #53433F - #85736E - #FBEEEB + #AE3200 #362F2D - #FFB59D + #FBEEEB + #85736E + #ECE3E0 + #F1E7E4 + #F6EBE7 + #FAF4F2 + #FBF6F4 From f4348df8709529b7b2319485fc8eb54c6e8173c7 Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Tue, 13 Aug 2024 13:42:14 +0600 Subject: [PATCH 147/297] Remove WebViewClientCompat --- .../interceptor/CloudflareInterceptor.kt | 18 ++-- .../util/system/WebViewClientCompat.kt | 88 ------------------- 2 files changed, 7 insertions(+), 99 deletions(-) delete mode 100644 core/common/src/main/kotlin/eu/kanade/tachiyomi/util/system/WebViewClientCompat.kt diff --git a/core/common/src/main/kotlin/eu/kanade/tachiyomi/network/interceptor/CloudflareInterceptor.kt b/core/common/src/main/kotlin/eu/kanade/tachiyomi/network/interceptor/CloudflareInterceptor.kt index 6a765c680..3522dea4f 100644 --- a/core/common/src/main/kotlin/eu/kanade/tachiyomi/network/interceptor/CloudflareInterceptor.kt +++ b/core/common/src/main/kotlin/eu/kanade/tachiyomi/network/interceptor/CloudflareInterceptor.kt @@ -2,11 +2,13 @@ package eu.kanade.tachiyomi.network.interceptor import android.annotation.SuppressLint import android.content.Context +import android.webkit.WebResourceError +import android.webkit.WebResourceRequest import android.webkit.WebView +import android.webkit.WebViewClient import android.widget.Toast import androidx.core.content.ContextCompat import eu.kanade.tachiyomi.network.AndroidCookieJar -import eu.kanade.tachiyomi.util.system.WebViewClientCompat import eu.kanade.tachiyomi.util.system.isOutdated import eu.kanade.tachiyomi.util.system.toast import okhttp3.Cookie @@ -73,7 +75,7 @@ class CloudflareInterceptor( executor.execute { webview = createWebView(originalRequest) - webview?.webViewClient = object : WebViewClientCompat() { + webview?.webViewClient = object : WebViewClient() { override fun onPageFinished(view: WebView, url: String) { fun isCloudFlareBypassed(): Boolean { return cookieManager.get(origRequestUrl.toHttpUrl()) @@ -92,15 +94,9 @@ class CloudflareInterceptor( } } - override fun onReceivedErrorCompat( - view: WebView, - errorCode: Int, - description: String?, - failingUrl: String, - isMainFrame: Boolean, - ) { - if (isMainFrame) { - if (errorCode in ERROR_CODES) { + override fun onReceivedError(view: WebView, request: WebResourceRequest, error: WebResourceError) { + if (request.isForMainFrame) { + if (error.errorCode in ERROR_CODES) { // Found the Cloudflare challenge page. challengeFound = true } else { diff --git a/core/common/src/main/kotlin/eu/kanade/tachiyomi/util/system/WebViewClientCompat.kt b/core/common/src/main/kotlin/eu/kanade/tachiyomi/util/system/WebViewClientCompat.kt deleted file mode 100644 index 6547a46e0..000000000 --- a/core/common/src/main/kotlin/eu/kanade/tachiyomi/util/system/WebViewClientCompat.kt +++ /dev/null @@ -1,88 +0,0 @@ -package eu.kanade.tachiyomi.util.system - -import android.webkit.WebResourceError -import android.webkit.WebResourceRequest -import android.webkit.WebResourceResponse -import android.webkit.WebView -import android.webkit.WebViewClient - -@Suppress("OverridingDeprecatedMember") -abstract class WebViewClientCompat : WebViewClient() { - - open fun shouldOverrideUrlCompat(view: WebView, url: String): Boolean { - return false - } - - open fun shouldInterceptRequestCompat(view: WebView, url: String): WebResourceResponse? { - return null - } - - open fun onReceivedErrorCompat( - view: WebView, - errorCode: Int, - description: String?, - failingUrl: String, - isMainFrame: Boolean, - ) { - } - - final override fun shouldOverrideUrlLoading( - view: WebView, - request: WebResourceRequest, - ): Boolean { - return shouldOverrideUrlCompat(view, request.url.toString()) - } - - final override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean { - return shouldOverrideUrlCompat(view, url) - } - - final override fun shouldInterceptRequest( - view: WebView, - request: WebResourceRequest, - ): WebResourceResponse? { - return shouldInterceptRequestCompat(view, request.url.toString()) - } - - final override fun shouldInterceptRequest(view: WebView, url: String): WebResourceResponse? { - return shouldInterceptRequestCompat(view, url) - } - - final override fun onReceivedError( - view: WebView, - request: WebResourceRequest, - error: WebResourceError, - ) { - onReceivedErrorCompat( - view, - error.errorCode, - error.description?.toString(), - request.url.toString(), - request.isForMainFrame, - ) - } - - final override fun onReceivedError( - view: WebView, - errorCode: Int, - description: String?, - failingUrl: String, - ) { - onReceivedErrorCompat(view, errorCode, description, failingUrl, failingUrl == view.url) - } - - final override fun onReceivedHttpError( - view: WebView, - request: WebResourceRequest, - error: WebResourceResponse, - ) { - onReceivedErrorCompat( - view, - error.statusCode, - error.reasonPhrase, - request.url - .toString(), - request.isForMainFrame, - ) - } -} From 1c47a6b9b35c622200c731cdbbc076f5263e8d06 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Wed, 14 Aug 2024 00:03:10 +0800 Subject: [PATCH 148/297] Add comment about RecyclerView cache size (#1119) Note for forks: Increasing cache size may cause OOM on API < 26, better to make it API 26+ only. --- .../kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt index ce1710cf0..3445f76c1 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt @@ -361,4 +361,5 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr } } +// Double the cache size to reduce rebinds/recycles incurred by the extra layout space on scroll direction changes private const val RecyclerViewCacheSize = 4 From 6f4e3f776f98d7a47dfa33b2cdfe992fc211ec28 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 14 Aug 2024 20:16:39 +0600 Subject: [PATCH 149/297] fix(deps): update dependency org.junit.jupiter:junit-jupiter to v5.11.0 (#1121) 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 3c4666c7e..88cf509a0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -89,7 +89,7 @@ sqldelight-android-paging = { module = "app.cash.sqldelight:androidx-paging3-ext sqldelight-dialects-sql = { module = "app.cash.sqldelight:sqlite-3-38-dialect", version.ref = "sqldelight" } sqldelight-gradle = { module = "app.cash.sqldelight:gradle-plugin", version.ref = "sqldelight" } -junit = "org.junit.jupiter:junit-jupiter:5.10.3" +junit = "org.junit.jupiter:junit-jupiter:5.11.0" kotest-assertions = "io.kotest:kotest-assertions-core:5.9.1" mockk = "io.mockk:mockk:1.13.12" From 3f050a83dd0907e0ffb56a1e1833f9de5b10b329 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 14 Aug 2024 20:18:25 +0600 Subject: [PATCH 150/297] chore(deps): update dependency gradle to v8.10 (#1122) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 09523c0e5..9355b4155 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From b2f1719c50365279e157a3b9ee015fc6c13a9a92 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 19 Aug 2024 10:59:11 +0600 Subject: [PATCH 151/297] fix(deps): update dependency org.conscrypt:conscrypt-android to v2.5.3 (#1135) 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 88cf509a0..76ad11c9a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -24,7 +24,7 @@ okhttp-brotli = { module = "com.squareup.okhttp3:okhttp-brotli", version.ref = " okhttp-dnsoverhttps = { module = "com.squareup.okhttp3:okhttp-dnsoverhttps", version.ref = "okhttp_version" } okio = "com.squareup.okio:okio:3.9.0" -conscrypt-android = "org.conscrypt:conscrypt-android:2.5.2" +conscrypt-android = "org.conscrypt:conscrypt-android:2.5.3" quickjs-android = "app.cash.quickjs:quickjs-android:0.9.2" From 777ae2461e1eb277a3aa0c998ff69e4f100387a1 Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Mon, 19 Aug 2024 12:51:37 +0600 Subject: [PATCH 152/297] Remove detekt (#1130) Annoying. More annoying in this project. --- .github/workflows/build_pull_request.yml | 2 +- .github/workflows/build_push.yml | 2 +- CONTRIBUTING.md | 4 - .../eu/kanade/presentation/util/Navigator.kt | 1 - app/src/main/java/eu/kanade/tachiyomi/App.kt | 1 - .../tachiyomi/data/backup/models/Backup.kt | 1 - .../data/backup/models/BackupChapter.kt | 1 - .../backup/models/BackupExtensionRepos.kt | 1 - .../data/backup/models/BackupManga.kt | 5 +- .../tachiyomi/data/coil/MangaCoverFetcher.kt | 1 - .../extension/util/ExtensionLoader.kt | 1 - .../ui/library/LibraryScreenModel.kt | 2 - .../core/migration/MigrationJobFactory.kt | 1 - buildSrc/build.gradle.kts | 1 - .../mihon.android.application.gradle.kts | 1 - .../main/kotlin/mihon.benchmark.gradle.kts | 1 - .../main/kotlin/mihon.code.detekt.gradle.kts | 47 - .../kotlin/mihon.library.compose.gradle.kts | 1 - .../src/main/kotlin/mihon.library.gradle.kts | 1 - config/detekt/baseline.xml | 1327 ----------------- config/detekt/detekt.yml | 24 - .../data/chapter/ChapterRepositoryImpl.kt | 1 - .../java/tachiyomi/data/manga/MangaMapper.kt | 2 - .../data/manga/MangaRepositoryImpl.kt | 1 - .../interactor/CreateExtensionRepo.kt | 1 - .../service/ExtensionRepoService.kt | 1 - gradle/libs.versions.toml | 6 - .../core/components/material/Scaffold.kt | 1 - 28 files changed, 3 insertions(+), 1436 deletions(-) delete mode 100644 buildSrc/src/main/kotlin/mihon.code.detekt.gradle.kts delete mode 100644 config/detekt/baseline.xml delete mode 100644 config/detekt/detekt.yml diff --git a/.github/workflows/build_pull_request.yml b/.github/workflows/build_pull_request.yml index 4ca360716..2cae6e891 100644 --- a/.github/workflows/build_pull_request.yml +++ b/.github/workflows/build_pull_request.yml @@ -38,7 +38,7 @@ jobs: uses: gradle/actions/setup-gradle@af1da67850ed9a4cedd57bfd976089dd991e2582 # v4.0.0 - name: Build app and run unit tests - run: ./gradlew detekt assembleStandardRelease testReleaseUnitTest testStandardReleaseUnitTest + run: ./gradlew assembleStandardRelease testReleaseUnitTest testStandardReleaseUnitTest - name: Upload APK uses: actions/upload-artifact@v4 diff --git a/.github/workflows/build_push.yml b/.github/workflows/build_push.yml index 88fe57f46..207b166a2 100644 --- a/.github/workflows/build_push.yml +++ b/.github/workflows/build_push.yml @@ -36,7 +36,7 @@ jobs: uses: gradle/actions/setup-gradle@af1da67850ed9a4cedd57bfd976089dd991e2582 # v4.0.0 - name: Build app and run unit tests - run: ./gradlew detekt assembleStandardRelease testReleaseUnitTest testStandardReleaseUnitTest + run: ./gradlew assembleStandardRelease testReleaseUnitTest testStandardReleaseUnitTest - name: Upload APK uses: actions/upload-artifact@v4 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2315fd44d..1272b30cb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -24,10 +24,6 @@ Before you start, please note that the ability to use following technologies is - [Android Studio](https://developer.android.com/studio) - Emulator or phone with developer options enabled to test changes. -## Linting - -Run the `detekt` gradle task. If the build fails, a report of issues can be found in `app/build/reports/detekt/`. The report is availble in several formats and details each issue that needs attention. - ## Getting help - Join [the Discord server](https://discord.gg/mihon) for online help and to ask questions while developing. diff --git a/app/src/main/java/eu/kanade/presentation/util/Navigator.kt b/app/src/main/java/eu/kanade/presentation/util/Navigator.kt index 86311d8e0..6cc93d6b2 100644 --- a/app/src/main/java/eu/kanade/presentation/util/Navigator.kt +++ b/app/src/main/java/eu/kanade/presentation/util/Navigator.kt @@ -28,7 +28,6 @@ import soup.compose.material.motion.animation.rememberSlideDistance /** * For invoking back press to the parent activity */ -@SuppressLint("ComposeCompositionLocalUsage") val LocalBackPress: ProvidableCompositionLocal<(() -> Unit)?> = staticCompositionLocalOf { null } interface Tab : cafe.adriel.voyager.navigator.tab.Tab { diff --git a/app/src/main/java/eu/kanade/tachiyomi/App.kt b/app/src/main/java/eu/kanade/tachiyomi/App.kt index d0b77cec1..877c76544 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/App.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/App.kt @@ -153,7 +153,6 @@ class App : Application(), DefaultLifecycleObserver, SingletonImageLoader.Factor ) } - @Suppress("MagicNumber") override fun newImageLoader(context: Context): ImageLoader { return ImageLoader.Builder(this).apply { val callFactoryLazy = lazy { Injekt.get().client } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt index 75c75b6b5..f026b30ff 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt @@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.data.backup.models import kotlinx.serialization.Serializable import kotlinx.serialization.protobuf.ProtoNumber -@Suppress("MagicNumber") @Serializable data class Backup( @ProtoNumber(1) val backupManga: List, diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupChapter.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupChapter.kt index d729efe16..b0d081a40 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupChapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupChapter.kt @@ -4,7 +4,6 @@ import kotlinx.serialization.Serializable import kotlinx.serialization.protobuf.ProtoNumber import tachiyomi.domain.chapter.model.Chapter -@Suppress("MagicNumber") @Serializable data class BackupChapter( // in 1.x some of these values have different names diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupExtensionRepos.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupExtensionRepos.kt index fa9968667..256def7b5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupExtensionRepos.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupExtensionRepos.kt @@ -4,7 +4,6 @@ import kotlinx.serialization.Serializable import kotlinx.serialization.protobuf.ProtoNumber import mihon.domain.extensionrepo.model.ExtensionRepo -@Suppress("MagicNumber") @Serializable class BackupExtensionRepos( @ProtoNumber(1) var baseUrl: String, diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupManga.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupManga.kt index 410ecc67a..7b7498398 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupManga.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupManga.kt @@ -5,10 +5,7 @@ import kotlinx.serialization.Serializable import kotlinx.serialization.protobuf.ProtoNumber import tachiyomi.domain.manga.model.Manga -@Suppress( - "DEPRECATION", - "MagicNumber", -) +@Suppress("DEPRECATION") @Serializable data class BackupManga( // in 1.x some of these values have different names diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/coil/MangaCoverFetcher.kt b/app/src/main/java/eu/kanade/tachiyomi/data/coil/MangaCoverFetcher.kt index 65a142099..832fe95f9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/coil/MangaCoverFetcher.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/coil/MangaCoverFetcher.kt @@ -45,7 +45,6 @@ import java.io.IOException * Available request parameter: * - [USE_CUSTOM_COVER_KEY]: Use custom cover if set by user, default is true */ -@Suppress("LongParameterList") class MangaCoverFetcher( private val url: String?, private val isLibraryManga: Boolean, diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionLoader.kt index 50ab94279..08027dc10 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionLoader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionLoader.kt @@ -223,7 +223,6 @@ internal object ExtensionLoader { * @param context The application context. * @param extensionInfo The extension to load. */ - @Suppress("LongMethod", "CyclomaticComplexMethod", "ReturnCount") private suspend fun loadExtension(context: Context, extensionInfo: ExtensionInfo): LoadResult { val pkgManager = context.packageManager val pkgInfo = extensionInfo.packageInfo 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 e866c98c9..286f58239 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 @@ -174,7 +174,6 @@ class LibraryScreenModel( /** * Applies library filters to the given map of manga. */ - @Suppress("LongMethod", "CyclomaticComplexMethod") private suspend fun LibraryMap.applyFilters( trackMap: Map>, trackingFiler: Map, @@ -256,7 +255,6 @@ class LibraryScreenModel( /** * Applies library sorting to the given map of manga. */ - @Suppress("LongMethod", "CyclomaticComplexMethod") private fun LibraryMap.applySort( // Map> trackMap: Map>, diff --git a/app/src/main/java/mihon/core/migration/MigrationJobFactory.kt b/app/src/main/java/mihon/core/migration/MigrationJobFactory.kt index 801411013..c452707d5 100644 --- a/app/src/main/java/mihon/core/migration/MigrationJobFactory.kt +++ b/app/src/main/java/mihon/core/migration/MigrationJobFactory.kt @@ -12,7 +12,6 @@ class MigrationJobFactory( private val scope: CoroutineScope ) { - @SuppressWarnings("MaxLineLength") fun create(migrations: List): Deferred = with(scope) { return migrations.sortedBy { it.version } .fold(CompletableDeferred(true)) { acc: Deferred, migration: Migration -> diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index b72b8a98b..b825b4172 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -6,7 +6,6 @@ dependencies { implementation(androidx.gradle) implementation(kotlinx.gradle) implementation(kotlinx.compose.compiler.gradle) - implementation(libs.detekt.gradlePlugin) implementation(gradleApi()) implementation(files(libs.javaClass.superclass.protectionDomain.codeSource.location)) diff --git a/buildSrc/src/main/kotlin/mihon.android.application.gradle.kts b/buildSrc/src/main/kotlin/mihon.android.application.gradle.kts index 3c4c00ac3..7ba9c60fb 100644 --- a/buildSrc/src/main/kotlin/mihon.android.application.gradle.kts +++ b/buildSrc/src/main/kotlin/mihon.android.application.gradle.kts @@ -3,7 +3,6 @@ import mihon.buildlogic.configureAndroid import mihon.buildlogic.configureTest plugins { - id("mihon.code.detekt") id("com.android.application") kotlin("android") } diff --git a/buildSrc/src/main/kotlin/mihon.benchmark.gradle.kts b/buildSrc/src/main/kotlin/mihon.benchmark.gradle.kts index b857c4343..3a43a2aa1 100644 --- a/buildSrc/src/main/kotlin/mihon.benchmark.gradle.kts +++ b/buildSrc/src/main/kotlin/mihon.benchmark.gradle.kts @@ -2,7 +2,6 @@ import mihon.buildlogic.configureAndroid import mihon.buildlogic.configureTest plugins { - id("mihon.code.detekt") id("com.android.test") kotlin("android") } diff --git a/buildSrc/src/main/kotlin/mihon.code.detekt.gradle.kts b/buildSrc/src/main/kotlin/mihon.code.detekt.gradle.kts deleted file mode 100644 index 986138ee6..000000000 --- a/buildSrc/src/main/kotlin/mihon.code.detekt.gradle.kts +++ /dev/null @@ -1,47 +0,0 @@ -import io.gitlab.arturbosch.detekt.Detekt -import io.gitlab.arturbosch.detekt.DetektCreateBaselineTask -import org.gradle.accessors.dm.LibrariesForLibs - -plugins { - id("io.gitlab.arturbosch.detekt") -} - -val libs = the() -dependencies { - detektPlugins(libs.detekt.rules.formatting) - detektPlugins(libs.detekt.rules.compose) -} - -private val configFile = files("$rootDir/config/detekt/detekt.yml") -private val baselineFile = file("$rootDir/config/detekt/baseline.xml") -private val kotlinFiles = "**/*.kt" -private val resourceFiles = "**/resources/**" -private val buildFiles = "**/build/**" -private val generatedFiles = "**/generated/**" -private val scriptsFiles = "**/*.kts" - -detekt { - buildUponDefaultConfig = true - parallel = true - autoCorrect = false - ignoreFailures = false - config.setFrom(configFile) - baseline = file(baselineFile) -} - -tasks.withType().configureEach { - include(kotlinFiles) - exclude(resourceFiles, buildFiles, generatedFiles, scriptsFiles) - reports { - html.required.set(true) - xml.required.set(false) - txt.required.set(false) - } -} - -tasks.withType().configureEach { - jvmTarget = JavaVersion.VERSION_17.toString() -} -tasks.withType().configureEach { - jvmTarget = JavaVersion.VERSION_17.toString() -} diff --git a/buildSrc/src/main/kotlin/mihon.library.compose.gradle.kts b/buildSrc/src/main/kotlin/mihon.library.compose.gradle.kts index 9f39d7737..0c37a3256 100644 --- a/buildSrc/src/main/kotlin/mihon.library.compose.gradle.kts +++ b/buildSrc/src/main/kotlin/mihon.library.compose.gradle.kts @@ -1,7 +1,6 @@ import mihon.buildlogic.configureCompose plugins { - id("mihon.code.detekt") id("com.android.library") } diff --git a/buildSrc/src/main/kotlin/mihon.library.gradle.kts b/buildSrc/src/main/kotlin/mihon.library.gradle.kts index 0ea496172..743bf07e3 100644 --- a/buildSrc/src/main/kotlin/mihon.library.gradle.kts +++ b/buildSrc/src/main/kotlin/mihon.library.gradle.kts @@ -2,7 +2,6 @@ import mihon.buildlogic.configureAndroid import mihon.buildlogic.configureTest plugins { - id("mihon.code.detekt") id("com.android.library") } diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml deleted file mode 100644 index 1845cae53..000000000 --- a/config/detekt/baseline.xml +++ /dev/null @@ -1,1327 +0,0 @@ - - - - - ComplexCondition:MangaScreenModel.kt$MangaScreenModel$(selectedItem.selected && selected) || (!selectedItem.selected && !selected) - ComplexCondition:ReaderNavigationOverlayView.kt$ReaderNavigationOverlayView$isVisible || (!showOnStart && firstLaunch) || navigation is DisabledNavigation - ComplexCondition:ReaderPageImageView.kt$ReaderPageImageView$config != null && config!!.landscapeZoom && config!!.minimumScaleType == SCALE_TYPE_CENTER_INSIDE && sWidth > sHeight && scale == minScale - ComposableParamOrder:ChapterSettingsDialog.kt$ChapterSettingsDialog - ComposableParamOrder:LazyLibraryGrid.kt$LazyLibraryGrid - ComposableParamOrder:SwitchPreferenceWidget.kt$SwitchPreferenceWidget - ComposableParamOrder:TrackingPreferenceWidget.kt$TrackingPreferenceWidget - ComposableParamOrder:TriStateListDialog.kt$TriStateListDialog - CompositionLocalAllowlist:Navigator.kt$LocalBackPress - CompositionLocalAllowlist:PreferenceItem.kt$LocalPreferenceHighlighted - CompositionLocalAllowlist:PreferenceItem.kt$LocalPreferenceMinHeight - ConstructorParameterNaming:AnilistModels.kt$ALManga$val average_score: Int - ConstructorParameterNaming:AnilistModels.kt$ALManga$val image_url_lge: String - ConstructorParameterNaming:AnilistModels.kt$ALManga$val publishing_status: String - ConstructorParameterNaming:AnilistModels.kt$ALManga$val remote_id: Long - ConstructorParameterNaming:AnilistModels.kt$ALManga$val start_date_fuzzy: Long - ConstructorParameterNaming:AnilistModels.kt$ALManga$val title_user_pref: String - ConstructorParameterNaming:AnilistModels.kt$ALManga$val total_chapters: Long - ConstructorParameterNaming:AnilistModels.kt$ALUserManga$val chapters_read: Int - ConstructorParameterNaming:AnilistModels.kt$ALUserManga$val completed_date_fuzzy: Long - ConstructorParameterNaming:AnilistModels.kt$ALUserManga$val library_id: Long - ConstructorParameterNaming:AnilistModels.kt$ALUserManga$val list_status: String - ConstructorParameterNaming:AnilistModels.kt$ALUserManga$val score_raw: Int - ConstructorParameterNaming:AnilistModels.kt$ALUserManga$val start_date_fuzzy: Long - ConstructorParameterNaming:AnilistModels.kt$OAuth$val access_token: String - ConstructorParameterNaming:AnilistModels.kt$OAuth$val expires_in: Long - ConstructorParameterNaming:AnilistModels.kt$OAuth$val token_type: String - ConstructorParameterNaming:BackupManga.kt$BackupManga$@ProtoNumber(103) var viewer_flags: Int? = null - ConstructorParameterNaming:BangumiModels.kt$Collection$val ep_status: Int? = 0 - ConstructorParameterNaming:BangumiModels.kt$Collection$val vol_status: Int? = 0 - ConstructorParameterNaming:BangumiModels.kt$OAuth$val access_token: String - ConstructorParameterNaming:BangumiModels.kt$OAuth$val created_at: Long = System.currentTimeMillis() / 1000 - ConstructorParameterNaming:BangumiModels.kt$OAuth$val expires_in: Long - ConstructorParameterNaming:BangumiModels.kt$OAuth$val refresh_token: String? - ConstructorParameterNaming:BangumiModels.kt$OAuth$val token_type: String - ConstructorParameterNaming:BangumiModels.kt$OAuth$val user_id: Long? - ConstructorParameterNaming:ExtensionDetailsScreenModel.kt$ExtensionDetailsScreenModel.State$private val _sources: ImmutableList<ExtensionSourceItem>? = null - ConstructorParameterNaming:KavitaModels.kt$SeriesDto$val thumbnail_url: String? = "" - ConstructorParameterNaming:KitsuModels.kt$OAuth$val access_token: String - ConstructorParameterNaming:KitsuModels.kt$OAuth$val created_at: Long - ConstructorParameterNaming:KitsuModels.kt$OAuth$val expires_in: Long - ConstructorParameterNaming:KitsuModels.kt$OAuth$val refresh_token: String? - ConstructorParameterNaming:KitsuModels.kt$OAuth$val token_type: String - ConstructorParameterNaming:MyAnimeListModels.kt$OAuth$val access_token: String - ConstructorParameterNaming:MyAnimeListModels.kt$OAuth$val created_at: Long = System.currentTimeMillis() - ConstructorParameterNaming:MyAnimeListModels.kt$OAuth$val expires_in: Long - ConstructorParameterNaming:MyAnimeListModels.kt$OAuth$val refresh_token: String - ConstructorParameterNaming:MyAnimeListModels.kt$OAuth$val token_type: String - ConstructorParameterNaming:ShikimoriModels.kt$OAuth$val access_token: String - ConstructorParameterNaming:ShikimoriModels.kt$OAuth$val created_at: Long - ConstructorParameterNaming:ShikimoriModels.kt$OAuth$val expires_in: Long - ConstructorParameterNaming:ShikimoriModels.kt$OAuth$val refresh_token: String? - ConstructorParameterNaming:ShikimoriModels.kt$OAuth$val token_type: String - CyclomaticComplexMethod:AnilistModels.kt$fun DomainTrack.toAnilistScore(): String - CyclomaticComplexMethod:BrowseSourceScreen.kt$@Composable fun BrowseSourceContent( source: Source?, mangaList: LazyPagingItems<StateFlow<Manga>>, columns: GridCells, displayMode: LibraryDisplayMode, snackbarHostState: SnackbarHostState, contentPadding: PaddingValues, onWebViewClick: () -> Unit, onHelpClick: () -> Unit, onLocalSourceHelpClick: () -> Unit, onMangaClick: (Manga) -> Unit, onMangaLongClick: (Manga) -> Unit, ) - CyclomaticComplexMethod:BrowseSourceScreen.kt$BrowseSourceScreen$@Composable override fun Content() - CyclomaticComplexMethod:BrowseSourceScreenModel.kt$BrowseSourceScreenModel$fun searchGenre(genreName: String) - CyclomaticComplexMethod:Button.kt$ButtonElevation$@Composable private fun animateElevation( enabled: Boolean, interactionSource: InteractionSource, ): State<Dp> - CyclomaticComplexMethod:DownloadCache.kt$DownloadCache$private fun renewCache() - CyclomaticComplexMethod:ExtensionLoader.kt$ExtensionLoader$private fun loadExtension(context: Context, extensionInfo: ExtensionInfo): LoadResult - CyclomaticComplexMethod:ExtensionsScreen.kt$@Composable private fun ExtensionContent( state: ExtensionsScreenModel.State, contentPadding: PaddingValues, onLongClickItem: (Extension) -> Unit, onClickItemCancel: (Extension) -> Unit, onOpenWebView: (Extension.Available) -> Unit, onInstallExtension: (Extension.Available) -> Unit, onUninstallExtension: (Extension) -> Unit, onUpdateExtension: (Extension.Installed) -> Unit, onTrustExtension: (Extension.Untrusted) -> Unit, onOpenExtension: (Extension.Installed) -> Unit, onClickUpdateAll: () -> Unit, ) - CyclomaticComplexMethod:ExtensionsScreen.kt$@Composable private fun ExtensionItemContent( extension: Extension, installStep: InstallStep, modifier: Modifier = Modifier, ) - CyclomaticComplexMethod:GetSourcesWithFavoriteCount.kt$GetSourcesWithFavoriteCount$private fun sortFn( direction: SetMigrateSorting.Direction, sorting: SetMigrateSorting.Mode, ): java.util.Comparator<Pair<Source, Long>> - CyclomaticComplexMethod:ImageUtil.kt$ImageUtil$fun chooseBackground(context: Context, imageStream: InputStream): Drawable - CyclomaticComplexMethod:LibraryScreenModel.kt$LibraryScreenModel$private fun LibraryMap.applySort( // Map<MangaId, List<Track>> trackMap: Map<Long, List<Track>>, ): LibraryMap - CyclomaticComplexMethod:LibraryScreenModel.kt$LibraryScreenModel$private suspend fun LibraryMap.applyFilters( trackMap: Map<Long, List<Track>>, loggedInTrackers: Map<Long, TriState>, ): LibraryMap - CyclomaticComplexMethod:LibraryTab.kt$LibraryTab$@Composable override fun Content() - CyclomaticComplexMethod:LibraryUpdateJob.kt$LibraryUpdateJob$private suspend fun addMangaToQueue(categoryId: Long) - CyclomaticComplexMethod:LocalSource.kt$LocalSource$override suspend fun getMangaDetails(manga: SManga): SManga - CyclomaticComplexMethod:LocalSource.kt$LocalSource$private fun updateCover(chapter: SChapter, manga: SManga): UniFile? - CyclomaticComplexMethod:MainActivity.kt$MainActivity$override fun onCreate(savedInstanceState: Bundle?) - CyclomaticComplexMethod:MainActivity.kt$MainActivity$private fun handleIntentAction(intent: Intent, navigator: Navigator): Boolean - CyclomaticComplexMethod:MangaInfoHeader.kt$@Composable private fun ColumnScope.MangaContentInfo( title: String, doSearch: (query: String, global: Boolean) -> Unit, author: String?, artist: String?, status: Long, sourceName: String, isStubSource: Boolean, textAlign: TextAlign? = LocalTextStyle.current.textAlign, ) - CyclomaticComplexMethod:MangaScreen.kt$MangaScreen$@Composable override fun Content() - CyclomaticComplexMethod:MangaScreenModel.kt$MangaScreenModel$fun toggleSelection( item: ChapterList.Item, selected: Boolean, userSelected: Boolean = false, fromLongPress: Boolean = false, ) - CyclomaticComplexMethod:MigrateDialog.kt$MigrateDialogScreenModel$private suspend fun migrateMangaInternal( oldSource: Source?, newSource: Source, oldManga: Manga, newManga: Manga, sourceChapters: List<SChapter>, replace: Boolean, flags: Int, ) - CyclomaticComplexMethod:NotificationReceiver.kt$NotificationReceiver$override fun onReceive(context: Context, intent: Intent) - CyclomaticComplexMethod:PagerViewer.kt$PagerViewer$override fun handleKeyEvent(event: KeyEvent): Boolean - CyclomaticComplexMethod:PagerViewerAdapter.kt$PagerViewerAdapter$fun setChapters(chapters: ViewerChapters, forceTransition: Boolean) - CyclomaticComplexMethod:PreferenceItem.kt$@Composable internal fun PreferenceItem( item: Preference.PreferenceItem<*>, highlightKey: String?, ) - CyclomaticComplexMethod:RateLimitInterceptor.kt$RateLimitInterceptor$override fun intercept(chain: Interceptor.Chain): Response - CyclomaticComplexMethod:ReaderActivity.kt$ReaderActivity$override fun onCreate(savedInstanceState: Bundle?) - CyclomaticComplexMethod:ReaderActivity.kt$ReaderActivity$private fun initializeMenu() - CyclomaticComplexMethod:Scaffold.kt$@Composable private fun ScaffoldLayout( fabPosition: FabPosition, topBar: @Composable () -> Unit, startBar: @Composable () -> Unit, content: @Composable (PaddingValues) -> Unit, snackbar: @Composable () -> Unit, fab: @Composable () -> Unit, contentWindowInsets: WindowInsets, bottomBar: @Composable () -> Unit, ) - CyclomaticComplexMethod:SourcesScreenModel.kt$SourcesScreenModel$private fun collectLatestSources(sources: List<Source>) - CyclomaticComplexMethod:SyncChaptersWithSource.kt$SyncChaptersWithSource$suspend fun await( rawSourceChapters: List<SChapter>, manga: Manga, source: Source, manualFetch: Boolean = false, fetchWindow: Pair<Long, Long> = Pair(0, 0), ): List<Chapter> - CyclomaticComplexMethod:TriStateListDialog.kt$@Composable fun <T> TriStateListDialog( title: String, message: String? = null, items: List<T>, initialChecked: List<T>, initialInversed: List<T>, itemLabel: @Composable (T) -> String, onDismissRequest: () -> Unit, onValueChanged: (newIncluded: List<T>, newExcluded: List<T>) -> Unit, ) - CyclomaticComplexMethod:UpdatesScreenModel.kt$UpdatesScreenModel$fun toggleSelection( item: UpdatesItem, selected: Boolean, userSelected: Boolean = false, fromLongPress: Boolean = false, ) - CyclomaticComplexMethod:VerticalFastScroller.kt$@Composable fun VerticalFastScroller( listState: LazyListState, modifier: Modifier = Modifier, thumbAllowed: () -> Boolean = { true }, thumbColor: Color = MaterialTheme.colorScheme.primary, topContentPadding: Dp = Dp.Hairline, bottomContentPadding: Dp = Dp.Hairline, endContentPadding: Dp = Dp.Hairline, content: @Composable () -> Unit, ) - CyclomaticComplexMethod:VerticalFastScroller.kt$@Composable fun VerticalGridFastScroller( state: LazyGridState, columns: GridCells, arrangement: Arrangement.Horizontal, contentPadding: PaddingValues, modifier: Modifier = Modifier, thumbAllowed: () -> Boolean = { true }, thumbColor: Color = MaterialTheme.colorScheme.primary, topContentPadding: Dp = Dp.Hairline, bottomContentPadding: Dp = Dp.Hairline, endContentPadding: Dp = Dp.Hairline, content: @Composable () -> Unit, ) - CyclomaticComplexMethod:WebtoonRecyclerView.kt$WebtoonRecyclerView.Detector$override fun onTouchEvent(ev: MotionEvent): Boolean - CyclomaticComplexMethod:WebtoonViewer.kt$WebtoonViewer$override fun handleKeyEvent(event: KeyEvent): Boolean - DestructuringDeclarationWithTooManyEntries:ExtensionsScreenModel.kt$ExtensionsScreenModel$(_updates, _installed, _available, _untrusted) - DestructuringDeclarationWithTooManyEntries:MangaInfoHeader.kt$(shrunk, expanded, actual, scrim) - EmptyCatchBlock:RarPageLoader.kt$RarPageLoader${ } - EqualsAlwaysReturnsTrueOrFalse:FilterList.kt$FilterList$override fun equals(other: Any?): Boolean - ExplicitItLambdaParameter:ColorFilterPage.kt${ index, it -> FilterChip( selected = colorFilterMode == index, onClick = { screenModel.preferences.colorFilterMode().set(index) }, label = { Text(stringResource(it.first)) }, ) } - ExplicitItLambdaParameter:LibraryTab.kt$LibraryTab${ it: LibraryManga -> scope.launchIO { val chapter = screenModel.getNextUnreadChapter(it.manga) if (chapter != null) { context.startActivity( ReaderActivity.newIntent(context, chapter.mangaId, chapter.id), ) } else { snackbarHostState.showSnackbar(context.stringResource(MR.strings.no_next_chapter)) } } Unit } - ExplicitItLambdaParameter:ReadingModePage.kt${ index, it -> FilterChip( selected = imageScaleType == index + 1, onClick = { screenModel.preferences.imageScaleType().set(index + 1) }, label = { Text(stringResource(it)) }, ) } - ExplicitItLambdaParameter:ReadingModePage.kt${ index, it -> FilterChip( selected = selected == index, onClick = { onSelect(index) }, label = { Text(stringResource(it)) }, ) } - ExplicitItLambdaParameter:ReadingModePage.kt${ index, it -> FilterChip( selected = zoomStart == index + 1, onClick = { screenModel.preferences.zoomStart().set(index + 1) }, label = { Text(stringResource(it)) }, ) } - ExplicitItLambdaParameter:SettingsReaderScreen.kt$SettingsReaderScreen${ index, it -> index + 1 to stringResource(it) } - ExplicitItLambdaParameter:SettingsReaderScreen.kt$SettingsReaderScreen${ index, it -> index to stringResource(it) } - FinalNewline:Commands.kt$.Commands.kt - ForEachOnRange:MangaBottomActionMenu.kt$0..<5 - ForEachOnRange:MangaBottomActionMenu.kt$0..<7 - ForEachOnRange:UpdatesWidget.kt$0..<rowCount - ForbiddenComment:AddTracks.kt$AddTracks$// TODO: merge into [SyncChapterProgressWithTrack]? - ForbiddenComment:AddTracks.kt$AddTracks$// TODO: update all trackers based on common data - ForbiddenComment:AppTheme.kt$AppTheme.NORD$// TODO: re-enable for preview - ForbiddenComment:BackupRestorer.kt$BackupRestorer$// TODO: optionally trigger online library + tracker update - ForbiddenComment:BangumiApi.kt$BangumiApi$// TODO: get user readed chapter here - ForbiddenComment:BaseTracker.kt$BaseTracker$// TODO: Store all scores as 10 point in the future maybe? - ForbiddenComment:BaselineProfileGenerator.kt$BaselineProfileGenerator$// TODO: automate storage permissions and possibly open manga details screen too? - ForbiddenComment:CategoryDialogs.kt$// TODO: https://issuetracker.google.com/issues/204502668 - ForbiddenComment:Chapter.kt$// TODO: Remove when all deps are migrated - ForbiddenComment:ConfigurableSource.kt$// TODO: use getSourcePreferences once all extensions are on ext-lib 1.5 - ForbiddenComment:DisplayExtensions.kt$// TODO: move the logic to `isTabletUi()` when main activity is rewritten in Compose - ForbiddenComment:ExtensionReposDialogs.kt$// TODO: https://issuetracker.google.com/issues/204502668 - ForbiddenComment:GlobalSearchToolbar.kt$// TODO: make this UX better; it only applies when triggering a new search - ForbiddenComment:HomeScreen.kt$HomeScreen$// TODO: https://issuetracker.google.com/u/0/issues/316327367 - ForbiddenComment:LibrarySettingsDialog.kt$// TODO: re-enable when custom intervals are ready for stable - ForbiddenComment:LibraryTabs.kt$// TODO: use default when width is fixed upstream - ForbiddenComment:LibraryUpdateJob.kt$LibraryUpdateJob$// TODO: surface skipped reasons to user? - ForbiddenComment:LocalSource.kt$LocalSource$// TODO: remove support for this entirely after a while - ForbiddenComment:Localize.kt$// TODO: janky workaround for https://github.com/icerockdev/moko-resources/issues/337 - ForbiddenComment:MainActivity.kt$MainActivity$// TODO: replace with ComponentActivity#enableEdgeToEdge - ForbiddenComment:Manga.kt$// TODO: move these into the domain model - ForbiddenComment:MangaCoverScreenModel.kt$MangaCoverScreenModel$// TODO: Handle animated cover - ForbiddenComment:MangaInfoHeader.kt$// TODO: show something better when using custom interval - ForbiddenComment:PreferenceItem.kt$// TODO: use different composable? - ForbiddenComment:ReaderPreferences.kt$ReaderPreferences$// TODO: default this to true if reader long strip ever goes stable - ForbiddenComment:SettingsAdvancedScreen.kt$SettingsAdvancedScreen$// TODO: allow private option in stable versions once URL handling is more fleshed out - ForbiddenComment:Tracker.kt$Tracker$// TODO: Store all scores as 10 point in the future maybe? - ForbiddenComment:Tracker.kt$Tracker$// TODO: move this to an interactor, and update all trackers based on common data - ForbiddenComment:VerticalFastScroller.kt$// TODO: Sometimes item height is not available when scrolling up - FunctionNaming:Downloader.kt$Downloader$private fun _clearQueue() - FunctionNaming:Pin.kt$fun Pins(vararg pins: Pin) - FunctionNaming:PullRefresh.kt$PullToRefreshStateImpl.Companion$fun Saver( extraVerticalOffset: Float, positionalThreshold: Float, enabled: () -> Boolean, onRefresh: () -> Unit, ) - FunctionNaming:Requests.kt$fun DELETE( url: String, headers: Headers = DEFAULT_HEADERS, body: RequestBody = DEFAULT_BODY, cache: CacheControl = DEFAULT_CACHE_CONTROL, ): Request - FunctionNaming:Requests.kt$fun GET( url: HttpUrl, headers: Headers = DEFAULT_HEADERS, cache: CacheControl = DEFAULT_CACHE_CONTROL, ): Request - FunctionNaming:Requests.kt$fun GET( url: String, headers: Headers = DEFAULT_HEADERS, cache: CacheControl = DEFAULT_CACHE_CONTROL, ): Request - FunctionNaming:Requests.kt$fun POST( url: String, headers: Headers = DEFAULT_HEADERS, body: RequestBody = DEFAULT_BODY, cache: CacheControl = DEFAULT_CACHE_CONTROL, ): Request - FunctionNaming:Requests.kt$fun PUT( url: String, headers: Headers = DEFAULT_HEADERS, body: RequestBody = DEFAULT_BODY, cache: CacheControl = DEFAULT_CACHE_CONTROL, ): Request - FunctionParameterNaming:MangaScreen.kt$MangaScreen$manga_: Manga? - FunctionParameterNaming:MangaScreen.kt$MangaScreen$source_: Source? - FunctionParameterNaming:WebViewInterceptor.kt$_name: String - FunctionParameterNaming:WebViewInterceptor.kt$_value: String - ImportOrdering:Commands.kt$import org.gradle.api.Project import java.io.ByteArrayOutputStream import java.text.SimpleDateFormat import java.util.TimeZone import java.util.Date - Indentation:LocalesConfigPlugin.kt$ - InstanceOfCheckForException:AppUpdateDownloadJob.kt$AppUpdateDownloadJob$e is CancellationException - InstanceOfCheckForException:AppUpdateDownloadJob.kt$AppUpdateDownloadJob$e is StreamResetException - InstanceOfCheckForException:BackupRestoreJob.kt$BackupRestoreJob$e is CancellationException - InstanceOfCheckForException:Downloader.kt$Downloader$e is CancellationException - InstanceOfCheckForException:Downloader.kt$Downloader$error is CancellationException - InstanceOfCheckForException:HttpPageLoader.kt$HttpPageLoader$e is CancellationException - InstanceOfCheckForException:LibraryUpdateJob.kt$LibraryUpdateJob$e is CancellationException - InstanceOfCheckForException:MangaScreenModel.kt$MangaScreenModel$e is HttpException - InstanceOfCheckForException:MangaScreenModel.kt$MangaScreenModel$e is NoChaptersException - InstanceOfCheckForException:MetadataUpdateJob.kt$MetadataUpdateJob$e is CancellationException - InstanceOfCheckForException:ReaderViewModel.kt$ReaderViewModel$e is CancellationException - InstanceOfCheckForException:UncaughtExceptionInterceptor.kt$UncaughtExceptionInterceptor$e is IOException - LargeClass:MangaScreenModel.kt$MangaScreenModel : StateScreenModel - LongMethod:AboutScreen.kt$AboutScreen$@Composable override fun Content() - LongMethod:AdaptiveSheet.kt$@Composable fun AdaptiveSheet( isTabletUi: Boolean, tonalElevation: Dp, enableSwipeDismiss: Boolean, onDismissRequest: () -> Unit, modifier: Modifier = Modifier, content: @Composable () -> Unit, ) - LongMethod:AnilistApi.kt$AnilistApi$suspend fun findLibManga(track: Track, userid: Int): Track? - LongMethod:AppBar.kt$@Composable fun AppBarActions( actions: ImmutableList<AppBar.AppBarAction>, ) - LongMethod:AppBar.kt$@Composable fun SearchToolbar( searchQuery: String?, onChangeSearchQuery: (String?) -> Unit, modifier: Modifier = Modifier, titleContent: @Composable () -> Unit = {}, navigateUp: (() -> Unit)? = null, searchEnabled: Boolean = true, placeholderText: String? = null, onSearch: (String) -> Unit = {}, onClickCloseSearch: () -> Unit = { onChangeSearchQuery(null) }, actions: @Composable RowScope.() -> Unit = {}, scrollBehavior: TopAppBarScrollBehavior? = null, visualTransformation: VisualTransformation = VisualTransformation.None, interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, ) - LongMethod:AppModule.kt$AppModule$override fun InjektRegistrar.registerInjectables() - LongMethod:AppThemePreferenceWidget.kt$@Composable fun AppThemePreviewItem( selected: Boolean, onClick: () -> Unit, ) - LongMethod:BrowseSourceScreen.kt$@Composable fun BrowseSourceContent( source: Source?, mangaList: LazyPagingItems<StateFlow<Manga>>, columns: GridCells, displayMode: LibraryDisplayMode, snackbarHostState: SnackbarHostState, contentPadding: PaddingValues, onWebViewClick: () -> Unit, onHelpClick: () -> Unit, onLocalSourceHelpClick: () -> Unit, onMangaClick: (Manga) -> Unit, onMangaLongClick: (Manga) -> Unit, ) - LongMethod:BrowseSourceScreen.kt$BrowseSourceScreen$@Composable override fun Content() - LongMethod:BrowseSourceToolbar.kt$@Composable fun BrowseSourceToolbar( searchQuery: String?, onSearchQueryChange: (String?) -> Unit, source: Source?, displayMode: LibraryDisplayMode, onDisplayModeChange: (LibraryDisplayMode) -> Unit, navigateUp: () -> Unit, onWebViewClick: () -> Unit, onHelpClick: () -> Unit, onSettingsClick: () -> Unit, onSearch: (String) -> Unit, scrollBehavior: TopAppBarScrollBehavior? = null, ) - LongMethod:Button.kt$ButtonElevation$@Composable private fun animateElevation( enabled: Boolean, interactionSource: InteractionSource, ): State<Dp> - LongMethod:CategoryDialogs.kt$@Composable fun ChangeCategoryDialog( initialSelection: ImmutableList<CheckboxState<Category>>, onDismissRequest: () -> Unit, onEditCategories: () -> Unit, onConfirm: (List<Long>, List<Long>) -> Unit, ) - LongMethod:ChapterDownloadIndicator.kt$@Composable private fun DownloadingIndicator( enabled: Boolean, downloadState: Download.State, downloadProgressProvider: () -> Int, onClick: (ChapterDownloadAction) -> Unit, modifier: Modifier = Modifier, ) - LongMethod:ChapterNavigator.kt$@Composable fun ChapterNavigator( isRtl: Boolean, onNextChapter: () -> Unit, enabledNext: Boolean, onPreviousChapter: () -> Unit, enabledPrevious: Boolean, currentPage: Int, totalPages: Int, onSliderValueChange: (Int) -> Unit, ) - LongMethod:ChapterSettingsDialog.kt$@Composable fun ChapterSettingsDialog( onDismissRequest: () -> Unit, manga: Manga? = null, onDownloadFilterChanged: (TriState) -> Unit, onUnreadFilterChanged: (TriState) -> Unit, onBookmarkedFilterChanged: (TriState) -> Unit, scanlatorFilterActive: Boolean, onScanlatorFilterClicked: (() -> Unit), onSortModeChanged: (Long) -> Unit, onDisplayModeChanged: (Long) -> Unit, onSetAsDefault: (applyToExistingManga: Boolean) -> Unit, onResetToDefault: () -> Unit, ) - LongMethod:ClearDatabaseScreen.kt$ClearDatabaseScreen$@Composable override fun Content() - LongMethod:ColorFilterPage.kt$@Composable internal fun ColumnScope.ColorFilterPage(screenModel: ReaderSettingsScreenModel) - LongMethod:CreateBackupScreen.kt$CreateBackupScreen$@Composable override fun Content() - LongMethod:DomainModule.kt$DomainModule$override fun InjektRegistrar.registerInjectables() - LongMethod:DownloadCache.kt$DownloadCache$private fun renewCache() - LongMethod:DownloadQueueScreen.kt$DownloadQueueScreen$@Composable override fun Content() - LongMethod:Downloader.kt$Downloader$private suspend fun downloadChapter(download: Download) - LongMethod:EditTextPreferenceWidget.kt$@Composable fun EditTextPreferenceWidget( title: String, subtitle: String?, icon: ImageVector?, value: String, onConfirm: suspend (String) -> Boolean, ) - LongMethod:ExtensionDetailsScreen.kt$@Composable fun ExtensionDetailsScreen( navigateUp: () -> Unit, state: ExtensionDetailsScreenModel.State, onClickSourcePreferences: (sourceId: Long) -> Unit, onClickEnableAll: () -> Unit, onClickDisableAll: () -> Unit, onClickClearCookies: () -> Unit, onClickUninstall: () -> Unit, onClickSource: (sourceId: Long) -> Unit, ) - LongMethod:ExtensionDetailsScreen.kt$@Composable private fun DetailsHeader( extension: Extension, onClickAgeRating: () -> Unit, onClickUninstall: () -> Unit, onClickAppInfo: (() -> Unit)?, ) - LongMethod:ExtensionLoader.kt$ExtensionLoader$private fun loadExtension(context: Context, extensionInfo: ExtensionInfo): LoadResult - LongMethod:ExtensionsScreen.kt$@Composable private fun ExtensionContent( state: ExtensionsScreenModel.State, contentPadding: PaddingValues, onLongClickItem: (Extension) -> Unit, onClickItemCancel: (Extension) -> Unit, onOpenWebView: (Extension.Available) -> Unit, onInstallExtension: (Extension.Available) -> Unit, onUninstallExtension: (Extension) -> Unit, onUpdateExtension: (Extension.Installed) -> Unit, onTrustExtension: (Extension.Untrusted) -> Unit, onOpenExtension: (Extension.Installed) -> Unit, onClickUpdateAll: () -> Unit, ) - LongMethod:ExtensionsScreen.kt$@Composable private fun ExtensionItemActions( extension: Extension, installStep: InstallStep, modifier: Modifier = Modifier, onClickItemCancel: (Extension) -> Unit = {}, onClickItemAction: (Extension) -> Unit = {}, onClickItemSecondaryAction: (Extension) -> Unit = {}, ) - LongMethod:GlobalSearchToolbar.kt$@Composable fun GlobalSearchToolbar( searchQuery: String?, progress: Int, total: Int, navigateUp: () -> Unit, onChangeSearchQuery: (String?) -> Unit, onSearch: (String) -> Unit, sourceFilter: SourceFilter, onChangeSearchFilter: (SourceFilter) -> Unit, onlyShowHasResults: Boolean, onToggleResults: () -> Unit, scrollBehavior: TopAppBarScrollBehavior, ) - LongMethod:HomeScreen.kt$HomeScreen$@Composable override fun Content() - LongMethod:ImageUtil.kt$ImageUtil$fun chooseBackground(context: Context, imageStream: InputStream): Drawable - LongMethod:InfoScreen.kt$@Composable fun InfoScreen( icon: ImageVector, headingText: String, subtitleText: String, acceptText: String, onAcceptClick: () -> Unit, canAccept: Boolean = true, rejectText: String? = null, onRejectClick: (() -> Unit)? = null, content: @Composable ColumnScope.() -> Unit, ) - LongMethod:LibraryContent.kt$@Composable fun LibraryContent( categories: List<Category>, searchQuery: String?, selection: List<LibraryManga>, contentPadding: PaddingValues, currentPage: () -> Int, hasActiveFilters: Boolean, showPageTabs: Boolean, onChangeCurrentPage: (Int) -> Unit, onMangaClicked: (Long) -> Unit, onContinueReadingClicked: ((LibraryManga) -> Unit)?, onToggleSelection: (LibraryManga) -> Unit, onToggleRangeSelection: (LibraryManga) -> Unit, onRefresh: (Category?) -> Boolean, onGlobalSearchClicked: () -> Unit, getNumberOfMangaForCategory: (Category) -> Int?, getDisplayMode: (Int) -> PreferenceMutableState<LibraryDisplayMode>, getColumnsForOrientation: (Boolean) -> PreferenceMutableState<Int>, getLibraryForPage: (Int) -> List<LibraryItem>, ) - LongMethod:LibraryPager.kt$@Composable fun LibraryPager( state: PagerState, contentPadding: PaddingValues, hasActiveFilters: Boolean, selectedManga: List<LibraryManga>, searchQuery: String?, onGlobalSearchClicked: () -> Unit, getDisplayMode: (Int) -> PreferenceMutableState<LibraryDisplayMode>, getColumnsForOrientation: (Boolean) -> PreferenceMutableState<Int>, getLibraryForPage: (Int) -> List<LibraryItem>, onClickManga: (LibraryManga) -> Unit, onLongClickManga: (LibraryManga) -> Unit, onClickContinueReading: ((LibraryManga) -> Unit)?, ) - LongMethod:LibraryScreenModel.kt$LibraryScreenModel$private fun LibraryMap.applySort( // Map<MangaId, List<Track>> trackMap: Map<Long, List<Track>>, ): LibraryMap - LongMethod:LibraryScreenModel.kt$LibraryScreenModel$private suspend fun LibraryMap.applyFilters( trackMap: Map<Long, List<Track>>, loggedInTrackers: Map<Long, TriState>, ): LibraryMap - LongMethod:LibrarySettingsDialog.kt$@Composable private fun ColumnScope.DisplayPage( screenModel: LibrarySettingsScreenModel, ) - LongMethod:LibrarySettingsDialog.kt$@Composable private fun ColumnScope.FilterPage( screenModel: LibrarySettingsScreenModel, ) - LongMethod:LibraryTab.kt$LibraryTab$@Composable override fun Content() - LongMethod:LibraryUpdateJob.kt$LibraryUpdateJob$private suspend fun addMangaToQueue(categoryId: Long) - LongMethod:LibraryUpdateJob.kt$LibraryUpdateJob$private suspend fun updateChapterList() - LongMethod:MainActivity.kt$MainActivity$override fun onCreate(savedInstanceState: Bundle?) - LongMethod:MainActivity.kt$MainActivity$private fun handleIntentAction(intent: Intent, navigator: Navigator): Boolean - LongMethod:MangaBottomActionMenu.kt$@Composable fun LibraryBottomActionMenu( visible: Boolean, onChangeCategoryClicked: () -> Unit, onMarkAsReadClicked: () -> Unit, onMarkAsUnreadClicked: () -> Unit, onDownloadClicked: ((DownloadAction) -> Unit)?, onDeleteClicked: () -> Unit, modifier: Modifier = Modifier, ) - LongMethod:MangaBottomActionMenu.kt$@Composable fun MangaBottomActionMenu( visible: Boolean, modifier: Modifier = Modifier, onBookmarkClicked: (() -> Unit)? = null, onRemoveBookmarkClicked: (() -> Unit)? = null, onMarkAsReadClicked: (() -> Unit)? = null, onMarkAsUnreadClicked: (() -> Unit)? = null, onMarkPreviousAsReadClicked: (() -> Unit)? = null, onDownloadClicked: (() -> Unit)? = null, onDeleteClicked: (() -> Unit)? = null, ) - LongMethod:MangaChapterListItem.kt$@Composable fun MangaChapterListItem( title: String, date: String?, readProgress: String?, scanlator: String?, read: Boolean, bookmark: Boolean, selected: Boolean, downloadIndicatorEnabled: Boolean, downloadStateProvider: () -> Download.State, downloadProgressProvider: () -> Int, chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction, chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction, onLongClick: () -> Unit, onClick: () -> Unit, onDownloadClick: ((ChapterDownloadAction) -> Unit)?, onChapterSwipe: (LibraryPreferences.ChapterSwipeAction) -> Unit, modifier: Modifier = Modifier, ) - LongMethod:MangaCoverDialog.kt$@Composable fun MangaCoverDialog( coverDataProvider: () -> Manga, isCustomCover: Boolean, snackbarHostState: SnackbarHostState, onShareClick: () -> Unit, onSaveClick: () -> Unit, onEditClick: ((EditCoverAction) -> Unit)?, onDismissRequest: () -> Unit, ) - LongMethod:MangaDialogs.kt$@Composable fun SetIntervalDialog( interval: Int, nextUpdate: Instant?, onDismissRequest: () -> Unit, onValueChanged: ((Int) -> Unit)? = null, ) - LongMethod:MangaInfoHeader.kt$@Composable fun ExpandableMangaDescription( defaultExpandState: Boolean, description: String?, tagsProvider: () -> List<String>?, onTagSearch: (String) -> Unit, onCopyTagToClipboard: (tag: String) -> Unit, modifier: Modifier = Modifier, ) - LongMethod:MangaInfoHeader.kt$@Composable private fun ColumnScope.MangaContentInfo( title: String, doSearch: (query: String, global: Boolean) -> Unit, author: String?, artist: String?, status: Long, sourceName: String, isStubSource: Boolean, textAlign: TextAlign? = LocalTextStyle.current.textAlign, ) - LongMethod:MangaInfoHeader.kt$@Composable private fun MangaSummary( expandedDescription: String, shrunkDescription: String, expanded: Boolean, modifier: Modifier = Modifier, ) - LongMethod:MangaScreen.kt$@Composable fun MangaScreen( state: MangaScreenModel.State.Success, snackbarHostState: SnackbarHostState, nextUpdate: Instant?, isTabletUi: Boolean, chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction, chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction, onBackClicked: () -> Unit, onChapterClicked: (Chapter) -> Unit, onDownloadChapter: ((List<ChapterList.Item>, ChapterDownloadAction) -> Unit)?, onAddToLibraryClicked: () -> Unit, onWebViewClicked: (() -> Unit)?, onWebViewLongClicked: (() -> Unit)?, onTrackingClicked: () -> Unit, // For tags menu onTagSearch: (String) -> Unit, onFilterButtonClicked: () -> Unit, onRefresh: () -> Unit, onContinueReading: () -> Unit, onSearch: (query: String, global: Boolean) -> Unit, // For cover dialog onCoverClicked: () -> Unit, // For top action menu onShareClicked: (() -> Unit)?, onDownloadActionClicked: ((DownloadAction) -> Unit)?, onEditCategoryClicked: (() -> Unit)?, onEditFetchIntervalClicked: (() -> Unit)?, onMigrateClicked: (() -> Unit)?, // For bottom action menu onMultiBookmarkClicked: (List<Chapter>, bookmarked: Boolean) -> Unit, onMultiMarkAsReadClicked: (List<Chapter>, markAsRead: Boolean) -> Unit, onMarkPreviousAsReadClicked: (Chapter) -> Unit, onMultiDeleteClicked: (List<Chapter>) -> Unit, // For chapter swipe onChapterSwipe: (ChapterList.Item, LibraryPreferences.ChapterSwipeAction) -> Unit, // Chapter selection onChapterSelected: (ChapterList.Item, Boolean, Boolean, Boolean) -> Unit, onAllChapterSelected: (Boolean) -> Unit, onInvertSelection: () -> Unit, ) - LongMethod:MangaScreen.kt$@Composable fun MangaScreenLargeImpl( state: MangaScreenModel.State.Success, snackbarHostState: SnackbarHostState, nextUpdate: Instant?, chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction, chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction, onBackClicked: () -> Unit, onChapterClicked: (Chapter) -> Unit, onDownloadChapter: ((List<ChapterList.Item>, ChapterDownloadAction) -> Unit)?, onAddToLibraryClicked: () -> Unit, onWebViewClicked: (() -> Unit)?, onWebViewLongClicked: (() -> Unit)?, onTrackingClicked: () -> Unit, // For tags menu onTagSearch: (String) -> Unit, onCopyTagToClipboard: (tag: String) -> Unit, onFilterButtonClicked: () -> Unit, onRefresh: () -> Unit, onContinueReading: () -> Unit, onSearch: (query: String, global: Boolean) -> Unit, // For cover dialog onCoverClicked: () -> Unit, // For top action menu onShareClicked: (() -> Unit)?, onDownloadActionClicked: ((DownloadAction) -> Unit)?, onEditCategoryClicked: (() -> Unit)?, onEditIntervalClicked: (() -> Unit)?, onMigrateClicked: (() -> Unit)?, // For bottom action menu onMultiBookmarkClicked: (List<Chapter>, bookmarked: Boolean) -> Unit, onMultiMarkAsReadClicked: (List<Chapter>, markAsRead: Boolean) -> Unit, onMarkPreviousAsReadClicked: (Chapter) -> Unit, onMultiDeleteClicked: (List<Chapter>) -> Unit, // For swipe actions onChapterSwipe: (ChapterList.Item, LibraryPreferences.ChapterSwipeAction) -> Unit, // Chapter selection onChapterSelected: (ChapterList.Item, Boolean, Boolean, Boolean) -> Unit, onAllChapterSelected: (Boolean) -> Unit, onInvertSelection: () -> Unit, ) - LongMethod:MangaScreen.kt$@Composable private fun MangaScreenSmallImpl( state: MangaScreenModel.State.Success, snackbarHostState: SnackbarHostState, nextUpdate: Instant?, chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction, chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction, onBackClicked: () -> Unit, onChapterClicked: (Chapter) -> Unit, onDownloadChapter: ((List<ChapterList.Item>, ChapterDownloadAction) -> Unit)?, onAddToLibraryClicked: () -> Unit, onWebViewClicked: (() -> Unit)?, onWebViewLongClicked: (() -> Unit)?, onTrackingClicked: () -> Unit, // For tags menu onTagSearch: (String) -> Unit, onCopyTagToClipboard: (tag: String) -> Unit, onFilterClicked: () -> Unit, onRefresh: () -> Unit, onContinueReading: () -> Unit, onSearch: (query: String, global: Boolean) -> Unit, // For cover dialog onCoverClicked: () -> Unit, // For top action menu onShareClicked: (() -> Unit)?, onDownloadActionClicked: ((DownloadAction) -> Unit)?, onEditCategoryClicked: (() -> Unit)?, onEditIntervalClicked: (() -> Unit)?, onMigrateClicked: (() -> Unit)?, // For bottom action menu onMultiBookmarkClicked: (List<Chapter>, bookmarked: Boolean) -> Unit, onMultiMarkAsReadClicked: (List<Chapter>, markAsRead: Boolean) -> Unit, onMarkPreviousAsReadClicked: (Chapter) -> Unit, onMultiDeleteClicked: (List<Chapter>) -> Unit, // For chapter swipe onChapterSwipe: (ChapterList.Item, LibraryPreferences.ChapterSwipeAction) -> Unit, // Chapter selection onChapterSelected: (ChapterList.Item, Boolean, Boolean, Boolean) -> Unit, onAllChapterSelected: (Boolean) -> Unit, onInvertSelection: () -> Unit, ) - LongMethod:MangaScreen.kt$MangaScreen$@Composable override fun Content() - LongMethod:MangaScreen.kt$private fun LazyListScope.sharedChapterItems( manga: Manga, chapters: List<ChapterList>, isAnyChapterSelected: Boolean, chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction, chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction, onChapterClicked: (Chapter) -> Unit, onDownloadChapter: ((List<ChapterList.Item>, ChapterDownloadAction) -> Unit)?, onChapterSelected: (ChapterList.Item, Boolean, Boolean, Boolean) -> Unit, onChapterSwipe: (ChapterList.Item, LibraryPreferences.ChapterSwipeAction) -> Unit, ) - LongMethod:MangaToolbar.kt$@Composable fun MangaToolbar( title: String, titleAlphaProvider: () -> Float, hasFilters: Boolean, onBackClicked: () -> Unit, onClickFilter: () -> Unit, onClickShare: (() -> Unit)?, onClickDownload: ((DownloadAction) -> Unit)?, onClickEditCategory: (() -> Unit)?, onClickRefresh: () -> Unit, onClickMigrate: (() -> Unit)?, // For action mode actionModeCounter: Int, onSelectAll: () -> Unit, onInvertSelection: () -> Unit, modifier: Modifier = Modifier, backgroundAlphaProvider: () -> Float = titleAlphaProvider, ) - LongMethod:MigrateDialog.kt$@Composable internal fun MigrateDialog( oldManga: Manga, newManga: Manga, screenModel: MigrateDialogScreenModel, onDismissRequest: () -> Unit, onClickTitle: () -> Unit, onPopScreen: () -> Unit, ) - LongMethod:MigrateDialog.kt$MigrateDialogScreenModel$private suspend fun migrateMangaInternal( oldSource: Source?, newSource: Source, oldManga: Manga, newManga: Manga, sourceChapters: List<SChapter>, replace: Boolean, flags: Int, ) - LongMethod:MoreScreen.kt$@Composable fun MoreScreen( downloadQueueStateProvider: () -> DownloadQueueState, downloadedOnly: Boolean, onDownloadedOnlyChange: (Boolean) -> Unit, incognitoMode: Boolean, onIncognitoModeChange: (Boolean) -> Unit, isFDroid: Boolean, onClickDownloadQueue: () -> Unit, onClickCategories: () -> Unit, onClickStats: () -> Unit, onClickDataAndStorage: () -> Unit, onClickSettings: () -> Unit, onClickAbout: () -> Unit, ) - LongMethod:Notifications.kt$Notifications$fun createChannels(context: Context) - LongMethod:PreferenceItem.kt$@Composable internal fun PreferenceItem( item: Preference.PreferenceItem<*>, highlightKey: String?, ) - LongMethod:ReaderActivity.kt$ReaderActivity$override fun onCreate(savedInstanceState: Bundle?) - LongMethod:ReaderActivity.kt$ReaderActivity$private fun initializeMenu() - LongMethod:ReaderAppBars.kt$@Composable fun ReaderAppBars( visible: Boolean, fullscreen: Boolean, mangaTitle: String?, chapterTitle: String?, navigateUp: () -> Unit, onClickTopAppBar: () -> Unit, bookmarked: Boolean, onToggleBookmarked: () -> Unit, onOpenInWebView: (() -> Unit)?, onShare: (() -> Unit)?, viewer: Viewer?, onNextChapter: () -> Unit, enabledNext: Boolean, onPreviousChapter: () -> Unit, enabledPrevious: Boolean, currentPage: Int, totalPages: Int, onSliderValueChange: (Int) -> Unit, readingMode: ReadingMode, onClickReadingMode: () -> Unit, orientation: ReaderOrientation, onClickOrientation: () -> Unit, cropEnabled: Boolean, onClickCropBorder: () -> Unit, onClickSettings: () -> Unit, ) - LongMethod:ReadingModePage.kt$@Composable private fun ColumnScope.PagerViewerSettings(screenModel: ReaderSettingsScreenModel) - LongMethod:Scaffold.kt$@Composable private fun ScaffoldLayout( fabPosition: FabPosition, topBar: @Composable () -> Unit, startBar: @Composable () -> Unit, content: @Composable (PaddingValues) -> Unit, snackbar: @Composable () -> Unit, fab: @Composable () -> Unit, contentWindowInsets: WindowInsets, bottomBar: @Composable () -> Unit, ) - LongMethod:ScanlatorFilterDialog.kt$@Composable fun ScanlatorFilterDialog( availableScanlators: Set<String>, excludedScanlators: Set<String>, onDismissRequest: () -> Unit, onConfirm: (Set<String>) -> Unit, ) - LongMethod:SettingsAdvancedScreen.kt$SettingsAdvancedScreen$@Composable private fun getExtensionsGroup( basePreferences: BasePreferences, ): Preference.PreferenceGroup - LongMethod:SettingsAdvancedScreen.kt$SettingsAdvancedScreen$@Composable private fun getNetworkGroup( networkPreferences: NetworkPreferences, ): Preference.PreferenceGroup - LongMethod:SettingsDataScreen.kt$SettingsDataScreen$@Composable private fun getBackupAndRestoreGroup(backupPreferences: BackupPreferences): Preference.PreferenceGroup - LongMethod:SettingsLibraryScreen.kt$SettingsLibraryScreen$@Composable private fun getGlobalUpdateGroup( allCategories: List<Category>, libraryPreferences: LibraryPreferences, ): Preference.PreferenceGroup - LongMethod:SettingsMainScreen.kt$SettingsMainScreen$@Composable fun Content(twoPane: Boolean) - LongMethod:SettingsReaderScreen.kt$SettingsReaderScreen$@Composable private fun getPagedGroup(readerPreferences: ReaderPreferences): Preference.PreferenceGroup - LongMethod:SettingsReaderScreen.kt$SettingsReaderScreen$@Composable private fun getWebtoonGroup(readerPreferences: ReaderPreferences): Preference.PreferenceGroup - LongMethod:SettingsSearchScreen.kt$@Composable private fun SearchResult( searchKey: String, modifier: Modifier = Modifier, listState: LazyListState = rememberLazyListState(), contentPadding: PaddingValues = PaddingValues(), onItemClick: (SearchResultItem) -> Unit, ) - LongMethod:SettingsSearchScreen.kt$SettingsSearchScreen$@Composable override fun Content() - LongMethod:SettingsTrackingScreen.kt$SettingsTrackingScreen$@Composable override fun getPreferences(): List<Preference> - LongMethod:SettingsTrackingScreen.kt$SettingsTrackingScreen$@Composable private fun TrackingLoginDialog( tracker: Tracker, uNameStringRes: StringResource, onDismissRequest: () -> Unit, ) - LongMethod:SourceFilterDialog.kt$@Composable private fun FilterItem(filter: Filter<*>, onUpdate: () -> Unit) - LongMethod:SourceSearchScreen.kt$SourceSearchScreen$@Composable override fun Content() - LongMethod:SyncChaptersWithSource.kt$SyncChaptersWithSource$suspend fun await( rawSourceChapters: List<SChapter>, manga: Manga, source: Source, manualFetch: Boolean = false, fetchWindow: Pair<Long, Long> = Pair(0, 0), ): List<Chapter> - LongMethod:TrackInfoDialog.kt$TrackInfoDialogHomeScreen$@Composable override fun Content() - LongMethod:TrackInfoDialog.kt$TrackerRemoveScreen$@Composable override fun Content() - LongMethod:TrackInfoDialogHome.kt$@Composable private fun TrackInfoItem( title: String, tracker: Tracker, status: StringResource?, onStatusClick: () -> Unit, chapters: String, onChaptersClick: () -> Unit, score: String?, onScoreClick: (() -> Unit)?, startDate: String?, onStartDateClick: (() -> Unit)?, endDate: String?, onEndDateClick: (() -> Unit)?, onNewSearch: () -> Unit, onOpenInBrowser: () -> Unit, onRemoved: () -> Unit, ) - LongMethod:TrackerSearch.kt$@Composable fun TrackerSearch( query: TextFieldValue, onQueryChange: (TextFieldValue) -> Unit, onDispatchQuery: () -> Unit, queryResult: Result<List<TrackSearch>>?, selected: TrackSearch?, onSelectedChange: (TrackSearch) -> Unit, onConfirmSelection: () -> Unit, onDismissRequest: () -> Unit, ) - LongMethod:TrackerSearch.kt$@Composable private fun SearchResultItem( trackSearch: TrackSearch, selected: Boolean, onClick: () -> Unit, ) - LongMethod:TriStateListDialog.kt$@Composable fun <T> TriStateListDialog( title: String, message: String? = null, items: List<T>, initialChecked: List<T>, initialInversed: List<T>, itemLabel: @Composable (T) -> String, onDismissRequest: () -> Unit, onValueChanged: (newIncluded: List<T>, newExcluded: List<T>) -> Unit, ) - LongMethod:UpdatesScreen.kt$@Composable fun UpdateScreen( state: UpdatesScreenModel.State, snackbarHostState: SnackbarHostState, lastUpdated: Long, onClickCover: (UpdatesItem) -> Unit, onSelectAll: (Boolean) -> Unit, onInvertSelection: () -> Unit, onUpdateLibrary: () -> Boolean, onDownloadChapter: (List<UpdatesItem>, ChapterDownloadAction) -> Unit, onMultiBookmarkClicked: (List<UpdatesItem>, bookmark: Boolean) -> Unit, onMultiMarkAsReadClicked: (List<UpdatesItem>, read: Boolean) -> Unit, onMultiDeleteClicked: (List<UpdatesItem>) -> Unit, onUpdateSelected: (UpdatesItem, Boolean, Boolean, Boolean) -> Unit, onOpenChapter: (UpdatesItem) -> Unit, ) - LongMethod:UpdatesTab.kt$UpdatesTab$@Composable override fun Content() - LongMethod:UpdatesUiItem.kt$@Composable private fun UpdatesUiItem( update: UpdatesWithRelations, selected: Boolean, readProgress: String?, onClick: () -> Unit, onLongClick: () -> Unit, onClickCover: (() -> Unit)?, onDownloadChapter: ((ChapterDownloadAction) -> Unit)?, // Download Indicator downloadStateProvider: () -> Download.State, downloadProgressProvider: () -> Int, modifier: Modifier = Modifier, ) - LongMethod:UpdatesWidget.kt$@Composable fun UpdatesWidget( data: ImmutableList<Pair<Long, Bitmap?>>?, contentColor: ColorProvider, topPadding: Dp, bottomPadding: Dp, modifier: GlanceModifier = GlanceModifier, ) - LongMethod:VerticalFastScroller.kt$@Composable fun VerticalFastScroller( listState: LazyListState, modifier: Modifier = Modifier, thumbAllowed: () -> Boolean = { true }, thumbColor: Color = MaterialTheme.colorScheme.primary, topContentPadding: Dp = Dp.Hairline, bottomContentPadding: Dp = Dp.Hairline, endContentPadding: Dp = Dp.Hairline, content: @Composable () -> Unit, ) - LongMethod:VerticalFastScroller.kt$@Composable fun VerticalGridFastScroller( state: LazyGridState, columns: GridCells, arrangement: Arrangement.Horizontal, contentPadding: PaddingValues, modifier: Modifier = Modifier, thumbAllowed: () -> Boolean = { true }, thumbColor: Color = MaterialTheme.colorScheme.primary, topContentPadding: Dp = Dp.Hairline, bottomContentPadding: Dp = Dp.Hairline, endContentPadding: Dp = Dp.Hairline, content: @Composable () -> Unit, ) - LongMethod:WebViewScreenContent.kt$@Composable fun WebViewScreenContent( onNavigateUp: () -> Unit, initialTitle: String?, url: String, onShare: (String) -> Unit, onOpenInBrowser: (String) -> Unit, onClearCookies: (String) -> Unit, headers: Map<String, String> = emptyMap(), onUrlChange: (String) -> Unit = {}, ) - LongMethod:WebtoonRecyclerView.kt$WebtoonRecyclerView.Detector$override fun onTouchEvent(ev: MotionEvent): Boolean - LongMethod:WheelPicker.kt$@Composable private fun <T> WheelPicker( items: ImmutableList<T>, modifier: Modifier = Modifier, startIndex: Int = 0, size: DpSize = DpSize(128.dp, 128.dp), onSelectionChanged: (index: Int) -> Unit = {}, manualInputType: KeyboardType? = null, backgroundContent: (@Composable (size: DpSize) -> Unit)? = { WheelPickerDefaults.Background(size = it) }, itemContent: @Composable LazyItemScope.(item: T) -> Unit, ) - LongParameterList:BottomReaderBar.kt$( backgroundColor: Color, readingMode: ReadingMode, onClickReadingMode: () -> Unit, orientation: ReaderOrientation, onClickOrientation: () -> Unit, cropEnabled: Boolean, onClickCropBorder: () -> Unit, onClickSettings: () -> Unit, ) - LongParameterList:BrowseSourceScreen.kt$( source: Source?, mangaList: LazyPagingItems<StateFlow<Manga>>, columns: GridCells, displayMode: LibraryDisplayMode, snackbarHostState: SnackbarHostState, contentPadding: PaddingValues, onWebViewClick: () -> Unit, onHelpClick: () -> Unit, onLocalSourceHelpClick: () -> Unit, onMangaClick: (Manga) -> Unit, onMangaLongClick: (Manga) -> Unit, ) - LongParameterList:BrowseSourceToolbar.kt$( searchQuery: String?, onSearchQueryChange: (String?) -> Unit, source: Source?, displayMode: LibraryDisplayMode, onDisplayModeChange: (LibraryDisplayMode) -> Unit, navigateUp: () -> Unit, onWebViewClick: () -> Unit, onHelpClick: () -> Unit, onSettingsClick: () -> Unit, onSearch: (String) -> Unit, scrollBehavior: TopAppBarScrollBehavior? = null, ) - LongParameterList:CategoryListItem.kt$( category: Category, canMoveUp: Boolean, canMoveDown: Boolean, onMoveUp: (Category) -> Unit, onMoveDown: (Category) -> Unit, onRename: () -> Unit, onDelete: () -> Unit, modifier: Modifier = Modifier, ) - LongParameterList:CategoryScreen.kt$( categories: List<Category>, lazyListState: LazyListState, paddingValues: PaddingValues, onClickRename: (Category) -> Unit, onClickDelete: (Category) -> Unit, onMoveUp: (Category) -> Unit, onMoveDown: (Category) -> Unit, ) - LongParameterList:CategoryScreen.kt$( state: CategoryScreenState.Success, onClickCreate: () -> Unit, onClickSortAlphabetically: () -> Unit, onClickRename: (Category) -> Unit, onClickDelete: (Category) -> Unit, onClickMoveUp: (Category) -> Unit, onClickMoveDown: (Category) -> Unit, navigateUp: () -> Unit, ) - LongParameterList:ChapterNavigator.kt$( isRtl: Boolean, onNextChapter: () -> Unit, enabledNext: Boolean, onPreviousChapter: () -> Unit, enabledPrevious: Boolean, currentPage: Int, totalPages: Int, onSliderValueChange: (Int) -> Unit, ) - LongParameterList:ChapterRepositoryImpl.kt$ChapterRepositoryImpl$( id: Long, mangaId: Long, url: String, name: String, scanlator: String?, read: Boolean, bookmark: Boolean, lastPageRead: Long, chapterNumber: Double, sourceOrder: Long, dateFetch: Long, dateUpload: Long, lastModifiedAt: Long, ) - LongParameterList:ChapterSettingsDialog.kt$( downloadFilter: TriState, onDownloadFilterChanged: ((TriState) -> Unit)?, unreadFilter: TriState, onUnreadFilterChanged: (TriState) -> Unit, bookmarkedFilter: TriState, onBookmarkedFilterChanged: (TriState) -> Unit, scanlatorFilterActive: Boolean, onScanlatorFilterClicked: (() -> Unit), ) - LongParameterList:ChapterSettingsDialog.kt$( onDismissRequest: () -> Unit, manga: Manga? = null, onDownloadFilterChanged: (TriState) -> Unit, onUnreadFilterChanged: (TriState) -> Unit, onBookmarkedFilterChanged: (TriState) -> Unit, scanlatorFilterActive: Boolean, onScanlatorFilterClicked: (() -> Unit), onSortModeChanged: (Long) -> Unit, onDisplayModeChanged: (Long) -> Unit, onSetAsDefault: (applyToExistingManga: Boolean) -> Unit, onResetToDefault: () -> Unit, ) - LongParameterList:ChapterTransition.kt$( topLabel: String, topChapter: Chapter?, topChapterDownloaded: Boolean, bottomLabel: String, bottomChapter: Chapter?, bottomChapterDownloaded: Boolean, fallbackLabel: String, chapterGap: Int, ) - LongParameterList:ExtensionDetailsScreen.kt$( contentPadding: PaddingValues, extension: Extension.Installed, sources: ImmutableList<ExtensionSourceItem>, onClickSourcePreferences: (sourceId: Long) -> Unit, onClickUninstall: () -> Unit, onClickSource: (sourceId: Long) -> Unit, ) - LongParameterList:ExtensionDetailsScreen.kt$( navigateUp: () -> Unit, state: ExtensionDetailsScreenModel.State, onClickSourcePreferences: (sourceId: Long) -> Unit, onClickEnableAll: () -> Unit, onClickDisableAll: () -> Unit, onClickClearCookies: () -> Unit, onClickUninstall: () -> Unit, onClickSource: (sourceId: Long) -> Unit, ) - LongParameterList:ExtensionsScreen.kt$( item: ExtensionUiModel.Item, onClickItem: (Extension) -> Unit, onLongClickItem: (Extension) -> Unit, onClickItemCancel: (Extension) -> Unit, onClickItemAction: (Extension) -> Unit, onClickItemSecondaryAction: (Extension) -> Unit, modifier: Modifier = Modifier, ) - LongParameterList:ExtensionsScreen.kt$( state: ExtensionsScreenModel.State, contentPadding: PaddingValues, onLongClickItem: (Extension) -> Unit, onClickItemCancel: (Extension) -> Unit, onOpenWebView: (Extension.Available) -> Unit, onInstallExtension: (Extension.Available) -> Unit, onUninstallExtension: (Extension) -> Unit, onUpdateExtension: (Extension.Installed) -> Unit, onTrustExtension: (Extension.Untrusted) -> Unit, onOpenExtension: (Extension.Installed) -> Unit, onClickUpdateAll: () -> Unit, ) - LongParameterList:ExtensionsScreen.kt$( state: ExtensionsScreenModel.State, contentPadding: PaddingValues, searchQuery: String?, onLongClickItem: (Extension) -> Unit, onClickItemCancel: (Extension) -> Unit, onOpenWebView: (Extension.Available) -> Unit, onInstallExtension: (Extension.Available) -> Unit, onUninstallExtension: (Extension) -> Unit, onUpdateExtension: (Extension.Installed) -> Unit, onTrustExtension: (Extension.Untrusted) -> Unit, onOpenExtension: (Extension.Installed) -> Unit, onClickUpdateAll: () -> Unit, onRefresh: () -> Unit, ) - LongParameterList:GlobalSearchScreen.kt$( items: Map<CatalogueSource, SearchItemResult>, contentPadding: PaddingValues, getManga: @Composable (Manga) -> State<Manga>, onClickSource: (CatalogueSource) -> Unit, onClickItem: (Manga) -> Unit, onLongClickItem: (Manga) -> Unit, fromSourceId: Long? = null, ) - LongParameterList:GlobalSearchScreen.kt$( state: SearchScreenModel.State, navigateUp: () -> Unit, onChangeSearchQuery: (String?) -> Unit, onSearch: (String) -> Unit, onChangeSearchFilter: (SourceFilter) -> Unit, onToggleResults: () -> Unit, getManga: @Composable (Manga) -> State<Manga>, onClickSource: (CatalogueSource) -> Unit, onClickItem: (Manga) -> Unit, onLongClickItem: (Manga) -> Unit, ) - LongParameterList:GlobalSearchToolbar.kt$( searchQuery: String?, progress: Int, total: Int, navigateUp: () -> Unit, onChangeSearchQuery: (String?) -> Unit, onSearch: (String) -> Unit, sourceFilter: SourceFilter, onChangeSearchFilter: (SourceFilter) -> Unit, onlyShowHasResults: Boolean, onToggleResults: () -> Unit, scrollBehavior: TopAppBarScrollBehavior, ) - LongParameterList:HistoryMapper.kt$HistoryMapper$( historyId: Long, mangaId: Long, chapterId: Long, title: String, thumbnailUrl: String?, sourceId: Long, isFavorite: Boolean, coverLastModified: Long, chapterNumber: Double, readAt: Date?, readDuration: Long, ) - LongParameterList:HistoryScreen.kt$( state: HistoryScreenModel.State, snackbarHostState: SnackbarHostState, onSearchQueryChange: (String?) -> Unit, onClickCover: (mangaId: Long) -> Unit, onClickResume: (mangaId: Long, chapterId: Long) -> Unit, onDialogChange: (HistoryScreenModel.Dialog?) -> Unit, ) - LongParameterList:InfoScreen.kt$( icon: ImageVector, headingText: String, subtitleText: String, acceptText: String, onAcceptClick: () -> Unit, canAccept: Boolean = true, rejectText: String? = null, onRejectClick: (() -> Unit)? = null, content: @Composable ColumnScope.() -> Unit, ) - LongParameterList:LibraryComfortableGrid.kt$( items: List<LibraryItem>, columns: Int, contentPadding: PaddingValues, selection: List<LibraryManga>, onClick: (LibraryManga) -> Unit, onLongClick: (LibraryManga) -> Unit, onClickContinueReading: ((LibraryManga) -> Unit)?, searchQuery: String?, onGlobalSearchClicked: () -> Unit, ) - LongParameterList:LibraryCompactGrid.kt$( items: List<LibraryItem>, showTitle: Boolean, columns: Int, contentPadding: PaddingValues, selection: List<LibraryManga>, onClick: (LibraryManga) -> Unit, onLongClick: (LibraryManga) -> Unit, onClickContinueReading: ((LibraryManga) -> Unit)?, searchQuery: String?, onGlobalSearchClicked: () -> Unit, ) - LongParameterList:LibraryContent.kt$( categories: List<Category>, searchQuery: String?, selection: List<LibraryManga>, contentPadding: PaddingValues, currentPage: () -> Int, hasActiveFilters: Boolean, showPageTabs: Boolean, onChangeCurrentPage: (Int) -> Unit, onMangaClicked: (Long) -> Unit, onContinueReadingClicked: ((LibraryManga) -> Unit)?, onToggleSelection: (LibraryManga) -> Unit, onToggleRangeSelection: (LibraryManga) -> Unit, onRefresh: (Category?) -> Boolean, onGlobalSearchClicked: () -> Unit, getNumberOfMangaForCategory: (Category) -> Int?, getDisplayMode: (Int) -> PreferenceMutableState<LibraryDisplayMode>, getColumnsForOrientation: (Boolean) -> PreferenceMutableState<Int>, getLibraryForPage: (Int) -> List<LibraryItem>, ) - LongParameterList:LibraryList.kt$( items: List<LibraryItem>, contentPadding: PaddingValues, selection: List<LibraryManga>, onClick: (LibraryManga) -> Unit, onLongClick: (LibraryManga) -> Unit, onClickContinueReading: ((LibraryManga) -> Unit)?, searchQuery: String?, onGlobalSearchClicked: () -> Unit, ) - LongParameterList:LibraryPager.kt$( state: PagerState, contentPadding: PaddingValues, hasActiveFilters: Boolean, selectedManga: List<LibraryManga>, searchQuery: String?, onGlobalSearchClicked: () -> Unit, getDisplayMode: (Int) -> PreferenceMutableState<LibraryDisplayMode>, getColumnsForOrientation: (Boolean) -> PreferenceMutableState<Int>, getLibraryForPage: (Int) -> List<LibraryItem>, onClickManga: (LibraryManga) -> Unit, onLongClickManga: (LibraryManga) -> Unit, onClickContinueReading: ((LibraryManga) -> Unit)?, ) - LongParameterList:LibraryToolbar.kt$( hasActiveFilters: Boolean, selectedCount: Int, title: LibraryToolbarTitle, onClickUnselectAll: () -> Unit, onClickSelectAll: () -> Unit, onClickInvertSelection: () -> Unit, onClickFilter: () -> Unit, onClickRefresh: () -> Unit, onClickGlobalUpdate: () -> Unit, onClickOpenRandomManga: () -> Unit, searchQuery: String?, onSearchQueryChange: (String?) -> Unit, scrollBehavior: TopAppBarScrollBehavior?, ) - LongParameterList:LibraryToolbar.kt$( title: LibraryToolbarTitle, hasFilters: Boolean, searchQuery: String?, onSearchQueryChange: (String?) -> Unit, onClickFilter: () -> Unit, onClickRefresh: () -> Unit, onClickGlobalUpdate: () -> Unit, onClickOpenRandomManga: () -> Unit, scrollBehavior: TopAppBarScrollBehavior?, ) - LongParameterList:ListPreferenceWidget.kt$( value: T, title: String, subtitle: String?, icon: ImageVector?, entries: Map<out T, String>, onValueChange: (T) -> Unit, ) - LongParameterList:MangaBottomActionMenu.kt$( visible: Boolean, onChangeCategoryClicked: () -> Unit, onMarkAsReadClicked: () -> Unit, onMarkAsUnreadClicked: () -> Unit, onDownloadClicked: ((DownloadAction) -> Unit)?, onDeleteClicked: () -> Unit, modifier: Modifier = Modifier, ) - LongParameterList:MangaChapterListItem.kt$( action: LibraryPreferences.ChapterSwipeAction, read: Boolean, bookmark: Boolean, downloadState: Download.State, background: Color, onSwipe: () -> Unit, ) - LongParameterList:MangaChapterListItem.kt$( title: String, date: String?, readProgress: String?, scanlator: String?, read: Boolean, bookmark: Boolean, selected: Boolean, downloadIndicatorEnabled: Boolean, downloadStateProvider: () -> Download.State, downloadProgressProvider: () -> Int, chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction, chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction, onLongClick: () -> Unit, onClick: () -> Unit, onDownloadClick: ((ChapterDownloadAction) -> Unit)?, onChapterSwipe: (LibraryPreferences.ChapterSwipeAction) -> Unit, modifier: Modifier = Modifier, ) - LongParameterList:MangaCoverDialog.kt$( coverDataProvider: () -> Manga, isCustomCover: Boolean, snackbarHostState: SnackbarHostState, onShareClick: () -> Unit, onSaveClick: () -> Unit, onEditClick: ((EditCoverAction) -> Unit)?, onDismissRequest: () -> Unit, ) - LongParameterList:MangaCoverFetcher.kt$MangaCoverFetcher$( private val url: String?, private val isLibraryManga: Boolean, private val options: Options, private val coverFileLazy: Lazy<File?>, private val customCoverFileLazy: Lazy<File>, private val diskCacheKeyLazy: Lazy<String>, private val sourceLazy: Lazy<HttpSource?>, private val callFactoryLazy: Lazy<Call.Factory>, private val diskCacheLazy: Lazy<DiskCache>, ) - LongParameterList:MangaInfoHeader.kt$( appBarPadding: Dp, coverDataProvider: () -> Manga, onCoverClick: () -> Unit, title: String, doSearch: (query: String, global: Boolean) -> Unit, author: String?, artist: String?, status: Long, sourceName: String, isStubSource: Boolean, ) - LongParameterList:MangaInfoHeader.kt$( favorite: Boolean, trackingCount: Int, nextUpdate: Instant?, isUserIntervalMode: Boolean, onAddToLibraryClicked: () -> Unit, onWebViewClicked: (() -> Unit)?, onWebViewLongClicked: (() -> Unit)?, onTrackingClicked: () -> Unit, onEditIntervalClicked: (() -> Unit)?, onEditCategory: (() -> Unit)?, modifier: Modifier = Modifier, ) - LongParameterList:MangaInfoHeader.kt$( isTabletUi: Boolean, appBarPadding: Dp, title: String, author: String?, artist: String?, sourceName: String, isStubSource: Boolean, coverDataProvider: () -> Manga, status: Long, onCoverClick: () -> Unit, doSearch: (query: String, global: Boolean) -> Unit, modifier: Modifier = Modifier, ) - LongParameterList:MangaInfoHeader.kt$( title: String, doSearch: (query: String, global: Boolean) -> Unit, author: String?, artist: String?, status: Long, sourceName: String, isStubSource: Boolean, textAlign: TextAlign? = LocalTextStyle.current.textAlign, ) - LongParameterList:MangaMapper.kt$MangaMapper$( id: Long, source: Long, url: String, artist: String?, author: String?, description: String?, genre: List<String>?, title: String, status: Long, thumbnailUrl: String?, favorite: Boolean, lastUpdate: Long?, nextUpdate: Long?, initialized: Boolean, viewerFlags: Long, chapterFlags: Long, coverLastModified: Long, dateAdded: Long, updateStrategy: UpdateStrategy, calculateInterval: Long, lastModifiedAt: Long, favoriteModifiedAt: Long?, ) - LongParameterList:MangaMapper.kt$MangaMapper$( id: Long, source: Long, url: String, artist: String?, author: String?, description: String?, genre: List<String>?, title: String, status: Long, thumbnailUrl: String?, favorite: Boolean, lastUpdate: Long?, nextUpdate: Long?, initialized: Boolean, viewerFlags: Long, chapterFlags: Long, coverLastModified: Long, dateAdded: Long, updateStrategy: UpdateStrategy, calculateInterval: Long, lastModifiedAt: Long, favoriteModifiedAt: Long?, totalCount: Long, readCount: Double, latestUpload: Long, chapterFetchedAt: Long, lastRead: Long, bookmarkCount: Double, category: Long, ) - LongParameterList:MangaRestorer.kt$MangaRestorer$( manga: Manga, chapters: List<BackupChapter>, categories: List<Long>, backupCategories: List<BackupCategory>, history: List<BackupHistory>, tracks: List<BackupTracking>, excludedScanlators: List<String>, ) - LongParameterList:MangaScreen.kt$( manga: Manga, chapters: List<ChapterList>, isAnyChapterSelected: Boolean, chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction, chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction, onChapterClicked: (Chapter) -> Unit, onDownloadChapter: ((List<ChapterList.Item>, ChapterDownloadAction) -> Unit)?, onChapterSelected: (ChapterList.Item, Boolean, Boolean, Boolean) -> Unit, onChapterSwipe: (ChapterList.Item, LibraryPreferences.ChapterSwipeAction) -> Unit, ) - LongParameterList:MangaScreen.kt$( selected: List<ChapterList.Item>, onMultiBookmarkClicked: (List<Chapter>, bookmarked: Boolean) -> Unit, onMultiMarkAsReadClicked: (List<Chapter>, markAsRead: Boolean) -> Unit, onMarkPreviousAsReadClicked: (Chapter) -> Unit, onDownloadChapter: ((List<ChapterList.Item>, ChapterDownloadAction) -> Unit)?, onMultiDeleteClicked: (List<Chapter>) -> Unit, fillFraction: Float, modifier: Modifier = Modifier, ) - LongParameterList:MangaScreen.kt$( state: MangaScreenModel.State.Success, snackbarHostState: SnackbarHostState, nextUpdate: Instant?, chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction, chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction, onBackClicked: () -> Unit, onChapterClicked: (Chapter) -> Unit, onDownloadChapter: ((List<ChapterList.Item>, ChapterDownloadAction) -> Unit)?, onAddToLibraryClicked: () -> Unit, onWebViewClicked: (() -> Unit)?, onWebViewLongClicked: (() -> Unit)?, onTrackingClicked: () -> Unit, // For tags menu onTagSearch: (String) -> Unit, onCopyTagToClipboard: (tag: String) -> Unit, onFilterButtonClicked: () -> Unit, onRefresh: () -> Unit, onContinueReading: () -> Unit, onSearch: (query: String, global: Boolean) -> Unit, // For cover dialog onCoverClicked: () -> Unit, // For top action menu onShareClicked: (() -> Unit)?, onDownloadActionClicked: ((DownloadAction) -> Unit)?, onEditCategoryClicked: (() -> Unit)?, onEditIntervalClicked: (() -> Unit)?, onMigrateClicked: (() -> Unit)?, // For bottom action menu onMultiBookmarkClicked: (List<Chapter>, bookmarked: Boolean) -> Unit, onMultiMarkAsReadClicked: (List<Chapter>, markAsRead: Boolean) -> Unit, onMarkPreviousAsReadClicked: (Chapter) -> Unit, onMultiDeleteClicked: (List<Chapter>) -> Unit, // For swipe actions onChapterSwipe: (ChapterList.Item, LibraryPreferences.ChapterSwipeAction) -> Unit, // Chapter selection onChapterSelected: (ChapterList.Item, Boolean, Boolean, Boolean) -> Unit, onAllChapterSelected: (Boolean) -> Unit, onInvertSelection: () -> Unit, ) - LongParameterList:MangaScreen.kt$( state: MangaScreenModel.State.Success, snackbarHostState: SnackbarHostState, nextUpdate: Instant?, chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction, chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction, onBackClicked: () -> Unit, onChapterClicked: (Chapter) -> Unit, onDownloadChapter: ((List<ChapterList.Item>, ChapterDownloadAction) -> Unit)?, onAddToLibraryClicked: () -> Unit, onWebViewClicked: (() -> Unit)?, onWebViewLongClicked: (() -> Unit)?, onTrackingClicked: () -> Unit, // For tags menu onTagSearch: (String) -> Unit, onCopyTagToClipboard: (tag: String) -> Unit, onFilterClicked: () -> Unit, onRefresh: () -> Unit, onContinueReading: () -> Unit, onSearch: (query: String, global: Boolean) -> Unit, // For cover dialog onCoverClicked: () -> Unit, // For top action menu onShareClicked: (() -> Unit)?, onDownloadActionClicked: ((DownloadAction) -> Unit)?, onEditCategoryClicked: (() -> Unit)?, onEditIntervalClicked: (() -> Unit)?, onMigrateClicked: (() -> Unit)?, // For bottom action menu onMultiBookmarkClicked: (List<Chapter>, bookmarked: Boolean) -> Unit, onMultiMarkAsReadClicked: (List<Chapter>, markAsRead: Boolean) -> Unit, onMarkPreviousAsReadClicked: (Chapter) -> Unit, onMultiDeleteClicked: (List<Chapter>) -> Unit, // For chapter swipe onChapterSwipe: (ChapterList.Item, LibraryPreferences.ChapterSwipeAction) -> Unit, // Chapter selection onChapterSelected: (ChapterList.Item, Boolean, Boolean, Boolean) -> Unit, onAllChapterSelected: (Boolean) -> Unit, onInvertSelection: () -> Unit, ) - LongParameterList:MangaScreen.kt$( state: MangaScreenModel.State.Success, snackbarHostState: SnackbarHostState, nextUpdate: Instant?, isTabletUi: Boolean, chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction, chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction, onBackClicked: () -> Unit, onChapterClicked: (Chapter) -> Unit, onDownloadChapter: ((List<ChapterList.Item>, ChapterDownloadAction) -> Unit)?, onAddToLibraryClicked: () -> Unit, onWebViewClicked: (() -> Unit)?, onWebViewLongClicked: (() -> Unit)?, onTrackingClicked: () -> Unit, // For tags menu onTagSearch: (String) -> Unit, onFilterButtonClicked: () -> Unit, onRefresh: () -> Unit, onContinueReading: () -> Unit, onSearch: (query: String, global: Boolean) -> Unit, // For cover dialog onCoverClicked: () -> Unit, // For top action menu onShareClicked: (() -> Unit)?, onDownloadActionClicked: ((DownloadAction) -> Unit)?, onEditCategoryClicked: (() -> Unit)?, onEditFetchIntervalClicked: (() -> Unit)?, onMigrateClicked: (() -> Unit)?, // For bottom action menu onMultiBookmarkClicked: (List<Chapter>, bookmarked: Boolean) -> Unit, onMultiMarkAsReadClicked: (List<Chapter>, markAsRead: Boolean) -> Unit, onMarkPreviousAsReadClicked: (Chapter) -> Unit, onMultiDeleteClicked: (List<Chapter>) -> Unit, // For chapter swipe onChapterSwipe: (ChapterList.Item, LibraryPreferences.ChapterSwipeAction) -> Unit, // Chapter selection onChapterSelected: (ChapterList.Item, Boolean, Boolean, Boolean) -> Unit, onAllChapterSelected: (Boolean) -> Unit, onInvertSelection: () -> Unit, ) - LongParameterList:MangaToolbar.kt$( title: String, titleAlphaProvider: () -> Float, hasFilters: Boolean, onBackClicked: () -> Unit, onClickFilter: () -> Unit, onClickShare: (() -> Unit)?, onClickDownload: ((DownloadAction) -> Unit)?, onClickEditCategory: (() -> Unit)?, onClickRefresh: () -> Unit, onClickMigrate: (() -> Unit)?, // For action mode actionModeCounter: Int, onSelectAll: () -> Unit, onInvertSelection: () -> Unit, modifier: Modifier = Modifier, backgroundAlphaProvider: () -> Float = titleAlphaProvider, ) - LongParameterList:MigrateDialog.kt$( oldManga: Manga, newManga: Manga, screenModel: MigrateDialogScreenModel, onDismissRequest: () -> Unit, onClickTitle: () -> Unit, onPopScreen: () -> Unit, ) - LongParameterList:MigrateDialog.kt$MigrateDialogScreenModel$( oldSource: Source?, newSource: Source, oldManga: Manga, newManga: Manga, sourceChapters: List<SChapter>, replace: Boolean, flags: Int, ) - LongParameterList:MigrateSearchScreen.kt$( state: SearchScreenModel.State, fromSourceId: Long?, navigateUp: () -> Unit, onChangeSearchQuery: (String?) -> Unit, onSearch: (String) -> Unit, onChangeSearchFilter: (SourceFilter) -> Unit, onToggleResults: () -> Unit, getManga: @Composable (Manga) -> State<Manga>, onClickSource: (CatalogueSource) -> Unit, onClickItem: (Manga) -> Unit, onLongClickItem: (Manga) -> Unit, ) - LongParameterList:MigrateSourceScreen.kt$( list: ImmutableList<Pair<Source, Long>>, contentPadding: PaddingValues, onClickItem: (Source) -> Unit, onLongClickItem: (Source) -> Unit, sortingMode: SetMigrateSorting.Mode, onToggleSortingMode: () -> Unit, sortingDirection: SetMigrateSorting.Direction, onToggleSortingDirection: () -> Unit, ) - LongParameterList:MoreScreen.kt$( downloadQueueStateProvider: () -> DownloadQueueState, downloadedOnly: Boolean, onDownloadedOnlyChange: (Boolean) -> Unit, incognitoMode: Boolean, onIncognitoModeChange: (Boolean) -> Unit, isFDroid: Boolean, onClickDownloadQueue: () -> Unit, onClickCategories: () -> Unit, onClickStats: () -> Unit, onClickDataAndStorage: () -> Unit, onClickSettings: () -> Unit, onClickAbout: () -> Unit, ) - LongParameterList:ReaderAppBars.kt$( visible: Boolean, fullscreen: Boolean, mangaTitle: String?, chapterTitle: String?, navigateUp: () -> Unit, onClickTopAppBar: () -> Unit, bookmarked: Boolean, onToggleBookmarked: () -> Unit, onOpenInWebView: (() -> Unit)?, onShare: (() -> Unit)?, viewer: Viewer?, onNextChapter: () -> Unit, enabledNext: Boolean, onPreviousChapter: () -> Unit, enabledPrevious: Boolean, currentPage: Int, totalPages: Int, onSliderValueChange: (Int) -> Unit, readingMode: ReadingMode, onClickReadingMode: () -> Unit, orientation: ReaderOrientation, onClickOrientation: () -> Unit, cropEnabled: Boolean, onClickCropBorder: () -> Unit, onClickSettings: () -> Unit, ) - LongParameterList:Scaffold.kt$( fabPosition: FabPosition, topBar: @Composable () -> Unit, startBar: @Composable () -> Unit, content: @Composable (PaddingValues) -> Unit, snackbar: @Composable () -> Unit, fab: @Composable () -> Unit, contentWindowInsets: WindowInsets, bottomBar: @Composable () -> Unit, ) - LongParameterList:Scrollbar.kt$( orientation: Orientation, reverseDirection: Boolean, atEnd: Boolean, showScrollbar: Boolean, thickness: Float, color: Color, alpha: () -> Float, thumbSize: Float, scrollOffset: Float, positionOffset: Float, ) - LongParameterList:SetMangaChapterFlags.kt$SetMangaChapterFlags$( mangaId: Long, unreadFilter: Long, downloadedFilter: Long, bookmarkedFilter: Long, sortingMode: Long, sortingDirection: Long, displayMode: Long, ) - LongParameterList:SyncChaptersWithSource.kt$SyncChaptersWithSource$( private val downloadManager: DownloadManager, private val downloadProvider: DownloadProvider, private val chapterRepository: ChapterRepository, private val shouldUpdateDbChapter: ShouldUpdateDbChapter, private val updateManga: UpdateManga, private val updateChapter: UpdateChapter, private val getChaptersByMangaId: GetChaptersByMangaId, private val getExcludedScanlators: GetExcludedScanlators, ) - LongParameterList:TrackInfoDialogHome.kt$( title: String, tracker: Tracker, status: StringResource?, onStatusClick: () -> Unit, chapters: String, onChaptersClick: () -> Unit, score: String?, onScoreClick: (() -> Unit)?, startDate: String?, onStartDateClick: (() -> Unit)?, endDate: String?, onEndDateClick: (() -> Unit)?, onNewSearch: () -> Unit, onOpenInBrowser: () -> Unit, onRemoved: () -> Unit, ) - LongParameterList:TrackInfoDialogHome.kt$( trackItems: List<TrackItem>, dateFormat: DateFormat, onStatusClick: (TrackItem) -> Unit, onChapterClick: (TrackItem) -> Unit, onScoreClick: (TrackItem) -> Unit, onStartDateEdit: (TrackItem) -> Unit, onEndDateEdit: (TrackItem) -> Unit, onNewSearch: (TrackItem) -> Unit, onOpenInBrowser: (TrackItem) -> Unit, onRemoved: (TrackItem) -> Unit, ) - LongParameterList:TrackInfoDialogSelector.kt$( title: String, initialSelectedDateMillis: Long, selectableDates: SelectableDates, onConfirm: (Long) -> Unit, onRemove: (() -> Unit)?, onDismissRequest: () -> Unit, ) - LongParameterList:TrackMapper.kt$TrackMapper$( id: Long, mangaId: Long, syncId: Long, remoteId: Long, libraryId: Long?, title: String, lastChapterRead: Double, totalChapters: Long, status: Long, score: Double, remoteUrl: String, startDate: Long, finishDate: Long, ) - LongParameterList:TrackerSearch.kt$( query: TextFieldValue, onQueryChange: (TextFieldValue) -> Unit, onDispatchQuery: () -> Unit, queryResult: Result<List<TrackSearch>>?, selected: TrackSearch?, onSelectedChange: (TrackSearch) -> Unit, onConfirmSelection: () -> Unit, onDismissRequest: () -> Unit, ) - LongParameterList:TriStateListDialog.kt$( title: String, message: String? = null, items: List<T>, initialChecked: List<T>, initialInversed: List<T>, itemLabel: @Composable (T) -> String, onDismissRequest: () -> Unit, onValueChanged: (newIncluded: List<T>, newExcluded: List<T>) -> Unit, ) - LongParameterList:UpdatesRepositoryImpl.kt$UpdatesRepositoryImpl$( mangaId: Long, mangaTitle: String, chapterId: Long, chapterName: String, scanlator: String?, read: Boolean, bookmark: Boolean, lastPageRead: Long, sourceId: Long, favorite: Boolean, thumbnailUrl: String?, coverLastModified: Long, dateUpload: Long, dateFetch: Long, ) - LongParameterList:UpdatesScreen.kt$( onUpdateLibrary: () -> Unit, // For action mode actionModeCounter: Int, onSelectAll: () -> Unit, onInvertSelection: () -> Unit, onCancelActionMode: () -> Unit, scrollBehavior: TopAppBarScrollBehavior, modifier: Modifier = Modifier, ) - LongParameterList:UpdatesScreen.kt$( state: UpdatesScreenModel.State, snackbarHostState: SnackbarHostState, lastUpdated: Long, onClickCover: (UpdatesItem) -> Unit, onSelectAll: (Boolean) -> Unit, onInvertSelection: () -> Unit, onUpdateLibrary: () -> Boolean, onDownloadChapter: (List<UpdatesItem>, ChapterDownloadAction) -> Unit, onMultiBookmarkClicked: (List<UpdatesItem>, bookmark: Boolean) -> Unit, onMultiMarkAsReadClicked: (List<UpdatesItem>, read: Boolean) -> Unit, onMultiDeleteClicked: (List<UpdatesItem>) -> Unit, onUpdateSelected: (UpdatesItem, Boolean, Boolean, Boolean) -> Unit, onOpenChapter: (UpdatesItem) -> Unit, ) - LongParameterList:UpdatesUiItem.kt$( uiModels: List<UpdatesUiModel>, selectionMode: Boolean, onUpdateSelected: (UpdatesItem, Boolean, Boolean, Boolean) -> Unit, onClickCover: (UpdatesItem) -> Unit, onClickUpdate: (UpdatesItem) -> Unit, onDownloadChapter: (List<UpdatesItem>, ChapterDownloadAction) -> Unit, ) - LongParameterList:UpdatesUiItem.kt$( update: UpdatesWithRelations, selected: Boolean, readProgress: String?, onClick: () -> Unit, onLongClick: () -> Unit, onClickCover: (() -> Unit)?, onDownloadChapter: ((ChapterDownloadAction) -> Unit)?, // Download Indicator downloadStateProvider: () -> Download.State, downloadProgressProvider: () -> Int, modifier: Modifier = Modifier, ) - LongParameterList:WebViewScreenContent.kt$( onNavigateUp: () -> Unit, initialTitle: String?, url: String, onShare: (String) -> Unit, onOpenInBrowser: (String) -> Unit, onClearCookies: (String) -> Unit, headers: Map<String, String> = emptyMap(), onUrlChange: (String) -> Unit = {}, ) - LongParameterList:WebtoonRecyclerView.kt$WebtoonRecyclerView$( fromRate: Float, toRate: Float, fromX: Float, toX: Float, fromY: Float, toY: Float, ) - LoopWithTooManyJumpStatements:DownloadStore.kt$DownloadStore$for - LoopWithTooManyJumpStatements:ImageUtil.kt$ImageUtil$for - LoopWithTooManyJumpStatements:Kavita.kt$Kavita$for - LoopWithTooManyJumpStatements:RateLimitInterceptor.kt$RateLimitInterceptor$while - LoopWithTooManyJumpStatements:UpdatesScreenModel.kt$UpdatesScreenModel$for - MagicNumber:AdaptiveSheet.kt$220 - MagicNumber:AdaptiveSheet.kt$90 - MagicNumber:Anilist.kt$Anilist$10 - MagicNumber:Anilist.kt$Anilist$10.0 - MagicNumber:Anilist.kt$Anilist$100 - MagicNumber:Anilist.kt$Anilist$10f - MagicNumber:Anilist.kt$Anilist$18 - MagicNumber:Anilist.kt$Anilist$20 - MagicNumber:Anilist.kt$Anilist$20.0 - MagicNumber:Anilist.kt$Anilist$25 - MagicNumber:Anilist.kt$Anilist$25.0 - MagicNumber:Anilist.kt$Anilist$35 - MagicNumber:Anilist.kt$Anilist$5 - MagicNumber:Anilist.kt$Anilist$60 - MagicNumber:AnilistApi.kt$AnilistApi$31536000000 - MagicNumber:AnilistModels.kt$10 - MagicNumber:AnilistModels.kt$30 - MagicNumber:AnilistModels.kt$35 - MagicNumber:AnilistModels.kt$50 - MagicNumber:AnilistModels.kt$60 - MagicNumber:AnilistModels.kt$70 - MagicNumber:AnilistModels.kt$90 - MagicNumber:App.kt$App$300 - MagicNumber:App.kt$App$8 - MagicNumber:AppThemePreferenceWidget.kt$0.3f - MagicNumber:AppThemePreferenceWidget.kt$0.5f - MagicNumber:AppThemePreferenceWidget.kt$0.6f - MagicNumber:AppThemePreferenceWidget.kt$0.7f - MagicNumber:AppThemePreferenceWidget.kt$0.8f - MagicNumber:AppThemePreferenceWidget.kt$16f - MagicNumber:AppThemePreferenceWidget.kt$9f - MagicNumber:AppUpdateDownloadJob.kt$AppUpdateDownloadJob.<no name provided>$100 - MagicNumber:AppUpdateDownloadJob.kt$AppUpdateDownloadJob.<no name provided>$200 - MagicNumber:AppUpdateNotifier.kt$AppUpdateNotifier$100 - MagicNumber:Backup.kt$Backup$100 - MagicNumber:Backup.kt$Backup$101 - MagicNumber:Backup.kt$Backup$104 - MagicNumber:Backup.kt$Backup$105 - MagicNumber:BackupCategory.kt$BackupCategory$100 - MagicNumber:BackupChapter.kt$BackupChapter$10 - MagicNumber:BackupChapter.kt$BackupChapter$11 - MagicNumber:BackupChapter.kt$BackupChapter$3 - MagicNumber:BackupChapter.kt$BackupChapter$4 - MagicNumber:BackupChapter.kt$BackupChapter$5 - MagicNumber:BackupChapter.kt$BackupChapter$6 - MagicNumber:BackupChapter.kt$BackupChapter$7 - MagicNumber:BackupChapter.kt$BackupChapter$8 - MagicNumber:BackupChapter.kt$BackupChapter$9 - MagicNumber:BackupCreateJob.kt$BackupCreateJob.Companion$10 - MagicNumber:BackupDecoder.kt$BackupDecoder$0x1f8b - MagicNumber:BackupHistory.kt$BackupHistory$3 - MagicNumber:BackupManga.kt$BackupManga$100 - MagicNumber:BackupManga.kt$BackupManga$101 - MagicNumber:BackupManga.kt$BackupManga$102 - MagicNumber:BackupManga.kt$BackupManga$103 - MagicNumber:BackupManga.kt$BackupManga$104 - MagicNumber:BackupManga.kt$BackupManga$105 - MagicNumber:BackupManga.kt$BackupManga$106 - MagicNumber:BackupManga.kt$BackupManga$107 - MagicNumber:BackupManga.kt$BackupManga$108 - MagicNumber:BackupManga.kt$BackupManga$13 - MagicNumber:BackupManga.kt$BackupManga$14 - MagicNumber:BackupManga.kt$BackupManga$16 - MagicNumber:BackupManga.kt$BackupManga$17 - MagicNumber:BackupManga.kt$BackupManga$18 - MagicNumber:BackupManga.kt$BackupManga$3 - MagicNumber:BackupManga.kt$BackupManga$4 - MagicNumber:BackupManga.kt$BackupManga$5 - MagicNumber:BackupManga.kt$BackupManga$6 - MagicNumber:BackupManga.kt$BackupManga$7 - MagicNumber:BackupManga.kt$BackupManga$8 - MagicNumber:BackupManga.kt$BackupManga$9 - MagicNumber:BackupPreferences.kt$BackupPreferences$12 - MagicNumber:BackupTracking.kt$BackupTracking$10 - MagicNumber:BackupTracking.kt$BackupTracking$100 - MagicNumber:BackupTracking.kt$BackupTracking$11 - MagicNumber:BackupTracking.kt$BackupTracking$3 - MagicNumber:BackupTracking.kt$BackupTracking$4 - MagicNumber:BackupTracking.kt$BackupTracking$5 - MagicNumber:BackupTracking.kt$BackupTracking$6 - MagicNumber:BackupTracking.kt$BackupTracking$7 - MagicNumber:BackupTracking.kt$BackupTracking$8 - MagicNumber:BackupTracking.kt$BackupTracking$9 - MagicNumber:Bangumi.kt$Bangumi$145 - MagicNumber:Bangumi.kt$Bangumi$153 - MagicNumber:Bangumi.kt$Bangumi$240 - MagicNumber:BangumiInterceptor.kt$BangumiInterceptor$1000 - MagicNumber:BangumiModels.kt$1000 - MagicNumber:BangumiModels.kt$3600 - MagicNumber:BangumiModels.kt$OAuth$1000 - MagicNumber:BasePreferenceWidget.kt$200 - MagicNumber:BrowseIcons.kt$0x1F888888 - MagicNumber:ChapterDownloadIndicator.kt$0.5f - MagicNumber:ChapterRecognition.kt$ChapterRecognition$10 - MagicNumber:ChapterRecognition.kt$ChapterRecognition$10.0 - MagicNumber:ChapterRecognition.kt$ChapterRecognition$2.0 - MagicNumber:ChapterRecognition.kt$ChapterRecognition$3 - MagicNumber:CircularProgressIndicator.kt$2000 - MagicNumber:ColorFilterPage.kt$16 - MagicNumber:ColorFilterPage.kt$24 - MagicNumber:ColorFilterPage.kt$8 - MagicNumber:CommonMangaItem.kt$0.33f - MagicNumber:CommonMangaItem.kt$0xAA000000 - MagicNumber:ContextExtensions.kt$3 - MagicNumber:ContextExtensions.kt$50 - MagicNumber:DateExtensions.kt$7 - MagicNumber:DelayedTrackingUpdateJob.kt$DelayedTrackingUpdateJob$3 - MagicNumber:DelayedTrackingUpdateJob.kt$DelayedTrackingUpdateJob.Companion$5 - MagicNumber:DeviceUtil.kt$DeviceUtil$1024 - MagicNumber:DeviceUtil.kt$DeviceUtil$3L - MagicNumber:DeviceUtil.kt$DeviceUtil$90000 - MagicNumber:DiskUtil.kt$DiskUtil$240 - MagicNumber:Download.kt$Download.State.DOWNLOADED$3 - MagicNumber:Download.kt$Download.State.ERROR$4 - MagicNumber:DownloadCache.kt$DownloadCache$1000 - MagicNumber:DownloadDropdownMenu.kt$10 - MagicNumber:DownloadDropdownMenu.kt$25 - MagicNumber:DownloadDropdownMenu.kt$5 - MagicNumber:DownloadHolder.kt$DownloadHolder$100 - MagicNumber:DownloadNotifier.kt$DownloadNotifier$15 - MagicNumber:DownloadNotifier.kt$DownloadNotifier$30 - MagicNumber:DownloadProvider.kt$DownloadProvider$4 - MagicNumber:DownloadQueueScreen.kt$DownloadQueueScreen$0.08f - MagicNumber:DownloadQueueScreen.kt$DownloadQueueScreen$0.12f - MagicNumber:DownloadQueueScreenModel.kt$DownloadQueueScreenModel$50 - MagicNumber:Downloader.kt$Downloader$100 - MagicNumber:Downloader.kt$Downloader$1000 - MagicNumber:Downloader.kt$Downloader$3 - MagicNumber:Downloader.kt$Downloader$5 - MagicNumber:DropdownMenu.kt$56 - MagicNumber:ExtensionDetailsScreen.kt$1.5f - MagicNumber:ExtensionInstallService.kt$ExtensionInstallService$100 - MagicNumber:FetchInterval.kt$FetchInterval$10 - MagicNumber:FetchInterval.kt$FetchInterval$1000 - MagicNumber:FetchInterval.kt$FetchInterval$3 - MagicNumber:FetchInterval.kt$FetchInterval$7 - MagicNumber:FetchInterval.kt$FetchInterval$8 - MagicNumber:GetApplicationRelease.kt$GetApplicationRelease$3 - MagicNumber:GlanceUtils.kt$10 - MagicNumber:GlanceUtils.kt$64 - MagicNumber:GlanceUtils.kt$95 - MagicNumber:GlobalSearchItem.kt$99f - MagicNumber:Hash.kt$Hash$15 - MagicNumber:Hash.kt$Hash$240 - MagicNumber:Hash.kt$Hash$4 - MagicNumber:HttpSource.kt$HttpSource$0xff - MagicNumber:HttpSource.kt$HttpSource$7 - MagicNumber:HttpSource.kt$HttpSource$8 - MagicNumber:ImageUtil.kt$ImageUtil$0.01 - MagicNumber:ImageUtil.kt$ImageUtil$0.0275 - MagicNumber:ImageUtil.kt$ImageUtil$100 - MagicNumber:ImageUtil.kt$ImageUtil$14 - MagicNumber:ImageUtil.kt$ImageUtil$18 - MagicNumber:ImageUtil.kt$ImageUtil$200 - MagicNumber:ImageUtil.kt$ImageUtil$22 - MagicNumber:ImageUtil.kt$ImageUtil$25 - MagicNumber:ImageUtil.kt$ImageUtil$3 - MagicNumber:ImageUtil.kt$ImageUtil$30 - MagicNumber:ImageUtil.kt$ImageUtil$32 - MagicNumber:ImageUtil.kt$ImageUtil$40 - MagicNumber:ImageUtil.kt$ImageUtil$5 - MagicNumber:ImageUtil.kt$ImageUtil$50 - MagicNumber:ImageUtil.kt$ImageUtil$6 - MagicNumber:ImageUtil.kt$ImageUtil$740 - MagicNumber:ImageUtil.kt$ImageUtil$9 - MagicNumber:Kavita.kt$Kavita$0xff - MagicNumber:Kavita.kt$Kavita$148 - MagicNumber:Kavita.kt$Kavita$198 - MagicNumber:Kavita.kt$Kavita$3 - MagicNumber:Kavita.kt$Kavita$7 - MagicNumber:Kavita.kt$Kavita$74 - MagicNumber:Kavita.kt$Kavita$8 - MagicNumber:KavitaApi.kt$KavitaApi$200 - MagicNumber:KavitaApi.kt$KavitaApi$204 - MagicNumber:KavitaApi.kt$KavitaApi$401 - MagicNumber:KavitaApi.kt$KavitaApi$500 - MagicNumber:KavitaModels.kt$OAuth$3 - MagicNumber:Kitsu.kt$Kitsu$20 - MagicNumber:Kitsu.kt$Kitsu$37 - MagicNumber:Kitsu.kt$Kitsu$50 - MagicNumber:Kitsu.kt$Kitsu$51 - MagicNumber:KitsuModels.kt$1000 - MagicNumber:KitsuModels.kt$3600 - MagicNumber:Komga.kt$Komga$37 - MagicNumber:Komga.kt$Komga$50 - MagicNumber:Komga.kt$Komga$51 - MagicNumber:LibraryScreenModel.kt$LibraryScreenModel$10 - MagicNumber:LibraryScreenModel.kt$LibraryScreenModel$25 - MagicNumber:LibraryScreenModel.kt$LibraryScreenModel$5 - MagicNumber:LibrarySortMode.kt$LibrarySort.Direction.Ascending$0b01000000 - MagicNumber:LibrarySortMode.kt$LibrarySort.Type.ChapterFetchDate$0b00011000 - MagicNumber:LibrarySortMode.kt$LibrarySort.Type.DateAdded$0b00011100 - MagicNumber:LibrarySortMode.kt$LibrarySort.Type.LastRead$0b00000100 - MagicNumber:LibrarySortMode.kt$LibrarySort.Type.LastUpdate$0b00001000 - MagicNumber:LibrarySortMode.kt$LibrarySort.Type.LatestChapter$0b00010100 - MagicNumber:LibrarySortMode.kt$LibrarySort.Type.TotalChapters$0b00010000 - MagicNumber:LibrarySortMode.kt$LibrarySort.Type.TrackerMean$0b000100000 - MagicNumber:LibrarySortMode.kt$LibrarySort.Type.UnreadCount$0b00001100 - MagicNumber:LibraryToolbar.kt$0.08f - MagicNumber:LibraryToolbar.kt$0.12f - MagicNumber:LibraryUpdateJob.kt$LibraryUpdateJob$5 - MagicNumber:LibraryUpdateJob.kt$LibraryUpdateJob.Companion$10 - MagicNumber:LibraryUpdateNotifier.kt$LibraryUpdateNotifier$40 - MagicNumber:MangaBottomActionMenu.kt$3 - MagicNumber:MangaBottomActionMenu.kt$4 - MagicNumber:MangaBottomActionMenu.kt$5 - MagicNumber:MangaBottomActionMenu.kt$6 - MagicNumber:MangaBottomActionMenu.kt$7 - MagicNumber:MangaCover.kt$MangaCover.Book$3f - MagicNumber:MangaInfoHeader.kt$0.2f - MagicNumber:MangaInfoHeader.kt$0.65f - MagicNumber:MangaScreenModel.kt$MangaScreenModel$10 - MagicNumber:MangaScreenModel.kt$MangaScreenModel$103 - MagicNumber:MangaScreenModel.kt$MangaScreenModel$25 - MagicNumber:MangaScreenModel.kt$MangaScreenModel$5 - MagicNumber:MangaUpdates.kt$MangaUpdates$146 - MagicNumber:MangaUpdates.kt$MangaUpdates$160 - MagicNumber:MangaUpdates.kt$MangaUpdates$173 - MagicNumber:MangaUpdatesApi.kt$MangaUpdatesApi$200 - MagicNumber:MetadataUpdateJob.kt$MetadataUpdateJob$5 - MagicNumber:Modifier.kt$0.16f - MagicNumber:Modifier.kt$0.22f - MagicNumber:MonetColorScheme.kt$MonetColorScheme.Companion$128 - MagicNumber:MyAnimeList.kt$MyAnimeList$162 - MagicNumber:MyAnimeList.kt$MyAnimeList$46 - MagicNumber:MyAnimeList.kt$MyAnimeList$81 - MagicNumber:MyAnimeListApi.kt$MyAnimeListApi$64 - MagicNumber:MyAnimeListInterceptor.kt$MyAnimeListInterceptor$401 - MagicNumber:MyAnimeListModels.kt$1000 - MagicNumber:NetworkHelper.kt$NetworkHelper$30 - MagicNumber:Page.kt$Page$100 - MagicNumber:PageIndicatorText.kt$235 - MagicNumber:PageIndicatorText.kt$45 - MagicNumber:PagerConfig.kt$PagerConfig$3 - MagicNumber:PagerConfig.kt$PagerConfig$4 - MagicNumber:PagerConfig.kt$PagerConfig$5 - MagicNumber:PagerPageHolder.kt$PagerPageHolder$16 - MagicNumber:PagerPageHolder.kt$PagerPageHolder$90f - MagicNumber:PagerViewer.kt$PagerViewer$5 - MagicNumber:PkceUtil.kt$PkceUtil$50 - MagicNumber:PullRefresh.kt$PullToRefreshStateImpl$4 - MagicNumber:ReaderActivity.kt$ReaderActivity$230 - MagicNumber:ReaderActivity.kt$ReaderActivity$242 - MagicNumber:ReaderActivity.kt$ReaderActivity.ReaderConfig$0.01f - MagicNumber:ReaderActivity.kt$ReaderActivity.ReaderConfig$100 - MagicNumber:ReaderActivity.kt$ReaderActivity.ReaderConfig$100f - MagicNumber:ReaderActivity.kt$ReaderActivity.ReaderConfig$255f - MagicNumber:ReaderActivity.kt$ReaderActivity.ReaderConfig$3 - MagicNumber:ReaderContentOverlay.kt$100f - MagicNumber:ReaderOrientation.kt$ReaderOrientation.FREE$0x00000008 - MagicNumber:ReaderOrientation.kt$ReaderOrientation.LANDSCAPE$0x00000018 - MagicNumber:ReaderOrientation.kt$ReaderOrientation.LOCKED_LANDSCAPE$0x00000028 - MagicNumber:ReaderOrientation.kt$ReaderOrientation.LOCKED_PORTRAIT$0x00000020 - MagicNumber:ReaderOrientation.kt$ReaderOrientation.PORTRAIT$0x00000010 - MagicNumber:ReaderOrientation.kt$ReaderOrientation.REVERSE_PORTRAIT$0x00000030 - MagicNumber:ReaderPageImageView.kt$ReaderPageImageView$180 - MagicNumber:ReaderPageImageView.kt$ReaderPageImageView$250 - MagicNumber:ReaderPageImageView.kt$ReaderPageImageView$500 - MagicNumber:ReaderPreferences.kt$ReaderPreferences$500 - MagicNumber:ReaderPreferences.kt$ReaderPreferences.ReaderHideThreshold.HIGH$13 - MagicNumber:ReaderPreferences.kt$ReaderPreferences.ReaderHideThreshold.HIGHEST$5 - MagicNumber:ReaderPreferences.kt$ReaderPreferences.ReaderHideThreshold.LOW$31 - MagicNumber:ReaderPreferences.kt$ReaderPreferences.ReaderHideThreshold.LOWEST$47 - MagicNumber:ReaderProgressIndicator.kt$ReaderProgressIndicator$100f - MagicNumber:ReaderSettingsDialog.kt$0.5f - MagicNumber:ReaderViewModel.kt$ReaderViewModel$0.25 - MagicNumber:ReadingMode.kt$ReadingMode.CONTINUOUS_VERTICAL$0x00000005 - MagicNumber:ReadingMode.kt$ReadingMode.VERTICAL$0x00000003 - MagicNumber:ReadingMode.kt$ReadingMode.WEBTOON$0x00000004 - MagicNumber:ReadingModePage.kt$100f - MagicNumber:ReadingModePage.kt$5 - MagicNumber:SaveImageNotifier.kt$SaveImageNotifier$1280 - MagicNumber:SaveImageNotifier.kt$SaveImageNotifier$720 - MagicNumber:Scaffold.kt$3 - MagicNumber:Scaffold.kt$4 - MagicNumber:Scaffold.kt$5 - MagicNumber:Scaffold.kt$6 - MagicNumber:Scaffold.kt$7 - MagicNumber:Scaffold.kt$8 - MagicNumber:Scaffold.kt$9 - MagicNumber:Scrollbar.kt$100 - MagicNumber:Scrollbar.kt$50 - MagicNumber:SecureActivityDelegate.kt$SecureActivityDelegate.Companion$60_000 - MagicNumber:SettingsDataScreen.kt$SettingsDataScreen$12 - MagicNumber:SettingsDataScreen.kt$SettingsDataScreen$168 - MagicNumber:SettingsDataScreen.kt$SettingsDataScreen$24 - MagicNumber:SettingsDataScreen.kt$SettingsDataScreen$48 - MagicNumber:SettingsDataScreen.kt$SettingsDataScreen$6 - MagicNumber:SettingsDownloadScreen.kt$SettingsDownloadScreen$10 - MagicNumber:SettingsDownloadScreen.kt$SettingsDownloadScreen$3 - MagicNumber:SettingsDownloadScreen.kt$SettingsDownloadScreen$4 - MagicNumber:SettingsDownloadScreen.kt$SettingsDownloadScreen$5 - MagicNumber:SettingsItems.kt$0.5f - MagicNumber:SettingsItems.kt$1.5f - MagicNumber:SettingsLibraryScreen.kt$SettingsLibraryScreen$12 - MagicNumber:SettingsLibraryScreen.kt$SettingsLibraryScreen$168 - MagicNumber:SettingsLibraryScreen.kt$SettingsLibraryScreen$24 - MagicNumber:SettingsLibraryScreen.kt$SettingsLibraryScreen$48 - MagicNumber:SettingsLibraryScreen.kt$SettingsLibraryScreen$72 - MagicNumber:SettingsMainScreen.kt$SettingsMainScreen$0.02f - MagicNumber:SettingsMainScreen.kt$SettingsMainScreen$0.05f - MagicNumber:SettingsMainScreen.kt$SettingsMainScreen$3 - MagicNumber:SettingsReaderScreen.kt$SettingsReaderScreen$100f - MagicNumber:SettingsReaderScreen.kt$SettingsReaderScreen$250 - MagicNumber:SettingsReaderScreen.kt$SettingsReaderScreen$3 - MagicNumber:SettingsReaderScreen.kt$SettingsReaderScreen$500 - MagicNumber:SettingsSearchScreen.kt$10 - MagicNumber:Shikimori.kt$Shikimori$40 - MagicNumber:ShikimoriModels.kt$1000 - MagicNumber:ShikimoriModels.kt$3600 - MagicNumber:Surface.kt$100f - MagicNumber:Surface.kt$4.5f - MagicNumber:Suwayomi.kt$Suwayomi$255 - MagicNumber:Suwayomi.kt$Suwayomi$35 - MagicNumber:Tabs.kt$0.08f - MagicNumber:Tabs.kt$0.12f - MagicNumber:TimeUtils.kt$4 - MagicNumber:TrackInfoDialog.kt$TrackChapterSelectorScreen.Model$10000 - MagicNumber:TrackInfoDialogSelector.kt$3L - MagicNumber:TrackInfoDialogSelector.kt$4L - MagicNumber:TrackInfoDialogSelector.kt$5L - MagicNumber:TrackInfoDialogSelector.kt$6L - MagicNumber:TrackerSearchPreviewProvider.kt$TrackerSearchPreviewProvider$10 - MagicNumber:TrackerSearchPreviewProvider.kt$TrackerSearchPreviewProvider$100 - MagicNumber:TrackerSearchPreviewProvider.kt$TrackerSearchPreviewProvider$1000L - MagicNumber:TrackerSearchPreviewProvider.kt$TrackerSearchPreviewProvider$100L - MagicNumber:TrackerSearchPreviewProvider.kt$TrackerSearchPreviewProvider$30 - MagicNumber:TrackerSearchPreviewProvider.kt$TrackerSearchPreviewProvider$365 - MagicNumber:TrackerSearchPreviewProvider.kt$TrackerSearchPreviewProvider$40 - MagicNumber:TrackingPreferenceWidget.kt$0xFF4CAF50 - MagicNumber:UniFileTempFileManager.kt$UniFileTempFileManager$3 - MagicNumber:UniFileTempFileManager.kt$UniFileTempFileManager$8192 - MagicNumber:UpdatesScreenModel.kt$UpdatesScreenModel$3 - MagicNumber:VerticalFastScroller.kt$100 - MagicNumber:ViewerNavigation.kt$ViewerNavigation.NavigationRegion.LEFT$0x11 - MagicNumber:ViewerNavigation.kt$ViewerNavigation.NavigationRegion.LEFT$0x28 - MagicNumber:ViewerNavigation.kt$ViewerNavigation.NavigationRegion.LEFT$0x7D - MagicNumber:ViewerNavigation.kt$ViewerNavigation.NavigationRegion.LEFT$0xCC - MagicNumber:ViewerNavigation.kt$ViewerNavigation.NavigationRegion.MENU$0x81 - MagicNumber:ViewerNavigation.kt$ViewerNavigation.NavigationRegion.MENU$0x8D - MagicNumber:ViewerNavigation.kt$ViewerNavigation.NavigationRegion.MENU$0x95 - MagicNumber:ViewerNavigation.kt$ViewerNavigation.NavigationRegion.MENU$0xCC - MagicNumber:ViewerNavigation.kt$ViewerNavigation.NavigationRegion.NEXT$0x84 - MagicNumber:ViewerNavigation.kt$ViewerNavigation.NavigationRegion.NEXT$0x96 - MagicNumber:ViewerNavigation.kt$ViewerNavigation.NavigationRegion.NEXT$0xCC - MagicNumber:ViewerNavigation.kt$ViewerNavigation.NavigationRegion.NEXT$0xE2 - MagicNumber:ViewerNavigation.kt$ViewerNavigation.NavigationRegion.PREV$0x33 - MagicNumber:ViewerNavigation.kt$ViewerNavigation.NavigationRegion.PREV$0x77 - MagicNumber:ViewerNavigation.kt$ViewerNavigation.NavigationRegion.PREV$0xCC - MagicNumber:ViewerNavigation.kt$ViewerNavigation.NavigationRegion.PREV$0xFF - MagicNumber:ViewerNavigation.kt$ViewerNavigation.NavigationRegion.RIGHT$0xA6 - MagicNumber:ViewerNavigation.kt$ViewerNavigation.NavigationRegion.RIGHT$0xCC - MagicNumber:ViewerNavigation.kt$ViewerNavigation.NavigationRegion.RIGHT$0xCF - MagicNumber:ViewerNavigation.kt$ViewerNavigation.NavigationRegion.RIGHT$0xD5 - MagicNumber:WebViewInterceptor.kt$WebViewInterceptor$30 - MagicNumber:WebtoonConfig.kt$WebtoonConfig$3 - MagicNumber:WebtoonConfig.kt$WebtoonConfig$4 - MagicNumber:WebtoonConfig.kt$WebtoonConfig$5 - MagicNumber:WebtoonPageHolder.kt$WebtoonPageHolder$0.8 - MagicNumber:WebtoonPageHolder.kt$WebtoonPageHolder$100f - MagicNumber:WebtoonPageHolder.kt$WebtoonPageHolder$16 - MagicNumber:WebtoonPageHolder.kt$WebtoonPageHolder$90f - MagicNumber:WebtoonRecyclerView.kt$WebtoonRecyclerView$0.4f - MagicNumber:WebtoonRecyclerView.kt$WebtoonRecyclerView$400 - MagicNumber:WebtoonRecyclerView.kt$WebtoonRecyclerView.Detector$0.5f - MagicNumber:WebtoonViewer.kt$WebtoonViewer$3 - MagicNumber:WebtoonViewer.kt$WebtoonViewer$5 - MagicNumber:WheelPicker.kt$0.2f - MagicNumber:WheelPicker.kt$1.2f - MagicNumber:WorkManagerExtensions.kt$500 - MatchingDeclarationName:ChapterDownloadIndicator.kt$ChapterDownloadAction - MatchingDeclarationName:CommonMangaItem.kt$CommonMangaItemDefaults - MatchingDeclarationName:EmptyScreen.kt$EmptyScreenAction - MatchingDeclarationName:LibrarySortMode.kt$LibrarySort : FlagWithMask - MatchingDeclarationName:MyAnimeListModels.kt$OAuth - MatchingDeclarationName:NetworkStateTracker.kt$NetworkState - MatchingDeclarationName:SettingsItems.kt$SettingsItemsPaddings - MatchingDeclarationName:ShikimoriModels.kt$OAuth - MatchingDeclarationName:TabbedDialog.kt$TabbedDialogPaddings - MaxLineLength:CoroutinesExtensions.kt$* - MaxLineLength:Downloader.kt$Downloader$. - MaxLineLength:LibraryUpdateJob.kt$LibraryUpdateJob$// failedUpdates will already have the source, don't need to copy it into the message - MaxLineLength:MainActivity.kt$MainActivity$// or the Google-specific search intent (triggered by saying or typing "search *query* on *Tachiyomi*" in Google Search/Google Assistant) - MaxLineLength:PreferenceScreen.kt$* - MaxLineLength:Scaffold.kt$* - MaxLineLength:SpecificHostRateLimitInterceptor.kt$* - MaxLineLength:WebViewUtil.kt$WebViewUtil$* - MemberNameEqualsClassName:ExtensionInstaller.kt$ExtensionInstaller$private val extensionInstaller = Injekt.get<BasePreferences>().extensionInstaller() - ModifierClickableOrder:ScanlatorFilterDialog.kt$clickable { if (isExcluded) { mutableExcludedScanlators.remove(scanlator) } else { mutableExcludedScanlators.add(scanlator) } } - ModifierMissing:AppBar.kt$AppBarActions - ModifierMissing:AppThemePreferenceWidget.kt$AppThemePreviewItem - ModifierMissing:BottomReaderBar.kt$BottomReaderBar - ModifierMissing:BrowseSourceComfortableGrid.kt$BrowseSourceComfortableGrid - ModifierMissing:BrowseSourceCompactGrid.kt$BrowseSourceCompactGrid - ModifierMissing:BrowseSourceList.kt$BrowseSourceList - ModifierMissing:BrowseSourceScreen.kt$BrowseSourceContent - ModifierMissing:BrowseSourceToolbar.kt$BrowseSourceToolbar - ModifierMissing:CategoryScreen.kt$CategoryScreen - ModifierMissing:ChapterNavigator.kt$ChapterNavigator - ModifierMissing:ChapterSettingsDialog.kt$ChapterSettingsDialog - ModifierMissing:ChapterSettingsDialog.kt$ScanlatorFilterItem - ModifierMissing:CollapsibleBox.kt$CollapsibleBox - ModifierMissing:CommonMangaItem.kt$MangaComfortableGridItem - ModifierMissing:CommonMangaItem.kt$MangaCompactGridItem - ModifierMissing:CommonMangaItem.kt$MangaListItem - ModifierMissing:CrashScreen.kt$CrashScreen - ModifierMissing:ExtensionDetailsScreen.kt$ExtensionDetailsScreen - ModifierMissing:ExtensionFilterScreen.kt$ExtensionFilterScreen - ModifierMissing:ExtensionReposScreen.kt$ExtensionReposScreen - ModifierMissing:ExtensionsScreen.kt$ExtensionScreen - ModifierMissing:GlobalSearchCardRow.kt$GlobalSearchCardRow - ModifierMissing:GlobalSearchResultItems.kt$GlobalSearchErrorResultItem - ModifierMissing:GlobalSearchResultItems.kt$GlobalSearchLoadingResultItem - ModifierMissing:GlobalSearchResultItems.kt$GlobalSearchResultItem - ModifierMissing:GlobalSearchScreen.kt$GlobalSearchScreen - ModifierMissing:GlobalSearchToolbar.kt$GlobalSearchToolbar - ModifierMissing:HistoryScreen.kt$HistoryScreen - ModifierMissing:HomeScreen.kt$HomeScreen$NavigationRailItem - ModifierMissing:InfoScreen.kt$InfoScreen - ModifierMissing:LibraryContent.kt$LibraryContent - ModifierMissing:LibraryPager.kt$LibraryPager - ModifierMissing:LibrarySettingsDialog.kt$LibrarySettingsDialog - ModifierMissing:LogoHeader.kt$LogoHeader - ModifierMissing:MangaCoverDialog.kt$MangaCoverDialog - ModifierMissing:MangaScreen.kt$MangaScreenLargeImpl - ModifierMissing:MigrateMangaScreen.kt$MigrateMangaScreen - ModifierMissing:MigrateSearchScreen.kt$MigrateSearchScreen - ModifierMissing:MigrateSourceScreen.kt$MigrateSourceScreen - ModifierMissing:ModeSelectionDialog.kt$ModeSelectionDialog - ModifierMissing:MoreScreen.kt$MoreScreen - ModifierMissing:NewUpdateScreen.kt$NewUpdateScreen - ModifierMissing:OnboardingScreen.kt$OnboardingScreen - ModifierMissing:PageIndicatorText.kt$PageIndicatorText - ModifierMissing:PreferenceGroupHeader.kt$PreferenceGroupHeader - ModifierMissing:PreferenceScaffold.kt$PreferenceScaffold - ModifierMissing:ReaderAppBars.kt$ReaderAppBars - ModifierMissing:ReaderPageActionsDialog.kt$ReaderPageActionsDialog - ModifierMissing:ReaderSettingsDialog.kt$ReaderSettingsDialog - ModifierMissing:SectionCard.kt$SectionCard - ModifierMissing:SettingsItems.kt$CheckboxItem - ModifierMissing:SettingsItems.kt$HeadingItem - ModifierMissing:SettingsItems.kt$IconItem - ModifierMissing:SettingsItems.kt$RadioItem - ModifierMissing:SettingsItems.kt$SelectItem - ModifierMissing:SettingsItems.kt$SettingsChipRow - ModifierMissing:SettingsItems.kt$SettingsIconGrid - ModifierMissing:SettingsItems.kt$SliderItem - ModifierMissing:SettingsItems.kt$SortItem - ModifierMissing:SettingsItems.kt$TextItem - ModifierMissing:SettingsItems.kt$TriStateItem - ModifierMissing:SettingsMainScreen.kt$SettingsMainScreen$Content - ModifierMissing:SourceFilterDialog.kt$SourceFilterDialog - ModifierMissing:SourcesFilterScreen.kt$SourcesFilterScreen - ModifierMissing:SourcesScreen.kt$SourcesScreen - ModifierMissing:StatsScreenContent.kt$StatsScreenContent - ModifierMissing:TabbedScreen.kt$TabbedScreen - ModifierMissing:Tabs.kt$TabText - ModifierMissing:TrackInfoDialogHome.kt$TrackInfoDialogHome - ModifierMissing:TrackInfoDialogSelector.kt$TrackChapterSelector - ModifierMissing:TrackInfoDialogSelector.kt$TrackDateSelector - ModifierMissing:TrackInfoDialogSelector.kt$TrackScoreSelector - ModifierMissing:TrackInfoDialogSelector.kt$TrackStatusSelector - ModifierMissing:TrackLogoIcon.kt$TrackLogoIcon - ModifierMissing:TrackerSearch.kt$TrackerSearch - ModifierMissing:UpdatesScreen.kt$UpdateScreen - ModifierMissing:WebViewScreenContent.kt$WebViewScreenContent - ModifierMissing:WheelPicker.kt$WheelPickerDefaults$Background - ModifierMissing:WheelPicker.kt$WheelPickerDefaults$Item - ModifierNotUsedAtRoot:DropdownMenu.kt$modifier = modifier - ModifierNotUsedAtRoot:MangaChapterListItem.kt$modifier = modifier .selectedBackground(selected) .combinedClickable( onClick = onClick, onLongClick = onLongClick, ) .padding(start = 16.dp, top = 12.dp, end = 8.dp, bottom = 12.dp) - ModifierNotUsedAtRoot:TrackingPreferenceWidget.kt$modifier = modifier .clickable(enabled = onClick != null, onClick = { onClick?.invoke() }) .fillMaxWidth() .padding(horizontal = PrefsHorizontalPadding, vertical = 8.dp) - NestedBlockDepth:Anilist.kt$Anilist$override suspend fun update(track: Track, didReadChapter: Boolean): Track - NestedBlockDepth:AppLanguageScreen.kt$AppLanguageScreen$private fun getLangs(context: Context): ImmutableList<Language> - NestedBlockDepth:BackupRestorer.kt$BackupRestorer$private fun writeErrorLog(): File - NestedBlockDepth:BrowseSourceScreenModel.kt$BrowseSourceScreenModel$fun searchGenre(genreName: String) - NestedBlockDepth:ChapterLoader.kt$ChapterLoader$private fun getPageLoader(chapter: ReaderChapter): PageLoader - NestedBlockDepth:CloseableExtensions.kt$inline fun <T : Closeable?> Array<T>.use(block: () -> Unit) - NestedBlockDepth:ContextExtensions.kt$fun Context.openInBrowser(uri: Uri, forceDefaultBrowser: Boolean = false) - NestedBlockDepth:DownloadQueueScreenModel.kt$DownloadQueueScreenModel.<no name provided>$override fun onMenuItemClick(position: Int, menuItem: MenuItem) - NestedBlockDepth:Downloader.kt$Downloader$private fun archiveChapter( mangaDir: UniFile, dirname: String, tmpDir: UniFile, ) - NestedBlockDepth:ExtensionInstaller.kt$ExtensionInstaller$fun installApk(downloadId: Long, uri: Uri) - NestedBlockDepth:ImageUtil.kt$ImageUtil$fun chooseBackground(context: Context, imageStream: InputStream): Drawable - NestedBlockDepth:KavitaApi.kt$KavitaApi$fun getNewToken(apiUrl: String, apiKey: String): String? - NestedBlockDepth:KavitaApi.kt$KavitaApi$private fun getLatestChapterRead(url: String): Double - NestedBlockDepth:Kitsu.kt$Kitsu$override suspend fun update(track: Track, didReadChapter: Boolean): Track - NestedBlockDepth:LibraryUpdateJob.kt$LibraryUpdateJob$private fun writeErrorFile(errors: List<Pair<Manga, String?>>): File - NestedBlockDepth:LocalSource.kt$LocalSource$private fun copyComicInfoFileFromArchive(chapterArchives: List<UniFile>, folderPath: String?): File? - NestedBlockDepth:LocalSource.kt$LocalSource$private fun updateCover(chapter: SChapter, manga: SManga): UniFile? - NestedBlockDepth:MyAnimeList.kt$MyAnimeList$override suspend fun update(track: Track, didReadChapter: Boolean): Track - NestedBlockDepth:SyncChaptersWithSource.kt$SyncChaptersWithSource$suspend fun await( rawSourceChapters: List<SChapter>, manga: Manga, source: Source, manualFetch: Boolean = false, fetchWindow: Pair<Long, Long> = Pair(0, 0), ): List<Chapter> - NestedBlockDepth:UniFileTempFileManager.kt$UniFileTempFileManager$fun createTempFile(file: UniFile): File - NestedBlockDepth:WebtoonRecyclerView.kt$WebtoonRecyclerView.Detector$override fun onTouchEvent(ev: MotionEvent): Boolean - NewLineAtEndOfFile:Commands.kt$.Commands.kt - NoConsecutiveBlankLines:LocalesConfigPlugin.kt$ - PreviewPublic:Scrollbar.kt$LazyListHorizontalScrollbarPreview - PreviewPublic:Scrollbar.kt$LazyListScrollbarPreview - RethrowCaughtException:LocalSource.kt$LocalSource$throw e - ReturnCount:AndroidDatabaseHandler.kt$AndroidDatabaseHandler$private suspend fun <T> dispatch(inTransaction: Boolean, block: suspend Database.() -> T): T - ReturnCount:AndroidSourceManager.kt$AndroidSourceManager$private suspend fun createStubSource(id: Long): StubSource - ReturnCount:BackupCreateJob.kt$BackupCreateJob$override suspend fun doWork(): Result - ReturnCount:ChapterRecognition.kt$ChapterRecognition$fun parseChapterNumber( mangaTitle: String, chapterName: String, chapterNumber: Double? = null, ): Double - ReturnCount:ChapterRecognition.kt$ChapterRecognition$private fun checkForDecimal(decimal: String?, alpha: String?): Double - ReturnCount:Download.kt$Download.Companion$suspend fun fromChapterId( chapterId: Long, getChapter: GetChapter = Injekt.get(), getManga: GetManga = Injekt.get(), sourceManager: SourceManager = Injekt.get(), ): Download? - ReturnCount:DownloadCache.kt$DownloadCache$fun isChapterDownloaded( chapterName: String, chapterScanlator: String?, mangaTitle: String, sourceId: Long, skipCache: Boolean, ): Boolean - ReturnCount:DownloadManager.kt$DownloadManager$fun renameSource(oldSource: Source, newSource: Source) - ReturnCount:Downloader.kt$Downloader$private fun isDownloadSuccessful( download: Download, tmpDir: UniFile, ): Boolean - ReturnCount:ExtensionInstallReceiver.kt$ExtensionInstallReceiver$override fun onReceive(context: Context, intent: Intent?) - ReturnCount:ExtensionInstallService.kt$ExtensionInstallService$override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int - ReturnCount:ExtensionInstaller.kt$ExtensionInstaller.DownloadCompletionReceiver$override fun onReceive(context: Context, intent: Intent?) - ReturnCount:ExtensionInstallerPreference.kt$ExtensionInstallerPreference$private fun check(value: ExtensionInstaller): ExtensionInstaller - ReturnCount:ExtensionLoader.kt$ExtensionLoader$fun installPrivateExtensionFile(context: Context, file: File): Boolean - ReturnCount:ExtensionLoader.kt$ExtensionLoader$private fun loadExtension(context: Context, extensionInfo: ExtensionInfo): LoadResult - ReturnCount:ExtensionLoader.kt$ExtensionLoader$private fun selectExtensionPackage(shared: ExtensionInfo?, private: ExtensionInfo?): ExtensionInfo? - ReturnCount:HttpPageLoader.kt$HttpPageLoader$private fun preloadNextPages(currentPage: ReaderPage, amount: Int): List<PriorityPage> - ReturnCount:ImageUtil.kt$ImageUtil$fun chooseBackground(context: Context, imageStream: InputStream): Drawable - ReturnCount:ImageUtil.kt$ImageUtil$fun isAnimatedAndSupported(stream: InputStream): Boolean - ReturnCount:ImageUtil.kt$ImageUtil$fun splitTallImage(tmpDir: UniFile, imageFile: UniFile, filenamePrefix: String): Boolean - ReturnCount:KavitaApi.kt$KavitaApi$fun getNewToken(apiUrl: String, apiKey: String): String? - ReturnCount:KavitaApi.kt$KavitaApi$private fun getLatestChapterRead(url: String): Double - ReturnCount:KitsuDateHelper.kt$KitsuDateHelper$fun parse(dateString: String?): Long - ReturnCount:LibraryUpdateJob.kt$LibraryUpdateJob$override suspend fun doWork(): Result - ReturnCount:LocalSource.kt$LocalSource$private fun copyComicInfoFileFromArchive(chapterArchives: List<UniFile>, folderPath: String?): File? - ReturnCount:MainActivity.kt$MainActivity$private fun handleIntentAction(intent: Intent, navigator: Navigator): Boolean - ReturnCount:MangaCoverFetcher.kt$MangaCoverFetcher$private suspend fun httpLoader(): FetchResult - ReturnCount:MangaExtensions.kt$fun Manga.prepUpdateCover(coverCache: CoverCache, remoteManga: SManga, refreshSameUrl: Boolean): Manga - ReturnCount:MangaExtensions.kt$fun Manga.removeCovers(coverCache: CoverCache = Injekt.get()): Manga - ReturnCount:MangaExtensions.kt$fun Manga.shouldDownloadNewChapters(dbCategories: List<Long>, preferences: DownloadPreferences): Boolean - ReturnCount:MangaScreen.kt$MangaScreen$private fun getMangaUrl(manga_: Manga?, source_: Source?): String? - ReturnCount:MissingChapters.kt$fun List<Double>.missingChaptersCount(): Int - ReturnCount:MissingChapters.kt$fun calculateChapterGap(higherChapter: Chapter?, lowerChapter: Chapter?): Int - ReturnCount:MyAnimeList.kt$MyAnimeList$override suspend fun search(query: String): List<TrackSearch> - ReturnCount:NetworkExtensions.kt$fun Context.isConnectedToWifi(): Boolean - ReturnCount:NetworkExtensions.kt$fun Context.isOnline(): Boolean - ReturnCount:PagerPageHolder.kt$PagerPageHolder$private fun process(page: ReaderPage, imageStream: BufferedInputStream): InputStream - ReturnCount:PagerViewer.kt$PagerViewer$override fun handleKeyEvent(event: KeyEvent): Boolean - ReturnCount:PagerViewer.kt$PagerViewer$private fun checkAllowPreload(page: ReaderPage?): Boolean - ReturnCount:PagerViewerAdapter.kt$PagerViewerAdapter$fun onPageSplit(currentPage: Any?, newPage: InsertPage) - ReturnCount:ReaderActivity.kt$ReaderActivity$override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean - ReturnCount:ReaderActivity.kt$ReaderActivity$private fun moveToPageIndex(index: Int) - ReturnCount:ReaderViewModel.kt$ReaderViewModel$fun getChapterUrl(): String? - ReturnCount:ReaderViewModel.kt$ReaderViewModel$fun setAsCover() - ReturnCount:ReaderViewModel.kt$ReaderViewModel$private fun downloadNextChapters() - ReturnCount:ReaderViewModel.kt$ReaderViewModel$private fun updateTrackChapterRead(readerChapter: ReaderChapter) - ReturnCount:ReaderViewModel.kt$ReaderViewModel$suspend fun preload(chapter: ReaderChapter) - ReturnCount:ViewExtensions.kt$fun View?.isVisibleOnScreen(): Boolean - ReturnCount:WebViewInterceptor.kt$WebViewInterceptor$override fun intercept(chain: Interceptor.Chain): Response - ReturnCount:WebViewInterceptor.kt$private fun isRequestHeaderSafe(_name: String, _value: String): Boolean - ReturnCount:WebtoonFrame.kt$WebtoonFrame$override fun dispatchTouchEvent(ev: MotionEvent): Boolean - ReturnCount:WebtoonPageHolder.kt$WebtoonPageHolder$private fun process(imageStream: BufferedInputStream): InputStream - ReturnCount:WebtoonRecyclerView.kt$WebtoonRecyclerView.Detector$override fun onTouchEvent(ev: MotionEvent): Boolean - ReturnCount:WebtoonViewer.kt$WebtoonViewer$override fun handleKeyEvent(event: KeyEvent): Boolean - ReturnCount:WebtoonViewer.kt$WebtoonViewer$private fun checkAllowPreload(page: ReaderPage?): Boolean - SerialVersionUIDInSerializableClass:Category.kt$Category : Serializable - SerialVersionUIDInSerializableClass:Manga.kt$Manga : Serializable - SpreadOperator:ChapterRepositoryImpl.kt$ChapterRepositoryImpl$(*chapterUpdates.toTypedArray()) - SpreadOperator:ChapterSanitizer.kt$ChapterSanitizer$(*CHAPTER_TRIM_CHARS) - SpreadOperator:LibraryScreenModel.kt$LibraryScreenModel$(*prefFlows) - SpreadOperator:MangaRepositoryImpl.kt$MangaRepositoryImpl$(*mangaUpdates.toTypedArray()) - SpreadOperator:SourcesScreenModel.kt$SourcesScreenModel$( SourceUiModel.Header(it.key), *it.value.map { source -> SourceUiModel.Item(source) }.toTypedArray(), ) - SpreadOperator:TrackRepositoryImpl.kt$TrackRepositoryImpl$(*tracks.toTypedArray()) - SwallowedException:AboutScreen.kt$AboutScreen$e: Exception - SwallowedException:AndroidPreference.kt$AndroidPreference$e: ClassCastException - SwallowedException:AndroidPreference.kt$AndroidPreference.Object$e: Exception - SwallowedException:Anilist.kt$Anilist$e: ClassCastException - SwallowedException:Anilist.kt$Anilist$e: Exception - SwallowedException:Anilist.kt$Anilist$e: Throwable - SwallowedException:AnilistModels.kt$ALManga$e: Exception - SwallowedException:BackupRestorer.kt$BackupRestorer$e: Exception - SwallowedException:Bangumi.kt$Bangumi$e: Exception - SwallowedException:Bangumi.kt$Bangumi$e: Throwable - SwallowedException:BrowseIcons.kt$e: Exception - SwallowedException:ChapterCache.kt$ChapterCache$e: IOException - SwallowedException:ChapterLoader.kt$ChapterLoader$e: UnsupportedRarV5Exception - SwallowedException:ContextExtensions.kt$e: Exception - SwallowedException:ContextExtensions.kt$e: PackageManager.NameNotFoundException - SwallowedException:CrashLogUtil.kt$CrashLogUtil$e: Throwable - SwallowedException:CreateBackupScreen.kt$CreateBackupScreen$e: ActivityNotFoundException - SwallowedException:DeviceUtil.kt$DeviceUtil$e: Exception - SwallowedException:DownloadPendingDeleter.kt$DownloadPendingDeleter$e: Exception - SwallowedException:DownloadStore.kt$DownloadStore$e: Exception - SwallowedException:Downloader.kt$Downloader$e: Throwable - SwallowedException:ExtensionLoader.kt$ExtensionLoader$error: PackageManager.NameNotFoundException - SwallowedException:GetChapterByUrlAndMangaId.kt$GetChapterByUrlAndMangaId$e: Exception - SwallowedException:HttpSource.kt$HttpSource$e: URISyntaxException - SwallowedException:ImageUtil.kt$ImageUtil$e: Exception - SwallowedException:Kavita.kt$Kavita$e: Exception - SwallowedException:KavitaApi.kt$KavitaApi$e: SocketTimeoutException - SwallowedException:Kitsu.kt$Kitsu$e: Exception - SwallowedException:KitsuModels.kt$KitsuSearchManga$e: IllegalArgumentException - SwallowedException:Komga.kt$Komga$e: Exception - SwallowedException:LibrarySortMode.kt$LibrarySort.Companion$e: Exception - SwallowedException:LocalSource.kt$LocalSource$e: Format.UnknownFormatException - SwallowedException:MangaScreen.kt$MangaScreen$e: Exception - SwallowedException:MangaUpdates.kt$MangaUpdates$e: Exception - SwallowedException:MangaUpdatesApi.kt$MangaUpdatesApi$e: Exception - SwallowedException:MetadataUpdateJob.kt$MetadataUpdateJob$e: Exception - SwallowedException:MyAnimeList.kt$MyAnimeList$e: Exception - SwallowedException:MyAnimeList.kt$MyAnimeList$e: Throwable - SwallowedException:MyAnimeListApi.kt$MyAnimeListApi$e: Exception - SwallowedException:OkHttpExtensions.kt$ex: Throwable - SwallowedException:Pager.kt$Pager$e: IllegalArgumentException - SwallowedException:Pager.kt$Pager$e: IndexOutOfBoundsException - SwallowedException:Pager.kt$Pager$e: NullPointerException - SwallowedException:PreferenceStore.kt$e: IllegalArgumentException - SwallowedException:RarPageLoader.kt$RarPageLoader$e: Exception - SwallowedException:ReaderActivity.kt$ReaderActivity$e: ArrayIndexOutOfBoundsException - SwallowedException:ReaderViewModel.kt$ReaderViewModel$e: Exception - SwallowedException:SettingsAdvancedScreen.kt$SettingsAdvancedScreen$e: ActivityNotFoundException - SwallowedException:SettingsDataScreen.kt$SettingsDataScreen$e: ActivityNotFoundException - SwallowedException:Shikimori.kt$Shikimori$e: Exception - SwallowedException:Shikimori.kt$Shikimori$e: Throwable - SwallowedException:StorageStep.kt$StorageStep$e: ActivityNotFoundException - SwallowedException:Suwayomi.kt$Suwayomi$e: Exception - SwallowedException:TrackInfoDialog.kt$TrackInfoDialogHomeScreen.Model$e: Exception - ThrowingExceptionsWithoutMessageOrCause:MangaScreenModel.kt$MangaScreenModel$IllegalStateException() - ThrowingExceptionsWithoutMessageOrCause:OkHttpExtensions.kt$Exception() - ThrowingExceptionsWithoutMessageOrCause:PackageInstallerInstaller.kt$PackageInstallerInstaller$IllegalStateException() - ThrowingExceptionsWithoutMessageOrCause:ShizukuInstaller.kt$ShizukuInstaller$IllegalStateException() - ThrowingExceptionsWithoutMessageOrCause:TrackInfoDialog.kt$TrackInfoDialogHomeScreen.Model$Exception() - ThrowsCount:BackupCreator.kt$BackupCreator$suspend fun backup(uri: Uri, options: BackupOptions): String - ThrowsCount:FileExtensions.kt$fun File.copyAndSetReadOnlyTo(target: File, overwrite: Boolean = false, bufferSize: Int = DEFAULT_BUFFER_SIZE): File - ThrowsCount:KavitaApi.kt$KavitaApi$fun getNewToken(apiUrl: String, apiKey: String): String? - ThrowsCount:LocalSource.kt$LocalSource$fun getFormat(chapter: SChapter): Format - TooGenericExceptionCaught:AboutScreen.kt$AboutScreen$e: Exception - TooGenericExceptionCaught:AddTracks.kt$AddTracks$e: Exception - TooGenericExceptionCaught:AndroidPreference.kt$AndroidPreference.Object$e: Exception - TooGenericExceptionCaught:Anilist.kt$Anilist$e: Exception - TooGenericExceptionCaught:Anilist.kt$Anilist$e: Throwable - TooGenericExceptionCaught:AnilistModels.kt$ALManga$e: Exception - TooGenericExceptionCaught:App.kt$App$e: Exception - TooGenericExceptionCaught:AppUpdateDownloadJob.kt$AppUpdateDownloadJob$e: Exception - TooGenericExceptionCaught:BackupCreateJob.kt$BackupCreateJob$e: Exception - TooGenericExceptionCaught:BackupCreator.kt$BackupCreator$e: Exception - TooGenericExceptionCaught:BackupFileValidator.kt$BackupFileValidator$e: Exception - TooGenericExceptionCaught:BackupRestoreJob.kt$BackupRestoreJob$e: Exception - TooGenericExceptionCaught:BackupRestorer.kt$BackupRestorer$e: Exception - TooGenericExceptionCaught:Bangumi.kt$Bangumi$e: Exception - TooGenericExceptionCaught:Bangumi.kt$Bangumi$e: Throwable - TooGenericExceptionCaught:BaseTracker.kt$BaseTracker$e: Exception - TooGenericExceptionCaught:BaseTracker.kt$BaseTracker$e: Throwable - TooGenericExceptionCaught:BrowseIcons.kt$e: Exception - TooGenericExceptionCaught:ChapterCache.kt$ChapterCache$e: Exception - TooGenericExceptionCaught:ChapterLoader.kt$ChapterLoader$e: Throwable - TooGenericExceptionCaught:ChapterRepositoryImpl.kt$ChapterRepositoryImpl$e: Exception - TooGenericExceptionCaught:CloseableExtensions.kt$closeException: Throwable - TooGenericExceptionCaught:CloseableExtensions.kt$e: Throwable - TooGenericExceptionCaught:CloudflareInterceptor.kt$CloudflareInterceptor$e: Exception - TooGenericExceptionCaught:ContextExtensions.kt$e: Exception - TooGenericExceptionCaught:ContextExtensions.kt$e: Throwable - TooGenericExceptionCaught:CrashLogUtil.kt$CrashLogUtil$e: Throwable - TooGenericExceptionCaught:CreateCategoryWithName.kt$CreateCategoryWithName$e: Exception - TooGenericExceptionCaught:DeleteCategory.kt$DeleteCategory$e: Exception - TooGenericExceptionCaught:DeleteTrack.kt$DeleteTrack$e: Exception - TooGenericExceptionCaught:DeviceUtil.kt$DeviceUtil$e: Exception - TooGenericExceptionCaught:DownloadCache.kt$DownloadCache$e: Throwable - TooGenericExceptionCaught:DownloadPendingDeleter.kt$DownloadPendingDeleter$e: Exception - TooGenericExceptionCaught:DownloadProvider.kt$DownloadProvider$e: Throwable - TooGenericExceptionCaught:DownloadStore.kt$DownloadStore$e: Exception - TooGenericExceptionCaught:Downloader.kt$Downloader$e: Exception - TooGenericExceptionCaught:Downloader.kt$Downloader$e: Throwable - TooGenericExceptionCaught:Downloader.kt$Downloader$error: Throwable - TooGenericExceptionCaught:ExtensionApi.kt$ExtensionApi$e: Throwable - TooGenericExceptionCaught:ExtensionDetailsScreenModel.kt$ExtensionDetailsScreenModel$e: Exception - TooGenericExceptionCaught:ExtensionInstallActivity.kt$ExtensionInstallActivity$error: Exception - TooGenericExceptionCaught:ExtensionInstaller.kt$ExtensionInstaller$e: Exception - TooGenericExceptionCaught:ExtensionLoader.kt$ExtensionLoader$e: Exception - TooGenericExceptionCaught:ExtensionLoader.kt$ExtensionLoader$e: Throwable - TooGenericExceptionCaught:ExtensionManager.kt$ExtensionManager$e: Exception - TooGenericExceptionCaught:GetChapter.kt$GetChapter$e: Exception - TooGenericExceptionCaught:GetChapterByUrlAndMangaId.kt$GetChapterByUrlAndMangaId$e: Exception - TooGenericExceptionCaught:GetChaptersByMangaId.kt$GetChaptersByMangaId$e: Exception - TooGenericExceptionCaught:GetManga.kt$GetManga$e: Exception - TooGenericExceptionCaught:GetTracks.kt$GetTracks$e: Exception - TooGenericExceptionCaught:GlobalExceptionHandler.kt$GlobalExceptionHandler.Companion$e: Exception - TooGenericExceptionCaught:HistoryRepositoryImpl.kt$HistoryRepositoryImpl$e: Exception - TooGenericExceptionCaught:HttpPageLoader.kt$HttpPageLoader$e: Throwable - TooGenericExceptionCaught:ImageSaver.kt$ImageSaver$e: Exception - TooGenericExceptionCaught:ImageUtil.kt$ImageUtil$e: Exception - TooGenericExceptionCaught:InsertTrack.kt$InsertTrack$e: Exception - TooGenericExceptionCaught:Kavita.kt$Kavita$e: Exception - TooGenericExceptionCaught:KavitaApi.kt$KavitaApi$e: Exception - TooGenericExceptionCaught:Kitsu.kt$Kitsu$e: Exception - TooGenericExceptionCaught:Komga.kt$Komga$e: Exception - TooGenericExceptionCaught:KomgaApi.kt$KomgaApi$e: Exception - TooGenericExceptionCaught:LibrarySortMode.kt$LibrarySort.Companion$e: Exception - TooGenericExceptionCaught:LibraryUpdateJob.kt$LibraryUpdateJob$e: Exception - TooGenericExceptionCaught:LibraryUpdateJob.kt$LibraryUpdateJob$e: Throwable - TooGenericExceptionCaught:LocalSource.kt$LocalSource$e: Exception - TooGenericExceptionCaught:LocalSource.kt$LocalSource$e: Throwable - TooGenericExceptionCaught:MainActivity.kt$MainActivity$e: Exception - TooGenericExceptionCaught:MangaCoverFetcher.kt$MangaCoverFetcher$e: Exception - TooGenericExceptionCaught:MangaCoverScreenModel.kt$MangaCoverScreenModel$e: Exception - TooGenericExceptionCaught:MangaCoverScreenModel.kt$MangaCoverScreenModel$e: Throwable - TooGenericExceptionCaught:MangaRepositoryImpl.kt$MangaRepositoryImpl$e: Exception - TooGenericExceptionCaught:MangaScreen.kt$MangaScreen$e: Exception - TooGenericExceptionCaught:MangaScreenModel.kt$MangaScreenModel$e: Throwable - TooGenericExceptionCaught:MangaUpdates.kt$MangaUpdates$e: Exception - TooGenericExceptionCaught:MangaUpdatesApi.kt$MangaUpdatesApi$e: Exception - TooGenericExceptionCaught:MetadataUpdateJob.kt$MetadataUpdateJob$e: Exception - TooGenericExceptionCaught:MetadataUpdateJob.kt$MetadataUpdateJob$e: Throwable - TooGenericExceptionCaught:MyAnimeList.kt$MyAnimeList$e: Exception - TooGenericExceptionCaught:MyAnimeList.kt$MyAnimeList$e: Throwable - TooGenericExceptionCaught:MyAnimeListApi.kt$MyAnimeListApi$e: Exception - TooGenericExceptionCaught:OkHttpExtensions.kt$<no name provided>$e: Exception - TooGenericExceptionCaught:OkHttpExtensions.kt$ex: Throwable - TooGenericExceptionCaught:OkioExtensions.kt$e: Exception - TooGenericExceptionCaught:PackageInstallerInstaller.kt$PackageInstallerInstaller$e: Exception - TooGenericExceptionCaught:Pager.kt$Pager$e: IndexOutOfBoundsException - TooGenericExceptionCaught:Pager.kt$Pager$e: NullPointerException - TooGenericExceptionCaught:PagerPageHolder.kt$PagerPageHolder$e: Throwable - TooGenericExceptionCaught:QueryPagingSource.kt$QueryPagingSource$e: Exception - TooGenericExceptionCaught:RarPageLoader.kt$RarPageLoader$e: Exception - TooGenericExceptionCaught:ReaderActivity.kt$ReaderActivity$e: ArrayIndexOutOfBoundsException - TooGenericExceptionCaught:ReaderViewModel.kt$ReaderViewModel$e: Exception - TooGenericExceptionCaught:ReaderViewModel.kt$ReaderViewModel$e: Throwable - TooGenericExceptionCaught:RefreshTracks.kt$RefreshTracks$e: Throwable - TooGenericExceptionCaught:RenameCategory.kt$RenameCategory$e: Exception - TooGenericExceptionCaught:ReorderCategory.kt$ReorderCategory$e: Exception - TooGenericExceptionCaught:RestoreBackupScreen.kt$RestoreBackupScreenModel$e: Exception - TooGenericExceptionCaught:SearchScreenModel.kt$SearchScreenModel$e: Exception - TooGenericExceptionCaught:SetMangaCategories.kt$SetMangaCategories$e: Exception - TooGenericExceptionCaught:SetReadStatus.kt$SetReadStatus$e: Exception - TooGenericExceptionCaught:SettingsAdvancedScreen.kt$SettingsAdvancedScreen$e: Throwable - TooGenericExceptionCaught:SettingsDataScreen.kt$SettingsDataScreen$e: Throwable - TooGenericExceptionCaught:SettingsTrackingScreen.kt$SettingsTrackingScreen$e: Throwable - TooGenericExceptionCaught:Shikimori.kt$Shikimori$e: Exception - TooGenericExceptionCaught:Shikimori.kt$Shikimori$e: Throwable - TooGenericExceptionCaught:ShizukuInstaller.kt$ShizukuInstaller$e: Exception - TooGenericExceptionCaught:SourcePagingSource.kt$SourcePagingSource$e: Exception - TooGenericExceptionCaught:Suwayomi.kt$Suwayomi$e: Exception - TooGenericExceptionCaught:SyncChapterProgressWithTrack.kt$SyncChapterProgressWithTrack$e: Throwable - TooGenericExceptionCaught:TrackChapter.kt$TrackChapter$e: Exception - TooGenericExceptionCaught:TrackInfoDialog.kt$TrackInfoDialogHomeScreen.Model$e: Exception - TooGenericExceptionCaught:TrackInfoDialog.kt$TrackerSearchScreen.Model$e: Throwable - TooGenericExceptionCaught:UncaughtExceptionInterceptor.kt$UncaughtExceptionInterceptor$e: Exception - TooGenericExceptionCaught:UpdateCategory.kt$UpdateCategory$e: Exception - TooGenericExceptionCaught:UpdateChapter.kt$UpdateChapter$e: Exception - TooGenericExceptionCaught:WebViewActivity.kt$WebViewActivity$e: Exception - TooGenericExceptionCaught:WebViewScreenModel.kt$WebViewScreenModel$e: Exception - TooGenericExceptionCaught:WebViewUtil.kt$WebViewUtil$e: Throwable - TooGenericExceptionCaught:WebtoonPageHolder.kt$WebtoonPageHolder$e: Throwable - TooGenericExceptionCaught:WidgetManager.kt$WidgetManager$e: Exception - TooGenericExceptionThrown:Anilist.kt$Anilist$throw Exception("$track not found on user library") - TooGenericExceptionThrown:Anilist.kt$Anilist$throw Exception("Unknown score type") - TooGenericExceptionThrown:AnilistApi.kt$AnilistApi$throw Exception("Could not find manga") - TooGenericExceptionThrown:AnilistInterceptor.kt$AnilistInterceptor$throw Exception("Not authenticated with Anilist") - TooGenericExceptionThrown:AppUpdateDownloadJob.kt$AppUpdateDownloadJob$throw Exception("Unsuccessful response") - TooGenericExceptionThrown:BangumiApi.kt$BangumiApi$throw Exception("Null Response") - TooGenericExceptionThrown:BangumiInterceptor.kt$BangumiInterceptor$throw Exception("Not authenticated with Bangumi") - TooGenericExceptionThrown:ChapterLoader.kt$ChapterLoader$throw Exception(context.stringResource(MR.strings.page_list_empty_error)) - TooGenericExceptionThrown:DownloadManager.kt$DownloadManager$throw Exception(context.stringResource(MR.strings.page_list_empty_error)) - TooGenericExceptionThrown:DownloadProvider.kt$DownloadProvider$throw Exception( context.stringResource( MR.strings.invalid_location, downloadsDir?.displayablePath ?: "", ), ) - TooGenericExceptionThrown:Downloader.kt$Downloader$throw Exception(context.stringResource(MR.strings.page_list_empty_error)) - TooGenericExceptionThrown:ExtensionLoader.kt$ExtensionLoader$throw Exception("Unknown source class type: ${obj.javaClass}") - TooGenericExceptionThrown:HttpSource.kt$HttpSource$throw RuntimeException(e) - TooGenericExceptionThrown:KitsuApi.kt$KitsuApi$throw Exception("Could not find manga") - TooGenericExceptionThrown:KitsuInterceptor.kt$KitsuInterceptor$throw Exception("Not authenticated with Kitsu") - TooGenericExceptionThrown:KitsuModels.kt$KitsuLibManga$throw Exception("Unknown status") - TooGenericExceptionThrown:KitsuModels.kt$throw Exception("Unknown status") - TooGenericExceptionThrown:LocalSource.kt$LocalSource$throw Exception(context.stringResource(MR.strings.chapter_not_found)) - TooGenericExceptionThrown:LocalSource.kt$LocalSource$throw Exception(context.stringResource(MR.strings.local_invalid_format)) - TooGenericExceptionThrown:MangaUpdates.kt$MangaUpdates$throw Throwable("Unable to login") - TooGenericExceptionThrown:ShikimoriApi.kt$ShikimoriApi$throw Exception("Too much mangas in response") - TooGenericExceptionThrown:ShikimoriInterceptor.kt$ShikimoriInterceptor$throw Exception("Not authenticated with Shikimori") - TooGenericExceptionThrown:ShizukuInstaller.kt$ShizukuInstaller$throw RuntimeException("Failed to commit install session $sessionId") - TooGenericExceptionThrown:ShizukuInstaller.kt$ShizukuInstaller$throw RuntimeException("Failed to create install session") - TooGenericExceptionThrown:ShizukuInstaller.kt$ShizukuInstaller$throw RuntimeException("Failed to write APK to session $sessionId") - TooGenericExceptionThrown:TrackInfoDialog.kt$TrackInfoDialogHomeScreen.Model$throw Exception() - TooManyFunctions:AndroidDatabaseHandler.kt$AndroidDatabaseHandler : DatabaseHandler - TooManyFunctions:Anilist.kt$Anilist : BaseTrackerDeletableTracker - TooManyFunctions:AnilistApi.kt$AnilistApi - TooManyFunctions:Bangumi.kt$Bangumi : BaseTracker - TooManyFunctions:BaseTracker.kt$BaseTracker : Tracker - TooManyFunctions:BrowseSourceScreenModel.kt$BrowseSourceScreenModel : StateScreenModel - TooManyFunctions:CategoryRepositoryImpl.kt$CategoryRepositoryImpl : CategoryRepository - TooManyFunctions:ChapterRepository.kt$ChapterRepository - TooManyFunctions:ChapterRepositoryImpl.kt$ChapterRepositoryImpl : ChapterRepository - TooManyFunctions:ChapterTransition.kt$eu.kanade.presentation.reader.ChapterTransition.kt - TooManyFunctions:DohProviders.kt$eu.kanade.tachiyomi.network.DohProviders.kt - TooManyFunctions:DownloadCache.kt$DownloadCache - TooManyFunctions:DownloadManager.kt$DownloadManager - TooManyFunctions:DownloadPreferences.kt$DownloadPreferences - TooManyFunctions:DownloadProvider.kt$DownloadProvider - TooManyFunctions:DownloadQueueScreenModel.kt$DownloadQueueScreenModel : ScreenModel - TooManyFunctions:Downloader.kt$Downloader - TooManyFunctions:EpubFile.kt$EpubFile : Closeable - TooManyFunctions:ExtensionLoader.kt$ExtensionLoader - TooManyFunctions:ExtensionManager.kt$ExtensionManager - TooManyFunctions:ExtensionsScreenModel.kt$ExtensionsScreenModel : StateScreenModel - TooManyFunctions:HttpSource.kt$HttpSource : CatalogueSource - TooManyFunctions:ImageUtil.kt$ImageUtil - TooManyFunctions:Kavita.kt$Kavita : BaseTrackerEnhancedTracker - TooManyFunctions:Kitsu.kt$Kitsu : BaseTrackerDeletableTracker - TooManyFunctions:Komga.kt$Komga : BaseTrackerEnhancedTracker - TooManyFunctions:LibraryPreferences.kt$LibraryPreferences - TooManyFunctions:LibraryScreenModel.kt$LibraryScreenModel : StateScreenModel - TooManyFunctions:LocalSource.kt$LocalSource : CatalogueSourceUnmeteredSource - TooManyFunctions:MangaCoverFetcher.kt$MangaCoverFetcher : Fetcher - TooManyFunctions:MangaRepository.kt$MangaRepository - TooManyFunctions:MangaRepositoryImpl.kt$MangaRepositoryImpl : MangaRepository - TooManyFunctions:MangaRestorer.kt$MangaRestorer - TooManyFunctions:MangaScreenModel.kt$MangaScreenModel : StateScreenModel - TooManyFunctions:MangaUpdates.kt$MangaUpdates : BaseTrackerDeletableTracker - TooManyFunctions:MyAnimeList.kt$MyAnimeList : BaseTrackerDeletableTracker - TooManyFunctions:MyAnimeListApi.kt$MyAnimeListApi - TooManyFunctions:NotificationReceiver.kt$NotificationReceiver : BroadcastReceiver - TooManyFunctions:NotificationReceiver.kt$NotificationReceiver$Companion - TooManyFunctions:PagerPageHolder.kt$PagerPageHolder : ReaderPageImageViewPositionableView - TooManyFunctions:PagerViewer.kt$PagerViewer : Viewer - TooManyFunctions:ParsedHttpSource.kt$ParsedHttpSource : HttpSource - TooManyFunctions:ReaderActivity.kt$ReaderActivity : BaseActivity - TooManyFunctions:ReaderPageImageView.kt$ReaderPageImageView : FrameLayout - TooManyFunctions:ReaderPreferences.kt$ReaderPreferences - TooManyFunctions:ReaderViewModel.kt$ReaderViewModel : ViewModel - TooManyFunctions:SettingsItems.kt$tachiyomi.presentation.core.components.SettingsItems.kt - TooManyFunctions:SharedPreferencesDataStore.kt$SharedPreferencesDataStore : PreferenceDataStore - TooManyFunctions:Shikimori.kt$Shikimori : BaseTrackerDeletableTracker - TooManyFunctions:SourcePreferences.kt$SourcePreferences - TooManyFunctions:Suwayomi.kt$Suwayomi : BaseTrackerEnhancedTracker - TooManyFunctions:Tracker.kt$Tracker - TooManyFunctions:UpdatesScreenModel.kt$UpdatesScreenModel : StateScreenModel - TooManyFunctions:WebtoonPageHolder.kt$WebtoonPageHolder : WebtoonBaseHolder - TooManyFunctions:WebtoonRecyclerView.kt$WebtoonRecyclerView : RecyclerView - TooManyFunctions:WebtoonViewer.kt$WebtoonViewer : Viewer - TopLevelPropertyNaming:App.kt$private const val ACTION_DISABLE_INCOGNITO_MODE = "tachi.action.DISABLE_INCOGNITO_MODE" - TopLevelPropertyNaming:AppBar.kt$const val SEARCH_DEBOUNCE_MILLIS = 250L - TopLevelPropertyNaming:BackupCreateJob.kt$private const val IS_AUTO_BACKUP_KEY = "is_auto_backup" // Boolean - TopLevelPropertyNaming:BackupCreateJob.kt$private const val LOCATION_URI_KEY = "location_uri" // String - TopLevelPropertyNaming:BackupCreateJob.kt$private const val OPTIONS_KEY = "options" // BooleanArray - TopLevelPropertyNaming:BackupCreateJob.kt$private const val TAG_AUTO = "BackupCreator" - TopLevelPropertyNaming:BackupCreateJob.kt$private const val TAG_MANUAL = "$TAG_AUTO:manual" - TopLevelPropertyNaming:BackupRestoreJob.kt$private const val LOCATION_URI_KEY = "location_uri" // String - TopLevelPropertyNaming:BackupRestoreJob.kt$private const val OPTIONS_KEY = "options" // BooleanArray - TopLevelPropertyNaming:BackupRestoreJob.kt$private const val SYNC_KEY = "sync" // Boolean - TopLevelPropertyNaming:ChapterCache.kt$/** Application cache version. */ private const val PARAMETER_APP_VERSION = 1 - TopLevelPropertyNaming:ChapterCache.kt$/** The maximum number of bytes this cache should use to store. */ private const val PARAMETER_CACHE_SIZE = 100L * 1024 * 1024 - TopLevelPropertyNaming:ChapterCache.kt$/** The number of values per cache entry. Must be positive. */ private const val PARAMETER_VALUE_COUNT = 1 - TopLevelPropertyNaming:ColorFilterPage.kt$private const val ALPHA_MASK: Long = 0xFF000000 - TopLevelPropertyNaming:ColorFilterPage.kt$private const val BLUE_MASK: Long = 0x000000FF - TopLevelPropertyNaming:ColorFilterPage.kt$private const val GREEN_MASK: Long = 0x0000FF00 - TopLevelPropertyNaming:ColorFilterPage.kt$private const val RED_MASK: Long = 0x00FF0000 - TopLevelPropertyNaming:ComicInfo.kt$const val COMIC_INFO_FILE = "ComicInfo.xml" - TopLevelPropertyNaming:DatabaseAdapter.kt$private const val LIST_OF_STRINGS_SEPARATOR = ", " - TopLevelPropertyNaming:DateExtensions.kt$private const val MILLISECONDS_IN_DAY = 86_400_000L - TopLevelPropertyNaming:DisplayExtensions.kt$// make sure icons on the nav rail fit private const val TABLET_UI_MIN_SCREEN_WIDTH_LANDSCAPE_DP = 600 - TopLevelPropertyNaming:DisplayExtensions.kt$// some tablets have screen width like 711dp = 1600px / 2.25 private const val TABLET_UI_MIN_SCREEN_WIDTH_PORTRAIT_DP = 700 - TopLevelPropertyNaming:DisplayExtensions.kt$private const val TABLET_UI_REQUIRED_SCREEN_WIDTH_DP = 720 - TopLevelPropertyNaming:DohProviders.kt$/** * Based on https://github.com/square/okhttp/blob/ef5d0c83f7bbd3a0c0534e7ca23cbc4ee7550f3b/okhttp-dnsoverhttps/src/test/java/okhttp3/dnsoverhttps/DohProviders.java */ const val PREF_DOH_CLOUDFLARE = 1 - TopLevelPropertyNaming:DohProviders.kt$const val PREF_DOH_360 = 7 - TopLevelPropertyNaming:DohProviders.kt$const val PREF_DOH_ADGUARD = 3 - TopLevelPropertyNaming:DohProviders.kt$const val PREF_DOH_ALIDNS = 5 - TopLevelPropertyNaming:DohProviders.kt$const val PREF_DOH_CONTROLD = 10 - TopLevelPropertyNaming:DohProviders.kt$const val PREF_DOH_DNSPOD = 6 - TopLevelPropertyNaming:DohProviders.kt$const val PREF_DOH_GOOGLE = 2 - TopLevelPropertyNaming:DohProviders.kt$const val PREF_DOH_MULLVAD = 9 - TopLevelPropertyNaming:DohProviders.kt$const val PREF_DOH_NJALLA = 11 - TopLevelPropertyNaming:DohProviders.kt$const val PREF_DOH_QUAD101 = 8 - TopLevelPropertyNaming:DohProviders.kt$const val PREF_DOH_QUAD9 = 4 - TopLevelPropertyNaming:DohProviders.kt$const val PREF_DOH_SHECAN = 12 - TopLevelPropertyNaming:Downloader.kt$// Arbitrary minimum required space to start a download: 200 MB private const val MIN_DISK_SPACE = 200L * 1024 * 1024 - TopLevelPropertyNaming:ExtensionInstallActivity.kt$private const val INSTALL_REQUEST_CODE = 500 - TopLevelPropertyNaming:GLUtil.kt$// Safe minimum default size private const val IMAGE_MAX_BITMAP_DIMENSION = 2048 - TopLevelPropertyNaming:GuidesStep.kt$const val GETTING_STARTED_URL = "https://mihon.app/docs/guides/getting-started" - TopLevelPropertyNaming:KomgaApi.kt$private const val READLIST_API = "/api/v1/readlists" - TopLevelPropertyNaming:LibraryUpdateNotifier.kt$private const val MANGA_PER_SOURCE_QUEUE_WARNING_THRESHOLD = 60 - TopLevelPropertyNaming:LibraryUpdateNotifier.kt$private const val NOTIF_ICON_SIZE = 192 - TopLevelPropertyNaming:LibraryUpdateNotifier.kt$private const val NOTIF_MAX_CHAPTERS = 5 - TopLevelPropertyNaming:LibraryUpdateNotifier.kt$private const val NOTIF_TITLE_MAX_LEN = 45 - TopLevelPropertyNaming:LocalCoverManager.kt$private const val DEFAULT_COVER_NAME = "cover.jpg" - TopLevelPropertyNaming:MainActivity.kt$// Splash screen private const val SPLASH_MIN_DURATION = 500 // ms - TopLevelPropertyNaming:MainActivity.kt$private const val SPLASH_EXIT_ANIM_DURATION = 400L // ms - TopLevelPropertyNaming:MainActivity.kt$private const val SPLASH_MAX_DURATION = 5000 // ms - TopLevelPropertyNaming:PackageInstallerInstaller.kt$private const val INSTALL_ACTION = "PackageInstallerInstaller.INSTALL_ACTION" - TopLevelPropertyNaming:ReaderNavigationOverlayView.kt$private const val FADE_DURATION = 1000L - TopLevelPropertyNaming:ReaderPageImageView.kt$private const val MAX_ZOOM_SCALE = 5F - TopLevelPropertyNaming:ShizukuInstaller.kt$private const val SHIZUKU_PERMISSION_REQUEST_CODE = 14045 - TopLevelPropertyNaming:StorageManager.kt$private const val AUTOMATIC_BACKUPS_PATH = "autobackup" - TopLevelPropertyNaming:StorageManager.kt$private const val DOWNLOADS_PATH = "downloads" - TopLevelPropertyNaming:StorageManager.kt$private const val LOCAL_SOURCE_PATH = "local" - TopLevelPropertyNaming:SuwayomiApi.kt$private const val ADDRESS_DEFAULT = "" - TopLevelPropertyNaming:SuwayomiApi.kt$private const val ADDRESS_TITLE = "Server URL Address" - TopLevelPropertyNaming:SuwayomiApi.kt$private const val LOGIN_DEFAULT = "" - TopLevelPropertyNaming:SuwayomiApi.kt$private const val LOGIN_TITLE = "Login (Basic Auth)" - TopLevelPropertyNaming:SuwayomiApi.kt$private const val PASSWORD_DEFAULT = "" - TopLevelPropertyNaming:SuwayomiApi.kt$private const val PASSWORD_TITLE = "Password (Basic Auth)" - TopLevelPropertyNaming:WebtoonAdapter.kt$/** * View holder type of a chapter page view. */ private const val PAGE_VIEW = 0 - TopLevelPropertyNaming:WebtoonAdapter.kt$/** * View holder type of a chapter transition view. */ private const val TRANSITION_VIEW = 1 - TopLevelPropertyNaming:WebtoonRecyclerView.kt$private const val ANIMATOR_DURATION_TIME = 200 - TopLevelPropertyNaming:WebtoonRecyclerView.kt$private const val DEFAULT_RATE = 1f - TopLevelPropertyNaming:WebtoonRecyclerView.kt$private const val MAX_SCALE_RATE = 3f - TopLevelPropertyNaming:WebtoonRecyclerView.kt$private const val MIN_RATE = 0.5f - UnstableCollections:CategoryScreen.kt$List<Category> - UnstableCollections:Commons.kt$List<Category> - UnstableCollections:Commons.kt$Set<String> - UnstableCollections:GlobalSearchCardRow.kt$List<Manga> - UnstableCollections:GlobalSearchScreen.kt$Map<CatalogueSource, SearchItemResult> - UnstableCollections:HistoryScreen.kt$List<HistoryUiModel> - UnstableCollections:LibraryComfortableGrid.kt$List<LibraryItem> - UnstableCollections:LibraryComfortableGrid.kt$List<LibraryManga> - UnstableCollections:LibraryCompactGrid.kt$List<LibraryItem> - UnstableCollections:LibraryCompactGrid.kt$List<LibraryManga> - UnstableCollections:LibraryContent.kt$List<Category> - UnstableCollections:LibraryContent.kt$List<LibraryManga> - UnstableCollections:LibraryList.kt$List<LibraryItem> - UnstableCollections:LibraryList.kt$List<LibraryManga> - UnstableCollections:LibraryPager.kt$List<LibraryManga> - UnstableCollections:LibraryTabs.kt$List<Category> - UnstableCollections:ListPreferenceWidget.kt$Map<out T, String> - UnstableCollections:MangaScreen.kt$List<ChapterList.Item> - UnstableCollections:MultiSelectListPreferenceWidget.kt$Set<String> - UnstableCollections:PreferenceScreen.kt$List<Preference> - UnstableCollections:ScanlatorFilterDialog.kt$Set<String> - UnstableCollections:SettingsDownloadScreen.kt$SettingsDownloadScreen$List<Category> - UnstableCollections:SettingsLibraryScreen.kt$SettingsLibraryScreen$List<Category> - UnstableCollections:TrackInfoDialogHome.kt$List<TrackItem> - UnstableCollections:TrackInfoDialogSelector.kt$Map<Long, StringResource?> - UnstableCollections:TriStateListDialog.kt$List<T> - UnstableCollections:UpdatesScreen.kt$List<UpdatesItem> - UnstableCollections:WebViewScreenContent.kt$Map<String, String> - UnusedParameter:UpdatesRepositoryImpl.kt$UpdatesRepositoryImpl$dateUpload: Long - UnusedPrivateMember:AppThemePreferenceWidget.kt$@PreviewLightDark @Composable private fun AppThemesListPreview() - UnusedPrivateMember:ChapterTransition.kt$@PreviewLightDark @Composable private fun TransitionTextLongTitlePreview() - UnusedPrivateMember:ChapterTransition.kt$@PreviewLightDark @Composable private fun TransitionTextNoNextPreview() - UnusedPrivateMember:ChapterTransition.kt$@PreviewLightDark @Composable private fun TransitionTextNoPreviousPreview() - UnusedPrivateMember:ChapterTransition.kt$@PreviewLightDark @Composable private fun TransitionTextPreview() - UnusedPrivateMember:ChapterTransition.kt$@PreviewLightDark @Composable private fun TransitionTextWithGapPreview() - UnusedPrivateMember:CrashScreen.kt$@PreviewLightDark @Composable private fun CrashScreenPreview() - UnusedPrivateMember:EmptyScreen.kt$@PreviewLightDark @Composable private fun NoActionPreview() - UnusedPrivateMember:EmptyScreen.kt$@PreviewLightDark @Composable private fun WithActionPreview() - UnusedPrivateMember:GuidesStep.kt$@PreviewLightDark @Composable private fun GuidesStepPreview() - UnusedPrivateMember:HistoryDialogs.kt$@PreviewLightDark @Composable private fun HistoryDeleteDialogPreview() - UnusedPrivateMember:HistoryItem.kt$@PreviewLightDark @Composable private fun HistoryItemPreviews( @PreviewParameter(HistoryWithRelationsProvider::class) historyWithRelations: HistoryWithRelations, ) - UnusedPrivateMember:InfoScreen.kt$@PreviewLightDark @Composable private fun InfoScaffoldPreview() - UnusedPrivateMember:InfoWidget.kt$@PreviewLightDark @Composable private fun InfoWidgetPreview() - UnusedPrivateMember:LibraryBadges.kt$@PreviewLightDark @Composable private fun BadgePreview() - UnusedPrivateMember:MissingChapterCountListItem.kt$@PreviewLightDark @Composable private fun Preview() - UnusedPrivateMember:ModeSelectionDialog.kt$@PreviewLightDark @Composable private fun Preview() - UnusedPrivateMember:NewUpdateScreen.kt$@PreviewLightDark @Composable private fun NewUpdateScreenPreview() - UnusedPrivateMember:OrientationSelectDialog.kt$@PreviewLightDark @Composable private fun DialogContentPreview() - UnusedPrivateMember:PageIndicatorText.kt$@PreviewLightDark @Composable private fun PageIndicatorTextPreview() - UnusedPrivateMember:PermissionStep.kt$PermissionStep$@Composable private fun SectionHeader( text: String, modifier: Modifier = Modifier, ) - UnusedPrivateMember:ReadingModeSelectDialog.kt$@PreviewLightDark @Composable private fun DialogContentPreview() - UnusedPrivateMember:SwitchPreferenceWidget.kt$@PreviewLightDark @Composable private fun SwitchPreferenceWidgetPreview() - UnusedPrivateMember:TextPreferenceWidget.kt$@PreviewLightDark @Composable private fun TextPreferenceWidgetPreview() - UnusedPrivateMember:TrackInfoDialogHome.kt$@PreviewLightDark @Composable private fun TrackInfoDialogHomePreviews( @PreviewParameter(TrackInfoDialogHomePreviewProvider::class) content: @Composable () -> Unit, ) - UnusedPrivateMember:TrackInfoDialogSelector.kt$@PreviewLightDark @Composable private fun TrackStatusSelectorPreviews() - UnusedPrivateMember:TrackLogoIcon.kt$@PreviewLightDark @Composable private fun TrackLogoIconPreviews( @PreviewParameter(TrackLogoIconPreviewProvider::class) tracker: Tracker, ) - UnusedPrivateMember:TrackerSearch.kt$@PreviewLightDark @Composable private fun TrackerSearchPreviews( @PreviewParameter(TrackerSearchPreviewProvider::class) content: @Composable () -> Unit, ) - UnusedPrivateProperty:JavaScriptEngine.kt$JavaScriptEngine$context: Context - UnusedPrivateProperty:LibraryUpdateJob.kt$LibraryUpdateJob.Companion$private const val MANGA_PER_SOURCE_QUEUE_WARNING_THRESHOLD = 60 - UnusedPrivateProperty:MainActivity.kt$MainActivity$private val sourcePreferences: SourcePreferences by injectLazy() - UnusedPrivateProperty:MainActivity.kt$MainActivity$private val uiPreferences: UiPreferences by injectLazy() - UnusedPrivateProperty:MetadataUpdateJob.kt$MetadataUpdateJob.Companion$private const val MANGA_PER_SOURCE_QUEUE_WARNING_THRESHOLD = 60 - UseCheckOrError:CatalogueSource.kt$CatalogueSource$throw IllegalStateException("Not used") - UseCheckOrError:MangaScreenModel.kt$MangaScreenModel$throw IllegalStateException() - UseCheckOrError:PackageInstallerInstaller.kt$PackageInstallerInstaller$throw IllegalStateException() - UseCheckOrError:ReadingMode.kt$ReadingMode.Companion$throw IllegalStateException("Preference value must be resolved: $preference") - UseCheckOrError:ShizukuInstaller.kt$ShizukuInstaller$throw IllegalStateException() - UseCheckOrError:Source.kt$Source$throw IllegalStateException("Not used") - UseCheckOrError:SourceFilterDialog.kt$throw IllegalStateException("Unknown TriState state: $this") - UseCheckOrError:TransactionContext.kt$TransactionElement$throw IllegalStateException("Transaction was never started or was already released") - VariableNaming:Chapter.kt$Chapter$var date_fetch: Long - VariableNaming:Chapter.kt$Chapter$var last_modified: Long - VariableNaming:Chapter.kt$Chapter$var last_page_read: Int - VariableNaming:Chapter.kt$Chapter$var manga_id: Long? - VariableNaming:Chapter.kt$Chapter$var source_order: Int - VariableNaming:LocalSource.kt$LocalSource$private val LATEST_FILTERS = FilterList(OrderBy.Latest(context)) - VariableNaming:LocalSource.kt$LocalSource$private val POPULAR_FILTERS = FilterList(OrderBy.Popular(context)) - VariableNaming:SChapter.kt$SChapter$var chapter_number: Float - VariableNaming:SChapter.kt$SChapter$var date_upload: Long - VariableNaming:SManga.kt$SManga$var thumbnail_url: String? - VariableNaming:SManga.kt$SManga$var update_strategy: UpdateStrategy - VariableNaming:Track.kt$Track$var finished_reading_date: Long - VariableNaming:Track.kt$Track$var last_chapter_read: Double - VariableNaming:Track.kt$Track$var library_id: Long? - VariableNaming:Track.kt$Track$var manga_id: Long - VariableNaming:Track.kt$Track$var remote_id: Long - VariableNaming:Track.kt$Track$var started_reading_date: Long - VariableNaming:Track.kt$Track$var total_chapters: Long - VariableNaming:Track.kt$Track$var tracker_id: Long - VariableNaming:Track.kt$Track$var tracking_url: String - VariableNaming:TrackSearch.kt$TrackSearch$var cover_url: String = "" - VariableNaming:TrackSearch.kt$TrackSearch$var publishing_status: String = "" - VariableNaming:TrackSearch.kt$TrackSearch$var publishing_type: String = "" - VariableNaming:TrackSearch.kt$TrackSearch$var start_date: String = "" - - diff --git a/config/detekt/detekt.yml b/config/detekt/detekt.yml deleted file mode 100644 index d1a3e3dbb..000000000 --- a/config/detekt/detekt.yml +++ /dev/null @@ -1,24 +0,0 @@ -naming: - FunctionNaming: - functionPattern: '[a-z][a-zA-Z0-9]*' - ignoreAnnotated: [ 'Composable' ] - TopLevelPropertyNaming: - constantPattern: '[A-Z][A-Za-z0-9]*' - -complexity: - LongMethod: - ignoreAnnotated: [ 'Composable' ] - LongParameterList: - ignoreDefaultParameters: true - ignoreAnnotated: [ 'Composable' ] - -style: - MagicNumber: - ignorePropertyDeclaration: true - ignoreCompanionObjectPropertyDeclaration: true - ReturnCount: - excludeGuardClauses: true - SerialVersionUIDInSerializableClass: - active: false - UnusedPrivateMember: - ignoreAnnotated: [ 'Preview' ] diff --git a/data/src/main/java/tachiyomi/data/chapter/ChapterRepositoryImpl.kt b/data/src/main/java/tachiyomi/data/chapter/ChapterRepositoryImpl.kt index 099ccb0da..ffc4e5446 100644 --- a/data/src/main/java/tachiyomi/data/chapter/ChapterRepositoryImpl.kt +++ b/data/src/main/java/tachiyomi/data/chapter/ChapterRepositoryImpl.kt @@ -127,7 +127,6 @@ class ChapterRepositoryImpl( } } - @Suppress("LongParameterList") private fun mapChapter( id: Long, mangaId: Long, diff --git a/data/src/main/java/tachiyomi/data/manga/MangaMapper.kt b/data/src/main/java/tachiyomi/data/manga/MangaMapper.kt index 8f0a68d43..53b45ad09 100644 --- a/data/src/main/java/tachiyomi/data/manga/MangaMapper.kt +++ b/data/src/main/java/tachiyomi/data/manga/MangaMapper.kt @@ -5,7 +5,6 @@ import tachiyomi.domain.library.model.LibraryManga import tachiyomi.domain.manga.model.Manga object MangaMapper { - @Suppress("LongParameterList") fun mapManga( id: Long, source: Long, @@ -58,7 +57,6 @@ object MangaMapper { version = version, ) - @Suppress("LongParameterList") fun mapLibraryManga( id: Long, source: Long, diff --git a/data/src/main/java/tachiyomi/data/manga/MangaRepositoryImpl.kt b/data/src/main/java/tachiyomi/data/manga/MangaRepositoryImpl.kt index 06b7bde58..f7aaf4c99 100644 --- a/data/src/main/java/tachiyomi/data/manga/MangaRepositoryImpl.kt +++ b/data/src/main/java/tachiyomi/data/manga/MangaRepositoryImpl.kt @@ -67,7 +67,6 @@ class MangaRepositoryImpl( } } - @Suppress("MagicNumber") override suspend fun getUpcomingManga(statuses: Set): Flow> { val epochMillis = LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toEpochSecond() * 1000 return handler.subscribeToList { diff --git a/domain/src/main/java/mihon/domain/extensionrepo/interactor/CreateExtensionRepo.kt b/domain/src/main/java/mihon/domain/extensionrepo/interactor/CreateExtensionRepo.kt index ec9ca6e72..c44006970 100644 --- a/domain/src/main/java/mihon/domain/extensionrepo/interactor/CreateExtensionRepo.kt +++ b/domain/src/main/java/mihon/domain/extensionrepo/interactor/CreateExtensionRepo.kt @@ -48,7 +48,6 @@ class CreateExtensionRepo( * * @param repo Extension Repo holder for passing to DB/Error Dialog */ - @Suppress("ReturnCount") private suspend fun handleInsertionError(repo: ExtensionRepo): Result { val repoExists = repository.getRepo(repo.baseUrl) if (repoExists != null) { diff --git a/domain/src/main/java/mihon/domain/extensionrepo/service/ExtensionRepoService.kt b/domain/src/main/java/mihon/domain/extensionrepo/service/ExtensionRepoService.kt index 8262961a7..27e00f3a2 100644 --- a/domain/src/main/java/mihon/domain/extensionrepo/service/ExtensionRepoService.kt +++ b/domain/src/main/java/mihon/domain/extensionrepo/service/ExtensionRepoService.kt @@ -17,7 +17,6 @@ class ExtensionRepoService( ) { val client = networkHelper.client - @Suppress("TooGenericExceptionCaught") suspend fun fetchRepoDetails( repo: String, ): ExtensionRepo? { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 76ad11c9a..648faf7f3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,8 +8,6 @@ shizuku_version = "12.2.0" sqldelight = "2.0.2" sqlite = "2.4.0" voyager = "1.0.0" -detekt = "1.23.6" -detektCompose = "0.3.12" [libraries] desugar = "com.android.tools:desugar_jdk_libs:2.0.4" @@ -98,10 +96,6 @@ voyager-screenmodel = { module = "cafe.adriel.voyager:voyager-screenmodel", vers voyager-tab-navigator = { module = "cafe.adriel.voyager:voyager-tab-navigator", version.ref = "voyager" } voyager-transitions = { module = "cafe.adriel.voyager:voyager-transitions", version.ref = "voyager" } -detekt-gradlePlugin = { module = "io.gitlab.arturbosch.detekt:detekt-gradle-plugin", version.ref = "detekt" } -detekt-rules-formatting = { module = "io.gitlab.arturbosch.detekt:detekt-formatting", version.ref = "detekt" } -detekt-rules-compose = { module = "io.nlopez.compose.rules:detekt", version.ref = "detektCompose" } - [bundles] okhttp = ["okhttp-core", "okhttp-logging", "okhttp-brotli", "okhttp-dnsoverhttps"] js-engine = ["quickjs-android"] diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Scaffold.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Scaffold.kt index 6420084a7..16063f621 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Scaffold.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Scaffold.kt @@ -152,7 +152,6 @@ fun Scaffold( * @param bottomBar the content to place at the bottom of the [Scaffold], on top of the * [content], typically a [NavigationBar]. */ -@Suppress("CyclomaticComplexMethod") @OptIn(ExperimentalMaterial3Api::class) @Composable private fun ScaffoldLayout( From ac41bffdc97b4cfed923de6b9e8e01cccf3eb6eb Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Mon, 19 Aug 2024 16:38:08 +0600 Subject: [PATCH 153/297] Generate locales_config.xml in build dir --- .../kotlin/mihon/buildlogic/ProjectExtensions.kt | 3 +++ .../mihon/buildlogic/tasks/LocalesConfigPlugin.kt | 9 ++++----- i18n/.gitignore | 2 -- i18n/build.gradle.kts | 13 +++++++++---- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/buildSrc/src/main/kotlin/mihon/buildlogic/ProjectExtensions.kt b/buildSrc/src/main/kotlin/mihon/buildlogic/ProjectExtensions.kt index 4b9e762b9..ae18dd637 100644 --- a/buildSrc/src/main/kotlin/mihon/buildlogic/ProjectExtensions.kt +++ b/buildSrc/src/main/kotlin/mihon/buildlogic/ProjectExtensions.kt @@ -15,6 +15,7 @@ import org.gradle.kotlin.dsl.the import org.gradle.kotlin.dsl.withType import org.jetbrains.kotlin.compose.compiler.gradle.ComposeCompilerGradlePluginExtension import org.jetbrains.kotlin.gradle.tasks.KotlinCompile +import java.io.File val Project.androidx get() = the() val Project.compose get() = the() @@ -106,3 +107,5 @@ internal fun Project.configureTest() { } } } + +val Project.generatedBuildDir: File get() = project.layout.buildDirectory.asFile.get().resolve("generated/mihon") diff --git a/buildSrc/src/main/kotlin/mihon/buildlogic/tasks/LocalesConfigPlugin.kt b/buildSrc/src/main/kotlin/mihon/buildlogic/tasks/LocalesConfigPlugin.kt index d84d2cb64..329e4a769 100644 --- a/buildSrc/src/main/kotlin/mihon/buildlogic/tasks/LocalesConfigPlugin.kt +++ b/buildSrc/src/main/kotlin/mihon/buildlogic/tasks/LocalesConfigPlugin.kt @@ -3,10 +3,11 @@ package mihon.buildlogic.tasks import org.gradle.api.Project import org.gradle.api.Task import org.gradle.api.tasks.TaskProvider +import java.io.File -private val emptyResourcesElement = "\\s*|".toRegex() +private val emptyResourcesElement = "\\s*|".toRegex() -fun Project.getLocalesConfigTask(): TaskProvider { +fun Project.getLocalesConfigTask(outputResourceDir: File): TaskProvider { return tasks.register("generateLocalesConfig") { val locales = fileTree("$projectDir/src/commonMain/moko-resources/") .matching { include("**/strings.xml") } @@ -16,7 +17,6 @@ fun Project.getLocalesConfigTask(): TaskProvider { .replace("base", "en") .replace("-r", "-") .replace("+", "-") - .takeIf(String::isNotBlank) ?: "en" } .sorted() .joinToString("\n") { "| " } @@ -28,10 +28,9 @@ fun Project.getLocalesConfigTask(): TaskProvider { | """.trimMargin() - file("$projectDir/src/androidMain/res/xml/locales_config.xml").apply { + outputResourceDir.resolve("xml/locales_config.xml").apply { parentFile.mkdirs() writeText(content) } } } - diff --git a/i18n/.gitignore b/i18n/.gitignore index 601f2b1cd..e69de29bb 100644 --- a/i18n/.gitignore +++ b/i18n/.gitignore @@ -1,2 +0,0 @@ -# Generated -locales_config.xml \ No newline at end of file diff --git a/i18n/build.gradle.kts b/i18n/build.gradle.kts index 7c7256acc..a7d5b889a 100644 --- a/i18n/build.gradle.kts +++ b/i18n/build.gradle.kts @@ -1,3 +1,4 @@ +import mihon.buildlogic.generatedBuildDir import mihon.buildlogic.tasks.getLocalesConfigTask import org.jetbrains.kotlin.gradle.tasks.KotlinCompile @@ -21,13 +22,17 @@ kotlin { } } +val generatedAndroidResourceDir = generatedBuildDir.resolve("android/res") + android { namespace = "tachiyomi.i18n" sourceSets { - named("main") { - res.srcDir("src/commonMain/resources") - } + val main by getting + main.res.srcDirs( + "src/commonMain/resources", + generatedAndroidResourceDir, + ) } lint { @@ -40,7 +45,7 @@ multiplatformResources { } tasks { - val localesConfigTask = project.getLocalesConfigTask() + val localesConfigTask = project.getLocalesConfigTask(generatedAndroidResourceDir) preBuild { dependsOn(localesConfigTask) } From 5ae8095ef1ed2ae9f98486f9148e933c77a28692 Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Mon, 19 Aug 2024 18:11:14 +0600 Subject: [PATCH 154/297] Add spotless (with ktlint) (#1136) --- .github/workflows/build_pull_request.yml | 2 +- .github/workflows/build_push.yml | 2 +- buildSrc/build.gradle.kts | 1 + ...hon.android.application.compose.gradle.kts | 2 ++ .../mihon.android.application.gradle.kts | 2 ++ .../main/kotlin/mihon.benchmark.gradle.kts | 2 ++ .../main/kotlin/mihon.code.lint.gradle.kts | 30 +++++++++++++++++++ .../kotlin/mihon.library.compose.gradle.kts | 2 ++ .../src/main/kotlin/mihon.library.gradle.kts | 2 ++ gradle/libs.versions.toml | 5 ++++ 10 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 buildSrc/src/main/kotlin/mihon.code.lint.gradle.kts diff --git a/.github/workflows/build_pull_request.yml b/.github/workflows/build_pull_request.yml index 2cae6e891..11ecb58ec 100644 --- a/.github/workflows/build_pull_request.yml +++ b/.github/workflows/build_pull_request.yml @@ -38,7 +38,7 @@ jobs: uses: gradle/actions/setup-gradle@af1da67850ed9a4cedd57bfd976089dd991e2582 # v4.0.0 - name: Build app and run unit tests - run: ./gradlew assembleStandardRelease testReleaseUnitTest testStandardReleaseUnitTest + run: ./gradlew spotlessCheck assembleStandardRelease testReleaseUnitTest testStandardReleaseUnitTest - name: Upload APK uses: actions/upload-artifact@v4 diff --git a/.github/workflows/build_push.yml b/.github/workflows/build_push.yml index 207b166a2..077bfad01 100644 --- a/.github/workflows/build_push.yml +++ b/.github/workflows/build_push.yml @@ -36,7 +36,7 @@ jobs: uses: gradle/actions/setup-gradle@af1da67850ed9a4cedd57bfd976089dd991e2582 # v4.0.0 - name: Build app and run unit tests - run: ./gradlew assembleStandardRelease testReleaseUnitTest testStandardReleaseUnitTest + run: ./gradlew spotlessCheck assembleStandardRelease testReleaseUnitTest testStandardReleaseUnitTest - name: Upload APK uses: actions/upload-artifact@v4 diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index b825b4172..5ed94c26b 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -6,6 +6,7 @@ dependencies { implementation(androidx.gradle) implementation(kotlinx.gradle) implementation(kotlinx.compose.compiler.gradle) + implementation(libs.spotless.gradle) implementation(gradleApi()) implementation(files(libs.javaClass.superclass.protectionDomain.codeSource.location)) diff --git a/buildSrc/src/main/kotlin/mihon.android.application.compose.gradle.kts b/buildSrc/src/main/kotlin/mihon.android.application.compose.gradle.kts index 6b330b1d9..767f758cb 100644 --- a/buildSrc/src/main/kotlin/mihon.android.application.compose.gradle.kts +++ b/buildSrc/src/main/kotlin/mihon.android.application.compose.gradle.kts @@ -3,6 +3,8 @@ import mihon.buildlogic.configureCompose plugins { id("com.android.application") kotlin("android") + + id("mihon.code.lint") } android { diff --git a/buildSrc/src/main/kotlin/mihon.android.application.gradle.kts b/buildSrc/src/main/kotlin/mihon.android.application.gradle.kts index 7ba9c60fb..080f9ca64 100644 --- a/buildSrc/src/main/kotlin/mihon.android.application.gradle.kts +++ b/buildSrc/src/main/kotlin/mihon.android.application.gradle.kts @@ -5,6 +5,8 @@ import mihon.buildlogic.configureTest plugins { id("com.android.application") kotlin("android") + + id("mihon.code.lint") } android { diff --git a/buildSrc/src/main/kotlin/mihon.benchmark.gradle.kts b/buildSrc/src/main/kotlin/mihon.benchmark.gradle.kts index 3a43a2aa1..50c47f280 100644 --- a/buildSrc/src/main/kotlin/mihon.benchmark.gradle.kts +++ b/buildSrc/src/main/kotlin/mihon.benchmark.gradle.kts @@ -4,6 +4,8 @@ import mihon.buildlogic.configureTest plugins { id("com.android.test") kotlin("android") + + id("mihon.code.lint") } android { diff --git a/buildSrc/src/main/kotlin/mihon.code.lint.gradle.kts b/buildSrc/src/main/kotlin/mihon.code.lint.gradle.kts new file mode 100644 index 000000000..9dfa7eef2 --- /dev/null +++ b/buildSrc/src/main/kotlin/mihon.code.lint.gradle.kts @@ -0,0 +1,30 @@ +import org.gradle.accessors.dm.LibrariesForLibs + +plugins { + id("com.diffplug.spotless") +} + +val libs = the() + +spotless { + kotlin { + target("**/*.kt", "**/*.kts") + targetExclude("**/build/**/*.kt") + ktlint(libs.ktlint.core.get().version) + .editorConfigOverride(mapOf( + "ktlint_function_naming_ignore_when_annotated_with" to "Composable", + "ktlint_standard_class-signature" to "disabled", + "ktlint_standard_discouraged-comment-location" to "disabled", + "ktlint_standard_function-expression-body" to "disabled", + "ktlint_standard_function-signature" to "disabled", + )) + trimTrailingWhitespace() + endWithNewline() + } + format("xml") { + target("**/*.xml") + targetExclude("**/build/**/*.xml") + trimTrailingWhitespace() + endWithNewline() + } +} diff --git a/buildSrc/src/main/kotlin/mihon.library.compose.gradle.kts b/buildSrc/src/main/kotlin/mihon.library.compose.gradle.kts index 0c37a3256..7b377ce4c 100644 --- a/buildSrc/src/main/kotlin/mihon.library.compose.gradle.kts +++ b/buildSrc/src/main/kotlin/mihon.library.compose.gradle.kts @@ -2,6 +2,8 @@ import mihon.buildlogic.configureCompose plugins { id("com.android.library") + + id("mihon.code.lint") } android { diff --git a/buildSrc/src/main/kotlin/mihon.library.gradle.kts b/buildSrc/src/main/kotlin/mihon.library.gradle.kts index 743bf07e3..4cf5f6efc 100644 --- a/buildSrc/src/main/kotlin/mihon.library.gradle.kts +++ b/buildSrc/src/main/kotlin/mihon.library.gradle.kts @@ -3,6 +3,8 @@ import mihon.buildlogic.configureTest plugins { id("com.android.library") + + id("mihon.code.lint") } android { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 648faf7f3..3ee860883 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,6 +8,8 @@ shizuku_version = "12.2.0" sqldelight = "2.0.2" sqlite = "2.4.0" voyager = "1.0.0" +spotless = "6.25.0" +ktlint-core = "1.3.1" [libraries] desugar = "com.android.tools:desugar_jdk_libs:2.0.4" @@ -96,6 +98,9 @@ voyager-screenmodel = { module = "cafe.adriel.voyager:voyager-screenmodel", vers voyager-tab-navigator = { module = "cafe.adriel.voyager:voyager-tab-navigator", version.ref = "voyager" } voyager-transitions = { module = "cafe.adriel.voyager:voyager-transitions", version.ref = "voyager" } +spotless-gradle = { group = "com.diffplug.spotless", name = "spotless-plugin-gradle", version.ref = "spotless" } +ktlint-core = { module = "com.pinterest.ktlint:ktlint-cli", version.ref = "ktlint-core" } + [bundles] okhttp = ["okhttp-core", "okhttp-logging", "okhttp-brotli", "okhttp-dnsoverhttps"] js-engine = ["quickjs-android"] From d6252ab7703d52ecf9f43de3ee36fd63e665a31f Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Mon, 19 Aug 2024 18:11:39 +0600 Subject: [PATCH 155/297] Address spotless lint errors (#1138) * Add spotless (with ktlint) * Run spotlessApply * screaming case screaming case screaming case * Update PagerViewerAdapter.kt * Update ReaderTransitionView.kt --- app/build.gradle.kts | 9 ++- .../interactor/SyncChaptersWithSource.kt | 5 +- .../java/eu/kanade/domain/ui/UiPreferences.kt | 6 +- .../browse/ExtensionDetailsScreen.kt | 6 +- .../presentation/browse/ExtensionsScreen.kt | 8 ++- .../presentation/browse/SourcesScreen.kt | 4 +- .../presentation/components/TabbedDialog.kt | 2 +- .../library/components/CommonMangaItem.kt | 10 ++-- .../manga/components/ChapterHeader.kt | 4 +- .../manga/components/MangaChapterListItem.kt | 10 ++-- .../manga/components/MangaInfoHeader.kt | 3 +- .../presentation/more/NewUpdateScreen.kt | 2 +- .../settings/screen/SettingsAdvancedScreen.kt | 2 +- .../screen/about/OpenSourceLicensesScreen.kt | 2 +- .../screen/debug/BackupSchemaScreen.kt | 6 +- .../settings/screen/debug/DebugInfoScreen.kt | 4 +- .../settings/screen/debug/WorkerInfoScreen.kt | 8 +-- .../settings/widget/TriStateListDialog.kt | 4 +- .../more/stats/components/StatsItem.kt | 4 +- .../presentation/reader/ChapterTransition.kt | 6 +- .../presentation/track/TrackInfoDialogHome.kt | 14 ++--- .../presentation/updates/UpdatesUiItem.kt | 6 +- .../eu/kanade/presentation/util/Navigator.kt | 1 - .../data/backup/restore/BackupRestorer.kt | 2 +- .../data/backup/restore/RestoreOptions.kt | 4 +- .../restorers/ExtensionRepoRestorer.kt | 4 +- .../tachiyomi/data/coil/MangaCoverFetcher.kt | 2 +- .../tachiyomi/data/database/models/Chapter.kt | 2 + .../data/database/models/ChapterImpl.kt | 2 + .../tachiyomi/data/database/models/Track.kt | 2 + .../data/database/models/TrackImpl.kt | 2 + .../tachiyomi/data/download/Downloader.kt | 15 +++-- .../data/library/LibraryUpdateJob.kt | 4 +- .../data/track/anilist/AnilistApi.kt | 38 ++++++------ .../data/track/bangumi/BangumiApi.kt | 46 +++++++------- .../tachiyomi/data/track/kitsu/KitsuApi.kt | 60 +++++++++---------- .../data/track/kitsu/KitsuDateHelper.kt | 4 +- .../tachiyomi/data/track/model/TrackSearch.kt | 2 + .../data/track/shikimori/ShikimoriApi.kt | 52 ++++++++-------- .../tachiyomi/extension/ExtensionManager.kt | 48 +++++++-------- .../tachiyomi/extension/model/InstallStep.kt | 8 ++- .../base/delegate/SecureActivityDelegate.kt | 2 +- .../browse/extension/ExtensionsScreenModel.kt | 20 ++++--- .../eu/kanade/tachiyomi/ui/home/HomeScreen.kt | 13 ++-- .../ui/library/LibraryScreenModel.kt | 2 +- .../ui/library/LibrarySettingsScreenModel.kt | 2 +- .../eu/kanade/tachiyomi/ui/more/MoreTab.kt | 6 +- .../tachiyomi/ui/reader/ReaderViewModel.kt | 10 +++- .../ui/reader/setting/ReaderPreferences.kt | 2 +- .../ui/reader/viewer/ReaderPageImageView.kt | 4 +- .../ui/reader/viewer/ReaderTransitionView.kt | 19 +++--- .../reader/viewer/pager/PagerViewerAdapter.kt | 4 +- .../ui/reader/viewer/webtoon/WebtoonConfig.kt | 2 +- .../viewer/webtoon/WebtoonRecyclerView.kt | 6 +- .../ui/reader/viewer/webtoon/WebtoonViewer.kt | 4 +- .../util/system/ChildFirstPathClassLoader.kt | 2 +- .../core/migration/MigrationJobFactory.kt | 10 +++- .../mihon/core/migration/MigrationStrategy.kt | 4 +- .../java/mihon/core/migration/Migrator.kt | 2 +- .../upcoming/components/calendar/Calendar.kt | 12 ++-- .../components/calendar/CalendarDay.kt | 9 +-- .../components/calendar/CalendarHeader.kt | 10 ++-- .../components/calendar/CalendarIndicator.kt | 8 +-- app/src/main/res/drawable/ic_glasses_24dp.xml | 2 +- .../drawable/material_popup_background.xml | 2 +- app/src/main/res/values/themes.xml | 2 +- app/src/main/res/xml/s_pen_actions.xml | 2 +- .../java/mihon/core/migration/MigratorTest.kt | 4 +- core-metadata/src/main/AndroidManifest.xml | 2 +- core/common/src/main/AndroidManifest.xml | 2 +- .../eu/kanade/tachiyomi/network/Requests.kt | 2 + .../core/common/util/system/ImageUtil.kt | 20 ++++--- data/src/main/AndroidManifest.xml | 2 +- .../java/tachiyomi/data/QueryPagingSource.kt | 4 +- domain/src/main/AndroidManifest.xml | 2 +- .../interactor/ShouldUpdateDbChapter.kt | 3 +- .../interactor/GetApplicationRelease.kt | 6 +- i18n/src/androidMain/AndroidManifest.xml | 2 +- .../commonMain/moko-resources/am/plurals.xml | 2 +- .../commonMain/moko-resources/am/strings.xml | 2 +- .../commonMain/moko-resources/ar/plurals.xml | 2 +- .../commonMain/moko-resources/ar/strings.xml | 2 +- .../commonMain/moko-resources/be/plurals.xml | 2 +- .../commonMain/moko-resources/be/strings.xml | 2 +- .../commonMain/moko-resources/bg/plurals.xml | 2 +- .../commonMain/moko-resources/bg/strings.xml | 2 +- .../commonMain/moko-resources/bn/plurals.xml | 2 +- .../commonMain/moko-resources/bn/strings.xml | 2 +- .../commonMain/moko-resources/ca/plurals.xml | 2 +- .../commonMain/moko-resources/ca/strings.xml | 2 +- .../commonMain/moko-resources/ceb/plurals.xml | 2 +- .../commonMain/moko-resources/ceb/strings.xml | 2 +- .../commonMain/moko-resources/cs/plurals.xml | 2 +- .../commonMain/moko-resources/cs/strings.xml | 2 +- .../commonMain/moko-resources/cv/plurals.xml | 2 +- .../commonMain/moko-resources/cv/strings.xml | 2 +- .../commonMain/moko-resources/da/plurals.xml | 2 +- .../commonMain/moko-resources/da/strings.xml | 2 +- .../commonMain/moko-resources/de/plurals.xml | 2 +- .../commonMain/moko-resources/de/strings.xml | 2 +- .../commonMain/moko-resources/el/plurals.xml | 2 +- .../commonMain/moko-resources/el/strings.xml | 2 +- .../commonMain/moko-resources/eo/plurals.xml | 2 +- .../commonMain/moko-resources/eo/strings.xml | 2 +- .../commonMain/moko-resources/es/plurals.xml | 2 +- .../commonMain/moko-resources/es/strings.xml | 2 +- .../commonMain/moko-resources/eu/plurals.xml | 2 +- .../commonMain/moko-resources/eu/strings.xml | 2 +- .../commonMain/moko-resources/fa/plurals.xml | 2 +- .../commonMain/moko-resources/fa/strings.xml | 2 +- .../commonMain/moko-resources/fi/plurals.xml | 2 +- .../commonMain/moko-resources/fi/strings.xml | 2 +- .../commonMain/moko-resources/fil/plurals.xml | 2 +- .../commonMain/moko-resources/fil/strings.xml | 2 +- .../commonMain/moko-resources/fr/plurals.xml | 2 +- .../commonMain/moko-resources/fr/strings.xml | 2 +- .../commonMain/moko-resources/gl/plurals.xml | 2 +- .../commonMain/moko-resources/gl/strings.xml | 2 +- .../commonMain/moko-resources/he/plurals.xml | 2 +- .../commonMain/moko-resources/he/strings.xml | 2 +- .../commonMain/moko-resources/hi/plurals.xml | 2 +- .../commonMain/moko-resources/hi/strings.xml | 2 +- .../commonMain/moko-resources/hr/plurals.xml | 2 +- .../commonMain/moko-resources/hr/strings.xml | 2 +- .../commonMain/moko-resources/hu/plurals.xml | 2 +- .../commonMain/moko-resources/hu/strings.xml | 2 +- .../commonMain/moko-resources/in/plurals.xml | 2 +- .../commonMain/moko-resources/in/strings.xml | 2 +- .../commonMain/moko-resources/it/plurals.xml | 2 +- .../commonMain/moko-resources/it/strings.xml | 2 +- .../commonMain/moko-resources/ja/plurals.xml | 2 +- .../commonMain/moko-resources/ja/strings.xml | 2 +- .../commonMain/moko-resources/jv/plurals.xml | 2 +- .../commonMain/moko-resources/jv/strings.xml | 2 +- .../moko-resources/ka-rGE/plurals.xml | 2 +- .../moko-resources/ka-rGE/strings.xml | 2 +- .../commonMain/moko-resources/kk/plurals.xml | 2 +- .../commonMain/moko-resources/kk/strings.xml | 2 +- .../commonMain/moko-resources/km/plurals.xml | 2 +- .../commonMain/moko-resources/km/strings.xml | 2 +- .../commonMain/moko-resources/kn/plurals.xml | 2 +- .../commonMain/moko-resources/kn/strings.xml | 2 +- .../commonMain/moko-resources/ko/plurals.xml | 2 +- .../commonMain/moko-resources/ko/strings.xml | 2 +- .../commonMain/moko-resources/lt/plurals.xml | 2 +- .../commonMain/moko-resources/lt/strings.xml | 2 +- .../commonMain/moko-resources/lv/plurals.xml | 2 +- .../commonMain/moko-resources/lv/strings.xml | 2 +- .../commonMain/moko-resources/ml/plurals.xml | 2 +- .../commonMain/moko-resources/ml/strings.xml | 2 +- .../commonMain/moko-resources/mr/plurals.xml | 2 +- .../commonMain/moko-resources/mr/strings.xml | 2 +- .../commonMain/moko-resources/ms/plurals.xml | 2 +- .../commonMain/moko-resources/ms/strings.xml | 2 +- .../moko-resources/nb-rNO/plurals.xml | 2 +- .../moko-resources/nb-rNO/strings.xml | 2 +- .../commonMain/moko-resources/ne/plurals.xml | 2 +- .../commonMain/moko-resources/ne/strings.xml | 2 +- .../commonMain/moko-resources/nl/plurals.xml | 2 +- .../commonMain/moko-resources/nl/strings.xml | 2 +- .../commonMain/moko-resources/nn/plurals.xml | 2 +- .../commonMain/moko-resources/nn/strings.xml | 2 +- .../commonMain/moko-resources/pl/plurals.xml | 2 +- .../commonMain/moko-resources/pl/strings.xml | 2 +- .../moko-resources/pt-rBR/plurals.xml | 2 +- .../moko-resources/pt-rBR/strings.xml | 2 +- .../commonMain/moko-resources/pt/plurals.xml | 2 +- .../commonMain/moko-resources/pt/strings.xml | 2 +- .../commonMain/moko-resources/ro/plurals.xml | 2 +- .../commonMain/moko-resources/ro/strings.xml | 2 +- .../commonMain/moko-resources/ru/plurals.xml | 2 +- .../commonMain/moko-resources/ru/strings.xml | 2 +- .../commonMain/moko-resources/sa/plurals.xml | 2 +- .../commonMain/moko-resources/sa/strings.xml | 2 +- .../commonMain/moko-resources/sah/plurals.xml | 2 +- .../commonMain/moko-resources/sah/strings.xml | 2 +- .../commonMain/moko-resources/sc/plurals.xml | 2 +- .../commonMain/moko-resources/sc/strings.xml | 2 +- .../commonMain/moko-resources/sdh/plurals.xml | 2 +- .../commonMain/moko-resources/sdh/strings.xml | 2 +- .../commonMain/moko-resources/sk/plurals.xml | 2 +- .../commonMain/moko-resources/sk/strings.xml | 2 +- .../commonMain/moko-resources/sq/plurals.xml | 2 +- .../commonMain/moko-resources/sq/strings.xml | 2 +- .../commonMain/moko-resources/sr/plurals.xml | 2 +- .../commonMain/moko-resources/sr/strings.xml | 2 +- .../commonMain/moko-resources/sv/plurals.xml | 2 +- .../commonMain/moko-resources/sv/strings.xml | 2 +- .../commonMain/moko-resources/te/plurals.xml | 2 +- .../commonMain/moko-resources/te/strings.xml | 2 +- .../commonMain/moko-resources/th/plurals.xml | 2 +- .../commonMain/moko-resources/th/strings.xml | 2 +- .../commonMain/moko-resources/tr/plurals.xml | 2 +- .../commonMain/moko-resources/tr/strings.xml | 2 +- .../commonMain/moko-resources/uk/plurals.xml | 2 +- .../commonMain/moko-resources/uk/strings.xml | 2 +- .../commonMain/moko-resources/uz/plurals.xml | 2 +- .../commonMain/moko-resources/uz/strings.xml | 2 +- .../commonMain/moko-resources/vi/plurals.xml | 2 +- .../commonMain/moko-resources/vi/strings.xml | 2 +- .../moko-resources/zh-rCN/plurals.xml | 2 +- .../moko-resources/zh-rCN/strings.xml | 2 +- .../moko-resources/zh-rTW/plurals.xml | 2 +- .../moko-resources/zh-rTW/strings.xml | 2 +- .../src/main/AndroidManifest.xml | 2 +- .../core/components/AdaptiveSheet.kt | 4 +- .../core/components/SettingsItems.kt | 7 +-- .../core/components/VerticalFastScroller.kt | 3 +- .../core/components/WheelPicker.kt | 10 ++-- .../core/components/material/Button.kt | 4 +- .../core/components/material/Constants.kt | 4 +- .../core/components/material/Scaffold.kt | 7 +-- .../presentation/core/icons/Discord.kt | 17 ++++-- .../presentation/core/icons/Facebook.kt | 17 ++++-- .../presentation/core/icons/Github.kt | 17 ++++-- .../presentation/core/icons/Reddit.kt | 17 ++++-- .../tachiyomi/presentation/core/icons/X.kt | 14 ++++- .../presentation/core/util/Modifier.kt | 4 +- .../res/values-night/colors_midnightdusk.xml | 2 +- .../res/values-night/colors_tidalwave.xml | 2 +- .../src/main/res/values/colors_tidalwave.xml | 2 +- .../src/main/AndroidManifest.xml | 2 +- .../src/main/res/values/colors_appwidget.xml | 2 +- .../src/androidMain/AndroidManifest.xml | 2 +- .../kanade/tachiyomi/source/model/SChapter.kt | 2 + .../tachiyomi/source/model/SChapterImpl.kt | 2 + .../kanade/tachiyomi/source/model/SManga.kt | 2 + .../tachiyomi/source/model/SMangaImpl.kt | 2 + .../src/androidMain/AndroidManifest.xml | 2 +- .../tachiyomi/source/local/LocalSource.kt | 13 ++-- 230 files changed, 580 insertions(+), 467 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 1dbee966e..015af54d7 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -17,7 +17,7 @@ if (gradle.startParameter.taskRequests.toString().contains("Standard")) { shortcutHelper.setFilePath("./shortcuts.xml") -val SUPPORTED_ABIS = setOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64") +val supportedAbis = setOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64") android { namespace = "eu.kanade.tachiyomi" @@ -35,7 +35,7 @@ android { buildConfigField("boolean", "PREVIEW", "false") ndk { - abiFilters += SUPPORTED_ABIS + abiFilters += supportedAbis } testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" @@ -45,7 +45,7 @@ android { abi { isEnable = true reset() - include(*SUPPORTED_ABIS.toTypedArray()) + include(*supportedAbis.toTypedArray()) isUniversalApk = true } } @@ -158,7 +158,7 @@ dependencies { implementation(compose.ui.tooling.preview) implementation(compose.ui.util) implementation(compose.accompanist.systemuicontroller) - + implementation(androidx.interpolator) implementation(androidx.paging.runtime) @@ -236,7 +236,6 @@ dependencies { implementation(libs.compose.webview) implementation(libs.compose.grid) - // Logging implementation(libs.logcat) diff --git a/app/src/main/java/eu/kanade/domain/chapter/interactor/SyncChaptersWithSource.kt b/app/src/main/java/eu/kanade/domain/chapter/interactor/SyncChaptersWithSource.kt index 300794b4c..80b6438ad 100644 --- a/app/src/main/java/eu/kanade/domain/chapter/interactor/SyncChaptersWithSource.kt +++ b/app/src/main/java/eu/kanade/domain/chapter/interactor/SyncChaptersWithSource.kt @@ -110,7 +110,10 @@ class SyncChaptersWithSource( if (shouldUpdateDbChapter.await(dbChapter, chapter)) { val shouldRenameChapter = downloadProvider.isChapterDirNameChanged(dbChapter, chapter) && downloadManager.isChapterDownloaded( - dbChapter.name, dbChapter.scanlator, manga.title, manga.source, + dbChapter.name, + dbChapter.scanlator, + manga.title, + manga.source, ) if (shouldRenameChapter) { diff --git a/app/src/main/java/eu/kanade/domain/ui/UiPreferences.kt b/app/src/main/java/eu/kanade/domain/ui/UiPreferences.kt index 2efefb517..a0a16251d 100644 --- a/app/src/main/java/eu/kanade/domain/ui/UiPreferences.kt +++ b/app/src/main/java/eu/kanade/domain/ui/UiPreferences.kt @@ -19,7 +19,11 @@ class UiPreferences( fun appTheme() = preferenceStore.getEnum( "pref_app_theme", - if (DeviceUtil.isDynamicColorAvailable) { AppTheme.MONET } else { AppTheme.DEFAULT }, + if (DeviceUtil.isDynamicColorAvailable) { + AppTheme.MONET + } else { + AppTheme.DEFAULT + }, ) fun themeDarkAmoled() = preferenceStore.getBoolean("pref_theme_dark_amoled_key", false) diff --git a/app/src/main/java/eu/kanade/presentation/browse/ExtensionDetailsScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/ExtensionDetailsScreen.kt index 277dc5e65..501c0b6fd 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/ExtensionDetailsScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/ExtensionDetailsScreen.kt @@ -232,7 +232,7 @@ private fun DetailsHeader( Extension name: ${extension.name} (lang: ${extension.lang}; package: ${extension.pkgName}) Extension version: ${extension.versionName} (lib: ${extension.libVersion}; version code: ${extension.versionCode}) NSFW: ${extension.isNsfw} - """.trimIndent() + """.trimIndent(), ) if (extension is Extension.Installed) { @@ -242,8 +242,8 @@ private fun DetailsHeader( Update available: ${extension.hasUpdate} Obsolete: ${extension.isObsolete} Shared: ${extension.isShared} - Repository: ${extension.repoUrl} - """.trimIndent() + Repository: ${extension.repoUrl} + """.trimIndent(), ) } } diff --git a/app/src/main/java/eu/kanade/presentation/browse/ExtensionsScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/ExtensionsScreen.kt index f5a6fedd4..475f0172d 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/ExtensionsScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/ExtensionsScreen.kt @@ -219,7 +219,9 @@ private fun ExtensionContent( when (it) { is Extension.Available -> onInstallExtension(it) is Extension.Installed -> onOpenExtension(it) - is Extension.Untrusted -> { trustState = it } + is Extension.Untrusted -> { + trustState = it + } } }, onLongClickItem = onLongClickItem, @@ -241,7 +243,9 @@ private fun ExtensionContent( onOpenExtension(it) } } - is Extension.Untrusted -> { trustState = it } + is Extension.Untrusted -> { + trustState = it + } } }, ) 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 56644b3d8..37c77419b 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/SourcesScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/SourcesScreen.kt @@ -28,7 +28,7 @@ import tachiyomi.domain.source.model.Pin import tachiyomi.domain.source.model.Source import tachiyomi.i18n.MR import tachiyomi.presentation.core.components.ScrollbarLazyColumn -import tachiyomi.presentation.core.components.material.SecondaryItemAlpha +import tachiyomi.presentation.core.components.material.SECONDARY_ALPHA import tachiyomi.presentation.core.components.material.padding import tachiyomi.presentation.core.components.material.topSmallPaddingValues import tachiyomi.presentation.core.i18n.stringResource @@ -148,7 +148,7 @@ private fun SourcePinButton( MaterialTheme.colorScheme.primary } else { MaterialTheme.colorScheme.onBackground.copy( - alpha = SecondaryItemAlpha, + alpha = SECONDARY_ALPHA, ) } val description = if (isPinned) MR.strings.action_unpin else MR.strings.action_pin diff --git a/app/src/main/java/eu/kanade/presentation/components/TabbedDialog.kt b/app/src/main/java/eu/kanade/presentation/components/TabbedDialog.kt index b651060f7..69b58c616 100644 --- a/app/src/main/java/eu/kanade/presentation/components/TabbedDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/components/TabbedDialog.kt @@ -79,7 +79,7 @@ fun TabbedDialog( modifier = Modifier.animateContentSize(), state = pagerState, verticalAlignment = Alignment.Top, - pageContent = { page -> content(page) } + pageContent = { page -> content(page) }, ) } } diff --git a/app/src/main/java/eu/kanade/presentation/library/components/CommonMangaItem.kt b/app/src/main/java/eu/kanade/presentation/library/components/CommonMangaItem.kt index b4a4c2cc0..a78462a75 100644 --- a/app/src/main/java/eu/kanade/presentation/library/components/CommonMangaItem.kt +++ b/app/src/main/java/eu/kanade/presentation/library/components/CommonMangaItem.kt @@ -62,7 +62,7 @@ private val ContinueReadingButtonIconSizeLarge = 20.dp private val ContinueReadingButtonGridPadding = 6.dp private val ContinueReadingButtonListSpacing = 8.dp -private const val GridSelectedCoverAlpha = 0.76f +private const val GRID_SELECTED_COVER_ALPHA = 0.76f /** * Layout of grid list item with title overlaying the cover. @@ -90,7 +90,7 @@ fun MangaCompactGridItem( MangaCover.Book( modifier = Modifier .fillMaxWidth() - .alpha(if (isSelected) GridSelectedCoverAlpha else coverAlpha), + .alpha(if (isSelected) GRID_SELECTED_COVER_ALPHA else coverAlpha), data = coverData, ) }, @@ -197,7 +197,7 @@ fun MangaComfortableGridItem( MangaCover.Book( modifier = Modifier .fillMaxWidth() - .alpha(if (isSelected) GridSelectedCoverAlpha else coverAlpha), + .alpha(if (isSelected) GRID_SELECTED_COVER_ALPHA else coverAlpha), data = coverData, ) }, @@ -371,7 +371,7 @@ fun MangaListItem( size = ContinueReadingButtonSizeSmall, iconSize = ContinueReadingButtonIconSizeSmall, onClick = onClickContinueReading, - modifier = Modifier.padding(start = ContinueReadingButtonListSpacing) + modifier = Modifier.padding(start = ContinueReadingButtonListSpacing), ) } } @@ -392,7 +392,7 @@ private fun ContinueReadingButton( containerColor = MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.9f), contentColor = contentColorFor(MaterialTheme.colorScheme.primaryContainer), ), - modifier = Modifier.size(size) + modifier = Modifier.size(size), ) { Icon( imageVector = Icons.Filled.PlayArrow, diff --git a/app/src/main/java/eu/kanade/presentation/manga/components/ChapterHeader.kt b/app/src/main/java/eu/kanade/presentation/manga/components/ChapterHeader.kt index 99ad1b37a..6067d24bd 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/components/ChapterHeader.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/components/ChapterHeader.kt @@ -12,7 +12,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import tachiyomi.i18n.MR -import tachiyomi.presentation.core.components.material.SecondaryItemAlpha +import tachiyomi.presentation.core.components.material.SECONDARY_ALPHA import tachiyomi.presentation.core.components.material.padding import tachiyomi.presentation.core.i18n.pluralStringResource import tachiyomi.presentation.core.i18n.stringResource @@ -60,6 +60,6 @@ private fun MissingChaptersWarning(count: Int) { maxLines = 1, overflow = TextOverflow.Ellipsis, style = MaterialTheme.typography.bodySmall, - color = MaterialTheme.colorScheme.error.copy(alpha = SecondaryItemAlpha), + color = MaterialTheme.colorScheme.error.copy(alpha = SECONDARY_ALPHA), ) } diff --git a/app/src/main/java/eu/kanade/presentation/manga/components/MangaChapterListItem.kt b/app/src/main/java/eu/kanade/presentation/manga/components/MangaChapterListItem.kt index 6f323993c..730c98afe 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/components/MangaChapterListItem.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/components/MangaChapterListItem.kt @@ -40,8 +40,8 @@ import eu.kanade.tachiyomi.data.download.model.Download import me.saket.swipe.SwipeableActionsBox import tachiyomi.domain.library.service.LibraryPreferences import tachiyomi.i18n.MR -import tachiyomi.presentation.core.components.material.ReadItemAlpha -import tachiyomi.presentation.core.components.material.SecondaryItemAlpha +import tachiyomi.presentation.core.components.material.DISABLED_ALPHA +import tachiyomi.presentation.core.components.material.SECONDARY_ALPHA import tachiyomi.presentation.core.i18n.stringResource import tachiyomi.presentation.core.util.selectedBackground @@ -132,7 +132,7 @@ fun MangaChapterListItem( maxLines = 1, overflow = TextOverflow.Ellipsis, onTextLayout = { textHeight = it.size.height }, - color = LocalContentColor.current.copy(alpha = if (read) ReadItemAlpha else 1f), + color = LocalContentColor.current.copy(alpha = if (read) DISABLED_ALPHA else 1f), ) } @@ -140,7 +140,7 @@ fun MangaChapterListItem( val subtitleStyle = MaterialTheme.typography.bodySmall .merge( color = LocalContentColor.current - .copy(alpha = if (read) ReadItemAlpha else SecondaryItemAlpha) + .copy(alpha = if (read) DISABLED_ALPHA else SECONDARY_ALPHA), ) ProvideTextStyle(value = subtitleStyle) { if (date != null) { @@ -156,7 +156,7 @@ fun MangaChapterListItem( text = readProgress, maxLines = 1, overflow = TextOverflow.Ellipsis, - color = LocalContentColor.current.copy(alpha = ReadItemAlpha), + color = LocalContentColor.current.copy(alpha = DISABLED_ALPHA), ) if (scanlator != null) DotSeparatorText() } diff --git a/app/src/main/java/eu/kanade/presentation/manga/components/MangaInfoHeader.kt b/app/src/main/java/eu/kanade/presentation/manga/components/MangaInfoHeader.kt index f65525646..3b8275f84 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/components/MangaInfoHeader.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/components/MangaInfoHeader.kt @@ -81,6 +81,7 @@ import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.util.system.copyToClipboard import tachiyomi.domain.manga.model.Manga import tachiyomi.i18n.MR +import tachiyomi.presentation.core.components.material.DISABLED_ALPHA import tachiyomi.presentation.core.components.material.TextButton import tachiyomi.presentation.core.components.material.padding import tachiyomi.presentation.core.i18n.pluralStringResource @@ -177,7 +178,7 @@ fun MangaActionRow( onEditCategory: (() -> Unit)?, modifier: Modifier = Modifier, ) { - val defaultActionButtonColor = MaterialTheme.colorScheme.onSurface.copy(alpha = .38f) + val defaultActionButtonColor = MaterialTheme.colorScheme.onSurface.copy(alpha = DISABLED_ALPHA) // TODO: show something better when using custom interval val nextUpdateDays = remember(nextUpdate) { diff --git a/app/src/main/java/eu/kanade/presentation/more/NewUpdateScreen.kt b/app/src/main/java/eu/kanade/presentation/more/NewUpdateScreen.kt index 3d561b0c3..87dd1ee4d 100644 --- a/app/src/main/java/eu/kanade/presentation/more/NewUpdateScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/NewUpdateScreen.kt @@ -75,7 +75,7 @@ private fun NewUpdateScreenPreview() { changelogInfo = """ ## Yay Foobar - + ### More info - Hello - World diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt index 646c8c042..b3a999559 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt @@ -340,7 +340,7 @@ object SettingsAdvancedScreen : SearchableSettings { chooseColorProfile.launch(arrayOf("*/*")) }, ), - ) + ), ) } diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/about/OpenSourceLicensesScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/about/OpenSourceLicensesScreen.kt index 3c2309b32..6e92d0cfc 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/about/OpenSourceLicensesScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/about/OpenSourceLicensesScreen.kt @@ -37,7 +37,7 @@ class OpenSourceLicensesScreen : Screen() { name = it.name, website = it.website, license = it.licenses.firstOrNull()?.htmlReadyLicenseContent.orEmpty(), - ) + ), ) }, ) diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/BackupSchemaScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/BackupSchemaScreen.kt index d5652b16a..8fe1d18c1 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/BackupSchemaScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/BackupSchemaScreen.kt @@ -28,7 +28,7 @@ import tachiyomi.presentation.core.i18n.stringResource class BackupSchemaScreen : Screen() { companion object { - const val title = "Backup file schema" + const val TITLE = "Backup file schema" } @Composable @@ -41,7 +41,7 @@ class BackupSchemaScreen : Screen() { Scaffold( topBar = { AppBar( - title = title, + title = TITLE, navigateUp = navigator::pop, actions = { AppBarActions( @@ -50,7 +50,7 @@ class BackupSchemaScreen : Screen() { title = stringResource(MR.strings.action_copy_to_clipboard), icon = Icons.Default.ContentCopy, onClick = { - context.copyToClipboard(title, schema) + context.copyToClipboard(TITLE, schema) }, ), ), diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/DebugInfoScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/DebugInfoScreen.kt index 0db4bd3c7..d44ee1319 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/DebugInfoScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/DebugInfoScreen.kt @@ -31,11 +31,11 @@ class DebugInfoScreen : Screen() { itemsProvider = { listOf( Preference.PreferenceItem.TextPreference( - title = WorkerInfoScreen.title, + title = WorkerInfoScreen.TITLE, onClick = { navigator.push(WorkerInfoScreen()) }, ), Preference.PreferenceItem.TextPreference( - title = BackupSchemaScreen.title, + title = BackupSchemaScreen.TITLE, onClick = { navigator.push(BackupSchemaScreen()) }, ), getAppInfoGroup(), diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/WorkerInfoScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/WorkerInfoScreen.kt index 4a57103d8..88f1e6da2 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/WorkerInfoScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/WorkerInfoScreen.kt @@ -49,7 +49,7 @@ import java.time.ZoneId class WorkerInfoScreen : Screen() { companion object { - const val title = "Worker info" + const val TITLE = "Worker info" } @Composable @@ -65,7 +65,7 @@ class WorkerInfoScreen : Screen() { Scaffold( topBar = { AppBar( - title = title, + title = TITLE, navigateUp = navigator::pop, actions = { AppBarActions( @@ -74,7 +74,7 @@ class WorkerInfoScreen : Screen() { title = stringResource(MR.strings.action_copy_to_clipboard), icon = Icons.Default.ContentCopy, onClick = { - context.copyToClipboard(title, enqueued + finished + running) + context.copyToClipboard(TITLE, enqueued + finished + running) }, ), ), @@ -159,7 +159,7 @@ class WorkerInfoScreen : Screen() { Injekt.get().dateFormat().get(), ), ) - appendLine("Next scheduled run: $timestamp",) + appendLine("Next scheduled run: $timestamp") appendLine("Attempt #${workInfo.runAttemptCount + 1}") } appendLine() diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/widget/TriStateListDialog.kt b/app/src/main/java/eu/kanade/presentation/more/settings/widget/TriStateListDialog.kt index be5029ac3..4f396068a 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/widget/TriStateListDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/widget/TriStateListDialog.kt @@ -32,7 +32,9 @@ import tachiyomi.i18n.MR import tachiyomi.presentation.core.i18n.stringResource private enum class State { - CHECKED, INVERSED, UNCHECKED + CHECKED, + INVERSED, + UNCHECKED, } @Composable diff --git a/app/src/main/java/eu/kanade/presentation/more/stats/components/StatsItem.kt b/app/src/main/java/eu/kanade/presentation/more/stats/components/StatsItem.kt index 8002b3d04..d38643ee1 100644 --- a/app/src/main/java/eu/kanade/presentation/more/stats/components/StatsItem.kt +++ b/app/src/main/java/eu/kanade/presentation/more/stats/components/StatsItem.kt @@ -15,7 +15,7 @@ import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign -import tachiyomi.presentation.core.components.material.SecondaryItemAlpha +import tachiyomi.presentation.core.components.material.SECONDARY_ALPHA import tachiyomi.presentation.core.components.material.padding @Composable @@ -73,7 +73,7 @@ private fun RowScope.BaseStatsItem( style = subtitleStyle .copy( color = MaterialTheme.colorScheme.onSurface - .copy(alpha = SecondaryItemAlpha), + .copy(alpha = SECONDARY_ALPHA), ), textAlign = TextAlign.Center, ) diff --git a/app/src/main/java/eu/kanade/presentation/reader/ChapterTransition.kt b/app/src/main/java/eu/kanade/presentation/reader/ChapterTransition.kt index 5fb749828..f76628b1a 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/ChapterTransition.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/ChapterTransition.kt @@ -226,7 +226,7 @@ private fun ChapterText( Text( text = buildAnnotatedString { if (downloaded) { - appendInlineContent(DownloadedIconContentId) + appendInlineContent(DOWNLOADED_ICON_ID) append(' ') } append(name) @@ -236,7 +236,7 @@ private fun ChapterText( overflow = TextOverflow.Ellipsis, style = MaterialTheme.typography.titleLarge, inlineContent = persistentMapOf( - DownloadedIconContentId to InlineTextContent( + DOWNLOADED_ICON_ID to InlineTextContent( Placeholder( width = 22.sp, height = 22.sp, @@ -273,7 +273,7 @@ private val CardColor: CardColors ) private val VerticalSpacerSize = 24.dp -private const val DownloadedIconContentId = "downloaded" +private const val DOWNLOADED_ICON_ID = "downloaded" private fun previewChapter(name: String, scanlator: String, chapterNumber: Double) = Chapter.create().copy( id = 0L, diff --git a/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHome.kt b/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHome.kt index 4e146c60e..3d766c4cf 100644 --- a/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHome.kt +++ b/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHome.kt @@ -38,7 +38,6 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.clip import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.style.TextAlign @@ -58,8 +57,6 @@ import tachiyomi.i18n.MR import tachiyomi.presentation.core.i18n.stringResource import java.time.format.DateTimeFormatter -private const val UnsetStatusTextAlpha = 0.5F - @Composable fun TrackInfoDialogHome( trackItems: List, @@ -211,10 +208,9 @@ private fun TrackInfoItem( if (onScoreClick != null) { VerticalDivider() TrackDetailsItem( - modifier = Modifier - .weight(1f) - .alpha(if (score == null) UnsetStatusTextAlpha else 1f), - text = score ?: stringResource(MR.strings.score), + modifier = Modifier.weight(1f), + text = score, + placeholder = stringResource(MR.strings.score), onClick = onScoreClick, ) } @@ -243,6 +239,8 @@ private fun TrackInfoItem( } } +private const val UNSET_TEXT_ALPHA = 0.5F + @Composable private fun TrackDetailsItem( text: String?, @@ -263,7 +261,7 @@ private fun TrackDetailsItem( overflow = TextOverflow.Ellipsis, style = MaterialTheme.typography.bodyMedium, textAlign = TextAlign.Center, - color = MaterialTheme.colorScheme.onSurface.copy(alpha = if (text == null) UnsetStatusTextAlpha else 1f), + color = MaterialTheme.colorScheme.onSurface.copy(alpha = if (text == null) UNSET_TEXT_ALPHA else 1f), ) } } diff --git a/app/src/main/java/eu/kanade/presentation/updates/UpdatesUiItem.kt b/app/src/main/java/eu/kanade/presentation/updates/UpdatesUiItem.kt index e0e60d4fb..40743185d 100644 --- a/app/src/main/java/eu/kanade/presentation/updates/UpdatesUiItem.kt +++ b/app/src/main/java/eu/kanade/presentation/updates/UpdatesUiItem.kt @@ -44,7 +44,7 @@ import eu.kanade.tachiyomi.ui.updates.UpdatesItem import tachiyomi.domain.updates.model.UpdatesWithRelations import tachiyomi.i18n.MR import tachiyomi.presentation.core.components.ListGroupHeader -import tachiyomi.presentation.core.components.material.ReadItemAlpha +import tachiyomi.presentation.core.components.material.DISABLED_ALPHA import tachiyomi.presentation.core.components.material.padding import tachiyomi.presentation.core.i18n.stringResource import tachiyomi.presentation.core.util.selectedBackground @@ -146,7 +146,7 @@ private fun UpdatesUiItem( modifier: Modifier = Modifier, ) { val haptic = LocalHapticFeedback.current - val textAlpha = if (update.read) ReadItemAlpha else 1f + val textAlpha = if (update.read) DISABLED_ALPHA else 1f Row( modifier = modifier @@ -220,7 +220,7 @@ private fun UpdatesUiItem( Text( text = readProgress, maxLines = 1, - color = LocalContentColor.current.copy(alpha = ReadItemAlpha), + color = LocalContentColor.current.copy(alpha = DISABLED_ALPHA), overflow = TextOverflow.Ellipsis, ) } diff --git a/app/src/main/java/eu/kanade/presentation/util/Navigator.kt b/app/src/main/java/eu/kanade/presentation/util/Navigator.kt index 6cc93d6b2..b033d4883 100644 --- a/app/src/main/java/eu/kanade/presentation/util/Navigator.kt +++ b/app/src/main/java/eu/kanade/presentation/util/Navigator.kt @@ -1,6 +1,5 @@ package eu.kanade.presentation.util -import android.annotation.SuppressLint import androidx.compose.animation.AnimatedContent import androidx.compose.animation.AnimatedContentTransitionScope import androidx.compose.animation.ContentTransform diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestorer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestorer.kt index c4275f96f..fec340fa3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestorer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestorer.kt @@ -167,7 +167,7 @@ class BackupRestorer( } private fun CoroutineScope.restoreExtensionRepos( - backupExtensionRepo: List + backupExtensionRepo: List, ) = launch { backupExtensionRepo .forEach { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/RestoreOptions.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/RestoreOptions.kt index 933bf0568..c2c88c16b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/RestoreOptions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/RestoreOptions.kt @@ -9,7 +9,7 @@ data class RestoreOptions( val categories: Boolean = true, val appSettings: Boolean = true, val extensionRepoSettings: Boolean = true, - val sourceSettings: Boolean = true + val sourceSettings: Boolean = true, ) { fun asBooleanArray() = booleanArrayOf( @@ -17,7 +17,7 @@ data class RestoreOptions( categories, appSettings, extensionRepoSettings, - sourceSettings + sourceSettings, ) fun canRestore() = libraryEntries || categories || appSettings || extensionRepoSettings || sourceSettings diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/ExtensionRepoRestorer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/ExtensionRepoRestorer.kt index 1dd0da491..006e48df1 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/ExtensionRepoRestorer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/ExtensionRepoRestorer.kt @@ -8,7 +8,7 @@ import uy.kohesive.injekt.api.get class ExtensionRepoRestorer( private val handler: DatabaseHandler = Injekt.get(), - private val getExtensionRepos: GetExtensionRepo = Injekt.get() + private val getExtensionRepos: GetExtensionRepo = Injekt.get(), ) { suspend operator fun invoke( @@ -32,7 +32,7 @@ class ExtensionRepoRestorer( backupRepo.name, backupRepo.shortName, backupRepo.website, - backupRepo.signingKeyFingerprint + backupRepo.signingKeyFingerprint, ) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/coil/MangaCoverFetcher.kt b/app/src/main/java/eu/kanade/tachiyomi/data/coil/MangaCoverFetcher.kt index 832fe95f9..8ccd6d4ba 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/coil/MangaCoverFetcher.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/coil/MangaCoverFetcher.kt @@ -85,7 +85,7 @@ class MangaCoverFetcher( source = ImageSource( file = file.toOkioPath(), fileSystem = FileSystem.SYSTEM, - diskCacheKey = diskCacheKey + diskCacheKey = diskCacheKey, ), mimeType = "image/*", dataSource = DataSource.DISK, diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Chapter.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Chapter.kt index f91368084..799998f20 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Chapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Chapter.kt @@ -1,3 +1,5 @@ +@file:Suppress("PropertyName", "ktlint:standard:property-naming") + package eu.kanade.tachiyomi.data.database.models import eu.kanade.tachiyomi.source.model.SChapter diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/ChapterImpl.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/ChapterImpl.kt index a92dd56df..7db913c99 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/ChapterImpl.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/ChapterImpl.kt @@ -1,3 +1,5 @@ +@file:Suppress("PropertyName", "ktlint:standard:property-naming") + package eu.kanade.tachiyomi.data.database.models class ChapterImpl : Chapter { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Track.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Track.kt index aac7ec4c3..15c12c4a0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Track.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Track.kt @@ -1,3 +1,5 @@ +@file:Suppress("PropertyName", "ktlint:standard:property-naming") + package eu.kanade.tachiyomi.data.database.models import java.io.Serializable diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/TrackImpl.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/TrackImpl.kt index 85868219f..da5aa2856 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/TrackImpl.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/TrackImpl.kt @@ -1,3 +1,5 @@ +@file:Suppress("PropertyName", "ktlint:standard:property-naming") + package eu.kanade.tachiyomi.data.database.models class TrackImpl : Track { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt index 57c3a9824..bf4940e2a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt @@ -180,7 +180,7 @@ class Downloader( fun clearQueue() { cancelDownloaderJob() - _clearQueue() + internalClearQueue() notifier.dismissProgress() } @@ -194,9 +194,12 @@ class Downloader( val activeDownloadsFlow = queueState.transformLatest { queue -> while (true) { val activeDownloads = queue.asSequence() - .filter { it.status.value <= Download.State.DOWNLOADING.value } // Ignore completed downloads, leave them in the queue + // Ignore completed downloads, leave them in the queue + .filter { it.status.value <= Download.State.DOWNLOADING.value } .groupBy { it.source } - .toList().take(5) // Concurrently download from 5 different sources + .toList() + // Concurrently download from 5 different sources + .take(5) .map { (_, downloads) -> downloads.first() } emit(activeDownloads) @@ -616,7 +619,7 @@ class Downloader( chapter, urls, categories, - source.name + source.name, ) // Remove the old file @@ -676,7 +679,7 @@ class Downloader( removeFromQueueIf { it.manga.id == manga.id } } - private fun _clearQueue() { + private fun internalClearQueue() { _queueState.update { it.forEach { download -> if (download.status == Download.State.DOWNLOADING || download.status == Download.State.QUEUE) { @@ -698,7 +701,7 @@ class Downloader( } pause() - _clearQueue() + internalClearQueue() addAllToQueue(downloads) if (wasRunning) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt index 258b1f754..3749c71fb 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt @@ -437,7 +437,9 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet val constraints = Constraints( requiredNetworkType = if (DEVICE_NETWORK_NOT_METERED in restrictions) { NetworkType.UNMETERED - } else { NetworkType.CONNECTED }, + } else { + NetworkType.CONNECTED + }, requiresCharging = DEVICE_CHARGING in restrictions, requiresBatteryNotLow = true, ) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt index c808d0f31..e31454e74 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt @@ -47,10 +47,10 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { return withIOContext { val query = """ |mutation AddManga(${'$'}mangaId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus) { - |SaveMediaListEntry (mediaId: ${'$'}mangaId, progress: ${'$'}progress, status: ${'$'}status) { - | id - | status - |} + |SaveMediaListEntry (mediaId: ${'$'}mangaId, progress: ${'$'}progress, status: ${'$'}status) { + | id + | status + |} |} | """.trimMargin() @@ -65,7 +65,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { with(json) { authClient.newCall( POST( - apiUrl, + API_URL, body = payload.toString().toRequestBody(jsonMime), ), ) @@ -109,7 +109,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { put("completedAt", createDate(track.finished_reading_date)) } } - authClient.newCall(POST(apiUrl, body = payload.toString().toRequestBody(jsonMime))) + authClient.newCall(POST(API_URL, body = payload.toString().toRequestBody(jsonMime))) .awaitSuccess() track } @@ -119,9 +119,9 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { withIOContext { val query = """ |mutation DeleteManga(${'$'}listId: Int) { - |DeleteMediaListEntry(id: ${'$'}listId) { + |DeleteMediaListEntry(id: ${'$'}listId) { |deleted - |} + |} |} | """.trimMargin() @@ -131,7 +131,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { put("listId", track.libraryId) } } - authClient.newCall(POST(apiUrl, body = payload.toString().toRequestBody(jsonMime))) + authClient.newCall(POST(API_URL, body = payload.toString().toRequestBody(jsonMime))) .awaitSuccess() } } @@ -172,7 +172,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { with(json) { authClient.newCall( POST( - apiUrl, + API_URL, body = payload.toString().toRequestBody(jsonMime), ), ) @@ -242,7 +242,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { with(json) { authClient.newCall( POST( - apiUrl, + API_URL, body = payload.toString().toRequestBody(jsonMime), ), ) @@ -286,7 +286,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { with(json) { authClient.newCall( POST( - apiUrl, + API_URL, body = payload.toString().toRequestBody(jsonMime), ), ) @@ -364,17 +364,17 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { } companion object { - private const val clientId = "16329" - private const val apiUrl = "https://graphql.anilist.co/" - private const val baseUrl = "https://anilist.co/api/v2/" - private const val baseMangaUrl = "https://anilist.co/manga/" + private const val CLIENT_ID = "16329" + private const val API_URL = "https://graphql.anilist.co/" + private const val BASE_URL = "https://anilist.co/api/v2/" + private const val BASE_MANGA_URL = "https://anilist.co/manga/" fun mangaUrl(mediaId: Long): String { - return baseMangaUrl + mediaId + return BASE_MANGA_URL + mediaId } - fun authUrl(): Uri = "${baseUrl}oauth/authorize".toUri().buildUpon() - .appendQueryParameter("client_id", clientId) + fun authUrl(): Uri = "${BASE_URL}oauth/authorize".toUri().buildUpon() + .appendQueryParameter("client_id", CLIENT_ID) .appendQueryParameter("response_type", "token") .build() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiApi.kt index 65d2dc805..c48fa2490 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiApi.kt @@ -42,7 +42,7 @@ class BangumiApi( .add("rating", track.score.toInt().toString()) .add("status", track.toBangumiStatus()) .build() - authClient.newCall(POST("$apiUrl/collection/${track.remote_id}/update", body = body)) + authClient.newCall(POST("$API_URL/collection/${track.remote_id}/update", body = body)) .awaitSuccess() track } @@ -55,7 +55,7 @@ class BangumiApi( .add("rating", track.score.toInt().toString()) .add("status", track.toBangumiStatus()) .build() - authClient.newCall(POST("$apiUrl/collection/${track.remote_id}/update", body = sbody)) + authClient.newCall(POST("$API_URL/collection/${track.remote_id}/update", body = sbody)) .awaitSuccess() // chapter update @@ -64,7 +64,7 @@ class BangumiApi( .build() authClient.newCall( POST( - "$apiUrl/subject/${track.remote_id}/update/watched_eps", + "$API_URL/subject/${track.remote_id}/update/watched_eps", body = body, ), ).awaitSuccess() @@ -75,7 +75,7 @@ class BangumiApi( suspend fun search(search: String): List { return withIOContext { - val url = "$apiUrl/search/subject/${URLEncoder.encode(search, StandardCharsets.UTF_8.name())}" + val url = "$API_URL/search/subject/${URLEncoder.encode(search, StandardCharsets.UTF_8.name())}" .toUri() .buildUpon() .appendQueryParameter("max_results", "20") @@ -124,7 +124,7 @@ class BangumiApi( suspend fun findLibManga(track: Track): Track? { return withIOContext { with(json) { - authClient.newCall(GET("$apiUrl/subject/${track.remote_id}")) + authClient.newCall(GET("$API_URL/subject/${track.remote_id}")) .awaitSuccess() .parseAs() .let { jsonToSearch(it) } @@ -134,7 +134,7 @@ class BangumiApi( suspend fun statusLibManga(track: Track): Track? { return withIOContext { - val urlUserRead = "$apiUrl/collection/${track.remote_id}" + val urlUserRead = "$API_URL/collection/${track.remote_id}" val requestUserRead = Request.Builder() .url(urlUserRead) .cacheControl(CacheControl.FORCE_NETWORK) @@ -171,41 +171,41 @@ class BangumiApi( } private fun accessTokenRequest(code: String) = POST( - oauthUrl, + OAUTH_URL, body = FormBody.Builder() .add("grant_type", "authorization_code") - .add("client_id", clientId) - .add("client_secret", clientSecret) + .add("client_id", CLIENT_ID) + .add("client_secret", CLIENT_SECRET) .add("code", code) - .add("redirect_uri", redirectUrl) + .add("redirect_uri", REDIRECT_URL) .build(), ) companion object { - private const val clientId = "bgm291665acbd06a4c28" - private const val clientSecret = "43e5ce36b207de16e5d3cfd3e79118db" + private const val CLIENT_ID = "bgm291665acbd06a4c28" + private const val CLIENT_SECRET = "43e5ce36b207de16e5d3cfd3e79118db" - private const val apiUrl = "https://api.bgm.tv" - private const val oauthUrl = "https://bgm.tv/oauth/access_token" - private const val loginUrl = "https://bgm.tv/oauth/authorize" + private const val API_URL = "https://api.bgm.tv" + private const val OAUTH_URL = "https://bgm.tv/oauth/access_token" + private const val LOGIN_URL = "https://bgm.tv/oauth/authorize" - private const val redirectUrl = "mihon://bangumi-auth" + private const val REDIRECT_URL = "mihon://bangumi-auth" fun authUrl(): Uri = - loginUrl.toUri().buildUpon() - .appendQueryParameter("client_id", clientId) + LOGIN_URL.toUri().buildUpon() + .appendQueryParameter("client_id", CLIENT_ID) .appendQueryParameter("response_type", "code") - .appendQueryParameter("redirect_uri", redirectUrl) + .appendQueryParameter("redirect_uri", REDIRECT_URL) .build() fun refreshTokenRequest(token: String) = POST( - oauthUrl, + OAUTH_URL, body = FormBody.Builder() .add("grant_type", "refresh_token") - .add("client_id", clientId) - .add("client_secret", clientSecret) + .add("client_id", CLIENT_ID) + .add("client_secret", CLIENT_SECRET) .add("refresh_token", token) - .add("redirect_uri", redirectUrl) + .add("redirect_uri", REDIRECT_URL) .build(), ) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt index cabdf87be..c124ddd13 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt @@ -66,7 +66,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor) with(json) { authClient.newCall( POST( - "${baseUrl}library-entries", + "${BASE_URL}library-entries", headers = headersOf( "Content-Type", "application/vnd.api+json", @@ -104,7 +104,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor) with(json) { authClient.newCall( Request.Builder() - .url("${baseUrl}library-entries/${track.remote_id}") + .url("${BASE_URL}library-entries/${track.remote_id}") .headers( headersOf( "Content-Type", @@ -130,7 +130,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor) authClient .newCall( DELETE( - "${baseUrl}library-entries/${track.remoteId}", + "${BASE_URL}library-entries/${track.remoteId}", headers = headersOf( "Content-Type", "application/vnd.api+json", @@ -143,7 +143,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor) suspend fun search(query: String): List { return withIOContext { with(json) { - authClient.newCall(GET(algoliaKeyUrl)) + authClient.newCall(GET(ALGOLIA_KEY_URL)) .awaitSuccess() .parseAs() .let { @@ -157,16 +157,16 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor) private suspend fun algoliaSearch(key: String, query: String): List { return withIOContext { val jsonObject = buildJsonObject { - put("params", "query=${URLEncoder.encode(query, StandardCharsets.UTF_8.name())}$algoliaFilter") + put("params", "query=${URLEncoder.encode(query, StandardCharsets.UTF_8.name())}$ALGOLIA_FILTER") } with(json) { client.newCall( POST( - algoliaUrl, + ALGOLIA_URL, headers = headersOf( "X-Algolia-Application-Id", - algoliaAppId, + ALGOLIA_APP_ID, "X-Algolia-API-Key", key, ), @@ -187,7 +187,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor) suspend fun findLibManga(track: Track, userId: String): Track? { return withIOContext { - val url = "${baseUrl}library-entries".toUri().buildUpon() + val url = "${BASE_URL}library-entries".toUri().buildUpon() .encodedQuery("filter[manga_id]=${track.remote_id}&filter[user_id]=$userId") .appendQueryParameter("include", "manga") .build() @@ -210,7 +210,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor) suspend fun getLibManga(track: Track): Track { return withIOContext { - val url = "${baseUrl}library-entries".toUri().buildUpon() + val url = "${BASE_URL}library-entries".toUri().buildUpon() .encodedQuery("filter[id]=${track.remote_id}") .appendQueryParameter("include", "manga") .build() @@ -237,11 +237,11 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor) .add("username", username) .add("password", password) .add("grant_type", "password") - .add("client_id", clientId) - .add("client_secret", clientSecret) + .add("client_id", CLIENT_ID) + .add("client_secret", CLIENT_SECRET) .build() with(json) { - client.newCall(POST(loginUrl, body = formBody)) + client.newCall(POST(LOGIN_URL, body = formBody)) .awaitSuccess() .parseAs() } @@ -250,7 +250,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor) suspend fun getCurrentUser(): String { return withIOContext { - val url = "${baseUrl}users".toUri().buildUpon() + val url = "${BASE_URL}users".toUri().buildUpon() .encodedQuery("filter[self]=true") .build() with(json) { @@ -265,35 +265,31 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor) } companion object { - private const val clientId = - "dd031b32d2f56c990b1425efe6c42ad847e7fe3ab46bf1299f05ecd856bdb7dd" - private const val clientSecret = - "54d7307928f63414defd96399fc31ba847961ceaecef3a5fd93144e960c0e151" + private const val CLIENT_ID = "dd031b32d2f56c990b1425efe6c42ad847e7fe3ab46bf1299f05ecd856bdb7dd" + private const val CLIENT_SECRET = "54d7307928f63414defd96399fc31ba847961ceaecef3a5fd93144e960c0e151" - private const val baseUrl = "https://kitsu.app/api/edge/" - private const val loginUrl = "https://kitsu.app/api/oauth/token" - private const val baseMangaUrl = "https://kitsu.app/manga/" - private const val algoliaKeyUrl = "https://kitsu.app/api/edge/algolia-keys/media/" + private const val BASE_URL = "https://kitsu.app/api/edge/" + private const val LOGIN_URL = "https://kitsu.app/api/oauth/token" + private const val BASE_MANGA_URL = "https://kitsu.app/manga/" + private const val ALGOLIA_KEY_URL = "https://kitsu.app/api/edge/algolia-keys/media/" - private const val algoliaUrl = - "https://AWQO5J657S-dsn.algolia.net/1/indexes/production_media/query/" - private const val algoliaAppId = "AWQO5J657S" - private const val algoliaFilter = - "&facetFilters=%5B%22kind%3Amanga%22%5D&attributesToRetrieve=" + - "%5B%22synopsis%22%2C%22averageRating%22%2C%22canonicalTitle%22%2C%22chapterCount%22%2C%22" + - "posterImage%22%2C%22startDate%22%2C%22subtype%22%2C%22endDate%22%2C%20%22id%22%5D" + private const val ALGOLIA_APP_ID = "AWQO5J657S" + private const val ALGOLIA_URL = "https://$ALGOLIA_APP_ID-dsn.algolia.net/1/indexes/production_media/query/" + private const val ALGOLIA_FILTER = "&facetFilters=%5B%22kind%3Amanga%22%5D&attributesToRetrieve=" + + "%5B%22synopsis%22%2C%22averageRating%22%2C%22canonicalTitle%22%2C%22chapterCount%22%2C%22" + + "posterImage%22%2C%22startDate%22%2C%22subtype%22%2C%22endDate%22%2C%20%22id%22%5D" fun mangaUrl(remoteId: Long): String { - return baseMangaUrl + remoteId + return BASE_MANGA_URL + remoteId } fun refreshTokenRequest(token: String) = POST( - loginUrl, + LOGIN_URL, body = FormBody.Builder() .add("grant_type", "refresh_token") .add("refresh_token", token) - .add("client_id", clientId) - .add("client_secret", clientSecret) + .add("client_id", CLIENT_ID) + .add("client_secret", CLIENT_SECRET) .build(), ) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuDateHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuDateHelper.kt index 6828e1e1a..e4521438b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuDateHelper.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuDateHelper.kt @@ -6,8 +6,8 @@ import java.util.Locale object KitsuDateHelper { - private const val pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" - private val formatter = SimpleDateFormat(pattern, Locale.ENGLISH) + private const val PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" + private val formatter = SimpleDateFormat(PATTERN, Locale.ENGLISH) fun convert(dateValue: Long): String? { if (dateValue == 0L) return null diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/model/TrackSearch.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/model/TrackSearch.kt index c1af76ebf..94160d6ab 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/model/TrackSearch.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/model/TrackSearch.kt @@ -1,3 +1,5 @@ +@file:Suppress("PropertyName", "ktlint:standard:property-naming") + package eu.kanade.tachiyomi.data.track.model import eu.kanade.tachiyomi.data.database.models.Track diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriApi.kt index 6eb93a636..08a695930 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriApi.kt @@ -54,7 +54,7 @@ class ShikimoriApi( } authClient.newCall( POST( - "$apiUrl/v2/user_rates", + "$API_URL/v2/user_rates", body = payload.toString().toRequestBody(jsonMime), ), ).awaitSuccess() @@ -73,14 +73,14 @@ class ShikimoriApi( suspend fun deleteLibManga(track: DomainTrack) { withIOContext { authClient - .newCall(DELETE("$apiUrl/v2/user_rates/${track.libraryId}")) + .newCall(DELETE("$API_URL/v2/user_rates/${track.libraryId}")) .awaitSuccess() } } suspend fun search(search: String): List { return withIOContext { - val url = "$apiUrl/mangas".toUri().buildUpon() + val url = "$API_URL/mangas".toUri().buildUpon() .appendQueryParameter("order", "popularity") .appendQueryParameter("search", search) .appendQueryParameter("limit", "20") @@ -103,10 +103,10 @@ class ShikimoriApi( remote_id = obj["id"]!!.jsonPrimitive.long title = obj["name"]!!.jsonPrimitive.content total_chapters = obj["chapters"]!!.jsonPrimitive.long - cover_url = baseUrl + obj["image"]!!.jsonObject["preview"]!!.jsonPrimitive.content + cover_url = BASE_URL + obj["image"]!!.jsonObject["preview"]!!.jsonPrimitive.content summary = "" score = obj["score"]!!.jsonPrimitive.double - tracking_url = baseUrl + obj["url"]!!.jsonPrimitive.content + tracking_url = BASE_URL + obj["url"]!!.jsonPrimitive.content publishing_status = obj["status"]!!.jsonPrimitive.content publishing_type = obj["kind"]!!.jsonPrimitive.content start_date = obj["aired_on"]!!.jsonPrimitive.contentOrNull ?: "" @@ -122,13 +122,13 @@ class ShikimoriApi( last_chapter_read = obj["chapters"]!!.jsonPrimitive.double score = obj["score"]!!.jsonPrimitive.int.toDouble() status = toTrackStatus(obj["status"]!!.jsonPrimitive.content) - tracking_url = baseUrl + mangas["url"]!!.jsonPrimitive.content + tracking_url = BASE_URL + mangas["url"]!!.jsonPrimitive.content } } suspend fun findLibManga(track: Track, userId: String): Track? { return withIOContext { - val urlMangas = "$apiUrl/mangas".toUri().buildUpon() + val urlMangas = "$API_URL/mangas".toUri().buildUpon() .appendPath(track.remote_id.toString()) .build() val mangas = with(json) { @@ -137,7 +137,7 @@ class ShikimoriApi( .parseAs() } - val url = "$apiUrl/v2/user_rates".toUri().buildUpon() + val url = "$API_URL/v2/user_rates".toUri().buildUpon() .appendQueryParameter("user_id", userId) .appendQueryParameter("target_id", track.remote_id.toString()) .appendQueryParameter("target_type", "Manga") @@ -161,7 +161,7 @@ class ShikimoriApi( suspend fun getCurrentUser(): Int { return with(json) { - authClient.newCall(GET("$apiUrl/users/whoami")) + authClient.newCall(GET("$API_URL/users/whoami")) .awaitSuccess() .parseAs() .let { @@ -181,39 +181,39 @@ class ShikimoriApi( } private fun accessTokenRequest(code: String) = POST( - oauthUrl, + OAUTH_URL, body = FormBody.Builder() .add("grant_type", "authorization_code") - .add("client_id", clientId) - .add("client_secret", clientSecret) + .add("client_id", CLIENT_ID) + .add("client_secret", CLIENT_SECRET) .add("code", code) - .add("redirect_uri", redirectUrl) + .add("redirect_uri", REDIRECT_URL) .build(), ) companion object { - private const val clientId = "PB9dq8DzI405s7wdtwTdirYqHiyVMh--djnP7lBUqSA" - private const val clientSecret = "NajpZcOBKB9sJtgNcejf8OB9jBN1OYYoo-k4h2WWZus" + private const val CLIENT_ID = "PB9dq8DzI405s7wdtwTdirYqHiyVMh--djnP7lBUqSA" + private const val CLIENT_SECRET = "NajpZcOBKB9sJtgNcejf8OB9jBN1OYYoo-k4h2WWZus" - private const val baseUrl = "https://shikimori.one" - private const val apiUrl = "$baseUrl/api" - private const val oauthUrl = "$baseUrl/oauth/token" - private const val loginUrl = "$baseUrl/oauth/authorize" + private const val BASE_URL = "https://shikimori.one" + private const val API_URL = "$BASE_URL/api" + private const val OAUTH_URL = "$BASE_URL/oauth/token" + private const val LOGIN_URL = "$BASE_URL/oauth/authorize" - private const val redirectUrl = "mihon://shikimori-auth" + private const val REDIRECT_URL = "mihon://shikimori-auth" - fun authUrl(): Uri = loginUrl.toUri().buildUpon() - .appendQueryParameter("client_id", clientId) - .appendQueryParameter("redirect_uri", redirectUrl) + fun authUrl(): Uri = LOGIN_URL.toUri().buildUpon() + .appendQueryParameter("client_id", CLIENT_ID) + .appendQueryParameter("redirect_uri", REDIRECT_URL) .appendQueryParameter("response_type", "code") .build() fun refreshTokenRequest(token: String) = POST( - oauthUrl, + OAUTH_URL, body = FormBody.Builder() .add("grant_type", "refresh_token") - .add("client_id", clientId) - .add("client_secret", clientSecret) + .add("client_id", CLIENT_ID) + .add("client_secret", CLIENT_SECRET) .add("refresh_token", token) .build(), ) diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt index 968263b5d..1b0f0f9b4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt @@ -62,14 +62,14 @@ class ExtensionManager( private val iconMap = mutableMapOf() - private val _installedExtensionsMapFlow = MutableStateFlow(emptyMap()) - val installedExtensionsFlow = _installedExtensionsMapFlow.mapExtensions(scope) + private val installedExtensionMapFlow = MutableStateFlow(emptyMap()) + val installedExtensionsFlow = installedExtensionMapFlow.mapExtensions(scope) - private val _availableExtensionsMapFlow = MutableStateFlow(emptyMap()) - val availableExtensionsFlow = _availableExtensionsMapFlow.mapExtensions(scope) + private val availableExtensionMapFlow = MutableStateFlow(emptyMap()) + val availableExtensionsFlow = availableExtensionMapFlow.mapExtensions(scope) - private val _untrustedExtensionsMapFlow = MutableStateFlow(emptyMap()) - val untrustedExtensionsFlow = _untrustedExtensionsMapFlow.mapExtensions(scope) + private val untrustedExtensionMapFlow = MutableStateFlow(emptyMap()) + val untrustedExtensionsFlow = untrustedExtensionMapFlow.mapExtensions(scope) init { initExtensions() @@ -79,7 +79,7 @@ class ExtensionManager( private var subLanguagesEnabledOnFirstRun = preferences.enabledLanguages().isSet() fun getAppIconForSource(sourceId: Long): Drawable? { - val pkgName = _installedExtensionsMapFlow.value.values + val pkgName = installedExtensionMapFlow.value.values .find { ext -> ext.sources.any { it.id == sourceId } } @@ -109,11 +109,11 @@ class ExtensionManager( private fun initExtensions() { val extensions = ExtensionLoader.loadExtensions(context) - _installedExtensionsMapFlow.value = extensions + installedExtensionMapFlow.value = extensions .filterIsInstance() .associate { it.extension.pkgName to it.extension } - _untrustedExtensionsMapFlow.value = extensions + untrustedExtensionMapFlow.value = extensions .filterIsInstance() .associate { it.extension.pkgName to it.extension } @@ -121,7 +121,7 @@ class ExtensionManager( } /** - * Finds the available extensions in the [api] and updates [_availableExtensionsMapFlow]. + * Finds the available extensions in the [api] and updates [availableExtensionMapFlow]. */ suspend fun findAvailableExtensions() { val extensions: List = try { @@ -134,7 +134,7 @@ class ExtensionManager( enableAdditionalSubLanguages(extensions) - _availableExtensionsMapFlow.value = extensions.associateBy { it.pkgName } + availableExtensionMapFlow.value = extensions.associateBy { it.pkgName } updatedInstalledExtensionsStatuses(extensions) setupAvailableExtensionsSourcesDataMap(extensions) } @@ -180,7 +180,7 @@ class ExtensionManager( return } - val installedExtensionsMap = _installedExtensionsMapFlow.value.toMutableMap() + val installedExtensionsMap = installedExtensionMapFlow.value.toMutableMap() var changed = false for ((pkgName, extension) in installedExtensionsMap) { val availableExt = availableExtensions.find { it.pkgName == pkgName } @@ -204,7 +204,7 @@ class ExtensionManager( } } if (changed) { - _installedExtensionsMapFlow.value = installedExtensionsMap + installedExtensionMapFlow.value = installedExtensionsMap } updatePendingUpdatesCount() } @@ -228,7 +228,7 @@ class ExtensionManager( * @param extension The extension to be updated. */ fun updateExtension(extension: Extension.Installed): Flow { - val availableExt = _availableExtensionsMapFlow.value[extension.pkgName] ?: return emptyFlow() + val availableExt = availableExtensionMapFlow.value[extension.pkgName] ?: return emptyFlow() return installExtension(availableExt) } @@ -265,11 +265,11 @@ class ExtensionManager( * @param extension the extension to trust */ suspend fun trust(extension: Extension.Untrusted) { - _untrustedExtensionsMapFlow.value[extension.pkgName] ?: return + untrustedExtensionMapFlow.value[extension.pkgName] ?: return trustExtension.trust(extension.pkgName, extension.versionCode, extension.signatureHash) - _untrustedExtensionsMapFlow.value -= extension.pkgName + untrustedExtensionMapFlow.value -= extension.pkgName ExtensionLoader.loadExtensionFromPkgName(context, extension.pkgName) .let { it as? LoadResult.Success } @@ -282,7 +282,7 @@ class ExtensionManager( * @param extension The extension to be registered. */ private fun registerNewExtension(extension: Extension.Installed) { - _installedExtensionsMapFlow.value += extension + installedExtensionMapFlow.value += extension } /** @@ -292,7 +292,7 @@ class ExtensionManager( * @param extension The extension to be registered. */ private fun registerUpdatedExtension(extension: Extension.Installed) { - _installedExtensionsMapFlow.value += extension + installedExtensionMapFlow.value += extension } /** @@ -302,8 +302,8 @@ class ExtensionManager( * @param pkgName The package name of the uninstalled application. */ private fun unregisterExtension(pkgName: String) { - _installedExtensionsMapFlow.value -= pkgName - _untrustedExtensionsMapFlow.value -= pkgName + installedExtensionMapFlow.value -= pkgName + untrustedExtensionMapFlow.value -= pkgName } /** @@ -322,8 +322,8 @@ class ExtensionManager( } override fun onExtensionUntrusted(extension: Extension.Untrusted) { - _installedExtensionsMapFlow.value -= extension.pkgName - _untrustedExtensionsMapFlow.value += extension + installedExtensionMapFlow.value -= extension.pkgName + untrustedExtensionMapFlow.value += extension updatePendingUpdatesCount() } @@ -347,14 +347,14 @@ class ExtensionManager( private fun Extension.Installed.updateExists(availableExtension: Extension.Available? = null): Boolean { val availableExt = availableExtension - ?: _availableExtensionsMapFlow.value[pkgName] + ?: availableExtensionMapFlow.value[pkgName] ?: return false return (availableExt.versionCode > versionCode || availableExt.libVersion > libVersion) } private fun updatePendingUpdatesCount() { - val pendingUpdateCount = _installedExtensionsMapFlow.value.values.count { it.hasUpdate } + val pendingUpdateCount = installedExtensionMapFlow.value.values.count { it.hasUpdate } preferences.extensionUpdatesCount().set(pendingUpdateCount) if (pendingUpdateCount == 0) { ExtensionUpdateNotifier(context).dismiss() diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/model/InstallStep.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/model/InstallStep.kt index d1049689e..cd9b40fad 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/model/InstallStep.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/model/InstallStep.kt @@ -1,7 +1,13 @@ package eu.kanade.tachiyomi.extension.model enum class InstallStep { - Idle, Pending, Downloading, Installing, Installed, Error; + Idle, + Pending, + Downloading, + Installing, + Installed, + Error, + ; fun isCompleted(): Boolean { return this == Installed || this == Error || this == Idle diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/delegate/SecureActivityDelegate.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/delegate/SecureActivityDelegate.kt index c3b94d639..20189be6d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/base/delegate/SecureActivityDelegate.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/base/delegate/SecureActivityDelegate.kt @@ -97,7 +97,7 @@ class SecureActivityDelegateImpl : SecureActivityDelegate, DefaultLifecycleObser val incognitoModeFlow = preferences.incognitoMode().changes() combine(secureScreenFlow, incognitoModeFlow) { secureScreen, incognitoMode -> secureScreen == SecurityPreferences.SecureScreenMode.ALWAYS || - secureScreen == SecurityPreferences.SecureScreenMode.INCOGNITO && incognitoMode + (secureScreen == SecurityPreferences.SecureScreenMode.INCOGNITO && incognitoMode) } .onEach(activity.window::setSecureScreen) .launchIn(activity.lifecycleScope) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionsScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionsScreenModel.kt index feb69c5ce..861c28ff6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionsScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionsScreenModel.kt @@ -41,7 +41,7 @@ class ExtensionsScreenModel( private val getExtensions: GetExtensionsByType = Injekt.get(), ) : StateScreenModel(State()) { - private var _currentDownloads = MutableStateFlow>(hashMapOf()) + private val currentDownloads = MutableStateFlow>(hashMapOf()) init { val context = Injekt.get() @@ -62,14 +62,20 @@ class ExtensionsScreenModel( it.name.contains(input, ignoreCase = true) || it.baseUrl.contains(input, ignoreCase = true) || it.id == input.toLongOrNull() - } || extension.name.contains(input, ignoreCase = true) + } || + extension.name.contains(input, ignoreCase = true) } is Extension.Installed -> { extension.sources.any { it.name.contains(input, ignoreCase = true) || it.id == input.toLongOrNull() || - if (it is HttpSource) { it.baseUrl.contains(input, ignoreCase = true) } else false - } || extension.name.contains(input, ignoreCase = true) + if (it is HttpSource) { + it.baseUrl.contains(input, ignoreCase = true) + } else { + false + } + } || + extension.name.contains(input, ignoreCase = true) } is Extension.Untrusted -> extension.name.contains(input, ignoreCase = true) } @@ -80,7 +86,7 @@ class ExtensionsScreenModel( screenModelScope.launchIO { combine( state.map { it.searchQuery }.distinctUntilChanged().debounce(SEARCH_DEBOUNCE_MILLIS), - _currentDownloads, + currentDownloads, getExtensions.subscribe(), ) { query, downloads, (_updates, _installed, _available, _untrusted) -> val searchQuery = query ?: "" @@ -166,11 +172,11 @@ class ExtensionsScreenModel( } private fun addDownloadState(extension: Extension, installStep: InstallStep) { - _currentDownloads.update { it + Pair(extension.pkgName, installStep) } + currentDownloads.update { it + Pair(extension.pkgName, installStep) } } private fun removeDownloadState(extension: Extension) { - _currentDownloads.update { it - extension.pkgName } + currentDownloads.update { it - extension.pkgName } } private suspend fun Flow.collectToInstallUpdate(extension: Extension) = diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/home/HomeScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/home/HomeScreen.kt index ff2cb7075..ac708ec2f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/home/HomeScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/home/HomeScreen.kt @@ -66,8 +66,8 @@ object HomeScreen : Screen() { private val openTabEvent = Channel() private val showBottomNavEvent = Channel() - private const val TabFadeDuration = 200 - private const val TabNavigatorKey = "HomeTabs" + private const val TAB_FADE_DURATION = 200 + private const val TAB_NAVIGATOR_KEY = "HomeTabs" private val tabs = listOf( LibraryTab, @@ -82,7 +82,7 @@ object HomeScreen : Screen() { val navigator = LocalNavigator.currentOrThrow TabNavigator( tab = LibraryTab, - key = TabNavigatorKey, + key = TAB_NAVIGATOR_KEY, ) { tabNavigator -> // Provide usable navigator to content screen CompositionLocalProvider(LocalNavigator provides navigator) { @@ -124,8 +124,11 @@ object HomeScreen : Screen() { AnimatedContent( targetState = tabNavigator.current, transitionSpec = { - materialFadeThroughIn(initialScale = 1f, durationMillis = TabFadeDuration) togetherWith - materialFadeThroughOut(durationMillis = TabFadeDuration) + materialFadeThroughIn( + initialScale = 1f, + durationMillis = TAB_FADE_DURATION, + ) togetherWith + materialFadeThroughOut(durationMillis = TAB_FADE_DURATION) }, label = "tabContent", ) { 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 286f58239..59121bcaf 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 @@ -258,7 +258,7 @@ class LibraryScreenModel( private fun LibraryMap.applySort( // Map> trackMap: Map>, - loggedInTrackerIds: Set + loggedInTrackerIds: Set, ): LibraryMap { val sortAlphabetically: (LibraryItem, LibraryItem) -> Int = { i1, i2 -> i1.libraryManga.manga.title.lowercase().compareToWithCollator(i2.libraryManga.manga.title.lowercase()) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsScreenModel.kt index bd5867797..388f516ce 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsScreenModel.kt @@ -32,7 +32,7 @@ class LibrarySettingsScreenModel( .stateIn( scope = screenModelScope, started = SharingStarted.WhileSubscribed(5.seconds.inWholeMilliseconds), - initialValue = trackerManager.loggedInTrackers() + initialValue = trackerManager.loggedInTrackers(), ) fun toggleFilter(preference: (LibraryPreferences) -> Preference) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/more/MoreTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/more/MoreTab.kt index 7e4ac0932..0279a6975 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/more/MoreTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/more/MoreTab.kt @@ -87,8 +87,8 @@ private class MoreScreenModel( var downloadedOnly by preferences.downloadedOnly().asState(screenModelScope) var incognitoMode by preferences.incognitoMode().asState(screenModelScope) - private var _state: MutableStateFlow = MutableStateFlow(DownloadQueueState.Stopped) - val downloadQueueState: StateFlow = _state.asStateFlow() + private var _downloadQueueState: MutableStateFlow = MutableStateFlow(DownloadQueueState.Stopped) + val downloadQueueState: StateFlow = _downloadQueueState.asStateFlow() init { // Handle running/paused status change and queue progress updating @@ -99,7 +99,7 @@ private class MoreScreenModel( ) { isRunning, downloadQueue -> Pair(isRunning, downloadQueue.size) } .collectLatest { (isDownloading, downloadQueueSize) -> val pendingDownloadExists = downloadQueueSize != 0 - _state.value = when { + _downloadQueueState.value = when { !pendingDownloadExists -> DownloadQueueState.Stopped !isDownloading -> DownloadQueueState.Paused(downloadQueueSize) else -> DownloadQueueState.Downloading(downloadQueueSize) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt index 259b45883..f633bdbad 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt @@ -165,13 +165,19 @@ class ReaderViewModel @JvmOverloads constructor( ( manga.downloadedFilterRaw == Manga.CHAPTER_SHOW_DOWNLOADED && !downloadManager.isChapterDownloaded( - it.name, it.scanlator, manga.title, manga.source, + it.name, + it.scanlator, + manga.title, + manga.source, ) ) || ( manga.downloadedFilterRaw == Manga.CHAPTER_SHOW_NOT_DOWNLOADED && downloadManager.isChapterDownloaded( - it.name, it.scanlator, manga.title, manga.source, + it.name, + it.scanlator, + manga.title, + manga.source, ) ) || (manga.bookmarkedFilterRaw == Manga.CHAPTER_SHOW_BOOKMARKED && !it.bookmark) || diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderPreferences.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderPreferences.kt index 57def3c12..5cd742ad1 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderPreferences.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderPreferences.kt @@ -142,7 +142,7 @@ class ReaderPreferences( enum class FlashColor { BLACK, WHITE, - WHITE_BLACK + WHITE_BLACK, } enum class TappingInvertMode( diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderPageImageView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderPageImageView.kt index 61e78c161..89d0b2e6e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderPageImageView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderPageImageView.kt @@ -404,7 +404,9 @@ open class ReaderPageImageView @JvmOverloads constructor( ) enum class ZoomStartPosition { - LEFT, CENTER, RIGHT + LEFT, + CENTER, + RIGHT, } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderTransitionView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderTransitionView.kt index 737b3633b..8918cdf58 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderTransitionView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderTransitionView.kt @@ -32,15 +32,16 @@ class ReaderTransitionView @JvmOverloads constructor(context: Context, attrs: At Data( transition = transition, currChapterDownloaded = transition.from.pageLoader?.isLocal == true, - goingToChapterDownloaded = manga.isLocal() || transition.to?.chapter?.let { goingToChapter -> - downloadManager.isChapterDownloaded( - chapterName = goingToChapter.name, - chapterScanlator = goingToChapter.scanlator, - mangaTitle = manga.title, - sourceId = manga.source, - skipCache = true, - ) - } ?: false, + goingToChapterDownloaded = manga.isLocal() || + transition.to?.chapter?.let { goingToChapter -> + downloadManager.isChapterDownloaded( + chapterName = goingToChapter.name, + chapterScanlator = goingToChapter.scanlator, + mangaTitle = manga.title, + sourceId = manga.source, + skipCache = true, + ) + } ?: false, ) } else { null diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewerAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewerAdapter.kt index 5ff4ecaae..7bb89a3e9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewerAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewerAdapter.kt @@ -92,7 +92,9 @@ class PagerViewerAdapter(private val viewer: PagerViewer) : ViewPagerAdapter() { // Add next chapter transition and pages. nextTransition = ChapterTransition.Next(chapters.currChapter, chapters.nextChapter) .also { - if (nextHasMissingChapters || forceTransition || + if ( + nextHasMissingChapters || + forceTransition || chapters.nextChapter?.state !is ReaderChapter.State.Loaded ) { newItems.add(it) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonConfig.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonConfig.kt index f55478862..164c4939d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonConfig.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonConfig.kt @@ -82,7 +82,7 @@ class WebtoonConfig( readerPreferences.webtoonDisableZoomOut() .register( { zoomOutDisabled = it }, - { zoomPropertyChangedListener?.invoke(it) } + { zoomPropertyChangedListener?.invoke(it) }, ) readerPreferences.webtoonDoubleTapZoomEnabled() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonRecyclerView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonRecyclerView.kt index fe232fe87..95cef7345 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonRecyclerView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonRecyclerView.kt @@ -182,7 +182,11 @@ class WebtoonRecyclerView @JvmOverloads constructor( setScaleRate(currentScale) - layoutParams.height = if (currentScale < 1) { (originalHeight / currentScale).toInt() } else { originalHeight } + layoutParams.height = if (currentScale < 1) { + (originalHeight / currentScale).toInt() + } else { + originalHeight + } halfHeight = layoutParams.height / 2 if (currentScale != DEFAULT_RATE) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt index 3445f76c1..9d2dac482 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt @@ -79,7 +79,7 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr .threshold init { - recycler.setItemViewCacheSize(RecyclerViewCacheSize) + recycler.setItemViewCacheSize(RECYCLER_VIEW_CACHE_SIZE) recycler.isVisible = false // Don't let the recycler layout yet recycler.layoutParams = ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT) recycler.isFocusable = false @@ -362,4 +362,4 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr } // Double the cache size to reduce rebinds/recycles incurred by the extra layout space on scroll direction changes -private const val RecyclerViewCacheSize = 4 +private const val RECYCLER_VIEW_CACHE_SIZE = 4 diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/system/ChildFirstPathClassLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/util/system/ChildFirstPathClassLoader.kt index b63dfd032..0823e765d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/system/ChildFirstPathClassLoader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/system/ChildFirstPathClassLoader.kt @@ -15,7 +15,7 @@ import java.util.Enumeration class ChildFirstPathClassLoader( dexPath: String, librarySearchPath: String?, - parent: ClassLoader + parent: ClassLoader, ) : PathClassLoader(dexPath, librarySearchPath, parent) { private val systemClassLoader: ClassLoader? = getSystemClassLoader() diff --git a/app/src/main/java/mihon/core/migration/MigrationJobFactory.kt b/app/src/main/java/mihon/core/migration/MigrationJobFactory.kt index c452707d5..cfb8db2b6 100644 --- a/app/src/main/java/mihon/core/migration/MigrationJobFactory.kt +++ b/app/src/main/java/mihon/core/migration/MigrationJobFactory.kt @@ -9,20 +9,24 @@ import tachiyomi.core.common.util.system.logcat class MigrationJobFactory( private val migrationContext: MigrationContext, - private val scope: CoroutineScope + private val scope: CoroutineScope, ) { fun create(migrations: List): Deferred = with(scope) { return migrations.sortedBy { it.version } .fold(CompletableDeferred(true)) { acc: Deferred, migration: Migration -> if (!migrationContext.dryrun) { - logcat { "Running migration: { name = ${migration::class.simpleName}, version = ${migration.version} }" } + logcat { + "Running migration: { name = ${migration::class.simpleName}, version = ${migration.version} }" + } async(start = CoroutineStart.UNDISPATCHED) { val prev = acc.await() migration(migrationContext) || prev } } else { - logcat { "(Dry-run) Running migration: { name = ${migration::class.simpleName}, version = ${migration.version} }" } + logcat { + "(Dry-run) Running migration: { name = ${migration::class.simpleName}, version = ${migration.version} }" + } CompletableDeferred(true) } } diff --git a/app/src/main/java/mihon/core/migration/MigrationStrategy.kt b/app/src/main/java/mihon/core/migration/MigrationStrategy.kt index 9fd5f4f91..8033ebc6d 100644 --- a/app/src/main/java/mihon/core/migration/MigrationStrategy.kt +++ b/app/src/main/java/mihon/core/migration/MigrationStrategy.kt @@ -12,7 +12,7 @@ interface MigrationStrategy { class DefaultMigrationStrategy( private val migrationJobFactory: MigrationJobFactory, private val migrationCompletedListener: MigrationCompletedListener, - private val scope: CoroutineScope + private val scope: CoroutineScope, ) : MigrationStrategy { override operator fun invoke(migrations: List): Deferred = with(scope) { @@ -46,7 +46,7 @@ class NoopMigrationStrategy(val state: Boolean) : MigrationStrategy { class VersionRangeMigrationStrategy( private val versions: IntRange, - private val strategy: DefaultMigrationStrategy + private val strategy: DefaultMigrationStrategy, ) : MigrationStrategy { override operator fun invoke(migrations: List): Deferred { diff --git a/app/src/main/java/mihon/core/migration/Migrator.kt b/app/src/main/java/mihon/core/migration/Migrator.kt index 2296aa074..c01a3873e 100644 --- a/app/src/main/java/mihon/core/migration/Migrator.kt +++ b/app/src/main/java/mihon/core/migration/Migrator.kt @@ -17,7 +17,7 @@ object Migrator { new: Int, migrations: List, dryrun: Boolean = false, - onMigrationComplete: () -> Unit + onMigrationComplete: () -> Unit, ) { val migrationContext = MigrationContext(dryrun) val migrationJobFactory = MigrationJobFactory(migrationContext, scope) diff --git a/app/src/main/java/mihon/feature/upcoming/components/calendar/Calendar.kt b/app/src/main/java/mihon/feature/upcoming/components/calendar/Calendar.kt index da511ddad..6b32c7f89 100644 --- a/app/src/main/java/mihon/feature/upcoming/components/calendar/Calendar.kt +++ b/app/src/main/java/mihon/feature/upcoming/components/calendar/Calendar.kt @@ -32,7 +32,7 @@ import java.time.temporal.WeekFields import java.util.Locale private val FontSize = 16.sp -private const val DaysOfWeek = 7 +private const val DAYS_OF_WEEK = 7 @Composable fun Calendar( @@ -54,7 +54,7 @@ fun Calendar( modifier = Modifier .fillMaxWidth() .padding(vertical = MaterialTheme.padding.small) - .padding(start = MaterialTheme.padding.medium) + .padding(start = MaterialTheme.padding.medium), ) CalendarGrid( selectedYearMonth = selectedYearMonth, @@ -72,8 +72,8 @@ private fun CalendarGrid( ) { val localeFirstDayOfWeek = WeekFields.of(Locale.getDefault()).firstDayOfWeek.value val weekDays = remember { - (0 until DaysOfWeek) - .map { DayOfWeek.of((localeFirstDayOfWeek - 1 + it) % DaysOfWeek + 1) } + (0 until DAYS_OF_WEEK) + .map { DayOfWeek.of((localeFirstDayOfWeek - 1 + it) % DAYS_OF_WEEK + 1) } .toImmutableList() } @@ -81,12 +81,12 @@ private fun CalendarGrid( val daysInMonth = selectedYearMonth.lengthOfMonth() VerticalGrid( - columns = SimpleGridCells.Fixed(DaysOfWeek), + columns = SimpleGridCells.Fixed(DAYS_OF_WEEK), modifier = if (isMediumWidthWindow() && !isExpandedWidthWindow()) { Modifier.widthIn(max = 360.dp) } else { Modifier - } + }, ) { weekDays.fastForEach { item -> Text( diff --git a/app/src/main/java/mihon/feature/upcoming/components/calendar/CalendarDay.kt b/app/src/main/java/mihon/feature/upcoming/components/calendar/CalendarDay.kt index 46ed355ab..3a8f3e6fb 100644 --- a/app/src/main/java/mihon/feature/upcoming/components/calendar/CalendarDay.kt +++ b/app/src/main/java/mihon/feature/upcoming/components/calendar/CalendarDay.kt @@ -19,9 +19,10 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import tachiyomi.presentation.core.components.material.DISABLED_ALPHA import java.time.LocalDate -private const val MaxEvents = 3 +private const val MAX_EVENTS = 3 @Composable fun CalendarDay( @@ -39,7 +40,7 @@ fun CalendarDay( Modifier.border( border = BorderStroke( width = 1.dp, - color = MaterialTheme.colorScheme.onBackground + color = MaterialTheme.colorScheme.onBackground, ), shape = CircleShape, ) @@ -57,14 +58,14 @@ fun CalendarDay( textAlign = TextAlign.Center, fontSize = 16.sp, color = if (date.isBefore(today)) { - MaterialTheme.colorScheme.onBackground.copy(alpha = 0.38f) + MaterialTheme.colorScheme.onBackground.copy(alpha = DISABLED_ALPHA) } else { MaterialTheme.colorScheme.onBackground }, fontWeight = FontWeight.SemiBold, ) Row(Modifier.offset(y = 12.dp)) { - val size = events.coerceAtMost(MaxEvents) + val size = events.coerceAtMost(MAX_EVENTS) for (index in 0 until size) { CalendarIndicator( index = index, diff --git a/app/src/main/java/mihon/feature/upcoming/components/calendar/CalendarHeader.kt b/app/src/main/java/mihon/feature/upcoming/components/calendar/CalendarHeader.kt index 55498ebb9..f5dbf5c48 100644 --- a/app/src/main/java/mihon/feature/upcoming/components/calendar/CalendarHeader.kt +++ b/app/src/main/java/mihon/feature/upcoming/components/calendar/CalendarHeader.kt @@ -63,20 +63,20 @@ fun CalenderHeader( } } -private const val MonthYearChangeAnimationDuration = 200 +private const val MONTH_YEAR_CHANGE_ANIMATION_DURATION = 200 private fun AnimatedContentTransitionScope.getAnimation(): ContentTransform { val movingForward = targetState > initialState val enterTransition = slideInVertically( - animationSpec = tween(durationMillis = MonthYearChangeAnimationDuration), + animationSpec = tween(durationMillis = MONTH_YEAR_CHANGE_ANIMATION_DURATION), ) { height -> if (movingForward) height else -height } + fadeIn( - animationSpec = tween(durationMillis = MonthYearChangeAnimationDuration), + animationSpec = tween(durationMillis = MONTH_YEAR_CHANGE_ANIMATION_DURATION), ) val exitTransition = slideOutVertically( - animationSpec = tween(durationMillis = MonthYearChangeAnimationDuration), + animationSpec = tween(durationMillis = MONTH_YEAR_CHANGE_ANIMATION_DURATION), ) { height -> if (movingForward) -height else height } + fadeOut( - animationSpec = tween(durationMillis = MonthYearChangeAnimationDuration), + animationSpec = tween(durationMillis = MONTH_YEAR_CHANGE_ANIMATION_DURATION), ) return (enterTransition togetherWith exitTransition) .using(SizeTransform(clip = false)) diff --git a/app/src/main/java/mihon/feature/upcoming/components/calendar/CalendarIndicator.kt b/app/src/main/java/mihon/feature/upcoming/components/calendar/CalendarIndicator.kt index 9aaca69de..f9e223107 100644 --- a/app/src/main/java/mihon/feature/upcoming/components/calendar/CalendarIndicator.kt +++ b/app/src/main/java/mihon/feature/upcoming/components/calendar/CalendarIndicator.kt @@ -12,8 +12,8 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp -private const val IndicatorScale = 12 -private const val IndicatorAlphaMultiplier = 0.3f +private const val INDICATOR_SCALE = 12 +private const val INDICATOR_ALPHA_MULTIPLIER = 0.3f @Composable fun CalendarIndicator( @@ -26,7 +26,7 @@ fun CalendarIndicator( modifier = modifier .padding(horizontal = 1.dp) .clip(shape = CircleShape) - .background(color = color.copy(alpha = (index + 1) * IndicatorAlphaMultiplier)) - .size(size = size.div(IndicatorScale)), + .background(color = color.copy(alpha = (index + 1) * INDICATOR_ALPHA_MULTIPLIER)) + .size(size = size.div(INDICATOR_SCALE)), ) } diff --git a/app/src/main/res/drawable/ic_glasses_24dp.xml b/app/src/main/res/drawable/ic_glasses_24dp.xml index 581a59914..572c2f06d 100644 --- a/app/src/main/res/drawable/ic_glasses_24dp.xml +++ b/app/src/main/res/drawable/ic_glasses_24dp.xml @@ -6,4 +6,4 @@ - \ No newline at end of file + diff --git a/app/src/main/res/drawable/material_popup_background.xml b/app/src/main/res/drawable/material_popup_background.xml index 09987c415..29bb97167 100644 --- a/app/src/main/res/drawable/material_popup_background.xml +++ b/app/src/main/res/drawable/material_popup_background.xml @@ -12,4 +12,4 @@ - \ No newline at end of file + diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index d0fb6fca7..263e7610b 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -445,7 +445,7 @@ @color/nord_surfaceContainerLow @color/nord_surfaceContainerLowest - +