Compare commits

..

13 Commits

Author SHA1 Message Date
AntsyLich
412815af06 Revert "Fix reader tap zones triggering after scrolling was stopped by the user" (#2670) 2025-11-07 13:07:14 +00:00
Weblate (bot)
f7fb68692a Translations update from Hosted Weblate (#2656)
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/cs/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/cs/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/de/
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/ru/
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: Doministo <doministo@seznam.cz>
Co-authored-by: Lyfja <45209212+lyfja@users.noreply.github.com>
Co-authored-by: Nataniel Dika Kurniawan <hikawaart2@gmail.com>
Co-authored-by: TheKingTermux <50316075+TheKingTermux@users.noreply.github.com>
Co-authored-by: ZerOriSama <godarms2010@live.com>
Co-authored-by: amigo browser <juniperforest1@proton.me>
2025-11-07 19:03:52 +06:00
AntsyLich
aa300cb53e Fix extra padding appearing in reader after user interactions (#2669) 2025-11-07 10:00:59 +00:00
Trevor Paley
855eea2ada Improve WebView multi-window UX (#2662)
- Navigation history for lower windows is preserved when a popup is opened
- Back gesture will close a popup window rather than the entire WebView activity when there is no previous page
- The leftmost close button closes the entire activity as before
- When a popup window is shown, a new button appears to close just that window
2025-11-07 15:26:04 +06:00
Mend Renovate
f4703ed83a Update dependency androidx.core:core-splashscreen to v1.2.0 (#2661) 2025-11-07 15:22:41 +06:00
NGB-Was-Taken
506d51a007 Fix flaky migration tests (#2663) 2025-11-07 15:21:17 +06:00
NGB-Was-Taken
9f9155121c Upload test report as artifact on failure (#2664) 2025-11-07 15:20:32 +06:00
AntsyLich
282110ef21 Release v0.19.3 2025-11-04 13:05:40 +06:00
AntsyLich
ace387f8bf Revert "Update dependency androidx.compose:compose-bom to v2025.10.01 (#2522)"
This reverts commit e8bdf58530.
2025-11-04 13:05:23 +06:00
Weblate (bot)
5e428071c9 Translations update from Hosted Weblate (#2646)
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/nl/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/hr/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/id/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/jv/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ms/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/tr/
Translation: Mihon/Mihon
Translation: Mihon/Mihon Plurals

Co-authored-by: Frosted <frosted@users.noreply.hosted.weblate.org>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Nataniel Dika Kurniawan <hikawaart2@gmail.com>
Co-authored-by: Siebrenvde <siebren@siebrenvde.dev>
2025-11-04 13:04:46 +06:00
AntsyLich
0acd80dd95 Fix long strip reader not scrolling on consecutive taps (#2650) 2025-11-04 06:46:48 +00:00
bapeey
bdb0ce4779 Fix WebView crash introduced in v0.19.2 (#2649) 2025-11-04 11:43:40 +06:00
Mend Renovate
e8bdf58530 Update dependency androidx.compose:compose-bom to v2025.10.01 (#2522) 2025-11-03 10:52:45 +06:00
25 changed files with 205 additions and 71 deletions

View File

@@ -30,7 +30,7 @@ body:
required: true required: true
- label: I have written a short but informative title. - label: I have written a short but informative title.
required: true required: true
- label: I have updated the app to version **[0.19.2](https://github.com/mihonapp/mihon/releases/latest)**. - label: I have updated the app to version **[0.19.3](https://github.com/mihonapp/mihon/releases/latest)**.
required: true required: true
- label: I will fill out all of the requested information in this form. - label: I will fill out all of the requested information in this form.
required: true required: true

View File

@@ -52,7 +52,7 @@ body:
label: Mihon version label: Mihon version
description: You can find your Mihon version in **More → About**. description: You can find your Mihon version in **More → About**.
placeholder: | placeholder: |
Example: "0.19.2" Example: "0.19.3"
validations: validations:
required: true required: true
@@ -95,7 +95,7 @@ body:
required: true required: true
- label: I have gone through the [FAQ](https://mihon.app/docs/faq/general) and [troubleshooting guide](https://mihon.app/docs/guides/troubleshooting/). - label: I have gone through the [FAQ](https://mihon.app/docs/faq/general) and [troubleshooting guide](https://mihon.app/docs/guides/troubleshooting/).
required: true required: true
- label: I have updated the app to version **[0.19.2](https://github.com/mihonapp/mihon/releases/latest)**. - label: I have updated the app to version **[0.19.3](https://github.com/mihonapp/mihon/releases/latest)**.
required: true required: true
- label: I have filled out all of the requested information in this form, including specific version numbers. - label: I have filled out all of the requested information in this form, including specific version numbers.
required: true required: true

View File

@@ -48,8 +48,16 @@ jobs:
run: ./gradlew assembleRelease -Pinclude-telemetry -Penable-updater run: ./gradlew assembleRelease -Pinclude-telemetry -Penable-updater
- name: Run unit tests - name: Run unit tests
id: unit_tests
run: ./gradlew testReleaseUnitTest run: ./gradlew testReleaseUnitTest
- name: Upload test report
if: steps.unit_tests.outcome == 'failure'
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: test-report-${{ github.sha }}
path: app/build/reports/tests/testReleaseUnitTest
- name: Upload APK - name: Upload APK
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with: with:

View File

@@ -10,7 +10,17 @@ The format is a modified version of [Keep a Changelog](https://keepachangelog.co
- `Fixed` - for any bug fixes. - `Fixed` - for any bug fixes.
- `Other` - for technical stuff. - `Other` - for technical stuff.
## [Unreleased] ## [v0.19.3] - 2025-11-07
### Improved
- Improved various aspects of the WebView multi window support ([@TheUnlocked](https://github.com/TheUnlocked)) ([#2662](https://github.com/mihonapp/mihon/pull/2662))
### Removed
- Revert "Fix reader tap zones triggering after scrolling was stopped by the user" due to introduction of regression ([@AntsyLich](https://github.com/AntsyLich)) ([#2670](https://github.com/mihonapp/mihon/pull/2670))
### Fixed
- Fix WebView crash introduced in 0.19.2 ([@bapeey](https://github.com/bapeey)) ([#2649](https://github.com/mihonapp/mihon/pull/2649))
- Fix extra padding appearing in reader after user interactions ([@AntsyLich](https://github.com/AntsyLich)) ([#2669](https://github.com/mihonapp/mihon/pull/2669))
- Fix long strip reader not scrolling on consecutive taps ([@AntsyLich](https://github.com/AntsyLich)) ([#2670](https://github.com/mihonapp/mihon/pull/2670))
## [v0.19.2] - 2025-11-02 ## [v0.19.2] - 2025-11-02
### Added ### Added
@@ -433,7 +443,8 @@ The format is a modified version of [Keep a Changelog](https://keepachangelog.co
- Branding to Mihon ([@AntsyLich](https://github.com/AntsyLich)) - Branding to Mihon ([@AntsyLich](https://github.com/AntsyLich))
- Minimum supported Android version to 8 ([@AntsyLich](https://github.com/AntsyLich)) ([`dfb3091`](https://github.com/mihonapp/mihon/commit/dfb3091e380dda3e9bfb64bf5c9a685cf3a03d0e)) - Minimum supported Android version to 8 ([@AntsyLich](https://github.com/AntsyLich)) ([`dfb3091`](https://github.com/mihonapp/mihon/commit/dfb3091e380dda3e9bfb64bf5c9a685cf3a03d0e))
[unreleased]: https://github.com/mihonapp/mihon/compare/v0.19.2...main [unreleased]: https://github.com/mihonapp/mihon/compare/v0.19.3...main
[v0.19.3]: https://github.com/mihonapp/mihon/compare/v0.19.2...v0.19.3
[v0.19.2]: https://github.com/mihonapp/mihon/compare/v0.19.1...v0.19.2 [v0.19.2]: https://github.com/mihonapp/mihon/compare/v0.19.1...v0.19.2
[v0.19.1]: https://github.com/mihonapp/mihon/compare/v0.19.0...v0.19.1 [v0.19.1]: https://github.com/mihonapp/mihon/compare/v0.19.0...v0.19.1
[v0.19.0]: https://github.com/mihonapp/mihon/compare/v0.18.0...v0.19.0 [v0.19.0]: https://github.com/mihonapp/mihon/compare/v0.18.0...v0.19.0

View File

@@ -26,8 +26,8 @@ android {
defaultConfig { defaultConfig {
applicationId = "app.mihon" applicationId = "app.mihon"
versionCode = 15 versionCode = 16
versionName = "0.19.2" versionName = "0.19.3"
buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"") buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"")
buildConfigField("String", "COMMIT_SHA", "\"${getGitSha()}\"") buildConfigField("String", "COMMIT_SHA", "\"${getGitSha()}\"")

View File

@@ -5,6 +5,7 @@ import android.graphics.Bitmap
import android.os.Message import android.os.Message
import android.webkit.WebResourceRequest import android.webkit.WebResourceRequest
import android.webkit.WebView import android.webkit.WebView
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@@ -28,7 +29,9 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import cafe.adriel.voyager.core.stack.mutableStateStackOf import cafe.adriel.voyager.core.stack.mutableStateStackOf
import com.kevinnzou.web.AccompanistWebChromeClient import com.kevinnzou.web.AccompanistWebChromeClient
@@ -36,12 +39,13 @@ import com.kevinnzou.web.AccompanistWebViewClient
import com.kevinnzou.web.LoadingState import com.kevinnzou.web.LoadingState
import com.kevinnzou.web.WebContent import com.kevinnzou.web.WebContent
import com.kevinnzou.web.WebView import com.kevinnzou.web.WebView
import com.kevinnzou.web.WebViewNavigator
import com.kevinnzou.web.WebViewState import com.kevinnzou.web.WebViewState
import com.kevinnzou.web.rememberWebViewNavigator
import eu.kanade.presentation.components.AppBar import eu.kanade.presentation.components.AppBar
import eu.kanade.presentation.components.AppBarActions import eu.kanade.presentation.components.AppBarActions
import eu.kanade.presentation.components.WarningBanner import eu.kanade.presentation.components.WarningBanner
import eu.kanade.tachiyomi.BuildConfig import eu.kanade.tachiyomi.BuildConfig
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.util.system.getHtml import eu.kanade.tachiyomi.util.system.getHtml
import eu.kanade.tachiyomi.util.system.setDefaultSettings import eu.kanade.tachiyomi.util.system.setDefaultSettings
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
@@ -50,13 +54,13 @@ import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.Scaffold import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.i18n.stringResource import tachiyomi.presentation.core.i18n.stringResource
class WebViewWindow(webContent: WebContent) { class WebViewWindow(webContent: WebContent, val navigator: WebViewNavigator) {
var state by mutableStateOf(WebViewState(webContent)) var state by mutableStateOf(WebViewState(webContent))
var popupMessage: Message? = null var popupMessage: Message? = null
private set private set
var webView: WebView? = null var webView: WebView? = null
constructor(popupMessage: Message) : this(WebContent.NavigatorOnly) { constructor(popupMessage: Message, navigator: WebViewNavigator) : this(WebContent.NavigatorOnly, navigator) {
this.popupMessage = popupMessage this.popupMessage = popupMessage
} }
} }
@@ -72,27 +76,20 @@ fun WebViewScreenContent(
headers: Map<String, String> = emptyMap(), headers: Map<String, String> = emptyMap(),
onUrlChange: (String) -> Unit = {}, onUrlChange: (String) -> Unit = {},
) { ) {
val coroutineScope = rememberCoroutineScope()
val windowStack = remember { val windowStack = remember {
mutableStateStackOf( mutableStateStackOf(
WebViewWindow( WebViewWindow(
WebContent.Url(url = url, additionalHttpHeaders = headers), WebContent.Url(url = url, additionalHttpHeaders = headers),
WebViewNavigator(coroutineScope),
), ),
) )
} }
val currentWindow = windowStack.lastItemOrNull!! val currentWindow = windowStack.lastItemOrNull!!
val navigator = currentWindow.navigator
val popState: (() -> Unit) = remember {
{
if (windowStack.size == 1) {
onNavigateUp()
} else {
windowStack.pop()
}
}
}
val navigator = rememberWebViewNavigator()
val uriHandler = LocalUriHandler.current val uriHandler = LocalUriHandler.current
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
@@ -133,21 +130,20 @@ fun WebViewScreenContent(
view: WebView?, view: WebView?,
request: WebResourceRequest?, request: WebResourceRequest?,
): Boolean { ): Boolean {
request?.let { val url = request?.url?.toString() ?: return false
// Don't attempt to open blobs as webpages
if (it.url.toString().startsWith("blob:http")) {
return false
}
// Ignore intents urls // Ignore intents urls
if (it.url.toString().startsWith("intent://")) { if (url.startsWith("intent://")) return true
// Only open valid web urls
if (url.startsWith("http") || url.startsWith("https")) {
if (url != view?.url) {
view?.loadUrl(url, headers)
return true return true
} }
// Continue with request, but with custom headers
view?.loadUrl(it.url.toString(), headers)
} }
return super.shouldOverrideUrlLoading(view, request)
return false
} }
} }
} }
@@ -162,7 +158,7 @@ fun WebViewScreenContent(
): Boolean { ): Boolean {
// if it wasn't initiated by a user gesture, we should ignore it like a normal browser would // if it wasn't initiated by a user gesture, we should ignore it like a normal browser would
if (isUserGesture) { if (isUserGesture) {
windowStack.push(WebViewWindow(resultMsg)) windowStack.push(WebViewWindow(resultMsg, WebViewNavigator(coroutineScope)))
return true return true
} }
return false return false
@@ -177,6 +173,18 @@ fun WebViewScreenContent(
return webView return webView
} }
val popState = remember<() -> Unit> {
{
if (windowStack.size == 1) {
onNavigateUp()
} else {
windowStack.pop()
}
}
}
BackHandler(windowStack.size > 1, popState)
Scaffold( Scaffold(
topBar = { topBar = {
Box { Box {
@@ -184,7 +192,7 @@ fun WebViewScreenContent(
AppBar( AppBar(
title = currentWindow.state.pageTitle ?: initialTitle, title = currentWindow.state.pageTitle ?: initialTitle,
subtitle = currentUrl, subtitle = currentUrl,
navigateUp = popState, navigateUp = onNavigateUp,
navigationIcon = Icons.Outlined.Close, navigationIcon = Icons.Outlined.Close,
actions = { actions = {
AppBarActions( AppBarActions(
@@ -225,7 +233,18 @@ fun WebViewScreenContent(
title = stringResource(MR.strings.pref_clear_cookies), title = stringResource(MR.strings.pref_clear_cookies),
onClick = { onClearCookies(currentUrl) }, onClick = { onClearCookies(currentUrl) },
), ),
), ).builder().apply {
if (windowStack.size > 1) {
add(
0,
AppBar.Action(
title = stringResource(MR.strings.action_webview_close_tab),
icon = ImageVector.vectorResource(R.drawable.ic_tab_close_24px),
onClick = popState,
),
)
}
}.build(),
) )
}, },
) )
@@ -298,7 +317,7 @@ fun WebViewScreenContent(
// The composable is being disposed but the WebView object is not. // The composable is being disposed but the WebView object is not.
// When the WebView element is recomposed, we will want the WebView to resume from its state // When the WebView element is recomposed, we will want the WebView to resume from its state
// before it was unmounted, we won't want it to reset back to its original target. // before it was unmounted, we won't want it to reset back to its original target.
window.state = WebViewState(WebContent.NavigatorOnly) window.state.content = WebContent.NavigatorOnly
} }
}, },
client = webClient, client = webClient,

View File

@@ -777,7 +777,8 @@ class ReaderActivity : BaseActivity() {
* Updates viewer inset depending on fullscreen reader preferences. * Updates viewer inset depending on fullscreen reader preferences.
*/ */
private fun updateViewerInset(fullscreen: Boolean, drawUnderCutout: Boolean) { private fun updateViewerInset(fullscreen: Boolean, drawUnderCutout: Boolean) {
val view = viewModel.state.value.viewer?.getView() ?: return if (!::binding.isInitialized) return
val view = binding.viewerContainer
view.applyInsetsPadding(ViewCompat.getRootWindowInsets(view), fullscreen, drawUnderCutout) view.applyInsetsPadding(ViewCompat.getRootWindowInsets(view), fullscreen, drawUnderCutout)
ViewCompat.setOnApplyWindowInsetsListener(view) { view, windowInsets -> ViewCompat.setOnApplyWindowInsetsListener(view) { view, windowInsets ->

View File

@@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.ui.reader.viewer.webtoon
import android.animation.AnimatorSet import android.animation.AnimatorSet
import android.animation.ValueAnimator import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet
import android.view.HapticFeedbackConstants import android.view.HapticFeedbackConstants
@@ -35,10 +34,6 @@ class WebtoonRecyclerView @JvmOverloads constructor(
private var firstVisibleItemPosition = 0 private var firstVisibleItemPosition = 0
private var lastVisibleItemPosition = 0 private var lastVisibleItemPosition = 0
private var currentScale = DEFAULT_RATE private var currentScale = DEFAULT_RATE
private var isScrolling = false
private var hasTappedWhileScrolling = false
var zoomOutDisabled = false var zoomOutDisabled = false
set(value) { set(value) {
field = value field = value
@@ -67,11 +62,7 @@ class WebtoonRecyclerView @JvmOverloads constructor(
super.onMeasure(widthSpec, heightSpec) super.onMeasure(widthSpec, heightSpec)
} }
@SuppressLint("ClickableViewAccessibility")
override fun onTouchEvent(e: MotionEvent): Boolean { override fun onTouchEvent(e: MotionEvent): Boolean {
if (e.actionMasked == MotionEvent.ACTION_DOWN) {
hasTappedWhileScrolling = isScrolling
}
detector.onTouchEvent(e) detector.onTouchEvent(e)
return super.onTouchEvent(e) return super.onTouchEvent(e)
} }
@@ -91,7 +82,6 @@ class WebtoonRecyclerView @JvmOverloads constructor(
val totalItemCount = layoutManager?.itemCount ?: 0 val totalItemCount = layoutManager?.itemCount ?: 0
atLastPosition = visibleItemCount > 0 && lastVisibleItemPosition == totalItemCount - 1 atLastPosition = visibleItemCount > 0 && lastVisibleItemPosition == totalItemCount - 1
atFirstPosition = firstVisibleItemPosition == 0 atFirstPosition = firstVisibleItemPosition == 0
isScrolling = state != SCROLL_STATE_IDLE
} }
private fun getPositionX(positionX: Float): Float { private fun getPositionX(positionX: Float): Float {
@@ -225,9 +215,7 @@ class WebtoonRecyclerView @JvmOverloads constructor(
inner class GestureListener : GestureDetectorWithLongTap.Listener() { inner class GestureListener : GestureDetectorWithLongTap.Listener() {
override fun onSingleTapConfirmed(ev: MotionEvent): Boolean { override fun onSingleTapConfirmed(ev: MotionEvent): Boolean {
if (!hasTappedWhileScrolling) { tapListener?.invoke(ev)
tapListener?.invoke(ev)
}
return false return false
} }

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M476,540L560,456L644,540L700,484L616,400L700,316L644,260L560,344L476,260L420,316L504,400L420,484L476,540ZM320,720Q287,720 263.5,696.5Q240,673 240,640L240,160Q240,127 263.5,103.5Q287,80 320,80L800,80Q833,80 856.5,103.5Q880,127 880,160L880,640Q880,673 856.5,696.5Q833,720 800,720L320,720ZM320,640L800,640Q800,640 800,640Q800,640 800,640L800,160Q800,160 800,160Q800,160 800,160L320,160Q320,160 320,160Q320,160 320,160L320,640Q320,640 320,640Q320,640 320,640ZM160,880Q127,880 103.5,856.5Q80,833 80,800L80,240L160,240L160,800Q160,800 160,800Q160,800 160,800L720,800L720,880L160,880ZM320,160L320,160Q320,160 320,160Q320,160 320,160L320,640Q320,640 320,640Q320,640 320,640L320,640Q320,640 320,640Q320,640 320,640L320,160Q320,160 320,160Q320,160 320,160Z"/>
</vector>

View File

@@ -1,9 +1,11 @@
package mihon.core.migration package mihon.core.migration
import io.kotest.assertions.nondeterministic.eventually
import io.mockk.slot import io.mockk.slot
import io.mockk.spyk import io.mockk.spyk
import io.mockk.verify import io.mockk.verify
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.newSingleThreadContext import kotlinx.coroutines.newSingleThreadContext
@@ -17,6 +19,7 @@ import org.junit.jupiter.api.Assertions.assertInstanceOf
import org.junit.jupiter.api.BeforeAll import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import kotlin.time.Duration.Companion.seconds
class MigratorTest { class MigratorTest {
@@ -26,7 +29,7 @@ class MigratorTest {
lateinit var migrationStrategyFactory: MigrationStrategyFactory lateinit var migrationStrategyFactory: MigrationStrategyFactory
@BeforeEach @BeforeEach
fun initilize() { fun initialize() {
migrationContext = MigrationContext(false) migrationContext = MigrationContext(false)
migrationJobFactory = spyk(MigrationJobFactory(migrationContext, CoroutineScope(Dispatchers.Main + Job()))) migrationJobFactory = spyk(MigrationJobFactory(migrationContext, CoroutineScope(Dispatchers.Main + Job())))
migrationCompletedListener = spyk<MigrationCompletedListener>(block = {}) migrationCompletedListener = spyk<MigrationCompletedListener>(block = {})
@@ -45,7 +48,7 @@ class MigratorTest {
verify { migrationJobFactory.create(capture(migrations)) } verify { migrationJobFactory.create(capture(migrations)) }
assertEquals(1, migrations.captured.size) assertEquals(1, migrations.captured.size)
verify { migrationCompletedListener() } eventually(2.seconds) { verify { migrationCompletedListener() } }
} }
@Test @Test
@@ -86,7 +89,7 @@ class MigratorTest {
verify { migrationJobFactory.create(capture(migrations)) } verify { migrationJobFactory.create(capture(migrations)) }
assertEquals(2, migrations.captured.size) assertEquals(2, migrations.captured.size)
verify { migrationCompletedListener() } eventually(2.seconds) { verify { migrationCompletedListener() } }
} }
@Test @Test
@@ -114,7 +117,7 @@ class MigratorTest {
verify { migrationJobFactory.create(capture(migrations)) } verify { migrationJobFactory.create(capture(migrations)) }
assertEquals(10, migrations.captured.size) assertEquals(10, migrations.captured.size)
verify { migrationCompletedListener() } eventually(2.seconds) { verify { migrationCompletedListener() } }
} }
@Test @Test
@@ -135,11 +138,12 @@ class MigratorTest {
verify { migrationJobFactory.create(capture(migrations)) } verify { migrationJobFactory.create(capture(migrations)) }
assertEquals(2, migrations.captured.size) assertEquals(2, migrations.captured.size)
verify { migrationCompletedListener() } eventually(2.seconds) { verify { migrationCompletedListener() } }
} }
companion object { companion object {
@OptIn(DelicateCoroutinesApi::class)
val mainThreadSurrogate = newSingleThreadContext("UI thread") val mainThreadSurrogate = newSingleThreadContext("UI thread")
@BeforeAll @BeforeAll

View File

@@ -12,7 +12,7 @@ appcompat = "androidx.appcompat:appcompat:1.7.1"
biometricktx = "androidx.biometric:biometric-ktx:1.2.0-alpha05" biometricktx = "androidx.biometric:biometric-ktx:1.2.0-alpha05"
constraintlayout = "androidx.constraintlayout:constraintlayout:2.2.1" constraintlayout = "androidx.constraintlayout:constraintlayout:2.2.1"
corektx = "androidx.core:core-ktx:1.17.0" corektx = "androidx.core:core-ktx:1.17.0"
splashscreen = "androidx.core:core-splashscreen:1.0.1" splashscreen = "androidx.core:core-splashscreen:1.2.0"
recyclerview = "androidx.recyclerview:recyclerview:1.4.0" recyclerview = "androidx.recyclerview:recyclerview:1.4.0"
viewpager = "androidx.viewpager:viewpager:1.1.0" viewpager = "androidx.viewpager:viewpager:1.1.0"
profileinstaller = "androidx.profileinstaller:profileinstaller:1.4.1" profileinstaller = "androidx.profileinstaller:profileinstaller:1.4.1"

View File

@@ -164,6 +164,7 @@
<string name="action_webview_back">Back</string> <string name="action_webview_back">Back</string>
<string name="action_webview_forward">Forward</string> <string name="action_webview_forward">Forward</string>
<string name="action_webview_refresh">Refresh</string> <string name="action_webview_refresh">Refresh</string>
<string name="action_webview_close_tab">Close tab</string>
<string name="action_start_downloading_now">Start downloading now</string> <string name="action_start_downloading_now">Start downloading now</string>
<string name="action_not_now">Not now</string> <string name="action_not_now">Not now</string>
<string name="action_add_anyway">Add anyway</string> <string name="action_add_anyway">Add anyway</string>

View File

@@ -95,4 +95,22 @@
<item quantity="few">%1$s stránky</item> <item quantity="few">%1$s stránky</item>
<item quantity="other">%1$s stránek</item> <item quantity="other">%1$s stránek</item>
</plurals> </plurals>
<plurals name="migrationListScreen.migrateDialog.migrateTitle">
<item quantity="one">Migrovat %1$d položku?</item>
<item quantity="few">Migrovat %1$d položky?</item>
<item quantity="many">Migrovat %1$d položek?</item>
<item quantity="other">Migrovat %1$d položek?</item>
</plurals>
<plurals name="migrationListScreen.migrateDialog.copyTitle">
<item quantity="one">Zkopírovat %1$d položku?</item>
<item quantity="few">Zkopírovat %1$d položky?</item>
<item quantity="many">Zkopírovat %1$d položkek?</item>
<item quantity="other">Zkopírovat %1$d položkek?</item>
</plurals>
<plurals name="migrationListScreen.migrateDialog.skipText">
<item quantity="one">Položka byla přeskočena</item>
<item quantity="few">%1$d položky byly přeskočeny</item>
<item quantity="many">%1$d položek bylo přeskočeno</item>
<item quantity="other">%1$d položek bylo přeskočeno</item>
</plurals>
</resources> </resources>

View File

@@ -540,7 +540,7 @@
<string name="update_72hour">Každé 3 dny</string> <string name="update_72hour">Každé 3 dny</string>
<string name="connected_to_wifi">Jen na Wi-Fi</string> <string name="connected_to_wifi">Jen na Wi-Fi</string>
<string name="pref_verbose_logging">Podrobné protokolování</string> <string name="pref_verbose_logging">Podrobné protokolování</string>
<string name="download_queue_size_warning">Varování: hromadné stahování může vést k tomu, že zdroje zpomalí a/nebo zablokují Mihon. Klepnutím se dozvíte více.</string> <string name="download_queue_size_warning">Varování: hromadné stahování může vést k tomu, že zdroje zpomalí a/nebo zablokují %s. Klepnutím se dozvíte více.</string>
<string name="ext_update_all">Aktualizovat vše</string> <string name="ext_update_all">Aktualizovat vše</string>
<string name="pref_verbose_logging_summary">Vypisovat podrobné informace do systémového protokolu (sníží výkon aplikace)</string> <string name="pref_verbose_logging_summary">Vypisovat podrobné informace do systémového protokolu (sníží výkon aplikace)</string>
<string name="channel_app_updates">Aktualizace aplikace</string> <string name="channel_app_updates">Aktualizace aplikace</string>
@@ -687,8 +687,8 @@
<string name="pref_page_rotate_invert">Překlopení orientace otočených širokých stránek</string> <string name="pref_page_rotate_invert">Překlopení orientace otočených širokých stránek</string>
<string name="pref_page_rotate">Otočení širokých stránek tak, aby se vešly</string> <string name="pref_page_rotate">Otočení širokých stránek tak, aby se vešly</string>
<string name="pref_debug_info">Ladící informace</string> <string name="pref_debug_info">Ladící informace</string>
<string name="pref_chapter_swipe_end">Přejetí prstem doprava</string> <string name="pref_chapter_swipe_end">Kapitola po přejetí doprava</string>
<string name="pref_chapter_swipe_start">Přejetí prstem doleva</string> <string name="pref_chapter_swipe_start">Kapitola po přejetí doleva</string>
<string name="pref_double_tap_zoom">Přiblížení dvojitým klepnutím</string> <string name="pref_double_tap_zoom">Přiblížení dvojitým klepnutím</string>
<string name="action_filter_interval_custom">Přizpůsobený interval aktualizace</string> <string name="action_filter_interval_custom">Přizpůsobený interval aktualizace</string>
<string name="action_sort_next_updated">Další očekávaná aktualizace</string> <string name="action_sort_next_updated">Další očekávaná aktualizace</string>
@@ -768,7 +768,7 @@
\nVybraná složka: %2$s</string> \nVybraná složka: %2$s</string>
<string name="invalid_backup_file_error">Úplná chyba:</string> <string name="invalid_backup_file_error">Úplná chyba:</string>
<string name="pref_library_update_smart_update">Chytrá aktualizace</string> <string name="pref_library_update_smart_update">Chytrá aktualizace</string>
<string name="action_add_repo_message">Přidat další repozitáře do Mihon. Měli by to být URL končící \"index.min.json\".</string> <string name="action_add_repo_message">Přidat další repozitáře do %s. Měli by to být URL končící \"index.min.json\".</string>
<string name="error_repo_exists">Tento repozitář již existuje!</string> <string name="error_repo_exists">Tento repozitář již existuje!</string>
<string name="action_delete_repo">Odstranit repozitář</string> <string name="action_delete_repo">Odstranit repozitář</string>
<string name="invalid_repo_name">Neplatná URL repozitáře</string> <string name="invalid_repo_name">Neplatná URL repozitáře</string>
@@ -833,7 +833,7 @@
<string name="upcoming_calendar_next">Následující měsíc</string> <string name="upcoming_calendar_next">Následující měsíc</string>
<string name="upcoming_guide">Návod k nadcházejícím kapitolám</string> <string name="upcoming_guide">Návod k nadcházejícím kapitolám</string>
<string name="label_auto">Automaticky</string> <string name="label_auto">Automaticky</string>
<string name="pref_mark_duplicate_read_chapter_read">Označit duplicitní přečtené kapitoly jako přečtené</string> <string name="pref_mark_duplicate_read_chapter_read">Označit duplicitní přečtenou kapitolu jako přečtenou</string>
<string name="theme_monochrome">Černobílý</string> <string name="theme_monochrome">Černobílý</string>
<string name="author">Autor</string> <string name="author">Autor</string>
<string name="artist">Umělec</string> <string name="artist">Umělec</string>
@@ -860,4 +860,11 @@
<string name="storage_failed_to_create_directory">Nepodařilo se vytvořit adresář: %s</string> <string name="storage_failed_to_create_directory">Nepodařilo se vytvořit adresář: %s</string>
<string name="clear_database_text">Chystáte se odstranit položky z databáze</string> <string name="clear_database_text">Chystáte se odstranit položky z databáze</string>
<string name="clear_db_exclude_read">Ponechat položky s přečtenými kapitolami</string> <string name="clear_db_exclude_read">Ponechat položky s přečtenými kapitolami</string>
<string name="label_donate">Přispěj</string>
<string name="theme_catppuccin">Catppuccin</string>
<string name="pref_hide_missing_chapter_indicators">Skrýt indikátory chybějících kapitol</string>
<string name="pref_disallow_non_ascii_filenames">Nepovolovat soubory s non-ASCII znaky</string>
<string name="pref_disallow_non_ascii_filenames_details">Zajišťuje kompatibilitu s určitými úložnými médii, která nepodporují Unicode. Pokud je tato funkce povolena, budete muset ručně přejmenovat názvy složkek source a manga tak, že nahradíte non-ASCII znaky jejich malými hexadecimálními znaky v UTF-8. Názvy souborů kapitol není nutné přejmenovávat.</string>
<string name="pref_download_concurrent_sources">Souběžné stahování zdrojů</string>
<string name="pref_download_concurrent_pages">Souběžné stahování stránek</string>
</resources> </resources>

View File

@@ -905,4 +905,7 @@
<string name="pref_display_images_description">Bilder in Mangabeschreibungen anzeigen</string> <string name="pref_display_images_description">Bilder in Mangabeschreibungen anzeigen</string>
<string name="pref_disallow_non_ascii_filenames">Nicht-ASCII-Dateinamen nicht zulassen</string> <string name="pref_disallow_non_ascii_filenames">Nicht-ASCII-Dateinamen nicht zulassen</string>
<string name="pref_disallow_non_ascii_filenames_details">Versichert Kompatibilität mit bestimmten Speichermedien, die Unicode nicht unterstützen. Ist diese Option aktiviert, müssen Quellen- und Manga-Ordner manuell umbenannt werden, indem Nicht-ASCII-Zeichen durch ihre UTF-8-Hexadezimaldarstellungen in Kleinbuchstaben ersetzt werden. Kapiteldateien müssen nicht umbenannt werden.</string> <string name="pref_disallow_non_ascii_filenames_details">Versichert Kompatibilität mit bestimmten Speichermedien, die Unicode nicht unterstützen. Ist diese Option aktiviert, müssen Quellen- und Manga-Ordner manuell umbenannt werden, indem Nicht-ASCII-Zeichen durch ihre UTF-8-Hexadezimaldarstellungen in Kleinbuchstaben ersetzt werden. Kapiteldateien müssen nicht umbenannt werden.</string>
<string name="pref_download_concurrent_sources">Gleichzeitige Quellendownloads</string>
<string name="pref_download_concurrent_pages">Gleichzeitige Seitendownloads</string>
<string name="pref_download_concurrent_pages_summary">Pro Quelle gleichzeitig heruntergeladene Seiten</string>
</resources> </resources>

View File

@@ -905,4 +905,7 @@
<string name="pref_display_images_description">Iscrtaj slike u opisima manga</string> <string name="pref_display_images_description">Iscrtaj slike u opisima manga</string>
<string name="pref_disallow_non_ascii_filenames">Zabrani imena datoteka koji nisu u ASCII formatu</string> <string name="pref_disallow_non_ascii_filenames">Zabrani imena datoteka koji nisu u ASCII formatu</string>
<string name="pref_disallow_non_ascii_filenames_details">Osigurava kompatibilnost s određenim medijima za spremanje podataka koji ne podržavaju Unicode. Kada je ova opcija aktivirana, morat ćeš ručno preimenovati izvor i mape s mangama zamjenjivanjem znakova koji nisu ASCII s njihovim UTF-8 heksadecimalnim vrijednostima (u malim slovima). Datoteke poglavlja se ne moraju preimenovati.</string> <string name="pref_disallow_non_ascii_filenames_details">Osigurava kompatibilnost s određenim medijima za spremanje podataka koji ne podržavaju Unicode. Kada je ova opcija aktivirana, morat ćeš ručno preimenovati izvor i mape s mangama zamjenjivanjem znakova koji nisu ASCII s njihovim UTF-8 heksadecimalnim vrijednostima (u malim slovima). Datoteke poglavlja se ne moraju preimenovati.</string>
<string name="pref_download_concurrent_sources">Istovremena preuzimanja izvora</string>
<string name="pref_download_concurrent_pages">Istovremena preuzimanja stranica</string>
<string name="pref_download_concurrent_pages_summary">Istovremeno preuzete stranice po izvoru</string>
</resources> </resources>

View File

@@ -905,4 +905,7 @@
<string name="migrationListScreen.matchWithoutChapterToast">Tidak ditemukan bab, entri ini tidak dapat digunakan untuk migrasi</string> <string name="migrationListScreen.matchWithoutChapterToast">Tidak ditemukan bab, entri ini tidak dapat digunakan untuk migrasi</string>
<string name="pref_disallow_non_ascii_filenames">Jangan izinkan nama file non-ASCII</string> <string name="pref_disallow_non_ascii_filenames">Jangan izinkan nama file non-ASCII</string>
<string name="pref_disallow_non_ascii_filenames_details">Memastikan kompatibilitas dengan beberapa media penyimpanan yang tidak mendukung Unicode. Jika opsi ini diaktifkan, Anda harus mengganti nama folder sumber dan manga secara manual dengan mengganti karakter non-ASCII menjadi representasi heksadesimal UTF-8 huruf kecil. File chapter tidak perlu diganti namanya.</string> <string name="pref_disallow_non_ascii_filenames_details">Memastikan kompatibilitas dengan beberapa media penyimpanan yang tidak mendukung Unicode. Jika opsi ini diaktifkan, Anda harus mengganti nama folder sumber dan manga secara manual dengan mengganti karakter non-ASCII menjadi representasi heksadesimal UTF-8 huruf kecil. File chapter tidak perlu diganti namanya.</string>
<string name="pref_download_concurrent_sources">Ambil berkas sumber secara bersamaan</string>
<string name="pref_download_concurrent_pages">Ambil berkas halaman secara bersamaan</string>
<string name="pref_download_concurrent_pages_summary">Halaman yang diunduh secara bersamaan per sumber</string>
</resources> </resources>

View File

@@ -540,7 +540,7 @@
<string name="action_display_language_badge">言語</string> <string name="action_display_language_badge">言語</string>
<string name="label_warning">警告</string> <string name="label_warning">警告</string>
<string name="pref_verbose_logging">Verboseログ出力</string> <string name="pref_verbose_logging">Verboseログ出力</string>
<string name="download_queue_size_warning">警告: 大量の一括ダウンロードにより、ソースは遅くなったり、Mihonを接続禁止したりする恐れがあります。詳しくはタップでご覧ください。</string> <string name="download_queue_size_warning">警告大量のダウンロード、ソースの速度低下や %s のブロックにつながる可能性があります。詳細を確認するにはタップしてください。</string>
<string name="update_72hour">3日ごと</string> <string name="update_72hour">3日ごと</string>
<string name="connected_to_wifi">Wi-Fi接続時のみ</string> <string name="connected_to_wifi">Wi-Fi接続時のみ</string>
<string name="ext_update_all">全て更新</string> <string name="ext_update_all">全て更新</string>
@@ -838,20 +838,20 @@
<string name="pref_behavior">行動</string> <string name="pref_behavior">行動</string>
<string name="pref_mark_duplicate_read_chapter_read_existing">章の読了後</string> <string name="pref_mark_duplicate_read_chapter_read_existing">章の読了後</string>
<string name="pref_update_library_manga_titles">ライブラリーのマンガのタイトルをソースに合わせて更新</string> <string name="pref_update_library_manga_titles">ライブラリーのマンガのタイトルをソースに合わせて更新</string>
<string name="pref_incognito_mode_extension_summary">拡張機能の既読章履歴を一時停止</string> <string name="pref_incognito_mode_extension_summary">拡張機能の閲覧履歴を一時停止</string>
<string name="logging_in">ログイン中…</string> <string name="logging_in">ログイン中…</string>
<string name="pref_mark_duplicate_read_chapter_read">重複する既読章を既読としてマークする</string> <string name="pref_mark_duplicate_read_chapter_read">重複する既読章を既読としてマークする</string>
<string name="pref_mark_duplicate_read_chapter_read_new">新章取得後</string> <string name="pref_mark_duplicate_read_chapter_read_new">新章取得後</string>
<string name="possible_duplicates_summary">ライブラリに名前が似ている作品があります。\n\n移行作品の選択、またはそのまま追加</string> <string name="possible_duplicates_summary">ライブラリに類似した名前のエントリが存在します。\n\n移行するエントリを選択するか、そのまま追加してください</string>
<string name="author">著者</string> <string name="author">著者</string>
<string name="artist">アーティスト</string> <string name="artist">アーティスト</string>
<string name="action_display_unread_badge">未読の章</string> <string name="action_display_unread_badge">未読の章</string>
<string name="storage_failed_to_create_download_directory">ダウンロードディレクトリの作成に失敗しました</string> <string name="storage_failed_to_create_download_directory">ダウンロードディレクトリの作成に失敗しました</string>
<string name="storage_failed_to_create_directory">ディレクトリの作成に失敗しました: %s</string> <string name="storage_failed_to_create_directory">ディレクトリの作成に失敗しました: %s</string>
<string name="clear_database_text">データベースから作品が削除されます</string> <string name="clear_database_text">データベースから作品が削除されます</string>
<string name="clear_database_history_warning">ライブラリ外作品の既読の章と進捗は失われます</string> <string name="clear_database_history_warning">非図書館エントリの章の読み取りと進捗は失われます</string>
<string name="clear_db_exclude_read">読み終えた章を含むエントリーを保持する</string> <string name="clear_db_exclude_read">読み終えた章を含むエントリーを保持する</string>
<string name="possible_duplicates_title">重複の可能性あり</string> <string name="possible_duplicates_title">重複の可能性</string>
<string name="label_donate">寄付する</string> <string name="label_donate">寄付する</string>
<string name="label_auto">自動車</string> <string name="label_auto">自動車</string>
<string name="theme_catppuccin">キャットプッチン</string> <string name="theme_catppuccin">キャットプッチン</string>
@@ -860,4 +860,13 @@
<string name="pref_hide_missing_chapter_indicators">欠落している章のインジケーターを非表示にする</string> <string name="pref_hide_missing_chapter_indicators">欠落している章のインジケーターを非表示にする</string>
<string name="pref_always_decode_long_strip_with_ssiv_2">レガシーデコーダーを長尺ストリップリーダーに使用する</string> <string name="pref_always_decode_long_strip_with_ssiv_2">レガシーデコーダーを長尺ストリップリーダーに使用する</string>
<string name="library_list">ライブラリーリスト</string> <string name="library_list">ライブラリーリスト</string>
<string name="pref_disallow_non_ascii_filenames">非ASCIIファイル名を許可しない</string>
<string name="pref_disallow_non_ascii_filenames_details">特定のUnicode非対応ストレージメディアとの互換性を確保します。有効にした場合、ソースフォルダとマンガフォルダは手動で名前を変更する必要があります。非ASCII文字を小文字のUTF-8 16進数表記に置き換えてください。チャプターファイルの名前変更は不要です。</string>
<string name="pref_download_concurrent_sources">同時ソースダウンロード</string>
<string name="pref_download_concurrent_pages">同時ページダウンロード</string>
<string name="pref_download_concurrent_pages_summary">ソースごとの同時ダウンロードページ数</string>
<string name="pref_update_library_manga_titles_summary">警告:マンガのタイトルが変更された場合、ダウンロードキューから削除されます(存在する場合)。</string>
<string name="tracked_privately">非公開で追跡</string>
<string name="action_toggle_private_on">非公開で追跡する</string>
<string name="action_toggle_private_off">公開で追跡する</string>
</resources> </resources>

View File

@@ -313,4 +313,29 @@
<string name="unlock_app_title">Bikak kunci %s</string> <string name="unlock_app_title">Bikak kunci %s</string>
<string name="action_set_interval">Trapake jeda wayah</string> <string name="action_set_interval">Trapake jeda wayah</string>
<string name="action_filter_interval_custom">Nganyari panyaris frekuensi</string> <string name="action_filter_interval_custom">Nganyari panyaris frekuensi</string>
<string name="action_sort_next_updated">nganyari kang diarep-arep sabanjure</string>
<string name="action_sort_tracker_score">Skor pelacak</string>
<string name="action_sort_random">mawut</string>
<string name="action_update_category">Mbaharui kategori</string>
<string name="action_open_random_manga">Bikak entri acak</string>
<string name="action_remove_everything">Busek sedaya</string>
<string name="action_copy_to_clipboard">Santun dhateng blabak klip</string>
<string name="action_copy_link">Santun link</string>
<string name="action_display_unread_badge">Bab durung diwaca</string>
<string name="action_display_show_continue_reading_button">Tombol lajengaken maos</string>
<string name="action_apply">Terapaken</string>
<string name="action_ok">OK</string>
<string name="action_move_to_bottom_all_for_series">Pindhah seri ka ngisor</string>
<string name="action_notes">Cathetan</string>
<string name="action_edit_notes">Ganti cathetan</string>
<string name="action_revert_to_default">Mbalikake marang default</string>
<string name="action_not_now">Ora saiki</string>
<string name="action_add_anyway">Tambahaken mawon</string>
<string name="pref_onboarding_guide">Panuntun wiwitan</string>
<string name="onboarding_heading">Sugeng rawuh!</string>
<string name="onboarding_description">Ayo awakdewe atur sawetara perkara ndhisik. Sampeyan uga mesthi isa ngowahi ing menu setelan mengko.</string>
<string name="onboarding_action_next">Terusane</string>
<string name="onboarding_action_finish">Rampung</string>
<string name="onboarding_action_skip">Nglangkungi</string>
<string name="onboarding_storage_info">Milih direktori kanggo nyimpen isi saka %1$s, kalebu unduhan bab, data backup, lan liya-liyane. \n \nApike kudu nganggo direktori kapisah. \n \ndirektori ingkang dipunpilih: %2$s</string>
</resources> </resources>

View File

@@ -904,4 +904,7 @@
<string name="migrationListScreen.matchWithoutChapterToast">Tidak ada bab yang dijumpai, entri ini tidak dapat digunakan untuk penghijrahan</string> <string name="migrationListScreen.matchWithoutChapterToast">Tidak ada bab yang dijumpai, entri ini tidak dapat digunakan untuk penghijrahan</string>
<string name="pref_disallow_non_ascii_filenames">Tidak benarkan nama fail bukan ASCII</string> <string name="pref_disallow_non_ascii_filenames">Tidak benarkan nama fail bukan ASCII</string>
<string name="pref_disallow_non_ascii_filenames_details">Memastikan keserasian dengan media penyimpanan tertentu yang tidak menyokong Unicode. Apabila ini diaktifkan, anda perlu menamakan semula folder sumber dan manga secara manual dengan menggantikan aksara bukan-ASCII dengan representasi heksadesimal UTF-8 huruf kecil mereka. Fail bab tidak perlu dinamakan semula.</string> <string name="pref_disallow_non_ascii_filenames_details">Memastikan keserasian dengan media penyimpanan tertentu yang tidak menyokong Unicode. Apabila ini diaktifkan, anda perlu menamakan semula folder sumber dan manga secara manual dengan menggantikan aksara bukan-ASCII dengan representasi heksadesimal UTF-8 huruf kecil mereka. Fail bab tidak perlu dinamakan semula.</string>
<string name="pref_download_concurrent_sources">Muat turun sumber serentak</string>
<string name="pref_download_concurrent_pages">Muat turun halaman serentak</string>
<string name="pref_download_concurrent_pages_summary">Halaman yang dimuat turun secara serentak setiap sumber</string>
</resources> </resources>

View File

@@ -76,4 +76,16 @@
<item quantity="one">%d repo</item> <item quantity="one">%d repo</item>
<item quantity="other">%d repo\'s</item> <item quantity="other">%d repo\'s</item>
</plurals> </plurals>
</resources> <plurals name="migrationListScreen.migrateDialog.migrateTitle">
<item quantity="one">%1$d item migreren?</item>
<item quantity="other">%1$d items migreren?</item>
</plurals>
<plurals name="migrationListScreen.migrateDialog.copyTitle">
<item quantity="one">%1$d item kopiëren?</item>
<item quantity="other">%1$d items kopiëren?</item>
</plurals>
<plurals name="migrationListScreen.migrateDialog.skipText">
<item quantity="one">Een item werd overgeslagen</item>
<item quantity="other">%1$d items werden overgeslagen</item>
</plurals>
</resources>

View File

@@ -905,4 +905,5 @@
<string name="label_donate">Спонсорство</string> <string name="label_donate">Спонсорство</string>
<string name="pref_disallow_non_ascii_filenames">Не позволять наименования файлов в виде non-ASCII</string> <string name="pref_disallow_non_ascii_filenames">Не позволять наименования файлов в виде non-ASCII</string>
<string name="pref_disallow_non_ascii_filenames_details">Обеспечивает совместимость с некоторыми носителями информации, которые не поддерживают Unicode. Когда этот функция включена, вам нужно будет вручную переименовать папки серий и источников, заменив non-ASCII символы на шестнадцатеричные UTF-8 в нижнем регистре. Файлы глав можно не переименовать.</string> <string name="pref_disallow_non_ascii_filenames_details">Обеспечивает совместимость с некоторыми носителями информации, которые не поддерживают Unicode. Когда этот функция включена, вам нужно будет вручную переименовать папки серий и источников, заменив non-ASCII символы на шестнадцатеричные UTF-8 в нижнем регистре. Файлы глав можно не переименовать.</string>
<string name="pref_download_concurrent_sources">Параллельные загрузки с источников</string>
</resources> </resources>

View File

@@ -905,7 +905,7 @@
<string name="label_donate">Bağış</string> <string name="label_donate">Bağış</string>
<string name="pref_disallow_non_ascii_filenames">ASCII olmayan dosya isimlerine izin verme</string> <string name="pref_disallow_non_ascii_filenames">ASCII olmayan dosya isimlerine izin verme</string>
<string name="pref_disallow_non_ascii_filenames_details">Unicode desteklemeyen bazı depolama sistemleri için uyumluluk sağlar. Etkinleştirildiğinde kaynak ve manga klasörlerini manuel olarak yeniden adlandırıp ASCII olmayan karakterleri küçük UTF-8 heksadesimal karşılıklarıyla değiştirmeniz gerekir. Bölüm dosyalarının yeniden adlandırılması gerekli değildir.</string> <string name="pref_disallow_non_ascii_filenames_details">Unicode desteklemeyen bazı depolama sistemleri için uyumluluk sağlar. Etkinleştirildiğinde kaynak ve manga klasörlerini manuel olarak yeniden adlandırıp ASCII olmayan karakterleri küçük UTF-8 heksadesimal karşılıklarıyla değiştirmeniz gerekir. Bölüm dosyalarının yeniden adlandırılması gerekli değildir.</string>
<string name="pref_download_concurrent_pages">Tek seferde indirilen sayfalar</string> <string name="pref_download_concurrent_pages">Tek seferde indirilen sayfa sayısı</string>
<string name="pref_download_concurrent_pages_summary">Her kaynak için aynı anda indirilen sayfalar</string> <string name="pref_download_concurrent_pages_summary">Her kaynak için aynı anda indirilen sayfa sayısı</string>
<string name="pref_download_concurrent_sources">Tek seferde indirilen kaynaklar</string> <string name="pref_download_concurrent_sources">Tek seferde indirilen kaynak sayısı</string>
</resources> </resources>

View File

@@ -859,7 +859,7 @@
<string name="storage_failed_to_create_download_directory">创建下载目录失败</string> <string name="storage_failed_to_create_download_directory">创建下载目录失败</string>
<string name="storage_failed_to_create_directory">创建目录失败: %s</string> <string name="storage_failed_to_create_directory">创建目录失败: %s</string>
<string name="logging_in">正在登录…</string> <string name="logging_in">正在登录…</string>
<string name="pref_update_library_manga_titles">更新书架中的漫画标题以匹配</string> <string name="pref_update_library_manga_titles">更新书架中的漫画标题以匹配</string>
<string name="pref_update_library_manga_titles_summary">警告:如果漫画被重命名,将会从下载队列中移除(如果存在)。</string> <string name="pref_update_library_manga_titles_summary">警告:如果漫画被重命名,将会从下载队列中移除(如果存在)。</string>
<string name="migrationConfigScreen.selectedHeader">选中</string> <string name="migrationConfigScreen.selectedHeader">选中</string>
<string name="migrationConfigScreen.selectNoneLabel">全不选</string> <string name="migrationConfigScreen.selectNoneLabel">全不选</string>
@@ -903,4 +903,9 @@
<string name="pref_hide_missing_chapter_indicators">隐藏缺失章节提示符</string> <string name="pref_hide_missing_chapter_indicators">隐藏缺失章节提示符</string>
<string name="pref_display_images_description">在漫画注释中显示图片</string> <string name="pref_display_images_description">在漫画注释中显示图片</string>
<string name="label_donate">捐赠</string> <string name="label_donate">捐赠</string>
<string name="pref_disallow_non_ascii_filenames">禁用非ASCII文件名</string>
<string name="pref_disallow_non_ascii_filenames_details">确保与某些不支持 Unicode 的存储介质相兼容。启用此功能后,你需要手动重命名图源和漫画文件夹,将非 ASCII 字符改为对应的 UTF-8 小写十六进制表示形式。章节文件无需重命名。</string>
<string name="pref_download_concurrent_sources">同时下载的图源数量</string>
<string name="pref_download_concurrent_pages">同时下载的页数</string>
<string name="pref_download_concurrent_pages_summary">每个图源同时下载的页数</string>
</resources> </resources>

View File

@@ -896,4 +896,7 @@
<string name="label_donate">捐贈</string> <string name="label_donate">捐贈</string>
<string name="pref_disallow_non_ascii_filenames">禁止使用非 ASCII 檔名</string> <string name="pref_disallow_non_ascii_filenames">禁止使用非 ASCII 檔名</string>
<string name="pref_disallow_non_ascii_filenames_details">確保與不支援 Unicode 的某些儲存媒體相容,啟用此選項後,你需要手動將來源與漫畫資料夾中的非 ASCII 字元改成對應的小寫 UTF-8 十六進位表示方式,章節檔案則不需要重新命名。</string> <string name="pref_disallow_non_ascii_filenames_details">確保與不支援 Unicode 的某些儲存媒體相容,啟用此選項後,你需要手動將來源與漫畫資料夾中的非 ASCII 字元改成對應的小寫 UTF-8 十六進位表示方式,章節檔案則不需要重新命名。</string>
<string name="pref_download_concurrent_sources">同時下載的來源數目</string>
<string name="pref_download_concurrent_pages">同時下載的頁數</string>
<string name="pref_download_concurrent_pages_summary">每個來源同時下載的頁數</string>
</resources> </resources>