Merge pull request #3 from tachiyomiorg/master

update to main repo
This commit is contained in:
jmir1 2021-04-22 15:16:54 +02:00 committed by jhmiramon
commit afffe462ef
75 changed files with 2184 additions and 464 deletions

1
.github/FUNDING.yml vendored
View file

@ -1,2 +1 @@
github: inorichi
ko_fi: inorichi

View file

@ -3,7 +3,7 @@
I acknowledge that:
- I have updated:
- To the latest version of the app (stable is v0.10.10)
- To the latest version of the app (stable is v0.10.11)
- 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

View file

@ -10,7 +10,7 @@ labels: "bug"
I acknowledge that:
- I have updated:
- To the latest version of the app (stable is v0.10.10)
- To the latest version of the app (stable is v0.10.11)
- 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

View file

@ -10,7 +10,7 @@ labels: "feature"
I acknowledge that:
- I have updated:
- To the latest version of the app (stable is v0.10.10)
- To the latest version of the app (stable is v0.10.11)
- 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

View file

@ -1,31 +0,0 @@
### r2903
- The MyAnimeList tracker was rewritten. You will need to log out and log in again.
### r1810
- Background jobs were migrated to a new system. You may need to toggle the settings to ensure they
run properly. This includes app updates, library updates, and automatic backups.
### r1340
- A new screen for managing extensions was added. If you previously installed extensions from FDroid,
you will have to uninstall all of them first (tap on the extension then uninstall), otherwise you won't be able
to update them due to signature mismatch. You won't lose anything in this process as the extensions themselves
don't store anything.
### r959
- The download manager has been rewritten and it's possible some of your downloads
aren't recognized anymore. You may have to check your downloads folder and manually delete those.
- You can now download to any folder in your SD card.
- The download directory setting has been reset.
### r857
- **Important!** Delete after read has been updated.
This means the value has been reset set to disabled.
This can be changed in Settings > Downloads
### r736
- **Important!** Now chapters follow the order of the sources. **It's required that you update your entire library
before reading in order for them to be synced.** Old behavior can be restored for a manga in the overflow menu of the chapters tab.
### r724
- Kissmanga covers may not load anymore. The only workaround is to update the details of the manga
from the info tab, or clearing the database (the latter won't fix covers from library manga).

View file

@ -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()}\"")
@ -265,7 +265,7 @@ dependencies {
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 {

View file

@ -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" />

View file

@ -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}"
}

View file

@ -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)
}
}

View file

@ -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()
private 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)
}
}

View file

@ -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) {}

View file

@ -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)

View file

@ -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()

View file

@ -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

View file

@ -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 {

View file

@ -3,7 +3,6 @@ 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
@ -45,18 +44,16 @@ class MigrationMangaController :
return MigrationMangaPresenter(sourceId)
}
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
binding = MigrationMangaControllerBinding.inflate(inflater)
override fun createBinding(inflater: LayoutInflater) = MigrationMangaControllerBinding.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 = MigrationMangaAdapter(this)
binding.recycler.layoutManager = LinearLayoutManager(view.context)

View file

@ -104,23 +104,22 @@ class SearchPresenter(
val prevMangaChapters = db.getChapters(prevManga).executeAsBlocking()
val maxChapterRead = prevMangaChapters
.filter { it.read }
.maxOfOrNull { it.chapter_number }
if (maxChapterRead != null) {
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
} else if (chapter.chapter_number <= maxChapterRead) {
chapter.read = 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

View file

@ -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)

View file

@ -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)

View file

@ -0,0 +1,30 @@
package eu.kanade.tachiyomi.ui.browse.source.browse
import com.jakewharton.rxrelay.PublishRelay
import eu.kanade.tachiyomi.source.model.AnimesPage
import eu.kanade.tachiyomi.source.model.SAnime
import rx.Observable
/**
* A general pager for source requests (latest updates, popular, search)
*/
abstract class AnimePager(var currentPage: Int = 1) {
var hasNextPage = true
private set
protected val results: PublishRelay<Pair<Int, List<SAnime>>> = PublishRelay.create()
fun results(): Observable<Pair<Int, List<SAnime>>> {
return results.asObservable()
}
abstract fun requestNext(): Observable<AnimesPage>
fun onPageReceived(animesPage: AnimesPage) {
val page = currentPage
currentPage++
hasNextPage = animesPage.hasNextPage && animesPage.animes.isNotEmpty()
results.call(Pair(page, animesPage.animes))
}
}

View file

@ -0,0 +1,32 @@
package eu.kanade.tachiyomi.ui.browse.source.browse
import eu.kanade.tachiyomi.source.AnimeCatalogueSource
import eu.kanade.tachiyomi.source.model.AnimesPage
import eu.kanade.tachiyomi.source.model.FilterList
import rx.Observable
import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers
open class AnimeSourcePager(val source: AnimeCatalogueSource, val query: String, val filters: FilterList) : AnimePager() {
override fun requestNext(): Observable<AnimesPage> {
val page = currentPage
val observable = if (query.isBlank() && filters.isEmpty()) {
source.fetchPopularAnime(page)
} else {
source.fetchSearchAnime(page, query, filters)
}
return observable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnNext {
if (it.animes.isNotEmpty()) {
onPageReceived(it)
} else {
throw NoResultsException()
}
}
}
}

View file

