Compare commits

...

30 Commits
v9.1 ... v9.1.3

Author SHA1 Message Date
Koitharu
bc68441585 Update parsers 2025-08-24 11:06:16 +03:00
Koitharu
1cc51b6a88 Refactor usage WebView for parsers 2025-08-24 10:39:23 +03:00
Kusou
fd5aca7252 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (868 of 868 strings)

Co-authored-by: Kusou <orion26br@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt_BR/
Translation: Kotatsu/Strings
2025-08-24 10:14:59 +03:00
Abay Emes
e447245fac Translated using Weblate (Kazakh)
Currently translated at 100.0% (9 of 9 strings)

Translated using Weblate (Kazakh)

Currently translated at 62.5% (543 of 868 strings)

Co-authored-by: Abay Emes <abayemes@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/kk/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/kk/
Translation: Kotatsu/Strings
Translation: Kotatsu/plurals
2025-08-24 10:14:59 +03:00
Draken
5af0ee1c69 Translated using Weblate (Vietnamese)
Currently translated at 100.0% (868 of 868 strings)

Co-authored-by: Draken <premieregirl26@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/vi/
Translation: Kotatsu/Strings
2025-08-24 10:14:59 +03:00
Shayan
c02d1641ab Translated using Weblate (Persian)
Currently translated at 59.2% (514 of 868 strings)

Co-authored-by: Shayan <shayans31516@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fa/
Translation: Kotatsu/Strings
2025-08-24 10:14:59 +03:00
Aray LXa
f55c525c8a Translated using Weblate (Persian)
Currently translated at 59.2% (514 of 868 strings)

Co-authored-by: Aray LXa <araylxa@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fa/
Translation: Kotatsu/Strings
2025-08-24 10:14:59 +03:00
Максим Горпиніч
a42fc87a9a Translated using Weblate (Ukrainian)
Currently translated at 100.0% (868 of 868 strings)

Co-authored-by: Максим Горпиніч <gorpinicmaksim0@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/uk/
Translation: Kotatsu/Strings
2025-08-24 10:14:59 +03:00
Juan Rubin
6b6905fd71 Translated using Weblate (Portuguese)
Currently translated at 100.0% (868 of 868 strings)

Co-authored-by: Juan Rubin <juancrubin08@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt/
Translation: Kotatsu/Strings
2025-08-24 10:14:59 +03:00
Koitharu
b7f57856db Author search support for external manga sources 2025-08-24 10:13:12 +03:00
Koitharu
1d6d626b62 Update parsers 2025-08-24 09:47:29 +03:00
Koitharu
d93ff92cc9 Update parsers and fix some deprecations 2025-08-16 08:11:44 +03:00
Koitharu
8eda113f3b Captcha group notification intent 2025-08-14 15:57:18 +03:00
Koitharu
3916c2619e Update parsers 2025-08-14 11:51:33 +03:00
Milo Ivir
1d3e8e55ca Translated using Weblate (Croatian)
Currently translated at 94.0% (816 of 868 strings)

Translated using Weblate (Croatian)

Currently translated at 92.7% (805 of 868 strings)

Co-authored-by: Milo Ivir <mail@milotype.de>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hr/
Translation: Kotatsu/Strings
2025-08-14 11:24:16 +03:00
Manuela Silva
2c3b4f29eb Translated using Weblate (Portuguese)
Currently translated at 97.8% (849 of 868 strings)

