mirror of
https://github.com/mihonapp/mihon.git
synced 2025-07-27 18:05:53 +02:00
Compare commits
91 Commits
Author | SHA1 | Date | |
---|---|---|---|
26ddc6e3aa | |||
1dc4a52f61 | |||
473a4fec70 | |||
1919c2d925 | |||
71e31e6c03 | |||
c01df7f0a1 | |||
6024f6175b | |||
33500e5b69 | |||
17899a6d6d | |||
4c3eb68d3a | |||
29ced9642d | |||
af82591d85 | |||
5bc4a446ec | |||
83e93b254e | |||
49c7dd0cac | |||
96d2fb62e4 | |||
c76a136d3f | |||
940409a4c3 | |||
071dd88ef8 | |||
a58a4634e2 | |||
5979e72662 | |||
010436e797 | |||
980709cccb | |||
fe80356756 | |||
cecf532ffd | |||
6cb255e60a | |||
b46fb7d1e1 | |||
8874193927 | |||
a4515ad251 | |||
55b0b57699 | |||
aab7795b4c | |||
196a8e6829 | |||
972cd98d7b | |||
a16b5d241b | |||
bfa918140f | |||
0721de5b81 | |||
a409fde519 | |||
8e34a30dce | |||
ba43462041 | |||
c8ae936ce9 | |||
853f949140 | |||
615b01a006 | |||
0eb5a3176b | |||
867a5a3ea0 | |||
42eaaa497f | |||
96c894ce5b | |||
c0214103a9 | |||
2b76a97989 | |||
9d77052d9c | |||
b4981058a2 | |||
032aa64195 | |||
7c8e8317a8 | |||
eb1cfc4cd4 | |||
f1e5cccee7 | |||
bc2ed763bd | |||
a35995b898 | |||
b1f46ed830 | |||
6c1565a7d4 | |||
2ca6b655ad | |||
a83a481ac8 | |||
65a8b63b3b | |||
b20ca36db9 | |||
189f92d7e8 | |||
cdd4ec6233 | |||
ef1bb4e800 | |||
c475acd1ea | |||
7d50d7ff52 | |||
28522f4f90 | |||
ec3a227a02 | |||
89decf3474 | |||
0b2794e843 | |||
554dfb5874 | |||
9c30fa1da3 | |||
e81bd61e24 | |||
7a0b54bb38 | |||
f060daf8c4 | |||
c1976ef599 | |||
f16fb4e1e4 | |||
5da2c82f47 | |||
d443245d66 | |||
9be3eea5fd | |||
07a9fd061d | |||
2a070c0b1e | |||
7b5106d206 | |||
821d9cdb02 | |||
28575936d3 | |||
83a04da4a0 | |||
0894b1394f | |||
eb33d3c991 | |||
d7f01abf3a | |||
80635343ae |
.github
app
build.gradle.kts
src
main
AndroidManifest.xml
java
eu
kanade
tachiyomi
App.kt
data
backup
download
library
notification
preference
saver
updater
extension
network
source
ui
base
browse
extension
migration
search
source
filter
download
library
manga
more
reader
setting
webview
util
widget
res
color
drawable
layout-sw720dp
layout
menu
values-b+es+419
values-bg
values-ca
values-cs
values-de
values-el
values-es
values-fi
values-fil
values-fr
values-he
values-hi
values-hr
values-it
values-ja
values-ko
values-ms
values-nb-rNO
values-night
values-or
values-pt-rBR
values-ro
values-ru
values-sc
values-sr
values-sv
values-th
values-tr
values-vi
values-zh-rCN
values-zh-rTW
values
buildSrc/src/main/kotlin
gradle
2
.github/ISSUE_TEMPLATE.md
vendored
2
.github/ISSUE_TEMPLATE.md
vendored
@ -3,7 +3,7 @@
|
||||
I acknowledge that:
|
||||
|
||||
- I have updated:
|
||||
- To the latest version of the app (stable is v0.13.2)
|
||||
- To the latest version of the app (stable is v0.13.5)
|
||||
- All extensions
|
||||
- I have tried the troubleshooting guide: https://tachiyomi.org/help/guides/troubleshooting-problems/
|
||||
- If this is an issue with an extension, that I should be opening an issue in https://github.com/tachiyomiorg/tachiyomi-extensions
|
||||
|
4
.github/ISSUE_TEMPLATE/report_issue.yml
vendored
4
.github/ISSUE_TEMPLATE/report_issue.yml
vendored
@ -53,7 +53,7 @@ body:
|
||||
label: Tachiyomi version
|
||||
description: You can find your Tachiyomi version in **More → About**.
|
||||
placeholder: |
|
||||
Example: "0.13.2"
|
||||
Example: "0.13.5"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
@ -98,7 +98,7 @@ body:
|
||||
required: true
|
||||
- label: I have tried the [troubleshooting guide](https://tachiyomi.org/help/guides/troubleshooting/).
|
||||
required: true
|
||||
- label: I have updated the app to version **[0.13.2](https://github.com/tachiyomiorg/tachiyomi/releases/latest)**.
|
||||
- label: I have updated the app to version **[0.13.5](https://github.com/tachiyomiorg/tachiyomi/releases/latest)**.
|
||||
required: true
|
||||
- label: I have updated all installed extensions.
|
||||
required: true
|
||||
|
2
.github/ISSUE_TEMPLATE/request_feature.yml
vendored
2
.github/ISSUE_TEMPLATE/request_feature.yml
vendored
@ -33,7 +33,7 @@ body:
|
||||
required: true
|
||||
- label: If this is an issue with an extension, I should be opening an issue in the [extensions repository](https://github.com/tachiyomiorg/tachiyomi-extensions/issues/new/choose).
|
||||
required: true
|
||||
- label: I have updated the app to version **[0.13.2](https://github.com/tachiyomiorg/tachiyomi/releases/latest)**.
|
||||
- label: I have updated the app to version **[0.13.5](https://github.com/tachiyomiorg/tachiyomi/releases/latest)**.
|
||||
required: true
|
||||
- label: I will fill out all of the requested information in this form.
|
||||
required: true
|
||||
|
11
.github/workflows/build_pull_request.yml
vendored
11
.github/workflows/build_pull_request.yml
vendored
@ -5,6 +5,9 @@ on:
|
||||
- '**.md'
|
||||
- 'app/src/main/res/**/strings.xml'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build app
|
||||
@ -12,15 +15,19 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Clone repo
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Validate Gradle Wrapper
|
||||
uses: gradle/wrapper-validation-action@v1
|
||||
|
||||
- name: Dependency Review
|
||||
uses: actions/dependency-review-action@v1
|
||||
|
||||
- name: Set up JDK 11
|
||||
uses: actions/setup-java@v1
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: 11
|
||||
distribution: adopt
|
||||
|
||||
- name: Copy CI gradle.properties
|
||||
run: |
|
||||
|
5
.github/workflows/build_push.yml
vendored
5
.github/workflows/build_push.yml
vendored
@ -19,15 +19,16 @@ jobs:
|
||||
all_but_latest: true
|
||||
|
||||
- name: Clone repo
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Validate Gradle Wrapper
|
||||
uses: gradle/wrapper-validation-action@v1
|
||||
|
||||
- name: Set up JDK 11
|
||||
uses: actions/setup-java@v1
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: 11
|
||||
distribution: adopt
|
||||
|
||||
- name: Copy CI gradle.properties
|
||||
run: |
|
||||
|
@ -24,8 +24,8 @@ android {
|
||||
applicationId = "eu.kanade.tachiyomi"
|
||||
minSdk = AndroidConfig.minSdk
|
||||
targetSdk = AndroidConfig.targetSdk
|
||||
versionCode = 78
|
||||
versionName = "0.13.2"
|
||||
versionCode = 81
|
||||
versionName = "0.13.5"
|
||||
|
||||
buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"")
|
||||
buildConfigField("String", "COMMIT_SHA", "\"${getGitSha()}\"")
|
||||
@ -155,7 +155,7 @@ dependencies {
|
||||
implementation(androidx.bundles.lifecycle)
|
||||
|
||||
// Job scheduling
|
||||
implementation(androidx.work.runtime)
|
||||
implementation(androidx.bundles.workmanager)
|
||||
|
||||
// RX
|
||||
implementation(libs.bundles.reactivex)
|
||||
@ -219,6 +219,7 @@ dependencies {
|
||||
exclude(group = "androidx.viewpager", module = "viewpager")
|
||||
}
|
||||
implementation(libs.insetter)
|
||||
implementation(libs.markwon)
|
||||
|
||||
// Conductor
|
||||
implementation(libs.bundles.conductor)
|
||||
|
@ -26,7 +26,6 @@
|
||||
android:name=".App"
|
||||
android:allowBackup="false"
|
||||
android:hardwareAccelerated="true"
|
||||
android:hasFragileUserData="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:largeHeap="true"
|
||||
|
@ -1,5 +1,6 @@
|
||||
package eu.kanade.tachiyomi
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.ActivityManager
|
||||
import android.app.Application
|
||||
import android.app.PendingIntent
|
||||
@ -8,6 +9,7 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.os.Build
|
||||
import android.os.Looper
|
||||
import android.webkit.WebView
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
@ -34,6 +36,7 @@ import eu.kanade.tachiyomi.util.preference.asImmediateFlow
|
||||
import eu.kanade.tachiyomi.util.system.AuthenticatorUtil
|
||||
import eu.kanade.tachiyomi.util.system.WebViewUtil
|
||||
import eu.kanade.tachiyomi.util.system.animatorDurationScale
|
||||
import eu.kanade.tachiyomi.util.system.isDevFlavor
|
||||
import eu.kanade.tachiyomi.util.system.logcat
|
||||
import eu.kanade.tachiyomi.util.system.notification
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
@ -56,6 +59,7 @@ open class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
|
||||
|
||||
private val disableIncognitoReceiver = DisableIncognitoReceiver()
|
||||
|
||||
@SuppressLint("LaunchActivityFromNotification")
|
||||
override fun onCreate() {
|
||||
super<Application>.onCreate()
|
||||
|
||||
@ -150,27 +154,31 @@ open class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
|
||||
}
|
||||
|
||||
override fun getPackageName(): String {
|
||||
try {
|
||||
// Override the value passed as X-Requested-With in WebView requests
|
||||
val stackTrace = Thread.currentThread().stackTrace
|
||||
for (element in stackTrace) {
|
||||
if ("org.chromium.base.BuildInfo".equals(element.className, ignoreCase = true)) {
|
||||
if ("getAll".equals(element.methodName, ignoreCase = true)) {
|
||||
return WebViewUtil.SPOOF_PACKAGE_NAME
|
||||
}
|
||||
break
|
||||
// This causes freezes in Android 6/7 for some reason
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
try {
|
||||
// Override the value passed as X-Requested-With in WebView requests
|
||||
val stackTrace = Looper.getMainLooper().thread.stackTrace
|
||||
val chromiumElement = stackTrace.find {
|
||||
it.className.equals(
|
||||
"org.chromium.base.BuildInfo",
|
||||
ignoreCase = true,
|
||||
)
|
||||
}
|
||||
if (chromiumElement?.methodName.equals("getAll", ignoreCase = true)) {
|
||||
return WebViewUtil.SPOOF_PACKAGE_NAME
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
return super.getPackageName()
|
||||
}
|
||||
|
||||
protected open fun setupAcra() {
|
||||
if (BuildConfig.FLAVOR != "dev") {
|
||||
if (isDevFlavor.not()) {
|
||||
initAcra {
|
||||
buildConfigClass = BuildConfig::class.java
|
||||
excludeMatchingSharedPreferencesKeys = arrayOf(".*username.*", ".*password.*", ".*token.*")
|
||||
excludeMatchingSharedPreferencesKeys = listOf(".*username.*", ".*password.*", ".*token.*")
|
||||
|
||||
httpSender {
|
||||
uri = BuildConfig.ACRA_URI
|
||||
|
@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.data.backup.full
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import com.hippo.unifile.UniFile
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.backup.AbstractBackupManager
|
||||
import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CATEGORY
|
||||
import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CATEGORY_MASK
|
||||
@ -54,7 +55,7 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
|
||||
|
||||
backup = Backup(
|
||||
backupManga(databaseManga, flags),
|
||||
backupCategories(),
|
||||
backupCategories(flags),
|
||||
emptyList(),
|
||||
backupExtensionInfo(databaseManga),
|
||||
)
|
||||
@ -90,6 +91,10 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
|
||||
}
|
||||
|
||||
val byteArray = parser.encodeToByteArray(BackupSerializer, backup!!)
|
||||
if (byteArray.isEmpty()) {
|
||||
throw IllegalStateException(context.getString(R.string.empty_backup_error))
|
||||
}
|
||||
|
||||
file.openOutputStream().also {
|
||||
// Force overwrite old file
|
||||
(it as? FileOutputStream)?.channel?.truncate(0)
|
||||
@ -128,10 +133,15 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
|
||||
*
|
||||
* @return list of [BackupCategory] to be backed up
|
||||
*/
|
||||
private fun backupCategories(): List<BackupCategory> {
|
||||
return databaseHelper.getCategories()
|
||||
.executeAsBlocking()
|
||||
.map { BackupCategory.copyFrom(it) }
|
||||
private fun backupCategories(options: Int): List<BackupCategory> {
|
||||
// Check if user wants category information in backup
|
||||
return if (options and BACKUP_CATEGORY_MASK == BACKUP_CATEGORY) {
|
||||
databaseHelper.getCategories()
|
||||
.executeAsBlocking()
|
||||
.map { BackupCategory.copyFrom(it) }
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,6 @@
|
||||
package eu.kanade.tachiyomi.data.download
|
||||
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.graphics.BitmapFactory
|
||||
import androidx.core.app.NotificationCompat
|
||||
@ -184,8 +185,10 @@ internal class DownloadNotifier(private val context: Context) {
|
||||
* Called when the downloader receives a warning.
|
||||
*
|
||||
* @param reason the text to show.
|
||||
* @param timeout duration after which to automatically dismiss the notification.
|
||||
* Only works on Android 8+.
|
||||
*/
|
||||
fun onWarning(reason: String) {
|
||||
fun onWarning(reason: String, timeout: Long? = null, contentIntent: PendingIntent? = null) {
|
||||
with(errorNotificationBuilder) {
|
||||
setContentTitle(context.getString(R.string.download_notifier_downloader_title))
|
||||
setStyle(NotificationCompat.BigTextStyle().bigText(reason))
|
||||
@ -194,6 +197,8 @@ internal class DownloadNotifier(private val context: Context) {
|
||||
clearActions()
|
||||
setContentIntent(NotificationHandler.openDownloadManagerPendingActivity(context))
|
||||
setProgress(0, 0, false)
|
||||
timeout?.let { setTimeoutAfter(it) }
|
||||
contentIntent?.let { setContentIntent(it) }
|
||||
|
||||
show(Notifications.ID_DOWNLOAD_CHAPTER_ERROR)
|
||||
}
|
||||
|
@ -1,18 +1,17 @@
|
||||
package eu.kanade.tachiyomi.data.download
|
||||
|
||||
import android.content.Context
|
||||
import android.webkit.MimeTypeMap
|
||||
import android.widget.Toast
|
||||
import com.hippo.unifile.UniFile
|
||||
import com.jakewharton.rxrelay.BehaviorRelay
|
||||
import com.jakewharton.rxrelay.PublishRelay
|
||||
import eu.kanade.tachiyomi.BuildConfig
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.cache.ChapterCache
|
||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.download.model.Download
|
||||
import eu.kanade.tachiyomi.data.download.model.DownloadQueue
|
||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateNotifier
|
||||
import eu.kanade.tachiyomi.data.notification.NotificationHandler
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.source.UnmeteredSource
|
||||
@ -28,7 +27,6 @@ import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||
import eu.kanade.tachiyomi.util.storage.saveTo
|
||||
import eu.kanade.tachiyomi.util.system.ImageUtil
|
||||
import eu.kanade.tachiyomi.util.system.logcat
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import kotlinx.coroutines.async
|
||||
import logcat.LogPriority
|
||||
import okhttp3.Response
|
||||
@ -275,14 +273,22 @@ class Downloader(
|
||||
|
||||
// Start downloader if needed
|
||||
if (autoStart && wasEmpty) {
|
||||
val queuedDownloads = queue.filter { it.source !is UnmeteredSource }.count()
|
||||
val maxDownloadsFromSource = queue
|
||||
.groupBy { it.source }
|
||||
.filterKeys { it !is UnmeteredSource }
|
||||
.maxOf { it.value.size }
|
||||
// TODO: show warnings in stable
|
||||
if (maxDownloadsFromSource > CHAPTERS_PER_SOURCE_QUEUE_WARNING_THRESHOLD && BuildConfig.FLAVOR != "stable") {
|
||||
.maxOfOrNull { it.value.size }
|
||||
?: 0
|
||||
if (
|
||||
queuedDownloads > DOWNLOADS_QUEUED_WARNING_THRESHOLD ||
|
||||
maxDownloadsFromSource > CHAPTERS_PER_SOURCE_QUEUE_WARNING_THRESHOLD
|
||||
) {
|
||||
withUIContext {
|
||||
context.toast(R.string.download_queue_size_warning, Toast.LENGTH_LONG)
|
||||
notifier.onWarning(
|
||||
context.getString(R.string.download_queue_size_warning),
|
||||
WARNING_NOTIF_TIMEOUT_MS,
|
||||
NotificationHandler.openUrl(context, LibraryUpdateNotifier.HELP_WARNING_URL),
|
||||
)
|
||||
}
|
||||
}
|
||||
DownloadService.start(context)
|
||||
@ -465,7 +471,7 @@ class Downloader(
|
||||
// Else read magic numbers.
|
||||
?: ImageUtil.findImageType { file.openInputStream() }?.mime
|
||||
|
||||
return MimeTypeMap.getSingleton().getExtensionFromMimeType(mime) ?: "jpg"
|
||||
return ImageUtil.getExtensionFromMimeType(mime)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -561,7 +567,9 @@ class Downloader(
|
||||
|
||||
companion object {
|
||||
const val TMP_DIR_SUFFIX = "_tmp"
|
||||
const val WARNING_NOTIF_TIMEOUT_MS = 30_000L
|
||||
const val CHAPTERS_PER_SOURCE_QUEUE_WARNING_THRESHOLD = 15
|
||||
private const val DOWNLOADS_QUEUED_WARNING_THRESHOLD = 30
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,9 +8,7 @@ import androidx.work.PeriodicWorkRequestBuilder
|
||||
import androidx.work.WorkManager
|
||||
import androidx.work.Worker
|
||||
import androidx.work.WorkerParameters
|
||||
import eu.kanade.tachiyomi.data.preference.DEVICE_CHARGING
|
||||
import eu.kanade.tachiyomi.data.preference.DEVICE_ONLY_ON_WIFI
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.preference.*
|
||||
import eu.kanade.tachiyomi.util.system.isConnectedToWifi
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
@ -21,8 +19,9 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
||||
|
||||
override fun doWork(): Result {
|
||||
val preferences = Injekt.get<PreferencesHelper>()
|
||||
if (requiresWifiConnection(preferences) && !context.isConnectedToWifi()) {
|
||||
Result.failure()
|
||||
val restrictions = preferences.libraryUpdateDeviceRestriction().get()
|
||||
if ((DEVICE_ONLY_ON_WIFI in restrictions) && !context.isConnectedToWifi()) {
|
||||
return Result.failure()
|
||||
}
|
||||
|
||||
return if (LibraryUpdateService.start(context)) {
|
||||
@ -41,8 +40,9 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
||||
if (interval > 0) {
|
||||
val restrictions = preferences.libraryUpdateDeviceRestriction().get()
|
||||
val constraints = Constraints.Builder()
|
||||
.setRequiredNetworkType(NetworkType.CONNECTED)
|
||||
.setRequiredNetworkType(if (DEVICE_NETWORK_NOT_METERED in restrictions) { NetworkType.UNMETERED } else { NetworkType.CONNECTED })
|
||||
.setRequiresCharging(DEVICE_CHARGING in restrictions)
|
||||
.setRequiresBatteryNotLow(DEVICE_BATTERY_NOT_LOW in restrictions)
|
||||
.build()
|
||||
|
||||
val request = PeriodicWorkRequestBuilder<LibraryUpdateJob>(
|
||||
@ -60,10 +60,5 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
||||
WorkManager.getInstance(context).cancelAllWorkByTag(TAG)
|
||||
}
|
||||
}
|
||||
|
||||
fun requiresWifiConnection(preferences: PreferencesHelper): Boolean {
|
||||
val restrictions = preferences.libraryUpdateDeviceRestriction().get()
|
||||
return DEVICE_ONLY_ON_WIFI in restrictions
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -90,6 +90,21 @@ class LibraryUpdateNotifier(private val context: Context) {
|
||||
)
|
||||
}
|
||||
|
||||
fun showQueueSizeWarningNotification() {
|
||||
val notificationBuilder = context.notificationBuilder(Notifications.CHANNEL_LIBRARY_PROGRESS) {
|
||||
setContentTitle(context.getString(R.string.label_warning))
|
||||
setStyle(NotificationCompat.BigTextStyle().bigText(context.getString(R.string.notification_size_warning)))
|
||||
setSmallIcon(R.drawable.ic_warning_white_24dp)
|
||||
setTimeoutAfter(Downloader.WARNING_NOTIF_TIMEOUT_MS)
|
||||
setContentIntent(NotificationHandler.openUrl(context, HELP_WARNING_URL))
|
||||
}
|
||||
|
||||
context.notificationManager.notify(
|
||||
Notifications.ID_LIBRARY_SIZE_WARNING,
|
||||
notificationBuilder.build(),
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows notification containing update entries that failed with action to open full log.
|
||||
*
|
||||
@ -128,8 +143,9 @@ class LibraryUpdateNotifier(private val context: Context) {
|
||||
Notifications.ID_LIBRARY_SKIPPED,
|
||||
context.notificationBuilder(Notifications.CHANNEL_LIBRARY_SKIPPED) {
|
||||
setContentTitle(context.resources.getString(R.string.notification_update_skipped, skipped))
|
||||
setContentText(context.getString(R.string.learn_more))
|
||||
setSmallIcon(R.drawable.ic_tachi)
|
||||
addAction(R.drawable.ic_help_24dp, context.getString(R.string.learn_more), NotificationHandler.openUrl(context, HELP_SKIPPED_URL))
|
||||
setContentIntent(NotificationHandler.openUrl(context, HELP_SKIPPED_URL))
|
||||
}
|
||||
.build(),
|
||||
)
|
||||
@ -325,6 +341,10 @@ class LibraryUpdateNotifier(private val context: Context) {
|
||||
}
|
||||
return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val HELP_WARNING_URL = "https://tachiyomi.org/help/faq/#why-does-the-app-warn-about-large-bulk-updates-and-downloads"
|
||||
}
|
||||
}
|
||||
|
||||
private const val NOTIF_MAX_CHAPTERS = 5
|
||||
|
@ -5,9 +5,7 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.IBinder
|
||||
import android.os.PowerManager
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.ContextCompat
|
||||
import eu.kanade.tachiyomi.BuildConfig
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
@ -43,7 +41,6 @@ import eu.kanade.tachiyomi.util.system.acquireWakeLock
|
||||
import eu.kanade.tachiyomi.util.system.createFileInCacheDir
|
||||
import eu.kanade.tachiyomi.util.system.isServiceRunning
|
||||
import eu.kanade.tachiyomi.util.system.logcat
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@ -177,6 +174,8 @@ class LibraryUpdateService(
|
||||
*/
|
||||
override fun onDestroy() {
|
||||
updateJob?.cancel()
|
||||
// Despite what Android Studio
|
||||
// states this can be null
|
||||
ioScope?.cancel()
|
||||
if (wakeLock.isHeld) {
|
||||
wakeLock.release()
|
||||
@ -236,8 +235,7 @@ class LibraryUpdateService(
|
||||
/**
|
||||
* Adds list of manga to be updated.
|
||||
*
|
||||
* @param category the ID of the category to update, or -1 if no category specified.
|
||||
* @param target the target to update.
|
||||
* @param categoryId the ID of the category to update, or -1 if no category specified.
|
||||
*/
|
||||
fun addMangaToQueue(categoryId: Int) {
|
||||
val libraryManga = db.getLibraryMangas().executeAsBlocking()
|
||||
@ -271,19 +269,17 @@ class LibraryUpdateService(
|
||||
.groupBy { it.source }
|
||||
.filterKeys { sourceManager.get(it) !is UnmeteredSource }
|
||||
.maxOfOrNull { it.value.size } ?: 0
|
||||
// TODO: show warnings in stable
|
||||
if (maxUpdatesFromSource > MANGA_PER_SOURCE_QUEUE_WARNING_THRESHOLD && BuildConfig.FLAVOR != "stable") {
|
||||
toast(R.string.notification_size_warning, Toast.LENGTH_LONG)
|
||||
if (maxUpdatesFromSource > MANGA_PER_SOURCE_QUEUE_WARNING_THRESHOLD) {
|
||||
notifier.showQueueSizeWarningNotification()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that updates the given list of manga. It's called in a background thread, so it's safe
|
||||
* Method that updates manga in [mangaToUpdate]. It's called in a background thread, so it's safe
|
||||
* to do heavy operations or network calls here.
|
||||
* For each manga it calls [updateManga] and updates the notification showing the current
|
||||
* progress.
|
||||
*
|
||||
* @param mangaToUpdate the list to update
|
||||
* @return an observable delivering the progress of each update.
|
||||
*/
|
||||
suspend fun updateChapterList() {
|
||||
@ -309,35 +305,38 @@ class LibraryUpdateService(
|
||||
return@async
|
||||
}
|
||||
|
||||
// Don't continue to update if manga not in library
|
||||
db.getManga(manga.id!!).executeAsBlocking() ?: return@forEach
|
||||
|
||||
withUpdateNotification(
|
||||
currentlyUpdatingManga,
|
||||
progressCount,
|
||||
manga,
|
||||
) { manga ->
|
||||
) { mangaWithNotif ->
|
||||
try {
|
||||
when {
|
||||
MANGA_NON_COMPLETED in restrictions && manga.status == SManga.COMPLETED -> {
|
||||
skippedUpdates.add(manga to getString(R.string.skipped_reason_completed))
|
||||
}
|
||||
MANGA_HAS_UNREAD in restrictions && manga.unreadCount != 0 -> {
|
||||
skippedUpdates.add(manga to getString(R.string.skipped_reason_not_caught_up))
|
||||
}
|
||||
MANGA_NON_READ in restrictions && manga.totalChapters > 0 && !manga.hasStarted -> {
|
||||
skippedUpdates.add(manga to getString(R.string.skipped_reason_not_started))
|
||||
}
|
||||
MANGA_NON_COMPLETED in restrictions && mangaWithNotif.status == SManga.COMPLETED ->
|
||||
skippedUpdates.add(mangaWithNotif to getString(R.string.skipped_reason_completed))
|
||||
|
||||
MANGA_HAS_UNREAD in restrictions && mangaWithNotif.unreadCount != 0 ->
|
||||
skippedUpdates.add(mangaWithNotif to getString(R.string.skipped_reason_not_caught_up))
|
||||
|
||||
MANGA_NON_READ in restrictions && mangaWithNotif.totalChapters > 0 && !mangaWithNotif.hasStarted ->
|
||||
skippedUpdates.add(mangaWithNotif to getString(R.string.skipped_reason_not_started))
|
||||
|
||||
else -> {
|
||||
// Convert to the manga that contains new chapters
|
||||
val (newChapters, _) = updateManga(manga)
|
||||
val (newChapters, _) = updateManga(mangaWithNotif)
|
||||
|
||||
if (newChapters.isNotEmpty()) {
|
||||
if (manga.shouldDownloadNewChapters(db, preferences)) {
|
||||
downloadChapters(manga, newChapters)
|
||||
if (mangaWithNotif.shouldDownloadNewChapters(db, preferences)) {
|
||||
downloadChapters(mangaWithNotif, newChapters)
|
||||
hasDownloads.set(true)
|
||||
}
|
||||
|
||||
// Convert to the manga that contains new chapters
|
||||
newUpdates.add(
|
||||
manga to newChapters.sortedByDescending { ch -> ch.source_order }
|
||||
mangaWithNotif to newChapters.sortedByDescending { ch -> ch.source_order }
|
||||
.toTypedArray(),
|
||||
)
|
||||
}
|
||||
@ -356,11 +355,11 @@ class LibraryUpdateService(
|
||||
e.message
|
||||
}
|
||||
}
|
||||
failedUpdates.add(manga to errorMessage)
|
||||
failedUpdates.add(mangaWithNotif to errorMessage)
|
||||
}
|
||||
|
||||
if (preferences.autoUpdateTrackers()) {
|
||||
updateTrackings(manga, loggedServices)
|
||||
updateTrackings(mangaWithNotif, loggedServices)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -408,6 +407,7 @@ class LibraryUpdateService(
|
||||
suspend fun updateManga(manga: Manga): Pair<List<Chapter>, List<Chapter>> {
|
||||
val source = sourceManager.getOrStub(manga.source)
|
||||
|
||||
var networkSManga: SManga? = null
|
||||
// Update manga details metadata
|
||||
if (preferences.autoUpdateMetadata()) {
|
||||
val updatedManga = source.getMangaDetails(manga.toMangaInfo())
|
||||
@ -419,14 +419,26 @@ class LibraryUpdateService(
|
||||
sManga.thumbnail_url = manga.thumbnail_url
|
||||
}
|
||||
|
||||
manga.copyFrom(sManga)
|
||||
db.insertManga(manga).executeAsBlocking()
|
||||
networkSManga = sManga
|
||||
}
|
||||
|
||||
val chapters = source.getChapterList(manga.toMangaInfo())
|
||||
.map { it.toSChapter() }
|
||||
|
||||
return syncChaptersWithSource(db, chapters, manga, source)
|
||||
// Get manga from database to account for if it was removed
|
||||
// from library or database
|
||||
val dbManga = db.getManga(manga.id!!).executeAsBlocking()
|
||||
?: return Pair(emptyList(), emptyList())
|
||||
|
||||
// Copy into [dbManga] to retain favourite value
|
||||
networkSManga?.let {
|
||||
dbManga.copyFrom(it)
|
||||
db.insertManga(dbManga).executeAsBlocking()
|
||||
}
|
||||
|
||||
// [dbmanga] was used so that manga data doesn't get overwritten
|
||||
// incase manga gets new chapter
|
||||
return syncChaptersWithSource(db, chapters, dbManga, source)
|
||||
}
|
||||
|
||||
private suspend fun updateCovers() {
|
||||
@ -449,16 +461,16 @@ class LibraryUpdateService(
|
||||
currentlyUpdatingManga,
|
||||
progressCount,
|
||||
manga,
|
||||
) { manga ->
|
||||
sourceManager.get(manga.source)?.let { source ->
|
||||
) { mangaWithNotif ->
|
||||
sourceManager.get(mangaWithNotif.source)?.let { source ->
|
||||
try {
|
||||
val networkManga =
|
||||
source.getMangaDetails(manga.toMangaInfo())
|
||||
source.getMangaDetails(mangaWithNotif.toMangaInfo())
|
||||
val sManga = networkManga.toSManga()
|
||||
manga.prepUpdateCover(coverCache, sManga, true)
|
||||
mangaWithNotif.prepUpdateCover(coverCache, sManga, true)
|
||||
sManga.thumbnail_url?.let {
|
||||
manga.thumbnail_url = it
|
||||
db.insertManga(manga).executeAsBlocking()
|
||||
mangaWithNotif.thumbnail_url = it
|
||||
db.insertManga(mangaWithNotif).executeAsBlocking()
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
// Ignore errors and continue
|
||||
|
@ -26,10 +26,11 @@ object Notifications {
|
||||
private const val GROUP_LIBRARY = "group_library"
|
||||
const val CHANNEL_LIBRARY_PROGRESS = "library_progress_channel"
|
||||
const val ID_LIBRARY_PROGRESS = -101
|
||||
const val ID_LIBRARY_SIZE_WARNING = -103
|
||||
const val CHANNEL_LIBRARY_ERROR = "library_errors_channel"
|
||||
const val ID_LIBRARY_ERROR = -102
|
||||
const val CHANNEL_LIBRARY_SKIPPED = "library_skipped_channel"
|
||||
const val ID_LIBRARY_SKIPPED = -103
|
||||
const val ID_LIBRARY_SKIPPED = -104
|
||||
|
||||
/**
|
||||
* Notification channel and ids used by the downloader.
|
||||
|
@ -3,7 +3,9 @@ package eu.kanade.tachiyomi.data.preference
|
||||
import eu.kanade.tachiyomi.R
|
||||
|
||||
const val DEVICE_ONLY_ON_WIFI = "wifi"
|
||||
const val DEVICE_NETWORK_NOT_METERED = "network_not_metered"
|
||||
const val DEVICE_CHARGING = "ac"
|
||||
const val DEVICE_BATTERY_NOT_LOW = "battery_not_low"
|
||||
|
||||
const val MANGA_NON_COMPLETED = "manga_ongoing"
|
||||
const val MANGA_HAS_UNREAD = "manga_fully_read"
|
||||
@ -28,13 +30,14 @@ object PreferenceValues {
|
||||
enum class AppTheme(val titleResId: Int?) {
|
||||
DEFAULT(R.string.label_default),
|
||||
MONET(R.string.theme_monet),
|
||||
GREEN_APPLE(R.string.theme_greenapple),
|
||||
LAVENDER(R.string.theme_lavender),
|
||||
MIDNIGHT_DUSK(R.string.theme_midnightdusk),
|
||||
STRAWBERRY_DAIQUIRI(R.string.theme_strawberrydaiquiri),
|
||||
YOTSUBA(R.string.theme_yotsuba),
|
||||
TAKO(R.string.theme_tako),
|
||||
GREEN_APPLE(R.string.theme_greenapple),
|
||||
TEALTURQUOISE(R.string.theme_tealturquoise),
|
||||
YINYANG(R.string.theme_yinyang),
|
||||
YOTSUBA(R.string.theme_yotsuba),
|
||||
|
||||
// Deprecated
|
||||
DARK_BLUE(null),
|
||||
|
@ -18,6 +18,7 @@ import eu.kanade.tachiyomi.ui.library.setting.SortModeSetting
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
|
||||
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
||||
import eu.kanade.tachiyomi.util.system.isDevFlavor
|
||||
import eu.kanade.tachiyomi.widget.ExtendedNavigationView
|
||||
import java.io.File
|
||||
import java.text.DateFormat
|
||||
@ -203,11 +204,11 @@ class PreferencesHelper(val context: Context) {
|
||||
|
||||
fun downloadOnlyOverWifi() = prefs.getBoolean(Keys.downloadOnlyOverWifi, true)
|
||||
|
||||
fun saveChaptersAsCBZ() = flowPrefs.getBoolean("save_chapter_as_cbz", false)
|
||||
fun saveChaptersAsCBZ() = flowPrefs.getBoolean("save_chapter_as_cbz", true)
|
||||
|
||||
fun folderPerManga() = prefs.getBoolean(Keys.folderPerManga, false)
|
||||
|
||||
fun numberOfBackups() = flowPrefs.getInt("backup_slots", 1)
|
||||
fun numberOfBackups() = flowPrefs.getInt("backup_slots", 2)
|
||||
|
||||
fun backupInterval() = flowPrefs.getInt("backup_interval", 0)
|
||||
|
||||
@ -277,10 +278,10 @@ class PreferencesHelper(val context: Context) {
|
||||
|
||||
fun pinnedSources() = flowPrefs.getStringSet("pinned_catalogues", emptySet())
|
||||
|
||||
fun downloadNew() = flowPrefs.getBoolean("download_new", false)
|
||||
fun downloadNewChapter() = flowPrefs.getBoolean("download_new", false)
|
||||
|
||||
fun downloadNewCategories() = flowPrefs.getStringSet("download_new_categories", emptySet())
|
||||
fun downloadNewCategoriesExclude() = flowPrefs.getStringSet("download_new_categories_exclude", emptySet())
|
||||
fun downloadNewChapterCategories() = flowPrefs.getStringSet("download_new_categories", emptySet())
|
||||
fun downloadNewChapterCategoriesExclude() = flowPrefs.getStringSet("download_new_categories_exclude", emptySet())
|
||||
|
||||
fun defaultCategory() = prefs.getInt(Keys.defaultCategory, -1)
|
||||
|
||||
@ -319,7 +320,7 @@ class PreferencesHelper(val context: Context) {
|
||||
if (DeviceUtil.isMiui) Values.ExtensionInstaller.LEGACY else Values.ExtensionInstaller.PACKAGEINSTALLER,
|
||||
)
|
||||
|
||||
fun verboseLogging() = prefs.getBoolean(Keys.verboseLogging, false)
|
||||
fun verboseLogging() = prefs.getBoolean(Keys.verboseLogging, isDevFlavor)
|
||||
|
||||
fun autoClearChapterCache() = prefs.getBoolean(Keys.autoClearChapterCache, false)
|
||||
|
||||
|
@ -13,6 +13,8 @@ import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||
import eu.kanade.tachiyomi.util.storage.cacheImageDir
|
||||
import eu.kanade.tachiyomi.util.storage.getUriCompat
|
||||
import eu.kanade.tachiyomi.util.system.ImageUtil
|
||||
import eu.kanade.tachiyomi.util.system.logcat
|
||||
import logcat.LogPriority
|
||||
import okio.IOException
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.ByteArrayOutputStream
|
||||
@ -30,11 +32,7 @@ class ImageSaver(
|
||||
val type = ImageUtil.findImageType(data) ?: throw Exception("Not an image")
|
||||
val filename = DiskUtil.buildValidFilename("${image.name}.${type.extension}")
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
||||
return save(data(), image.location.directory(context), filename)
|
||||
}
|
||||
|
||||
if (image.location !is Location.Pictures) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || image.location !is Location.Pictures) {
|
||||
return save(data(), image.location.directory(context), filename)
|
||||
}
|
||||
|
||||
@ -54,13 +52,18 @@ class ImageSaver(
|
||||
val picture = context.contentResolver.insert(
|
||||
pictureDir,
|
||||
contentValues,
|
||||
) ?: throw IOException("Couldn't create file")
|
||||
) ?: throw IOException(context.getString(R.string.error_saving_picture))
|
||||
|
||||
data().use { input ->
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
context.contentResolver.openOutputStream(picture, "w").use { output ->
|
||||
input.copyTo(output!!)
|
||||
try {
|
||||
data().use { input ->
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
context.contentResolver.openOutputStream(picture, "w").use { output ->
|
||||
input.copyTo(output!!)
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logcat(LogPriority.ERROR, e)
|
||||
throw IOException(context.getString(R.string.error_saving_picture))
|
||||
}
|
||||
|
||||
DiskUtil.scanMedia(context, picture)
|
||||
|
@ -8,6 +8,7 @@ import eu.kanade.tachiyomi.network.NetworkHelper
|
||||
import eu.kanade.tachiyomi.network.await
|
||||
import eu.kanade.tachiyomi.network.parseAs
|
||||
import eu.kanade.tachiyomi.util.lang.withIOContext
|
||||
import eu.kanade.tachiyomi.util.system.getInstallerPackageName
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.util.Date
|
||||
import java.util.concurrent.TimeUnit
|
||||
@ -33,14 +34,19 @@ class AppUpdateChecker {
|
||||
|
||||
// Check if latest version is different from current version
|
||||
if (isNewVersion(it.version)) {
|
||||
AppUpdateResult.NewUpdate(it)
|
||||
if (context.getInstallerPackageName() == "org.fdroid.fdroid") {
|
||||
AppUpdateResult.NewUpdateFdroidInstallation
|
||||
} else {
|
||||
AppUpdateResult.NewUpdate(it)
|
||||
}
|
||||
} else {
|
||||
AppUpdateResult.NoNewUpdate
|
||||
}
|
||||
}
|
||||
|
||||
if (result is AppUpdateResult.NewUpdate) {
|
||||
AppUpdateNotifier(context).promptUpdate(result.release)
|
||||
when (result) {
|
||||
is AppUpdateResult.NewUpdate -> AppUpdateNotifier(context).promptUpdate(result.release)
|
||||
is AppUpdateResult.NewUpdateFdroidInstallation -> AppUpdateNotifier(context).promptFdroidUpdate()
|
||||
}
|
||||
|
||||
result
|
||||
@ -50,6 +56,7 @@ class AppUpdateChecker {
|
||||
private fun isNewVersion(versionTag: String): Boolean {
|
||||
// Removes prefixes like "r" or "v"
|
||||
val newVersion = versionTag.replace("[^\\d.]".toRegex(), "")
|
||||
val oldVersion = BuildConfig.VERSION_NAME.replace("[^\\d.]".toRegex(), "")
|
||||
|
||||
return if (BuildConfig.PREVIEW) {
|
||||
// Preview builds: based on releases in "tachiyomiorg/tachiyomi-preview" repo
|
||||
@ -58,7 +65,15 @@ class AppUpdateChecker {
|
||||
} else {
|
||||
// Release builds: based on releases in "tachiyomiorg/tachiyomi" repo
|
||||
// tagged as something like "v0.1.2"
|
||||
newVersion != BuildConfig.VERSION_NAME
|
||||
val newSemVer = newVersion.split(".").map { it.toInt() }
|
||||
val oldSemVer = oldVersion.split(".").map { it.toInt() }
|
||||
|
||||
oldSemVer.mapIndexed { index, i ->
|
||||
if (newSemVer[index] > i) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -58,6 +58,22 @@ internal class AppUpdateNotifier(private val context: Context) {
|
||||
notificationBuilder.show()
|
||||
}
|
||||
|
||||
/**
|
||||
* Some people are still installing the app from F-Droid, so we avoid prompting GitHub-based
|
||||
* updates.
|
||||
*
|
||||
* We can prompt them to migrate to the GitHub version though.
|
||||
*/
|
||||
fun promptFdroidUpdate() {
|
||||
with(notificationBuilder) {
|
||||
setContentTitle(context.getString(R.string.update_check_notification_update_available))
|
||||
setContentText(context.getString(R.string.update_check_fdroid_migration_info))
|
||||
setSmallIcon(R.drawable.ic_tachi)
|
||||
setContentIntent(NotificationHandler.openUrl(context, "https://tachiyomi.org/help/faq/#how-do-i-migrate-from-the-f-droid-version"))
|
||||
}
|
||||
notificationBuilder.show()
|
||||
}
|
||||
|
||||
/**
|
||||
* Call when apk download starts.
|
||||
*
|
||||
|
@ -2,5 +2,6 @@ package eu.kanade.tachiyomi.data.updater
|
||||
|
||||
sealed class AppUpdateResult {
|
||||
class NewUpdate(val release: GithubRelease) : AppUpdateResult()
|
||||
object NewUpdateFdroidInstallation : AppUpdateResult()
|
||||
object NoNewUpdate : AppUpdateResult()
|
||||
}
|
||||
|
@ -244,11 +244,6 @@ class ExtensionManager(
|
||||
installer.updateInstallStep(downloadId, InstallStep.Installing)
|
||||
}
|
||||
|
||||
fun setInstallationResult(downloadId: Long, result: Boolean) {
|
||||
val step = if (result) InstallStep.Installed else InstallStep.Error
|
||||
installer.updateInstallStep(downloadId, step)
|
||||
}
|
||||
|
||||
fun updateInstallStep(downloadId: Long, step: InstallStep) {
|
||||
installer.updateInstallStep(downloadId, step)
|
||||
}
|
||||
|
@ -11,7 +11,9 @@ import eu.kanade.tachiyomi.network.NetworkHelper
|
||||
import eu.kanade.tachiyomi.network.await
|
||||
import eu.kanade.tachiyomi.network.parseAs
|
||||
import eu.kanade.tachiyomi.util.lang.withIOContext
|
||||
import eu.kanade.tachiyomi.util.system.logcat
|
||||
import kotlinx.serialization.Serializable
|
||||
import logcat.LogPriority
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.util.Date
|
||||
import java.util.concurrent.TimeUnit
|
||||
@ -21,11 +23,27 @@ internal class ExtensionGithubApi {
|
||||
private val networkService: NetworkHelper by injectLazy()
|
||||
private val preferences: PreferencesHelper by injectLazy()
|
||||
|
||||
private var requiresFallbackSource = false
|
||||
|
||||
suspend fun findExtensions(): List<Extension.Available> {
|
||||
return withIOContext {
|
||||
val extensions = networkService.client
|
||||
.newCall(GET("${REPO_URL_PREFIX}index.min.json"))
|
||||
.await()
|
||||
val githubResponse = if (requiresFallbackSource) null else try {
|
||||
networkService.client
|
||||
.newCall(GET("${REPO_URL_PREFIX}index.min.json"))
|
||||
.await()
|
||||
} catch (e: Throwable) {
|
||||
logcat(LogPriority.ERROR, e) { "Failed to get extensions from GitHub" }
|
||||
requiresFallbackSource = true
|
||||
null
|
||||
}
|
||||
|
||||
val response = githubResponse ?: run {
|
||||
networkService.client
|
||||
.newCall(GET("${FALLBACK_REPO_URL_PREFIX}index.min.json"))
|
||||
.await()
|
||||
}
|
||||
|
||||
val extensions = response
|
||||
.parseAs<List<ExtensionJsonObject>>()
|
||||
.toExtensions()
|
||||
|
||||
@ -85,7 +103,7 @@ internal class ExtensionGithubApi {
|
||||
hasChangelog = it.hasChangelog == 1,
|
||||
sources = it.sources?.toExtensionSources() ?: emptyList(),
|
||||
apkName = it.apk,
|
||||
iconUrl = "${REPO_URL_PREFIX}icon/${it.apk.replace(".apk", ".png")}",
|
||||
iconUrl = "${getUrlPrefix()}icon/${it.apk.replace(".apk", ".png")}",
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -101,11 +119,20 @@ internal class ExtensionGithubApi {
|
||||
}
|
||||
|
||||
fun getApkUrl(extension: Extension.Available): String {
|
||||
return "${REPO_URL_PREFIX}apk/${extension.apkName}"
|
||||
return "${getUrlPrefix()}apk/${extension.apkName}"
|
||||
}
|
||||
|
||||
private fun getUrlPrefix(): String {
|
||||
return if (requiresFallbackSource) {
|
||||
FALLBACK_REPO_URL_PREFIX
|
||||
} else {
|
||||
REPO_URL_PREFIX
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private const val REPO_URL_PREFIX = "https://raw.githubusercontent.com/tachiyomiorg/tachiyomi-extensions/repo/"
|
||||
private const val FALLBACK_REPO_URL_PREFIX = "https://gcore.jsdelivr.net/gh/tachiyomiorg/tachiyomi-extensions@repo/"
|
||||
|
||||
@Serializable
|
||||
private data class ExtensionJsonObject(
|
||||
|
@ -52,9 +52,9 @@ class ShizukuInstaller(private val service: Service) : Installer(service) {
|
||||
val size = service.getUriSize(entry.uri) ?: throw IllegalStateException()
|
||||
service.contentResolver.openInputStream(entry.uri)!!.use {
|
||||
val createCommand = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
"pm install-create --user current -i ${service.packageName} -S $size"
|
||||
"pm install-create --user current -r -i ${service.packageName} -S $size"
|
||||
} else {
|
||||
"pm install-create -i ${service.packageName} -S $size"
|
||||
"pm install-create -r -i ${service.packageName} -S $size"
|
||||
}
|
||||
val createResult = exec(createCommand)
|
||||
sessionId = SESSION_ID_REGEX.find(createResult.out)?.value
|
||||
|
@ -29,9 +29,9 @@ class AndroidCookieJar : CookieJar {
|
||||
}
|
||||
}
|
||||
|
||||
fun remove(url: HttpUrl, cookieNames: List<String>? = null, maxAge: Int = -1) {
|
||||
fun remove(url: HttpUrl, cookieNames: List<String>? = null, maxAge: Int = -1): Int {
|
||||
val urlString = url.toString()
|
||||
val cookies = manager.getCookie(urlString) ?: return
|
||||
val cookies = manager.getCookie(urlString) ?: return 0
|
||||
|
||||
fun List<String>.filterNames(): List<String> {
|
||||
return if (cookieNames != null) {
|
||||
@ -41,10 +41,11 @@ class AndroidCookieJar : CookieJar {
|
||||
}
|
||||
}
|
||||
|
||||
cookies.split(";")
|
||||
return cookies.split(";")
|
||||
.map { it.substringBefore("=") }
|
||||
.filterNames()
|
||||
.onEach { manager.setCookie(urlString, "$it=;Max-Age=$maxAge") }
|
||||
.count()
|
||||
}
|
||||
|
||||
fun removeAll() {
|
||||
|
@ -13,6 +13,10 @@ const val PREF_DOH_CLOUDFLARE = 1
|
||||
const val PREF_DOH_GOOGLE = 2
|
||||
const val PREF_DOH_ADGUARD = 3
|
||||
const val PREF_DOH_QUAD9 = 4
|
||||
const val PREF_DOH_ALIDNS = 5
|
||||
const val PREF_DOH_DNSPOD = 6
|
||||
const val PREF_DOH_360 = 7
|
||||
const val PREF_DOH_QUAD101 = 8
|
||||
|
||||
fun OkHttpClient.Builder.dohCloudflare() = dns(
|
||||
DnsOverHttps.Builder().client(build())
|
||||
@ -68,3 +72,51 @@ fun OkHttpClient.Builder.dohQuad9() = dns(
|
||||
)
|
||||
.build(),
|
||||
)
|
||||
|
||||
fun OkHttpClient.Builder.dohAliDNS() = dns(
|
||||
DnsOverHttps.Builder().client(build())
|
||||
.url("https://dns.alidns.com/dns-query".toHttpUrl())
|
||||
.bootstrapDnsHosts(
|
||||
InetAddress.getByName("223.5.5.5"),
|
||||
InetAddress.getByName("223.6.6.6"),
|
||||
InetAddress.getByName("2400:3200::1"),
|
||||
InetAddress.getByName("2400:3200:baba::1"),
|
||||
)
|
||||
.build(),
|
||||
)
|
||||
|
||||
fun OkHttpClient.Builder.dohDNSPod() = dns(
|
||||
DnsOverHttps.Builder().client(build())
|
||||
.url("https://doh.pub/dns-query".toHttpUrl())
|
||||
.bootstrapDnsHosts(
|
||||
InetAddress.getByName("1.12.12.12"),
|
||||
InetAddress.getByName("120.53.53.53"),
|
||||
)
|
||||
.build(),
|
||||
)
|
||||
|
||||
fun OkHttpClient.Builder.doh360() = dns(
|
||||
DnsOverHttps.Builder().client(build())
|
||||
.url("https://doh.360.cn/dns-query".toHttpUrl())
|
||||
.bootstrapDnsHosts(
|
||||
InetAddress.getByName("101.226.4.6"),
|
||||
InetAddress.getByName("218.30.118.6"),
|
||||
InetAddress.getByName("123.125.81.6"),
|
||||
InetAddress.getByName("140.207.198.6"),
|
||||
InetAddress.getByName("180.163.249.75"),
|
||||
InetAddress.getByName("101.199.113.208"),
|
||||
InetAddress.getByName("36.99.170.86"),
|
||||
)
|
||||
.build(),
|
||||
)
|
||||
|
||||
fun OkHttpClient.Builder.dohQuad101() = dns(
|
||||
DnsOverHttps.Builder().client(build())
|
||||
.url("https://dns.twnic.tw/dns-query".toHttpUrl())
|
||||
.bootstrapDnsHosts(
|
||||
InetAddress.getByName("101.101.101.101"),
|
||||
InetAddress.getByName("2001:de4::101"),
|
||||
InetAddress.getByName("2001:de4::102"),
|
||||
)
|
||||
.build(),
|
||||
)
|
||||
|
@ -27,7 +27,8 @@ class NetworkHelper(context: Context) {
|
||||
.cookieJar(cookieManager)
|
||||
.connectTimeout(30, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
.fastFallback(true)
|
||||
.callTimeout(2, TimeUnit.MINUTES)
|
||||
// .fastFallback(true) // TODO: re-enable when OkHttp 5 is stabler
|
||||
.addInterceptor(UserAgentInterceptor())
|
||||
|
||||
if (preferences.verboseLogging()) {
|
||||
@ -42,6 +43,10 @@ class NetworkHelper(context: Context) {
|
||||
PREF_DOH_GOOGLE -> builder.dohGoogle()
|
||||
PREF_DOH_ADGUARD -> builder.dohAdGuard()
|
||||
PREF_DOH_QUAD9 -> builder.dohQuad9()
|
||||
PREF_DOH_ALIDNS -> builder.dohAliDNS()
|
||||
PREF_DOH_DNSPOD -> builder.dohDNSPod()
|
||||
PREF_DOH_360 -> builder.doh360()
|
||||
PREF_DOH_QUAD101 -> builder.dohQuad101()
|
||||
}
|
||||
|
||||
return builder
|
||||
|
@ -4,6 +4,7 @@ import android.os.SystemClock
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Response
|
||||
import java.io.IOException
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/**
|
||||
@ -36,6 +37,11 @@ private class RateLimitInterceptor(
|
||||
private val rateLimitMillis = unit.toMillis(period)
|
||||
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
// Ignore canceled calls, otherwise they would jam the queue
|
||||
if (chain.call().isCanceled()) {
|
||||
throw IOException()
|
||||
}
|
||||
|
||||
synchronized(requestQueue) {
|
||||
val now = SystemClock.elapsedRealtime()
|
||||
val waitTime = if (requestQueue.size < permits) {
|
||||
@ -51,6 +57,11 @@ private class RateLimitInterceptor(
|
||||
}
|
||||
}
|
||||
|
||||
// Final check
|
||||
if (chain.call().isCanceled()) {
|
||||
throw IOException()
|
||||
}
|
||||
|
||||
if (requestQueue.size == permits) {
|
||||
requestQueue.removeAt(0)
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import okhttp3.HttpUrl
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Response
|
||||
import java.io.IOException
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/**
|
||||
@ -41,9 +42,13 @@ class SpecificHostRateLimitInterceptor(
|
||||
private val host = httpUrl.host
|
||||
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
if (chain.request().url.host != host) {
|
||||
// Ignore canceled calls, otherwise they would jam the queue
|
||||
if (chain.call().isCanceled()) {
|
||||
throw IOException()
|
||||
} else if (chain.request().url.host != host) {
|
||||
return chain.proceed(chain.request())
|
||||
}
|
||||
|
||||
synchronized(requestQueue) {
|
||||
val now = SystemClock.elapsedRealtime()
|
||||
val waitTime = if (requestQueue.size < permits) {
|
||||
@ -59,6 +64,11 @@ class SpecificHostRateLimitInterceptor(
|
||||
}
|
||||
}
|
||||
|
||||
// Final check
|
||||
if (chain.call().isCanceled()) {
|
||||
throw IOException()
|
||||
}
|
||||
|
||||
if (requestQueue.size == permits) {
|
||||
requestQueue.removeAt(0)
|
||||
}
|
||||
|
@ -2,7 +2,9 @@ package eu.kanade.tachiyomi.source
|
||||
|
||||
import android.content.Context
|
||||
import com.github.junrar.Archive
|
||||
import com.hippo.unifile.UniFile
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
import eu.kanade.tachiyomi.source.model.Filter
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||
@ -17,7 +19,6 @@ import eu.kanade.tachiyomi.util.lang.compareToCaseInsensitiveNaturalOrder
|
||||
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||
import eu.kanade.tachiyomi.util.storage.EpubFile
|
||||
import eu.kanade.tachiyomi.util.system.ImageUtil
|
||||
import eu.kanade.tachiyomi.util.system.logcat
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
@ -26,10 +27,11 @@ import kotlinx.serialization.json.decodeFromStream
|
||||
import kotlinx.serialization.json.intOrNull
|
||||
import kotlinx.serialization.json.jsonArray
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
import logcat.LogPriority
|
||||
import rx.Observable
|
||||
import tachiyomi.source.model.ChapterInfo
|
||||
import tachiyomi.source.model.MangaInfo
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
@ -37,130 +39,104 @@ import java.io.InputStream
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.zip.ZipFile
|
||||
|
||||
class LocalSource(private val context: Context) : CatalogueSource, UnmeteredSource {
|
||||
|
||||
companion object {
|
||||
const val ID = 0L
|
||||
const val HELP_URL = "https://tachiyomi.org/help/guides/local-manga/"
|
||||
|
||||
private const val COVER_NAME = "cover.jpg"
|
||||
private val LATEST_THRESHOLD = TimeUnit.MILLISECONDS.convert(7, TimeUnit.DAYS)
|
||||
|
||||
fun updateCover(context: Context, manga: SManga, input: InputStream): File? {
|
||||
val dir = getBaseDirectories(context).firstOrNull()
|
||||
if (dir == null) {
|
||||
input.close()
|
||||
return null
|
||||
}
|
||||
var cover = getCoverFile(File("${dir.absolutePath}/${manga.url}"))
|
||||
if (cover == null) {
|
||||
cover = File("${dir.absolutePath}/${manga.url}", COVER_NAME)
|
||||
}
|
||||
// It might not exist if using the external SD card
|
||||
cover.parentFile?.mkdirs()
|
||||
input.use {
|
||||
cover.outputStream().use {
|
||||
input.copyTo(it)
|
||||
}
|
||||
}
|
||||
manga.thumbnail_url = cover.absolutePath
|
||||
return cover
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns valid cover file inside [parent] directory.
|
||||
*/
|
||||
private fun getCoverFile(parent: File): File? {
|
||||
return parent.listFiles()?.find { it.nameWithoutExtension == "cover" }?.takeIf {
|
||||
it.isFile && ImageUtil.isImage(it.name) { it.inputStream() }
|
||||
}
|
||||
}
|
||||
|
||||
private fun getBaseDirectories(context: Context): List<File> {
|
||||
val c = context.getString(R.string.app_name) + File.separator + "local"
|
||||
return DiskUtil.getExternalStorages(context).map { File(it.absolutePath, c) }
|
||||
}
|
||||
}
|
||||
class LocalSource(
|
||||
private val context: Context,
|
||||
private val coverCache: CoverCache = Injekt.get(),
|
||||
) : CatalogueSource, UnmeteredSource {
|
||||
|
||||
private val json: Json by injectLazy()
|
||||
|
||||
override val id = ID
|
||||
override val name = context.getString(R.string.local_source)
|
||||
override val lang = "other"
|
||||
override val supportsLatest = true
|
||||
override val name: String = context.getString(R.string.local_source)
|
||||
|
||||
override val id: Long = ID
|
||||
|
||||
override val lang: String = "other"
|
||||
|
||||
override fun toString() = name
|
||||
|
||||
override val supportsLatest: Boolean = true
|
||||
|
||||
// Browse related
|
||||
override fun fetchPopularManga(page: Int) = fetchSearchManga(page, "", POPULAR_FILTERS)
|
||||
|
||||
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
|
||||
val baseDirs = getBaseDirectories(context)
|
||||
override fun fetchLatestUpdates(page: Int) = fetchSearchManga(page, "", LATEST_FILTERS)
|
||||
|
||||
val time = if (filters === LATEST_FILTERS) System.currentTimeMillis() - LATEST_THRESHOLD else 0L
|
||||
var mangaDirs = baseDirs
|
||||
.asSequence()
|
||||
.mapNotNull { it.listFiles()?.toList() }
|
||||
.flatten()
|
||||
.filter { it.isDirectory }
|
||||
.filterNot { it.name.startsWith('.') }
|
||||
.filter { if (time == 0L) it.name.contains(query, ignoreCase = true) else it.lastModified() >= time }
|
||||
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
|
||||
val baseDirsFiles = getBaseDirectoriesFiles(context)
|
||||
|
||||
var mangaDirs = baseDirsFiles
|
||||
// Filter out files that are hidden and is not a folder
|
||||
.filter { it.isDirectory && !it.name.startsWith('.') }
|
||||
.distinctBy { it.name }
|
||||
|
||||
val state = ((if (filters.isEmpty()) POPULAR_FILTERS else filters)[0] as OrderBy).state
|
||||
when (state?.index) {
|
||||
0 -> {
|
||||
mangaDirs = if (state.ascending) {
|
||||
mangaDirs.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER, { it.name }))
|
||||
} else {
|
||||
mangaDirs.sortedWith(compareByDescending(String.CASE_INSENSITIVE_ORDER, { it.name }))
|
||||
}
|
||||
}
|
||||
1 -> {
|
||||
mangaDirs = if (state.ascending) {
|
||||
mangaDirs.sortedBy(File::lastModified)
|
||||
} else {
|
||||
mangaDirs.sortedByDescending(File::lastModified)
|
||||
}
|
||||
val lastModifiedLimit = if (filters === LATEST_FILTERS) System.currentTimeMillis() - LATEST_THRESHOLD else 0L
|
||||
// Filter by query or last modified
|
||||
mangaDirs = mangaDirs.filter {
|
||||
if (lastModifiedLimit == 0L) {
|
||||
it.name.contains(query, ignoreCase = true)
|
||||
} else {
|
||||
it.lastModified() >= lastModifiedLimit
|
||||
}
|
||||
}
|
||||
|
||||
filters.forEach { filter ->
|
||||
when (filter) {
|
||||
is OrderBy -> {
|
||||
when (filter.state!!.index) {
|
||||
0 -> {
|
||||
mangaDirs = if (filter.state!!.ascending) {
|
||||
mangaDirs.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER) { it.name })
|
||||
} else {
|
||||
mangaDirs.sortedWith(compareByDescending(String.CASE_INSENSITIVE_ORDER) { it.name })
|
||||
}
|
||||
}
|
||||
1 -> {
|
||||
mangaDirs = if (filter.state!!.ascending) {
|
||||
mangaDirs.sortedBy(File::lastModified)
|
||||
} else {
|
||||
mangaDirs.sortedByDescending(File::lastModified)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else -> { /* Do nothing */ }
|
||||
}
|
||||
}
|
||||
|
||||
// Transform mangaDirs to list of SManga
|
||||
val mangas = mangaDirs.map { mangaDir ->
|
||||
SManga.create().apply {
|
||||
title = mangaDir.name
|
||||
url = mangaDir.name
|
||||
|
||||
// Try to find the cover
|
||||
for (dir in baseDirs) {
|
||||
val cover = getCoverFile(File("${dir.absolutePath}/$url"))
|
||||
if (cover != null && cover.exists()) {
|
||||
thumbnail_url = cover.absolutePath
|
||||
break
|
||||
}
|
||||
val cover = getCoverFile(mangaDir.name, baseDirsFiles)
|
||||
if (cover != null && cover.exists()) {
|
||||
thumbnail_url = cover.absolutePath
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val sManga = this
|
||||
val mangaInfo = this.toMangaInfo()
|
||||
runBlocking {
|
||||
val chapters = getChapterList(mangaInfo)
|
||||
if (chapters.isNotEmpty()) {
|
||||
val chapter = chapters.last().toSChapter()
|
||||
val format = getFormat(chapter)
|
||||
if (format is Format.Epub) {
|
||||
EpubFile(format.file).use { epub ->
|
||||
epub.fillMangaMetadata(sManga)
|
||||
}
|
||||
}
|
||||
// Fetch chapters of all the manga
|
||||
mangas.forEach { manga ->
|
||||
val mangaInfo = manga.toMangaInfo()
|
||||
runBlocking {
|
||||
val chapters = getChapterList(mangaInfo)
|
||||
if (chapters.isNotEmpty()) {
|
||||
val chapter = chapters.last().toSChapter()
|
||||
val format = getFormat(chapter)
|
||||
|
||||
// Copy the cover from the first chapter found.
|
||||
if (thumbnail_url == null) {
|
||||
try {
|
||||
val dest = updateCover(chapter, sManga)
|
||||
thumbnail_url = dest?.absolutePath
|
||||
} catch (e: Exception) {
|
||||
logcat(LogPriority.ERROR, e)
|
||||
}
|
||||
if (format is Format.Epub) {
|
||||
EpubFile(format.file).use { epub ->
|
||||
epub.fillMangaMetadata(manga)
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the cover from the first chapter found if not available
|
||||
if (manga.thumbnail_url == null) {
|
||||
updateCover(chapter, manga)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -168,38 +144,44 @@ class LocalSource(private val context: Context) : CatalogueSource, UnmeteredSour
|
||||
return Observable.just(MangasPage(mangas.toList(), false))
|
||||
}
|
||||
|
||||
override fun fetchLatestUpdates(page: Int) = fetchSearchManga(page, "", LATEST_FILTERS)
|
||||
|
||||
// Manga details related
|
||||
override suspend fun getMangaDetails(manga: MangaInfo): MangaInfo {
|
||||
val localDetails = getBaseDirectories(context)
|
||||
.asSequence()
|
||||
.mapNotNull { File(it, manga.key).listFiles()?.toList() }
|
||||
.flatten()
|
||||
var mangaInfo = manga
|
||||
|
||||
val baseDirsFile = getBaseDirectoriesFiles(context)
|
||||
|
||||
val coverFile = getCoverFile(manga.key, baseDirsFile)
|
||||
|
||||
coverFile?.let {
|
||||
mangaInfo = mangaInfo.copy(cover = it.absolutePath)
|
||||
}
|
||||
|
||||
val localDetails = getMangaDirsFiles(manga.key, baseDirsFile)
|
||||
.firstOrNull { it.extension.equals("json", ignoreCase = true) }
|
||||
|
||||
return if (localDetails != null) {
|
||||
if (localDetails != null) {
|
||||
val obj = json.decodeFromStream<JsonObject>(localDetails.inputStream())
|
||||
|
||||
manga.copy(
|
||||
title = obj["title"]?.jsonPrimitive?.contentOrNull ?: manga.title,
|
||||
author = obj["author"]?.jsonPrimitive?.contentOrNull ?: manga.author,
|
||||
artist = obj["artist"]?.jsonPrimitive?.contentOrNull ?: manga.artist,
|
||||
description = obj["description"]?.jsonPrimitive?.contentOrNull ?: manga.description,
|
||||
genres = obj["genre"]?.jsonArray?.map { it.jsonPrimitive.content } ?: manga.genres,
|
||||
status = obj["status"]?.jsonPrimitive?.intOrNull ?: manga.status,
|
||||
mangaInfo = mangaInfo.copy(
|
||||
title = obj["title"]?.jsonPrimitive?.contentOrNull ?: mangaInfo.title,
|
||||
author = obj["author"]?.jsonPrimitive?.contentOrNull ?: mangaInfo.author,
|
||||
artist = obj["artist"]?.jsonPrimitive?.contentOrNull ?: mangaInfo.artist,
|
||||
description = obj["description"]?.jsonPrimitive?.contentOrNull ?: mangaInfo.description,
|
||||
genres = obj["genre"]?.jsonArray?.map { it.jsonPrimitive.content } ?: mangaInfo.genres,
|
||||
status = obj["status"]?.jsonPrimitive?.intOrNull ?: mangaInfo.status,
|
||||
)
|
||||
} else {
|
||||
manga
|
||||
}
|
||||
|
||||
return mangaInfo
|
||||
}
|
||||
|
||||
// Chapters
|
||||
override suspend fun getChapterList(manga: MangaInfo): List<ChapterInfo> {
|
||||
val sManga = manga.toSManga()
|
||||
|
||||
val chapters = getBaseDirectories(context)
|
||||
.asSequence()
|
||||
.mapNotNull { File(it, manga.key).listFiles()?.toList() }
|
||||
.flatten()
|
||||
val baseDirsFile = getBaseDirectoriesFiles(context)
|
||||
return getMangaDirsFiles(manga.key, baseDirsFile)
|
||||
// Only keep supported formats
|
||||
.filter { it.isDirectory || isSupportedFile(it.extension) }
|
||||
.map { chapterFile ->
|
||||
SChapter.create().apply {
|
||||
@ -211,15 +193,14 @@ class LocalSource(private val context: Context) : CatalogueSource, UnmeteredSour
|
||||
}
|
||||
date_upload = chapterFile.lastModified()
|
||||
|
||||
ChapterRecognition.parseChapterNumber(this, sManga)
|
||||
|
||||
val format = getFormat(chapterFile)
|
||||
if (format is Format.Epub) {
|
||||
EpubFile(format.file).use { epub ->
|
||||
epub.fillChapterMetadata(this)
|
||||
}
|
||||
}
|
||||
|
||||
name = getCleanChapterTitle(name)
|
||||
ChapterRecognition.parseChapterNumber(this, sManga)
|
||||
}
|
||||
}
|
||||
.map { it.toChapterInfo() }
|
||||
@ -228,19 +209,24 @@ class LocalSource(private val context: Context) : CatalogueSource, UnmeteredSour
|
||||
if (c == 0) c2.name.compareToCaseInsensitiveNaturalOrder(c1.name) else c
|
||||
}
|
||||
.toList()
|
||||
|
||||
return chapters
|
||||
}
|
||||
|
||||
override suspend fun getPageList(chapter: ChapterInfo) = throw Exception("Unused")
|
||||
// Filters
|
||||
override fun getFilterList() = FilterList(OrderBy(context))
|
||||
|
||||
/**
|
||||
* Trim whitespace/delimiter characters from chapter names.
|
||||
*/
|
||||
private fun getCleanChapterTitle(chapterName: String): String {
|
||||
return chapterName.trim(*WHITESPACE_CHARS.toCharArray(), '-', '_', ',', ':')
|
||||
}
|
||||
private val POPULAR_FILTERS = FilterList(OrderBy(context))
|
||||
private val LATEST_FILTERS = FilterList(OrderBy(context).apply { state = Filter.Sort.Selection(1, false) })
|
||||
|
||||
private class OrderBy(context: Context) : Filter.Sort(
|
||||
context.getString(R.string.local_filter_order_by),
|
||||
arrayOf(context.getString(R.string.title), context.getString(R.string.date)),
|
||||
Selection(0, true),
|
||||
)
|
||||
|
||||
// Unused stuff
|
||||
override suspend fun getPageList(chapter: ChapterInfo) = throw UnsupportedOperationException("Unused")
|
||||
|
||||
// Miscellaneous
|
||||
private fun isSupportedFile(extension: String): Boolean {
|
||||
return extension.lowercase() in SUPPORTED_ARCHIVE_TYPES
|
||||
}
|
||||
@ -304,54 +290,89 @@ class LocalSource(private val context: Context) : CatalogueSource, UnmeteredSour
|
||||
}
|
||||
}
|
||||
}
|
||||
.also { coverCache.clearMemoryCache() }
|
||||
}
|
||||
|
||||
override fun getFilterList() = POPULAR_FILTERS
|
||||
|
||||
private val POPULAR_FILTERS = FilterList(OrderBy(context))
|
||||
private val LATEST_FILTERS = FilterList(OrderBy(context).apply { state = Filter.Sort.Selection(1, false) })
|
||||
|
||||
private class OrderBy(context: Context) : Filter.Sort(
|
||||
context.getString(R.string.local_filter_order_by),
|
||||
arrayOf(context.getString(R.string.title), context.getString(R.string.date)),
|
||||
Selection(0, true),
|
||||
)
|
||||
|
||||
sealed class Format {
|
||||
data class Directory(val file: File) : Format()
|
||||
data class Zip(val file: File) : Format()
|
||||
data class Rar(val file: File) : Format()
|
||||
data class Epub(val file: File) : Format()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ID = 0L
|
||||
const val HELP_URL = "https://tachiyomi.org/help/guides/local-manga/"
|
||||
|
||||
private const val DEFAULT_COVER_NAME = "cover.jpg"
|
||||
private val LATEST_THRESHOLD = TimeUnit.MILLISECONDS.convert(7, TimeUnit.DAYS)
|
||||
|
||||
private fun getBaseDirectories(context: Context): Sequence<File> {
|
||||
val localFolder = context.getString(R.string.app_name) + File.separator + "local"
|
||||
return DiskUtil.getExternalStorages(context)
|
||||
.map { File(it.absolutePath, localFolder) }
|
||||
.asSequence()
|
||||
}
|
||||
|
||||
private fun getBaseDirectoriesFiles(context: Context): Sequence<File> {
|
||||
return getBaseDirectories(context)
|
||||
// Get all the files inside all baseDir
|
||||
.flatMap { it.listFiles().orEmpty().toList() }
|
||||
}
|
||||
|
||||
private fun getMangaDir(mangaUrl: String, baseDirsFile: Sequence<File>): File? {
|
||||
return baseDirsFile
|
||||
// Get the first mangaDir or null
|
||||
.firstOrNull { it.isDirectory && it.name == mangaUrl }
|
||||
}
|
||||
|
||||
private fun getMangaDirsFiles(mangaUrl: String, baseDirsFile: Sequence<File>): Sequence<File> {
|
||||
return baseDirsFile
|
||||
// Filter out ones that are not related to the manga and is not a directory
|
||||
.filter { it.isDirectory && it.name == mangaUrl }
|
||||
// Get all the files inside the filtered folders
|
||||
.flatMap { it.listFiles().orEmpty().toList() }
|
||||
}
|
||||
|
||||
private fun getCoverFile(mangaUrl: String, baseDirsFile: Sequence<File>): File? {
|
||||
return getMangaDirsFiles(mangaUrl, baseDirsFile)
|
||||
// Get all file whose names start with 'cover'
|
||||
.filter { it.isFile && it.nameWithoutExtension.equals("cover", ignoreCase = true) }
|
||||
// Get the first actual image
|
||||
.firstOrNull {
|
||||
ImageUtil.isImage(it.name) { it.inputStream() }
|
||||
}
|
||||
}
|
||||
|
||||
fun updateCover(context: Context, manga: SManga, inputStream: InputStream): File? {
|
||||
val baseDirsFiles = getBaseDirectoriesFiles(context)
|
||||
|
||||
val mangaDir = getMangaDir(manga.url, baseDirsFiles)
|
||||
if (mangaDir == null) {
|
||||
inputStream.close()
|
||||
return null
|
||||
}
|
||||
|
||||
var coverFile = getCoverFile(manga.url, baseDirsFiles)
|
||||
if (coverFile == null) {
|
||||
coverFile = File(mangaDir.absolutePath, DEFAULT_COVER_NAME)
|
||||
}
|
||||
|
||||
// It might not exist at this point
|
||||
coverFile.parentFile?.mkdirs()
|
||||
inputStream.use { input ->
|
||||
coverFile.outputStream().use { output ->
|
||||
input.copyTo(output)
|
||||
}
|
||||
}
|
||||
|
||||
// Create a .nomedia file
|
||||
DiskUtil.createNoMediaFile(UniFile.fromFile(mangaDir), context)
|
||||
|
||||
manga.thumbnail_url = coverFile.absolutePath
|
||||
return coverFile
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val SUPPORTED_ARCHIVE_TYPES = listOf("zip", "cbz", "rar", "cbr", "epub")
|
||||
|
||||
private val WHITESPACE_CHARS = arrayOf(
|
||||
' ',
|
||||
'\u0009',
|
||||
'\u000A',
|
||||
'\u000B',
|
||||
'\u000C',
|
||||
'\u000D',
|
||||
'\u0020',
|
||||
'\u0085',
|
||||
'\u00A0',
|
||||
'\u1680',
|
||||
'\u2000',
|
||||
'\u2001',
|
||||
'\u2002',
|
||||
'\u2003',
|
||||
'\u2004',
|
||||
'\u2005',
|
||||
'\u2006',
|
||||
'\u2007',
|
||||
'\u2008',
|
||||
'\u2009',
|
||||
'\u200A',
|
||||
'\u2028',
|
||||
'\u2029',
|
||||
'\u202F',
|
||||
'\u205F',
|
||||
'\u3000',
|
||||
)
|
||||
|
@ -371,6 +371,6 @@ abstract class HttpSource : CatalogueSource {
|
||||
override fun getFilterList() = FilterList()
|
||||
|
||||
companion object {
|
||||
const val DEFAULT_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36 Edg/88.0.705.63"
|
||||
const val DEFAULT_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.124 Safari/537.36 Edg/102.0.1245.44"
|
||||
}
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ abstract class DialogController : Controller {
|
||||
/**
|
||||
* Dismiss the dialog and pop this controller
|
||||
*/
|
||||
private fun dismissDialog() {
|
||||
fun dismissDialog() {
|
||||
if (dismissed) {
|
||||
return
|
||||
}
|
||||
|
@ -20,6 +20,9 @@ interface ThemingDelegate {
|
||||
PreferenceValues.AppTheme.GREEN_APPLE -> {
|
||||
resIds += R.style.Theme_Tachiyomi_GreenApple
|
||||
}
|
||||
PreferenceValues.AppTheme.LAVENDER -> {
|
||||
resIds += R.style.Theme_Tachiyomi_Lavender
|
||||
}
|
||||
PreferenceValues.AppTheme.MIDNIGHT_DUSK -> {
|
||||
resIds += R.style.Theme_Tachiyomi_MidnightDusk
|
||||
}
|
||||
|
@ -259,11 +259,11 @@ class ExtensionDetailsController(bundle: Bundle? = null) :
|
||||
?.map { it.baseUrl }
|
||||
?.distinct() ?: emptyList()
|
||||
|
||||
urls.forEach {
|
||||
val cleared = urls.sumOf {
|
||||
network.cookieManager.remove(it.toHttpUrl())
|
||||
}
|
||||
|
||||
logcat { "Cleared cookies for: ${urls.joinToString()}" }
|
||||
logcat { "Cleared $cleared cookies for: ${urls.joinToString()}" }
|
||||
}
|
||||
|
||||
private fun Source.isEnabled(): Boolean {
|
||||
|
@ -129,7 +129,10 @@ class SearchController(
|
||||
}
|
||||
(targetController as? SearchController)?.copyManga(manga, newManga)
|
||||
}
|
||||
.setNeutralButton(android.R.string.cancel, null)
|
||||
.setNeutralButton(activity?.getString(R.string.action_show_manga)) { _, _ ->
|
||||
dismissDialog()
|
||||
router.pushController(MangaController(newManga).withFadeTransaction())
|
||||
}
|
||||
.create()
|
||||
}
|
||||
}
|
||||
|
@ -42,10 +42,10 @@ open class TriStateItem(val filter: Filter.TriState) : AbstractFlexibleItem<TriS
|
||||
else -> throw Exception("Unknown state")
|
||||
},
|
||||
)?.apply {
|
||||
val color = if (filter.state == Filter.TriState.STATE_INCLUDE) {
|
||||
view.context.getResourceColor(R.attr.colorAccent)
|
||||
} else {
|
||||
val color = if (filter.state == Filter.TriState.STATE_IGNORE) {
|
||||
view.context.getResourceColor(R.attr.colorOnBackground, 0.38f)
|
||||
} else {
|
||||
view.context.getResourceColor(R.attr.colorPrimary)
|
||||
}
|
||||
|
||||
setTint(color)
|
||||
|
@ -36,7 +36,7 @@ data class DownloadHeaderItem(
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other is DownloadHeaderItem) {
|
||||
return name == other.name
|
||||
return id == other.id && name == other.name
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ class DownloadHolder(private val view: View, val adapter: DownloadAdapter) :
|
||||
view.popupMenu(
|
||||
menuRes = R.menu.download_single,
|
||||
initMenu = {
|
||||
findItem(R.id.move_to_top).isVisible = bindingAdapterPosition != 0
|
||||
findItem(R.id.move_to_top).isVisible = bindingAdapterPosition > 1
|
||||
findItem(R.id.move_to_bottom).isVisible =
|
||||
bindingAdapterPosition != adapter.itemCount - 1
|
||||
},
|
||||
|
@ -8,7 +8,6 @@ import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.core.view.doOnAttach
|
||||
import androidx.core.view.isVisible
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler
|
||||
import com.bluelinelabs.conductor.ControllerChangeType
|
||||
@ -304,8 +303,10 @@ class LibraryController(
|
||||
onTabsSettingsChanged(firstLaunch = true)
|
||||
|
||||
// Delay the scroll position to allow the view to be properly measured.
|
||||
view.doOnAttach {
|
||||
(activity as? MainActivity)?.binding?.tabs?.setScrollPosition(binding.libraryPager.currentItem, 0f, true)
|
||||
view.post {
|
||||
if (isAttached) {
|
||||
(activity as? MainActivity)?.binding?.tabs?.setScrollPosition(binding.libraryPager.currentItem, 0f, true)
|
||||
}
|
||||
}
|
||||
|
||||
// Send the manga map to child fragments after the adapter is updated.
|
||||
|
@ -795,7 +795,7 @@ class MangaController :
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
logcat(LogPriority.ERROR, e)
|
||||
activity?.toast(R.string.error_saving_cover)
|
||||
activity?.toast(R.string.error_sharing_cover)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ import androidx.core.text.buildSpannedString
|
||||
import androidx.core.text.color
|
||||
import androidx.core.view.isVisible
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.databinding.ChaptersItemBinding
|
||||
import eu.kanade.tachiyomi.source.LocalSource
|
||||
@ -35,6 +36,8 @@ class ChapterHolder(
|
||||
itemView.context.getString(R.string.display_mode_chapter, number)
|
||||
}
|
||||
else -> chapter.name
|
||||
// TODO: show cleaned name consistently around the app
|
||||
// else -> cleanChapterName(chapter, manga)
|
||||
}
|
||||
|
||||
// Set correct text color
|
||||
@ -80,4 +83,47 @@ class ChapterHolder(
|
||||
binding.download.isVisible = item.manga.source != LocalSource.ID
|
||||
binding.download.setState(item.status, item.progress)
|
||||
}
|
||||
|
||||
private fun cleanChapterName(chapter: Chapter, manga: Manga): String {
|
||||
return chapter.name
|
||||
.trim()
|
||||
.removePrefix(manga.title)
|
||||
.trim(*CHAPTER_TRIM_CHARS)
|
||||
}
|
||||
}
|
||||
|
||||
private val CHAPTER_TRIM_CHARS = arrayOf(
|
||||
// Whitespace
|
||||
' ',
|
||||
'\u0009',
|
||||
'\u000A',
|
||||
'\u000B',
|
||||
'\u000C',
|
||||
'\u000D',
|
||||
'\u0020',
|
||||
'\u0085',
|
||||
'\u00A0',
|
||||
'\u1680',
|
||||
'\u2000',
|
||||
'\u2001',
|
||||
'\u2002',
|
||||
'\u2003',
|
||||
'\u2004',
|
||||
'\u2005',
|
||||
'\u2006',
|
||||
'\u2007',
|
||||
'\u2008',
|
||||
'\u2009',
|
||||
'\u200A',
|
||||
'\u2028',
|
||||
'\u2029',
|
||||
'\u202F',
|
||||
'\u205F',
|
||||
'\u3000',
|
||||
|
||||
// Separators
|
||||
'-',
|
||||
'_',
|
||||
',',
|
||||
':',
|
||||
).toCharArray()
|
||||
|
@ -121,6 +121,7 @@ class AboutController : SettingsController(), NoAppBarElevationController {
|
||||
is AppUpdateResult.NoNewUpdate -> {
|
||||
activity?.toast(R.string.update_check_no_new_updates)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
} catch (error: Exception) {
|
||||
activity?.toast(error.message)
|
||||
|
@ -2,35 +2,58 @@ package eu.kanade.tachiyomi.ui.more
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.text.method.LinkMovementMethod
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import androidx.core.os.bundleOf
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.updater.AppUpdateResult
|
||||
import eu.kanade.tachiyomi.data.updater.AppUpdateService
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.openInBrowser
|
||||
import io.noties.markwon.Markwon
|
||||
|
||||
class NewUpdateDialogController(bundle: Bundle? = null) : DialogController(bundle) {
|
||||
|
||||
constructor(update: AppUpdateResult.NewUpdate) : this(
|
||||
bundleOf(BODY_KEY to update.release.info, URL_KEY to update.release.getDownloadLink()),
|
||||
bundleOf(
|
||||
BODY_KEY to update.release.info,
|
||||
RELEASE_URL_KEY to update.release.releaseLink,
|
||||
DOWNLOAD_URL_KEY to update.release.getDownloadLink(),
|
||||
),
|
||||
)
|
||||
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
val releaseBody = args.getString(BODY_KEY)!!
|
||||
.replace("""---(\R|.)*Checksums(\R|.)*""".toRegex(), "")
|
||||
val info = Markwon.create(activity!!).toMarkdown(releaseBody)
|
||||
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setTitle(R.string.update_check_notification_update_available)
|
||||
.setMessage(args.getString(BODY_KEY) ?: "")
|
||||
.setMessage(info)
|
||||
.setPositiveButton(R.string.update_check_confirm) { _, _ ->
|
||||
val appContext = applicationContext
|
||||
if (appContext != null) {
|
||||
applicationContext?.let { context ->
|
||||
// Start download
|
||||
val url = args.getString(URL_KEY) ?: ""
|
||||
AppUpdateService.start(appContext, url)
|
||||
val url = args.getString(DOWNLOAD_URL_KEY)!!
|
||||
AppUpdateService.start(context, url)
|
||||
}
|
||||
}
|
||||
.setNegativeButton(R.string.update_check_ignore, null)
|
||||
.setNeutralButton(R.string.update_check_open) { _, _ ->
|
||||
openInBrowser(args.getString(RELEASE_URL_KEY)!!)
|
||||
}
|
||||
.create()
|
||||
}
|
||||
|
||||
override fun onAttach(view: View) {
|
||||
super.onAttach(view)
|
||||
|
||||
// Make links in Markdown text clickable
|
||||
(dialog?.findViewById(android.R.id.message) as? TextView)?.movementMethod =
|
||||
LinkMovementMethod.getInstance()
|
||||
}
|
||||
}
|
||||
|
||||
private const val BODY_KEY = "NewUpdateDialogController.body"
|
||||
private const val URL_KEY = "NewUpdateDialogController.key"
|
||||
private const val RELEASE_URL_KEY = "NewUpdateDialogController.release_url"
|
||||
private const val DOWNLOAD_URL_KEY = "NewUpdateDialogController.download_url"
|
||||
|
@ -226,6 +226,11 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>() {
|
||||
super.onSaveInstanceState(outState)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
presenter.saveProgress()
|
||||
super.onPause()
|
||||
}
|
||||
|
||||
/**
|
||||
* Set menu visibility again on activity resume to apply immersive mode again if needed.
|
||||
* Helps with rotations.
|
||||
|
@ -4,7 +4,6 @@ import android.app.Application
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import com.jakewharton.rxrelay.BehaviorRelay
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.database.models.History
|
||||
@ -22,6 +21,7 @@ import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||
import eu.kanade.tachiyomi.ui.reader.loader.ChapterLoader
|
||||
import eu.kanade.tachiyomi.ui.reader.loader.HttpPageLoader
|
||||
import eu.kanade.tachiyomi.ui.reader.model.InsertPage
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
||||
@ -345,6 +345,14 @@ class ReaderPresenter(
|
||||
* that the user doesn't have to wait too long to continue reading.
|
||||
*/
|
||||
private fun preload(chapter: ReaderChapter) {
|
||||
if (chapter.pageLoader is HttpPageLoader) {
|
||||
val manga = manga ?: return
|
||||
val isDownloaded = downloadManager.isChapterDownloaded(chapter.chapter, manga)
|
||||
if (isDownloaded) {
|
||||
chapter.state = ReaderChapter.State.Wait
|
||||
}
|
||||
}
|
||||
|
||||
if (chapter.state != ReaderChapter.State.Wait && chapter.state !is ReaderChapter.State.Error) {
|
||||
return
|
||||
}
|
||||
@ -456,6 +464,10 @@ class ReaderPresenter(
|
||||
}
|
||||
}
|
||||
|
||||
fun saveProgress() {
|
||||
getCurrentChapter()?.let { onChapterChanged(it) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from the activity to preload the given [chapter].
|
||||
*/
|
||||
@ -662,20 +674,22 @@ class ReaderPresenter(
|
||||
|
||||
Observable
|
||||
.fromCallable {
|
||||
if (manga.isLocal()) {
|
||||
val context = Injekt.get<Application>()
|
||||
LocalSource.updateCover(context, manga, stream())
|
||||
manga.updateCoverLastModified(db)
|
||||
R.string.cover_updated
|
||||
SetAsCoverResult.Success
|
||||
} else {
|
||||
if (manga.favorite) {
|
||||
coverCache.setCustomCoverToCache(manga, stream())
|
||||
stream().use {
|
||||
if (manga.isLocal()) {
|
||||
val context = Injekt.get<Application>()
|
||||
LocalSource.updateCover(context, manga, it)
|
||||
manga.updateCoverLastModified(db)
|
||||
coverCache.clearMemoryCache()
|
||||
SetAsCoverResult.Success
|
||||
} else {
|
||||
SetAsCoverResult.AddToLibraryFirst
|
||||
if (manga.favorite) {
|
||||
coverCache.setCustomCoverToCache(manga, it)
|
||||
manga.updateCoverLastModified(db)
|
||||
coverCache.clearMemoryCache()
|
||||
SetAsCoverResult.Success
|
||||
} else {
|
||||
SetAsCoverResult.AddToLibraryFirst
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ open class ReaderPageImageView @JvmOverloads constructor(
|
||||
|
||||
private fun SubsamplingScaleImageView.landscapeZoom(forward: Boolean) {
|
||||
if (config != null && config!!.landscapeZoom && config!!.minimumScaleType == SCALE_TYPE_CENTER_INSIDE && sWidth > sHeight && scale == minScale) {
|
||||
handler.postDelayed({
|
||||
handler?.postDelayed({
|
||||
val point = when (config!!.zoomStartPosition) {
|
||||
ZoomStartPosition.LEFT -> if (forward) PointF(0F, 0F) else PointF(sWidth.toFloat(), 0F)
|
||||
ZoomStartPosition.RIGHT -> if (forward) PointF(sWidth.toFloat(), 0F) else PointF(0F, 0F)
|
||||
|
@ -26,7 +26,6 @@ class ReaderTransitionView @JvmOverloads constructor(context: Context, attrs: At
|
||||
is ChapterTransition.Prev -> bindPrevChapterTransition(transition)
|
||||
is ChapterTransition.Next -> bindNextChapterTransition(transition)
|
||||
}
|
||||
|
||||
missingChapterWarning(transition)
|
||||
}
|
||||
|
||||
|
@ -66,9 +66,14 @@ abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer {
|
||||
set(value) {
|
||||
field = value
|
||||
if (value) {
|
||||
awaitingIdleViewerChapters?.let {
|
||||
setChaptersInternal(it)
|
||||
awaitingIdleViewerChapters?.let { viewerChapters ->
|
||||
setChaptersInternal(viewerChapters)
|
||||
awaitingIdleViewerChapters = null
|
||||
if (viewerChapters.currChapter.pages?.size == 1) {
|
||||
adapter.nextTransition?.to?.let {
|
||||
activity.requestPreloadChapter(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ class WebtoonTransitionHolder(
|
||||
layout.orientation = LinearLayout.VERTICAL
|
||||
layout.gravity = Gravity.CENTER
|
||||
|
||||
val paddingVertical = 48.dpToPx
|
||||
val paddingVertical = 128.dpToPx
|
||||
val paddingHorizontal = 32.dpToPx
|
||||
layout.setPadding(paddingHorizontal, paddingVertical, paddingHorizontal, paddingVertical)
|
||||
|
||||
|
@ -103,6 +103,12 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr
|
||||
activity.requestPreloadChapter(firstItem.to)
|
||||
}
|
||||
}
|
||||
|
||||
val lastIndex = layoutManager.findLastEndVisibleItemPosition()
|
||||
val lastItem = adapter.items.getOrNull(lastIndex)
|
||||
if (lastItem is ChapterTransition.Next && lastItem.to == null) {
|
||||
activity.showMenu()
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
@ -216,9 +222,6 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr
|
||||
if (toChapter != null) {
|
||||
logcat { "Request preload destination chapter because we're on the transition" }
|
||||
activity.requestPreloadChapter(toChapter)
|
||||
} else if (transition is ChapterTransition.Next) {
|
||||
// No more chapters, show menu because the user is probably going to close the reader
|
||||
activity.showMenu()
|
||||
}
|
||||
}
|
||||
|
||||
@ -245,7 +248,7 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr
|
||||
logcat { "moveToPage" }
|
||||
val position = adapter.items.indexOf(page)
|
||||
if (position != -1) {
|
||||
recycler.scrollToPosition(position)
|
||||
layoutManager.scrollToPositionWithOffset(position, 0)
|
||||
if (layoutManager.findLastEndVisibleItemPosition() == -1) {
|
||||
onScrolled(pos = position)
|
||||
}
|
||||
|
@ -4,10 +4,11 @@ import android.annotation.SuppressLint
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Intent
|
||||
import android.provider.Settings
|
||||
import android.webkit.WebStorage
|
||||
import android.webkit.WebView
|
||||
import androidx.core.net.toUri
|
||||
import androidx.preference.PreferenceScreen
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.BuildConfig
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.cache.ChapterCache
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
@ -15,9 +16,13 @@ import eu.kanade.tachiyomi.data.library.LibraryUpdateService
|
||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateService.Target
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues
|
||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||
import eu.kanade.tachiyomi.network.PREF_DOH_360
|
||||
import eu.kanade.tachiyomi.network.PREF_DOH_ADGUARD
|
||||
import eu.kanade.tachiyomi.network.PREF_DOH_ALIDNS
|
||||
import eu.kanade.tachiyomi.network.PREF_DOH_CLOUDFLARE
|
||||
import eu.kanade.tachiyomi.network.PREF_DOH_DNSPOD
|
||||
import eu.kanade.tachiyomi.network.PREF_DOH_GOOGLE
|
||||
import eu.kanade.tachiyomi.network.PREF_DOH_QUAD101
|
||||
import eu.kanade.tachiyomi.network.PREF_DOH_QUAD9
|
||||
import eu.kanade.tachiyomi.ui.base.controller.openInBrowser
|
||||
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||
@ -38,11 +43,16 @@ import eu.kanade.tachiyomi.util.preference.summaryRes
|
||||
import eu.kanade.tachiyomi.util.preference.switchPreference
|
||||
import eu.kanade.tachiyomi.util.preference.titleRes
|
||||
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
||||
import eu.kanade.tachiyomi.util.system.isDevFlavor
|
||||
import eu.kanade.tachiyomi.util.system.isPackageInstalled
|
||||
import eu.kanade.tachiyomi.util.system.logcat
|
||||
import eu.kanade.tachiyomi.util.system.powerManager
|
||||
import eu.kanade.tachiyomi.util.system.setDefaultSettings
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import logcat.LogPriority
|
||||
import rikka.sui.Sui
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.io.File
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||
|
||||
class SettingsAdvancedController : SettingsController() {
|
||||
@ -55,7 +65,7 @@ class SettingsAdvancedController : SettingsController() {
|
||||
override fun setupPreferenceScreen(screen: PreferenceScreen) = screen.apply {
|
||||
titleRes = R.string.pref_category_advanced
|
||||
|
||||
if (BuildConfig.FLAVOR != "dev") {
|
||||
if (isDevFlavor.not()) {
|
||||
switchPreference {
|
||||
key = "acra.enable"
|
||||
titleRes = R.string.pref_enable_acra
|
||||
@ -78,7 +88,7 @@ class SettingsAdvancedController : SettingsController() {
|
||||
key = Keys.verboseLogging
|
||||
titleRes = R.string.pref_verbose_logging
|
||||
summaryRes = R.string.pref_verbose_logging_summary
|
||||
defaultValue = false
|
||||
defaultValue = isDevFlavor
|
||||
|
||||
onChange {
|
||||
activity?.toast(R.string.requires_app_restart)
|
||||
@ -161,6 +171,12 @@ class SettingsAdvancedController : SettingsController() {
|
||||
activity?.toast(R.string.cookies_cleared)
|
||||
}
|
||||
}
|
||||
preference {
|
||||
key = "pref_clear_webview_data"
|
||||
titleRes = R.string.pref_clear_webview_data
|
||||
|
||||
onClick { clearWebViewData() }
|
||||
}
|
||||
intListPreference {
|
||||
key = Keys.dohProvider
|
||||
titleRes = R.string.pref_dns_over_https
|
||||
@ -170,6 +186,10 @@ class SettingsAdvancedController : SettingsController() {
|
||||
"Google",
|
||||
"AdGuard",
|
||||
"Quad9",
|
||||
"AliDNS",
|
||||
"DNSPod",
|
||||
"360",
|
||||
"Quad 101",
|
||||
)
|
||||
entryValues = arrayOf(
|
||||
"-1",
|
||||
@ -177,6 +197,10 @@ class SettingsAdvancedController : SettingsController() {
|
||||
PREF_DOH_GOOGLE.toString(),
|
||||
PREF_DOH_ADGUARD.toString(),
|
||||
PREF_DOH_QUAD9.toString(),
|
||||
PREF_DOH_ALIDNS.toString(),
|
||||
PREF_DOH_DNSPOD.toString(),
|
||||
PREF_DOH_360.toString(),
|
||||
PREF_DOH_QUAD101.toString(),
|
||||
)
|
||||
defaultValue = "-1"
|
||||
summary = "%s"
|
||||
@ -274,10 +298,29 @@ class SettingsAdvancedController : SettingsController() {
|
||||
resources?.getString(R.string.used_cache, chapterCache.readableSize)
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
logcat(LogPriority.ERROR, e)
|
||||
withUIContext { activity?.toast(R.string.cache_delete_error) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun clearWebViewData() {
|
||||
if (activity == null) return
|
||||
try {
|
||||
val webview = WebView(activity!!)
|
||||
webview.setDefaultSettings()
|
||||
webview.clearCache(true)
|
||||
webview.clearFormData()
|
||||
webview.clearHistory()
|
||||
webview.clearSslPreferences()
|
||||
WebStorage.getInstance().deleteAllData()
|
||||
activity?.applicationInfo?.dataDir?.let { File("$it/app_webview/").deleteRecursively() }
|
||||
activity?.toast(R.string.webview_data_deleted)
|
||||
} catch (e: Throwable) {
|
||||
logcat(LogPriority.ERROR, e)
|
||||
activity?.toast(R.string.cache_delete_error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private const val CLEAR_CACHE_KEY = "pref_clear_cache_key"
|
||||
|
@ -125,20 +125,20 @@ class SettingsDownloadController : SettingsController() {
|
||||
titleRes = R.string.pref_category_auto_download
|
||||
|
||||
switchPreference {
|
||||
bindTo(preferences.downloadNew())
|
||||
bindTo(preferences.downloadNewChapter())
|
||||
titleRes = R.string.pref_download_new
|
||||
}
|
||||
preference {
|
||||
bindTo(preferences.downloadNewCategories())
|
||||
bindTo(preferences.downloadNewChapterCategories())
|
||||
titleRes = R.string.categories
|
||||
onClick {
|
||||
DownloadCategoriesDialog().showDialog(router)
|
||||
}
|
||||
|
||||
visibleIf(preferences.downloadNew()) { it }
|
||||
visibleIf(preferences.downloadNewChapter()) { it }
|
||||
|
||||
fun updateSummary() {
|
||||
val selectedCategories = preferences.downloadNewCategories().get()
|
||||
val selectedCategories = preferences.downloadNewChapterCategories().get()
|
||||
.mapNotNull { id -> categories.find { it.id == id.toInt() } }
|
||||
.sortedBy { it.order }
|
||||
val includedItemsText = if (selectedCategories.isEmpty()) {
|
||||
@ -147,7 +147,7 @@ class SettingsDownloadController : SettingsController() {
|
||||
selectedCategories.joinToString { it.name }
|
||||
}
|
||||
|
||||
val excludedCategories = preferences.downloadNewCategoriesExclude().get()
|
||||
val excludedCategories = preferences.downloadNewChapterCategoriesExclude().get()
|
||||
.mapNotNull { id -> categories.find { it.id == id.toInt() } }
|
||||
.sortedBy { it.order }
|
||||
val excludedItemsText = if (excludedCategories.isEmpty()) {
|
||||
@ -163,10 +163,10 @@ class SettingsDownloadController : SettingsController() {
|
||||
}
|
||||
}
|
||||
|
||||
preferences.downloadNewCategories().asFlow()
|
||||
preferences.downloadNewChapterCategories().asFlow()
|
||||
.onEach { updateSummary() }
|
||||
.launchIn(viewScope)
|
||||
preferences.downloadNewCategoriesExclude().asFlow()
|
||||
preferences.downloadNewChapterCategoriesExclude().asFlow()
|
||||
.onEach { updateSummary() }
|
||||
.launchIn(viewScope)
|
||||
}
|
||||
@ -254,8 +254,8 @@ class SettingsDownloadController : SettingsController() {
|
||||
var selected = categories
|
||||
.map {
|
||||
when (it.id.toString()) {
|
||||
in preferences.downloadNewCategories().get() -> QuadStateTextView.State.CHECKED.ordinal
|
||||
in preferences.downloadNewCategoriesExclude().get() -> QuadStateTextView.State.INVERSED.ordinal
|
||||
in preferences.downloadNewChapterCategories().get() -> QuadStateTextView.State.CHECKED.ordinal
|
||||
in preferences.downloadNewChapterCategoriesExclude().get() -> QuadStateTextView.State.INVERSED.ordinal
|
||||
else -> QuadStateTextView.State.UNCHECKED.ordinal
|
||||
}
|
||||
}
|
||||
@ -282,8 +282,8 @@ class SettingsDownloadController : SettingsController() {
|
||||
.map { categories[it].id.toString() }
|
||||
.toSet()
|
||||
|
||||
preferences.downloadNewCategories().set(included)
|
||||
preferences.downloadNewCategoriesExclude().set(excluded)
|
||||
preferences.downloadNewChapterCategories().set(included)
|
||||
preferences.downloadNewChapterCategoriesExclude().set(excluded)
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
|
@ -11,12 +11,7 @@ import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.database.models.Category
|
||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
|
||||
import eu.kanade.tachiyomi.data.preference.DEVICE_CHARGING
|
||||
import eu.kanade.tachiyomi.data.preference.DEVICE_ONLY_ON_WIFI
|
||||
import eu.kanade.tachiyomi.data.preference.MANGA_HAS_UNREAD
|
||||
import eu.kanade.tachiyomi.data.preference.MANGA_NON_COMPLETED
|
||||
import eu.kanade.tachiyomi.data.preference.MANGA_NON_READ
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.preference.*
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.databinding.PrefLibraryColumnsBinding
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
@ -159,8 +154,8 @@ class SettingsLibraryController : SettingsController() {
|
||||
multiSelectListPreference {
|
||||
bindTo(preferences.libraryUpdateDeviceRestriction())
|
||||
titleRes = R.string.pref_library_update_restriction
|
||||
entriesRes = arrayOf(R.string.connected_to_wifi, R.string.charging)
|
||||
entryValues = arrayOf(DEVICE_ONLY_ON_WIFI, DEVICE_CHARGING)
|
||||
entriesRes = arrayOf(R.string.connected_to_wifi, R.string.network_not_metered, R.string.charging, R.string.battery_not_low)
|
||||
entryValues = arrayOf(DEVICE_ONLY_ON_WIFI, DEVICE_NETWORK_NOT_METERED, DEVICE_CHARGING, DEVICE_BATTERY_NOT_LOW)
|
||||
|
||||
visibleIf(preferences.libraryUpdateInterval()) { it > 0 }
|
||||
|
||||
@ -176,7 +171,9 @@ class SettingsLibraryController : SettingsController() {
|
||||
.map {
|
||||
when (it) {
|
||||
DEVICE_ONLY_ON_WIFI -> context.getString(R.string.connected_to_wifi)
|
||||
DEVICE_NETWORK_NOT_METERED -> context.getString(R.string.network_not_metered)
|
||||
DEVICE_CHARGING -> context.getString(R.string.charging)
|
||||
DEVICE_BATTERY_NOT_LOW -> context.getString(R.string.battery_not_low)
|
||||
else -> it
|
||||
}
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ class ClearDatabaseController :
|
||||
|
||||
adapter = FlexibleAdapter<ClearDatabaseSourceItem>(null, this, true)
|
||||
binding.recycler.adapter = adapter
|
||||
binding.recycler.layoutManager = LinearLayoutManager(activity)
|
||||
binding.recycler.layoutManager = LinearLayoutManager(activity!!)
|
||||
binding.recycler.setHasFixedSize(true)
|
||||
adapter?.fastScroller = binding.fastScroller
|
||||
recycler = binding.recycler
|
||||
|
@ -17,17 +17,20 @@ import androidx.lifecycle.lifecycleScope
|
||||
import eu.kanade.tachiyomi.BuildConfig
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.databinding.WebviewActivityBinding
|
||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
|
||||
import eu.kanade.tachiyomi.util.system.WebViewClientCompat
|
||||
import eu.kanade.tachiyomi.util.system.WebViewUtil
|
||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||
import eu.kanade.tachiyomi.util.system.logcat
|
||||
import eu.kanade.tachiyomi.util.system.openInBrowser
|
||||
import eu.kanade.tachiyomi.util.system.setDefaultSettings
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
import reactivecircus.flowbinding.appcompat.navigationClicks
|
||||
import reactivecircus.flowbinding.swiperefreshlayout.refreshes
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
@ -37,11 +40,16 @@ class WebViewActivity : BaseActivity() {
|
||||
private lateinit var binding: WebviewActivityBinding
|
||||
|
||||
private val sourceManager: SourceManager by injectLazy()
|
||||
private val network: NetworkHelper by injectLazy()
|
||||
|
||||
private var bundle: Bundle? = null
|
||||
|
||||
private var isRefreshing: Boolean = false
|
||||
|
||||
init {
|
||||
registerSecureActivity(this)
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
@ -176,6 +184,7 @@ class WebViewActivity : BaseActivity() {
|
||||
R.id.action_web_refresh -> refreshPage()
|
||||
R.id.action_web_share -> shareWebpage()
|
||||
R.id.action_web_browser -> openInBrowser()
|
||||
R.id.action_clear_cookies -> clearCookies()
|
||||
}
|
||||
return super.onOptionsItemSelected(item)
|
||||
}
|
||||
@ -207,8 +216,10 @@ class WebViewActivity : BaseActivity() {
|
||||
openInBrowser(binding.webview.url!!, forceDefaultBrowser = true)
|
||||
}
|
||||
|
||||
init {
|
||||
registerSecureActivity(this)
|
||||
private fun clearCookies() {
|
||||
val url = binding.webview.url!!
|
||||
val cleared = network.cookieManager.remove(url.toHttpUrl())
|
||||
logcat { "Cleared $cleared cookies for: $url" }
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -56,14 +56,14 @@ fun Manga.shouldDownloadNewChapters(db: DatabaseHelper, prefs: PreferencesHelper
|
||||
if (!favorite) return false
|
||||
|
||||
// Boolean to determine if user wants to automatically download new chapters.
|
||||
val downloadNew = prefs.downloadNew().get()
|
||||
if (!downloadNew) return false
|
||||
val downloadNewChapter = prefs.downloadNewChapter().get()
|
||||
if (!downloadNewChapter) return false
|
||||
|
||||
val categoriesToDownload = prefs.downloadNewCategories().get().map(String::toInt)
|
||||
val categoriesToExclude = prefs.downloadNewCategoriesExclude().get().map(String::toInt)
|
||||
val includedCategories = prefs.downloadNewChapterCategories().get().map { it.toInt() }
|
||||
val excludedCategories = prefs.downloadNewChapterCategoriesExclude().get().map { it.toInt() }
|
||||
|
||||
// Default: download from all categories
|
||||
if (categoriesToDownload.isEmpty() && categoriesToExclude.isEmpty()) return true
|
||||
// Default: Download from all categories
|
||||
if (includedCategories.isEmpty() && excludedCategories.isEmpty()) return true
|
||||
|
||||
// Get all categories, else default category (0)
|
||||
val categoriesForManga =
|
||||
@ -72,8 +72,11 @@ fun Manga.shouldDownloadNewChapters(db: DatabaseHelper, prefs: PreferencesHelper
|
||||
.takeUnless { it.isEmpty() } ?: listOf(0)
|
||||
|
||||
// In excluded category
|
||||
if (categoriesForManga.intersect(categoriesToExclude).isNotEmpty()) return false
|
||||
if (categoriesForManga.any { it in excludedCategories }) return false
|
||||
|
||||
// Included category not selected
|
||||
if (includedCategories.isEmpty()) return true
|
||||
|
||||
// In included category
|
||||
return categoriesForManga.intersect(categoriesToDownload).isNotEmpty()
|
||||
return categoriesForManga.any { it in includedCategories }
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.util.Date
|
||||
import java.util.TreeSet
|
||||
import kotlin.math.max
|
||||
|
||||
/**
|
||||
* Helper method for syncing the list of chapters from the source with the ones from the database.
|
||||
@ -59,6 +60,9 @@ fun syncChaptersWithSource(
|
||||
}
|
||||
}
|
||||
|
||||
var maxTimestamp = 0L // in previous chapters to add
|
||||
val rightNow = Date().time
|
||||
|
||||
for (sourceChapter in sourceChapters) {
|
||||
// This forces metadata update for the main viewable things in the chapter list.
|
||||
if (source is HttpSource) {
|
||||
@ -72,7 +76,9 @@ fun syncChaptersWithSource(
|
||||
// Add the chapter if not in db already, or update if the metadata changed.
|
||||
if (dbChapter == null) {
|
||||
if (sourceChapter.date_upload == 0L) {
|
||||
sourceChapter.date_upload = Date().time
|
||||
sourceChapter.date_upload = if (maxTimestamp == 0L) rightNow else maxTimestamp
|
||||
} else {
|
||||
maxTimestamp = max(maxTimestamp, sourceChapter.date_upload)
|
||||
}
|
||||
toAdd.add(sourceChapter)
|
||||
} else {
|
||||
@ -97,6 +103,7 @@ fun syncChaptersWithSource(
|
||||
return Pair(emptyList(), emptyList())
|
||||
}
|
||||
|
||||
// Keep it a List instead of a Set. See #6372.
|
||||
val readded = mutableListOf<Chapter>()
|
||||
|
||||
db.inTransaction {
|
||||
@ -154,6 +161,7 @@ fun syncChaptersWithSource(
|
||||
db.updateLastUpdated(manga).executeAsBlocking()
|
||||
}
|
||||
|
||||
@Suppress("ConvertArgumentToSet")
|
||||
return Pair(toAdd.subtract(readded).toList(), toDelete.subtract(readded).toList())
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,6 @@
|
||||
package eu.kanade.tachiyomi.util.system
|
||||
|
||||
import eu.kanade.tachiyomi.BuildConfig
|
||||
|
||||
val isDevFlavor: Boolean
|
||||
get() = BuildConfig.FLAVOR == "dev"
|
@ -87,7 +87,11 @@ fun Context.copyToClipboard(label: String, content: String) {
|
||||
val clipboard = getSystemService<ClipboardManager>()!!
|
||||
clipboard.setPrimaryClip(ClipData.newPlainText(label, content))
|
||||
|
||||
toast(getString(R.string.copied_to_clipboard, content.truncateCenter(50)))
|
||||
// Android 13 and higher shows a visual confirmation of copied contents
|
||||
// https://developer.android.com/about/versions/13/features/copy-paste
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.S_V2) {
|
||||
toast(getString(R.string.copied_to_clipboard, content.truncateCenter(50)))
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
logcat(LogPriority.ERROR, e)
|
||||
toast(R.string.clipboard_copy_error)
|
||||
@ -382,6 +386,19 @@ fun Context.isPackageInstalled(packageName: String): Boolean {
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.getInstallerPackageName(): String? {
|
||||
return try {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
packageManager.getInstallSourceInfo(packageName).installingPackageName
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
packageManager.getInstallerPackageName(packageName)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.getApplicationIcon(pkgName: String): Drawable? {
|
||||
return try {
|
||||
packageManager.getApplicationIcon(pkgName)
|
||||
|
@ -10,6 +10,7 @@ import android.graphics.drawable.ColorDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.os.Build
|
||||
import android.webkit.MimeTypeMap
|
||||
import androidx.core.graphics.alpha
|
||||
import androidx.core.graphics.applyCanvas
|
||||
import androidx.core.graphics.blue
|
||||
@ -56,6 +57,12 @@ object ImageUtil {
|
||||
return null
|
||||
}
|
||||
|
||||
fun getExtensionFromMimeType(mime: String?): String {
|
||||
return MimeTypeMap.getSingleton().getExtensionFromMimeType(mime)
|
||||
?: SUPPLEMENTARY_MIMETYPE_MAPPING[mime]
|
||||
?: "jpg"
|
||||
}
|
||||
|
||||
fun isAnimatedAndSupported(stream: InputStream): Boolean {
|
||||
try {
|
||||
val type = getImageType(stream) ?: return false
|
||||
@ -392,4 +399,10 @@ object ImageUtil {
|
||||
|
||||
private fun Int.isWhite(): Boolean =
|
||||
red + blue + green > 740
|
||||
|
||||
// Android doesn't include some mappings
|
||||
private val SUPPLEMENTARY_MIMETYPE_MAPPING = mapOf(
|
||||
// https://issuetracker.google.com/issues/182703810
|
||||
"image/jxl" to "jxl",
|
||||
)
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ open class ExtendedNavigationView @JvmOverloads constructor(
|
||||
* @param context any context.
|
||||
* @param resId the vector resource to load and tint
|
||||
*/
|
||||
fun tintVector(context: Context, resId: Int, @AttrRes colorAttrRes: Int = R.attr.colorAccent): Drawable {
|
||||
fun tintVector(context: Context, resId: Int, @AttrRes colorAttrRes: Int = R.attr.colorPrimary): Drawable {
|
||||
return AppCompatResources.getDrawable(context, resId)!!.apply {
|
||||
setTint(context.getResourceColor(if (enabled) colorAttrRes else R.attr.colorControlNormal))
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ class QuadStateTextView @JvmOverloads constructor(context: Context, attrs: Attri
|
||||
val tint = if (state == State.UNCHECKED) {
|
||||
context.getThemeColor(R.attr.colorControlNormal)
|
||||
} else {
|
||||
context.getThemeColor(R.attr.colorAccent)
|
||||
context.getThemeColor(R.attr.colorPrimary)
|
||||
}
|
||||
if (tint != 0) {
|
||||
TextViewCompat.setCompoundDrawableTintList(this, ColorStateList.valueOf(tint))
|
||||
|
5
app/src/main/res/color/slider_active_track.xml
Normal file
5
app/src/main/res/color/slider_active_track.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:color="?attr/colorPrimary" android:state_enabled="true"/>
|
||||
<item android:alpha="@dimen/material_emphasis_disabled" android:color="?attr/colorOnSurface"/>
|
||||
</selector>
|
5
app/src/main/res/color/slider_inactive_track.xml
Normal file
5
app/src/main/res/color/slider_inactive_track.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:alpha="0.24" android:color="?attr/colorPrimary" android:state_enabled="true"/>
|
||||
<item android:alpha="@dimen/material_emphasis_disabled" android:color="?attr/colorOnSurface"/>
|
||||
</selector>
|
@ -1,8 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:width="36dp"
|
||||
android:height="36dp"
|
||||
android:drawable="@drawable/ic_tachi"
|
||||
android:gravity="center" />
|
||||
</layer-list>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:pathData="M50.61,39.254C50.65,40.029 50.691,41.036 50.719,41.513L50.773,42.371L44.96,42.331C41.772,42.303 39.049,42.235 38.926,42.166C38.695,42.058 38.682,42.248 38.682,44.944L38.682,47.831L38.995,47.75C39.893,47.491 43.53,47.395 53.796,47.395C64.064,47.395 67.698,47.491 68.611,47.75L68.911,47.831L68.911,44.944C68.911,42.248 68.897,42.058 68.678,42.166C68.542,42.235 65.819,42.303 62.634,42.331L56.819,42.371L56.873,41.513C56.9,41.036 56.941,40.029 56.981,39.254L57.037,37.864L50.555,37.864L50.61,39.254ZM44.645,49.329C43.23,49.861 42.086,50.377 42.086,50.459C42.086,50.555 42.276,51.044 42.509,51.563C43.597,53.973 45.312,59.937 45.79,62.945C45.87,63.53 46.008,64.008 46.089,64.008C46.171,64.008 47.505,63.572 49.072,63.041C51.1,62.333 51.889,62.006 51.889,61.856C51.889,61.42 49.467,53.551 48.322,50.282C47.805,48.839 47.586,48.349 47.41,48.362C47.287,48.362 46.049,48.798 44.645,49.329Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M59.406,49.397C58.957,52.257 57.282,57.785 55.484,62.333L54.545,64.688L37.456,64.688L37.456,70.136L70.544,70.136L70.544,64.688L65.493,64.688C61.503,64.688 60.454,64.648 60.509,64.511C60.55,64.43 60.876,63.708 61.23,62.918C61.571,62.128 62.252,60.426 62.728,59.12C63.641,56.614 65.643,50.364 65.643,49.997C65.643,49.819 65.016,49.614 62.756,49.057C61.163,48.662 59.788,48.349 59.706,48.349C59.624,48.349 59.488,48.825 59.406,49.397Z"
|
||||
android:fillColor="#000000"/>
|
||||
</vector>
|
||||
|
@ -17,7 +17,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/side_nav"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
@ -35,7 +35,7 @@
|
||||
android:background="?attr/colorTertiary"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/side_nav"
|
||||
app:layout_constraintTop_toBottomOf="@+id/appbar"
|
||||
tools:visibility="visible">
|
||||
|
||||
@ -56,7 +56,7 @@
|
||||
android:background="?attr/colorPrimary"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/side_nav"
|
||||
app:layout_constraintTop_toBottomOf="@+id/downloaded_only"
|
||||
tools:visibility="visible">
|
||||
|
||||
@ -73,11 +73,10 @@
|
||||
<com.google.android.material.navigationrail.NavigationRailView
|
||||
android:id="@+id/side_nav"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
app:elevation="0dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingTop="?attr/actionBarSize"
|
||||
app:elevation="1dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/incognito_mode"
|
||||
app:menu="@menu/main_nav" />
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
|
@ -95,9 +95,10 @@
|
||||
|
||||
<TextView
|
||||
android:id="@+id/left_page_text"
|
||||
android:layout_width="32dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:minWidth="32dp"
|
||||
android:textColor="?attr/colorOnSurface"
|
||||
android:textSize="15sp"
|
||||
tools:text="1" />
|
||||
@ -116,9 +117,10 @@
|
||||
|
||||
<TextView
|
||||
android:id="@+id/right_page_text"
|
||||
android:layout_width="32dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:minWidth="32dp"
|
||||
android:textColor="?attr/colorOnSurface"
|
||||
android:textSize="15sp"
|
||||
tools:text="15" />
|
||||
|
@ -11,7 +11,6 @@
|
||||
android:id="@+id/upper_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:textAppearance="?attr/textAppearanceTitleMedium"
|
||||
tools:text="Top" />
|
||||
|
||||
@ -19,7 +18,7 @@
|
||||
android:id="@+id/warning"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<ImageView
|
||||
@ -44,6 +43,7 @@
|
||||
android:id="@+id/lower_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:textAppearance="?attr/textAppearanceTitleMedium"
|
||||
tools:text="Bottom" />
|
||||
|
||||
|
@ -31,4 +31,9 @@
|
||||
android:title="@string/action_open_in_browser"
|
||||
app:showAsAction="never" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_clear_cookies"
|
||||
android:title="@string/pref_clear_cookies"
|
||||
app:showAsAction="never" />
|
||||
|
||||
</menu>
|
||||
|
@ -250,7 +250,7 @@
|
||||
<string name="secure_screen_summary">Ocultar contenido de la aplicación al cambiar entre aplicaciones y bloquear las capturas de pantalla</string>
|
||||
<string name="secure_screen">Pantalla segura</string>
|
||||
<plurals name="lock_after_mins">
|
||||
<item quantity="one">Después de 1 minuto</item>
|
||||
<item quantity="one">Después de %1$s minuto</item>
|
||||
<item quantity="other">Después de %1$s minutos</item>
|
||||
</plurals>
|
||||
<string name="lock_never">Nunca</string>
|
||||
@ -364,7 +364,7 @@
|
||||
<string name="username">Nombre de usuario</string>
|
||||
<string name="login_title">Iniciar sesión en %1$s</string>
|
||||
<plurals name="download_queue_summary">
|
||||
<item quantity="one">Queda 1</item>
|
||||
<item quantity="one">Queda %1$s</item>
|
||||
<item quantity="other">Quedan %1$s</item>
|
||||
</plurals>
|
||||
<string name="downloaded_only_summary">Filtrar todo el manga en tu libreria</string>
|
||||
@ -416,7 +416,7 @@
|
||||
\n\"%1$s\"</string>
|
||||
<string name="delete_downloads_for_manga">¿Eliminar capítulos descargados\?</string>
|
||||
<plurals name="manga_num_chapters">
|
||||
<item quantity="one">1 capítulo</item>
|
||||
<item quantity="one">%1$s capítulo</item>
|
||||
<item quantity="other">%1$s capítulos</item>
|
||||
</plurals>
|
||||
<string name="manga_info_collapse">Menos</string>
|
||||
@ -448,11 +448,11 @@
|
||||
<string name="notification_chapters_single_and_more">Capítulo %1$s y %2$d más</string>
|
||||
<string name="notification_chapters_single">Capítulo %1$s</string>
|
||||
<plurals name="notification_chapters_generic">
|
||||
<item quantity="one">1 nuevo capítulo</item>
|
||||
<item quantity="one">%1$d nuevo capítulo</item>
|
||||
<item quantity="other">%1$d nuevos capítulos</item>
|
||||
</plurals>
|
||||
<plurals name="notification_new_chapters_summary">
|
||||
<item quantity="one">Para 1 título</item>
|
||||
<item quantity="one">Para %d título</item>
|
||||
<item quantity="other">Para %d títulos</item>
|
||||
</plurals>
|
||||
<string name="notification_new_chapters">Nuevos capítulos encontrados</string>
|
||||
@ -504,7 +504,7 @@
|
||||
<string name="pref_category_reading_mode">Modo de lectura</string>
|
||||
<string name="pref_category_theme">Tema</string>
|
||||
<plurals name="num_trackers">
|
||||
<item quantity="one">1 rastreador</item>
|
||||
<item quantity="one">%d rastreador</item>
|
||||
<item quantity="other">%d rastreadores</item>
|
||||
</plurals>
|
||||
<string name="channel_errors">Errores</string>
|
||||
@ -519,7 +519,7 @@
|
||||
<string name="ext_nsfw_short">18+</string>
|
||||
<string name="parental_controls_info">Esto no evita que las extensiones no oficiales o potencialmente marcadas incorrectamente muestren contenido para mayores de 18 años dentro de la aplicación.</string>
|
||||
<plurals name="missing_chapters_warning">
|
||||
<item quantity="one">Omitiendo 1 capítulo, o la fuente no lo encuentra o se ha filtrado</item>
|
||||
<item quantity="one">Omitiendo %d capítulo, o la fuente no lo encuentra o se ha filtrado</item>
|
||||
<item quantity="other">Omitiendo %d capítulos, o la fuente no los encuentra o se han filtrado</item>
|
||||
</plurals>
|
||||
<string name="share_page_info">%1$s: %2$s, página %3$d</string>
|
||||
@ -714,4 +714,5 @@
|
||||
<string name="notification_update_skipped">%1$d actualización(es) omitida(s)</string>
|
||||
<string name="rotation_reverse_portrait">Retrato inverso</string>
|
||||
<string name="action_move_to_top_all_for_series">Mover la serie al principio</string>
|
||||
<string name="disabled_nav">Desactivado</string>
|
||||
</resources>
|
@ -441,7 +441,7 @@
|
||||
<string name="ext_updates_pending">Налични ъпдейти</string>
|
||||
<string name="pref_category_display">Показване</string>
|
||||
<string name="hide_notification_content">Скривай съдържанието на уведомленията</string>
|
||||
<string name="secure_screen_summary">Скрий съдържанието на приложението и блокирай скрийншотове</string>
|
||||
<string name="secure_screen_summary">Скрий съдържанието на приложението и блокирай снимките на екрана</string>
|
||||
<plurals name="lock_after_mins">
|
||||
<item quantity="one">След 1 минута</item>
|
||||
<item quantity="other">След %1$s минути</item>
|
||||
@ -723,4 +723,7 @@
|
||||
<string name="connected_to_wifi">Само през Wi-Fi</string>
|
||||
<string name="download_queue_size_warning">Предупреждение: големите масови изтегляния могат да доведат до забавяне на източниците и/или блокиране на Tachiyomi</string>
|
||||
<string name="action_filter_started">Започнати</string>
|
||||
<string name="action_show_manga">Покажи манга</string>
|
||||
<string name="action_faq_and_guides">Често задавани въпроси и ръководства</string>
|
||||
<string name="action_display_cover_only_grid">Решетка само с корици</string>
|
||||
</resources>
|
@ -708,10 +708,11 @@
|
||||
<string name="skipped_reason_completed">S\'ha omès perquè la sèrie està completada</string>
|
||||
<string name="skipped_reason_not_started">S\'ha omès perquè no hi ha cap capítol llegit</string>
|
||||
<string name="skipped_reason_not_caught_up">S\'ha omès perquè hi ha capítols no llegits</string>
|
||||
<string name="learn_more">Més informació</string>
|
||||
<string name="learn_more">Premeu per a obtenir més informació</string>
|
||||
<string name="channel_skipped">Omesa</string>
|
||||
<string name="notification_update_error">Han fallat %1$d actualitzacions</string>
|
||||
<string name="notification_update_skipped">S\'han omès %1$d actualitzacions</string>
|
||||
<string name="rotation_reverse_portrait">Vertical inversa</string>
|
||||
<string name="action_move_to_top_all_for_series">Mou la sèrie a dalt de tot</string>
|
||||
<string name="disabled_nav">Desactivat</string>
|
||||
</resources>
|
@ -723,4 +723,5 @@
|
||||
<string name="learn_more">Zjistit více</string>
|
||||
<string name="skipped_reason_not_started">Přeskočeno, protože nebyly přečteny žádné kapitoly</string>
|
||||
<string name="skipped_reason_completed">Přeskočeno, protože série je dokončena</string>
|
||||
<string name="disabled_nav">Zakázáno</string>
|
||||
</resources>
|
@ -6,7 +6,7 @@
|
||||
<string name="chapters">Kapitel</string>
|
||||
<string name="history">Verlauf</string>
|
||||
<string name="label_settings">Einstellungen</string>
|
||||
<string name="label_download_queue">Downloadwarteschlange</string>
|
||||
<string name="label_download_queue">Download-Warteschlange</string>
|
||||
<string name="label_library">Bibliothek</string>
|
||||
<string name="label_recent_manga">Verlauf</string>
|
||||
<string name="label_backup">Sichern und Wiederherstellen</string>
|
||||
@ -80,7 +80,7 @@
|
||||
<string name="all">Alle</string>
|
||||
<string name="pref_library_update_restriction">Geräteeinschränkungen für automatische Aktualisierungen</string>
|
||||
<string name="charging">Am Laden</string>
|
||||
<string name="pref_update_only_non_completed">Ist abgeschlossene Serie</string>
|
||||
<string name="pref_update_only_non_completed">Mit dem Status „Abgeschlossen“</string>
|
||||
<string name="pref_auto_update_manga_sync">Fortschritt nach dem Lesen aktualisieren</string>
|
||||
<string name="pref_start_screen">Startbildschirm</string>
|
||||
<string name="default_category">Standardkategorie</string>
|
||||
@ -128,7 +128,7 @@
|
||||
<string name="pref_remove_after_read">Automatisch nach dem Lesen löschen</string>
|
||||
<string name="custom_dir">Eigener Speicherort</string>
|
||||
<string name="disabled">Deaktiviert</string>
|
||||
<string name="last_read_chapter">ab zuletzt gelesenem Kapitel</string>
|
||||
<string name="last_read_chapter">Ab zuletzt gelesenem Kapitel</string>
|
||||
<string name="second_to_last">Ab zweitletzt gelesenem Kapitel</string>
|
||||
<string name="third_to_last">Ab drittletzt gelesenem Kapitel</string>
|
||||
<string name="fourth_to_last">Ab viertletzt gelesenem Kapitel</string>
|
||||
@ -673,7 +673,7 @@
|
||||
<string name="pref_verbose_logging_summary">Ausführliche Protokolle im Systemprotokoll ausgeben (verringert die Anwendungsleistung)</string>
|
||||
<string name="action_display_language_badge">Sprache</string>
|
||||
<string name="label_warning">Warnung</string>
|
||||
<string name="notification_size_warning">Achtung: Große Aktualisierungen schaden Quellen und könnten zu langsameren Aktualisierungen sowie höherem Akkuverbrauch führen</string>
|
||||
<string name="notification_size_warning">Große Aktualisierungen schaden Quellen und könnten zu langsameren Aktualisierungen sowie höherem Akkuverbrauch führen</string>
|
||||
<string name="backup_info">Automatische Sicherungen sind sehr zu empfehlen. Du solltest auch Kopien an anderen Orten aufbewahren.</string>
|
||||
<string name="connected_to_wifi">Nur über WLAN</string>
|
||||
<string name="update_72hour">Alle 3 Tage</string>
|
||||
@ -686,8 +686,8 @@
|
||||
<string name="database_clean">Datenbank bereinigt</string>
|
||||
<string name="extension_api_error">Herunterladen der Erweiterungsliste ist fehlgeschlagen</string>
|
||||
<string name="privacy_policy">Datenschutzbestimmungen</string>
|
||||
<string name="pref_update_only_completely_read">Hat ungelesene Kapitel</string>
|
||||
<string name="pref_library_update_manga_restriction">Aktualisierung überspringen</string>
|
||||
<string name="pref_update_only_completely_read">Mit ungelesenen Kapiteln</string>
|
||||
<string name="pref_library_update_manga_restriction">Aktualisierung der Titel überspringen</string>
|
||||
<string name="library_errors_help">Für Hilfe zum Beheben von Fehlern bei Bibliotheksaktualisierungen, siehe %1$s</string>
|
||||
<string name="save_chapter_as_cbz">Als CBZ-Archiv speichern</string>
|
||||
<string name="cancelled">Abgebrochen</string>
|
||||
@ -704,15 +704,17 @@
|
||||
<string name="pref_landscape_zoom">Bild im Querformat vergrößern</string>
|
||||
<string name="pref_navigate_pan">Innerhalb der Seite navigieren</string>
|
||||
<string name="action_filter_started">Angefangen</string>
|
||||
<string name="pref_update_only_started">Keine gelesenen Kapitel</string>
|
||||
<string name="pref_update_only_started">Die noch nicht begonnen wurden</string>
|
||||
<string name="skipped_reason_completed">Übersprungen, da die Serie abgeschlossen ist</string>
|
||||
<string name="skipped_reason_not_caught_up">Übersprungen, weil es ungelesene Kapitel gibt</string>
|
||||
<string name="skipped_reason_not_started">Übersprungen, weil keine Kapitel gelesen wurden</string>
|
||||
<string name="notification_update_error">%1$d Aktualisierung(en) fehlgeschlagen</string>
|
||||
<string name="notification_update_skipped">%1$d Aktualisierung(en) übersprungen</string>
|
||||
<string name="channel_skipped">Übersprungen</string>
|
||||
<string name="learn_more">Mehr erfahren</string>
|
||||
<string name="learn_more">Antippen, um mehr zu erfahren</string>
|
||||
<string name="rotation_reverse_portrait">Umgekehrtes Hochformat</string>
|
||||
<string name="action_move_to_top_all_for_series">Serie nach oben verschieben</string>
|
||||
<string name="disabled_nav">Deaktiviert</string>
|
||||
<string name="error_saving_picture">Fehler beim Speichern des Bildes</string>
|
||||
<string name="update_check_fdroid_migration_info">Eine neue Version ist aus dem offiziellen Repository verfügbar. Tippe, um zu erfahren, wie man aus inoffiziellen F-Droid-Versionen migriert.</string>
|
||||
</resources>
|
@ -87,7 +87,7 @@
|
||||
<string name="all">Όλα</string>
|
||||
<string name="pref_library_update_restriction">Περιορισμοί αυτόματων ενημερώσεων συσκευής</string>
|
||||
<string name="charging">Φορτίζει</string>
|
||||
<string name="pref_update_only_non_completed">Ολοκληρωμένη σειρά</string>
|
||||
<string name="pref_update_only_non_completed">Με κατάσταση \"Ολοκληρωμένο\"</string>
|
||||
<string name="pref_auto_update_manga_sync">Ενημέρωση προόδου μετά την ανάγνωση</string>
|
||||
<string name="pref_start_screen">Οθόνη εκκίνησης</string>
|
||||
<string name="default_category">Προεπιλεγμένη κατηγορία</string>
|
||||
@ -686,8 +686,8 @@
|
||||
<string name="database_clean">Καθαρισμός βάσης δεδομένων</string>
|
||||
<string name="extension_api_error">Απέτυχε η λήψη λίστας επεκτάσεων</string>
|
||||
<string name="privacy_policy">Πολιτική απορρήτου</string>
|
||||
<string name="pref_library_update_manga_restriction">Παράλειψη ενημέρωσης</string>
|
||||
<string name="pref_update_only_completely_read">Έχει αδιάβαστα κεφάλαια</string>
|
||||
<string name="pref_library_update_manga_restriction">Παράλειψη ενημέρωσης τίτλων</string>
|
||||
<string name="pref_update_only_completely_read">Με αδιάβαστο(α) κεφάλαιο(α)</string>
|
||||
<string name="library_errors_help">Για βοήθεια σχετικά με τον τρόπο διόρθωσης σφαλμάτων ενημέρωσης βιβλιοθήκης, ανατρέξτε στο %1$s</string>
|
||||
<string name="save_chapter_as_cbz">Αποθήκευση ως αρχείο CBZ</string>
|
||||
<string name="cancelled">Ακυρώθηκε</string>
|
||||
@ -703,16 +703,18 @@
|
||||
\nΘέλετε ακόμα να συνεχίσετε;</string>
|
||||
<string name="action_display_cover_only_grid">Πλέγμα μόνο με εξώφυλλα</string>
|
||||
<string name="action_filter_started">Ξεκίνησε</string>
|
||||
<string name="pref_update_only_started">Δεν έχει διαβασμένα κεφάλαια</string>
|
||||
<string name="pref_update_only_started">Που δεν έχουν ξεκινήσει</string>
|
||||
<string name="pref_navigate_pan">Πλοήγηση για οριζόντια μετακίνηση</string>
|
||||
<string name="skipped_reason_completed">Παραλείφθηκε επειδή η σειρά ολοκληρώθηκε</string>
|
||||
<string name="skipped_reason_not_caught_up">Παραβλέφθηκε επειδή υπάρχουν μη αναγνωσμένα κεφάλαια</string>
|
||||
<string name="skipped_reason_not_started">Παραλείπεται επειδή δεν έχουν διαβαστεί κεφάλαια</string>
|
||||
<string name="notification_update_error">%1$d ενημέρωση(ες) απέτυχε(-αν)</string>
|
||||
<string name="learn_more">Μάθετε περισσότερα</string>
|
||||
<string name="learn_more">Πατήστε για να μάθετε περισσότερα</string>
|
||||
<string name="channel_skipped">Παραλήφθηκαν</string>
|
||||
<string name="notification_update_skipped">%1$d ενημέρωση(εις) παραλείφθηκε(-αν)</string>
|
||||
<string name="rotation_reverse_portrait">Αντίστροφο πορτρέτο</string>
|
||||
<string name="action_move_to_top_all_for_series">Μετακίνηση σειράς στην κορυφή</string>
|
||||
<string name="disabled_nav">Απενεργοποιημένο</string>
|
||||
<string name="update_check_fdroid_migration_info">Μια νέα έκδοση είναι διαθέσιμη από τις επίσημες κυκλοφορίες. Πατήστε για να μάθετε πώς να μεταβείτε από ανεπίσημες κυκλοφορίες του F-Droid.</string>
|
||||
<string name="error_saving_picture">Σφάλμα κατά την αποθήκευση της εικόνας</string>
|
||||
</resources>
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="name">Nombre</string>
|
||||
<string name="name">Español</string>
|
||||
<!-- Activities and fragments labels (toolbar title) -->
|
||||
<string name="label_settings">Ajustes</string>
|
||||
<string name="label_download_queue">Cola de descargas</string>
|
||||
@ -63,7 +63,7 @@
|
||||
<string name="update_48hour">Cada 2 días</string>
|
||||
<string name="pref_library_update_restriction">Restricciones de actualización automática del dispositivo</string>
|
||||
<string name="charging">Mientras se carga la batería</string>
|
||||
<string name="pref_update_only_non_completed">Serie completada</string>
|
||||
<string name="pref_update_only_non_completed">Series completadas</string>
|
||||
<string name="pref_auto_update_manga_sync">Actualizar progreso al terminar un capítulo</string>
|
||||
<!-- Reader section -->
|
||||
<string name="pref_fullscreen">Pantalla completa</string>
|
||||
@ -644,7 +644,7 @@
|
||||
<string name="information_empty_category_dialog">Todavía no existen categorías.</string>
|
||||
<string name="notification_updating">Actualizando biblioteca… (%1$d/%2$d)</string>
|
||||
<string name="error_no_match">No se han encontrado coincidencias</string>
|
||||
<string name="source_unsupported">No se admite el origen</string>
|
||||
<string name="source_unsupported">Fuente no soportada</string>
|
||||
<string name="unread">No leídos</string>
|
||||
<string name="tracker_komga_warning">Este servicio de seguimiento sólo es compatible con la fuente Komga.</string>
|
||||
<string name="error_sharing_cover">Error al compartir portada</string>
|
||||
@ -703,7 +703,7 @@
|
||||
<string name="pref_verbose_logging">Registro detallado</string>
|
||||
<string name="pref_verbose_logging_summary">Mostrar registros detallados en el registro del sistema (reduce el rendimiento de la aplicación)</string>
|
||||
<string name="label_warning">Advertencia</string>
|
||||
<string name="notification_size_warning">Cuidado: las actualizaciones grandes pueden implicar un mayor uso de la batería y que los distintos servicios bloqueen o ralenticen el acceso a tu dispositivo</string>
|
||||
<string name="notification_size_warning">Las actualizaciones grandes pueden implicar un mayor uso de la batería y que los distintos servicios bloqueen o ralenticen el acceso a tu dispositivo</string>
|
||||
<string name="action_display_language_badge">Idioma</string>
|
||||
<string name="backup_info">Es una buena idea tener copias de respaldo automáticas, así como respaldarlas fuera de tu dispositivo.</string>
|
||||
<string name="connected_to_wifi">Solo con Wi-Fi</string>
|
||||
@ -717,8 +717,8 @@
|
||||
<string name="clear_database_source_item_count">Hay %1$d manga que no pertenece a la biblioteca en la base de datos</string>
|
||||
<string name="extension_api_error">No se pudo descargar el listado de extensiones</string>
|
||||
<string name="privacy_policy">Política de privacidad</string>
|
||||
<string name="pref_update_only_completely_read">Capítulos sin leer</string>
|
||||
<string name="pref_library_update_manga_restriction">Omitir la actualización</string>
|
||||
<string name="pref_update_only_completely_read">Con capítulos sin leer</string>
|
||||
<string name="pref_library_update_manga_restriction">Omitir actualizaciones</string>
|
||||
<string name="library_errors_help">Si necesitas ayuda para resolver los errores de actualización de la biblioteca mira en %1$s</string>
|
||||
<string name="save_chapter_as_cbz">Guardar como archivo CBZ</string>
|
||||
<string name="on_hiatus">En pausa</string>
|
||||
@ -735,15 +735,17 @@
|
||||
\n
|
||||
\n¿Quieres seguir\?</string>
|
||||
<string name="action_filter_started">Empezados</string>
|
||||
<string name="pref_update_only_started">Sin capítulos leídos</string>
|
||||
<string name="pref_update_only_started">Series sin empezar</string>
|
||||
<string name="skipped_reason_completed">Omitido porque la serie está completa</string>
|
||||
<string name="skipped_reason_not_caught_up">Omitido porque hay capítulos sin leer</string>
|
||||
<string name="skipped_reason_not_started">Omitido porque no hay capítulos leídos</string>
|
||||
<string name="learn_more">Más información</string>
|
||||
<string name="learn_more">Ver más detalles</string>
|
||||
<string name="channel_skipped">Omitidas</string>
|
||||
<string name="notification_update_error">Actualizaciones fallidas: %1$d</string>
|
||||
<string name="notification_update_skipped">Actualizaciones omitidas: %1$d</string>
|
||||
<string name="rotation_reverse_portrait">En vertical, al revés</string>
|
||||
<string name="action_move_to_top_all_for_series">Mover al primer puesto</string>
|
||||
<string name="disabled_nav">Desactivado</string>
|
||||
<string name="update_check_fdroid_migration_info">Hay una actualización disponible en la página oficial. Toca para aprender a migrar desde una versión no oficial de F-Droid.</string>
|
||||
<string name="error_saving_picture">No se ha podido guardar la imagen</string>
|
||||
</resources>
|
@ -62,7 +62,7 @@
|
||||
<string name="information_no_downloads">Ei latauksia</string>
|
||||
<string name="information_no_recent">Ei viimeisimpiä päivityksiä</string>
|
||||
<string name="information_no_recent_manga">Ei mitään luettu viime aikoina</string>
|
||||
<string name="information_empty_library">Kirjastosi on tyhjä. Lisää sarjoja kirjastoosi Selaa-kohdasta.</string>
|
||||
<string name="information_empty_library">Kirjastosi on tyhjä.</string>
|
||||
<string name="information_empty_category">Sinulla ei ole kategorioita. Napauta pluspainiketta, jos haluat luoda sellaisen kirjaston järjestämistä varten.</string>
|
||||
<string name="download_notifier_downloader_title">Lataaja</string>
|
||||
<string name="download_notifier_title_error">Virhe</string>
|
||||
@ -104,7 +104,7 @@
|
||||
<string name="action_display">Näkymä</string>
|
||||
<string name="action_display_grid">Kompakti ruudukko</string>
|
||||
<string name="action_display_list">Lista</string>
|
||||
<string name="action_display_download_badge">Näytä ladattujen määrä</string>
|
||||
<string name="action_display_download_badge">Ladatut luvut</string>
|
||||
<string name="action_cancel">Peruuta</string>
|
||||
<string name="action_sort">Järjestä</string>
|
||||
<string name="action_install">Asenna</string>
|
||||
@ -125,17 +125,17 @@
|
||||
<string name="pref_library_columns">Kohteita per rivi</string>
|
||||
<string name="portrait">Pystysuunta</string>
|
||||
<string name="landscape">Vaakataso</string>
|
||||
<string name="pref_library_update_interval">Päivitystiheys</string>
|
||||
<string name="update_never">Manuaalinen</string>
|
||||
<string name="pref_library_update_interval">Automaattinen päivitys</string>
|
||||
<string name="update_never">Pois</string>
|
||||
<string name="update_6hour">Kuuden tunnin välein</string>
|
||||
<string name="update_12hour">12 tunnin välein</string>
|
||||
<string name="update_24hour">Päivittäin</string>
|
||||
<string name="update_48hour">Kahden päivän välein</string>
|
||||
<string name="update_weekly">Viikoittain</string>
|
||||
<string name="all">Kaikki</string>
|
||||
<string name="pref_library_update_restriction">Päivityksen rajoitukset</string>
|
||||
<string name="pref_library_update_restriction">Automaattisen päivityksen laitteistorajoitukset</string>
|
||||
<string name="charging">Latauksessa</string>
|
||||
<string name="pref_update_only_non_completed">Päivitä vain jatkuvat sarjat</string>
|
||||
<string name="pref_update_only_non_completed">Sarja on päättynyt</string>
|
||||
<string name="pref_auto_update_manga_sync">Päivitä luvun edistyminen lukemisen jälkeen</string>
|
||||
<string name="pref_start_screen">Aloitusnäyttö</string>
|
||||
<string name="default_category">Oletus kategoria</string>
|
||||
@ -372,7 +372,7 @@
|
||||
<string name="notification_check_updates">Etsitään uusia lukuja</string>
|
||||
<string name="lock_when_idle">Lukitse käyttämättömänä</string>
|
||||
<string name="secure_screen">Salaa näyttö</string>
|
||||
<string name="secure_screen_summary">Piilota sovelluksen sisältö kun sovelluksia vaihdetaan ja estä kuvakaappauksien otto</string>
|
||||
<string name="secure_screen_summary">Turvallinen ruutu piilottaa sovelluksen sisällön sovelluksia vaihdettaessa ja estää kuvakaappauksen ottamisen</string>
|
||||
<string name="pref_disable_battery_optimization">Poista akun optimointi käytöstä</string>
|
||||
<string name="pref_disable_battery_optimization_summary">Auttaa taustalla pyörivien kirjaston päivitysten ja varmuuskopioiden kanssa</string>
|
||||
<string name="battery_optimization_disabled">Akun optimointi on jo poistettu käytöstä</string>
|
||||
@ -451,7 +451,7 @@
|
||||
<item quantity="other">Valmistui %1$s virheitä löytyi %2$s</item>
|
||||
</plurals>
|
||||
<string name="pref_true_color_summary">Vähentää juovia, mutta vaikuttaa suorituskykyyn</string>
|
||||
<string name="action_display_unread_badge">Näytä lukemattomien määrä</string>
|
||||
<string name="action_display_unread_badge">Lukemattomat</string>
|
||||
<string name="viewer">Lukutila</string>
|
||||
<string name="battery_optimization_setting_activity_not_found">Laiteasetuksia ei voitu avata</string>
|
||||
<string name="tracking_info">Yksisuuntainen synkronointi lukujen seurantapalveluiden päivittämiseksi. Määritä yksittäisten mangamerkintöjen seuranta seurantapainikkeesta.</string>
|
||||
@ -542,7 +542,7 @@
|
||||
<string name="spen_previous_page">Edellinen sivu</string>
|
||||
<string name="migration_help_guide">Lähteen siirto-opas</string>
|
||||
<string name="pref_category_nsfw_content">NSFW (18+) lähteet</string>
|
||||
<string name="pref_show_nsfw_source">Näytä lähdeluettelossa</string>
|
||||
<string name="pref_show_nsfw_source">Näytä lähde- ja lisäosaluettelossa</string>
|
||||
<string name="file_picker_error">Tiedostonvalitsinsovellusta ei löytynyt</string>
|
||||
<string name="myanimelist_relogin">Kirjaudu uudelleen MAL: iin</string>
|
||||
<string name="pref_viewer_nav">Navigointiasettelu</string>
|
||||
@ -582,7 +582,7 @@
|
||||
<string name="pref_download_new_categories_details">Poissuljettuihin kategorioihin kuuluvia mangoja ei ladata, vaikka ne olisivat myös sisällytetyissä kategorioissa.</string>
|
||||
<string name="pref_category_auto_download">Automaattinen lataus</string>
|
||||
<string name="pref_library_update_categories_details">Poissuljettuihin kategorioihin sisältyvää mangaa ei päivitetä, vaikka ne olisivat myös sisällytetyissä kategorioissa.</string>
|
||||
<string name="action_show_errors">Näytä virheet</string>
|
||||
<string name="action_show_errors">Näytä lisätiedot</string>
|
||||
<string name="update_check_eol">Tätä Android-versiota ei enää tueta</string>
|
||||
<string name="clipboard_copy_error">Kopiointi leikepöydälle epäonnistui</string>
|
||||
<string name="rotation_landscape">Vaakatasossa</string>
|
||||
@ -606,4 +606,63 @@
|
||||
<string name="on">Päällä</string>
|
||||
<string name="getting_started_guide">Aloitusopas</string>
|
||||
<string name="download_queue_size_warning">Varoitus: massalataukset voivat johtaa siihen, että lähteet muuttuvat hitaammiksi käyttää ja/tai ne estävät Tachiyomin käytön</string>
|
||||
<string name="pref_library_update_show_tab_badge">Näytä lukemattomien määrä päivitys ikoneissa</string>
|
||||
<string name="alignment_center">Keskimmäinen</string>
|
||||
<string name="pref_library_update_refresh_trackers_summary">Päivitä seurantapalvelimet kirjaston päivityksen yhteydessä</string>
|
||||
<plurals name="relative_time">
|
||||
<item quantity="one">Eilen</item>
|
||||
<item quantity="other">%1$d päivää sitten</item>
|
||||
</plurals>
|
||||
<string name="action_show_manga">Näytä manga</string>
|
||||
<string name="action_display_cover_only_grid">Kansikuva ruudukko</string>
|
||||
<string name="theme_monet">Dynaaminen</string>
|
||||
<string name="theme_greenapple">Vihreä omena</string>
|
||||
<string name="alignment_bottom">Alin</string>
|
||||
<string name="recently">Viimeaikoina</string>
|
||||
<string name="label_default">Oletus</string>
|
||||
<string name="action_filter_started">Aloitettu</string>
|
||||
<string name="action_display_local_badge">Laitteelle tallennettu manga</string>
|
||||
<string name="pref_library_update_refresh_trackers">Päivitä seurantapalvelimet automaattisesti</string>
|
||||
<string name="action_sort_count">Yhteenlaskettu manga</string>
|
||||
<string name="action_start_downloading_now">Aloita lataaminen nyt</string>
|
||||
<string name="theme_yinyang">Ying ja Yang</string>
|
||||
<string name="theme_midnightdusk">Keskiyön hämärä</string>
|
||||
<string name="theme_strawberrydaiquiri">Mansikka Daiquiri</string>
|
||||
<string name="pref_category_appearance">Ulkonäkö</string>
|
||||
<string name="theme_tealturquoise">Sinivihreä ja turkoosi</string>
|
||||
<string name="theme_yotsuba">Yotsuba</string>
|
||||
<string name="alignment_top">Päällimmäinen</string>
|
||||
<string name="pref_side_nav_icon_alignment">Sivunavigaation kuvakkeiden kohdistus</string>
|
||||
<string name="pref_dark_theme_pure_black">Täysin musta pimeätila</string>
|
||||
<string name="pref_category_navigation">Navigaatio</string>
|
||||
<string name="pref_update_only_started">Ei lukemattomia lukuja</string>
|
||||
<string name="pref_relative_format">Suhteelliset aikamerkit</string>
|
||||
<string name="pref_relative_time_short">Lyhyt (tänään, eilen)</string>
|
||||
<string name="pref_relative_time_long">Pitkä (lyhyt+, N päivää sitten)</string>
|
||||
<string name="relative_time_today">Tänään</string>
|
||||
<string name="pref_update_only_completely_read">Sarjalla on lukemattomia kappaleita</string>
|
||||
<string name="pref_app_theme">Sovelluksen teema</string>
|
||||
<string name="label_warning">Varoitus</string>
|
||||
<string name="confirm_lock_change">Tunnistaudu vahvistaaksesi muutokset</string>
|
||||
<string name="action_display_language_badge">Kieli</string>
|
||||
<string name="pref_category_timestamps">Aikaleimat</string>
|
||||
<string name="action_faq_and_guides">Usein kysytyt kysymykset ja oppaat</string>
|
||||
<string name="pref_library_update_manga_restriction">Ohita päivitys</string>
|
||||
<string name="action_move_to_top_all_for_series">Siirrä sarja päällimmäiseksi</string>
|
||||
<string name="theme_tako">Tako</string>
|
||||
<string name="update_72hour">Joka 3. Päivä</string>
|
||||
<string name="connected_to_wifi">Ainoastaan WiFillä</string>
|
||||
<string name="pref_inverted_colors">Käänteisväri</string>
|
||||
<string name="webtoon_side_padding_5">5%</string>
|
||||
<string name="ext_app_info">Sovelluksen tiedot</string>
|
||||
<string name="ext_installer_legacy">Perinteinen</string>
|
||||
<string name="rotation_reverse_portrait">Käänteinen kuva</string>
|
||||
<string name="categorized_display_settings">Kategoria kohtaiset asetukset lajittelulle ja näytölle</string>
|
||||
<string name="ext_installer_shizuku_stopped">Shizuku on pysähtynyt</string>
|
||||
<string name="disabled_nav">Poistettu käytöstä</string>
|
||||
<string name="ext_installer_shizuku_unavailable_dialog">Asenna ja aja Shizuku käyttääksesi Shizukua laajennusten asentamiseen</string>
|
||||
<string name="ext_update_all">Päivitä kaikki</string>
|
||||
<string name="extension_api_error">Laajennusluettelon halu epäonnistui</string>
|
||||
<string name="ext_install_service_notif">Asennetaan laajennusta…</string>
|
||||
<string name="ext_installer_pref">Asentaja</string>
|
||||
</resources>
|
@ -520,7 +520,7 @@
|
||||
<string name="ext_nsfw_short">18+</string>
|
||||
<plurals name="missing_chapters_warning">
|
||||
<item quantity="one">Lalaktawan ang %d kabanata, siguro baka wala sa source ito, o baka nasala ito</item>
|
||||
<item quantity="other">Lalaktawan ang %d (na) kabanata, siguro baka wala sa source sila, o baka nasala sila</item>
|
||||
<item quantity="other">Lalaktawan ang %d (na) kabanata, siguro baka sa source ang mga ito, o baka nasala sila</item>
|
||||
</plurals>
|
||||
<string name="no_chapters_error">Walang nakitang kabanata</string>
|
||||
<string name="confirm_set_chapter_settings">Gusto mo bang i-save at ipagpaubaya ang pagsasaayos na ito\?</string>
|
||||
@ -604,7 +604,7 @@
|
||||
<string name="local_invalid_format">Walang bisa ang ayos ng kabanata</string>
|
||||
<string name="chapter_not_found">Hindi makita ang kabanata</string>
|
||||
<string name="source_unsupported">Di suportado ang source</string>
|
||||
<string name="unread">Hindi basahin</string>
|
||||
<string name="unread">Hindi nababasa</string>
|
||||
<string name="alignment_center">Gitna</string>
|
||||
<string name="pref_side_nav_icon_alignment">Hilera ng nabigasyon sa gilid</string>
|
||||
<string name="error_sharing_cover">Di maibahagi ang cover</string>
|
||||
@ -690,7 +690,7 @@
|
||||
<string name="pref_update_only_completely_read">May hindi pa nabasang kabanata</string>
|
||||
<string name="pref_library_update_manga_restriction">Lakdawan ang pag-update</string>
|
||||
<string name="save_chapter_as_cbz">I-save bilang CBZ archive</string>
|
||||
<string name="publishing_finished">Tapos na\'ng mailathala</string>
|
||||
<string name="publishing_finished">Tapos nang mailathala</string>
|
||||
<string name="on_hiatus">Naka-hiatus</string>
|
||||
<string name="cancelled">Kinansela</string>
|
||||
<string name="backup_restore_invalid_uri">Error: walang URI</string>
|
||||
@ -714,4 +714,5 @@
|
||||
<string name="rotation_reverse_portrait">Baligtad na patayo</string>
|
||||
<string name="notification_update_skipped">Nilaktawan ang %1$d (na) update</string>
|
||||
<string name="action_move_to_top_all_for_series">Ilagay sa taas ang serye</string>
|
||||
<string name="disabled_nav">Nakasara</string>
|
||||
</resources>
|
@ -14,7 +14,7 @@
|
||||
<string name="action_filter_downloaded">Téléchargés</string>
|
||||
<string name="action_filter_bookmarked">Signets</string>
|
||||
<string name="action_filter_unread">Non lus</string>
|
||||
<string name="action_filter_empty">Enlever le filtre</string>
|
||||
<string name="action_filter_empty">Retirer le filtre</string>
|
||||
<string name="action_sort_alpha">Alphabétiquement</string>
|
||||
<string name="action_sort_last_read">Dernier lu</string>
|
||||
<string name="action_search">Rechercher</string>
|
||||
@ -748,4 +748,5 @@
|
||||
<string name="channel_skipped">Ignoré</string>
|
||||
<string name="rotation_reverse_portrait">Portrait inversé</string>
|
||||
<string name="action_move_to_top_all_for_series">Déplacer la série vers le haut</string>
|
||||
<string name="disabled_nav">Désactivé</string>
|
||||
</resources>
|
@ -264,38 +264,38 @@
|
||||
<string name="backup_choice">מה אתה רוצה לגבות\?</string>
|
||||
<string name="backup_restore_content">פעולת שחזור משתמשת במקורות בכדי להשיג נתונים, עלויות הספק עשויות לחול.
|
||||
\n
|
||||
\nוודא שהתקנת את כל התוספים הנחוצים והתחרת למקורות ושירותי המעקב לפני השחזור.</string>
|
||||
\nוודא שהתקנת את כל התוספים הנחוצים והתחברת למקורות ושירותי המעקב לפני השחזור.</string>
|
||||
<string name="restore_completed">השחזור הושלם</string>
|
||||
<string name="backup_created">גיבוי נוצר</string>
|
||||
<string name="pref_backup_slots">מספר גיבויים אוטומטיים מקסימליים</string>
|
||||
<string name="pref_backup_slots">מספר גיבויים מקסימלי</string>
|
||||
<string name="pref_backup_interval">תדירות גיבוי</string>
|
||||
<string name="pref_backup_service_category">שירות</string>
|
||||
<string name="pref_backup_service_category">גיבויים אוטומטיים</string>
|
||||
<string name="pref_backup_directory">מיקום גיבוי</string>
|
||||
<string name="pref_restore_backup_summ">שחזר ספרייה מקובץ גיבוי</string>
|
||||
<string name="pref_restore_backup">שחזור גיבוי</string>
|
||||
<string name="pref_create_backup_summ">ניתן לשימוש על מנת לשחזר את הספרייה הנוכחית</string>
|
||||
<string name="pref_create_backup">צור גיבוי</string>
|
||||
<string name="services">שירותים</string>
|
||||
<string name="pref_auto_update_manga_sync">סנכרן פרקים לאחר סיום קריאה</string>
|
||||
<string name="pref_download_new">הורד פרקים חדשים</string>
|
||||
<string name="fifth_to_last">פרק חמישי מהסוף</string>
|
||||
<string name="fourth_to_last">פרק רביעי מהסוף</string>
|
||||
<string name="third_to_last">פרק שלישי מהסוף</string>
|
||||
<string name="second_to_last">פרק שני מהסוף</string>
|
||||
<string name="pref_auto_update_manga_sync">עדכן התקדמות לאחר הקריאה</string>
|
||||
<string name="pref_download_new">הורדת פרקים חדשים</string>
|
||||
<string name="fifth_to_last">הפרק החמישי מהסוף שנקרא</string>
|
||||
<string name="fourth_to_last">הפרק הרביעי מהסוף שנקרא</string>
|
||||
<string name="third_to_last">הפרק השלישי מהסוף שנקרא</string>
|
||||
<string name="second_to_last">הפרק השני מהסוף שנקרא</string>
|
||||
<string name="last_read_chapter">פרק שנקרא בפעם האחרונה</string>
|
||||
<string name="custom_dir">מיקום מותאם אישית</string>
|
||||
<string name="pref_remove_after_read">הסר לאחר סיום קריאה</string>
|
||||
<string name="pref_remove_after_marked_as_read">הסר כאשר מסומן כנקרא</string>
|
||||
<string name="pref_remove_after_read">אוטומטי לאחר סיום הקריאה</string>
|
||||
<string name="pref_remove_after_marked_as_read">אחרי שמסומן ידנית כנקרא</string>
|
||||
<string name="pref_download_directory">מיקום הורדה</string>
|
||||
<string name="pref_always_show_chapter_transition">הצג תמיד מעברי פרקים</string>
|
||||
<string name="color_filter_a_value">אלפא</string>
|
||||
<string name="color_filter_b_value">כחול</string>
|
||||
<string name="color_filter_g_value">ירוק</string>
|
||||
<string name="color_filter_r_value">אדום</string>
|
||||
<string name="rotation_force_landscape">כפה מצב מאוזן</string>
|
||||
<string name="rotation_force_portrait">כפה מצב מאונך</string>
|
||||
<string name="rotation_force_landscape">מאוזן נעול</string>
|
||||
<string name="rotation_force_portrait">מאונך נעול</string>
|
||||
<string name="rotation_free">חופשי</string>
|
||||
<string name="pref_rotation_type">סיבוב</string>
|
||||
<string name="pref_rotation_type">ברירת המחדל של סוג הסיבוב</string>
|
||||
<string name="double_tap_anim_speed_fast">מהירה</string>
|
||||
<string name="double_tap_anim_speed_normal">רגילה</string>
|
||||
<string name="double_tap_anim_speed_0">בלי אנימציה</string>
|
||||
@ -315,7 +315,7 @@
|
||||
<string name="vertical_viewer">אנכי</string>
|
||||
<string name="right_to_left_viewer">ימין לשמאל</string>
|
||||
<string name="left_to_right_viewer">שמאל לימין</string>
|
||||
<string name="pref_viewer_type">מציג ברירת מחדל</string>
|
||||
<string name="pref_viewer_type">ברירת המחדל של מצב הקריאה</string>
|
||||
<string name="black_background">שחור</string>
|
||||
<string name="white_background">לבן</string>
|
||||
<string name="pref_reader_theme">צבע רקע</string>
|
||||
@ -327,15 +327,15 @@
|
||||
<string name="pref_keep_screen_on">השאר מסך דלוק</string>
|
||||
<string name="filter_mode_darken">שרוף / מוחשך</string>
|
||||
<string name="filter_mode_screen">מסך</string>
|
||||
<string name="pref_custom_color_filter">השתמש במסנן צבע מותאם אישית</string>
|
||||
<string name="pref_custom_brightness">השתמש בבהירות מותאמת אישית</string>
|
||||
<string name="pref_custom_color_filter">מסנן צבע מותאם אישית</string>
|
||||
<string name="pref_custom_brightness">בהירות מותאמת אישית</string>
|
||||
<string name="pref_crop_borders">חתוך גבולות</string>
|
||||
<string name="pref_true_color">צבע 32-סיביות</string>
|
||||
<string name="pref_show_page_number">הצג מספר עמוד</string>
|
||||
<string name="pref_double_tap_anim_speed">מהירות הנפשה בהקשה כפולה</string>
|
||||
<string name="pref_page_transitions">הנפשת מעברי דפים</string>
|
||||
<string name="pref_cutout_short">הצג תוכן באזור החתוך</string>
|
||||
<string name="pref_enable_automatic_extension_updates">בדוק אם קיימים עדכונים עבור תוספים</string>
|
||||
<string name="pref_enable_automatic_extension_updates">בדוק אם קיימים עדכוני הרחבות</string>
|
||||
<string name="untrusted_extension">תוסף לא מאומת</string>
|
||||
<string name="obsolete_extension_message">תוסף זה אינו זמין עוד.</string>
|
||||
<string name="pref_fullscreen">מסך מלא</string>
|
||||
@ -492,4 +492,63 @@
|
||||
<string name="update_72hour">כל 3 ימים</string>
|
||||
<string name="connected_to_wifi">רק ב Wi-Fi</string>
|
||||
<string name="restrictions">הגבלות: %s</string>
|
||||
<string name="pref_show_reading_mode_summary">הראה לזמן קצר את הסגנון כשהקראן נפתח</string>
|
||||
<string name="pref_read_with_tapping_inverted">לחיצה הופכית</string>
|
||||
<string name="off">כבוי</string>
|
||||
<string name="on">פעיל</string>
|
||||
<string name="pref_grayscale">טווח גווני האפור</string>
|
||||
<string name="pref_inverted_colors">הופכי</string>
|
||||
<string name="tapping_inverted_horizontal">אופקי</string>
|
||||
<string name="right_and_left_nav">ימין ושמאל</string>
|
||||
<string name="nav_zone_next">הבא</string>
|
||||
<string name="nav_zone_right">ימין</string>
|
||||
<string name="rotation_type">סוג הסיבוב</string>
|
||||
<string name="rotation_portrait">מאונך</string>
|
||||
<string name="rotation_landscape">מאוזן</string>
|
||||
<string name="webtoon_side_padding_5">5%</string>
|
||||
<string name="webtoon_side_padding_10">10%</string>
|
||||
<string name="webtoon_side_padding_15">15%</string>
|
||||
<string name="pref_hide_threshold">רגישות החבאת התפריט בגלילה</string>
|
||||
<string name="pref_highest">הכי גבוה</string>
|
||||
<string name="pref_high">גבוה</string>
|
||||
<string name="pref_low">נמוך</string>
|
||||
<string name="pref_lowest">הכי נמוך</string>
|
||||
<string name="pref_category_delete_chapters">מחק פרקים</string>
|
||||
<string name="pref_remove_exclude_categories">קטגוריות מוחרגות</string>
|
||||
<string name="pref_download_new_categories_details">מנגה הנמצאת בקטגוריית מנועי ההורדות לא תעודכן גם אם היא נכללת בקטגורייה אחרת שכן מורדת.</string>
|
||||
<string name="save_chapter_as_cbz">שמור כארכיון CBZ</string>
|
||||
<string name="enhanced_services">שירותים משופרים</string>
|
||||
<string name="edge_nav">גבול</string>
|
||||
<string name="l_nav">עשוי בצורת L</string>
|
||||
<string name="nav_zone_left">שמאל</string>
|
||||
<string name="nav_zone_prev">הקודם</string>
|
||||
<string name="pref_category_reading">קריאה</string>
|
||||
<string name="webtoon_side_padding_20">20%</string>
|
||||
<string name="webtoon_side_padding_25">25%</string>
|
||||
<string name="pref_category_reading_mode">מצב קריאה</string>
|
||||
<string name="webtoon_side_padding_0">ללא</string>
|
||||
<string name="pref_category_auto_download">הורדה אוטומטית</string>
|
||||
<string name="gray_background">אפור</string>
|
||||
<string name="vertical_plus_viewer">אנכי מתמשך</string>
|
||||
<string name="pager_viewer">עמודים</string>
|
||||
<string name="rotation_reverse_portrait">מאונך הפוך</string>
|
||||
<string name="pref_create_folder_per_manga">שמור דפים בתיקיות נפרדות</string>
|
||||
<string name="tapping_inverted_vertical">אנכי</string>
|
||||
<string name="tapping_inverted_both">שניהם</string>
|
||||
<string name="pref_reader_actions">פעולות</string>
|
||||
<string name="pref_read_with_long_tap">הראה בלחיצה ארוכה</string>
|
||||
<string name="automatic_background">אוטומטי</string>
|
||||
<string name="pref_remove_bookmarked_chapters">אפשר מחיקת פרקים שסומנו</string>
|
||||
<string name="disabled">לא מאופשר</string>
|
||||
<string name="pref_create_folder_per_manga_summary">צור תיקיות בהתאם לכותרת המנגה</string>
|
||||
<string name="enhanced_tracking_info">שירותים המספקים שירותים משופרים למקורות ספציפיים. מנגות יהיו במעקב אוטומטי אחרי הוספה לספרייה שלך.</string>
|
||||
<string name="backup_restore_missing_sources">מקורות חסרים:</string>
|
||||
<string name="invalid_backup_file">קובץ גיבוי לא תקין</string>
|
||||
<string name="invalid_backup_file_missing_data">חסרים נתונים בקובץ.</string>
|
||||
<string name="invalid_backup_file_missing_manga">הגיבוי לא מכיל שום מנגה.</string>
|
||||
<string name="pref_search_pinned_sources_only">כלול רק מקורות נעוצים</string>
|
||||
<string name="source_not_found_name">מקור לא נמצא: %1$s</string>
|
||||
<string name="tracker_not_logged_in">לא מחובר ל: %1$s</string>
|
||||
<string name="backup_restore_invalid_uri">שגיאה: URI ריק</string>
|
||||
<string name="action_track">מעקב</string>
|
||||
</resources>
|
@ -349,7 +349,7 @@
|
||||
<string name="lock_always">हमेशा</string>
|
||||
<string name="lock_never">कभी नहीँ</string>
|
||||
<plurals name="lock_after_mins">
|
||||
<item quantity="one">1 मिनट के बाद</item>
|
||||
<item quantity="one">%1$s मिनट के बाद</item>
|
||||
<item quantity="other">%1$s मिनट के बाद</item>
|
||||
</plurals>
|
||||
<string name="secure_screen">स्क्रीन सुरक्षित करें</string>
|
||||
@ -380,8 +380,8 @@
|
||||
<string name="email">ईमेल पता</string>
|
||||
<string name="pref_always_show_chapter_transition">हमेशा अध्याय संक्रमण दिखाएं</string>
|
||||
<plurals name="notification_new_chapters_summary">
|
||||
<item quantity="one">1 शीर्षक के लिए</item>
|
||||
<item quantity="other">%d शीर्षक के लिए</item>
|
||||
<item quantity="one">%d शीर्षक के लिए</item>
|
||||
<item quantity="other">%d शीर्षकों के लिए</item>
|
||||
</plurals>
|
||||
<string name="action_menu">मेन्यू</string>
|
||||
<string name="action_reorganize_by">पुनःक्रमित</string>
|
||||
@ -436,8 +436,8 @@
|
||||
<string name="restore_duration">%02d मिनट,%02d सेकंड</string>
|
||||
<string name="downloaded_only_summary">अपने पुस्तकालय में सभी मंगा फ़िल्टर करे</string>
|
||||
<plurals name="download_queue_summary">
|
||||
<item quantity="one">1 शेष</item>
|
||||
<item quantity="other">%1$s शेष</item>
|
||||
<item quantity="one">%1$s बचा हुआ</item>
|
||||
<item quantity="other">%1$s बचा हुआ</item>
|
||||
</plurals>
|
||||
<string name="pref_search_pinned_sources_only">केवल पिन किए गए स्रोत शामिल हैं</string>
|
||||
<string name="viewer">पढ़न मोड</string>
|
||||
@ -482,7 +482,7 @@
|
||||
<string name="action_disable">बंद करें</string>
|
||||
<string name="action_start">प्रारंभ</string>
|
||||
<plurals name="manga_num_chapters">
|
||||
<item quantity="one">1 अध्याय</item>
|
||||
<item quantity="one">%1$s अध्याय</item>
|
||||
<item quantity="other">%1$s अध्याय</item>
|
||||
</plurals>
|
||||
<string name="label_network">नेटवर्क</string>
|
||||
@ -504,7 +504,7 @@
|
||||
<string name="pref_category_theme">थीम</string>
|
||||
<string name="action_sort_date_added">तारीख को जोड़ा गया</string>
|
||||
<plurals name="num_trackers">
|
||||
<item quantity="one">1 ट्रैकर</item>
|
||||
<item quantity="one">%d ट्रैकर</item>
|
||||
<item quantity="other">%d ट्रैकरस</item>
|
||||
</plurals>
|
||||
<string name="no_pinned_sources">कोई पिन किया हुआ सोर्स नही है</string>
|
||||
@ -519,8 +519,8 @@
|
||||
<string name="ext_nsfw_short">18+</string>
|
||||
<string name="parental_controls_info">यह अनौपचारिक या संभावित रूप से फ़्लैग किए गए एक्सटेंशन को ऐप के भीतर NSFW (18+) सामग्री के सामने आने से नहीं रोकता है।</string>
|
||||
<plurals name="missing_chapters_warning">
|
||||
<item quantity="one">1 अध्याय छोड़ा जा रहा है, या तो स्रोत में यह अनुपलब्ध है या इसे फ़िल्टर कर दिया गया है</item>
|
||||
<item quantity="other">%d अध्याय छोड़े जा रहा है, या तो स्रोत में यह अनुपलब्ध है या इसे फ़िल्टर कर दिया गया है</item>
|
||||
<item quantity="one">%d अध्याय को छोड़कर, या तो स्रोत में यह अनुपलब्ध है या इसे फ़िल्टर कर दिया गया है</item>
|
||||
<item quantity="other">%d अध्यायों को छोड़कर, या तो स्रोत में वे नहीं हैं या उन्हें फ़िल्टर कर दिया गया है</item>
|
||||
</plurals>
|
||||
<string name="chapter_settings_updated">अपडेट किए गए डिफ़ॉल्ट अध्याय सेटिंग्स</string>
|
||||
<string name="no_chapters_error">कोई अध्याय नहीं मिला</string>
|
||||
@ -703,6 +703,16 @@
|
||||
<string name="skipped_reason_not_started">छोड़ दिया गया क्योंकि कोई अध्याय पढ़ा नहीं गया</string>
|
||||
<string name="pref_update_only_started">कोई अध्याय नहीं पढ़ा</string>
|
||||
<string name="action_show_manga">मंगा दिखाएँ</string>
|
||||
<string name="action_filter_started">शुरू किया</string>
|
||||
<string name="action_filter_started">शुरू किया गया</string>
|
||||
<string name="action_display_cover_only_grid">केवल कवर ग्रिड</string>
|
||||
<string name="disabled_nav">अक्षम</string>
|
||||
<string name="rotation_reverse_portrait">रिवर्स पोर्ट्रेट</string>
|
||||
<string name="notification_update_error">%1$d अपडेट विफल</string>
|
||||
<string name="confirm_manga_add_duplicate">आपकी लाइब्रेरी में एक ही नाम के साथ लेकिन एक अलग स्रोत (%1$s) से एक प्रविष्टि है।
|
||||
\n
|
||||
\nक्या आप अभी भी जारी रखना चाहते हैं\?</string>
|
||||
<string name="notification_update_skipped">%1$d अपडेट छोड़े गए</string>
|
||||
<string name="pref_navigate_pan">पैन पर नेविगेट करें</string>
|
||||
<string name="pref_landscape_zoom">ज़ूम लैंडस्केप इमेज</string>
|
||||
<string name="action_move_to_top_all_for_series">श्रृंखला को शीर्ष पर ले जाएं</string>
|
||||
</resources>
|
@ -271,7 +271,7 @@
|
||||
<string name="notification_first_add_to_library">Prije toga, dodaj manga u biblioteku</string>
|
||||
<string name="notification_cover_update_failed">Neuspjelo ažuriranje naslovnice</string>
|
||||
<plurals name="notification_chapters_multiple_and_more">
|
||||
<item quantity="one">Poglavlja %1$s i još %2$s</item>
|
||||
<item quantity="one">Poglavlja %1$s i još jedno</item>
|
||||
<item quantity="few">Poglavlja %1$s i još %2$s</item>
|
||||
<item quantity="other">Poglavlja %1$s i još %2$s</item>
|
||||
</plurals>
|
||||
@ -726,4 +726,5 @@
|
||||
<string name="notification_update_skipped">Preskočena aktualiziranja: %1$d</string>
|
||||
<string name="rotation_reverse_portrait">Preokrenuto uspravno</string>
|
||||
<string name="action_move_to_top_all_for_series">Pomakni serijal na vrh</string>
|
||||
<string name="disabled_nav">Deaktivirano</string>
|
||||
</resources>
|
@ -73,7 +73,7 @@
|
||||
<string name="all">Tutte</string>
|
||||
<string name="pref_library_update_restriction">Restrizioni del dispositivo agli aggiornamenti automatici</string>
|
||||
<string name="charging">In carica</string>
|
||||
<string name="pref_update_only_non_completed">È una serie completa</string>
|
||||
<string name="pref_update_only_non_completed">Con stato \"completa\"</string>
|
||||
<string name="pref_auto_update_manga_sync">Aggiorna il tracking dopo la lettura</string>
|
||||
<string name="pref_start_screen">Schermata iniziale</string>
|
||||
<!-- Reader section -->
|
||||
@ -707,7 +707,7 @@
|
||||
<string name="action_display_language_badge">Lingua</string>
|
||||
<string name="label_warning">Attenzione</string>
|
||||
<string name="backup_info">I backup automatici sono altamente consigliati. Dovresti tenere delle copie anche in altri posti.</string>
|
||||
<string name="notification_size_warning">Attenzione: grossi aggiornamenti danneggiano le fonti, possono rallentare gli aggiornamenti e aumentare il consumo di batteria</string>
|
||||
<string name="notification_size_warning">Grossi aggiornamenti danneggiano le fonti, possono rallentare gli aggiornamenti e aumentare il consumo di batteria</string>
|
||||
<string name="connected_to_wifi">Solo su Wi-Fi</string>
|
||||
<string name="update_72hour">Ogni 3 giorni</string>
|
||||
<string name="download_queue_size_warning">Attenzione: grossi download di massa possono rallentare le fonti e/o bloccare tachiyomi</string>
|
||||
@ -719,8 +719,8 @@
|
||||
<string name="database_clean">Database pulito</string>
|
||||
<string name="extension_api_error">Impossibile ottenere l\'elenco estensioni</string>
|
||||
<string name="privacy_policy">Politica sulla privacy</string>
|
||||
<string name="pref_update_only_completely_read">Ha capitoli non letti</string>
|
||||
<string name="pref_library_update_manga_restriction">Salta l\'aggiornamento</string>
|
||||
<string name="pref_update_only_completely_read">Con capitoli non letti</string>
|
||||
<string name="pref_library_update_manga_restriction">Salta l\'aggiornamento di serie</string>
|
||||
<string name="library_errors_help">Per un aiuto su come risolvere gli errori di aggiornamento della libreria vedi %1$s</string>
|
||||
<string name="save_chapter_as_cbz">Salva come archivio CBZ</string>
|
||||
<string name="cancelled">Cancellata</string>
|
||||
@ -737,15 +737,17 @@
|
||||
\nVuoi comunque continuare\?</string>
|
||||
<string name="action_display_cover_only_grid">Griglia con solo copertine</string>
|
||||
<string name="action_filter_started">Iniziati</string>
|
||||
<string name="pref_update_only_started">Nessun capitolo letto</string>
|
||||
<string name="pref_update_only_started">Che non sono state iniziate</string>
|
||||
<string name="skipped_reason_completed">Saltato perché la serie è completa</string>
|
||||
<string name="skipped_reason_not_caught_up">Saltato perché ci sono capitoli non letti</string>
|
||||
<string name="skipped_reason_not_started">Saltato perché non ci sono capitoli letti</string>
|
||||
<string name="channel_skipped">Saltato</string>
|
||||
<string name="notification_update_error">%1$d aggiornamento(i) fallito(i)</string>
|
||||
<string name="notification_update_skipped">%1$d aggiornamento(i) saltato(i)</string>
|
||||
<string name="learn_more">Approfondisci</string>
|
||||
<string name="learn_more">Tocca per approfondire</string>
|
||||
<string name="rotation_reverse_portrait">Verticale inverso</string>
|
||||
<string name="action_move_to_top_all_for_series">Sposta la serie in cima</string>
|
||||
<string name="disabled_nav">Disattivato</string>
|
||||
<string name="update_check_fdroid_migration_info">C\'è una nuova versione ufficiale disponibile. Tocca per imparare a migrare dalle release non ufficiali di F-droid.</string>
|
||||
<string name="error_saving_picture">Errore durante il salvataggio dell\'immagine</string>
|
||||
</resources>
|
@ -702,4 +702,5 @@
|
||||
<string name="notification_update_error">%1$d件の更新に失敗しました</string>
|
||||
<string name="rotation_reverse_portrait">縦向き(反転)</string>
|
||||
<string name="action_move_to_top_all_for_series">シリーズをトップに移動</string>
|
||||
<string name="disabled_nav">無効</string>
|
||||
</resources>
|
@ -12,8 +12,8 @@
|
||||
<string name="action_filter_bookmarked">북마크됨</string>
|
||||
<string name="action_filter_unread">읽지 않음</string>
|
||||
<string name="action_filter_empty">필터 제거</string>
|
||||
<string name="action_sort_alpha">알파벳 순으로</string>
|
||||
<string name="action_sort_last_read">읽은 순으로</string>
|
||||
<string name="action_sort_alpha">알파벳 순</string>
|
||||
<string name="action_sort_last_read">마지막으로 읽은 순</string>
|
||||
<string name="action_search">검색</string>
|
||||
<string name="action_select_all">전체 선택</string>
|
||||
<string name="action_mark_as_read">읽음으로 표시</string>
|
||||
@ -34,10 +34,10 @@
|
||||
<string name="action_edit_cover">표지 수정</string>
|
||||
<string name="action_stop">정지</string>
|
||||
<string name="action_remove">제거</string>
|
||||
<string name="action_resume">계속 읽기</string>
|
||||
<string name="action_resume">계속</string>
|
||||
<string name="action_open_in_browser">브라우저에서 열기</string>
|
||||
<string name="action_display_mode">타이틀 표시 변경</string>
|
||||
<string name="action_display_grid">그리드</string>
|
||||
<string name="action_display_grid">작은 그리드</string>
|
||||
<string name="action_display_list">리스트</string>
|
||||
<string name="action_cancel">취소</string>
|
||||
<string name="action_sort">정렬</string>
|
||||
@ -49,7 +49,7 @@
|
||||
<string name="label_library">서재</string>
|
||||
<string name="label_recent_manga">기록</string>
|
||||
<string name="label_recent_updates">업데이트</string>
|
||||
<string name="action_sort_total">모든 회차</string>
|
||||
<string name="action_sort_total">회차의 수 순</string>
|
||||
<string name="action_previous_chapter">이전 화</string>
|
||||
<string name="action_next_chapter">다음 화</string>
|
||||
<string name="action_retry">재시도</string>
|
||||
@ -77,14 +77,14 @@
|
||||
<string name="portrait">세로</string>
|
||||
<string name="landscape">가로</string>
|
||||
<string name="pref_library_update_interval">자동 업데이트</string>
|
||||
<string name="update_never">수동</string>
|
||||
<string name="update_never">끄기</string>
|
||||
<string name="update_6hour">6시간</string>
|
||||
<string name="update_12hour">12시간</string>
|
||||
<string name="update_24hour">1일</string>
|
||||
<string name="update_48hour">2일</string>
|
||||
<string name="update_weekly">1주</string>
|
||||
<string name="all">전부</string>
|
||||
<string name="pref_library_update_restriction">서재 업데이트 제한</string>
|
||||
<string name="pref_library_update_restriction">자동 업데이트 조건</string>
|
||||
<string name="charging">충전중</string>
|
||||
<string name="pref_start_screen">시작 화면</string>
|
||||
<string name="default_category">기본 카테고리</string>
|
||||
@ -146,9 +146,9 @@
|
||||
<string name="pref_restore_backup">백업 복원</string>
|
||||
<string name="pref_restore_backup_summ">백업 파일에서 서재 복원</string>
|
||||
<string name="pref_backup_directory">백업 위치</string>
|
||||
<string name="pref_backup_service_category">서비스</string>
|
||||
<string name="pref_backup_service_category">자동 백업</string>
|
||||
<string name="pref_backup_interval">백업 주기</string>
|
||||
<string name="pref_backup_slots">최대 자동 백업</string>
|
||||
<string name="pref_backup_slots">최대 백업</string>
|
||||
<string name="backup_created">백업 생성됨</string>
|
||||
<string name="restore_completed">복원 완료</string>
|
||||
<string name="restoring_backup">백업 복원중</string>
|
||||
@ -162,7 +162,7 @@
|
||||
<string name="pref_clear_database">데이터베이스 삭제</string>
|
||||
<string name="pref_clear_database_summary">서재에 추가되지 않은 만화의 기록을 삭제합니다</string>
|
||||
<string name="clear_database_confirmation">확실합니까\? 서재에 없는 만화의 읽은 기록이 삭제됩니다</string>
|
||||
<string name="pref_refresh_library_tracking">동기화 메타데이터 새로 고침</string>
|
||||
<string name="pref_refresh_library_tracking">트래커 동기화 새로고침</string>
|
||||
<string name="pref_refresh_library_tracking_summary">상태 및 평점, 마지막으로 읽은 회차를 동기화 서비스로부터 업데이트합니다</string>
|
||||
<string name="version">버전</string>
|
||||
<string name="pref_enable_acra">오류 보고서 전송</string>
|
||||
@ -219,7 +219,7 @@
|
||||
<string name="chapter_progress">페이지: %1$d</string>
|
||||
<string name="no_next_chapter">다음 화가 없습니다</string>
|
||||
<string name="no_previous_chapter">이전 화가 없습니다</string>
|
||||
<string name="decode_image_error">이미지를 디코드 할 수 없습니다</string>
|
||||
<string name="decode_image_error">이미지를 로드할 수 없습니다</string>
|
||||
<string name="confirm_set_image_as_cover">이 이미지를 표지로 사용합니까\?</string>
|
||||
<string name="transition_finished">완료:</string>
|
||||
<string name="transition_current">현재:</string>
|
||||
@ -250,7 +250,7 @@
|
||||
<string name="download_notifier_unknown_error">다운로드 중에 예기치 않은 오류가 발생하였습니다</string>
|
||||
<string name="download_notifier_download_paused">다운로드 일시중지됨</string>
|
||||
<string name="action_display_download_badge">다운로드된 회차</string>
|
||||
<string name="pref_update_only_non_completed">연재 중인 만화만 업데이트</string>
|
||||
<string name="pref_update_only_non_completed">연재가 끝남</string>
|
||||
<string name="pref_auto_update_manga_sync">읽은 기록 동기화</string>
|
||||
<string name="default_category_summary">항상 물어보기</string>
|
||||
<string name="pref_create_backup_summ">현재 서재를 나중에 복구하는 데 사용 가능</string>
|
||||
@ -286,7 +286,7 @@
|
||||
<string name="licensed">판권작</string>
|
||||
<string name="copied_to_clipboard">클립보드에 복사됨:
|
||||
\n%1$s</string>
|
||||
<string name="show_title">제목 표시</string>
|
||||
<string name="show_title">소스 제목</string>
|
||||
<string name="custom_download">다운로드 할 회차 직접 입력</string>
|
||||
<string name="download_custom">사용자 정의</string>
|
||||
<string name="reading">읽는 중</string>
|
||||
@ -308,7 +308,7 @@
|
||||
<string name="download_notifier_text_only_wifi">Wi-Fi 연결 사용 불가능</string>
|
||||
<string name="download_notifier_no_network">네트워크 연결 사용 불가능</string>
|
||||
<string name="channel_common">일반</string>
|
||||
<string name="pref_read_with_long_tap">길게 눌러 대화상자 표시</string>
|
||||
<string name="pref_read_with_long_tap">길게 눌러 표시</string>
|
||||
<string name="action_open_in_web_view">WebView로 열기</string>
|
||||
<string name="pref_true_color">32비트 컬러</string>
|
||||
<string name="pref_skip_read_chapters">읽음 표시된 회차 건너뛰기</string>
|
||||
@ -339,7 +339,7 @@
|
||||
<string name="logout">로그아웃</string>
|
||||
<string name="logout_title">%1$s 에서 로그아웃 하시겠습니까\?</string>
|
||||
<plurals name="download_queue_summary">
|
||||
<item quantity="other">%1$s 개 남았습니다</item>
|
||||
<item quantity="other">%1$s 개 남음</item>
|
||||
</plurals>
|
||||
<string name="notification_incognito_text">시크릿 모드 끄기</string>
|
||||
<string name="label_downloaded_only">다운로드가 완료된 항목만 표시</string>
|
||||
@ -349,10 +349,10 @@
|
||||
<string name="licenses">오픈 소스 라이센스</string>
|
||||
<string name="battery_optimization_setting_activity_not_found">디바이스 설정을 열 수 없습니다</string>
|
||||
<string name="pref_disable_battery_optimization">배터리 최적화 끄기</string>
|
||||
<string name="restore_miui_warning">MIUI 최적화가 꺼져 있을 경우 백업/복원 기능은 정상 작동하지 않을 수 있습니다.</string>
|
||||
<string name="restore_miui_warning">MIUI 최적화가 꺼져 있을 경우 백업/복원 기능이 정상 작동하지 않을 수 있습니다.</string>
|
||||
<string name="restore_in_progress">복원이 이미 진행중 입니다</string>
|
||||
<string name="requires_app_restart">설정을 적용하기 위해 앱을 재시작해야 합니다</string>
|
||||
<string name="pref_dns_over_https">DNS over HTTPS</string>
|
||||
<string name="pref_dns_over_https">DNS over HTTPS (DoH)</string>
|
||||
<string name="label_data">데이터</string>
|
||||
<string name="backup_in_progress">백업이 이미 진행중입니다</string>
|
||||
<string name="restoring_backup_error">백업 복원 실패</string>
|
||||
@ -392,8 +392,8 @@
|
||||
<string name="label_default">기본값</string>
|
||||
<string name="action_select_inverse">선택 반전</string>
|
||||
<string name="action_search_settings">검색 설정</string>
|
||||
<string name="action_sort_date_added">추가된 날짜</string>
|
||||
<string name="action_sort_latest_chapter">최신 화</string>
|
||||
<string name="action_sort_date_added">서재에 추가된 시간 순</string>
|
||||
<string name="action_sort_latest_chapter">최신 화 업로드 순</string>
|
||||
<string name="l_nav">L자 모양</string>
|
||||
<string name="pref_read_with_tapping_inverted">터치 반전</string>
|
||||
<string name="tapping_inverted_none">없음</string>
|
||||
@ -500,4 +500,207 @@
|
||||
<string name="channel_app_updates">앱 업데이트</string>
|
||||
<string name="channel_progress">진행 상황</string>
|
||||
<string name="channel_errors">오류</string>
|
||||
<string name="database_clean">데이터베이스 정리</string>
|
||||
<string name="learn_more">터치하여 자세히 알아보기</string>
|
||||
<string name="chapter_settings_updated">기본 회차 설정을 업데이트 했습니다</string>
|
||||
<string name="channel_skipped">건너뜀</string>
|
||||
<string name="channel_new_chapters">회차 업데이트</string>
|
||||
<string name="pref_jump_to_chapters">시작 시 회차 표시</string>
|
||||
<string name="include">포함: %s</string>
|
||||
<string name="label_background_activity">백그라운드 활동</string>
|
||||
<string name="pref_update_only_completely_read">안 읽은 회차가 있음</string>
|
||||
<string name="categorized_display_settings">카테고리 별 표시/정렬 설정</string>
|
||||
<string name="ext_installer_shizuku_unavailable_dialog">Shizuku를 확장기능 인스톨러로 사용하려면 Shizuku를 먼저 설치해 주세요.</string>
|
||||
<string name="ext_update_all">전부 업데이트</string>
|
||||
<string name="backup_restore_invalid_uri">에러: 빈 URI</string>
|
||||
<string name="invalid_backup_file_missing_manga">백업에 만화가 포함되어있지 않습니다.</string>
|
||||
<string name="pref_dump_crash_logs_summary">개발자와 공유할 수 있는 오류 로그 파일을 생성합니다</string>
|
||||
<string name="crash_log_saved">오류 로그가 저장되었습니다</string>
|
||||
<string name="privacy_policy">개인정보 보호 정책</string>
|
||||
<string name="share_page_info">%1$s: %2$s, %3$d페이지</string>
|
||||
<string name="clear_history_confirmation">계속하시겠습니까\? 모든 기록이 삭제됩니다.</string>
|
||||
<string name="disabled_nav">비활성화</string>
|
||||
<string name="invalid_backup_file_missing_data">파일에 필요한 데이터가 포함되어있지 않습니다.</string>
|
||||
<string name="backup_restore_missing_sources">없어진 소스:</string>
|
||||
<string name="backup_restore_missing_trackers">로그인 되지않은 트래커:</string>
|
||||
<string name="pref_auto_clear_chapter_cache">앱 종료 시 회차 캐시 삭제</string>
|
||||
<string name="clear_database_source_item_count">데이터베이스에 없는 만화가 %1$d개 있습니다</string>
|
||||
<string name="about_dont_kill_my_app">일부 제조사는 백그라운드 서비스를 종료하는 추가적인 제한 사항이 있습니다. 자세한 사항은 웹사이트를 참조하세요.</string>
|
||||
<string name="pref_tablet_ui_mode">태블릿 UI</string>
|
||||
<string name="tabs_header">탭</string>
|
||||
<string name="http_error_hint">WebView에서 사이트 열기</string>
|
||||
<string name="pinned_sources">핀 설정됨</string>
|
||||
<string name="action_global_search_query">\"%1$s\"를 전역 검색합니다</string>
|
||||
<string name="local_source_help_guide">로컬 저장소 사용법</string>
|
||||
<string name="no_pinned_sources">핀 설정된 소스가 없습니다</string>
|
||||
<string name="local_invalid_format">잘못된 회차 포맷</string>
|
||||
<string name="unknown_status">알 수 없는 상태</string>
|
||||
<string name="on_hiatus">휴재중</string>
|
||||
<string name="manga_info_expand">상세정보 표시</string>
|
||||
<string name="manga_info_collapse">상세정보 숨김</string>
|
||||
<string name="clipboard_copy_error">클립보드로 복사에 실패하였습니다</string>
|
||||
<string name="tracker_komga_warning">이 트래커는 Komga 소스에만 호환됩니다.</string>
|
||||
<plurals name="num_trackers">
|
||||
<item quantity="other">%d개의 트래커</item>
|
||||
</plurals>
|
||||
<string name="add_tracking">트래커 추가</string>
|
||||
<string name="paused">일시정지</string>
|
||||
<string name="error_invalid_date_supplied">잘못된 날짜입니다</string>
|
||||
<string name="myanimelist_relogin">MAL에 다시 로그인해 주세요</string>
|
||||
<string name="loader_not_implemented_error">소스를 찾을 수 없습니다</string>
|
||||
<string name="page_list_empty_error">페이지를 찾을 수 없습니다</string>
|
||||
<plurals name="missing_chapters_warning">
|
||||
<item quantity="other">소스에 존재하지 않거나 필터링되어 있는 %d개의 회차를 건너뛰었습니다</item>
|
||||
</plurals>
|
||||
<string name="pref_clear_history">내역 삭제</string>
|
||||
<string name="clear_history_completed">기록이 삭제되었습니다</string>
|
||||
<string name="download_insufficient_space">저장 공간이 부족하여 회차를 다운로드 할 수 없습니다</string>
|
||||
<string name="download_queue_size_warning">경고: 한꺼번에 많은 양을 다운로드 할 경우 소스가 느려지거나 Tachiyomi를 차단할 수 있습니다</string>
|
||||
<string name="notification_check_updates">새로운 회차 확인 중</string>
|
||||
<string name="notification_size_warning">경고: 대량의 업데이트는 소스에 과도한 부하를 줄 수 있고 배터리 사용량을 증가시킵니다</string>
|
||||
<string name="notification_chapters_single">%1$s화</string>
|
||||
<string name="notification_update_error">%1$d개의 업데이트가 실패했습니다</string>
|
||||
<string name="notification_update_skipped">%1$d개의 업데이트를 건너 뛰었습니다</string>
|
||||
<string name="library_errors_help">서재 업데이트 오류를 해결하려면 %1$s를 참조하세요</string>
|
||||
<string name="skipped_reason_completed">완결된 만화를 건너 뛰었습니다</string>
|
||||
<string name="skipped_reason_not_started">읽지 않은 만화를 건너 뛰었습니다</string>
|
||||
<string name="update_check_eol">이 안드로이드 버젼은 더이상 지원되지 않습니다</string>
|
||||
<plurals name="update_check_notification_ext_updates">
|
||||
<item quantity="other">%d개의 확장기능 업데이트가 있습니다</item>
|
||||
</plurals>
|
||||
<string name="information_cloudflare_bypass_failure">Cloudflare를 통과하지 못했습니다</string>
|
||||
<string name="information_webview_required">Tachiyomi를 사용하려면 WebView가 필요합니다</string>
|
||||
<string name="information_webview_outdated">호환성을 위해 WebView 어플리케이션을 업데이트 해 주세요</string>
|
||||
<string name="pref_navigate_pan">페이지 내 이동</string>
|
||||
<string name="obsolete_extension_message">이 확장기능은 더이상 이용이 불가능합니다.</string>
|
||||
<string name="ext_install_service_notif">확장기능 설치 중…</string>
|
||||
<string name="ext_installer_legacy">레거시</string>
|
||||
<string name="webtoon_side_padding_10">10%</string>
|
||||
<string name="action_track">트래킹</string>
|
||||
<string name="pref_refresh_library_covers">서재 만화 표지 새로고침</string>
|
||||
<string name="pref_dump_crash_logs">오류 로그 덤프</string>
|
||||
<string name="chapter_not_found">회차를 찾을 수 없습니다</string>
|
||||
<string name="error_no_match">결과가 없습니다</string>
|
||||
<string name="channel_crash_logs">오류 로그</string>
|
||||
<string name="ext_nsfw_warning">19금 콘텐츠가 포함될 수 있습니다</string>
|
||||
<string name="action_filter_tracked">트래커 사용</string>
|
||||
<string name="action_start">시작</string>
|
||||
<string name="source_not_found_name">소스 %1$s를 찾을 수 없습니다</string>
|
||||
<string name="action_start_downloading_now">지금 다운로드 시작</string>
|
||||
<string name="ext_installer_pref">인스톨러</string>
|
||||
<string name="ext_installer_shizuku_stopped">Shizuku가 실행 중이 아닙니다</string>
|
||||
<string name="manga_from_library">서재의 만화</string>
|
||||
<string name="downloaded_chapters">다운로드된 회차</string>
|
||||
<string name="publishing_finished">완결됨</string>
|
||||
<string name="confirm_manga_add_duplicate">서재에 제목이 같지만 소스가 다른 항목이 있습니다 (%1$s).
|
||||
\n
|
||||
\n계속하시겠습니까\?</string>
|
||||
<string name="unread">읽지 않음</string>
|
||||
<string name="cancelled">취소됨</string>
|
||||
<string name="no_chapters_error">검색된 회차가 없습니다</string>
|
||||
<string name="source_unsupported">지원되지 않는 소스입니다</string>
|
||||
<string name="download_notifier_download_finish">다운로드 완료</string>
|
||||
<string name="spen_previous_page">이전 페이지</string>
|
||||
<string name="action_show_manga">만화 보기</string>
|
||||
<string name="action_desc">내림차순</string>
|
||||
<string name="theme_monet">활력</string>
|
||||
<string name="action_display_cover_only_grid">표지 그리드</string>
|
||||
<string name="action_reorganize_by">재정렬</string>
|
||||
<string name="action_newest">최신 순</string>
|
||||
<string name="pref_category_theme">테마</string>
|
||||
<string name="theme_midnightdusk">한밤중의 어둠</string>
|
||||
<string name="ext_obsolete">지원 종료</string>
|
||||
<string name="tracker_not_logged_in">로그인 불가: %1$s</string>
|
||||
<string name="no_results_found">검색 결과가 없습니다</string>
|
||||
<string name="pref_dual_page_invert_summary">이중 페이지 분할 시 배치가 읽는 방향과 다를 경우 사용하세요</string>
|
||||
<string name="ext_nsfw_short">19금</string>
|
||||
<string name="action_filter_started">읽는 중</string>
|
||||
<string name="action_display_show_tabs">카테고리 탭 보이기</string>
|
||||
<string name="action_sort_chapter_fetch_date">정보가 갱신된 시간 순</string>
|
||||
<string name="action_sort_count">만화의 총 개수</string>
|
||||
<string name="action_webview_back">뒤로가기</string>
|
||||
<string name="battery_optimization_disabled">배터리 최적화가 이미 꺼져 있습니다</string>
|
||||
<string name="action_order_by_chapter_number">회차 번호 순</string>
|
||||
<string name="action_move_to_top">맨 위로 이동</string>
|
||||
<string name="action_sort_last_checked">마지막으로 확인한 순</string>
|
||||
<string name="action_order_by_upload_date">업로드 날짜 순</string>
|
||||
<string name="action_move_to_bottom">맨 아래로 이동</string>
|
||||
<string name="action_asc">오름차순</string>
|
||||
<string name="action_oldest">오래된 순</string>
|
||||
<string name="theme_tealturquoise">옥색</string>
|
||||
<string name="recently">최근</string>
|
||||
<string name="theme_strawberrydaiquiri">딸기 칵테일</string>
|
||||
<string name="extension_api_error">확장기능 목록 취득 실패</string>
|
||||
<string name="pref_library_update_refresh_trackers_summary">서재 업데이트 시 트래커 갱신</string>
|
||||
<string name="exclude">제외: %s</string>
|
||||
<string name="unofficial_extension_message">이 확장기능은 공식 확장기능이 아닙니다.</string>
|
||||
<string name="tracking_info">트래커 서비스에 만화 진행 상황을 동기화합니다. 트래킹 버튼을 이용하여 각각의 만화 별로 트래킹을 설정하세요.</string>
|
||||
<string name="webtoon_side_padding_20">20%</string>
|
||||
<string name="webtoon_side_padding_25">25%</string>
|
||||
<string name="tracking_guide">트래커 가이드</string>
|
||||
<string name="enhanced_services">향상된 서비스</string>
|
||||
<string name="webtoon_side_padding_5">5%</string>
|
||||
<string name="webtoon_side_padding_15">15%</string>
|
||||
<string name="pref_download_new_categories_details">카테고리가 다운로드에서 제외된 경우 다른 카테고리에 포함되어 있어도 다운로드 되지 않습니다.</string>
|
||||
<string name="enhanced_tracking_info">특정 소스에 향상된 서비스를 제공합니다. 서재에 만화가 추가될 시 자동으로 트래킹 됩니다.</string>
|
||||
<string name="pref_search_pinned_sources_only">핀 설정된 소스만 포함</string>
|
||||
<string name="backup_restore_content_full">백업 파일에서 데이터가 복구됩니다.
|
||||
\n
|
||||
\n복구 완료 후 없어진 소스를 다시 설치하고 트래킹 서비스에 로그인 해야 합니다.</string>
|
||||
<string name="backup_info">자동 백업이 매우 권장됩니다. 백업 파일은 다른 장소에 나눠 보관하세요.</string>
|
||||
<string name="pref_disable_battery_optimization_summary">백그라운드 서재 업데이트와 라이브러리 업데이트를 도울 수 있습니다</string>
|
||||
<string name="pref_verbose_logging">자세한 로그</string>
|
||||
<string name="pref_verbose_logging_summary">자세한 로그를 시스템 로그에 기록 (성능이 하락할 수 있습니다)</string>
|
||||
<string name="badges_header">배지</string>
|
||||
<string name="date">날짜</string>
|
||||
<string name="local_filter_order_by">정렬</string>
|
||||
<string name="track_started_reading_date">읽기 시작한 날짜</string>
|
||||
<string name="track_finished_reading_date">다 읽은 날짜</string>
|
||||
<plurals name="notification_new_chapters_summary">
|
||||
<item quantity="other">%d개의 만화</item>
|
||||
</plurals>
|
||||
<plurals name="notification_chapters_generic">
|
||||
<item quantity="other">%1$d개의 새로운 회차</item>
|
||||
</plurals>
|
||||
<string name="skipped_reason_not_caught_up">읽지 않은 회차가 있는 만화를 건너 뛰었습니다</string>
|
||||
<string name="information_empty_category_dialog">등록된 카테고리가 없습니다.</string>
|
||||
<string name="pref_create_folder_per_manga_summary">만화 제목에 따라 폴더 생성</string>
|
||||
<string name="migration_help_guide">소스 이전 설명서</string>
|
||||
<string name="migration_selection_prompt">원본 소스를 선택하세요</string>
|
||||
<string name="action_display_local_badge">로컬 만화</string>
|
||||
<string name="action_display_show_number_of_items">항목 수 보이기</string>
|
||||
<string name="action_disable">끄기</string>
|
||||
<string name="action_pin">핀</string>
|
||||
<string name="action_unpin">핀 해제</string>
|
||||
<string name="action_cancel_all">모두 취소</string>
|
||||
<string name="cancel_all_for_series">이 만화의 항목을 모두 취소</string>
|
||||
<string name="action_webview_forward">앞으로가기</string>
|
||||
<string name="pref_create_folder_per_manga">각각의 폴더에 페이지 저장</string>
|
||||
<string name="action_faq_and_guides">FAQ와 설명서</string>
|
||||
<string name="pref_update_only_started">읽은 회차 없음</string>
|
||||
<string name="action_move_to_top_all_for_series">만화 전체를 맨 위로 이동</string>
|
||||
<string name="action_webview_refresh">새로고침</string>
|
||||
<string name="theme_greenapple">초록 사과</string>
|
||||
<string name="theme_tako">문어</string>
|
||||
<string name="theme_yinyang">음과 양</string>
|
||||
<string name="theme_yotsuba">요츠바</string>
|
||||
<string name="pref_side_nav_icon_alignment">네비게이션 아이콘 정렬</string>
|
||||
<string name="alignment_top">위</string>
|
||||
<string name="alignment_center">중앙</string>
|
||||
<string name="alignment_bottom">아래</string>
|
||||
<string name="pref_category_nsfw_content">19금 소스</string>
|
||||
<string name="pref_show_nsfw_source">소스 또는 확장기능 목록에 보이기</string>
|
||||
<string name="parental_controls_info">오류 또는 잘못된 분류로 인하여 19금 콘텐츠가 표시될 가능성이 있습니다.</string>
|
||||
<string name="action_show_errors">터치하여 자세히 보기</string>
|
||||
<string name="update_72hour">3일</string>
|
||||
<string name="restrictions">제한: %s</string>
|
||||
<string name="pref_library_update_categories_details">카테고리가 업데이트에서 제외된 경우 다른 카테고리에 포함되어 있어도 업데이트 되지 않습니다.</string>
|
||||
<string name="ext_updates_pending">업데이트 대기 중</string>
|
||||
<string name="pref_library_update_refresh_metadata_summary">서재 업데이트 시 새로운 표지와 설명 확인</string>
|
||||
<string name="notification_chapters_single_and_more">%1$s화와 그 이후 %2$d화</string>
|
||||
<string name="notification_chapters_multiple">%1$s화</string>
|
||||
<plurals name="notification_chapters_multiple_and_more">
|
||||
<item quantity="other">%1$s화와 그 이후 %2$d화</item>
|
||||
</plurals>
|
||||
<string name="file_picker_error">파일 선택 어플리케이션이 없습니다</string>
|
||||
</resources>
|
@ -83,7 +83,7 @@
|
||||
<string name="all">Semua</string>
|
||||
<string name="pref_library_update_restriction">Sekatan kemas kini automatik peranti</string>
|
||||
<string name="charging">Ketika mengecas</string>
|
||||
<string name="pref_update_only_non_completed">Siri sudah selesai</string>
|
||||
<string name="pref_update_only_non_completed">Dengan status \"Sudah selesai\"</string>
|
||||
<string name="pref_auto_update_manga_sync">Kemas kini selepas dibaca</string>
|
||||
<string name="pref_start_screen">Skrin permulaan</string>
|
||||
<string name="default_category">Kategori lalai</string>
|
||||
@ -674,8 +674,8 @@
|
||||
<string name="clear_database_source_item_count">%1$d manga bukan pustaka dalam pangkalan data</string>
|
||||
<string name="extension_api_error">Gagal mendapatkan senarai sambungan</string>
|
||||
<string name="privacy_policy">Dasar privasi</string>
|
||||
<string name="pref_library_update_manga_restriction">Langkau mengemaskini</string>
|
||||
<string name="pref_update_only_completely_read">Ada bab yang belum dibaca</string>
|
||||
<string name="pref_library_update_manga_restriction">Langkau mengemaskini siri</string>
|
||||
<string name="pref_update_only_completely_read">Dengan bab yang belum dibaca</string>
|
||||
<string name="library_errors_help">Untuk bantuan cara menyelesaikan ralat kemas kini pustaka, lihat %1$s</string>
|
||||
<string name="save_chapter_as_cbz">Simpan sebagai arkib CBZ</string>
|
||||
<string name="cancelled">Dibatalkan</string>
|
||||
@ -691,7 +691,7 @@
|
||||
\nAdakah anda masih ingin meneruskan\?</string>
|
||||
<string name="action_display_cover_only_grid">Cuma grid muka hadapan</string>
|
||||
<string name="skipped_reason_completed">Dilangkau kerana siri sudah lengkap</string>
|
||||
<string name="pref_update_only_started">Tiada bab dibaca</string>
|
||||
<string name="pref_update_only_started">Yang mana bacaan belum dimulakan</string>
|
||||
<string name="skipped_reason_not_caught_up">Dilangkau kerana ada bab yang belum dibaca</string>
|
||||
<string name="skipped_reason_not_started">Dilangkau kerana masih belum membaca mana-mana bab</string>
|
||||
<string name="pref_landscape_zoom">Zum imej landskap</string>
|
||||
@ -699,7 +699,10 @@
|
||||
<string name="notification_update_error">%1$d kemas kini gagal</string>
|
||||
<string name="notification_update_skipped">%1$d kemas kini dilangkau</string>
|
||||
<string name="channel_skipped">Dilangkau</string>
|
||||
<string name="learn_more">Ketahui selebihnya</string>
|
||||
<string name="learn_more">Ketik untuk ketahui selebihnya</string>
|
||||
<string name="rotation_reverse_portrait">Potret terbalik</string>
|
||||
<string name="action_move_to_top_all_for_series">Alih siri ke atas</string>
|
||||
<string name="disabled_nav">Dinyahkan</string>
|
||||
<string name="error_saving_picture">Ralat menyimpan gambar</string>
|
||||
<string name="update_check_fdroid_migration_info">Versi baharu tersedia daripada pengeluaran rasmi. Ketik untuk mengetahui bagaimana untuk berhijrah daripada keluaran tidak rasmi F-Droid.</string>
|
||||
</resources>
|
@ -711,7 +711,8 @@
|
||||
<string name="pref_auto_clear_chapter_cache">Tøm kapittelbufferen ved lukking av appen</string>
|
||||
<string name="notification_update_error">%1$d oppdatering(er) mislyktes</string>
|
||||
<string name="notification_update_skipped">%1$d oppdatering(er) hoppet over</string>
|
||||
<string name="learn_more">Lær mer</string>
|
||||
<string name="learn_more">Trykk for å finne ut mer</string>
|
||||
<string name="skipped_reason_not_started">Hoppet over fordi ingen kapitler er lest</string>
|
||||
<string name="channel_skipped">Hoppet over</string>
|
||||
<string name="disabled_nav">Deaktivert</string>
|
||||
</resources>
|
37
app/src/main/res/values-night/color_lavender.xml
Normal file
37
app/src/main/res/values-night/color_lavender.xml
Normal file
@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Colors for Lavender theme
|
||||
~
|
||||
~ Color scheme by Osyx
|
||||
~
|
||||
~ Key colors:
|
||||
~ Primary #A177FF
|
||||
~ Secondary #A177FF
|
||||
~ Tertiary #5E25E1
|
||||
~ Neutral #111129
|
||||
-->
|
||||
<resources>
|
||||
<color name="lavender_primary">#A177FF</color>
|
||||
<color name="lavender_onPrimary">#111129</color>
|
||||
<color name="lavender_primaryContainer">#A177FF</color>
|
||||
<color name="lavender_onPrimaryContainer">#111129</color>
|
||||
<color name="lavender_secondary">#A177FF</color>
|
||||
<color name="lavender_onSecondary">#111129</color>
|
||||
<color name="lavender_secondaryContainer">#A177FF</color>
|
||||
<color name="lavender_onSecondaryContainer">#111129</color>
|
||||
<color name="lavender_tertiary">#5E25E1</color>
|
||||
<color name="lavender_onTertiary">#E8E8E8</color>
|
||||
<color name="lavender_tertiaryContainer">#111129</color>
|
||||
<color name="lavender_onTertiaryContainer">#DEE8FF</color>
|
||||
<color name="lavender_background">#111129</color>
|
||||
<color name="lavender_onBackground">#DEE8FF</color>
|
||||
<color name="lavender_surface">#111129</color>
|
||||
<color name="lavender_onSurface">#DEE8FF</color>
|
||||
<color name="lavender_surfaceVariant">#2CB6B6B6</color>
|
||||
<color name="lavender_onSurfaceVariant">#E8E8E8</color>
|
||||
<color name="lavender_outline">#A8905FFF</color>
|
||||
<color name="lavender_inverseOnSurface">#DEE8FF</color>
|
||||
<color name="lavender_inverseSurface">#221247</color>
|
||||
<color name="lavender_primaryInverse">#A177FF</color>
|
||||
<color name="lavender_elevationOverlay">@color/lavender_primary</color>
|
||||
</resources>
|
@ -1,2 +1,83 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
<resources>
|
||||
<string name="download_notifier_title_error">ତ୍ରୁଟି</string>
|
||||
<string name="date">ତାରିଖ</string>
|
||||
<string name="privacy_policy">ଗୋପନୀୟତା ନୀତି</string>
|
||||
<string name="black_background">କଳା</string>
|
||||
<string name="white_background">ଧଳା</string>
|
||||
<string name="nav_zone_left">ବାମ</string>
|
||||
<string name="nav_zone_right">ଡାହାଣ</string>
|
||||
<string name="left_to_right_viewer">ବାମରୁ ଡାହାଣ</string>
|
||||
<string name="right_to_left_viewer">ଡାହାଣରୁ ବାମ</string>
|
||||
<string name="zoom_start_left">ବାମ</string>
|
||||
<string name="zoom_start_right">ଡାହାଣ</string>
|
||||
<string name="version">ସଂସ୍କରଣ</string>
|
||||
<string name="description">ବର୍ଣ୍ଣନା</string>
|
||||
<string name="in_library">ଲାଇବ୍ରେରୀରେ</string>
|
||||
<string name="manga_info_full_title_label">ଆଖ୍ୟା</string>
|
||||
<string name="copied_to_clipboard">କ୍ଲିପବୋର୍ଡରେ କପି କରିନିଆଗଲା:
|
||||
\n%1$s</string>
|
||||
<string name="manga_cover">ମଲାଟ</string>
|
||||
<string name="learn_more">ଅଧିକ ଜାଣନ୍ତୁ</string>
|
||||
<string name="channel_progress">ପ୍ରଗତି</string>
|
||||
<string name="email">ଇମେଲ୍ ଠିକଣା</string>
|
||||
<string name="action_filter_started">ଆରମ୍ଭ କରିଛନ୍ତି</string>
|
||||
<string name="action_sort_alpha">ବର୍ଣ୍ଣମାଳା ଅନୁଯାୟୀ</string>
|
||||
<string name="action_newest">ସବୁଠୁ ନୂଆ</string>
|
||||
<string name="action_asc">ଆରୋହଣ</string>
|
||||
<string name="ext_language_info">ଭାଷା: %1$s</string>
|
||||
<string name="action_oldest">ସବୁଠୁ ପୁରୁଣା</string>
|
||||
<string name="add_to_library">ଲାଇବ୍ରେରୀରେ ଯୋଡ଼ନ୍ତୁ</string>
|
||||
<string name="action_desc">ଅବରୋହଣ</string>
|
||||
<string name="pref_category_library">ଲାଇବ୍ରେରୀ</string>
|
||||
<string name="pref_category_reader">ପାଠକ</string>
|
||||
<plurals name="relative_time">
|
||||
<item quantity="one">ଗତକାଲି</item>
|
||||
<item quantity="other">%1$d ଦିନ ପୂର୍ବେ</item>
|
||||
</plurals>
|
||||
<string name="title">ଆଖ୍ୟା</string>
|
||||
<string name="action_sort">ସଜାନ୍ତୁ</string>
|
||||
<string name="name">ନାମ</string>
|
||||
<string name="history">ଇତିବୃତ୍ତି</string>
|
||||
<string name="label_default">ଡିଫଲ୍ଟ</string>
|
||||
<string name="manga">ମାଙ୍ଗା</string>
|
||||
<string name="action_edit">ସମ୍ପାଦନା</string>
|
||||
<string name="action_add">ଯୋଡ଼ନ୍ତୁ</string>
|
||||
<string name="action_edit_cover">ମଲାଟ ସମ୍ପାଦନା</string>
|
||||
<string name="on">ଚାଲୁ</string>
|
||||
<string name="off">ବନ୍ଦ</string>
|
||||
<string name="action_sort_date_added">ଯୋଡ଼ାଯିବା ତାରିଖ</string>
|
||||
<string name="action_select_all">ସବୁ ଚୟନ କରନ୍ତୁ</string>
|
||||
<string name="pref_incognito_mode">ଅପରିଚିତ ମୋଡ୍</string>
|
||||
<string name="action_display_language_badge">ଭାଷା</string>
|
||||
<string name="action_menu">ମେନୁ</string>
|
||||
<string name="action_filter">ଶୋଧନ</string>
|
||||
<string name="action_filter_downloaded">ଡାଉନଲୋଡ୍ ହୋଇଅଛି</string>
|
||||
<string name="action_filter_bookmarked">ବୁକମାର୍କ ହୋଇଅଛି</string>
|
||||
<string name="action_filter_tracked">ଟ୍ରାକ୍ ହୋଇଅଛି</string>
|
||||
<string name="action_filter_unread">ପଢ଼ି ନାହାଁନ୍ତି</string>
|
||||
<string name="action_filter_empty">ଶୋଧକ ହଟାନ୍ତୁ</string>
|
||||
<string name="action_sort_count">ସର୍ବମୋଟ ମାଙ୍ଗା</string>
|
||||
<string name="action_sort_last_read">ଶେଷ ପଠନ</string>
|
||||
<string name="action_sort_chapter_fetch_date">ଅଣାଯିବା ତାରିଖ</string>
|
||||
<string name="pref_category_advanced">ବିକଶିତ</string>
|
||||
<string name="pref_category_theme">ଥିମ୍</string>
|
||||
<string name="pref_theme_mode">ଗାଢ଼ ମୋଡ୍</string>
|
||||
<string name="theme_light">ବନ୍ଦ</string>
|
||||
<string name="theme_dark">ଚାଲୁ</string>
|
||||
<string name="pref_app_theme">ଆପ୍ ଥିମ୍</string>
|
||||
<string name="password">ପାସ୍ୱାର୍ଡ଼</string>
|
||||
<string name="update_never">ବନ୍ଦ</string>
|
||||
<string name="pref_category_appearance">ରୂପ</string>
|
||||
<string name="theme_system">ସିଷ୍ଟମ୍ କୁ ଅନୁସରଣ କରିବା</string>
|
||||
<string name="relative_time_today">ଆଜି</string>
|
||||
<string name="portrait">ପୋର୍ଟ୍ରେଟ୍</string>
|
||||
<string name="landscape">ଲ୍ୟାଣ୍ଡସ୍କେପ୍</string>
|
||||
<string name="update_48hour">ପ୍ରତି ୨ ଦିନରେ</string>
|
||||
<string name="ext_app_info">ଆପ୍ ସୂଚନା</string>
|
||||
<string name="ext_version_info">ସଂସ୍କରଣ: %1$s</string>
|
||||
<string name="pref_keep_screen_on">ସ୍କ୍ରିନ୍ ସଚଳ ରଖନ୍ତୁ</string>
|
||||
<string name="update_6hour">ପ୍ରତି ୬ ଘଣ୍ଟାରେ</string>
|
||||
<string name="update_12hour">ପ୍ରତି ୧୨ ଘଣ୍ଟାରେ</string>
|
||||
<string name="update_72hour">ପ୍ରତି ୩ ଦିନରେ</string>
|
||||
</resources>
|
@ -82,7 +82,7 @@
|
||||
<string name="all">Todas</string>
|
||||
<string name="pref_library_update_restriction">Restrições do dispositivo para atualizações automáticas</string>
|
||||
<string name="charging">Carregando</string>
|
||||
<string name="pref_update_only_non_completed">É uma série finalizada</string>
|
||||
<string name="pref_update_only_non_completed">Com o estado \"Completo\"</string>
|
||||
<string name="pref_auto_update_manga_sync">Atualizar o progresso após a leitura</string>
|
||||
<string name="pref_start_screen">Tela inicial</string>
|
||||
<string name="default_category">Categoria padrão</string>
|
||||
@ -672,7 +672,7 @@
|
||||
<string name="pref_verbose_logging_summary">Imprime registros detalhados no registro de eventos do sistema (reduz o desempenho do aplicativo)</string>
|
||||
<string name="pref_verbose_logging">Registro de eventos verboso</string>
|
||||
<string name="action_display_language_badge">Idioma</string>
|
||||
<string name="notification_size_warning">Aviso: atualizações com muitos itens prejudicam as fontes e podem deixar as atualizações lentas e aumentar o uso da bateria</string>
|
||||
<string name="notification_size_warning">Atualizações com muitos itens prejudicam as fontes e podem deixar as atualizações lentas e aumentar o uso da bateria</string>
|
||||
<string name="label_warning">Aviso</string>
|
||||
<string name="backup_info">Backups automáticos são altamente recomendados. Você deve manter cópias em outros locais também.</string>
|
||||
<string name="connected_to_wifi">Somente no Wi-Fi</string>
|
||||
@ -686,8 +686,8 @@
|
||||
<string name="database_clean">Banco de dados limpo</string>
|
||||
<string name="extension_api_error">Erro ao obter a lista de extensões</string>
|
||||
<string name="privacy_policy">Política de privacidade</string>
|
||||
<string name="pref_update_only_completely_read">Possui capítulos não lidos</string>
|
||||
<string name="pref_library_update_manga_restriction">Pular a atualização</string>
|
||||
<string name="pref_update_only_completely_read">Com capítulos não lidos</string>
|
||||
<string name="pref_library_update_manga_restriction">Pular a atualização de títulos</string>
|
||||
<string name="library_errors_help">Para obter ajuda sobre como corrigir erros de atualização da biblioteca, veja %1$s</string>
|
||||
<string name="save_chapter_as_cbz">Salvar como arquivo CBZ</string>
|
||||
<string name="publishing_finished">Publicação finalizada</string>
|
||||
@ -704,15 +704,17 @@
|
||||
<string name="pref_landscape_zoom">Dar zoom em imagens horizontais</string>
|
||||
<string name="action_display_cover_only_grid">Grade somente com capas</string>
|
||||
<string name="action_filter_started">Iniciado</string>
|
||||
<string name="pref_update_only_started">Sem capítulos lidos</string>
|
||||
<string name="pref_update_only_started">Que não tiveram a leitura iniciada</string>
|
||||
<string name="skipped_reason_completed">Pulado porque a série está finalizada</string>
|
||||
<string name="skipped_reason_not_caught_up">Pulado porque há capítulos não lidos</string>
|
||||
<string name="skipped_reason_not_started">Pulado porque nenhum capítulo foi lido</string>
|
||||
<string name="notification_update_skipped">%1$d atualização(ões) pulada(s)</string>
|
||||
<string name="channel_skipped">Puladas</string>
|
||||
<string name="notification_update_error">%1$d atualização(ões) falhou(aram)</string>
|
||||
<string name="learn_more">Saiba mais</string>
|
||||
<string name="learn_more">Toque para saber mais</string>
|
||||
<string name="rotation_reverse_portrait">Retrato invertido</string>
|
||||
<string name="action_move_to_top_all_for_series">Mover série para o topo</string>
|
||||
<string name="disabled_nav">Desativado</string>
|
||||
<string name="update_check_fdroid_migration_info">Uma nova versão está disponível nos releases oficiais. Toque para saber como migrar dos releases não oficiais do F-Droid.</string>
|
||||
<string name="error_saving_picture">Erro ao salvar a imagem</string>
|
||||
</resources>
|
@ -620,4 +620,7 @@
|
||||
<string name="theme_tako">Tako</string>
|
||||
<string name="theme_yinyang">Yin și Yang</string>
|
||||
<string name="theme_yotsuba">Yotsuba</string>
|
||||
<string name="publishing_finished">Editare finalizată</string>
|
||||
<string name="cancelled">Anulat</string>
|
||||
<string name="on_hiatus">În pauză</string>
|
||||
</resources>
|
@ -156,7 +156,7 @@
|
||||
<string name="pref_rotation_type">Ориентация по умолчанию</string>
|
||||
<string name="pref_show_page_number">Номер страницы</string>
|
||||
<string name="pref_start_screen">Начальный экран</string>
|
||||
<string name="pref_update_only_non_completed">Завершенная серия</string>
|
||||
<string name="pref_update_only_non_completed">Серия завершена</string>
|
||||
<string name="pref_viewer_type">Режим чтения</string>
|
||||
<string name="pref_zoom_start">Стартовая позиция увеличения</string>
|
||||
<string name="reading">Читаю</string>
|
||||
@ -696,7 +696,7 @@
|
||||
<string name="pref_verbose_logging_summary">Записывать подробный журнал в системный журнал (снижает производительность приложения)</string>
|
||||
<string name="action_display_language_badge">Язык</string>
|
||||
<string name="label_warning">Предупреждение</string>
|
||||
<string name="notification_size_warning">Предупреждение: большое количество обновлений серий могут привести к замедлению работы источников и увеличению расхода батареи</string>
|
||||
<string name="notification_size_warning">Большое количество обновлений серий могут привести к замедлению работы источников и увеличению расхода батареи</string>
|
||||
<string name="backup_info">Настоятельно рекомендуется использовать автоматические резервные копии. Вы также должны хранить копии в разных папках.</string>
|
||||
<string name="connected_to_wifi">Только по Wi-Fi</string>
|
||||
<string name="update_72hour">Каждые 3 дня</string>
|
||||
@ -709,8 +709,8 @@
|
||||
<string name="database_clean">Очистка базы данных</string>
|
||||
<string name="extension_api_error">Не удалось получить список расширений</string>
|
||||
<string name="privacy_policy">Политика конфиденциальности</string>
|
||||
<string name="pref_update_only_completely_read">Имеет непрочитанные главы</string>
|
||||
<string name="pref_library_update_manga_restriction">Пропускать обновление</string>
|
||||
<string name="pref_update_only_completely_read">Есть непрочитанные главы</string>
|
||||
<string name="pref_library_update_manga_restriction">Пропускать обновления</string>
|
||||
<string name="library_errors_help">Для помощи в исправлении ошибок библиотеки, нажать %1$s</string>
|
||||
<string name="save_chapter_as_cbz">Сохранить как архив CBZ</string>
|
||||
<string name="cancelled">Отменено</string>
|
||||
@ -731,11 +731,13 @@
|
||||
<string name="skipped_reason_completed">Пропущено, так как серия завершена</string>
|
||||
<string name="skipped_reason_not_caught_up">Пропущено, потому что есть непрочитанные главы</string>
|
||||
<string name="skipped_reason_not_started">Пропущено, потому что серия не начата</string>
|
||||
<string name="learn_more">Подробнее</string>
|
||||
<string name="learn_more">Нажать для подробностей</string>
|
||||
<string name="channel_skipped">Пропущено</string>
|
||||
<string name="notification_update_error">%1$d обновление(ий) не удалось</string>
|
||||
<string name="notification_update_skipped">%1$d обновление(ий) пропущено</string>
|
||||
<string name="rotation_reverse_portrait">Портретная наоборот</string>
|
||||
<string name="action_move_to_top_all_for_series">Переместить серию в начало</string>
|
||||
<string name="disabled_nav">Отключено</string>
|
||||
<string name="update_check_fdroid_migration_info">Новая версия доступна на оф. странице Tachiyomi. Нажмите, чтобы узнать как мигрировать с неофициальной версии из F-Droid.</string>
|
||||
<string name="error_saving_picture">Не удалось сохранить изображение</string>
|
||||
</resources>
|
@ -689,7 +689,7 @@
|
||||
<string name="save_chapter_as_cbz">Sarva comente archìviu CBZ</string>
|
||||
<string name="library_errors_help">Pro tènnere un\'agiudu pro acontzare sos errores de agiornamentu de sa biblioteca pòmpia·ti %1$s</string>
|
||||
<string name="pref_library_update_manga_restriction">Brinca sos agiornamentos</string>
|
||||
<string name="pref_update_only_completely_read">Tenet capìtulos non lèghidos</string>
|
||||
<string name="pref_update_only_completely_read">Cun capìtulos non lèghidos</string>
|
||||
<string name="action_faq_and_guides">PF e ghias</string>
|
||||
<string name="publishing_finished">Publicatzione acabada</string>
|
||||
<string name="on_hiatus">In pàusa</string>
|
||||
@ -700,7 +700,7 @@
|
||||
<string name="pref_landscape_zoom">Ismànnia s\'immàgine in orizontale</string>
|
||||
<string name="action_filter_started">Incumintzadu</string>
|
||||
<string name="action_display_cover_only_grid">Grìllia cun coberteddas ebbia</string>
|
||||
<string name="pref_update_only_started">Perunu capìtulu lèghidu</string>
|
||||
<string name="pref_update_only_started">No incumintzadas</string>
|
||||
<string name="confirm_manga_add_duplicate">Tenes un\'elementu in sa biblioteca tua cun su matessi nùmene ma dae una fonte diferente (%1$s).
|
||||
\n
|
||||
\nBoles sighire su matessi\?</string>
|
||||
@ -708,10 +708,13 @@
|
||||
<string name="skipped_reason_completed">Brincadu ca sa sèrie est acabada</string>
|
||||
<string name="skipped_reason_not_caught_up">Brincadu ca bi sunt capìtulos non lèghidos</string>
|
||||
<string name="skipped_reason_not_started">Brincadu ca non bi sunt capìtulos lèghidos</string>
|
||||
<string name="learn_more">Àteras informatziones</string>
|
||||
<string name="learn_more">Toca pro àteras informatziones</string>
|
||||
<string name="channel_skipped">Brincadu</string>
|
||||
<string name="notification_update_error">%1$d agiornamentu(os) fallidu(os)</string>
|
||||
<string name="notification_update_skipped">%1$d agiornamentu(os) brincadu(os)</string>
|
||||
<string name="rotation_reverse_portrait">Verticale a s\'imbesse</string>
|
||||
<string name="action_move_to_top_all_for_series">Move sa sèrie cara a pitzos</string>
|
||||
<string name="disabled_nav">Disabilitadu</string>
|
||||
<string name="error_saving_picture">Errore in su sarvamentu de s\'immàgine</string>
|
||||
<string name="update_check_fdroid_migration_info">B\'est una versione noa ufitziale a disponimentu. Toca pro imparare comente tramudare dae sas versiones no ufitziales de F-Droid.</string>
|
||||
</resources>
|
@ -274,7 +274,7 @@
|
||||
<string name="lock_always">Увек</string>
|
||||
<string name="lock_never">Никада</string>
|
||||
<plurals name="lock_after_mins">
|
||||
<item quantity="one">Након %1$s минут</item>
|
||||
<item quantity="one">After 1%1$s minutes</item>
|
||||
<item quantity="few">Након %1$s минута</item>
|
||||
<item quantity="other">Након %1$s минута</item>
|
||||
</plurals>
|
||||
@ -495,9 +495,9 @@
|
||||
<string name="pref_category_reading_mode">Начин читања</string>
|
||||
<string name="ext_installer_pref">Instaler</string>
|
||||
<plurals name="missing_chapters_warning">
|
||||
<item quantity="one">Прескаче се %d поглавље, или не постоји у извору или је филтером издвојено</item>
|
||||
<item quantity="few">Прескаче се %d поглавља, или не постоји у извору или је филтером издвојено</item>
|
||||
<item quantity="other">Прескаче се %d поглавља, или не постоји у извору или је филтером издвојено</item>
|
||||
<item quantity="one">Preskače se %d poglavlje,ili ne postoji u izvori ili su izdvojeni filterom</item>
|
||||
<item quantity="few">Preskače se %d poglavlje,ili ne postoji u izvori ili su izdvojeni filterom</item>
|
||||
<item quantity="other">Preskače se %d poglavlje,ili ne postoji u izvori ili su izdvojeni filterom</item>
|
||||
</plurals>
|
||||
<string name="pref_category_auto_download">Аутоматско преузимање</string>
|
||||
<string name="action_track">Прати</string>
|
||||
@ -529,9 +529,9 @@
|
||||
<string name="unknown_status">Nepoznat status</string>
|
||||
<string name="local_filter_order_by">Poređaj po</string>
|
||||
<plurals name="num_trackers">
|
||||
<item quantity="one">%d трекер</item>
|
||||
<item quantity="few">%d трекера</item>
|
||||
<item quantity="other">%d трекера</item>
|
||||
<item quantity="one">%d tragač</item>
|
||||
<item quantity="few">%d tragača</item>
|
||||
<item quantity="other">%d tragač</item>
|
||||
</plurals>
|
||||
<string name="enhanced_services">Побољшани сервиси</string>
|
||||
<string name="tracker_not_logged_in">Нисте пријаљени у: %1$s</string>
|
||||
@ -711,7 +711,7 @@
|
||||
\n
|
||||
\nDa li i dalje želite da nastavite\?</string>
|
||||
<string name="notification_update_error">%1$d ažuriranje nije uspelo</string>
|
||||
<string name="learn_more">Saznajte više</string>
|
||||
<string name="learn_more">Pritisnite za više</string>
|
||||
<string name="library_errors_help">Za pomoć o tome kako da popravite greške u ažuriranju kolekcije, pogledajte %1$s</string>
|
||||
<string name="skipped_reason_not_started">Preskočeno jer nijedno poglavlje nije pročitano</string>
|
||||
<string name="channel_skipped">Preskočeno</string>
|
||||
@ -726,4 +726,5 @@
|
||||
<string name="notification_update_skipped">%1$d ažuriranje je preskočeno</string>
|
||||
<string name="skipped_reason_completed">Preskočeno jer je serijal završen</string>
|
||||
<string name="skipped_reason_not_caught_up">Preskočeno jer ima nepročitanih poglavlja</string>
|
||||
<string name="disabled_nav">Onesposobljen</string>
|
||||
</resources>
|
@ -87,7 +87,7 @@
|
||||
<string name="all">Alla</string>
|
||||
<string name="pref_library_update_restriction">Automatiska uppdateringar av enhetsbegränsningar</string>
|
||||
<string name="charging">Laddning</string>
|
||||
<string name="pref_update_only_non_completed">Är avslutad serie</string>
|
||||
<string name="pref_update_only_non_completed">Med status \"Avslutat\"</string>
|
||||
<string name="pref_auto_update_manga_sync">Uppdatera förlopp efter läsning</string>
|
||||
<string name="pref_start_screen">Startskärm</string>
|
||||
<string name="default_category">Standardkategori</string>
|
||||
@ -686,20 +686,20 @@
|
||||
<string name="database_clean">Rengör databasen</string>
|
||||
<string name="backup_restore_invalid_uri">Fel: tom URI</string>
|
||||
<string name="library_errors_help">För hjälp med att åtgärda fel i biblioteksuppdateringar, se %1$s</string>
|
||||
<string name="pref_library_update_manga_restriction">Hoppa över uppdatering</string>
|
||||
<string name="pref_library_update_manga_restriction">Hoppa över att uppdatera titlar</string>
|
||||
<string name="cancelled">Avbruten</string>
|
||||
<string name="on_hiatus">På uppehåll</string>
|
||||
<string name="publishing_finished">Publiceringen avslutad</string>
|
||||
<string name="save_chapter_as_cbz">Spara som CBZ-arkiv</string>
|
||||
<string name="privacy_policy">Integritetspolicy</string>
|
||||
<string name="action_faq_and_guides">Vanliga frågor och guider</string>
|
||||
<string name="pref_update_only_completely_read">Har olästa kapitel</string>
|
||||
<string name="pref_update_only_completely_read">Med olästa kapitel</string>
|
||||
<string name="extension_api_error">Det gick inte att hämta tilläggslistan</string>
|
||||
<string name="webtoon_side_padding_5">5%</string>
|
||||
<string name="action_show_manga">Visa manga</string>
|
||||
<string name="action_filter_started">Startad</string>
|
||||
<string name="action_display_cover_only_grid">Endast omslags-rutnät</string>
|
||||
<string name="pref_update_only_started">Inga lästa kapitel</string>
|
||||
<string name="pref_update_only_started">Som inte har startats</string>
|
||||
<string name="pref_navigate_pan">Navigera till pan</string>
|
||||
<string name="confirm_manga_add_duplicate">Du har en post i ditt bibliotek med samma namn men från en annan källa (%1$s).
|
||||
\n
|
||||
@ -708,10 +708,13 @@
|
||||
<string name="skipped_reason_completed">Hoppade över eftersom serien är klar</string>
|
||||
<string name="skipped_reason_not_caught_up">Hoppade över eftersom det finns olästa kapitel</string>
|
||||
<string name="skipped_reason_not_started">Hoppade över eftersom inga kapitel läses</string>
|
||||
<string name="learn_more">Läs mer</string>
|
||||
<string name="learn_more">Tryck på för att få veta mer</string>
|
||||
<string name="notification_update_error">%1$d uppdatering(ar) misslyckades</string>
|
||||
<string name="notification_update_skipped">%1$d uppdatering(ar) hoppades över</string>
|
||||
<string name="channel_skipped">Hoppat över</string>
|
||||
<string name="rotation_reverse_portrait">Omvänt porträtt</string>
|
||||
<string name="action_move_to_top_all_for_series">Flytta serien till toppen</string>
|
||||
<string name="disabled_nav">Inaktiverad</string>
|
||||
<string name="error_saving_picture">Fel vid lagring av bild</string>
|
||||
<string name="update_check_fdroid_migration_info">En ny version finns tillgänglig i de officiella utgåvorna. Tryck på för att lära dig hur du flyttar från inofficiella F-Droid-versioner.</string>
|
||||
</resources>
|
@ -702,4 +702,5 @@
|
||||
<string name="channel_skipped">ข้ามแล้ว</string>
|
||||
<string name="rotation_reverse_portrait">แนวตั้งแบบกลับด้าน</string>
|
||||
<string name="action_move_to_top_all_for_series">ย้ายเรื่องไปด้านบน</string>
|
||||
<string name="disabled_nav">ปิดใช้งาน</string>
|
||||
</resources>
|
@ -87,7 +87,7 @@
|
||||
<string name="all">Tümü</string>
|
||||
<string name="pref_library_update_restriction">Otomatik güncellemeler aygıt kısıtlamaları</string>
|
||||
<string name="charging">Şarj oluyor</string>
|
||||
<string name="pref_update_only_non_completed">Tamamlanan seriler</string>
|
||||
<string name="pref_update_only_non_completed">\"Tamamlanan\" durumda olan</string>
|
||||
<string name="pref_auto_update_manga_sync">Okuyunca ilerlemeyi güncelle</string>
|
||||
<string name="pref_start_screen">Başlangıç ekranı</string>
|
||||
<string name="default_category">Varsayılan kategori</string>
|
||||
@ -672,7 +672,7 @@
|
||||
<string name="label_warning">Uyarı</string>
|
||||
<string name="action_display_language_badge">Dil</string>
|
||||
<string name="backup_info">Otomatik yedeklemeler şiddetle tavsiye edilir. Kopyaları başka yerlerde de tutmalısınız.</string>
|
||||
<string name="notification_size_warning">Uyarı: büyük güncellemeler kaynaklara zarar verir ve daha yavaş güncellemelere ve de pil kullanımının artmasına neden olabilir</string>
|
||||
<string name="notification_size_warning">Büyük güncellemeler kaynaklara zarar verir ve daha yavaş güncellemelere ve ayrıca pil kullanımının artmasına neden olabilir</string>
|
||||
<string name="pref_verbose_logging">Ayrıntılı günlük kaydı</string>
|
||||
<string name="pref_verbose_logging_summary">Ayrıntılı günlükleri sistem günlüğüne yaz (uygulama performansını düşürür)</string>
|
||||
<string name="connected_to_wifi">Yalnızca Wi-Fi\'de</string>
|
||||
@ -685,7 +685,7 @@
|
||||
<string name="clear_database_source_item_count">Veri tabanında %1$d kitaplık dışı manga</string>
|
||||
<string name="database_clean">Veri tabanı temiz</string>
|
||||
<string name="extension_api_error">Uzantı listesi alınamadı</string>
|
||||
<string name="pref_library_update_manga_restriction">Güncellemeyi atla</string>
|
||||
<string name="pref_library_update_manga_restriction">Başlıkları güncellemeyi atla</string>
|
||||
<string name="save_chapter_as_cbz">CBZ arşivi olarak kaydet</string>
|
||||
<string name="publishing_finished">Yayımı tamamlandı</string>
|
||||
<string name="privacy_policy">Gizlilik politikası</string>
|
||||
@ -701,8 +701,8 @@
|
||||
<string name="action_display_cover_only_grid">Sadece-kapak ızgara</string>
|
||||
<string name="backup_restore_invalid_uri">Hata: boş URI</string>
|
||||
<string name="action_faq_and_guides">SSS ve Kılavuzlar</string>
|
||||
<string name="pref_update_only_completely_read">Okunmayan bölümleri olan</string>
|
||||
<string name="pref_update_only_started">Yalnızca okumaya başlanan mangaları güncelleme</string>
|
||||
<string name="pref_update_only_completely_read">Okunmayan bölüm(ler)i olan</string>
|
||||
<string name="pref_update_only_started">Bu başlamadı</string>
|
||||
<string name="skipped_reason_completed">Manga tamamlandığı için atlandı</string>
|
||||
<string name="skipped_reason_not_caught_up">Okunmamış bölümler olduğu için atlandı</string>
|
||||
<string name="skipped_reason_not_started">Hiçbir bölüm okunmadığı için atlandı</string>
|
||||
@ -710,9 +710,11 @@
|
||||
<string name="pref_landscape_zoom">Yatay görseli yakınlaştır</string>
|
||||
<string name="notification_update_error">%1$d güncelleme başarısız oldu</string>
|
||||
<string name="notification_update_skipped">%1$d güncelleme atlandı</string>
|
||||
<string name="learn_more">Daha fazla bilgi edin</string>
|
||||
<string name="learn_more">Daha fazla bilgi edinmek için dokunun</string>
|
||||
<string name="channel_skipped">Atlandı</string>
|
||||
<string name="rotation_reverse_portrait">Ters dikey</string>
|
||||
<string name="action_move_to_top_all_for_series">Seriyi en üste taşı</string>
|
||||
<string name="disabled_nav">Devre dışı</string>
|
||||
<string name="update_check_fdroid_migration_info">Resmi yayınlardan yeni bir sürüm var. Resmi olmayan F-Droid sürümlerinden nasıl geçiş yapacağınızı öğrenmek için dokunun.</string>
|
||||
<string name="error_saving_picture">Resim kaydedilirken hata oluştu</string>
|
||||
</resources>
|
@ -629,7 +629,7 @@
|
||||
<string name="date">Ngày</string>
|
||||
<string name="local_filter_order_by">Xếp theo</string>
|
||||
<string name="local_invalid_format">Định dạng chương không đúng</string>
|
||||
<string name="chapter_not_found">Chương không tìm thấy</string>
|
||||
<string name="chapter_not_found">Không tìm thấy chương</string>
|
||||
<string name="on">Bật</string>
|
||||
<string name="off">Tắt</string>
|
||||
<string name="pref_library_update_refresh_trackers_summary">Cập nhật theo dõi khi cập nhật thư viện</string>
|
||||
@ -736,4 +736,5 @@
|
||||
<string name="skipped_reason_not_started">Đã bỏ qua vì không có chương được đọc</string>
|
||||
<string name="channel_skipped">Bỏ qua</string>
|
||||
<string name="action_move_to_top_all_for_series">Di chuyển bộ truyện lên đầu</string>
|
||||
<string name="disabled_nav">Vô hiệu hóa</string>
|
||||
</resources>
|
@ -87,7 +87,7 @@
|
||||
<string name="all">全部</string>
|
||||
<string name="pref_library_update_restriction">设备自动更新限制</string>
|
||||
<string name="charging">正在充电</string>
|
||||
<string name="pref_update_only_non_completed">已完结连载</string>
|
||||
<string name="pref_update_only_non_completed">状态为“已完结”</string>
|
||||
<string name="pref_auto_update_manga_sync">阅读后更新进度</string>
|
||||
<string name="pref_start_screen">起始页面</string>
|
||||
<string name="default_category">默认分类</string>
|
||||
@ -662,7 +662,7 @@
|
||||
<string name="label_warning">警告</string>
|
||||
<string name="action_display_language_badge">语言</string>
|
||||
<string name="backup_info">强烈建议启用自动备份,你也应该在其他地方保存副本。</string>
|
||||
<string name="notification_size_warning">警告:大型更新会损害图源,并可能导致更新速度变慢以及电池用量增加</string>
|
||||
<string name="notification_size_warning">大型更新会损害图源,并可能导致更新速度变慢以及电池用量增加</string>
|
||||
<string name="connected_to_wifi">仅连接至 Wi-Fi 时</string>
|
||||
<string name="update_72hour">每 3 天</string>
|
||||
<string name="download_queue_size_warning">警告:批量下载可能会导致图源变慢和/或图源封锁 Tachiyomi</string>
|
||||
@ -674,8 +674,8 @@
|
||||
<string name="clear_database_source_item_count">数据库有 %1$d 本漫画不在书架中</string>
|
||||
<string name="extension_api_error">无法获取扩展插件列表</string>
|
||||
<string name="privacy_policy">隐私政策</string>
|
||||
<string name="pref_update_only_completely_read">有未读完的章节</string>
|
||||
<string name="pref_library_update_manga_restriction">跳过更新</string>
|
||||
<string name="pref_update_only_completely_read">有未读章节</string>
|
||||
<string name="pref_library_update_manga_restriction">跳过更新标题</string>
|
||||
<string name="library_errors_help">有关如何修复库更新错误的帮助,请参阅 %1$s</string>
|
||||
<string name="save_chapter_as_cbz">保存为 CBZ 存档</string>
|
||||
<string name="publishing_finished">发布完成</string>
|
||||
@ -692,15 +692,17 @@
|
||||
\n
|
||||
\n你仍希望继续吗?</string>
|
||||
<string name="action_filter_started">已开始</string>
|
||||
<string name="pref_update_only_started">无已读章节</string>
|
||||
<string name="pref_update_only_started">尚未开始</string>
|
||||
<string name="skipped_reason_completed">跳过,因连载完结</string>
|
||||
<string name="skipped_reason_not_caught_up">跳过,因有未读章节</string>
|
||||
<string name="skipped_reason_not_started">跳过,因无已读章节</string>
|
||||
<string name="learn_more">了解更多</string>
|
||||
<string name="learn_more">轻按了解更多</string>
|
||||
<string name="notification_update_error">%1$d 个更新失败了</string>
|
||||
<string name="notification_update_skipped">已跳过 %1$d 个更新</string>
|
||||
<string name="channel_skipped">已跳过</string>
|
||||
<string name="rotation_reverse_portrait">反转竖屏</string>
|
||||
<string name="action_move_to_top_all_for_series">将连载移动到顶部</string>
|
||||
<string name="action_move_to_top_all_for_series">将连载置顶</string>
|
||||
<string name="disabled_nav">已禁用</string>
|
||||
<string name="error_saving_picture">保存图片出错</string>
|
||||
<string name="update_check_fdroid_migration_info">新版本可从官方版本中获得。 轻按以了解如何从非官方 F-Droid 版本迁移。</string>
|
||||
</resources>
|
@ -506,7 +506,7 @@
|
||||
<string name="pref_category_delete_chapters">刪除章節</string>
|
||||
<string name="chapter_settings_updated">已更新章節設定預設值</string>
|
||||
<plurals name="missing_chapters_warning">
|
||||
<item quantity="other">略過了 %d 章,也許是來源沒有這些章節,或其已被你的篩選規則排除</item>
|
||||
<item quantity="other">略過了 %d 章,也許是來源沒有這些章節,或其已被篩選規則排除</item>
|
||||
</plurals>
|
||||
<string name="action_search_settings">搜尋設定</string>
|
||||
<string name="chapter_settings">章節設定</string>
|
||||
@ -701,4 +701,6 @@
|
||||
<string name="notification_update_error">%1$d 項更新失敗</string>
|
||||
<string name="notification_update_skipped">已略過 %1$d 項更新</string>
|
||||
<string name="channel_skipped">略過</string>
|
||||
<string name="action_move_to_top_all_for_series">置頂此叢書</string>
|
||||
<string name="disabled_nav">已停用</string>
|
||||
</resources>
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user