@ -0,0 +1,620 @@
package eu.kanade.tachiyomi.ui.browse.source.browse
import android.content.res.Configuration
import android.os.Bundle
import android.view.LayoutInflater
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.core.view.updatePadding
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.list.listItems
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
import com.google.android.material.snackbar.Snackbar
import com.tfcporciuncula.flow.Preference
import dev.chrisbanes.insetter.applyInsetter
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.items.IFlexible
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Anime
import eu.kanade.tachiyomi.data.database.models.Category
import eu.kanade.tachiyomi.data.preference.PreferenceValues.DisplayMode
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.asImmediateFlow
import eu.kanade.tachiyomi.databinding.AnimeSourceControllerBinding
import eu.kanade.tachiyomi.source.AnimeCatalogueSource
import eu.kanade.tachiyomi.source.LocalAnimeSource
import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.online.AnimeHttpSource
import eu.kanade.tachiyomi.ui.anime.AnimeController
import eu.kanade.tachiyomi.ui.animelib.ChangeAnimeCategoriesDialog
import eu.kanade.tachiyomi.ui.base.controller.FabController
import eu.kanade.tachiyomi.ui.base.controller.SearchableNucleusController
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchController
import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.ui.more.MoreController
import eu.kanade.tachiyomi.ui.webview.WebViewActivity
import eu.kanade.tachiyomi.util.system.connectivityManager
import eu.kanade.tachiyomi.util.system.openInBrowser
import eu.kanade.tachiyomi.util.system.toast
import eu.kanade.tachiyomi.util.view.inflate
import eu.kanade.tachiyomi.util.view.shrinkOnScroll
import eu.kanade.tachiyomi.util.view.snack
import eu.kanade.tachiyomi.widget.AutofitRecyclerView
import eu.kanade.tachiyomi.widget.EmptyView
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import timber.log.Timber
import uy.kohesive.injekt.injectLazy
/**
* Controller to manage the catalogues available in the app.
*/
open class BrowseAnimeSourceController(bundle: Bundle) :
SearchableNucleusController<AnimeSourceControllerBinding, BrowseAnimeSourcePresenter>(bundle),
FabController,
FlexibleAdapter.OnItemClickListener,
FlexibleAdapter.OnItemLongClickListener,
FlexibleAdapter.EndlessScrollListener,
ChangeAnimeCategoriesDialog.Listener {
constructor(source: AnimeCatalogueSource, searchQuery: String? = null) : this(
Bundle().apply {
putLong(SOURCE_ID_KEY, source.id)
if (searchQuery != null) {
putString(SEARCH_QUERY_KEY, searchQuery)
}
}
)
private val preferences: PreferencesHelper by injectLazy()
/**
* Adapter containing the list of anime from the catalogue.
*/
protected var adapter: FlexibleAdapter<IFlexible<*>>? = null
private var actionFab: ExtendedFloatingActionButton? = null
private var actionFabScrollListener: RecyclerView.OnScrollListener? = null
/**
* Snackbar containing an error message when a request fails.
*/
private var snack: Snackbar? = null
/**
* Sheet containing filter items.
*/
private var filterSheet: SourceFilterSheet? = null
/**
* Recycler view with the list of results.
*/
private var recycler: RecyclerView? = null
/**
* Subscription for the number of anime per row.
*/
private var numColumnsJob: Job? = null
/**
* Endless loading item.
*/
private var progressItem: ProgressItem? = null
init {
setHasOptionsMenu(true)
}
override fun getTitle(): String? {
return presenter.source.name
}
override fun createPresenter(): BrowseAnimeSourcePresenter {
return BrowseAnimeSourcePresenter(args.getLong(SOURCE_ID_KEY), args.getString(SEARCH_QUERY_KEY))
}
override fun createBinding(inflater: LayoutInflater) = AnimeSourceControllerBinding.inflate(inflater)
override fun onViewCreated(view: View) {
super.onViewCreated(view)
// Prepare filter sheet
initFilterSheet()
// Initialize adapter, scroll listener and recycler views
adapter = FlexibleAdapter(null, this)
setupRecycler(view)
binding.progress.isVisible = true
}
open fun initFilterSheet() {
if (presenter.sourceFilters.isEmpty()) {
return
}
filterSheet = SourceFilterSheet(
activity!!,
onFilterClicked = {
val allDefault = presenter.sourceFilters == presenter.source.getFilterList()
showProgressBar()
adapter?.clear()
presenter.setSourceFilter(if (allDefault) FilterList() else presenter.sourceFilters)
},
onResetClicked = {
presenter.appliedFilters = FilterList()
val newFilters = presenter.source.getFilterList()
presenter.sourceFilters = newFilters
filterSheet?.setFilters(presenter.filterItems)
}
)
filterSheet?.setFilters(presenter.filterItems)
// TODO: [ExtendedFloatingActionButton] hide/show methods don't work properly
filterSheet?.setOnShowListener { actionFab?.isVisible = false }
filterSheet?.setOnDismissListener { actionFab?.isVisible = true }
actionFab?.setOnClickListener { filterSheet?.show() }
actionFab?.isVisible = true
}
override fun configureFab(fab: ExtendedFloatingActionButton) {
actionFab = fab
// Controlled by initFilterSheet()
fab.isVisible = false
fab.setText(R.string.action_filter)
fab.setIconResource(R.drawable.ic_filter_list_24dp)
}
override fun cleanupFab(fab: ExtendedFloatingActionButton) {
fab.setOnClickListener(null)
actionFabScrollListener?.let { recycler?.removeOnScrollListener(it) }
actionFab = null
}
override fun onDestroyView(view: View) {
numColumnsJob?.cancel()
numColumnsJob = null
adapter = null
snack = null
recycler = null
super.onDestroyView(view)
}
private fun setupRecycler(view: View) {
numColumnsJob?.cancel()
var oldPosition = RecyclerView.NO_POSITION
val oldRecycler = binding.catalogueView.getChildAt(1)
if (oldRecycler is RecyclerView) {
oldPosition = (oldRecycler.layoutManager as LinearLayoutManager).findFirstVisibleItemPosition()
oldRecycler.adapter = null
binding.catalogueView.removeView(oldRecycler)
}
val recycler = if (preferences.sourceDisplayMode().get() == DisplayMode.LIST) {
RecyclerView(view.context).apply {
id = R.id.recycler
layoutManager = LinearLayoutManager(context)
layoutParams = RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
}
} else {
(binding.catalogueView.inflate(R.layout.source_recycler_autofit) as AutofitRecyclerView).apply {
numColumnsJob = getColumnsPreferenceForCurrentOrientation().asImmediateFlow { spanCount = it }
.drop(1)
// Set again the adapter to recalculate the covers height
.onEach { adapter = this@BrowseAnimeSourceController.adapter }
.launchIn(viewScope)
(layoutManager as GridLayoutManager).spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
override fun getSpanSize(position: Int): Int {
return when (adapter?.getItemViewType(position)) {
R.layout.source_compact_grid_item, R.layout.source_comfortable_grid_item, null -> 1
else -> spanCount
}
}
}
}
}
if (filterSheet != null) {
// Add bottom padding if filter FAB is visible
recycler.updatePadding(bottom = view.resources.getDimensionPixelOffset(R.dimen.fab_list_padding))
recycler.clipToPadding = false
actionFab?.shrinkOnScroll(recycler)
}
recycler.applyInsetter {
type(navigationBars = true) {
padding()
}
}
recycler.setHasFixedSize(true)
recycler.adapter = adapter
binding.catalogueView.addView(recycler, 1)
if (oldPosition != RecyclerView.NO_POSITION) {
recycler.layoutManager?.scrollToPosition(oldPosition)
}
this.recycler = recycler
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
createOptionsMenu(menu, inflater, R.menu.source_browse, R.id.action_search)
val searchItem = menu.findItem(R.id.action_search)
searchItem.fixExpand(
onExpand = { invalidateMenuOnExpand() },
onCollapse = {
if (router.backstackSize >= 2 && router.backstack[router.backstackSize - 2].controller() is GlobalSearchController) {
router.popController(this)
} else {
nonSubmittedQuery = ""
searchWithQuery("")
}
true
}
)
val displayItem = when (preferences.sourceDisplayMode().get()) {
DisplayMode.COMPACT_GRID -> R.id.action_compact_grid
DisplayMode.COMFORTABLE_GRID -> R.id.action_comfortable_grid
DisplayMode.LIST -> R.id.action_list
}
menu.findItem(displayItem).isChecked = true
}
override fun onSearchViewQueryTextSubmit(query: String?) {
searchWithQuery(query ?: "")
}
override fun onPrepareOptionsMenu(menu: Menu) {
super.onPrepareOptionsMenu(menu)
val isHttpSource = presenter.source is AnimeHttpSource
menu.findItem(R.id.action_open_in_web_view).isVisible = isHttpSource
val isLocalSource = presenter.source is LocalAnimeSource
menu.findItem(R.id.action_local_source_help).isVisible = isLocalSource
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_search -> expandActionViewFromInteraction = true
R.id.action_compact_grid -> setDisplayMode(DisplayMode.COMPACT_GRID)
R.id.action_comfortable_grid -> setDisplayMode(DisplayMode.COMFORTABLE_GRID)
R.id.action_list -> setDisplayMode(DisplayMode.LIST)
R.id.action_open_in_web_view -> openInWebView()
R.id.action_local_source_help -> openLocalSourceHelpGuide()
}
return super.onOptionsItemSelected(item)
}
private fun openInWebView() {
val source = presenter.source as? AnimeHttpSource ?: return
val activity = activity ?: return
val intent = WebViewActivity.newIntent(activity, source.baseUrl, source.id, presenter.source.name)
startActivity(intent)
}
private fun openLocalSourceHelpGuide() {
activity?.openInBrowser(LocalAnimeSource.HELP_URL)
}
/**
* Restarts the request with a new query.
*
* @param newQuery the new query.
*/
fun searchWithQuery(newQuery: String) {
// If text didn't change, do nothing
if (presenter.query == newQuery) {
return
}
showProgressBar()
adapter?.clear()
presenter.restartPager(newQuery)
}
/**
* Called from the presenter when the network request is received.
*
* @param page the current page.
* @param animes the list of anime of the page.
*/
fun onAddPage(page: Int, animes: List<AnimeSourceItem>) {
val adapter = adapter ?: return
hideProgressBar()
if (page == 1) {
adapter.clear()
resetProgressItem()
}
adapter.onLoadMoreComplete(animes)
}
/**
* Called from the presenter when the network request fails.
*
* @param error the error received.
*/
fun onAddPageError(error: Throwable) {
Timber.e(error)
val adapter = adapter ?: return
adapter.onLoadMoreComplete(null)
hideProgressBar()
snack?.dismiss()
val message = getErrorMessage(error)
val retryAction = View.OnClickListener {
// If not the first page, show bottom progress bar.
if (adapter.mainItemCount > 0 && progressItem != null) {
adapter.addScrollableFooterWithDelay(progressItem!!, 0, true)
} else {
showProgressBar()
}
presenter.requestNext()
}
if (adapter.isEmpty) {
val actions = if (presenter.source is LocalAnimeSource) {
listOf(
EmptyView.Action(R.string.local_source_help_guide, R.drawable.ic_help_24dp) { openLocalSourceHelpGuide() }
)
} else {
listOf(
EmptyView.Action(R.string.action_retry, R.drawable.ic_refresh_24dp, retryAction),
EmptyView.Action(R.string.action_open_in_web_view, R.drawable.ic_public_24dp) { openInWebView() },
EmptyView.Action(R.string.label_help, R.drawable.ic_help_24dp) { activity?.openInBrowser(MoreController.URL_HELP) }
)
}
binding.emptyView.show(message, actions)
} else {
snack = (activity as? MainActivity)?.binding?.rootCoordinator?.snack(message, Snackbar.LENGTH_INDEFINITE) {
setAction(R.string.action_retry, retryAction)
}
}
}
private fun getErrorMessage(error: Throwable): String {
if (error is NoResultsException) {
return binding.catalogueView.context.getString(R.string.no_results_found)
}
return when {
error.message == null -> ""
error.message!!.startsWith("HTTP error") -> "${error.message}: ${binding.catalogueView.context.getString(R.string.http_error_hint)}"
else -> error.message!!
}
}
/**
* Sets a new progress item and reenables the scroll listener.
*/
private fun resetProgressItem() {
progressItem = ProgressItem()
adapter?.endlessTargetCount = 0
adapter?.setEndlessScrollListener(this, progressItem!!)
}
/**
* Called by the adapter when scrolled near the bottom.
*/
override fun onLoadMore(lastPosition: Int, currentPage: Int) {
if (presenter.hasNextPage()) {
presenter.requestNext()
} else {
adapter?.onLoadMoreComplete(null)
adapter?.endlessTargetCount = 1
}
}
override fun noMoreLoad(newItemsSize: Int) {
}
/**
* Called from the presenter when a anime is initialized.
*
* @param anime the anime initialized
*/
fun onAnimeInitialized(anime: Anime) {
getHolder(anime)?.setImage(anime)
}
/**
* Sets the current display mode.
*
* @param mode the mode to change to
*/
private fun setDisplayMode(mode: DisplayMode) {
val view = view ?: return
val adapter = adapter ?: return
preferences.sourceDisplayMode().set(mode)
activity?.invalidateOptionsMenu()
setupRecycler(view)
// Initialize animes if not on a metered connection
if (!view.context.connectivityManager.isActiveNetworkMetered) {
val animes = (0 until adapter.itemCount).mapNotNull {
(adapter.getItem(it) as? AnimeSourceItem)?.anime
}
presenter.initializeAnimes(animes)
}
}
/**
* Returns a preference for the number of anime per row based on the current orientation.
*
* @return the preference.
*/
private fun getColumnsPreferenceForCurrentOrientation(): Preference<Int> {
return if (resources?.configuration?.orientation == Configuration.ORIENTATION_PORTRAIT) {
preferences.portraitColumns()
} else {
preferences.landscapeColumns()
}
}
/**
* Returns the view holder for the given anime.
*
* @param anime the anime to find.
* @return the holder of the anime or null if it's not bound.
*/
private fun getHolder(anime: Anime): AnimeSourceHolder<*>? {
val adapter = adapter ?: return null
adapter.allBoundViewHolders.forEach { holder ->
val item = adapter.getItem(holder.bindingAdapterPosition) as? AnimeSourceItem
if (item != null && item.anime.id!! == anime.id!!) {
return holder as AnimeSourceHolder<*>
}
}
return null
}
/**
* Shows the progress bar.
*/
private fun showProgressBar() {
binding.emptyView.hide()
binding.progress.isVisible = true
snack?.dismiss()
snack = null
}
/**
* Hides active progress bars.
*/
private fun hideProgressBar() {
binding.emptyView.hide()
binding.progress.isVisible = false
}
/**
* Called when a anime is clicked.
*
* @param position the position of the element clicked.
* @return true if the item should be selected, false otherwise.
*/
override fun onItemClick(view: View, position: Int): Boolean {
val item = adapter?.getItem(position) as? AnimeSourceItem ?: return false
router.pushController(AnimeController(item.anime, true).withFadeTransaction())
return false
}
/**
* Called when a anime is long clicked.
*
* Adds the anime to the default category if none is set it shows a list of categories for the user to put the anime
* in, the list consists of the default category plus the user's categories. The default category is preselected on
* new anime, and on already favorited anime the anime's categories are preselected.
*
* @param position the position of the element clicked.
*/
override fun onItemLongClick(position: Int) {
val activity = activity ?: return
val anime = (adapter?.getItem(position) as? AnimeSourceItem?)?.anime ?: return
if (anime.favorite) {
MaterialDialog(activity)
.listItems(
items = listOf(activity.getString(R.string.remove_from_library)),
waitForPositiveButton = false
) { _, which, _ ->
when (which) {
0 -> {
presenter.changeAnimeFavorite(anime)
adapter?.notifyItemChanged(position)
activity.toast(activity.getString(R.string.manga_removed_library))
}
}
}
.show()
} else {
val categories = presenter.getCategories()
val defaultCategoryId = preferences.defaultCategory()
val defaultCategory = categories.find { it.id == defaultCategoryId }
when {
// Default category set
defaultCategory != null -> {
presenter.moveAnimeToCategory(anime, defaultCategory)
presenter.changeAnimeFavorite(anime)
adapter?.notifyItemChanged(position)
activity.toast(activity.getString(R.string.manga_added_library))
}
// Automatic 'Default' or no categories
defaultCategoryId == 0 || categories.isEmpty() -> {
presenter.moveAnimeToCategory(anime, null)
presenter.changeAnimeFavorite(anime)
adapter?.notifyItemChanged(position)
activity.toast(activity.getString(R.string.manga_added_library))
}
// Choose a category
else -> {
val ids = presenter.getAnimeCategoryIds(anime)
val preselected = ids.mapNotNull { id ->
categories.indexOfFirst { it.id == id }.takeIf { it != -1 }
}.toTypedArray()
ChangeAnimeCategoriesDialog(this, listOf(anime), categories, preselected)
.showDialog(router)
}
}
}
}
/**
* Update anime to use selected categories.
*
* @param animes The list of anime to move to categories.
* @param categories The list of categories where anime will be placed.
*/
override fun updateCategoriesForAnimes(animes: List<Anime>, categories: List<Category>) {
val anime = animes.firstOrNull() ?: return
presenter.changeAnimeFavorite(anime)
presenter.updateAnimeCategories(anime, categories)
val position = adapter?.currentItems?.indexOfFirst { it -> (it as AnimeSourceItem).anime.id == anime.id }
if (position != null) {
adapter?.notifyItemChanged(position)
}
activity?.toast(activity?.getString(R.string.manga_added_library))
}
protected companion object {
const val SOURCE_ID_KEY = "sourceId"
const val SEARCH_QUERY_KEY = "searchQuery"
}
}

