mirror of
https://github.com/mihonapp/mihon.git
synced 2025-07-30 03:15:54 +02:00
Compare commits
20 Commits
Author | SHA1 | Date | |
---|---|---|---|
c87ba6231d | |||
c5ca739b49 | |||
00fe4cdf2d | |||
69be3e1e87 | |||
2cb3984d68 | |||
5901978889 | |||
8bf1cf3cc5 | |||
f6af1184bc | |||
4880741b8b | |||
e8627800fe | |||
907fbb94a2 | |||
fd2028557e | |||
91fa1ec6b2 | |||
628c525599 | |||
bbc00768f0 | |||
5b09461ccf | |||
1a439ecece | |||
836aec4396 | |||
0b5dec9bab | |||
fd56123267 |
.github
README.mdapp
build.gradle
build.gradle.ktssrc
main
AndroidManifest.xml
java
eu
kanade
tachiyomi
Migrations.kt
data
backup
download
library
preference
track
extension
source
ui
base
controller
browse
extension
source
library
manga
more
reader
recent
setting
SettingsAdvancedController.ktSettingsBackupController.ktSettingsBrowseController.ktSettingsDownloadController.kt
search
webview
util
widget
res
drawable
layout
values-ar
values-b+es+419
values-bg
values-bn
values-ca
values-cv
values-de
values-el
values-es
values-fa
values-fi
values-fil
values-fr
values-hi
values-hr
values-in
values-it
values-ja
values-ka-rGE
values-kn
values-ms
values-nb-rNO
values-nl
values-pl
values-pt-rBR
values-pt
values-ro
values-ru
values-sah
values-sc
values-sv
values-tr
values-uk
values-zh-rCN
values-zh-rTW
values
2
.github/ISSUE_TEMPLATE.md
vendored
2
.github/ISSUE_TEMPLATE.md
vendored
@ -2,7 +2,7 @@
|
||||
|
||||
I acknowledge that:
|
||||
|
||||
- I have updated to the latest version of the app (stable is v0.10.5)
|
||||
- I have updated to the latest version of the app (stable is v0.10.7)
|
||||
- I have updated all extensions
|
||||
- If this is an issue with an extension, that I should be opening an issue in https://github.com/inorichi/tachiyomi-extensions
|
||||
|
||||
|
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -9,7 +9,7 @@ labels: "bug"
|
||||
|
||||
I acknowledge that:
|
||||
|
||||
- I have updated to the latest version of the app (stable is v0.10.5)
|
||||
- I have updated to the latest version of the app (stable is v0.10.7)
|
||||
- I have updated all extensions
|
||||
- If this is an issue with an extension, that I should be opening an issue in https://github.com/inorichi/tachiyomi-extensions
|
||||
|
||||
|
2
.github/ISSUE_TEMPLATE/feature_request.md
vendored
2
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -9,7 +9,7 @@ labels: "feature"
|
||||
|
||||
I acknowledge that:
|
||||
|
||||
- I have updated to the latest version of the app (stable is v0.10.5)
|
||||
- I have updated to the latest version of the app (stable is v0.10.7)
|
||||
- I have updated all extensions
|
||||
- If this is an issue with an extension, that I should be opening an issue in https://github.com/inorichi/tachiyomi-extensions
|
||||
|
||||
|
@ -58,7 +58,7 @@ DON'T: https://github.com/inorichi/tachiyomi/issues/75
|
||||
* Write a detailed issue, explaining what it should do or how. Avoid writing just "like X app does"
|
||||
* Include screenshot (if needed)
|
||||
|
||||
Catalogue requests should be created at https://github.com/inorichi/tachiyomi-extensions, they do not belong in this repository.
|
||||
Source requests should be created at https://github.com/inorichi/tachiyomi-extensions, they do not belong in this repository.
|
||||
</details>
|
||||
|
||||
## FAQ
|
||||
|
@ -5,8 +5,8 @@ import java.text.SimpleDateFormat
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'com.mikepenz.aboutlibraries.plugin'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
apply plugin: 'kotlin-parcelize'
|
||||
apply plugin: 'kotlinx-serialization'
|
||||
apply plugin: 'com.github.zellius.shortcut-helper'
|
||||
|
||||
@ -42,8 +42,8 @@ android {
|
||||
minSdkVersion AndroidConfig.minSdk
|
||||
targetSdkVersion AndroidConfig.targetSdk
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
versionCode 52
|
||||
versionName "0.10.6"
|
||||
versionCode 53
|
||||
versionName "0.10.7"
|
||||
|
||||
buildConfigField "String", "COMMIT_COUNT", "\"${getCommitCount()}\""
|
||||
buildConfigField "String", "COMMIT_SHA", "\"${getGitSha()}\""
|
||||
@ -67,13 +67,13 @@ android {
|
||||
applicationIdSuffix ".debug"
|
||||
}
|
||||
release {
|
||||
postprocessing {
|
||||
obfuscate false
|
||||
optimizeCode true
|
||||
removeUnusedCode false
|
||||
removeUnusedResources true
|
||||
proguardFiles 'proguard-rules.pro'
|
||||
}
|
||||
// postprocessing {
|
||||
// obfuscate false
|
||||
// optimizeCode true
|
||||
// removeUnusedCode false
|
||||
// removeUnusedResources true
|
||||
// proguardFiles 'proguard-rules.pro'
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,10 +123,6 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
androidExtensions {
|
||||
experimental = true
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
// Source models and interfaces from Tachiyomi 1.x
|
||||
@ -239,7 +235,6 @@ dependencies {
|
||||
implementation 'com.github.dmytrodanylyk.android-process-button:library:1.0.4'
|
||||
implementation 'eu.davidea:flexible-adapter:5.1.0'
|
||||
implementation 'eu.davidea:flexible-adapter-ui:1.0.0'
|
||||
implementation 'com.nononsenseapps:filepicker:2.5.2'
|
||||
implementation 'com.nightlynexus.viewstatepageradapter:viewstatepageradapter:1.1.0'
|
||||
implementation 'com.github.chrisbanes:PhotoView:2.3.0'
|
||||
implementation 'com.github.carlosesco:DirectionalViewPager:a844dbca0a'
|
||||
@ -280,7 +275,7 @@ dependencies {
|
||||
|
||||
implementation "org.jetbrains.kotlin:kotlin-reflect:$BuildPluginsVersion.KOTLIN"
|
||||
|
||||
final coroutines_version = '1.4.1'
|
||||
final coroutines_version = '1.4.2'
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
|
||||
|
||||
|
@ -80,10 +80,6 @@
|
||||
<activity
|
||||
android:name=".ui.webview.WebViewActivity"
|
||||
android:configChanges="uiMode|orientation|screenSize" />
|
||||
<activity
|
||||
android:name=".widget.CustomLayoutPickerActivity"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/FilePickerTheme" />
|
||||
<activity
|
||||
android:name=".ui.setting.track.AnilistLoginActivity"
|
||||
android:label="Anilist">
|
||||
|
@ -10,6 +10,7 @@ import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.data.updater.UpdaterJob
|
||||
import eu.kanade.tachiyomi.extension.ExtensionUpdateJob
|
||||
import eu.kanade.tachiyomi.ui.library.LibrarySort
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import eu.kanade.tachiyomi.widget.ExtendedNavigationView
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
@ -92,6 +93,7 @@ object Migrations {
|
||||
}
|
||||
if (oldVersion < 44) {
|
||||
// Reset sorting preference if using removed sort by source
|
||||
@Suppress("DEPRECATION")
|
||||
if (preferences.librarySortingMode().get() == LibrarySort.SOURCE) {
|
||||
preferences.librarySortingMode().set(LibrarySort.ALPHA)
|
||||
}
|
||||
@ -117,7 +119,10 @@ object Migrations {
|
||||
|
||||
// Force MAL log out due to login flow change
|
||||
val trackManager = Injekt.get<TrackManager>()
|
||||
trackManager.myAnimeList.logout()
|
||||
if (trackManager.myAnimeList.isLogged) {
|
||||
trackManager.myAnimeList.logout()
|
||||
context.toast(R.string.myanimelist_relogin)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
@ -146,7 +146,7 @@ class BackupNotifier(private val context: Context) {
|
||||
val uri = destFile.getUriCompat(context)
|
||||
|
||||
addAction(
|
||||
R.drawable.nnf_ic_file_folder,
|
||||
R.drawable.ic_folder_24dp,
|
||||
context.getString(R.string.action_open_log),
|
||||
NotificationReceiver.openErrorLogPendingActivity(context, uri)
|
||||
)
|
||||
|
@ -137,7 +137,7 @@ class DownloadPendingDeleter(context: Context) {
|
||||
val id: Long,
|
||||
val url: String,
|
||||
val name: String,
|
||||
val scanlator: String?
|
||||
val scanlator: String? = null
|
||||
)
|
||||
|
||||
/**
|
||||
|
@ -109,7 +109,7 @@ class LibraryUpdateNotifier(private val context: Context) {
|
||||
|
||||
setContentIntent(errorLogIntent)
|
||||
addAction(
|
||||
R.drawable.nnf_ic_file_folder,
|
||||
R.drawable.ic_folder_24dp,
|
||||
context.getString(R.string.action_open_log),
|
||||
errorLogIntent
|
||||
)
|
||||
|
@ -121,7 +121,9 @@ object PreferenceKeys {
|
||||
|
||||
const val automaticExtUpdates = "automatic_ext_updates"
|
||||
|
||||
const val allowNsfwSource = "allow_nsfw_source"
|
||||
const val showNsfwSource = "show_nsfw_source"
|
||||
const val showNsfwExtension = "show_nsfw_extension"
|
||||
const val labelNsfwExtension = "label_nsfw_extension"
|
||||
|
||||
const val startScreen = "start_screen"
|
||||
|
||||
|
@ -37,10 +37,4 @@ object PreferenceValues {
|
||||
VERTICAL,
|
||||
BOTH
|
||||
}
|
||||
|
||||
enum class NsfwAllowance {
|
||||
ALLOWED,
|
||||
PARTIAL,
|
||||
BLOCKED
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ import com.tfcporciuncula.flow.Preference
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues.DisplayMode
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues.NsfwAllowance
|
||||
import eu.kanade.tachiyomi.data.track.TrackService
|
||||
import eu.kanade.tachiyomi.data.track.anilist.Anilist
|
||||
import eu.kanade.tachiyomi.widget.ExtendedNavigationView
|
||||
@ -225,7 +224,9 @@ class PreferencesHelper(val context: Context) {
|
||||
|
||||
fun automaticExtUpdates() = flowPrefs.getBoolean(Keys.automaticExtUpdates, true)
|
||||
|
||||
fun allowNsfwSource() = flowPrefs.getEnum(Keys.allowNsfwSource, NsfwAllowance.ALLOWED)
|
||||
fun showNsfwSource() = flowPrefs.getBoolean(Keys.showNsfwSource, true)
|
||||
fun showNsfwExtension() = flowPrefs.getBoolean(Keys.showNsfwExtension, true)
|
||||
fun labelNsfwExtension() = prefs.getBoolean(Keys.labelNsfwExtension, true)
|
||||
|
||||
fun extensionUpdatesCount() = flowPrefs.getInt("ext_updates_count", 0)
|
||||
|
||||
|
@ -63,7 +63,7 @@ data class ALUserManga(
|
||||
"DROPPED" -> Anilist.DROPPED
|
||||
"PLANNING" -> Anilist.PLANNING
|
||||
"REPEATING" -> Anilist.REPEATING
|
||||
else -> throw NotImplementedError("Unknown status")
|
||||
else -> throw NotImplementedError("Unknown status: $list_status")
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,7 +74,7 @@ fun Track.toAnilistStatus() = when (status) {
|
||||
Anilist.DROPPED -> "DROPPED"
|
||||
Anilist.PLANNING -> "PLANNING"
|
||||
Anilist.REPEATING -> "REPEATING"
|
||||
else -> throw NotImplementedError("Unknown status")
|
||||
else -> throw NotImplementedError("Unknown status: $status")
|
||||
}
|
||||
|
||||
private val preferences: PreferencesHelper by injectLazy()
|
||||
@ -102,5 +102,5 @@ fun Track.toAnilistScore(): String = when (preferences.anilistScoreType().get())
|
||||
}
|
||||
// 10 point decimal
|
||||
"POINT_10_DECIMAL" -> (score / 10).toString()
|
||||
else -> throw Exception("Unknown score type")
|
||||
else -> throw NotImplementedError("Unknown score type")
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ fun Track.toBangumiStatus() = when (status) {
|
||||
Bangumi.ON_HOLD -> "on_hold"
|
||||
Bangumi.DROPPED -> "dropped"
|
||||
Bangumi.PLANNING -> "wish"
|
||||
else -> throw NotImplementedError("Unknown status")
|
||||
else -> throw NotImplementedError("Unknown status: $status")
|
||||
}
|
||||
|
||||
fun toTrackStatus(status: String) = when (status) {
|
||||
@ -17,6 +17,5 @@ fun toTrackStatus(status: String) = when (status) {
|
||||
"on_hold" -> Bangumi.ON_HOLD
|
||||
"dropped" -> Bangumi.DROPPED
|
||||
"wish" -> Bangumi.PLANNING
|
||||
|
||||
else -> throw Exception("Unknown status")
|
||||
else -> throw NotImplementedError("Unknown status: $status")
|
||||
}
|
||||
|
@ -111,7 +111,7 @@ class MyAnimeList(private val context: Context, id: Int) : TrackService(id) {
|
||||
|
||||
fun ensureLoggedIn() {
|
||||
if (isAuthorized) return
|
||||
if (!isLogged) throw Exception("MAL login credentials not found")
|
||||
if (!isLogged) throw Exception(context.getString(R.string.myanimelist_creds_missing))
|
||||
}
|
||||
|
||||
override fun logout() {
|
||||
|
@ -9,7 +9,7 @@ fun Track.toShikimoriStatus() = when (status) {
|
||||
Shikimori.DROPPED -> "dropped"
|
||||
Shikimori.PLANNING -> "planned"
|
||||
Shikimori.REPEATING -> "rewatching"
|
||||
else -> throw NotImplementedError("Unknown status")
|
||||
else -> throw NotImplementedError("Unknown status: $status")
|
||||
}
|
||||
|
||||
fun toTrackStatus(status: String) = when (status) {
|
||||
@ -19,6 +19,5 @@ fun toTrackStatus(status: String) = when (status) {
|
||||
"dropped" -> Shikimori.DROPPED
|
||||
"planned" -> Shikimori.PLANNING
|
||||
"rewatching" -> Shikimori.REPEATING
|
||||
|
||||
else -> throw Exception("Unknown status")
|
||||
else -> throw NotImplementedError("Unknown status: $status")
|
||||
}
|
||||
|
@ -124,8 +124,7 @@ class ExtensionManager(
|
||||
.map { it.extension }
|
||||
installedExtensions
|
||||
.flatMap { it.sources }
|
||||
// overwrite is needed until the bundled sources are removed
|
||||
.forEach { sourceManager.registerSource(it, true) }
|
||||
.forEach { sourceManager.registerSource(it) }
|
||||
|
||||
untrustedExtensions = extensions
|
||||
.filterIsInstance<LoadResult.Untrusted>()
|
||||
|
@ -6,7 +6,6 @@ import android.content.pm.PackageInfo
|
||||
import android.content.pm.PackageManager
|
||||
import dalvik.system.PathClassLoader
|
||||
import eu.kanade.tachiyomi.annotations.Nsfw
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.extension.model.Extension
|
||||
import eu.kanade.tachiyomi.extension.model.LoadResult
|
||||
@ -26,8 +25,8 @@ import uy.kohesive.injekt.injectLazy
|
||||
internal object ExtensionLoader {
|
||||
|
||||
private val preferences: PreferencesHelper by injectLazy()
|
||||
private val allowNsfwSource by lazy {
|
||||
preferences.allowNsfwSource().get()
|
||||
private val loadNsfwSource by lazy {
|
||||
preferences.showNsfwSource().get()
|
||||
}
|
||||
|
||||
private const val EXTENSION_FEATURE = "tachiyomi.extension"
|
||||
@ -133,7 +132,7 @@ internal object ExtensionLoader {
|
||||
}
|
||||
|
||||
val isNsfw = appInfo.metaData.getInt(METADATA_NSFW) == 1
|
||||
if (allowNsfwSource == PreferenceValues.NsfwAllowance.BLOCKED && isNsfw) {
|
||||
if (!loadNsfwSource && isNsfw) {
|
||||
return LoadResult.Error("NSFW extension $pkgName not allowed")
|
||||
}
|
||||
|
||||
@ -218,7 +217,7 @@ internal object ExtensionLoader {
|
||||
* Checks whether a Source or SourceFactory is annotated with @Nsfw.
|
||||
*/
|
||||
private fun isSourceNsfw(clazz: Any): Boolean {
|
||||
if (allowNsfwSource == PreferenceValues.NsfwAllowance.ALLOWED) {
|
||||
if (loadNsfwSource) {
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -62,14 +62,18 @@ interface Source : tachiyomi.source.Source {
|
||||
/**
|
||||
* [1.x API] Get the updated details for a manga.
|
||||
*/
|
||||
@Suppress("DEPRECATION")
|
||||
override suspend fun getMangaDetails(manga: MangaInfo): MangaInfo {
|
||||
return fetchMangaDetails(manga.toSManga()).awaitSingle()
|
||||
.toMangaInfo()
|
||||
val sManga = manga.toSManga()
|
||||
val networkManga = fetchMangaDetails(sManga).awaitSingle()
|
||||
sManga.copyFrom(networkManga)
|
||||
return sManga.toMangaInfo()
|
||||
}
|
||||
|
||||
/**
|
||||
* [1.x API] Get all the available chapters for a manga.
|
||||
*/
|
||||
@Suppress("DEPRECATION")
|
||||
override suspend fun getChapterList(manga: MangaInfo): List<ChapterInfo> {
|
||||
return fetchChapterList(manga.toSManga()).awaitSingle()
|
||||
.map { it.toChapterInfo() }
|
||||
@ -78,6 +82,7 @@ interface Source : tachiyomi.source.Source {
|
||||
/**
|
||||
* [1.x API] Get the list of pages a chapter has.
|
||||
*/
|
||||
@Suppress("DEPRECATION")
|
||||
override suspend fun getPageList(chapter: ChapterInfo): List<tachiyomi.source.model.Page> {
|
||||
return fetchPageList(chapter.toSChapter()).awaitSingle()
|
||||
.map { it.toPageUrl() }
|
||||
|
@ -32,11 +32,11 @@ open class SourceManager(private val context: Context) {
|
||||
|
||||
fun getCatalogueSources() = sourcesMap.values.filterIsInstance<CatalogueSource>()
|
||||
|
||||
internal fun registerSource(source: Source, overwrite: Boolean = false) {
|
||||
if (overwrite || !sourcesMap.containsKey(source.id)) {
|
||||
internal fun registerSource(source: Source) {
|
||||
if (!sourcesMap.containsKey(source.id)) {
|
||||
sourcesMap[source.id] = source
|
||||
}
|
||||
if (overwrite || !stubSourcesMap.containsKey(source.id)) {
|
||||
if (!stubSourcesMap.containsKey(source.id)) {
|
||||
stubSourcesMap[source.id] = StubSource(source.id)
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,6 @@ import com.bluelinelabs.conductor.ControllerChangeHandler
|
||||
import com.bluelinelabs.conductor.ControllerChangeType
|
||||
import com.bluelinelabs.conductor.RestoreViewOnCreateController
|
||||
import kotlinx.android.extensions.LayoutContainer
|
||||
import kotlinx.android.synthetic.clearFindViewByIdCache
|
||||
import timber.log.Timber
|
||||
|
||||
abstract class BaseController<VB : ViewBinding>(bundle: Bundle? = null) :
|
||||
@ -54,11 +53,6 @@ abstract class BaseController<VB : ViewBinding>(bundle: Bundle? = null) :
|
||||
return inflateView(inflater, container)
|
||||
}
|
||||
|
||||
override fun onDestroyView(view: View) {
|
||||
super.onDestroyView(view)
|
||||
clearFindViewByIdCache()
|
||||
}
|
||||
|
||||
abstract fun inflateView(inflater: LayoutInflater, container: ViewGroup): View
|
||||
|
||||
open fun onViewCreated(view: View) {}
|
||||
|
@ -4,16 +4,23 @@ import android.view.View
|
||||
import eu.davidea.viewholders.FlexibleViewHolder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.glide.GlideApp
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.databinding.ExtensionCardItemBinding
|
||||
import eu.kanade.tachiyomi.extension.model.Extension
|
||||
import eu.kanade.tachiyomi.extension.model.InstallStep
|
||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class ExtensionHolder(view: View, val adapter: ExtensionAdapter) :
|
||||
FlexibleViewHolder(view, adapter) {
|
||||
|
||||
private val binding = ExtensionCardItemBinding.bind(view)
|
||||
|
||||
private val shouldLabelNsfw by lazy {
|
||||
Injekt.get<PreferencesHelper>().labelNsfwExtension()
|
||||
}
|
||||
|
||||
init {
|
||||
binding.extButton.setOnClickListener {
|
||||
adapter.buttonClickListener.onButtonClick(bindingAdapterPosition)
|
||||
@ -30,7 +37,7 @@ class ExtensionHolder(view: View, val adapter: ExtensionAdapter) :
|
||||
extension is Extension.Untrusted -> itemView.context.getString(R.string.ext_untrusted)
|
||||
extension is Extension.Installed && extension.isObsolete -> itemView.context.getString(R.string.ext_obsolete)
|
||||
extension is Extension.Installed && extension.isUnofficial -> itemView.context.getString(R.string.ext_unofficial)
|
||||
extension.isNsfw -> itemView.context.getString(R.string.ext_nsfw_short)
|
||||
extension.isNsfw && shouldLabelNsfw -> itemView.context.getString(R.string.ext_nsfw_short)
|
||||
else -> ""
|
||||
}.toUpperCase()
|
||||
|
||||
|
@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.ui.browse.extension
|
||||
import android.app.Application
|
||||
import android.os.Bundle
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.extension.ExtensionManager
|
||||
import eu.kanade.tachiyomi.extension.model.Extension
|
||||
@ -56,7 +55,7 @@ open class ExtensionPresenter(
|
||||
private fun toItems(tuple: ExtensionTuple): List<ExtensionItem> {
|
||||
val context = Injekt.get<Application>()
|
||||
val activeLangs = preferences.enabledLanguages().get()
|
||||
val showNsfwExtensions = preferences.allowNsfwSource().get() != PreferenceValues.NsfwAllowance.BLOCKED
|
||||
val showNsfwExtensions = preferences.showNsfwExtension().get()
|
||||
|
||||
val (installed, untrusted, available) = tuple
|
||||
|
||||
|
@ -459,7 +459,6 @@ open class BrowseSourceController(bundle: Bundle) :
|
||||
val adapter = adapter ?: return
|
||||
|
||||
preferences.sourceDisplayMode().set(mode)
|
||||
presenter.refreshDisplayMode()
|
||||
activity?.invalidateOptionsMenu()
|
||||
setupRecycler(view)
|
||||
|
||||
|
@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.ui.browse.source.browse
|
||||
|
||||
import android.os.Bundle
|
||||
import eu.davidea.flexibleadapter.items.IFlexible
|
||||
import eu.davidea.flexibleadapter.items.ISectionable
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.database.models.Category
|
||||
@ -34,10 +33,13 @@ import eu.kanade.tachiyomi.util.chapter.ChapterSettingsHelper
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import eu.kanade.tachiyomi.util.lang.launchUI
|
||||
import eu.kanade.tachiyomi.util.removeCovers
|
||||
import kotlinx.coroutines.Job
|
||||
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 kotlinx.coroutines.isActive
|
||||
import rx.Observable
|
||||
import rx.Subscription
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
@ -106,11 +108,6 @@ open class BrowseSourcePresenter(
|
||||
*/
|
||||
private var pageSubscription: Subscription? = null
|
||||
|
||||
/**
|
||||
* Job to initialize manga details.
|
||||
*/
|
||||
private var initializerJob: Job? = null
|
||||
|
||||
override fun onCreate(savedState: Bundle?) {
|
||||
super.onCreate(savedState)
|
||||
|
||||
@ -140,8 +137,6 @@ open class BrowseSourcePresenter(
|
||||
this.query = query
|
||||
this.appliedFilters = filters
|
||||
|
||||
initializeManga()
|
||||
|
||||
// Create a new pager.
|
||||
pager = createPager(query, filters)
|
||||
|
||||
@ -193,27 +188,6 @@ open class BrowseSourcePresenter(
|
||||
return pager.hasNextPage
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribes to the initializer of manga details and updates the view if needed.
|
||||
*/
|
||||
private fun initializeManga() {
|
||||
initializerJob?.cancel()
|
||||
initializerJob = launchIO {
|
||||
mangaDetailsFlow
|
||||
.onEach { mangas ->
|
||||
if (!isActive) return@onEach
|
||||
|
||||
try {
|
||||
mangas.filter { it.thumbnail_url == null && !it.initialized }
|
||||
.map { getMangaDetails(it) }
|
||||
.forEach { launchUI { view?.onMangaInitialized(it) } }
|
||||
} catch (error: Exception) {
|
||||
launchUI { Timber.e(error) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a manga from the database for the given manga from network. It creates a new entry
|
||||
* if the manga is not yet in the database.
|
||||
@ -239,7 +213,19 @@ open class BrowseSourcePresenter(
|
||||
* @param mangas the list of manga to initialize.
|
||||
*/
|
||||
fun initializeMangas(mangas: List<Manga>) {
|
||||
launchIO { mangaDetailsFlow.emit(mangas) }
|
||||
launchIO {
|
||||
mangas.asFlow()
|
||||
.filter { it.thumbnail_url == null && !it.initialized }
|
||||
.map { getMangaDetails(it) }
|
||||
.onEach {
|
||||
launchUI {
|
||||
@Suppress("DEPRECATION")
|
||||
view?.onMangaInitialized(it)
|
||||
}
|
||||
}
|
||||
.catch { e -> Timber.e(e) }
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -249,17 +235,15 @@ open class BrowseSourcePresenter(
|
||||
* @return the initialized manga
|
||||
*/
|
||||
private suspend fun getMangaDetails(manga: Manga): Manga {
|
||||
return try {
|
||||
source.getMangaDetails(manga.toMangaInfo())
|
||||
.let { networkManga ->
|
||||
manga.copyFrom(networkManga.toSManga())
|
||||
manga.initialized = true
|
||||
db.insertManga(manga).executeAsBlocking()
|
||||
manga
|
||||
}
|
||||
try {
|
||||
val networkManga = source.getMangaDetails(manga.toMangaInfo())
|
||||
manga.copyFrom(networkManga.toSManga())
|
||||
manga.initialized = true
|
||||
db.insertManga(manga).executeAsBlocking()
|
||||
} catch (e: Exception) {
|
||||
manga
|
||||
Timber.e(e)
|
||||
}
|
||||
return manga
|
||||
}
|
||||
|
||||
/**
|
||||
@ -283,13 +267,6 @@ open class BrowseSourcePresenter(
|
||||
db.insertManga(manga).executeAsBlocking()
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the active display mode.
|
||||
*/
|
||||
fun refreshDisplayMode() {
|
||||
initializeManga()
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the filter states for the current source.
|
||||
*
|
||||
@ -321,7 +298,7 @@ open class BrowseSourcePresenter(
|
||||
is Filter.Text -> TextSectionItem(it)
|
||||
is Filter.Select<*> -> SelectSectionItem(it)
|
||||
else -> null
|
||||
} as? ISectionable<*, *>
|
||||
}
|
||||
}
|
||||
subItems.forEach { it.header = group }
|
||||
group.subItems = subItems
|
||||
|
@ -1,9 +1,10 @@
|
||||
package eu.kanade.tachiyomi.ui.library
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Category
|
||||
import eu.kanade.tachiyomi.databinding.LibraryCategoryBinding
|
||||
import eu.kanade.tachiyomi.util.view.inflate
|
||||
import eu.kanade.tachiyomi.widget.RecyclerViewPagerAdapter
|
||||
|
||||
@ -34,8 +35,9 @@ class LibraryAdapter(private val controller: LibraryController) : RecyclerViewPa
|
||||
* @return a new view.
|
||||
*/
|
||||
override fun createView(container: ViewGroup): View {
|
||||
val view = container.inflate(R.layout.library_category) as LibraryCategoryView
|
||||
view.onCreate(controller)
|
||||
val binding = LibraryCategoryBinding.inflate(LayoutInflater.from(container.context), container, false)
|
||||
val view: LibraryCategoryView = binding.root
|
||||
view.onCreate(controller, binding)
|
||||
return view
|
||||
}
|
||||
|
||||
|
@ -14,12 +14,11 @@ import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateService
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues.DisplayMode
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.databinding.LibraryCategoryBinding
|
||||
import eu.kanade.tachiyomi.util.lang.plusAssign
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import eu.kanade.tachiyomi.util.view.inflate
|
||||
import eu.kanade.tachiyomi.widget.AutofitRecyclerView
|
||||
import kotlinx.android.synthetic.main.library_category.view.fast_scroller
|
||||
import kotlinx.android.synthetic.main.library_category.view.swipe_refresh
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
@ -70,15 +69,15 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
|
||||
|
||||
private var lastClickPosition = -1
|
||||
|
||||
fun onCreate(controller: LibraryController) {
|
||||
fun onCreate(controller: LibraryController, binding: LibraryCategoryBinding) {
|
||||
this.controller = controller
|
||||
|
||||
recycler = if (preferences.libraryDisplayMode().get() == DisplayMode.LIST) {
|
||||
(swipe_refresh.inflate(R.layout.library_list_recycler) as RecyclerView).apply {
|
||||
(binding.swipeRefresh.inflate(R.layout.library_list_recycler) as RecyclerView).apply {
|
||||
layoutManager = LinearLayoutManager(context)
|
||||
}
|
||||
} else {
|
||||
(swipe_refresh.inflate(R.layout.library_grid_recycler) as AutofitRecyclerView).apply {
|
||||
(binding.swipeRefresh.inflate(R.layout.library_grid_recycler) as AutofitRecyclerView).apply {
|
||||
spanCount = controller.mangaPerRow
|
||||
}
|
||||
}
|
||||
@ -87,28 +86,28 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
|
||||
|
||||
recycler.setHasFixedSize(true)
|
||||
recycler.adapter = adapter
|
||||
swipe_refresh.addView(recycler)
|
||||
adapter.fastScroller = fast_scroller
|
||||
binding.swipeRefresh.addView(recycler)
|
||||
adapter.fastScroller = binding.fastScroller
|
||||
|
||||
recycler.scrollStateChanges()
|
||||
.onEach {
|
||||
// Disable swipe refresh when view is not at the top
|
||||
val firstPos = (recycler.layoutManager as LinearLayoutManager)
|
||||
.findFirstCompletelyVisibleItemPosition()
|
||||
swipe_refresh.isEnabled = firstPos <= 0
|
||||
binding.swipeRefresh.isEnabled = firstPos <= 0
|
||||
}
|
||||
.launchIn(scope)
|
||||
|
||||
// Double the distance required to trigger sync
|
||||
swipe_refresh.setDistanceToTriggerSync((2 * 64 * resources.displayMetrics.density).toInt())
|
||||
swipe_refresh.refreshes()
|
||||
binding.swipeRefresh.setDistanceToTriggerSync((2 * 64 * resources.displayMetrics.density).toInt())
|
||||
binding.swipeRefresh.refreshes()
|
||||
.onEach {
|
||||
if (LibraryUpdateService.start(context, category)) {
|
||||
context.toast(R.string.updating_category)
|
||||
}
|
||||
|
||||
// It can be a very long operation, so we disable swipe refresh and show a toast.
|
||||
swipe_refresh.isRefreshing = false
|
||||
binding.swipeRefresh.isRefreshing = false
|
||||
}
|
||||
.launchIn(scope)
|
||||
}
|
||||
|
@ -143,7 +143,7 @@ class LibraryController(
|
||||
if (preferences.categoryTabs().get()) {
|
||||
currentTitle = resources?.getString(R.string.label_library)
|
||||
} else {
|
||||
adapter?.categories?.get(binding.libraryPager.currentItem)?.let {
|
||||
adapter?.categories?.getOrNull(binding.libraryPager.currentItem)?.let {
|
||||
currentTitle = it.name
|
||||
}
|
||||
}
|
||||
|
@ -923,7 +923,7 @@ class MangaController :
|
||||
private fun markPreviousAsRead(chapters: List<ChapterItem>) {
|
||||
val adapter = chaptersAdapter ?: return
|
||||
val prevChapters = if (presenter.sortDescending()) adapter.items.reversed() else adapter.items
|
||||
val chapterPos = prevChapters.indexOf(chapters.last())
|
||||
val chapterPos = prevChapters.indexOf(chapters.lastOrNull())
|
||||
if (chapterPos != -1) {
|
||||
markAsRead(prevChapters.take(chapterPos))
|
||||
}
|
||||
|
@ -33,9 +33,6 @@ import java.util.TimeZone
|
||||
|
||||
class AboutController : SettingsController() {
|
||||
|
||||
/**
|
||||
* Checks for new releases
|
||||
*/
|
||||
private val updateChecker by lazy { GithubUpdateChecker() }
|
||||
|
||||
private val dateFormat: DateFormat = preferences.dateFormat()
|
||||
|
@ -20,7 +20,7 @@ class DirectoryPageLoader(val file: File) : PageLoader() {
|
||||
override fun getPages(): Observable<List<ReaderPage>> {
|
||||
return file.listFiles()
|
||||
.filter { !it.isDirectory && ImageUtil.isImage(it.name) { FileInputStream(it) } }
|
||||
.sortedWith(Comparator<File> { f1, f2 -> f1.name.compareToCaseInsensitiveNaturalOrder(f2.name) })
|
||||
.sortedWith { f1, f2 -> f1.name.compareToCaseInsensitiveNaturalOrder(f2.name) }
|
||||
.mapIndexed { i, file ->
|
||||
val streamFn = { FileInputStream(file) }
|
||||
ReaderPage(i).apply {
|
||||
|
@ -8,7 +8,6 @@ import eu.kanade.tachiyomi.util.system.ImageUtil
|
||||
import rx.Observable
|
||||
import java.io.File
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipFile
|
||||
|
||||
/**
|
||||
@ -40,7 +39,7 @@ class ZipPageLoader(file: File) : PageLoader() {
|
||||
override fun getPages(): Observable<List<ReaderPage>> {
|
||||
return zip.entries().toList()
|
||||
.filter { !it.isDirectory && ImageUtil.isImage(it.name) { zip.getInputStream(it) } }
|
||||
.sortedWith(Comparator<ZipEntry> { f1, f2 -> f1.name.compareToCaseInsensitiveNaturalOrder(f2.name) })
|
||||
.sortedWith { f1, f2 -> f1.name.compareToCaseInsensitiveNaturalOrder(f2.name) }
|
||||
.mapIndexed { i, entry ->
|
||||
val streamFn = { zip.getInputStream(entry) }
|
||||
ReaderPage(i).apply {
|
||||
|
@ -185,7 +185,7 @@ abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer {
|
||||
* activity of the change and requests the preload of the next chapter if this is the last page.
|
||||
*/
|
||||
private fun onReaderPageSelected(page: ReaderPage, allowPreload: Boolean) {
|
||||
val pages = page.chapter.pages!! // Won't be null because it's the loaded chapter
|
||||
val pages = page.chapter.pages ?: return
|
||||
Timber.d("onReaderPageSelected: ${page.number}/${pages.size}")
|
||||
activity.onPageSelected(page)
|
||||
|
||||
|
@ -185,7 +185,7 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr
|
||||
* activity of the change and requests the preload of the next chapter if this is the last page.
|
||||
*/
|
||||
private fun onPageSelected(page: ReaderPage, allowPreload: Boolean) {
|
||||
val pages = page.chapter.pages!! // Won't be null because it's the loaded chapter
|
||||
val pages = page.chapter.pages ?: return
|
||||
Timber.d("onPageSelected: ${page.number}/${pages.size}")
|
||||
activity.onPageSelected(page)
|
||||
|
||||
@ -293,11 +293,11 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr
|
||||
}
|
||||
KeyEvent.KEYCODE_MENU -> if (isUp) activity.toggleMenu()
|
||||
|
||||
KeyEvent.KEYCODE_DPAD_RIGHT,
|
||||
KeyEvent.KEYCODE_DPAD_LEFT,
|
||||
KeyEvent.KEYCODE_DPAD_UP,
|
||||
KeyEvent.KEYCODE_PAGE_UP -> if (isUp) scrollUp()
|
||||
|
||||
KeyEvent.KEYCODE_DPAD_LEFT,
|
||||
KeyEvent.KEYCODE_DPAD_RIGHT,
|
||||
KeyEvent.KEYCODE_DPAD_DOWN,
|
||||
KeyEvent.KEYCODE_PAGE_DOWN -> if (isUp) scrollDown()
|
||||
else -> return false
|
||||
|
@ -2,26 +2,26 @@ package eu.kanade.tachiyomi.ui.recent
|
||||
|
||||
import android.text.format.DateUtils
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.AbstractHeaderItem
|
||||
import eu.davidea.flexibleadapter.items.IFlexible
|
||||
import eu.davidea.viewholders.FlexibleViewHolder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.databinding.RecentSectionItemBinding
|
||||
import java.util.Date
|
||||
|
||||
class DateSectionItem(val date: Date) : AbstractHeaderItem<DateSectionItem.Holder>() {
|
||||
class DateSectionItem(val date: Date) : AbstractHeaderItem<DateSectionItem.DateSectionItemHolder>() {
|
||||
|
||||
override fun getLayoutRes(): Int {
|
||||
return R.layout.recent_section_item
|
||||
}
|
||||
|
||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): Holder {
|
||||
return Holder(view, adapter)
|
||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): DateSectionItemHolder {
|
||||
return DateSectionItemHolder(view, adapter)
|
||||
}
|
||||
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>, holder: Holder, position: Int, payloads: List<Any?>?) {
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>, holder: DateSectionItemHolder, position: Int, payloads: List<Any?>?) {
|
||||
holder.bind(this)
|
||||
}
|
||||
|
||||
@ -37,14 +37,14 @@ class DateSectionItem(val date: Date) : AbstractHeaderItem<DateSectionItem.Holde
|
||||
return date.hashCode()
|
||||
}
|
||||
|
||||
class Holder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter, true) {
|
||||
inner class DateSectionItemHolder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter, true) {
|
||||
|
||||
private val binding = RecentSectionItemBinding.bind(view)
|
||||
|
||||
private val now = Date().time
|
||||
|
||||
val section_text: TextView = view.findViewById(R.id.section_text)
|
||||
|
||||
fun bind(item: DateSectionItem) {
|
||||
section_text.text = DateUtils.getRelativeTimeSpanString(item.date.time, now, DateUtils.DAY_IN_MILLIS)
|
||||
binding.sectionText.text = DateUtils.getRelativeTimeSpanString(item.date.time, now, DateUtils.DAY_IN_MILLIS)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ class SettingsAdvancedController : SettingsController() {
|
||||
switchPreference {
|
||||
key = Keys.enableDoh
|
||||
titleRes = R.string.pref_dns_over_https
|
||||
summaryRes = R.string.pref_dns_over_https_summary
|
||||
summaryRes = R.string.requires_app_restart
|
||||
defaultValue = false
|
||||
}
|
||||
}
|
||||
|
@ -39,7 +39,6 @@ import eu.kanade.tachiyomi.util.preference.preferenceCategory
|
||||
import eu.kanade.tachiyomi.util.preference.summaryRes
|
||||
import eu.kanade.tachiyomi.util.preference.switchPreference
|
||||
import eu.kanade.tachiyomi.util.preference.titleRes
|
||||
import eu.kanade.tachiyomi.util.system.getFilePicker
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
@ -125,13 +124,11 @@ class SettingsBackupController : SettingsController() {
|
||||
titleRes = R.string.pref_backup_directory
|
||||
|
||||
onClick {
|
||||
val currentDir = preferences.backupsDirectory().get()
|
||||
try {
|
||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||
startActivityForResult(intent, CODE_BACKUP_DIR)
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
// Fall back to custom picker on error
|
||||
startActivityForResult(preferences.context.getFilePicker(currentDir), CODE_BACKUP_DIR)
|
||||
activity?.toast(R.string.file_picker_error)
|
||||
}
|
||||
}
|
||||
|
||||
@ -205,7 +202,7 @@ class SettingsBackupController : SettingsController() {
|
||||
)
|
||||
}
|
||||
CODE_BACKUP_RESTORE -> {
|
||||
uri?.path?.let { path ->
|
||||
uri?.path?.let {
|
||||
val fileName = DocumentFile.fromSingleUri(activity, uri)!!.name!!
|
||||
when {
|
||||
fileName.endsWith(".proto.gz") -> {
|
||||
@ -258,7 +255,6 @@ class SettingsBackupController : SettingsController() {
|
||||
|
||||
fun createBackup(flags: Int, type: Int) {
|
||||
backupFlags = flags
|
||||
val currentDir = preferences.backupsDirectory().get()
|
||||
val code = when (type) {
|
||||
BackupConst.BACKUP_TYPE_FULL -> CODE_FULL_BACKUP_CREATE
|
||||
else -> CODE_LEGACY_BACKUP_CREATE
|
||||
@ -277,8 +273,7 @@ class SettingsBackupController : SettingsController() {
|
||||
|
||||
startActivityForResult(intent, code)
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
// Handle errors where the Android ROM doesn't support the built in picker
|
||||
startActivityForResult(preferences.context.getFilePicker(currentDir), code)
|
||||
activity?.toast(R.string.file_picker_error)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,12 +2,16 @@ package eu.kanade.tachiyomi.ui.setting
|
||||
|
||||
import androidx.preference.PreferenceScreen
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.asImmediateFlow
|
||||
import eu.kanade.tachiyomi.extension.ExtensionUpdateJob
|
||||
import eu.kanade.tachiyomi.util.preference.defaultValue
|
||||
import eu.kanade.tachiyomi.util.preference.infoPreference
|
||||
import eu.kanade.tachiyomi.util.preference.onChange
|
||||
import eu.kanade.tachiyomi.util.preference.preferenceCategory
|
||||
import eu.kanade.tachiyomi.util.preference.summaryRes
|
||||
import eu.kanade.tachiyomi.util.preference.switchPreference
|
||||
import eu.kanade.tachiyomi.util.preference.titleRes
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||
|
||||
class SettingsBrowseController : SettingsController() {
|
||||
@ -41,27 +45,29 @@ class SettingsBrowseController : SettingsController() {
|
||||
}
|
||||
}
|
||||
|
||||
// preferenceCategory {
|
||||
// titleRes = R.string.pref_category_nsfw_content
|
||||
//
|
||||
// listPreference {
|
||||
// key = Keys.allowNsfwSource
|
||||
// titleRes = R.string.pref_allow_nsfw_sources
|
||||
// entriesRes = arrayOf(
|
||||
// R.string.pref_allow_nsfw_sources_allowed,
|
||||
// R.string.pref_allow_nsfw_sources_allowed_multisource,
|
||||
// R.string.pref_allow_nsfw_sources_blocked
|
||||
// )
|
||||
// entryValues = arrayOf(
|
||||
// PreferenceValues.NsfwAllowance.ALLOWED.name,
|
||||
// PreferenceValues.NsfwAllowance.PARTIAL.name,
|
||||
// PreferenceValues.NsfwAllowance.BLOCKED.name
|
||||
// )
|
||||
// defaultValue = PreferenceValues.NsfwAllowance.ALLOWED.name
|
||||
// summary = "%s"
|
||||
// }
|
||||
//
|
||||
// infoPreference(R.string.parental_controls_info)
|
||||
// }
|
||||
preferenceCategory {
|
||||
titleRes = R.string.pref_category_nsfw_content
|
||||
|
||||
switchPreference {
|
||||
key = Keys.showNsfwSource
|
||||
titleRes = R.string.pref_show_nsfw_source
|
||||
summaryRes = R.string.requires_app_restart
|
||||
defaultValue = true
|
||||
}
|
||||
switchPreference {
|
||||
key = Keys.showNsfwExtension
|
||||
titleRes = R.string.pref_show_nsfw_extension
|
||||
defaultValue = true
|
||||
}
|
||||
switchPreference {
|
||||
key = Keys.labelNsfwExtension
|
||||
titleRes = R.string.pref_label_nsfw_extension
|
||||
defaultValue = true
|
||||
|
||||
preferences.showNsfwExtension().asImmediateFlow { isVisible = it }.launchIn(scope)
|
||||
}
|
||||
|
||||
infoPreference(R.string.parental_controls_info)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ import eu.kanade.tachiyomi.util.preference.preference
|
||||
import eu.kanade.tachiyomi.util.preference.preferenceCategory
|
||||
import eu.kanade.tachiyomi.util.preference.switchPreference
|
||||
import eu.kanade.tachiyomi.util.preference.titleRes
|
||||
import eu.kanade.tachiyomi.util.system.getFilePicker
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import uy.kohesive.injekt.Injekt
|
||||
@ -155,12 +155,12 @@ class SettingsDownloadController : SettingsController() {
|
||||
preferences.downloadsDirectory().set(path.toString())
|
||||
}
|
||||
|
||||
fun customDirectorySelected(currentDir: String) {
|
||||
fun customDirectorySelected() {
|
||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||
try {
|
||||
startActivityForResult(intent, DOWNLOAD_DIR)
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
startActivityForResult(preferences.context.getFilePicker(currentDir), DOWNLOAD_DIR)
|
||||
activity?.toast(R.string.file_picker_error)
|
||||
}
|
||||
}
|
||||
|
||||
@ -181,7 +181,7 @@ class SettingsDownloadController : SettingsController() {
|
||||
) { _, position, text ->
|
||||
val target = targetController as? SettingsDownloadController
|
||||
if (position == externalDirs.lastIndex) {
|
||||
target?.customDirectorySelected(currentDir)
|
||||
target?.customDirectorySelected()
|
||||
} else {
|
||||
target?.predefinedDirectorySelected(text.toString())
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ object SettingsSearchHelper {
|
||||
(pref.title != null) -> {
|
||||
// Is an actual preference
|
||||
val title = pref.title.toString()
|
||||
val summary = if (pref.summary != null) pref.summary.toString() else ""
|
||||
val summary = pref.summary?.toString() ?: ""
|
||||
val breadcrumbsStr = addLocalizedBreadcrumb(breadcrumbs, "${pref.title}")
|
||||
|
||||
prefSearchResultList.add(
|
||||
|
@ -31,15 +31,17 @@ open class BaseWebViewActivity : BaseActivity<WebviewActivityBinding>() {
|
||||
if (!WebViewUtil.supportsWebView(this)) {
|
||||
toast(R.string.information_webview_required, Toast.LENGTH_LONG)
|
||||
finish()
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
binding = WebviewActivityBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
} catch (e: Exception) {
|
||||
} catch (e: Throwable) {
|
||||
// Potentially throws errors like "Error inflating class android.webkit.WebView"
|
||||
toast(R.string.information_webview_required, Toast.LENGTH_LONG)
|
||||
finish()
|
||||
return
|
||||
}
|
||||
|
||||
title = intent.extras?.getString(TITLE_KEY)
|
||||
|
@ -29,10 +29,8 @@ import androidx.core.graphics.green
|
||||
import androidx.core.graphics.red
|
||||
import androidx.core.net.toUri
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||
import com.nononsenseapps.filepicker.FilePickerActivity
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.util.lang.truncateCenter
|
||||
import eu.kanade.tachiyomi.widget.CustomLayoutPickerActivity
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
/**
|
||||
@ -98,19 +96,6 @@ fun Context.notification(channelId: String, block: (NotificationCompat.Builder.(
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to construct an Intent to use a custom file picker.
|
||||
* @param currentDir the path the file picker will open with.
|
||||
* @return an Intent to start the file picker activity.
|
||||
*/
|
||||
fun Context.getFilePicker(currentDir: String): Intent {
|
||||
return Intent(this, CustomLayoutPickerActivity::class.java)
|
||||
.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false)
|
||||
.putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, true)
|
||||
.putExtra(FilePickerActivity.EXTRA_MODE, FilePickerActivity.MODE_DIR)
|
||||
.putExtra(FilePickerActivity.EXTRA_START_PATH, currentDir)
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the give permission is granted.
|
||||
*
|
||||
|
@ -13,7 +13,7 @@ object WebViewUtil {
|
||||
|
||||
const val REQUESTED_WITH = "com.android.browser"
|
||||
|
||||
const val MINIMUM_WEBVIEW_VERSION = 84
|
||||
const val MINIMUM_WEBVIEW_VERSION = 86
|
||||
|
||||
fun supportsWebView(context: Context): Boolean {
|
||||
try {
|
||||
|
@ -1,33 +0,0 @@
|
||||
package eu.kanade.tachiyomi.widget
|
||||
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.nononsenseapps.filepicker.AbstractFilePickerFragment
|
||||
import com.nononsenseapps.filepicker.FilePickerActivity
|
||||
import com.nononsenseapps.filepicker.FilePickerFragment
|
||||
import com.nononsenseapps.filepicker.LogicHandler
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.util.view.inflate
|
||||
import java.io.File
|
||||
|
||||
class CustomLayoutPickerActivity : FilePickerActivity() {
|
||||
|
||||
override fun getFragment(startPath: String?, mode: Int, allowMultiple: Boolean, allowCreateDir: Boolean):
|
||||
AbstractFilePickerFragment<File> {
|
||||
val fragment = CustomLayoutFilePickerFragment()
|
||||
fragment.setArgs(startPath, mode, allowMultiple, allowCreateDir)
|
||||
return fragment
|
||||
}
|
||||
}
|
||||
|
||||
class CustomLayoutFilePickerFragment : FilePickerFragment() {
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
return when (viewType) {
|
||||
LogicHandler.VIEWTYPE_DIR -> {
|
||||
val view = parent.inflate(R.layout.common_listitem_dir)
|
||||
DirViewHolder(view)
|
||||
}
|
||||
else -> super.onCreateViewHolder(parent, viewType)
|
||||
}
|
||||
}
|
||||
}
|
9
app/src/main/res/drawable/ic_folder_24dp.xml
Normal file
9
app/src/main/res/drawable/ic_folder_24dp.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M10,4H4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V8c0,-1.1 -0.9,-2 -2,-2h-8l-2,-2z" />
|
||||
</vector>
|
@ -1,38 +0,0 @@
|
||||
<?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:id="@+id/nnf_item_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?android:listPreferredItemHeight"
|
||||
android:background="?selectableItemBackground"
|
||||
android:focusable="true"
|
||||
android:minHeight="?android:listPreferredItemHeight"
|
||||
android:nextFocusLeft="@+id/nnf_button_cancel"
|
||||
android:nextFocusRight="@+id/nnf_button_ok"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/item_icon"
|
||||
android:layout_width="?android:listPreferredItemHeight"
|
||||
android:layout_height="?android:listPreferredItemHeight"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="center"
|
||||
android:src="@drawable/nnf_ic_file_folder"
|
||||
android:visibility="visible"
|
||||
app:tint="?attr/colorAccent"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/text1"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center_vertical"
|
||||
android:maxLines="1"
|
||||
android:padding="8dp"
|
||||
android:singleLine="true"
|
||||
android:text="@string/nnf_name" />
|
||||
|
||||
</LinearLayout>
|
@ -601,7 +601,7 @@
|
||||
<string name="action_start">ابدأ</string>
|
||||
<string name="action_sort_date_added">تاريخ الاضافة</string>
|
||||
<string name="whats_new">ما الجديد</string>
|
||||
<string name="pref_dns_over_https_summary">يتطلب إعادة تشغيل التطبيق ليتم تفعيله</string>
|
||||
<string name="requires_app_restart">يتطلب إعادة تشغيل التطبيق ليتم تفعيله</string>
|
||||
<string name="label_network">شبكة الاتصال</string>
|
||||
<string name="backup_restore_missing_trackers">أجهزة التتبع التي لم يتم تسجيل الدخول إليها:</string>
|
||||
<string name="pref_remove_bookmarked_chapters">حذف الفصول ذات العلامة المرجعية</string>
|
||||
|
@ -375,7 +375,7 @@
|
||||
<string name="pref_clear_chapter_cache">Borrar caché de los capítulos</string>
|
||||
<string name="label_data">Datos</string>
|
||||
<string name="cookies_cleared">Cookies borradas</string>
|
||||
<string name="pref_dns_over_https_summary">Requiere el reinicio de la aplicación para que surta efecto</string>
|
||||
<string name="requires_app_restart">Requiere el reinicio de la aplicación para que surta efecto</string>
|
||||
<string name="battery_optimization_disabled">La optimización de la batería ya está desactivada</string>
|
||||
<string name="pref_disable_battery_optimization_summary">Ayuda con las actualizaciones y las copias de seguridad de biblioteca en segundo plano</string>
|
||||
<string name="pref_disable_battery_optimization">Desactivar optimización de batería</string>
|
||||
|
@ -581,7 +581,7 @@
|
||||
<string name="tabs_header">Раздели</string>
|
||||
<string name="badges_header">Значки</string>
|
||||
<string name="label_data">Данни</string>
|
||||
<string name="pref_dns_over_https_summary">Изисква рестартиране на приложението, за да влезе в сила</string>
|
||||
<string name="requires_app_restart">Изисква рестартиране на приложението, за да влезе в сила</string>
|
||||
<string name="label_network">Мрежа</string>
|
||||
<string name="backup_restore_missing_sources">Липсващи източници:</string>
|
||||
<string name="invalid_backup_file_missing_manga">Резервното копие не съдържа манга.</string>
|
||||
|
@ -464,7 +464,7 @@
|
||||
<string name="set_chapter_settings_as_default">প্রকৃত হিসেবে সংরক্ষণ করুন</string>
|
||||
<string name="confirm_set_chapter_settings">আপনি কি নিশ্চিত সেটিংসগুলো প্রকৃত হিসেবে সংরক্ষণ করবেন\?</string>
|
||||
<string name="label_data">তথ্য</string>
|
||||
<string name="pref_dns_over_https_summary">কার্যকর করতে অ্যাপ পুনরারম্ভ করতে হবে</string>
|
||||
<string name="requires_app_restart">কার্যকর করতে অ্যাপ পুনরারম্ভ করতে হবে</string>
|
||||
<string name="label_network">নেটওয়ার্ক</string>
|
||||
<string name="restoring_backup_canceled">পুনরুদ্ধার বাতিল করা হয়েছে</string>
|
||||
<string name="restoring_backup_error">ব্যাকআপ পুনরুদ্ধার ব্যর্থ হয়েছে</string>
|
||||
|
@ -573,7 +573,7 @@
|
||||
<string name="action_global_search_query">Cerca \"%1$s\" globalment</string>
|
||||
<string name="updated_version">S\'ha actualitzat a la v%1$s</string>
|
||||
<string name="whats_new">Novetats</string>
|
||||
<string name="pref_dns_over_https_summary">Cal reiniciar l\'aplicació perquè s\'apliqui</string>
|
||||
<string name="requires_app_restart">Cal reiniciar l\'aplicació perquè s\'apliqui</string>
|
||||
<string name="label_network">Xarxa</string>
|
||||
<string name="pref_category_reading_mode">Mode de lectura</string>
|
||||
<string name="pref_show_reading_mode_summary">Mostra breument el mode actual en obrir el lector</string>
|
||||
|
@ -558,7 +558,7 @@
|
||||
<string name="cache_deleted">Кеша тастнӑ. %1$d файла катертнӗ</string>
|
||||
<string name="pref_clear_chapter_cache">Сыпӑксен кешне тасат</string>
|
||||
<string name="label_data">Пӗлӗмсем</string>
|
||||
<string name="pref_dns_over_https_summary">Вӑя кӗрес тесен хушӑма сӳнтерсе ҫутмалла</string>
|
||||
<string name="requires_app_restart">Вӑя кӗрес тесен хушӑма сӳнтерсе ҫутмалла</string>
|
||||
<string name="restoring_backup_canceled">Тавӑрнине пӑрахӑҫланӑ</string>
|
||||
<string name="restoring_backup_error">Янтӑв тавӑрни йӑнӑшӗ</string>
|
||||
<string name="restoring_backup">Янтӑв тавӑрни</string>
|
||||
|
@ -568,7 +568,7 @@
|
||||
<item quantity="other">%1$s Kapitel</item>
|
||||
</plurals>
|
||||
<string name="action_open_in_settings">In den Einstellungen öffnen</string>
|
||||
<string name="pref_dns_over_https_summary">App muss neu gestartet werden, um die Einstellung zu übernehmen</string>
|
||||
<string name="requires_app_restart">App muss neu gestartet werden, um die Einstellung zu übernehmen</string>
|
||||
<string name="pref_dns_over_https" translatable="false">DNS über HTTPS (Cloudflare)</string>
|
||||
<string name="label_network">Netzwerk</string>
|
||||
<string name="pref_jump_to_chapters">Beim Öffnen zu den Kapiteln springen</string>
|
||||
|
@ -568,7 +568,7 @@
|
||||
<item quantity="other">%1$s κεφάλαια</item>
|
||||
</plurals>
|
||||
<string name="action_open_in_settings">Άνοιγμα στις Ρυθμίσεις</string>
|
||||
<string name="pref_dns_over_https_summary">Απαιτείται επανεκκίνηση της εφαρμογής για να τεθεί σε ισχύ</string>
|
||||
<string name="requires_app_restart">Απαιτείται επανεκκίνηση της εφαρμογής για να τεθεί σε ισχύ</string>
|
||||
<string name="pref_dns_over_https" translatable="false">DNS μέσω HTTPS (Cloudflare)</string>
|
||||
<string name="label_network">Δίκτυο</string>
|
||||
<string name="pref_jump_to_chapters">Μετάβαση στα κεφάλαια κατά το άνοιγμα</string>
|
||||
|
@ -599,7 +599,7 @@
|
||||
<string name="action_sort_descending">Descendente</string>
|
||||
<string name="action_disable">Desactivar</string>
|
||||
<string name="action_open_in_settings">Abrir en Configuración</string>
|
||||
<string name="pref_dns_over_https_summary">Requiere el reinicio de la aplicación para que surta efecto</string>
|
||||
<string name="requires_app_restart">Requiere el reinicio de la aplicación para que surta efecto</string>
|
||||
<string name="pref_dns_over_https" translatable="false">DNS sobre HTTPS (Cloudflare)</string>
|
||||
<string name="label_network">Red</string>
|
||||
<string name="pref_jump_to_chapters">Saltar a los capítulos abiertos</string>
|
||||
|
@ -581,7 +581,7 @@
|
||||
<string name="no_pinned_sources">شما هیچ منبع پینشدهای ندارید</string>
|
||||
<string name="action_global_search_query">«%1$s» در همه منابع جستجو شود</string>
|
||||
<string name="whats_new">اخبار</string>
|
||||
<string name="pref_dns_over_https_summary">برای اعمال تغییرات برنامه نیاز به راه اندازی مجدد دارد</string>
|
||||
<string name="requires_app_restart">برای اعمال تغییرات برنامه نیاز به راه اندازی مجدد دارد</string>
|
||||
<string name="label_network">شبکه</string>
|
||||
<string name="backup_restore_missing_trackers">ردیابیهایی که به سیستم وارد نشده اند:</string>
|
||||
<string name="pref_category_reading_mode">حالت خواندن</string>
|
||||
|
@ -568,7 +568,7 @@
|
||||
<item quantity="other">%1$s lukua</item>
|
||||
</plurals>
|
||||
<string name="action_open_in_settings">Avaa Asetuksissa</string>
|
||||
<string name="pref_dns_over_https_summary">Edellyttää sovelluksen käynnistämistä uudelleen</string>
|
||||
<string name="requires_app_restart">Edellyttää sovelluksen käynnistämistä uudelleen</string>
|
||||
<string name="pref_dns_over_https" translatable="false">DNS HTTPS:n kautta (Cloudflare)</string>
|
||||
<string name="label_network">Verkko</string>
|
||||
<string name="pref_jump_to_chapters">Siirry lukuihin avatessa</string>
|
||||
|
@ -568,7 +568,7 @@
|
||||
<string name="pref_clear_chapter_cache">Linisin ang cache ng kabanata</string>
|
||||
<string name="label_data">Data</string>
|
||||
<string name="cookies_cleared">Nalinis na ang mga cookie</string>
|
||||
<string name="pref_dns_over_https_summary">Nangangailangang buksan muli ang app para gumana</string>
|
||||
<string name="requires_app_restart">Nangangailangang buksan muli ang app para gumana</string>
|
||||
<string name="pref_clear_cookies">Linisin ang mga cookie</string>
|
||||
<string name="label_network">Network</string>
|
||||
<string name="restoring_backup_error">Pumalya sa pagbalik sa backup</string>
|
||||
|
@ -602,7 +602,7 @@
|
||||
<string name="action_sort_descending">Décroissant</string>
|
||||
<string name="action_disable">Désactiver</string>
|
||||
<string name="action_open_in_settings">Ouvrir dans les paramètres</string>
|
||||
<string name="pref_dns_over_https_summary">Nécessite un redémarrage de l\'application pour prendre effet</string>
|
||||
<string name="requires_app_restart">Nécessite un redémarrage de l\'application pour prendre effet</string>
|
||||
<string name="pref_dns_over_https" translatable="false">DNS sur HTTPS (Cloudflare)</string>
|
||||
<string name="label_network">Réseau</string>
|
||||
<string name="tapping_inverted_both">Les deux</string>
|
||||
|
@ -578,7 +578,7 @@
|
||||
<string name="pref_read_with_tapping_inverted">उलटा दोहन</string>
|
||||
<string name="unknown_status">अज्ञात स्थिति</string>
|
||||
<string name="unknown_author">अज्ञात लेखक</string>
|
||||
<string name="pref_dns_over_https_summary">प्रभावी होने के लिए ऐप पुनः आरंभ करने की आवश्यकता है</string>
|
||||
<string name="requires_app_restart">प्रभावी होने के लिए ऐप पुनः आरंभ करने की आवश्यकता है</string>
|
||||
<string name="action_download_unread">अपठित अध्याय डाउनलोड करें</string>
|
||||
<string name="whats_new">नया क्या है</string>
|
||||
<string name="download_insufficient_space">कम डिस्क स्पेस के कारण अध्याय डाउनलोड नहीं कर सका</string>
|
||||
|
@ -578,7 +578,7 @@
|
||||
<item quantity="few">%1$s poglavlja</item>
|
||||
<item quantity="other">%1$s poglavlja</item>
|
||||
</plurals>
|
||||
<string name="pref_dns_over_https_summary">Za preuzimanje postavke, ponovo pokreni program</string>
|
||||
<string name="requires_app_restart">Za preuzimanje postavke, ponovo pokreni program</string>
|
||||
<string name="pref_dns_over_https" translatable="false">DNS preko HTTPS-a (Cloudflare)</string>
|
||||
<string name="label_network">Mreža</string>
|
||||
<string name="tapping_inverted_both">Oboje</string>
|
||||
|
@ -555,7 +555,7 @@
|
||||
<plurals name="manga_num_chapters">
|
||||
<item quantity="other">%1$s bab</item>
|
||||
</plurals>
|
||||
<string name="pref_dns_over_https_summary">Mulai ulang aplikasi untuk menerapkan pengaturan</string>
|
||||
<string name="requires_app_restart">Mulai ulang aplikasi untuk menerapkan pengaturan</string>
|
||||
<string name="pref_dns_over_https" translatable="false">DNS melalui HTTPS (Cloudflare)</string>
|
||||
<string name="label_network">Jaringan</string>
|
||||
<string name="pref_jump_to_chapters">Lompat ke bab saat dibuka</string>
|
||||
|
@ -604,7 +604,7 @@
|
||||
<string name="unknown_author">Autore sconosciuto</string>
|
||||
<string name="updated_version">Aggiornato verso v%1$s</string>
|
||||
<string name="whats_new">Le novità</string>
|
||||
<string name="pref_dns_over_https_summary">Richiede il riavvio dell\'applicazione per avere effetto</string>
|
||||
<string name="requires_app_restart">Richiede il riavvio dell\'applicazione per avere effetto</string>
|
||||
<string name="pref_dns_over_https" translatable="false">DNS via HTTPS (Cloudflare)</string>
|
||||
<string name="label_network">Rete</string>
|
||||
<string name="pref_show_reading_mode_summary">Mostra brevemente la modalità corrente all\'apertura del lettore</string>
|
||||
|
@ -564,7 +564,7 @@
|
||||
<string name="tapping_inverted_none">なし</string>
|
||||
<string name="unknown_status">不明なステータス</string>
|
||||
<string name="unknown_author">作者不明</string>
|
||||
<string name="pref_dns_over_https_summary">変更を適用するためには再起動してください</string>
|
||||
<string name="requires_app_restart">変更を適用するためには再起動してください</string>
|
||||
<string name="label_network">ネットワーク</string>
|
||||
<string name="pref_jump_to_chapters">起動時にチャプターを表示</string>
|
||||
<string name="pref_read_with_tapping_inverted">タップでのページめくりを反転</string>
|
||||
|
@ -563,7 +563,7 @@
|
||||
</plurals>
|
||||
<string name="updated_version">განახლებულია v%1$s-მდე</string>
|
||||
<string name="whats_new">რა არის ახალი</string>
|
||||
<string name="pref_dns_over_https_summary">ასამოქმედებლად საჭიროა აპლიკაციის გადატვირთვა</string>
|
||||
<string name="requires_app_restart">ასამოქმედებლად საჭიროა აპლიკაციის გადატვირთვა</string>
|
||||
<string name="label_network">ქსელი</string>
|
||||
<plurals name="restore_completed_message">
|
||||
<item quantity="one">გაკეთებულია %1$s %2$s შეცდომით</item>
|
||||
|
@ -578,7 +578,7 @@
|
||||
<string name="action_global_search_query">\"%1$s\" ಅನ್ನು ಗ್ಲೋಬಲ್ ಸರ್ಚ್ ಮಾಡಿ</string>
|
||||
<string name="updated_version">v%1$s ಗೆ ಅಪ್ಡೇಟ್ ಆಗಿದೆ</string>
|
||||
<string name="whats_new">ಹೊಸತೇನಿದೆ</string>
|
||||
<string name="pref_dns_over_https_summary">ಜಾರಿಗೆ ಬರಲು ಅಪ್ಲಿಕೇಶನ್ ಮರುಪ್ರಾರಂಭದ ಅಗತ್ಯವಿದೆ</string>
|
||||
<string name="requires_app_restart">ಜಾರಿಗೆ ಬರಲು ಅಪ್ಲಿಕೇಶನ್ ಮರುಪ್ರಾರಂಭದ ಅಗತ್ಯವಿದೆ</string>
|
||||
<string name="label_network">ಅಡ್ವಾನ್ಸ್ಡ್ ಸೆಕ್ಷನ್</string>
|
||||
<string name="pref_category_reading_mode">ಓದುವ ಮೊಡ್</string>
|
||||
<string name="pref_jump_to_chapters">ಓಪನ್ ಮಾಡಿದ ಮೇಲೆ ಅಧ್ಯಯಕ್ಕೆ ಹೋಗಿ</string>
|
||||
|
@ -558,7 +558,7 @@
|
||||
</plurals>
|
||||
<string name="action_sort_descending">Menurun</string>
|
||||
<string name="action_disable">Matikan</string>
|
||||
<string name="pref_dns_over_https_summary">Mula semula diperlukan untuk berkesan</string>
|
||||
<string name="requires_app_restart">Mula semula diperlukan untuk berkesan</string>
|
||||
<string name="pref_dns_over_https" translatable="false">DNS melalui HTTPS (Cloudflare)</string>
|
||||
<string name="label_network">Rangkaian</string>
|
||||
<string name="pref_jump_to_chapters">Terus ke bab bila buka</string>
|
||||
|
@ -523,7 +523,7 @@
|
||||
<string name="battery_optimization_disabled">Batterioptimalisering er allerede deaktivert</string>
|
||||
<string name="pref_disable_battery_optimization">Deaktiver batterioptimalisering</string>
|
||||
<string name="label_data">Data</string>
|
||||
<string name="pref_dns_over_https_summary">Krever omstart for å tre i kraft</string>
|
||||
<string name="requires_app_restart">Krever omstart for å tre i kraft</string>
|
||||
<string name="label_network">Nettverk</string>
|
||||
<string name="restoring_backup_canceled">Avbrutt gjenoppretting</string>
|
||||
<string name="restore_in_progress">Gjenoppretting er allerede i gang</string>
|
||||
|
@ -568,7 +568,7 @@
|
||||
</plurals>
|
||||
<string name="action_sort_descending">Aflopend</string>
|
||||
<string name="action_open_in_settings">In Instellingen openen</string>
|
||||
<string name="pref_dns_over_https_summary">Herstart van de app nodig om van kracht te worden</string>
|
||||
<string name="requires_app_restart">Herstart van de app nodig om van kracht te worden</string>
|
||||
<string name="pref_dns_over_https" translatable="false">DNS over HTTPS (Cloudflare)</string>
|
||||
<string name="label_network">Netwerk</string>
|
||||
<string name="pref_jump_to_chapters">Ga naar de hoofdstukken bij openen</string>
|
||||
|
@ -581,7 +581,7 @@
|
||||
<string name="action_disable">Wyłącz</string>
|
||||
<string name="action_open_in_settings">Otwórz w ustawieniach</string>
|
||||
<string name="action_start">Start</string>
|
||||
<string name="pref_dns_over_https_summary">Wymaga ponownego uruchomienia aplikacji</string>
|
||||
<string name="requires_app_restart">Wymaga ponownego uruchomienia aplikacji</string>
|
||||
<string name="pref_dns_over_https" translatable="false">DNS przez HTTPS (Cloudflare)</string>
|
||||
<string name="label_network">Sieć</string>
|
||||
<string name="pref_jump_to_chapters">Przeskocz do rozdziałów przy otwarciu</string>
|
||||
|
@ -568,7 +568,7 @@
|
||||
<item quantity="other">%1$s capítulos</item>
|
||||
</plurals>
|
||||
<string name="action_open_in_settings">Abrir nas Configurações</string>
|
||||
<string name="pref_dns_over_https_summary">Requer o reinício do aplicativo para ter efeito</string>
|
||||
<string name="requires_app_restart">Requer o reinício do aplicativo para ter efeito</string>
|
||||
<string name="pref_dns_over_https" translatable="false">DNS sob HTTPS (Cloudflare)</string>
|
||||
<string name="label_network">Rede</string>
|
||||
<string name="pref_jump_to_chapters">Pular para os capítulos ao abrir</string>
|
||||
|
@ -606,7 +606,7 @@
|
||||
</plurals>
|
||||
<string name="unknown_status">Estado desconhecido</string>
|
||||
<string name="unknown_author">Autor desconhecido</string>
|
||||
<string name="pref_dns_over_https_summary">Requer reinício da app para ter efeito</string>
|
||||
<string name="requires_app_restart">Requer reinício da app para ter efeito</string>
|
||||
<string name="label_network">Rede</string>
|
||||
<string name="pref_dns_over_https" translatable="false">DNS por HTTPS (Cloudflare)</string>
|
||||
<string name="updated_version">Atualizado para v%1$s</string>
|
||||
|
@ -575,7 +575,7 @@
|
||||
<item quantity="few">%1$s capitole</item>
|
||||
<item quantity="other">%1$s de capitole</item>
|
||||
</plurals>
|
||||
<string name="pref_dns_over_https_summary">Necesită restartarea aplicației pentru a avea efect</string>
|
||||
<string name="requires_app_restart">Necesită restartarea aplicației pentru a avea efect</string>
|
||||
<string name="pref_dns_over_https" translatable="false">DNS prin HTTPS (Cloudflare)</string>
|
||||
<string name="action_sort_descending">Descrescător</string>
|
||||
<string name="action_disable">Dezactivați</string>
|
||||
|
@ -586,7 +586,7 @@
|
||||
<item quantity="other">%1$s глав</item>
|
||||
</plurals>
|
||||
<string name="action_sort_descending">По убыванию</string>
|
||||
<string name="pref_dns_over_https_summary">Требуется перезапуск приложения для вступления в силу</string>
|
||||
<string name="requires_app_restart">Требуется перезапуск приложения для вступления в силу</string>
|
||||
<string name="pref_dns_over_https" translatable="false">DNS по HTTPS (Cloudflare)</string>
|
||||
<string name="label_network">Сеть</string>
|
||||
<string name="pref_jump_to_chapters">Переходить к главам при запуске</string>
|
||||
|
@ -345,7 +345,7 @@
|
||||
<string name="pref_remove_after_marked_as_read">Ааҕыллыбыт диэн суруллубутун кэннэ</string>
|
||||
<string name="pref_download_only_over_wifi">Wi-Fi эрэ баар буоллаҕына хачайдаа</string>
|
||||
<string name="pref_download_directory">Хачайдааһын сурунаала</string>
|
||||
<string name="pref_dns_over_https_summary">Уларыйыы киирэрин гына эбилиги хос холбоо</string>
|
||||
<string name="requires_app_restart">Уларыйыы киирэрин гына эбилиги хос холбоо</string>
|
||||
<string name="cache_delete_error">Кээс сотторуутугар сыыһааһын буолла</string>
|
||||
<string name="cache_deleted">Кээс ыраастанна. %1$d билэ сотторуллубут этэ</string>
|
||||
<string name="used_cache">Туттуллубут: %1$s</string>
|
||||
|
@ -568,7 +568,7 @@
|
||||
<item quantity="one">1 capìtulu</item>
|
||||
<item quantity="other">%1$s capìtulos</item>
|
||||
</plurals>
|
||||
<string name="pref_dns_over_https_summary">Tenet bisòngiu chi torres a allùghere s\'aplicatzione pro tènnere efetu</string>
|
||||
<string name="requires_app_restart">Tenet bisòngiu chi torres a allùghere s\'aplicatzione pro tènnere efetu</string>
|
||||
<string name="pref_dns_over_https" translatable="false">DNS pro mèdiu de HTTPS (Cloudflare)</string>
|
||||
<string name="label_network">Retza</string>
|
||||
<string name="pref_jump_to_chapters">Brinca a sos capìtulos a s\'abertura</string>
|
||||
|
@ -572,7 +572,7 @@
|
||||
</plurals>
|
||||
<string name="unknown_status">Okänd status</string>
|
||||
<string name="unknown_author">Okänd författare</string>
|
||||
<string name="pref_dns_over_https_summary">Kräver omstart av appen för att börja gälla</string>
|
||||
<string name="requires_app_restart">Kräver omstart av appen för att börja gälla</string>
|
||||
<string name="pref_dns_over_https" translatable="false">DNS över HTTPS (Cloudflare)</string>
|
||||
<string name="label_network">Nätverk</string>
|
||||
<string name="pref_jump_to_chapters">Hoppa till kapitel vid öppning</string>
|
||||
|
@ -568,7 +568,7 @@
|
||||
<item quantity="other">%1$s bölüm</item>
|
||||
</plurals>
|
||||
<string name="action_open_in_settings">Ayarlarda aç</string>
|
||||
<string name="pref_dns_over_https_summary">Etkili olması için uygulama yeniden başlatılmalıdır</string>
|
||||
<string name="requires_app_restart">Etkili olması için uygulama yeniden başlatılmalıdır</string>
|
||||
<string name="pref_dns_over_https" translatable="false">HTTPS ile DNS (Cloudflare)</string>
|
||||
<string name="label_network">Ağ</string>
|
||||
<string name="pref_jump_to_chapters">Açınca bölümlere git</string>
|
||||
|
@ -591,7 +591,7 @@
|
||||
<string name="pref_read_with_tapping_inverted">Інвертувати тицяння</string>
|
||||
<string name="unknown_status">Невідомий статус</string>
|
||||
<string name="unknown_author">Невідомий автор</string>
|
||||
<string name="pref_dns_over_https_summary">Потрібен перезапуск, щоб зміни вступили в дію</string>
|
||||
<string name="requires_app_restart">Потрібен перезапуск, щоб зміни вступили в дію</string>
|
||||
<string name="pref_dns_over_https" translatable="false">DNS понад HTTPS (Cloudflare)</string>
|
||||
<string name="label_network">Мережа</string>
|
||||
<string name="pref_jump_to_chapters">Перейти до глав при відкритті</string>
|
||||
|
@ -558,7 +558,7 @@
|
||||
<item quantity="other">%1$s 个章节</item>
|
||||
</plurals>
|
||||
<string name="action_open_in_settings">在设置中打开</string>
|
||||
<string name="pref_dns_over_https_summary">需要重启应用才能生效</string>
|
||||
<string name="requires_app_restart">需要重启应用才能生效</string>
|
||||
<string name="pref_dns_over_https" translatable="false">DNS over HTTPS (Cloudflare)</string>
|
||||
<string name="label_network">网络</string>
|
||||
<string name="pref_jump_to_chapters">打开时跳转到阅读章节</string>
|
||||
|
@ -525,7 +525,7 @@
|
||||
<plurals name="num_categories">
|
||||
<item quantity="other">%d 個分類</item>
|
||||
</plurals>
|
||||
<string name="pref_dns_over_https_summary">需要重新啟動應用程式以套用</string>
|
||||
<string name="requires_app_restart">需要重新啟動應用程式以套用</string>
|
||||
<string name="pref_dns_over_https" translatable="false">DNS over HTTPS (Cloudflare)</string>
|
||||
<string name="label_network">網路</string>
|
||||
<string name="tapping_inverted_both">全部</string>
|
||||
|
@ -172,11 +172,10 @@
|
||||
<string name="secure_screen_summary">Hide app contents when switching apps and block screenshots</string>
|
||||
<string name="hide_notification_content">Hide notification content</string>
|
||||
|
||||
<string name="pref_category_nsfw_content">18+ content</string>
|
||||
<string name="pref_allow_nsfw_sources">18+ sources</string>
|
||||
<string name="pref_allow_nsfw_sources_allowed">Show</string>
|
||||
<string name="pref_allow_nsfw_sources_allowed_multisource">Hide in sources but show in extensions list</string>
|
||||
<string name="pref_allow_nsfw_sources_blocked">Hide</string>
|
||||
<string name="pref_category_nsfw_content">NSFW (18+) sources</string>
|
||||
<string name="pref_show_nsfw_source">Show in sources list</string>
|
||||
<string name="pref_show_nsfw_extension">Show in extensions list</string>
|
||||
<string name="pref_label_nsfw_extension">Label in extensions list</string>
|
||||
<string name="parental_controls_info">This does not prevent unofficial or potentially incorrectly flagged extensions from surfacing 18+ content within the app.</string>
|
||||
|
||||
<!-- Library section -->
|
||||
@ -390,7 +389,7 @@
|
||||
<string name="label_network">Network</string>
|
||||
<string name="pref_clear_cookies">Clear cookies</string>
|
||||
<string name="pref_dns_over_https" translatable="false">DNS over HTTPS (Cloudflare)</string>
|
||||
<string name="pref_dns_over_https_summary">Requires app restart to take effect</string>
|
||||
<string name="requires_app_restart">Requires app restart to take effect</string>
|
||||
<string name="cookies_cleared">Cookies cleared</string>
|
||||
<string name="label_data">Data</string>
|
||||
<string name="pref_clear_chapter_cache">Clear chapter cache</string>
|
||||
@ -570,6 +569,8 @@
|
||||
<string name="track_type">Type</string>
|
||||
<string name="track_author">Author</string>
|
||||
<string name="error_invalid_date_supplied">Invalid date supplied</string>
|
||||
<string name="myanimelist_creds_missing">MAL login credentials not found</string>
|
||||
<string name="myanimelist_relogin">Please login to MAL again</string>
|
||||
|
||||
<!-- Category activity -->
|
||||
<string name="error_category_exists">A category with this name already exists!</string>
|
||||
@ -666,6 +667,7 @@
|
||||
<!-- File Picker Titles -->
|
||||
<string name="file_select_cover">Select cover image</string>
|
||||
<string name="file_select_backup">Select backup file</string>
|
||||
<string name="file_picker_error">No file picker app found</string>
|
||||
|
||||
<!--UpdateCheck-->
|
||||
<string name="update_check_confirm">Download</string>
|
||||
|
@ -325,22 +325,4 @@
|
||||
<item name="android:textSize">15sp</item>
|
||||
</style>
|
||||
|
||||
|
||||
<!--===-->
|
||||
<!--OLD-->
|
||||
<!--===-->
|
||||
<style name="FilePickerTheme" parent="NNF_BaseTheme.Light">
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimary</item>
|
||||
<item name="colorAccent">@color/colorAccentLight</item>
|
||||
<item name="colorButtonNormal">@color/colorPrimary</item>
|
||||
<item name="android:textSize">14sp</item>
|
||||
|
||||
<item name="alertDialogTheme">@style/FilePickerAlertDialogTheme</item>
|
||||
|
||||
<item name="nnf_toolbarTheme">@style/ThemeOverlay.AppCompat.Dark.ActionBar</item>
|
||||
</style>
|
||||
|
||||
<style name="FilePickerAlertDialogTheme" parent="Theme.MaterialComponents.Light.Dialog.Alert" />
|
||||
|
||||
</resources>
|
||||
|
@ -27,7 +27,7 @@ buildscript {
|
||||
dependencies {
|
||||
classpath("com.github.zellius:android-shortcut-gradle-plugin:0.1.2")
|
||||
classpath("com.google.gms:google-services:4.3.4")
|
||||
classpath("com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin:" + BuildPluginsVersion.ABOUTLIB_PLUGIN)
|
||||
classpath("com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin:${BuildPluginsVersion.ABOUTLIB_PLUGIN}")
|
||||
classpath(kotlin("serialization", version = BuildPluginsVersion.KOTLIN))
|
||||
}
|
||||
repositories {
|
||||
|
Reference in New Issue
Block a user