Co-authored-by: Manuela Silva <mmsrs@sky.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt/
Translation: Kotatsu/Strings
2025-08-14 11:24:16 +03:00
Marco Ramazzotti
ee530002b6 Translated using Weblate (Japanese)
Currently translated at 55.1% (479 of 868 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (868 of 868 strings)

Co-authored-by: Marco Ramazzotti <cuordilava@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/it/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ja/
Translation: Kotatsu/Strings
2025-08-14 11:24:16 +03:00
Lorenzo Stella
59d530e0dc Translated using Weblate (Italian)
Currently translated at 100.0% (868 of 868 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (868 of 868 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (868 of 868 strings)

Co-authored-by: Lorenzo Stella <lorenzo.stella.1408@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/it/
Translation: Kotatsu/Strings
2025-08-14 11:24:16 +03:00
Nicola Bortoletto
52a132caed Translated using Weblate (Italian)
Currently translated at 100.0% (868 of 868 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (868 of 868 strings)

Co-authored-by: Nicola Bortoletto <nicola.bortoletto@live.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/it/
Translation: Kotatsu/Strings
2025-08-14 11:24:16 +03:00
Макар Разин
379d2dd8d4 Translated using Weblate (Russian)
Currently translated at 100.0% (868 of 868 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (868 of 868 strings)

Co-authored-by: Макар Разин <makarrazin14@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/be/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ru/
Translation: Kotatsu/Strings
2025-08-14 11:24:16 +03:00
R2E
f8cefa3e8d Translated using Weblate (Arabic)
Currently translated at 92.9% (807 of 868 strings)

Co-authored-by: R2E <mokhalad875@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ar/
Translation: Kotatsu/Strings
2025-08-14 11:24:16 +03:00
Champ0999
5e1eda850c Translated using Weblate (Italian)
Currently translated at 99.8% (867 of 868 strings)

Co-authored-by: Champ0999 <champ0999@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/it/
Translation: Kotatsu/Strings
2025-08-14 11:24:16 +03:00
gekka
18cc0ad0fb Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.5% (864 of 868 strings)

Co-authored-by: gekka <1778962971@qq.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2025-08-14 11:24:16 +03:00
Kuraki
11dd49c626 Translated using Weblate (Turkish)
Currently translated at 100.0% (868 of 868 strings)

Co-authored-by: Kuraki <qkuraki@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translation: Kotatsu/Strings
2025-08-14 11:24:16 +03:00
Draken
2ad8ab0258 Translated using Weblate (Vietnamese)
Currently translated at 100.0% (868 of 868 strings)

Co-authored-by: Draken <premieregirl26@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/vi/
Translation: Kotatsu/Strings
2025-08-14 11:24:16 +03:00
Dragibus Noir
4f8c5325a4 Translated using Weblate (French)
Currently translated at 100.0% (868 of 868 strings)

Co-authored-by: Dragibus Noir <big.confetti700@aleeas.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fr/
Translation: Kotatsu/Strings
2025-08-14 11:24:16 +03:00
Koitharu
6e181a59a3 Update sync auth activity ui 2025-08-14 10:39:06 +03:00
Koitharu
7a7d20dbf4 AutoFixService fixes 2025-08-10 16:09:26 +03:00
Koitharu
83d5f8e378 UI fixes 2025-08-05 15:50:39 +03:00
Koitharu
5ac9bad728 Fix MultiMutex unlock when cancelled 2025-08-05 14:02:46 +03:00
36 changed files with 738 additions and 374 deletions

View File

@@ -21,8 +21,8 @@ android {
applicationId 'org.koitharu.kotatsu'
minSdk = 21
targetSdk = 36
versionCode = 1024
versionName = '9.1'
versionCode = 1027
versionName = '9.1.3'
generatedDensities = []
testInstrumentationRunner 'org.koitharu.kotatsu.HiltTestRunner'
ksp {

View File

@@ -17,6 +17,7 @@ import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.runBlocking
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.alternatives.domain.AutoFixUseCase
import org.koitharu.kotatsu.alternatives.domain.AutoFixUseCase.NoAlternativesException
import org.koitharu.kotatsu.core.ErrorReporterReceiver
import org.koitharu.kotatsu.core.model.getTitle
import org.koitharu.kotatsu.core.model.isNsfw
@@ -47,7 +48,7 @@ class AutoFixService : CoroutineIntentService() {
override fun onCreate() {
super.onCreate()
notificationManager = NotificationManagerCompat.from(applicationContext)
notificationManager = NotificationManagerCompat.from(this)
}
override suspend fun IntentJobContext.processIntent(intent: Intent) {
@@ -58,7 +59,7 @@ class AutoFixService : CoroutineIntentService() {
val result = runCatchingCancellable {
autoFixUseCase.invoke(mangaId)
}
if (applicationContext.checkNotificationPermission(CHANNEL_ID)) {
if (checkNotificationPermission(CHANNEL_ID)) {
val notification = buildNotification(startId, result)
notificationManager.notify(TAG, startId, notification)
}
@@ -67,7 +68,7 @@ class AutoFixService : CoroutineIntentService() {
}
override fun IntentJobContext.onError(error: Throwable) {
if (applicationContext.checkNotificationPermission(CHANNEL_ID)) {
if (checkNotificationPermission(CHANNEL_ID)) {
val notification = runBlocking { buildNotification(startId, Result.failure(error)) }
notificationManager.notify(TAG, startId, notification)
}
@@ -75,7 +76,7 @@ class AutoFixService : CoroutineIntentService() {
@SuppressLint("InlinedApi")
private fun startForeground(jobContext: IntentJobContext) {
val title = applicationContext.getString(R.string.fixing_manga)
val title = getString(R.string.fixing_manga)
val channel = NotificationChannelCompat.Builder(CHANNEL_ID, NotificationManagerCompat.IMPORTANCE_MIN)
.setName(title)
.setShowBadge(false)
@@ -85,7 +86,7 @@ class AutoFixService : CoroutineIntentService() {
.build()
notificationManager.createNotificationChannel(channel)
val notification = NotificationCompat.Builder(applicationContext, CHANNEL_ID)
val notification = NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle(title)
.setPriority(NotificationCompat.PRIORITY_MIN)
.setDefaults(0)
@@ -97,7 +98,7 @@ class AutoFixService : CoroutineIntentService() {
.setCategory(NotificationCompat.CATEGORY_PROGRESS)
.addAction(
appcompatR.drawable.abc_ic_clear_material,
applicationContext.getString(android.R.string.cancel),
getString(android.R.string.cancel),
jobContext.getCancelIntent(),
)
.build()
@@ -110,7 +111,7 @@ class AutoFixService : CoroutineIntentService() {
}
private suspend fun buildNotification(startId: Int, result: Result<Pair<Manga, Manga?>>): Notification {
val notification = NotificationCompat.Builder(applicationContext, CHANNEL_ID)
val notification = NotificationCompat.Builder(this, CHANNEL_ID)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setDefaults(0)
.setSilent(true)
@@ -119,17 +120,17 @@ class AutoFixService : CoroutineIntentService() {
if (replacement != null) {
notification.setLargeIcon(
coil.execute(
ImageRequest.Builder(applicationContext)
ImageRequest.Builder(this)
.data(replacement.coverUrl)
.mangaSourceExtra(replacement.source)
.build(),
).toBitmapOrNull(),
)
notification.setSubText(replacement.title)
val intent = AppRouter.detailsIntent(applicationContext, replacement)
val intent = AppRouter.detailsIntent(this, replacement)
notification.setContentIntent(
PendingIntentCompat.getActivity(
applicationContext,
this,
replacement.id.toInt(),
intent,
PendingIntent.FLAG_UPDATE_CURRENT,
@@ -143,35 +144,35 @@ class AutoFixService : CoroutineIntentService() {
},
)
notification
.setContentTitle(applicationContext.getString(R.string.fixed))
.setContentTitle(getString(R.string.fixed))
.setContentText(
applicationContext.getString(
getString(
R.string.manga_replaced,
seed.title,
seed.source.getTitle(applicationContext),
seed.source.getTitle(this),
replacement.title,
replacement.source.getTitle(applicationContext),
replacement.source.getTitle(this),
),
)
.setSmallIcon(R.drawable.ic_stat_done)
} else {
notification
.setContentTitle(applicationContext.getString(R.string.fixing_manga))
.setContentText(applicationContext.getString(R.string.no_fix_required, seed.title))
.setContentTitle(getString(R.string.fixing_manga))
.setContentText(getString(R.string.no_fix_required, seed.title))
.setSmallIcon(android.R.drawable.stat_sys_warning)
}
}.onFailure { error ->
notification
.setContentTitle(applicationContext.getString(R.string.error_occurred))
.setContentTitle(getString(R.string.error_occurred))
.setContentText(
if (error is AutoFixUseCase.NoAlternativesException) {
applicationContext.getString(R.string.no_alternatives_found, error.seed.manga.title)
if (error is NoAlternativesException) {
getString(R.string.no_alternatives_found, error.seed.manga.title)
} else {
error.getDisplayMessage(applicationContext.resources)
error.getDisplayMessage(resources)
},
).setSmallIcon(android.R.drawable.stat_notify_error)
ErrorReporterReceiver.getNotificationAction(
context = applicationContext,
context = this,
e = error,
notificationId = startId,
notificationTag = TAG,

View File

@@ -4,7 +4,6 @@ import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.os.BadParcelableException
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.app.PendingIntentCompat
@@ -65,7 +64,7 @@ class ErrorReporterReceiver : BroadcastReceiver() {
e: Throwable,
notificationId: Int,
notificationTag: String?,
): PendingIntent? = try {
): PendingIntent? = runCatching {
val intent = Intent(context, ErrorReporterReceiver::class.java)
intent.setAction(ACTION_REPORT)
intent.setData("err://${e.hashCode()}".toUri())
@@ -73,9 +72,9 @@ class ErrorReporterReceiver : BroadcastReceiver() {
intent.putExtra(EXTRA_NOTIFICATION_ID, notificationId)
intent.putExtra(EXTRA_NOTIFICATION_TAG, notificationTag)
PendingIntentCompat.getBroadcast(context, 0, intent, 0, false)
} catch (e: BadParcelableException) {
}.onFailure { e ->
// probably cannot write exception as serializable
e.printStackTraceDebug()
null
}
}.getOrNull()
}
}

View File

@@ -54,6 +54,7 @@ import org.koitharu.kotatsu.core.util.ext.processLifecycleScope
import org.koitharu.kotatsu.core.util.ext.toBitmapOrNull
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.network.CloudFlareHelper
import org.koitharu.kotatsu.parsers.util.mapToArray
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
import javax.inject.Inject
import javax.inject.Provider
@@ -152,6 +153,15 @@ class CaptchaHandler @Inject constructor(
.setOnlyAlertOnce(true)
.setSmallIcon(R.drawable.ic_bot)
.setGroup(GROUP_CAPTCHA)
.setContentIntent(
PendingIntentCompat.getActivities(
context, GROUP_NOTIFICATION_ID,
exceptions.mapToArray { e ->
AppRouter.cloudFlareResolveIntent(context, e)
},
0, false,
),
)
.setContentText(
context.getString(
R.string.captcha_required_summary, context.getString(R.string.app_name),
@@ -172,7 +182,6 @@ class CaptchaHandler @Inject constructor(
private suspend fun buildNotification(exception: CloudFlareProtectedException): Notification {
val intent = AppRouter.cloudFlareResolveIntent(context, exception)
.setData(exception.url.toUri())
val discardIntent = Intent(ACTION_DISCARD)
.putExtra(AppRouter.KEY_SOURCE, exception.source.name)
.setData("source://${exception.source.name}".toUri())

View File

@@ -0,0 +1,58 @@
package org.koitharu.kotatsu.core.network.webview
import android.content.Context
import android.webkit.WebView
import androidx.annotation.MainThread
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
import org.koitharu.kotatsu.core.util.ext.configureForParser
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
import org.koitharu.kotatsu.core.util.ext.sanitizeHeaderValue
import org.koitharu.kotatsu.parsers.util.nullIfEmpty
import java.lang.ref.WeakReference
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
@Singleton
class WebViewExecutor @Inject constructor(
@ApplicationContext private val context: Context
) {
private var webViewCached: WeakReference<WebView>? = null
private val mutex = Mutex()
suspend fun evaluateJs(baseUrl: String?, script: String): String? = mutex.withLock {
withContext(Dispatchers.Main.immediate) {
val webView = obtainWebView()
if (!baseUrl.isNullOrEmpty()) {
suspendCoroutine { cont ->
webView.webViewClient = ContinuationResumeWebViewClient(cont)
webView.loadDataWithBaseURL(baseUrl, " ", "text/html", null, null)
}
}
suspendCoroutine { cont ->
webView.evaluateJavascript(script) { result ->
cont.resume(result?.takeUnless { it == "null" })
}
}
}
}
@MainThread
fun getDefaultUserAgent() = runCatching {
obtainWebView().settings.userAgentString.sanitizeHeaderValue().trim().nullIfEmpty()
}.onFailure { e ->
e.printStackTraceDebug()
}.getOrNull()
@MainThread
private fun obtainWebView(): WebView = webViewCached?.get() ?: WebView(context).also {
it.configureForParser(null)
webViewCached = WeakReference(it)
}
}

View File

@@ -3,15 +3,10 @@ package org.koitharu.kotatsu.core.parser
import android.annotation.SuppressLint
import android.content.Context
import android.util.Base64
import android.webkit.WebView
import androidx.annotation.MainThread
import androidx.core.os.LocaleListCompat
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
import kotlinx.coroutines.withTimeout
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
@@ -22,11 +17,8 @@ import org.koitharu.kotatsu.core.exceptions.InteractiveActionRequiredException
import org.koitharu.kotatsu.core.image.BitmapDecoderCompat
import org.koitharu.kotatsu.core.network.MangaHttpClient
import org.koitharu.kotatsu.core.network.cookies.MutableCookieJar
import org.koitharu.kotatsu.core.network.webview.ContinuationResumeWebViewClient
import org.koitharu.kotatsu.core.network.webview.WebViewExecutor
import org.koitharu.kotatsu.core.prefs.SourceSettings
import org.koitharu.kotatsu.core.util.ext.configureForParser
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
import org.koitharu.kotatsu.core.util.ext.sanitizeHeaderValue
import org.koitharu.kotatsu.core.util.ext.toList
import org.koitharu.kotatsu.core.util.ext.toMimeType
import org.koitharu.kotatsu.core.util.ext.use
@@ -37,25 +29,21 @@ import org.koitharu.kotatsu.parsers.config.MangaSourceConfig
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.network.UserAgents
import org.koitharu.kotatsu.parsers.util.map
import java.lang.ref.WeakReference
import java.util.Locale
import java.util.concurrent.TimeUnit
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
@Singleton
class MangaLoaderContextImpl @Inject constructor(
@MangaHttpClient override val httpClient: OkHttpClient,
override val cookieJar: MutableCookieJar,
@ApplicationContext private val androidContext: Context,
private val webViewExecutor: WebViewExecutor,
) : MangaLoaderContext() {
private var webViewCached: WeakReference<WebView>? = null
private val webViewUserAgent by lazy { obtainWebViewUserAgent() }
private val jsMutex = Mutex()
private val jsTimeout = TimeUnit.SECONDS.toMillis(4)
@Deprecated("Provide a base url")
@@ -63,22 +51,7 @@ class MangaLoaderContextImpl @Inject constructor(
override suspend fun evaluateJs(script: String): String? = evaluateJs("", script)
override suspend fun evaluateJs(baseUrl: String, script: String): String? = withTimeout(jsTimeout) {
jsMutex.withLock {
withContext(Dispatchers.Main.immediate) {
val webView = obtainWebView()
if (baseUrl.isNotEmpty()) {
suspendCoroutine { cont ->
webView.webViewClient = ContinuationResumeWebViewClient(cont)
webView.loadDataWithBaseURL(baseUrl, " ", "text/html", null, null)
}
}
suspendCoroutine { cont ->
webView.evaluateJavascript(script) { result ->
cont.resume(result?.takeUnless { it == "null" })
}
}
}
}
webViewExecutor.evaluateJs(baseUrl, script)
}
override fun getDefaultUserAgent(): String = webViewUserAgent
@@ -119,27 +92,14 @@ class MangaLoaderContextImpl @Inject constructor(
override fun createBitmap(width: Int, height: Int): Bitmap = BitmapWrapper.create(width, height)
@MainThread
private fun obtainWebView(): WebView = webViewCached?.get() ?: WebView(androidContext).also {
it.configureForParser(null)
webViewCached = WeakReference(it)
}
private fun obtainWebViewUserAgent(): String {
val mainDispatcher = Dispatchers.Main.immediate
return if (!mainDispatcher.isDispatchNeeded(EmptyCoroutineContext)) {
obtainWebViewUserAgentImpl()
webViewExecutor.getDefaultUserAgent()
} else {
runBlocking(mainDispatcher) {
obtainWebViewUserAgentImpl()
webViewExecutor.getDefaultUserAgent()
}
}
} ?: UserAgents.FIREFOX_MOBILE
}
@MainThread
private fun obtainWebViewUserAgentImpl() = runCatching {
obtainWebView().settings.userAgentString.sanitizeHeaderValue()
}.onFailure { e ->
e.printStackTraceDebug()
}.getOrDefault(UserAgents.FIREFOX_MOBILE)
}

View File

@@ -53,6 +53,9 @@ class ExternalPluginContentSource(
filter.states.forEach { uri.appendQueryParameter("state", it.name) }
filter.locale?.let { uri.appendQueryParameter("locale", it.language) }
filter.contentRating.forEach { uri.appendQueryParameter("content_rating", it.name) }
if (!filter.author.isNullOrEmpty()) {
uri.appendQueryParameter("author", filter.author)
}
if (!filter.query.isNullOrEmpty()) {
uri.appendQueryParameter("query", filter.query)
}
@@ -196,6 +199,7 @@ class ExternalPluginContentSource(
isYearSupported = cursor.getBooleanOrDefault(COLUMN_YEAR, false),
isYearRangeSupported = cursor.getBooleanOrDefault(COLUMN_YEAR_RANGE, false),
isOriginalLocaleSupported = cursor.getBooleanOrDefault(COLUMN_ORIGINAL_LOCALE, false),
isAuthorSearchSupported = cursor.getBooleanOrDefault(COLUMN_AUTHOR, false),
),
)
} else {

View File

@@ -31,8 +31,8 @@ open class MultiMutex<T : Any> {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
lock(element)
return try {
lock(element)
block()
} finally {
unlock(element)

View File

@@ -183,6 +183,8 @@ fun View.setTooltipCompat(tooltip: CharSequence?) {
}
}
fun View.setTooltipCompat(@StringRes tooltipResId: Int) = setTooltipCompat(context.getString(tooltipResId))
val Toolbar.menuView: ActionMenuView?
get() {
menu // to call ensureMenu()

View File

@@ -35,7 +35,7 @@ class ExploreRepository @Inject constructor(
val details = runCatchingCancellable {
mangaRepositoryFactory.create(manga.source).getDetails(manga)
}.getOrNull() ?: continue
if ((settings.isSuggestionsExcludeNsfw && details.isNsfw) || details in tagsBlacklist) {
if ((settings.isSuggestionsExcludeNsfw && details.isNsfw()) || details in tagsBlacklist) {
continue
}
return details
@@ -55,7 +55,7 @@ class ExploreRepository @Inject constructor(
val details = runCatchingCancellable {
mangaRepositoryFactory.create(manga.source).getDetails(manga)
}.getOrNull() ?: continue
if ((skipNsfw && details.isNsfw) || details in tagsBlacklist) {
if ((skipNsfw && details.isNsfw()) || details in tagsBlacklist) {
continue
}
return details
@@ -80,7 +80,7 @@ class ExploreRepository @Inject constructor(
filter = MangaListFilter(tags = setOfNotNull(tag)),
).asArrayList()
if (settings.isSuggestionsExcludeNsfw) {
list.removeAll { it.isNsfw }
list.removeAll { it.isNsfw() }
}
if (blacklist.isNotEmpty()) {
list.removeAll { manga -> manga in blacklist }

View File

@@ -11,6 +11,7 @@ import androidx.core.view.isVisible
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.util.ext.getQuantityStringSafe
import org.koitharu.kotatsu.core.util.ext.setTooltipCompat
import org.koitharu.kotatsu.databinding.ItemCategoriesAllBinding
import org.koitharu.kotatsu.databinding.ItemCategoryBinding
import org.koitharu.kotatsu.favourites.ui.categories.FavouriteCategoriesListListener
@@ -91,6 +92,13 @@ fun allCategoriesAD(
R.drawable.ic_eye_off
},
)
binding.imageViewVisible.setTooltipCompat(
if (item.isVisible) {
R.string.hide
} else {
R.string.show
},
)
binding.coversView.setCoversAsync(item.covers)
}
}

View File

@@ -10,6 +10,7 @@ import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.plus
import org.koitharu.kotatsu.core.model.isNsfw
import org.koitharu.kotatsu.core.parser.MangaDataRepository
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.prefs.ListMode
@@ -45,7 +46,7 @@ abstract class MangaListViewModel(
abstract fun onRetry()
protected fun List<Manga>.skipNsfwIfNeeded() = if (settings.isNsfwContentDisabled) {
filterNot { it.isNsfw }
filterNot { it.isNsfw() }
} else {
this
}

View File

@@ -12,6 +12,7 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.runInterruptible
import org.koitharu.kotatsu.core.model.LocalMangaSource
import org.koitharu.kotatsu.core.model.isLocal
import org.koitharu.kotatsu.core.model.isNsfw
import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.util.AlphanumComparator
@@ -94,7 +95,7 @@ class LocalMangaRepository @Inject constructor(
}
val list = getRawList()
if (settings.isNsfwContentDisabled) {
list.removeAll { it.manga.isNsfw }
list.removeAll { it.manga.isNsfw() }
}
if (filter != null) {
val query = filter.query
@@ -109,7 +110,7 @@ class LocalMangaRepository @Inject constructor(
}
filter.contentRating.singleOrNull()?.let { contentRating ->
val isNsfw = contentRating == ContentRating.ADULT
list.retainAll { it.manga.isNsfw == isNsfw }
list.retainAll { it.manga.isNsfw() == isNsfw }
}
if (!query.isNullOrEmpty() && order == SortOrder.RELEVANCE) {
list.sortBy { it.manga.title.levenshteinDistance(query) }

View File

@@ -1,15 +1,18 @@
package org.koitharu.kotatsu.main.ui
import android.os.Bundle
import android.view.Gravity
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.widget.FrameLayout
import androidx.activity.OnBackPressedCallback
import androidx.annotation.IdRes
import androidx.core.view.isEmpty
import androidx.core.view.isVisible
import androidx.core.view.iterator
import androidx.core.view.size
import androidx.core.view.updateLayoutParams
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.LifecycleOwner
@@ -66,6 +69,9 @@ class MainNavigationDelegate(
navBar.setOnItemSelectedListener(this)
navBar.setOnItemReselectedListener(this)
navRailHeader?.run {
root.updateLayoutParams<FrameLayout.LayoutParams> {
gravity = Gravity.TOP or Gravity.CENTER
}
val horizontalPadding = (navBar as NavigationRailView).itemActiveIndicatorMarginHorizontal
root.setPadding(horizontalPadding, 0, horizontalPadding, 0)
buttonExpand.setOnClickListener(this@MainNavigationDelegate)
@@ -295,6 +301,9 @@ class MainNavigationDelegate(
if (value) {
navBar.expand()
navRailHeader?.run {
root.updateLayoutParams<FrameLayout.LayoutParams> {
gravity = Gravity.TOP or Gravity.START
}
railFab.extend()
buttonExpand.setImageResource(R.drawable.ic_drawer_menu_open)
buttonExpand.setContentDescriptionAndTooltip(R.string.collapse)
@@ -304,6 +313,9 @@ class MainNavigationDelegate(
} else {
navBar.collapse()
navRailHeader?.run {
root.updateLayoutParams<FrameLayout.LayoutParams> {
gravity = Gravity.TOP or Gravity.CENTER
}
railFab.shrink()
buttonExpand.setImageResource(R.drawable.ic_drawer_menu)
buttonExpand.setContentDescriptionAndTooltip(R.string.expand)

View File

@@ -76,7 +76,7 @@ class SearchV2Helper @AssistedInject constructor(
private fun MutableList<Manga>.postFilter(query: String, kind: SearchKind) {
if (settings.isNsfwContentDisabled) {
removeAll { it.isNsfw }
removeAll { it.isNsfw() }
}
when (kind) {
SearchKind.TITLE -> retainAll { m ->

View File

@@ -229,7 +229,7 @@ class SuggestionsWorker @AssistedInject constructor(
if (details.rating > 0 && details.rating < RATING_MIN) {
continue
}
if (details.isNsfw && (appSettings.isSuggestionsExcludeNsfw || appSettings.isNsfwContentDisabled)) {
if (details.isNsfw() && (appSettings.isSuggestionsExcludeNsfw || appSettings.isNsfwContentDisabled)) {
continue
}
if (details in tagsBlacklist) {
@@ -277,7 +277,7 @@ class SuggestionsWorker @AssistedInject constructor(
filter = MangaListFilter(tags = setOfNotNull(tag)),
).asArrayList()
if (appSettings.isSuggestionsExcludeNsfw) {
list.removeAll { it.isNsfw }
list.removeAll { it.isNsfw() }
}
if (blacklist.isNotEmpty()) {
list.removeAll { manga -> manga in blacklist }

View File

@@ -5,18 +5,20 @@ import android.accounts.AccountAuthenticatorResponse
import android.accounts.AccountManager
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.View
import android.widget.Button
import android.view.ViewGroup.MarginLayoutParams
import android.widget.Toast
import androidx.activity.OnBackPressedCallback
import androidx.activity.viewModels
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
import androidx.fragment.app.FragmentResultListener
import androidx.transition.Fade
import androidx.transition.TransitionManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.transition.MaterialSharedAxis
import dagger.hilt.android.AndroidEntryPoint
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.ui.BaseActivity
@@ -31,13 +33,20 @@ import org.koitharu.kotatsu.databinding.ActivitySyncAuthBinding
import org.koitharu.kotatsu.sync.data.SyncSettings
import org.koitharu.kotatsu.sync.domain.SyncAuthResult
private const val PAGE_EMAIL = 0
private const val PAGE_PASSWORD = 1
private const val PASSWORD_MIN_LENGTH = 4
@AndroidEntryPoint
class SyncAuthActivity : BaseActivity<ActivitySyncAuthBinding>(), View.OnClickListener, FragmentResultListener {
class SyncAuthActivity : BaseActivity<ActivitySyncAuthBinding>(), View.OnClickListener, FragmentResultListener,
DefaultTextWatcher {
private var accountAuthenticatorResponse: AccountAuthenticatorResponse? = null
private var resultBundle: Bundle? = null
private val pageBackCallback = PageBackCallback()
private val regexEmail = Regex("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$", RegexOption.IGNORE_CASE)
private val viewModel by viewModels<SyncAuthViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
@@ -46,14 +55,11 @@ class SyncAuthActivity : BaseActivity<ActivitySyncAuthBinding>(), View.OnClickLi
accountAuthenticatorResponse =
intent.getParcelableExtraCompat(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE)
accountAuthenticatorResponse?.onRequestContinued()
viewBinding.buttonCancel.setOnClickListener(this)
viewBinding.buttonNext.setOnClickListener(this)
viewBinding.buttonBack.setOnClickListener(this)
viewBinding.buttonDone.setOnClickListener(this)
viewBinding.layoutProgress.setOnClickListener(this)
viewBinding.buttonSettings.setOnClickListener(this)
viewBinding.editEmail.addTextChangedListener(EmailTextWatcher(viewBinding.buttonNext))
viewBinding.editPassword.addTextChangedListener(PasswordTextWatcher(viewBinding.buttonDone))
viewBinding.editEmail.addTextChangedListener(this)
viewBinding.editPassword.addTextChangedListener(this)
onBackPressedDispatcher.addCallback(pageBackCallback)
@@ -65,17 +71,25 @@ class SyncAuthActivity : BaseActivity<ActivitySyncAuthBinding>(), View.OnClickLi
}
supportFragmentManager.setFragmentResultListener(SyncHostDialogFragment.REQUEST_KEY, this, this)
pageBackCallback.update()
if (savedInstanceState == null) {
setPage(PAGE_EMAIL)
} else {
pageBackCallback.update()
}
}
override fun onApplyWindowInsets(v: View, insets: WindowInsetsCompat): WindowInsetsCompat {
val barsInsets = insets.systemBarsInsets
val basePadding = resources.getDimensionPixelOffset(R.dimen.screen_padding)
viewBinding.root.setPadding(
barsInsets.left + basePadding,
barsInsets.top + basePadding,
barsInsets.right + basePadding,
barsInsets.bottom + basePadding,
viewBinding.root.updatePadding(top = barsInsets.top)
viewBinding.dockedToolbarChild.updateLayoutParams<MarginLayoutParams> {
leftMargin = barsInsets.left
rightMargin = barsInsets.right
bottomMargin = barsInsets.bottom
}
val basePadding = viewBinding.layoutContent.paddingBottom
viewBinding.layoutContent.updatePadding(
left = barsInsets.left + basePadding,
right = barsInsets.right + basePadding,
)
return insets.consumeAllSystemBarsInsets()
}
@@ -88,22 +102,18 @@ class SyncAuthActivity : BaseActivity<ActivitySyncAuthBinding>(), View.OnClickLi
}
R.id.button_next -> {
viewBinding.groupLogin.isVisible = false
viewBinding.groupPassword.isVisible = true
pageBackCallback.update()
setPage(PAGE_PASSWORD)
viewBinding.editPassword.requestFocus()
}
R.id.button_back -> {
viewBinding.groupPassword.isVisible = false
viewBinding.groupLogin.isVisible = true
pageBackCallback.update()
setPage(PAGE_EMAIL)
viewBinding.editEmail.requestFocus()
}
R.id.button_done -> {
viewModel.obtainToken(
email = viewBinding.editEmail.text.toString(),
email = viewBinding.editEmail.text.toString().trim(),
password = viewBinding.editPassword.text.toString(),
)
}
@@ -128,12 +138,39 @@ class SyncAuthActivity : BaseActivity<ActivitySyncAuthBinding>(), View.OnClickLi
super.finish()
}
override fun afterTextChanged(s: Editable?) {
val isLoading = viewModel.isLoading.value
val email = viewBinding.editEmail.text?.trim()?.toString()
val password = viewBinding.editPassword.text?.toString()
viewBinding.buttonNext.isEnabled = !isLoading && !email.isNullOrEmpty() && regexEmail.matches(email)
viewBinding.buttonDone.isEnabled = !isLoading && password != null && password.length >= PASSWORD_MIN_LENGTH
}
private fun onLoadingStateChanged(isLoading: Boolean) {
if (isLoading == viewBinding.layoutProgress.isVisible) {
return
with(viewBinding) {
progressBar.isInvisible = !isLoading
editEmail.isEnabled = !isLoading
editPassword.isEnabled = !isLoading
}
afterTextChanged(null)
pageBackCallback.update()
}
private fun setPage(page: Int) {
with(viewBinding) {
val currentPage = if (layoutEmail.isVisible) PAGE_EMAIL else PAGE_PASSWORD
if (currentPage != page) {
val transition = MaterialSharedAxis(MaterialSharedAxis.X, page > currentPage)
TransitionManager.beginDelayedTransition(layoutContent, transition)
}
buttonNext.isVisible = page == PAGE_EMAIL
buttonBack.isVisible = page == PAGE_PASSWORD
buttonSettings.isVisible = page == PAGE_EMAIL
buttonDone.isVisible = page == PAGE_PASSWORD
buttonCancel.isVisible = page == PAGE_EMAIL
layoutEmail.isVisible = page == PAGE_EMAIL
layoutPassword.isVisible = page == PAGE_PASSWORD
}
TransitionManager.beginDelayedTransition(viewBinding.root, Fade())
viewBinding.layoutProgress.isVisible = isLoading
pageBackCallback.update()
}
@@ -174,43 +211,16 @@ class SyncAuthActivity : BaseActivity<ActivitySyncAuthBinding>(), View.OnClickLi
super.finishAfterTransition()
}
private class EmailTextWatcher(
private val button: Button,
) : TextWatcher {
private val regexEmail = Regex("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$", RegexOption.IGNORE_CASE)
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) = Unit
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) = Unit
override fun afterTextChanged(s: Editable?) {
val text = s?.toString()
button.isEnabled = !text.isNullOrEmpty() && regexEmail.matches(text)
}
}
private class PasswordTextWatcher(
private val button: Button,
) : DefaultTextWatcher {
override fun afterTextChanged(s: Editable?) {
val text = s?.toString()
button.isEnabled = text != null && text.length >= 4
}
}
private inner class PageBackCallback : OnBackPressedCallback(false) {
override fun handleOnBackPressed() {
viewBinding.groupLogin.isVisible = true
viewBinding.groupPassword.isVisible = false
setPage(PAGE_EMAIL)
viewBinding.editEmail.requestFocus()
update()
}
fun update() {
isEnabled = !viewBinding.layoutProgress.isVisible && viewBinding.groupPassword.isVisible
isEnabled = !viewBinding.progressBar.isVisible && viewBinding.editPassword.isVisible
}
}
}

View File

@@ -1,227 +1,156 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="@dimen/screen_padding">
android:orientation="vertical">
<TextView
android:id="@+id/textView_title"
android:layout_width="0dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="16dp"
android:layout_marginHorizontal="@dimen/screen_padding"
android:layout_marginTop="24dp"
android:drawablePadding="@dimen/screen_padding"
android:gravity="center_horizontal"
android:text="@string/sync_title"
android:textAppearance="?textAppearanceHeadline5"
app:drawableTint="?colorPrimary"
app:drawableTopCompat="@drawable/ic_sync"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
app:drawableTopCompat="@drawable/ic_sync" />
<ImageButton
android:id="@+id/button_settings"
android:layout_width="wrap_content"
<com.google.android.material.progressindicator.LinearProgressIndicator
android:id="@+id/progressBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?selectableItemBackgroundBorderless"
android:contentDescription="@string/settings"
android:tooltipText="@string/settings"
android:padding="4dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_settings" />
android:layout_marginHorizontal="@dimen/screen_padding"
android:layout_marginTop="@dimen/screen_padding"
android:max="100"
android:visibility="invisible" />
<TextView
android:id="@+id/textView_subtitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:gravity="center_horizontal"
android:text="@string/email_enter_hint"
android:textAppearance="?textAppearanceSubtitle1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/textView_title" />
<ScrollView
android:id="@+id/scrollView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/layout_email"
style="?textInputOutlinedStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
app:errorIconDrawable="@null"
app:helperText="@string/sync_auth_hint"
app:hintEnabled="false"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/textView_subtitle">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/edit_email"
<LinearLayout
android:id="@+id/layout_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:autofillHints="username"
android:imeOptions="actionDone"
android:inputType="textEmailAddress"
android:singleLine="true"
android:textSize="16sp"
tools:text="test@mail.com" />
android:orientation="vertical"
android:paddingHorizontal="@dimen/screen_padding"
android:paddingBottom="@dimen/screen_padding">
</com.google.android.material.textfield.TextInputLayout>
<TextView
android:id="@+id/textView_subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/sync_auth_hint"
android:textAppearance="?textAppearanceBodySmall" />
<Button
android:id="@+id/button_cancel"
style="?materialButtonOutlinedStyle"
android:layout_width="wrap_content"
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/layout_email"
style="?textInputOutlinedStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
app:errorIconDrawable="@null">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/edit_email"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:autofillHints="username"
android:hint="@string/email"
android:imeOptions="actionDone"
android:inputType="textEmailAddress"
android:singleLine="true"
android:textSize="16sp" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/layout_password"
style="?textInputOutlinedStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
app:endIconMode="password_toggle"
app:errorIconDrawable="@null">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/edit_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:autofillHints="password"
android:hint="@string/password"
android:imeOptions="actionDone"
android:inputType="textPassword"
android:maxLength="24"
android:singleLine="true"
android:textSize="16sp" />
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="@+id/button_settings"
style="?borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="@string/settings" />
</LinearLayout>
</ScrollView>
<com.google.android.material.dockedtoolbar.DockedToolbarLayout
android:id="@+id/docked_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@android:string/cancel"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" />
android:fitsSystemWindows="false">
<Button
android:id="@+id/button_next"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:enabled="false"
android:text="@string/next"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<TextView
android:id="@+id/textView_subtitle_2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:gravity="center_horizontal"
android:text="@string/enter_password"
android:textAppearance="?textAppearanceSubtitle1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/textView_title" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/layout_password"
style="?textInputOutlinedStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
app:endIconMode="password_toggle"
app:errorIconDrawable="@null"
app:hintEnabled="false"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/textView_subtitle_2">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/edit_password"
<FrameLayout
android:id="@+id/docked_toolbar_child"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:autofillHints="password"
android:imeOptions="actionDone"
android:inputType="textPassword"
android:maxLength="24"
android:singleLine="true"
android:textSize="16sp"
tools:text="qwerty" />
android:layout_height="@dimen/m3_comp_toolbar_docked_container_height">
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="@+id/button_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start"
android:text="@android:string/cancel" />
<Button
android:id="@+id/button_back"
style="?materialButtonOutlinedStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/back"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="@+id/button_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start"
android:text="@string/back"
android:visibility="gone" />
<Button
android:id="@+id/button_done"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:enabled="false"
android:text="@string/done"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<Button
android:id="@+id/button_next"
style="?materialButtonTonalStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|end"
android:enabled="false"
android:text="@string/next" />
<androidx.constraintlayout.widget.Group
android:id="@+id/group_login"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="textView_subtitle,button_cancel,button_next,layout_email" />
<Button
android:id="@+id/button_done"
style="?materialButtonTonalStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|end"
android:enabled="false"
android:text="@string/done"
android:visibility="gone" />
<androidx.constraintlayout.widget.Group
android:id="@+id/group_password"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:constraint_referenced_ids="textView_subtitle_2,button_back,button_done,layout_password" />
</FrameLayout>
</com.google.android.material.dockedtoolbar.DockedToolbarLayout>
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier_input"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="bottom"
app:constraint_referenced_ids="layout_email,layout_password" />
<View
android:id="@+id/view_line"
android:layout_width="4dp"
android:layout_height="0dp"
android:background="@drawable/bg_chip"
android:backgroundTint="?colorError"
app:layout_constraintBottom_toBottomOf="@id/textView_hint_body"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/textView_hint_title" />
<TextView
android:id="@+id/textView_hint_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginTop="32dp"
android:drawablePadding="10dp"
android:gravity="center_vertical"
android:text="@string/unstable_feature"
android:textAppearance="?textAppearanceTitleMedium"
app:drawableStartCompat="@drawable/ic_alert_outline"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/view_line"
app:layout_constraintTop_toBottomOf="@id/barrier_input" />
<TextView
android:id="@+id/textView_hint_body"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:paddingBottom="6dp"
android:text="@string/unstable_feature_summary"
android:textAppearance="?textAppearanceBodyMedium"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@id/textView_hint_title"
app:layout_constraintTop_toBottomOf="@id/textView_hint_title" />
<FrameLayout
android:id="@+id/layout_progress"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="?android:windowBackground"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/textView_title">
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="@+id/circularProgressIndicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminate="true" />
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>

View File

@@ -794,4 +794,17 @@
<string name="global_search">البحث العالمي</string>
<string name="search_everywhere">البحث في كل مكان</string>
<string name="badges_in_lists">الشارات في القوائم</string>
<string name="nsfw_16">16+</string>
<string name="reader_navigation_inverted">عكس التنقل اثناء التصفح</string>
<string name="reader_navigation_inverted_summary">عكس اتجاه زر التحكم في الصوت ومفتاح التنقل الاتجاهي في الأجهزة (يسار/أعلى/أسفل/يمين)</string>
<string name="clear_browser_data">مسح بيانات المتصفح</string>
<string name="clear_browser_data_summary">مسح بيانات المتصفح، مثل ذاكرة التخزين المؤقت وملفات تعريف الارتباط. تحذير: قد يصبح التفويض في مصادر المانجا غير صالح.</string>
<string name="no_write_permission_to_file">ليس لديك صلاحية لكتابة ملف.</string>
<string name="exclude_nsfw_from_suggestions_summary">لن تظهر المانغا المخصصة للبالغين في الاقتراحات. قد لا يعمل هذا الخيار بدقة مع بعض المصادر.</string>
<string name="include_disabled_sources">"شمل المصادر المعطلة."</string>
<string name="suggestions_disabled_sources_summary">"اضهار الاقتراحات من كل مصادر المانقا شامل المعطلين."</string>
<string name="tags_warnings">­ابراز التصنيفات الخطيرة</string>
<string name="tags_warnings_summary">ابراز التصنيفات التي قد تكون غير مناسبة لغالبية المستخدين.</string>
<string name="error_non_file_uri">لا يمكن استخدام المسار المحدد لأنه لا يشير إلى ملف أو دليل.</string>
<string name="manga_override_hint">ستؤثر هذه التغييرات على كيفية عرض المانجا في التطبيق.</string>
</resources>

View File

@@ -835,4 +835,28 @@
<string name="theme_name_itsuka">Іцука</string>
<string name="theme_name_totoro">Тоторо</string>
<string name="book_effect">Жаўтлявы фон (фільтр сіняга)</string>
<string name="local_storage_cleanup">Ачыстка лакальнага сховішча</string>
<string name="packup_creation_failed">Рэзервовае капіраванне не атрымалася</string>
<string name="main_screen">Галоўны экран</string>
<string name="main_screen_fab">Паказаць плаваючую кнопку «Працягнуць»</string>
<string name="main_screen_fab_summary">Дазваляе працягнуць чытанне адным пстрычкай мышы. Гэтая кнопка не адлюстроўваецца ў рэжыме інкогніта або калі гісторыя пустая</string>
<string name="error_corrupted_zip">Пашкоджаны ZIP-архіў (%s)</string>
<string name="discord_rpc">Discord Rich Presence</string>
<string name="discord_token">Токен Discord</string>
<string name="discord_token_summary">Увядзіце свой токен Discord, каб уключыць Rich Presence</string>
<string name="discord_token_description">Увядзіце свой токен Discord або націсніце %s, каб атрымаць яго з дапамогай браўзера</string>
<string name="discord_token_hint">Устаўце сюды свой токен Discord</string>
<string name="discord_rpc_summary">Пакажыце свой статус чытання ў Discord</string>
<string name="obtain">Атрымаць</string>
<string name="discord_rpc_description">Чытанне мангі на Kotatsu - праграма для чытання мангі</string>
<string name="reading_s">Чытанне %s</string>
<string name="read_on_s">Чытаць далей %s</string>
<string name="rpc_skip_nsfw_summary">Не выкарыстоўваць RPC для дарослага кантэнту</string>
<string name="invalid_token">Няправільны токен: %s</string>
<string name="show_floating_control_button">Паказаць плаваючую кнопку кіравання</string>
<string name="unavailable">Недаступна</string>
<string name="manga_restricted_description">Гэтая манга недаступная для чытання на гэтай крыніцы. Паспрабуйце знайсці яе на іншых крыніцах або адкрыйце ў браўзеры для атрымання дадатковай інфармацыі</string>
<string name="no_chapters_in_manga">Гэтая манга не ўтрымлівае раздзелаў</string>
<string name="chapters_load_failed">Не атрымалася загрузіць спіс раздзелаў</string>
<string name="telegram_integration">Інтэграцыя з Telegram</string>
</resources>

View File

@@ -123,7 +123,7 @@
<string name="manga_shelf">تاقچه</string>
<string name="not_available">در دسترس نیست</string>
<string name="cannot_find_available_storage">محل ذخیره سازی قابل دسترسی ئی یافت نشد</string>
<string name="scale_mode">حالت scale</string>
<string name="scale_mode">مقیاس</string>
<string name="zoom_mode_fit_center">متناسب به مرکز</string>
<string name="zoom_mode_keep_start">نگه داشتن در شروع</string>
<string name="reverse">معکوس</string>
@@ -280,4 +280,237 @@
<string name="report">گزارش</string>
<string name="status_planned">برنامه‌ریزی شده</string>
<string name="show_reading_indicators_summary">نشان دادن درصد خوانده شده در تاریخچه و پسندیده‌ها</string>
<string name="appwidget_recent_description">مانگا های اخیراً خوانده شده</string>
<string name="clear_cookies_summary">می‌تواند در صورت بروز برخی مشکلات کمک کند. همه مجوزها باطل خواهند شد</string>
<string name="show_all">نمایش همه</string>
<string name="invalid_domain_message">دامنه نامعتبر</string>
<string name="invalid_server_address_message">آدرس سرور نامعتیر</string>
<string name="select_range">انتخاب بازه</string>
<string name="clear_all_history">پاک کردن همه تاریخچه</string>
<string name="last_2_hours">۲ ساعت گذشته</string>
<string name="history_cleared">تاریخچه پاک شد</string>
<string name="manage">مدیریت</string>
<string name="no_bookmarks_yet">هنوز هیچ نشانکی وجود ندارد</string>
<string name="no_bookmarks_summary">می‌توانید هنگام خواندن مانگا نشانک ایجاد کنید</string>
<string name="bookmarks_removed">نشانک حذف شد</string>
<string name="no_manga_sources">هیچ منبعی برای مانگا وجود ندارد</string>
<string name="no_manga_sources_text">برای خواندن مانگا به صورت برخط، منابع مانگا را فعال کنید</string>
<string name="random">تصادفی</string>
<string name="categories_delete_confirm">آیا مطمئن هستید که می‌خواهید دسته‌های مورد علاقه انتخاب‌شده را حذف کنید؟\nتمام مانگاهای موجود در آن از بین خواهند رفت و این قابل بازگشت نیست.</string>
<string name="reorder">مرتب‌سازی مجدد</string>
<string name="empty">تهی</string>
<string name="explore">کاوش</string>
<string name="confirm_exit">برای خروج دکمه بازگشت را دوباره فشار دهید</string>
<string name="exit_confirmation_summary">دکمه باز گشت را دوبار بفشارید تا از برنامه خارج شوید</string>
<string name="exit_confirmation">تایید خروج</string>
<string name="saved_manga">مانگا های ذخیره شده</string>
<string name="pages_cache">حافظه نهان صفحات</string>
<string name="other_cache">دیگر حافظه های نهان</string>
<string name="storage_usage">فضای ذخیره‌سازی استفاده شده</string>
<string name="available">در دسترس</string>
<string name="removed_from_favourites">از مورد علاقه‌ها حذف شد</string>
<string name="options">گزینه ها</string>
<string name="not_found_404">محتوا حذف شده یا پیدا نشد</string>
<string name="incognito_mode">حالت ناشناس</string>
<string name="no_chapters">بدون فصل</string>
<string name="automatic_scroll">پیمایش خودکار</string>
<string name="reader_info_pattern">چپتر.%2$d%1$dصفحه.%4$d%3$d</string>
<string name="reader_info_bar">نمایش نوار اطلاعات در خوانشگر</string>
<string name="comics_archive">آرشیو کامیک ها</string>
<string name="folder_with_images">پوشه با تصویر</string>
<string name="importing_manga">وارد کردن مانگا</string>
<string name="import_completed">وارد کردن کامل شد</string>
<string name="import_completed_hint">شما میتوانید پرونده اصلی را از حافظه برای آزاد سازی فضای ذخیره سازی پاک کنید</string>
<string name="import_will_start_soon">وارد کردن به زودی آغاز خواهد شد</string>
<string name="feed">خوراک</string>
<string name="history_shortcuts">نمایش میانبرهای اخیر مانگا</string>
<string name="history_shortcuts_summary">دسترسی به مانگاهای اخیر با فشار طولانی روی آیکون برنامه</string>
<string name="reader_control_ltr_summary">جهت تغییر صفحه را به حالت خوانشگر تنظیم نکنید، به عنوان مثال، فشار دادن کلید سمت راست همیشه به صفحه بعدی می‌رود. این گزینه فقط بر دستگاه‌های ورودی سخت‌افزاری تأثیر می‌گذارد</string>
<string name="reader_control_ltr">کنترل خوانشگر ارگونومیک</string>
<string name="color_correction">تصحیح رنگ</string>
<string name="brightness">روشنایی</string>
<string name="contrast">کنتراست</string>
<string name="reset">بازنشانی</string>
<string name="text_unsaved_changes_prompt">ذخیره یا لغو تغییرات ذخیره نشده؟</string>
<string name="discard">لغو</string>
<string name="error_no_space_left">هیچ فضایی روی دستگاه باقی نمانده است</string>
<string name="reader_slider">نمایش اسلایدر تعویض صفحه</string>
<string name="webtoon_zoom">بزرگ نمایی وبتوون</string>
<string name="network_unavailable">شبکه در دسترس نیست</string>
<string name="network_unavailable_hint">برای خواندن مانگا به صورت برخط، وایفای یا دیتای تلفن همراه را روشن کنید</string>
<string name="server_error">خطای سمت سرویس دهنده (%1$d). لطفا بعداً دوباره تلاش کنید</string>
<string name="clear_new_chapters_counters">اطلاعات مربوط به فصل های جدید رو هم پاک کن</string>
<string name="compact">فشرده</string>
<string name="source_disabled">منبع غیر فعال شده است</string>
<string name="prefetch_content">پیش بازگذاری محتوا</string>
<string name="mark_as_current">نشانه گذاری به عنوان فعلی</string>
<string name="language">زبان</string>
<string name="share_logs">اشتراک گذاری گزارش</string>
<string name="enable_logging">فعال کردن گزارشات</string>
<string name="enable_logging_summary">ثبت برخی عمیات برای اهداف اشکال زدایی. اگه نمیدونی داری چیکار میکنی این گزینه رو روشن نکن</string>
<string name="show_suspicious_content">نمایش محتوای مشکوک</string>
<string name="theme_name_dynamic">پویا</string>
<string name="theme_name_expressive">صریح (تست)</string>
<string name="color_theme">طرح رنگ</string>
<string name="show_in_grid_view">نمایش به حالت شبکه ای</string>
<string name="theme_name_miku">میکو</string>
<string name="theme_name_asuka">آسوکا</string>
<string name="theme_name_mion">میون</string>
<string name="theme_name_rikka">ریکا</string>
<string name="theme_name_sakura">ساکورا</string>
<string name="theme_name_mamimi">مامیمی</string>
<string name="theme_name_kanade">کاناده</string>
<string name="nothing_here">چیزی اینجا نیست</string>
<string name="scrobbling_empty_hint">برای فعال کردن پیگیری پیشرفت خواندن، منو را انتخاب کنید ← پیگیری در صفحه جزئیات مانگا.</string>
<string name="services">خدمات</string>
<string name="allow_unstable_updates">اجازه بروزرسانی های ناپایدار</string>
<string name="allow_unstable_updates_summary">دریافت اعلان درباره ورژن های ناپایدار</string>
<string name="download_started">بارگیری آغاز شد</string>
<string name="got_it">متوجه شدم</string>
<string name="sources_reorder_tip">برای مرتب‌سازی مجدد آیتم‌ها، روی آنها ضربه بزنید و نگه دارید</string>
<string name="user_agent">هدر UserAgent</string>
<string name="settings_apply_restart_required">لطفا برای اعمال این تغییرات، برنامه را مجددا راه اندازی کنید</string>
<string name="comics_archive_import_description">میتونی یک یا چند فایل .cbz یا .zip رو انتخاب کنی، هر فایل به صورت یک مانگای مجزا شناخته میشه.</string>
<string name="folder_with_images_import_description">میتونی یک پوشه حاوی آرشیو ها یا تصاویر انتخاب کنی. هر آرشیو (یا زیرشاخه) به عنوان یک فصل شناخته میشن.</string>
<string name="speed">سرعت</string>
<string name="show_on_shelf">نمایش در ققسه</string>
<string name="sync_auth_hint">میتونی وارد یک اکانت بشی یا یک اکانت جدید بسازی</string>
<string name="find_similar">پیدا کردن مشابه</string>
<string name="sync_settings">تنظیمات همگام سازی</string>
<string name="server_address">آدرس سرور</string>
<string name="sync_host_description">می‌توانید از یک سرور همگام‌سازی خود-میزبان یا یک سرور پیش‌فرض استفاده کنید. اگر مطمئن نیستید که چه کاری انجام می‌دهید، این را تغییر ندهید.</string>
<string name="ignore_ssl_errors">نادیده گرفتن خطا های SSL</string>
<string name="mirror_switching">انتخاب خودکار آینه</string>
<string name="mirror_switching_summary">در صورت وجود آینه، دامنه‌ها را برای منابع مانگا به صورت خودکار تغییر دهید</string>
<string name="pause">توقف</string>
<string name="resume">ازسرگیری</string>
<string name="paused">متوقف شده</string>
<string name="remove_completed">منوی آیتم؛ اقدام برای حذف آیتم های کامل شده</string>
<string name="cancel_all">لغو همه</string>
<string name="downloads_wifi_only">بارگیری فقط از طریق وایفای</string>
<string name="downloads_wifi_only_summary">توقف دانلود در زمان تغییرشبکه به داده تلفن همراه</string>
<string name="suggestion_manga">پیشنهاد:%s</string>
<string name="suggestions_notifications_summary">گاهی اوقات اعلان‌هایی با مانگا پیشنهادی نمایش داده می‌شود</string>
<string name="more">بیشتر</string>
<string name="enable">فعال</string>
<string name="no_thanks">نه ممنون</string>
<string name="cancel_all_downloads_confirm">تمام دانلودهای فعال لغو می‌شوند، داده‌هایی که به‌طور ناقص دانلود شده‌اند از بین می‌روند</string>
<string name="remove_completed_downloads_confirm">تاریخچه بارگیری شما برای همیشه حذف خواهد شد. شامل فایل های بارگیری شده نمیشود</string>
<string name="text_downloads_list_holder">شما هیچ بارگیری ندارید</string>
<string name="downloads_paused">بارگیری ها متوقف شده اند</string>
<string name="downloads_removed">بارگیری ها حذف شده اند</string>
<string name="web_view_unavailable">وب ویو در دسترس نیست: بررسی کنید ارائه دهنده وب ویو نصب شده باشد</string>
<string name="clear_network_cache">پاک کردن حافظه نهان شبکه</string>
<string name="type">نویسه</string>
<string name="address">آدرس</string>
<string name="port">درگاه</string>
<string name="proxy">پروکسی</string>
<string name="invalid_value_message">مقدار نامعتبر</string>
<string name="email_password_enter_hint">برای ادامه رایانامه و گذرواژه را وارد کنید</string>
<string name="downloaded">بارگیری شده</string>
<string name="images_proxy_title">پروکسی بهینه سازی تصاویر</string>
<string name="images_procy_description">استفاده از سرویس wsrv.nl (در صورت امکان) برای کاهش مصرف ترافیک و افزایش سرعت بارگیری تصویر</string>
<string name="invert_colors">معکوس کردن رنگ ها</string>
<string name="username">نام کاربری</string>
<string name="password">گذرواژه</string>
<string name="authorization_optional">اعتبار سنجی (اختیاری)</string>
<string name="invalid_port_number">شماره درگاه نامعتبر</string>
<string name="network">شبکه</string>
<string name="data_and_privacy">داده ها و حریم خصوصی</string>
<string name="restore_summary">بازیابی نسخه پشتیبان تهیه شده قبلی</string>
<string name="webtoon_zoom_summary">امکان زوم در حالت وبتون</string>
<string name="reader_info_bar_summary">نمایش زمان و پیشرفت کنونی در بالای صفحه نمایش</string>
<string name="show_pages_numbers_summary">نمایش شماره صفحه در گوشیه پایین صفحه</string>
<string name="clear_source_cookies_summary">پاک کردن کوکی ها برای یک دامنه خاص. در بیشتر موارد، مجوز را باطل می‌کند</string>
<string name="download_option_all_chapters">تمام فصل ها ترجمه شده %s</string>
<string name="download_option_whole_manga">تمام مانگا</string>
<string name="download_option_first_n_chapters">ابتدا %s</string>
<string name="download_option_next_unread_n_chapters">خوانده نشده بعدی %s</string>
<string name="download_option_all_unread">تمام فصل های خوانده نشده</string>
<string name="download_option_all_unread_b">تمام فصل های خوانده نشده (%s)</string>
<string name="download_option_manual_selection">انتخاب فصل به صورت دستی</string>
<string name="pick_custom_directory">انتخاب پوشه سفارشی</string>
<string name="no_access_to_file">شما دسترسی به این پرونده یا پوشه را ندارید</string>
<string name="local_manga_directories">پوشه های مانگای محلی</string>
<string name="description">توضیحات</string>
<string name="this_month">این ماه</string>
<string name="voice_search">جستجوی صوتی</string>
<string name="related_manga">مانگا های مرتبط</string>
<string name="color_light">حالت روز</string>
<string name="color_dark">حالت شب</string>
<string name="color_white">سفید</string>
<string name="color_black">مشکی</string>
<string name="background">پسزمینه</string>
<string name="data_not_restored">داده ها بازیابی نشدند</string>
<string name="data_not_restored_text">از انتخاب درست پرونده پشتیبان اطمینان حاصل کنید</string>
<string name="manage_categories">مدیریت دسته بندی ها</string>
<string name="suggestions_wifi_only_summary">به‌روزرسانی نکردن پیشنهادها با استفاده از اتصالات شبکه محدود</string>
<string name="tracker_wifi_only_summary">عدم بررسی بروزرسانی فصل ها با اتصال شبکه محدود</string>
<string name="search_hint">عنوان مانگا را وارد کنید، ژانر یا نام منبع</string>
<string name="progress">پیشرفت</string>
<string name="order_added">اضافه شده</string>
<string name="show">نمایش</string>
<string name="captcha_required_summary">%s نیازمند حل کردن کپچا برای کار کردن است</string>
<string name="languages">زبان ها</string>
<string name="unknown">ناشناخته</string>
<string name="in_progress">درحال انجام</string>
<string name="disable_nsfw">غیر فعال سازی NSFW</string>
<string name="too_many_requests_message">درخواست‌ها خیلی زیاد است. بعداً دوباره امتحان کنید</string>
<string name="too_many_requests_message_retry">درخواست‌ها خیلی زیاد است. بعدا از %s دوباره تلاش کنید</string>
<string name="related_manga_summary">نمایش یک فهرست از مانگا های مرتبط. در برخی موارد ممکن است اشتباه یا ناقص باشد</string>
<string name="advanced">پیشرفته</string>
<string name="manga_list">مدیریت فهرست</string>
<string name="error_corrupted_file">داده نامعتبر است یا پرونده خراب است</string>
<string name="on_device">روی دستگاه</string>
<string name="directories">پوشه ها</string>
<string name="main_screen_sections">بخش‌های صفحه اصلی</string>
<string name="items_limit_exceeded">نمیتوان آیتم های بیشتری اضافه کرد</string>
<string name="to_top">به بالا</string>
<string name="moved_to_top">به بالا منتقل شد</string>
<string name="zoom_out">کوچک نمایی</string>
<string name="zoom_in">بزرگ نمایی</string>
<string name="reader_zoom_buttons">نمایش دکمه های بزرگنمایی</string>
<string name="reader_zoom_buttons_summary">اینکه آیا دکمه‌های کنترل بزرگنمایی در گوشه پایین سمت راست نمایش داده شوند یا خیر</string>
<string name="keep_screen_on">روشن نگه داشتن صفحه نمایش</string>
<string name="keep_screen_on_summary">جلوگیری از خاموش شدن صفحه نمایش در زمان خواندن مانگاه</string>
<string name="state_abandoned">رها شده</string>
<string name="enhanced_colors_summary">باندینگ را کاهش می‌دهد، اما ممکن است بر عملکرد تأثیر بگذارد</string>
<string name="enhanced_colors">حالت رنگ ۳۲ بیتی</string>
<string name="suggest_new_sources">پیشنهاد منابع جدید بعد از بروزرسانی برنامه</string>
<string name="suggest_new_sources_summary">درخواست فعال کردن منابع تازه اضافه شده پس از به‌روزرسانی برنامه</string>
<string name="list_options">گزینه های فهرست</string>
<string name="by_relevance">ارتباط</string>
<string name="categories">دسته بندی ها</string>
<string name="online_variant">نوع برخط</string>
<string name="periodic_backups">پشتیبان‌گیری‌های دوره‌ای</string>
<string name="backup_frequency">فرکانس ایجاد نسخه پشتیبان</string>
<string name="frequency_every_day">هر روز</string>
<string name="frequency_every_2_days">هر ۲ دوز</string>
<string name="frequency_once_per_week">هر هفته</string>
<string name="frequency_twice_per_month">دوبار در ماه</string>
<string name="frequency_once_per_month">یک بار درماه</string>
<string name="periodic_backups_enable">فعال کردن پشتیبان گیری دوره ای</string>
<string name="backups_output_directory">پوشه خروجی پشتیبان گیری</string>
<string name="last_successful_backup">آخرین پشتیبان گیری موفق:%s</string>
<string name="lock_screen_rotation">قفل چرخش صفحه</string>
<string name="content_type_manga">مانگا</string>
<string name="content_type_hentai">هنتای</string>
<string name="content_type_comics">کامیک بوک</string>
<string name="content_type_other">دیگر</string>
<string name="sources_catalog">کاتالوگ منابع</string>
<string name="source_enabled">منبع فعال شد</string>
<string name="no_manga_sources_catalog_text">هیچ منبع فعالی در این بخش وجود ندارد، یا همه آنها قبلا اضافه شده اند.\nبا ما همراه باشید</string>
<string name="no_manga_sources_found">هیچ منبع فعال بر اساس جستجوی شما یافت نشد</string>
<string name="catalog">کاتالوگ</string>
<string name="manage_sources">مدیریت منابع</string>
<string name="manual">دستی</string>
<string name="available_d">دردسترس: %1$d</string>
<string name="disable_nsfw_summary">در صورت امکان مانگای بزرگسالان و منابع NSFW را غیر فعال کنید</string>
<string name="state_paused">متوقف شده</string>
<string name="reader_optimize">کاهش مصرف حافظه (آزمایشی)</string>
<string name="reader_optimize_summary">کاهش کیفیت صفحات خارج از صفحه برای استفاده کمتر از حافظه</string>
<string name="state">حالت</string>
<string name="downloads_resumed">بارگیری‌ها ازسر گرفته شده‌اند</string>
<string name="downloads_cancelled">بارگیری‌ها لغو شده‌اند</string>
<string name="suggestions_enable_prompt">آیا می‌خواهید پیشنهادهای مانگای شخصی شده دریافت کنید؟</string>
</resources>

View File

@@ -856,4 +856,5 @@
<string name="manga_restricted_description">Ce manga nest pas disponible à la lecture sur cette source. Essaie de le chercher dans dautres sources ou ouvre-le dans un navigateur pour plus dinformations</string>
<string name="no_chapters_in_manga">Ce manga ne contient aucun chapitre</string>
<string name="chapters_load_failed">Échec du chargement de la liste des chapitres</string>
<string name="telegram_integration">Intégration Telegram</string>
</resources>

View File

@@ -44,12 +44,12 @@
<string name="nothing_found">Ništa nije pronađeno</string>
<string name="read">Čitaj</string>
<string name="you_have_not_favourites_yet">Još nema favorita</string>
<string name="add_to_favourites">Označite ovo kao favorit</string>
<string name="add_to_favourites">Dodaj u favorite</string>
<string name="add_new_category">Nova kategorija</string>
<string name="add">Dodaj</string>
<string name="save">Sačuvaj</string>
<string name="share">Podijeli</string>
<string name="create_shortcut">Napravi prečicu</string>
<string name="create_shortcut">Napravi prečicu</string>
<string name="share_s">Podijeli %s</string>
<string name="search">Pretraži</string>
<string name="search_manga">Pretraži mangu</string>
@@ -266,7 +266,7 @@
<string name="enable_logging">Omogući bilježenje</string>
<string name="enable_logging_summary">Snimite neke radnje u svrhu otklanjanja pogrešaka. Nemojte ga uključivati ako niste sigurni što radite</string>
<string name="show_suspicious_content">Prikaži sumnjiv sadržaj</string>
<string name="theme_name_dynamic">Dinamičan</string>
<string name="theme_name_dynamic">Dinamična</string>
<string name="color_theme">Shema boja</string>
<string name="show_in_grid_view">Prikaži u mrežnom prikazu</string>
<string name="theme_name_miku">Miku</string>
@@ -474,7 +474,7 @@
<string name="file_not_found">Datoteka nije pronađena</string>
<string name="data_restored_success">Svi podaci su vraćeni</string>
<string name="data_restored_with_errors">Podaci su vraćeni, ali ima grešaka</string>
<string name="backup_information">Možete stvoriti sigurnosnu kopiju svoje povijesti i favorita i vratiti je</string>
<string name="backup_information">Možete stvoriti sigurnosnu kopiju svoje povijesti i favorita i obnoviti je</string>
<string name="yesterday">Jučer</string>
<string name="long_ago">Davno</string>
<string name="data_restored">Vraćeno</string>
@@ -782,4 +782,24 @@
<string name="global_search">Globalna pretraga</string>
<string name="search_everywhere">Traži svuda</string>
<string name="badges_in_lists">Značke u popisima</string>
<string name="nsfw_16">16+</string>
<string name="theme_name_expressive">Ekspresivna (test)</string>
<string name="chapter_volume_number">Svezak %1$s Poglavlje %2$s</string>
<string name="chapter_number">Poglavlje %s</string>
<string name="unnamed_chapter">Neimenovano poglavlje</string>
<string name="search_disabled_sources">Pretraži deaktivirane izvore</string>
<string name="error_details">Detalji greške</string>
<string name="error_disclaimer_manga">Pokušaj otvoriti manga u web pregledniku kako bi provjerio/la je li dostupan na izvornom mjestu.</string>
<string name="error_disclaimer_app_outdated">Izgleda da je tvoja Kotatsu verzija zastarjela. Instaliraj najnoviju verziju za dobivanje svih dostupnih ispravki.</string>
<string name="link_to_manga_in_app">Poveznica na manga u Kotatsu</string>
<string name="link_to_manga_on_s">Poveznica na manga na %s</string>
<string name="error_disclaimer_report">Pošalji izvještaj o grešci programerima. To će nam pomoći da istražimo i ispravimo problem.</string>
<string name="clear_browser_data">Izbriši podatke iz preglednika</string>
<string name="clear_browser_data_summary">Izbriši podatke iz preglednika poput predmemorije i kolačića. Upozorenje: Autorizacija na izvorima mange može postati nevažeća</string>
<string name="no_write_permission_to_file">Nema dozvolu za pisanje u datoteku</string>
<string name="exclude_nsfw_from_suggestions_summary">Manga za odrasle se neće prikazivati u prijedlozima. Ova opcija možda neće točno funkcionirati s nekim izvorima</string>
<string name="include_disabled_sources">Uključi deaktivirane izvore</string>
<string name="suggestions_disabled_sources_summary">Prikaži prijedloge iz svih izvora mange, uključujući deaktivirane</string>
<string name="tags_warnings">Istakni opasne žanrove</string>
<string name="tags_warnings_summary">Istakni žanrove koji bi mogli biti neprikladni za većinu korisnika</string>
</resources>

View File

@@ -50,7 +50,7 @@
<string name="detailed_list">Elenco dettagliato</string>
<string name="text_delete_local_manga">Vuoi davvero eliminare \" %s\" dalla memoria locale del tuo dispositivo?</string>
<string name="_s_deleted_from_local_storage">\"%s\" eliminato dall\'archiviazione locale</string>
<string name="list">Liste</string>
<string name="list">Lista</string>
<string name="chapters">Capitoli</string>
<string name="details">Dettagli</string>
<string name="network_error">Errore di connessione</string>
@@ -318,7 +318,7 @@
<string name="importing_manga">Importazione di manga</string>
<string name="import_will_start_soon">L\'importazione inizierà presto</string>
<string name="feed">Flusso</string>
<string name="reader_control_ltr_summary">Non adattare la direzione di cambio pagina alla modalità di lettura; ad esempio, premendo il tasto destro, si passa sempre alla pagina successiva. Questa opzione riguarda solo i dispositivi di input hardware</string>
<string name="reader_control_ltr_summary">Non adeguare la direzione dello sfoglio alla modalità di lettura impostata. Ad esempio: premere la freccia destra passerà sempre alla pagina seguente. Questa impostazione ha effetto solo sui dispositivi di input hardware</string>
<string name="contrast">Contrasto</string>
<string name="reset">Ripristina</string>
<string name="reader_slider">Mostra il cursore di cambio pagina</string>
@@ -543,7 +543,7 @@
<string name="last_read">Ultima lettura</string>
<string name="reading_time_estimation_summary">Il tempo di lettura stimato potrebbe essere inaccurato</string>
<string name="reading_time_estimation">Mostra il tempo di lettura stimato</string>
<string name="email_password_enter_hint">Inserisci la tua email e password per continuare</string>
<string name="email_password_enter_hint">Inserisci email e password per continuare</string>
<string name="show_menu">Mostra menu</string>
<string name="switch_pages_volume_buttons_summary">Usa i pulsanti del volume per cambiare pagine</string>
<string name="tap_action">Azioni tap</string>
@@ -566,7 +566,7 @@
<string name="toggle_ui">Mostra/nascondi UI</string>
<string name="next_chapter">Prossimo capitolo</string>
<string name="prev_page">Pagina precedente</string>
<string name="next_page">Prossima pagina</string>
<string name="next_page">Pagina successiva</string>
<string name="reader_actions">Azioni del lettore</string>
<string name="switch_pages_volume_buttons">Abilita pulsanti del volume</string>
<string name="reader_fullscreen_summary">Nascondi le barre di stato e di notifica</string>
@@ -603,7 +603,7 @@
<string name="three_months">Tre mesi</string>
<string name="empty_stats_text">Non ci sono statistiche per il periodo selezionato</string>
<string name="ask_for_dest_dir_every_time">Chiedi per la cartella di destinazione ogni volta</string>
<string name="pages_saving">Salva pagine</string>
<string name="pages_saving">Salvando le pagine</string>
<string name="preferred_download_format">Formato download preferito</string>
<string name="single_cbz_file">File CBZ singolo</string>
<string name="multiple_cbz_files">Molti file CBZ</string>
@@ -647,10 +647,10 @@
<string name="chapters_read">Capitoli letti</string>
<string name="chapters_left">Capitoli rimasti</string>
<string name="default_webtoon_zoom_out">Riduzione dello zoom Webtoon predefinito</string>
<string name="crop_pages">Ritagliare le pagine</string>
<string name="unpin">Sblocca</string>
<string name="source_unpinned">Fonte non individuata</string>
<string name="sources_unpinned">Fonti non individuate</string>
<string name="crop_pages">Ritaglia le pagine</string>
<string name="unpin">Rimuovi</string>
<string name="source_unpinned">Fonte rimossa</string>
<string name="sources_unpinned">Fonti rimosse</string>
<string name="tracker_debug_info_summary">Informazioni di debug sui controlli in background per i nuovi capitoli</string>
<string name="location">Posizione</string>
<string name="chapters_deleted_pattern">Rimosso %1$s, cancellato %2$s</string>
@@ -857,4 +857,6 @@
<string name="unavailable">Non disponibile</string>
<string name="manga_restricted_description">Questo manga non è disponibile per la lettura da questa fonte. Prova a cercarlo in altre fonti o aprilo in un browser per maggiori informazioni</string>
<string name="no_chapters_in_manga">Questo manga non contiene capitoli</string>
<string name="telegram_integration">Integrazione con Telegram</string>
<string name="chapters_load_failed">Errore nel caricamento della lista dei capitoli</string>
</resources>

View File

@@ -22,11 +22,11 @@
<string name="history_is_empty">まだ履歴はありません</string>
<string name="read">読む</string>
<string name="you_have_not_favourites_yet">お気に入りの本はありません</string>
<string name="add_to_favourites">お気に入り</string>
<string name="add_to_favourites">お気に入りに追加</string>
<string name="add_new_category">新しいカテゴリー</string>
<string name="add">追加</string>
<string name="save">保存</string>
<string name="create_shortcut">ショートカットを作成</string>
<string name="create_shortcut">ショートカットを作成</string>
<string name="share_s">%s を共有する</string>
<string name="manga_downloading_">ダウンロード中…</string>
<string name="processing_">処理中…</string>
@@ -305,7 +305,7 @@
<string name="incognito_mode">シークレットモード</string>
<string name="folder_with_images">画像を含むフォルダ</string>
<string name="import_will_start_soon">まもなくインポートが開始されます</string>
<string name="removed_from_favourites">お気に入りから削除</string>
<string name="removed_from_favourites">お気に入りから削除されました</string>
<string name="options">オプション</string>
<string name="import_completed_hint">ストレージから元のファイルを削除して、容量を節約することができます</string>
<string name="reader_info_pattern">Ch.%1$d/%2$d Pg.%3$d/%4$d</string>
@@ -472,4 +472,6 @@
<string name="enable_all_sources">すべての漫画ソースを有効にする</string>
<string name="enable_all_sources_summary">利用可能なすべての漫画ソースを永久に有効にする</string>
<string name="all_sources_enabled">すべてのソースが有効</string>
<string name="automatic">自動</string>
<string name="invalid_server_address_message">無効なサーバーアドレス</string>
</resources>

View File

@@ -29,7 +29,11 @@
<item quantity="other">%1$d сағат бұрын</item>
</plurals>
<plurals name="hours">
<item quantity="one">Бір</item>
<item quantity="one">%1$d сағат</item>
<item quantity="other">Нөл , екі, үш, төрт, бес, алты, жеті, сегіз, тоғыз, он</item>
</plurals>
</resources>
<plurals name="minutes">
<item quantity="one">%1$d минут</item>
<item quantity="other">%1$d минут</item>
</plurals>
</resources>

View File

@@ -31,7 +31,7 @@
<string name="add">Қосу</string>
<string name="save">Сақтау</string>
<string name="share">Бөлісу</string>
<string name="create_shortcut">Таңбаша жасау</string>
<string name="create_shortcut">Таңбаша жасау</string>
<string name="share_s">%s бөлісу</string>
<string name="search">Іздеу</string>
<string name="manga_downloading_">Жүктеліп жатыр…</string>
@@ -53,7 +53,7 @@
<string name="remove">Жою</string>
<string name="_s_deleted_from_local_storage">«%s» құрылғыдан жойылды</string>
<string name="save_page">Бетті сақтау</string>
<string name="page_saved">Сақталды</string>
<string name="page_saved">Бет сақталды</string>
<string name="share_image">Суретті бөлісу</string>
<string name="_import">Импорт</string>
<string name="no_description">Сипаттамасы жоқ</string>
@@ -79,7 +79,7 @@
<string name="notification_sound">Мәлімдеме дыбысы</string>
<string name="light_indicator">LED индикаттау</string>
<string name="vibration">Діріл</string>
<string name="favourites_categories">Таңдаулы санаттар</string>
<string name="favourites_categories">Таңдаулы санаты</string>
<string name="remove_category">Жою</string>
<string name="text_empty_holder_primary">Мына жер бос екен…</string>
<string name="text_history_holder_primary">Бұ жерде оқығаныңыз тұрады</string>
@@ -257,7 +257,7 @@
<string name="hide">Жасыру</string>
<string name="exclude_nsfw_from_history_summary">ҰЯТСЫЗ деген маңганы оқығаныңыз тарихыңызда сақталмайды</string>
<string name="show_reading_indicators_summary">Таңдаулы мен тарихта оқылған туынды пайызын көрсету</string>
<string name="use_fingerprint">Қолжетімді болса саусақ ізін қолдану</string>
<string name="use_fingerprint">Қолжетімді болса биометрика қолдану</string>
<string name="onboard_text">Маңганы қай тілде оқығыңыз келетінін таңдаңыз. Кейінірек баптауда өзгертіп ала аласыз.</string>
<string name="suggestions_updating">Ұсынысты жаңарту</string>
<string name="percent_string_pattern">%%%1$s</string>
@@ -537,4 +537,8 @@
<string name="reader_actions">Оқымадағы әрекет</string>
<string name="sync_auth">Синхрондау тіркелгісіне кіру</string>
<string name="config_reset_confirm">Әдепкі баптауға қайтайық па? Әрекетті қайтаруға болмайды.</string>
<string name="retry">Қайталау</string>
<string name="pages_saved">Беттер сақталды</string>
<string name="text_empty_holder_secondary_filtered">Сүзіп алғаныңызға сай маңга жоқ</string>
<string name="nsfw_16">16+</string>
</resources>

View File

@@ -838,4 +838,22 @@
<string name="main_screen_fab">Mostrar botão Continuar flutuante</string>
<string name="main_screen_fab_summary">Permite continuar a leitura com um clique. Este botão não aparecerá no modo anônimo ou quando o histórico estiver vazio</string>
<string name="error_corrupted_zip">Arquivo ZIP corrompido (%s)</string>
<string name="discord_token_hint">Cole seu Token do Discord aqui</string>
<string name="discord_rpc_summary">Mostra seu status de leitura no Discord</string>
<string name="obtain">Obtenha</string>
<string name="discord_rpc_description">Lendo mangá no Kotatsu - um aplicativo de leitura de mangá</string>
<string name="reading_s">Lendo %s</string>
<string name="rpc_skip_nsfw_summary">Não usar RPC para conteúdo adulto</string>
<string name="invalid_token">Token inválido: %s</string>
<string name="show_floating_control_button">Mostrar botão de controle flutuante</string>
<string name="unavailable">Indisponível</string>
<string name="manga_restricted_description">Este mangá não está disponível para leitura nessa fonte. Tente pesquisar por ele em outras fontes ou abrir em um navegador para mais informação</string>
<string name="no_chapters_in_manga">Este mangá não contém nenhum capítulo</string>
<string name="chapters_load_failed">Falha ao carregar lista de capítulos</string>
<string name="telegram_integration">Integração com Telegram</string>
<string name="discord_token">Token do Discord</string>
<string name="discord_token_summary">Insira seu Token do Discord para habilitar a Rich Presence</string>
<string name="discord_rpc">Discord Rich Presence</string>
<string name="discord_token_description">Insira seu Token do Discord ou clique em %s para obtê-lo usando o navegador</string>
<string name="read_on_s">Leia em %s</string>
</resources>

View File

@@ -65,7 +65,7 @@
<string name="app_update_available">Uma nova versão do app está disponível</string>
<string name="open_in_browser">Abrir no navegador da web</string>
<string name="notifications">Notificações</string>
<string name="new_chapters">Capítulos novos</string>
<string name="new_chapters">Novos capítulos</string>
<string name="download">Download</string>
<string name="notifications_settings">Configurações das notificações</string>
<string name="light_indicator">Indicador LED</string>
@@ -330,7 +330,7 @@
<string name="import_will_start_soon">A importação começará em breve</string>
<string name="feed">Fluxo</string>
<string name="manga_error_description_pattern">Detalhes do erro:&lt;br&gt;&lt;tt&gt;%1$s&lt;/tt&gt;&lt;br&gt;&lt;br&gt;1. Tente &lt;a href=%2$s&gt;abra a página do mangá em um navegador da web&lt;/a&gt; para garantir que o mesmo esteja disponível em sua fonte&lt;br&gt;2. Se estiver disponível, envie um relatório de erro para os desenvolvedores.</string>
<string name="reader_control_ltr_summary">Tocar a borda direita ou pressionar a tecla direita, sempre mudará para a próxima página.</string>
<string name="reader_control_ltr_summary">Não ajustar a direção da mudança de página no modo de editor, por exemplo, pressionar a tecla direita muda sempre para a página seguinte. Esta opção só afeta os dispositivos de hardware de entrada</string>
<string name="reader_control_ltr">Controle ergonômico do leitor</string>
<string name="discard">Descartar</string>
<string name="language">Idioma</string>
@@ -836,4 +836,26 @@
<string name="book_effect">Fundo amarelaso (filtro de luz azul)</string>
<string name="local_storage_cleanup">Limpeza do armazenamento local</string>
<string name="packup_creation_failed">Falha ao criar backup</string>
<string name="main_screen">Ecrã principal</string>
<string name="main_screen_fab">Mostrar botão flutuante \"Continuar\"</string>
<string name="discord_token">Código do Discord</string>
<string name="main_screen_fab_summary">Permite que continue lendo em um clique. Esse botão não irá aparecer no modo incógnito or quando o histórico estiver vazio</string>
<string name="error_corrupted_zip">Arquivo ZIP corrompido (%s)</string>
<string name="discord_rpc">Rich Presence do Discord</string>
<string name="discord_token_summary">Entre seu Token do Discord para habilitar Rich Presence</string>
<string name="discord_token_description">Entre seu Token do Discord ou clique %s para obtê-lo pelo navegador</string>
<string name="discord_token_hint">Cole seu Token do Discord aqui</string>
<string name="discord_rpc_summary">Mostrar seu estado de leitura no Discord</string>
<string name="obtain">Obter</string>
<string name="discord_rpc_description">Lendo manga no Kotatsu - um app leitor de manga</string>
<string name="reading_s">Lendo %s</string>
<string name="read_on_s">Lendo em %s</string>
<string name="rpc_skip_nsfw_summary">Não use RPC para conteúdo adulto</string>
<string name="invalid_token">Token inválido: %s</string>
<string name="show_floating_control_button">Mostrar botão de controle flutuante</string>
<string name="unavailable">Indisponível</string>
<string name="manga_restricted_description">Esse manga não está disponível para leitura nessa fonte. Tente pesquisá-lo em outras fontes ou abra-o no navegador para mais informação</string>
<string name="no_chapters_in_manga">Esse manga não contém capítulos</string>
<string name="chapters_load_failed">Falha ao carregar lista de capítulos</string>
<string name="telegram_integration">Integração Telegram</string>
</resources>

View File

@@ -835,4 +835,28 @@
<string name="book_effect">Желтоватый фон (фильтр синего)</string>
<string name="reader_navigation_inverted_summary">Поменять местами направление кнопки регулировки громкости и аппаратной клавиши навигации (влево/вверх/вниз/вправо)</string>
<string name="reader_multitask_summary">Позволяет держать открытыми несколько читалок с разной мангой одновременно</string>
<string name="local_storage_cleanup">Очистка локального хранилища</string>
<string name="packup_creation_failed">Не удалось создать резервную копию</string>
<string name="main_screen">Главный экран</string>
<string name="main_screen_fab">Показать плавающую кнопку «Продолжить»</string>
<string name="main_screen_fab_summary">Позволяет продолжить чтение одним кликом. Эта кнопка не отображается в режиме инкогнито или при пустой истории</string>
<string name="error_corrupted_zip">Повреждённый ZIP-архив (%s)</string>
<string name="discord_rpc">Discord Rich Presence</string>
<string name="discord_token">Токен Discord</string>
<string name="discord_token_summary">Введите свой токен Discord, чтобы включить Rich Presence</string>
<string name="discord_token_description">Введите свой токен Discord или нажмите %s, чтобы получить его через браузер</string>
<string name="discord_token_hint">Вставьте свой токен Discord сюда</string>
<string name="discord_rpc_summary">Покажите свой статус чтения в Discord</string>
<string name="obtain">Получить</string>
<string name="discord_rpc_description">Чтение манги в Kotatsu — приложение для чтения манги</string>
<string name="reading_s">Чтение %s</string>
<string name="read_on_s">Читать дальше %s</string>
<string name="rpc_skip_nsfw_summary">Не использовать RPC для контента для взрослых</string>
<string name="invalid_token">Недействительный токен: %s</string>
<string name="show_floating_control_button">Показать плавающую кнопку управления</string>
<string name="unavailable">Недоступно</string>
<string name="manga_restricted_description">Эта манга недоступна для чтения в этом источнике. Попробуйте поискать её в других источниках или открыть в браузере, чтобы узнать больше</string>
<string name="no_chapters_in_manga">Эта манга не содержит глав</string>
<string name="chapters_load_failed">Не удалось загрузить список глав</string>
<string name="telegram_integration">Интеграция с Telegram</string>
</resources>

View File

@@ -858,4 +858,5 @@
<string name="manga_restricted_description">Bu manga, okumak için bu kaynakta mevcut değil. Başka kaynaklarda aramayı ya da daha fazla bilgi için tarayıcıda açmayı deneyin</string>
<string name="no_chapters_in_manga">Bu manga bölüm içermiyor</string>
<string name="chapters_load_failed">Bölüm listesi yüklenemedi</string>
<string name="telegram_integration">Telegram entegrasyonu</string>
</resources>

View File

@@ -794,7 +794,7 @@
<string name="unnamed_chapter">Безіменний розділ</string>
<string name="search_disabled_sources">Пошук за відключеними джерелами</string>
<string name="error_details">Подробиці помилки</string>
<string name="book_effect">Жовтуватий фон (фільтр синього)</string>
<string name="book_effect">Жовтуватий фон (синій фільтр)</string>
<string name="theme_name_totoro">Тоторо</string>
<string name="theme_name_itsuka">Іцука</string>
<string name="reader_multitask_summary">Дозволяє тримати відкритими кілька читалок із різною манґою одночасно</string>
@@ -804,7 +804,7 @@
<string name="collapse_long_description">Згорнути довгий опис</string>
<string name="adblock_summary">Блокування реклами у вбудованому браузері (бета)</string>
<string name="adblock">Блокувати рекламу у браузері</string>
<string name="expand">Розширити</string>
<string name="expand">Розгорнути</string>
<string name="collapse">Згорнути</string>
<string name="changelog_summary">Історія змін для нещодавно випущених версій</string>
<string name="changelog">Журнал змін</string>
@@ -841,21 +841,22 @@
<string name="main_screen_fab">Показати плаваючу кнопку «Продовжити»</string>
<string name="main_screen_fab_summary">Дозволяє продовжити читання одним кліком. Ця кнопка не з\'являється в режимі інкогніто або коли історія порожня</string>
<string name="error_corrupted_zip">Пошкоджений архів ZIP (%s)</string>
<string name="discord_rpc">Discord Rich Presence</string>
<string name="discord_rpc">Багатий на присутність у Discord</string>
<string name="discord_token">Токен Discord</string>
<string name="discord_token_summary">Введіть свій токен Discord, щоб увімкнути Rich Presence</string>
<string name="discord_token_description">Введіть свій Discord токен або натисніть %s, щоб отримати його за допомогою браузера</string>
<string name="discord_token_hint">Вставте тут свій токен Discord</string>
<string name="discord_rpc_summary">Показувати свій статус читання в Discord</string>
<string name="discord_rpc_summary">Покажіть свій статус читання в Discord</string>
<string name="obtain">Отримати</string>
<string name="discord_rpc_description">Читання манги на Kotatsu - програма для читання манґи</string>
<string name="reading_s">Читання %s</string>
<string name="read_on_s">Читати на %s</string>
<string name="rpc_skip_nsfw_summary">Не використовувати RPC для контенту для дорослих</string>
<string name="rpc_skip_nsfw_summary">Не використовуйте RPC для контенту для дорослих</string>
<string name="invalid_token">Недійсний токен: %s</string>
<string name="show_floating_control_button">Показати плаваючу кнопку керування</string>
<string name="unavailable">Недоступно</string>
<string name="manga_restricted_description">Ця манга недоступна для читання в цьому джерелі. Спробуйте знайти її в інших джерелах або відкрити в браузері, щоб отримати додаткову інформацію</string>
<string name="no_chapters_in_manga">Ця манга не містить жодних розділів</string>
<string name="chapters_load_failed">Не вдалося завантажити список розділів</string>
<string name="telegram_integration">Інтеграція з Telegram</string>
</resources>

View File

@@ -166,7 +166,7 @@
<string name="network_unavailable">Không có mạng</string>
<string name="network_unavailable_hint">Bật wifi hoặc dữ liệu di động để đọc truyện trực tuyến</string>
<string name="prefetch_content">Tải trước nội dung</string>
<string name="mark_as_current">Đánh dấu hiện tại</string>
<string name="mark_as_current">Đánh dấu hiện tại đã đọc xong</string>
<string name="enable_logging_summary">Lưu một số thông tin cho mục đích gỡ lỗi. Đừng bật nó nếu bạn không biết mình đang làm gì</string>
<string name="show_suspicious_content">Hiển thị nội dung khả nghi</string>
<string name="theme_name_dynamic">Động</string>
@@ -856,4 +856,5 @@
<string name="manga_restricted_description">Truyện này không có sẵn trên nguồn này. Hãy thử tìm kiếm truyện này với nguồn đọc khác hoặc mở nó trong trình duyệt để biết thêm chi tiết</string>
<string name="no_chapters_in_manga">Truyện này không có sẵn chương nào cả ツ</string>
<string name="chapters_load_failed">Không thể tải danh sách chương hiện có</string>
<string name="telegram_integration">Tích hợp Telegram</string>
</resources>

View File

@@ -854,4 +854,5 @@
<string name="no_chapters_in_manga">没有找到此漫画的任何章节</string>
<string name="chapters_load_failed">加载章节列表失败</string>
<string name="manga_restricted_description">此漫画在图源中无法阅读,尝试在别的图源中搜索此漫画或打开内置浏览器获取更多信息</string>
<string name="telegram_integration">Telegram集成</string>
</resources>

View File

@@ -51,17 +51,16 @@
app:isPreferenceVisible="false" />
<PreferenceCategory
android:key="backup_periodic_tg"
android:title="@string/telegram_integration"
app:isPreferenceVisible="false"
android:key="backup_periodic_tg"
tools:isPreferenceVisible="true">
<SwitchPreferenceCompat
android:defaultValue="false"
android:dependency="backup_periodic"
android:key="backup_periodic_tg_enabled"
android:title="@string/send_backups_telegram"
app:allowDividerAbove="true" />
android:title="@string/send_backups_telegram" />
<EditTextPreference
android:dependency="backup_periodic_tg_enabled"

View File

@@ -34,12 +34,12 @@ material = "1.14.0-alpha03"
moshi = "1.15.2"
okhttp = "4.12.0"
okio = "3.12.0"
parsers = "74d0951d3d"
parsers = "36c3a88d63"
preference = "1.2.1"
recyclerview = "1.4.0"
room = "2.7.2"
serialization = "1.8.1"
ssiv = "5132f1e609"
ssiv = "376930523c"
swiperefreshlayout = "1.1.0"
testRules = "1.6.1"
testRunner = "1.6.2"