View file

@ -0,0 +1,371 @@
package eu.kanade.tachiyomi.ui.browse.source.browse
import android.os.Bundle
import eu.davidea.flexibleadapter.items.IFlexible
import eu.kanade.tachiyomi.data.cache.AnimeCoverCache
import eu.kanade.tachiyomi.data.database.AnimeDatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Anime
import eu.kanade.tachiyomi.data.database.models.AnimeCategory
import eu.kanade.tachiyomi.data.database.models.Category
import eu.kanade.tachiyomi.data.database.models.toAnimeInfo
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.source.AnimeCatalogueSource
import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.model.Filter
import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.SAnime
import eu.kanade.tachiyomi.source.model.toSAnime
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
import eu.kanade.tachiyomi.ui.browse.source.filter.CheckboxItem
import eu.kanade.tachiyomi.ui.browse.source.filter.CheckboxSectionItem
import eu.kanade.tachiyomi.ui.browse.source.filter.GroupItem
import eu.kanade.tachiyomi.ui.browse.source.filter.HeaderItem
import eu.kanade.tachiyomi.ui.browse.source.filter.SelectItem
import eu.kanade.tachiyomi.ui.browse.source.filter.SelectSectionItem
import eu.kanade.tachiyomi.ui.browse.source.filter.SeparatorItem
import eu.kanade.tachiyomi.ui.browse.source.filter.SortGroup
import eu.kanade.tachiyomi.ui.browse.source.filter.SortItem
import eu.kanade.tachiyomi.ui.browse.source.filter.TextItem
import eu.kanade.tachiyomi.ui.browse.source.filter.TextSectionItem
import eu.kanade.tachiyomi.ui.browse.source.filter.TriStateItem
import eu.kanade.tachiyomi.ui.browse.source.filter.TriStateSectionItem
import eu.kanade.tachiyomi.util.episode.EpisodeSettingsHelper
import eu.kanade.tachiyomi.util.lang.launchIO
import eu.kanade.tachiyomi.util.lang.withUIContext
import eu.kanade.tachiyomi.util.removeCovers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import rx.Observable
import rx.Subscription
import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers
import timber.log.Timber
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.util.Date
/**
* Presenter of [BrowseSourceController].
*/
open class BrowseAnimeSourcePresenter(
private val sourceId: Long,
searchQuery: String? = null,
private val sourceManager: SourceManager = Injekt.get(),
private val db: AnimeDatabaseHelper = Injekt.get(),
private val prefs: PreferencesHelper = Injekt.get(),
private val coverCache: AnimeCoverCache = Injekt.get()
) : BasePresenter<BrowseAnimeSourceController>() {
/**
* Selected source.
*/
lateinit var source: AnimeCatalogueSource
/**
* Modifiable list of filters.
*/
var sourceFilters = FilterList()
set(value) {
field = value
filterItems = value.toItems()
}
var filterItems: List<IFlexible<*>> = emptyList()
/**
* List of filters used by the [Pager]. If empty alongside [query], the popular query is used.
*/
var appliedFilters = FilterList()
/**
* Pager containing a list of anime results.
*/
private lateinit var pager: AnimePager
/**
* Flow of anime list to initialize.
*/
private val animeDetailsFlow = MutableStateFlow<List<Anime>>(emptyList())
/**
* Subscription for the pager.
*/
private var pagerSubscription: Subscription? = null
/**
* Subscription for one request from the pager.
*/
private var pageSubscription: Subscription? = null
init {
query = searchQuery ?: ""
}
override fun onCreate(savedState: Bundle?) {
super.onCreate(savedState)
source = sourceManager.get(sourceId) as? AnimeCatalogueSource ?: return
sourceFilters = source.getFilterList()
if (savedState != null) {
query = savedState.getString(::query.name, "")
}
restartPager()
}
override fun onSave(state: Bundle) {
state.putString(::query.name, query)
super.onSave(state)
}
/**
* Restarts the pager for the active source with the provided query and filters.
*
* @param query the query.
* @param filters the current state of the filters (for search mode).
*/
fun restartPager(query: String = this.query, filters: FilterList = this.appliedFilters) {
this.query = query
this.appliedFilters = filters
// Create a new pager.
pager = createPager(query, filters)
val sourceId = source.id
val sourceDisplayMode = prefs.sourceDisplayMode()
// Prepare the pager.
pagerSubscription?.let { remove(it) }
pagerSubscription = pager.results()
.observeOn(Schedulers.io())
.map { (first, second) -> first to second.map { networkToLocalAnime(it, sourceId) } }
.doOnNext { initializeAnimes(it.second) }
.map { (first, second) -> first to second.map { AnimeSourceItem(it, sourceDisplayMode) } }
.observeOn(AndroidSchedulers.mainThread())
.subscribeReplay(
{ view, (page, animes) ->
view.onAddPage(page, animes)
},
{ _, error ->
Timber.e(error)
}
)
// Request first page.
requestNext()
}
/**
* Requests the next page for the active pager.
*/
fun requestNext() {
if (!hasNextPage()) return
pageSubscription?.let { remove(it) }
pageSubscription = Observable.defer { pager.requestNext() }
.subscribeFirst(
{ _, _ ->
// Nothing to do when onNext is emitted.
},
BrowseAnimeSourceController::onAddPageError
)
}
/**
* Returns true if the last fetched page has a next page.
*/
fun hasNextPage(): Boolean {
return pager.hasNextPage
}
/**
* Returns a anime from the database for the given anime from network. It creates a new entry
* if the anime is not yet in the database.
*
* @param sAnime the anime from the source.
* @return a anime from the database.
*/
private fun networkToLocalAnime(sAnime: SAnime, sourceId: Long): Anime {
var localAnime = db.getAnime(sAnime.url, sourceId).executeAsBlocking()
if (localAnime == null) {
val newAnime = Anime.create(sAnime.url, sAnime.title, sourceId)
newAnime.copyFrom(sAnime)
val result = db.insertAnime(newAnime).executeAsBlocking()
newAnime.id = result.insertedId()
localAnime = newAnime
}
return localAnime
}
/**
* Initialize a list of anime.
*
* @param animes the list of anime to initialize.
*/
fun initializeAnimes(animes: List<Anime>) {
presenterScope.launchIO {
animes.asFlow()
.filter { it.thumbnail_url == null && !it.initialized }
.map { getAnimeDetails(it) }
.onEach {
withUIContext {
@Suppress("DEPRECATION")
view?.onAnimeInitialized(it)
}
}
.catch { e -> Timber.e(e) }
.collect()
}
}
/**
* Returns the initialized anime.
*
* @param anime the anime to initialize.
* @return the initialized anime
*/
private suspend fun getAnimeDetails(anime: Anime): Anime {
try {
val networkAnime = source.getAnimeDetails(anime.toAnimeInfo())
anime.copyFrom(networkAnime.toSAnime())
anime.initialized = true
db.insertAnime(anime).executeAsBlocking()
} catch (e: Exception) {
Timber.e(e)
}
return anime
}
/**
* Adds or removes a anime from the library.
*
* @param anime the anime to update.
*/
fun changeAnimeFavorite(anime: Anime) {
anime.favorite = !anime.favorite
anime.date_added = when (anime.favorite) {
true -> Date().time
false -> 0
}
if (!anime.favorite) {
anime.removeCovers(coverCache)
} else {
EpisodeSettingsHelper.applySettingDefaults(anime)
}
db.insertAnime(anime).executeAsBlocking()
}
/**
* Set the filter states for the current source.
*
* @param filters a list of active filters.
*/
fun setSourceFilter(filters: FilterList) {
restartPager(filters = filters)
}
open fun createPager(query: String, filters: FilterList): AnimePager {
return AnimeSourcePager(source, query, filters)
}
private fun FilterList.toItems(): List<IFlexible<*>> {
return mapNotNull { filter ->
when (filter) {
is Filter.Header -> HeaderItem(filter)
is Filter.Separator -> SeparatorItem(filter)
is Filter.CheckBox -> CheckboxItem(filter)
is Filter.TriState -> TriStateItem(filter)
is Filter.Text -> TextItem(filter)
is Filter.Select<*> -> SelectItem(filter)
is Filter.Group<*> -> {
val group = GroupItem(filter)
val subItems = filter.state.mapNotNull {
when (it) {
is Filter.CheckBox -> CheckboxSectionItem(it)
is Filter.TriState -> TriStateSectionItem(it)
is Filter.Text -> TextSectionItem(it)
is Filter.Select<*> -> SelectSectionItem(it)
else -> null
}
}
subItems.forEach { it.header = group }
group.subItems = subItems
group
}
is Filter.Sort -> {
val group = SortGroup(filter)
val subItems = filter.values.map {
SortItem(it, group)
}
group.subItems = subItems
group
}
}
}
}
/**
* Get user categories.
*
* @return List of categories, not including the default category
*/
fun getCategories(): List<Category> {
return db.getCategories().executeAsBlocking()
}
/**
* Gets the category id's the anime is in, if the anime is not in a category, returns the default id.
*
* @param anime the anime to get categories from.
* @return Array of category ids the anime is in, if none returns default id
*/
fun getAnimeCategoryIds(anime: Anime): Array<Int?> {
val categories = db.getCategoriesForAnime(anime).executeAsBlocking()
return categories.mapNotNull { it.id }.toTypedArray()
}
/**
* Move the given anime to categories.
*
* @param categories the selected categories.
* @param anime the anime to move.
*/
private fun moveAnimeToCategories(anime: Anime, categories: List<Category>) {
val mc = categories.filter { it.id != 0 }.map { AnimeCategory.create(anime, it) }
db.setAnimeCategories(mc, listOf(anime))
}
/**
* Move the given anime to the category.
*
* @param category the selected category.
* @param anime the anime to move.
*/
fun moveAnimeToCategory(anime: Anime, category: Category?) {
moveAnimeToCategories(anime, listOfNotNull(category))
}
/**
* Update anime to use selected categories.
*
* @param anime needed to change
* @param selectedCategories selected categories
*/
fun updateAnimeCategories(anime: Anime, selectedCategories: List<Category>) {
if (!anime.favorite) {
changeAnimeFavorite(anime)
}
moveAnimeToCategories(anime, selectedCategories)
}
}

