mirror of
https://github.com/mihonapp/mihon.git
synced 2025-06-26 19:17:51 +02:00
Compare commits
56 Commits
Author | SHA1 | Date | |
---|---|---|---|
0eb8d7d081 | |||
554f890ae3 | |||
dd1743698f | |||
b092e98ac9 | |||
9ee6262aed | |||
24a2d86f41 | |||
b5c5c66336 | |||
7654feb6a8 | |||
a598ac3993 | |||
cab919d74c | |||
60a929b92c | |||
356b7c346a | |||
ad57fde1c5 | |||
17f7dea21b | |||
b40af7c3c6 | |||
9065362fde | |||
d264b03ca1 | |||
ad9bad3d17 | |||
dfd858034f | |||
58ad8fa8c0 | |||
38610d8a24 | |||
27cec697bf | |||
024f9a8c76 | |||
f7cc36f2f0 | |||
ef5148ebb4 | |||
6dbc0a6fd5 | |||
fba3f9d501 | |||
d9f8137362 | |||
28416489b2 | |||
54a23ddd1f | |||
3287ca9cf2 | |||
a59e134862 | |||
1f8c5b0120 | |||
c7f839ea4a | |||
d981245723 | |||
1f729f1cb3 | |||
b4577d6676 | |||
544adb9940 | |||
1875c4a752 | |||
5f0493f1e5 | |||
c749e50bec | |||
a4e5e3ece5 | |||
2a69d1b051 | |||
126e1e2d9d | |||
0586e1d3ad | |||
07cb1c237e | |||
f4f1efe5fa | |||
37fdf4d434 | |||
99b46096a4 | |||
12e90ae35e | |||
023311a874 | |||
155a4dd463 | |||
15bed1ac4c | |||
27f55f8098 | |||
00598879e2 | |||
df274a0a78 |
1
.github/FUNDING.yml
vendored
1
.github/FUNDING.yml
vendored
@ -1,2 +1 @@
|
||||
github: inorichi
|
||||
ko_fi: inorichi
|
||||
|
10
.github/ISSUE_TEMPLATE.md
vendored
10
.github/ISSUE_TEMPLATE.md
vendored
@ -2,9 +2,15 @@
|
||||
|
||||
I acknowledge that:
|
||||
|
||||
- I have updated to the latest version of the app (stable is v0.10.10)
|
||||
- I have updated all extensions
|
||||
- I have updated:
|
||||
- To the latest version of the app (stable is v0.10.10)
|
||||
- All extensions
|
||||
- I have tried the troubleshooting guide: https://tachiyomi.org/help/guides/troubleshooting-problems/
|
||||
- If this is an issue with an extension, that I should be opening an issue in https://github.com/tachiyomiorg/tachiyomi-extensions
|
||||
- I have searched the existing issues and this is new ticket **NOT** a duplicate or related to another open issue
|
||||
- I will fill out the title and the information in this template
|
||||
|
||||
Note that the issue will be automatically closed if you do not fill out the title or requested information.
|
||||
|
||||
**DELETE THIS SECTION IF YOU HAVE READ AND ACKNOWLEDGED IT**
|
||||
|
||||
|
10
.github/ISSUE_TEMPLATE/bug_report.md
vendored
10
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -9,9 +9,15 @@ labels: "bug"
|
||||
|
||||
I acknowledge that:
|
||||
|
||||
- I have updated to the latest version of the app (stable is v0.10.10)
|
||||
- I have updated all extensions
|
||||
- I have updated:
|
||||
- To the latest version of the app (stable is v0.10.10)
|
||||
- All extensions
|
||||
- I have tried the troubleshooting guide: https://tachiyomi.org/help/guides/troubleshooting-problems/
|
||||
- If this is an issue with an extension, that I should be opening an issue in https://github.com/tachiyomiorg/tachiyomi-extensions
|
||||
- I have searched the existing issues and this is new ticket **NOT** a duplicate or related to another open issue
|
||||
- I will fill out the title and the information in this template
|
||||
|
||||
Note that the issue will be automatically closed if you do not fill out the title or requested information.
|
||||
|
||||
**DELETE THIS SECTION IF YOU HAVE READ AND ACKNOWLEDGED IT**
|
||||
|
||||
|
9
.github/ISSUE_TEMPLATE/feature_request.md
vendored
9
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -9,9 +9,14 @@ labels: "feature"
|
||||
|
||||
I acknowledge that:
|
||||
|
||||
- I have updated to the latest version of the app (stable is v0.10.10)
|
||||
- I have updated all extensions
|
||||
- I have updated:
|
||||
- To the latest version of the app (stable is v0.10.10)
|
||||
- All extensions
|
||||
- If this is an issue with an extension, that I should be opening an issue in https://github.com/tachiyomiorg/tachiyomi-extensions
|
||||
- I have searched the existing issues and this is new ticket **NOT** a duplicate or related to another open issue
|
||||
- I will fill out the title and the information in this template
|
||||
|
||||
Note that the issue will be automatically closed if you do not fill out the title or requested information.
|
||||
|
||||
**DELETE THIS SECTION IF YOU HAVE READ AND ACKNOWLEDGED IT**
|
||||
|
||||
|
BIN
.github/readme-images/screens.png
vendored
BIN
.github/readme-images/screens.png
vendored
Binary file not shown.
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 454 KiB |
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -88,7 +88,7 @@ jobs:
|
||||
MD5: ${{ env.APK_MD5 }}
|
||||
files: |
|
||||
tachiyomi-${{ env.VERSION_TAG }}.apk
|
||||
draft: ${{ github.event.inputs.dry-run != '' }}
|
||||
draft: true
|
||||
prerelease: false
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
@ -11,7 +11,7 @@ Tachiyomi is a free and open source manga reader for Android 5.0 and above.
|
||||
## Features
|
||||
|
||||
Features include:
|
||||
* Online reading from sources such as MangaDex, MangaSee, Mangakakalot, [and more](https://github.com/tachiyomiorg/tachiyomi-extensions)
|
||||
* Online reading from [a variety of sources](https://github.com/tachiyomiorg/tachiyomi-extensions)
|
||||
* Local reading of downloaded manga
|
||||
* A configurable reader with multiple viewers, reading directions and other settings.
|
||||
* [MyAnimeList](https://myanimelist.net/), [AniList](https://anilist.co/), [Kitsu](https://kitsu.io/), [Shikimori](https://shikimori.one), and [Bangumi](https://bgm.tv/) support
|
||||
|
@ -29,8 +29,8 @@ android {
|
||||
minSdkVersion(AndroidConfig.minSdk)
|
||||
targetSdkVersion(AndroidConfig.targetSdk)
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
versionCode = 57
|
||||
versionName = "0.10.10"
|
||||
versionCode = 58
|
||||
versionName = "0.10.11"
|
||||
|
||||
buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"")
|
||||
buildConfigField("String", "COMMIT_SHA", "\"${getGitSha()}\"")
|
||||
@ -163,7 +163,7 @@ dependencies {
|
||||
implementation("org.conscrypt:conscrypt-android:2.5.1")
|
||||
|
||||
// JSON
|
||||
val kotlinSerializationVersion = "1.0.1"
|
||||
val kotlinSerializationVersion = "1.1.0"
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinSerializationVersion")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-protobuf:$kotlinSerializationVersion")
|
||||
implementation("com.google.code.gson:gson:2.8.6")
|
||||
@ -174,7 +174,7 @@ dependencies {
|
||||
|
||||
// Disk
|
||||
implementation("com.jakewharton:disklrucache:2.0.2")
|
||||
implementation("com.github.tachiyomiorg:unifile:e9e3a40")
|
||||
implementation("com.github.tachiyomiorg:unifile:17bec43")
|
||||
implementation("com.github.junrar:junrar:7.4.0")
|
||||
|
||||
// HTML parser
|
||||
@ -260,12 +260,12 @@ dependencies {
|
||||
|
||||
implementation(kotlin("reflect", version = BuildPluginsVersion.KOTLIN))
|
||||
|
||||
val coroutinesVersion = "1.4.2"
|
||||
val coroutinesVersion = "1.4.3"
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion")
|
||||
|
||||
// For detecting memory leaks; see https://square.github.io/leakcanary/
|
||||
// debugImplementation("com.squareup.leakcanary:leakcanary-android:2.6")
|
||||
// debugImplementation("com.squareup.leakcanary:leakcanary-android:2.7")
|
||||
}
|
||||
|
||||
tasks {
|
||||
|
@ -32,7 +32,7 @@
|
||||
android:largeHeap="true"
|
||||
android:requestLegacyExternalStorage="true"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:theme="@style/Theme.Tachiyomi.Light"
|
||||
android:theme="@style/Theme.Base"
|
||||
android:networkSecurityConfig="@xml/network_security_config">
|
||||
<activity
|
||||
android:name=".ui.main.MainActivity"
|
||||
@ -84,7 +84,7 @@
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".ui.security.BiometricUnlockActivity"
|
||||
android:theme="@style/Theme.Splash" />
|
||||
android:theme="@style/Theme.Base" />
|
||||
<activity
|
||||
android:name=".ui.webview.WebViewActivity"
|
||||
android:configChanges="uiMode|orientation|screenSize" />
|
||||
|
@ -2,17 +2,17 @@ package eu.kanade.tachiyomi.data.cache
|
||||
|
||||
import android.content.Context
|
||||
import android.text.format.Formatter
|
||||
import com.github.salomonbrys.kotson.fromJson
|
||||
import com.google.gson.Gson
|
||||
import com.jakewharton.disklrucache.DiskLruCache
|
||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||
import eu.kanade.tachiyomi.util.storage.saveTo
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import okhttp3.Response
|
||||
import okio.buffer
|
||||
import okio.sink
|
||||
import rx.Observable
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
@ -42,8 +42,7 @@ class ChapterCache(private val context: Context) {
|
||||
const val PARAMETER_CACHE_SIZE = 100L * 1024 * 1024
|
||||
}
|
||||
|
||||
/** Google Json class used for parsing JSON files. */
|
||||
private val gson: Gson by injectLazy()
|
||||
private val json: Json by injectLazy()
|
||||
|
||||
/** Cache class used for cache management. */
|
||||
private val diskCache = DiskLruCache.open(
|
||||
@ -56,7 +55,7 @@ class ChapterCache(private val context: Context) {
|
||||
/**
|
||||
* Returns directory of cache.
|
||||
*/
|
||||
val cacheDir: File
|
||||
private val cacheDir: File
|
||||
get() = diskCache.directory
|
||||
|
||||
/**
|
||||
@ -71,43 +70,19 @@ class ChapterCache(private val context: Context) {
|
||||
val readableSize: String
|
||||
get() = Formatter.formatFileSize(context, realSize)
|
||||
|
||||
/**
|
||||
* Remove file from cache.
|
||||
*
|
||||
* @param file name of file "md5.0".
|
||||
* @return status of deletion for the file.
|
||||
*/
|
||||
fun removeFileFromCache(file: String): Boolean {
|
||||
// Make sure we don't delete the journal file (keeps track of cache).
|
||||
if (file == "journal" || file.startsWith("journal.")) {
|
||||
return false
|
||||
}
|
||||
|
||||
return try {
|
||||
// Remove the extension from the file to get the key of the cache
|
||||
val key = file.substringBeforeLast(".")
|
||||
// Remove file from cache.
|
||||
diskCache.remove(key)
|
||||
} catch (e: Exception) {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get page list from cache.
|
||||
*
|
||||
* @param chapter the chapter.
|
||||
* @return an observable of the list of pages.
|
||||
* @return the list of pages.
|
||||
*/
|
||||
fun getPageListFromCache(chapter: Chapter): Observable<List<Page>> {
|
||||
return Observable.fromCallable {
|
||||
// Get the key for the chapter.
|
||||
val key = DiskUtil.hashKeyForDisk(getKey(chapter))
|
||||
fun getPageListFromCache(chapter: Chapter): List<Page> {
|
||||
// Get the key for the chapter.
|
||||
val key = DiskUtil.hashKeyForDisk(getKey(chapter))
|
||||
|
||||
// Convert JSON string to list of objects. Throws an exception if snapshot is null
|
||||
diskCache.get(key).use {
|
||||
gson.fromJson<List<Page>>(it.getString(0))
|
||||
}
|
||||
// Convert JSON string to list of objects. Throws an exception if snapshot is null
|
||||
return diskCache.get(key).use {
|
||||
json.decodeFromString(it.getString(0))
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,7 +94,7 @@ class ChapterCache(private val context: Context) {
|
||||
*/
|
||||
fun putPageListToCache(chapter: Chapter, pages: List<Page>) {
|
||||
// Convert list of pages to json string.
|
||||
val cachedValue = gson.toJson(pages)
|
||||
val cachedValue = json.encodeToString(pages)
|
||||
|
||||
// Initialize the editor (edits the values for an entry).
|
||||
var editor: DiskLruCache.Editor? = null
|
||||
@ -199,6 +174,38 @@ class ChapterCache(private val context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
fun clear(): Int {
|
||||
var deletedFiles = 0
|
||||
cacheDir.listFiles()?.forEach {
|
||||
if (removeFileFromCache(it.name)) {
|
||||
deletedFiles++
|
||||
}
|
||||
}
|
||||
return deletedFiles
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove file from cache.
|
||||
*
|
||||
* @param file name of file "md5.0".
|
||||
* @return status of deletion for the file.
|
||||
*/
|
||||
private fun removeFileFromCache(file: String): Boolean {
|
||||
// Make sure we don't delete the journal file (keeps track of cache).
|
||||
if (file == "journal" || file.startsWith("journal.")) {
|
||||
return false
|
||||
}
|
||||
|
||||
return try {
|
||||
// Remove the extension from the file to get the key of the cache
|
||||
val key = file.substringBeforeLast(".")
|
||||
// Remove file from cache.
|
||||
diskCache.remove(key)
|
||||
} catch (e: Exception) {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
private fun getKey(chapter: Chapter): String {
|
||||
return "${chapter.manga_id}${chapter.url}"
|
||||
}
|
||||
|
@ -28,7 +28,6 @@ internal class DownloadNotifier(private val context: Context) {
|
||||
context.notificationBuilder(Notifications.CHANNEL_DOWNLOADER_PROGRESS) {
|
||||
setLargeIcon(BitmapFactory.decodeResource(context.resources, R.mipmap.ic_launcher))
|
||||
setAutoCancel(false)
|
||||
setOngoing(true)
|
||||
setOnlyAlertOnce(true)
|
||||
}
|
||||
}
|
||||
@ -84,7 +83,6 @@ internal class DownloadNotifier(private val context: Context) {
|
||||
*/
|
||||
fun onProgressChange(download: Download) {
|
||||
with(progressNotificationBuilder) {
|
||||
// Check if first call.
|
||||
if (!isDownloading) {
|
||||
setSmallIcon(android.R.drawable.stat_sys_download)
|
||||
clearActions()
|
||||
@ -116,6 +114,7 @@ internal class DownloadNotifier(private val context: Context) {
|
||||
}
|
||||
|
||||
setProgress(download.pages!!.size, download.downloadedImages, false)
|
||||
setOngoing(true)
|
||||
|
||||
show(Notifications.ID_DOWNLOAD_CHAPTER_PROGRESS)
|
||||
}
|
||||
@ -130,6 +129,7 @@ internal class DownloadNotifier(private val context: Context) {
|
||||
setContentText(context.getString(R.string.download_notifier_download_paused))
|
||||
setSmallIcon(R.drawable.ic_pause_24dp)
|
||||
setProgress(0, 0, false)
|
||||
setOngoing(false)
|
||||
clearActions()
|
||||
// Open download manager when clicked
|
||||
setContentIntent(NotificationHandler.openDownloadManagerPendingActivity(context))
|
||||
|
@ -65,7 +65,7 @@ class DownloadProvider(private val context: Context) {
|
||||
* @param source the source to query.
|
||||
*/
|
||||
fun findSourceDir(source: Source): UniFile? {
|
||||
return downloadsDir.findFile(getSourceDirName(source))
|
||||
return downloadsDir.findFile(getSourceDirName(source), true)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,9 +1,6 @@
|
||||
package eu.kanade.tachiyomi.data.updater
|
||||
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.work.Constraints
|
||||
import androidx.work.ExistingPeriodicWorkPolicy
|
||||
import androidx.work.NetworkType
|
||||
@ -11,52 +8,26 @@ import androidx.work.PeriodicWorkRequestBuilder
|
||||
import androidx.work.WorkManager
|
||||
import androidx.work.Worker
|
||||
import androidx.work.WorkerParameters
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||
import eu.kanade.tachiyomi.data.updater.github.GithubUpdateChecker
|
||||
import eu.kanade.tachiyomi.util.system.notificationManager
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class UpdaterJob(private val context: Context, workerParams: WorkerParameters) :
|
||||
Worker(context, workerParams) {
|
||||
|
||||
override fun doWork(): Result {
|
||||
return runBlocking {
|
||||
try {
|
||||
val result = GithubUpdateChecker().checkForUpdate()
|
||||
override fun doWork() = runBlocking {
|
||||
try {
|
||||
val result = GithubUpdateChecker().checkForUpdate()
|
||||
|
||||
if (result is UpdateResult.NewUpdate<*>) {
|
||||
val url = result.release.downloadLink
|
||||
|
||||
val intent = Intent(context, UpdaterService::class.java).apply {
|
||||
putExtra(UpdaterService.EXTRA_DOWNLOAD_URL, url)
|
||||
}
|
||||
|
||||
NotificationCompat.Builder(context, Notifications.CHANNEL_COMMON).update {
|
||||
setContentTitle(context.getString(R.string.app_name))
|
||||
setContentText(context.getString(R.string.update_check_notification_update_available))
|
||||
setSmallIcon(android.R.drawable.stat_sys_download_done)
|
||||
// Download action
|
||||
addAction(
|
||||
android.R.drawable.stat_sys_download_done,
|
||||
context.getString(R.string.action_download),
|
||||
PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
)
|
||||
}
|
||||
}
|
||||
Result.success()
|
||||
} catch (e: Exception) {
|
||||
Result.failure()
|
||||
if (result is UpdateResult.NewUpdate<*>) {
|
||||
UpdaterNotifier(context).promptUpdate(result.release.downloadLink)
|
||||
}
|
||||
Result.success()
|
||||
} catch (e: Exception) {
|
||||
Result.failure()
|
||||
}
|
||||
}
|
||||
|
||||
fun NotificationCompat.Builder.update(block: NotificationCompat.Builder.() -> Unit) {
|
||||
block()
|
||||
context.notificationManager.notify(Notifications.ID_UPDATER, build())
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "UpdateChecker"
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
package eu.kanade.tachiyomi.data.updater
|
||||
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import androidx.core.app.NotificationCompat
|
||||
import eu.kanade.tachiyomi.R
|
||||
@ -28,6 +30,27 @@ internal class UpdaterNotifier(private val context: Context) {
|
||||
context.notificationManager.notify(id, build())
|
||||
}
|
||||
|
||||
fun promptUpdate(url: String) {
|
||||
val intent = Intent(context, UpdaterService::class.java).apply {
|
||||
putExtra(UpdaterService.EXTRA_DOWNLOAD_URL, url)
|
||||
}
|
||||
val pendingIntent = PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
with(notificationBuilder) {
|
||||
setContentTitle(context.getString(R.string.app_name))
|
||||
setContentText(context.getString(R.string.update_check_notification_update_available))
|
||||
setSmallIcon(android.R.drawable.stat_sys_download_done)
|
||||
setContentIntent(pendingIntent)
|
||||
|
||||
clearActions()
|
||||
addAction(
|
||||
android.R.drawable.stat_sys_download_done,
|
||||
context.getString(R.string.action_download),
|
||||
pendingIntent
|
||||
)
|
||||
}
|
||||
notificationBuilder.show()
|
||||
}
|
||||
|
||||
/**
|
||||
* Call when apk download starts.
|
||||
*
|
||||
@ -63,19 +86,20 @@ internal class UpdaterNotifier(private val context: Context) {
|
||||
* @param uri path location of apk.
|
||||
*/
|
||||
fun onDownloadFinished(uri: Uri) {
|
||||
val installIntent = NotificationHandler.installApkPendingActivity(context, uri)
|
||||
with(notificationBuilder) {
|
||||
setContentText(context.getString(R.string.update_check_notification_download_complete))
|
||||
setSmallIcon(android.R.drawable.stat_sys_download_done)
|
||||
setOnlyAlertOnce(false)
|
||||
setProgress(0, 0, false)
|
||||
// Install action
|
||||
setContentIntent(NotificationHandler.installApkPendingActivity(context, uri))
|
||||
setContentIntent(installIntent)
|
||||
|
||||
clearActions()
|
||||
addAction(
|
||||
R.drawable.ic_system_update_alt_white_24dp,
|
||||
context.getString(R.string.action_install),
|
||||
NotificationHandler.installApkPendingActivity(context, uri)
|
||||
installIntent
|
||||
)
|
||||
// Cancel action
|
||||
addAction(
|
||||
R.drawable.ic_close_24dp,
|
||||
context.getString(R.string.action_cancel),
|
||||
@ -96,13 +120,13 @@ internal class UpdaterNotifier(private val context: Context) {
|
||||
setSmallIcon(android.R.drawable.stat_sys_warning)
|
||||
setOnlyAlertOnce(false)
|
||||
setProgress(0, 0, false)
|
||||
// Retry action
|
||||
|
||||
clearActions()
|
||||
addAction(
|
||||
R.drawable.ic_refresh_24dp,
|
||||
context.getString(R.string.action_retry),
|
||||
UpdaterService.downloadApkPendingService(context, url)
|
||||
)
|
||||
// Cancel action
|
||||
addAction(
|
||||
R.drawable.ic_close_24dp,
|
||||
context.getString(R.string.action_cancel),
|
||||
|
@ -163,7 +163,7 @@ internal object ExtensionLoader {
|
||||
else -> throw Exception("Unknown source class type! ${obj.javaClass}")
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
Timber.w(e, "Extension load error: $extName ($it)")
|
||||
Timber.e(e, "Extension load error: $extName ($it)")
|
||||
return LoadResult.Error(e)
|
||||
}
|
||||
}
|
||||
|
@ -1,65 +1,39 @@
|
||||
package eu.kanade.tachiyomi.ui.base.activity
|
||||
|
||||
import android.content.res.Configuration
|
||||
import android.os.Build
|
||||
import android.content.res.Configuration.UI_MODE_NIGHT_MASK
|
||||
import android.content.res.Configuration.UI_MODE_NIGHT_YES
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues.DarkThemeVariant
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues.LightThemeVariant
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues.ThemeMode
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues as Values
|
||||
|
||||
abstract class BaseThemedActivity : AppCompatActivity() {
|
||||
|
||||
val preferences: PreferencesHelper by injectLazy()
|
||||
|
||||
val isDarkMode: Boolean by lazy {
|
||||
val themeMode = preferences.themeMode().get()
|
||||
(themeMode == Values.ThemeMode.dark) ||
|
||||
(
|
||||
themeMode == Values.ThemeMode.system &&
|
||||
(resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES)
|
||||
)
|
||||
}
|
||||
|
||||
private val lightTheme: Int by lazy {
|
||||
when (preferences.themeLight().get()) {
|
||||
Values.LightThemeVariant.blue -> R.style.Theme_Tachiyomi_LightBlue
|
||||
else -> {
|
||||
when {
|
||||
// Light status + navigation bar
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1 -> {
|
||||
R.style.Theme_Tachiyomi_Light_Api27
|
||||
}
|
||||
// Light status bar + fallback gray navigation bar
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> {
|
||||
R.style.Theme_Tachiyomi_Light_Api23
|
||||
}
|
||||
// Fallback gray status + navigation bar
|
||||
else -> {
|
||||
R.style.Theme_Tachiyomi_Light
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val darkTheme: Int by lazy {
|
||||
when (preferences.themeDark().get()) {
|
||||
Values.DarkThemeVariant.blue -> R.style.Theme_Tachiyomi_DarkBlue
|
||||
Values.DarkThemeVariant.amoled -> R.style.Theme_Tachiyomi_Amoled
|
||||
else -> R.style.Theme_Tachiyomi_Dark
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
setTheme(
|
||||
when {
|
||||
isDarkMode -> darkTheme
|
||||
else -> lightTheme
|
||||
val isDarkMode = when (preferences.themeMode().get()) {
|
||||
ThemeMode.light -> false
|
||||
ThemeMode.dark -> true
|
||||
ThemeMode.system -> resources.configuration.uiMode and UI_MODE_NIGHT_MASK == UI_MODE_NIGHT_YES
|
||||
}
|
||||
val themeId = if (isDarkMode) {
|
||||
when (preferences.themeDark().get()) {
|
||||
DarkThemeVariant.default -> R.style.Theme_Tachiyomi_Dark
|
||||
DarkThemeVariant.blue -> R.style.Theme_Tachiyomi_Dark_Blue
|
||||
DarkThemeVariant.amoled -> R.style.Theme_Tachiyomi_Dark_Amoled
|
||||
}
|
||||
)
|
||||
|
||||
} else {
|
||||
when (preferences.themeLight().get()) {
|
||||
LightThemeVariant.default -> R.style.Theme_Tachiyomi_Light
|
||||
LightThemeVariant.blue -> R.style.Theme_Tachiyomi_Light_Blue
|
||||
}
|
||||
}
|
||||
setTheme(themeId)
|
||||
super.onCreate(savedInstanceState)
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,8 @@ import timber.log.Timber
|
||||
abstract class BaseController<VB : ViewBinding>(bundle: Bundle? = null) :
|
||||
RestoreViewOnCreateController(bundle) {
|
||||
|
||||
lateinit var binding: VB
|
||||
protected lateinit var binding: VB
|
||||
private set
|
||||
|
||||
lateinit var viewScope: CoroutineScope
|
||||
|
||||
@ -51,11 +52,12 @@ abstract class BaseController<VB : ViewBinding>(bundle: Bundle? = null) :
|
||||
)
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup, savedViewState: Bundle?): View {
|
||||
return inflateView(inflater, container)
|
||||
}
|
||||
abstract fun createBinding(inflater: LayoutInflater): VB
|
||||
|
||||
abstract fun inflateView(inflater: LayoutInflater, container: ViewGroup): View
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup, savedViewState: Bundle?): View {
|
||||
binding = createBinding(inflater)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
open fun onViewCreated(view: View) {}
|
||||
|
||||
|
@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.ui.browse
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.os.bundleOf
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler
|
||||
@ -50,10 +49,7 @@ class BrowseController :
|
||||
return resources!!.getString(R.string.browse)
|
||||
}
|
||||
|
||||
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
|
||||
binding = PagerControllerBinding.inflate(inflater)
|
||||
return binding.root
|
||||
}
|
||||
override fun createBinding(inflater: LayoutInflater) = PagerControllerBinding.inflate(inflater)
|
||||
|
||||
override fun onViewCreated(view: View) {
|
||||
super.onViewCreated(view)
|
||||
|
@ -5,7 +5,6 @@ import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler
|
||||
@ -57,18 +56,16 @@ open class ExtensionController :
|
||||
return ExtensionPresenter()
|
||||
}
|
||||
|
||||
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
|
||||
binding = ExtensionControllerBinding.inflate(inflater)
|
||||
override fun createBinding(inflater: LayoutInflater) = ExtensionControllerBinding.inflate(inflater)
|
||||
|
||||
override fun onViewCreated(view: View) {
|
||||
super.onViewCreated(view)
|
||||
|
||||
binding.recycler.applyInsetter {
|
||||
type(navigationBars = true) {
|
||||
padding()
|
||||
}
|
||||
}
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View) {
|
||||
super.onViewCreated(view)
|
||||
|
||||
binding.swipeRefresh.isRefreshing = true
|
||||
binding.swipeRefresh.refreshes()
|
||||
|
@ -4,12 +4,12 @@ import android.annotation.SuppressLint
|
||||
import android.view.View
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.viewholders.FlexibleViewHolder
|
||||
import eu.kanade.tachiyomi.databinding.SourceMainControllerCardHeaderBinding
|
||||
import eu.kanade.tachiyomi.databinding.SectionHeaderItemBinding
|
||||
|
||||
class ExtensionGroupHolder(view: View, adapter: FlexibleAdapter<*>) :
|
||||
FlexibleViewHolder(view, adapter) {
|
||||
|
||||
private val binding = SourceMainControllerCardHeaderBinding.bind(view)
|
||||
private val binding = SectionHeaderItemBinding.bind(view)
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
fun bind(item: ExtensionGroupItem) {
|
||||
|
@ -19,7 +19,7 @@ data class ExtensionGroupItem(val name: String, val size: Int, val showSize: Boo
|
||||
* Returns the layout resource of this item.
|
||||
*/
|
||||
override fun getLayoutRes(): Int {
|
||||
return R.layout.source_main_controller_card_header
|
||||
return R.layout.section_header_item
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -12,7 +12,6 @@ import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.view.ContextThemeWrapper
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.preference.Preference
|
||||
@ -65,15 +64,9 @@ class ExtensionDetailsController(bundle: Bundle? = null) :
|
||||
setHasOptionsMenu(true)
|
||||
}
|
||||
|
||||
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
|
||||
override fun createBinding(inflater: LayoutInflater): ExtensionDetailControllerBinding {
|
||||
val themedInflater = inflater.cloneInContext(getPreferenceThemeContext())
|
||||
binding = ExtensionDetailControllerBinding.inflate(themedInflater)
|
||||
binding.extensionPrefsRecycler.applyInsetter {
|
||||
type(navigationBars = true) {
|
||||
padding()
|
||||
}
|
||||
}
|
||||
return binding.root
|
||||
return ExtensionDetailControllerBinding.inflate(themedInflater)
|
||||
}
|
||||
|
||||
override fun createPresenter(): ExtensionDetailsPresenter {
|
||||
@ -88,6 +81,12 @@ class ExtensionDetailsController(bundle: Bundle? = null) :
|
||||
override fun onViewCreated(view: View) {
|
||||
super.onViewCreated(view)
|
||||
|
||||
binding.extensionPrefsRecycler.applyInsetter {
|
||||
type(navigationBars = true) {
|
||||
padding()
|
||||
}
|
||||
}
|
||||
|
||||
val extension = presenter.extension ?: return
|
||||
val context = view.context
|
||||
|
||||
|
@ -6,7 +6,6 @@ import android.os.Bundle
|
||||
import android.util.TypedValue
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.view.ContextThemeWrapper
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.preference.DialogPreference
|
||||
@ -45,10 +44,9 @@ class SourcePreferencesController(bundle: Bundle? = null) :
|
||||
bundleOf(SOURCE_ID to sourceId)
|
||||
)
|
||||
|
||||
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
|
||||
override fun createBinding(inflater: LayoutInflater): SourcePreferencesControllerBinding {
|
||||
val themedInflater = inflater.cloneInContext(getPreferenceThemeContext())
|
||||
binding = SourcePreferencesControllerBinding.inflate(themedInflater)
|
||||
return binding.root
|
||||
return SourcePreferencesControllerBinding.inflate(themedInflater)
|
||||
}
|
||||
|
||||
override fun createPresenter(): SourcePreferencesPresenter {
|
||||
|
@ -3,9 +3,9 @@ package eu.kanade.tachiyomi.ui.browse.migration.manga
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import dev.chrisbanes.insetter.applyInsetter
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.kanade.tachiyomi.databinding.MigrationMangaControllerBinding
|
||||
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
||||
@ -44,14 +44,17 @@ class MigrationMangaController :
|
||||
return MigrationMangaPresenter(sourceId)
|
||||
}
|
||||
|
||||
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
|
||||
binding = MigrationMangaControllerBinding.inflate(inflater)
|
||||
return binding.root
|
||||
}
|
||||
override fun createBinding(inflater: LayoutInflater) = MigrationMangaControllerBinding.inflate(inflater)
|
||||
|
||||
override fun onViewCreated(view: View) {
|
||||
super.onViewCreated(view)
|
||||
|
||||
binding.recycler.applyInsetter {
|
||||
type(navigationBars = true) {
|
||||
padding()
|
||||
}
|
||||
}
|
||||
|
||||
adapter = MigrationMangaAdapter(this)
|
||||
binding.recycler.layoutManager = LinearLayoutManager(view.context)
|
||||
binding.recycler.adapter = adapter
|
||||
|
@ -104,24 +104,22 @@ class SearchPresenter(
|
||||
val prevMangaChapters = db.getChapters(prevManga).executeAsBlocking()
|
||||
val maxChapterRead = prevMangaChapters
|
||||
.filter { it.read }
|
||||
.maxByOrNull { it.chapter_number }?.chapter_number
|
||||
val bookmarkedChapters = prevMangaChapters
|
||||
.filter { it.bookmark && it.isRecognizedNumber }
|
||||
.map { it.chapter_number }
|
||||
if (maxChapterRead != null) {
|
||||
val dbChapters = db.getChapters(manga).executeAsBlocking()
|
||||
for (chapter in dbChapters) {
|
||||
if (chapter.isRecognizedNumber) {
|
||||
if (chapter.chapter_number <= maxChapterRead) {
|
||||
chapter.read = true
|
||||
}
|
||||
if (chapter.chapter_number in bookmarkedChapters) {
|
||||
chapter.bookmark = true
|
||||
}
|
||||
.maxOfOrNull { it.chapter_number } ?: 0f
|
||||
val dbChapters = db.getChapters(manga).executeAsBlocking()
|
||||
for (chapter in dbChapters) {
|
||||
if (chapter.isRecognizedNumber) {
|
||||
val prevChapter = prevMangaChapters
|
||||
.find { it.isRecognizedNumber && it.chapter_number == chapter.chapter_number }
|
||||
if (prevChapter != null) {
|
||||
chapter.date_fetch = prevChapter.date_fetch
|
||||
chapter.bookmark = prevChapter.bookmark
|
||||
}
|
||||
if (chapter.chapter_number <= maxChapterRead) {
|
||||
chapter.read = true
|
||||
}
|
||||
}
|
||||
db.insertChapters(dbChapters).executeAsBlocking()
|
||||
}
|
||||
db.insertChapters(dbChapters).executeAsBlocking()
|
||||
}
|
||||
|
||||
// Update categories
|
||||
|
@ -5,7 +5,6 @@ import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import dev.chrisbanes.insetter.applyInsetter
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
@ -30,18 +29,16 @@ class MigrationSourcesController :
|
||||
return MigrationSourcesPresenter()
|
||||
}
|
||||
|
||||
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
|
||||
binding = MigrationSourcesControllerBinding.inflate(inflater)
|
||||
override fun createBinding(inflater: LayoutInflater) = MigrationSourcesControllerBinding.inflate(inflater)
|
||||
|
||||
override fun onViewCreated(view: View) {
|
||||
super.onViewCreated(view)
|
||||
|
||||
binding.recycler.applyInsetter {
|
||||
type(navigationBars = true) {
|
||||
padding()
|
||||
}
|
||||
}
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View) {
|
||||
super.onViewCreated(view)
|
||||
|
||||
adapter = SourceAdapter(this)
|
||||
binding.recycler.layoutManager = LinearLayoutManager(view.context)
|
||||
|
@ -7,7 +7,7 @@ import eu.davidea.flexibleadapter.items.AbstractHeaderItem
|
||||
import eu.davidea.flexibleadapter.items.IFlexible
|
||||
import eu.davidea.viewholders.FlexibleViewHolder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.databinding.SourceMainControllerCardHeaderBinding
|
||||
import eu.kanade.tachiyomi.databinding.SectionHeaderItemBinding
|
||||
|
||||
/**
|
||||
* Item that contains the selection header.
|
||||
@ -18,7 +18,7 @@ class SelectionHeader : AbstractHeaderItem<SelectionHeader.Holder>() {
|
||||
* Returns the layout resource of this item.
|
||||
*/
|
||||
override fun getLayoutRes(): Int {
|
||||
return R.layout.source_main_controller_card_header
|
||||
return R.layout.section_header_item
|
||||
}
|
||||
|
||||
/**
|
||||
@ -45,7 +45,7 @@ class SelectionHeader : AbstractHeaderItem<SelectionHeader.Holder>() {
|
||||
|
||||
class Holder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter) {
|
||||
|
||||
private val binding = SourceMainControllerCardHeaderBinding.bind(view)
|
||||
private val binding = SectionHeaderItemBinding.bind(view)
|
||||
|
||||
init {
|
||||
binding.title.text = view.context.getString(R.string.migration_selection_prompt)
|
||||
|
@ -3,13 +3,13 @@ package eu.kanade.tachiyomi.ui.browse.source
|
||||
import android.view.View
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.viewholders.FlexibleViewHolder
|
||||
import eu.kanade.tachiyomi.databinding.SourceMainControllerCardHeaderBinding
|
||||
import eu.kanade.tachiyomi.databinding.SectionHeaderItemBinding
|
||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||
|
||||
class LangHolder(view: View, adapter: FlexibleAdapter<*>) :
|
||||
FlexibleViewHolder(view, adapter) {
|
||||
|
||||
private val binding = SourceMainControllerCardHeaderBinding.bind(view)
|
||||
private val binding = SectionHeaderItemBinding.bind(view)
|
||||
|
||||
fun bind(item: LangItem) {
|
||||
binding.title.text = LocaleHelper.getSourceDisplayName(item.code, itemView.context)
|
||||
|
@ -18,7 +18,7 @@ data class LangItem(val code: String) : AbstractHeaderItem<LangHolder>() {
|
||||
* Returns the layout resource of this item.
|
||||
*/
|
||||
override fun getLayoutRes(): Int {
|
||||
return R.layout.source_main_controller_card_header
|
||||
return R.layout.section_header_item
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -8,7 +8,6 @@ import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.list.listItems
|
||||
@ -67,25 +66,16 @@ class SourceController :
|
||||
return SourcePresenter()
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiate the view with [R.layout.source_main_controller].
|
||||
*
|
||||
* @param inflater used to load the layout xml.
|
||||
* @param container containing parent views.
|
||||
* @return inflated view.
|
||||
*/
|
||||
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
|
||||
binding = SourceMainControllerBinding.inflate(inflater)
|
||||
override fun createBinding(inflater: LayoutInflater) = SourceMainControllerBinding.inflate(inflater)
|
||||
|
||||
override fun onViewCreated(view: View) {
|
||||
super.onViewCreated(view)
|
||||
|
||||
binding.recycler.applyInsetter {
|
||||
type(navigationBars = true) {
|
||||
padding()
|
||||
}
|
||||
}
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View) {
|
||||
super.onViewCreated(view)
|
||||
|
||||
adapter = SourceAdapter(this)
|
||||
|
||||
|
@ -8,7 +8,6 @@ import eu.kanade.tachiyomi.databinding.SourceMainControllerCardItemBinding
|
||||
import eu.kanade.tachiyomi.source.LocalSource
|
||||
import eu.kanade.tachiyomi.source.icon
|
||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||
import eu.kanade.tachiyomi.util.view.setVectorCompat
|
||||
|
||||
class SourceHolder(private val view: View, val adapter: SourceAdapter) :
|
||||
@ -46,9 +45,9 @@ class SourceHolder(private val view: View, val adapter: SourceAdapter) :
|
||||
|
||||
binding.pin.isVisible = true
|
||||
if (item.isPinned) {
|
||||
binding.pin.setVectorCompat(R.drawable.ic_push_pin_24dp, view.context.getResourceColor(R.attr.colorAccent))
|
||||
binding.pin.setVectorCompat(R.drawable.ic_push_pin_24dp, R.attr.colorAccent)
|
||||
} else {
|
||||
binding.pin.setVectorCompat(R.drawable.ic_push_pin_outline_24dp, view.context.getResourceColor(android.R.attr.textColorHint))
|
||||
binding.pin.setVectorCompat(R.drawable.ic_push_pin_outline_24dp, android.R.attr.textColorHint)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -124,10 +124,7 @@ open class BrowseSourceController(bundle: Bundle) :
|
||||
return BrowseSourcePresenter(args.getLong(SOURCE_ID_KEY), args.getString(SEARCH_QUERY_KEY))
|
||||
}
|
||||
|
||||
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
|
||||
binding = SourceControllerBinding.inflate(inflater)
|
||||
return binding.root
|
||||
}
|
||||
override fun createBinding(inflater: LayoutInflater) = SourceControllerBinding.inflate(inflater)
|
||||
|
||||
override fun onViewCreated(view: View) {
|
||||
super.onViewCreated(view)
|
||||
@ -269,6 +266,7 @@ open class BrowseSourceController(bundle: Bundle) :
|
||||
if (router.backstackSize >= 2 && router.backstack[router.backstackSize - 2].controller() is GlobalSearchController) {
|
||||
router.popController(this)
|
||||
} else {
|
||||
nonSubmittedQuery = ""
|
||||
searchWithQuery("")
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@ import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.IFlexible
|
||||
import eu.kanade.tachiyomi.databinding.SourceFilterSheetBinding
|
||||
@ -17,10 +18,10 @@ class SourceFilterSheet(
|
||||
onResetClicked: () -> Unit
|
||||
) : BaseBottomSheetDialog(activity) {
|
||||
|
||||
private var filterNavView: FilterNavigationView
|
||||
private var filterNavView: FilterNavigationView = FilterNavigationView(activity)
|
||||
private val sheetBehavior: BottomSheetBehavior<*>
|
||||
|
||||
init {
|
||||
filterNavView = FilterNavigationView(activity)
|
||||
filterNavView.onFilterClicked = {
|
||||
onFilterClicked()
|
||||
this.dismiss()
|
||||
@ -28,13 +29,23 @@ class SourceFilterSheet(
|
||||
filterNavView.onResetClicked = onResetClicked
|
||||
|
||||
setContentView(filterNavView)
|
||||
|
||||
sheetBehavior = BottomSheetBehavior.from(filterNavView.parent as ViewGroup)
|
||||
}
|
||||
|
||||
override fun show() {
|
||||
super.show()
|
||||
sheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
}
|
||||
|
||||
fun setFilters(items: List<IFlexible<*>>) {
|
||||
filterNavView.adapter.updateDataSet(items)
|
||||
}
|
||||
|
||||
class FilterNavigationView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
||||
class FilterNavigationView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null
|
||||
) :
|
||||
SimpleNavigationView(context, attrs) {
|
||||
|
||||
var onFilterClicked = {}
|
||||
@ -42,9 +53,12 @@ class SourceFilterSheet(
|
||||
|
||||
val adapter: FlexibleAdapter<IFlexible<*>> = FlexibleAdapter<IFlexible<*>>(null)
|
||||
.setDisplayHeadersAtStartUp(true)
|
||||
.setStickyHeaders(true)
|
||||
|
||||
private val binding = SourceFilterSheetBinding.inflate(LayoutInflater.from(context), null, false)
|
||||
private val binding = SourceFilterSheetBinding.inflate(
|
||||
LayoutInflater.from(context),
|
||||
null,
|
||||
false
|
||||
)
|
||||
|
||||
init {
|
||||
recycler.adapter = adapter
|
||||
|
@ -6,7 +6,6 @@ import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
@ -50,22 +49,7 @@ open class GlobalSearchController(
|
||||
setHasOptionsMenu(true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiate the view with [R.layout.global_search_controller].
|
||||
*
|
||||
* @param inflater used to load the layout xml.
|
||||
* @param container containing parent views.
|
||||
* @return inflated view
|
||||
*/
|
||||
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
|
||||
binding = GlobalSearchControllerBinding.inflate(inflater)
|
||||
binding.recycler.applyInsetter {
|
||||
type(navigationBars = true) {
|
||||
padding()
|
||||
}
|
||||
}
|
||||
return binding.root
|
||||
}
|
||||
override fun createBinding(inflater: LayoutInflater) = GlobalSearchControllerBinding.inflate(inflater)
|
||||
|
||||
override fun getTitle(): String? {
|
||||
return presenter.query
|
||||
@ -142,6 +126,12 @@ open class GlobalSearchController(
|
||||
override fun onViewCreated(view: View) {
|
||||
super.onViewCreated(view)
|
||||
|
||||
binding.recycler.applyInsetter {
|
||||
type(navigationBars = true) {
|
||||
padding()
|
||||
}
|
||||
}
|
||||
|
||||
adapter = GlobalSearchAdapter(this)
|
||||
|
||||
// Create recycler and set adapter.
|
||||
|
@ -4,7 +4,6 @@ import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
@ -68,21 +67,7 @@ class CategoryController :
|
||||
return resources?.getString(R.string.action_edit_categories)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the view of this controller.
|
||||
*
|
||||
* @param inflater The layout inflater to create the view from XML.
|
||||
* @param container The parent view for this one.
|
||||
*/
|
||||
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
|
||||
binding = CategoriesControllerBinding.inflate(inflater)
|
||||
binding.recycler.applyInsetter {
|
||||
type(navigationBars = true) {
|
||||
padding()
|
||||
}
|
||||
}
|
||||
return binding.root
|
||||
}
|
||||
override fun createBinding(inflater: LayoutInflater) = CategoriesControllerBinding.inflate(inflater)
|
||||
|
||||
/**
|
||||
* Called after view inflation. Used to initialize the view.
|
||||
@ -92,6 +77,12 @@ class CategoryController :
|
||||
override fun onViewCreated(view: View) {
|
||||
super.onViewCreated(view)
|
||||
|
||||
binding.recycler.applyInsetter {
|
||||
type(navigationBars = true) {
|
||||
padding()
|
||||
}
|
||||
}
|
||||
|
||||
adapter = CategoryAdapter(this@CategoryController)
|
||||
binding.recycler.layoutManager = LinearLayoutManager(view.context)
|
||||
binding.recycler.setHasFixedSize(true)
|
||||
|
@ -5,7 +5,6 @@ import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
@ -55,15 +54,7 @@ class DownloadController :
|
||||
setHasOptionsMenu(true)
|
||||
}
|
||||
|
||||
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
|
||||
binding = DownloadControllerBinding.inflate(inflater)
|
||||
binding.recycler.applyInsetter {
|
||||
type(navigationBars = true) {
|
||||
padding()
|
||||
}
|
||||
}
|
||||
return binding.root
|
||||
}
|
||||
override fun createBinding(inflater: LayoutInflater) = DownloadControllerBinding.inflate(inflater)
|
||||
|
||||
override fun createPresenter(): DownloadPresenter {
|
||||
return DownloadPresenter()
|
||||
@ -76,6 +67,12 @@ class DownloadController :
|
||||
override fun onViewCreated(view: View) {
|
||||
super.onViewCreated(view)
|
||||
|
||||
binding.recycler.applyInsetter {
|
||||
type(navigationBars = true) {
|
||||
padding()
|
||||
}
|
||||
}
|
||||
|
||||
// Check if download queue is empty and update information accordingly.
|
||||
setInformationView()
|
||||
|
||||
|
@ -7,7 +7,6 @@ import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.core.graphics.drawable.DrawableCompat
|
||||
@ -18,6 +17,7 @@ import com.google.android.material.tabs.TabLayout
|
||||
import com.jakewharton.rxrelay.BehaviorRelay
|
||||
import com.jakewharton.rxrelay.PublishRelay
|
||||
import com.tfcporciuncula.flow.Preference
|
||||
import dev.chrisbanes.insetter.applyInsetter
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Category
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
@ -163,14 +163,17 @@ class LibraryController(
|
||||
return LibraryPresenter()
|
||||
}
|
||||
|
||||
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
|
||||
binding = LibraryControllerBinding.inflate(inflater)
|
||||
return binding.root
|
||||
}
|
||||
override fun createBinding(inflater: LayoutInflater) = LibraryControllerBinding.inflate(inflater)
|
||||
|
||||
override fun onViewCreated(view: View) {
|
||||
super.onViewCreated(view)
|
||||
|
||||
binding.actionToolbar.applyInsetter {
|
||||
type(navigationBars = true) {
|
||||
margin(bottom = true)
|
||||
}
|
||||
}
|
||||
|
||||
adapter = LibraryAdapter(this)
|
||||
binding.libraryPager.adapter = adapter
|
||||
binding.libraryPager.pageSelections()
|
||||
|
@ -13,6 +13,7 @@ import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.marginTop
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.PreferenceDialogController
|
||||
@ -49,6 +50,8 @@ import eu.kanade.tachiyomi.ui.recent.history.HistoryController
|
||||
import eu.kanade.tachiyomi.ui.recent.updates.UpdatesController
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import eu.kanade.tachiyomi.util.lang.launchUI
|
||||
import eu.kanade.tachiyomi.util.system.InternalResourceHelper
|
||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
@ -98,23 +101,27 @@ class MainActivity : BaseViewBindingActivity<MainActivityBinding>() {
|
||||
padding(left = true, top = true, right = true)
|
||||
}
|
||||
}
|
||||
binding.bottomNav.applyInsetter {
|
||||
type(navigationBars = true) {
|
||||
padding()
|
||||
}
|
||||
}
|
||||
binding.rootFab.applyInsetter {
|
||||
type(navigationBars = true) {
|
||||
margin()
|
||||
}
|
||||
}
|
||||
binding.bottomNav.applyInsetter {
|
||||
type(navigationBars = true) {
|
||||
padding()
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure navigation bar is on bottom when making it transparent
|
||||
// Make sure navigation bar is on bottom before we modify it
|
||||
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _, insets ->
|
||||
if (insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom > 0) {
|
||||
// Keep scrim on light theme if windowLightNavigationBar is not available
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1 || isDarkMode) {
|
||||
window.navigationBarColor = Color.TRANSPARENT
|
||||
window.navigationBarColor = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q &&
|
||||
!InternalResourceHelper.getBoolean(this, "config_navBarNeedsScrim", true)
|
||||
) {
|
||||
Color.TRANSPARENT
|
||||
} else {
|
||||
// Set navbar scrim 70% of navigationBarColor
|
||||
getResourceColor(android.R.attr.navigationBarColor, 0.7F)
|
||||
}
|
||||
}
|
||||
insets
|
||||
@ -146,6 +153,9 @@ class MainActivity : BaseViewBindingActivity<MainActivityBinding>() {
|
||||
val controller = router.getControllerWithTag(id.toString()) as? LibraryController
|
||||
controller?.showSettingsSheet()
|
||||
}
|
||||
R.id.nav_updates -> {
|
||||
router.pushController(DownloadController().withFadeTransaction())
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
@ -439,7 +449,7 @@ class MainActivity : BaseViewBindingActivity<MainActivityBinding>() {
|
||||
fun fixViewToBottom(view: View) {
|
||||
val listener = AppBarLayout.OnOffsetChangedListener { appBarLayout, verticalOffset ->
|
||||
val maxAbsOffset = appBarLayout.measuredHeight - binding.tabs.measuredHeight
|
||||
view.translationY = -maxAbsOffset - verticalOffset.toFloat()
|
||||
view.translationY = -maxAbsOffset - verticalOffset.toFloat() + appBarLayout.marginTop
|
||||
}
|
||||
binding.appbar.addOnOffsetChangedListener(listener)
|
||||
fixedViewsToBottom[view] = listener
|
||||
|
@ -11,7 +11,6 @@ import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.core.graphics.blue
|
||||
@ -199,18 +198,21 @@ class MangaController :
|
||||
)
|
||||
}
|
||||
|
||||
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
|
||||
binding = MangaControllerBinding.inflate(inflater)
|
||||
override fun createBinding(inflater: LayoutInflater) = MangaControllerBinding.inflate(inflater)
|
||||
|
||||
override fun onViewCreated(view: View) {
|
||||
super.onViewCreated(view)
|
||||
|
||||
binding.recycler.applyInsetter {
|
||||
type(navigationBars = true) {
|
||||
padding()
|
||||
}
|
||||
}
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View) {
|
||||
super.onViewCreated(view)
|
||||
binding.actionToolbar.applyInsetter {
|
||||
type(navigationBars = true) {
|
||||
margin(bottom = true)
|
||||
}
|
||||
}
|
||||
|
||||
if (manga == null || source == null) return
|
||||
|
||||
@ -850,7 +852,6 @@ class MangaController :
|
||||
binding.actionToolbar.findItem(R.id.action_mark_as_unread)?.isVisible = chapters.all { it.chapter.read }
|
||||
|
||||
// Hide FAB to avoid interfering with the bottom action toolbar
|
||||
// actionFab?.hide()
|
||||
actionFab?.isVisible = false
|
||||
}
|
||||
return false
|
||||
@ -882,10 +883,6 @@ class MangaController :
|
||||
chaptersAdapter?.clearSelection()
|
||||
selectedChapters.clear()
|
||||
actionMode = null
|
||||
|
||||
// TODO: there seems to be a bug in MaterialComponents where the [ExtendedFloatingActionButton]
|
||||
// fails to show up properly
|
||||
// actionFab?.show()
|
||||
actionFab?.isVisible = true
|
||||
}
|
||||
|
||||
@ -1008,9 +1005,10 @@ class MangaController :
|
||||
// OVERFLOW MENU DIALOGS
|
||||
|
||||
private fun getUnreadChaptersSorted() = presenter.chapters
|
||||
.sortedWith(presenter.getChapterSort())
|
||||
.filter { !it.read && it.status == Download.State.NOT_DOWNLOADED }
|
||||
.distinctBy { it.name }
|
||||
.sortedByDescending { it.source_order }
|
||||
.reversed()
|
||||
|
||||
private fun downloadChapters(choice: Int) {
|
||||
val chaptersToDownload = when (choice) {
|
||||
|
@ -429,7 +429,11 @@ class MangaPresenter(
|
||||
observable = observable.filter { !it.bookmark }
|
||||
}
|
||||
|
||||
val sortFunction: (Chapter, Chapter) -> Int = when (manga.sorting) {
|
||||
return observable.toSortedList(getChapterSort())
|
||||
}
|
||||
|
||||
fun getChapterSort(): (Chapter, Chapter) -> Int {
|
||||
return when (manga.sorting) {
|
||||
Manga.SORTING_SOURCE -> when (sortDescending()) {
|
||||
true -> { c1, c2 -> c1.source_order.compareTo(c2.source_order) }
|
||||
false -> { c1, c2 -> c2.source_order.compareTo(c1.source_order) }
|
||||
@ -444,8 +448,6 @@ class MangaPresenter(
|
||||
}
|
||||
else -> throw NotImplementedError("Unimplemented sorting method")
|
||||
}
|
||||
|
||||
return observable.toSortedList(sortFunction)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -472,7 +474,7 @@ class MangaPresenter(
|
||||
* Returns the next unread chapter or null if everything is read.
|
||||
*/
|
||||
fun getNextUnreadChapter(): ChapterItem? {
|
||||
return chapters.sortedByDescending { it.source_order }.find { !it.read }
|
||||
return chapters.sortedWith(getChapterSort()).findLast { !it.read }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,9 +1,9 @@
|
||||
package eu.kanade.tachiyomi.ui.manga.chapter
|
||||
|
||||
import android.text.SpannableString
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.text.style.ForegroundColorSpan
|
||||
import android.view.View
|
||||
import androidx.core.text.buildSpannedString
|
||||
import androidx.core.text.color
|
||||
import androidx.core.view.isVisible
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
@ -59,8 +59,10 @@ class ChapterHolder(
|
||||
descriptions.add(adapter.dateFormat.format(Date(chapter.date_upload)))
|
||||
}
|
||||
if (!chapter.read && chapter.last_page_read > 0) {
|
||||
val lastPageRead = SpannableString(itemView.context.getString(R.string.chapter_progress, chapter.last_page_read + 1)).apply {
|
||||
setSpan(ForegroundColorSpan(adapter.readColor), 0, length, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
val lastPageRead = buildSpannedString {
|
||||
color(adapter.readColor) {
|
||||
append(itemView.context.getString(R.string.chapter_progress, chapter.last_page_read + 1))
|
||||
}
|
||||
}
|
||||
descriptions.add(lastPageRead)
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package eu.kanade.tachiyomi.ui.more
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.preference.PreferenceScreen
|
||||
@ -15,6 +14,7 @@ import eu.kanade.tachiyomi.data.updater.github.GithubUpdateChecker
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.openInBrowser
|
||||
import eu.kanade.tachiyomi.ui.setting.SettingsController
|
||||
import eu.kanade.tachiyomi.util.CrashLogUtil
|
||||
import eu.kanade.tachiyomi.util.lang.launchNow
|
||||
import eu.kanade.tachiyomi.util.lang.toDateTimestampString
|
||||
import eu.kanade.tachiyomi.util.preference.onClick
|
||||
@ -138,6 +138,7 @@ class AboutController : SettingsController() {
|
||||
.withAboutIconShown(false)
|
||||
.withAboutVersionShown(false)
|
||||
.withLicenseShown(true)
|
||||
.withEdgeToEdge(true)
|
||||
.start(activity!!)
|
||||
}
|
||||
}
|
||||
@ -201,19 +202,10 @@ class AboutController : SettingsController() {
|
||||
}
|
||||
|
||||
private fun copyDebugInfo() {
|
||||
val deviceInfo =
|
||||
"""
|
||||
App version: ${BuildConfig.VERSION_NAME} (${BuildConfig.FLAVOR}, ${BuildConfig.COMMIT_SHA}, ${BuildConfig.VERSION_CODE})
|
||||
Android version: ${Build.VERSION.RELEASE} (SDK ${Build.VERSION.SDK_INT})
|
||||
Android build ID: ${Build.DISPLAY}
|
||||
Device brand: ${Build.BRAND}
|
||||
Device manufacturer: ${Build.MANUFACTURER}
|
||||
Device name: ${Build.DEVICE}
|
||||
Device model: ${Build.MODEL}
|
||||
Device product name: ${Build.PRODUCT}
|
||||
""".trimIndent()
|
||||
|
||||
activity?.copyToClipboard("Debug information", deviceInfo)
|
||||
activity?.let {
|
||||
val deviceInfo = CrashLogUtil(it).getDebugInfo()
|
||||
activity?.copyToClipboard("Debug information", deviceInfo)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getFormattedBuildTime(): String {
|
||||
|
@ -1,7 +1,11 @@
|
||||
package eu.kanade.tachiyomi.ui.more
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceScreen
|
||||
import eu.kanade.tachiyomi.R
|
||||
@ -26,7 +30,10 @@ import eu.kanade.tachiyomi.util.preference.switchPreference
|
||||
import eu.kanade.tachiyomi.util.preference.titleRes
|
||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||
import eu.kanade.tachiyomi.util.system.openInBrowser
|
||||
import rx.Observable
|
||||
import rx.Subscription
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import rx.subscriptions.CompositeSubscription
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||
|
||||
@ -39,6 +46,9 @@ class MoreController :
|
||||
private var isDownloading: Boolean = false
|
||||
private var downloadQueueSize: Int = 0
|
||||
|
||||
private var untilDestroySubscriptions = CompositeSubscription()
|
||||
private set
|
||||
|
||||
override fun setupPreferenceScreen(screen: PreferenceScreen) = screen.apply {
|
||||
titleRes = R.string.label_more
|
||||
|
||||
@ -115,6 +125,19 @@ class MoreController :
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup, savedInstanceState: Bundle?): View {
|
||||
if (untilDestroySubscriptions.isUnsubscribed) {
|
||||
untilDestroySubscriptions = CompositeSubscription()
|
||||
}
|
||||
|
||||
return super.onCreateView(inflater, container, savedInstanceState)
|
||||
}
|
||||
|
||||
override fun onDestroyView(view: View) {
|
||||
super.onDestroyView(view)
|
||||
untilDestroySubscriptions.unsubscribe()
|
||||
}
|
||||
|
||||
private fun initDownloadQueueSummary(preference: Preference) {
|
||||
// Handle running/paused status change
|
||||
DownloadService.runningRelay
|
||||
@ -141,6 +164,10 @@ class MoreController :
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T> Observable<T>.subscribeUntilDestroy(onNext: (T) -> Unit): Subscription {
|
||||
return subscribe(onNext).also { untilDestroySubscriptions.add(it) }
|
||||
}
|
||||
|
||||
private class MoreHeaderPreference @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
||||
Preference(context, attrs) {
|
||||
|
||||
|
@ -10,7 +10,6 @@ import android.graphics.Bitmap
|
||||
import android.graphics.Color
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.Gravity
|
||||
import android.view.KeyEvent
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
@ -414,6 +413,11 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
|
||||
setOnClickListener {
|
||||
ReaderSettingsSheet(this@ReaderActivity).show()
|
||||
}
|
||||
|
||||
setOnLongClickListener {
|
||||
ReaderSettingsSheet(this@ReaderActivity, showColorFilterSettings = true).show()
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -554,10 +558,12 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
|
||||
}
|
||||
|
||||
private fun showReadingModeToast(mode: Int) {
|
||||
val strings = resources.getStringArray(R.array.viewers_selector)
|
||||
readingModeToast?.cancel()
|
||||
readingModeToast = toast(strings[mode]) {
|
||||
it.setGravity(Gravity.CENTER_VERTICAL or Gravity.CENTER_HORIZONTAL, 0, 0)
|
||||
try {
|
||||
val strings = resources.getStringArray(R.array.viewers_selector)
|
||||
readingModeToast?.cancel()
|
||||
readingModeToast = toast(strings[mode])
|
||||
} catch (e: ArrayIndexOutOfBoundsException) {
|
||||
Timber.e("Unknown reading mode: $mode")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,8 +85,7 @@ class HttpPageLoader(
|
||||
* the local cache, otherwise fallbacks to network.
|
||||
*/
|
||||
override fun getPages(): Observable<List<ReaderPage>> {
|
||||
return chapterCache
|
||||
.getPageListFromCache(chapter.chapter)
|
||||
return Observable.fromCallable { chapterCache.getPageListFromCache(chapter.chapter) }
|
||||
.onErrorResumeNext { source.fetchPageList(chapter.chapter) }
|
||||
.map { pages ->
|
||||
pages.mapIndexed { index, page ->
|
||||
|
@ -8,7 +8,10 @@ import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||
import eu.kanade.tachiyomi.widget.SimpleTabSelectedListener
|
||||
import eu.kanade.tachiyomi.widget.sheet.TabbedBottomSheetDialog
|
||||
|
||||
class ReaderSettingsSheet(private val activity: ReaderActivity) : TabbedBottomSheetDialog(activity) {
|
||||
class ReaderSettingsSheet(
|
||||
private val activity: ReaderActivity,
|
||||
showColorFilterSettings: Boolean = false,
|
||||
) : TabbedBottomSheetDialog(activity) {
|
||||
|
||||
private val readingModeSettings = ReaderReadingModeSettings(activity)
|
||||
private val generalSettings = ReaderGeneralSettings(activity)
|
||||
@ -40,6 +43,10 @@ class ReaderSettingsSheet(private val activity: ReaderActivity) : TabbedBottomSh
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if (showColorFilterSettings) {
|
||||
binding.tabs.getTabAt(filterTabIndex)?.select()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getTabViews() = listOf(
|
||||
|
@ -79,16 +79,7 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr
|
||||
recycler.addOnScrollListener(
|
||||
object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
val position = layoutManager.findLastEndVisibleItemPosition()
|
||||
val item = adapter.items.getOrNull(position)
|
||||
val allowPreload = checkAllowPreload(item as? ReaderPage)
|
||||
if (item != null && currentPage != item) {
|
||||
currentPage = item
|
||||
when (item) {
|
||||
is ReaderPage -> onPageSelected(item, allowPreload)
|
||||
is ChapterTransition -> onTransitionSelected(item)
|
||||
}
|
||||
}
|
||||
onScrolled()
|
||||
|
||||
if (dy < 0) {
|
||||
val firstIndex = layoutManager.findFirstVisibleItemPosition()
|
||||
@ -243,11 +234,27 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr
|
||||
val position = adapter.items.indexOf(page)
|
||||
if (position != -1) {
|
||||
recycler.scrollToPosition(position)
|
||||
if (layoutManager.findLastEndVisibleItemPosition() == -1) {
|
||||
onScrolled(position)
|
||||
}
|
||||
} else {
|
||||
Timber.d("Page $page not found in adapter")
|
||||
}
|
||||
}
|
||||
|
||||
fun onScrolled(pos: Int? = null) {
|
||||
val position = pos ?: layoutManager.findLastEndVisibleItemPosition()
|
||||
val item = adapter.items.getOrNull(position)
|
||||
val allowPreload = checkAllowPreload(item as? ReaderPage)
|
||||
if (item != null && currentPage != item) {
|
||||
currentPage = item
|
||||
when (item) {
|
||||
is ReaderPage -> onPageSelected(item, allowPreload)
|
||||
is ChapterTransition -> onTransitionSelected(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scrolls up by [scrollDistance].
|
||||
*/
|
||||
|
@ -8,13 +8,13 @@ import eu.davidea.flexibleadapter.items.AbstractHeaderItem
|
||||
import eu.davidea.flexibleadapter.items.IFlexible
|
||||
import eu.davidea.viewholders.FlexibleViewHolder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.databinding.RecentSectionItemBinding
|
||||
import eu.kanade.tachiyomi.databinding.SectionHeaderItemBinding
|
||||
import java.util.Date
|
||||
|
||||
class DateSectionItem(val date: Date) : AbstractHeaderItem<DateSectionItem.DateSectionItemHolder>() {
|
||||
|
||||
override fun getLayoutRes(): Int {
|
||||
return R.layout.recent_section_item
|
||||
return R.layout.section_header_item
|
||||
}
|
||||
|
||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): DateSectionItemHolder {
|
||||
@ -39,12 +39,12 @@ class DateSectionItem(val date: Date) : AbstractHeaderItem<DateSectionItem.DateS
|
||||
|
||||
inner class DateSectionItemHolder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter, true) {
|
||||
|
||||
private val binding = RecentSectionItemBinding.bind(view)
|
||||
private val binding = SectionHeaderItemBinding.bind(view)
|
||||
|
||||
private val now = Date().time
|
||||
|
||||
fun bind(item: DateSectionItem) {
|
||||
binding.sectionText.text = DateUtils.getRelativeTimeSpanString(item.date.time, now, DateUtils.DAY_IN_MILLIS)
|
||||
binding.title.text = DateUtils.getRelativeTimeSpanString(item.date.time, now, DateUtils.DAY_IN_MILLIS)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,6 @@ class HistoryAdapter(controller: HistoryController) :
|
||||
|
||||
init {
|
||||
setDisplayHeadersAtStartUp(true)
|
||||
setStickyHeaders(true)
|
||||
}
|
||||
|
||||
interface OnResumeClickListener {
|
||||
|
@ -7,7 +7,6 @@ import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
@ -20,7 +19,6 @@ import eu.kanade.tachiyomi.data.database.models.History
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.databinding.HistoryControllerBinding
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.NoToolbarElevationController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.RootController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||
@ -36,13 +34,10 @@ import uy.kohesive.injekt.injectLazy
|
||||
|
||||
/**
|
||||
* Fragment that shows recently read manga.
|
||||
* Uses [R.layout.history_controller].
|
||||
* UI related actions should be called from here.
|
||||
*/
|
||||
class HistoryController :
|
||||
NucleusController<HistoryControllerBinding, HistoryPresenter>(),
|
||||
RootController,
|
||||
NoToolbarElevationController,
|
||||
FlexibleAdapter.OnUpdateListener,
|
||||
FlexibleAdapter.EndlessScrollListener,
|
||||
HistoryAdapter.OnRemoveClickListener,
|
||||
@ -76,18 +71,16 @@ class HistoryController :
|
||||
return HistoryPresenter()
|
||||
}
|
||||
|
||||
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
|
||||
binding = HistoryControllerBinding.inflate(inflater)
|
||||
override fun createBinding(inflater: LayoutInflater) = HistoryControllerBinding.inflate(inflater)
|
||||
|
||||
override fun onViewCreated(view: View) {
|
||||
super.onViewCreated(view)
|
||||
|
||||
binding.recycler.applyInsetter {
|
||||
type(navigationBars = true) {
|
||||
padding()
|
||||
}
|
||||
}
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View) {
|
||||
super.onViewCreated(view)
|
||||
|
||||
// Initialize adapter
|
||||
binding.recycler.layoutManager = LinearLayoutManager(view.context)
|
||||
|
@ -18,7 +18,6 @@ class UpdatesAdapter(
|
||||
|
||||
init {
|
||||
setDisplayHeadersAtStartUp(true)
|
||||
setStickyHeaders(true)
|
||||
}
|
||||
|
||||
interface OnCoverClickListener {
|
||||
|
@ -5,7 +5,6 @@ import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
@ -19,7 +18,6 @@ import eu.kanade.tachiyomi.data.download.model.Download
|
||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateService
|
||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||
import eu.kanade.tachiyomi.databinding.UpdatesControllerBinding
|
||||
import eu.kanade.tachiyomi.ui.base.controller.NoToolbarElevationController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.RootController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||
@ -37,13 +35,10 @@ import timber.log.Timber
|
||||
|
||||
/**
|
||||
* Fragment that shows recent chapters.
|
||||
* Uses [R.layout.updates_controller].
|
||||
* UI related actions should be called from here.
|
||||
*/
|
||||
class UpdatesController :
|
||||
NucleusController<UpdatesControllerBinding, UpdatesPresenter>(),
|
||||
RootController,
|
||||
NoToolbarElevationController,
|
||||
ActionMode.Callback,
|
||||
FlexibleAdapter.OnItemClickListener,
|
||||
FlexibleAdapter.OnItemLongClickListener,
|
||||
@ -75,18 +70,21 @@ class UpdatesController :
|
||||
return UpdatesPresenter()
|
||||
}
|
||||
|
||||
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
|
||||
binding = UpdatesControllerBinding.inflate(inflater)
|
||||
override fun createBinding(inflater: LayoutInflater) = UpdatesControllerBinding.inflate(inflater)
|
||||
|
||||
override fun onViewCreated(view: View) {
|
||||
super.onViewCreated(view)
|
||||
binding.recycler.applyInsetter {
|
||||
type(navigationBars = true) {
|
||||
padding()
|
||||
}
|
||||
}
|
||||
return binding.root
|
||||
}
|
||||
binding.actionToolbar.applyInsetter {
|
||||
type(navigationBars = true) {
|
||||
margin(bottom = true)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View) {
|
||||
super.onViewCreated(view)
|
||||
view.context.notificationManager.cancel(Notifications.ID_NEW_CHAPTERS)
|
||||
|
||||
// Init RecyclerView and adapter
|
||||
|
@ -1,21 +1,19 @@
|
||||
package eu.kanade.tachiyomi.ui.security
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.biometric.BiometricPrompt
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.ui.base.activity.BaseThemedActivity
|
||||
import eu.kanade.tachiyomi.util.system.BiometricUtil
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import timber.log.Timber
|
||||
import java.util.Date
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
/**
|
||||
* Blank activity with a BiometricPrompt.
|
||||
*/
|
||||
class BiometricUnlockActivity : AppCompatActivity() {
|
||||
class BiometricUnlockActivity : BaseThemedActivity() {
|
||||
|
||||
private val preferences: PreferencesHelper by injectLazy()
|
||||
private val executor = Executors.newSingleThreadExecutor()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@ -27,6 +25,7 @@ class BiometricUnlockActivity : AppCompatActivity() {
|
||||
object : BiometricPrompt.AuthenticationCallback() {
|
||||
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
|
||||
super.onAuthenticationError(errorCode, errString)
|
||||
Timber.e(errString.toString())
|
||||
finishAffinity()
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,8 @@ import eu.kanade.tachiyomi.network.PREF_DOH_CLOUDFLARE
|
||||
import eu.kanade.tachiyomi.network.PREF_DOH_GOOGLE
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
import eu.kanade.tachiyomi.util.CrashLogUtil
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import eu.kanade.tachiyomi.util.lang.withUIContext
|
||||
import eu.kanade.tachiyomi.util.preference.defaultValue
|
||||
import eu.kanade.tachiyomi.util.preference.intListPreference
|
||||
import eu.kanade.tachiyomi.util.preference.onChange
|
||||
@ -32,9 +34,6 @@ import eu.kanade.tachiyomi.util.preference.switchPreference
|
||||
import eu.kanade.tachiyomi.util.preference.titleRes
|
||||
import eu.kanade.tachiyomi.util.system.powerManager
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import rx.Observable
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import rx.schedulers.Schedulers
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||
|
||||
@ -172,27 +171,18 @@ class SettingsAdvancedController : SettingsController() {
|
||||
|
||||
private fun clearChapterCache() {
|
||||
if (activity == null) return
|
||||
val files = chapterCache.cacheDir.listFiles() ?: return
|
||||
|
||||
var deletedFiles = 0
|
||||
|
||||
Observable.defer { Observable.from(files) }
|
||||
.doOnNext { file ->
|
||||
if (chapterCache.removeFileFromCache(file.name)) {
|
||||
deletedFiles++
|
||||
launchIO {
|
||||
try {
|
||||
val deletedFiles = chapterCache.clear()
|
||||
withUIContext {
|
||||
activity?.toast(resources?.getString(R.string.cache_deleted, deletedFiles))
|
||||
findPreference(CLEAR_CACHE_KEY)?.summary =
|
||||
resources?.getString(R.string.used_cache, chapterCache.readableSize)
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
withUIContext { activity?.toast(R.string.cache_delete_error) }
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.doOnError {
|
||||
activity?.toast(R.string.cache_delete_error)
|
||||
}
|
||||
.doOnCompleted {
|
||||
activity?.toast(resources?.getString(R.string.cache_deleted, deletedFiles))
|
||||
findPreference(CLEAR_CACHE_KEY)?.summary =
|
||||
resources?.getString(R.string.used_cache, chapterCache.readableSize)
|
||||
}
|
||||
.subscribe()
|
||||
}
|
||||
}
|
||||
|
||||
class ClearDatabaseDialogController : DialogController() {
|
||||
|
@ -24,9 +24,6 @@ import eu.kanade.tachiyomi.ui.base.controller.BaseController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.RootController
|
||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||
import kotlinx.coroutines.MainScope
|
||||
import rx.Observable
|
||||
import rx.Subscription
|
||||
import rx.subscriptions.CompositeSubscription
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
@ -35,19 +32,14 @@ abstract class SettingsController : PreferenceController() {
|
||||
var preferenceKey: String? = null
|
||||
val preferences: PreferencesHelper = Injekt.get()
|
||||
val viewScope = MainScope()
|
||||
|
||||
var untilDestroySubscriptions = CompositeSubscription()
|
||||
private set
|
||||
private var themedContext: Context? = null
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup, savedInstanceState: Bundle?): View {
|
||||
if (untilDestroySubscriptions.isUnsubscribed) {
|
||||
untilDestroySubscriptions = CompositeSubscription()
|
||||
}
|
||||
|
||||
val view = super.onCreateView(inflater, container, savedInstanceState)
|
||||
|
||||
if (this is RootController) {
|
||||
view.updatePadding(bottom = view.context.resources.getDimensionPixelSize(R.dimen.action_toolbar_list_padding))
|
||||
listView.clipToPadding = false
|
||||
listView.updatePadding(bottom = view.context.resources.getDimensionPixelSize(R.dimen.action_toolbar_list_padding))
|
||||
}
|
||||
|
||||
listView.applyInsetter {
|
||||
@ -77,25 +69,31 @@ abstract class SettingsController : PreferenceController() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onChangeStarted(handler: ControllerChangeHandler, type: ControllerChangeType) {
|
||||
if (type.isEnter) {
|
||||
setTitle()
|
||||
}
|
||||
setHasOptionsMenu(type.isEnter)
|
||||
super.onChangeStarted(handler, type)
|
||||
}
|
||||
|
||||
override fun onDestroyView(view: View) {
|
||||
super.onDestroyView(view)
|
||||
untilDestroySubscriptions.unsubscribe()
|
||||
themedContext = null
|
||||
}
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
val screen = preferenceManager.createPreferenceScreen(getThemedContext())
|
||||
val tv = TypedValue()
|
||||
activity!!.theme.resolveAttribute(R.attr.preferenceTheme, tv, true)
|
||||
themedContext = ContextThemeWrapper(activity, tv.resourceId)
|
||||
|
||||
val screen = preferenceManager.createPreferenceScreen(themedContext)
|
||||
preferenceScreen = screen
|
||||
setupPreferenceScreen(screen)
|
||||
}
|
||||
|
||||
abstract fun setupPreferenceScreen(screen: PreferenceScreen): PreferenceScreen
|
||||
|
||||
private fun getThemedContext(): Context {
|
||||
val tv = TypedValue()
|
||||
activity!!.theme.resolveAttribute(R.attr.preferenceTheme, tv, true)
|
||||
return ContextThemeWrapper(activity, tv.resourceId)
|
||||
}
|
||||
|
||||
private fun animatePreferenceHighlight(view: View) {
|
||||
ValueAnimator
|
||||
.ofObject(ArgbEvaluator(), Color.TRANSPARENT, view.context.getResourceColor(R.attr.rippleColor))
|
||||
@ -111,7 +109,7 @@ abstract class SettingsController : PreferenceController() {
|
||||
return preferenceScreen?.title?.toString()
|
||||
}
|
||||
|
||||
fun setTitle() {
|
||||
private fun setTitle() {
|
||||
var parentController = parentController
|
||||
while (parentController != null) {
|
||||
if (parentController is BaseController<*> && parentController.getTitle() != null) {
|
||||
@ -122,16 +120,4 @@ abstract class SettingsController : PreferenceController() {
|
||||
|
||||
(activity as? AppCompatActivity)?.supportActionBar?.title = getTitle()
|
||||
}
|
||||
|
||||
override fun onChangeStarted(handler: ControllerChangeHandler, type: ControllerChangeType) {
|
||||
if (type.isEnter) {
|
||||
setTitle()
|
||||
}
|
||||
setHasOptionsMenu(type.isEnter)
|
||||
super.onChangeStarted(handler, type)
|
||||
}
|
||||
|
||||
fun <T> Observable<T>.subscribeUntilDestroy(onNext: (T) -> Unit): Subscription {
|
||||
return subscribe(onNext).also { untilDestroySubscriptions.add(it) }
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import eu.kanade.tachiyomi.R
|
||||
@ -33,17 +32,7 @@ class SettingsSearchController :
|
||||
setHasOptionsMenu(true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiate the view with [R.layout.settings_search_controller].
|
||||
*
|
||||
* @param inflater used to load the layout xml.
|
||||
* @param container containing parent views.
|
||||
* @return inflated view
|
||||
*/
|
||||
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
|
||||
binding = SettingsSearchControllerBinding.inflate(inflater)
|
||||
return binding.root
|
||||
}
|
||||
override fun createBinding(inflater: LayoutInflater) = SettingsSearchControllerBinding.inflate(inflater)
|
||||
|
||||
override fun getTitle(): String? {
|
||||
return presenter.query
|
||||
|
@ -139,8 +139,10 @@ class WebViewActivity : BaseViewBindingActivity<WebviewActivityBinding>() {
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
binding.webview?.destroy()
|
||||
super.onDestroy()
|
||||
|
||||
// Binding sometimes isn't actually instantiated yet somehow
|
||||
binding?.webview?.destroy()
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
|
@ -2,15 +2,18 @@ package eu.kanade.tachiyomi.util
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import eu.kanade.tachiyomi.BuildConfig
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
|
||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import eu.kanade.tachiyomi.util.lang.withUIContext
|
||||
import eu.kanade.tachiyomi.util.storage.getUriCompat
|
||||
import eu.kanade.tachiyomi.util.system.createFileInCacheDir
|
||||
import eu.kanade.tachiyomi.util.system.notificationBuilder
|
||||
import eu.kanade.tachiyomi.util.system.notificationManager
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import java.io.IOException
|
||||
|
||||
class CrashLogUtil(private val context: Context) {
|
||||
|
||||
@ -19,31 +22,44 @@ class CrashLogUtil(private val context: Context) {
|
||||
}
|
||||
|
||||
fun dumpLogs() {
|
||||
try {
|
||||
val file = context.createFileInCacheDir("tachiyomi_crash_logs.txt")
|
||||
Runtime.getRuntime().exec("logcat *:E -d -f ${file.absolutePath}")
|
||||
launchIO {
|
||||
try {
|
||||
val file = context.createFileInCacheDir("tachiyomi_crash_logs.txt")
|
||||
Runtime.getRuntime().exec("logcat *:E -d -f ${file.absolutePath}").waitFor()
|
||||
file.appendText(getDebugInfo())
|
||||
|
||||
showNotification(file.getUriCompat(context))
|
||||
} catch (e: IOException) {
|
||||
context.toast("Failed to get logs")
|
||||
showNotification(file.getUriCompat(context))
|
||||
} catch (e: Throwable) {
|
||||
withUIContext { context.toast("Failed to get logs") }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getDebugInfo(): String {
|
||||
return """
|
||||
App version: ${BuildConfig.VERSION_NAME} (${BuildConfig.FLAVOR}, ${BuildConfig.COMMIT_SHA}, ${BuildConfig.VERSION_CODE})
|
||||
Android version: ${Build.VERSION.RELEASE} (SDK ${Build.VERSION.SDK_INT})
|
||||
Android build ID: ${Build.DISPLAY}
|
||||
Device brand: ${Build.BRAND}
|
||||
Device manufacturer: ${Build.MANUFACTURER}
|
||||
Device name: ${Build.DEVICE}
|
||||
Device model: ${Build.MODEL}
|
||||
Device product name: ${Build.PRODUCT}
|
||||
""".trimIndent()
|
||||
}
|
||||
|
||||
private fun showNotification(uri: Uri) {
|
||||
context.notificationManager.cancel(Notifications.ID_CRASH_LOGS)
|
||||
|
||||
with(notificationBuilder) {
|
||||
setContentTitle(context.getString(R.string.crash_log_saved))
|
||||
|
||||
// Clear old actions if they exist
|
||||
clearActions()
|
||||
|
||||
addAction(
|
||||
R.drawable.ic_folder_24dp,
|
||||
context.getString(R.string.action_open_log),
|
||||
NotificationReceiver.openErrorLogPendingActivity(context, uri)
|
||||
)
|
||||
|
||||
addAction(
|
||||
R.drawable.ic_share_24dp,
|
||||
context.getString(R.string.action_share),
|
||||
|
@ -157,3 +157,5 @@ private fun shouldUpdateDbChapter(dbChapter: Chapter, sourceChapter: SChapter):
|
||||
dbChapter.date_upload != sourceChapter.date_upload ||
|
||||
dbChapter.chapter_number != sourceChapter.chapter_number
|
||||
}
|
||||
|
||||
class NoChaptersException : Exception()
|
||||
|
@ -1,3 +0,0 @@
|
||||
package eu.kanade.tachiyomi.util.chapter
|
||||
|
||||
class NoChaptersException : Exception()
|
@ -1,12 +1,17 @@
|
||||
package eu.kanade.tachiyomi.util.system
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import androidx.biometric.BiometricManager
|
||||
import androidx.biometric.BiometricManager.Authenticators
|
||||
|
||||
object BiometricUtil {
|
||||
|
||||
fun getSupportedAuthenticators(context: Context): Int {
|
||||
if (isLegacySecured(context)) {
|
||||
return Authenticators.BIOMETRIC_WEAK or Authenticators.DEVICE_CREDENTIAL
|
||||
}
|
||||
|
||||
return listOf(
|
||||
Authenticators.BIOMETRIC_STRONG,
|
||||
Authenticators.BIOMETRIC_WEAK,
|
||||
@ -17,10 +22,22 @@ object BiometricUtil {
|
||||
}
|
||||
|
||||
fun isSupported(context: Context): Boolean {
|
||||
return getSupportedAuthenticators(context) != 0
|
||||
return isLegacySecured(context) || getSupportedAuthenticators(context) != 0
|
||||
}
|
||||
|
||||
fun isDeviceCredentialAllowed(context: Context): Boolean {
|
||||
return getSupportedAuthenticators(context) and Authenticators.DEVICE_CREDENTIAL != 0
|
||||
return isLegacySecured(context) || (getSupportedAuthenticators(context) and Authenticators.DEVICE_CREDENTIAL != 0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the device is secured with a PIN, pattern or password.
|
||||
*/
|
||||
private fun isLegacySecured(context: Context): Boolean {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
|
||||
if (context.keyguardManager.isDeviceSecure) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package eu.kanade.tachiyomi.util.system
|
||||
|
||||
import android.app.ActivityManager
|
||||
import android.app.KeyguardManager
|
||||
import android.app.Notification
|
||||
import android.app.NotificationManager
|
||||
import android.content.BroadcastReceiver
|
||||
@ -33,6 +34,7 @@ import androidx.core.net.toUri
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.util.lang.truncateCenter
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@ -68,10 +70,15 @@ fun Context.toast(text: String?, duration: Int = Toast.LENGTH_SHORT, block: (Toa
|
||||
fun Context.copyToClipboard(label: String, content: String) {
|
||||
if (content.isBlank()) return
|
||||
|
||||
val clipboard = getSystemService<ClipboardManager>()!!
|
||||
clipboard.setPrimaryClip(ClipData.newPlainText(label, content))
|
||||
try {
|
||||
val clipboard = getSystemService<ClipboardManager>()!!
|
||||
clipboard.setPrimaryClip(ClipData.newPlainText(label, content))
|
||||
|
||||
toast(getString(R.string.copied_to_clipboard, content.truncateCenter(50)))
|
||||
toast(getString(R.string.copied_to_clipboard, content.truncateCenter(50)))
|
||||
} catch (e: Throwable) {
|
||||
Timber.e(e)
|
||||
toast(R.string.clipboard_copy_error)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -153,24 +160,18 @@ val Float.dpToPxEnd: Float
|
||||
val Resources.isLTR
|
||||
get() = configuration.layoutDirection == View.LAYOUT_DIRECTION_LTR
|
||||
|
||||
/**
|
||||
* Property to get the notification manager from the context.
|
||||
*/
|
||||
val Context.notificationManager: NotificationManager
|
||||
get() = getSystemService()!!
|
||||
|
||||
/**
|
||||
* Property to get the connectivity manager from the context.
|
||||
*/
|
||||
val Context.connectivityManager: ConnectivityManager
|
||||
get() = getSystemService()!!
|
||||
|
||||
/**
|
||||
* Property to get the power manager from the context.
|
||||
*/
|
||||
val Context.powerManager: PowerManager
|
||||
get() = getSystemService()!!
|
||||
|
||||
val Context.keyguardManager: KeyguardManager
|
||||
get() = getSystemService()!!
|
||||
|
||||
/**
|
||||
* Convenience method to acquire a partial wake lock.
|
||||
*/
|
||||
|
@ -0,0 +1,26 @@
|
||||
package eu.kanade.tachiyomi.util.system
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Resources
|
||||
|
||||
object InternalResourceHelper {
|
||||
|
||||
fun getBoolean(context: Context, resName: String, defaultValue: Boolean): Boolean {
|
||||
val id = getResourceId(resName, "bool")
|
||||
return if (id != 0) {
|
||||
context.createPackageContext("android", 0).resources.getBoolean(id)
|
||||
} else {
|
||||
defaultValue
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get resource id from system resources
|
||||
* @param resName resource name to get
|
||||
* @param type resource type of [resName] to get
|
||||
* @return 0 if not available
|
||||
*/
|
||||
private fun getResourceId(resName: String, type: String): Int {
|
||||
return Resources.getSystem().getIdentifier(resName, type, "android")
|
||||
}
|
||||
}
|
@ -1,19 +1,21 @@
|
||||
package eu.kanade.tachiyomi.util.view
|
||||
|
||||
import android.widget.ImageView
|
||||
import androidx.annotation.AttrRes
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||
|
||||
/**
|
||||
* Set a vector on a [ImageView].
|
||||
*
|
||||
* @param drawable id of drawable resource
|
||||
*/
|
||||
fun ImageView.setVectorCompat(@DrawableRes drawable: Int, tint: Int? = null) {
|
||||
fun ImageView.setVectorCompat(@DrawableRes drawable: Int, @AttrRes tint: Int? = null) {
|
||||
val vector = AppCompatResources.getDrawable(context, drawable)
|
||||
if (tint != null) {
|
||||
vector?.mutate()
|
||||
vector?.setTint(tint)
|
||||
vector?.setTint(context.getResourceColor(tint))
|
||||
}
|
||||
setImageDrawable(vector)
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import androidx.annotation.MenuRes
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.core.view.isVisible
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.databinding.CommonActionToolbarBinding
|
||||
import eu.kanade.tachiyomi.databinding.ActionToolbarBinding
|
||||
|
||||
/**
|
||||
* A toolbar holding only menu items.
|
||||
@ -20,25 +20,21 @@ import eu.kanade.tachiyomi.databinding.CommonActionToolbarBinding
|
||||
class ActionToolbar @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
||||
FrameLayout(context, attrs) {
|
||||
|
||||
private val binding: CommonActionToolbarBinding
|
||||
|
||||
init {
|
||||
binding = CommonActionToolbarBinding.inflate(LayoutInflater.from(context), this, true)
|
||||
}
|
||||
private val binding = ActionToolbarBinding.inflate(LayoutInflater.from(context), this, true)
|
||||
|
||||
/**
|
||||
* Remove menu items and remove listener.
|
||||
*/
|
||||
fun destroy() {
|
||||
binding.commonActionMenu.menu.clear()
|
||||
binding.commonActionMenu.setOnMenuItemClickListener(null)
|
||||
binding.menu.menu.clear()
|
||||
binding.menu.setOnMenuItemClickListener(null)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a menu item if found.
|
||||
*/
|
||||
fun findItem(@IdRes itemId: Int): MenuItem? {
|
||||
return binding.commonActionMenu.menu.findItem(itemId)
|
||||
return binding.menu.menu.findItem(itemId)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -46,14 +42,14 @@ class ActionToolbar @JvmOverloads constructor(context: Context, attrs: Attribute
|
||||
*/
|
||||
fun show(mode: ActionMode, @MenuRes menuRes: Int, listener: (item: MenuItem?) -> Boolean) {
|
||||
// Avoid re-inflating the menu
|
||||
if (binding.commonActionMenu.menu.size() == 0) {
|
||||
mode.menuInflater.inflate(menuRes, binding.commonActionMenu.menu)
|
||||
binding.commonActionMenu.setOnMenuItemClickListener { listener(it) }
|
||||
if (binding.menu.menu.size() == 0) {
|
||||
mode.menuInflater.inflate(menuRes, binding.menu.menu)
|
||||
binding.menu.setOnMenuItemClickListener { listener(it) }
|
||||
}
|
||||
|
||||
binding.commonActionToolbar.isVisible = true
|
||||
binding.actionToolbar.isVisible = true
|
||||
val bottomAnimation = AnimationUtils.loadAnimation(context, R.anim.enter_from_bottom)
|
||||
binding.commonActionToolbar.startAnimation(bottomAnimation)
|
||||
binding.actionToolbar.startAnimation(bottomAnimation)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -64,10 +60,10 @@ class ActionToolbar @JvmOverloads constructor(context: Context, attrs: Attribute
|
||||
bottomAnimation.setAnimationListener(
|
||||
object : SimpleAnimationListener() {
|
||||
override fun onAnimationEnd(animation: Animation) {
|
||||
binding.commonActionToolbar.isVisible = false
|
||||
binding.actionToolbar.isVisible = false
|
||||
}
|
||||
}
|
||||
)
|
||||
binding.commonActionToolbar.startAnimation(bottomAnimation)
|
||||
binding.actionToolbar.startAnimation(bottomAnimation)
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package eu.kanade.tachiyomi.ui.reader.setting
|
||||
package eu.kanade.tachiyomi.widget
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.Gravity
|
||||
@ -7,15 +8,21 @@ import android.view.LayoutInflater
|
||||
import android.view.MenuItem
|
||||
import android.widget.FrameLayout
|
||||
import androidx.annotation.ArrayRes
|
||||
import androidx.appcompat.view.menu.MenuBuilder
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.forEach
|
||||
import androidx.core.view.get
|
||||
import com.tfcporciuncula.flow.Preference
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.databinding.SpinnerPreferenceBinding
|
||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||
|
||||
class SpinnerPreference @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
||||
class MaterialSpinnerView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
||||
FrameLayout(context, attrs) {
|
||||
|
||||
private var entries = emptyList<String>()
|
||||
private var selectedPosition = 0
|
||||
private var popup: PopupMenu? = null
|
||||
|
||||
var onItemSelectedListener: ((Int) -> Unit)? = null
|
||||
@ -30,17 +37,26 @@ class SpinnerPreference @JvmOverloads constructor(context: Context, attrs: Attri
|
||||
}
|
||||
}
|
||||
|
||||
private val emptyIcon by lazy {
|
||||
ContextCompat.getDrawable(context, R.drawable.ic_blank_24dp)
|
||||
}
|
||||
private val checkmarkIcon by lazy {
|
||||
ContextCompat.getDrawable(context, R.drawable.ic_check_24dp)?.mutate()?.apply {
|
||||
setTint(context.getResourceColor(android.R.attr.textColorPrimary))
|
||||
}
|
||||
}
|
||||
|
||||
private val binding = SpinnerPreferenceBinding.inflate(LayoutInflater.from(context), this, false)
|
||||
|
||||
init {
|
||||
addView(binding.root)
|
||||
|
||||
val attr = context.obtainStyledAttributes(attrs, R.styleable.SpinnerPreference)
|
||||
val attr = context.obtainStyledAttributes(attrs, R.styleable.MaterialSpinnerView)
|
||||
|
||||
val title = attr.getString(R.styleable.SpinnerPreference_title).orEmpty()
|
||||
val title = attr.getString(R.styleable.MaterialSpinnerView_title).orEmpty()
|
||||
binding.title.text = title
|
||||
|
||||
val entries = (attr.getTextArray(R.styleable.SpinnerPreference_android_entries) ?: emptyArray()).map { it.toString() }
|
||||
val entries = (attr.getTextArray(R.styleable.MaterialSpinnerView_android_entries) ?: emptyArray()).map { it.toString() }
|
||||
this.entries = entries
|
||||
binding.details.text = entries.firstOrNull().orEmpty()
|
||||
|
||||
@ -48,6 +64,14 @@ class SpinnerPreference @JvmOverloads constructor(context: Context, attrs: Attri
|
||||
}
|
||||
|
||||
fun setSelection(selection: Int) {
|
||||
popup?.menu?.get(selectedPosition)?.let {
|
||||
it.icon = emptyIcon
|
||||
it.title = entries[selectedPosition]
|
||||
}
|
||||
selectedPosition = selection
|
||||
popup?.menu?.get(selectedPosition)?.let {
|
||||
it.icon = checkmarkIcon
|
||||
}
|
||||
binding.details.text = entries.getOrNull(selection).orEmpty()
|
||||
}
|
||||
|
||||
@ -118,11 +142,19 @@ class SpinnerPreference @JvmOverloads constructor(context: Context, attrs: Attri
|
||||
return pos
|
||||
}
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
fun createPopupMenu(onItemClick: (Int) -> Unit): PopupMenu {
|
||||
val popup = PopupMenu(context, this, Gravity.END, R.attr.actionOverflowMenuStyle, 0)
|
||||
entries.forEachIndexed { index, entry ->
|
||||
popup.menu.add(0, index, 0, entry)
|
||||
}
|
||||
(popup.menu as? MenuBuilder)?.setOptionalIconsVisible(true)
|
||||
popup.menu.forEach {
|
||||
it.icon = emptyIcon
|
||||
}
|
||||
popup.menu.getItem(selectedPosition)?.let {
|
||||
it.icon = checkmarkIcon
|
||||
}
|
||||
popup.setOnMenuItemClickListener { menuItem ->
|
||||
val pos = menuClicked(menuItem)
|
||||
onItemClick(pos)
|
@ -1,13 +1,10 @@
|
||||
package eu.kanade.tachiyomi.widget.materialdialogs
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.util.AttributeSet
|
||||
import androidx.annotation.AttrRes
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.appcompat.widget.AppCompatImageView
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||
import eu.kanade.tachiyomi.util.view.setVectorCompat
|
||||
|
||||
class QuadStateCheckBox @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
||||
AppCompatImageView(context, attrs) {
|
||||
@ -19,19 +16,11 @@ class QuadStateCheckBox @JvmOverloads constructor(context: Context, attrs: Attri
|
||||
}
|
||||
|
||||
private fun updateDrawable() {
|
||||
val drawable = when (state) {
|
||||
State.UNCHECKED -> tintVector(context, R.drawable.ic_check_box_outline_blank_24dp, R.attr.colorControlNormal)
|
||||
State.INDETERMINATE -> tintVector(context, R.drawable.ic_indeterminate_check_box_24dp)
|
||||
State.CHECKED -> tintVector(context, R.drawable.ic_check_box_24dp)
|
||||
State.INVERSED -> tintVector(context, R.drawable.ic_check_box_x_24dp)
|
||||
}
|
||||
|
||||
setImageDrawable(drawable)
|
||||
}
|
||||
|
||||
private fun tintVector(context: Context, resId: Int, @AttrRes colorAttrRes: Int = R.attr.colorAccent): Drawable {
|
||||
return AppCompatResources.getDrawable(context, resId)!!.apply {
|
||||
setTint(context.getResourceColor(colorAttrRes))
|
||||
when (state) {
|
||||
State.UNCHECKED -> setVectorCompat(R.drawable.ic_check_box_outline_blank_24dp, R.attr.colorControlNormal)
|
||||
State.INDETERMINATE -> setVectorCompat(R.drawable.ic_indeterminate_check_box_24dp, R.attr.colorAccent)
|
||||
State.CHECKED -> setVectorCompat(R.drawable.ic_check_box_24dp, R.attr.colorAccent)
|
||||
State.INVERSED -> setVectorCompat(R.drawable.ic_check_box_x_24dp, R.attr.colorAccent)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@ import eu.kanade.tachiyomi.widget.ViewPagerAdapter
|
||||
|
||||
abstract class TabbedBottomSheetDialog(private val activity: Activity) : BaseBottomSheetDialog(activity) {
|
||||
|
||||
val binding: CommonTabbedSheetBinding = CommonTabbedSheetBinding.inflate(activity.layoutInflater)
|
||||
val binding = CommonTabbedSheetBinding.inflate(activity.layoutInflater)
|
||||
|
||||
init {
|
||||
val adapter = LibrarySettingsSheetAdapter()
|
||||
|
7
app/src/main/res/drawable/ic_blank_24dp.xml
Normal file
7
app/src/main/res/drawable/ic_blank_24dp.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<size
|
||||
android:width="24dp"
|
||||
android:height="24dp" />
|
||||
<solid android:color="@android:color/transparent" />
|
||||
</shape>
|
9
app/src/main/res/drawable/ic_check_24dp.xml
Normal file
9
app/src/main/res/drawable/ic_check_24dp.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="@android:color/black"
|
||||
android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z" />
|
||||
</vector>
|
@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/black"
|
||||
android:pathData="M22.15,13.85H1.85A1.86,1.86,0,0,1,0,12H0a1.86,1.86,0,0,1,1.85-1.85H22.15A1.86,1.86,0,0,1,24,12h0A1.86,1.86,0,0,1,22.15,13.85Z" />
|
||||
</vector>
|
@ -2,7 +2,7 @@
|
||||
<FrameLayout 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:id="@+id/common_action_toolbar"
|
||||
android:id="@+id/action_toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipToPadding="false"
|
||||
@ -25,7 +25,7 @@
|
||||
app:contentInsetStart="8dp">
|
||||
|
||||
<androidx.appcompat.widget.ActionMenuView
|
||||
android:id="@+id/common_action_menu"
|
||||
android:id="@+id/menu"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
@ -17,7 +17,7 @@
|
||||
android:clipToPadding="false"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="@dimen/action_toolbar_list_padding"
|
||||
tools:listitem="@layout/source_main_controller_card_header" />
|
||||
tools:listitem="@layout/section_header_item" />
|
||||
|
||||
</eu.kanade.tachiyomi.widget.ThemedSwipeRefreshLayout>
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:theme="?attr/actionBarTheme"
|
||||
app:layout_scrollFlags="scroll|enterAlways|snap" />
|
||||
app:layout_scrollFlags="scroll|enterAlways" />
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/tabs"
|
||||
|
@ -60,7 +60,8 @@
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?attr/actionBarSize"
|
||||
android:background="?attr/colorPrimary" />
|
||||
|
||||
<LinearLayout
|
||||
|
@ -10,14 +10,14 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<eu.kanade.tachiyomi.ui.reader.setting.SpinnerPreference
|
||||
<eu.kanade.tachiyomi.widget.MaterialSpinnerView
|
||||
android:id="@+id/rotation_mode"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:entries="@array/rotation_type"
|
||||
app:title="@string/pref_rotation_type" />
|
||||
|
||||
<eu.kanade.tachiyomi.ui.reader.setting.SpinnerPreference
|
||||
<eu.kanade.tachiyomi.widget.MaterialSpinnerView
|
||||
android:id="@+id/background_color"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -15,28 +15,28 @@
|
||||
android:paddingEnd="16dp"
|
||||
android:textAppearance="@style/TextAppearance.Medium.SubHeading" />
|
||||
|
||||
<eu.kanade.tachiyomi.ui.reader.setting.SpinnerPreference
|
||||
<eu.kanade.tachiyomi.widget.MaterialSpinnerView
|
||||
android:id="@+id/pager_nav"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:entries="@array/pager_nav"
|
||||
app:title="@string/pref_viewer_nav" />
|
||||
|
||||
<eu.kanade.tachiyomi.ui.reader.setting.SpinnerPreference
|
||||
<eu.kanade.tachiyomi.widget.MaterialSpinnerView
|
||||
android:id="@+id/tapping_inverted"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:entries="@array/invert_tapping_mode"
|
||||
app:title="@string/pref_read_with_tapping_inverted" />
|
||||
|
||||
<eu.kanade.tachiyomi.ui.reader.setting.SpinnerPreference
|
||||
<eu.kanade.tachiyomi.widget.MaterialSpinnerView
|
||||
android:id="@+id/scale_type"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:entries="@array/image_scale_type"
|
||||
app:title="@string/pref_image_scale_type" />
|
||||
|
||||
<eu.kanade.tachiyomi.ui.reader.setting.SpinnerPreference
|
||||
<eu.kanade.tachiyomi.widget.MaterialSpinnerView
|
||||
android:id="@+id/zoom_start"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -10,7 +10,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<eu.kanade.tachiyomi.ui.reader.setting.SpinnerPreference
|
||||
<eu.kanade.tachiyomi.widget.MaterialSpinnerView
|
||||
android:id="@+id/viewer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -15,21 +15,21 @@
|
||||
android:paddingEnd="16dp"
|
||||
android:textAppearance="@style/TextAppearance.Medium.SubHeading" />
|
||||
|
||||
<eu.kanade.tachiyomi.ui.reader.setting.SpinnerPreference
|
||||
<eu.kanade.tachiyomi.widget.MaterialSpinnerView
|
||||
android:id="@+id/webtoon_nav"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:entries="@array/webtoon_nav"
|
||||
app:title="@string/pref_viewer_nav" />
|
||||
|
||||
<eu.kanade.tachiyomi.ui.reader.setting.SpinnerPreference
|
||||
<eu.kanade.tachiyomi.widget.MaterialSpinnerView
|
||||
android:id="@+id/tapping_inverted"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:entries="@array/invert_tapping_mode"
|
||||
app:title="@string/pref_read_with_tapping_inverted" />
|
||||
|
||||
<eu.kanade.tachiyomi.ui.reader.setting.SpinnerPreference
|
||||
<eu.kanade.tachiyomi.widget.MaterialSpinnerView
|
||||
android:id="@+id/webtoon_side_padding"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -1,21 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="32dp"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:elevation="4dp"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/section_text"
|
||||
style="@style/TextAppearance.Regular.SubHeading"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:maxLines="1"
|
||||
android:textColor="?attr/colorOnPrimary"
|
||||
android:textStyle="bold" />
|
||||
|
||||
</FrameLayout>
|
@ -1,7 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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">
|
||||
@ -15,19 +14,6 @@
|
||||
android:paddingStart="?attr/listPreferredItemPaddingStart"
|
||||
android:paddingEnd="?attr/listPreferredItemPaddingEnd">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/pull_up_bar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="24dp"
|
||||
android:alpha="0.5"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@drawable/ic_drag_pill_24dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:tint="?attr/colorOnSurface"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/reset_btn"
|
||||
style="@style/Theme.Widget.Button"
|
||||
|
@ -12,7 +12,7 @@
|
||||
android:clipToPadding="false"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="@dimen/action_toolbar_list_padding"
|
||||
tools:listitem="@layout/source_main_controller_card_header" />
|
||||
tools:listitem="@layout/section_header_item" />
|
||||
|
||||
<eu.kanade.tachiyomi.widget.MaterialFastScroll
|
||||
android:id="@+id/fast_scroller"
|
||||
|
@ -630,7 +630,7 @@
|
||||
<string name="action_disable_all">Zakázat vše</string>
|
||||
<string name="action_enable_all">Povolit vše</string>
|
||||
<string name="action_search_settings">Nastavení vyhledávání</string>
|
||||
<string name="action_sort_date_added">Data přidání</string>
|
||||
<string name="action_sort_date_added">Datum přidání</string>
|
||||
<string name="action_sort_last_checked">Naposledy zkontrolováno</string>
|
||||
<string name="action_filter_tracked">Sledováno</string>
|
||||
<string name="confirm_exit">Opětovným stisknutím tlačítka aplikaci opustíte</string>
|
||||
@ -668,4 +668,15 @@
|
||||
<string name="pref_category_display">Zobrazení</string>
|
||||
<string name="action_display_show_tabs">Zobrazovat karty kategorií</string>
|
||||
<string name="action_display_unread_badge">Odznáček u nepřečtených</string>
|
||||
<string name="update_check_eol">Tato verze systému Android již není podporována</string>
|
||||
<string name="clipboard_copy_error">Kopírování do schránky se nezdařilo</string>
|
||||
<string name="tracker_not_logged_in">Nejsi přihlášen/a: %1$s</string>
|
||||
<string name="vertical_plus_viewer">Průběžné vertikální</string>
|
||||
<string name="edge_nav">Okraj</string>
|
||||
<string name="pref_read_with_tapping_inverted">Převrátit klepnutí</string>
|
||||
<string name="pref_dual_page_split">Rozdělení na dvě stránky</string>
|
||||
<string name="pref_show_navigation_mode_summary">Ukázat oblast klepnutí když je čtečka otevřená</string>
|
||||
<string name="theme_system">Systém sledování</string>
|
||||
<string name="action_show_errors">Zobrazit chyby</string>
|
||||
<string name="action_sort_chapter_fetch_date">Datum načtení</string>
|
||||
</resources>
|
@ -672,4 +672,7 @@
|
||||
<string name="pref_download_new_categories_details">Manga in ausgeschlossenen Kategorien werden nicht heruntergeladen, auch wenn sie in eingeschlossenen Kategorien vorhanden sind.</string>
|
||||
<string name="pref_category_auto_download">Automatisches Herunterladen</string>
|
||||
<string name="pref_library_update_categories_details">Manga in ausgeschlossenen Kategorien werden nicht aktualisiert, auch wenn sie in eingeschlossenen Kategorien vorhanden sind.</string>
|
||||
<string name="action_show_errors">Fehler anzeigen</string>
|
||||
<string name="update_check_eol">Diese Android-Version wird nicht mehr unterstützt</string>
|
||||
<string name="clipboard_copy_error">Kopieren in die Zwischenablage fehlgeschlagen</string>
|
||||
</resources>
|
@ -672,4 +672,7 @@
|
||||
<string name="pref_download_new_categories_details">Τα Manga σε εξαιρούμενες κατηγορίες δεν θα ληφθούν ακόμα κι αν ανήκουν και σε κατηγορίες που περιλαμβάνονται.</string>
|
||||
<string name="pref_category_auto_download">Αυτόματη λήψη</string>
|
||||
<string name="pref_library_update_categories_details">Τα manga στις αποκλεισμένες κατηγορίες δεν θα ενημερώνονται ακόμη και αν βρίσκονται επίσης στις συμπεριλαμβανόμενες κατηγορίες.</string>
|
||||
<string name="action_show_errors">Εμφάνιση σφαλμάτων</string>
|
||||
<string name="update_check_eol">Αυτή η έκδοση Android δεν υποστηρίζεται πλέον</string>
|
||||
<string name="clipboard_copy_error">Απέτυχε η αντιγραφή στο πρόχειρο</string>
|
||||
</resources>
|
@ -4,15 +4,15 @@
|
||||
<string name="label_recent_manga">Historio</string>
|
||||
<string name="label_recent_updates">Ĝisdatigoj</string>
|
||||
<string name="label_library">Biblioteko</string>
|
||||
<string name="label_download_queue">Elŝutos</string>
|
||||
<string name="label_download_queue">Elŝutoj</string>
|
||||
<string name="label_settings">Agordoj</string>
|
||||
<string name="label_more">Plu</string>
|
||||
<string name="label_more">Pli</string>
|
||||
<string name="name">Nomo</string>
|
||||
<string name="information_no_recent">Neniuj ĝisdatigoj</string>
|
||||
<string name="information_no_downloads">Neniu elŝuto</string>
|
||||
<string name="label_help">Asistado</string>
|
||||
<string name="label_extension_info">Konektprogramaro Informaĵo</string>
|
||||
<string name="label_extensions">Konektoprogramaro</string>
|
||||
<string name="label_extensions">Aldonaĵoj</string>
|
||||
<string name="label_migration">Migri</string>
|
||||
<string name="label_backup">Arĥivo</string>
|
||||
<string name="website">Retejo</string>
|
||||
@ -162,4 +162,114 @@
|
||||
<string name="ext_nsfw_short">18+</string>
|
||||
<string name="ext_language_info">Lingvo: %1$s</string>
|
||||
<string name="ext_version_info">Versio: %1$s</string>
|
||||
<string name="nav_zone_next">Sekv\'</string>
|
||||
<string name="nav_zone_prev">Antaŭ\'</string>
|
||||
<string name="browse">Foliumi</string>
|
||||
<string name="manga_chapters_tab">Ĉapitroj</string>
|
||||
<plurals name="manga_num_chapters">
|
||||
<item quantity="one">1 ĉapitro</item>
|
||||
<item quantity="other">%1$s ĉapitroj</item>
|
||||
</plurals>
|
||||
<string name="downloaded_chapters">Elŝutitaj ĉapitroj</string>
|
||||
<string name="in_library">En biblioteko</string>
|
||||
<string name="library_search_hint">Titolo aŭ aŭtoro…</string>
|
||||
<string name="manga_added_library">Aldonita al biblioteko</string>
|
||||
<string name="add_to_library">Aldoni al biblioteko</string>
|
||||
<string name="custom_dir">Propra dosierujo</string>
|
||||
<string name="pref_remove_after_read">Post legi ilin</string>
|
||||
<string name="pref_download_only_over_wifi">Elŝuti nur per Vifio</string>
|
||||
<string name="webtoon_side_padding_25">25%</string>
|
||||
<string name="webtoon_side_padding_20">20%</string>
|
||||
<string name="webtoon_side_padding_15">15%</string>
|
||||
<string name="webtoon_side_padding_10">10%</string>
|
||||
<string name="webtoon_side_padding_0">Neniu</string>
|
||||
<string name="pref_category_reading">Legada</string>
|
||||
<string name="pref_category_reading_mode">Legada reĝimo</string>
|
||||
<string name="color_filter_a_value">Vid</string>
|
||||
<string name="color_filter_b_value">Blu</string>
|
||||
<string name="color_filter_g_value">Verd</string>
|
||||
<string name="color_filter_r_value">Ruĝ</string>
|
||||
<string name="rotation_lock">Ŝlosita</string>
|
||||
<string name="rotation_free">Libera</string>
|
||||
<string name="pref_rotation_type">Orientiĝo</string>
|
||||
<string name="double_tap_anim_speed_fast">Rapida</string>
|
||||
<string name="double_tap_anim_speed_normal">Normala</string>
|
||||
<string name="zoom_start_automatic">Aŭtomate</string>
|
||||
<string name="scale_type_smart_fit">Ŝaĝa adapto</string>
|
||||
<string name="scale_type_fit_height">Adapti al alto</string>
|
||||
<string name="scale_type_fit_width">Adapti al larĝo</string>
|
||||
<string name="vertical_plus_viewer">Seninterrompe vertikale</string>
|
||||
<string name="vertical_viewer">Vertikale</string>
|
||||
<string name="nav_zone_right">Dekstra</string>
|
||||
<string name="nav_zone_left">Maldekstra</string>
|
||||
<string name="right_and_left_nav">Dekstra kaj Maldekstra</string>
|
||||
<string name="l_nav">En formo kiel \"L\"</string>
|
||||
<string name="default_nav">Defaŭlte</string>
|
||||
<string name="default_viewer">Defaŭlte</string>
|
||||
<string name="tapping_inverted_both">Ambaŭ</string>
|
||||
<string name="tapping_inverted_vertical">Vertikala</string>
|
||||
<string name="tapping_inverted_horizontal">Horizontala</string>
|
||||
<string name="tapping_inverted_none">Nenio</string>
|
||||
<string name="pref_reader_navigation">Navigo</string>
|
||||
<string name="pref_skip_read_chapters">Preterpasi ĉapitrojn markitajn kiel legitaj</string>
|
||||
<string name="pref_keep_screen_on">Ne malŝalti ekranon</string>
|
||||
<string name="filter_mode_screen">Ekranado</string>
|
||||
<string name="filter_mode_multiply">Obligado</string>
|
||||
<string name="filter_mode_overlay">Plustavolo</string>
|
||||
<string name="filter_mode_default">Defaŭlta</string>
|
||||
<string name="pref_custom_brightness">Adaptita lumeco</string>
|
||||
<string name="pref_crop_borders">Stuci borderojn</string>
|
||||
<string name="pref_true_color">32-bitaj koloroj</string>
|
||||
<string name="pref_show_reading_mode">Legada reĝimo</string>
|
||||
<string name="pref_show_page_number">Montri numero de paĝo</string>
|
||||
<string name="pref_lock_orientation">Ŝlosi orientiĝon</string>
|
||||
<string name="pref_fullscreen">Plenekrano</string>
|
||||
<string name="obsolete_extension_message">Ĉi tiu aldonaĵo ne estas plu disponebla.</string>
|
||||
<string name="all_lang">Ĉiuj</string>
|
||||
<string name="all">Ĉio</string>
|
||||
<string name="pref_library_update_prioritization">Ĝisdatiga ordigo</string>
|
||||
<string name="update_48hour">Po unu fojon 2 tage</string>
|
||||
<string name="update_12hour">Po unu fojon 12 hore</string>
|
||||
<string name="update_8hour">Po unu fojon 8 hore</string>
|
||||
<string name="update_6hour">Po unu fojon 6 hore</string>
|
||||
<string name="update_4hour">Po unu fojon 4 hore</string>
|
||||
<string name="update_3hour">Po unu fojon 3 hore</string>
|
||||
<string name="update_2hour">Po unu fojon 2 hore</string>
|
||||
<string name="update_1hour">Po unu fojon hore</string>
|
||||
<string name="update_never">Mana</string>
|
||||
<string name="pref_library_update_interval">Ofteco de ĝisdatigoj</string>
|
||||
<string name="pref_category_library_update">Ĝisdatigoj</string>
|
||||
<string name="default_columns">Defaŭlte</string>
|
||||
<string name="landscape">Horizontale</string>
|
||||
<string name="portrait">Vertikale</string>
|
||||
<string name="pref_category_display">Montrado</string>
|
||||
<string name="pref_show_nsfw_extension">Montri en aldonaĵlisto</string>
|
||||
<string name="pref_show_nsfw_source">Montri en fontlisto</string>
|
||||
<string name="pref_category_nsfw_content">MPL/NSFW (18+) fontoj</string>
|
||||
<string name="pref_confirm_exit">Konfirmi eliron</string>
|
||||
<string name="theme_dark_amoled">AMOLED-a nigra</string>
|
||||
<string name="pref_category_locale">Lingvo</string>
|
||||
<string name="pref_category_general">Ĝenerala</string>
|
||||
<string name="app_not_available">Apo maldisponebla</string>
|
||||
<string name="action_restore">Restaŭro</string>
|
||||
<string name="action_show_errors">Montri erarojn</string>
|
||||
<string name="action_reset">Restartigi</string>
|
||||
<string name="action_sort_descending">Malkreskante</string>
|
||||
<string name="action_display_show_number_of_items">Montri nombro de elementoj</string>
|
||||
<string name="action_display_show_tabs">Montri kategoriajn langetojn</string>
|
||||
<string name="action_display_unread_badge">Nelegitajsignoj</string>
|
||||
<string name="action_display_download_badge">Elŝutosignoj</string>
|
||||
<string name="action_display_grid">Kompakta krado</string>
|
||||
<string name="action_display">Montrado</string>
|
||||
<string name="action_display_mode">Montrada reĝimo</string>
|
||||
<string name="action_open_in_web_view">Malfermi per WebView</string>
|
||||
<string name="action_move">Movi</string>
|
||||
<string name="action_resume">Daŭrigi</string>
|
||||
<string name="action_pause">Paŭzigi</string>
|
||||
<string name="action_next_unread">Sekva nelegita</string>
|
||||
<string name="action_sort_down">Ordigi malkreskante</string>
|
||||
<string name="action_sort_up">Ordigi kreskante</string>
|
||||
<string name="action_edit_cover">Redakti kovrilon</string>
|
||||
<string name="action_move_category">Aldoni al kategorioj</string>
|
||||
<string name="action_global_search">Serĉi ĉie</string>
|
||||
</resources>
|
@ -672,4 +672,7 @@
|
||||
<string name="pref_download_new_categories_details">Poissuljettuihin kategorioihin kuuluvia mangoja ei ladata, vaikka ne olisivat myös sisällytetyissä kategorioissa.</string>
|
||||
<string name="pref_category_auto_download">Automaattinen lataus</string>
|
||||
<string name="pref_library_update_categories_details">Poissuljettuihin kategorioihin sisältyvää mangaa ei päivitetä, vaikka ne olisivat myös sisällytetyissä kategorioissa.</string>
|
||||
<string name="action_show_errors">Näytä virheet</string>
|
||||
<string name="update_check_eol">Tätä Android-versiota ei enää tueta</string>
|
||||
<string name="clipboard_copy_error">Kopiointi leikepöydälle epäonnistui</string>
|
||||
</resources>
|
@ -254,7 +254,7 @@
|
||||
<string name="all_lang">Lahat</string>
|
||||
<string name="all">Lahat</string>
|
||||
<plurals name="num_categories">
|
||||
<item quantity="one">1 kategorya</item>
|
||||
<item quantity="one">%d kategorya</item>
|
||||
<item quantity="other">%d (na) kategorya</item>
|
||||
</plurals>
|
||||
<string name="default_category_summary">Palaging tanungin</string>
|
||||
@ -526,7 +526,7 @@
|
||||
<string name="username">Sagisag (username)</string>
|
||||
<string name="login_title">Mag-login sa %1$s</string>
|
||||
<plurals name="download_queue_summary">
|
||||
<item quantity="one">Isa na lang</item>
|
||||
<item quantity="one">1 na lang</item>
|
||||
<item quantity="other">%1$s na lang</item>
|
||||
</plurals>
|
||||
<string name="downloaded_only_summary">Isalâ ang Aklatan</string>
|
||||
@ -672,4 +672,5 @@
|
||||
<string name="none">Wala</string>
|
||||
<string name="pref_library_update_categories_details">Di ia-update ang mga manga na nasa di kasamang kategorya kahit na nasa kasamang kategorya ang mga ito.</string>
|
||||
<string name="action_sort_chapter_fetch_date">Petsa kinuha</string>
|
||||
<string name="action_show_errors">Ipakita ang mga error</string>
|
||||
</resources>
|
@ -706,4 +706,7 @@
|
||||
<string name="pref_library_update_categories_details">Les mangas dans les catégories exclus ne seront pas mises a jour meme s\'ils sont aussi dans les catégories inlcus.</string>
|
||||
<string name="pref_download_new_categories_details">Les mangas dans les catégories exclus ne seront pas mise a jour meme s\'ils sont aussi dans les catégories inclus.</string>
|
||||
<string name="pref_category_auto_download">Téléchargement Automatique</string>
|
||||
<string name="action_show_errors">Afficher les erreurs</string>
|
||||
<string name="update_check_eol">Cette version d\'Android n\'est plus supportée</string>
|
||||
<string name="clipboard_copy_error">Échec de la copie dans le presse-papiers</string>
|
||||
</resources>
|
@ -684,4 +684,5 @@
|
||||
<string name="include">Uključi: %s</string>
|
||||
<string name="pref_library_update_categories_details">Manga u isključenim kategorijama neće se ažurirati čak niti ako se također nalaze u uključenim kategorijama.</string>
|
||||
<string name="action_sort_chapter_fetch_date">Datum preuzimanja</string>
|
||||
<string name="action_show_errors">Prikaži greške</string>
|
||||
</resources>
|
@ -80,7 +80,7 @@
|
||||
<string name="portrait">Tegak</string>
|
||||
<string name="landscape">Menyamping</string>
|
||||
<string name="default_columns">Asali</string>
|
||||
<string name="pref_library_update_interval">Frekuensi pembaruan perpustakaan</string>
|
||||
<string name="pref_library_update_interval">Frekuensi pembaruan</string>
|
||||
<string name="update_never">Manual</string>
|
||||
<string name="update_1hour">Tiap jam</string>
|
||||
<string name="update_2hour">Tiap 2 jam</string>
|
||||
@ -91,7 +91,7 @@
|
||||
<string name="update_48hour">Tiap 2 hari</string>
|
||||
<string name="update_weekly">Tiap minggu</string>
|
||||
<string name="all">Semua</string>
|
||||
<string name="pref_library_update_restriction">Pembatasan pembaruan perpustakaan</string>
|
||||
<string name="pref_library_update_restriction">Pembatasan pembaruan</string>
|
||||
<string name="pref_library_update_restriction_summary">Perbaharui hanya ketika kondisi terpenuhi</string>
|
||||
<string name="charging">Sedang mengisi daya</string>
|
||||
<string name="pref_update_only_non_completed">Perbarui manga yang masih belum tamat saja</string>
|
||||
@ -376,7 +376,7 @@
|
||||
<string name="filter_mode_lighten">Dodge / Cerahkan</string>
|
||||
<string name="filter_mode_darken">Burn / Gelapkan</string>
|
||||
<string name="label_help">Bantuan</string>
|
||||
<string name="pref_library_update_prioritization">Urutan perbarui perpustakaan</string>
|
||||
<string name="pref_library_update_prioritization">Urutan pembaruan</string>
|
||||
<string name="no_results_found">Hasil tidak ditemukan</string>
|
||||
<string name="migration_selection_prompt">Pilih sumber untuk migrasi dari</string>
|
||||
<string name="action_webview_back">Kembali</string>
|
||||
@ -639,4 +639,7 @@
|
||||
<string name="action_display_show_number_of_items">Tampilkan jumlah item</string>
|
||||
<string name="update_8hour">Setiap 8 jam</string>
|
||||
<string name="update_4hour">Setiap 4 jam</string>
|
||||
<string name="none">Kosong</string>
|
||||
<string name="action_show_errors">Tampilkan error</string>
|
||||
<string name="action_sort_chapter_fetch_date">Tanggal diambil</string>
|
||||
</resources>
|
@ -594,7 +594,7 @@
|
||||
</plurals>
|
||||
<string name="unknown_status">Stato sconosciuto</string>
|
||||
<string name="unknown_author">Autore sconosciuto</string>
|
||||
<string name="updated_version">Aggiornato verso v%1$s</string>
|
||||
<string name="updated_version">Aggiornato a v%1$s</string>
|
||||
<string name="whats_new">Le novità</string>
|
||||
<string name="requires_app_restart">Richiesto riavvio dell\'app per applicare le modifiche</string>
|
||||
<string name="label_network">Rete</string>
|
||||
@ -702,4 +702,8 @@
|
||||
<string name="nav_zone_right">Destra</string>
|
||||
<string name="nav_zone_left">Sinistra</string>
|
||||
<string name="pref_library_update_categories_details">Manga che si trovano in categorie escluse non saranno aggiornati anche se si trovano in categorie incluse.</string>
|
||||
<string name="pref_dns_over_https">DNS via HTTPS</string>
|
||||
<string name="pref_show_navigation_mode">Mostra schema di navigazione</string>
|
||||
<string name="pref_show_navigation_mode_summary">Mostra zone di tocco quando il lettore viene aperto</string>
|
||||
<string name="action_show_errors">Mostra errori</string>
|
||||
</resources>
|
@ -70,7 +70,7 @@
|
||||
<string name="portrait">縦向き</string>
|
||||
<string name="landscape">横向き</string>
|
||||
<string name="default_columns">デフォルト</string>
|
||||
<string name="pref_library_update_interval">ライブラリ更新頻度</string>
|
||||
<string name="pref_library_update_interval">更新頻度</string>
|
||||
<string name="update_never">マニュアル</string>
|
||||
<string name="update_1hour">毎時間</string>
|
||||
<string name="update_2hour">2時間ごと</string>
|
||||
@ -81,7 +81,7 @@
|
||||
<string name="update_48hour">2日ごと</string>
|
||||
<string name="update_weekly">毎週</string>
|
||||
<string name="all">すべて</string>
|
||||
<string name="pref_library_update_restriction">ライブラリ更新制限</string>
|
||||
<string name="pref_library_update_restriction">更新制限</string>
|
||||
<string name="pref_library_update_restriction_summary">条件が満たされた場合にのみ更新する</string>
|
||||
<string name="charging">充電中</string>
|
||||
<string name="pref_update_only_non_completed">連載中のマンガのみ更新</string>
|
||||
@ -369,7 +369,7 @@
|
||||
<string name="filter_mode_default">既定</string>
|
||||
<string name="filter_mode_overlay">オーバーレイ</string>
|
||||
<string name="filter_mode_screen">スクリーン</string>
|
||||
<string name="pref_library_update_prioritization">ライブラリ更新の順</string>
|
||||
<string name="pref_library_update_prioritization">更新の順</string>
|
||||
<string name="no_results_found">結果が見つかりませんでした</string>
|
||||
<string name="migration_selection_prompt">移行元を選択</string>
|
||||
<string name="action_webview_back">前へ</string>
|
||||
@ -380,7 +380,7 @@
|
||||
<string name="ext_obsolete">廃止済み</string>
|
||||
<string name="obsolete_extension_message">この拡張機能は利用不可になりました。</string>
|
||||
<string name="pref_date_format">日付形式</string>
|
||||
<string name="pref_category_library_update">更新</string>
|
||||
<string name="pref_category_library_update">グローバルアップデート</string>
|
||||
<string name="logout_title">%1$sからログアウトしますか?</string>
|
||||
<string name="logout">ログアウト</string>
|
||||
<string name="logout_success">ログアウトしました</string>
|
||||
@ -402,7 +402,7 @@
|
||||
<string name="theme_dark_amoled">AMOLEDブラック</string>
|
||||
<string name="pref_manage_notifications">通知設定</string>
|
||||
<string name="pref_category_security">セキュリティ</string>
|
||||
<string name="lock_with_biometrics">生体認証</string>
|
||||
<string name="lock_with_biometrics">アンロックを必要とする</string>
|
||||
<string name="lock_when_idle">タイムアウトロック</string>
|
||||
<string name="lock_always">常時</string>
|
||||
<string name="lock_never">しない</string>
|
||||
@ -650,6 +650,15 @@
|
||||
<string name="nav_zone_left">左</string>
|
||||
<string name="nav_zone_next">次へ</string>
|
||||
<string name="nav_zone_prev">前へ</string>
|
||||
<string name="pref_show_navigation_mode_summary">ビューアが立ち上がるとタップゾーンをしばらく表示します</string>
|
||||
<string name="pref_show_navigation_mode_summary">ビューアが立ち上がるとタップゾーンを表示します</string>
|
||||
<string name="pref_show_navigation_mode">ナビゲーションレイアウトオーバーレイを表示</string>
|
||||
<string name="pref_dns_over_https">DNS over HTTPS</string>
|
||||
<string name="pref_download_new_categories_details">含まれているカテゴリーに入っていても、除外対象カテゴリーにあるマンガは更新されません。</string>
|
||||
<string name="pref_category_auto_download">自動ダウンロード</string>
|
||||
<string name="exclude">下記を除外:%s</string>
|
||||
<string name="include">下記を含む:%s</string>
|
||||
<string name="none">なし</string>
|
||||
<string name="pref_library_update_categories_details">含まれているカテゴリーに入っていても、除外対象カテゴリーにあるマンガは更新されません。</string>
|
||||
<string name="action_show_errors">エラーを表示</string>
|
||||
<string name="action_sort_chapter_fetch_date">日付を取得しました</string>
|
||||
</resources>
|
@ -14,7 +14,7 @@
|
||||
<string name="lock_never">ಎಂದಿಗೂ ಇಲ್ಲ</string>
|
||||
<string name="lock_always">ಯಾವಾಗಲೂ</string>
|
||||
<string name="lock_when_idle">ನಿಷ್ಕ್ರಿಯವಾಗಿದ್ದಾಗ ಲಾಕ್ ಮಾಡಿ</string>
|
||||
<string name="lock_with_biometrics">"ಬೆರಳಚ್ಚ ಬದ್ರತೆ"</string>
|
||||
<string name="lock_with_biometrics">ಅನ್ ಲಾಕ್ ಅಗತ್ಯವಿದೆ</string>
|
||||
<string name="pref_category_security">ಭದ್ರತೆ</string>
|
||||
<string name="pref_manage_notifications">ಸೂಚನೆಗಳನ್ನು ನಿರ್ವಹಿಸಿ</string>
|
||||
<string name="pref_confirm_exit">ನಿರ್ಗಮನವನ್ನು ಖಚಿತಪಡಿಸಿ</string>
|
||||
@ -281,8 +281,8 @@
|
||||
<string name="pref_update_only_non_completed">ಚಾಲ್ತಿಯಿರುವ ಮಾಂಗಾವನ್ನು ಮಾತ್ರ ನವೀಕರಿಸಿ</string>
|
||||
<string name="charging">ಚಾರ್ಜಿಂಗ್</string>
|
||||
<string name="pref_library_update_restriction_summary">ಷರತ್ತುಗಳನ್ನು ಪೂರೈಸಿದಾಗ ಮಾತ್ರ ನವೀಕರಿಸಿ</string>
|
||||
<string name="pref_library_update_restriction">ಗ್ರಂಥಾಲಯ ನವೀಕರಣ ನಿರ್ಬಂಧಗಳು</string>
|
||||
<string name="pref_library_update_prioritization">ಗ್ರಂಥಾಲಯ ನವೀಕರಣ ಪಾಳಿ</string>
|
||||
<string name="pref_library_update_restriction">ನವೀಕರಣ ನಿರ್ಬಂಧಗಳು</string>
|
||||
<string name="pref_library_update_prioritization">ನವೀಕರಣ ಪಾಳಿ</string>
|
||||
<string name="update_weekly">ವಾರಕ್ಕೊಮ್ಮೆ</string>
|
||||
<string name="update_48hour">ಪ್ರತಿ 2 ದಿನಗಳಿಗೊಮ್ಮೆ</string>
|
||||
<string name="update_24hour">ಪ್ರತಿದಿನ</string>
|
||||
@ -292,7 +292,7 @@
|
||||
<string name="update_2hour">ಪ್ರತಿ 2 ಗಂಟೆಗಳಿಗೊಮ್ಮೆ</string>
|
||||
<string name="update_1hour">ಗಂಟೆ</string>
|
||||
<string name="update_never">ಸ್ವಂತ ಮಾಡು</string>
|
||||
<string name="pref_library_update_interval">ಗ್ರಂಥಾಲಯ ನವೀಕರಣ ಆವರ್ತನ</string>
|
||||
<string name="pref_library_update_interval">ನವೀಕರಣ ಆವರ್ತನ</string>
|
||||
<string name="pref_category_library_update">ನವೀಕರಣಗಳು</string>
|
||||
<string name="default_columns">ಡೀಫಾಲ್ಟ್</string>
|
||||
<string name="source_requires_login">ಈ ಮೂಲದ ಬಳಕೆಗೆ ಲಾಗಿನ್ ಆಗುವ ಅಗತ್ಯವಿದೆ</string>
|
||||
@ -607,7 +607,7 @@
|
||||
<string name="backup_restore_missing_trackers">ಟ್ರ್ಯಾಕರ್ ಗಳು ಲಾಗಿನ್ ಆಗಿಲ್ಲ:</string>
|
||||
<string name="pref_remove_bookmarked_chapters">ಬುಕ್ ಮಾರ್ಕ್ ಮಾಡಿದ ಅಧ್ಯಾಯಗಳನ್ನು ಅಳಿಸಿ</string>
|
||||
<string name="pref_category_delete_chapters">ಅಧ್ಯಾಯಗಳನ್ನು ಅಳಿಸಿ</string>
|
||||
<string name="ext_nsfw_warning">18+ ವಿಷಯವನ್ನು ಹೊಂದಿರಬಹುದು</string>
|
||||
<string name="ext_nsfw_warning">NSFW (18+) ವಿಷಯವನ್ನು ಹೊಂದಿರಬಹುದು</string>
|
||||
<string name="ext_nsfw_short">18+</string>
|
||||
<string name="pref_hide_bottom_bar_on_scroll">ಸ್ಕ್ರಾಲ್ ಮಾಡಿದಾಗ ಕೆಳಗಿನ ಪಟ್ಟಿಯನ್ನು ಮರೆಮಾಡಿ</string>
|
||||
<string name="action_search_settings">ಸಂಯೋಜನೆಗಳಲ್ಲಿ ಹುಡುಕಿ</string>
|
||||
@ -622,7 +622,8 @@
|
||||
<string name="pref_clear_history">ಇತಿಹಾಸವನ್ನು ತೆರವುಗೊಳಿಸಿ</string>
|
||||
<string name="clear_history_confirmation">ನೀವು ಖಚಿತವಾಗಿರುವಿರಾ\? ಎಲ್ಲಾ ಇತಿಹಾಸವೂ ಕಳೆದುಹೋಗುತ್ತದೆ.</string>
|
||||
<string name="clear_history_completed">ಇತಿಹಾಸವನ್ನು ಅಳಿಸಲಾಗಿದೆ</string>
|
||||
<string name="invalid_backup_file_type">ಅಮಾನ್ಯ ಬ್ಯಾಕಪ್ ಫೈಲ್:%1$s</string>
|
||||
<string name="invalid_backup_file_type">ಅಮಾನ್ಯ ಬ್ಯಾಕಪ್ ಫೈಲ್ ಪ್ರಕಾರ:%1$s
|
||||
\nಫೈಲ್ ಪ್ರಕಾರ .proto.gz ಅಥವಾ .json ನೊಂದಿಗೆ ಕೊನೆಗೊಳ್ಳಬೇಕು.</string>
|
||||
<string name="pref_backup_auto_create_legacy">ಹಳೆಯ ಪ್ರಕಾರದ ಬ್ಯಾಕಪ್ ಅನ್ನು ಸಹ ರಚಿಸಿ</string>
|
||||
<string name="pref_create_legacy_backup_summary">ತಚಿಯೋಮಿಯ ಹಳೆಯ ಆವೃತ್ತಿಗಳಲ್ಲಿ ಬಳಸಬಹುದು</string>
|
||||
<string name="pref_create_legacy_backup">ಹಳೆಯ ಪ್ರಕಾರದ ಬ್ಯಾಕಪ್ ರಚಿಸಿ</string>
|
||||
@ -635,8 +636,41 @@
|
||||
<string name="update_4hour">ಪ್ರತಿ ೪ ಗಂಟೆಗೆ</string>
|
||||
<string name="action_desc">ಮೊದಲು ಚಿಕ್ಕದು</string>
|
||||
<string name="action_asc">ಮೊದಲ ಸಾಣ್ಣದ್ದು</string>
|
||||
<string name="action_order_by_chapter_number">ಅಧ್ಯಾಯ ಸಾಂಖ್ಯಯಂತೆ</string>
|
||||
<string name="action_order_by_upload_date">ದಿನಾಂಕ ದಂತೆ</string>
|
||||
<string name="action_display_show_number_of_items">"ವಸ್ತುವಿನ ಸಾಂಖ್ಯ ತೋರಿಸಿ"</string>
|
||||
<string name="action_sort_chapter_fetch_date">ಪಡೆಯುಲಾದ ಮಾಹಿತಿ</string>
|
||||
<string name="action_order_by_chapter_number">ಅಧ್ಯಾಯ ಸಂಖ್ಯೆಯಿಂದ</string>
|
||||
<string name="action_order_by_upload_date">ಅಪ್ಲೋಡ್ ದಿನಾಂಕ ದಂತೆ</string>
|
||||
<string name="action_display_show_number_of_items">ವಸ್ತುಗಳ ಸಂಖ್ಯೆಯನ್ನು ತೋರಿಸಿ</string>
|
||||
<string name="action_sort_chapter_fetch_date">ಸಿಕ್ಕ ಮಾಹಿತಿ</string>
|
||||
<string name="channel_crash_logs">ಕ್ರ್ಯಾಶ್ ಲಾಗ್ ಗಳು</string>
|
||||
<string name="track_finished_reading_date">ಓದಿ ಮುಗಿಸಿದ ದಿನಾಂಕ</string>
|
||||
<string name="track_started_reading_date">ಓದಲು ಪ್ರಾರಂಭಿಸಿದ ದಿನಾಂಕ</string>
|
||||
<string name="crash_log_saved">ಕ್ರ್ಯಾಶ್ ಲಾಗ್ಗಳನ್ನು ಉಳಿಸಲಾಗಿದೆ</string>
|
||||
<string name="pref_dump_crash_logs_summary">ಡೆವಲಪರ್ಗಳೊಂದಿಗೆ ಹಂಚಿಕೊಳ್ಳಲು ದೋಷದೆ ಲಾಗ್ಗಳನ್ನು ಫೈಲ್ಗೆ ಸೇರಿಸಿ</string>
|
||||
<string name="pref_dump_crash_logs">ಕ್ರ್ಯಾಶ್ ಲಾಗ್ಗಳನ್ನು ಡಂಪ್ ಮಾಡಿ</string>
|
||||
<string name="pref_dns_over_https">HTTPS ಮೇಲೆ DNS ಬಳಸಿ</string>
|
||||
<string name="backup_restore_content_full">ಬ್ಯಾಕಪ್ ಫೈಲ್ನಿಂದ ಡೇಟಾವನ್ನು ಮರುಸ್ಥಾಪಿಸಲಾಗುತ್ತದೆ.
|
||||
\n
|
||||
\nಕಾಣೆಯಾದ ಯಾವುದೇ ವಿಸ್ತರಣೆಗಳನ್ನು ನೀವು ಪುನಃ ಸ್ಥಾಪಿಸಬೇಕಾಗುತ್ತದೆ ಮತ್ತು ಅವುಗಳನ್ನು ಬಳಸಲು ಟ್ರ್ಯಾಕಿಂಗ್ ಸೇವೆಗಳಿಗೆ ಲಾಗ್ ಇನ್ ಮಾಡಬೇಕಾಗುತ್ತದೆ.</string>
|
||||
<string name="pref_download_new_categories_details">ಹೊರಗಿಡಲಾದ ವಿಭಾಗಗಳಲ್ಲಿ ಮಾಂಗಾವನ್ನು ಸೇರಿಸಿದ ವಿಭಾಗಗಳಲ್ಲಿದ್ದರೂ ಅವುಗಳನ್ನು ಡೌನ್ಲೋಡ್ ಮಾಡಲಾಗುವುದಿಲ್ಲ.</string>
|
||||
<string name="pref_category_auto_download">ಸ್ವಯಂ ಡೌನ್ಲೋಡ್</string>
|
||||
<string name="pref_viewer_nav">ನ್ಯಾವಿಗೇಶನ್ ಲೇಔಟ್</string>
|
||||
<string name="nav_zone_right">ಬಲಕ್ಕೆ</string>
|
||||
<string name="nav_zone_left">ಎಡಕ್ಕೆ</string>
|
||||
<string name="nav_zone_next">ಮುಂದಿನ</string>
|
||||
<string name="nav_zone_prev">ಹಿಂದಿನ</string>
|
||||
<string name="right_and_left_nav">ಬಲ ಮತ್ತು ಎಡ</string>
|
||||
<string name="edge_nav">ಅಂಚು</string>
|
||||
<string name="kindlish_nav">ಕಿಂಡಲ್-ಇಶ್</string>
|
||||
<string name="l_nav">L ಆಕಾರದ</string>
|
||||
<string name="default_nav">ಪೂರ್ವನಿಯೋಜಿತ</string>
|
||||
<string name="pref_dual_page_invert_summary">ಡ್ಯುಯಲ್ ಪೇಜ್ ಸ್ಪ್ಲಿಟ್ ನ ಪ್ಲೇಸ್ ಮೆಂಟ್ ಓದುವ ದಿಕ್ಕಿಗೆ ಹೊಂದಿಕೆಯಾಗದಿದ್ದರೆ</string>
|
||||
<string name="pref_dual_page_invert">ಡ್ಯುಯಲ್ ಪೇಜ್ ಸ್ಪ್ಲಿಟ್ ಪ್ಲೇಸ್ಮೆಂಟ್ ಅನ್ನು ತಿರುಗಿಸಿ</string>
|
||||
<string name="pref_dual_page_split">ಡ್ಯುಯಲ್ ಪುಟ ವಿಭಜನೆ</string>
|
||||
<string name="pref_show_navigation_mode_summary">ರೀಡರ್ ತೆರೆದಾಗ ಟ್ಯಾಪ್ ವಲಯಗಳನ್ನು ತೋರಿಸಿ</string>
|
||||
<string name="pref_show_navigation_mode">ನ್ಯಾವಿಗೇಶನ್ ಲೇಔಟ್ ಓವರ್ ಲೇ ತೋರಿಸಿ</string>
|
||||
<string name="exclude">ಹೊರಗಿಡಿ: %s</string>
|
||||
<string name="include">ಸೇರಿಸಿ: %s</string>
|
||||
<string name="none">ಯಾವುದು ಅಲ್ಲ</string>
|
||||
<string name="pref_library_update_categories_details">ಹೊರಗಿಡಲಾದ ವರ್ಗಗಳಲ್ಲಿನ ಮಾಂಗಾ ಸೇರಿಸಿದ ವಿಭಾಗಗಳಲ್ಲಿದ್ದರೂ ನವೀಕರಿಸಲಾಗುವುದಿಲ್ಲ.</string>
|
||||
<string name="network_unmetered">ಅಳತೆಯಿಲ್ಲದ ನೆಟ್ವರ್ಕ್</string>
|
||||
<string name="action_show_errors">ದೋಷಗಳನ್ನು ತೋರಿಸು</string>
|
||||
</resources>
|
@ -101,7 +101,7 @@
|
||||
<string name="pref_auto_update_manga_sync">Kemas kini bab selepas dibaca</string>
|
||||
<string name="pref_start_screen">Skrin permulaan</string>
|
||||
<string name="pref_language">Bahasa</string>
|
||||
<string name="system_default">Lalai</string>
|
||||
<string name="system_default">Sistem asal</string>
|
||||
<string name="default_category">Kategori lalai</string>
|
||||
<string name="default_category_summary">Sentiasa tanya</string>
|
||||
<string name="pref_fullscreen">Skrin penuh</string>
|
||||
@ -152,7 +152,7 @@
|
||||
<string name="pref_remove_after_marked_as_read">Selepas ditandakan sebagai dibaca secara manual</string>
|
||||
<string name="pref_remove_after_read">Setelah membaca</string>
|
||||
<string name="custom_dir">Lokasi tersuai</string>
|
||||
<string name="disabled">Dinyahaktifkan</string>
|
||||
<string name="disabled">Di nyahkan</string>
|
||||
<string name="last_read_chapter">Bab terakhir dibaca</string>
|
||||
<string name="second_to_last">Bab kedua terakhir</string>
|
||||
<string name="third_to_last">Bab ketiga terakhir</string>
|
||||
@ -212,7 +212,7 @@
|
||||
<string name="local_source">Sumber lokal</string>
|
||||
<string name="other_source">Lain</string>
|
||||
<string name="invalid_combination">Lalai tidak boleh dipilih bersama kategori lain</string>
|
||||
<string name="added_to_library">Manga ini telah ditambahkan ke pustaka anda</string>
|
||||
<string name="added_to_library">Ditambah ke pustaka</string>
|
||||
<string name="action_global_search_hint">Carian keseluruhan…</string>
|
||||
<string name="latest">Terkini</string>
|
||||
<string name="browse">Semak imbas</string>
|
||||
@ -232,7 +232,7 @@
|
||||
<string name="chapter_downloading">Muat turun dalam progres</string>
|
||||
<string name="chapter_downloading_progress">Memuat turun (%1$d/%2$d)</string>
|
||||
<string name="chapter_error">Ralat</string>
|
||||
<string name="chapter_paused">Dihenti sebentar</string>
|
||||
<string name="chapter_paused">Ditangguh</string>
|
||||
<string name="fetch_chapters_error">Tidak berhasil mendapatkan bab</string>
|
||||
<string name="show_title">Tajuk sumber</string>
|
||||
<string name="show_chapter_number">Nombor bab</string>
|
||||
@ -244,7 +244,7 @@
|
||||
<string name="download_5">5 bab seterusnya</string>
|
||||
<string name="download_10">10 bab seterusnya</string>
|
||||
<string name="download_all">Semua</string>
|
||||
<string name="download_unread">Belum dibaca</string>
|
||||
<string name="download_unread">Muat turun yang belum di baca</string>
|
||||
<string name="confirm_delete_chapters">Adakah anda pasti ingin memadamkan bab yang dipilih\?</string>
|
||||
<string name="manga_tracking_tab">Penjejakan</string>
|
||||
<string name="reading">Sedang baca</string>
|
||||
@ -274,7 +274,7 @@
|
||||
<string name="chapter_subtitle">Bab %1$s</string>
|
||||
<string name="no_next_chapter">Bab seterusnya tidak dijumpai</string>
|
||||
<string name="no_previous_chapter">Bab sebelumnya tidak dijumpai</string>
|
||||
<string name="decode_image_error">Imej tidak dapat dimuatkan</string>
|
||||
<string name="decode_image_error">Imej tidak dapat di muatkan</string>
|
||||
<string name="confirm_set_image_as_cover">Guna imej ini sebagai muka hadapan\?</string>
|
||||
<string name="download_queue_error">Memuat turun bab tidak berjaya. Anda boleh mencuba lagi di bahagian muat turun</string>
|
||||
<string name="notification_update_progress">Progres kemas kini: %1$d/%2$d</string>
|
||||
@ -319,7 +319,7 @@
|
||||
<string name="ext_update">Kemaskini</string>
|
||||
<string name="ext_install">Pasang</string>
|
||||
<string name="ext_pending">Masih menunggu</string>
|
||||
<string name="ext_downloading">Muat turun dalam progres</string>
|
||||
<string name="ext_downloading">Menuat turun</string>
|
||||
<string name="ext_installing">Memasang</string>
|
||||
<string name="ext_installed">Dipasang</string>
|
||||
<string name="ext_trust">Dipercayai</string>
|
||||
@ -391,9 +391,9 @@
|
||||
<string name="logout_title">Log keluar daripada %1$s\?</string>
|
||||
<string name="logout">Log keluar</string>
|
||||
<string name="logout_success">Anda telah log keluar</string>
|
||||
<string name="currently_reading">Sedang baca</string>
|
||||
<string name="currently_reading">Sedang di baca</string>
|
||||
<string name="paused">Ditangguh</string>
|
||||
<string name="want_to_read">Ingin baca</string>
|
||||
<string name="want_to_read">Hendak di baca</string>
|
||||
<string name="label_more">Lain-lain</string>
|
||||
<string name="action_sort_latest_chapter">Bab terkini</string>
|
||||
<string name="action_view_chapters">Buka bab</string>
|
||||
@ -408,7 +408,7 @@
|
||||
<string name="theme_dark_amoled">AMOLED</string>
|
||||
<string name="pref_manage_notifications">Uruskan pemberitahuan</string>
|
||||
<string name="pref_category_security">Keselamatan</string>
|
||||
<string name="lock_with_biometrics">Memerlukan buka kunci</string>
|
||||
<string name="lock_with_biometrics">Kunci dengan biometrik</string>
|
||||
<string name="lock_when_idle">Kunci apabila terbiar</string>
|
||||
<string name="lock_always">Selalu</string>
|
||||
<string name="lock_never">Tidak</string>
|
||||
@ -474,8 +474,8 @@
|
||||
<string name="add_tracking">Tambah penjejakan</string>
|
||||
<string name="manga_info_collapse">Tutup</string>
|
||||
<string name="manga_info_expand">Buka</string>
|
||||
<string name="in_library">Dalam pustaka</string>
|
||||
<string name="add_to_library">Tambah ke pustaka</string>
|
||||
<string name="in_library">Dalam Pustaka</string>
|
||||
<string name="add_to_library">Tambah ke Pustaka</string>
|
||||
<string name="pinned_sources">Disematkan</string>
|
||||
<string name="licenses">Lesen perisian sumber terbuka</string>
|
||||
<string name="website">Laman web</string>
|
||||
@ -660,4 +660,7 @@
|
||||
<string name="pref_library_update_categories_details">Manga di dalam kategori berkecuali tidak akan dikemaskini walaupun ianya ada di dalam kategori hanya.</string>
|
||||
<string name="pref_download_new_categories_details">Manga di dalam kategori berkecuali tidak akan dimuat turun walaupun ianya ada di dalam kategori hanya.</string>
|
||||
<string name="pref_category_auto_download">Muat turun automatik</string>
|
||||
<string name="action_show_errors">Tunjuk ralat</string>
|
||||
<string name="update_check_eol">Versi Android ini tidak lagi disokong</string>
|
||||
<string name="clipboard_copy_error">Gagal menyalin ke papan keratan</string>
|
||||
</resources>
|
@ -122,8 +122,8 @@
|
||||
<string name="pref_category_tracking">Sporing</string>
|
||||
<string name="portrait">Stående</string>
|
||||
<string name="landscape">Liggende</string>
|
||||
<string name="pref_library_update_interval">Frekvens for oppdatering av bibliotek</string>
|
||||
<string name="pref_library_update_restriction">Restriksjoner for oppdatering av bibliotek</string>
|
||||
<string name="pref_library_update_interval">Oppdateringsfrekvens</string>
|
||||
<string name="pref_library_update_restriction">Oppdateringsrestriksjoner</string>
|
||||
<string name="pref_library_update_restriction_summary">Kun oppdater når disse vilkårene oppfylles</string>
|
||||
<string name="pref_update_only_non_completed">Kun oppdater pågående manga</string>
|
||||
<string name="pref_auto_update_manga_sync">Oppdater kapittelfremdrift etter lesing</string>
|
||||
@ -376,7 +376,7 @@
|
||||
<string name="filter_mode_multiply">Multiplisere</string>
|
||||
<string name="filter_mode_lighten">Unngå / lysne</string>
|
||||
<string name="filter_mode_darken">Brenn / mørkere</string>
|
||||
<string name="pref_library_update_prioritization">Rekkefølge for biblioteksoppdatering</string>
|
||||
<string name="pref_library_update_prioritization">Oppdateringsrekkefølge</string>
|
||||
<string name="no_results_found">Resultatløst</string>
|
||||
<string name="migration_selection_prompt">Velg en kilde å migrere fra</string>
|
||||
<string name="action_webview_back">Tilbake</string>
|
||||
@ -387,7 +387,7 @@
|
||||
<string name="ext_obsolete">Foreldet</string>
|
||||
<string name="obsolete_extension_message">Denne utvidelsen er ikke lenger tilgjengelig.</string>
|
||||
<string name="pref_date_format">Datoformat</string>
|
||||
<string name="pref_category_library_update">Oppdateringer</string>
|
||||
<string name="pref_category_library_update">Global oppdatering</string>
|
||||
<string name="logout_title">Logg ut fra %1$s\?</string>
|
||||
<string name="logout">Logg ut</string>
|
||||
<string name="logout_success">Du er utlogget</string>
|
||||
@ -669,4 +669,8 @@
|
||||
<string name="update_8hour">Hver 8 time</string>
|
||||
<string name="update_4hour">Hver 4 time</string>
|
||||
<string name="action_sort_chapter_fetch_date">Dato hentet</string>
|
||||
<string name="pref_download_new_categories_details">Manga i utelukkede kategorier vil ikke bli nedlastet selv om de også er i inkluderte kategorier.</string>
|
||||
<string name="pref_category_auto_download">Last ned automatisk</string>
|
||||
<string name="pref_library_update_categories_details">Manga i utelukkede kategorier vil ikke bli oppdatert selv om de også er i inkluderte kategorier.</string>
|
||||
<string name="action_show_errors">Vis feil</string>
|
||||
</resources>
|
@ -672,4 +672,5 @@
|
||||
<string name="pref_library_update_categories_details">Manga in uitgesloten categorieën worden niet bijgewerkt, zelfs niet als ze onder opgenomen categorieën vallen.</string>
|
||||
<string name="action_sort_chapter_fetch_date">Datum opgehaald</string>
|
||||
<string name="none">Geen</string>
|
||||
<string name="action_show_errors">Fouten weergeven</string>
|
||||
</resources>
|
@ -641,7 +641,7 @@
|
||||
<string name="track_started_reading_date">Data de início da leitura</string>
|
||||
<string name="crash_log_saved">Registros de travamento salvos</string>
|
||||
<string name="pref_dump_crash_logs_summary">Salva os registros de erro em um arquivo para o compartilhamento com os desenvolvedores</string>
|
||||
<string name="pref_dump_crash_logs">Limpar os registros de travamentos</string>
|
||||
<string name="pref_dump_crash_logs">Exportar os registros de travamentos</string>
|
||||
<string name="network_unmetered">Rede ilimitada</string>
|
||||
<string name="action_desc">Decrescente</string>
|
||||
<string name="action_asc">Crescente</string>
|
||||
@ -672,4 +672,7 @@
|
||||
<string name="pref_library_update_categories_details">Os mangás nas categorias excluídas não serão atualizados mesmo que eles também estejam nas categorias incluídas.</string>
|
||||
<string name="pref_download_new_categories_details">Os mangás nas categorias excluídas não serão disponibilizados offline mesmo que eles também estejam nas categorias incluídas.</string>
|
||||
<string name="pref_category_auto_download">Disponibilizar offline automaticamente</string>
|
||||
<string name="action_show_errors">Mostrar erros</string>
|
||||
<string name="update_check_eol">Esta versão do Android não é mais suportada</string>
|
||||
<string name="clipboard_copy_error">Erro ao copiar para a área de transferência</string>
|
||||
</resources>
|
@ -59,7 +59,7 @@
|
||||
<string name="portrait">Retrato</string>
|
||||
<string name="landscape">Paisagem</string>
|
||||
<string name="default_columns">Padrão</string>
|
||||
<string name="pref_library_update_interval">Frequência de atualização da biblioteca</string>
|
||||
<string name="pref_library_update_interval">Frequência de atualização</string>
|
||||
<string name="update_never">Manual</string>
|
||||
<string name="update_1hour">Hora à hora</string>
|
||||
<string name="update_2hour">A cada 2 horas</string>
|
||||
@ -69,7 +69,7 @@
|
||||
<string name="update_24hour">Diariamente</string>
|
||||
<string name="update_48hour">A cada 2 dias</string>
|
||||
<string name="all">Tudo</string>
|
||||
<string name="pref_library_update_restriction">Restrições sobre a atualização da biblioteca</string>
|
||||
<string name="pref_library_update_restriction">Restrições sobre a atualização</string>
|
||||
<string name="pref_library_update_restriction_summary">Atualizar apenas quando se cumprem as condições</string>
|
||||
<string name="charging">A carregar</string>
|
||||
<string name="pref_update_only_non_completed">Atualizar apenas mangás a decorrer</string>
|
||||
@ -181,7 +181,7 @@
|
||||
<string name="sort_by_source">Por fonte</string>
|
||||
<string name="sort_by_number">Por número de capítulo</string>
|
||||
<string name="manga_download">Transferir</string>
|
||||
<string name="download_1">Próximo capítulo</string>
|
||||
<string name="download_1">Capítulo seguinte</string>
|
||||
<string name="download_5">Próximos 5 capítulos</string>
|
||||
<string name="download_10">Próximos 10 capítulos</string>
|
||||
<string name="download_all">Tudo</string>
|
||||
@ -406,7 +406,7 @@
|
||||
<string name="pref_color_filter_mode">Modo de mistura do filtro de cores</string>
|
||||
<string name="filter_mode_lighten">Sub-exposição / Clarear</string>
|
||||
<string name="label_help">Ajuda</string>
|
||||
<string name="pref_library_update_prioritization">Ordem de atualização da biblioteca</string>
|
||||
<string name="pref_library_update_prioritization">Ordem de atualização</string>
|
||||
<string name="no_results_found">Nenhum resultado encontrado</string>
|
||||
<string name="migration_selection_prompt">Selecione uma fonte da qual migrar</string>
|
||||
<string name="action_webview_back">Voltar</string>
|
||||
@ -417,7 +417,7 @@
|
||||
<string name="ext_obsolete">Obsoleto</string>
|
||||
<string name="obsolete_extension_message">Esta extensão já não está disponível.</string>
|
||||
<string name="pref_date_format">Formato da data</string>
|
||||
<string name="pref_category_library_update">Atualizações</string>
|
||||
<string name="pref_category_library_update">Atualização global</string>
|
||||
<string name="logout_title">Terminar sessão em %1$s\?</string>
|
||||
<string name="logout">Terminar sessão</string>
|
||||
<string name="logout_success">Sua sessão está agora encerrada</string>
|
||||
@ -438,7 +438,7 @@
|
||||
<string name="theme_dark_amoled">Preto AMOLED</string>
|
||||
<string name="pref_manage_notifications">Gerir notificações</string>
|
||||
<string name="pref_category_security">Segurança</string>
|
||||
<string name="lock_with_biometrics">Bloqueio com biometria</string>
|
||||
<string name="lock_with_biometrics">Requerer desbloqueio</string>
|
||||
<string name="lock_when_idle">Bloquear automaticamente</string>
|
||||
<string name="lock_always">Sempre</string>
|
||||
<string name="lock_never">Nunca</string>
|
||||
@ -690,8 +690,19 @@
|
||||
<string name="nav_zone_left">Esquerda</string>
|
||||
<string name="nav_zone_next">Seguinte</string>
|
||||
<string name="nav_zone_prev">Anterior</string>
|
||||
<string name="pref_show_navigation_mode_summary">Brevemente mostrar zonas de toque quando o leitor é aberto</string>
|
||||
<string name="pref_show_navigation_mode_summary">Mostrar zonas de toque quando o leitor é aberto</string>
|
||||
<string name="pref_show_navigation_mode">Mostrar sobreposição da disposição de navegação</string>
|
||||
<string name="update_8hour">A cada 8 horas</string>
|
||||
<string name="update_4hour">A cada 4 horas</string>
|
||||
<string name="none">Nenhum</string>
|
||||
<string name="pref_dns_over_https">DNS por HTTPS</string>
|
||||
<string name="pref_category_auto_download">Transferir automaticamente</string>
|
||||
<string name="update_check_eol">Esta versão do Android não é mais suportada</string>
|
||||
<string name="clipboard_copy_error">Falha ao copiar para a área de transferência</string>
|
||||
<string name="pref_download_new_categories_details">Mangá nas categorias excluídas não será transferida mesmo que também esteja em categorias incluídas.</string>
|
||||
<string name="exclude">Excluir: %s</string>
|
||||
<string name="include">Incluir: %s</string>
|
||||
<string name="pref_library_update_categories_details">Mangá em categorias excluídas não será atualizada mesmo que também estejam nas categorias incluídas.</string>
|
||||
<string name="action_show_errors">Mostrar erros</string>
|
||||
<string name="action_sort_chapter_fetch_date">Data de procura</string>
|
||||
</resources>
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user