Compare commits

...

20 Commits

Author SHA1 Message Date
c87ba6231d Release 0.10.7 2020-12-13 21:02:28 -05:00
c5ca739b49 Fix loading fallback thumbnails in browse view (closes #4127) 2020-12-13 20:47:48 -05:00
00fe4cdf2d Minor code cleanup 2020-12-13 18:11:18 -05:00
69be3e1e87 Complete migration off of Kotlin synthetics 2020-12-13 18:01:51 -05:00
2cb3984d68 Show MAL relogin message on update, localize error message 2020-12-13 17:52:21 -05:00
5901978889 Use view binding for date headers 2020-12-13 17:47:29 -05:00
8bf1cf3cc5 Update to coroutines 1.4.2
Should fix crashes on some devices. See https://github.com/Kotlin/kotlinx.coroutines/issues/2371
2020-12-13 17:18:59 -05:00
f6af1184bc Reword NSFW settings section 2020-12-13 17:18:38 -05:00
4880741b8b More crash fixes 2020-12-13 17:18:28 -05:00
e8627800fe Remove bundled fallback file picker 2020-12-13 12:42:10 -05:00
907fbb94a2 Require WebView 86+ 2020-12-13 11:27:05 -05:00
fd2028557e Some crash fixes 2020-12-13 11:00:46 -05:00
91fa1ec6b2 Suppress some deprecation warnings 2020-12-12 23:50:28 -05:00
628c525599 Disable release postprocessing (Proguard)
Caused the following error for someone:

Detected problmes with app native libraries (please consult log for detail):
libavcoded.so: text relocations
libswresample.so:test relocations
2020-12-12 23:50:05 -05:00
bbc00768f0 Note that toggling NSFW sources requires a restart 2020-12-12 17:27:11 -05:00
5b09461ccf Break out NSFW hiding/labeling into separate settings 2020-12-12 17:20:54 -05:00
1a439ecece Remove source overwrite logic since built-in sources no longer exist 2020-12-12 16:15:18 -05:00
836aec4396 Flip left/right key events for Webtoon viewer (fixes #4111) 2020-12-12 15:50:56 -05:00
0b5dec9bab Revert "Hide incomplete NSFW source labelling settings"
This reverts commit a3b1690d38.
2020-12-12 11:32:55 -05:00
fd56123267 [SKIP CI] Update issue templates 2020-12-12 11:32:44 -05:00
85 changed files with 214 additions and 337 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -137,7 +137,7 @@ class DownloadPendingDeleter(context: Context) {
val id: Long,
val url: String,
val name: String,
val scanlator: String?
val scanlator: String? = null
)
/**

View File

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

View File

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

View File

@ -37,10 +37,4 @@ object PreferenceValues {
VERTICAL,
BOTH
}
enum class NsfwAllowance {
ALLOWED,
PARTIAL,
BLOCKED
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -459,7 +459,6 @@ open class BrowseSourceController(bundle: Bundle) :
val adapter = adapter ?: return
preferences.sourceDisplayMode().set(mode)
presenter.refreshDisplayMode()
activity?.invalidateOptionsMenu()
setupRecycler(view)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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"></string>
<string name="pref_jump_to_chapters">ınca bölümlere git</string>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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