Compare commits

...

32 Commits

Author SHA1 Message Date
Jobobby04 3de4711e03 Try this Shizuku fix 2024-10-27 13:34:33 -04:00
Weblate (bot) 106f63a657 Translations update from Hosted Weblate (#1289)
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy-plurals/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/ar/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/as/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/es/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/fil/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/id/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/it/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/ru/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/zh_Hant/
Translation: Mihon/TachiyomiSY
Translation: Mihon/TachiyomiSY Plurals

Co-authored-by: Dexroneum <Rozhenkov69@gmail.com>
Co-authored-by: Eji-san <ejierubani@gmail.com>
Co-authored-by: Fordas <fordas15@gmail.com>
Co-authored-by: Giorgio Sanna <sannagiorgio1997@gmail.com>
Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Co-authored-by: Itsmechinmoy <itsmechinmoy@users.noreply.hosted.weblate.org>
Co-authored-by: Noah Kenzie Rodriguez-Beus <noahbeus@protonmail.com>
Co-authored-by: Sergeev Vladimir Dmitrievich <sekhmych@gmail.com>
Co-authored-by: Swyter <swyterzone@gmail.com>
Co-authored-by: ZerOriSama <godarms2010@live.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: ɴᴇᴋᴏ <s99095lkjjim@gmail.com>
2024-10-26 23:44:53 -04:00
Luqman 3c09343f7b allow chapter 0 dupe auto mark as read (#1291) 2024-10-26 23:31:44 -04:00
Jobobby04 86e1406565 Spotless 2024-10-26 23:30:07 -04:00
jobobby04 b48556aa9f Fix for ExHentai 2024-10-26 23:06:30 -04:00
Cuong-Tran f3e905513f Fix app crash when removing tracked entry from tracker (#1380)
(cherry picked from commit 6de06419f8afd842f7037e3ecb51200037af3a85)
2024-10-26 22:25:23 -04:00
Roshan Varughese 633a1892b3 Allow completely disabling "Update tracker" snackbar on mark as read (#1374)
Also fixes #1369

(cherry picked from commit fc2f339ea1cdc43c0041b2fed497dcfda853b85e)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt
2024-10-26 22:25:11 -04:00
Cuong-Tran 74cf08b47b Add libs.material to presentation-widget (#1373)
Fixes some build issues

(cherry picked from commit 264030d6ecbc7492d884eb328b74399cd722dcb0)
2024-10-26 22:16:09 -04:00
Jobobby04 cc7ce80abf Ignore Shizuku min sdk since desurging is enabled 2024-10-26 22:15:35 -04:00
AntsyLich e06941f82d Update dependency com.pinterest.ktlint:ktlint-cli to v1.4.0
Co-authored-by: Mend Renovate <bot@renovateapp.com>
(cherry picked from commit 140083ee39df7d458e5ff9abc6d0ee9831d99387)
2024-10-26 21:59:54 -04:00
AntsyLich a8a290d03d Cleanup Slider usage
(cherry picked from commit df9fff60da3a38acd8fcd540b5fdd275be93f2d5)

# Conflicts:
#	app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt
#	app/src/main/java/eu/kanade/presentation/reader/components/ChapterNavigator.kt
2024-10-26 21:59:33 -04:00
Mend Renovate b49ca3ce4c Update dependency me.zhanghai.android.libarchive:library to v1.1.4 (#1378)
(cherry picked from commit aae0e3459ce13398a64b5cd9995f4a40a0120822)
2024-10-26 21:53:38 -04:00
Cuong-Tran c51c364cdd Avoid blocking call to load categories in settings (#1364)
(cherry picked from commit f7752a98b2452a69f22a469d0bcbf761fb1c6569)

# Conflicts:
#	app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsLibraryScreen.kt
2024-10-26 21:53:27 -04:00
abdurisaq 366415d323 Fix settings SliderItem steps count (#1356)
(cherry picked from commit 2ba7ed32802ffca1946d567b8afe49bfd3f4326e)
2024-10-26 21:52:33 -04:00
Roshan Varughese 14f6fd7908 Rework Auto Track on Mark as Read (#1365)
(cherry picked from commit c153ac01f545ce9259c58aa5d5f7223d2f8f628b)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt
2024-10-26 21:52:24 -04:00
Mend Renovate 15f1ee2205 Update dependency com.google.firebase:firebase-bom to v33.5.1 (#1362)
(cherry picked from commit 78d2cc75d5dc04fe5cddcfaeb0a4502d48392f2d)
2024-10-26 21:51:14 -04:00
AntsyLich 651579b243 Update shizuku.version to v13.1.0
(cherry picked from commit c550a81598c98ef9a22dac8f6a408f5c15235fde)
2024-10-26 21:50:55 -04:00
Mend Renovate 8f596069fa Update dependency com.google.firebase:firebase-bom to v33.5.0 (#1352)
(cherry picked from commit 0be36a10c36d3b8c5802ff515302ed29cc8fa013)
2024-10-26 21:50:41 -04:00
Mend Renovate a28d526102 Update dependency org.junit.jupiter:junit-jupiter to v5.11.3 (#1351)
(cherry picked from commit e16c3953c709a6c35c4655f916119fdf665baa62)
2024-10-26 21:50:34 -04:00
Jobobby04 bbaa74d99c Fix build 2024-10-20 01:51:54 -04:00
AntsyLich 310b1ad69b Pass uncaught exception to default handler in GlobalExceptionHandler
Fixes #1347

(cherry picked from commit f3a2f566c8a09ab862758ae69b43da2a2cd8f1db)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/crash/GlobalExceptionHandler.kt
2024-10-20 01:04:23 -04:00
AntsyLich 7f37989c4e Rework Firebase setup
Fixes #1332
Closes #1339

(cherry picked from commit 15e3f28aa36bec3c31f212c572ab57ce960cc862)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/App.kt
2024-10-20 01:03:36 -04:00
AntsyLich 185920b984 Address deprecation, suggestion and spotless
(cherry picked from commit 3bf70b230fc2c3eda58c4d46dec3fb75668e4f69)
2024-10-20 01:02:06 -04:00
AntsyLich 4639077756 Revert "Tweak Preference.collectAsState"
This reverts commit 3bddb5538528c19388e364d21e6a6c16487af759.

Fixes #1341

(cherry picked from commit eb3bea8150ce9bf2320d15c879cbebaa6d51a4c6)
2024-10-20 01:01:58 -04:00
Mend Renovate 0bf1519c25 Update dependency androidx.compose:compose-bom to v2024.10.00 (#1338)
(cherry picked from commit 5612ae0149e9231c9691ee782da8159489a0d057)
2024-10-20 01:01:48 -04:00
Mend Renovate 45a36cef32 Update xml.serialization.version to v0.90.2 (#1331)
* Update xml.serialization.version to v0.90.2

* Fix build

---------

Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>
(cherry picked from commit dbf6ad2ca7e0525f597010709e87d094d10e4f8d)

# Conflicts:
#	source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt
2024-10-20 01:01:41 -04:00
AntsyLich dece1bc0cb Change "Invalidate downloads index" to "Reindex downloads"
(cherry picked from commit d2afbfe4ede283076aae40633c79c3f90b4390e7)
2024-10-20 01:01:09 -04:00
Mend Renovate eaffd3f2dc Update dependency androidx.annotation:annotation to v1.9.0 (#1336)
(cherry picked from commit 337806d9e17e92a9134d59324e9857d05abc4db3)
2024-10-20 01:00:58 -04:00
Mend Renovate aabe409ee5 Update dependency androidx.glance:glance-appwidget to v1.1.1 (#1335)
(cherry picked from commit 443f6e0ae53dadce1f66818fac0cd1eeaa5fec27)
2024-10-20 01:00:50 -04:00
Mend Renovate e626cdd030 Update dependency androidx.benchmark:benchmark-macro-junit4 to v1.3.3 (#1334)
(cherry picked from commit 572ee2f02a980a60a1120e7c0c88060fb1a7b3d2)
2024-10-20 01:00:43 -04:00
Mend Renovate b161c333ec Update dependency androidx.activity:activity-compose to v1.9.3 (#1333)
(cherry picked from commit ba1343bed8c00d5ed976111c710c9b5648676a59)
2024-10-20 01:00:36 -04:00
FlaminSarge e587bb7f44 [skip ci] Update i18n readme (#1328)
(cherry picked from commit 9f3d5d13d4fedcca53ebb779a2cfca1e286c79da)
2024-10-20 01:00:26 -04:00
60 changed files with 818 additions and 215 deletions
@@ -1,9 +0,0 @@
package mihon.core.firebase
import android.content.Context
import eu.kanade.tachiyomi.core.security.PrivacyPreferences
import kotlinx.coroutines.CoroutineScope
object Firebase {
fun setup(context: Context, preference: PrivacyPreferences, scope: CoroutineScope) = Unit
}
@@ -0,0 +1,11 @@
package mihon.core.firebase
import android.content.Context
object FirebaseConfig {
fun init(context: Context) = Unit
fun setAnalyticsEnabled(enabled: Boolean) = Unit
fun setCrashlyticsEnabled(enabled: Boolean) = Unit
}
+3
View File
@@ -415,4 +415,7 @@
</activity> </activity>
</application> </application>
<uses-sdk tools:overrideLibrary="rikka.shizuku.api"
tools:ignore="ManifestOrder" />
</manifest> </manifest>
@@ -0,0 +1,10 @@
package eu.kanade.domain.track.model
import dev.icerock.moko.resources.StringResource
import tachiyomi.i18n.MR
enum class AutoTrackState(val titleRes: StringResource) {
ALWAYS(MR.strings.lock_always),
ASK(MR.strings.default_category_summary),
NEVER(MR.strings.lock_never),
}
@@ -1,9 +1,11 @@
package eu.kanade.domain.track.service package eu.kanade.domain.track.service
import eu.kanade.domain.track.model.AutoTrackState
import eu.kanade.tachiyomi.data.track.Tracker import eu.kanade.tachiyomi.data.track.Tracker
import eu.kanade.tachiyomi.data.track.anilist.Anilist import eu.kanade.tachiyomi.data.track.anilist.Anilist
import tachiyomi.core.common.preference.Preference import tachiyomi.core.common.preference.Preference
import tachiyomi.core.common.preference.PreferenceStore import tachiyomi.core.common.preference.PreferenceStore
import tachiyomi.core.common.preference.getEnum
class TrackPreferences( class TrackPreferences(
private val preferenceStore: PreferenceStore, private val preferenceStore: PreferenceStore,
@@ -35,4 +37,9 @@ class TrackPreferences(
fun anilistScoreType() = preferenceStore.getString("anilist_score_type", Anilist.POINT_10) fun anilistScoreType() = preferenceStore.getString("anilist_score_type", Anilist.POINT_10)
fun autoUpdateTrack() = preferenceStore.getBoolean("pref_auto_update_manga_sync_key", true) fun autoUpdateTrack() = preferenceStore.getBoolean("pref_auto_update_manga_sync_key", true)
fun autoUpdateTrackOnMarkRead() = preferenceStore.getEnum(
"pref_auto_update_manga_on_mark_read",
AutoTrackState.ALWAYS,
)
} }
@@ -15,7 +15,6 @@ import eu.kanade.presentation.more.settings.widget.TriStateListDialog
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.persistentMapOf import kotlinx.collections.immutable.persistentMapOf
import kotlinx.collections.immutable.toImmutableMap import kotlinx.collections.immutable.toImmutableMap
import kotlinx.coroutines.runBlocking
import tachiyomi.domain.category.interactor.GetCategories import tachiyomi.domain.category.interactor.GetCategories
import tachiyomi.domain.category.model.Category import tachiyomi.domain.category.model.Category
import tachiyomi.domain.download.service.DownloadPreferences import tachiyomi.domain.download.service.DownloadPreferences
@@ -35,7 +34,7 @@ object SettingsDownloadScreen : SearchableSettings {
@Composable @Composable
override fun getPreferences(): List<Preference> { override fun getPreferences(): List<Preference> {
val getCategories = remember { Injekt.get<GetCategories>() } val getCategories = remember { Injekt.get<GetCategories>() }
val allCategories by getCategories.subscribe().collectAsState(initial = runBlocking { getCategories.await() }) val allCategories by getCategories.subscribe().collectAsState(initial = emptyList())
val downloadPreferences = remember { Injekt.get<DownloadPreferences>() } val downloadPreferences = remember { Injekt.get<DownloadPreferences>() }
return listOf( return listOf(
@@ -25,7 +25,6 @@ import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.persistentMapOf import kotlinx.collections.immutable.persistentMapOf
import kotlinx.collections.immutable.toImmutableMap import kotlinx.collections.immutable.toImmutableMap
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import tachiyomi.domain.UnsortedPreferences import tachiyomi.domain.UnsortedPreferences
import tachiyomi.domain.category.interactor.GetCategories import tachiyomi.domain.category.interactor.GetCategories
import tachiyomi.domain.category.interactor.ResetCategoryFlags import tachiyomi.domain.category.interactor.ResetCategoryFlags
@@ -57,9 +56,7 @@ object SettingsLibraryScreen : SearchableSettings {
override fun getPreferences(): List<Preference> { override fun getPreferences(): List<Preference> {
val getCategories = remember { Injekt.get<GetCategories>() } val getCategories = remember { Injekt.get<GetCategories>() }
val libraryPreferences = remember { Injekt.get<LibraryPreferences>() } val libraryPreferences = remember { Injekt.get<LibraryPreferences>() }
val allCategories by getCategories.subscribe().collectAsState( val allCategories by getCategories.subscribe().collectAsState(initial = emptyList())
initial = runBlocking { getCategories.await() },
)
// SY --> // SY -->
val unsortedPreferences = remember { Injekt.get<UnsortedPreferences>() } val unsortedPreferences = remember { Injekt.get<UnsortedPreferences>() }
// SY <-- // SY <--
@@ -40,6 +40,7 @@ import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import dev.icerock.moko.resources.StringResource import dev.icerock.moko.resources.StringResource
import eu.kanade.domain.track.model.AutoTrackState
import eu.kanade.domain.track.service.TrackPreferences import eu.kanade.domain.track.service.TrackPreferences
import eu.kanade.presentation.more.settings.Preference import eu.kanade.presentation.more.settings.Preference
import eu.kanade.tachiyomi.data.track.EnhancedTracker import eu.kanade.tachiyomi.data.track.EnhancedTracker
@@ -53,6 +54,7 @@ import eu.kanade.tachiyomi.util.system.openInBrowser
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableList
import kotlinx.collections.immutable.toPersistentMap
import tachiyomi.core.common.util.lang.launchIO import tachiyomi.core.common.util.lang.launchIO
import tachiyomi.core.common.util.lang.withUIContext import tachiyomi.core.common.util.lang.withUIContext
import tachiyomi.domain.source.service.SourceManager import tachiyomi.domain.source.service.SourceManager
@@ -85,6 +87,7 @@ object SettingsTrackingScreen : SearchableSettings {
val trackPreferences = remember { Injekt.get<TrackPreferences>() } val trackPreferences = remember { Injekt.get<TrackPreferences>() }
val trackerManager = remember { Injekt.get<TrackerManager>() } val trackerManager = remember { Injekt.get<TrackerManager>() }
val sourceManager = remember { Injekt.get<SourceManager>() } val sourceManager = remember { Injekt.get<SourceManager>() }
val autoTrackStatePref = trackPreferences.autoUpdateTrackOnMarkRead()
var dialog by remember { mutableStateOf<Any?>(null) } var dialog by remember { mutableStateOf<Any?>(null) }
dialog?.run { dialog?.run {
@@ -125,6 +128,13 @@ object SettingsTrackingScreen : SearchableSettings {
pref = trackPreferences.autoUpdateTrack(), pref = trackPreferences.autoUpdateTrack(),
title = stringResource(MR.strings.pref_auto_update_manga_sync), title = stringResource(MR.strings.pref_auto_update_manga_sync),
), ),
Preference.PreferenceItem.ListPreference(
pref = trackPreferences.autoUpdateTrackOnMarkRead(),
title = stringResource(MR.strings.pref_auto_update_manga_on_mark_read),
entries = AutoTrackState.entries
.associateWith { stringResource(it.titleRes) }
.toPersistentMap(),
),
Preference.PreferenceGroup( Preference.PreferenceGroup(
title = stringResource(MR.strings.services), title = stringResource(MR.strings.services),
preferenceItems = persistentListOf( preferenceItems = persistentListOf(
@@ -25,7 +25,7 @@ import androidx.compose.ui.unit.dp
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.util.system.isPreviewBuildType import eu.kanade.tachiyomi.util.system.isPreviewBuildType
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import nl.adaptivity.xmlutil.AndroidXmlReader import nl.adaptivity.xmlutil.core.AndroidXmlReader
import nl.adaptivity.xmlutil.serialization.XML import nl.adaptivity.xmlutil.serialization.XML
import nl.adaptivity.xmlutil.serialization.XmlSerialName import nl.adaptivity.xmlutil.serialization.XmlSerialName
import nl.adaptivity.xmlutil.serialization.XmlValue import nl.adaptivity.xmlutil.serialization.XmlValue
@@ -84,7 +84,7 @@ fun ReaderAppBars(
enabledPrevious: Boolean, enabledPrevious: Boolean,
currentPage: Int, currentPage: Int,
totalPages: Int, totalPages: Int,
onSliderValueChange: (Int) -> Unit, onPageIndexChange: (Int) -> Unit,
readingMode: ReadingMode, readingMode: ReadingMode,
onClickReadingMode: () -> Unit, onClickReadingMode: () -> Unit,
@@ -154,7 +154,7 @@ fun ReaderAppBars(
enabledPrevious = enabledPrevious, enabledPrevious = enabledPrevious,
currentPage = currentPage, currentPage = currentPage,
totalPages = totalPages, totalPages = totalPages,
onSliderValueChange = onSliderValueChange, onPageIndexChange = onPageIndexChange,
isVerticalSlider = true, isVerticalSlider = true,
currentPageText = currentPageText, currentPageText = currentPageText,
) )
@@ -182,7 +182,7 @@ fun ReaderAppBars(
enabledPrevious = enabledPrevious, enabledPrevious = enabledPrevious,
currentPage = currentPage, currentPage = currentPage,
totalPages = totalPages, totalPages = totalPages,
onSliderValueChange = onSliderValueChange, onPageIndexChange = onPageIndexChange,
isVerticalSlider = true, isVerticalSlider = true,
currentPageText = currentPageText, currentPageText = currentPageText,
) )
@@ -285,7 +285,7 @@ fun ReaderAppBars(
enabledPrevious = enabledPrevious, enabledPrevious = enabledPrevious,
currentPage = currentPage, currentPage = currentPage,
totalPages = totalPages, totalPages = totalPages,
onSliderValueChange = onSliderValueChange, onPageIndexChange = onPageIndexChange,
isVerticalSlider = false, isVerticalSlider = false,
currentPageText = currentPageText, currentPageText = currentPageText,
) )
@@ -18,7 +18,6 @@ import androidx.compose.material3.FilledIconButton
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButtonDefaults import androidx.compose.material3.IconButtonDefaults
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Slider
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.surfaceColorAtElevation import androidx.compose.material3.surfaceColorAtElevation
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -45,8 +44,8 @@ import androidx.compose.ui.unit.dp
import eu.kanade.presentation.theme.TachiyomiPreviewTheme import eu.kanade.presentation.theme.TachiyomiPreviewTheme
import eu.kanade.presentation.util.isTabletUi import eu.kanade.presentation.util.isTabletUi
import tachiyomi.i18n.MR import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.Slider
import tachiyomi.presentation.core.i18n.stringResource import tachiyomi.presentation.core.i18n.stringResource
import kotlin.math.roundToInt
@Composable @Composable
fun ChapterNavigator( fun ChapterNavigator(
@@ -61,7 +60,7 @@ fun ChapterNavigator(
currentPageText: String, currentPageText: String,
// SY <-- // SY <--
totalPages: Int, totalPages: Int,
onSliderValueChange: (Int) -> Unit, onPageIndexChange: (Int) -> Unit,
) { ) {
// SY --> // SY -->
if (isVerticalSlider) { if (isVerticalSlider) {
@@ -73,7 +72,7 @@ fun ChapterNavigator(
currentPage = currentPage, currentPage = currentPage,
currentPageText = currentPageText, currentPageText = currentPageText,
totalPages = totalPages, totalPages = totalPages,
onSliderValueChange = onSliderValueChange, onPageIndexChange = onPageIndexChange,
) )
return return
} }
@@ -138,14 +137,11 @@ fun ChapterNavigator(
modifier = Modifier modifier = Modifier
.weight(1f) .weight(1f)
.padding(horizontal = 8.dp), .padding(horizontal = 8.dp),
value = currentPage.toFloat(), value = currentPage,
valueRange = 1f..totalPages.toFloat(), valueRange = 1..totalPages,
steps = totalPages - 2, onValueChange = f@{
onValueChange = { if (it == currentPage) return@f
val new = it.roundToInt() - 1 onPageIndexChange(it - 1)
if (new != currentPage) {
onSliderValueChange(new)
}
}, },
interactionSource = interactionSource, interactionSource = interactionSource,
) )
@@ -184,7 +180,7 @@ fun ChapterNavigatorVert(
currentPageText: String, currentPageText: String,
// SY <-- // SY <--
totalPages: Int, totalPages: Int,
onSliderValueChange: (Int) -> Unit, onPageIndexChange: (Int) -> Unit,
) { ) {
val isTabletUi = isTabletUi() val isTabletUi = isTabletUi()
val verticalPadding = if (isTabletUi) 24.dp else 8.dp val verticalPadding = if (isTabletUi) 24.dp else 8.dp
@@ -259,11 +255,11 @@ fun ChapterNavigatorVert(
} }
} }
.weight(1f), .weight(1f),
value = currentPage.toFloat(), value = currentPage,
valueRange = 1f..totalPages.toFloat(), valueRange = 1..totalPages,
steps = totalPages, onValueChange = f@{
onValueChange = { if (it == currentPage) return@f
onSliderValueChange(it.roundToInt() - 1) onPageIndexChange(it - 1)
}, },
interactionSource = interactionSource, interactionSource = interactionSource,
) )
@@ -301,7 +297,7 @@ private fun ChapterNavigatorPreview() {
enabledPrevious = true, enabledPrevious = true,
currentPage = currentPage, currentPage = currentPage,
totalPages = 10, totalPages = 10,
onSliderValueChange = { currentPage = it }, onPageIndexChange = { currentPage = (it + 1) },
// SY --> // SY -->
currentPageText = "1", currentPageText = "1",
isVerticalSlider = false, isVerticalSlider = false,
+16 -7
View File
@@ -71,7 +71,7 @@ import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import logcat.LogPriority import logcat.LogPriority
import logcat.LogcatLogger import logcat.LogcatLogger
import mihon.core.firebase.Firebase import mihon.core.firebase.FirebaseConfig
import mihon.core.migration.Migrator import mihon.core.migration.Migrator
import mihon.core.migration.migrations.migrations import mihon.core.migration.migrations.migrations
import org.conscrypt.Conscrypt import org.conscrypt.Conscrypt
@@ -100,6 +100,7 @@ class App : Application(), DefaultLifecycleObserver, SingletonImageLoader.Factor
@SuppressLint("LaunchActivityFromNotification") @SuppressLint("LaunchActivityFromNotification")
override fun onCreate() { override fun onCreate() {
super<Application>.onCreate() super<Application>.onCreate()
FirebaseConfig.init(applicationContext)
GlobalExceptionHandler.initialize(applicationContext, CrashActivity::class.java) GlobalExceptionHandler.initialize(applicationContext, CrashActivity::class.java)
@@ -127,12 +128,12 @@ class App : Application(), DefaultLifecycleObserver, SingletonImageLoader.Factor
setupExhLogging() // EXH logging setupExhLogging() // EXH logging
LogcatLogger.install(XLogLogcatLogger()) // SY Redirect Logcat to XLog LogcatLogger.install(XLogLogcatLogger()) // SY Redirect Logcat to XLog
Firebase.setup(applicationContext, privacyPreferences, ProcessLifecycleOwner.get().lifecycleScope)
setupNotificationChannels() setupNotificationChannels()
ProcessLifecycleOwner.get().lifecycle.addObserver(this) ProcessLifecycleOwner.get().lifecycle.addObserver(this)
val scope = ProcessLifecycleOwner.get().lifecycleScope
// Show notification to disable Incognito Mode when it's enabled // Show notification to disable Incognito Mode when it's enabled
basePreferences.incognitoMode().changes() basePreferences.incognitoMode().changes()
.onEach { enabled -> .onEach { enabled ->
@@ -160,14 +161,22 @@ class App : Application(), DefaultLifecycleObserver, SingletonImageLoader.Factor
cancelNotification(Notifications.ID_INCOGNITO_MODE) cancelNotification(Notifications.ID_INCOGNITO_MODE)
} }
} }
.launchIn(ProcessLifecycleOwner.get().lifecycleScope) .launchIn(scope)
privacyPreferences.analytics()
.changes()
.onEach(FirebaseConfig::setAnalyticsEnabled)
.launchIn(scope)
privacyPreferences.crashlytics()
.changes()
.onEach(FirebaseConfig::setCrashlyticsEnabled)
.launchIn(scope)
setAppCompatDelegateThemeMode(Injekt.get<UiPreferences>().themeMode().get()) setAppCompatDelegateThemeMode(Injekt.get<UiPreferences>().themeMode().get())
// Updates widget update // Updates widget update
with(WidgetManager(Injekt.get(), Injekt.get())) { WidgetManager(Injekt.get(), Injekt.get()).apply { init(scope) }
init(ProcessLifecycleOwner.get().lifecycleScope)
}
/*if (!LogcatLogger.isInstalled && networkPreferences.verboseLogging().get()) { /*if (!LogcatLogger.isInstalled && networkPreferences.verboseLogging().get()) {
LogcatLogger.install(AndroidLogcatLogger(LogPriority.VERBOSE)) LogcatLogger.install(AndroidLogcatLogger(LogPriority.VERBOSE))
@@ -2,8 +2,6 @@ package eu.kanade.tachiyomi.crash
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import com.google.firebase.crashlytics.ktx.crashlytics
import com.google.firebase.ktx.Firebase
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
import kotlinx.serialization.descriptors.PrimitiveKind import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
@@ -13,7 +11,6 @@ import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import logcat.LogPriority import logcat.LogPriority
import tachiyomi.core.common.util.system.logcat import tachiyomi.core.common.util.system.logcat
import kotlin.system.exitProcess
class GlobalExceptionHandler private constructor( class GlobalExceptionHandler private constructor(
private val applicationContext: Context, private val applicationContext: Context,
@@ -33,14 +30,9 @@ class GlobalExceptionHandler private constructor(
} }
override fun uncaughtException(thread: Thread, exception: Throwable) { override fun uncaughtException(thread: Thread, exception: Throwable) {
try { logcat(priority = LogPriority.ERROR, throwable = exception)
logcat(priority = LogPriority.ERROR, throwable = exception) launchActivity(applicationContext, activityToBeLaunched, exception)
Firebase.crashlytics.recordException(exception) defaultHandler.uncaughtException(thread, exception)
launchActivity(applicationContext, activityToBeLaunched, exception)
exitProcess(0)
} catch (_: Exception) {
defaultHandler.uncaughtException(thread, exception)
}
} }
private fun launchActivity( private fun launchActivity(
@@ -1,4 +1,4 @@
@file:Suppress("PropertyName", "ktlint:standard:property-naming") @file:Suppress("PropertyName")
package eu.kanade.tachiyomi.data.database.models package eu.kanade.tachiyomi.data.database.models
@@ -1,4 +1,4 @@
@file:Suppress("PropertyName", "ktlint:standard:property-naming") @file:Suppress("PropertyName")
package eu.kanade.tachiyomi.data.database.models package eu.kanade.tachiyomi.data.database.models
@@ -1,4 +1,4 @@
@file:Suppress("PropertyName", "ktlint:standard:property-naming") @file:Suppress("PropertyName")
package eu.kanade.tachiyomi.data.database.models package eu.kanade.tachiyomi.data.database.models
@@ -1,4 +1,4 @@
@file:Suppress("PropertyName", "ktlint:standard:property-naming") @file:Suppress("PropertyName")
package eu.kanade.tachiyomi.data.database.models package eu.kanade.tachiyomi.data.database.models
@@ -96,13 +96,13 @@ class DownloadCache(
private val diskCacheFile: File private val diskCacheFile: File
get() = File(context.cacheDir, "dl_index_cache_v3") get() = File(context.cacheDir, "dl_index_cache_v3")
private val rootDownloadsDirLock = Mutex() private val rootDownloadsDirMutex = Mutex()
private var rootDownloadsDir = RootDirectory(storageManager.getDownloadsDirectory()) private var rootDownloadsDir = RootDirectory(storageManager.getDownloadsDirectory())
init { init {
// Attempt to read cache file // Attempt to read cache file
scope.launch { scope.launch {
rootDownloadsDirLock.withLock { rootDownloadsDirMutex.withLock {
try { try {
if (diskCacheFile.exists()) { if (diskCacheFile.exists()) {
val diskCache = diskCacheFile.inputStream().use { val diskCache = diskCacheFile.inputStream().use {
@@ -112,7 +112,7 @@ class DownloadCache(
lastRenew = System.currentTimeMillis() lastRenew = System.currentTimeMillis()
} }
} catch (e: Throwable) { } catch (e: Throwable) {
logcat(LogPriority.ERROR, e) { "Failed to initialize disk cache" } logcat(LogPriority.ERROR, e) { "Failed to initialize from disk cache" }
diskCacheFile.delete() diskCacheFile.delete()
} }
} }
@@ -200,7 +200,7 @@ class DownloadCache(
* @param manga the manga of the chapter. * @param manga the manga of the chapter.
*/ */
suspend fun addChapter(chapterDirName: String, mangaUniFile: UniFile, manga: Manga) { suspend fun addChapter(chapterDirName: String, mangaUniFile: UniFile, manga: Manga) {
rootDownloadsDirLock.withLock { rootDownloadsDirMutex.withLock {
// Retrieve the cached source directory or cache a new one // Retrieve the cached source directory or cache a new one
var sourceDir = rootDownloadsDir.sourceDirs[manga.source] var sourceDir = rootDownloadsDir.sourceDirs[manga.source]
if (sourceDir == null) { if (sourceDir == null) {
@@ -232,7 +232,7 @@ class DownloadCache(
* @param manga the manga of the chapter. * @param manga the manga of the chapter.
*/ */
suspend fun removeChapter(chapter: Chapter, manga: Manga) { suspend fun removeChapter(chapter: Chapter, manga: Manga) {
rootDownloadsDirLock.withLock { rootDownloadsDirMutex.withLock {
val sourceDir = rootDownloadsDir.sourceDirs[manga.source] ?: return val sourceDir = rootDownloadsDir.sourceDirs[manga.source] ?: return
val mangaDir = sourceDir.mangaDirs[ val mangaDir = sourceDir.mangaDirs[
provider.getMangaDirName( provider.getMangaDirName(
@@ -251,7 +251,7 @@ class DownloadCache(
// SY --> // SY -->
suspend fun removeFolders(folders: List<String>, manga: Manga) { suspend fun removeFolders(folders: List<String>, manga: Manga) {
rootDownloadsDirLock.withLock { rootDownloadsDirMutex.withLock {
val sourceDir = rootDownloadsDir.sourceDirs[manga.source] ?: return val sourceDir = rootDownloadsDir.sourceDirs[manga.source] ?: return
val mangaDir = sourceDir.mangaDirs[provider.getMangaDirName(manga.ogTitle)] ?: return val mangaDir = sourceDir.mangaDirs[provider.getMangaDirName(manga.ogTitle)] ?: return
folders.forEach { chapter -> folders.forEach { chapter ->
@@ -271,7 +271,7 @@ class DownloadCache(
* @param manga the manga of the chapter. * @param manga the manga of the chapter.
*/ */
suspend fun removeChapters(chapters: List<Chapter>, manga: Manga) { suspend fun removeChapters(chapters: List<Chapter>, manga: Manga) {
rootDownloadsDirLock.withLock { rootDownloadsDirMutex.withLock {
val sourceDir = rootDownloadsDir.sourceDirs[manga.source] ?: return val sourceDir = rootDownloadsDir.sourceDirs[manga.source] ?: return
val mangaDir = sourceDir.mangaDirs[ val mangaDir = sourceDir.mangaDirs[
provider.getMangaDirName( provider.getMangaDirName(
@@ -296,7 +296,7 @@ class DownloadCache(
* @param manga the manga to remove. * @param manga the manga to remove.
*/ */
suspend fun removeManga(manga: Manga) { suspend fun removeManga(manga: Manga) {
rootDownloadsDirLock.withLock { rootDownloadsDirMutex.withLock {
val sourceDir = rootDownloadsDir.sourceDirs[manga.source] ?: return val sourceDir = rootDownloadsDir.sourceDirs[manga.source] ?: return
val mangaDirName = provider.getMangaDirName(/* SY --> */ manga.ogTitle /* SY <-- */) val mangaDirName = provider.getMangaDirName(/* SY --> */ manga.ogTitle /* SY <-- */)
if (sourceDir.mangaDirs.containsKey(mangaDirName)) { if (sourceDir.mangaDirs.containsKey(mangaDirName)) {
@@ -308,7 +308,7 @@ class DownloadCache(
} }
suspend fun removeSource(source: Source) { suspend fun removeSource(source: Source) {
rootDownloadsDirLock.withLock { rootDownloadsDirMutex.withLock {
rootDownloadsDir.sourceDirs -= source.id rootDownloadsDir.sourceDirs -= source.id
} }
@@ -349,10 +349,10 @@ class DownloadCache(
val sourceMap = sources.associate { provider.getSourceDirName(it).lowercase() to it.id } val sourceMap = sources.associate { provider.getSourceDirName(it).lowercase() to it.id }
rootDownloadsDirLock.withLock { rootDownloadsDirMutex.withLock {
rootDownloadsDir = RootDirectory(storageManager.getDownloadsDirectory()) val updatedRootDir = RootDirectory(storageManager.getDownloadsDirectory())
val sourceDirs = rootDownloadsDir.dir?.listFiles().orEmpty() updatedRootDir.sourceDirs = updatedRootDir.dir?.listFiles().orEmpty()
.filter { it.isDirectory && !it.name.isNullOrBlank() } .filter { it.isDirectory && !it.name.isNullOrBlank() }
.mapNotNull { dir -> .mapNotNull { dir ->
val sourceId = sourceMap[dir.name!!.lowercase()] val sourceId = sourceMap[dir.name!!.lowercase()]
@@ -360,36 +360,35 @@ class DownloadCache(
} }
.toMap() .toMap()
rootDownloadsDir.sourceDirs = sourceDirs updatedRootDir.sourceDirs.values.map { sourceDir ->
async {
sourceDir.mangaDirs = sourceDir.dir?.listFiles().orEmpty()
.filter { it.isDirectory && !it.name.isNullOrBlank() }
.associate { it.name!! to MangaDirectory(it) }
sourceDirs.values sourceDir.mangaDirs.values.forEach { mangaDir ->
.map { sourceDir -> val chapterDirs = mangaDir.dir?.listFiles().orEmpty()
async { .mapNotNull {
sourceDir.mangaDirs = sourceDir.dir?.listFiles().orEmpty() when {
.filter { it.isDirectory && !it.name.isNullOrBlank() } // Ignore incomplete downloads
.associate { it.name!! to MangaDirectory(it) } it.name?.endsWith(Downloader.TMP_DIR_SUFFIX) == true -> null
// Folder of images
sourceDir.mangaDirs.values.forEach { mangaDir -> it.isDirectory -> it.name
val chapterDirs = mangaDir.dir?.listFiles().orEmpty() // CBZ files
.mapNotNull { it.isFile && it.extension == "cbz" -> it.nameWithoutExtension
when { // Anything else is irrelevant
// Ignore incomplete downloads else -> null
it.name?.endsWith(Downloader.TMP_DIR_SUFFIX) == true -> null
// Folder of images
it.isDirectory -> it.name
// CBZ files
it.isFile && it.extension == "cbz" -> it.nameWithoutExtension
// Anything else is irrelevant
else -> null
}
} }
.toMutableSet() }
.toMutableSet()
mangaDir.chapterDirs = chapterDirs mangaDir.chapterDirs = chapterDirs
}
} }
} }
}
.awaitAll() .awaitAll()
rootDownloadsDir = updatedRootDir
} }
_isInitializing.emit(false) _isInitializing.emit(false)
@@ -404,7 +404,7 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
it.read it.read
} }
val newReadChapters = this.filter { chapter -> val newReadChapters = this.filter { chapter ->
chapter.chapterNumber > 0 && chapter.chapterNumber >= 0 &&
readChapters.any { readChapters.any {
it.chapterNumber == chapter.chapterNumber it.chapterNumber == chapter.chapterNumber
} }
@@ -1,4 +1,4 @@
@file:Suppress("PropertyName", "ktlint:standard:property-naming") @file:Suppress("PropertyName")
package eu.kanade.tachiyomi.data.track.model package eu.kanade.tachiyomi.data.track.model
@@ -14,10 +14,12 @@ import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import logcat.LogPriority import logcat.LogPriority
import rikka.shizuku.Shizuku import rikka.shizuku.Shizuku
import rikka.shizuku.ShizukuRemoteProcess
import tachiyomi.core.common.util.system.logcat import tachiyomi.core.common.util.system.logcat
import tachiyomi.i18n.MR import tachiyomi.i18n.MR
import java.io.BufferedReader import java.io.BufferedReader
import java.io.InputStream import java.io.InputStream
import java.lang.reflect.Method
class ShizukuInstaller(private val service: Service) : Installer(service) { class ShizukuInstaller(private val service: Service) : Installer(service) {
@@ -93,9 +95,9 @@ class ShizukuInstaller(private val service: Service) : Installer(service) {
super.onDestroy() super.onDestroy()
} }
private val newProcess: Method
private fun exec(command: String, stdin: InputStream? = null): ShellResult { private fun exec(command: String, stdin: InputStream? = null): ShellResult {
@Suppress("DEPRECATION") val process = newProcess.invoke(null, arrayOf("sh", "-c", command), null, null) as ShizukuRemoteProcess
val process = Shizuku.newProcess(arrayOf("sh", "-c", command), null, null)
if (stdin != null) { if (stdin != null) {
process.outputStream.use { stdin.copyTo(it) } process.outputStream.use { stdin.copyTo(it) }
} }
@@ -122,6 +124,9 @@ class ShizukuInstaller(private val service: Service) : Installer(service) {
service.stopSelf() service.stopSelf()
false false
} }
newProcess = Shizuku::class.java
.getDeclaredMethod("newProcess", Array::class.java, Array::class.java, String::class.java)
newProcess.isAccessible = true
} }
} }
@@ -449,7 +449,11 @@ class EHentai(
private fun parseChapterPage(response: Element) = with(response) { private fun parseChapterPage(response: Element) = with(response) {
select(".gdtm a").map { select(".gdtm a").map {
Pair(it.child(0).attr("alt").toInt(), it.attr("href")) Pair(it.child(0).attr("alt").toInt(), it.attr("href"))
}.sortedBy(Pair<Int, String>::first).map { it.second } }.plus(
select("#gdt a").map {
Pair(it.child(0).attr("title").removePrefix("Page ").substringBefore(":").toInt(), it.attr("href"))
},
).sortedBy(Pair<Int, String>::first).map { it.second }
} }
private fun chapterPageCall(np: String): Observable<Response> { private fun chapterPageCall(np: String): Observable<Response> {
@@ -1214,7 +1218,8 @@ class EHentai(
val body = doc.body() val body = doc.body()
val previews = body val previews = body
.select("#gdt div div") .select("#gdt > div > div")
.plus(body.select("#gdt > a"))
.map { .map {
val preview = parseNormalPreview(it) val preview = parseNormalPreview(it)
PagePreviewInfo(preview.index, imageUrl = preview.toUrl()) PagePreviewInfo(preview.index, imageUrl = preview.toUrl())
@@ -1250,8 +1255,15 @@ class EHentai(
* Parse normal previews with regular expressions * Parse normal previews with regular expressions
*/ */
private fun parseNormalPreview(element: Element): EHentaiThumbnailPreview { private fun parseNormalPreview(element: Element): EHentaiThumbnailPreview {
val index = element.selectFirst("img")!!.attr("alt").toInt() val imgElement = element.selectFirst("img")
val styles = element.attr("style").split(";").mapNotNull { it.trimOrNull() } val index = imgElement?.attr("alt")?.toInt()
?: element.child(0).attr("title").removePrefix("Page ").substringBefore(":").toInt()
val styleElement = if (imgElement != null) {
element
} else {
element.child(0)
}
val styles = styleElement.attr("style").split(";").mapNotNull { it.trimOrNull() }
val width = styles.first { it.startsWith("width:") } val width = styles.first { it.startsWith("width:") }
.removePrefix("width:") .removePrefix("width:")
.removeSuffix("px") .removeSuffix("px")
@@ -1275,7 +1287,7 @@ class EHentai(
.removeSuffix("px") .removeSuffix("px")
.toInt() .toInt()
return EHentaiThumbnailPreview(url, width, height, widthOffset, index).also(::println) return EHentaiThumbnailPreview(url, width, height, widthOffset, index)
} }
data class EHentaiThumbnailPreview( data class EHentaiThumbnailPreview(
val imageUrl: String, val imageUrl: String,
@@ -346,12 +346,13 @@ class MainActivity : BaseActivity() {
@Composable @Composable
private fun HandleOnNewIntent(context: Context, navigator: Navigator) { private fun HandleOnNewIntent(context: Context, navigator: Navigator) {
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
callbackFlow<Intent> { callbackFlow {
val componentActivity = context as ComponentActivity val componentActivity = context as ComponentActivity
val consumer = Consumer<Intent> { trySend(it) } val consumer = Consumer<Intent> { trySend(it) }
componentActivity.addOnNewIntentListener(consumer) componentActivity.addOnNewIntentListener(consumer)
awaitClose { componentActivity.removeOnNewIntentListener(consumer) } awaitClose { componentActivity.removeOnNewIntentListener(consumer) }
}.collectLatest { handleIntentAction(it, navigator) } }
.collectLatest { handleIntentAction(it, navigator) }
} }
} }
@@ -407,6 +408,7 @@ class MainActivity : BaseActivity() {
* When custom animation is used, status and navigation bar color will be set to transparent and will be restored * When custom animation is used, status and navigation bar color will be set to transparent and will be restored
* after the animation is finished. * after the animation is finished.
*/ */
@Suppress("Deprecation")
private fun setSplashScreenExitAnimation(splashScreen: SplashScreen?) { private fun setSplashScreenExitAnimation(splashScreen: SplashScreen?) {
val root = findViewById<View>(android.R.id.content) val root = findViewById<View>(android.R.id.content)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S && splashScreen != null) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S && splashScreen != null) {
@@ -29,7 +29,9 @@ import eu.kanade.domain.manga.model.toSManga
import eu.kanade.domain.source.service.SourcePreferences import eu.kanade.domain.source.service.SourcePreferences
import eu.kanade.domain.track.interactor.AddTracks import eu.kanade.domain.track.interactor.AddTracks
import eu.kanade.domain.track.interactor.TrackChapter import eu.kanade.domain.track.interactor.TrackChapter
import eu.kanade.domain.track.model.AutoTrackState
import eu.kanade.domain.track.model.toDomainTrack import eu.kanade.domain.track.model.toDomainTrack
import eu.kanade.domain.track.service.TrackPreferences
import eu.kanade.domain.ui.UiPreferences import eu.kanade.domain.ui.UiPreferences
import eu.kanade.presentation.manga.DownloadAction import eu.kanade.presentation.manga.DownloadAction
import eu.kanade.presentation.manga.components.ChapterDownloadAction import eu.kanade.presentation.manga.components.ChapterDownloadAction
@@ -48,6 +50,7 @@ import eu.kanade.tachiyomi.source.online.all.MergedSource
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
import eu.kanade.tachiyomi.util.chapter.getNextUnread import eu.kanade.tachiyomi.util.chapter.getNextUnread
import eu.kanade.tachiyomi.util.removeCovers import eu.kanade.tachiyomi.util.removeCovers
import eu.kanade.tachiyomi.util.system.toast
import exh.debug.DebugToggles import exh.debug.DebugToggles
import exh.eh.EHentaiUpdateHelper import exh.eh.EHentaiUpdateHelper
import exh.log.xLogD import exh.log.xLogD
@@ -145,6 +148,7 @@ class MangaScreenModel(
private val isFromSource: Boolean, private val isFromSource: Boolean,
val smartSearched: Boolean, val smartSearched: Boolean,
private val libraryPreferences: LibraryPreferences = Injekt.get(), private val libraryPreferences: LibraryPreferences = Injekt.get(),
private val trackPreferences: TrackPreferences = Injekt.get(),
readerPreferences: ReaderPreferences = Injekt.get(), readerPreferences: ReaderPreferences = Injekt.get(),
uiPreferences: UiPreferences = Injekt.get(), uiPreferences: UiPreferences = Injekt.get(),
private val trackerManager: TrackerManager = Injekt.get(), private val trackerManager: TrackerManager = Injekt.get(),
@@ -208,6 +212,7 @@ class MangaScreenModel(
val chapterSwipeStartAction = libraryPreferences.swipeToEndAction().get() val chapterSwipeStartAction = libraryPreferences.swipeToEndAction().get()
val chapterSwipeEndAction = libraryPreferences.swipeToStartAction().get() val chapterSwipeEndAction = libraryPreferences.swipeToStartAction().get()
var autoTrackState = trackPreferences.autoUpdateTrackOnMarkRead().get()
private val skipFiltered by readerPreferences.skipFiltered().asState(screenModelScope) private val skipFiltered by readerPreferences.skipFiltered().asState(screenModelScope)
@@ -1264,13 +1269,25 @@ class MangaScreenModel(
chapters = chapters.toTypedArray(), chapters = chapters.toTypedArray(),
) )
if (!read) return@launchIO if (
successState?.hasLoggedInTrackers == false ||
!read || autoTrackState == AutoTrackState.NEVER
) {
return@launchIO
}
val tracks = getTracks.await(mangaId) val tracks = getTracks.await(mangaId)
val maxChapterNumber = chapters.maxOf { it.chapterNumber } val maxChapterNumber = chapters.maxOf { it.chapterNumber }
val shouldPromptTrackingUpdate = tracks.any { track -> maxChapterNumber > track.lastChapterRead } val shouldPromptTrackingUpdate = tracks.any { track -> maxChapterNumber > track.lastChapterRead }
if (!shouldPromptTrackingUpdate) return@launchIO if (!shouldPromptTrackingUpdate) return@launchIO
if (autoTrackState == AutoTrackState.ALWAYS) {
trackChapter.await(context, mangaId, maxChapterNumber)
withUIContext {
context.toast(context.stringResource(MR.strings.trackers_updated_summary, maxChapterNumber.toInt()))
}
return@launchIO
}
val result = snackbarHostState.showSnackbar( val result = snackbarHostState.showSnackbar(
message = context.stringResource(MR.strings.confirm_tracker_update, maxChapterNumber.toInt()), message = context.stringResource(MR.strings.confirm_tracker_update, maxChapterNumber.toInt()),
@@ -824,7 +824,11 @@ private data class TrackerRemoveScreen(
fun deleteMangaFromService() { fun deleteMangaFromService() {
screenModelScope.launchNonCancellable { screenModelScope.launchNonCancellable {
(tracker as DeletableTracker).delete(track) try {
(tracker as DeletableTracker).delete(track)
} catch (e: Exception) {
logcat(LogPriority.ERROR, e) { "Failed to delete entry from service" }
}
} }
} }
@@ -478,7 +478,7 @@ class ReaderActivity : BaseActivity() {
enabledPrevious = state.viewerChapters?.prevChapter != null, enabledPrevious = state.viewerChapters?.prevChapter != null,
currentPage = state.currentPage, currentPage = state.currentPage,
totalPages = state.totalPages, totalPages = state.totalPages,
onSliderValueChange = { onPageIndexChange = {
isScrollingThroughPages = true isScrollingThroughPages = true
moveToPageIndex(it) moveToPageIndex(it)
}, },
@@ -700,7 +700,7 @@ class ReaderViewModel @JvmOverloads constructor(
// SY <-- // SY <--
readerChapter.chapter.read = true readerChapter.chapter.read = true
// SY --> // SY -->
if (readerChapter.chapter.chapter_number > 0 && readerPreferences.markReadDupe().get()) { if (readerChapter.chapter.chapter_number >= 0 && readerPreferences.markReadDupe().get()) {
getChaptersByMangaId.await(manga!!.id).sortedByDescending { it.sourceOrder } getChaptersByMangaId.await(manga!!.id).sortedByDescending { it.sourceOrder }
.filter { .filter {
it.id != readerChapter.chapter.id && it.id != readerChapter.chapter.id &&
@@ -1,20 +0,0 @@
package mihon.core.firebase
import android.content.Context
import com.google.firebase.analytics.FirebaseAnalytics
import com.google.firebase.crashlytics.FirebaseCrashlytics
import eu.kanade.tachiyomi.core.security.PrivacyPreferences
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
object Firebase {
fun setup(context: Context, preference: PrivacyPreferences, scope: CoroutineScope) {
preference.analytics().changes().onEach { enabled ->
FirebaseAnalytics.getInstance(context).setAnalyticsCollectionEnabled(enabled)
}.launchIn(scope)
preference.crashlytics().changes().onEach { enabled ->
FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(enabled)
}.launchIn(scope)
}
}
@@ -0,0 +1,25 @@
package mihon.core.firebase
import android.content.Context
import com.google.firebase.FirebaseApp
import com.google.firebase.analytics.FirebaseAnalytics
import com.google.firebase.crashlytics.FirebaseCrashlytics
object FirebaseConfig {
private lateinit var analytics: FirebaseAnalytics
private lateinit var crashlytics: FirebaseCrashlytics
fun init(context: Context) {
analytics = FirebaseAnalytics.getInstance(context)
FirebaseApp.initializeApp(context)
crashlytics = FirebaseCrashlytics.getInstance()
}
fun setAnalyticsEnabled(enabled: Boolean) {
analytics.setAnalyticsCollectionEnabled(enabled)
}
fun setCrashlyticsEnabled(enabled: Boolean) {
crashlytics.isCrashlyticsCollectionEnabled = enabled
}
}
@@ -1,4 +1,4 @@
@file:Suppress("FunctionName", "ktlint:standard:function-naming") @file:Suppress("FunctionName")
package eu.kanade.tachiyomi.network package eu.kanade.tachiyomi.network
+2 -2
View File
@@ -7,7 +7,7 @@ interpolator_version = "1.0.0"
[libraries] [libraries]
gradle = { module = "com.android.tools.build:gradle", version.ref = "agp_version" } gradle = { module = "com.android.tools.build:gradle", version.ref = "agp_version" }
annotation = "androidx.annotation:annotation:1.8.2" annotation = "androidx.annotation:annotation:1.9.0"
appcompat = "androidx.appcompat:appcompat:1.7.0" appcompat = "androidx.appcompat:appcompat:1.7.0"
biometricktx = "androidx.biometric:biometric-ktx:1.2.0-alpha05" biometricktx = "androidx.biometric:biometric-ktx:1.2.0-alpha05"
constraintlayout = "androidx.constraintlayout:constraintlayout:2.1.4" constraintlayout = "androidx.constraintlayout:constraintlayout:2.1.4"
@@ -28,7 +28,7 @@ paging-compose = { module = "androidx.paging:paging-compose", version.ref = "pag
interpolator = { group = "androidx.interpolator", name = "interpolator", version.ref = "interpolator_version" } interpolator = { group = "androidx.interpolator", name = "interpolator", version.ref = "interpolator_version" }
benchmark-macro = "androidx.benchmark:benchmark-macro-junit4:1.3.2" benchmark-macro = "androidx.benchmark:benchmark-macro-junit4:1.3.3"
test-ext = "androidx.test.ext:junit-ktx:1.2.1" test-ext = "androidx.test.ext:junit-ktx:1.2.1"
test-espresso-core = "androidx.test.espresso:espresso-core:3.6.1" test-espresso-core = "androidx.test.espresso:espresso-core:3.6.1"
test-uiautomator = "androidx.test.uiautomator:uiautomator:2.3.0" test-uiautomator = "androidx.test.uiautomator:uiautomator:2.3.0"
+3 -3
View File
@@ -1,8 +1,8 @@
[versions] [versions]
compose-bom = "2024.09.03" compose-bom = "2024.10.00"
[libraries] [libraries]
activity = "androidx.activity:activity-compose:1.9.2" activity = "androidx.activity:activity-compose:1.9.3"
bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" } bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" }
foundation = { module = "androidx.compose.foundation:foundation" } foundation = { module = "androidx.compose.foundation:foundation" }
animation = { module = "androidx.compose.animation:animation" } animation = { module = "androidx.compose.animation:animation" }
@@ -15,4 +15,4 @@ ui-util = { module = "androidx.compose.ui:ui-util" }
material3-core = { module = "androidx.compose.material3:material3" } material3-core = { module = "androidx.compose.material3:material3" }
material-icons = { module = "androidx.compose.material:material-icons-extended" } material-icons = { module = "androidx.compose.material:material-icons-extended" }
glance = "androidx.glance:glance-appwidget:1.1.0" glance = "androidx.glance:glance-appwidget:1.1.1"
+1 -1
View File
@@ -1,7 +1,7 @@
[versions] [versions]
kotlin_version = "2.0.21" kotlin_version = "2.0.21"
serialization_version = "1.7.3" serialization_version = "1.7.3"
xml_serialization_version = "0.86.3" xml_serialization_version = "0.90.2"
[libraries] [libraries]
reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin_version" } reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin_version" }
+5 -5
View File
@@ -4,13 +4,13 @@ leakcanary = "2.14"
moko = "0.24.2" moko = "0.24.2"
okhttp_version = "5.0.0-alpha.14" okhttp_version = "5.0.0-alpha.14"
richtext = "0.20.0" richtext = "0.20.0"
shizuku_version = "12.2.0" shizuku_version = "13.1.5"
sqldelight = "2.0.2" sqldelight = "2.0.2"
sqlite = "2.4.0" sqlite = "2.4.0"
voyager = "1.0.0" voyager = "1.0.0"
spotless = "6.25.0" spotless = "6.25.0"
ktlint-core = "1.3.1" ktlint-core = "1.4.0"
firebase-bom = "33.4.0" firebase-bom = "33.5.1"
[libraries] [libraries]
desugar = "com.android.tools:desugar_jdk_libs:2.1.2" desugar = "com.android.tools:desugar_jdk_libs:2.1.2"
@@ -32,7 +32,7 @@ jsoup = "org.jsoup:jsoup:1.18.1"
disklrucache = "com.jakewharton:disklrucache:2.0.2" disklrucache = "com.jakewharton:disklrucache:2.0.2"
unifile = "com.github.tachiyomiorg:unifile:e0def6b3dc" unifile = "com.github.tachiyomiorg:unifile:e0def6b3dc"
libarchive = "me.zhanghai.android.libarchive:library:1.1.3" libarchive = "me.zhanghai.android.libarchive:library:1.1.4"
sqlite-framework = { module = "androidx.sqlite:sqlite-framework", version.ref = "sqlite" } sqlite-framework = { module = "androidx.sqlite:sqlite-framework", version.ref = "sqlite" }
sqlite-ktx = { module = "androidx.sqlite:sqlite-ktx", version.ref = "sqlite" } sqlite-ktx = { module = "androidx.sqlite:sqlite-ktx", version.ref = "sqlite" }
@@ -89,7 +89,7 @@ sqldelight-coroutines = { module = "app.cash.sqldelight:coroutines-extensions-jv
sqldelight-android-paging = { module = "app.cash.sqldelight:androidx-paging3-extensions", version.ref = "sqldelight" } sqldelight-android-paging = { module = "app.cash.sqldelight:androidx-paging3-extensions", version.ref = "sqldelight" }
sqldelight-dialects-sql = { module = "app.cash.sqldelight:sqlite-3-38-dialect", version.ref = "sqldelight" } sqldelight-dialects-sql = { module = "app.cash.sqldelight:sqlite-3-38-dialect", version.ref = "sqldelight" }
junit = "org.junit.jupiter:junit-jupiter:5.11.2" junit = "org.junit.jupiter:junit-jupiter:5.11.3"
kotest-assertions = "io.kotest:kotest-assertions-core:5.9.1" kotest-assertions = "io.kotest:kotest-assertions-core:5.9.1"
mockk = "io.mockk:mockk:1.13.13" mockk = "io.mockk:mockk:1.13.13"
@@ -272,7 +272,7 @@
<string name="friday">শুক্ৰবাৰ</string> <string name="friday">শুক্ৰবাৰ</string>
<string name="encrypt_database">ডেটাবেছ এনক্ৰিপ্ট কৰক</string> <string name="encrypt_database">ডেটাবেছ এনক্ৰিপ্ট কৰক</string>
<string name="encrypt_database_subtitle">প্ৰভাৱিত হ’বলৈ অ্যাপ পুনৰাৰম্ভৰ প্ৰয়োজন</string> <string name="encrypt_database_subtitle">প্ৰভাৱিত হ’বলৈ অ্যাপ পুনৰাৰম্ভৰ প্ৰয়োজন</string>
<string name="encrypt_database_message">&lt;font color=\'red\'&gt;ই চমু হোৱাৰ অৰ্থ হৈছে নতুন ডেটাবেছ সৃষ্টি কৰা হ’ব। আপোনাৰ ডাটা সংৰক্ষণৰ বাবে এই পদক্ষেপসমূহ ব্যৱহাৰ কৰক&lt;br&gt;1. SETTINGS -&gt; BACKUP -&gt; CREATE&lt;br&gt;2. SYSTEM SETTINGS -&gt; CLEAR APP DATA&lt;br&gt;3. APP খোলক আৰু এনক্ৰিপ্ট কৰক&lt;br&gt;4. SYSTEM SETTINGS -&gt; FORCE RESTART&lt;br&gt;5. SETTINGS -&gt; BACKUP -&gt; RESTORE&lt;/font&gt;</string> <string name="encrypt_database_message"><![CDATA[<font color=\'red\'>ই চমু হোৱাৰ অৰ্থ হৈছে নতুন ডেটাবেছ সৃষ্টি কৰা হ’ব। আপোনাৰ ডাটা সংৰক্ষণৰ বাবে এই পদক্ষেপসমূহ ব্যৱহাৰ কৰক<br>1. SETTINGS -> BACKUP -> CREATE<br>2. SYSTEM SETTINGS -> CLEAR APP DATA<br>3. APP খোলক আৰু এনক্ৰিপ্ট কৰক<br>4. SYSTEM SETTINGS -> FORCE RESTART<br>5. SETTINGS -> BACKUP -> RESTORE</font>]]></string>
<string name="password_protect_downloads">ডাউনলোডসমূহ পাসৱৰ্ডৰ দ্বাৰা ৰক্ষা কৰক</string> <string name="password_protect_downloads">ডাউনলোডসমূহ পাসৱৰ্ডৰ দ্বাৰা ৰক্ষা কৰক</string>
<string name="delete_cbz_archive_password">CBZ আর্কাইভ পাসৱৰ্ড মচি দিয়ক</string> <string name="delete_cbz_archive_password">CBZ আর্কাইভ পাসৱৰ্ড মচি দিয়ক</string>
<string name="cbz_archive_password">CBZ আর্কাইভ পাসৱৰ্ড</string> <string name="cbz_archive_password">CBZ আর্কাইভ পাসৱৰ্ড</string>
@@ -472,7 +472,7 @@
<string name="favorites_sync_processing_throttle">%1$s <string name="favorites_sync_processing_throttle">%1$s
\n \n
\nচিঞৰ বৰ্তমান থ্ৰ\'টেল হৈছে (ExHentaiৰ পৰা নিষিদ্ধ হোৱাৰ পৰা বাচিবলৈ) আৰু সম্পূৰ্ণ হ\'বলৈ বহু সময় লাগিব পাৰে।</string> \nচিঞৰ বৰ্তমান থ্ৰ\'টেল হৈছে (ExHentaiৰ পৰা নিষিদ্ধ হোৱাৰ পৰা বাচিবলৈ) আৰু সম্পূৰ্ণ হ\'বলৈ বহু সময় লাগিব পাৰে।</string>
<string name="favorites_sync_notes_message">1. এপৰ বিভাগৰ নামত হোৱা পৰিবৰ্তনসমূহ &lt;b&gt;সমন্বিত নহয়&lt;/b&gt;! দয়া কৰি &lt;i&gt;ExHentaiত বিভাগৰ নাম সলনি কৰক&lt;/i&gt;। বিভাগৰ নামবোৰ প্ৰত্যেকবাৰ সমন্বয়ৰ সময়ত ExHentai চাৰ্ভাৰসমূহৰ পৰা নকল কৰা হব।&lt;br&gt;&lt;br&gt;2. ExHentaiত থকা পছন্দৰ বিভাগসমূহ এপৰ &lt;b&gt;প্ৰথম 10 বিভাগৰ সৈতে মিলে&lt;/b&gt; (‘Default’ বিভাগ বাদে)। &lt;i&gt;অন্যান্য বিভাগৰ গেছবুকসমূহ &lt;b&gt;সমন্বিত নহ’ব&lt;/b&gt;!&lt;/i&gt;&lt;br&gt;&lt;br&gt;3. &lt;font color=\'red\'&gt;&lt;b&gt;সমন্বয়ৰ সময়ত নিশ্চিত কৰক যে আপোনাৰ ইণ্টাৰনেট সংযোগ স্থিৰ আছে!&lt;/b&gt;&lt;/font&gt; যদি চিঞৰ চলি থকা সময়ত ইণ্টাৰনেট বিচ্ছিন্ন হয়, তেন্তে আপোনাৰ চিঞৰসমূহ &lt;i&gt;আংশিকভাৱে সমন্বিত অৱস্থা&lt;/i&gt;ত ৰোৱা হ\'ব পাৰে।&lt;br&gt;&lt;br&gt;4. চিঞৰ চলি থকা সময়ত এপ খোলা ৰাখক। Android পিছৰ পটত থকা এপসমূহ বন্ধ কৰিব পাৰে আৰু ই যদি চিঞৰ চলি থকা সময়ত হয় তেন্তে ই বেয়া হ\'ব পাৰে।&lt;br&gt;&lt;br&gt;5. &lt;b&gt;পছন্দসমূহ একাধিক বিভাগত ৰাখিব নালাগে&lt;/b&gt; (এপই ইয়াৰ সমৰ্থন কৰে)। এইয়ে সমন্বয় এলগ\'ৰিদমৰ বিভ্ৰান্তি সৃষ্টি কৰিব পাৰে কিয়নো ExHentai প্ৰত্যেক পছন্দৰ একেটা বিভাগতে থকাটো অনুমতি দিয়ে।&lt;br&gt;&lt;br&gt;এই সংলাপ মাত্ৰ একবাৰ আহিব। আপুনি \'Settings &gt; E-Hentai &gt; Show favorites sync notes\' ত গৈ পুনৰ এই মন্তব্যসমূহ পঢ়িব পাৰে।</string> <string name="favorites_sync_notes_message"><![CDATA[1. এপৰ বিভাগৰ নামত হোৱা পৰিবৰ্তনসমূহ <b>সমন্বিত নহয়</b>! দয়া কৰি <i>ExHentaiত বিভাগৰ নাম সলনি কৰক</i>। বিভাগৰ নামবোৰ প্ৰত্যেকবাৰ সমন্বয়ৰ সময়ত ExHentai চাৰ্ভাৰসমূহৰ পৰা নকল কৰা হব।<br><br>2. ExHentaiত থকা পছন্দৰ বিভাগসমূহ এপৰ <b>প্ৰথম 10 বিভাগৰ সৈতে মিলে</b> (\Default\ বিভাগ বাদে)। <i>অন্যান্য বিভাগৰ গেছবুকসমূহ <b>সমন্বিত নহ’ব</b>!</i><br><br>3. <font color=\'red\'><b>সমন্বয়ৰ সময়ত নিশ্চিত কৰক যে আপোনাৰ ইণ্টাৰনেট সংযোগ স্থিৰ আছে!</b></font> যদি চিঞৰ চলি থকা সময়ত ইণ্টাৰনেট বিচ্ছিন্ন হয়, তেন্তে আপোনাৰ চিঞৰসমূহ <i>আংশিকভাৱে সমন্বিত অৱস্থা</i>ত ৰোৱা হ'ব পাৰে।<br><br>4. চিঞৰ চলি থকা সময়ত এপ খোলা ৰাখক। Android পিছৰ পটত থকা এপসমূহ বন্ধ কৰিব পাৰে আৰু ই যদি চিঞৰ চলি থকা সময়ত হয় তেন্তে ই বেয়া হ'ব পাৰে।<br><br>5. <b>পছন্দসমূহ একাধিক বিভাগত ৰাখিব নালাগে</b> (এপই ইয়াৰ সমৰ্থন কৰে)। এইয়ে সমন্বয় এলগ'ৰিদমৰ বিভ্ৰান্তি সৃষ্টি কৰিব পাৰে কিয়নো ExHentai প্ৰত্যেক পছন্দৰ একেটা বিভাগতে থকাটো অনুমতি দিয়ে।<br><br>এই সংলাপ মাত্ৰ একবাৰ আহিব। আপুনি \'Settings > E-Hentai > Show favorites sync notes'\ ত গৈ পুনৰ এই মন্তব্যসমূহ পঢ়িব পাৰে।]]></string>
<string name="favorites_sync_reset">আপুনি নিশ্চিতনে?</string> <string name="favorites_sync_reset">আপুনি নিশ্চিতনে?</string>
<string name="favorites_sync_conformation_message">আপুনি নিশ্চিত যে আপোনাৰ পছন্দসমূহ E-Hentaiৰ সৈতে সমন্বয় কৰিবলৈ ইচ্ছা কৰিছে?</string> <string name="favorites_sync_conformation_message">আপুনি নিশ্চিত যে আপোনাৰ পছন্দসমূহ E-Hentaiৰ সৈতে সমন্বয় কৰিবলৈ ইচ্ছা কৰিছে?</string>
<string name="favorites_sync_reset_message">চিঞৰ অৱস্থা পুনৰ ছেট কৰাৰ ফলত আপোনাৰ পৰবর্তী চিঞৰ অত্যন্ত ধীৰ গতিত হ\'ব পাৰে।</string> <string name="favorites_sync_reset_message">চিঞৰ অৱস্থা পুনৰ ছেট কৰাৰ ফলত আপোনাৰ পৰবর্তী চিঞৰ অত্যন্ত ধীৰ গতিত হ\'ব পাৰে।</string>
@@ -636,4 +636,7 @@
\nসতর্কতা: পাসৱৰ্ড ভুলিলে আর্কাইভৰ ভিতৰ ডাটা চিৰদিনৰ বাবে হেৰাই যাব</string> \nসতর্কতা: পাসৱৰ্ড ভুলিলে আর্কাইভৰ ভিতৰ ডাটা চিৰদিনৰ বাবে হেৰাই যাব</string>
<string name="rating5">মধ্যমীয়া</string> <string name="rating5">মধ্যমীয়া</string>
<string name="relation_sequel">ছিকুৱেল</string> <string name="relation_sequel">ছিকুৱেল</string>
<string name="add_tags">টেগ যোগ কৰক</string>
<string name="multi_tags_comma_separated">টেগ(সমূহ), ক\'মা ব্যৱহাৰ কৰি প্ৰৱেশ কৰক।</string>
<string name="alt_titles">বিকল্প শিৰোনামসমূহ</string>
</resources> </resources>
@@ -60,7 +60,7 @@
<string name="tag_watching_threshhold">Umbral de Monitoreo de Etiquetas</string> <string name="tag_watching_threshhold">Umbral de Monitoreo de Etiquetas</string>
<string name="tag_watching_threshhold_summary">Las galerías recientemente subidas se incluirán en la pantalla de observación si tienen al menos una etiqueta observada con peso positivo, y la suma de los pesos de sus etiquetas observadas alcanza este valor o es mayor. Este umbral se puede establecer entre 0 y 9999. Actualmente: %1$d</string> <string name="tag_watching_threshhold_summary">Las galerías recientemente subidas se incluirán en la pantalla de observación si tienen al menos una etiqueta observada con peso positivo, y la suma de los pesos de sus etiquetas observadas alcanza este valor o es mayor. Este umbral se puede establecer entre 0 y 9999. Actualmente: %1$d</string>
<string name="watched_list_default">Estado Predeterminado del Filtro de la Lista Observada</string> <string name="watched_list_default">Estado Predeterminado del Filtro de la Lista Observada</string>
<string name="watched_list_state_summary">Cuando navegas por ExHentai/E-Hentai, ¿debería estar habilitado por defecto el filtro de la lista observada?</string> <string name="watched_list_state_summary">Al navegar por ExHentai/E-Hentai, ¿debería estar activado por defecto el filtro de la lista vigilada?</string>
<string name="pref_enhanced_e_hentai_view_summary">Habilitar/Deshabilitar el menú de navegación mejorado hecho para E/ExHentai</string> <string name="pref_enhanced_e_hentai_view_summary">Habilitar/Deshabilitar el menú de navegación mejorado hecho para E/ExHentai</string>
<string name="favorites_sync">Sincronización de Favoritos de E-Hentai</string> <string name="favorites_sync">Sincronización de Favoritos de E-Hentai</string>
<string name="tag_filtering_threshhold_summary">Puedes filtrar suavemente las etiquetas añadiéndolas a la página Mis Etiquetas de E/ExHentai con un peso negativo. Si una galería tiene etiquetas que suman un peso inferior a este valor, se filtra de la vista. Este umbral se puede establecer entre -9999 y 0. Actualmente: %1$d</string> <string name="tag_filtering_threshhold_summary">Puedes filtrar suavemente las etiquetas añadiéndolas a la página Mis Etiquetas de E/ExHentai con un peso negativo. Si una galería tiene etiquetas que suman un peso inferior a este valor, se filtra de la vista. Este umbral se puede establecer entre -9999 y 0. Actualmente: %1$d</string>
@@ -96,16 +96,7 @@
<string name="eh_settings_configuration_failed_message">Se ha producido un error durante el proceso de configuración: %1$s</string> <string name="eh_settings_configuration_failed_message">Se ha producido un error durante el proceso de configuración: %1$s</string>
<string name="eh_settings_uploading_to_server">Cargar la configuración en el servidor</string> <string name="eh_settings_uploading_to_server">Cargar la configuración en el servidor</string>
<string name="time_between_batches_summary_2">%1$s comprueba/actualiza las galerías por lotes. Esto significa que esperará %2$d hora(s), comprobará %3$d galerías, esperará %2$d hora(s), comprobará %3$d y así sucesivamente…</string> <string name="time_between_batches_summary_2">%1$s comprueba/actualiza las galerías por lotes. Esto significa que esperará %2$d hora(s), comprobará %3$d galerías, esperará %2$d hora(s), comprobará %3$d y así sucesivamente…</string>
<string name="gallery_updater_stats_time">" <string name="gallery_updater_stats_time">\nGalerías que se comprobaron en:\n- hora: %1$d\n- 6 horas: %2$d\n- 12 horas: %3$d\n- día: %4$d\n- 2 días: %5$d\n- semana: %6$d\n- mes: %7$d\n- año: %8$d</string>
\nGalerías que se comprobaron en la última:
\n- hora: %1$d
\n- 6 horas: %2$d
\n- 12 horas: %3$d
\n- día: %4$d
\n- 2 días: %5$d
\n- semana: %6$d
\n- mes: %7$d
\n- año: %8$d"</string>
<string name="settings_profile_note_message">La aplicación añadirá ahora un nuevo perfil de configuración en E-Hentai y ExHentai para optimizar el rendimiento de la aplicación. Asegúrate de tener menos de tres perfiles en ambos sitios. <string name="settings_profile_note_message">La aplicación añadirá ahora un nuevo perfil de configuración en E-Hentai y ExHentai para optimizar el rendimiento de la aplicación. Asegúrate de tener menos de tres perfiles en ambos sitios.
\n \n
\nSi no tienes ni idea de lo que son los perfiles de configuración, probablemente no importe, simplemente pulsa \"Aceptar\".</string> \nSi no tienes ni idea de lo que son los perfiles de configuración, probablemente no importe, simplemente pulsa \"Aceptar\".</string>
@@ -126,7 +117,7 @@
<string name="enable_source_blacklist">Activar lista negra de fuentes</string> <string name="enable_source_blacklist">Activar lista negra de fuentes</string>
<string name="enable_source_blacklist_summary">Ocultar extensiones/fuentes que son incompatibles con %1$s. Reinicie la aplicación forzosamente después de realizar el cambio.</string> <string name="enable_source_blacklist_summary">Ocultar extensiones/fuentes que son incompatibles con %1$s. Reinicie la aplicación forzosamente después de realizar el cambio.</string>
<string name="open_debug_menu">Abrir menú de depuración</string> <string name="open_debug_menu">Abrir menú de depuración</string>
<string name="open_debug_menu_summary">¡NO TOQUES ESTE MENÚ A MENOS QUE SEPAS LO QUE ESTÁS HACIENDO! <font color="red">¡PUEDE CORROMPER TU BIBLIOTECA!</font></string> <string name="open_debug_menu_summary"><![CDATA[¡NO TOQUE ESTE MENÚ A MENOS QUE SEPA LO QUE ESTÁ HACIENDO! <font color=\'red\'>¡PUEDE CORROMPER SU BIBLIOTECA!</font>]]></string>
<string name="starting_cleanup">Comenzando la limpieza</string> <string name="starting_cleanup">Comenzando la limpieza</string>
<string name="clean_up_downloaded_chapters">Limpiar capítulos descargados</string> <string name="clean_up_downloaded_chapters">Limpiar capítulos descargados</string>
<string name="delete_unused_chapters">Eliminar carpetas de capítulos inexistentes, parcialmente descargadas y leídas</string> <string name="delete_unused_chapters">Eliminar carpetas de capítulos inexistentes, parcialmente descargadas y leídas</string>
@@ -172,4 +163,450 @@
<string name="pref_skip_pre_migration_summary">Utilizar las últimas preferencias y fuentes guardadas antes de la migración para migrar</string> <string name="pref_skip_pre_migration_summary">Utilizar las últimas preferencias y fuentes guardadas antes de la migración para migrar</string>
<string name="library_group_updates">Actualizaciones de categorías dinámicas de la biblioteca</string> <string name="library_group_updates">Actualizaciones de categorías dinámicas de la biblioteca</string>
<string name="library_group_updates_global">Ejecutar siempre actualizaciones globales</string> <string name="library_group_updates_global">Ejecutar siempre actualizaciones globales</string>
<string name="library_group_updates_all">Publicar siempre actualizaciones de categorías</string>
<string name="pref_mark_read_dupe_chapters">Marcar capítulos duplicados como leídos</string>
<string name="pref_library_mark_duplicate_chapters">Marcar nuevos capítulos duplicados como leídos</string>
<string name="pref_library_mark_duplicate_chapters_summary">Marcar automáticamente nuevos capítulos como leídos si se han leído antes</string>
<string name="update_1hour">Cada hora</string>
<string name="pref_hide_feed">Ocultar pestaña Feed</string>
<string name="pref_source_source_filtering_summery">Filtrar las fuentes que están en categorías, haciendo que las fuentes no se pongan debajo del idioma si están en una categoría</string>
<string name="pref_source_navigation_summery">Reemplace el botón más reciente con una vista de exploración personalizada que incluya tanto lo más reciente como la exploración</string>
<string name="all_read_entries">Todas las obras leídas</string>
<string name="library_group_updates_all_but_ungrouped">Ejecutar actualizaciones globales solo para no agrupados, actualizaciones de categoría para otros</string>
<string name="pref_mark_read_dupe_chapters_summary">Marcar capítulos duplicados como leídos después de leerlos</string>
<string name="update_30min">Cada 30 minutos</string>
<string name="pref_source_source_filtering">Filtrar las fuentes en categorías</string>
<string name="update_3hour">Cada 3 horas</string>
<string name="pref_feed_position">Posición de la pestaña Feed</string>
<string name="pref_feed_position_summery">¿Quieres que la pestaña feed sea la primera pestaña en navegar? Esto hará que sea la pestaña predeterminada al abrir la navegación, no se recomienda si está con datos móviles o una red medida</string>
<string name="pref_source_navigation">Reemplazar el botón más reciente</string>
<string name="pref_local_source_hidden_folders">Carpetas ocultas de fuente local</string>
<string name="pref_local_source_hidden_folders_summery">Permite a la fuente local leer carpetas ocultas</string>
<string name="label_sync">Sincronizar</string>
<string name="custom_entry_info">Información de entrada personalizada</string>
<string name="label_triggers">Disparadores</string>
<string name="sync_error">Error al sincronizar la biblioteca</string>
<string name="sync_complete">Sincronización de biblioteca completa</string>
<string name="sync_in_progress">Sincronización en curso</string>
<string name="pref_sync_host">Host</string>
<string name="pref_sync_host_summ">Introduce la dirección de host para sincronizar tu biblioteca</string>
<string name="pref_sync_api_key">Clave API</string>
<string name="pref_sync_api_key_summ">Introduce la clave API para sincronizar tu biblioteca</string>
<string name="pref_sync_now_group_title">Acciones de sincronización</string>
<string name="pref_sync_service">Servicio</string>
<string name="pref_sync_automatic_category">Sincronización automática</string>
<string name="pref_choose_what_to_sync">Elige qué sincronizar</string>
<string name="syncyomi">SyncYomi</string>
<string name="last_synchronization">Última sincronización: %1$s</string>
<string name="pref_google_drive_purge_sync_data">Borrar los datos de sincronización de Google Drive</string>
<string name="google_drive_sync_data_purged">Sincronizar datos purgador de Google Drive</string>
<string name="google_drive_sync_data_not_found">Ningún dato de sincronización encontrado en Google Drive</string>
<string name="google_drive_sync_data_purge_error">Error purgando datos de sincronización de Google Drive, intenta iniciar sesión de nuevo.</string>
<string name="google_drive_login_success">Sesión iniciada en Google Drive</string>
<string name="google_drive_login_failed">Error al iniciar sesión en Google Drive: %s</string>
<string name="google_drive_not_signed_in">Sesión no iniciada en Google Drive</string>
<string name="error_uploading_sync_data">Error subiendo los datos de sincronización a Google Drive</string>
<string name="error_before_sync_gdrive">Error antes de sincronizar: %s</string>
<string name="pref_sync_options">Crear condiciones para activar la sincronización</string>
<string name="pref_sync_options_summ">Se puede utilizar para establecer condiciones para activar la sincronización</string>
<string name="sync_on_chapter_read">Sincronizar al leer un capítulo</string>
<string name="sync_on_chapter_open">Sincronizar al abrir un capítulo</string>
<string name="sync_on_app_resume">Sincronizar al reanudar la aplicación</string>
<string name="sync_library">Sincronizar biblioteca</string>
<string name="biometric_lock_times">Horario de bloqueo biométrico</string>
<string name="action_edit_biometric_lock_times">Editar horarios de bloqueo</string>
<string name="biometric_lock_times_empty">No tienes horarios de bloqueo biométrico. Pulsa el botón «+» para añadir uno.</string>
<string name="biometric_lock_time_conflicts">¡Una hora de bloqueo entra en conflicto con otra existente!</string>
<string name="biometric_lock_start_time">Introducir hora de inicio</string>
<string name="biometric_lock_end_time">Introducir hora de finalización</string>
<string name="delete_time_range">Eliminar intervalo de tiempo</string>
<string name="delete_time_range_confirmation">¿Deseas eliminar el intervalo de tiempo %s?</string>
<string name="biometric_lock_days">Días de bloqueo biométrico</string>
<string name="biometric_lock_days_summary">Días para tener la aplicación bloqueada</string>
<string name="sunday">Domingo</string>
<string name="monday">Lunes</string>
<string name="tuesday">Martes</string>
<string name="wednesday">Miércoles</string>
<string name="saturday">Sábado</string>
<string name="set_cbz_zip_password">Establecer contraseña en el archivo CBZ</string>
<string name="pref_sync_now">Sincronizar ahora</string>
<string name="pref_sync_now_subtitle">Inicia la sincronización inmediata de tus datos</string>
<string name="pref_sync_interval">Frecuencia de sincronización</string>
<string name="pref_sync_service_category">Sincronizar</string>
<string name="pref_google_drive_sign_in">Iniciar sesión</string>
<string name="error_deleting_google_drive_lock_file">Error borrando el archivo de bloqueo de Google Drive</string>
<string name="google_drive">Google Drive</string>
<string name="pref_purge_confirmation_message">Al eliminar los datos de sincronización, se eliminarán todos los datos sincronizados a Google Drive. ¿Estás seguro de que deseas continuar?</string>
<string name="pref_purge_confirmation_title">Confirmación de purga</string>
<string name="sync_on_app_start">Sincronizar al iniciar la aplicación</string>
<string name="thursday">Jueves</string>
<string name="encrypt_database">Cifrar base de datos</string>
<string name="friday">Viernes</string>
<string name="encrypt_database_subtitle">Requiere reiniciar la aplicación para que surta efecto</string>
<string name="encrypt_database_message"><![CDATA[<font color=\'red\'>ACTIVAR ESTO CREARÁ UNA NUEVA BASE DE DATOS. USA ESTOS PASOS PARA MANTENER TUS DATOS<br>1. AJUSTES -> COPIA DE SEGURIDAD -> CREAR<br>2. AJUSTES DEL SISTEMA -> BORRAR LOS DATOS DE LA APLICACIÓN<br>3. ABRIR LA APLICACIÓN Y ACTIVAR ESTO<br>4. AJUSTES DEL SISTEMA -> FORZAR REINICIO<br>5. AJUSTES -> COPIA DE SEGURIDAD -> RESTAURAR</font>]]></string>
<string name="password_protect_downloads">Descargas protegidas por contraseña</string>
<string name="password_protect_downloads_summary">Encripta las descargas de archivos CBZ con la contraseña dada.\nADVERTENCIA: LOS DATOS DE LOS ARCHIVOS SE PERDERÁN PARA SIEMPRE SI SE OLVIDA LA CONTRASEÑA</string>
<string name="delete_cbz_archive_password">Eliminar contraseña de archivo CBZ</string>
<string name="cbz_archive_password">Contraseña del archivo CBZ</string>
<string name="wrong_cbz_archive_password">Contraseña incorrecta del archivo CBZ</string>
<string name="encryption_type">Tipo de cifrado</string>
<string name="aes_256">AES 256</string>
<string name="aes_128">AES 128</string>
<string name="standard_zip_encryption">Cifrado zip estándar (rápido pero inseguro)</string>
<string name="page_downloading">Descarga de la página</string>
<string name="download_threads">Descargar hilos</string>
<string name="aggressively_load_pages">Forzar la carga de páginas</string>
<string name="aggressively_load_pages_summary">Descarga lentamente el capítulo entero mientras lees en vez de cargar las páginas que estás viendo.</string>
<string name="reader_preload_amount">Número de páginas precargadas</string>
<string name="reader_preload_amount_4_pages">4 Páginas</string>
<string name="reader_preload_amount_6_pages">6 Páginas</string>
<string name="download_threads_summary">Los valores más altos pueden acelerar la descarga de imágenes significativamente, pero también pueden activar bloqueos. El valor recomendado es 2 o 3. El valor actual es: %s</string>
<string name="skip_queue_on_retry">Saltar la cola al reintentar</string>
<string name="skip_queue_on_retry_summary">Normalmente, al pulsar el botón de reintentar una descarga fallida se esperará hasta que el descargador haya terminado de descargar la última página antes de comenzar a volver a descargar la página fallida. Habilitar esto forzará al descargador a comenzar a volver a descargar la página fallida tan pronto como presione el botón de reintentar.</string>
<string name="reader_preload_amount_8_pages">8 Páginas</string>
<string name="reader_preload_amount_10_pages">10 Páginas</string>
<string name="reader_preload_amount_12_pages">12 Páginas</string>
<string name="reader_preload_amount_14_pages">14 Páginas</string>
<string name="reader_preload_amount_16_pages">16 Páginas</string>
<string name="reader_preload_amount_20_pages">20 Páginas</string>
<string name="reader_cache_size">Tamaño de la caché del lector</string>
<string name="preserve_reading_position">Guardar la posición de lectura en las entradas leídas</string>
<string name="auto_webtoon_mode">Modo webtoon automático</string>
<string name="auto_webtoon_mode_summary">Utilice el modo webtoon automático para las entradas que se detecte que probablemente utilicen el formato de tira larga</string>
<string name="enable_zoom_out">Activar alejar</string>
<string name="tap_scroll_page">Toque para desplazarse por la página</string>
<string name="reader_preload_amount_summary">La cantidad de páginas que se deben precargar al leer. Los valores más altos darán como resultado una experiencia de lectura más fluida, a expensas de un mayor uso de caché. Se recomienda aumentar la cantidad de caché que asigna cuando utiliza valores más altos</string>
<string name="reader_cache_size_summary">La cantidad de imágenes que se guardarán en el dispositivo durante la lectura. Los valores más altos darán como resultado una experiencia de lectura más suave, a costa de un mayor uso del espacio en disco</string>
<string name="reader_bottom_buttons">Botones inferiores del lector</string>
<string name="tap_scroll_page_summary">Al habilitar esta opción, al tocar se desplazará por la página en lugar del tamaño de la pantalla</string>
<string name="reader_bottom_buttons_summary">Personaliza los botones que aparecen en la parte inferior del lector</string>
<string name="pref_show_vert_seekbar_landscape">Mostrar la barra de desplazamiento vertical en modo horizontal</string>
<string name="pref_show_vert_seekbar_landscape_summary">Habilite la barra de desplazamiento vertical cuando esté en modo horizontal</string>
<string name="pref_left_handed_vertical_seekbar">Barra de desplazamiento vertical para zurdos</string>
<string name="pref_left_handed_vertical_seekbar_summary">Alterna en qué lado está la barra de desplazamiento</string>
<string name="pref_force_horz_seekbar_summary">Elimina la barra de desplazamiento vertical completamente en favor de la horizontal</string>
<string name="pref_smooth_scroll">Desplazamiento automático suave</string>
<string name="eh_retry_all">Reintentar todo</string>
<string name="eh_autoscroll_help">Ayuda de desplazamiento automático</string>
<string name="eh_autoscroll_help_message">Desplazarse automáticamente a la siguiente página en el intervalo especificado. El intervalo se especifica en segundos.</string>
<string name="eh_autoscroll_freq_invalid">Frecuencia inválida</string>
<string name="eh_retry_all_help">Ayuda de reintentar todo</string>
<string name="pref_force_horz_seekbar">Forzar barra de desplazamiento horizontal</string>
<string name="eh_autoscroll">Desplazamiento automático</string>
<string name="eh_boost_page">Potenciar página</string>
<string name="eh_retry_all_help_message">Vuelve a añadir todas las páginas erróneas a la cola de descarga.</string>
<string name="eh_boost_page_help">Ayuda de potenciado de página</string>
<string name="eh_boost_page_errored">La página no se pudo cargar, ¡presione el botón de reintentar en su lugar!</string>
<string name="eh_boost_page_downloading">¡Esta página ya se está descargando!</string>
<string name="eh_boost_page_downloaded">¡Esta página ya se ha descargado!</string>
<string name="eh_boost_boosted">¡Página actual potenciada!</string>
<string name="eh_boost_page_help_message">Por lo general, un programa de descarga sólo puede descargar una determinada cantidad de páginas a la vez. Esto significa que puede esperar a que se descargue la página, pero el programa de descarga no comenzará a descargarla hasta que tenga espacio de descarga libre. Al presionar \"Acelerar la descarga de la página\" se obligará al descargador a comenzar a descargar la página actual, independientemente de si hay espacio disponible o no.</string>
<string name="eh_boost_invalid_loader">¡Esta página no puede ser potenciada (cargador de página inválido)!</string>
<string name="eh_boost_page_invalid">¡Esta página no puede ser potenciada (página inválida)!</string>
<string name="action_set_first_page_cover">Establecer primera página como portada</string>
<string name="action_set_second_page_cover">Establecer segunda página como portada</string>
<string name="action_save_first_page">Guardar primera imagen</string>
<string name="action_save_second_page">Guardar segunda imagen</string>
<string name="action_share_first_page">Compartir primera imagen</string>
<string name="action_share_second_page">Compartir segunda imagen</string>
<string name="action_save_combined_page">Guarda página combinada</string>
<string name="action_copy_first_page">Copiar primera página</string>
<string name="action_copy_second_page">Copiar segunda página</string>
<string name="action_copy_combined_page">Copiar página combinada</string>
<string name="share_pages_info">%1$s: %2$s, páginas %3$s</string>
<string name="eh_auto_webtoon_snack">Lectura estilo webtoon</string>
<string name="page_layout">Diseño de página</string>
<string name="double_pages">Páginas dobles</string>
<string name="single_page">Página individual</string>
<string name="automatic_orientation">Automática (basada en la orientación)</string>
<string name="shift_double_pages">Desplazar una página</string>
<string name="automatic_can_still_switch">Mientras se use el diseño de página automático, aún puedes cambiar entre diseños durante la lectura sin sobrescribir esta configuración</string>
<string name="invert_double_pages">Invertir páginas dobles</string>
<string name="center_margin">Centrar margen</string>
<string name="center_margin_none">Ninguno</string>
<string name="center_margin_double_page">Añadir a página doble</string>
<string name="center_margin_wide_page">Añadie a página ancha</string>
<string name="center_margin_double_and_wide_page">Añadir a ambos</string>
<string name="pref_center_margin">Centrar tipo de margen</string>
<string name="pref_center_margin_summary">Inserta un espaciador para acomodar el espacio muerto en dispositivos plegables.</string>
<string name="archive_mode_load_from_file">Cargar desde archivo</string>
<string name="archive_mode_load_into_memory">Cargar en memoria</string>
<string name="archive_mode_cache_to_disk">Copiar al disco</string>
<string name="pref_archive_reader_mode">Modo de lectura de archivos</string>
<string name="pref_archive_reader_mode_summary">La forma en la que se cargan imágenes dentro de archivos, como CBZ o CBR</string>
<string name="az_recommends">Ver recomendaciones</string>
<string name="merge">Unir</string>
<string name="merge_with_another_source">Unir con otro</string>
<string name="failed_merge">Error al unir entrada: %1$s</string>
<string name="merge_unknown_entry">ID de entrada desconocido: %1$d</string>
<string name="merged_already">¡Esta entrada ya está fusionada con la entrada actual!</string>
<string name="merge_duplicate">¡Esta entrada unida es un duplicado!</string>
<string name="reset_tags">Restablecer etiquetas</string>
<string name="reset_info">Restablecer información</string>
<string name="title_hint">Título: %1$s</string>
<string name="description_hint">Descripción: %1$s</string>
<string name="author_hint">Autor: %1$s</string>
<string name="artist_hint">Artista: %1$s</string>
<string name="thumbnail_url_hint">Url de miniatura: %1$s</string>
<string name="add_tags">Añadir etiquetas</string>
<string name="action_share_combined_page">Compartir página combinada</string>
<string name="entry_merged">¡Entrada unida!</string>
<string name="multi_tags_comma_separated">Introducir etiqueta(s), separada(s) por comas.</string>
<string name="add_tag">Añadir etiqueta</string>
<string name="find_in_another_source">Buscar en otra fuente</string>
<string name="save_search_failed_to_load_message">Un error ocurrió mientras se cargaban tus búsquedas guardadas.</string>
<string name="save_search_failed_to_load">¡Error al cargar las búsquedas guardadas!</string>
<string name="delete_tag">Eliminar etiqueta</string>
<string name="redundant_extension_message">Esta extensión es redundante y no será usada dentro de esta versión de Tachiyomi.</string>
<string name="use_intelligent_search">Título de búsqueda + palabras clave del título</string>
<string name="only_show_updated_entries">Mostrar solo entradas con nuevos capítulos</string>
<string name="match_enabled_sources">Coincidir fuentes activadas</string>
<string name="no_chapters_found_for_migration">Ningún capítulo encontrado, esta entrada no puede ser usada para la migración</string>
<string name="stop_migrating">¿Dejar de migrar?</string>
<string name="skipping_">(saltando %1$d)</string>
<string name="no_valid_entry">Ninguna entrada válida seleccionada</string>
<string name="ungrouped">Desagrupado</string>
<string name="favorites_sync_error">Error al sincronizar favoritos</string>
<string name="show_gallery">Mostrar galería</string>
<string name="favorites_sync_done_errors_message">Errores ocurridos durante el proceso de sincronización que fueron ignorados:\n%1$s</string>
<string name="favorites_sync_calculating_remote_changes">Calculando cambios remotos</string>
<string name="favorites_sync_calculating_local_changes">Calculando cambios locales</string>
<string name="favorites_sync_gallery_in_multiple_categories">¡La galería: %1$s está en más de una categoría (%2$s)!</string>
<string name="favorites_sync_processing_throttle">%1$s\n\nLa sincronización está actualmente limitada (para evitar ser baneada de ExHentai) y puede llevar bastante tiempo completarse.</string>
<string name="favorites_sync_initializing">Iniciando sincronización</string>
<string name="data_saver_exclude">Excluir del ahorro de datos</string>
<string name="data_saver_stop_exclude">Dejar de excluir del ahorro de datos</string>
<string name="automatic_search_error">¡Error realizando la búsqueda automática!</string>
<string name="save_search">¿Guardar consulta de búsqueda actual?</string>
<string name="save_search_hint">Mi nombre de búsqueda</string>
<string name="save_search_delete">¿Eliminar las consultas de búsqueda guardadas?</string>
<string name="save_search_delete_message">¿Estás seguro que deseas eliminar tu consulta de búsqueda guardada: \'%1$s\'?</string>
<string name="save_search_invalid">Búsqueda guardada inválida, los filtros han cambiado</string>
<string name="no_source_categories">Ninguna categoría de fuente disponible</string>
<string name="invalid_category_name">Nombre de categoría inválido</string>
<string name="pref_tag_sorting">Etiquetas de ordenación de etiqueta</string>
<string name="tag_sorting">Ordenación de etiqueta</string>
<string name="action_edit_tags">Editar etiquetas</string>
<string name="delete_tag_confirmation">¿Deseas eliminar la etiqueta %s?</string>
<string name="select_sources">Seleccionar fuentes</string>
<string name="migration">Migración</string>
<string name="pre_migration_skip_toast">Para mostrar esta pantalla de nuevo, ve a Ajustes -&gt; Biblioteca.</string>
<string name="data_to_include_in_migration">Datos a incluir en la migración</string>
<string name="include_extra_search_parameter">Incluir parámetros de búsqueda adicionales durante la búsqueda</string>
<string name="use_most_chapters">Usar fuente con la mayoría de capítulos (más lenta)</string>
<string name="skip_this_step_next_time">Saltar este paso la próxima vez</string>
<string name="latest_">Último: %1$s</string>
<string name="migrating_to">migrar a</string>
<string name="match_pinned_sources">Coincidir fuentes fijadas</string>
<string name="no_alternatives_found">Ninguna alternativa encontrada</string>
<string name="action_stop">Parar</string>
<string name="favorites_syncing">Sincronización de favoritos</string>
<string name="favorites_sync_done_errors">Sincronización de favoritos completa sin errores</string>
<string name="favorites_sync_verifying_library">Verificando la biblioteca local</string>
<string name="favorites_sync_gallery_multiple_categories_error">¡La galería %1$d está en múltiples categorías!</string>
<string name="favorites_sync_failed_to_featch">¡Error al obtener los favoritos del servidor remoto!</string>
<string name="favorites_sync_cleaning_up">Limpiando</string>
<string name="favorites_sync_ignoring_exception">¡Ignorando excepción!</string>
<string name="favorites_sync_network_error">¡Error de sincronización de red!</string>
<string name="favorites_sync_remote_not_exist">¡La galería remota no existe, saltando: %1$s!</string>
<string name="favorites_sync_failed_to_add_to_local">Error al añadir la galería a la base de datos local:</string>
<string name="favorites_sync_failed_to_add_to_local_error">\'%1$s\' %2$s</string>
<string name="favorites_sync_failed_to_add_to_local_unknown_type">¡\'%1$s\' (%2$s) no es una galería válida!</string>
<string name="favorites_sync_waiting_for_start">Esperando a que la sincronización se inicie</string>
<string name="searching_source">Buscando fuente…</string>
<string name="could_not_find_entry">¡No se pudo encontrar la entrada en la fuente!</string>
<string name="saved_searches">Búsquedas guardadas</string>
<string name="save_search_invalid_name">Nombre de búsqueda guardado inválido</string>
<string name="error_tag_exists">¡Esta etiqueta existe!</string>
<string name="hide_not_found_entries">Ocultar entradas no encontradas</string>
<string name="ext_redundant">Redundante</string>
<string name="use_first_source">Usar primera fuente con alternativa</string>
<string name="favorites_sync_bad_library_state">%1$s La sincronización no empezará hasta que la galería esté en una única categoría.</string>
<string name="favorites_sync_error_string">Un error ocurrió durante el proceso de sincronización: %1$s</string>
<string name="favorites_sync_downloading">Descargando favoritos desde el servidor remoto</string>
<string name="favorites_sync_syncing_category_names">Actualizando nombres de categorías</string>
<string name="favorites_sync_sync_error">¡Error de sincronización!</string>
<string name="favorites_sync_could_not_fetch">¡No se pudieron obtener los favoritos!</string>
<string name="favorites_sync_adding_to_remote">Añadiendo galería %1$d de %2$d al servidor remoto</string>
<string name="favorites_sync_complete">¡Sincronización completa!</string>
<string name="favorites_sync_unknown_error">Error desconocido: %1$s</string>
<string name="favorites_sync_remove_from_local">Eliminando galería %1$d de %2$d de la biblioteca local</string>
<string name="favorites_sync_add_to_local">Añadiendo galería %1$d de %2$d a la biblioteca local</string>
<string name="favorites_sync_removing_galleries">Eliminando %1$d galerías del servidor remoto</string>
<string name="favorites_sync_unable_to_delete">¡No se pudo eliminar las galerías del servidor remoto!</string>
<string name="tracking_status">Estado de seguimiento</string>
<string name="not_tracked">Sin seguir</string>
<string name="sync_favorites">Sincronizar favoritos de EH</string>
<string name="favorites_sync_reset">¿Estás seguro?</string>
<string name="favorites_sync_reset_message">Restablecer el estado de sincronización puede hacer que la próxima sincronización sea extremadamente lenta.</string>
<string name="information_empty_tags">No tienes etiquetas. Pulsa el botón «+» para añadir uno y ordenar tu biblioteca por etiquetas</string>
<string name="favorites_sync_notes">NOTAS IMPORTANTES DE SINCRONIZACIÓN DE FAVORITOS</string>
<string name="eh_batch_add_title">Introduce las galerías para añadir (separadas por una nueva línea):</string>
<string name="eh_batch_add">Añadir por lotes</string>
<string name="eh_batch_add_button">Añadir galerías</string>
<string name="eh_batch_add_finish">Finalizada</string>
<string name="eh_batch_add_adding_galleries">Añadiendo las galerías…</string>
<string name="batch_add_no_valid_galleries">¡Sin galerías que añadir!</string>
<string name="batch_add_summary">\nResumen:\nAñadida(s): %1$d galeria(s)\nError(es) en: %2$d galeria(s)</string>
<string name="batch_add_success_log_message">Galería añadida: %1$s</string>
<string name="batch_add">Añadir por lotes</string>
<string name="batch_add_ok">[De acuerdo]</string>
<string name="batch_add_error">[ERROR]</string>
<string name="batch_add_unknown_type_log_message">Entrada desconocida para la galería: %1$s</string>
<string name="batch_add_unknown_source_log_message">Fuente desconocida para la galería: %1$s</string>
<string name="batch_add_not_exist_log_message">La galería no existe: %1$s</string>
<string name="batch_add_no_valid_galleries_message">¡Especifica al menos una galería para añadir!</string>
<string name="gallery_adder_importing_gallery">Importando la galería (url: %1$s, fav: %2$s, forceSource: %3$s)…</string>
<string name="gallery_adder_source_uri_must_match">¡Hubo un error al verificar coincidencias de URI de origen!</string>
<string name="favorites_sync_conformation_message">¿Estás seguro de que deseas sincronizar tus favoritos con E-Hentai?</string>
<string name="eh_batch_add_description">Ejemplo:\n\nhttp://e-hentai.org/g/12345/1a2b3c4e\nhttp://g.e-hentai.org/g/67890/6f7g8h9i\nhttp://exhentai.org/g/13579/1a3b5c7e\nhttps://exhentai.org/g/24680/2f4g6h8i\n\nTambién admite datos exportados de E-H\n</string>
<string name="gallery_adder_uri_map_to_gallery_error">¡Error en el mapa URI de origen al asignarlo a la galería!</string>
<string name="rating9">Increíble</string>
<string name="rating5">Regular</string>
<string name="rating4">Malo</string>
<string name="rating6">Aceptable</string>
<string name="rating2">Doloroso</string>
<string name="rating1">Insoportable</string>
<string name="misc">Miscelánea</string>
<string name="more_info">Más información</string>
<string name="id">Id</string>
<string name="genre">Género</string>
<string name="thumbnail_url">Enlace de la miniatura</string>
<string name="total_favorites">Favoritos totales</string>
<string name="total_ratings">Valoraciones totales</string>
<string name="group">Grupo</string>
<string name="english_title">Título en inglés</string>
<string name="collection">Colección</string>
<string name="parodies">Parodias</string>
<string name="author">Autor</string>
<string name="manga_updates_id">Id de Manga updates</string>
<string name="anime_planet_id">Id de Anime planet</string>
<string name="translated">Traducido</string>
<string name="mangadex_sync_follows_to_library_summary">Baja las entradas de MangaDex a tu biblioteca si no se han añadido ya.</string>
<string name="community_recommendations">Recomendaciones de la comunidad</string>
<string name="relation_main_story">Historia principal</string>
<string name="relation_sequel">Secuela</string>
<string name="relation_spin_off">Spin-off</string>
<string name="relation_alternate_story">Historia alternativa</string>
<string name="relation_alternate_version">Versión alternativa</string>
<string name="feed_add">¿Añadir %1$s al feed?</string>
<string name="error_with_reason">Error: %1$s</string>
<string name="could_not_open_entry">No se pudo abrir esta entrada:\n\n%1$s</string>
<string name="launching_app">Iniciando aplicación…</string>
<string name="loading_entry">Cargando entrada…</string>
<string name="page_previews">Vistas previas de página</string>
<string name="more_previews">Más vistas previas</string>
<string name="pref_clear_page_preview_cache">Limpiar la caché de vista previa de página</string>
<string name="page_preview_page_go_to">Ir a</string>
<string name="rating10">Obra maestra</string>
<string name="rating8">Genial</string>
<string name="token">Token</string>
<string name="visible">Visible</string>
<string name="language">Idioma</string>
<string name="gallery_size">Tamaño de galería</string>
<string name="average_rating">Valoración media</string>
<string name="path">Ruta</string>
<string name="cover_image_file_type">Tipo de archivo de imagen de portada</string>
<string name="thumbnail_image_file_type">Tipo de archivo de imagen de miniatura</string>
<string name="last_chapter_number">Número del último capítulo</string>
<string name="anilist_id">Id de Anilist</string>
<string name="kitsu_id">Id de Kitsu</string>
<string name="mal_id">Id de Mal</string>
<string name="is_visible">Visible: %1$s</string>
<string name="delete_merged_entry">¿Estás seguro?</string>
<string name="delete_merged_entry_desc">Esto eliminará la entrada de la combinación, al usarlo también se perderá cualquier cambio sin guardar aplicado a la entrada combinada</string>
<string name="md_follows_unfollowed">No seguida</string>
<string name="mangadex_sync_follows_to_library">Sincronizar las entradas de MangaDex en tu biblioteca</string>
<string name="alt_titles">Títulos alternativos</string>
<string name="select_scanlators">Grupos de traductores a mostrar</string>
<string name="relation_based_on">Basada en</string>
<string name="relation_shared_universe">Universo compartido</string>
<string name="relation_colored">Coloreada</string>
<string name="relation_serialization">Publicación por entregas</string>
<string name="include_all_read_entries">Incluir todas las entradas leídas</string>
<string name="ignore_non_library_entries">Ignorar entradas que no pertenecen a la biblioteca</string>
<string name="asian_porn">Porno asiático</string>
<string name="rating3">Horrible</string>
<string name="rating7">Bueno</string>
<string name="doujinshi">Doujinshi</string>
<string name="video">Vídeo</string>
<string name="merge_settings">Ajustes de combinación</string>
<string name="short_title">Título corto</string>
<string name="artist">Artista</string>
<string name="characters">Personajes</string>
<string name="relation_adapted_from">Adaptada de</string>
<string name="relation_doujinshi">Doujinshi</string>
<string name="relation_prequel">Precuela</string>
<string name="relation_same_franchise">Misma franquicia</string>
<string name="japanese_title">Título en japonés</string>
<string name="rating0">Desastroso</string>
<string name="alt_title">Título alternativo</string>
<string name="no_rating">Sin calificar</string>
<string name="cosplay">Cosplay</string>
<string name="relation_side_story">Historia secundaria</string>
<string name="pref_crop_borders_pager">Recortar borde de página</string>
<string name="pref_crop_borders_continuous_vertical">Recortar el borde vertical</string>
<string name="humanize_fallback">hace unos instantes</string>
<string name="pref_crop_borders_webtoon">Recortar bordes Webtoon</string>
<string name="feed">Feed</string>
<string name="feed_delete">¿Borrar artículo de feed?</string>
<string name="too_many_in_feed">Demasiadas fuentes en su feed, no puede añadir más de 10</string>
<string name="action_add_tags_message">¡Lee esto! ¡Etiquetas deben ser exactas, no hay coincidencias parciales, no puedes hacer netorare para excluir mujer:netorare o similar!\nEl estilo para etiquetas de nombre es\n\"mujer: solo mujer\"\n¡sin citas!\n¡Se pueden añadir multiples variantes de la misma etiqueta, así que puedes hacer \"etiqueta:netorare\" para NHentai y \"mujer:netorare\" para E-Hentai!</string>
<string name="select_none">Selecciona ninguno</string>
<string name="feed_tab_empty">No tiene fuentes en su feed, navegar a la parte superior derecha para añadir una</string>
<string name="skip_pre_migration">Saltar pre-migración</string>
<string name="search_parameter">Buscar parámetro (p. ej. idioma:inglés)</string>
<string name="lewd">Lascivo</string>
<string name="favorites_sync_notes_message"><![CDATA[1. Los cambios en los nombres de las categorías de la aplicación <b> NO </b> se sincronizan. Por favor, <i> cambia los nombres de las categorías en ExHentai en su lugar </i> . Los nombres de las categorías se copiarán de los servidores de ExHentai en cada sincronización. <br> <br> 2. Las categorías favoritas de ExHentai corresponden a las <b> primeras 10 categorías de la aplicación </b> (excluyendo la categoría \'Predeterminada\'). <i> ¡ Las galerías de otras categorías <b> NO </b> se sincronizarán! </i> <br> <br> 3. <font color=\'red\'> <b> ¡ASEGÚRATE DE TENER UNA CONEXIÓN A INTERNET ESTABLE CUANDO LA SINCRONIZACIÓN ESTÉ EN PROGRESO! </b> </font> Si Internet se desconecta mientras la aplicación se está sincronizando, tus favoritos pueden quedar en un <i> estado parcialmente sincronizado </i> . <br> <br> 4. Mantén la aplicación abierta mientras se sincronizan los favoritos. Android cerrará algunas veces las aplicaciones que están en segundo plano y eso podría ser malo si sucede mientras la aplicación se está sincronizando. <br> <br> 5. <b> NO coloques favoritos en múltiples categorías </b> (la aplicación lo admite). Esto puede confundir al algoritmo de sincronización, ya que ExHentai solo permite que cada favorito esté en una categoría. <br> <br> Este cuadro de diálogo solo aparecerá una vez. Puedes leer estas notas nuevamente yendo a \'Configuración > E-Hentai > Mostrar notas de sincronización de favoritos\'.]]></string>
<string name="game_cg">Juego CG</string>
<string name="western">Oeste</string>
<string name="non_h">No-H</string>
<string name="is_exhentai_gallery">Galería Exhentai</string>
<string name="date_posted">Fecha de publicación</string>
<string name="last_update_check">Comprobación de la última actualización</string>
<string name="aged">Envejecido</string>
<string name="media_id">Identificación de medios</string>
<string name="rating_string">Cadena de valoración</string>
<string name="no_dedupe">No deduplicado</string>
<string name="dedupe_priority">Eliminar duplicados por prioridad</string>
<string name="dedupe_most_chapters">Mostrar fuentes con la mayor cantidad de capítulos</string>
<string name="dedupe_highest_chapter">Mostrar fuente con el número de capítulo más alto</string>
<string name="mangadex_preffered_source">Fuente preferida MangaDex</string>
<string name="mangadex_similar">Similar MangaDex</string>
<string name="relation_preserialization">Pre-serialización</string>
<string name="gallery_adder_uri_map_to_chapter_error">¡Error en el mapa URI de origen al capítulo!</string>
<string name="gallery_adder_uri_clean_error">¡Error al limpiar la URL de origen!</string>
<string name="gallery_adder_chapter_fetch_error">¡Error al actualizar los capítulos de la galería: %1$s!</string>
<string name="gallery_adder_could_not_add_gallery">¡No se ha podido añadir la galería (url: %1$s)!</string>
<string name="gallery_adder_could_not_identify_chapter">¡No se ha podido identificar el capítulo (url: %1$s)!</string>
<string name="artist_cg">Artista CG</string>
<string name="image_set">Conjunto de imágenes</string>
<string name="artbook">Libro de arte</string>
<string name="page_count">Número de páginas</string>
<string name="parent">Padre</string>
<string name="uploader">Cargador</string>
<string name="url">URL</string>
<string name="uploader_capital">Cargador principal</string>
<string name="follow_status">Seguir estado</string>
<string name="language_translated">%1$s TR</string>
<string name="fetch_chapter_updates">Obtener actualizaciones de capítulos</string>
<string name="chapter_updates_merged_entry">Alternar actualizaciones de capítulos</string>
<string name="chapter_updates_merged_entry_desc">Cambiar esto desactivará o habilitará las actualizaciones de capítulos para esta entrada fusionada</string>
<string name="download_merged_entry">Alternar descargar nuevo capítulo</string>
<string name="merged_references_invalid">Referencias combinadas no válidas</string>
<string name="merged_chapter_updates_error">Error al alternar actualizaciones de capítulos</string>
<string name="merged_toggle_download_chapters_error">Error al alternar la descarga del capítulo</string>
<string name="allow_deduplication">Permitir deduplicación:</string>
<string name="deduplication_mode">Modo deduplicación:</string>
<string name="deduplication_entry_info">Entrada de información:</string>
<string name="mangadex_add_to_follows">Añadir a seguidores MangaDex</string>
<string name="random">Aleatorio</string>
<string name="mangadex_push_favorites_to_mangadex">Sincronizar entradas de la biblioteca con MangaDex</string>
<string name="similar">Similar a %1$s</string>
<string name="download_merged_entry_desc">Activar esta opción se activará o desactivará la descarga de capítulos para esta entrada combinada</string>
<string name="mangadex_preffered_source_summary">Establecer tu fuente MangaDex preferida, se usará para seguidores y otras funciones en la aplicación</string>
<string name="mangadex_follows">Seguidores MangaDex</string>
<string name="mangadex_push_favorites_to_mangadex_summary">Sincroniza cualquier entrada rastreada no incluida en MdList con MangaDex como lectura.</string>
<string name="relation_similar">Similar</string>
<string name="relation_monochrome">Monocromo</string>
</resources> </resources>
@@ -61,7 +61,7 @@
<string name="log_level">Level ng pag-log</string> <string name="log_level">Level ng pag-log</string>
<string name="log_level_summary">Ang pagbabago nito ay maaaring makaapekto sa performance ng app. Piliting i-restart ang app pagkatapos baguhin. Kasalukuyang halaga: %s</string> <string name="log_level_summary">Ang pagbabago nito ay maaaring makaapekto sa performance ng app. Piliting i-restart ang app pagkatapos baguhin. Kasalukuyang halaga: %s</string>
<string name="open_debug_menu">Buksan ang menu ng pag-debug</string> <string name="open_debug_menu">Buksan ang menu ng pag-debug</string>
<string name="open_debug_menu_summary">HUWAG PAKIALAMAN ANG MENU NA ITO MALIBAN KUNG ALAM MO ANG GINAGAWA MO! <font color="red">MAARI ITONG MA-CORRUPT ANG IYONG AKLATAN! </font></string> <string name="open_debug_menu_summary"><![CDATA[HUWAG PAKIALAMAN ANG MENU NA ITO MALIBAN KUNG ALAM MO ANG GINAGAWA MO! <font color=\'red\'>MAARI ITONG MA-CORRUPT ANG IYONG AKLATAN!</font>]]></string>
<string name="clean_orphaned_downloads">Linisin ang na-orphan</string> <string name="clean_orphaned_downloads">Linisin ang na-orphan</string>
<string name="clean_read_downloads">Linisin ang nabasa-na</string> <string name="clean_read_downloads">Linisin ang nabasa-na</string>
<string name="clean_read_entries_not_in_library">Linisin ang mga entry na wala sa aklatan</string> <string name="clean_read_entries_not_in_library">Linisin ang mga entry na wala sa aklatan</string>
@@ -601,4 +601,10 @@
<string name="relation_sequel">Karugtong</string> <string name="relation_sequel">Karugtong</string>
<string name="relation_alternate_story">Alternatibong kwento</string> <string name="relation_alternate_story">Alternatibong kwento</string>
<string name="relation_colored">Nakulayan</string> <string name="relation_colored">Nakulayan</string>
<string name="add_tags">Magdagdag ng Mga Tag</string>
<string name="multi_tags_comma_separated">Maglagay ng (mga) tag, na pinaghihiwalay ng mga kuwit (,).</string>
<string name="settings_profile_note">Profile note na mga setting</string>
<string name="pref_sync_api_key">API key</string>
<string name="alt_titles">Alternatibong mga Title</string>
<string name="pref_sync_host">Host</string>
</resources> </resources>
@@ -563,4 +563,11 @@
<string name="pref_hide_feed">Sembunyikan tab Umpan</string> <string name="pref_hide_feed">Sembunyikan tab Umpan</string>
<string name="pref_feed_position">Posisi tab Umpan</string> <string name="pref_feed_position">Posisi tab Umpan</string>
<string name="pref_feed_position_summery">Apakah Anda ingin tab Umpan menjadi tab pertama dalam penjelajahan? Ini akan menjadikannya tab default saat membuka penjelajahan, tidak disarankan jika Anda menggunakan data atau jaringan terukur</string> <string name="pref_feed_position_summery">Apakah Anda ingin tab Umpan menjadi tab pertama dalam penjelajahan? Ini akan menjadikannya tab default saat membuka penjelajahan, tidak disarankan jika Anda menggunakan data atau jaringan terukur</string>
<string name="error_uploading_sync_data">Terjadi kesalahan saat mengunggah data sinkronisasi ke Google Drive</string>
<string name="google_drive_login_failed">Gagal masuk ke Google Drive: %s</string>
<string name="google_drive_not_signed_in">Belum masuk ke Google Drive</string>
<string name="pref_sync_options">Buat pemicu sinkronisasi</string>
<string name="error_deleting_google_drive_lock_file">Kesalahan saat menghapus file kunci Google Drive</string>
<string name="error_before_sync_gdrive">Gagal sebelum sinkron: %s</string>
<string name="pref_purge_confirmation_title">Konfirmasi pembersihan</string>
</resources> </resources>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="action_skip_entry">Non migrare</string>
<string name="action_search_manually">Cerca manualmente</string>
<string name="action_migrate_now">Migra ora</string>
<string name="action_copy_now">Copia ora</string>
</resources>
@@ -656,4 +656,18 @@
<string name="action_copy_second_page">Копировать вторую страницу</string> <string name="action_copy_second_page">Копировать вторую страницу</string>
<string name="only_show_updated_entries">Показывать серии только с новыми главами</string> <string name="only_show_updated_entries">Показывать серии только с новыми главами</string>
<string name="action_copy_combined_page">Копировать объединенную страницу</string> <string name="action_copy_combined_page">Копировать объединенную страницу</string>
<string name="pref_category_eh">E-Hentai</string>
<string name="wsrv">wsrv.nl</string>
<string name="eh_image_quality_1280">1280x</string>
<string name="pref_category_mangadex">MangaDex</string>
<string name="eh_image_quality_980">980x</string>
<string name="eh_image_quality_1600">1600x</string>
<string name="eh_image_quality_2400">2400x</string>
<string name="eh_image_quality_780">780x</string>
<string name="syncyomi">SyncYomi</string>
<string name="aes_256">AES 256</string>
<string name="aes_128">AES 128</string>
<string name="add_tags">Добавить тэги</string>
<string name="multi_tags_comma_separated">Введите тэг(и), разделёнными запятыми.</string>
<string name="alt_titles">Альт. названия</string>
</resources> </resources>
@@ -643,4 +643,19 @@
<string name="action_copy_second_page">复制第二页</string> <string name="action_copy_second_page">复制第二页</string>
<string name="action_copy_combined_page">复制合并页</string> <string name="action_copy_combined_page">复制合并页</string>
<string name="only_show_updated_entries">仅显示包含新章节的条目</string> <string name="only_show_updated_entries">仅显示包含新章节的条目</string>
<string name="url">Url</string>
<string name="alt_titles">别名</string>
<string name="add_tags">添加标签</string>
<string name="multi_tags_comma_separated">输入标签,用逗号隔开。</string>
<string name="aes_128">AES 128</string>
<string name="aged">年龄限制</string>
<string name="anilist_id">Anilist id</string>
<string name="kitsu_id">Kitsu id</string>
<string name="mal_id">Mal id</string>
<string name="anime_planet_id">Anime planet id</string>
<string name="syncyomi">SyncYomi</string>
<string name="aes_256">AES 256</string>
<string name="favorites_sync_failed_to_add_to_local_error">\'%1$s\' %2$s</string>
<string name="id">Id</string>
<string name="token">Token</string>
</resources> </resources>
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<plurals name="cleanup_done"> <plurals name="cleanup_done">
<item quantity="other">清理完成。清理了 %d 個資料夾</item> <item quantity="other">清理清理了 %d 個資料夾</item>
</plurals> </plurals>
<plurals name="num_lock_times"> <plurals name="num_lock_times">
<item quantity="other">%d 個鎖定時間表</item> <item quantity="other">%d 個鎖定時間表</item>
@@ -10,9 +10,8 @@
<item quantity="other">重試 %1$d 個失敗的頁面……</item> <item quantity="other">重試 %1$d 個失敗的頁面……</item>
</plurals> </plurals>
<plurals name="pref_tag_sorting_desc"> <plurals name="pref_tag_sorting_desc">
<item quantity="other">%1$d 個標籤在排序列表中 這在書中增加了一個選項,以基於優先級的標籤列表進行排序,這意味著作品將以你想要的標籤優先的方式進行排序</item> <item quantity="other">%1$d 個標籤在排序列表中 這在書中增加了一個選項,以基於優先級的標籤列表進行排序,這意味著作品將以你想要的標籤優先的方式進行排序</item>
</plurals> </plurals>
<plurals name="migrate_entry"> <plurals name="migrate_entry">
<item quantity="other">遷移 %1$d%2$s 作品?</item> <item quantity="other">遷移 %1$d%2$s 作品?</item>
</plurals> </plurals>
@@ -22,17 +21,14 @@
<plurals name="entry_migrated"> <plurals name="entry_migrated">
<item quantity="other">%d 個作品已遷移</item> <item quantity="other">%d 個作品已遷移</item>
</plurals> </plurals>
<!-- Extra gallery info --> <!-- Extra gallery info -->
<plurals name="num_pages"> <plurals name="num_pages">
<item quantity="other">%1$d 頁</item> <item quantity="other">%1$d 頁</item>
</plurals> </plurals>
<!-- Enhanced E/ExHentai Browse View --> <!-- Enhanced E/ExHentai Browse View -->
<plurals name="browse_language_and_pages"> <plurals name="browse_language_and_pages">
<item quantity="other">%2$s, %1$d 頁</item> <item quantity="other">%2$s, %1$d 頁</item>
</plurals> </plurals>
<!-- Humanize time --> <!-- Humanize time -->
<plurals name="humanize_year"> <plurals name="humanize_year">
<item quantity="other">%1$d 年前</item> <item quantity="other">%1$d 年前</item>
@@ -55,7 +51,7 @@
<plurals name="humanize_second"> <plurals name="humanize_second">
<item quantity="other">%1$d 秒前</item> <item quantity="other">%1$d 秒前</item>
</plurals> </plurals>
<plurals name="row_count"> <plurals name="row_count">
<item quantity="other">%d 行</item> <item quantity="other">%d 行</item>
</plurals> </plurals>
</resources> </resources>
@@ -27,12 +27,12 @@
<string name="enable_exhentai">啟用 ExHentai</string> <string name="enable_exhentai">啟用 ExHentai</string>
<string name="requires_login">需要登入</string> <string name="requires_login">需要登入</string>
<string name="use_hentai_at_home">使用 Hentai@Home 網路</string> <string name="use_hentai_at_home">使用 Hentai@Home 網路</string>
<string name="use_hentai_at_home_summary">如果可用,您是否希望透過 Hentai@Home 網路載入圖片?停用此選項將減少您能夠瀏覽的頁面數量\n選項:\n- 任何用戶端(建議)\n- 使用預設通訊埠的用戶端(可能會稍慢如果防火牆或代理阻止非標準的流量時啟用此選項)</string> <string name="use_hentai_at_home_summary">如果可用,您是否希望透過 Hentai@Home 網路載入圖片?停用此選項將減少您能夠瀏覽的頁面數量\n選項:\n- 任何用戶端(建議)\n- 使用預設通訊埠的用戶端(可能會稍慢如果防火牆或代理阻止非標準的流量時啟用此選項)</string>
<string name="use_hentai_at_home_option_1">任何用戶端(建議)</string> <string name="use_hentai_at_home_option_1">任何用戶端(建議)</string>
<string name="use_hentai_at_home_option_2">僅使用預設通訊埠的用戶端</string> <string name="use_hentai_at_home_option_2">僅使用預設通訊埠的用戶端</string>
<string name="show_japanese_titles">在搜尋結果中顯示日文標題</string> <string name="show_japanese_titles">在搜尋結果中顯示日文標題</string>
<string name="show_japanese_titles_option_1">目前在搜尋結果中顯示日文標題,變更後請到進階設定清除章節快取</string> <string name="show_japanese_titles_option_1">目前在搜尋結果中顯示日文標題,變更後請到進階設定清除章節快取</string>
<string name="show_japanese_titles_option_2">目前在搜尋結果中顯示英文/羅馬拼音的標題變更後請到進階設定清除章節快取</string> <string name="show_japanese_titles_option_2">目前在搜尋結果中顯示英文/羅馬拼音的標題變更後請到進階設定清除章節快取</string>
<string name="use_original_images">使用原圖</string> <string name="use_original_images">使用原圖</string>
<string name="use_original_images_on">目前使用的是原始圖片</string> <string name="use_original_images_on">目前使用的是原始圖片</string>
<string name="use_original_images_off">目前使用的是重新取樣圖片</string> <string name="use_original_images_off">目前使用的是重新取樣圖片</string>
@@ -41,12 +41,12 @@
<string name="watched_tags_exh">ExHentai 收藏的標籤</string> <string name="watched_tags_exh">ExHentai 收藏的標籤</string>
<string name="tag_filtering_threshold">標籤過濾臨界值</string> <string name="tag_filtering_threshold">標籤過濾臨界值</string>
<string name="tag_filtering_threshhold_error">必須介於 -9999 和 0</string> <string name="tag_filtering_threshhold_error">必須介於 -9999 和 0</string>
<string name="tag_filtering_threshhold_summary">你可以透過在 "我的 Tags E/ExHentai" 頁面新增負的權重來軟過濾標籤如果一個畫廊的標籤加起來的權重低於這個值,它就會被過濾掉這個臨界值可以在 -9999 和 0 之間設定 目前:%1$d</string> <string name="tag_filtering_threshhold_summary">你可以透過在我的 Tags E/ExHentai頁面新增負的權重來軟過濾標籤如果一個畫廊的標籤加起來的權重低於這個值,它就會被過濾掉這個臨界值可以在 -9999 和 0 之間設定 目前:%1$d</string>
<string name="tag_watching_threshhold">標籤收藏臨界值</string> <string name="tag_watching_threshhold">標籤收藏臨界值</string>
<string name="tag_watching_threshhold_error">必須介於 0 和 9999</string> <string name="tag_watching_threshhold_error">必須介於 0 和 9999</string>
<string name="tag_watching_threshhold_summary">如果最近上傳的畫廊至少有一個權重為正的已收藏標籤,並且其已收藏標籤的權重之和達到這個值或更高,就會被列入已收藏頁面這個臨界值可以在 0 到 9999 之間設定目前:%1$d</string> <string name="tag_watching_threshhold_summary">如果最近上傳的畫廊至少有一個權重為正的已收藏標籤,並且其已收藏標籤的權重之和達到這個值或更高,就會被列入已收藏頁面這個臨界值可以在 0 到 9999 之間設定目前:%1$d</string>
<string name="language_filtering">語言過濾</string> <string name="language_filtering">語言過濾</string>
<string name="language_filtering_summary">如果您想在畫廊列表和搜尋中隱藏某些語言的畫廊,請在彈出的對話框中選擇它們\n請注意,無論您的搜尋條件為何,匹配的畫廊都不會出現\n勾選 = 排除</string> <string name="language_filtering_summary">如果您想在畫廊列表和搜尋中隱藏某些語言的畫廊,請在彈出的對話框中選擇它們\n請注意,無論您的搜尋條件為何,匹配的畫廊都不會出現\n勾選 = 排除</string>
<string name="frong_page_categories">首頁類別</string> <string name="frong_page_categories">首頁類別</string>
<string name="fromt_page_categories_summary">你希望在首頁和搜尋中預設顯示哪些類別?它們仍然可以透過啟用它們的過濾器而被啟用</string> <string name="fromt_page_categories_summary">你希望在首頁和搜尋中預設顯示哪些類別?它們仍然可以透過啟用它們的過濾器而被啟用</string>
<string name="watched_list_default">監視列表過濾器預設狀態</string> <string name="watched_list_default">監視列表過濾器預設狀態</string>
@@ -59,14 +59,14 @@
<string name="pref_enhanced_e_hentai_view_summary">啟用或停用為 E/ExHentai 製作的增強型瀏覽選單</string> <string name="pref_enhanced_e_hentai_view_summary">啟用或停用為 E/ExHentai 製作的增強型瀏覽選單</string>
<string name="favorites_sync">E-Hentai 收藏同步</string> <string name="favorites_sync">E-Hentai 收藏同步</string>
<string name="disable_favorites_uploading">停用收藏上傳</string> <string name="disable_favorites_uploading">停用收藏上傳</string>
<string name="disable_favorites_uploading_summary">僅從 ExHentai 下載收藏夾應用程式中對收藏夾的任何變更都不會被上傳防止 ExHentai 上的收藏夾意外遺失請注意,刪除的變更仍會被應用(如果您在 ExHentai 上刪除了一個收藏夾,它也會在本應用程式中刪除)</string> <string name="disable_favorites_uploading_summary">僅從 ExHentai 下載收藏夾應用程式中對收藏夾的任何變更都不會被上傳防止 ExHentai 上的收藏夾意外遺失請注意,刪除的變更仍會被應用(如果您在 ExHentai 上刪除了一個收藏夾,它也會在本應用程式中刪除)</string>
<string name="show_favorite_sync_notes">顯示收藏夾同步注意事項</string> <string name="show_favorite_sync_notes">顯示收藏夾同步注意事項</string>
<string name="show_favorite_sync_notes_summary">顯示一些關於收藏夾同步功能的注意事項</string> <string name="show_favorite_sync_notes_summary">顯示一些關於收藏夾同步功能的注意事項</string>
<string name="please_login">請登入!</string> <string name="please_login">請登入!</string>
<string name="ignore_sync_errors">盡可能忽略同步錯誤</string> <string name="ignore_sync_errors">盡可能忽略同步錯誤</string>
<string name="ignore_sync_errors_summary">在同步過程中遇到錯誤時,不要立即中止當同步完成時,錯誤仍然會顯示在某些情況下可能會導致收藏夾的遺失在同步大型資料庫時很有用</string> <string name="ignore_sync_errors_summary">在同步過程中遇到錯誤時,不要立即中止當同步完成時,錯誤仍然會顯示在某些情況下可能會導致收藏夾的遺失在同步大型資料庫時很有用</string>
<string name="force_sync_state_reset">強制重設同步狀態</string> <string name="force_sync_state_reset">強制重設同步狀態</string>
<string name="force_sync_state_reset_summary">在下一次同步時執行完整的重新同步,移除的項目將不會被同步應用程式中的所有收藏將會重新上傳到 ExHentai,而 ExHentai 上的所有收藏也會重新下載到應用程式中這在同步中斷後修復同步問題時非常有用</string> <string name="force_sync_state_reset_summary">在下一次同步時執行完整的重新同步,移除的項目將不會被同步應用程式中的所有收藏將會重新上傳到 ExHentai,而 ExHentai 上的所有收藏也會重新下載到應用程式中這在同步中斷後修復同步問題時非常有用</string>
<string name="sync_state_reset">同步狀態重設</string> <string name="sync_state_reset">同步狀態重設</string>
<string name="gallery_update_checker">畫廊更新檢查器</string> <string name="gallery_update_checker">畫廊更新檢查器</string>
<string name="auto_update_restrictions">自動更新限制</string> <string name="auto_update_restrictions">自動更新限制</string>
@@ -79,17 +79,17 @@
<string name="time_between_batches_12_hours">12 小時</string> <string name="time_between_batches_12_hours">12 小時</string>
<string name="time_between_batches_24_hours">24 小時</string> <string name="time_between_batches_24_hours">24 小時</string>
<string name="time_between_batches_48_hours">48 小時</string> <string name="time_between_batches_48_hours">48 小時</string>
<string name="time_between_batches_summary_1">在 %1$s 以內不會檢查您書櫃中的畫廊是否有更新</string> <string name="time_between_batches_summary_1">在 %1$s 以內不會檢查您書櫃中的畫廊是否有更新</string>
<string name="time_between_batches_summary_2">%1$s 會分批檢查/更新畫廊這代表它將等待 %2$d 小時,檢查 %3$d 畫廊,等待 %2$d 小時,檢查 %3$d ……</string> <string name="time_between_batches_summary_2">%1$s 會分批檢查/更新畫廊這代表它將等待 %2$d 小時,檢查 %3$d 畫廊,等待 %2$d 小時,檢查 %3$d ……</string>
<string name="show_updater_statistics">顯示更新器的統計資料</string> <string name="show_updater_statistics">顯示更新器的統計資料</string>
<string name="gallery_updater_statistics_collection">收集統計資料中……</string> <string name="gallery_updater_statistics_collection">收集統計資料中……</string>
<string name="gallery_updater_statistics">畫廊更新器統計</string> <string name="gallery_updater_statistics">畫廊更新器統計</string>
<string name="gallery_updater_stats_text">更新器最後執行於 %1$s,檢查了可檢查的 %3$d 個畫廊中的 %2$d 個</string> <string name="gallery_updater_stats_text">更新器最後執行於 %1$s,檢查了可檢查的 %3$d 個畫廊中的 %2$d 個</string>
<string name="gallery_updater_not_ran_yet">更新器從未執行</string> <string name="gallery_updater_not_ran_yet">更新器從未執行</string>
<string name="gallery_updater_stats_time">\n上一次檢查的畫廊:\n- 1 小時: %1$d\n- 6 小時: %2$d\n- 12 小時: %3$d\n- 1 天: %4$d\n- 2 天: %5$d\n- 1 周: %6$d\n- 1 個月: %7$d\n- 1 年: %8$d</string> <string name="gallery_updater_stats_time">\n上一次檢查的畫廊:\n- 1 小時: %1$d\n- 6 小時: %2$d\n- 12 小時: %3$d\n- 1 天: %4$d\n- 2 天: %5$d\n- 1 周: %6$d\n- 1 個月: %7$d\n- 1 年: %8$d</string>
<!-- EH Settings Upload Dialogs --> <!-- EH Settings Upload Dialogs -->
<string name="settings_profile_note">建立設定檔說明</string> <string name="settings_profile_note">建立設定檔說明</string>
<string name="settings_profile_note_message">本應用程式現在將在 E-Hentai 和 ExHentai 上建立一個新的設定檔,以最佳化應用程式的性能。請確保您在這兩個網站上擁有的設定檔少於三個\n\n如果你不知道什麼是設定檔,那麼對你無影響,只需點擊確定”。</string> <string name="settings_profile_note_message">本應用程式現在將在 E-Hentai 和 ExHentai 上建立一個新的設定檔,以最佳化應用程式的性能。請確保您在這兩個網站上擁有的設定檔少於三個\n\n如果你不知道什麼是設定檔,那麼對你無影響,只需點擊確定</string>
<string name="eh_settings_successfully_uploaded">設定檔上傳成功!</string> <string name="eh_settings_successfully_uploaded">設定檔上傳成功!</string>
<string name="eh_settings_configuration_failed">設定失敗!</string> <string name="eh_settings_configuration_failed">設定失敗!</string>
<string name="eh_settings_configuration_failed_message">在設定過程中出現錯誤:%1$s</string> <string name="eh_settings_configuration_failed_message">在設定過程中出現錯誤:%1$s</string>
@@ -101,7 +101,7 @@
<string name="alternative_login_page">備用登入頁面</string> <string name="alternative_login_page">備用登入頁面</string>
<string name="skip_page_restyling">跳過頁面重排</string> <string name="skip_page_restyling">跳過頁面重排</string>
<string name="custom_igneous_cookie">自訂 igneous cookie</string> <string name="custom_igneous_cookie">自訂 igneous cookie</string>
<string name="custom_igneous_cookie_message">某些使用者無法正常存取 ExHentai,必須輸入特定的 igneous cookie,此選項為這些使用者設計</string> <string name="custom_igneous_cookie_message">某些使用者無法正常存取 ExHentai,必須輸入特定的 igneous cookie,此選項為這些使用者設計</string>
<!-- Advanced Settings --> <!-- Advanced Settings -->
<string name="developer_tools">開發者工具</string> <string name="developer_tools">開發者工具</string>
<string name="toggle_hentai_features">啟用整合的 Hentai 功能</string> <string name="toggle_hentai_features">啟用整合的 Hentai 功能</string>
@@ -109,7 +109,7 @@
<string name="toggle_delegated_sources">啟用代理來源</string> <string name="toggle_delegated_sources">啟用代理來源</string>
<string name="toggle_delegated_sources_summary">下列來源如果已安裝則應用程式 %1$s 代理: %2$s</string> <string name="toggle_delegated_sources_summary">下列來源如果已安裝則應用程式 %1$s 代理: %2$s</string>
<string name="log_level">日誌等級</string> <string name="log_level">日誌等級</string>
<string name="log_level_summary">變更此選項會影響應用程式性能變更需要完全重啟應用程式才能生效現在的值:%s</string> <string name="log_level_summary">變更此選項會影響應用程式性能變更需要完全重啟應用程式才能生效現在的值:%s</string>
<string name="enable_source_blacklist">啟用來源黑名單</string> <string name="enable_source_blacklist">啟用來源黑名單</string>
<string name="enable_source_blacklist_summary">如果與 %1$s 不相容則隱藏擴充套件或來源。變更需要完全重啟應用程式才能生效。</string> <string name="enable_source_blacklist_summary">如果與 %1$s 不相容則隱藏擴充套件或來源。變更需要完全重啟應用程式才能生效。</string>
<string name="open_debug_menu">開啟 Debug 選單</string> <string name="open_debug_menu">開啟 Debug 選單</string>
@@ -300,7 +300,7 @@
<string name="eh_retry_all_help">重試所有說明</string> <string name="eh_retry_all_help">重試所有說明</string>
<string name="eh_retry_all_help_message">將所有下載失敗的頁面重新加入下載佇列。</string> <string name="eh_retry_all_help_message">將所有下載失敗的頁面重新加入下載佇列。</string>
<string name="eh_boost_page_help">加速頁面說明</string> <string name="eh_boost_page_help">加速頁面說明</string>
<string name="eh_boost_page_help_message">通常情況下,下載器在同一時間只能下載特定數量的頁面。這代表你在等待頁面下載時不會立即開始下載,直到有一個空閒的下載執行緒。啟用加速頁面將迫使下載器立即開始下載,而不管是否有可用的執行緒。</string> <string name="eh_boost_page_help_message">通常情況下,下載器在同一時間只能下載特定數量的頁面。這代表你在等待頁面下載時不會立即開始下載,直到有一個空閒的下載執行緒。啟用加速頁面將迫使下載器立即開始下載,而不管是否有可用的執行緒。</string>
<string name="eh_boost_page_invalid">此頁面無法加速(無效頁面)!</string> <string name="eh_boost_page_invalid">此頁面無法加速(無效頁面)!</string>
<string name="eh_boost_page_errored">頁面載入失敗,請按重試按鈕!</string> <string name="eh_boost_page_errored">頁面載入失敗,請按重試按鈕!</string>
<string name="eh_boost_page_downloading">此頁面已經在下載了!</string> <string name="eh_boost_page_downloading">此頁面已經在下載了!</string>
@@ -657,4 +657,7 @@
<string name="action_copy_second_page">複製第二頁</string> <string name="action_copy_second_page">複製第二頁</string>
<string name="action_copy_combined_page">複製合併頁</string> <string name="action_copy_combined_page">複製合併頁</string>
<string name="only_show_updated_entries">僅顯示包含新章節的條目</string> <string name="only_show_updated_entries">僅顯示包含新章節的條目</string>
<string name="add_tags">新增標籤</string>
<string name="multi_tags_comma_separated">輸入標籤,可用逗號分隔</string>
<string name="alt_titles">替代標題</string>
</resources> </resources>
+1 -1
View File
@@ -2,4 +2,4 @@
This module houses the string resources and translations. This module houses the string resources and translations.
Original English strings are manged in `src/commonMain/resources/MR/base/`. Translations are done externally via Weblate. See [our website](https://mihon.app/docs/contribute#translation) for more details. Original English strings are managed in `src/commonMain/moko-resources/base/`. Translations are done externally via Weblate. See [our website](https://mihon.app/docs/contribute#translation) for more details.
@@ -509,6 +509,7 @@
<!-- Tracking section --> <!-- Tracking section -->
<string name="tracking_guide">Tracking guide</string> <string name="tracking_guide">Tracking guide</string>
<string name="pref_auto_update_manga_sync">Update progress after reading</string> <string name="pref_auto_update_manga_sync">Update progress after reading</string>
<string name="pref_auto_update_manga_on_mark_read">Update progress when marked as read</string>
<string name="services">Trackers</string> <string name="services">Trackers</string>
<string name="tracking_info">One-way sync to update the chapter progress in external tracker services. Set up tracking for individual entries from their tracking button.</string> <string name="tracking_info">One-way sync to update the chapter progress in external tracker services. Set up tracking for individual entries from their tracking button.</string>
<string name="enhanced_services">Enhanced trackers</string> <string name="enhanced_services">Enhanced trackers</string>
@@ -582,7 +583,7 @@
<string name="pref_reset_user_agent_string">Reset default user agent string</string> <string name="pref_reset_user_agent_string">Reset default user agent string</string>
<string name="requires_app_restart">Requires app restart to take effect</string> <string name="requires_app_restart">Requires app restart to take effect</string>
<string name="cookies_cleared">Cookies cleared</string> <string name="cookies_cleared">Cookies cleared</string>
<string name="pref_invalidate_download_cache">Invalidate downloads index</string> <string name="pref_invalidate_download_cache">Reindex downloads</string>
<string name="pref_invalidate_download_cache_summary">Force app to recheck downloaded chapters</string> <string name="pref_invalidate_download_cache_summary">Force app to recheck downloaded chapters</string>
<string name="download_cache_invalidated">Downloads index invalidated</string> <string name="download_cache_invalidated">Downloads index invalidated</string>
<string name="pref_clear_database">Clear database</string> <string name="pref_clear_database">Clear database</string>
@@ -739,6 +740,7 @@
<string name="exclude_scanlators">Exclude scanlators</string> <string name="exclude_scanlators">Exclude scanlators</string>
<string name="no_scanlators_found">No scanlators found</string> <string name="no_scanlators_found">No scanlators found</string>
<string name="confirm_tracker_update">Update trackers to chapter %d?</string> <string name="confirm_tracker_update">Update trackers to chapter %d?</string>
<string name="trackers_updated_summary">Trackers updated to chapter %d</string>
<!-- Tracking Screen --> <!-- Tracking Screen -->
<string name="manga_tracking_tab">Tracking</string> <string name="manga_tracking_tab">Tracking</string>
@@ -28,7 +28,6 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.RadioButton import androidx.compose.material3.RadioButton
import androidx.compose.material3.Slider
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@@ -47,6 +46,7 @@ import tachiyomi.core.common.preference.Preference
import tachiyomi.core.common.preference.TriState import tachiyomi.core.common.preference.TriState
import tachiyomi.core.common.preference.toggle import tachiyomi.core.common.preference.toggle
import tachiyomi.presentation.core.components.material.DISABLED_ALPHA import tachiyomi.presentation.core.components.material.DISABLED_ALPHA
import tachiyomi.presentation.core.components.material.Slider
import tachiyomi.presentation.core.components.material.padding import tachiyomi.presentation.core.components.material.padding
import tachiyomi.presentation.core.i18n.stringResource import tachiyomi.presentation.core.i18n.stringResource
import tachiyomi.presentation.core.theme.header import tachiyomi.presentation.core.theme.header
@@ -193,17 +193,14 @@ fun SliderItem(
} }
Slider( Slider(
value = value.toFloat(),
onValueChange = {
val newValue = it.toInt()
if (newValue != value) {
onChange(newValue)
haptic.performHapticFeedback(HapticFeedbackType.TextHandleMove)
}
},
modifier = Modifier.weight(1.5f), modifier = Modifier.weight(1.5f),
valueRange = min.toFloat()..max.toFloat(), value = value,
steps = max - min, onValueChange = f@{
if (it == value) return@f
onChange(it)
haptic.performHapticFeedback(HapticFeedbackType.TextHandleMove)
},
valueRange = min..max,
) )
} }
} }
@@ -0,0 +1,48 @@
package tachiyomi.presentation.core.components.material
import androidx.annotation.IntRange
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.material3.Slider
import androidx.compose.material3.SliderColors
import androidx.compose.material3.SliderDefaults
import androidx.compose.material3.SliderState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
@Composable
fun Slider(
value: Int,
onValueChange: (Int) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
valueRange: ClosedRange<Int> = 0..1,
@IntRange(from = 0) steps: Int = with(valueRange) { (endInclusive - start) - 1 },
onValueChangeFinished: (() -> Unit)? = null,
colors: SliderColors = SliderDefaults.colors(),
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
thumb: @Composable (SliderState) -> Unit = {
SliderDefaults.Thumb(
interactionSource = interactionSource,
colors = colors,
enabled = enabled,
)
},
track: @Composable (SliderState) -> Unit = { sliderState ->
SliderDefaults.Track(colors = colors, enabled = enabled, sliderState = sliderState)
},
) {
Slider(
value = value.toFloat(),
onValueChange = { onValueChange(it.toInt()) },
modifier = modifier,
enabled = enabled,
valueRange = with(valueRange) { start.toFloat()..endInclusive.toFloat() },
steps = steps,
onValueChangeFinished = onValueChangeFinished,
colors = colors,
interactionSource = interactionSource,
thumb = thumb,
track = track,
)
}
@@ -82,5 +82,5 @@ val CustomIcons.Discord: ImageVector
return _discord!! return _discord!!
} }
@Suppress("ObjectPropertyName", "ktlint:standard:backing-property-naming") @Suppress("ObjectPropertyName")
private var _discord: ImageVector? = null private var _discord: ImageVector? = null
@@ -59,5 +59,5 @@ val CustomIcons.Facebook: ImageVector
return _facebook!! return _facebook!!
} }
@Suppress("ObjectPropertyName", "ktlint:standard:backing-property-naming") @Suppress("ObjectPropertyName")
private var _facebook: ImageVector? = null private var _facebook: ImageVector? = null
@@ -64,5 +64,5 @@ val CustomIcons.Github: ImageVector
return _github!! return _github!!
} }
@Suppress("ObjectPropertyName", "ktlint:standard:backing-property-naming") @Suppress("ObjectPropertyName")
private var _github: ImageVector? = null private var _github: ImageVector? = null
@@ -90,5 +90,5 @@ val CustomIcons.Reddit: ImageVector
return _reddit!! return _reddit!!
} }
@Suppress("ObjectPropertyName", "ktlint:standard:backing-property-naming") @Suppress("ObjectPropertyName")
private var _reddit: ImageVector? = null private var _reddit: ImageVector? = null
@@ -57,5 +57,5 @@ val CustomIcons.X: ImageVector
return _x!! return _x!!
} }
@Suppress("ObjectPropertyName", "ktlint:standard:backing-property-naming") @Suppress("ObjectPropertyName")
private var _x: ImageVector? = null private var _x: ImageVector? = null
@@ -4,12 +4,10 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.State import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import kotlinx.coroutines.CoroutineScope
import tachiyomi.core.common.preference.Preference import tachiyomi.core.common.preference.Preference
@Composable @Composable
fun <T> Preference<T>.collectAsState(scope: CoroutineScope = rememberCoroutineScope()): State<T> { fun <T> Preference<T>.collectAsState(): State<T> {
val flow = remember(this) { stateIn(scope) } val flow = remember(this) { changes() }
return flow.collectAsState() return flow.collectAsState(initial = get())
} }
+1
View File
@@ -20,6 +20,7 @@ dependencies {
api(projects.i18n) api(projects.i18n)
implementation(compose.glance) implementation(compose.glance)
implementation(libs.material)
implementation(kotlinx.immutables) implementation(kotlinx.immutables)
@@ -1,4 +1,4 @@
@file:Suppress("PropertyName", "ktlint:standard:property-naming") @file:Suppress("PropertyName")
package eu.kanade.tachiyomi.source.model package eu.kanade.tachiyomi.source.model
@@ -1,4 +1,4 @@
@file:Suppress("PropertyName", "ktlint:standard:property-naming") @file:Suppress("PropertyName")
package eu.kanade.tachiyomi.source.model package eu.kanade.tachiyomi.source.model
@@ -1,4 +1,4 @@
@file:Suppress("PropertyName", "ktlint:standard:property-naming") @file:Suppress("PropertyName")
package eu.kanade.tachiyomi.source.model package eu.kanade.tachiyomi.source.model
@@ -1,4 +1,4 @@
@file:Suppress("PropertyName", "ktlint:standard:property-naming") @file:Suppress("PropertyName")
package eu.kanade.tachiyomi.source.model package eu.kanade.tachiyomi.source.model
@@ -19,7 +19,7 @@ import kotlinx.serialization.json.decodeFromStream
import logcat.LogPriority import logcat.LogPriority
import mihon.core.common.archive.ZipWriter import mihon.core.common.archive.ZipWriter
import mihon.core.common.archive.archiveReader import mihon.core.common.archive.archiveReader
import nl.adaptivity.xmlutil.AndroidXmlReader import nl.adaptivity.xmlutil.core.AndroidXmlReader
import nl.adaptivity.xmlutil.serialization.XML import nl.adaptivity.xmlutil.serialization.XML
import tachiyomi.core.common.i18n.stringResource import tachiyomi.core.common.i18n.stringResource
import tachiyomi.core.common.storage.extension import tachiyomi.core.common.storage.extension
@@ -60,10 +60,10 @@ actual class LocalSource(
private val json: Json by injectLazy() private val json: Json by injectLazy()
private val xml: XML by injectLazy() private val xml: XML by injectLazy()
@Suppress("PrivatePropertyName", "ktlint:standard:property-naming") @Suppress("PrivatePropertyName")
private val PopularFilters = FilterList(OrderBy.Popular(context)) private val PopularFilters = FilterList(OrderBy.Popular(context))
@Suppress("PrivatePropertyName", "ktlint:standard:property-naming") @Suppress("PrivatePropertyName")
private val LatestFilters = FilterList(OrderBy.Latest(context)) private val LatestFilters = FilterList(OrderBy.Latest(context))
override val name: String = context.stringResource(MR.strings.local_source) override val name: String = context.stringResource(MR.strings.local_source)