mirror of
https://github.com/mihonapp/mihon.git
synced 2025-06-26 19:17:51 +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 |
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