View file

@ -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("")
}

View file

@ -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.

View file

@ -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)

View file

@ -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()

View file

@ -131,6 +131,15 @@ class MainActivity : BaseViewBindingActivity<MainActivityBinding>() {
tabAnimator = ViewHeightAnimator(binding.tabs, 0L)
bottomNavAnimator = ViewHeightAnimator(binding.bottomNav)
// If bottom nav is hidden, make it visible again when the app bar is expanded
binding.appbar.addOnOffsetChangedListener(
AppBarLayout.OnOffsetChangedListener { _, verticalOffset ->
if (verticalOffset == 0) {
showBottomNav(true)
}
}
)
// Set behavior of bottom nav
preferences.hideBottomBar()
.asImmediateFlow { setBottomNavBehaviorOnScroll() }

View file

@ -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,8 +198,11 @@ 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()
@ -211,11 +213,6 @@ class MangaController :
margin(bottom = true)
}
}
return binding.root
}
override fun onViewCreated(view: View) {
super.onViewCreated(view)
if (manga == null || source == null) return
@ -1007,11 +1004,17 @@ 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 }
.reversed()
private fun getUnreadChaptersSorted(): List<ChapterItem> {
val chapters = presenter.chapters
.sortedWith(presenter.getChapterSort())
.filter { !it.read && it.status == Download.State.NOT_DOWNLOADED }
.distinctBy { it.name }
return if (presenter.sortDescending()) {
chapters.reversed()
} else {
chapters
}
}
private fun downloadChapters(choice: Int) {
val chaptersToDownload = when (choice) {

View file

@ -474,7 +474,12 @@ class MangaPresenter(
* Returns the next unread chapter or null if everything is read.
*/
fun getNextUnreadChapter(): ChapterItem? {
return chapters.sortedWith(getChapterSort()).findLast { !it.read }
val chapters = chapters.sortedWith(getChapterSort())
return if (sortDescending()) {
return chapters.findLast { !it.read }
} else {
chapters.find { !it.read }
}
}
/**

View file

@ -78,15 +78,6 @@ class AboutController : SettingsController() {
openInBrowser(url)
}
}
if (BuildConfig.DEBUG) {
preference {
key = "pref_about_notices"
titleRes = R.string.notices
onClick {
openInBrowser("https://github.com/tachiyomiorg/tachiyomi/blob/master/PREVIEW_RELEASE_NOTES.md")
}
}
}
preferenceCategory {
preference {
@ -97,6 +88,14 @@ class AboutController : SettingsController() {
onClick { openInBrowser(it) }
}
}
preference {
key = "pref_about_facebook"
title = "Facebook"
"https://facebook.com/tachiyomiorg".also {
summary = it
onClick { openInBrowser(it) }
}
}
preference {
key = "pref_about_twitter"
title = "Twitter"
@ -116,15 +115,7 @@ class AboutController : SettingsController() {
preference {
key = "pref_about_github"
title = "GitHub"
"https://github.com/tachiyomiorg/tachiyomi".also {
summary = it
onClick { openInBrowser(it) }
}
}
preference {
key = "pref_about_label_extensions"
titleRes = R.string.label_extensions
"https://github.com/tachiyomiorg/tachiyomi-extensions".also {
"https://github.com/tachiyomiorg".also {
summary = it
onClick { openInBrowser(it) }
}

View file

@ -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 ->

View file

@ -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
@ -72,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)

View file

@ -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
@ -69,8 +68,10 @@ 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()
@ -81,11 +82,7 @@ class UpdatesController :
margin(bottom = true)
}
}
return binding.root
}
override fun onViewCreated(view: View) {
super.onViewCreated(view)
view.context.notificationManager.cancel(Notifications.ID_NEW_CHAPTERS)
// Init RecyclerView and adapter

View file

@ -1,22 +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 timber.log.Timber
import uy.kohesive.injekt.injectLazy
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?) {

View file

@ -20,6 +20,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
@ -31,9 +33,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
@ -171,27 +170,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() {

View file

@ -32,6 +32,7 @@ abstract class SettingsController : PreferenceController() {
var preferenceKey: String? = null
val preferences: PreferencesHelper = Injekt.get()
val viewScope = MainScope()
private var themedContext: Context? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup, savedInstanceState: Bundle?): View {
val view = super.onCreateView(inflater, container, savedInstanceState)
@ -76,20 +77,23 @@ abstract class SettingsController : PreferenceController() {
super.onChangeStarted(handler, type)
}
override fun onDestroyView(view: View) {
super.onDestroyView(view)
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))

View file

@ -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

View file

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/catalogue_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".ui.browse.source.browse.BrowseSourceController">
<FrameLayout
android:id="@+id/progress"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
tools:visibility="visible">
<com.google.android.material.progressindicator.CircularProgressIndicator
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminate="true" />
</FrameLayout>
</LinearLayout>
<eu.kanade.tachiyomi.widget.EmptyView
android:id="@+id/empty_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:visibility="gone" />
</FrameLayout>

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<eu.kanade.tachiyomi.widget.AutofitRecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/animelib_grid"
style="@style/Theme.Widget.GridView.Source"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:columnWidth="140dp"
android:paddingStart="5dp"
android:paddingTop="5dp"
android:paddingEnd="5dp"
android:paddingBottom="@dimen/action_toolbar_list_padding"
tools:listitem="@layout/source_compact_grid_item" />

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/animelib_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingBottom="@dimen/action_toolbar_list_padding"
tools:listitem="@layout/source_list_item" />

View file

@ -0,0 +1,249 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView 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="wrap_content"
android:padding="16dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- Color filter -->
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/switch_color_filter"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/pref_custom_color_filter"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<!-- Red filter -->
<SeekBar
android:id="@+id/seekbar_color_filter_red"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:max="255"
android:padding="@dimen/material_component_text_fields_floating_label_padding_between_label_and_input_text"
app:layout_constraintEnd_toStartOf="@id/txt_color_filter_red_value"
app:layout_constraintStart_toEndOf="@id/color_filter_symbols_barrier"
app:layout_constraintTop_toBottomOf="@id/switch_color_filter" />
<TextView
android:id="@+id/txt_color_filter_red_symbol"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/color_filter_r_value"
android:textAppearance="@style/TextAppearance.Medium.SubHeading"
app:layout_constraintBottom_toBottomOf="@id/seekbar_color_filter_red"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/seekbar_color_filter_red" />
<TextView
android:id="@+id/txt_color_filter_red_value"
android:layout_width="30dp"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:textAppearance="@style/TextAppearance.Medium.SubHeading"
app:layout_constraintBottom_toBottomOf="@id/seekbar_color_filter_red"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/seekbar_color_filter_red" />
<!-- Green filter -->
<SeekBar
android:id="@+id/seekbar_color_filter_green"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:max="255"
android:padding="@dimen/material_component_text_fields_floating_label_padding_between_label_and_input_text"
app:layout_constraintEnd_toStartOf="@id/txt_color_filter_green_value"
app:layout_constraintStart_toEndOf="@id/color_filter_symbols_barrier"
app:layout_constraintTop_toBottomOf="@id/seekbar_color_filter_red" />
<TextView
android:id="@+id/txt_color_filter_green_symbol"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/color_filter_g_value"
android:textAppearance="@style/TextAppearance.Medium.SubHeading"
app:layout_constraintBottom_toBottomOf="@id/seekbar_color_filter_green"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/seekbar_color_filter_green" />
<TextView
android:id="@+id/txt_color_filter_green_value"
android:layout_width="30dp"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:textAppearance="@style/TextAppearance.Medium.SubHeading"
app:layout_constraintBottom_toBottomOf="@id/seekbar_color_filter_green"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/seekbar_color_filter_green" />
<!-- Blue filter -->
<SeekBar
android:id="@+id/seekbar_color_filter_blue"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:max="255"
android:padding="@dimen/material_component_text_fields_floating_label_padding_between_label_and_input_text"
app:layout_constraintEnd_toStartOf="@id/txt_color_filter_blue_value"
app:layout_constraintStart_toEndOf="@id/color_filter_symbols_barrier"
app:layout_constraintTop_toBottomOf="@id/seekbar_color_filter_green" />
<TextView
android:id="@+id/txt_color_filter_blue_symbol"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/color_filter_b_value"
android:textAppearance="@style/TextAppearance.Medium.SubHeading"
app:layout_constraintBottom_toBottomOf="@id/seekbar_color_filter_blue"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/seekbar_color_filter_blue" />
<TextView
android:id="@+id/txt_color_filter_blue_value"
android:layout_width="30dp"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:textAppearance="@style/TextAppearance.Medium.SubHeading"
app:layout_constraintBottom_toBottomOf="@id/seekbar_color_filter_blue"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/seekbar_color_filter_blue" />
<!-- Alpha filter -->
<SeekBar
android:id="@+id/seekbar_color_filter_alpha"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:max="255"
android:padding="@dimen/material_component_text_fields_floating_label_padding_between_label_and_input_text"
app:layout_constraintEnd_toStartOf="@id/txt_color_filter_alpha_value"
app:layout_constraintStart_toEndOf="@id/color_filter_symbols_barrier"
app:layout_constraintTop_toBottomOf="@id/seekbar_color_filter_blue" />
<TextView
android:id="@+id/txt_color_filter_alpha_symbol"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/color_filter_a_value"
android:textAppearance="@style/TextAppearance.Medium.SubHeading"
app:layout_constraintBottom_toBottomOf="@id/seekbar_color_filter_alpha"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/seekbar_color_filter_alpha" />
<TextView
android:id="@+id/txt_color_filter_alpha_value"
android:layout_width="30dp"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:textAppearance="@style/TextAppearance.Medium.SubHeading"
app:layout_constraintBottom_toBottomOf="@id/seekbar_color_filter_alpha"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/seekbar_color_filter_alpha" />
<!-- Filter mode -->
<TextView
android:id="@+id/color_filter_mode_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/pref_color_filter_mode"
app:layout_constraintBaseline_toBaselineOf="@id/color_filter_mode"
app:layout_constraintEnd_toStartOf="@id/color_filter_mode"
app:layout_constraintStart_toStartOf="parent" />
<androidx.appcompat.widget.AppCompatSpinner
android:id="@+id/color_filter_mode"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:entries="@array/color_filter_modes"
app:layout_constraintEnd_toStartOf="@id/spinner_end"
app:layout_constraintStart_toEndOf="@id/verticalcenter"
app:layout_constraintTop_toBottomOf="@id/seekbar_color_filter_alpha" />
<!-- Brightness -->
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/custom_brightness"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/pref_custom_brightness"
app:layout_constraintTop_toBottomOf="@id/color_filter_mode_text" />
<!-- Brightness value -->
<eu.kanade.tachiyomi.widget.NegativeSeekBar
android:id="@+id/brightness_seekbar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:padding="@dimen/material_component_text_fields_floating_label_padding_between_label_and_input_text"
app:layout_constraintEnd_toStartOf="@id/txt_brightness_seekbar_value"
app:layout_constraintStart_toEndOf="@id/txt_brightness_seekbar_icon"
app:layout_constraintTop_toBottomOf="@id/custom_brightness"
app:max_seek="100"
app:min_seek="-75" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/txt_brightness_seekbar_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.Medium.SubHeading"
android:tint="?attr/colorOnBackground"
app:layout_constraintBottom_toBottomOf="@id/brightness_seekbar"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/brightness_seekbar"
app:srcCompat="@drawable/ic_brightness_5_24dp" />
<TextView
android:id="@+id/txt_brightness_seekbar_value"
android:layout_width="30dp"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.Medium.SubHeading"
app:layout_constraintBottom_toBottomOf="@id/brightness_seekbar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/brightness_seekbar" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/color_filter_symbols_barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="end"
app:constraint_referenced_ids="txt_color_filter_alpha_symbol,txt_color_filter_blue_symbol,txt_color_filter_red_symbol,txt_color_filter_green_symbol" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/verticalcenter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
<android.widget.Space
android:id="@+id/spinner_end"
android:layout_width="16dp"
android:layout_height="0dp"
app:layout_constraintStart_toEndOf="parent"
tools:ignore="MissingConstraints" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>

View file

@ -0,0 +1,94 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView 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="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<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.widget.MaterialSpinnerView
android:id="@+id/background_color"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:entries="@array/reader_themes"
app:title="@string/pref_reader_theme" />
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/show_page_number"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:textColor="?android:attr/textColorSecondary"
android:text="@string/pref_show_page_number" />
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/fullscreen"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:textColor="?android:attr/textColorSecondary"
android:text="@string/pref_fullscreen" />
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/cutout_short"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:textColor="?android:attr/textColorSecondary"
android:text="@string/pref_cutout_short"
android:visibility="gone"
tools:visibility="visible" />
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/keepscreen"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:textColor="?android:attr/textColorSecondary"
android:text="@string/pref_keep_screen_on" />
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/long_tap"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:textColor="?android:attr/textColorSecondary"
android:text="@string/pref_read_with_long_tap" />
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/always_show_episode_transition"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:textColor="?android:attr/textColorSecondary"
android:text="@string/pref_always_show_chapter_transition" />
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/page_transitions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:textColor="?android:attr/textColorSecondary"
android:text="@string/pref_page_transitions" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>

View file

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView 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="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<eu.kanade.tachiyomi.widget.MaterialSpinnerView
android:id="@+id/viewer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="24dp"
android:entries="@array/viewers_selector"
app:title="@string/pref_category_for_this_series" />
<!-- Pager preferences -->
<include
android:id="@+id/pager_prefs_group"
layout="@layout/reader_pager_settings"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
tools:visibility="visible" />
<!-- Webtoon preferences -->
<include
android:id="@+id/webtoon_prefs_group"
layout="@layout/reader_webtoon_settings"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>

View file

@ -0,0 +1,49 @@
<?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="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/upper_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:textSize="17.5sp"
tools:text="Top" />
<LinearLayout
android:id="@+id/warning"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:gravity="center_vertical">
<ImageView
android:layout_width="18dp"
android:layout_height="18dp"
android:layout_marginEnd="8dp"
android:scaleType="fitCenter"
app:srcCompat="@drawable/ic_warning_white_24dp"
app:tint="?attr/colorOnBackground"
tools:ignore="ContentDescription" />
<TextView
android:id="@+id/warning_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="Warning" />
</LinearLayout>
<TextView
android:id="@+id/lower_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="17.5sp"
tools:text="Bottom" />
</LinearLayout>

View file

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_move_to_category"
android:icon="@drawable/ic_label_24dp"
android:title="@string/action_move_category"
app:iconTint="?attr/colorOnPrimary"
app:showAsAction="always" />
<item
android:id="@+id/action_download_unread"
android:icon="@drawable/ic_get_app_24dp"
android:title="@string/action_download_unread"
app:iconTint="?attr/colorOnPrimary"
app:showAsAction="always" />
<item
android:id="@+id/action_mark_as_read"
android:icon="@drawable/ic_done_24dp"
android:title="@string/action_mark_as_read"
app:iconTint="?attr/colorOnPrimary"
app:showAsAction="always" />
<item
android:id="@+id/action_mark_as_unread"
android:icon="@drawable/ic_done_outline_24dp"
android:title="@string/action_mark_as_unread"
app:iconTint="?attr/colorOnPrimary"
app:showAsAction="always" />
<item
android:id="@+id/action_delete"
android:icon="@drawable/ic_delete_24dp"
android:title="@string/action_delete"
app:iconTint="?attr/colorOnPrimary"
app:showAsAction="always" />
</menu>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -83,7 +83,7 @@
<string name="pref_library_columns">Elemente pe rând</string>
<string name="portrait">Portret</string>
<string name="default_columns">Prestabilit</string>
<string name="pref_library_update_interval">Frecvența actualizării bibliotecii</string>
<string name="pref_library_update_interval">Frecvență de actualizare</string>
<string name="update_never">Manual</string>
<string name="update_1hour">La fiecare oră</string>
<string name="update_2hour">La fiecare 2 ore</string>
@ -94,7 +94,7 @@
<string name="update_48hour">La fiecare 2 zile</string>
<string name="update_weekly">Săptămânal</string>
<string name="all">Toate</string>
<string name="pref_library_update_restriction">Restricții actualizare bibliotecă</string>
<string name="pref_library_update_restriction">Restricții de actualizare</string>
<string name="pref_library_update_restriction_summary">Actualizează doar când condițiile sunt împlinite</string>
<string name="charging">Se încarcă</string>
<string name="pref_update_only_non_completed">Actualizați doar manga în desfășurare</string>
@ -108,7 +108,7 @@
<string name="ext_update">Actualizează</string>
<string name="ext_install">Instalează</string>
<string name="ext_pending">În așteptare</string>
<string name="ext_downloading">În curs de descărcare</string>
<string name="ext_downloading">Se descarcă</string>
<string name="ext_installing">În curs de instalare</string>
<string name="ext_installed">Instalată</string>
<string name="ext_trust">Ai încredere</string>
@ -275,7 +275,7 @@
<string name="sort_by_number">După numărul capitolului</string>
<string name="manga_download">Descarcă</string>
<string name="custom_download">Descarcă cantitate personalizată</string>
<string name="download_1">Următorul capitol</string>
<string name="download_1">Capitolul următor</string>
<string name="download_5">Următoarele 5 capitole</string>
<string name="download_10">Următoarele 10 capitole</string>
<string name="download_custom">Personalizat</string>
@ -286,7 +286,7 @@
<string name="reading">Citind</string>
<string name="completed">Terminată</string>
<string name="dropped">Abandonată</string>
<string name="on_hold">In așteptare</string>
<string name="on_hold">În așteptare</string>
<string name="plan_to_read">Planificat pentru citit</string>
<string name="repeating">Recitind</string>
<string name="score">Scor</string>
@ -305,10 +305,10 @@
<string name="saving_picture">Imaginea se salvează</string>
<string name="options">Opțiuni</string>
<string name="custom_filter">Filtru personalizat</string>
<string name="set_as_cover">Stabilește că și copertă</string>
<string name="set_as_cover">Stabilește ca și copertă</string>
<string name="cover_updated">Copertă actualizată</string>
<string name="page_downloaded">Pagină copiată în %1$s</string>
<string name="downloading">Se descărcă…</string>
<string name="downloading">Se descarcă…</string>
<string name="download_progress">Descărcat %1$d%%</string>
<string name="chapter_progress">Pagina: %1$d</string>
<string name="chapter_subtitle">Capitolul %1$s</string>
@ -376,7 +376,7 @@
<string name="pref_skip_read_chapters">Treci peste capitolele marcate ca Citit</string>
<string name="pref_read_with_long_tap">Dialog prin apăsare lunga</string>
<string name="label_help">Ajutor</string>
<string name="pref_library_update_prioritization">Ordinea actualizării bibliotecii</string>
<string name="pref_library_update_prioritization">Ordinea actualizărilor</string>
<string name="no_results_found">Nici un rezultat găsit</string>
<string name="migration_selection_prompt">Selectați o sursă din care să migrați</string>
<string name="action_webview_back">Înapoi</string>
@ -387,7 +387,7 @@
<string name="ext_obsolete">Învechit</string>
<string name="obsolete_extension_message">Această extensie nu mai este disponibilă.</string>
<string name="pref_date_format">Formatul datei</string>
<string name="pref_category_library_update">Actualizări</string>
<string name="pref_category_library_update">Actualizare globală</string>
<string name="logout_title">Deconectează-te de la %1$s\?</string>
<string name="logout">Deconectează-te</string>
<string name="logout_success">Acum ești deconectat</string>
@ -407,7 +407,7 @@
<string name="theme_dark_amoled">Negru AMOLED</string>
<string name="pref_manage_notifications">Setări notificări</string>
<string name="pref_category_security">Securitate</string>
<string name="lock_with_biometrics">Blocare cu amprentă</string>
<string name="lock_with_biometrics">Necesită deblocare</string>
<string name="unlock_app">Deblochează Tachiyomi</string>
<string name="action_sort_latest_chapter">Ultimul capitol</string>
<string name="lock_when_idle">Blocați când este inactiv</string>
@ -525,7 +525,7 @@
</plurals>
<string name="battery_optimization_setting_activity_not_found">Imposibil de deschis setările dispozitivului</string>
<plurals name="restore_completed_message">
<item quantity="one">Gata în %1$s cu %2$s eroare</item>
<item quantity="one">Gata în %1$s cu eroarea %2$s</item>
<item quantity="few">Gata în %1$s cu %2$s erori</item>
<item quantity="other">Gata în %1$s cu %2$s erori</item>
</plurals>
@ -631,7 +631,8 @@
<string name="spen_next_page">Pagina următoare</string>
<string name="spen_previous_page">Pagina anterioară</string>
<string name="migration_help_guide">Ghid de migrare a sursei</string>
<string name="invalid_backup_file_type">Fișierul copiei de rezervă este nevalid: %1$s</string>
<string name="invalid_backup_file_type">Tip de fișier de restaurare nevalid: %1$s
\nAr trebui să se termine cu .proto.gz sau .json.</string>
<string name="pref_backup_auto_create_legacy">De asemenea, creați copii de rezervă de moștenire</string>
<string name="pref_create_legacy_backup_summary">Poate fi utilizat în versiuni mai vechi de Tachiyomi</string>
<string name="pref_create_legacy_backup">Crează copie de rezervă de moștenire</string>
@ -644,7 +645,7 @@
<string name="myanimelist_creds_missing">Datele de conectare la site-ul MAL nu au fost găsite</string>
<string name="pref_dual_page_invert">Inversează plasamentul paginilor duble despărțite</string>
<string name="pref_dual_page_split">împărțirea paginilor duble</string>
<string name="pref_show_navigation_mode_summary">Afișați scurt zonele de atingere când cititorul este deschis</string>
<string name="pref_show_navigation_mode_summary">Afișați zonele de atingere atunci când cititorul este deschis</string>
<string name="pref_show_navigation_mode">Afișați suprapunerea aspectului de navigare</string>
<string name="network_unmetered">Rețea nemăsurată</string>
<string name="update_8hour">O dată la 8 ore</string>
@ -653,4 +654,37 @@
<string name="action_asc">Ascendent</string>
<string name="action_order_by_chapter_number">După numărul capitolului</string>
<string name="action_order_by_upload_date">După data postării</string>
<string name="exclude">Excludeți: %s</string>
<string name="include">Includeți: %s</string>
<string name="pref_library_update_categories_details">Manga din categoriile excluse nu vor fi actualizate, chiar dacă se află și în categoriile incluse.</string>
<string name="action_show_errors">Afișați erorile</string>
<string name="action_display_show_number_of_items">Afișare număr de elemente</string>
<string name="none">Nici unul</string>
<string name="pref_dns_over_https">DNS peste HTTPS</string>
<string name="channel_crash_logs">Jurnale de erori fatale</string>
<string name="track_finished_reading_date">Data încheierii citirii</string>
<string name="track_started_reading_date">Data începerii citirii</string>
<string name="crash_log_saved">Jurnalele de erori fatale salvate</string>
<string name="pref_dump_crash_logs">Aruncați jurnalele de erori fatale</string>
<string name="pref_dump_crash_logs_summary">Salvează jurnalele de erori într-un fișier pentru partajarea cu dezvoltatorii</string>
<string name="pref_viewer_nav">Aspect de navigare</string>
<string name="edge_nav">Margine</string>
<string name="kindlish_nav">Similar unui Kindle</string>
<string name="l_nav">În formă de L</string>
<string name="default_nav">Implicită</string>
<string name="action_sort_chapter_fetch_date">Data preluată</string>
<string name="action_filter_tracked">Urmărit</string>
<string name="backup_restore_content_full">Datele din fișierul de rezervă vor fi restaurate.
\n
\nVa trebui să instalați toate extensiile lipsă și să vă conectați ulterior la serviciile de urmărire pentru a le utiliza.</string>
<string name="pref_download_new_categories_details">Manga din categoriile excluse nu vor fi descărcate, chiar dacă se află și în categoriile incluse.</string>
<string name="pref_category_auto_download">Descărcare automată</string>
<string name="nav_zone_right">Dreapta</string>
<string name="nav_zone_left">Stânga</string>
<string name="nav_zone_next">Următorul</string>
<string name="nav_zone_prev">Anterior</string>
<string name="right_and_left_nav">Dreapta și stânga</string>
<string name="pref_dual_page_invert_summary">Dacă amplasarea divizării duble a paginii nu corespunde cu direcția de citire</string>
<string name="update_check_eol">Această versiune Android nu mai este suportată</string>
<string name="clipboard_copy_error">Nu s-a reușit copierea în clipboard</string>
</resources>

View file

@ -99,13 +99,13 @@
<string name="download_notifier_unknown_error">Не могу скачать главу из-за непревиденной ошибки</string>
<string name="download_progress">Загружен(о) %1$d%%</string>
<string name="download_queue_error">Невозможно скачать главы. Можете попробовать еще раз в разделе загрузок</string>
<string name="download_unread">Не прочитано</string>
<string name="downloading">Загрузка</string>
<string name="download_unread">Непрочитано</string>
<string name="downloading">Загружается</string>
<string name="dropped">Заброшено</string>
<string name="error_category_exists">Категория с таким именем уже существует!</string>
<string name="fetch_chapters_error">Не могу получить главы</string>
<string name="fifth_to_last">Пятая от прочитанной главы</string>
<string name="file_select_backup">Выбрать файл бэкапа</string>
<string name="file_select_backup">Выбрать файл резервной копии</string>
<string name="file_select_cover">Выбрать обложку</string>
<string name="fourth_to_last">Четвёртая от прочитанной главы</string>
<string name="information_empty_library">Ваша библиотека пуста. Добавьте тайтлы в библиотеку из Поиска.</string>
@ -262,7 +262,7 @@
<string name="action_restore">Восстановить</string>
<string name="action_undo">Отменить</string>
<string name="added_to_library">Манга была добавлена в библиотеку</string>
<string name="backup_choice">Что вы хотите бэкапить\?</string>
<string name="backup_choice">Что вы хотите резервировать\?</string>
<string name="backup_created">Резевная копия создана</string>
<string name="backup_restore_content">При восстановлении используются данные из источников, что может вызвать большой расход трафика.
\n
@ -279,17 +279,17 @@
<string name="local_source">Локальная манга</string>
<string name="manga">Манга</string>
<string name="no_more_results">Больше нет результатов</string>
<string name="pref_backup_directory">Каталог бэкапа</string>
<string name="pref_backup_interval">Частота бэкапов</string>
<string name="pref_backup_service_category">Автоматические бэкапы</string>
<string name="pref_backup_slots">Максимальное количество бэкапов</string>
<string name="pref_create_backup">Создать бэкап</string>
<string name="pref_backup_directory">Каталог резервной копии</string>
<string name="pref_backup_interval">Частота резервных копий</string>
<string name="pref_backup_service_category">Автоматические резервные копии</string>
<string name="pref_backup_slots">Максимальное количество резервных копий</string>
<string name="pref_create_backup">Создать резервную копию</string>
<string name="pref_create_backup_summ">Можно использовать для восстановления текущей библиотеки</string>
<string name="pref_crop_borders">Обрезать поля</string>
<string name="pref_refresh_library_tracking">Обновить отслеживание</string>
<string name="pref_refresh_library_tracking_summary">Обновляет статус, оценку и последнюю прочитанную главу из сервисов отслеживания</string>
<string name="pref_restore_backup">Восстановить из бэкапа</string>
<string name="pref_restore_backup_summ">Восстановить библиотеку из бэкапа</string>
<string name="pref_restore_backup">Восстановить из резервной копии</string>
<string name="pref_restore_backup_summ">Восстановить библиотеку из резервной копии</string>
<string name="restore_completed">Восстановление завершено</string>
<string name="restoring_backup">Восстановление из резервной копии</string>
<string name="short_recent_updates">Обновления</string>
@ -449,7 +449,7 @@
<string name="updating_library">Обновление библиотеки</string>
<string name="http_error_hint">Проверить страницу в WebView</string>
<string name="battery_optimization_disabled">Оптимизация батареи уже выключена</string>
<string name="pref_disable_battery_optimization_summary">Помогает с фоновым обновлением библиотеки и бэкапом</string>
<string name="pref_disable_battery_optimization_summary">Помогает с фоновым обновлением библиотеки и резевной копии</string>
<string name="pref_disable_battery_optimization">Выключить оптимизацию батареи</string>
<string name="theme_light_default">По умолчанию</string>
<plurals name="update_check_notification_ext_updates">
@ -506,10 +506,10 @@
<string name="downloaded_only_summary">Фильтрует всю мангу в вашей библиотеке</string>
<string name="check_for_updates">Проверить обновления</string>
<string name="restoring_backup_canceled">Восстановление отменено</string>
<string name="restoring_backup_error">Ошибка восстановления из бэкапа</string>
<string name="restoring_backup_error">Ошибка восстановления из резервной копии</string>
<string name="restore_in_progress">Восстановление уже выполняется</string>
<string name="creating_backup_error">Ошибка бэкапа</string>
<string name="backup_in_progress">Бэкап уже выполняется</string>
<string name="creating_backup_error">Не удалось создать резервную копию</string>
<string name="backup_in_progress">Резервная копия уже выполняется</string>
<string name="restore_duration">%02d мин, %02d сек</string>
<string name="pref_search_pinned_sources_only">Включать только закрепленные источники</string>
<plurals name="download_queue_summary">
@ -605,7 +605,7 @@
</plurals>
<string name="no_pinned_sources">У вас нет закрепленных источников</string>
<string name="download_notifier_download_finish">Загрузка завершена</string>
<string name="group_backup_restore">Бэкап и восстановление</string>
<string name="group_backup_restore">Резервирование и восстановление</string>
<string name="group_downloader">Загрузки</string>
<string name="channel_complete">Завершение</string>
<string name="channel_progress">Прогресс</string>
@ -673,8 +673,8 @@
<string name="action_display_show_number_of_items">Показать число объектов</string>
<string name="right_and_left_nav">Справа и слева</string>
<string name="pref_dual_page_split">Двухстраничное разделение</string>
<string name="pref_dual_page_invert">Инвертировать двухстраничное размещение разделения</string>
<string name="pref_dual_page_invert_summary">Если двухстраничное размещение разделения не соответствует направлению чтения</string>
<string name="pref_dual_page_invert">Инвертировать двухстраничное разделение</string>
<string name="pref_dual_page_invert_summary">Если двухстраничное разделение не соответствует направлению чтения</string>
<string name="backup_restore_content_full">Данные из файла резевной копии будут восстановлены.
\n
\nВам будет нужно установить все недостающие расширения, и после этого войти в сервисы отслеживания для их использования.</string>
@ -685,7 +685,7 @@
<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">Показывать наложение схемы навигации</string>
<string name="pref_show_navigation_mode">Показывать наложение макета навигации</string>
<string name="pref_dns_over_https">DNS по HTTPS</string>
<string name="none">Нет</string>
<string name="exclude">Исключать: %s</string>
@ -694,4 +694,7 @@
<string name="pref_download_new_categories_details">Манга в исключенных категориях не будет загруженна, даже если она также находится во включенных категориях.</string>
<string name="pref_library_update_categories_details">Манга в исключенных категориях не будет обновляться, даже если она также находится во включенных категориях.</string>
<string name="pref_category_auto_download">Автозагрузка</string>
<string name="action_show_errors">Показать ошибки</string>
<string name="update_check_eol">Эта версия Андроида больше не поддерживается</string>
<string name="clipboard_copy_error">Не удалось скопировать в буфер обмена</string>
</resources>

View file

@ -87,7 +87,7 @@
<string name="portrait">Orientamentu verticale</string>
<string name="landscape">Orientamentu orizontale</string>
<string name="default_columns">Predefinidu</string>
<string name="pref_library_update_interval">Frecuèntzia de agiornamentu de sa biblioteca</string>
<string name="pref_library_update_interval">Frecuèntzia de agiornamentu</string>
<string name="update_never">Manuale</string>
<string name="update_1hour">Cada ora</string>
<string name="update_2hour">Cada 2 oras</string>
@ -98,7 +98,7 @@
<string name="update_48hour">Cada 2 dies</string>
<string name="update_weekly">Cada chida</string>
<string name="all">Totus</string>
<string name="pref_library_update_restriction">Restritziones a s\'agiornamentu de sa biblioteca</string>
<string name="pref_library_update_restriction">Restritziones a s\'agiornamentu</string>
<string name="pref_library_update_restriction_summary">Agiorna petzi cando sas cunditziones benint rispetadas</string>
<string name="charging">Carrighende</string>
<string name="pref_update_only_non_completed">Agiorna sos manga in cursu ebbia</string>
@ -376,7 +376,7 @@
<string name="filter_mode_lighten">Istransi / Acrari</string>
<string name="filter_mode_darken">Brùsia / Iscuri</string>
<string name="label_help">Agiudu</string>
<string name="pref_library_update_prioritization">Òrdine de agiornamentu de sa biblioteca</string>
<string name="pref_library_update_prioritization">Òrdine de agiornamentu</string>
<string name="no_results_found">Perunu resultadu agadadu</string>
<string name="migration_selection_prompt">Ischerta una mitza dae sa cale tramudare</string>
<string name="action_webview_back">In segus</string>
@ -387,7 +387,7 @@
<string name="ext_obsolete">Obsoleta</string>
<string name="obsolete_extension_message">Cust\'estensione no est prus a disponimentu.</string>
<string name="pref_date_format">Formadu de sa data</string>
<string name="pref_category_library_update">Agiornamentos</string>
<string name="pref_category_library_update">Agiornamentu globale</string>
<string name="logout_title">Essire dae %1$s\?</string>
<string name="logout">Essi</string>
<string name="logout_success">Ses essidu</string>
@ -669,4 +669,10 @@
<string name="include">Include: %s</string>
<string name="none">Perunu</string>
<string name="action_sort_chapter_fetch_date">Data recuperada</string>
</resources>
<string name="pref_download_new_categories_details">Sos manga in sas categorias esclùdidas non s\'ant a iscarrigare nemmancu si sunt fintzas in categorias inclùdidas.</string>
<string name="pref_category_auto_download">Iscarrigamentu automàticu</string>
<string name="pref_library_update_categories_details">Sos manga in sas categorias esclùdidas non s\'ant a agiornare nemmancu si sunt fintzas in categorias inclùdidas.</string>
<string name="action_show_errors">Ammustra sos errores</string>
<string name="clipboard_copy_error">Còpia in punta de billete fallida</string>
<string name="update_check_eol">Custa versione de Android no est prus suportada</string>
</resources>

View file

@ -672,4 +672,7 @@
<string name="pref_download_new_categories_details">Manga i uteslutna kategorier laddas inte ner även om de också ingår i inkluderade kategorier.</string>
<string name="pref_category_auto_download">Ladda ned automatiskt</string>
<string name="pref_library_update_categories_details">Manga i uteslutna kategorier uppdateras inte även om de också ingår i inkluderade kategorier.</string>
<string name="action_show_errors">Visa fel</string>
<string name="update_check_eol">Denna Android-version stöds inte längre</string>
<string name="clipboard_copy_error">Kunde inte kopiera till urklipp</string>
</resources>

View file

@ -318,7 +318,7 @@
<string name="confirm_set_image_as_cover">Bu görsel kapak resmi olarak kullanılsın mı\?</string>
<string name="migration_info">Taşınılacak kaynağı seçmek için dokunun</string>
<string name="migration_dialog_what_to_include">Eklenecek veriyi seç</string>
<string name="migrate">Taşın</string>
<string name="migrate">Geçiş yap</string>
<string name="copy">Kopyala</string>
<string name="download_queue_error">Bölümler indirilemedi. İndirmeler bölümünden yeniden deneyebilirsiniz</string>
<string name="notification_update_progress">Güncelleme ilerlemesi: %1$d/%2$d</string>
@ -672,4 +672,7 @@
<string name="pref_download_new_categories_details">Hariç tutulan kategorilerdeki manga, dahil edilen kategorilerde olsa bile indirilmeyecektir.</string>
<string name="pref_category_auto_download">Otomatik indir</string>
<string name="pref_library_update_categories_details">Hariç tutulan kategorilerdeki manga, dahil edilen kategorilerde olsa bile güncellenmeyecektir.</string>
<string name="action_show_errors">Hataları göster</string>
<string name="update_check_eol">Bu Android sürümü artık desteklenmiyor</string>
<string name="clipboard_copy_error">Panoya kopyalanamadı</string>
</resources>

View file

@ -692,4 +692,5 @@
<string name="none">Ніхто</string>
<string name="pref_library_update_categories_details">Мангу в виключених категоріях не буде оновлено, навіть якщо вона також знаходиться у включених категоріях.</string>
<string name="action_sort_chapter_fetch_date">Дата отримання</string>
<string name="action_show_errors">Показати помилки</string>
</resources>

View file

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.Tachiyomi.Light.Api23">
<item name="android:statusBarColor">@color/md_white_1000</item>
<style name="Base.V23.Theme.Tachiyomi.Light" parent="Base.Theme.Tachiyomi.Light">
<item name="android:statusBarColor">?attr/colorPrimary</item>
<item name="android:windowLightStatusBar">true</item>
</style>
<style name="Theme.Tachiyomi.Light" parent="Base.V23.Theme.Tachiyomi.Light" />
</resources>

View file

@ -1,12 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.Tachiyomi.Light.Api27">
<item name="android:statusBarColor">@color/md_white_1000</item>
<item name="android:windowLightStatusBar">true</item>
<item name="android:navigationBarColor">@color/md_white_1000</item>
<style name="Base.V27.Theme.Tachiyomi.Light" parent="Base.V23.Theme.Tachiyomi.Light">
<item name="android:navigationBarColor">?attr/colorPrimary</item>
<item name="android:windowLightNavigationBar">true</item>
</style>
<style name="Theme.Tachiyomi.Light" parent="Base.V27.Theme.Tachiyomi.Light" />
</resources>

View file

@ -180,7 +180,7 @@
<string name="pref_remove_after_marked_as_read">手动标记为已读后</string>
<string name="pref_remove_after_read">阅毕</string>
<string name="custom_dir">自定义路径</string>
<string name="disabled">关闭</string>
<string name="disabled">已禁用</string>
<string name="last_read_chapter">最后阅读的章节</string>
<string name="second_to_last">倒数第二章</string>
<string name="third_to_last">倒数第三章</string>
@ -393,7 +393,7 @@
<string name="logout_success">你已登出</string>
<string name="paused">已暂停</string>
<string name="currently_reading">正在阅读</string>
<string name="want_to_read">要阅</string>
<string name="want_to_read">想读</string>
<string name="label_more">更多</string>
<string name="action_sort_latest_chapter">最新章节</string>
<string name="action_view_chapters">查看章节</string>
@ -660,4 +660,7 @@
<string name="pref_library_update_categories_details">应用不会更新位于排除分类中的漫画,即使它们同样位于包括的分类中。</string>
<string name="pref_download_new_categories_details">应用不会下载位于排除分类中的漫画,即使它们同样位于包括的分类中。</string>
<string name="pref_category_auto_download">自动下载</string>
<string name="action_show_errors">显示错误</string>
<string name="update_check_eol">英勇不再支持此 Android 版本</string>
<string name="clipboard_copy_error">未能复制到剪贴板</string>
</resources>

View file

@ -451,7 +451,6 @@
<string name="version">Version</string>
<string name="build_time">Build time</string>
<string name="whats_new">What\'s new</string>
<string name="notices">Preview build notices</string>
<string name="licenses">Open source licenses</string>
<string name="check_for_updates">Check for updates</string>
<string name="updated_version">Updated to v%1$s</string>

View file

@ -47,8 +47,9 @@
<item name="android:textDirection">locale</item>
<!-- Themes -->
<item name="android:statusBarColor">?attr/colorPrimary</item>
<item name="android:navigationBarColor">?attr/colorPrimary</item>
<item name="android:statusBarColor">@color/md_black_1000</item>
<item name="android:navigationBarColor">@color/md_black_1000</item>
<item name="android:navigationBarDividerColor" tools:targetApi="o_mr1">@null</item>
<item name="android:enforceNavigationBarContrast" tools:targetApi="Q">false</item>
<item name="windowActionModeOverlay">true</item>
<item name="elevationOverlayEnabled">false</item>
@ -84,28 +85,24 @@
<!-- Custom Attributes-->
<item name="colorLibrarySelection">?attr/colorAccent</item>
<item name="colorLibrarySelectionActive">@color/selectorColorLight</item>
<item name="colorFilterActive">@color/filterColorDark</item>
<item name="colorFilterActive">@color/filterColorLight</item>
</style>
<!--===========-->
<!-- Main Theme-->
<!--===========-->
<style name="Theme.Tachiyomi.Light" parent="Theme.Base">
<item name="android:statusBarColor">@color/md_black_1000</item>
<item name="android:navigationBarColor">@color/md_black_1000_54</item>
<style name="Base.Theme.Tachiyomi.Light" parent="Theme.Base" />
<style name="Theme.Tachiyomi.Light" parent="Base.Theme.Tachiyomi.Light" />
<item name="colorFilterActive">@color/filterColorLight</item>
</style>
<style name="Theme.Tachiyomi.LightBlue" parent="Theme.Base">
<style name="Theme.Tachiyomi.Light.Blue">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorOnPrimary">@color/textColorPrimaryDark</item>
<item name="colorAccentOnPrimary">@color/textColorPrimaryDark</item>
<item name="colorPrimaryVariant">@color/colorPrimaryDark</item>
<item name="colorFilterActive">@color/filterColorDark</item>
<item name="actionBarTheme">@style/Theme.Toolbar.Light</item>
<item name="android:navigationBarColor">@color/colorPrimary_70</item>
<item name="android:windowLightStatusBar" tools:targetApi="m">false</item>
<item name="android:windowLightNavigationBar" tools:targetApi="o_mr1">false</item>
</style>
<!--=============-->
@ -145,6 +142,7 @@
<!-- Themes -->
<item name="android:statusBarColor">?attr/colorPrimary</item>
<item name="android:navigationBarColor">?attr/colorPrimary</item>
<item name="android:navigationBarDividerColor" tools:targetApi="o_mr1">@null</item>
<item name="android:enforceNavigationBarContrast" tools:targetApi="Q">false</item>
<item name="windowActionModeOverlay">true</item>
<item name="elevationOverlayEnabled">false</item>
@ -184,16 +182,15 @@
<item name="colorFilterActive">@color/filterColorDark</item>
</style>
<style name="Theme.Tachiyomi.Dark" parent="Theme.Base.Dark">
</style>
<style name="Theme.Tachiyomi.Dark" parent="Theme.Base.Dark" />
<style name="Theme.Tachiyomi.DarkBlue" parent="Theme.Base.Dark">
<style name="Theme.Tachiyomi.Dark.Blue">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorAccentOnPrimary">@color/textColorPrimaryDark</item>
<item name="colorPrimaryVariant">@color/colorPrimary</item>
</style>
<style name="Theme.Tachiyomi.Amoled" parent="Theme.Base.Dark">
<style name="Theme.Tachiyomi.Dark.Amoled">
<item name="colorPrimary">@color/colorAmoledPrimary</item>
<item name="colorPrimaryVariant">@color/colorAmoledPrimary</item>
<item name="colorSurface">@color/colorAmoledPrimary</item>
@ -255,7 +252,7 @@
<!--===============-->
<!-- Launch Screen -->
<!--===============-->
<style name="Theme.Splash" parent="Theme.Tachiyomi.LightBlue">
<style name="Theme.Splash" parent="Theme.Tachiyomi.Light.Blue">
<item name="colorBackgroundSplash">@color/colorPrimary</item>
<item name="android:windowBackground">@drawable/splash_background</item>

View file

@ -11,7 +11,7 @@
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
org.gradle.jvmargs=-Xmx2048m
org.gradle.jvmargs=-Xmx3072m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit