Compare commits
60 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5c14879c12 | |||
| 1682962703 | |||
| a1daf53188 | |||
| b0bdee8c72 | |||
| 72c091d317 | |||
| 1cc796a62e | |||
| cd40c0fb32 | |||
| 88edd18d02 | |||
| ba9d010f78 | |||
| 1ed375968e | |||
| 9e525515ea | |||
| bd7201cfb9 | |||
| d9ca2b69e8 | |||
| 925fb118af | |||
| 4552221020 | |||
| 24b66b7030 | |||
| 58decd076c | |||
| a7d93ae751 | |||
| d225b7c586 | |||
| 4c51d01236 | |||
| 4d46e84f54 | |||
| af51607053 | |||
| 1c8e6dcd6f | |||
| 7a398dabba | |||
| b7fcf7ccda | |||
| acbda604cc | |||
| 97f3dd3b25 | |||
| 60758f89ed | |||
| e96895345e | |||
| eec1236b8b | |||
| ee1e783126 | |||
| f3ab39cb1f | |||
| ba75395648 | |||
| fe0b14ab97 | |||
| 91d2140288 | |||
| 0417969dd6 | |||
| 5d8d2ce48a | |||
| b15277f134 | |||
| 76ca27f681 | |||
| 56923c76d4 | |||
| 32e19736b9 | |||
| 11b01b2771 | |||
| 460ff13e54 | |||
| 57f77c8105 | |||
| a2eb22964a | |||
| 7158bae26a | |||
| 807ce846d5 | |||
| 0b68f2c62a | |||
| b7d6cc8dd0 | |||
| 8b1fd30902 | |||
| aff43f3aeb | |||
| 0047d2e5d8 | |||
| d87385f5b3 | |||
| c17e9573b7 | |||
| 9c01119d24 | |||
| bbc839e234 | |||
| 917f20894b | |||
| 3a3b719b8b | |||
| 1903437ecf | |||
| 5c26bb3a52 |
+103
-85
@@ -1,16 +1,19 @@
|
|||||||
@file:Suppress("ChromeOsAbiSupport")
|
|
||||||
|
|
||||||
import mihon.buildlogic.getBuildTime
|
import mihon.gradle.getBuildTime
|
||||||
import mihon.buildlogic.getCommitCount
|
import mihon.gradle.getLatestCommitCount
|
||||||
import mihon.buildlogic.getGitSha
|
import mihon.gradle.getLatestCommitSha
|
||||||
|
import mihon.gradle.tasks.ReplaceShortcutsPlaceholderTask
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("mihon.android.application")
|
alias(mihonx.plugins.android.application)
|
||||||
id("mihon.android.application.compose")
|
alias(mihonx.plugins.compose)
|
||||||
|
alias(mihonx.plugins.spotless)
|
||||||
|
|
||||||
kotlin("plugin.parcelize")
|
kotlin("plugin.parcelize")
|
||||||
kotlin("plugin.serialization")
|
|
||||||
// id("com.github.zellius.shortcut-helper")
|
|
||||||
alias(libs.plugins.aboutLibraries)
|
alias(libs.plugins.aboutLibraries)
|
||||||
|
alias(libs.plugins.kotlin.serialization)
|
||||||
|
|
||||||
id("com.github.ben-manes.versions")
|
id("com.github.ben-manes.versions")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,42 +24,26 @@ if (gradle.startParameter.taskRequests.toString().contains("Standard")) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// shortcutHelper.setFilePath("./shortcuts.xml")
|
|
||||||
|
|
||||||
val supportedAbis = setOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64")
|
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "eu.kanade.tachiyomi"
|
namespace = "eu.kanade.tachiyomi"
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId = "eu.kanade.tachiyomi.sy"
|
applicationId = "eu.kanade.tachiyomi.sy"
|
||||||
|
|
||||||
versionCode = 75
|
versionCode = 77
|
||||||
versionName = "1.12.0"
|
versionName = "1.12.0"
|
||||||
|
|
||||||
buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"")
|
buildConfigField("String", "COMMIT_COUNT", "\"${getLatestCommitCount()}\"")
|
||||||
buildConfigField("String", "COMMIT_SHA", "\"${getGitSha()}\"")
|
buildConfigField("String", "COMMIT_SHA", "\"${getLatestCommitSha()}\"")
|
||||||
buildConfigField("String", "BUILD_TIME", "\"${getBuildTime(useLastCommitTime = false)}\"")
|
buildConfigField("String", "BUILD_TIME", "\"${getBuildTime(useLatestCommitTime = false)}\"")
|
||||||
buildConfigField("boolean", "INCLUDE_UPDATER", "false")
|
buildConfigField("boolean", "INCLUDE_UPDATER", "false")
|
||||||
|
|
||||||
ndk {
|
|
||||||
abiFilters += supportedAbis
|
|
||||||
}
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
|
|
||||||
splits {
|
|
||||||
abi {
|
|
||||||
isEnable = true
|
|
||||||
reset()
|
|
||||||
include(*supportedAbis.toTypedArray())
|
|
||||||
isUniversalApk = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
named("debug") {
|
named("debug") {
|
||||||
versionNameSuffix = "-${getCommitCount()}"
|
versionNameSuffix = "-${getLatestCommitCount()}"
|
||||||
applicationIdSuffix = ".debug"
|
applicationIdSuffix = ".debug"
|
||||||
isPseudoLocalesEnabled = true
|
isPseudoLocalesEnabled = true
|
||||||
}
|
}
|
||||||
@@ -72,7 +59,7 @@ android {
|
|||||||
isShrinkResources = true
|
isShrinkResources = true
|
||||||
setProguardFiles(listOf(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"))
|
setProguardFiles(listOf(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"))
|
||||||
|
|
||||||
buildConfigField("String", "BUILD_TIME", "\"${getBuildTime(useLastCommitTime = true)}\"")
|
buildConfigField("String", "BUILD_TIME", "\"${getBuildTime(useLatestCommitTime = true)}\"")
|
||||||
}
|
}
|
||||||
create("benchmark") {
|
create("benchmark") {
|
||||||
initWith(getByName("release"))
|
initWith(getByName("release"))
|
||||||
@@ -90,6 +77,15 @@ android {
|
|||||||
getByName("benchmark").res.srcDirs("src/debug/res")
|
getByName("benchmark").res.srcDirs("src/debug/res")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
splits {
|
||||||
|
abi {
|
||||||
|
isEnable = true
|
||||||
|
isUniversalApk = true
|
||||||
|
reset()
|
||||||
|
include("armeabi-v7a", "arm64-v8a", "x86", "x86_64")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
flavorDimensions.add("default")
|
flavorDimensions.add("default")
|
||||||
|
|
||||||
productFlavors {
|
productFlavors {
|
||||||
@@ -106,20 +102,31 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
packaging {
|
packaging {
|
||||||
resources.excludes.addAll(
|
jniLibs {
|
||||||
listOf(
|
keepDebugSymbols += listOf(
|
||||||
|
"libandroidx.graphics.path",
|
||||||
|
"libarchive-jni",
|
||||||
|
"libconscrypt_jni",
|
||||||
|
"libimagedecoder",
|
||||||
|
"libquickjs",
|
||||||
|
"libsqlite3x",
|
||||||
|
)
|
||||||
|
.map { "**/$it.so" }
|
||||||
|
}
|
||||||
|
resources {
|
||||||
|
excludes += setOf(
|
||||||
"kotlin-tooling-metadata.json",
|
"kotlin-tooling-metadata.json",
|
||||||
"META-INF/DEPENDENCIES",
|
|
||||||
"LICENSE.txt",
|
"LICENSE.txt",
|
||||||
"META-INF/LICENSE",
|
"META-INF/**/*.properties",
|
||||||
"META-INF/**/LICENSE.txt",
|
"META-INF/**/LICENSE.txt",
|
||||||
"META-INF/*.properties",
|
"META-INF/*.properties",
|
||||||
"META-INF/**/*.properties",
|
|
||||||
"META-INF/README.md",
|
|
||||||
"META-INF/NOTICE",
|
|
||||||
"META-INF/*.version",
|
"META-INF/*.version",
|
||||||
),
|
"META-INF/DEPENDENCIES",
|
||||||
)
|
"META-INF/LICENSE",
|
||||||
|
"META-INF/NOTICE",
|
||||||
|
"META-INF/README.md",
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependenciesInfo {
|
dependenciesInfo {
|
||||||
@@ -177,94 +184,92 @@ dependencies {
|
|||||||
implementation(projects.presentationWidget)
|
implementation(projects.presentationWidget)
|
||||||
|
|
||||||
// Compose
|
// Compose
|
||||||
implementation(compose.activity)
|
implementation(libs.androidx.activity.compose)
|
||||||
implementation(compose.foundation)
|
implementation(libs.androidx.compose.foundation)
|
||||||
implementation(compose.material3.core)
|
implementation(libs.androidx.compose.material3)
|
||||||
implementation(compose.material.icons)
|
implementation(libs.androidx.compose.materialIcons)
|
||||||
implementation(compose.animation)
|
implementation(libs.androidx.compose.animation)
|
||||||
implementation(compose.animation.graphics)
|
implementation(libs.androidx.compose.animationGraphics)
|
||||||
debugImplementation(compose.ui.tooling)
|
debugImplementation(libs.androidx.compose.uiTooling)
|
||||||
implementation(compose.ui.tooling.preview)
|
implementation(libs.androidx.compose.uiToolingPreview)
|
||||||
implementation(compose.ui.util)
|
implementation(libs.androidx.compose.uiUtil)
|
||||||
|
|
||||||
implementation(androidx.interpolator)
|
implementation(libs.androidx.interpolator)
|
||||||
|
|
||||||
implementation(androidx.paging.runtime)
|
implementation(libs.androidx.paging.runtime)
|
||||||
implementation(androidx.paging.compose)
|
implementation(libs.androidx.paging.compose)
|
||||||
|
|
||||||
implementation(libs.bundles.sqlite)
|
implementation(libs.androidx.sqlite.bundled)
|
||||||
// SY -->
|
// SY -->
|
||||||
implementation(sylibs.sqlcipher)
|
implementation(sylibs.sqlcipher)
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
implementation(kotlinx.reflect)
|
implementation(libs.kotlin.reflect)
|
||||||
implementation(kotlinx.immutables)
|
implementation(libs.kotlinx.collections.immutable)
|
||||||
|
|
||||||
implementation(platform(kotlinx.coroutines.bom))
|
implementation(libs.bundles.kotlinx.coroutines)
|
||||||
implementation(kotlinx.bundles.coroutines)
|
|
||||||
|
|
||||||
// AndroidX libraries
|
// AndroidX libraries
|
||||||
implementation(androidx.annotation)
|
implementation(libs.androidx.annotation)
|
||||||
implementation(androidx.appcompat)
|
implementation(libs.androidx.appCompat)
|
||||||
implementation(androidx.biometricktx)
|
implementation(libs.androidx.biometric)
|
||||||
implementation(androidx.constraintlayout)
|
implementation(libs.androidx.constraintLayout)
|
||||||
implementation(androidx.corektx)
|
implementation(libs.androidx.core)
|
||||||
implementation(androidx.splashscreen)
|
implementation(libs.androidx.coreSplashScreen)
|
||||||
implementation(androidx.recyclerview)
|
implementation(libs.androidx.recyclerView)
|
||||||
implementation(androidx.viewpager)
|
implementation(libs.androidx.viewPager)
|
||||||
implementation(androidx.profileinstaller)
|
implementation(libs.androidx.profileInstaller)
|
||||||
|
|
||||||
implementation(androidx.bundles.lifecycle)
|
implementation(libs.bundles.androidx.lifecycle)
|
||||||
|
|
||||||
// Job scheduling
|
// Job scheduling
|
||||||
implementation(androidx.workmanager)
|
implementation(libs.androidx.work)
|
||||||
|
|
||||||
// RxJava
|
// RxJava
|
||||||
implementation(libs.rxjava)
|
implementation(libs.rxJava)
|
||||||
|
|
||||||
// Networking
|
// Networking
|
||||||
implementation(libs.bundles.okhttp)
|
implementation(libs.bundles.okhttp)
|
||||||
implementation(libs.okio)
|
implementation(libs.okio)
|
||||||
implementation(libs.conscrypt.android) // TLS 1.3 support for Android < 10
|
implementation(libs.conscrypt) // TLS 1.3 support for Android < 10
|
||||||
|
|
||||||
// Data serialization (JSON, protobuf, xml)
|
// Data serialization (JSON, protobuf, xml)
|
||||||
implementation(kotlinx.bundles.serialization)
|
implementation(libs.bundles.serialization)
|
||||||
|
|
||||||
// HTML parser
|
// HTML parser
|
||||||
implementation(libs.jsoup)
|
implementation(libs.jsoup)
|
||||||
|
|
||||||
// Disk
|
// Disk
|
||||||
implementation(libs.disklrucache)
|
implementation(libs.diskLruCache)
|
||||||
implementation(libs.unifile)
|
implementation(libs.unifile)
|
||||||
|
|
||||||
// Preferences
|
// Preferences
|
||||||
implementation(libs.preferencektx)
|
implementation(libs.androidx.preference)
|
||||||
|
|
||||||
// Dependency injection
|
// Dependency injection
|
||||||
implementation(libs.injekt)
|
implementation(libs.injekt)
|
||||||
|
|
||||||
// Image loading
|
// Image loading
|
||||||
implementation(platform(libs.coil.bom))
|
|
||||||
implementation(libs.bundles.coil)
|
implementation(libs.bundles.coil)
|
||||||
implementation(libs.subsamplingscaleimageview) {
|
implementation(libs.subsamplingScaleImageView) {
|
||||||
exclude(module = "image-decoder")
|
exclude(module = "image-decoder")
|
||||||
}
|
}
|
||||||
implementation(libs.image.decoder)
|
implementation(libs.image.decoder)
|
||||||
|
|
||||||
// UI libraries
|
// UI libraries
|
||||||
implementation(libs.material)
|
implementation(libs.material)
|
||||||
implementation(libs.flexible.adapter.core)
|
implementation(libs.flexibleAdapter)
|
||||||
implementation(libs.photoview)
|
implementation(libs.photoView)
|
||||||
implementation(libs.directionalviewpager) {
|
implementation(libs.directionalViewPager) {
|
||||||
exclude(group = "androidx.viewpager", module = "viewpager")
|
exclude(group = "androidx.viewpager", module = "viewpager")
|
||||||
}
|
}
|
||||||
implementation(libs.richeditor.compose)
|
implementation(libs.composeRichEditor)
|
||||||
implementation(libs.aboutLibraries.compose)
|
implementation(libs.aboutLibraries.compose)
|
||||||
implementation(libs.bundles.voyager)
|
implementation(libs.bundles.voyager)
|
||||||
implementation(libs.compose.materialmotion)
|
implementation(libs.composeMaterialMotion)
|
||||||
implementation(libs.swipe)
|
implementation(libs.swipe)
|
||||||
implementation(libs.compose.webview)
|
implementation(libs.composeWebview)
|
||||||
implementation(libs.compose.grid)
|
implementation(libs.composeGrid)
|
||||||
implementation(libs.reorderable)
|
implementation(libs.reorderable)
|
||||||
implementation(libs.bundles.markdown)
|
implementation(libs.bundles.markdown)
|
||||||
implementation(libs.materialKolor)
|
implementation(libs.materialKolor)
|
||||||
@@ -288,10 +293,10 @@ dependencies {
|
|||||||
testRuntimeOnly(libs.junit.platform.launcher)
|
testRuntimeOnly(libs.junit.platform.launcher)
|
||||||
|
|
||||||
// For detecting memory leaks; see https://square.github.io/leakcanary/
|
// For detecting memory leaks; see https://square.github.io/leakcanary/
|
||||||
// debugImplementation(libs.leakcanary.android)
|
// debugImplementation(libs.leakCanary.android)
|
||||||
implementation(libs.leakcanary.plumber)
|
implementation(libs.leakCanary.plumber)
|
||||||
|
|
||||||
testImplementation(kotlinx.coroutines.test)
|
testImplementation(libs.kotlinx.coroutines.test)
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
// Firebase (EH)
|
// Firebase (EH)
|
||||||
@@ -319,6 +324,19 @@ dependencies {
|
|||||||
}
|
}
|
||||||
|
|
||||||
androidComponents {
|
androidComponents {
|
||||||
|
onVariants { variant ->
|
||||||
|
val resSource = variant.sources.res ?: return@onVariants
|
||||||
|
|
||||||
|
val variantName = variant.name.replaceFirstChar { it.uppercase() }
|
||||||
|
val replaceShortcutsPlaceholderTask = tasks.register<ReplaceShortcutsPlaceholderTask>(
|
||||||
|
"replace${variantName}ShortcutPlaceholder",
|
||||||
|
) {
|
||||||
|
applicationId.set(variant.applicationId)
|
||||||
|
shortcutsFile.set(projectDir.resolve("src/main/shortcuts.xml"))
|
||||||
|
}
|
||||||
|
resSource.addGeneratedSourceDirectory(replaceShortcutsPlaceholderTask) { it.outputDir }
|
||||||
|
}
|
||||||
|
|
||||||
onVariants(selector().withFlavor("default" to "standard")) {
|
onVariants(selector().withFlavor("default" to "standard")) {
|
||||||
// Only excluding in standard flavor because this breaks
|
// Only excluding in standard flavor because this breaks
|
||||||
// Layout Inspector's Compose tree
|
// Layout Inspector's Compose tree
|
||||||
@@ -328,6 +346,6 @@ androidComponents {
|
|||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath(kotlinx.gradle)
|
classpath(libs.kotlin.gradle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+2
@@ -299,3 +299,5 @@
|
|||||||
-dontwarn org.ietf.jgss.GSSManager
|
-dontwarn org.ietf.jgss.GSSManager
|
||||||
-dontwarn org.ietf.jgss.GSSName
|
-dontwarn org.ietf.jgss.GSSName
|
||||||
-dontwarn org.ietf.jgss.Oid
|
-dontwarn org.ietf.jgss.Oid
|
||||||
|
-dontwarn com.google.re2j.Matcher
|
||||||
|
-dontwarn com.google.re2j.Pattern
|
||||||
|
|||||||
@@ -9,19 +9,22 @@ import tachiyomi.i18n.MR
|
|||||||
|
|
||||||
class BasePreferences(
|
class BasePreferences(
|
||||||
val context: Context,
|
val context: Context,
|
||||||
private val preferenceStore: PreferenceStore,
|
preferenceStore: PreferenceStore,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun downloadedOnly() = preferenceStore.getBoolean(
|
val downloadedOnly: Preference<Boolean> = preferenceStore.getBoolean(
|
||||||
Preference.appStateKey("pref_downloaded_only"),
|
Preference.appStateKey("pref_downloaded_only"),
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
|
|
||||||
fun incognitoMode() = preferenceStore.getBoolean(Preference.appStateKey("incognito_mode"), false)
|
val incognitoMode: Preference<Boolean> = preferenceStore.getBoolean(Preference.appStateKey("incognito_mode"), false)
|
||||||
|
|
||||||
fun extensionInstaller() = ExtensionInstallerPreference(context, preferenceStore)
|
val extensionInstaller: ExtensionInstallerPreference = ExtensionInstallerPreference(context, preferenceStore)
|
||||||
|
|
||||||
fun shownOnboardingFlow() = preferenceStore.getBoolean(Preference.appStateKey("onboarding_complete"), false)
|
val shownOnboardingFlow: Preference<Boolean> = preferenceStore.getBoolean(
|
||||||
|
Preference.appStateKey("onboarding_complete"),
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
|
||||||
enum class ExtensionInstaller(val titleRes: StringResource, val requiresSystemPermission: Boolean) {
|
enum class ExtensionInstaller(val titleRes: StringResource, val requiresSystemPermission: Boolean) {
|
||||||
LEGACY(MR.strings.ext_installer_legacy, true),
|
LEGACY(MR.strings.ext_installer_legacy, true),
|
||||||
@@ -30,9 +33,17 @@ class BasePreferences(
|
|||||||
PRIVATE(MR.strings.ext_installer_private, false),
|
PRIVATE(MR.strings.ext_installer_private, false),
|
||||||
}
|
}
|
||||||
|
|
||||||
fun displayProfile() = preferenceStore.getString("pref_display_profile_key", "")
|
val displayProfile: Preference<String> = preferenceStore.getString("pref_display_profile_key", "")
|
||||||
|
|
||||||
fun hardwareBitmapThreshold() = preferenceStore.getInt("pref_hardware_bitmap_threshold", GLUtil.SAFE_TEXTURE_LIMIT)
|
val hardwareBitmapThreshold: Preference<Int> = preferenceStore.getInt(
|
||||||
|
"pref_hardware_bitmap_threshold",
|
||||||
|
GLUtil.SAFE_TEXTURE_LIMIT,
|
||||||
|
)
|
||||||
|
|
||||||
fun alwaysDecodeLongStripWithSSIV() = preferenceStore.getBoolean("pref_always_decode_long_strip_with_ssiv", false)
|
val alwaysDecodeLongStripWithSSIV: Preference<Boolean> = preferenceStore.getBoolean(
|
||||||
|
"pref_always_decode_long_strip_with_ssiv",
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
|
||||||
|
val installationId: Preference<String> = preferenceStore.getString(Preference.appStateKey("installation_id"), "")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ class SetReadStatus(
|
|||||||
return@withNonCancellableContext Result.InternalError(e)
|
return@withNonCancellableContext Result.InternalError(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (read && downloadPreferences.removeAfterMarkedAsRead().get()) {
|
if (read && downloadPreferences.removeAfterMarkedAsRead.get()) {
|
||||||
chaptersToUpdate
|
chaptersToUpdate
|
||||||
.groupBy { it.mangaId }
|
.groupBy { it.mangaId }
|
||||||
.forEach { (mangaId, chapters) ->
|
.forEach { (mangaId, chapters) ->
|
||||||
|
|||||||
@@ -176,7 +176,7 @@ class SyncChaptersWithSource(
|
|||||||
val deletedChapterNumberDateFetchMap = removedChapters.sortedByDescending { it.dateFetch }
|
val deletedChapterNumberDateFetchMap = removedChapters.sortedByDescending { it.dateFetch }
|
||||||
.associate { it.chapterNumber to it.dateFetch }
|
.associate { it.chapterNumber to it.dateFetch }
|
||||||
|
|
||||||
val markDuplicateAsRead = libraryPreferences.markDuplicateReadChapterAsRead().get()
|
val markDuplicateAsRead = libraryPreferences.markDuplicateReadChapterAsRead.get()
|
||||||
.contains(LibraryPreferences.MARK_DUPLICATE_CHAPTER_READ_NEW)
|
.contains(LibraryPreferences.MARK_DUPLICATE_CHAPTER_READ_NEW)
|
||||||
|
|
||||||
// Date fetch is set in such a way that the upper ones will have bigger value than the lower ones
|
// Date fetch is set in such a way that the upper ones will have bigger value than the lower ones
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ class GetExtensionLanguages(
|
|||||||
) {
|
) {
|
||||||
fun subscribe(): Flow<List<String>> {
|
fun subscribe(): Flow<List<String>> {
|
||||||
return combine(
|
return combine(
|
||||||
preferences.enabledLanguages().changes(),
|
preferences.enabledLanguages.changes(),
|
||||||
extensionManager.availableExtensionsFlow,
|
extensionManager.availableExtensionsFlow,
|
||||||
) { enabledLanguage, availableExtensions ->
|
) { enabledLanguage, availableExtensions ->
|
||||||
availableExtensions
|
availableExtensions
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class GetExtensionSources(
|
|||||||
val isMultiLangSingleSource =
|
val isMultiLangSingleSource =
|
||||||
isMultiSource && extension.sources.map { it.name }.distinct().size == 1
|
isMultiSource && extension.sources.map { it.name }.distinct().size == 1
|
||||||
|
|
||||||
return preferences.disabledSources().changes().map { disabledSources ->
|
return preferences.disabledSources.changes().map { disabledSources ->
|
||||||
fun Source.isEnabled() = id.toString() !in disabledSources
|
fun Source.isEnabled() = id.toString() !in disabledSources
|
||||||
|
|
||||||
extension.sources
|
extension.sources
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ class GetExtensionsByType(
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
fun subscribe(): Flow<Extensions> {
|
fun subscribe(): Flow<Extensions> {
|
||||||
val showNsfwSources = preferences.showNsfwSource().get()
|
val showNsfwSources = preferences.showNsfwSource.get()
|
||||||
|
|
||||||
return combine(
|
return combine(
|
||||||
preferences.enabledLanguages().changes(),
|
preferences.enabledLanguages.changes(),
|
||||||
extensionManager.installedExtensionsFlow,
|
extensionManager.installedExtensionsFlow,
|
||||||
extensionManager.untrustedExtensionsFlow,
|
extensionManager.untrustedExtensionsFlow,
|
||||||
extensionManager.availableExtensionsFlow,
|
extensionManager.availableExtensionsFlow,
|
||||||
|
|||||||
@@ -14,11 +14,11 @@ class TrustExtension(
|
|||||||
suspend fun isTrusted(pkgInfo: PackageInfo, fingerprints: List<String>): Boolean {
|
suspend fun isTrusted(pkgInfo: PackageInfo, fingerprints: List<String>): Boolean {
|
||||||
val trustedFingerprints = extensionRepoRepository.getAll().map { it.signingKeyFingerprint }.toHashSet()
|
val trustedFingerprints = extensionRepoRepository.getAll().map { it.signingKeyFingerprint }.toHashSet()
|
||||||
val key = "${pkgInfo.packageName}:${PackageInfoCompat.getLongVersionCode(pkgInfo)}:${fingerprints.last()}"
|
val key = "${pkgInfo.packageName}:${PackageInfoCompat.getLongVersionCode(pkgInfo)}:${fingerprints.last()}"
|
||||||
return trustedFingerprints.any { fingerprints.contains(it) } || key in preferences.trustedExtensions().get()
|
return trustedFingerprints.any { fingerprints.contains(it) } || key in preferences.trustedExtensions.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun trust(pkgName: String, versionCode: Long, signatureHash: String) {
|
fun trust(pkgName: String, versionCode: Long, signatureHash: String) {
|
||||||
preferences.trustedExtensions().getAndSet { exts ->
|
preferences.trustedExtensions.getAndSet { exts ->
|
||||||
// Remove previously trusted versions
|
// Remove previously trusted versions
|
||||||
val removed = exts.filterNot { it.startsWith("$pkgName:") }.toMutableSet()
|
val removed = exts.filterNot { it.startsWith("$pkgName:") }.toMutableSet()
|
||||||
|
|
||||||
@@ -27,6 +27,6 @@ class TrustExtension(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun revokeAll() {
|
fun revokeAll() {
|
||||||
preferences.trustedExtensions().delete()
|
preferences.trustedExtensions.delete()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ class CreateSortTag(
|
|||||||
return Result.TagExists
|
return Result.TagExists
|
||||||
}
|
}
|
||||||
|
|
||||||
val size = preferences.sortTagsForLibrary().get().size
|
val size = preferences.sortTagsForLibrary.get().size
|
||||||
|
|
||||||
preferences.sortTagsForLibrary() += encodeTag(size, tag)
|
preferences.sortTagsForLibrary += encodeTag(size, tag)
|
||||||
|
|
||||||
return Result.Success
|
return Result.Success
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ class DeleteSortTag(
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
fun await(tag: String) {
|
fun await(tag: String) {
|
||||||
preferences.sortTagsForLibrary().set(
|
preferences.sortTagsForLibrary.set(
|
||||||
(getSortTag.await() - tag).mapIndexed { index, s ->
|
(getSortTag.await() - tag).mapIndexed { index, s ->
|
||||||
CreateSortTag.encodeTag(index, s)
|
CreateSortTag.encodeTag(index, s)
|
||||||
}.toSet(),
|
}.toSet(),
|
||||||
|
|||||||
@@ -7,14 +7,14 @@ import tachiyomi.domain.library.service.LibraryPreferences
|
|||||||
class GetSortTag(private val preferences: LibraryPreferences) {
|
class GetSortTag(private val preferences: LibraryPreferences) {
|
||||||
|
|
||||||
fun subscribe(): Flow<List<String>> {
|
fun subscribe(): Flow<List<String>> {
|
||||||
return preferences.sortTagsForLibrary().changes()
|
return preferences.sortTagsForLibrary.changes()
|
||||||
.map(::mapSortTags)
|
.map(::mapSortTags)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun await() = getSortTags(preferences).let(::mapSortTags)
|
fun await() = getSortTags(preferences).let(::mapSortTags)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun getSortTags(preferences: LibraryPreferences) = preferences.sortTagsForLibrary().get()
|
fun getSortTags(preferences: LibraryPreferences) = preferences.sortTagsForLibrary.get()
|
||||||
|
|
||||||
fun mapSortTags(tags: Set<String>) = tags.mapNotNull {
|
fun mapSortTags(tags: Set<String>) = tags.mapNotNull {
|
||||||
val index = it.indexOf('|')
|
val index = it.indexOf('|')
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class ReorderSortTag(
|
|||||||
val reorderedTag = reorderedTags.removeAt(currentIndex)
|
val reorderedTag = reorderedTags.removeAt(currentIndex)
|
||||||
reorderedTags.add(newPosition, reorderedTag)
|
reorderedTags.add(newPosition, reorderedTag)
|
||||||
|
|
||||||
preferences.sortTagsForLibrary().set(
|
preferences.sortTagsForLibrary.set(
|
||||||
reorderedTags.mapIndexed { index, s ->
|
reorderedTags.mapIndexed { index, s ->
|
||||||
CreateSortTag.encodeTag(index, s)
|
CreateSortTag.encodeTag(index, s)
|
||||||
}.toSet(),
|
}.toSet(),
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ class UpdateManga(
|
|||||||
|
|
||||||
// if the manga isn't a favorite (or 'update titles' preference is enabled), set its title from source and update in db
|
// if the manga isn't a favorite (or 'update titles' preference is enabled), set its title from source and update in db
|
||||||
val title =
|
val title =
|
||||||
if (remoteTitle.isNotEmpty() && (!localManga.favorite || libraryPreferences.updateMangaTitles().get())) {
|
if (remoteTitle.isNotEmpty() && (!localManga.favorite || libraryPreferences.updateMangaTitles.get())) {
|
||||||
remoteTitle
|
remoteTitle
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ val Manga.readerOrientation: Long
|
|||||||
|
|
||||||
val Manga.downloadedFilter: TriState
|
val Manga.downloadedFilter: TriState
|
||||||
get() {
|
get() {
|
||||||
if (Injekt.get<BasePreferences>().downloadedOnly().get()) return TriState.ENABLED_IS
|
if (Injekt.get<BasePreferences>().downloadedOnly.get()) return TriState.ENABLED_IS
|
||||||
return when (downloadedFilterRaw) {
|
return when (downloadedFilterRaw) {
|
||||||
Manga.CHAPTER_SHOW_DOWNLOADED -> TriState.ENABLED_IS
|
Manga.CHAPTER_SHOW_DOWNLOADED -> TriState.ENABLED_IS
|
||||||
Manga.CHAPTER_SHOW_NOT_DOWNLOADED -> TriState.ENABLED_NOT
|
Manga.CHAPTER_SHOW_NOT_DOWNLOADED -> TriState.ENABLED_NOT
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ class CreateSourceCategory(private val preferences: SourcePreferences) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create category.
|
// Create category.
|
||||||
preferences.sourcesTabCategories() += category
|
preferences.sourcesTabCategories += category
|
||||||
|
|
||||||
return Result.Success
|
return Result.Success
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ import tachiyomi.core.common.preference.minusAssign
|
|||||||
class DeleteSourceCategory(private val preferences: SourcePreferences) {
|
class DeleteSourceCategory(private val preferences: SourcePreferences) {
|
||||||
|
|
||||||
fun await(category: String) {
|
fun await(category: String) {
|
||||||
preferences.sourcesTabSourcesInCategories().getAndSet { sourcesInCategories ->
|
preferences.sourcesTabSourcesInCategories.getAndSet { sourcesInCategories ->
|
||||||
sourcesInCategories.filterNot { it.substringAfter("|") == category }.toSet()
|
sourcesInCategories.filterNot { it.substringAfter("|") == category }.toSet()
|
||||||
}
|
}
|
||||||
preferences.sourcesTabCategories() -= category
|
preferences.sourcesTabCategories -= category
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,17 +18,17 @@ class GetEnabledSources(
|
|||||||
|
|
||||||
fun subscribe(): Flow<List<Source>> {
|
fun subscribe(): Flow<List<Source>> {
|
||||||
return combine(
|
return combine(
|
||||||
preferences.pinnedSources().changes(),
|
preferences.pinnedSources.changes(),
|
||||||
combine(
|
combine(
|
||||||
preferences.enabledLanguages().changes(),
|
preferences.enabledLanguages.changes(),
|
||||||
preferences.disabledSources().changes(),
|
preferences.disabledSources.changes(),
|
||||||
preferences.lastUsedSource().changes(),
|
preferences.lastUsedSource.changes(),
|
||||||
) { a, b, c -> Triple(a, b, c) },
|
) { a, b, c -> Triple(a, b, c) },
|
||||||
// SY -->
|
// SY -->
|
||||||
combine(
|
combine(
|
||||||
preferences.dataSaverExcludedSources().changes(),
|
preferences.dataSaverExcludedSources.changes(),
|
||||||
preferences.sourcesTabSourcesInCategories().changes(),
|
preferences.sourcesTabSourcesInCategories.changes(),
|
||||||
preferences.sourcesTabCategoriesFilter().changes(),
|
preferences.sourcesTabCategoriesFilter.changes(),
|
||||||
) { a, b, c -> Triple(a, b, c) },
|
) { a, b, c -> Triple(a, b, c) },
|
||||||
// SY <--
|
// SY <--
|
||||||
repository.getSources(),
|
repository.getSources(),
|
||||||
|
|||||||
@@ -13,19 +13,19 @@ class GetIncognitoState(
|
|||||||
private val extensionManager: ExtensionManager,
|
private val extensionManager: ExtensionManager,
|
||||||
) {
|
) {
|
||||||
fun await(sourceId: Long?): Boolean {
|
fun await(sourceId: Long?): Boolean {
|
||||||
if (basePreferences.incognitoMode().get()) return true
|
if (basePreferences.incognitoMode.get()) return true
|
||||||
if (sourceId == null) return false
|
if (sourceId == null) return false
|
||||||
val extensionPackage = extensionManager.getExtensionPackage(sourceId) ?: return false
|
val extensionPackage = extensionManager.getExtensionPackage(sourceId) ?: return false
|
||||||
|
|
||||||
return extensionPackage in sourcePreferences.incognitoExtensions().get()
|
return extensionPackage in sourcePreferences.incognitoExtensions.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun subscribe(sourceId: Long?): Flow<Boolean> {
|
fun subscribe(sourceId: Long?): Flow<Boolean> {
|
||||||
if (sourceId == null) return basePreferences.incognitoMode().changes()
|
if (sourceId == null) return basePreferences.incognitoMode.changes()
|
||||||
|
|
||||||
return combine(
|
return combine(
|
||||||
basePreferences.incognitoMode().changes(),
|
basePreferences.incognitoMode.changes(),
|
||||||
sourcePreferences.incognitoExtensions().changes(),
|
sourcePreferences.incognitoExtensions.changes(),
|
||||||
extensionManager.getExtensionPackageAsFlow(sourceId),
|
extensionManager.getExtensionPackageAsFlow(sourceId),
|
||||||
) { incognito, incognitoExtensions, extensionPackage ->
|
) { incognito, incognitoExtensions, extensionPackage ->
|
||||||
incognito || (extensionPackage in incognitoExtensions)
|
incognito || (extensionPackage in incognitoExtensions)
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ class GetLanguagesWithSources(
|
|||||||
|
|
||||||
fun subscribe(): Flow<SortedMap<String, List<Source>>> {
|
fun subscribe(): Flow<SortedMap<String, List<Source>>> {
|
||||||
return combine(
|
return combine(
|
||||||
preferences.enabledLanguages().changes(),
|
preferences.enabledLanguages.changes(),
|
||||||
preferences.disabledSources().changes(),
|
preferences.disabledSources.changes(),
|
||||||
repository.getOnlineSources(),
|
repository.getOnlineSources(),
|
||||||
) { enabledLanguage, disabledSource, onlineSources ->
|
) { enabledLanguage, disabledSource, onlineSources ->
|
||||||
val sortedSources = onlineSources.filterNot { it.id in BlacklistedSources.HIDDEN_SOURCES }.sortedWith(
|
val sortedSources = onlineSources.filterNot { it.id in BlacklistedSources.HIDDEN_SOURCES }.sortedWith(
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ class GetShowLatest(
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
fun subscribe(hasSmartSearchConfig: Boolean): Flow<Boolean> {
|
fun subscribe(hasSmartSearchConfig: Boolean): Flow<Boolean> {
|
||||||
return preferences.useNewSourceNavigation().changes()
|
return preferences.useNewSourceNavigation.changes()
|
||||||
.map {
|
.map {
|
||||||
!hasSmartSearchConfig && !it
|
!hasSmartSearchConfig && !it
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,6 @@ class GetSourceCategories(
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
fun subscribe(): Flow<List<String>> {
|
fun subscribe(): Flow<List<String>> {
|
||||||
return preferences.sourcesTabCategories().changes().map { it.sortedWith(String.CASE_INSENSITIVE_ORDER) }
|
return preferences.sourcesTabCategories.changes().map { it.sortedWith(String.CASE_INSENSITIVE_ORDER) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ class GetSourcesWithFavoriteCount(
|
|||||||
|
|
||||||
fun subscribe(): Flow<List<Pair<Source, Long>>> {
|
fun subscribe(): Flow<List<Pair<Source, Long>>> {
|
||||||
return combine(
|
return combine(
|
||||||
preferences.migrationSortingDirection().changes(),
|
preferences.migrationSortingDirection.changes(),
|
||||||
preferences.migrationSortingMode().changes(),
|
preferences.migrationSortingMode.changes(),
|
||||||
repository.getSourcesWithFavoriteCount(),
|
repository.getSourcesWithFavoriteCount(),
|
||||||
) { direction, mode, list ->
|
) { direction, mode, list ->
|
||||||
list
|
list
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class RenameSourceCategory(
|
|||||||
CreateSourceCategory.Result.Success -> {}
|
CreateSourceCategory.Result.Success -> {}
|
||||||
}
|
}
|
||||||
|
|
||||||
preferences.sourcesTabSourcesInCategories().getAndSet { sourcesInCategories ->
|
preferences.sourcesTabSourcesInCategories.getAndSet { sourcesInCategories ->
|
||||||
sourcesInCategories.map {
|
sourcesInCategories.map {
|
||||||
val index = it.indexOf('|')
|
val index = it.indexOf('|')
|
||||||
if (index != -1 && it.substring(index + 1) == categoryOld) {
|
if (index != -1 && it.substring(index + 1) == categoryOld) {
|
||||||
@@ -24,7 +24,7 @@ class RenameSourceCategory(
|
|||||||
}
|
}
|
||||||
}.toSet()
|
}.toSet()
|
||||||
}
|
}
|
||||||
preferences.sourcesTabCategories().getAndSet {
|
preferences.sourcesTabCategories.getAndSet {
|
||||||
it.minus(categoryOld).plus(categoryNew)
|
it.minus(categoryOld).plus(categoryNew)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ class SetMigrateSorting(
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
fun await(mode: Mode, direction: Direction) {
|
fun await(mode: Mode, direction: Direction) {
|
||||||
preferences.migrationSortingMode().set(mode)
|
preferences.migrationSortingMode.set(mode)
|
||||||
preferences.migrationSortingDirection().set(direction)
|
preferences.migrationSortingDirection.set(direction)
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class Mode {
|
enum class Mode {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ class SetSourceCategories(
|
|||||||
|
|
||||||
fun await(source: Source, sourceCategories: List<String>) {
|
fun await(source: Source, sourceCategories: List<String>) {
|
||||||
val sourceIdString = source.id.toString()
|
val sourceIdString = source.id.toString()
|
||||||
preferences.sourcesTabSourcesInCategories().getAndSet { sourcesInCategories ->
|
preferences.sourcesTabSourcesInCategories.getAndSet { sourcesInCategories ->
|
||||||
val currentSourceCategories = sourcesInCategories.filterNot {
|
val currentSourceCategories = sourcesInCategories.filterNot {
|
||||||
it.substringBefore('|') == sourceIdString
|
it.substringBefore('|') == sourceIdString
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ class ToggleExcludeFromDataSaver(
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
fun await(source: Source) {
|
fun await(source: Source) {
|
||||||
preferences.dataSaverExcludedSources().getAndSet {
|
preferences.dataSaverExcludedSources.getAndSet {
|
||||||
if (source.id.toString() in it) {
|
if (source.id.toString() in it) {
|
||||||
it - source.id.toString()
|
it - source.id.toString()
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ class ToggleIncognito(
|
|||||||
private val preferences: SourcePreferences,
|
private val preferences: SourcePreferences,
|
||||||
) {
|
) {
|
||||||
fun await(extensions: String, enable: Boolean) {
|
fun await(extensions: String, enable: Boolean) {
|
||||||
preferences.incognitoExtensions().getAndSet {
|
preferences.incognitoExtensions.getAndSet {
|
||||||
if (enable) it.plus(extensions) else it.minus(extensions)
|
if (enable) it.plus(extensions) else it.minus(extensions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ class ToggleLanguage(
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
fun await(language: String) {
|
fun await(language: String) {
|
||||||
val isEnabled = language in preferences.enabledLanguages().get()
|
val isEnabled = language in preferences.enabledLanguages.get()
|
||||||
preferences.enabledLanguages().getAndSet { enabled ->
|
preferences.enabledLanguages.getAndSet { enabled ->
|
||||||
if (isEnabled) enabled.minus(language) else enabled.plus(language)
|
if (isEnabled) enabled.minus(language) else enabled.plus(language)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,19 +13,19 @@ class ToggleSource(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun await(sourceId: Long, enable: Boolean = isEnabled(sourceId)) {
|
fun await(sourceId: Long, enable: Boolean = isEnabled(sourceId)) {
|
||||||
preferences.disabledSources().getAndSet { disabled ->
|
preferences.disabledSources.getAndSet { disabled ->
|
||||||
if (enable) disabled.minus("$sourceId") else disabled.plus("$sourceId")
|
if (enable) disabled.minus("$sourceId") else disabled.plus("$sourceId")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun await(sourceIds: List<Long>, enable: Boolean) {
|
fun await(sourceIds: List<Long>, enable: Boolean) {
|
||||||
val transformedSourceIds = sourceIds.map { it.toString() }
|
val transformedSourceIds = sourceIds.map { it.toString() }
|
||||||
preferences.disabledSources().getAndSet { disabled ->
|
preferences.disabledSources.getAndSet { disabled ->
|
||||||
if (enable) disabled.minus(transformedSourceIds) else disabled.plus(transformedSourceIds)
|
if (enable) disabled.minus(transformedSourceIds) else disabled.plus(transformedSourceIds)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isEnabled(sourceId: Long): Boolean {
|
private fun isEnabled(sourceId: Long): Boolean {
|
||||||
return sourceId.toString() in preferences.disabledSources().get()
|
return sourceId.toString() in preferences.disabledSources.get()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ class ToggleSourcePin(
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
fun await(source: Source) {
|
fun await(source: Source) {
|
||||||
val isPinned = source.id.toString() in preferences.pinnedSources().get()
|
val isPinned = source.id.toString() in preferences.pinnedSources.get()
|
||||||
preferences.pinnedSources().getAndSet { pinned ->
|
preferences.pinnedSources.getAndSet { pinned ->
|
||||||
if (isPinned) pinned.minus("${source.id}") else pinned.plus("${source.id}")
|
if (isPinned) pinned.minus("${source.id}") else pinned.plus("${source.id}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,80 +10,86 @@ import tachiyomi.core.common.preference.getLongArray
|
|||||||
import tachiyomi.domain.library.model.LibraryDisplayMode
|
import tachiyomi.domain.library.model.LibraryDisplayMode
|
||||||
|
|
||||||
class SourcePreferences(
|
class SourcePreferences(
|
||||||
private val preferenceStore: PreferenceStore,
|
preferenceStore: PreferenceStore,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun sourceDisplayMode() = preferenceStore.getObjectFromString(
|
val sourceDisplayMode: Preference<LibraryDisplayMode> = preferenceStore.getObjectFromString(
|
||||||
"pref_display_mode_catalogue",
|
"pref_display_mode_catalogue",
|
||||||
LibraryDisplayMode.default,
|
LibraryDisplayMode.default,
|
||||||
LibraryDisplayMode.Serializer::serialize,
|
LibraryDisplayMode.Serializer::serialize,
|
||||||
LibraryDisplayMode.Serializer::deserialize,
|
LibraryDisplayMode.Serializer::deserialize,
|
||||||
)
|
)
|
||||||
|
|
||||||
fun enabledLanguages() = preferenceStore.getStringSet("source_languages", LocaleHelper.getDefaultEnabledLanguages())
|
val enabledLanguages: Preference<Set<String>> = preferenceStore.getStringSet(
|
||||||
|
"source_languages",
|
||||||
|
LocaleHelper.getDefaultEnabledLanguages(),
|
||||||
|
)
|
||||||
|
|
||||||
fun disabledSources() = preferenceStore.getStringSet("hidden_catalogues", emptySet())
|
val disabledSources: Preference<Set<String>> = preferenceStore.getStringSet("hidden_catalogues", emptySet())
|
||||||
|
|
||||||
fun incognitoExtensions() = preferenceStore.getStringSet("incognito_extensions", emptySet())
|
val incognitoExtensions: Preference<Set<String>> = preferenceStore.getStringSet("incognito_extensions", emptySet())
|
||||||
|
|
||||||
fun pinnedSources() = preferenceStore.getStringSet("pinned_catalogues", emptySet())
|
val pinnedSources: Preference<Set<String>> = preferenceStore.getStringSet("pinned_catalogues", emptySet())
|
||||||
|
|
||||||
fun lastUsedSource() = preferenceStore.getLong(
|
val lastUsedSource: Preference<Long> = preferenceStore.getLong(
|
||||||
Preference.appStateKey("last_catalogue_source"),
|
Preference.appStateKey("last_catalogue_source"),
|
||||||
-1,
|
-1,
|
||||||
)
|
)
|
||||||
|
|
||||||
fun showNsfwSource() = preferenceStore.getBoolean("show_nsfw_source", true)
|
val showNsfwSource: Preference<Boolean> = preferenceStore.getBoolean("show_nsfw_source", true)
|
||||||
|
|
||||||
fun migrationSortingMode() = preferenceStore.getEnum("pref_migration_sorting", SetMigrateSorting.Mode.ALPHABETICAL)
|
val migrationSortingMode: Preference<SetMigrateSorting.Mode> = preferenceStore.getEnum(
|
||||||
|
"pref_migration_sorting",
|
||||||
|
SetMigrateSorting.Mode.ALPHABETICAL,
|
||||||
|
)
|
||||||
|
|
||||||
fun migrationSortingDirection() = preferenceStore.getEnum(
|
val migrationSortingDirection: Preference<SetMigrateSorting.Direction> = preferenceStore.getEnum(
|
||||||
"pref_migration_direction",
|
"pref_migration_direction",
|
||||||
SetMigrateSorting.Direction.ASCENDING,
|
SetMigrateSorting.Direction.ASCENDING,
|
||||||
)
|
)
|
||||||
|
|
||||||
fun hideInLibraryItems() = preferenceStore.getBoolean("browse_hide_in_library_items", false)
|
val hideInLibraryItems: Preference<Boolean> = preferenceStore.getBoolean("browse_hide_in_library_items", false)
|
||||||
|
|
||||||
fun extensionRepos() = preferenceStore.getStringSet("extension_repos", emptySet())
|
val extensionRepos: Preference<Set<String>> = preferenceStore.getStringSet("extension_repos", emptySet())
|
||||||
|
|
||||||
fun extensionUpdatesCount() = preferenceStore.getInt("ext_updates_count", 0)
|
val extensionUpdatesCount: Preference<Int> = preferenceStore.getInt("ext_updates_count", 0)
|
||||||
|
|
||||||
fun trustedExtensions() = preferenceStore.getStringSet(
|
val trustedExtensions: Preference<Set<String>> = preferenceStore.getStringSet(
|
||||||
Preference.appStateKey("trusted_extensions"),
|
Preference.appStateKey("trusted_extensions"),
|
||||||
emptySet(),
|
emptySet(),
|
||||||
)
|
)
|
||||||
|
|
||||||
fun globalSearchFilterState() = preferenceStore.getBoolean(
|
val globalSearchFilterState: Preference<Boolean> = preferenceStore.getBoolean(
|
||||||
Preference.appStateKey("has_filters_toggle_state"),
|
Preference.appStateKey("has_filters_toggle_state"),
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
fun enableSourceBlacklist() = preferenceStore.getBoolean("eh_enable_source_blacklist", true)
|
val enableSourceBlacklist: Preference<Boolean> = preferenceStore.getBoolean("eh_enable_source_blacklist", true)
|
||||||
|
|
||||||
fun sourcesTabCategories() = preferenceStore.getStringSet("sources_tab_categories", mutableSetOf())
|
val sourcesTabCategories: Preference<Set<String>> = preferenceStore.getStringSet("sources_tab_categories", mutableSetOf())
|
||||||
|
|
||||||
fun sourcesTabCategoriesFilter() = preferenceStore.getBoolean("sources_tab_categories_filter", false)
|
val sourcesTabCategoriesFilter: Preference<Boolean> = preferenceStore.getBoolean("sources_tab_categories_filter", false)
|
||||||
|
|
||||||
fun sourcesTabSourcesInCategories() = preferenceStore.getStringSet("sources_tab_source_categories", mutableSetOf())
|
val sourcesTabSourcesInCategories: Preference<Set<String>> = preferenceStore.getStringSet("sources_tab_source_categories", mutableSetOf())
|
||||||
|
|
||||||
fun dataSaver() = preferenceStore.getEnum("data_saver", DataSaver.NONE)
|
val dataSaver: Preference<DataSaver> = preferenceStore.getEnum("data_saver", DataSaver.NONE)
|
||||||
|
|
||||||
fun dataSaverIgnoreJpeg() = preferenceStore.getBoolean("ignore_jpeg", false)
|
val dataSaverIgnoreJpeg: Preference<Boolean> = preferenceStore.getBoolean("ignore_jpeg", false)
|
||||||
|
|
||||||
fun dataSaverIgnoreGif() = preferenceStore.getBoolean("ignore_gif", true)
|
val dataSaverIgnoreGif: Preference<Boolean> = preferenceStore.getBoolean("ignore_gif", true)
|
||||||
|
|
||||||
fun dataSaverImageQuality() = preferenceStore.getInt("data_saver_image_quality", 80)
|
val dataSaverImageQuality: Preference<Int> = preferenceStore.getInt("data_saver_image_quality", 80)
|
||||||
|
|
||||||
fun dataSaverImageFormatJpeg() = preferenceStore.getBoolean("data_saver_image_format_jpeg", false)
|
val dataSaverImageFormatJpeg: Preference<Boolean> = preferenceStore.getBoolean("data_saver_image_format_jpeg", false)
|
||||||
|
|
||||||
fun dataSaverServer() = preferenceStore.getString("data_saver_server", "")
|
val dataSaverServer: Preference<String> = preferenceStore.getString("data_saver_server", "")
|
||||||
|
|
||||||
fun dataSaverColorBW() = preferenceStore.getBoolean("data_saver_color_bw", false)
|
val dataSaverColorBW: Preference<Boolean> = preferenceStore.getBoolean("data_saver_color_bw", false)
|
||||||
|
|
||||||
fun dataSaverExcludedSources() = preferenceStore.getStringSet("data_saver_excluded", emptySet())
|
val dataSaverExcludedSources: Preference<Set<String>> = preferenceStore.getStringSet("data_saver_excluded", emptySet())
|
||||||
|
|
||||||
fun dataSaverDownloader() = preferenceStore.getBoolean("data_saver_downloader", true)
|
val dataSaverDownloader: Preference<Boolean> = preferenceStore.getBoolean("data_saver_downloader", true)
|
||||||
|
|
||||||
enum class DataSaver {
|
enum class DataSaver {
|
||||||
NONE,
|
NONE,
|
||||||
@@ -91,32 +97,38 @@ class SourcePreferences(
|
|||||||
WSRV_NL,
|
WSRV_NL,
|
||||||
}
|
}
|
||||||
|
|
||||||
fun allowLocalSourceHiddenFolders() = preferenceStore.getBoolean("allow_local_source_hidden_folders", false)
|
val allowLocalSourceHiddenFolders: Preference<Boolean> = preferenceStore.getBoolean("allow_local_source_hidden_folders", false)
|
||||||
|
|
||||||
fun preferredMangaDexId() = preferenceStore.getString("preferred_mangaDex_id", "0")
|
val preferredMangaDexId: Preference<String> = preferenceStore.getString("preferred_mangaDex_id", "0")
|
||||||
|
|
||||||
fun mangadexSyncToLibraryIndexes() = preferenceStore.getStringSet(
|
val mangadexSyncToLibraryIndexes: Preference<Set<String>> = preferenceStore.getStringSet(
|
||||||
"pref_mangadex_sync_to_library_indexes",
|
"pref_mangadex_sync_to_library_indexes",
|
||||||
emptySet(),
|
emptySet(),
|
||||||
)
|
)
|
||||||
|
|
||||||
fun recommendationSearchFlags() = preferenceStore.getInt("rec_search_flags", Int.MAX_VALUE)
|
val recommendationSearchFlags: Preference<Int> = preferenceStore.getInt("rec_search_flags", Int.MAX_VALUE)
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
fun migrationSources() = preferenceStore.getLongArray("migration_sources", emptyList())
|
val migrationSources: Preference<List<Long>> = preferenceStore.getLongArray("migration_sources", emptyList())
|
||||||
|
|
||||||
fun migrationFlags() = preferenceStore.getObjectFromInt(
|
val migrationFlags: Preference<Set<MigrationFlag>> = preferenceStore.getObjectFromInt(
|
||||||
key = "migration_flags",
|
key = "migration_flags",
|
||||||
defaultValue = MigrationFlag.entries.toSet(),
|
defaultValue = MigrationFlag.entries.toSet(),
|
||||||
serializer = { MigrationFlag.toBit(it) },
|
serializer = { MigrationFlag.toBit(it) },
|
||||||
deserializer = { value: Int -> MigrationFlag.fromBit(value) },
|
deserializer = { value: Int -> MigrationFlag.fromBit(value) },
|
||||||
)
|
)
|
||||||
|
|
||||||
fun migrationDeepSearchMode() = preferenceStore.getBoolean("migration_deep_search", false)
|
val migrationDeepSearchMode: Preference<Boolean> = preferenceStore.getBoolean("migration_deep_search", false)
|
||||||
|
|
||||||
fun migrationPrioritizeByChapters() = preferenceStore.getBoolean("migration_prioritize_by_chapters", false)
|
val migrationPrioritizeByChapters: Preference<Boolean> = preferenceStore.getBoolean(
|
||||||
|
"migration_prioritize_by_chapters",
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
|
||||||
fun migrationHideUnmatched() = preferenceStore.getBoolean("migration_hide_unmatched", false)
|
val migrationHideUnmatched: Preference<Boolean> = preferenceStore.getBoolean("migration_hide_unmatched", false)
|
||||||
|
|
||||||
fun migrationHideWithoutUpdates() = preferenceStore.getBoolean("migration_hide_without_updates", false)
|
val migrationHideWithoutUpdates: Preference<Boolean> = preferenceStore.getBoolean(
|
||||||
|
"migration_hide_without_updates",
|
||||||
|
false,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,21 +9,21 @@ import java.util.UUID
|
|||||||
class SyncPreferences(
|
class SyncPreferences(
|
||||||
private val preferenceStore: PreferenceStore,
|
private val preferenceStore: PreferenceStore,
|
||||||
) {
|
) {
|
||||||
fun clientHost() = preferenceStore.getString("sync_client_host", "https://sync.tachiyomi.org")
|
val clientHost: Preference<String> = preferenceStore.getString("sync_client_host", "https://sync.tachiyomi.org")
|
||||||
fun clientAPIKey() = preferenceStore.getString("sync_client_api_key", "")
|
val clientAPIKey: Preference<String> = preferenceStore.getString("sync_client_api_key", "")
|
||||||
fun lastSyncTimestamp() = preferenceStore.getLong(Preference.appStateKey("last_sync_timestamp"), 0L)
|
val lastSyncTimestamp: Preference<Long> = preferenceStore.getLong(Preference.appStateKey("last_sync_timestamp"), 0L)
|
||||||
|
|
||||||
fun lastSyncEtag() = preferenceStore.getString("sync_etag", "")
|
val lastSyncEtag: Preference<String> = preferenceStore.getString("sync_etag", "")
|
||||||
|
|
||||||
fun syncInterval() = preferenceStore.getInt("sync_interval", 0)
|
val syncInterval: Preference<Int> = preferenceStore.getInt("sync_interval", 0)
|
||||||
fun syncService() = preferenceStore.getInt("sync_service", 0)
|
val syncService: Preference<Int> = preferenceStore.getInt("sync_service", 0)
|
||||||
|
|
||||||
fun googleDriveAccessToken() = preferenceStore.getString(
|
val googleDriveAccessToken: Preference<String> = preferenceStore.getString(
|
||||||
Preference.appStateKey("google_drive_access_token"),
|
Preference.appStateKey("google_drive_access_token"),
|
||||||
"",
|
"",
|
||||||
)
|
)
|
||||||
|
|
||||||
fun googleDriveRefreshToken() = preferenceStore.getString(
|
val googleDriveRefreshToken: Preference<String> = preferenceStore.getString(
|
||||||
Preference.appStateKey("google_drive_refresh_token"),
|
Preference.appStateKey("google_drive_refresh_token"),
|
||||||
"",
|
"",
|
||||||
)
|
)
|
||||||
@@ -42,7 +42,7 @@ class SyncPreferences(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun isSyncEnabled(): Boolean {
|
fun isSyncEnabled(): Boolean {
|
||||||
return syncService().get() != 0
|
return syncService.get() != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getSyncSettings(): SyncSettings {
|
fun getSyncSettings(): SyncSettings {
|
||||||
|
|||||||
@@ -34,17 +34,17 @@ class TrackPreferences(
|
|||||||
|
|
||||||
fun trackToken(tracker: Tracker) = preferenceStore.getString(Preference.privateKey("track_token_${tracker.id}"), "")
|
fun trackToken(tracker: Tracker) = preferenceStore.getString(Preference.privateKey("track_token_${tracker.id}"), "")
|
||||||
|
|
||||||
fun anilistScoreType() = preferenceStore.getString("anilist_score_type", Anilist.POINT_10)
|
val anilistScoreType: Preference<String> = preferenceStore.getString("anilist_score_type", Anilist.POINT_10)
|
||||||
|
|
||||||
fun autoUpdateTrack() = preferenceStore.getBoolean("pref_auto_update_manga_sync_key", true)
|
val autoUpdateTrack: Preference<Boolean> = preferenceStore.getBoolean("pref_auto_update_manga_sync_key", true)
|
||||||
|
|
||||||
fun autoUpdateTrackOnMarkRead() = preferenceStore.getEnum(
|
val autoUpdateTrackOnMarkRead: Preference<AutoTrackState> = preferenceStore.getEnum(
|
||||||
"pref_auto_update_manga_on_mark_read",
|
"pref_auto_update_manga_on_mark_read",
|
||||||
AutoTrackState.ALWAYS,
|
AutoTrackState.ALWAYS,
|
||||||
)
|
)
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
fun resolveUsingSourceMetadata() = preferenceStore.getBoolean(
|
val resolveUsingSourceMetadata: Preference<Boolean> = preferenceStore.getBoolean(
|
||||||
"pref_resolve_using_source_metadata_key",
|
"pref_resolve_using_source_metadata_key",
|
||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import eu.kanade.domain.ui.model.TabletUiMode
|
|||||||
import eu.kanade.domain.ui.model.ThemeMode
|
import eu.kanade.domain.ui.model.ThemeMode
|
||||||
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
||||||
import eu.kanade.tachiyomi.util.system.isDynamicColorAvailable
|
import eu.kanade.tachiyomi.util.system.isDynamicColorAvailable
|
||||||
|
import tachiyomi.core.common.preference.Preference
|
||||||
import tachiyomi.core.common.preference.PreferenceStore
|
import tachiyomi.core.common.preference.PreferenceStore
|
||||||
import tachiyomi.core.common.preference.getEnum
|
import tachiyomi.core.common.preference.getEnum
|
||||||
import java.time.format.DateTimeFormatter
|
import java.time.format.DateTimeFormatter
|
||||||
@@ -13,10 +14,10 @@ import java.time.format.FormatStyle
|
|||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
class UiPreferences(
|
class UiPreferences(
|
||||||
private val preferenceStore: PreferenceStore,
|
preferenceStore: PreferenceStore,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun themeMode() = preferenceStore.getEnum(
|
val themeMode = preferenceStore.getEnum(
|
||||||
"pref_theme_mode_key",
|
"pref_theme_mode_key",
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
ThemeMode.SYSTEM
|
ThemeMode.SYSTEM
|
||||||
@@ -25,7 +26,7 @@ class UiPreferences(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
fun appTheme() = preferenceStore.getEnum(
|
val appTheme: Preference<AppTheme> = preferenceStore.getEnum(
|
||||||
"pref_app_theme",
|
"pref_app_theme",
|
||||||
if (DeviceUtil.isDynamicColorAvailable) {
|
if (DeviceUtil.isDynamicColorAvailable) {
|
||||||
AppTheme.MONET
|
AppTheme.MONET
|
||||||
@@ -34,37 +35,37 @@ class UiPreferences(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
fun themeDarkAmoled() = preferenceStore.getBoolean("pref_theme_dark_amoled_key", false)
|
val themeDarkAmoled: Preference<Boolean> = preferenceStore.getBoolean("pref_theme_dark_amoled_key", false)
|
||||||
|
|
||||||
fun relativeTime() = preferenceStore.getBoolean("relative_time_v2", true)
|
val relativeTime: Preference<Boolean> = preferenceStore.getBoolean("relative_time_v2", true)
|
||||||
|
|
||||||
fun dateFormat() = preferenceStore.getString("app_date_format", "")
|
val dateFormat: Preference<String> = preferenceStore.getString("app_date_format", "")
|
||||||
|
|
||||||
fun tabletUiMode() = preferenceStore.getEnum("tablet_ui_mode", TabletUiMode.AUTOMATIC)
|
val tabletUiMode: Preference<TabletUiMode> = preferenceStore.getEnum("tablet_ui_mode", TabletUiMode.AUTOMATIC)
|
||||||
|
|
||||||
fun imagesInDescription() = preferenceStore.getBoolean("pref_render_images_description", true)
|
val imagesInDescription: Preference<Boolean> = preferenceStore.getBoolean("pref_render_images_description", true)
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
|
|
||||||
fun expandFilters() = preferenceStore.getBoolean("eh_expand_filters", false)
|
val expandFilters: Preference<Boolean> = preferenceStore.getBoolean("eh_expand_filters", false)
|
||||||
|
|
||||||
fun hideFeedTab() = preferenceStore.getBoolean("hide_latest_tab", false)
|
val hideFeedTab: Preference<Boolean> = preferenceStore.getBoolean("hide_latest_tab", false)
|
||||||
|
|
||||||
fun feedTabInFront() = preferenceStore.getBoolean("latest_tab_position", false)
|
val feedTabInFront: Preference<Boolean> = preferenceStore.getBoolean("latest_tab_position", false)
|
||||||
|
|
||||||
fun recommendsInOverflow() = preferenceStore.getBoolean("recommends_in_overflow", false)
|
val recommendsInOverflow: Preference<Boolean> = preferenceStore.getBoolean("recommends_in_overflow", false)
|
||||||
|
|
||||||
fun mergeInOverflow() = preferenceStore.getBoolean("merge_in_overflow", true)
|
val mergeInOverflow: Preference<Boolean> = preferenceStore.getBoolean("merge_in_overflow", true)
|
||||||
|
|
||||||
fun previewsRowCount() = preferenceStore.getInt("pref_previews_row_count", 4)
|
val previewsRowCount: Preference<Int> = preferenceStore.getInt("pref_previews_row_count", 4)
|
||||||
|
|
||||||
fun useNewSourceNavigation() = preferenceStore.getBoolean("use_new_source_navigation", true)
|
val useNewSourceNavigation: Preference<Boolean> = preferenceStore.getBoolean("use_new_source_navigation", true)
|
||||||
|
|
||||||
fun bottomBarLabels() = preferenceStore.getBoolean("pref_show_bottom_bar_labels", true)
|
val bottomBarLabels: Preference<Boolean> = preferenceStore.getBoolean("pref_show_bottom_bar_labels", true)
|
||||||
|
|
||||||
fun showNavUpdates() = preferenceStore.getBoolean("pref_show_updates_button", true)
|
val showNavUpdates: Preference<Boolean> = preferenceStore.getBoolean("pref_show_updates_button", true)
|
||||||
|
|
||||||
fun showNavHistory() = preferenceStore.getBoolean("pref_show_history_button", true)
|
val showNavHistory: Preference<Boolean> = preferenceStore.getBoolean("pref_show_history_button", true)
|
||||||
|
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ fun relativeDateText(
|
|||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
val preferences = remember { Injekt.get<UiPreferences>() }
|
val preferences = remember { Injekt.get<UiPreferences>() }
|
||||||
val relativeTime = remember { preferences.relativeTime().get() }
|
val relativeTime = remember { preferences.relativeTime.get() }
|
||||||
val dateFormat = remember { UiPreferences.dateFormat(preferences.dateFormat().get()) }
|
val dateFormat = remember { UiPreferences.dateFormat(preferences.dateFormat.get()) }
|
||||||
|
|
||||||
return localDate?.toRelativeString(
|
return localDate?.toRelativeString(
|
||||||
context = context,
|
context = context,
|
||||||
|
|||||||
@@ -100,9 +100,9 @@ fun LibrarySettingsDialog(
|
|||||||
private fun ColumnScope.FilterPage(
|
private fun ColumnScope.FilterPage(
|
||||||
screenModel: LibrarySettingsScreenModel,
|
screenModel: LibrarySettingsScreenModel,
|
||||||
) {
|
) {
|
||||||
val filterDownloaded by screenModel.libraryPreferences.filterDownloaded().collectAsState()
|
val filterDownloaded by screenModel.libraryPreferences.filterDownloaded.collectAsState()
|
||||||
val downloadedOnly by screenModel.preferences.downloadedOnly().collectAsState()
|
val downloadedOnly by screenModel.preferences.downloadedOnly.collectAsState()
|
||||||
val autoUpdateMangaRestrictions by screenModel.libraryPreferences.autoUpdateMangaRestrictions().collectAsState()
|
val autoUpdateMangaRestrictions by screenModel.libraryPreferences.autoUpdateMangaRestrictions.collectAsState()
|
||||||
|
|
||||||
TriStateItem(
|
TriStateItem(
|
||||||
label = stringResource(MR.strings.label_downloaded),
|
label = stringResource(MR.strings.label_downloaded),
|
||||||
@@ -114,25 +114,25 @@ private fun ColumnScope.FilterPage(
|
|||||||
enabled = !downloadedOnly,
|
enabled = !downloadedOnly,
|
||||||
onClick = { screenModel.toggleFilter(LibraryPreferences::filterDownloaded) },
|
onClick = { screenModel.toggleFilter(LibraryPreferences::filterDownloaded) },
|
||||||
)
|
)
|
||||||
val filterUnread by screenModel.libraryPreferences.filterUnread().collectAsState()
|
val filterUnread by screenModel.libraryPreferences.filterUnread.collectAsState()
|
||||||
TriStateItem(
|
TriStateItem(
|
||||||
label = stringResource(MR.strings.action_filter_unread),
|
label = stringResource(MR.strings.action_filter_unread),
|
||||||
state = filterUnread,
|
state = filterUnread,
|
||||||
onClick = { screenModel.toggleFilter(LibraryPreferences::filterUnread) },
|
onClick = { screenModel.toggleFilter(LibraryPreferences::filterUnread) },
|
||||||
)
|
)
|
||||||
val filterStarted by screenModel.libraryPreferences.filterStarted().collectAsState()
|
val filterStarted by screenModel.libraryPreferences.filterStarted.collectAsState()
|
||||||
TriStateItem(
|
TriStateItem(
|
||||||
label = stringResource(MR.strings.label_started),
|
label = stringResource(MR.strings.label_started),
|
||||||
state = filterStarted,
|
state = filterStarted,
|
||||||
onClick = { screenModel.toggleFilter(LibraryPreferences::filterStarted) },
|
onClick = { screenModel.toggleFilter(LibraryPreferences::filterStarted) },
|
||||||
)
|
)
|
||||||
val filterBookmarked by screenModel.libraryPreferences.filterBookmarked().collectAsState()
|
val filterBookmarked by screenModel.libraryPreferences.filterBookmarked.collectAsState()
|
||||||
TriStateItem(
|
TriStateItem(
|
||||||
label = stringResource(MR.strings.action_filter_bookmarked),
|
label = stringResource(MR.strings.action_filter_bookmarked),
|
||||||
state = filterBookmarked,
|
state = filterBookmarked,
|
||||||
onClick = { screenModel.toggleFilter(LibraryPreferences::filterBookmarked) },
|
onClick = { screenModel.toggleFilter(LibraryPreferences::filterBookmarked) },
|
||||||
)
|
)
|
||||||
val filterCompleted by screenModel.libraryPreferences.filterCompleted().collectAsState()
|
val filterCompleted by screenModel.libraryPreferences.filterCompleted.collectAsState()
|
||||||
TriStateItem(
|
TriStateItem(
|
||||||
label = stringResource(MR.strings.completed),
|
label = stringResource(MR.strings.completed),
|
||||||
state = filterCompleted,
|
state = filterCompleted,
|
||||||
@@ -143,7 +143,7 @@ private fun ColumnScope.FilterPage(
|
|||||||
(isDevFlavor || isPreviewBuildType) &&
|
(isDevFlavor || isPreviewBuildType) &&
|
||||||
LibraryPreferences.MANGA_OUTSIDE_RELEASE_PERIOD in autoUpdateMangaRestrictions
|
LibraryPreferences.MANGA_OUTSIDE_RELEASE_PERIOD in autoUpdateMangaRestrictions
|
||||||
) {
|
) {
|
||||||
val filterIntervalCustom by screenModel.libraryPreferences.filterIntervalCustom().collectAsState()
|
val filterIntervalCustom by screenModel.libraryPreferences.filterIntervalCustom.collectAsState()
|
||||||
TriStateItem(
|
TriStateItem(
|
||||||
label = stringResource(MR.strings.action_filter_interval_custom),
|
label = stringResource(MR.strings.action_filter_interval_custom),
|
||||||
state = filterIntervalCustom,
|
state = filterIntervalCustom,
|
||||||
@@ -151,7 +151,7 @@ private fun ColumnScope.FilterPage(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
// SY -->
|
// SY -->
|
||||||
val filterLewd by screenModel.libraryPreferences.filterLewd().collectAsState()
|
val filterLewd by screenModel.libraryPreferences.filterLewd.collectAsState()
|
||||||
TriStateItem(
|
TriStateItem(
|
||||||
label = stringResource(SYMR.strings.lewd),
|
label = stringResource(SYMR.strings.lewd),
|
||||||
state = filterLewd,
|
state = filterLewd,
|
||||||
@@ -194,7 +194,7 @@ private fun ColumnScope.SortPage(
|
|||||||
) {
|
) {
|
||||||
val trackers by screenModel.trackersFlow.collectAsState()
|
val trackers by screenModel.trackersFlow.collectAsState()
|
||||||
// SY -->
|
// SY -->
|
||||||
val globalSortMode by screenModel.libraryPreferences.sortingMode().collectAsState()
|
val globalSortMode by screenModel.libraryPreferences.sortingMode.collectAsState()
|
||||||
val sortingMode = if (screenModel.grouping == LibraryGroup.BY_DEFAULT) {
|
val sortingMode = if (screenModel.grouping == LibraryGroup.BY_DEFAULT) {
|
||||||
category.sort.type
|
category.sort.type
|
||||||
} else {
|
} else {
|
||||||
@@ -206,9 +206,9 @@ private fun ColumnScope.SortPage(
|
|||||||
!globalSortMode.isAscending
|
!globalSortMode.isAscending
|
||||||
}
|
}
|
||||||
val hasSortTags by remember {
|
val hasSortTags by remember {
|
||||||
screenModel.libraryPreferences.sortTagsForLibrary().changes()
|
screenModel.libraryPreferences.sortTagsForLibrary.changes()
|
||||||
.map { it.isNotEmpty() }
|
.map { it.isNotEmpty() }
|
||||||
}.collectAsState(initial = screenModel.libraryPreferences.sortTagsForLibrary().get().isNotEmpty())
|
}.collectAsState(initial = screenModel.libraryPreferences.sortTagsForLibrary.get().isNotEmpty())
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
val options = remember(trackers.isEmpty()/* SY --> */, hasSortTags/* SY <-- */) {
|
val options = remember(trackers.isEmpty()/* SY --> */, hasSortTags/* SY <-- */) {
|
||||||
@@ -287,7 +287,7 @@ private val displayModes = listOf(
|
|||||||
private fun ColumnScope.DisplayPage(
|
private fun ColumnScope.DisplayPage(
|
||||||
screenModel: LibrarySettingsScreenModel,
|
screenModel: LibrarySettingsScreenModel,
|
||||||
) {
|
) {
|
||||||
val displayMode by screenModel.libraryPreferences.displayMode().collectAsState()
|
val displayMode by screenModel.libraryPreferences.displayMode.collectAsState()
|
||||||
SettingsChipRow(MR.strings.action_display_mode) {
|
SettingsChipRow(MR.strings.action_display_mode) {
|
||||||
displayModes.map { (titleRes, mode) ->
|
displayModes.map { (titleRes, mode) ->
|
||||||
FilterChip(
|
FilterChip(
|
||||||
@@ -302,9 +302,9 @@ private fun ColumnScope.DisplayPage(
|
|||||||
val configuration = LocalConfiguration.current
|
val configuration = LocalConfiguration.current
|
||||||
val columnPreference = remember {
|
val columnPreference = remember {
|
||||||
if (configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
if (configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||||
screenModel.libraryPreferences.landscapeColumns()
|
screenModel.libraryPreferences.landscapeColumns
|
||||||
} else {
|
} else {
|
||||||
screenModel.libraryPreferences.portraitColumns()
|
screenModel.libraryPreferences.portraitColumns
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -326,33 +326,33 @@ private fun ColumnScope.DisplayPage(
|
|||||||
HeadingItem(MR.strings.overlay_header)
|
HeadingItem(MR.strings.overlay_header)
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(MR.strings.action_display_download_badge),
|
label = stringResource(MR.strings.action_display_download_badge),
|
||||||
pref = screenModel.libraryPreferences.downloadBadge(),
|
pref = screenModel.libraryPreferences.downloadBadge,
|
||||||
)
|
)
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(MR.strings.action_display_unread_badge),
|
label = stringResource(MR.strings.action_display_unread_badge),
|
||||||
pref = screenModel.libraryPreferences.unreadBadge(),
|
pref = screenModel.libraryPreferences.unreadBadge,
|
||||||
)
|
)
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(MR.strings.action_display_local_badge),
|
label = stringResource(MR.strings.action_display_local_badge),
|
||||||
pref = screenModel.libraryPreferences.localBadge(),
|
pref = screenModel.libraryPreferences.localBadge,
|
||||||
)
|
)
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(MR.strings.action_display_language_badge),
|
label = stringResource(MR.strings.action_display_language_badge),
|
||||||
pref = screenModel.libraryPreferences.languageBadge(),
|
pref = screenModel.libraryPreferences.languageBadge,
|
||||||
)
|
)
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(MR.strings.action_display_show_continue_reading_button),
|
label = stringResource(MR.strings.action_display_show_continue_reading_button),
|
||||||
pref = screenModel.libraryPreferences.showContinueReadingButton(),
|
pref = screenModel.libraryPreferences.showContinueReadingButton,
|
||||||
)
|
)
|
||||||
|
|
||||||
HeadingItem(MR.strings.tabs_header)
|
HeadingItem(MR.strings.tabs_header)
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(MR.strings.action_display_show_tabs),
|
label = stringResource(MR.strings.action_display_show_tabs),
|
||||||
pref = screenModel.libraryPreferences.categoryTabs(),
|
pref = screenModel.libraryPreferences.categoryTabs,
|
||||||
)
|
)
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(MR.strings.action_display_show_number_of_items),
|
label = stringResource(MR.strings.action_display_show_number_of_items),
|
||||||
pref = screenModel.libraryPreferences.categoryNumberOfItems(),
|
pref = screenModel.libraryPreferences.categoryNumberOfItems,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ fun ChapterSettingsDialog(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val downloadedOnly = remember { Injekt.get<BasePreferences>().downloadedOnly().get() }
|
val downloadedOnly = remember { Injekt.get<BasePreferences>().downloadedOnly.get() }
|
||||||
|
|
||||||
TabbedDialog(
|
TabbedDialog(
|
||||||
onDismissRequest = onDismissRequest,
|
onDismissRequest = onDismissRequest,
|
||||||
|
|||||||
@@ -656,7 +656,7 @@ private fun MangaSummary(
|
|||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
val preferences = remember { Injekt.get<UiPreferences>() }
|
val preferences = remember { Injekt.get<UiPreferences>() }
|
||||||
val loadImages = remember { preferences.imagesInDescription().get() }
|
val loadImages = remember { preferences.imagesInDescription.get() }
|
||||||
val animProgress by animateFloatAsState(
|
val animProgress by animateFloatAsState(
|
||||||
targetValue = if (expanded) 1f else 0f,
|
targetValue = if (expanded) 1f else 0f,
|
||||||
label = "summary",
|
label = "summary",
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ internal class PermissionStep : OnboardingStep {
|
|||||||
color = MaterialTheme.colorScheme.onPrimaryContainer,
|
color = MaterialTheme.colorScheme.onPrimaryContainer,
|
||||||
)
|
)
|
||||||
|
|
||||||
val crashlyticsPref = privacyPreferences.crashlytics()
|
val crashlyticsPref = privacyPreferences.crashlytics
|
||||||
val crashlytics by crashlyticsPref.collectAsState()
|
val crashlytics by crashlyticsPref.collectAsState()
|
||||||
PermissionSwitch(
|
PermissionSwitch(
|
||||||
title = stringResource(MR.strings.onboarding_permission_crashlytics),
|
title = stringResource(MR.strings.onboarding_permission_crashlytics),
|
||||||
@@ -131,7 +131,7 @@ internal class PermissionStep : OnboardingStep {
|
|||||||
onToggleChange = crashlyticsPref::set,
|
onToggleChange = crashlyticsPref::set,
|
||||||
)
|
)
|
||||||
|
|
||||||
val analyticsPref = privacyPreferences.analytics()
|
val analyticsPref = privacyPreferences.analytics
|
||||||
val analytics by analyticsPref.collectAsState()
|
val analytics by analyticsPref.collectAsState()
|
||||||
PermissionSwitch(
|
PermissionSwitch(
|
||||||
title = stringResource(MR.strings.onboarding_permission_analytics),
|
title = stringResource(MR.strings.onboarding_permission_analytics),
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import uy.kohesive.injekt.api.get
|
|||||||
|
|
||||||
internal class StorageStep : OnboardingStep {
|
internal class StorageStep : OnboardingStep {
|
||||||
|
|
||||||
private val storagePref = Injekt.get<StoragePreferences>().baseStorageDirectory()
|
private val storagePref = Injekt.get<StoragePreferences>().baseStorageDirectory
|
||||||
|
|
||||||
private var _isComplete by mutableStateOf(false)
|
private var _isComplete by mutableStateOf(false)
|
||||||
|
|
||||||
|
|||||||
@@ -19,13 +19,13 @@ internal class ThemeStep : OnboardingStep {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun Content() {
|
override fun Content() {
|
||||||
val themeModePref = uiPreferences.themeMode()
|
val themeModePref = uiPreferences.themeMode
|
||||||
val themeMode by themeModePref.collectAsState()
|
val themeMode by themeModePref.collectAsState()
|
||||||
|
|
||||||
val appThemePref = uiPreferences.appTheme()
|
val appThemePref = uiPreferences.appTheme
|
||||||
val appTheme by appThemePref.collectAsState()
|
val appTheme by appThemePref.collectAsState()
|
||||||
|
|
||||||
val amoledPref = uiPreferences.themeDarkAmoled()
|
val amoledPref = uiPreferences.themeDarkAmoled
|
||||||
val amoled by amoledPref.collectAsState()
|
val amoled by amoledPref.collectAsState()
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ sealed class Preference {
|
|||||||
override val title: String,
|
override val title: String,
|
||||||
override val subtitle: CharSequence? = null,
|
override val subtitle: CharSequence? = null,
|
||||||
override val enabled: Boolean = true,
|
override val enabled: Boolean = true,
|
||||||
|
val widget: @Composable (() -> Unit)? = null,
|
||||||
val onClick: (() -> Unit)? = null,
|
val onClick: (() -> Unit)? = null,
|
||||||
) : PreferenceItem<String, Unit>() {
|
) : PreferenceItem<String, Unit>() {
|
||||||
override val icon: ImageVector? = null
|
override val icon: ImageVector? = null
|
||||||
|
|||||||
@@ -147,6 +147,7 @@ internal fun PreferenceItem(
|
|||||||
title = item.title,
|
title = item.title,
|
||||||
subtitle = item.subtitle,
|
subtitle = item.subtitle,
|
||||||
icon = item.icon,
|
icon = item.icon,
|
||||||
|
widget = item.widget,
|
||||||
onPreferenceClick = item.onClick,
|
onPreferenceClick = item.onClick,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ fun ConfigureExhDialog(run: Boolean, onRunning: () -> Unit) {
|
|||||||
|
|
||||||
LaunchedEffect(run) {
|
LaunchedEffect(run) {
|
||||||
if (run) {
|
if (run) {
|
||||||
if (exhPreferences.exhShowSettingsUploadWarning().get()) {
|
if (exhPreferences.exhShowSettingsUploadWarning.get()) {
|
||||||
warnDialogOpen = true
|
warnDialogOpen = true
|
||||||
} else {
|
} else {
|
||||||
configureDialogOpen = true
|
configureDialogOpen = true
|
||||||
@@ -57,7 +57,7 @@ fun ConfigureExhDialog(run: Boolean, onRunning: () -> Unit) {
|
|||||||
confirmButton = {
|
confirmButton = {
|
||||||
TextButton(
|
TextButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
exhPreferences.exhShowSettingsUploadWarning().set(false)
|
exhPreferences.exhShowSettingsUploadWarning.set(false)
|
||||||
configureDialogOpen = true
|
configureDialogOpen = true
|
||||||
warnDialogOpen = false
|
warnDialogOpen = false
|
||||||
},
|
},
|
||||||
|
|||||||
+32
-29
@@ -131,7 +131,7 @@ object SettingsAdvancedScreen : SearchableSettings {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
/* SY --> Preference.PreferenceItem.SwitchPreference(
|
/* SY --> Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = networkPreferences.verboseLogging(),
|
preference = networkPreferences.verboseLogging,
|
||||||
title = stringResource(MR.strings.pref_verbose_logging),
|
title = stringResource(MR.strings.pref_verbose_logging),
|
||||||
subtitle = stringResource(MR.strings.pref_verbose_logging_summary),
|
subtitle = stringResource(MR.strings.pref_verbose_logging_summary),
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
@@ -223,6 +223,7 @@ object SettingsAdvancedScreen : SearchableSettings {
|
|||||||
private fun getDataGroup(): Preference.PreferenceGroup {
|
private fun getDataGroup(): Preference.PreferenceGroup {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val navigator = LocalNavigator.currentOrThrow
|
val navigator = LocalNavigator.currentOrThrow
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
return Preference.PreferenceGroup(
|
return Preference.PreferenceGroup(
|
||||||
title = stringResource(MR.strings.label_data),
|
title = stringResource(MR.strings.label_data),
|
||||||
@@ -231,8 +232,10 @@ object SettingsAdvancedScreen : SearchableSettings {
|
|||||||
title = stringResource(MR.strings.pref_invalidate_download_cache),
|
title = stringResource(MR.strings.pref_invalidate_download_cache),
|
||||||
subtitle = stringResource(MR.strings.pref_invalidate_download_cache_summary),
|
subtitle = stringResource(MR.strings.pref_invalidate_download_cache_summary),
|
||||||
onClick = {
|
onClick = {
|
||||||
Injekt.get<DownloadCache>().invalidateCache()
|
scope.launch {
|
||||||
context.toast(MR.strings.download_cache_invalidated)
|
Injekt.get<DownloadCache>().invalidateCache()
|
||||||
|
context.toast(MR.strings.download_cache_invalidated)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.TextPreference(
|
Preference.PreferenceItem.TextPreference(
|
||||||
@@ -251,7 +254,7 @@ object SettingsAdvancedScreen : SearchableSettings {
|
|||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val networkHelper = remember { Injekt.get<NetworkHelper>() }
|
val networkHelper = remember { Injekt.get<NetworkHelper>() }
|
||||||
|
|
||||||
val userAgentPref = networkPreferences.defaultUserAgent()
|
val userAgentPref = networkPreferences.defaultUserAgent
|
||||||
val userAgent by userAgentPref.collectAsState()
|
val userAgent by userAgentPref.collectAsState()
|
||||||
|
|
||||||
return Preference.PreferenceGroup(
|
return Preference.PreferenceGroup(
|
||||||
@@ -287,7 +290,7 @@ object SettingsAdvancedScreen : SearchableSettings {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
preference = networkPreferences.dohProvider(),
|
preference = networkPreferences.dohProvider,
|
||||||
entries = persistentMapOf(
|
entries = persistentMapOf(
|
||||||
-1 to stringResource(MR.strings.disabled),
|
-1 to stringResource(MR.strings.disabled),
|
||||||
PREF_DOH_CLOUDFLARE to "Cloudflare",
|
PREF_DOH_CLOUDFLARE to "Cloudflare",
|
||||||
@@ -368,12 +371,12 @@ object SettingsAdvancedScreen : SearchableSettings {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = libraryPreferences.updateMangaTitles(),
|
preference = libraryPreferences.updateMangaTitles,
|
||||||
title = stringResource(MR.strings.pref_update_library_manga_titles),
|
title = stringResource(MR.strings.pref_update_library_manga_titles),
|
||||||
subtitle = stringResource(MR.strings.pref_update_library_manga_titles_summary),
|
subtitle = stringResource(MR.strings.pref_update_library_manga_titles_summary),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = libraryPreferences.disallowNonAsciiFilenames(),
|
preference = libraryPreferences.disallowNonAsciiFilenames,
|
||||||
title = stringResource(MR.strings.pref_disallow_non_ascii_filenames),
|
title = stringResource(MR.strings.pref_disallow_non_ascii_filenames),
|
||||||
subtitle = stringResource(MR.strings.pref_disallow_non_ascii_filenames_details),
|
subtitle = stringResource(MR.strings.pref_disallow_non_ascii_filenames_details),
|
||||||
),
|
),
|
||||||
@@ -390,7 +393,7 @@ object SettingsAdvancedScreen : SearchableSettings {
|
|||||||
title = stringResource(MR.strings.pref_category_downloads),
|
title = stringResource(MR.strings.pref_category_downloads),
|
||||||
preferenceItems = persistentListOf(
|
preferenceItems = persistentListOf(
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = downloadPreferences.includeChapterUrlHash(),
|
preference = downloadPreferences.includeChapterUrlHash,
|
||||||
title = stringResource(SYMR.strings.pref_include_chapter_url_hash),
|
title = stringResource(SYMR.strings.pref_include_chapter_url_hash),
|
||||||
subtitle = stringResource(SYMR.strings.pref_include_chapter_url_hash_desc),
|
subtitle = stringResource(SYMR.strings.pref_include_chapter_url_hash_desc),
|
||||||
),
|
),
|
||||||
@@ -410,14 +413,14 @@ object SettingsAdvancedScreen : SearchableSettings {
|
|||||||
uri?.let {
|
uri?.let {
|
||||||
val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
|
val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||||
context.contentResolver.takePersistableUriPermission(uri, flags)
|
context.contentResolver.takePersistableUriPermission(uri, flags)
|
||||||
basePreferences.displayProfile().set(uri.toString())
|
basePreferences.displayProfile.set(uri.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Preference.PreferenceGroup(
|
return Preference.PreferenceGroup(
|
||||||
title = stringResource(MR.strings.pref_category_reader),
|
title = stringResource(MR.strings.pref_category_reader),
|
||||||
preferenceItems = persistentListOf(
|
preferenceItems = persistentListOf(
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
preference = basePreferences.hardwareBitmapThreshold(),
|
preference = basePreferences.hardwareBitmapThreshold,
|
||||||
entries = GLUtil.CUSTOM_TEXTURE_LIMIT_OPTIONS
|
entries = GLUtil.CUSTOM_TEXTURE_LIMIT_OPTIONS
|
||||||
.mapIndexed { index, option ->
|
.mapIndexed { index, option ->
|
||||||
val display = if (index == 0) {
|
val display = if (index == 0) {
|
||||||
@@ -437,13 +440,13 @@ object SettingsAdvancedScreen : SearchableSettings {
|
|||||||
GLUtil.DEVICE_TEXTURE_LIMIT > GLUtil.SAFE_TEXTURE_LIMIT,
|
GLUtil.DEVICE_TEXTURE_LIMIT > GLUtil.SAFE_TEXTURE_LIMIT,
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = basePreferences.alwaysDecodeLongStripWithSSIV(),
|
preference = basePreferences.alwaysDecodeLongStripWithSSIV,
|
||||||
title = stringResource(MR.strings.pref_always_decode_long_strip_with_ssiv_2),
|
title = stringResource(MR.strings.pref_always_decode_long_strip_with_ssiv_2),
|
||||||
subtitle = stringResource(MR.strings.pref_always_decode_long_strip_with_ssiv_summary),
|
subtitle = stringResource(MR.strings.pref_always_decode_long_strip_with_ssiv_summary),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.TextPreference(
|
Preference.PreferenceItem.TextPreference(
|
||||||
title = stringResource(MR.strings.pref_display_profile),
|
title = stringResource(MR.strings.pref_display_profile),
|
||||||
subtitle = basePreferences.displayProfile().get(),
|
subtitle = basePreferences.displayProfile.get(),
|
||||||
onClick = {
|
onClick = {
|
||||||
chooseColorProfile.launch(arrayOf("*/*"))
|
chooseColorProfile.launch(arrayOf("*/*"))
|
||||||
},
|
},
|
||||||
@@ -458,7 +461,7 @@ object SettingsAdvancedScreen : SearchableSettings {
|
|||||||
): Preference.PreferenceGroup {
|
): Preference.PreferenceGroup {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val uriHandler = LocalUriHandler.current
|
val uriHandler = LocalUriHandler.current
|
||||||
val extensionInstallerPref = basePreferences.extensionInstaller()
|
val extensionInstallerPref = basePreferences.extensionInstaller
|
||||||
var shizukuMissing by rememberSaveable { mutableStateOf(false) }
|
var shizukuMissing by rememberSaveable { mutableStateOf(false) }
|
||||||
val trustExtension = remember { Injekt.get<TrustExtension>() }
|
val trustExtension = remember { Injekt.get<TrustExtension>() }
|
||||||
|
|
||||||
@@ -658,12 +661,12 @@ object SettingsAdvancedScreen : SearchableSettings {
|
|||||||
@Composable
|
@Composable
|
||||||
private fun getDataSaverGroup(): Preference.PreferenceGroup {
|
private fun getDataSaverGroup(): Preference.PreferenceGroup {
|
||||||
val sourcePreferences = remember { Injekt.get<SourcePreferences>() }
|
val sourcePreferences = remember { Injekt.get<SourcePreferences>() }
|
||||||
val dataSaver by sourcePreferences.dataSaver().collectAsState()
|
val dataSaver by sourcePreferences.dataSaver.collectAsState()
|
||||||
return Preference.PreferenceGroup(
|
return Preference.PreferenceGroup(
|
||||||
title = stringResource(SYMR.strings.data_saver),
|
title = stringResource(SYMR.strings.data_saver),
|
||||||
preferenceItems = persistentListOf(
|
preferenceItems = persistentListOf(
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
preference = sourcePreferences.dataSaver(),
|
preference = sourcePreferences.dataSaver,
|
||||||
title = stringResource(SYMR.strings.data_saver),
|
title = stringResource(SYMR.strings.data_saver),
|
||||||
subtitle = stringResource(SYMR.strings.data_saver_summary),
|
subtitle = stringResource(SYMR.strings.data_saver_summary),
|
||||||
entries = persistentMapOf(
|
entries = persistentMapOf(
|
||||||
@@ -673,28 +676,28 @@ object SettingsAdvancedScreen : SearchableSettings {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.EditTextPreference(
|
Preference.PreferenceItem.EditTextPreference(
|
||||||
preference = sourcePreferences.dataSaverServer(),
|
preference = sourcePreferences.dataSaverServer,
|
||||||
title = stringResource(SYMR.strings.bandwidth_data_saver_server),
|
title = stringResource(SYMR.strings.bandwidth_data_saver_server),
|
||||||
subtitle = stringResource(SYMR.strings.data_saver_server_summary),
|
subtitle = stringResource(SYMR.strings.data_saver_server_summary),
|
||||||
enabled = dataSaver == DataSaver.BANDWIDTH_HERO,
|
enabled = dataSaver == DataSaver.BANDWIDTH_HERO,
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = sourcePreferences.dataSaverDownloader(),
|
preference = sourcePreferences.dataSaverDownloader,
|
||||||
title = stringResource(SYMR.strings.data_saver_downloader),
|
title = stringResource(SYMR.strings.data_saver_downloader),
|
||||||
enabled = dataSaver != DataSaver.NONE,
|
enabled = dataSaver != DataSaver.NONE,
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = sourcePreferences.dataSaverIgnoreJpeg(),
|
preference = sourcePreferences.dataSaverIgnoreJpeg,
|
||||||
title = stringResource(SYMR.strings.data_saver_ignore_jpeg),
|
title = stringResource(SYMR.strings.data_saver_ignore_jpeg),
|
||||||
enabled = dataSaver != DataSaver.NONE,
|
enabled = dataSaver != DataSaver.NONE,
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = sourcePreferences.dataSaverIgnoreGif(),
|
preference = sourcePreferences.dataSaverIgnoreGif,
|
||||||
title = stringResource(SYMR.strings.data_saver_ignore_gif),
|
title = stringResource(SYMR.strings.data_saver_ignore_gif),
|
||||||
enabled = dataSaver != DataSaver.NONE,
|
enabled = dataSaver != DataSaver.NONE,
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
preference = sourcePreferences.dataSaverImageQuality(),
|
preference = sourcePreferences.dataSaverImageQuality,
|
||||||
title = stringResource(SYMR.strings.data_saver_image_quality),
|
title = stringResource(SYMR.strings.data_saver_image_quality),
|
||||||
subtitle = stringResource(SYMR.strings.data_saver_image_quality_summary),
|
subtitle = stringResource(SYMR.strings.data_saver_image_quality_summary),
|
||||||
entries = listOf(
|
entries = listOf(
|
||||||
@@ -710,10 +713,10 @@ object SettingsAdvancedScreen : SearchableSettings {
|
|||||||
enabled = dataSaver != DataSaver.NONE,
|
enabled = dataSaver != DataSaver.NONE,
|
||||||
),
|
),
|
||||||
kotlin.run {
|
kotlin.run {
|
||||||
val dataSaverImageFormatJpeg by sourcePreferences.dataSaverImageFormatJpeg()
|
val dataSaverImageFormatJpeg by sourcePreferences.dataSaverImageFormatJpeg
|
||||||
.collectAsState()
|
.collectAsState()
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = sourcePreferences.dataSaverImageFormatJpeg(),
|
preference = sourcePreferences.dataSaverImageFormatJpeg,
|
||||||
title = stringResource(SYMR.strings.data_saver_image_format),
|
title = stringResource(SYMR.strings.data_saver_image_format),
|
||||||
subtitle = if (dataSaverImageFormatJpeg) {
|
subtitle = if (dataSaverImageFormatJpeg) {
|
||||||
stringResource(SYMR.strings.data_saver_image_format_summary_on)
|
stringResource(SYMR.strings.data_saver_image_format_summary_on)
|
||||||
@@ -724,7 +727,7 @@ object SettingsAdvancedScreen : SearchableSettings {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = sourcePreferences.dataSaverColorBW(),
|
preference = sourcePreferences.dataSaverColorBW,
|
||||||
title = stringResource(SYMR.strings.data_saver_color_bw),
|
title = stringResource(SYMR.strings.data_saver_color_bw),
|
||||||
enabled = dataSaver == DataSaver.BANDWIDTH_HERO,
|
enabled = dataSaver == DataSaver.BANDWIDTH_HERO,
|
||||||
),
|
),
|
||||||
@@ -744,7 +747,7 @@ object SettingsAdvancedScreen : SearchableSettings {
|
|||||||
title = stringResource(SYMR.strings.developer_tools),
|
title = stringResource(SYMR.strings.developer_tools),
|
||||||
preferenceItems = persistentListOf(
|
preferenceItems = persistentListOf(
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = exhPreferences.isHentaiEnabled(),
|
preference = exhPreferences.isHentaiEnabled,
|
||||||
title = stringResource(SYMR.strings.toggle_hentai_features),
|
title = stringResource(SYMR.strings.toggle_hentai_features),
|
||||||
subtitle = stringResource(SYMR.strings.toggle_hentai_features_summary),
|
subtitle = stringResource(SYMR.strings.toggle_hentai_features_summary),
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
@@ -759,7 +762,7 @@ object SettingsAdvancedScreen : SearchableSettings {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = delegateSourcePreferences.delegateSources(),
|
preference = delegateSourcePreferences.delegateSources,
|
||||||
title = stringResource(SYMR.strings.toggle_delegated_sources),
|
title = stringResource(SYMR.strings.toggle_delegated_sources),
|
||||||
subtitle = stringResource(
|
subtitle = stringResource(
|
||||||
SYMR.strings.toggle_delegated_sources_summary,
|
SYMR.strings.toggle_delegated_sources_summary,
|
||||||
@@ -769,7 +772,7 @@ object SettingsAdvancedScreen : SearchableSettings {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
preference = exhPreferences.logLevel(),
|
preference = exhPreferences.logLevel,
|
||||||
title = stringResource(SYMR.strings.log_level),
|
title = stringResource(SYMR.strings.log_level),
|
||||||
subtitle = stringResource(SYMR.strings.log_level_summary),
|
subtitle = stringResource(SYMR.strings.log_level_summary),
|
||||||
entries = EHLogLevel.entries.mapIndexed { index, ehLogLevel ->
|
entries = EHLogLevel.entries.mapIndexed { index, ehLogLevel ->
|
||||||
@@ -779,7 +782,7 @@ object SettingsAdvancedScreen : SearchableSettings {
|
|||||||
}.toMap().toImmutableMap(),
|
}.toMap().toImmutableMap(),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = sourcePreferences.enableSourceBlacklist(),
|
preference = sourcePreferences.enableSourceBlacklist,
|
||||||
title = stringResource(SYMR.strings.enable_source_blacklist),
|
title = stringResource(SYMR.strings.enable_source_blacklist),
|
||||||
subtitle = stringResource(
|
subtitle = stringResource(
|
||||||
SYMR.strings.enable_source_blacklist_summary,
|
SYMR.strings.enable_source_blacklist_summary,
|
||||||
@@ -813,7 +816,7 @@ object SettingsAdvancedScreen : SearchableSettings {
|
|||||||
TextButton(
|
TextButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
dismiss()
|
dismiss()
|
||||||
securityPreferences.encryptDatabase().set(true)
|
securityPreferences.encryptDatabase.set(true)
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
Text(text = stringResource(MR.strings.action_ok))
|
Text(text = stringResource(MR.strings.action_ok))
|
||||||
@@ -823,7 +826,7 @@ object SettingsAdvancedScreen : SearchableSettings {
|
|||||||
}
|
}
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
title = stringResource(SYMR.strings.encrypt_database),
|
title = stringResource(SYMR.strings.encrypt_database),
|
||||||
preference = securityPreferences.encryptDatabase(),
|
preference = securityPreferences.encryptDatabase,
|
||||||
subtitle = stringResource(SYMR.strings.encrypt_database_subtitle),
|
subtitle = stringResource(SYMR.strings.encrypt_database_subtitle),
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
if (it) {
|
if (it) {
|
||||||
|
|||||||
+16
-16
@@ -56,13 +56,13 @@ object SettingsAppearanceScreen : SearchableSettings {
|
|||||||
): Preference.PreferenceGroup {
|
): Preference.PreferenceGroup {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
val themeModePref = uiPreferences.themeMode()
|
val themeModePref = uiPreferences.themeMode
|
||||||
val themeMode by themeModePref.collectAsState()
|
val themeMode by themeModePref.collectAsState()
|
||||||
|
|
||||||
val appThemePref = uiPreferences.appTheme()
|
val appThemePref = uiPreferences.appTheme
|
||||||
val appTheme by appThemePref.collectAsState()
|
val appTheme by appThemePref.collectAsState()
|
||||||
|
|
||||||
val amoledPref = uiPreferences.themeDarkAmoled()
|
val amoledPref = uiPreferences.themeDarkAmoled
|
||||||
val amoled by amoledPref.collectAsState()
|
val amoled by amoledPref.collectAsState()
|
||||||
|
|
||||||
return Preference.PreferenceGroup(
|
return Preference.PreferenceGroup(
|
||||||
@@ -109,7 +109,7 @@ object SettingsAppearanceScreen : SearchableSettings {
|
|||||||
|
|
||||||
val now = remember { LocalDate.now() }
|
val now = remember { LocalDate.now() }
|
||||||
|
|
||||||
val dateFormat by uiPreferences.dateFormat().collectAsState()
|
val dateFormat by uiPreferences.dateFormat.collectAsState()
|
||||||
val formattedNow = remember(dateFormat) {
|
val formattedNow = remember(dateFormat) {
|
||||||
UiPreferences.dateFormat(dateFormat).format(now)
|
UiPreferences.dateFormat(dateFormat).format(now)
|
||||||
}
|
}
|
||||||
@@ -122,7 +122,7 @@ object SettingsAppearanceScreen : SearchableSettings {
|
|||||||
onClick = { navigator.push(AppLanguageScreen()) },
|
onClick = { navigator.push(AppLanguageScreen()) },
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
preference = uiPreferences.tabletUiMode(),
|
preference = uiPreferences.tabletUiMode,
|
||||||
entries = TabletUiMode.entries
|
entries = TabletUiMode.entries
|
||||||
.associateWith { stringResource(it.titleRes) }
|
.associateWith { stringResource(it.titleRes) }
|
||||||
.toImmutableMap(),
|
.toImmutableMap(),
|
||||||
@@ -133,7 +133,7 @@ object SettingsAppearanceScreen : SearchableSettings {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
preference = uiPreferences.dateFormat(),
|
preference = uiPreferences.dateFormat,
|
||||||
entries = DateFormats
|
entries = DateFormats
|
||||||
.associateWith {
|
.associateWith {
|
||||||
val formattedDate = UiPreferences.dateFormat(it).format(now)
|
val formattedDate = UiPreferences.dateFormat(it).format(now)
|
||||||
@@ -143,7 +143,7 @@ object SettingsAppearanceScreen : SearchableSettings {
|
|||||||
title = stringResource(MR.strings.pref_date_format),
|
title = stringResource(MR.strings.pref_date_format),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = uiPreferences.relativeTime(),
|
preference = uiPreferences.relativeTime,
|
||||||
title = stringResource(MR.strings.pref_relative_format),
|
title = stringResource(MR.strings.pref_relative_format),
|
||||||
subtitle = stringResource(
|
subtitle = stringResource(
|
||||||
MR.strings.pref_relative_format_summary,
|
MR.strings.pref_relative_format_summary,
|
||||||
@@ -152,7 +152,7 @@ object SettingsAppearanceScreen : SearchableSettings {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = uiPreferences.imagesInDescription(),
|
preference = uiPreferences.imagesInDescription,
|
||||||
title = stringResource(MR.strings.pref_display_images_description),
|
title = stringResource(MR.strings.pref_display_images_description),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -162,22 +162,22 @@ object SettingsAppearanceScreen : SearchableSettings {
|
|||||||
// SY -->
|
// SY -->
|
||||||
@Composable
|
@Composable
|
||||||
fun getForkGroup(uiPreferences: UiPreferences): Preference.PreferenceGroup {
|
fun getForkGroup(uiPreferences: UiPreferences): Preference.PreferenceGroup {
|
||||||
val previewsRowCount by uiPreferences.previewsRowCount().collectAsState()
|
val previewsRowCount by uiPreferences.previewsRowCount.collectAsState()
|
||||||
|
|
||||||
return Preference.PreferenceGroup(
|
return Preference.PreferenceGroup(
|
||||||
stringResource(SYMR.strings.pref_category_fork),
|
stringResource(SYMR.strings.pref_category_fork),
|
||||||
preferenceItems = persistentListOf(
|
preferenceItems = persistentListOf(
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = uiPreferences.expandFilters(),
|
preference = uiPreferences.expandFilters,
|
||||||
title = stringResource(SYMR.strings.toggle_expand_search_filters),
|
title = stringResource(SYMR.strings.toggle_expand_search_filters),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = uiPreferences.recommendsInOverflow(),
|
preference = uiPreferences.recommendsInOverflow,
|
||||||
title = stringResource(SYMR.strings.put_recommends_in_overflow),
|
title = stringResource(SYMR.strings.put_recommends_in_overflow),
|
||||||
subtitle = stringResource(SYMR.strings.put_recommends_in_overflow_summary),
|
subtitle = stringResource(SYMR.strings.put_recommends_in_overflow_summary),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = uiPreferences.mergeInOverflow(),
|
preference = uiPreferences.mergeInOverflow,
|
||||||
title = stringResource(SYMR.strings.put_merge_in_overflow),
|
title = stringResource(SYMR.strings.put_merge_in_overflow),
|
||||||
subtitle = stringResource(SYMR.strings.put_merge_in_overflow_summary),
|
subtitle = stringResource(SYMR.strings.put_merge_in_overflow_summary),
|
||||||
),
|
),
|
||||||
@@ -195,7 +195,7 @@ object SettingsAppearanceScreen : SearchableSettings {
|
|||||||
},
|
},
|
||||||
valueRange = 0..10,
|
valueRange = 0..10,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
uiPreferences.previewsRowCount().set(it)
|
uiPreferences.previewsRowCount.set(it)
|
||||||
true
|
true
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -209,15 +209,15 @@ object SettingsAppearanceScreen : SearchableSettings {
|
|||||||
stringResource(SYMR.strings.pref_category_navbar),
|
stringResource(SYMR.strings.pref_category_navbar),
|
||||||
preferenceItems = persistentListOf(
|
preferenceItems = persistentListOf(
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = uiPreferences.showNavUpdates(),
|
preference = uiPreferences.showNavUpdates,
|
||||||
title = stringResource(SYMR.strings.pref_hide_updates_button),
|
title = stringResource(SYMR.strings.pref_hide_updates_button),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = uiPreferences.showNavHistory(),
|
preference = uiPreferences.showNavHistory,
|
||||||
title = stringResource(SYMR.strings.pref_hide_history_button),
|
title = stringResource(SYMR.strings.pref_hide_history_button),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = uiPreferences.bottomBarLabels(),
|
preference = uiPreferences.bottomBarLabels,
|
||||||
title = stringResource(SYMR.strings.pref_show_bottom_bar_labels),
|
title = stringResource(SYMR.strings.pref_show_bottom_bar_labels),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
+9
-9
@@ -46,7 +46,7 @@ object SettingsBrowseScreen : SearchableSettings {
|
|||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
val hideFeedTab by remember { Injekt.get<UiPreferences>().hideFeedTab().asState(scope) }
|
val hideFeedTab by remember { Injekt.get<UiPreferences>().hideFeedTab.asState(scope) }
|
||||||
val uiPreferences = remember { Injekt.get<UiPreferences>() }
|
val uiPreferences = remember { Injekt.get<UiPreferences>() }
|
||||||
// SY <--
|
// SY <--
|
||||||
return listOf(
|
return listOf(
|
||||||
@@ -55,7 +55,7 @@ object SettingsBrowseScreen : SearchableSettings {
|
|||||||
title = stringResource(MR.strings.label_sources),
|
title = stringResource(MR.strings.label_sources),
|
||||||
preferenceItems = persistentListOf(
|
preferenceItems = persistentListOf(
|
||||||
kotlin.run {
|
kotlin.run {
|
||||||
val count by sourcePreferences.sourcesTabCategories().collectAsState()
|
val count by sourcePreferences.sourcesTabCategories.collectAsState()
|
||||||
Preference.PreferenceItem.TextPreference(
|
Preference.PreferenceItem.TextPreference(
|
||||||
title = stringResource(MR.strings.action_edit_categories),
|
title = stringResource(MR.strings.action_edit_categories),
|
||||||
subtitle = pluralStringResource(MR.plurals.num_categories, count.size, count.size),
|
subtitle = pluralStringResource(MR.plurals.num_categories, count.size, count.size),
|
||||||
@@ -65,17 +65,17 @@ object SettingsBrowseScreen : SearchableSettings {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = sourcePreferences.sourcesTabCategoriesFilter(),
|
preference = sourcePreferences.sourcesTabCategoriesFilter,
|
||||||
title = stringResource(SYMR.strings.pref_source_source_filtering),
|
title = stringResource(SYMR.strings.pref_source_source_filtering),
|
||||||
subtitle = stringResource(SYMR.strings.pref_source_source_filtering_summery),
|
subtitle = stringResource(SYMR.strings.pref_source_source_filtering_summery),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = uiPreferences.useNewSourceNavigation(),
|
preference = uiPreferences.useNewSourceNavigation,
|
||||||
title = stringResource(SYMR.strings.pref_source_navigation),
|
title = stringResource(SYMR.strings.pref_source_navigation),
|
||||||
subtitle = stringResource(SYMR.strings.pref_source_navigation_summery),
|
subtitle = stringResource(SYMR.strings.pref_source_navigation_summery),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = sourcePreferences.allowLocalSourceHiddenFolders(),
|
preference = sourcePreferences.allowLocalSourceHiddenFolders,
|
||||||
title = stringResource(SYMR.strings.pref_local_source_hidden_folders),
|
title = stringResource(SYMR.strings.pref_local_source_hidden_folders),
|
||||||
subtitle = stringResource(SYMR.strings.pref_local_source_hidden_folders_summery),
|
subtitle = stringResource(SYMR.strings.pref_local_source_hidden_folders_summery),
|
||||||
),
|
),
|
||||||
@@ -85,11 +85,11 @@ object SettingsBrowseScreen : SearchableSettings {
|
|||||||
title = stringResource(SYMR.strings.feed),
|
title = stringResource(SYMR.strings.feed),
|
||||||
preferenceItems = persistentListOf(
|
preferenceItems = persistentListOf(
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = uiPreferences.hideFeedTab(),
|
preference = uiPreferences.hideFeedTab,
|
||||||
title = stringResource(SYMR.strings.pref_hide_feed),
|
title = stringResource(SYMR.strings.pref_hide_feed),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = uiPreferences.feedTabInFront(),
|
preference = uiPreferences.feedTabInFront,
|
||||||
title = stringResource(SYMR.strings.pref_feed_position),
|
title = stringResource(SYMR.strings.pref_feed_position),
|
||||||
subtitle = stringResource(SYMR.strings.pref_feed_position_summery),
|
subtitle = stringResource(SYMR.strings.pref_feed_position_summery),
|
||||||
enabled = hideFeedTab.not(),
|
enabled = hideFeedTab.not(),
|
||||||
@@ -101,7 +101,7 @@ object SettingsBrowseScreen : SearchableSettings {
|
|||||||
title = stringResource(MR.strings.label_sources),
|
title = stringResource(MR.strings.label_sources),
|
||||||
preferenceItems = persistentListOf(
|
preferenceItems = persistentListOf(
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = sourcePreferences.hideInLibraryItems(),
|
preference = sourcePreferences.hideInLibraryItems,
|
||||||
title = stringResource(MR.strings.pref_hide_in_library_items),
|
title = stringResource(MR.strings.pref_hide_in_library_items),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.TextPreference(
|
Preference.PreferenceItem.TextPreference(
|
||||||
@@ -117,7 +117,7 @@ object SettingsBrowseScreen : SearchableSettings {
|
|||||||
title = stringResource(MR.strings.pref_category_nsfw_content),
|
title = stringResource(MR.strings.pref_category_nsfw_content),
|
||||||
preferenceItems = persistentListOf(
|
preferenceItems = persistentListOf(
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = sourcePreferences.showNsfwSource(),
|
preference = sourcePreferences.showNsfwSource,
|
||||||
title = stringResource(MR.strings.pref_show_nsfw_source),
|
title = stringResource(MR.strings.pref_show_nsfw_source),
|
||||||
subtitle = stringResource(MR.strings.requires_app_restart),
|
subtitle = stringResource(MR.strings.requires_app_restart),
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
|
|||||||
+18
-15
@@ -119,7 +119,7 @@ object SettingsDataScreen : SearchableSettings {
|
|||||||
val storagePreferences = Injekt.get<StoragePreferences>()
|
val storagePreferences = Injekt.get<StoragePreferences>()
|
||||||
|
|
||||||
val syncPreferences = remember { Injekt.get<SyncPreferences>() }
|
val syncPreferences = remember { Injekt.get<SyncPreferences>() }
|
||||||
val syncService by syncPreferences.syncService().collectAsState()
|
val syncService by syncPreferences.syncService.collectAsState()
|
||||||
|
|
||||||
return persistentListOf(
|
return persistentListOf(
|
||||||
getStorageLocationPref(storagePreferences = storagePreferences),
|
getStorageLocationPref(storagePreferences = storagePreferences),
|
||||||
@@ -185,11 +185,11 @@ object SettingsDataScreen : SearchableSettings {
|
|||||||
storagePreferences: StoragePreferences,
|
storagePreferences: StoragePreferences,
|
||||||
): Preference.PreferenceItem.TextPreference {
|
): Preference.PreferenceItem.TextPreference {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val pickStorageLocation = storageLocationPicker(storagePreferences.baseStorageDirectory())
|
val pickStorageLocation = storageLocationPicker(storagePreferences.baseStorageDirectory)
|
||||||
|
|
||||||
return Preference.PreferenceItem.TextPreference(
|
return Preference.PreferenceItem.TextPreference(
|
||||||
title = stringResource(MR.strings.pref_storage_location),
|
title = stringResource(MR.strings.pref_storage_location),
|
||||||
subtitle = storageLocationText(storagePreferences.baseStorageDirectory()),
|
subtitle = storageLocationText(storagePreferences.baseStorageDirectory),
|
||||||
onClick = {
|
onClick = {
|
||||||
try {
|
try {
|
||||||
pickStorageLocation.launch(null)
|
pickStorageLocation.launch(null)
|
||||||
@@ -205,7 +205,7 @@ object SettingsDataScreen : SearchableSettings {
|
|||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val navigator = LocalNavigator.currentOrThrow
|
val navigator = LocalNavigator.currentOrThrow
|
||||||
|
|
||||||
val lastAutoBackup by backupPreferences.lastAutoBackupTimestamp().collectAsState()
|
val lastAutoBackup by backupPreferences.lastAutoBackupTimestamp.collectAsState()
|
||||||
|
|
||||||
val chooseBackup = rememberLauncherForActivityResult(
|
val chooseBackup = rememberLauncherForActivityResult(
|
||||||
object : ActivityResultContracts.GetContent() {
|
object : ActivityResultContracts.GetContent() {
|
||||||
@@ -272,7 +272,7 @@ object SettingsDataScreen : SearchableSettings {
|
|||||||
|
|
||||||
// Automatic backups
|
// Automatic backups
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
preference = backupPreferences.backupInterval(),
|
preference = backupPreferences.backupInterval,
|
||||||
entries = persistentMapOf(
|
entries = persistentMapOf(
|
||||||
0 to stringResource(MR.strings.off),
|
0 to stringResource(MR.strings.off),
|
||||||
6 to stringResource(MR.strings.update_6hour),
|
6 to stringResource(MR.strings.update_6hour),
|
||||||
@@ -303,7 +303,10 @@ object SettingsDataScreen : SearchableSettings {
|
|||||||
|
|
||||||
val chapterCache = remember { Injekt.get<ChapterCache>() }
|
val chapterCache = remember { Injekt.get<ChapterCache>() }
|
||||||
var cacheReadableSizeSema by remember { mutableIntStateOf(0) }
|
var cacheReadableSizeSema by remember { mutableIntStateOf(0) }
|
||||||
val cacheReadableSize = remember(cacheReadableSizeSema) { chapterCache.readableSize }
|
var cacheReadableSize by remember { mutableStateOf(context.stringResource(MR.strings.calculating)) }
|
||||||
|
LaunchedEffect(cacheReadableSizeSema) {
|
||||||
|
cacheReadableSize = chapterCache.getReadableSize()
|
||||||
|
}
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
val pagePreviewCache = remember { Injekt.get<PagePreviewCache>() }
|
val pagePreviewCache = remember { Injekt.get<PagePreviewCache>() }
|
||||||
@@ -365,7 +368,7 @@ object SettingsDataScreen : SearchableSettings {
|
|||||||
),
|
),
|
||||||
// SY <--
|
// SY <--
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = libraryPreferences.autoClearChapterCache(),
|
preference = libraryPreferences.autoClearChapterCache,
|
||||||
title = stringResource(MR.strings.pref_auto_clear_chapter_cache),
|
title = stringResource(MR.strings.pref_auto_clear_chapter_cache),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -517,7 +520,7 @@ object SettingsDataScreen : SearchableSettings {
|
|||||||
title = stringResource(SYMR.strings.pref_sync_service_category),
|
title = stringResource(SYMR.strings.pref_sync_service_category),
|
||||||
preferenceItems = persistentListOf(
|
preferenceItems = persistentListOf(
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
preference = syncPreferences.syncService(),
|
preference = syncPreferences.syncService,
|
||||||
title = stringResource(SYMR.strings.pref_sync_service),
|
title = stringResource(SYMR.strings.pref_sync_service),
|
||||||
entries = persistentMapOf(
|
entries = persistentMapOf(
|
||||||
SyncManager.SyncService.NONE.value to stringResource(MR.strings.off),
|
SyncManager.SyncService.NONE.value to stringResource(MR.strings.off),
|
||||||
@@ -660,7 +663,7 @@ object SettingsDataScreen : SearchableSettings {
|
|||||||
|
|
||||||
val qrScanLauncher = rememberLauncherForActivityResult(ScanContract()) {
|
val qrScanLauncher = rememberLauncherForActivityResult(ScanContract()) {
|
||||||
if (it.contents != null && it.contents.isNotEmpty()) {
|
if (it.contents != null && it.contents.isNotEmpty()) {
|
||||||
syncPreferences.clientAPIKey().set(it.contents)
|
syncPreferences.clientAPIKey.set(it.contents)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
@@ -677,13 +680,13 @@ object SettingsDataScreen : SearchableSettings {
|
|||||||
Preference.PreferenceItem.EditTextPreference(
|
Preference.PreferenceItem.EditTextPreference(
|
||||||
title = stringResource(SYMR.strings.pref_sync_host),
|
title = stringResource(SYMR.strings.pref_sync_host),
|
||||||
subtitle = stringResource(SYMR.strings.pref_sync_host_summ),
|
subtitle = stringResource(SYMR.strings.pref_sync_host_summ),
|
||||||
preference = syncPreferences.clientHost(),
|
preference = syncPreferences.clientHost,
|
||||||
onValueChanged = { newValue ->
|
onValueChanged = { newValue ->
|
||||||
scope.launch {
|
scope.launch {
|
||||||
// Trim spaces at the beginning and end, then remove trailing slash if present
|
// Trim spaces at the beginning and end, then remove trailing slash if present
|
||||||
val trimmedValue = newValue.trim()
|
val trimmedValue = newValue.trim()
|
||||||
val modifiedValue = trimmedValue.trimEnd { it == '/' }
|
val modifiedValue = trimmedValue.trimEnd { it == '/' }
|
||||||
syncPreferences.clientHost().set(modifiedValue)
|
syncPreferences.clientHost.set(modifiedValue)
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
},
|
},
|
||||||
@@ -691,12 +694,12 @@ object SettingsDataScreen : SearchableSettings {
|
|||||||
Preference.PreferenceItem.CustomPreference(
|
Preference.PreferenceItem.CustomPreference(
|
||||||
title = stringResource(SYMR.strings.pref_sync_api_key),
|
title = stringResource(SYMR.strings.pref_sync_api_key),
|
||||||
) {
|
) {
|
||||||
val values by syncPreferences.clientAPIKey().collectAsState()
|
val values by syncPreferences.clientAPIKey.collectAsState()
|
||||||
EditTextPreferenceWidget(
|
EditTextPreferenceWidget(
|
||||||
title = stringResource(SYMR.strings.pref_sync_api_key),
|
title = stringResource(SYMR.strings.pref_sync_api_key),
|
||||||
subtitle = stringResource(SYMR.strings.pref_sync_api_key_summ),
|
subtitle = stringResource(SYMR.strings.pref_sync_api_key_summ),
|
||||||
onConfirm = {
|
onConfirm = {
|
||||||
syncPreferences.clientAPIKey().set(it)
|
syncPreferences.clientAPIKey.set(it)
|
||||||
true
|
true
|
||||||
},
|
},
|
||||||
icon = null,
|
icon = null,
|
||||||
@@ -752,8 +755,8 @@ object SettingsDataScreen : SearchableSettings {
|
|||||||
@Composable
|
@Composable
|
||||||
private fun getAutomaticSyncGroup(syncPreferences: SyncPreferences): Preference.PreferenceGroup {
|
private fun getAutomaticSyncGroup(syncPreferences: SyncPreferences): Preference.PreferenceGroup {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val syncIntervalPref = syncPreferences.syncInterval()
|
val syncIntervalPref = syncPreferences.syncInterval
|
||||||
val lastSync by syncPreferences.lastSyncTimestamp().collectAsState()
|
val lastSync by syncPreferences.lastSyncTimestamp.collectAsState()
|
||||||
|
|
||||||
return Preference.PreferenceGroup(
|
return Preference.PreferenceGroup(
|
||||||
title = stringResource(SYMR.strings.pref_sync_automatic_category),
|
title = stringResource(SYMR.strings.pref_sync_automatic_category),
|
||||||
|
|||||||
+16
-16
@@ -37,19 +37,19 @@ object SettingsDownloadScreen : SearchableSettings {
|
|||||||
val allCategories by getCategories.subscribe().collectAsState(initial = emptyList())
|
val allCategories by getCategories.subscribe().collectAsState(initial = emptyList())
|
||||||
|
|
||||||
val downloadPreferences = remember { Injekt.get<DownloadPreferences>() }
|
val downloadPreferences = remember { Injekt.get<DownloadPreferences>() }
|
||||||
val parallelSourceLimit by downloadPreferences.parallelSourceLimit().collectAsState()
|
val parallelSourceLimit by downloadPreferences.parallelSourceLimit.collectAsState()
|
||||||
val parallelPageLimit by downloadPreferences.parallelPageLimit().collectAsState()
|
val parallelPageLimit by downloadPreferences.parallelPageLimit.collectAsState()
|
||||||
return listOf(
|
return listOf(
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = downloadPreferences.downloadOnlyOverWifi(),
|
preference = downloadPreferences.downloadOnlyOverWifi,
|
||||||
title = stringResource(MR.strings.connected_to_wifi),
|
title = stringResource(MR.strings.connected_to_wifi),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = downloadPreferences.saveChaptersAsCBZ(),
|
preference = downloadPreferences.saveChaptersAsCBZ,
|
||||||
title = stringResource(MR.strings.save_chapter_as_cbz),
|
title = stringResource(MR.strings.save_chapter_as_cbz),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = downloadPreferences.splitTallImages(),
|
preference = downloadPreferences.splitTallImages,
|
||||||
title = stringResource(MR.strings.split_tall_images),
|
title = stringResource(MR.strings.split_tall_images),
|
||||||
subtitle = stringResource(MR.strings.split_tall_images_summary),
|
subtitle = stringResource(MR.strings.split_tall_images_summary),
|
||||||
),
|
),
|
||||||
@@ -57,14 +57,14 @@ object SettingsDownloadScreen : SearchableSettings {
|
|||||||
value = parallelSourceLimit,
|
value = parallelSourceLimit,
|
||||||
valueRange = 1..10,
|
valueRange = 1..10,
|
||||||
title = stringResource(MR.strings.pref_download_concurrent_sources),
|
title = stringResource(MR.strings.pref_download_concurrent_sources),
|
||||||
onValueChanged = { downloadPreferences.parallelSourceLimit().set(it) },
|
onValueChanged = { downloadPreferences.parallelSourceLimit.set(it) },
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SliderPreference(
|
Preference.PreferenceItem.SliderPreference(
|
||||||
value = parallelPageLimit,
|
value = parallelPageLimit,
|
||||||
valueRange = 1..15,
|
valueRange = 1..15,
|
||||||
title = stringResource(MR.strings.pref_download_concurrent_pages),
|
title = stringResource(MR.strings.pref_download_concurrent_pages),
|
||||||
subtitle = stringResource(MR.strings.pref_download_concurrent_pages_summary),
|
subtitle = stringResource(MR.strings.pref_download_concurrent_pages_summary),
|
||||||
onValueChanged = { downloadPreferences.parallelPageLimit().set(it) },
|
onValueChanged = { downloadPreferences.parallelPageLimit.set(it) },
|
||||||
),
|
),
|
||||||
getDeleteChaptersGroup(
|
getDeleteChaptersGroup(
|
||||||
downloadPreferences = downloadPreferences,
|
downloadPreferences = downloadPreferences,
|
||||||
@@ -87,11 +87,11 @@ object SettingsDownloadScreen : SearchableSettings {
|
|||||||
title = stringResource(MR.strings.pref_category_delete_chapters),
|
title = stringResource(MR.strings.pref_category_delete_chapters),
|
||||||
preferenceItems = persistentListOf(
|
preferenceItems = persistentListOf(
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = downloadPreferences.removeAfterMarkedAsRead(),
|
preference = downloadPreferences.removeAfterMarkedAsRead,
|
||||||
title = stringResource(MR.strings.pref_remove_after_marked_as_read),
|
title = stringResource(MR.strings.pref_remove_after_marked_as_read),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
preference = downloadPreferences.removeAfterReadSlots(),
|
preference = downloadPreferences.removeAfterReadSlots,
|
||||||
entries = persistentMapOf(
|
entries = persistentMapOf(
|
||||||
-1 to stringResource(MR.strings.disabled),
|
-1 to stringResource(MR.strings.disabled),
|
||||||
0 to stringResource(MR.strings.last_read_chapter),
|
0 to stringResource(MR.strings.last_read_chapter),
|
||||||
@@ -103,7 +103,7 @@ object SettingsDownloadScreen : SearchableSettings {
|
|||||||
title = stringResource(MR.strings.pref_remove_after_read),
|
title = stringResource(MR.strings.pref_remove_after_read),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = downloadPreferences.removeBookmarkedChapters(),
|
preference = downloadPreferences.removeBookmarkedChapters,
|
||||||
title = stringResource(MR.strings.pref_remove_bookmarked_chapters),
|
title = stringResource(MR.strings.pref_remove_bookmarked_chapters),
|
||||||
),
|
),
|
||||||
getExcludedCategoriesPreference(
|
getExcludedCategoriesPreference(
|
||||||
@@ -120,7 +120,7 @@ object SettingsDownloadScreen : SearchableSettings {
|
|||||||
categories: () -> List<Category>,
|
categories: () -> List<Category>,
|
||||||
): Preference.PreferenceItem.MultiSelectListPreference {
|
): Preference.PreferenceItem.MultiSelectListPreference {
|
||||||
return Preference.PreferenceItem.MultiSelectListPreference(
|
return Preference.PreferenceItem.MultiSelectListPreference(
|
||||||
preference = downloadPreferences.removeExcludeCategories(),
|
preference = downloadPreferences.removeExcludeCategories,
|
||||||
entries = categories()
|
entries = categories()
|
||||||
.associate { it.id.toString() to it.visualName }
|
.associate { it.id.toString() to it.visualName }
|
||||||
.toImmutableMap(),
|
.toImmutableMap(),
|
||||||
@@ -133,10 +133,10 @@ object SettingsDownloadScreen : SearchableSettings {
|
|||||||
downloadPreferences: DownloadPreferences,
|
downloadPreferences: DownloadPreferences,
|
||||||
allCategories: List<Category>,
|
allCategories: List<Category>,
|
||||||
): Preference.PreferenceGroup {
|
): Preference.PreferenceGroup {
|
||||||
val downloadNewChaptersPref = downloadPreferences.downloadNewChapters()
|
val downloadNewChaptersPref = downloadPreferences.downloadNewChapters
|
||||||
val downloadNewUnreadChaptersOnlyPref = downloadPreferences.downloadNewUnreadChaptersOnly()
|
val downloadNewUnreadChaptersOnlyPref = downloadPreferences.downloadNewUnreadChaptersOnly
|
||||||
val downloadNewChapterCategoriesPref = downloadPreferences.downloadNewChapterCategories()
|
val downloadNewChapterCategoriesPref = downloadPreferences.downloadNewChapterCategories
|
||||||
val downloadNewChapterCategoriesExcludePref = downloadPreferences.downloadNewChapterCategoriesExclude()
|
val downloadNewChapterCategoriesExcludePref = downloadPreferences.downloadNewChapterCategoriesExclude
|
||||||
|
|
||||||
val downloadNewChapters by downloadNewChaptersPref.collectAsState()
|
val downloadNewChapters by downloadNewChaptersPref.collectAsState()
|
||||||
|
|
||||||
@@ -194,7 +194,7 @@ object SettingsDownloadScreen : SearchableSettings {
|
|||||||
title = stringResource(MR.strings.download_ahead),
|
title = stringResource(MR.strings.download_ahead),
|
||||||
preferenceItems = persistentListOf(
|
preferenceItems = persistentListOf(
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
preference = downloadPreferences.autoDownloadWhileReading(),
|
preference = downloadPreferences.autoDownloadWhileReading,
|
||||||
entries = listOf(0, 2, 3, 5, 10)
|
entries = listOf(0, 2, 3, 5, 10)
|
||||||
.associateWith {
|
.associateWith {
|
||||||
if (it == 0) {
|
if (it == 0) {
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ object SettingsEhScreen : SearchableSettings {
|
|||||||
@Composable
|
@Composable
|
||||||
override fun getTitleRes() = SYMR.strings.pref_category_eh
|
override fun getTitleRes() = SYMR.strings.pref_category_eh
|
||||||
|
|
||||||
override fun isEnabled(): Boolean = Injekt.get<ExhPreferences>().isHentaiEnabled().get()
|
override fun isEnabled(): Boolean = Injekt.get<ExhPreferences>().isHentaiEnabled.get()
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun Reconfigure(
|
fun Reconfigure(
|
||||||
@@ -96,14 +96,14 @@ object SettingsEhScreen : SearchableSettings {
|
|||||||
openWarnConfigureDialogController: () -> Unit,
|
openWarnConfigureDialogController: () -> Unit,
|
||||||
) {
|
) {
|
||||||
var initialLoadGuard by remember { mutableStateOf(false) }
|
var initialLoadGuard by remember { mutableStateOf(false) }
|
||||||
val useHentaiAtHome by exhPreferences.useHentaiAtHome().collectAsState()
|
val useHentaiAtHome by exhPreferences.useHentaiAtHome.collectAsState()
|
||||||
val useJapaneseTitle by exhPreferences.useJapaneseTitle().collectAsState()
|
val useJapaneseTitle by exhPreferences.useJapaneseTitle.collectAsState()
|
||||||
val useOriginalImages by exhPreferences.exhUseOriginalImages().collectAsState()
|
val useOriginalImages by exhPreferences.exhUseOriginalImages.collectAsState()
|
||||||
val ehTagFilterValue by exhPreferences.ehTagFilterValue().collectAsState()
|
val ehTagFilterValue by exhPreferences.ehTagFilterValue.collectAsState()
|
||||||
val ehTagWatchingValue by exhPreferences.ehTagWatchingValue().collectAsState()
|
val ehTagWatchingValue by exhPreferences.ehTagWatchingValue.collectAsState()
|
||||||
val settingsLanguages by exhPreferences.exhSettingsLanguages().collectAsState()
|
val settingsLanguages by exhPreferences.exhSettingsLanguages.collectAsState()
|
||||||
val enabledCategories by exhPreferences.exhEnabledCategories().collectAsState()
|
val enabledCategories by exhPreferences.exhEnabledCategories.collectAsState()
|
||||||
val imageQuality by exhPreferences.imageQuality().collectAsState()
|
val imageQuality by exhPreferences.imageQuality.collectAsState()
|
||||||
DisposableEffect(
|
DisposableEffect(
|
||||||
useHentaiAtHome,
|
useHentaiAtHome,
|
||||||
useJapaneseTitle,
|
useJapaneseTitle,
|
||||||
@@ -128,7 +128,7 @@ object SettingsEhScreen : SearchableSettings {
|
|||||||
val getFlatMetadataById: GetFlatMetadataById = remember { Injekt.get() }
|
val getFlatMetadataById: GetFlatMetadataById = remember { Injekt.get() }
|
||||||
val deleteFavoriteEntries: DeleteFavoriteEntries = remember { Injekt.get() }
|
val deleteFavoriteEntries: DeleteFavoriteEntries = remember { Injekt.get() }
|
||||||
val getExhFavoriteMangaWithMetadata: GetExhFavoriteMangaWithMetadata = remember { Injekt.get() }
|
val getExhFavoriteMangaWithMetadata: GetExhFavoriteMangaWithMetadata = remember { Injekt.get() }
|
||||||
val exhentaiEnabled by exhPreferences.enableExhentai().collectAsState()
|
val exhentaiEnabled by exhPreferences.enableExhentai.collectAsState()
|
||||||
var runConfigureDialog by remember { mutableStateOf(false) }
|
var runConfigureDialog by remember { mutableStateOf(false) }
|
||||||
val openWarnConfigureDialogController = { runConfigureDialog = true }
|
val openWarnConfigureDialogController = { runConfigureDialog = true }
|
||||||
|
|
||||||
@@ -191,9 +191,9 @@ object SettingsEhScreen : SearchableSettings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val value by exhPreferences.enableExhentai().collectAsState()
|
val value by exhPreferences.enableExhentai.collectAsState()
|
||||||
return Preference.PreferenceItem.SwitchPreference(
|
return Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = exhPreferences.enableExhentai(),
|
preference = exhPreferences.enableExhentai,
|
||||||
title = stringResource(SYMR.strings.enable_exhentai),
|
title = stringResource(SYMR.strings.enable_exhentai),
|
||||||
subtitle = if (!value) {
|
subtitle = if (!value) {
|
||||||
stringResource(SYMR.strings.requires_login)
|
stringResource(SYMR.strings.requires_login)
|
||||||
@@ -202,7 +202,7 @@ object SettingsEhScreen : SearchableSettings {
|
|||||||
},
|
},
|
||||||
onValueChanged = { newVal ->
|
onValueChanged = { newVal ->
|
||||||
if (!newVal) {
|
if (!newVal) {
|
||||||
exhPreferences.enableExhentai().set(false)
|
exhPreferences.enableExhentai.set(false)
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
activityResultContract.launch(EhLoginActivity.newIntent(context))
|
activityResultContract.launch(EhLoginActivity.newIntent(context))
|
||||||
@@ -218,7 +218,7 @@ object SettingsEhScreen : SearchableSettings {
|
|||||||
exhPreferences: ExhPreferences,
|
exhPreferences: ExhPreferences,
|
||||||
): Preference.PreferenceItem.ListPreference<Int> {
|
): Preference.PreferenceItem.ListPreference<Int> {
|
||||||
return Preference.PreferenceItem.ListPreference(
|
return Preference.PreferenceItem.ListPreference(
|
||||||
preference = exhPreferences.useHentaiAtHome(),
|
preference = exhPreferences.useHentaiAtHome,
|
||||||
title = stringResource(SYMR.strings.use_hentai_at_home),
|
title = stringResource(SYMR.strings.use_hentai_at_home),
|
||||||
subtitle = stringResource(SYMR.strings.use_hentai_at_home_summary),
|
subtitle = stringResource(SYMR.strings.use_hentai_at_home_summary),
|
||||||
entries = persistentMapOf(
|
entries = persistentMapOf(
|
||||||
@@ -234,9 +234,9 @@ object SettingsEhScreen : SearchableSettings {
|
|||||||
exhentaiEnabled: Boolean,
|
exhentaiEnabled: Boolean,
|
||||||
exhPreferences: ExhPreferences,
|
exhPreferences: ExhPreferences,
|
||||||
): Preference.PreferenceItem.SwitchPreference {
|
): Preference.PreferenceItem.SwitchPreference {
|
||||||
val value by exhPreferences.useJapaneseTitle().collectAsState()
|
val value by exhPreferences.useJapaneseTitle.collectAsState()
|
||||||
return Preference.PreferenceItem.SwitchPreference(
|
return Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = exhPreferences.useJapaneseTitle(),
|
preference = exhPreferences.useJapaneseTitle,
|
||||||
title = stringResource(SYMR.strings.show_japanese_titles),
|
title = stringResource(SYMR.strings.show_japanese_titles),
|
||||||
subtitle = if (value) {
|
subtitle = if (value) {
|
||||||
stringResource(SYMR.strings.show_japanese_titles_option_1)
|
stringResource(SYMR.strings.show_japanese_titles_option_1)
|
||||||
@@ -252,9 +252,9 @@ object SettingsEhScreen : SearchableSettings {
|
|||||||
exhentaiEnabled: Boolean,
|
exhentaiEnabled: Boolean,
|
||||||
exhPreferences: ExhPreferences,
|
exhPreferences: ExhPreferences,
|
||||||
): Preference.PreferenceItem.SwitchPreference {
|
): Preference.PreferenceItem.SwitchPreference {
|
||||||
val value by exhPreferences.exhUseOriginalImages().collectAsState()
|
val value by exhPreferences.exhUseOriginalImages.collectAsState()
|
||||||
return Preference.PreferenceItem.SwitchPreference(
|
return Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = exhPreferences.exhUseOriginalImages(),
|
preference = exhPreferences.exhUseOriginalImages,
|
||||||
title = stringResource(SYMR.strings.use_original_images),
|
title = stringResource(SYMR.strings.use_original_images),
|
||||||
subtitle = if (value) {
|
subtitle = if (value) {
|
||||||
stringResource(SYMR.strings.use_original_images_on)
|
stringResource(SYMR.strings.use_original_images_on)
|
||||||
@@ -353,7 +353,7 @@ object SettingsEhScreen : SearchableSettings {
|
|||||||
exhentaiEnabled: Boolean,
|
exhentaiEnabled: Boolean,
|
||||||
exhPreferences: ExhPreferences,
|
exhPreferences: ExhPreferences,
|
||||||
): Preference.PreferenceItem.TextPreference {
|
): Preference.PreferenceItem.TextPreference {
|
||||||
val value by exhPreferences.ehTagFilterValue().collectAsState()
|
val value by exhPreferences.ehTagFilterValue.collectAsState()
|
||||||
var dialogOpen by remember { mutableStateOf(false) }
|
var dialogOpen by remember { mutableStateOf(false) }
|
||||||
if (dialogOpen) {
|
if (dialogOpen) {
|
||||||
TagThresholdDialog(
|
TagThresholdDialog(
|
||||||
@@ -364,7 +364,7 @@ object SettingsEhScreen : SearchableSettings {
|
|||||||
outsideRangeError = stringResource(SYMR.strings.tag_filtering_threshhold_error),
|
outsideRangeError = stringResource(SYMR.strings.tag_filtering_threshhold_error),
|
||||||
onValueChange = {
|
onValueChange = {
|
||||||
dialogOpen = false
|
dialogOpen = false
|
||||||
exhPreferences.ehTagFilterValue().set(it)
|
exhPreferences.ehTagFilterValue.set(it)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -383,7 +383,7 @@ object SettingsEhScreen : SearchableSettings {
|
|||||||
exhentaiEnabled: Boolean,
|
exhentaiEnabled: Boolean,
|
||||||
exhPreferences: ExhPreferences,
|
exhPreferences: ExhPreferences,
|
||||||
): Preference.PreferenceItem.TextPreference {
|
): Preference.PreferenceItem.TextPreference {
|
||||||
val value by exhPreferences.ehTagWatchingValue().collectAsState()
|
val value by exhPreferences.ehTagWatchingValue.collectAsState()
|
||||||
var dialogOpen by remember { mutableStateOf(false) }
|
var dialogOpen by remember { mutableStateOf(false) }
|
||||||
if (dialogOpen) {
|
if (dialogOpen) {
|
||||||
TagThresholdDialog(
|
TagThresholdDialog(
|
||||||
@@ -394,7 +394,7 @@ object SettingsEhScreen : SearchableSettings {
|
|||||||
outsideRangeError = stringResource(SYMR.strings.tag_watching_threshhold_error),
|
outsideRangeError = stringResource(SYMR.strings.tag_watching_threshhold_error),
|
||||||
onValueChange = {
|
onValueChange = {
|
||||||
dialogOpen = false
|
dialogOpen = false
|
||||||
exhPreferences.ehTagWatchingValue().set(it)
|
exhPreferences.ehTagWatchingValue.set(it)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -606,7 +606,7 @@ object SettingsEhScreen : SearchableSettings {
|
|||||||
exhentaiEnabled: Boolean,
|
exhentaiEnabled: Boolean,
|
||||||
exhPreferences: ExhPreferences,
|
exhPreferences: ExhPreferences,
|
||||||
): Preference.PreferenceItem.TextPreference {
|
): Preference.PreferenceItem.TextPreference {
|
||||||
val value by exhPreferences.exhSettingsLanguages().collectAsState()
|
val value by exhPreferences.exhSettingsLanguages.collectAsState()
|
||||||
var dialogOpen by remember { mutableStateOf(false) }
|
var dialogOpen by remember { mutableStateOf(false) }
|
||||||
if (dialogOpen) {
|
if (dialogOpen) {
|
||||||
LanguagesDialog(
|
LanguagesDialog(
|
||||||
@@ -614,7 +614,7 @@ object SettingsEhScreen : SearchableSettings {
|
|||||||
initialValue = value,
|
initialValue = value,
|
||||||
onValueChange = {
|
onValueChange = {
|
||||||
dialogOpen = false
|
dialogOpen = false
|
||||||
exhPreferences.exhSettingsLanguages().set(it)
|
exhPreferences.exhSettingsLanguages.set(it)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -772,7 +772,7 @@ object SettingsEhScreen : SearchableSettings {
|
|||||||
exhentaiEnabled: Boolean,
|
exhentaiEnabled: Boolean,
|
||||||
exhPreferences: ExhPreferences,
|
exhPreferences: ExhPreferences,
|
||||||
): Preference.PreferenceItem.TextPreference {
|
): Preference.PreferenceItem.TextPreference {
|
||||||
val value by exhPreferences.exhEnabledCategories().collectAsState()
|
val value by exhPreferences.exhEnabledCategories.collectAsState()
|
||||||
var dialogOpen by remember { mutableStateOf(false) }
|
var dialogOpen by remember { mutableStateOf(false) }
|
||||||
if (dialogOpen) {
|
if (dialogOpen) {
|
||||||
FrontPageCategoriesDialog(
|
FrontPageCategoriesDialog(
|
||||||
@@ -780,7 +780,7 @@ object SettingsEhScreen : SearchableSettings {
|
|||||||
initialValue = value,
|
initialValue = value,
|
||||||
onValueChange = {
|
onValueChange = {
|
||||||
dialogOpen = false
|
dialogOpen = false
|
||||||
exhPreferences.exhEnabledCategories().set(it)
|
exhPreferences.exhEnabledCategories.set(it)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -800,7 +800,7 @@ object SettingsEhScreen : SearchableSettings {
|
|||||||
exhPreferences: ExhPreferences,
|
exhPreferences: ExhPreferences,
|
||||||
): Preference.PreferenceItem.SwitchPreference {
|
): Preference.PreferenceItem.SwitchPreference {
|
||||||
return Preference.PreferenceItem.SwitchPreference(
|
return Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = exhPreferences.exhWatchedListDefaultState(),
|
preference = exhPreferences.exhWatchedListDefaultState,
|
||||||
title = stringResource(SYMR.strings.watched_list_default),
|
title = stringResource(SYMR.strings.watched_list_default),
|
||||||
subtitle = stringResource(SYMR.strings.watched_list_state_summary),
|
subtitle = stringResource(SYMR.strings.watched_list_state_summary),
|
||||||
enabled = exhentaiEnabled,
|
enabled = exhentaiEnabled,
|
||||||
@@ -813,7 +813,7 @@ object SettingsEhScreen : SearchableSettings {
|
|||||||
exhPreferences: ExhPreferences,
|
exhPreferences: ExhPreferences,
|
||||||
): Preference.PreferenceItem.ListPreference<String> {
|
): Preference.PreferenceItem.ListPreference<String> {
|
||||||
return Preference.PreferenceItem.ListPreference(
|
return Preference.PreferenceItem.ListPreference(
|
||||||
preference = exhPreferences.imageQuality(),
|
preference = exhPreferences.imageQuality,
|
||||||
title = stringResource(SYMR.strings.eh_image_quality_summary),
|
title = stringResource(SYMR.strings.eh_image_quality_summary),
|
||||||
subtitle = stringResource(SYMR.strings.eh_image_quality),
|
subtitle = stringResource(SYMR.strings.eh_image_quality),
|
||||||
entries = persistentMapOf(
|
entries = persistentMapOf(
|
||||||
@@ -831,7 +831,7 @@ object SettingsEhScreen : SearchableSettings {
|
|||||||
@Composable
|
@Composable
|
||||||
fun enhancedEhentaiView(exhPreferences: ExhPreferences): Preference.PreferenceItem.SwitchPreference {
|
fun enhancedEhentaiView(exhPreferences: ExhPreferences): Preference.PreferenceItem.SwitchPreference {
|
||||||
return Preference.PreferenceItem.SwitchPreference(
|
return Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = exhPreferences.enhancedEHentaiView(),
|
preference = exhPreferences.enhancedEHentaiView,
|
||||||
title = stringResource(SYMR.strings.pref_enhanced_e_hentai_view),
|
title = stringResource(SYMR.strings.pref_enhanced_e_hentai_view),
|
||||||
subtitle = stringResource(SYMR.strings.pref_enhanced_e_hentai_view_summary),
|
subtitle = stringResource(SYMR.strings.pref_enhanced_e_hentai_view_summary),
|
||||||
)
|
)
|
||||||
@@ -840,7 +840,7 @@ object SettingsEhScreen : SearchableSettings {
|
|||||||
@Composable
|
@Composable
|
||||||
fun readOnlySync(exhPreferences: ExhPreferences): Preference.PreferenceItem.SwitchPreference {
|
fun readOnlySync(exhPreferences: ExhPreferences): Preference.PreferenceItem.SwitchPreference {
|
||||||
return Preference.PreferenceItem.SwitchPreference(
|
return Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = exhPreferences.exhReadOnlySync(),
|
preference = exhPreferences.exhReadOnlySync,
|
||||||
title = stringResource(SYMR.strings.disable_favorites_uploading),
|
title = stringResource(SYMR.strings.disable_favorites_uploading),
|
||||||
subtitle = stringResource(SYMR.strings.disable_favorites_uploading_summary),
|
subtitle = stringResource(SYMR.strings.disable_favorites_uploading_summary),
|
||||||
)
|
)
|
||||||
@@ -865,7 +865,7 @@ object SettingsEhScreen : SearchableSettings {
|
|||||||
@Composable
|
@Composable
|
||||||
fun lenientSync(exhPreferences: ExhPreferences): Preference.PreferenceItem.SwitchPreference {
|
fun lenientSync(exhPreferences: ExhPreferences): Preference.PreferenceItem.SwitchPreference {
|
||||||
return Preference.PreferenceItem.SwitchPreference(
|
return Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = exhPreferences.exhLenientSync(),
|
preference = exhPreferences.exhLenientSync,
|
||||||
title = stringResource(SYMR.strings.ignore_sync_errors),
|
title = stringResource(SYMR.strings.ignore_sync_errors),
|
||||||
subtitle = stringResource(SYMR.strings.ignore_sync_errors_summary),
|
subtitle = stringResource(SYMR.strings.ignore_sync_errors_summary),
|
||||||
)
|
)
|
||||||
@@ -937,10 +937,10 @@ object SettingsEhScreen : SearchableSettings {
|
|||||||
fun updateCheckerFrequency(
|
fun updateCheckerFrequency(
|
||||||
exhPreferences: ExhPreferences,
|
exhPreferences: ExhPreferences,
|
||||||
): Preference.PreferenceItem.ListPreference<Int> {
|
): Preference.PreferenceItem.ListPreference<Int> {
|
||||||
val value by exhPreferences.exhAutoUpdateFrequency().collectAsState()
|
val value by exhPreferences.exhAutoUpdateFrequency.collectAsState()
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
return Preference.PreferenceItem.ListPreference(
|
return Preference.PreferenceItem.ListPreference(
|
||||||
preference = exhPreferences.exhAutoUpdateFrequency(),
|
preference = exhPreferences.exhAutoUpdateFrequency,
|
||||||
title = stringResource(SYMR.strings.time_between_batches),
|
title = stringResource(SYMR.strings.time_between_batches),
|
||||||
subtitle = if (value == 0) {
|
subtitle = if (value == 0) {
|
||||||
stringResource(SYMR.strings.time_between_batches_summary_1, stringResource(MR.strings.app_name))
|
stringResource(SYMR.strings.time_between_batches_summary_1, stringResource(MR.strings.app_name))
|
||||||
@@ -973,10 +973,10 @@ object SettingsEhScreen : SearchableSettings {
|
|||||||
fun autoUpdateRequirements(
|
fun autoUpdateRequirements(
|
||||||
exhPreferences: ExhPreferences,
|
exhPreferences: ExhPreferences,
|
||||||
): Preference.PreferenceItem.MultiSelectListPreference {
|
): Preference.PreferenceItem.MultiSelectListPreference {
|
||||||
val value by exhPreferences.exhAutoUpdateRequirements().collectAsState()
|
val value by exhPreferences.exhAutoUpdateRequirements.collectAsState()
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
return Preference.PreferenceItem.MultiSelectListPreference(
|
return Preference.PreferenceItem.MultiSelectListPreference(
|
||||||
preference = exhPreferences.exhAutoUpdateRequirements(),
|
preference = exhPreferences.exhAutoUpdateRequirements,
|
||||||
title = stringResource(SYMR.strings.auto_update_restrictions),
|
title = stringResource(SYMR.strings.auto_update_restrictions),
|
||||||
subtitle = remember(value) {
|
subtitle = remember(value) {
|
||||||
context.stringResource(
|
context.stringResource(
|
||||||
@@ -1150,7 +1150,7 @@ object SettingsEhScreen : SearchableSettings {
|
|||||||
value = withIOContext {
|
value = withIOContext {
|
||||||
try {
|
try {
|
||||||
val stats =
|
val stats =
|
||||||
exhPreferences.exhAutoUpdateStats().get().nullIfBlank()?.let {
|
exhPreferences.exhAutoUpdateStats.get().nullIfBlank()?.let {
|
||||||
Json.decodeFromString<EHentaiUpdaterStats>(it)
|
Json.decodeFromString<EHentaiUpdaterStats>(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+15
-15
@@ -79,7 +79,7 @@ object SettingsLibraryScreen : SearchableSettings {
|
|||||||
val userCategoriesCount = allCategories.filterNot(Category::isSystemCategory).size
|
val userCategoriesCount = allCategories.filterNot(Category::isSystemCategory).size
|
||||||
|
|
||||||
// For default category
|
// For default category
|
||||||
val ids = listOf(libraryPreferences.defaultCategory().defaultValue()) +
|
val ids = listOf(libraryPreferences.defaultCategory.defaultValue()) +
|
||||||
allCategories.fastMap { it.id.toInt() }
|
allCategories.fastMap { it.id.toInt() }
|
||||||
val labels = listOf(stringResource(MR.strings.default_category_summary)) +
|
val labels = listOf(stringResource(MR.strings.default_category_summary)) +
|
||||||
allCategories.fastMap { it.visualName }
|
allCategories.fastMap { it.visualName }
|
||||||
@@ -97,12 +97,12 @@ object SettingsLibraryScreen : SearchableSettings {
|
|||||||
onClick = { navigator.push(CategoryScreen()) },
|
onClick = { navigator.push(CategoryScreen()) },
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
preference = libraryPreferences.defaultCategory(),
|
preference = libraryPreferences.defaultCategory,
|
||||||
entries = ids.zip(labels).toMap().toImmutableMap(),
|
entries = ids.zip(labels).toMap().toImmutableMap(),
|
||||||
title = stringResource(MR.strings.default_category),
|
title = stringResource(MR.strings.default_category),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = libraryPreferences.categorizedDisplaySettings(),
|
preference = libraryPreferences.categorizedDisplaySettings,
|
||||||
title = stringResource(MR.strings.categorized_display_settings),
|
title = stringResource(MR.strings.categorized_display_settings),
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
if (!it) {
|
if (!it) {
|
||||||
@@ -124,9 +124,9 @@ object SettingsLibraryScreen : SearchableSettings {
|
|||||||
): Preference.PreferenceGroup {
|
): Preference.PreferenceGroup {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
val autoUpdateIntervalPref = libraryPreferences.autoUpdateInterval()
|
val autoUpdateIntervalPref = libraryPreferences.autoUpdateInterval
|
||||||
val autoUpdateCategoriesPref = libraryPreferences.updateCategories()
|
val autoUpdateCategoriesPref = libraryPreferences.updateCategories
|
||||||
val autoUpdateCategoriesExcludePref = libraryPreferences.updateCategoriesExclude()
|
val autoUpdateCategoriesExcludePref = libraryPreferences.updateCategoriesExclude
|
||||||
|
|
||||||
val autoUpdateInterval by autoUpdateIntervalPref.collectAsState()
|
val autoUpdateInterval by autoUpdateIntervalPref.collectAsState()
|
||||||
|
|
||||||
@@ -170,7 +170,7 @@ object SettingsLibraryScreen : SearchableSettings {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.MultiSelectListPreference(
|
Preference.PreferenceItem.MultiSelectListPreference(
|
||||||
preference = libraryPreferences.autoUpdateDeviceRestrictions(),
|
preference = libraryPreferences.autoUpdateDeviceRestrictions,
|
||||||
entries = persistentMapOf(
|
entries = persistentMapOf(
|
||||||
DEVICE_ONLY_ON_WIFI to stringResource(MR.strings.connected_to_wifi),
|
DEVICE_ONLY_ON_WIFI to stringResource(MR.strings.connected_to_wifi),
|
||||||
DEVICE_NETWORK_NOT_METERED to stringResource(MR.strings.network_not_metered),
|
DEVICE_NETWORK_NOT_METERED to stringResource(MR.strings.network_not_metered),
|
||||||
@@ -196,7 +196,7 @@ object SettingsLibraryScreen : SearchableSettings {
|
|||||||
),
|
),
|
||||||
// SY -->
|
// SY -->
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
preference = libraryPreferences.groupLibraryUpdateType(),
|
preference = libraryPreferences.groupLibraryUpdateType,
|
||||||
title = stringResource(SYMR.strings.library_group_updates),
|
title = stringResource(SYMR.strings.library_group_updates),
|
||||||
entries = persistentMapOf(
|
entries = persistentMapOf(
|
||||||
GroupLibraryMode.GLOBAL to stringResource(SYMR.strings.library_group_updates_global),
|
GroupLibraryMode.GLOBAL to stringResource(SYMR.strings.library_group_updates_global),
|
||||||
@@ -207,12 +207,12 @@ object SettingsLibraryScreen : SearchableSettings {
|
|||||||
),
|
),
|
||||||
// SY <--
|
// SY <--
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = libraryPreferences.autoUpdateMetadata(),
|
preference = libraryPreferences.autoUpdateMetadata,
|
||||||
title = stringResource(MR.strings.pref_library_update_refresh_metadata),
|
title = stringResource(MR.strings.pref_library_update_refresh_metadata),
|
||||||
subtitle = stringResource(MR.strings.pref_library_update_refresh_metadata_summary),
|
subtitle = stringResource(MR.strings.pref_library_update_refresh_metadata_summary),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.MultiSelectListPreference(
|
Preference.PreferenceItem.MultiSelectListPreference(
|
||||||
preference = libraryPreferences.autoUpdateMangaRestrictions(),
|
preference = libraryPreferences.autoUpdateMangaRestrictions,
|
||||||
entries = persistentMapOf(
|
entries = persistentMapOf(
|
||||||
MANGA_HAS_UNREAD to stringResource(MR.strings.pref_update_only_completely_read),
|
MANGA_HAS_UNREAD to stringResource(MR.strings.pref_update_only_completely_read),
|
||||||
MANGA_NON_READ to stringResource(MR.strings.pref_update_only_started),
|
MANGA_NON_READ to stringResource(MR.strings.pref_update_only_started),
|
||||||
@@ -222,7 +222,7 @@ object SettingsLibraryScreen : SearchableSettings {
|
|||||||
title = stringResource(MR.strings.pref_library_update_smart_update),
|
title = stringResource(MR.strings.pref_library_update_smart_update),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = libraryPreferences.newShowUpdatesCount(),
|
preference = libraryPreferences.newShowUpdatesCount,
|
||||||
title = stringResource(MR.strings.pref_library_update_show_tab_badge),
|
title = stringResource(MR.strings.pref_library_update_show_tab_badge),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -237,7 +237,7 @@ object SettingsLibraryScreen : SearchableSettings {
|
|||||||
title = stringResource(MR.strings.pref_behavior),
|
title = stringResource(MR.strings.pref_behavior),
|
||||||
preferenceItems = persistentListOf(
|
preferenceItems = persistentListOf(
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
preference = libraryPreferences.swipeToStartAction(),
|
preference = libraryPreferences.swipeToStartAction,
|
||||||
entries = persistentMapOf(
|
entries = persistentMapOf(
|
||||||
LibraryPreferences.ChapterSwipeAction.Disabled to
|
LibraryPreferences.ChapterSwipeAction.Disabled to
|
||||||
stringResource(MR.strings.disabled),
|
stringResource(MR.strings.disabled),
|
||||||
@@ -251,7 +251,7 @@ object SettingsLibraryScreen : SearchableSettings {
|
|||||||
title = stringResource(MR.strings.pref_chapter_swipe_start),
|
title = stringResource(MR.strings.pref_chapter_swipe_start),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
preference = libraryPreferences.swipeToEndAction(),
|
preference = libraryPreferences.swipeToEndAction,
|
||||||
entries = persistentMapOf(
|
entries = persistentMapOf(
|
||||||
LibraryPreferences.ChapterSwipeAction.Disabled to
|
LibraryPreferences.ChapterSwipeAction.Disabled to
|
||||||
stringResource(MR.strings.disabled),
|
stringResource(MR.strings.disabled),
|
||||||
@@ -265,7 +265,7 @@ object SettingsLibraryScreen : SearchableSettings {
|
|||||||
title = stringResource(MR.strings.pref_chapter_swipe_end),
|
title = stringResource(MR.strings.pref_chapter_swipe_end),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.MultiSelectListPreference(
|
Preference.PreferenceItem.MultiSelectListPreference(
|
||||||
preference = libraryPreferences.markDuplicateReadChapterAsRead(),
|
preference = libraryPreferences.markDuplicateReadChapterAsRead,
|
||||||
entries = persistentMapOf(
|
entries = persistentMapOf(
|
||||||
MARK_DUPLICATE_CHAPTER_READ_EXISTING to
|
MARK_DUPLICATE_CHAPTER_READ_EXISTING to
|
||||||
stringResource(MR.strings.pref_mark_duplicate_read_chapter_read_existing),
|
stringResource(MR.strings.pref_mark_duplicate_read_chapter_read_existing),
|
||||||
@@ -281,7 +281,7 @@ object SettingsLibraryScreen : SearchableSettings {
|
|||||||
// SY -->
|
// SY -->
|
||||||
@Composable
|
@Composable
|
||||||
fun getSortingCategory(navigator: Navigator, libraryPreferences: LibraryPreferences): Preference.PreferenceGroup {
|
fun getSortingCategory(navigator: Navigator, libraryPreferences: LibraryPreferences): Preference.PreferenceGroup {
|
||||||
val tagCount by libraryPreferences.sortTagsForLibrary().collectAsState()
|
val tagCount by libraryPreferences.sortTagsForLibrary.collectAsState()
|
||||||
return Preference.PreferenceGroup(
|
return Preference.PreferenceGroup(
|
||||||
stringResource(SYMR.strings.pref_sorting_settings),
|
stringResource(SYMR.strings.pref_sorting_settings),
|
||||||
preferenceItems = persistentListOf(
|
preferenceItems = persistentListOf(
|
||||||
|
|||||||
+2
-2
@@ -175,7 +175,7 @@ object SettingsMangadexScreen : SearchableSettings {
|
|||||||
sourcePreferences: SourcePreferences,
|
sourcePreferences: SourcePreferences,
|
||||||
): Preference.PreferenceItem.ListPreference<String> {
|
): Preference.PreferenceItem.ListPreference<String> {
|
||||||
return Preference.PreferenceItem.ListPreference(
|
return Preference.PreferenceItem.ListPreference(
|
||||||
preference = sourcePreferences.preferredMangaDexId(),
|
preference = sourcePreferences.preferredMangaDexId,
|
||||||
title = stringResource(SYMR.strings.mangadex_preffered_source),
|
title = stringResource(SYMR.strings.mangadex_preffered_source),
|
||||||
subtitle = stringResource(SYMR.strings.mangadex_preffered_source_summary),
|
subtitle = stringResource(SYMR.strings.mangadex_preffered_source_summary),
|
||||||
entries = MdUtil.getEnabledMangaDexs(sourcePreferences)
|
entries = MdUtil.getEnabledMangaDexs(sourcePreferences)
|
||||||
@@ -255,7 +255,7 @@ object SettingsMangadexScreen : SearchableSettings {
|
|||||||
onDismissRequest = { dialogOpen = false },
|
onDismissRequest = { dialogOpen = false },
|
||||||
onSelectionConfirmed = { items ->
|
onSelectionConfirmed = { items ->
|
||||||
dialogOpen = false
|
dialogOpen = false
|
||||||
sourcePreferences.mangadexSyncToLibraryIndexes().set(
|
sourcePreferences.mangadexSyncToLibraryIndexes.set(
|
||||||
List(items.size) { index -> (index + 1).toString() }.toSet(),
|
List(items.size) { index -> (index + 1).toString() }.toSet(),
|
||||||
)
|
)
|
||||||
LibraryUpdateJob.startNow(
|
LibraryUpdateJob.startNow(
|
||||||
|
|||||||
+67
-67
@@ -34,19 +34,19 @@ object SettingsReaderScreen : SearchableSettings {
|
|||||||
override fun getPreferences(): List<Preference> {
|
override fun getPreferences(): List<Preference> {
|
||||||
val readerPref = remember { Injekt.get<ReaderPreferences>() }
|
val readerPref = remember { Injekt.get<ReaderPreferences>() }
|
||||||
// SY -->
|
// SY -->
|
||||||
val forceHorizontalSeekbar by readerPref.forceHorizontalSeekbar().collectAsState()
|
val forceHorizontalSeekbar by readerPref.forceHorizontalSeekbar.collectAsState()
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
return listOf(
|
return listOf(
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
preference = readerPref.defaultReadingMode(),
|
preference = readerPref.defaultReadingMode,
|
||||||
entries = ReadingMode.entries.drop(1)
|
entries = ReadingMode.entries.drop(1)
|
||||||
.associate { it.flagValue to stringResource(it.stringRes) }
|
.associate { it.flagValue to stringResource(it.stringRes) }
|
||||||
.toImmutableMap(),
|
.toImmutableMap(),
|
||||||
title = stringResource(MR.strings.pref_viewer_type),
|
title = stringResource(MR.strings.pref_viewer_type),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
preference = readerPref.doubleTapAnimSpeed(),
|
preference = readerPref.doubleTapAnimSpeed,
|
||||||
entries = persistentMapOf(
|
entries = persistentMapOf(
|
||||||
1 to stringResource(MR.strings.double_tap_anim_speed_0),
|
1 to stringResource(MR.strings.double_tap_anim_speed_0),
|
||||||
500 to stringResource(MR.strings.double_tap_anim_speed_normal),
|
500 to stringResource(MR.strings.double_tap_anim_speed_normal),
|
||||||
@@ -55,29 +55,29 @@ object SettingsReaderScreen : SearchableSettings {
|
|||||||
title = stringResource(MR.strings.pref_double_tap_anim_speed),
|
title = stringResource(MR.strings.pref_double_tap_anim_speed),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = readerPref.showReadingMode(),
|
preference = readerPref.showReadingMode,
|
||||||
title = stringResource(MR.strings.pref_show_reading_mode),
|
title = stringResource(MR.strings.pref_show_reading_mode),
|
||||||
subtitle = stringResource(MR.strings.pref_show_reading_mode_summary),
|
subtitle = stringResource(MR.strings.pref_show_reading_mode_summary),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = readerPref.showNavigationOverlayOnStart(),
|
preference = readerPref.showNavigationOverlayOnStart,
|
||||||
title = stringResource(MR.strings.pref_show_navigation_mode),
|
title = stringResource(MR.strings.pref_show_navigation_mode),
|
||||||
subtitle = stringResource(MR.strings.pref_show_navigation_mode_summary),
|
subtitle = stringResource(MR.strings.pref_show_navigation_mode_summary),
|
||||||
),
|
),
|
||||||
// SY -->
|
// SY -->
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = readerPref.forceHorizontalSeekbar(),
|
preference = readerPref.forceHorizontalSeekbar,
|
||||||
title = stringResource(SYMR.strings.pref_force_horz_seekbar),
|
title = stringResource(SYMR.strings.pref_force_horz_seekbar),
|
||||||
subtitle = stringResource(SYMR.strings.pref_force_horz_seekbar_summary),
|
subtitle = stringResource(SYMR.strings.pref_force_horz_seekbar_summary),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = readerPref.landscapeVerticalSeekbar(),
|
preference = readerPref.landscapeVerticalSeekbar,
|
||||||
title = stringResource(SYMR.strings.pref_show_vert_seekbar_landscape),
|
title = stringResource(SYMR.strings.pref_show_vert_seekbar_landscape),
|
||||||
subtitle = stringResource(SYMR.strings.pref_show_vert_seekbar_landscape_summary),
|
subtitle = stringResource(SYMR.strings.pref_show_vert_seekbar_landscape_summary),
|
||||||
enabled = !forceHorizontalSeekbar,
|
enabled = !forceHorizontalSeekbar,
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = readerPref.leftVerticalSeekbar(),
|
preference = readerPref.leftVerticalSeekbar,
|
||||||
title = stringResource(SYMR.strings.pref_left_handed_vertical_seekbar),
|
title = stringResource(SYMR.strings.pref_left_handed_vertical_seekbar),
|
||||||
subtitle = stringResource(SYMR.strings.pref_left_handed_vertical_seekbar_summary),
|
subtitle = stringResource(SYMR.strings.pref_left_handed_vertical_seekbar_summary),
|
||||||
enabled = !forceHorizontalSeekbar,
|
enabled = !forceHorizontalSeekbar,
|
||||||
@@ -85,7 +85,7 @@ object SettingsReaderScreen : SearchableSettings {
|
|||||||
// SY <--
|
// SY <--
|
||||||
/* SY -->
|
/* SY -->
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = readerPref.pageTransitions(),
|
preference = readerPref.pageTransitions,
|
||||||
title = stringResource(MR.strings.pref_page_transitions),
|
title = stringResource(MR.strings.pref_page_transitions),
|
||||||
),
|
),
|
||||||
SY <-- */
|
SY <-- */
|
||||||
@@ -108,20 +108,20 @@ object SettingsReaderScreen : SearchableSettings {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun getDisplayGroup(readerPreferences: ReaderPreferences): Preference.PreferenceGroup {
|
private fun getDisplayGroup(readerPreferences: ReaderPreferences): Preference.PreferenceGroup {
|
||||||
val fullscreenPref = readerPreferences.fullscreen()
|
val fullscreenPref = readerPreferences.fullscreen
|
||||||
val fullscreen by fullscreenPref.collectAsState()
|
val fullscreen by fullscreenPref.collectAsState()
|
||||||
return Preference.PreferenceGroup(
|
return Preference.PreferenceGroup(
|
||||||
title = stringResource(MR.strings.pref_category_display),
|
title = stringResource(MR.strings.pref_category_display),
|
||||||
preferenceItems = persistentListOf(
|
preferenceItems = persistentListOf(
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
preference = readerPreferences.defaultOrientationType(),
|
preference = readerPreferences.defaultOrientationType,
|
||||||
entries = ReaderOrientation.entries.drop(1)
|
entries = ReaderOrientation.entries.drop(1)
|
||||||
.associate { it.flagValue to stringResource(it.stringRes) }
|
.associate { it.flagValue to stringResource(it.stringRes) }
|
||||||
.toImmutableMap(),
|
.toImmutableMap(),
|
||||||
title = stringResource(MR.strings.pref_rotation_type),
|
title = stringResource(MR.strings.pref_rotation_type),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
preference = readerPreferences.readerTheme(),
|
preference = readerPreferences.readerTheme,
|
||||||
entries = persistentMapOf(
|
entries = persistentMapOf(
|
||||||
1 to stringResource(MR.strings.black_background),
|
1 to stringResource(MR.strings.black_background),
|
||||||
2 to stringResource(MR.strings.gray_background),
|
2 to stringResource(MR.strings.gray_background),
|
||||||
@@ -135,16 +135,16 @@ object SettingsReaderScreen : SearchableSettings {
|
|||||||
title = stringResource(MR.strings.pref_fullscreen),
|
title = stringResource(MR.strings.pref_fullscreen),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = readerPreferences.drawUnderCutout(),
|
preference = readerPreferences.drawUnderCutout,
|
||||||
title = stringResource(MR.strings.pref_cutout_short),
|
title = stringResource(MR.strings.pref_cutout_short),
|
||||||
enabled = LocalView.current.hasDisplayCutout() && fullscreen,
|
enabled = LocalView.current.hasDisplayCutout() && fullscreen,
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = readerPreferences.keepScreenOn(),
|
preference = readerPreferences.keepScreenOn,
|
||||||
title = stringResource(MR.strings.pref_keep_screen_on),
|
title = stringResource(MR.strings.pref_keep_screen_on),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = readerPreferences.showPageNumber(),
|
preference = readerPreferences.showPageNumber,
|
||||||
title = stringResource(MR.strings.pref_show_page_number),
|
title = stringResource(MR.strings.pref_show_page_number),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -153,21 +153,21 @@ object SettingsReaderScreen : SearchableSettings {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun getEInkGroup(readerPreferences: ReaderPreferences): Preference.PreferenceGroup {
|
private fun getEInkGroup(readerPreferences: ReaderPreferences): Preference.PreferenceGroup {
|
||||||
val flashPageState by readerPreferences.flashOnPageChange().collectAsState()
|
val flashPageState by readerPreferences.flashOnPageChange.collectAsState()
|
||||||
|
|
||||||
val flashMillisPref = readerPreferences.flashDurationMillis()
|
val flashMillisPref = readerPreferences.flashDurationMillis
|
||||||
val flashMillis by flashMillisPref.collectAsState()
|
val flashMillis by flashMillisPref.collectAsState()
|
||||||
|
|
||||||
val flashIntervalPref = readerPreferences.flashPageInterval()
|
val flashIntervalPref = readerPreferences.flashPageInterval
|
||||||
val flashInterval by flashIntervalPref.collectAsState()
|
val flashInterval by flashIntervalPref.collectAsState()
|
||||||
|
|
||||||
val flashColorPref = readerPreferences.flashColor()
|
val flashColorPref = readerPreferences.flashColor
|
||||||
|
|
||||||
return Preference.PreferenceGroup(
|
return Preference.PreferenceGroup(
|
||||||
title = "E-Ink",
|
title = "E-Ink",
|
||||||
preferenceItems = persistentListOf(
|
preferenceItems = persistentListOf(
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = readerPreferences.flashOnPageChange(),
|
preference = readerPreferences.flashOnPageChange,
|
||||||
title = stringResource(MR.strings.pref_flash_page),
|
title = stringResource(MR.strings.pref_flash_page),
|
||||||
subtitle = stringResource(MR.strings.pref_flash_page_summ),
|
subtitle = stringResource(MR.strings.pref_flash_page_summ),
|
||||||
),
|
),
|
||||||
@@ -208,19 +208,19 @@ object SettingsReaderScreen : SearchableSettings {
|
|||||||
title = stringResource(MR.strings.pref_category_reading),
|
title = stringResource(MR.strings.pref_category_reading),
|
||||||
preferenceItems = persistentListOf(
|
preferenceItems = persistentListOf(
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = readerPreferences.skipRead(),
|
preference = readerPreferences.skipRead,
|
||||||
title = stringResource(MR.strings.pref_skip_read_chapters),
|
title = stringResource(MR.strings.pref_skip_read_chapters),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = readerPreferences.skipFiltered(),
|
preference = readerPreferences.skipFiltered,
|
||||||
title = stringResource(MR.strings.pref_skip_filtered_chapters),
|
title = stringResource(MR.strings.pref_skip_filtered_chapters),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = readerPreferences.skipDupe(),
|
preference = readerPreferences.skipDupe,
|
||||||
title = stringResource(MR.strings.pref_skip_dupe_chapters),
|
title = stringResource(MR.strings.pref_skip_dupe_chapters),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = readerPreferences.alwaysShowChapterTransition(),
|
preference = readerPreferences.alwaysShowChapterTransition,
|
||||||
title = stringResource(MR.strings.pref_always_show_chapter_transition),
|
title = stringResource(MR.strings.pref_always_show_chapter_transition),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -229,10 +229,10 @@ object SettingsReaderScreen : SearchableSettings {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun getPagedGroup(readerPreferences: ReaderPreferences): Preference.PreferenceGroup {
|
private fun getPagedGroup(readerPreferences: ReaderPreferences): Preference.PreferenceGroup {
|
||||||
val navModePref = readerPreferences.navigationModePager()
|
val navModePref = readerPreferences.navigationModePager
|
||||||
val imageScaleTypePref = readerPreferences.imageScaleType()
|
val imageScaleTypePref = readerPreferences.imageScaleType
|
||||||
val dualPageSplitPref = readerPreferences.dualPageSplitPaged()
|
val dualPageSplitPref = readerPreferences.dualPageSplitPaged
|
||||||
val rotateToFitPref = readerPreferences.dualPageRotateToFit()
|
val rotateToFitPref = readerPreferences.dualPageRotateToFit
|
||||||
|
|
||||||
val navMode by navModePref.collectAsState()
|
val navMode by navModePref.collectAsState()
|
||||||
val imageScaleType by imageScaleTypePref.collectAsState()
|
val imageScaleType by imageScaleTypePref.collectAsState()
|
||||||
@@ -251,7 +251,7 @@ object SettingsReaderScreen : SearchableSettings {
|
|||||||
title = stringResource(MR.strings.pref_viewer_nav),
|
title = stringResource(MR.strings.pref_viewer_nav),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
preference = readerPreferences.pagerNavInverted(),
|
preference = readerPreferences.pagerNavInverted,
|
||||||
entries = persistentListOf(
|
entries = persistentListOf(
|
||||||
ReaderPreferences.TappingInvertMode.NONE,
|
ReaderPreferences.TappingInvertMode.NONE,
|
||||||
ReaderPreferences.TappingInvertMode.HORIZONTAL,
|
ReaderPreferences.TappingInvertMode.HORIZONTAL,
|
||||||
@@ -272,7 +272,7 @@ object SettingsReaderScreen : SearchableSettings {
|
|||||||
title = stringResource(MR.strings.pref_image_scale_type),
|
title = stringResource(MR.strings.pref_image_scale_type),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
preference = readerPreferences.zoomStart(),
|
preference = readerPreferences.zoomStart,
|
||||||
entries = ReaderPreferences.ZoomStart
|
entries = ReaderPreferences.ZoomStart
|
||||||
.mapIndexed { index, it -> index + 1 to stringResource(it) }
|
.mapIndexed { index, it -> index + 1 to stringResource(it) }
|
||||||
.toMap()
|
.toMap()
|
||||||
@@ -280,22 +280,22 @@ object SettingsReaderScreen : SearchableSettings {
|
|||||||
title = stringResource(MR.strings.pref_zoom_start),
|
title = stringResource(MR.strings.pref_zoom_start),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = readerPreferences.cropBorders(),
|
preference = readerPreferences.cropBorders,
|
||||||
title = stringResource(MR.strings.pref_crop_borders),
|
title = stringResource(MR.strings.pref_crop_borders),
|
||||||
),
|
),
|
||||||
// SY -->
|
// SY -->
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = readerPreferences.pageTransitionsPager(),
|
preference = readerPreferences.pageTransitionsPager,
|
||||||
title = stringResource(MR.strings.pref_page_transitions),
|
title = stringResource(MR.strings.pref_page_transitions),
|
||||||
),
|
),
|
||||||
// SY <--
|
// SY <--
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = readerPreferences.landscapeZoom(),
|
preference = readerPreferences.landscapeZoom,
|
||||||
title = stringResource(MR.strings.pref_landscape_zoom),
|
title = stringResource(MR.strings.pref_landscape_zoom),
|
||||||
enabled = imageScaleType == 1,
|
enabled = imageScaleType == 1,
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = readerPreferences.navigateToPan(),
|
preference = readerPreferences.navigateToPan,
|
||||||
title = stringResource(MR.strings.pref_navigate_pan),
|
title = stringResource(MR.strings.pref_navigate_pan),
|
||||||
enabled = navMode != 5,
|
enabled = navMode != 5,
|
||||||
),
|
),
|
||||||
@@ -308,7 +308,7 @@ object SettingsReaderScreen : SearchableSettings {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = readerPreferences.dualPageInvertPaged(),
|
preference = readerPreferences.dualPageInvertPaged,
|
||||||
title = stringResource(MR.strings.pref_dual_page_invert),
|
title = stringResource(MR.strings.pref_dual_page_invert),
|
||||||
subtitle = stringResource(MR.strings.pref_dual_page_invert_summary),
|
subtitle = stringResource(MR.strings.pref_dual_page_invert_summary),
|
||||||
enabled = dualPageSplit,
|
enabled = dualPageSplit,
|
||||||
@@ -322,7 +322,7 @@ object SettingsReaderScreen : SearchableSettings {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = readerPreferences.dualPageRotateToFitInvert(),
|
preference = readerPreferences.dualPageRotateToFitInvert,
|
||||||
title = stringResource(MR.strings.pref_page_rotate_invert),
|
title = stringResource(MR.strings.pref_page_rotate_invert),
|
||||||
enabled = rotateToFit,
|
enabled = rotateToFit,
|
||||||
),
|
),
|
||||||
@@ -334,10 +334,10 @@ object SettingsReaderScreen : SearchableSettings {
|
|||||||
private fun getWebtoonGroup(readerPreferences: ReaderPreferences): Preference.PreferenceGroup {
|
private fun getWebtoonGroup(readerPreferences: ReaderPreferences): Preference.PreferenceGroup {
|
||||||
val numberFormat = remember { NumberFormat.getPercentInstance() }
|
val numberFormat = remember { NumberFormat.getPercentInstance() }
|
||||||
|
|
||||||
val navModePref = readerPreferences.navigationModeWebtoon()
|
val navModePref = readerPreferences.navigationModeWebtoon
|
||||||
val dualPageSplitPref = readerPreferences.dualPageSplitWebtoon()
|
val dualPageSplitPref = readerPreferences.dualPageSplitWebtoon
|
||||||
val rotateToFitPref = readerPreferences.dualPageRotateToFitWebtoon()
|
val rotateToFitPref = readerPreferences.dualPageRotateToFitWebtoon
|
||||||
val webtoonSidePaddingPref = readerPreferences.webtoonSidePadding()
|
val webtoonSidePaddingPref = readerPreferences.webtoonSidePadding
|
||||||
|
|
||||||
val navMode by navModePref.collectAsState()
|
val navMode by navModePref.collectAsState()
|
||||||
val dualPageSplit by dualPageSplitPref.collectAsState()
|
val dualPageSplit by dualPageSplitPref.collectAsState()
|
||||||
@@ -356,7 +356,7 @@ object SettingsReaderScreen : SearchableSettings {
|
|||||||
title = stringResource(MR.strings.pref_viewer_nav),
|
title = stringResource(MR.strings.pref_viewer_nav),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
preference = readerPreferences.webtoonNavInverted(),
|
preference = readerPreferences.webtoonNavInverted,
|
||||||
entries = persistentListOf(
|
entries = persistentListOf(
|
||||||
ReaderPreferences.TappingInvertMode.NONE,
|
ReaderPreferences.TappingInvertMode.NONE,
|
||||||
ReaderPreferences.TappingInvertMode.HORIZONTAL,
|
ReaderPreferences.TappingInvertMode.HORIZONTAL,
|
||||||
@@ -378,7 +378,7 @@ object SettingsReaderScreen : SearchableSettings {
|
|||||||
onValueChanged = { webtoonSidePaddingPref.set(it) },
|
onValueChanged = { webtoonSidePaddingPref.set(it) },
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
preference = readerPreferences.readerHideThreshold(),
|
preference = readerPreferences.readerHideThreshold,
|
||||||
entries = persistentMapOf(
|
entries = persistentMapOf(
|
||||||
ReaderPreferences.ReaderHideThreshold.HIGHEST to stringResource(MR.strings.pref_highest),
|
ReaderPreferences.ReaderHideThreshold.HIGHEST to stringResource(MR.strings.pref_highest),
|
||||||
ReaderPreferences.ReaderHideThreshold.HIGH to stringResource(MR.strings.pref_high),
|
ReaderPreferences.ReaderHideThreshold.HIGH to stringResource(MR.strings.pref_high),
|
||||||
@@ -388,7 +388,7 @@ object SettingsReaderScreen : SearchableSettings {
|
|||||||
title = stringResource(MR.strings.pref_hide_threshold),
|
title = stringResource(MR.strings.pref_hide_threshold),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = readerPreferences.cropBordersWebtoon(),
|
preference = readerPreferences.cropBordersWebtoon,
|
||||||
title = stringResource(MR.strings.pref_crop_borders),
|
title = stringResource(MR.strings.pref_crop_borders),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
@@ -400,7 +400,7 @@ object SettingsReaderScreen : SearchableSettings {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = readerPreferences.dualPageInvertWebtoon(),
|
preference = readerPreferences.dualPageInvertWebtoon,
|
||||||
title = stringResource(MR.strings.pref_dual_page_invert),
|
title = stringResource(MR.strings.pref_dual_page_invert),
|
||||||
subtitle = stringResource(MR.strings.pref_dual_page_invert_summary),
|
subtitle = stringResource(MR.strings.pref_dual_page_invert_summary),
|
||||||
enabled = dualPageSplit,
|
enabled = dualPageSplit,
|
||||||
@@ -414,21 +414,21 @@ object SettingsReaderScreen : SearchableSettings {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = readerPreferences.dualPageRotateToFitInvertWebtoon(),
|
preference = readerPreferences.dualPageRotateToFitInvertWebtoon,
|
||||||
title = stringResource(MR.strings.pref_page_rotate_invert),
|
title = stringResource(MR.strings.pref_page_rotate_invert),
|
||||||
enabled = rotateToFit,
|
enabled = rotateToFit,
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = readerPreferences.webtoonDoubleTapZoomEnabled(),
|
preference = readerPreferences.webtoonDoubleTapZoomEnabled,
|
||||||
title = stringResource(MR.strings.pref_double_tap_zoom),
|
title = stringResource(MR.strings.pref_double_tap_zoom),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = readerPreferences.webtoonDisableZoomOut(),
|
preference = readerPreferences.webtoonDisableZoomOut,
|
||||||
title = stringResource(MR.strings.pref_webtoon_disable_zoom_out),
|
title = stringResource(MR.strings.pref_webtoon_disable_zoom_out),
|
||||||
),
|
),
|
||||||
// SY -->
|
// SY -->
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = readerPreferences.pageTransitionsWebtoon(),
|
preference = readerPreferences.pageTransitionsWebtoon,
|
||||||
title = stringResource(MR.strings.pref_page_transitions),
|
title = stringResource(MR.strings.pref_page_transitions),
|
||||||
),
|
),
|
||||||
// SY <--
|
// SY <--
|
||||||
@@ -443,12 +443,12 @@ object SettingsReaderScreen : SearchableSettings {
|
|||||||
title = stringResource(MR.strings.vertical_plus_viewer),
|
title = stringResource(MR.strings.vertical_plus_viewer),
|
||||||
preferenceItems = persistentListOf(
|
preferenceItems = persistentListOf(
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = readerPreferences.continuousVerticalTappingByPage(),
|
preference = readerPreferences.continuousVerticalTappingByPage,
|
||||||
title = stringResource(SYMR.strings.tap_scroll_page),
|
title = stringResource(SYMR.strings.tap_scroll_page),
|
||||||
subtitle = stringResource(SYMR.strings.tap_scroll_page_summary),
|
subtitle = stringResource(SYMR.strings.tap_scroll_page_summary),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = readerPreferences.cropBordersContinuousVertical(),
|
preference = readerPreferences.cropBordersContinuousVertical,
|
||||||
title = stringResource(MR.strings.pref_crop_borders),
|
title = stringResource(MR.strings.pref_crop_borders),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -458,7 +458,7 @@ object SettingsReaderScreen : SearchableSettings {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun getNavigationGroup(readerPreferences: ReaderPreferences): Preference.PreferenceGroup {
|
private fun getNavigationGroup(readerPreferences: ReaderPreferences): Preference.PreferenceGroup {
|
||||||
val readWithVolumeKeysPref = readerPreferences.readWithVolumeKeys()
|
val readWithVolumeKeysPref = readerPreferences.readWithVolumeKeys
|
||||||
val readWithVolumeKeys by readWithVolumeKeysPref.collectAsState()
|
val readWithVolumeKeys by readWithVolumeKeysPref.collectAsState()
|
||||||
return Preference.PreferenceGroup(
|
return Preference.PreferenceGroup(
|
||||||
title = stringResource(MR.strings.pref_reader_navigation),
|
title = stringResource(MR.strings.pref_reader_navigation),
|
||||||
@@ -468,7 +468,7 @@ object SettingsReaderScreen : SearchableSettings {
|
|||||||
title = stringResource(MR.strings.pref_read_with_volume_keys),
|
title = stringResource(MR.strings.pref_read_with_volume_keys),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = readerPreferences.readWithVolumeKeysInverted(),
|
preference = readerPreferences.readWithVolumeKeysInverted,
|
||||||
title = stringResource(MR.strings.pref_read_with_volume_keys_inverted),
|
title = stringResource(MR.strings.pref_read_with_volume_keys_inverted),
|
||||||
enabled = readWithVolumeKeys,
|
enabled = readWithVolumeKeys,
|
||||||
),
|
),
|
||||||
@@ -482,11 +482,11 @@ object SettingsReaderScreen : SearchableSettings {
|
|||||||
title = stringResource(MR.strings.pref_reader_actions),
|
title = stringResource(MR.strings.pref_reader_actions),
|
||||||
preferenceItems = persistentListOf(
|
preferenceItems = persistentListOf(
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = readerPreferences.readWithLongTap(),
|
preference = readerPreferences.readWithLongTap,
|
||||||
title = stringResource(MR.strings.pref_read_with_long_tap),
|
title = stringResource(MR.strings.pref_read_with_long_tap),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = readerPreferences.folderPerManga(),
|
preference = readerPreferences.folderPerManga,
|
||||||
title = stringResource(MR.strings.pref_create_folder_per_manga),
|
title = stringResource(MR.strings.pref_create_folder_per_manga),
|
||||||
subtitle = stringResource(MR.strings.pref_create_folder_per_manga_summary),
|
subtitle = stringResource(MR.strings.pref_create_folder_per_manga_summary),
|
||||||
),
|
),
|
||||||
@@ -501,7 +501,7 @@ object SettingsReaderScreen : SearchableSettings {
|
|||||||
title = stringResource(SYMR.strings.page_downloading),
|
title = stringResource(SYMR.strings.page_downloading),
|
||||||
preferenceItems = persistentListOf(
|
preferenceItems = persistentListOf(
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
preference = readerPreferences.preloadSize(),
|
preference = readerPreferences.preloadSize,
|
||||||
title = stringResource(SYMR.strings.reader_preload_amount),
|
title = stringResource(SYMR.strings.reader_preload_amount),
|
||||||
subtitle = stringResource(SYMR.strings.reader_preload_amount_summary),
|
subtitle = stringResource(SYMR.strings.reader_preload_amount_summary),
|
||||||
entries = persistentMapOf(
|
entries = persistentMapOf(
|
||||||
@@ -516,13 +516,13 @@ object SettingsReaderScreen : SearchableSettings {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
preference = readerPreferences.readerThreads(),
|
preference = readerPreferences.readerThreads,
|
||||||
title = stringResource(SYMR.strings.download_threads),
|
title = stringResource(SYMR.strings.download_threads),
|
||||||
subtitle = stringResource(SYMR.strings.download_threads_summary),
|
subtitle = stringResource(SYMR.strings.download_threads_summary),
|
||||||
entries = List(5) { it }.associateWith { it.toString() }.toImmutableMap(),
|
entries = List(5) { it }.associateWith { it.toString() }.toImmutableMap(),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
preference = readerPreferences.cacheSize(),
|
preference = readerPreferences.cacheSize,
|
||||||
title = stringResource(SYMR.strings.reader_cache_size),
|
title = stringResource(SYMR.strings.reader_cache_size),
|
||||||
subtitle = stringResource(SYMR.strings.reader_cache_size_summary),
|
subtitle = stringResource(SYMR.strings.reader_cache_size_summary),
|
||||||
entries = persistentMapOf(
|
entries = persistentMapOf(
|
||||||
@@ -545,7 +545,7 @@ object SettingsReaderScreen : SearchableSettings {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = readerPreferences.aggressivePageLoading(),
|
preference = readerPreferences.aggressivePageLoading,
|
||||||
title = stringResource(SYMR.strings.aggressively_load_pages),
|
title = stringResource(SYMR.strings.aggressively_load_pages),
|
||||||
subtitle = stringResource(SYMR.strings.aggressively_load_pages_summary),
|
subtitle = stringResource(SYMR.strings.aggressively_load_pages_summary),
|
||||||
),
|
),
|
||||||
@@ -555,26 +555,26 @@ object SettingsReaderScreen : SearchableSettings {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun getForkSettingsGroup(readerPreferences: ReaderPreferences): Preference.PreferenceGroup {
|
private fun getForkSettingsGroup(readerPreferences: ReaderPreferences): Preference.PreferenceGroup {
|
||||||
val pageLayout by readerPreferences.pageLayout().collectAsState()
|
val pageLayout by readerPreferences.pageLayout.collectAsState()
|
||||||
return Preference.PreferenceGroup(
|
return Preference.PreferenceGroup(
|
||||||
title = stringResource(SYMR.strings.pref_category_fork),
|
title = stringResource(SYMR.strings.pref_category_fork),
|
||||||
preferenceItems = persistentListOf(
|
preferenceItems = persistentListOf(
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = readerPreferences.readerInstantRetry(),
|
preference = readerPreferences.readerInstantRetry,
|
||||||
title = stringResource(SYMR.strings.skip_queue_on_retry),
|
title = stringResource(SYMR.strings.skip_queue_on_retry),
|
||||||
subtitle = stringResource(SYMR.strings.skip_queue_on_retry_summary),
|
subtitle = stringResource(SYMR.strings.skip_queue_on_retry_summary),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = readerPreferences.preserveReadingPosition(),
|
preference = readerPreferences.preserveReadingPosition,
|
||||||
title = stringResource(SYMR.strings.preserve_reading_position),
|
title = stringResource(SYMR.strings.preserve_reading_position),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = readerPreferences.useAutoWebtoon(),
|
preference = readerPreferences.useAutoWebtoon,
|
||||||
title = stringResource(SYMR.strings.auto_webtoon_mode),
|
title = stringResource(SYMR.strings.auto_webtoon_mode),
|
||||||
subtitle = stringResource(SYMR.strings.auto_webtoon_mode_summary),
|
subtitle = stringResource(SYMR.strings.auto_webtoon_mode_summary),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.MultiSelectListPreference(
|
Preference.PreferenceItem.MultiSelectListPreference(
|
||||||
preference = readerPreferences.readerBottomButtons(),
|
preference = readerPreferences.readerBottomButtons,
|
||||||
title = stringResource(SYMR.strings.reader_bottom_buttons),
|
title = stringResource(SYMR.strings.reader_bottom_buttons),
|
||||||
subtitle = stringResource(SYMR.strings.reader_bottom_buttons_summary),
|
subtitle = stringResource(SYMR.strings.reader_bottom_buttons_summary),
|
||||||
entries = ReaderBottomButton.entries
|
entries = ReaderBottomButton.entries
|
||||||
@@ -582,7 +582,7 @@ object SettingsReaderScreen : SearchableSettings {
|
|||||||
.toImmutableMap(),
|
.toImmutableMap(),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
preference = readerPreferences.pageLayout(),
|
preference = readerPreferences.pageLayout,
|
||||||
title = stringResource(SYMR.strings.page_layout),
|
title = stringResource(SYMR.strings.page_layout),
|
||||||
subtitle = stringResource(SYMR.strings.automatic_can_still_switch),
|
subtitle = stringResource(SYMR.strings.automatic_can_still_switch),
|
||||||
entries = ReaderPreferences.PageLayouts
|
entries = ReaderPreferences.PageLayouts
|
||||||
@@ -591,12 +591,12 @@ object SettingsReaderScreen : SearchableSettings {
|
|||||||
.toImmutableMap(),
|
.toImmutableMap(),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = readerPreferences.invertDoublePages(),
|
preference = readerPreferences.invertDoublePages,
|
||||||
title = stringResource(SYMR.strings.invert_double_pages),
|
title = stringResource(SYMR.strings.invert_double_pages),
|
||||||
enabled = pageLayout != PagerConfig.PageLayout.SINGLE_PAGE,
|
enabled = pageLayout != PagerConfig.PageLayout.SINGLE_PAGE,
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
preference = readerPreferences.centerMarginType(),
|
preference = readerPreferences.centerMarginType,
|
||||||
title = stringResource(SYMR.strings.center_margin),
|
title = stringResource(SYMR.strings.center_margin),
|
||||||
subtitle = stringResource(SYMR.strings.pref_center_margin_summary),
|
subtitle = stringResource(SYMR.strings.pref_center_margin_summary),
|
||||||
entries = ReaderPreferences.CenterMarginTypes
|
entries = ReaderPreferences.CenterMarginTypes
|
||||||
@@ -605,7 +605,7 @@ object SettingsReaderScreen : SearchableSettings {
|
|||||||
.toImmutableMap(),
|
.toImmutableMap(),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
preference = readerPreferences.archiveReaderMode(),
|
preference = readerPreferences.archiveReaderMode,
|
||||||
title = stringResource(SYMR.strings.pref_archive_reader_mode),
|
title = stringResource(SYMR.strings.pref_archive_reader_mode),
|
||||||
subtitle = stringResource(SYMR.strings.pref_archive_reader_mode_summary),
|
subtitle = stringResource(SYMR.strings.pref_archive_reader_mode_summary),
|
||||||
entries = ReaderPreferences.archiveModeTypes
|
entries = ReaderPreferences.archiveModeTypes
|
||||||
|
|||||||
+14
-14
@@ -85,12 +85,12 @@ object SettingsSecurityScreen : SearchableSettings {
|
|||||||
): Preference.PreferenceGroup {
|
): Preference.PreferenceGroup {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val authSupported = remember { context.isAuthenticationSupported() }
|
val authSupported = remember { context.isAuthenticationSupported() }
|
||||||
val useAuthPref = securityPreferences.useAuthenticator()
|
val useAuthPref = securityPreferences.useAuthenticator
|
||||||
val useAuth by useAuthPref.collectAsState()
|
val useAuth by useAuthPref.collectAsState()
|
||||||
|
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
val isCbzPasswordSet by remember { CbzCrypto.isPasswordSetState(scope) }.collectAsState()
|
val isCbzPasswordSet by remember { CbzCrypto.isPasswordSetState(scope) }.collectAsState()
|
||||||
val passwordProtectDownloads by securityPreferences.passwordProtectDownloads().collectAsState()
|
val passwordProtectDownloads by securityPreferences.passwordProtectDownloads.collectAsState()
|
||||||
|
|
||||||
return Preference.PreferenceGroup(
|
return Preference.PreferenceGroup(
|
||||||
title = stringResource(MR.strings.pref_security),
|
title = stringResource(MR.strings.pref_security),
|
||||||
@@ -106,7 +106,7 @@ object SettingsSecurityScreen : SearchableSettings {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
preference = securityPreferences.lockAppAfter(),
|
preference = securityPreferences.lockAppAfter,
|
||||||
entries = LockAfterValues
|
entries = LockAfterValues
|
||||||
.associateWith {
|
.associateWith {
|
||||||
when (it) {
|
when (it) {
|
||||||
@@ -125,11 +125,11 @@ object SettingsSecurityScreen : SearchableSettings {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = securityPreferences.hideNotificationContent(),
|
preference = securityPreferences.hideNotificationContent,
|
||||||
title = stringResource(MR.strings.hide_notification_content),
|
title = stringResource(MR.strings.hide_notification_content),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
preference = securityPreferences.secureScreen(),
|
preference = securityPreferences.secureScreen,
|
||||||
entries = SecurityPreferences.SecureScreenMode.entries
|
entries = SecurityPreferences.SecureScreenMode.entries
|
||||||
.associateWith { stringResource(it.titleRes) }
|
.associateWith { stringResource(it.titleRes) }
|
||||||
.toImmutableMap(),
|
.toImmutableMap(),
|
||||||
@@ -137,13 +137,13 @@ object SettingsSecurityScreen : SearchableSettings {
|
|||||||
),
|
),
|
||||||
// SY -->
|
// SY -->
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = securityPreferences.passwordProtectDownloads(),
|
preference = securityPreferences.passwordProtectDownloads,
|
||||||
title = stringResource(SYMR.strings.password_protect_downloads),
|
title = stringResource(SYMR.strings.password_protect_downloads),
|
||||||
subtitle = stringResource(SYMR.strings.password_protect_downloads_summary),
|
subtitle = stringResource(SYMR.strings.password_protect_downloads_summary),
|
||||||
enabled = isCbzPasswordSet,
|
enabled = isCbzPasswordSet,
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
preference = securityPreferences.encryptionType(),
|
preference = securityPreferences.encryptionType,
|
||||||
title = stringResource(SYMR.strings.encryption_type),
|
title = stringResource(SYMR.strings.encryption_type),
|
||||||
entries = SecurityPreferences.EncryptionType.entries
|
entries = SecurityPreferences.EncryptionType.entries
|
||||||
.associateWith { stringResource(it.titleRes) }
|
.associateWith { stringResource(it.titleRes) }
|
||||||
@@ -160,7 +160,7 @@ object SettingsSecurityScreen : SearchableSettings {
|
|||||||
dialogOpen = false
|
dialogOpen = false
|
||||||
|
|
||||||
CbzCrypto.deleteKeyCbz()
|
CbzCrypto.deleteKeyCbz()
|
||||||
securityPreferences.cbzPassword().set(CbzCrypto.encryptCbz(password.replace("\n", "")))
|
securityPreferences.cbzPassword.set(CbzCrypto.encryptCbz(password.replace("\n", "")))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -175,13 +175,13 @@ object SettingsSecurityScreen : SearchableSettings {
|
|||||||
title = stringResource(SYMR.strings.delete_cbz_archive_password),
|
title = stringResource(SYMR.strings.delete_cbz_archive_password),
|
||||||
onClick = {
|
onClick = {
|
||||||
CbzCrypto.deleteKeyCbz()
|
CbzCrypto.deleteKeyCbz()
|
||||||
securityPreferences.cbzPassword().set("")
|
securityPreferences.cbzPassword.set("")
|
||||||
},
|
},
|
||||||
enabled = isCbzPasswordSet,
|
enabled = isCbzPasswordSet,
|
||||||
),
|
),
|
||||||
kotlin.run {
|
kotlin.run {
|
||||||
val navigator = LocalNavigator.currentOrThrow
|
val navigator = LocalNavigator.currentOrThrow
|
||||||
val count by securityPreferences.authenticatorTimeRanges().collectAsState()
|
val count by securityPreferences.authenticatorTimeRanges.collectAsState()
|
||||||
Preference.PreferenceItem.TextPreference(
|
Preference.PreferenceItem.TextPreference(
|
||||||
title = stringResource(SYMR.strings.action_edit_biometric_lock_times),
|
title = stringResource(SYMR.strings.action_edit_biometric_lock_times),
|
||||||
subtitle = pluralStringResource(
|
subtitle = pluralStringResource(
|
||||||
@@ -196,7 +196,7 @@ object SettingsSecurityScreen : SearchableSettings {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
kotlin.run {
|
kotlin.run {
|
||||||
val selection by securityPreferences.authenticatorDays().collectAsState()
|
val selection by securityPreferences.authenticatorDays.collectAsState()
|
||||||
var dialogOpen by remember { mutableStateOf(false) }
|
var dialogOpen by remember { mutableStateOf(false) }
|
||||||
if (dialogOpen) {
|
if (dialogOpen) {
|
||||||
SetLockedDaysDialog(
|
SetLockedDaysDialog(
|
||||||
@@ -204,7 +204,7 @@ object SettingsSecurityScreen : SearchableSettings {
|
|||||||
initialSelection = selection,
|
initialSelection = selection,
|
||||||
onDaysSelected = {
|
onDaysSelected = {
|
||||||
dialogOpen = false
|
dialogOpen = false
|
||||||
securityPreferences.authenticatorDays().set(it)
|
securityPreferences.authenticatorDays.set(it)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -384,12 +384,12 @@ object SettingsSecurityScreen : SearchableSettings {
|
|||||||
title = stringResource(MR.strings.pref_firebase),
|
title = stringResource(MR.strings.pref_firebase),
|
||||||
preferenceItems = persistentListOf(
|
preferenceItems = persistentListOf(
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = privacyPreferences.crashlytics(),
|
preference = privacyPreferences.crashlytics,
|
||||||
title = stringResource(MR.strings.onboarding_permission_crashlytics),
|
title = stringResource(MR.strings.onboarding_permission_crashlytics),
|
||||||
subtitle = stringResource(MR.strings.onboarding_permission_crashlytics_description),
|
subtitle = stringResource(MR.strings.onboarding_permission_crashlytics_description),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = privacyPreferences.analytics(),
|
preference = privacyPreferences.analytics,
|
||||||
title = stringResource(MR.strings.onboarding_permission_analytics),
|
title = stringResource(MR.strings.onboarding_permission_analytics),
|
||||||
subtitle = stringResource(MR.strings.onboarding_permission_analytics_description),
|
subtitle = stringResource(MR.strings.onboarding_permission_analytics_description),
|
||||||
),
|
),
|
||||||
|
|||||||
+4
-4
@@ -91,7 +91,7 @@ object SettingsTrackingScreen : SearchableSettings {
|
|||||||
val trackPreferences = remember { Injekt.get<TrackPreferences>() }
|
val trackPreferences = remember { Injekt.get<TrackPreferences>() }
|
||||||
val trackerManager = remember { Injekt.get<TrackerManager>() }
|
val trackerManager = remember { Injekt.get<TrackerManager>() }
|
||||||
val sourceManager = remember { Injekt.get<SourceManager>() }
|
val sourceManager = remember { Injekt.get<SourceManager>() }
|
||||||
val autoTrackStatePref = trackPreferences.autoUpdateTrackOnMarkRead()
|
val autoTrackStatePref = trackPreferences.autoUpdateTrackOnMarkRead
|
||||||
|
|
||||||
var dialog by remember { mutableStateOf<Any?>(null) }
|
var dialog by remember { mutableStateOf<Any?>(null) }
|
||||||
dialog?.run {
|
dialog?.run {
|
||||||
@@ -129,11 +129,11 @@ object SettingsTrackingScreen : SearchableSettings {
|
|||||||
|
|
||||||
return listOf(
|
return listOf(
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = trackPreferences.autoUpdateTrack(),
|
preference = trackPreferences.autoUpdateTrack,
|
||||||
title = stringResource(MR.strings.pref_auto_update_manga_sync),
|
title = stringResource(MR.strings.pref_auto_update_manga_sync),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
preference = trackPreferences.autoUpdateTrackOnMarkRead(),
|
preference = trackPreferences.autoUpdateTrackOnMarkRead,
|
||||||
entries = AutoTrackState.entries
|
entries = AutoTrackState.entries
|
||||||
.associateWith { stringResource(it.titleRes) }
|
.associateWith { stringResource(it.titleRes) }
|
||||||
.toPersistentMap(),
|
.toPersistentMap(),
|
||||||
@@ -141,7 +141,7 @@ object SettingsTrackingScreen : SearchableSettings {
|
|||||||
),
|
),
|
||||||
// SY -->
|
// SY -->
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
preference = trackPreferences.resolveUsingSourceMetadata(),
|
preference = trackPreferences.resolveUsingSourceMetadata,
|
||||||
title = stringResource(SYMR.strings.pref_tracker_resolve_using_source_metadata),
|
title = stringResource(SYMR.strings.pref_tracker_resolve_using_source_metadata),
|
||||||
subtitle = stringResource(SYMR.strings.pref_tracker_resolve_using_source_metadata_summary),
|
subtitle = stringResource(SYMR.strings.pref_tracker_resolve_using_source_metadata_summary),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -297,7 +297,7 @@ object AboutScreen : Screen() {
|
|||||||
)
|
)
|
||||||
.toDateTimestampString(
|
.toDateTimestampString(
|
||||||
UiPreferences.dateFormat(
|
UiPreferences.dateFormat(
|
||||||
Injekt.get<UiPreferences>().dateFormat().get(),
|
Injekt.get<UiPreferences>().dateFormat.get(),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
|||||||
@@ -9,12 +9,18 @@ import androidx.compose.material3.LinearProgressIndicator
|
|||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import tachiyomi.presentation.core.components.material.padding
|
import tachiyomi.presentation.core.components.material.padding
|
||||||
import tachiyomi.presentation.core.i18n.stringResource
|
import tachiyomi.presentation.core.i18n.stringResource
|
||||||
@@ -45,10 +51,24 @@ private fun StorageInfo(
|
|||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
val available = remember(file) { DiskUtil.getAvailableStorageSpace(file) }
|
var available by remember(file) { mutableStateOf(-1L) }
|
||||||
val availableText = remember(available) { Formatter.formatFileSize(context, available) }
|
var total by remember(file) { mutableStateOf(-1L) }
|
||||||
val total = remember(file) { DiskUtil.getTotalStorageSpace(file) }
|
|
||||||
val totalText = remember(total) { Formatter.formatFileSize(context, total) }
|
LaunchedEffect(file) {
|
||||||
|
available = withContext(Dispatchers.IO) { DiskUtil.getAvailableStorageSpace(file) }
|
||||||
|
total = withContext(Dispatchers.IO) { DiskUtil.getTotalStorageSpace(file) }
|
||||||
|
}
|
||||||
|
|
||||||
|
val availableText = if (available == -1L) {
|
||||||
|
stringResource(MR.strings.calculating)
|
||||||
|
} else {
|
||||||
|
Formatter.formatFileSize(context, available)
|
||||||
|
}
|
||||||
|
val totalText = if (total == -1L) {
|
||||||
|
stringResource(MR.strings.calculating)
|
||||||
|
} else {
|
||||||
|
Formatter.formatFileSize(context, total)
|
||||||
|
}
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
verticalArrangement = Arrangement.spacedBy(MaterialTheme.padding.extraSmall),
|
verticalArrangement = Arrangement.spacedBy(MaterialTheme.padding.extraSmall),
|
||||||
@@ -58,13 +78,15 @@ private fun StorageInfo(
|
|||||||
style = MaterialTheme.typography.header,
|
style = MaterialTheme.typography.header,
|
||||||
)
|
)
|
||||||
|
|
||||||
LinearProgressIndicator(
|
if (total > 0) {
|
||||||
modifier = Modifier
|
LinearProgressIndicator(
|
||||||
.clip(MaterialTheme.shapes.small)
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.clip(MaterialTheme.shapes.small)
|
||||||
.height(12.dp),
|
.fillMaxWidth()
|
||||||
progress = { (1 - (available / total.toFloat())) },
|
.height(12.dp),
|
||||||
)
|
progress = { (1 - (available / total.toFloat())) },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(MR.strings.available_disk_space_info, availableText, totalText),
|
text = stringResource(MR.strings.available_disk_space_info, availableText, totalText),
|
||||||
|
|||||||
+42
@@ -1,24 +1,38 @@
|
|||||||
package eu.kanade.presentation.more.settings.screen.debug
|
package eu.kanade.presentation.more.settings.screen.debug
|
||||||
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.outlined.Autorenew
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.ReadOnlyComposable
|
import androidx.compose.runtime.ReadOnlyComposable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.produceState
|
import androidx.compose.runtime.produceState
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.profileinstaller.ProfileVerifier
|
import androidx.profileinstaller.ProfileVerifier
|
||||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||||
|
import eu.kanade.domain.base.BasePreferences
|
||||||
import eu.kanade.presentation.more.settings.Preference
|
import eu.kanade.presentation.more.settings.Preference
|
||||||
import eu.kanade.presentation.more.settings.PreferenceScaffold
|
import eu.kanade.presentation.more.settings.PreferenceScaffold
|
||||||
import eu.kanade.presentation.more.settings.screen.about.AboutScreen
|
import eu.kanade.presentation.more.settings.screen.about.AboutScreen
|
||||||
import eu.kanade.presentation.util.Screen
|
import eu.kanade.presentation.util.Screen
|
||||||
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
||||||
import eu.kanade.tachiyomi.util.system.WebViewUtil
|
import eu.kanade.tachiyomi.util.system.WebViewUtil
|
||||||
|
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||||
import kotlinx.collections.immutable.mutate
|
import kotlinx.collections.immutable.mutate
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.coroutines.guava.await
|
import kotlinx.coroutines.guava.await
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import mihon.core.common.FeatureFlags
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
|
import tachiyomi.presentation.core.util.collectAsState
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
class DebugInfoScreen : Screen() {
|
class DebugInfoScreen : Screen() {
|
||||||
|
|
||||||
@@ -47,6 +61,12 @@ class DebugInfoScreen : Screen() {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun getAppInfoGroup(): Preference.PreferenceGroup {
|
private fun getAppInfoGroup(): Preference.PreferenceGroup {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
|
val installationIdPref = remember { Injekt.get<BasePreferences>().installationId }
|
||||||
|
val installationId by installationIdPref.collectAsState()
|
||||||
|
|
||||||
return Preference.PreferenceGroup(
|
return Preference.PreferenceGroup(
|
||||||
title = "App info",
|
title = "App info",
|
||||||
preferenceItems = persistentListOf(
|
preferenceItems = persistentListOf(
|
||||||
@@ -58,6 +78,28 @@ class DebugInfoScreen : Screen() {
|
|||||||
title = "Build time",
|
title = "Build time",
|
||||||
subtitle = AboutScreen.getFormattedBuildTime(),
|
subtitle = AboutScreen.getFormattedBuildTime(),
|
||||||
),
|
),
|
||||||
|
Preference.PreferenceItem.TextPreference(
|
||||||
|
title = "Installation ID",
|
||||||
|
subtitle = installationId,
|
||||||
|
widget = {
|
||||||
|
IconButton(
|
||||||
|
onClick = {
|
||||||
|
scope.launch {
|
||||||
|
installationIdPref.set(FeatureFlags.newInstallationId())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Outlined.Autorenew,
|
||||||
|
tint = MaterialTheme.colorScheme.primary,
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onClick = {
|
||||||
|
context.copyToClipboard(installationId, installationId)
|
||||||
|
},
|
||||||
|
),
|
||||||
getProfileVerifierPreference(),
|
getProfileVerifierPreference(),
|
||||||
Preference.PreferenceItem.TextPreference(
|
Preference.PreferenceItem.TextPreference(
|
||||||
title = "WebView version",
|
title = "WebView version",
|
||||||
|
|||||||
+1
-1
@@ -156,7 +156,7 @@ class WorkerInfoScreen : Screen() {
|
|||||||
)
|
)
|
||||||
.toDateTimestampString(
|
.toDateTimestampString(
|
||||||
UiPreferences.dateFormat(
|
UiPreferences.dateFormat(
|
||||||
Injekt.get<UiPreferences>().dateFormat().get(),
|
Injekt.get<UiPreferences>().dateFormat.get(),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
appendLine("Next scheduled run: $timestamp")
|
appendLine("Next scheduled run: $timestamp")
|
||||||
|
|||||||
@@ -24,10 +24,10 @@ class DisplayRefreshHost {
|
|||||||
internal var currentDisplayRefresh by mutableStateOf(false)
|
internal var currentDisplayRefresh by mutableStateOf(false)
|
||||||
private val readerPreferences = Injekt.get<ReaderPreferences>()
|
private val readerPreferences = Injekt.get<ReaderPreferences>()
|
||||||
|
|
||||||
internal val flashMillis = readerPreferences.flashDurationMillis()
|
internal val flashMillis = readerPreferences.flashDurationMillis
|
||||||
internal val flashMode = readerPreferences.flashColor()
|
internal val flashMode = readerPreferences.flashColor
|
||||||
|
|
||||||
internal val flashIntervalPref = readerPreferences.flashPageInterval()
|
internal val flashIntervalPref = readerPreferences.flashPageInterval
|
||||||
|
|
||||||
// Internal State for Flash
|
// Internal State for Flash
|
||||||
private var flashInterval = flashIntervalPref.get()
|
private var flashInterval = flashIntervalPref.get()
|
||||||
|
|||||||
@@ -22,10 +22,10 @@ import tachiyomi.presentation.core.util.collectAsState
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun ColumnScope.ColorFilterPage(screenModel: ReaderSettingsScreenModel) {
|
internal fun ColumnScope.ColorFilterPage(screenModel: ReaderSettingsScreenModel) {
|
||||||
val customBrightness by screenModel.preferences.customBrightness().collectAsState()
|
val customBrightness by screenModel.preferences.customBrightness.collectAsState()
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(MR.strings.pref_custom_brightness),
|
label = stringResource(MR.strings.pref_custom_brightness),
|
||||||
pref = screenModel.preferences.customBrightness(),
|
pref = screenModel.preferences.customBrightness,
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -35,31 +35,31 @@ internal fun ColumnScope.ColorFilterPage(screenModel: ReaderSettingsScreenModel)
|
|||||||
* 0 sets system brightness and hides the overlay.
|
* 0 sets system brightness and hides the overlay.
|
||||||
*/
|
*/
|
||||||
if (customBrightness) {
|
if (customBrightness) {
|
||||||
val customBrightnessValue by screenModel.preferences.customBrightnessValue().collectAsState()
|
val customBrightnessValue by screenModel.preferences.customBrightnessValue.collectAsState()
|
||||||
SliderItem(
|
SliderItem(
|
||||||
value = customBrightnessValue,
|
value = customBrightnessValue,
|
||||||
valueRange = -75..100,
|
valueRange = -75..100,
|
||||||
steps = 0,
|
steps = 0,
|
||||||
label = stringResource(MR.strings.pref_custom_brightness),
|
label = stringResource(MR.strings.pref_custom_brightness),
|
||||||
onChange = { screenModel.preferences.customBrightnessValue().set(it) },
|
onChange = { screenModel.preferences.customBrightnessValue.set(it) },
|
||||||
pillColor = MaterialTheme.colorScheme.surfaceContainerHighest,
|
pillColor = MaterialTheme.colorScheme.surfaceContainerHighest,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val colorFilter by screenModel.preferences.colorFilter().collectAsState()
|
val colorFilter by screenModel.preferences.colorFilter.collectAsState()
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(MR.strings.pref_custom_color_filter),
|
label = stringResource(MR.strings.pref_custom_color_filter),
|
||||||
pref = screenModel.preferences.colorFilter(),
|
pref = screenModel.preferences.colorFilter,
|
||||||
)
|
)
|
||||||
if (colorFilter) {
|
if (colorFilter) {
|
||||||
val colorFilterValue by screenModel.preferences.colorFilterValue().collectAsState()
|
val colorFilterValue by screenModel.preferences.colorFilterValue.collectAsState()
|
||||||
SliderItem(
|
SliderItem(
|
||||||
value = colorFilterValue.red,
|
value = colorFilterValue.red,
|
||||||
valueRange = 0..255,
|
valueRange = 0..255,
|
||||||
steps = 0,
|
steps = 0,
|
||||||
label = stringResource(MR.strings.color_filter_r_value),
|
label = stringResource(MR.strings.color_filter_r_value),
|
||||||
onChange = { newRValue ->
|
onChange = { newRValue ->
|
||||||
screenModel.preferences.colorFilterValue().getAndSet {
|
screenModel.preferences.colorFilterValue.getAndSet {
|
||||||
getColorValue(it, newRValue, RED_MASK, 16)
|
getColorValue(it, newRValue, RED_MASK, 16)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -71,7 +71,7 @@ internal fun ColumnScope.ColorFilterPage(screenModel: ReaderSettingsScreenModel)
|
|||||||
steps = 0,
|
steps = 0,
|
||||||
label = stringResource(MR.strings.color_filter_g_value),
|
label = stringResource(MR.strings.color_filter_g_value),
|
||||||
onChange = { newGValue ->
|
onChange = { newGValue ->
|
||||||
screenModel.preferences.colorFilterValue().getAndSet {
|
screenModel.preferences.colorFilterValue.getAndSet {
|
||||||
getColorValue(it, newGValue, GREEN_MASK, 8)
|
getColorValue(it, newGValue, GREEN_MASK, 8)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -83,7 +83,7 @@ internal fun ColumnScope.ColorFilterPage(screenModel: ReaderSettingsScreenModel)
|
|||||||
steps = 0,
|
steps = 0,
|
||||||
label = stringResource(MR.strings.color_filter_b_value),
|
label = stringResource(MR.strings.color_filter_b_value),
|
||||||
onChange = { newBValue ->
|
onChange = { newBValue ->
|
||||||
screenModel.preferences.colorFilterValue().getAndSet {
|
screenModel.preferences.colorFilterValue.getAndSet {
|
||||||
getColorValue(it, newBValue, BLUE_MASK, 0)
|
getColorValue(it, newBValue, BLUE_MASK, 0)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -95,19 +95,19 @@ internal fun ColumnScope.ColorFilterPage(screenModel: ReaderSettingsScreenModel)
|
|||||||
steps = 0,
|
steps = 0,
|
||||||
label = stringResource(MR.strings.color_filter_a_value),
|
label = stringResource(MR.strings.color_filter_a_value),
|
||||||
onChange = { newAValue ->
|
onChange = { newAValue ->
|
||||||
screenModel.preferences.colorFilterValue().getAndSet {
|
screenModel.preferences.colorFilterValue.getAndSet {
|
||||||
getColorValue(it, newAValue, ALPHA_MASK, 24)
|
getColorValue(it, newAValue, ALPHA_MASK, 24)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
pillColor = MaterialTheme.colorScheme.surfaceContainerHighest,
|
pillColor = MaterialTheme.colorScheme.surfaceContainerHighest,
|
||||||
)
|
)
|
||||||
|
|
||||||
val colorFilterMode by screenModel.preferences.colorFilterMode().collectAsState()
|
val colorFilterMode by screenModel.preferences.colorFilterMode.collectAsState()
|
||||||
SettingsChipRow(MR.strings.pref_color_filter_mode) {
|
SettingsChipRow(MR.strings.pref_color_filter_mode) {
|
||||||
ColorFilterMode.mapIndexed { index, it ->
|
ColorFilterMode.mapIndexed { index, it ->
|
||||||
FilterChip(
|
FilterChip(
|
||||||
selected = colorFilterMode == index,
|
selected = colorFilterMode == index,
|
||||||
onClick = { screenModel.preferences.colorFilterMode().set(index) },
|
onClick = { screenModel.preferences.colorFilterMode.set(index) },
|
||||||
label = { Text(stringResource(it.first)) },
|
label = { Text(stringResource(it.first)) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -116,11 +116,11 @@ internal fun ColumnScope.ColorFilterPage(screenModel: ReaderSettingsScreenModel)
|
|||||||
|
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(MR.strings.pref_grayscale),
|
label = stringResource(MR.strings.pref_grayscale),
|
||||||
pref = screenModel.preferences.grayscale(),
|
pref = screenModel.preferences.grayscale,
|
||||||
)
|
)
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(MR.strings.pref_inverted_colors),
|
label = stringResource(MR.strings.pref_inverted_colors),
|
||||||
pref = screenModel.preferences.invertedColors(),
|
pref = screenModel.preferences.invertedColors,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,24 +34,24 @@ private val flashColors = listOf(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun ColumnScope.GeneralPage(screenModel: ReaderSettingsScreenModel) {
|
internal fun ColumnScope.GeneralPage(screenModel: ReaderSettingsScreenModel) {
|
||||||
val readerTheme by screenModel.preferences.readerTheme().collectAsState()
|
val readerTheme by screenModel.preferences.readerTheme.collectAsState()
|
||||||
|
|
||||||
val flashPageState by screenModel.preferences.flashOnPageChange().collectAsState()
|
val flashPageState by screenModel.preferences.flashOnPageChange.collectAsState()
|
||||||
|
|
||||||
val flashMillisPref = screenModel.preferences.flashDurationMillis()
|
val flashMillisPref = screenModel.preferences.flashDurationMillis
|
||||||
val flashMillis by flashMillisPref.collectAsState()
|
val flashMillis by flashMillisPref.collectAsState()
|
||||||
|
|
||||||
val flashIntervalPref = screenModel.preferences.flashPageInterval()
|
val flashIntervalPref = screenModel.preferences.flashPageInterval
|
||||||
val flashInterval by flashIntervalPref.collectAsState()
|
val flashInterval by flashIntervalPref.collectAsState()
|
||||||
|
|
||||||
val flashColorPref = screenModel.preferences.flashColor()
|
val flashColorPref = screenModel.preferences.flashColor
|
||||||
val flashColor by flashColorPref.collectAsState()
|
val flashColor by flashColorPref.collectAsState()
|
||||||
|
|
||||||
SettingsChipRow(MR.strings.pref_reader_theme) {
|
SettingsChipRow(MR.strings.pref_reader_theme) {
|
||||||
themes.map { (labelRes, value) ->
|
themes.map { (labelRes, value) ->
|
||||||
FilterChip(
|
FilterChip(
|
||||||
selected = readerTheme == value,
|
selected = readerTheme == value,
|
||||||
onClick = { screenModel.preferences.readerTheme().set(value) },
|
onClick = { screenModel.preferences.readerTheme.set(value) },
|
||||||
label = { Text(stringResource(labelRes)) },
|
label = { Text(stringResource(labelRes)) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -59,66 +59,66 @@ internal fun ColumnScope.GeneralPage(screenModel: ReaderSettingsScreenModel) {
|
|||||||
|
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(MR.strings.pref_show_page_number),
|
label = stringResource(MR.strings.pref_show_page_number),
|
||||||
pref = screenModel.preferences.showPageNumber(),
|
pref = screenModel.preferences.showPageNumber,
|
||||||
)
|
)
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
val forceHorizontalSeekbar by screenModel.preferences.forceHorizontalSeekbar().collectAsState()
|
val forceHorizontalSeekbar by screenModel.preferences.forceHorizontalSeekbar.collectAsState()
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(SYMR.strings.pref_force_horz_seekbar),
|
label = stringResource(SYMR.strings.pref_force_horz_seekbar),
|
||||||
pref = screenModel.preferences.forceHorizontalSeekbar(),
|
pref = screenModel.preferences.forceHorizontalSeekbar,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!forceHorizontalSeekbar) {
|
if (!forceHorizontalSeekbar) {
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(SYMR.strings.pref_show_vert_seekbar_landscape),
|
label = stringResource(SYMR.strings.pref_show_vert_seekbar_landscape),
|
||||||
pref = screenModel.preferences.landscapeVerticalSeekbar(),
|
pref = screenModel.preferences.landscapeVerticalSeekbar,
|
||||||
)
|
)
|
||||||
|
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(SYMR.strings.pref_left_handed_vertical_seekbar),
|
label = stringResource(SYMR.strings.pref_left_handed_vertical_seekbar),
|
||||||
pref = screenModel.preferences.leftVerticalSeekbar(),
|
pref = screenModel.preferences.leftVerticalSeekbar,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(MR.strings.pref_fullscreen),
|
label = stringResource(MR.strings.pref_fullscreen),
|
||||||
pref = screenModel.preferences.fullscreen(),
|
pref = screenModel.preferences.fullscreen,
|
||||||
)
|
)
|
||||||
|
|
||||||
val isFullscreen by screenModel.preferences.fullscreen().collectAsState()
|
val isFullscreen by screenModel.preferences.fullscreen.collectAsState()
|
||||||
if (LocalActivity.current?.hasDisplayCutout() == true && isFullscreen) {
|
if (LocalActivity.current?.hasDisplayCutout() == true && isFullscreen) {
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(MR.strings.pref_cutout_short),
|
label = stringResource(MR.strings.pref_cutout_short),
|
||||||
pref = screenModel.preferences.drawUnderCutout(),
|
pref = screenModel.preferences.drawUnderCutout,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(MR.strings.pref_keep_screen_on),
|
label = stringResource(MR.strings.pref_keep_screen_on),
|
||||||
pref = screenModel.preferences.keepScreenOn(),
|
pref = screenModel.preferences.keepScreenOn,
|
||||||
)
|
)
|
||||||
|
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(MR.strings.pref_read_with_long_tap),
|
label = stringResource(MR.strings.pref_read_with_long_tap),
|
||||||
pref = screenModel.preferences.readWithLongTap(),
|
pref = screenModel.preferences.readWithLongTap,
|
||||||
)
|
)
|
||||||
|
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(MR.strings.pref_always_show_chapter_transition),
|
label = stringResource(MR.strings.pref_always_show_chapter_transition),
|
||||||
pref = screenModel.preferences.alwaysShowChapterTransition(),
|
pref = screenModel.preferences.alwaysShowChapterTransition,
|
||||||
)
|
)
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
/*CheckboxItem(
|
/*CheckboxItem(
|
||||||
label = stringResource(MR.strings.pref_page_transitions),
|
label = stringResource(MR.strings.pref_page_transitions),
|
||||||
pref = screenModel.preferences.pageTransitions(),
|
pref = screenModel.preferences.pageTransitions,
|
||||||
) SY <-- */
|
) SY <-- */
|
||||||
|
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(MR.strings.pref_flash_page),
|
label = stringResource(MR.strings.pref_flash_page),
|
||||||
pref = screenModel.preferences.flashOnPageChange(),
|
pref = screenModel.preferences.flashOnPageChange,
|
||||||
)
|
)
|
||||||
if (flashPageState) {
|
if (flashPageState) {
|
||||||
SliderItem(
|
SliderItem(
|
||||||
@@ -153,7 +153,7 @@ internal fun ColumnScope.GeneralPage(screenModel: ReaderSettingsScreenModel) {
|
|||||||
// SY -->
|
// SY -->
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(SYMR.strings.auto_webtoon_mode),
|
label = stringResource(SYMR.strings.auto_webtoon_mode),
|
||||||
pref = screenModel.preferences.useAutoWebtoon(),
|
pref = screenModel.preferences.useAutoWebtoon,
|
||||||
)
|
)
|
||||||
// SY <--
|
// SY <--
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,44 +67,44 @@ internal fun ColumnScope.ReadingModePage(screenModel: ReaderSettingsScreenModel)
|
|||||||
private fun ColumnScope.PagerViewerSettings(screenModel: ReaderSettingsScreenModel) {
|
private fun ColumnScope.PagerViewerSettings(screenModel: ReaderSettingsScreenModel) {
|
||||||
HeadingItem(MR.strings.pager_viewer)
|
HeadingItem(MR.strings.pager_viewer)
|
||||||
|
|
||||||
val navigationModePager by screenModel.preferences.navigationModePager().collectAsState()
|
val navigationModePager by screenModel.preferences.navigationModePager.collectAsState()
|
||||||
val pagerNavInverted by screenModel.preferences.pagerNavInverted().collectAsState()
|
val pagerNavInverted by screenModel.preferences.pagerNavInverted.collectAsState()
|
||||||
TapZonesItems(
|
TapZonesItems(
|
||||||
selected = navigationModePager,
|
selected = navigationModePager,
|
||||||
onSelect = screenModel.preferences.navigationModePager()::set,
|
onSelect = screenModel.preferences.navigationModePager::set,
|
||||||
invertMode = pagerNavInverted,
|
invertMode = pagerNavInverted,
|
||||||
onSelectInvertMode = screenModel.preferences.pagerNavInverted()::set,
|
onSelectInvertMode = screenModel.preferences.pagerNavInverted::set,
|
||||||
)
|
)
|
||||||
|
|
||||||
val imageScaleType by screenModel.preferences.imageScaleType().collectAsState()
|
val imageScaleType by screenModel.preferences.imageScaleType.collectAsState()
|
||||||
SettingsChipRow(MR.strings.pref_image_scale_type) {
|
SettingsChipRow(MR.strings.pref_image_scale_type) {
|
||||||
ReaderPreferences.ImageScaleType.mapIndexed { index, it ->
|
ReaderPreferences.ImageScaleType.mapIndexed { index, it ->
|
||||||
FilterChip(
|
FilterChip(
|
||||||
selected = imageScaleType == index + 1,
|
selected = imageScaleType == index + 1,
|
||||||
onClick = { screenModel.preferences.imageScaleType().set(index + 1) },
|
onClick = { screenModel.preferences.imageScaleType.set(index + 1) },
|
||||||
label = { Text(stringResource(it)) },
|
label = { Text(stringResource(it)) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val zoomStart by screenModel.preferences.zoomStart().collectAsState()
|
val zoomStart by screenModel.preferences.zoomStart.collectAsState()
|
||||||
SettingsChipRow(MR.strings.pref_zoom_start) {
|
SettingsChipRow(MR.strings.pref_zoom_start) {
|
||||||
ReaderPreferences.ZoomStart.mapIndexed { index, it ->
|
ReaderPreferences.ZoomStart.mapIndexed { index, it ->
|
||||||
FilterChip(
|
FilterChip(
|
||||||
selected = zoomStart == index + 1,
|
selected = zoomStart == index + 1,
|
||||||
onClick = { screenModel.preferences.zoomStart().set(index + 1) },
|
onClick = { screenModel.preferences.zoomStart.set(index + 1) },
|
||||||
label = { Text(stringResource(it)) },
|
label = { Text(stringResource(it)) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
val pageLayout by screenModel.preferences.pageLayout().collectAsState()
|
val pageLayout by screenModel.preferences.pageLayout.collectAsState()
|
||||||
SettingsChipRow(SYMR.strings.page_layout) {
|
SettingsChipRow(SYMR.strings.page_layout) {
|
||||||
ReaderPreferences.PageLayouts.mapIndexed { index, it ->
|
ReaderPreferences.PageLayouts.mapIndexed { index, it ->
|
||||||
FilterChip(
|
FilterChip(
|
||||||
selected = pageLayout == index,
|
selected = pageLayout == index,
|
||||||
onClick = { screenModel.preferences.pageLayout().set(index) },
|
onClick = { screenModel.preferences.pageLayout.set(index) },
|
||||||
label = { Text(stringResource(it)) },
|
label = { Text(stringResource(it)) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -113,62 +113,62 @@ private fun ColumnScope.PagerViewerSettings(screenModel: ReaderSettingsScreenMod
|
|||||||
|
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(MR.strings.pref_crop_borders),
|
label = stringResource(MR.strings.pref_crop_borders),
|
||||||
pref = screenModel.preferences.cropBorders(),
|
pref = screenModel.preferences.cropBorders,
|
||||||
)
|
)
|
||||||
|
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(MR.strings.pref_landscape_zoom),
|
label = stringResource(MR.strings.pref_landscape_zoom),
|
||||||
pref = screenModel.preferences.landscapeZoom(),
|
pref = screenModel.preferences.landscapeZoom,
|
||||||
)
|
)
|
||||||
|
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(MR.strings.pref_navigate_pan),
|
label = stringResource(MR.strings.pref_navigate_pan),
|
||||||
pref = screenModel.preferences.navigateToPan(),
|
pref = screenModel.preferences.navigateToPan,
|
||||||
)
|
)
|
||||||
|
|
||||||
val dualPageSplitPaged by screenModel.preferences.dualPageSplitPaged().collectAsState()
|
val dualPageSplitPaged by screenModel.preferences.dualPageSplitPaged.collectAsState()
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(MR.strings.pref_dual_page_split),
|
label = stringResource(MR.strings.pref_dual_page_split),
|
||||||
pref = screenModel.preferences.dualPageSplitPaged(),
|
pref = screenModel.preferences.dualPageSplitPaged,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (dualPageSplitPaged) {
|
if (dualPageSplitPaged) {
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(MR.strings.pref_dual_page_invert),
|
label = stringResource(MR.strings.pref_dual_page_invert),
|
||||||
pref = screenModel.preferences.dualPageInvertPaged(),
|
pref = screenModel.preferences.dualPageInvertPaged,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val dualPageRotateToFit by screenModel.preferences.dualPageRotateToFit().collectAsState()
|
val dualPageRotateToFit by screenModel.preferences.dualPageRotateToFit.collectAsState()
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(MR.strings.pref_page_rotate),
|
label = stringResource(MR.strings.pref_page_rotate),
|
||||||
pref = screenModel.preferences.dualPageRotateToFit(),
|
pref = screenModel.preferences.dualPageRotateToFit,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (dualPageRotateToFit) {
|
if (dualPageRotateToFit) {
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(MR.strings.pref_page_rotate_invert),
|
label = stringResource(MR.strings.pref_page_rotate_invert),
|
||||||
pref = screenModel.preferences.dualPageRotateToFitInvert(),
|
pref = screenModel.preferences.dualPageRotateToFitInvert,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(MR.strings.pref_page_transitions),
|
label = stringResource(MR.strings.pref_page_transitions),
|
||||||
pref = screenModel.preferences.pageTransitionsPager(),
|
pref = screenModel.preferences.pageTransitionsPager,
|
||||||
)
|
)
|
||||||
|
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(SYMR.strings.invert_double_pages),
|
label = stringResource(SYMR.strings.invert_double_pages),
|
||||||
pref = screenModel.preferences.invertDoublePages(),
|
pref = screenModel.preferences.invertDoublePages,
|
||||||
)
|
)
|
||||||
|
|
||||||
val centerMarginType by screenModel.preferences.centerMarginType().collectAsState()
|
val centerMarginType by screenModel.preferences.centerMarginType.collectAsState()
|
||||||
SettingsChipRow(SYMR.strings.pref_center_margin) {
|
SettingsChipRow(SYMR.strings.pref_center_margin) {
|
||||||
ReaderPreferences.CenterMarginTypes.mapIndexed { index, it ->
|
ReaderPreferences.CenterMarginTypes.mapIndexed { index, it ->
|
||||||
FilterChip(
|
FilterChip(
|
||||||
selected = centerMarginType == index,
|
selected = centerMarginType == index,
|
||||||
onClick = { screenModel.preferences.centerMarginType().set(index) },
|
onClick = { screenModel.preferences.centerMarginType.set(index) },
|
||||||
label = { Text(stringResource(it)) },
|
label = { Text(stringResource(it)) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -182,77 +182,77 @@ private fun ColumnScope.WebtoonViewerSettings(screenModel: ReaderSettingsScreenM
|
|||||||
|
|
||||||
HeadingItem(MR.strings.webtoon_viewer)
|
HeadingItem(MR.strings.webtoon_viewer)
|
||||||
|
|
||||||
val navigationModeWebtoon by screenModel.preferences.navigationModeWebtoon().collectAsState()
|
val navigationModeWebtoon by screenModel.preferences.navigationModeWebtoon.collectAsState()
|
||||||
val webtoonNavInverted by screenModel.preferences.webtoonNavInverted().collectAsState()
|
val webtoonNavInverted by screenModel.preferences.webtoonNavInverted.collectAsState()
|
||||||
TapZonesItems(
|
TapZonesItems(
|
||||||
selected = navigationModeWebtoon,
|
selected = navigationModeWebtoon,
|
||||||
onSelect = screenModel.preferences.navigationModeWebtoon()::set,
|
onSelect = screenModel.preferences.navigationModeWebtoon::set,
|
||||||
invertMode = webtoonNavInverted,
|
invertMode = webtoonNavInverted,
|
||||||
onSelectInvertMode = screenModel.preferences.webtoonNavInverted()::set,
|
onSelectInvertMode = screenModel.preferences.webtoonNavInverted::set,
|
||||||
)
|
)
|
||||||
|
|
||||||
val webtoonSidePadding by screenModel.preferences.webtoonSidePadding().collectAsState()
|
val webtoonSidePadding by screenModel.preferences.webtoonSidePadding.collectAsState()
|
||||||
SliderItem(
|
SliderItem(
|
||||||
value = webtoonSidePadding,
|
value = webtoonSidePadding,
|
||||||
valueRange = ReaderPreferences.let { it.WEBTOON_PADDING_MIN..it.WEBTOON_PADDING_MAX },
|
valueRange = ReaderPreferences.let { it.WEBTOON_PADDING_MIN..it.WEBTOON_PADDING_MAX },
|
||||||
label = stringResource(MR.strings.pref_webtoon_side_padding),
|
label = stringResource(MR.strings.pref_webtoon_side_padding),
|
||||||
valueString = numberFormat.format(webtoonSidePadding / 100f),
|
valueString = numberFormat.format(webtoonSidePadding / 100f),
|
||||||
onChange = {
|
onChange = {
|
||||||
screenModel.preferences.webtoonSidePadding().set(it)
|
screenModel.preferences.webtoonSidePadding.set(it)
|
||||||
},
|
},
|
||||||
pillColor = MaterialTheme.colorScheme.surfaceContainerHighest,
|
pillColor = MaterialTheme.colorScheme.surfaceContainerHighest,
|
||||||
)
|
)
|
||||||
|
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(MR.strings.pref_crop_borders),
|
label = stringResource(MR.strings.pref_crop_borders),
|
||||||
pref = screenModel.preferences.cropBordersWebtoon(),
|
pref = screenModel.preferences.cropBordersWebtoon,
|
||||||
)
|
)
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(SYMR.strings.pref_smooth_scroll),
|
label = stringResource(SYMR.strings.pref_smooth_scroll),
|
||||||
pref = screenModel.preferences.smoothAutoScroll(),
|
pref = screenModel.preferences.smoothAutoScroll,
|
||||||
)
|
)
|
||||||
|
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(MR.strings.pref_page_transitions),
|
label = stringResource(MR.strings.pref_page_transitions),
|
||||||
pref = screenModel.preferences.pageTransitionsWebtoon(),
|
pref = screenModel.preferences.pageTransitionsWebtoon,
|
||||||
)
|
)
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
val dualPageSplitWebtoon by screenModel.preferences.dualPageSplitWebtoon().collectAsState()
|
val dualPageSplitWebtoon by screenModel.preferences.dualPageSplitWebtoon.collectAsState()
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(MR.strings.pref_dual_page_split),
|
label = stringResource(MR.strings.pref_dual_page_split),
|
||||||
pref = screenModel.preferences.dualPageSplitWebtoon(),
|
pref = screenModel.preferences.dualPageSplitWebtoon,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (dualPageSplitWebtoon) {
|
if (dualPageSplitWebtoon) {
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(MR.strings.pref_dual_page_invert),
|
label = stringResource(MR.strings.pref_dual_page_invert),
|
||||||
pref = screenModel.preferences.dualPageInvertWebtoon(),
|
pref = screenModel.preferences.dualPageInvertWebtoon,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val dualPageRotateToFitWebtoon by screenModel.preferences.dualPageRotateToFitWebtoon().collectAsState()
|
val dualPageRotateToFitWebtoon by screenModel.preferences.dualPageRotateToFitWebtoon.collectAsState()
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(MR.strings.pref_page_rotate),
|
label = stringResource(MR.strings.pref_page_rotate),
|
||||||
pref = screenModel.preferences.dualPageRotateToFitWebtoon(),
|
pref = screenModel.preferences.dualPageRotateToFitWebtoon,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (dualPageRotateToFitWebtoon) {
|
if (dualPageRotateToFitWebtoon) {
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(MR.strings.pref_page_rotate_invert),
|
label = stringResource(MR.strings.pref_page_rotate_invert),
|
||||||
pref = screenModel.preferences.dualPageRotateToFitInvertWebtoon(),
|
pref = screenModel.preferences.dualPageRotateToFitInvertWebtoon,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(MR.strings.pref_double_tap_zoom),
|
label = stringResource(MR.strings.pref_double_tap_zoom),
|
||||||
pref = screenModel.preferences.webtoonDoubleTapZoomEnabled(),
|
pref = screenModel.preferences.webtoonDoubleTapZoomEnabled,
|
||||||
)
|
)
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(MR.strings.pref_webtoon_disable_zoom_out),
|
label = stringResource(MR.strings.pref_webtoon_disable_zoom_out),
|
||||||
pref = screenModel.preferences.webtoonDisableZoomOut(),
|
pref = screenModel.preferences.webtoonDisableZoomOut,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,7 +263,7 @@ private fun ColumnScope.WebtoonWithGapsViewerSettings(screenModel: ReaderSetting
|
|||||||
|
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
label = stringResource(MR.strings.pref_crop_borders),
|
label = stringResource(MR.strings.pref_crop_borders),
|
||||||
pref = screenModel.preferences.cropBordersContinuousVertical(),
|
pref = screenModel.preferences.cropBordersContinuousVertical,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ fun TachiyomiTheme(
|
|||||||
) {
|
) {
|
||||||
val uiPreferences = Injekt.get<UiPreferences>()
|
val uiPreferences = Injekt.get<UiPreferences>()
|
||||||
BaseTachiyomiTheme(
|
BaseTachiyomiTheme(
|
||||||
appTheme = appTheme ?: uiPreferences.appTheme().get(),
|
appTheme = appTheme ?: uiPreferences.appTheme.get(),
|
||||||
isAmoled = amoled ?: uiPreferences.themeDarkAmoled().get(),
|
isAmoled = amoled ?: uiPreferences.themeDarkAmoled.get(),
|
||||||
content = content,
|
content = content,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,28 +55,28 @@ fun UpdatesFilterDialog(
|
|||||||
private fun ColumnScope.FilterSheet(
|
private fun ColumnScope.FilterSheet(
|
||||||
screenModel: UpdatesSettingsScreenModel,
|
screenModel: UpdatesSettingsScreenModel,
|
||||||
) {
|
) {
|
||||||
val filterDownloaded by screenModel.updatesPreferences.filterDownloaded().collectAsState()
|
val filterDownloaded by screenModel.updatesPreferences.filterDownloaded.collectAsState()
|
||||||
TriStateItem(
|
TriStateItem(
|
||||||
label = stringResource(MR.strings.label_downloaded),
|
label = stringResource(MR.strings.label_downloaded),
|
||||||
state = filterDownloaded,
|
state = filterDownloaded,
|
||||||
onClick = { screenModel.toggleFilter(UpdatesPreferences::filterDownloaded) },
|
onClick = { screenModel.toggleFilter(UpdatesPreferences::filterDownloaded) },
|
||||||
)
|
)
|
||||||
|
|
||||||
val filterUnread by screenModel.updatesPreferences.filterUnread().collectAsState()
|
val filterUnread by screenModel.updatesPreferences.filterUnread.collectAsState()
|
||||||
TriStateItem(
|
TriStateItem(
|
||||||
label = stringResource(MR.strings.action_filter_unread),
|
label = stringResource(MR.strings.action_filter_unread),
|
||||||
state = filterUnread,
|
state = filterUnread,
|
||||||
onClick = { screenModel.toggleFilter(UpdatesPreferences::filterUnread) },
|
onClick = { screenModel.toggleFilter(UpdatesPreferences::filterUnread) },
|
||||||
)
|
)
|
||||||
|
|
||||||
val filterStarted by screenModel.updatesPreferences.filterStarted().collectAsState()
|
val filterStarted by screenModel.updatesPreferences.filterStarted.collectAsState()
|
||||||
TriStateItem(
|
TriStateItem(
|
||||||
label = stringResource(MR.strings.label_started),
|
label = stringResource(MR.strings.label_started),
|
||||||
state = filterStarted,
|
state = filterStarted,
|
||||||
onClick = { screenModel.toggleFilter(UpdatesPreferences::filterStarted) },
|
onClick = { screenModel.toggleFilter(UpdatesPreferences::filterStarted) },
|
||||||
)
|
)
|
||||||
|
|
||||||
val filterBookmarked by screenModel.updatesPreferences.filterBookmarked().collectAsState()
|
val filterBookmarked by screenModel.updatesPreferences.filterBookmarked.collectAsState()
|
||||||
TriStateItem(
|
TriStateItem(
|
||||||
label = stringResource(MR.strings.action_filter_bookmarked),
|
label = stringResource(MR.strings.action_filter_bookmarked),
|
||||||
state = filterBookmarked,
|
state = filterBookmarked,
|
||||||
@@ -85,9 +85,9 @@ private fun ColumnScope.FilterSheet(
|
|||||||
|
|
||||||
HorizontalDivider(modifier = Modifier.padding(MaterialTheme.padding.small))
|
HorizontalDivider(modifier = Modifier.padding(MaterialTheme.padding.small))
|
||||||
|
|
||||||
val filterExcludedScanlators by screenModel.updatesPreferences.filterExcludedScanlators().collectAsState()
|
val filterExcludedScanlators by screenModel.updatesPreferences.filterExcludedScanlators.collectAsState()
|
||||||
|
|
||||||
fun toggleScanlatorFilter() = screenModel.updatesPreferences.filterExcludedScanlators().getAndSet { !it }
|
fun toggleScanlatorFilter() = screenModel.updatesPreferences.filterExcludedScanlators.getAndSet { !it }
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package eu.kanade.presentation.webview
|
|||||||
import android.content.pm.ApplicationInfo
|
import android.content.pm.ApplicationInfo
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.os.Message
|
import android.os.Message
|
||||||
|
import android.webkit.JsPromptResult
|
||||||
|
import android.webkit.JsResult
|
||||||
import android.webkit.WebResourceRequest
|
import android.webkit.WebResourceRequest
|
||||||
import android.webkit.WebView
|
import android.webkit.WebView
|
||||||
import androidx.activity.compose.BackHandler
|
import androidx.activity.compose.BackHandler
|
||||||
@@ -20,6 +22,7 @@ import androidx.compose.material3.LinearProgressIndicator
|
|||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.DisposableEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.key
|
import androidx.compose.runtime.key
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
@@ -95,6 +98,11 @@ fun WebViewScreenContent(
|
|||||||
|
|
||||||
var currentUrl by remember { mutableStateOf(url) }
|
var currentUrl by remember { mutableStateOf(url) }
|
||||||
var showCloudflareHelp by remember { mutableStateOf(false) }
|
var showCloudflareHelp by remember { mutableStateOf(false) }
|
||||||
|
var isActive by remember { mutableStateOf(true) }
|
||||||
|
|
||||||
|
DisposableEffect(Unit) {
|
||||||
|
onDispose { isActive = false }
|
||||||
|
}
|
||||||
|
|
||||||
val webClient = remember {
|
val webClient = remember {
|
||||||
object : AccompanistWebViewClient() {
|
object : AccompanistWebViewClient() {
|
||||||
@@ -163,6 +171,36 @@ fun WebViewScreenContent(
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onJsAlert(view: WebView, url: String?, message: String?, result: JsResult): Boolean {
|
||||||
|
if (!isActive) {
|
||||||
|
result.confirm()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return super.onJsAlert(view, url, message, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onJsConfirm(view: WebView, url: String?, message: String?, result: JsResult): Boolean {
|
||||||
|
if (!isActive) {
|
||||||
|
result.cancel()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return super.onJsConfirm(view, url, message, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onJsPrompt(
|
||||||
|
view: WebView,
|
||||||
|
url: String?,
|
||||||
|
message: String?,
|
||||||
|
defaultValue: String?,
|
||||||
|
result: JsPromptResult,
|
||||||
|
): Boolean {
|
||||||
|
if (!isActive) {
|
||||||
|
result.cancel()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return super.onJsPrompt(view, url, message, defaultValue, result)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ class App : Application(), DefaultLifecycleObserver, SingletonImageLoader.Factor
|
|||||||
val scope = ProcessLifecycleOwner.get().lifecycleScope
|
val scope = ProcessLifecycleOwner.get().lifecycleScope
|
||||||
|
|
||||||
// Show notification to disable Incognito Mode when it's enabled
|
// Show notification to disable Incognito Mode when it's enabled
|
||||||
basePreferences.incognitoMode().changes()
|
basePreferences.incognitoMode.changes()
|
||||||
.onEach { enabled ->
|
.onEach { enabled ->
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
disableIncognitoReceiver.register()
|
disableIncognitoReceiver.register()
|
||||||
@@ -169,25 +169,25 @@ class App : Application(), DefaultLifecycleObserver, SingletonImageLoader.Factor
|
|||||||
}
|
}
|
||||||
.launchIn(scope)
|
.launchIn(scope)
|
||||||
|
|
||||||
privacyPreferences.analytics()
|
privacyPreferences.analytics
|
||||||
.changes()
|
.changes()
|
||||||
.onEach(FirebaseConfig::setAnalyticsEnabled)
|
.onEach(FirebaseConfig::setAnalyticsEnabled)
|
||||||
.launchIn(scope)
|
.launchIn(scope)
|
||||||
|
|
||||||
privacyPreferences.crashlytics()
|
privacyPreferences.crashlytics
|
||||||
.changes()
|
.changes()
|
||||||
.onEach(FirebaseConfig::setCrashlyticsEnabled)
|
.onEach(FirebaseConfig::setCrashlyticsEnabled)
|
||||||
.launchIn(scope)
|
.launchIn(scope)
|
||||||
|
|
||||||
basePreferences.hardwareBitmapThreshold().let { preference ->
|
basePreferences.hardwareBitmapThreshold.let { preference ->
|
||||||
if (!preference.isSet()) preference.set(GLUtil.DEVICE_TEXTURE_LIMIT)
|
if (!preference.isSet()) preference.set(GLUtil.DEVICE_TEXTURE_LIMIT)
|
||||||
}
|
}
|
||||||
|
|
||||||
basePreferences.hardwareBitmapThreshold().changes()
|
basePreferences.hardwareBitmapThreshold.changes()
|
||||||
.onEach { ImageUtil.hardwareBitmapThreshold = it }
|
.onEach { ImageUtil.hardwareBitmapThreshold = it }
|
||||||
.launchIn(scope)
|
.launchIn(scope)
|
||||||
|
|
||||||
setAppCompatDelegateThemeMode(Injekt.get<UiPreferences>().themeMode().get())
|
setAppCompatDelegateThemeMode(Injekt.get<UiPreferences>().themeMode.get())
|
||||||
|
|
||||||
// Updates widget update
|
// Updates widget update
|
||||||
WidgetManager(Injekt.get(), Injekt.get()).apply { init(scope) }
|
WidgetManager(Injekt.get(), Injekt.get()).apply { init(scope) }
|
||||||
@@ -256,7 +256,7 @@ class App : Application(), DefaultLifecycleObserver, SingletonImageLoader.Factor
|
|||||||
|
|
||||||
crossfade((300 * this@App.animatorDurationScale).toInt())
|
crossfade((300 * this@App.animatorDurationScale).toInt())
|
||||||
allowRgb565(DeviceUtil.isLowRamDevice(this@App))
|
allowRgb565(DeviceUtil.isLowRamDevice(this@App))
|
||||||
if (networkPreferences.verboseLogging().get()) logger(DebugLogger())
|
if (networkPreferences.verboseLogging.get()) logger(DebugLogger())
|
||||||
|
|
||||||
// Coil spawns a new thread for every image load by default
|
// Coil spawns a new thread for every image load by default
|
||||||
fetcherCoroutineContext(Dispatchers.IO.limitedParallelism(8))
|
fetcherCoroutineContext(Dispatchers.IO.limitedParallelism(8))
|
||||||
@@ -376,7 +376,7 @@ class App : Application(), DefaultLifecycleObserver, SingletonImageLoader.Factor
|
|||||||
private var registered = false
|
private var registered = false
|
||||||
|
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
basePreferences.incognitoMode().set(false)
|
basePreferences.incognitoMode.set(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun register() {
|
fun register() {
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ class BackupNotifier(private val context: Context) {
|
|||||||
}
|
}
|
||||||
setContentTitle(contentTitle)
|
setContentTitle(contentTitle)
|
||||||
|
|
||||||
if (!preferences.hideNotificationContent().get()) {
|
if (!preferences.hideNotificationContent.get()) {
|
||||||
setContentText(content)
|
setContentText(content)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ class BackupCreateJob(private val context: Context, workerParams: WorkerParamete
|
|||||||
|
|
||||||
fun setupTask(context: Context, prefInterval: Int? = null) {
|
fun setupTask(context: Context, prefInterval: Int? = null) {
|
||||||
val backupPreferences = Injekt.get<BackupPreferences>()
|
val backupPreferences = Injekt.get<BackupPreferences>()
|
||||||
val interval = prefInterval ?: backupPreferences.backupInterval().get()
|
val interval = prefInterval ?: backupPreferences.backupInterval.get()
|
||||||
if (interval > 0) {
|
if (interval > 0) {
|
||||||
val constraints = Constraints(
|
val constraints = Constraints(
|
||||||
requiresBatteryNotLow = true,
|
requiresBatteryNotLow = true,
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ class BackupCreator(
|
|||||||
BackupFileValidator(context).validate(fileUri)
|
BackupFileValidator(context).validate(fileUri)
|
||||||
|
|
||||||
if (isAutoBackup) {
|
if (isAutoBackup) {
|
||||||
backupPreferences.lastAutoBackupTimestamp().set(Instant.now().toEpochMilli())
|
backupPreferences.lastAutoBackupTimestamp.set(Instant.now().toEpochMilli())
|
||||||
}
|
}
|
||||||
|
|
||||||
return fileUri.toString()
|
return fileUri.toString()
|
||||||
|
|||||||
@@ -13,12 +13,18 @@ class BackupCategory(
|
|||||||
@ProtoNumber(100) var flags: Long = 0,
|
@ProtoNumber(100) var flags: Long = 0,
|
||||||
// SY specific values
|
// SY specific values
|
||||||
/*@ProtoNumber(600) var mangaOrder: List<Long> = emptyList(),*/
|
/*@ProtoNumber(600) var mangaOrder: List<Long> = emptyList(),*/
|
||||||
|
@ProtoNumber(601) var version: Long = 0,
|
||||||
|
@ProtoNumber(602) var uid: Long = 0,
|
||||||
|
@ProtoNumber(603) var lastModifiedAt: Long = 0,
|
||||||
) {
|
) {
|
||||||
fun toCategory(id: Long) = Category(
|
fun toCategory(id: Long) = Category(
|
||||||
id = id,
|
id = id,
|
||||||
name = this@BackupCategory.name,
|
name = this@BackupCategory.name,
|
||||||
flags = this@BackupCategory.flags,
|
flags = this@BackupCategory.flags,
|
||||||
order = this@BackupCategory.order,
|
order = this@BackupCategory.order,
|
||||||
|
version = this@BackupCategory.version,
|
||||||
|
uid = this@BackupCategory.uid,
|
||||||
|
lastModifiedAt = this@BackupCategory.lastModifiedAt,
|
||||||
/*mangaOrder = this@BackupCategory.mangaOrder*/
|
/*mangaOrder = this@BackupCategory.mangaOrder*/
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -29,5 +35,8 @@ val backupCategoryMapper = { category: Category ->
|
|||||||
name = category.name,
|
name = category.name,
|
||||||
order = category.order,
|
order = category.order,
|
||||||
flags = category.flags,
|
flags = category.flags,
|
||||||
|
version = category.version,
|
||||||
|
uid = category.uid,
|
||||||
|
lastModifiedAt = category.lastModifiedAt,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+49
-6
@@ -17,22 +17,65 @@ class CategoriesRestorer(
|
|||||||
if (backupCategories.isNotEmpty()) {
|
if (backupCategories.isNotEmpty()) {
|
||||||
val dbCategories = getCategories.await()
|
val dbCategories = getCategories.await()
|
||||||
val dbCategoriesByName = dbCategories.associateBy { it.name }
|
val dbCategoriesByName = dbCategories.associateBy { it.name }
|
||||||
|
// SY -->
|
||||||
|
val dbCategoriesByUid = dbCategories.associateBy { it.uid } // Map by UID
|
||||||
|
// SY <--
|
||||||
|
|
||||||
var nextOrder = dbCategories.maxOfOrNull { it.order }?.plus(1) ?: 0
|
var nextOrder = dbCategories.maxOfOrNull { it.order }?.plus(1) ?: 0
|
||||||
|
|
||||||
val categories = backupCategories
|
val categories = backupCategories
|
||||||
.sortedBy { it.order }
|
.sortedBy { it.order }
|
||||||
.map {
|
// SY -->
|
||||||
val dbCategory = dbCategoriesByName[it.name]
|
.map { backupCategory ->
|
||||||
if (dbCategory != null) return@map dbCategory
|
var dbCategory = if (backupCategory.uid != 0L) {
|
||||||
|
dbCategoriesByUid[backupCategory.uid]
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dbCategory == null) {
|
||||||
|
dbCategory = dbCategoriesByName[backupCategory.name]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dbCategory != null) {
|
||||||
|
handler.await {
|
||||||
|
categoriesQueries.update(
|
||||||
|
name = backupCategory.name,
|
||||||
|
order = backupCategory.order,
|
||||||
|
flags = backupCategory.flags,
|
||||||
|
version = backupCategory.version,
|
||||||
|
uid = if (backupCategory.uid != 0L) backupCategory.uid else dbCategory.uid,
|
||||||
|
last_modified_at = backupCategory.lastModifiedAt,
|
||||||
|
isSyncing = 1,
|
||||||
|
categoryId = dbCategory.id,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return@map dbCategory
|
||||||
|
}
|
||||||
|
|
||||||
val order = nextOrder++
|
val order = nextOrder++
|
||||||
handler.awaitOneExecutable {
|
handler.awaitOneExecutable {
|
||||||
categoriesQueries.insert(it.name, order, it.flags)
|
categoriesQueries.insert(
|
||||||
|
backupCategory.name,
|
||||||
|
order,
|
||||||
|
backupCategory.flags,
|
||||||
|
backupCategory.version,
|
||||||
|
backupCategory.uid,
|
||||||
|
backupCategory.lastModifiedAt,
|
||||||
|
)
|
||||||
categoriesQueries.selectLastInsertedRowId()
|
categoriesQueries.selectLastInsertedRowId()
|
||||||
}
|
}
|
||||||
.let { id -> it.toCategory(id).copy(order = order) }
|
.let { id -> backupCategory.toCategory(id).copy(order = order) }
|
||||||
}
|
}
|
||||||
|
// SY <--
|
||||||
|
|
||||||
libraryPreferences.categorizedDisplaySettings().set(
|
// SY -->
|
||||||
|
handler.await {
|
||||||
|
categoriesQueries.resetIsSyncing()
|
||||||
|
}
|
||||||
|
// SY <--
|
||||||
|
|
||||||
|
libraryPreferences.categorizedDisplaySettings.set(
|
||||||
(dbCategories + categories)
|
(dbCategories + categories)
|
||||||
.distinctBy { it.flags }
|
.distinctBy { it.flags }
|
||||||
.size > 1,
|
.size > 1,
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import kotlinx.coroutines.Job
|
|||||||
import kotlinx.coroutines.flow.drop
|
import kotlinx.coroutines.flow.drop
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
@@ -43,10 +44,10 @@ class ChapterCache(
|
|||||||
private val scope = CoroutineScope(Job() + Dispatchers.Main)
|
private val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||||
|
|
||||||
/** Cache class used for cache management. */
|
/** Cache class used for cache management. */
|
||||||
private var diskCache = setupDiskCache(readerPreferences.cacheSize().get().toLong())
|
private var diskCache = setupDiskCache(readerPreferences.cacheSize.get().toLong())
|
||||||
|
|
||||||
init {
|
init {
|
||||||
readerPreferences.cacheSize().changes()
|
readerPreferences.cacheSize.changes()
|
||||||
.drop(1)
|
.drop(1)
|
||||||
.onEach {
|
.onEach {
|
||||||
// Save old cache for destruction later
|
// Save old cache for destruction later
|
||||||
@@ -63,17 +64,13 @@ class ChapterCache(
|
|||||||
*/
|
*/
|
||||||
private val cacheDir: File = diskCache.directory
|
private val cacheDir: File = diskCache.directory
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns real size of directory.
|
|
||||||
*/
|
|
||||||
private val realSize: Long
|
|
||||||
get() = DiskUtil.getDirectorySize(cacheDir)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns real size of directory in human readable format.
|
* Returns real size of directory in human readable format.
|
||||||
*/
|
*/
|
||||||
val readableSize: String
|
suspend fun getReadableSize(): String = withContext(Dispatchers.IO) {
|
||||||
get() = Formatter.formatFileSize(context, realSize)
|
val size = DiskUtil.getDirectorySize(cacheDir)
|
||||||
|
Formatter.formatFileSize(context, size)
|
||||||
|
}
|
||||||
|
|
||||||
// --> EH
|
// --> EH
|
||||||
// Cache size is in MB
|
// Cache size is in MB
|
||||||
|
|||||||
@@ -12,14 +12,17 @@ import kotlinx.coroutines.Dispatchers
|
|||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.awaitAll
|
import kotlinx.coroutines.awaitAll
|
||||||
|
import kotlinx.coroutines.cancelAndJoin
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.ensureActive
|
import kotlinx.coroutines.ensureActive
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.debounce
|
import kotlinx.coroutines.flow.debounce
|
||||||
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.flow.onStart
|
import kotlinx.coroutines.flow.onStart
|
||||||
import kotlinx.coroutines.flow.receiveAsFlow
|
import kotlinx.coroutines.flow.receiveAsFlow
|
||||||
@@ -109,13 +112,19 @@ class DownloadCache(
|
|||||||
ProtoBuf.decodeFromByteArray<RootDirectory>(it.readBytes())
|
ProtoBuf.decodeFromByteArray<RootDirectory>(it.readBytes())
|
||||||
}
|
}
|
||||||
rootDownloadsDir = diskCache
|
rootDownloadsDir = diskCache
|
||||||
lastRenew = System.currentTimeMillis()
|
|
||||||
}
|
}
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
logcat(LogPriority.ERROR, e) { "Failed to initialize from disk cache" }
|
logcat(LogPriority.ERROR, e) { "Failed to initialize from disk cache" }
|
||||||
diskCacheFile.delete()
|
diskCacheFile.delete()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sourceManager.catalogueSources
|
||||||
|
.map { sources -> sources.map { it.id }.toSet() }
|
||||||
|
.distinctUntilChanged()
|
||||||
|
.collect {
|
||||||
|
restartRenewal()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
storageManager.changes
|
storageManager.changes
|
||||||
@@ -353,19 +362,34 @@ class DownloadCache(
|
|||||||
notifyChanges()
|
notifyChanges()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun invalidateCache() {
|
suspend fun invalidateCache() {
|
||||||
lastRenew = 0L
|
renewalJob?.cancelAndJoin()
|
||||||
renewalJob?.cancel()
|
|
||||||
diskCacheFile.delete()
|
diskCacheFile.delete()
|
||||||
renewCache()
|
lastRenew = 0L
|
||||||
|
renewCache(forceRenew = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Safely cancels any in-progress renewal job, resets the last-renew timestamp, and
|
||||||
|
* immediately starts a new renewal, bypassing the time-based throttle.
|
||||||
|
*/
|
||||||
|
private fun restartRenewal() {
|
||||||
|
renewalJob?.cancel()
|
||||||
|
lastRenew = 0L
|
||||||
|
renewCache(forceRenew = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renews the downloads cache.
|
* Renews the downloads cache.
|
||||||
|
*
|
||||||
|
* @param forceRenew when `true`, the time-based throttle is bypassed. Use this after
|
||||||
|
* explicitly cancelling the previous job to avoid a race where the cancelled job's
|
||||||
|
* [invokeOnCompletion] handler sets [lastRenew] after the reset but before the new
|
||||||
|
* job's guard check.
|
||||||
*/
|
*/
|
||||||
private fun renewCache() {
|
private fun renewCache(forceRenew: Boolean = false) {
|
||||||
// Avoid renewing cache if in the process nor too often
|
// Avoid renewing cache if in the process nor too often
|
||||||
if (lastRenew + renewInterval >= System.currentTimeMillis() || renewalJob?.isActive == true) {
|
if ((!forceRenew && lastRenew + renewInterval >= System.currentTimeMillis()) || renewalJob?.isActive == true) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -376,15 +400,14 @@ class DownloadCache(
|
|||||||
|
|
||||||
// Try to wait until extensions and sources have loaded
|
// Try to wait until extensions and sources have loaded
|
||||||
// SY -->
|
// SY -->
|
||||||
var sources = emptyList<Source>()
|
|
||||||
withTimeoutOrNull(30.seconds) {
|
withTimeoutOrNull(30.seconds) {
|
||||||
extensionManager.isInitialized.first { it }
|
// SY <--
|
||||||
sourceManager.isInitialized.first { it }
|
sourceManager.catalogueSources.first { it.isNotEmpty() }
|
||||||
|
// SY -->
|
||||||
sources = getSources()
|
|
||||||
}
|
}
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
|
val sources = getSources()
|
||||||
val sourceMap = sources.associate { provider.getSourceDirName(it).lowercase() to it.id }
|
val sourceMap = sources.associate { provider.getSourceDirName(it).lowercase() to it.id }
|
||||||
|
|
||||||
rootDownloadsDirMutex.withLock {
|
rootDownloadsDirMutex.withLock {
|
||||||
@@ -459,8 +482,9 @@ class DownloadCache(
|
|||||||
|
|
||||||
private var updateDiskCacheJob: Job? = null
|
private var updateDiskCacheJob: Job? = null
|
||||||
private fun updateDiskCache() {
|
private fun updateDiskCache() {
|
||||||
updateDiskCacheJob?.cancel()
|
val previousJob = updateDiskCacheJob
|
||||||
updateDiskCacheJob = scope.launchIO {
|
updateDiskCacheJob = scope.launchIO {
|
||||||
|
previousJob?.cancelAndJoin()
|
||||||
delay(1000)
|
delay(1000)
|
||||||
ensureActive()
|
ensureActive()
|
||||||
val bytes = ProtoBuf.encodeToByteArray(rootDownloadsDir)
|
val bytes = ProtoBuf.encodeToByteArray(rootDownloadsDir)
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ class DownloadJob(context: Context, workerParams: WorkerParameters) : CoroutineW
|
|||||||
override suspend fun doWork(): Result {
|
override suspend fun doWork(): Result {
|
||||||
var networkCheck = checkNetworkState(
|
var networkCheck = checkNetworkState(
|
||||||
applicationContext.activeNetworkState(),
|
applicationContext.activeNetworkState(),
|
||||||
downloadPreferences.downloadOnlyOverWifi().get(),
|
downloadPreferences.downloadOnlyOverWifi.get(),
|
||||||
)
|
)
|
||||||
var active = networkCheck && downloadManager.downloaderStart()
|
var active = networkCheck && downloadManager.downloaderStart()
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ class DownloadJob(context: Context, workerParams: WorkerParameters) : CoroutineW
|
|||||||
coroutineScope {
|
coroutineScope {
|
||||||
combineTransform(
|
combineTransform(
|
||||||
applicationContext.networkStateFlow(),
|
applicationContext.networkStateFlow(),
|
||||||
downloadPreferences.downloadOnlyOverWifi().changes(),
|
downloadPreferences.downloadOnlyOverWifi.changes(),
|
||||||
transform = { a, b -> emit(checkNetworkState(a, b)) },
|
transform = { a, b -> emit(checkNetworkState(a, b)) },
|
||||||
)
|
)
|
||||||
.onEach { networkCheck = it }
|
.onEach { networkCheck = it }
|
||||||
|
|||||||
@@ -109,10 +109,10 @@ class DownloadManager(
|
|||||||
return queueState.value.find { it.chapter.id == chapterId }
|
return queueState.value.find { it.chapter.id == chapterId }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun startDownloadNow(chapterId: Long) {
|
suspend fun startDownloadNow(chapterId: Long) {
|
||||||
val existingDownload = getQueuedDownloadOrNull(chapterId)
|
val existingDownload = getQueuedDownloadOrNull(chapterId)
|
||||||
// If not in queue try to start a new download
|
// If not in queue try to start a new download
|
||||||
val toAdd = existingDownload ?: runBlocking { Download.fromChapterId(chapterId) } ?: return
|
val toAdd = existingDownload ?: Download.fromChapterId(chapterId) ?: return
|
||||||
queueState.value.toMutableList().apply {
|
queueState.value.toMutableList().apply {
|
||||||
existingDownload?.let { remove(it) }
|
existingDownload?.let { remove(it) }
|
||||||
add(0, toAdd)
|
add(0, toAdd)
|
||||||
@@ -470,7 +470,7 @@ class DownloadManager(
|
|||||||
|
|
||||||
private suspend fun getChaptersToDelete(chapters: List<Chapter>, manga: Manga): List<Chapter> {
|
private suspend fun getChaptersToDelete(chapters: List<Chapter>, manga: Manga): List<Chapter> {
|
||||||
// Retrieve the categories that are set to exclude from being deleted on read
|
// Retrieve the categories that are set to exclude from being deleted on read
|
||||||
val categoriesToExclude = downloadPreferences.removeExcludeCategories().get().map(String::toLong)
|
val categoriesToExclude = downloadPreferences.removeExcludeCategories.get().map(String::toLong)
|
||||||
|
|
||||||
val categoriesForManga = getCategories.await(manga.id)
|
val categoriesForManga = getCategories.await(manga.id)
|
||||||
.map { it.id }
|
.map { it.id }
|
||||||
@@ -481,7 +481,7 @@ class DownloadManager(
|
|||||||
chapters
|
chapters
|
||||||
}
|
}
|
||||||
|
|
||||||
return if (!downloadPreferences.removeBookmarkedChapters().get()) {
|
return if (!downloadPreferences.removeBookmarkedChapters.get()) {
|
||||||
filteredCategoryManga.filterNot { it.bookmark }
|
filteredCategoryManga.filterNot { it.bookmark }
|
||||||
} else {
|
} else {
|
||||||
filteredCategoryManga
|
filteredCategoryManga
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ internal class DownloadNotifier(private val context: Context) {
|
|||||||
download.pages!!.size,
|
download.pages!!.size,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (preferences.hideNotificationContent().get()) {
|
if (preferences.hideNotificationContent.get()) {
|
||||||
setContentTitle(downloadingProgressText)
|
setContentTitle(downloadingProgressText)
|
||||||
setContentText(null)
|
setContentText(null)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ class DownloadProvider(
|
|||||||
fun getSourceDirName(source: Source): String {
|
fun getSourceDirName(source: Source): String {
|
||||||
return DiskUtil.buildValidFilename(
|
return DiskUtil.buildValidFilename(
|
||||||
source.toString(),
|
source.toString(),
|
||||||
disallowNonAscii = libraryPreferences.disallowNonAsciiFilenames().get(),
|
disallowNonAscii = libraryPreferences.disallowNonAsciiFilenames.get(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,7 +176,7 @@ class DownloadProvider(
|
|||||||
fun getMangaDirName(mangaTitle: String): String {
|
fun getMangaDirName(mangaTitle: String): String {
|
||||||
return DiskUtil.buildValidFilename(
|
return DiskUtil.buildValidFilename(
|
||||||
mangaTitle,
|
mangaTitle,
|
||||||
disallowNonAscii = libraryPreferences.disallowNonAsciiFilenames().get(),
|
disallowNonAscii = libraryPreferences.disallowNonAsciiFilenames.get(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,8 +191,8 @@ class DownloadProvider(
|
|||||||
chapterName: String,
|
chapterName: String,
|
||||||
chapterScanlator: String?,
|
chapterScanlator: String?,
|
||||||
chapterUrl: String,
|
chapterUrl: String,
|
||||||
disallowNonAsciiFilenames: Boolean = libraryPreferences.disallowNonAsciiFilenames().get(),
|
disallowNonAsciiFilenames: Boolean = libraryPreferences.disallowNonAsciiFilenames.get(),
|
||||||
includeChapterUrlHash: Boolean = downloadPreferences.includeChapterUrlHash().get(),
|
includeChapterUrlHash: Boolean = downloadPreferences.includeChapterUrlHash.get(),
|
||||||
): String {
|
): String {
|
||||||
var dirName = sanitizeChapterName(chapterName)
|
var dirName = sanitizeChapterName(chapterName)
|
||||||
if (!chapterScanlator.isNullOrBlank()) {
|
if (!chapterScanlator.isNullOrBlank()) {
|
||||||
@@ -235,8 +235,8 @@ class DownloadProvider(
|
|||||||
chapterName,
|
chapterName,
|
||||||
chapterScanlator,
|
chapterScanlator,
|
||||||
chapterUrl,
|
chapterUrl,
|
||||||
!libraryPreferences.disallowNonAsciiFilenames().get(),
|
!libraryPreferences.disallowNonAsciiFilenames.get(),
|
||||||
!downloadPreferences.includeChapterUrlHash().get(),
|
!downloadPreferences.includeChapterUrlHash.get(),
|
||||||
)
|
)
|
||||||
|
|
||||||
return buildList(2) {
|
return buildList(2) {
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ class DownloadStore(
|
|||||||
/**
|
/**
|
||||||
* Returns the list of downloads to restore. It should be called in a background thread.
|
* Returns the list of downloads to restore. It should be called in a background thread.
|
||||||
*/
|
*/
|
||||||
fun restore(): List<Download> {
|
suspend fun restore(): List<Download> {
|
||||||
val objs = preferences.all
|
val objs = preferences.all
|
||||||
.mapNotNull { it.value as? String }
|
.mapNotNull { it.value as? String }
|
||||||
.mapNotNull { deserialize(it) }
|
.mapNotNull { deserialize(it) }
|
||||||
@@ -100,10 +100,10 @@ class DownloadStore(
|
|||||||
val cachedManga = mutableMapOf<Long, Manga?>()
|
val cachedManga = mutableMapOf<Long, Manga?>()
|
||||||
for ((mangaId, chapterId) in objs) {
|
for ((mangaId, chapterId) in objs) {
|
||||||
val manga = cachedManga.getOrPut(mangaId) {
|
val manga = cachedManga.getOrPut(mangaId) {
|
||||||
runBlocking { getManga.await(mangaId) }
|
getManga.await(mangaId)
|
||||||
} ?: continue
|
} ?: continue
|
||||||
val source = sourceManager.get(manga.source) as? HttpSource ?: continue
|
val source = sourceManager.get(manga.source) as? HttpSource ?: continue
|
||||||
val chapter = runBlocking { getChapter.await(chapterId) } ?: continue
|
val chapter = getChapter.await(chapterId) ?: continue
|
||||||
downloads.add(Download(source, manga, chapter))
|
downloads.add(Download(source, manga, chapter))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ import kotlinx.coroutines.DelicateCoroutinesApi
|
|||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.SupervisorJob
|
import kotlinx.coroutines.SupervisorJob
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.asFlow
|
import kotlinx.coroutines.flow.asFlow
|
||||||
@@ -50,7 +49,6 @@ import okhttp3.Response
|
|||||||
import tachiyomi.core.common.i18n.stringResource
|
import tachiyomi.core.common.i18n.stringResource
|
||||||
import tachiyomi.core.common.storage.extension
|
import tachiyomi.core.common.storage.extension
|
||||||
import tachiyomi.core.common.util.lang.launchIO
|
import tachiyomi.core.common.util.lang.launchIO
|
||||||
import tachiyomi.core.common.util.lang.launchNow
|
|
||||||
import tachiyomi.core.common.util.lang.withIOContext
|
import tachiyomi.core.common.util.lang.withIOContext
|
||||||
import tachiyomi.core.common.util.system.ImageUtil
|
import tachiyomi.core.common.util.system.ImageUtil
|
||||||
import tachiyomi.core.common.util.system.logcat
|
import tachiyomi.core.common.util.system.logcat
|
||||||
@@ -121,9 +119,9 @@ class Downloader(
|
|||||||
var isPaused: Boolean = false
|
var isPaused: Boolean = false
|
||||||
|
|
||||||
init {
|
init {
|
||||||
launchNow {
|
scope.launch {
|
||||||
val chapters = async { store.restore() }
|
val chapters = store.restore()
|
||||||
addAllToQueue(chapters.await())
|
addAllToQueue(chapters)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,7 +201,7 @@ class Downloader(
|
|||||||
downloaderJob = scope.launch {
|
downloaderJob = scope.launch {
|
||||||
val activeDownloadsFlow = combine(
|
val activeDownloadsFlow = combine(
|
||||||
queueState,
|
queueState,
|
||||||
downloadPreferences.parallelSourceLimit().changes(),
|
downloadPreferences.parallelSourceLimit.changes(),
|
||||||
) { a, b -> a to b }.transformLatest { (queue, parallelCount) ->
|
) { a, b -> a to b }.transformLatest { (queue, parallelCount) ->
|
||||||
while (true) {
|
while (true) {
|
||||||
val activeDownloads = queue.asSequence()
|
val activeDownloads = queue.asSequence()
|
||||||
@@ -380,7 +378,7 @@ class Downloader(
|
|||||||
reIndexedPages
|
reIndexedPages
|
||||||
}
|
}
|
||||||
|
|
||||||
val dataSaver = if (sourcePreferences.dataSaverDownloader().get()) {
|
val dataSaver = if (sourcePreferences.dataSaverDownloader.get()) {
|
||||||
DataSaver(download.source, sourcePreferences)
|
DataSaver(download.source, sourcePreferences)
|
||||||
} else {
|
} else {
|
||||||
DataSaver.NoOp
|
DataSaver.NoOp
|
||||||
@@ -394,7 +392,7 @@ class Downloader(
|
|||||||
download.status = Download.State.DOWNLOADING
|
download.status = Download.State.DOWNLOADING
|
||||||
|
|
||||||
// Start downloading images, consider we can have downloaded images already
|
// Start downloading images, consider we can have downloaded images already
|
||||||
pageList.asFlow().flatMapMerge(concurrency = downloadPreferences.parallelPageLimit().get()) { page ->
|
pageList.asFlow().flatMapMerge(concurrency = downloadPreferences.parallelPageLimit.get()) { page ->
|
||||||
flow {
|
flow {
|
||||||
// Fetch image URL if necessary
|
// Fetch image URL if necessary
|
||||||
if (page.imageUrl.isNullOrEmpty()) {
|
if (page.imageUrl.isNullOrEmpty()) {
|
||||||
@@ -431,7 +429,7 @@ class Downloader(
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Only rename the directory if it's downloaded
|
// Only rename the directory if it's downloaded
|
||||||
if (downloadPreferences.saveChaptersAsCBZ().get()) {
|
if (downloadPreferences.saveChaptersAsCBZ.get()) {
|
||||||
archiveChapter(mangaDir, chapterDirname, tmpDir)
|
archiveChapter(mangaDir, chapterDirname, tmpDir)
|
||||||
} else {
|
} else {
|
||||||
tmpDir.renameTo(chapterDirname)
|
tmpDir.renameTo(chapterDirname)
|
||||||
@@ -579,7 +577,7 @@ class Downloader(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun splitTallImageIfNeeded(page: Page, tmpDir: UniFile) {
|
private fun splitTallImageIfNeeded(page: Page, tmpDir: UniFile) {
|
||||||
if (!downloadPreferences.splitTallImages().get()) return
|
if (!downloadPreferences.splitTallImages.get()) return
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val filenamePrefix = "%03d".format(Locale.ENGLISH, page.number)
|
val filenamePrefix = "%03d".format(Locale.ENGLISH, page.number)
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
|||||||
if (tags.contains(WORK_NAME_AUTO)) {
|
if (tags.contains(WORK_NAME_AUTO)) {
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
|
||||||
val preferences = Injekt.get<LibraryPreferences>()
|
val preferences = Injekt.get<LibraryPreferences>()
|
||||||
val restrictions = preferences.autoUpdateDeviceRestrictions().get()
|
val restrictions = preferences.autoUpdateDeviceRestrictions.get()
|
||||||
if ((DEVICE_ONLY_ON_WIFI in restrictions) && !context.isConnectedToWifi()) {
|
if ((DEVICE_ONLY_ON_WIFI in restrictions) && !context.isConnectedToWifi()) {
|
||||||
return Result.retry()
|
return Result.retry()
|
||||||
}
|
}
|
||||||
@@ -157,7 +157,7 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
|||||||
|
|
||||||
// If this is a chapter update, set the last update time to now
|
// If this is a chapter update, set the last update time to now
|
||||||
if (target == Target.CHAPTERS) {
|
if (target == Target.CHAPTERS) {
|
||||||
libraryPreferences.lastUpdatedTimestamp().set(Instant.now().toEpochMilli())
|
libraryPreferences.lastUpdatedTimestamp.set(Instant.now().toEpochMilli())
|
||||||
}
|
}
|
||||||
|
|
||||||
val categoryId = inputData.getLong(KEY_CATEGORY, -1L)
|
val categoryId = inputData.getLong(KEY_CATEGORY, -1L)
|
||||||
@@ -213,7 +213,7 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
|||||||
private suspend fun addMangaToQueue(categoryId: Long, group: Int, groupExtra: String?) {
|
private suspend fun addMangaToQueue(categoryId: Long, group: Int, groupExtra: String?) {
|
||||||
val libraryManga = getLibraryManga.await()
|
val libraryManga = getLibraryManga.await()
|
||||||
// SY -->
|
// SY -->
|
||||||
val groupLibraryUpdateType = libraryPreferences.groupLibraryUpdateType().get()
|
val groupLibraryUpdateType = libraryPreferences.groupLibraryUpdateType.get()
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
val listToUpdate = if (categoryId != -1L) {
|
val listToUpdate = if (categoryId != -1L) {
|
||||||
@@ -225,8 +225,8 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
|||||||
(groupLibraryUpdateType == GroupLibraryMode.ALL_BUT_UNGROUPED && group == LibraryGroup.UNGROUPED)
|
(groupLibraryUpdateType == GroupLibraryMode.ALL_BUT_UNGROUPED && group == LibraryGroup.UNGROUPED)
|
||||||
) {
|
) {
|
||||||
// SY <--
|
// SY <--
|
||||||
val includedCategories = libraryPreferences.updateCategories().get().map { it.toLong() }.toSet()
|
val includedCategories = libraryPreferences.updateCategories.get().map { it.toLong() }.toSet()
|
||||||
val excludedCategories = libraryPreferences.updateCategoriesExclude().get().map { it.toLong() }.toSet()
|
val excludedCategories = libraryPreferences.updateCategoriesExclude.get().map { it.toLong() }.toSet()
|
||||||
|
|
||||||
libraryManga.filter {
|
libraryManga.filter {
|
||||||
val included = includedCategories.isEmpty() || it.categories.intersect(includedCategories).isNotEmpty()
|
val included = includedCategories.isEmpty() || it.categories.intersect(includedCategories).isNotEmpty()
|
||||||
@@ -271,7 +271,7 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
|||||||
// SY <--
|
// SY <--
|
||||||
}
|
}
|
||||||
|
|
||||||
val restrictions = libraryPreferences.autoUpdateMangaRestrictions().get()
|
val restrictions = libraryPreferences.autoUpdateMangaRestrictions.get()
|
||||||
val skippedUpdates = mutableListOf<Pair<Manga, String?>>()
|
val skippedUpdates = mutableListOf<Pair<Manga, String?>>()
|
||||||
val (_, fetchWindowUpperBound) = fetchInterval.getWindow(ZonedDateTime.now())
|
val (_, fetchWindowUpperBound) = fetchInterval.getWindow(ZonedDateTime.now())
|
||||||
|
|
||||||
@@ -406,7 +406,7 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
|||||||
hasDownloads.store(true)
|
hasDownloads.store(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
libraryPreferences.newUpdatesCount().getAndSet { it + newChapters.size }
|
libraryPreferences.newUpdatesCount.getAndSet { it + newChapters.size }
|
||||||
|
|
||||||
// Convert to the manga that contains new chapters
|
// Convert to the manga that contains new chapters
|
||||||
newUpdates.add(manga to newChapters.toTypedArray())
|
newUpdates.add(manga to newChapters.toTypedArray())
|
||||||
@@ -482,7 +482,7 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
|||||||
val source = sourceManager.getOrStub(manga.source)
|
val source = sourceManager.getOrStub(manga.source)
|
||||||
|
|
||||||
// Update manga metadata if needed
|
// Update manga metadata if needed
|
||||||
if (libraryPreferences.autoUpdateMetadata().get()) {
|
if (libraryPreferences.autoUpdateMetadata.get()) {
|
||||||
val networkManga = source.getMangaDetails(manga.toSManga())
|
val networkManga = source.getMangaDetails(manga.toSManga())
|
||||||
updateManga.awaitUpdateFromSource(manga, networkManga, manualFetch = false, coverCache)
|
updateManga.awaitUpdateFromSource(manga, networkManga, manualFetch = false, coverCache)
|
||||||
}
|
}
|
||||||
@@ -559,7 +559,7 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
|||||||
var count = 0
|
var count = 0
|
||||||
val mangaDex = MdUtil.getEnabledMangaDex(preferences, sourceManager = sourceManager)
|
val mangaDex = MdUtil.getEnabledMangaDex(preferences, sourceManager = sourceManager)
|
||||||
?: return@coroutineScope
|
?: return@coroutineScope
|
||||||
val syncFollowStatusInts = preferences.mangadexSyncToLibraryIndexes().get().map { it.toInt() }
|
val syncFollowStatusInts = preferences.mangadexSyncToLibraryIndexes.get().map { it.toInt() }
|
||||||
|
|
||||||
val size: Int
|
val size: Int
|
||||||
mangaDex.fetchAllFollows()
|
mangaDex.fetchAllFollows()
|
||||||
@@ -740,9 +740,9 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
|||||||
prefInterval: Int? = null,
|
prefInterval: Int? = null,
|
||||||
) {
|
) {
|
||||||
val preferences = Injekt.get<LibraryPreferences>()
|
val preferences = Injekt.get<LibraryPreferences>()
|
||||||
val interval = prefInterval ?: preferences.autoUpdateInterval().get()
|
val interval = prefInterval ?: preferences.autoUpdateInterval.get()
|
||||||
if (interval > 0) {
|
if (interval > 0) {
|
||||||
val restrictions = preferences.autoUpdateDeviceRestrictions().get()
|
val restrictions = preferences.autoUpdateDeviceRestrictions.get()
|
||||||
val networkType = if (DEVICE_NETWORK_NOT_METERED in restrictions) {
|
val networkType = if (DEVICE_NETWORK_NOT_METERED in restrictions) {
|
||||||
NetworkType.UNMETERED
|
NetworkType.UNMETERED
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ class LibraryUpdateNotifier(
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!securityPreferences.hideNotificationContent().get()) {
|
if (!securityPreferences.hideNotificationContent.get()) {
|
||||||
val updatingText = manga.joinToString("\n") { it.title.chop(40) }
|
val updatingText = manga.joinToString("\n") { it.title.chop(40) }
|
||||||
progressNotificationBuilder.setStyle(NotificationCompat.BigTextStyle().bigText(updatingText))
|
progressNotificationBuilder.setStyle(NotificationCompat.BigTextStyle().bigText(updatingText))
|
||||||
}
|
}
|
||||||
@@ -155,7 +155,7 @@ class LibraryUpdateNotifier(
|
|||||||
Notifications.ID_LIBRARY_ERROR,
|
Notifications.ID_LIBRARY_ERROR,
|
||||||
Notifications.CHANNEL_LIBRARY_ERROR,
|
Notifications.CHANNEL_LIBRARY_ERROR,
|
||||||
) {
|
) {
|
||||||
setContentTitle(context.stringResource(MR.strings.notification_update_error, failed))
|
setContentTitle(context.pluralStringResource(MR.plurals.notification_update_error, failed, failed))
|
||||||
setContentText(context.stringResource(MR.strings.action_show_errors))
|
setContentText(context.stringResource(MR.strings.action_show_errors))
|
||||||
setSmallIcon(R.drawable.ic_tachi)
|
setSmallIcon(R.drawable.ic_tachi)
|
||||||
|
|
||||||
@@ -175,7 +175,7 @@ class LibraryUpdateNotifier(
|
|||||||
Notifications.CHANNEL_NEW_CHAPTERS,
|
Notifications.CHANNEL_NEW_CHAPTERS,
|
||||||
) {
|
) {
|
||||||
setContentTitle(context.stringResource(MR.strings.notification_new_chapters))
|
setContentTitle(context.stringResource(MR.strings.notification_new_chapters))
|
||||||
if (updates.size == 1 && !securityPreferences.hideNotificationContent().get()) {
|
if (updates.size == 1 && !securityPreferences.hideNotificationContent.get()) {
|
||||||
setContentText(updates.first().first.title.chop(NOTIF_TITLE_MAX_LEN))
|
setContentText(updates.first().first.title.chop(NOTIF_TITLE_MAX_LEN))
|
||||||
} else {
|
} else {
|
||||||
setContentText(
|
setContentText(
|
||||||
@@ -186,7 +186,7 @@ class LibraryUpdateNotifier(
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!securityPreferences.hideNotificationContent().get()) {
|
if (!securityPreferences.hideNotificationContent.get()) {
|
||||||
setStyle(
|
setStyle(
|
||||||
NotificationCompat.BigTextStyle().bigText(
|
NotificationCompat.BigTextStyle().bigText(
|
||||||
updates.joinToString("\n") {
|
updates.joinToString("\n") {
|
||||||
@@ -210,7 +210,7 @@ class LibraryUpdateNotifier(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Per-manga notification
|
// Per-manga notification
|
||||||
if (!securityPreferences.hideNotificationContent().get()) {
|
if (!securityPreferences.hideNotificationContent.get()) {
|
||||||
launchUI {
|
launchUI {
|
||||||
context.notify(
|
context.notify(
|
||||||
updates.map { (manga, chapters) ->
|
updates.map { (manga, chapters) ->
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import kotlinx.coroutines.DelicateCoroutinesApi
|
|||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import tachiyomi.core.common.Constants
|
import tachiyomi.core.common.Constants
|
||||||
import tachiyomi.core.common.util.lang.launchIO
|
import tachiyomi.core.common.util.lang.launchIO
|
||||||
|
import tachiyomi.core.common.util.lang.withUIContext
|
||||||
import tachiyomi.domain.chapter.interactor.GetChapter
|
import tachiyomi.domain.chapter.interactor.GetChapter
|
||||||
import tachiyomi.domain.chapter.interactor.UpdateChapter
|
import tachiyomi.domain.chapter.interactor.UpdateChapter
|
||||||
import tachiyomi.domain.chapter.model.Chapter
|
import tachiyomi.domain.chapter.model.Chapter
|
||||||
@@ -84,11 +85,18 @@ class NotificationReceiver : BroadcastReceiver() {
|
|||||||
ACTION_CANCEL_APP_UPDATE_DOWNLOAD -> cancelDownloadAppUpdate(context)
|
ACTION_CANCEL_APP_UPDATE_DOWNLOAD -> cancelDownloadAppUpdate(context)
|
||||||
// Open reader activity
|
// Open reader activity
|
||||||
ACTION_OPEN_CHAPTER -> {
|
ACTION_OPEN_CHAPTER -> {
|
||||||
openChapter(
|
val pendingResult = goAsync()
|
||||||
context,
|
launchIO {
|
||||||
intent.getLongExtra(EXTRA_MANGA_ID, -1),
|
try {
|
||||||
intent.getLongExtra(EXTRA_CHAPTER_ID, -1),
|
openChapter(
|
||||||
)
|
context,
|
||||||
|
intent.getLongExtra(EXTRA_MANGA_ID, -1),
|
||||||
|
intent.getLongExtra(EXTRA_CHAPTER_ID, -1),
|
||||||
|
)
|
||||||
|
} finally {
|
||||||
|
pendingResult.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Mark updated manga chapters as read
|
// Mark updated manga chapters as read
|
||||||
ACTION_MARK_AS_READ -> {
|
ACTION_MARK_AS_READ -> {
|
||||||
@@ -153,16 +161,18 @@ class NotificationReceiver : BroadcastReceiver() {
|
|||||||
* @param mangaId id of manga
|
* @param mangaId id of manga
|
||||||
* @param chapterId id of chapter
|
* @param chapterId id of chapter
|
||||||
*/
|
*/
|
||||||
private fun openChapter(context: Context, mangaId: Long, chapterId: Long) {
|
private suspend fun openChapter(context: Context, mangaId: Long, chapterId: Long) {
|
||||||
val manga = runBlocking { getManga.await(mangaId) }
|
val manga = getManga.await(mangaId)
|
||||||
val chapter = runBlocking { getChapter.await(chapterId) }
|
val chapter = getChapter.await(chapterId)
|
||||||
if (manga != null && chapter != null) {
|
withUIContext {
|
||||||
val intent = ReaderActivity.newIntent(context, manga.id, chapter.id).apply {
|
if (manga != null && chapter != null) {
|
||||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
val intent = ReaderActivity.newIntent(context, manga.id, chapter.id).apply {
|
||||||
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||||
|
}
|
||||||
|
context.startActivity(intent)
|
||||||
|
} else {
|
||||||
|
context.toast(MR.strings.chapter_error)
|
||||||
}
|
}
|
||||||
context.startActivity(intent)
|
|
||||||
} else {
|
|
||||||
context.toast(MR.strings.chapter_error)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,7 +226,7 @@ class NotificationReceiver : BroadcastReceiver() {
|
|||||||
val toUpdate = chapterUrls.mapNotNull { getChapter.await(it, mangaId) }
|
val toUpdate = chapterUrls.mapNotNull { getChapter.await(it, mangaId) }
|
||||||
.map {
|
.map {
|
||||||
val chapter = it.copy(read = true)
|
val chapter = it.copy(read = true)
|
||||||
if (downloadPreferences.removeAfterMarkedAsRead().get()) {
|
if (downloadPreferences.removeAfterMarkedAsRead.get()) {
|
||||||
val manga = getManga.await(mangaId)
|
val manga = getManga.await(mangaId)
|
||||||
if (manga != null) {
|
if (manga != null) {
|
||||||
val source = sourceManager.get(manga.source)
|
val source = sourceManager.get(manga.source)
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ class SyncDataJob(private val context: Context, workerParams: WorkerParameters)
|
|||||||
|
|
||||||
fun setupTask(context: Context, prefInterval: Int? = null) {
|
fun setupTask(context: Context, prefInterval: Int? = null) {
|
||||||
val syncPreferences = Injekt.get<SyncPreferences>()
|
val syncPreferences = Injekt.get<SyncPreferences>()
|
||||||
val interval = prefInterval ?: syncPreferences.syncInterval().get()
|
val interval = prefInterval ?: syncPreferences.syncInterval.get()
|
||||||
|
|
||||||
if (interval > 0) {
|
if (interval > 0) {
|
||||||
val request = PeriodicWorkRequestBuilder<SyncDataJob>(
|
val request = PeriodicWorkRequestBuilder<SyncDataJob>(
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ class SyncManager(
|
|||||||
handler.await(inTransaction = true) {
|
handler.await(inTransaction = true) {
|
||||||
mangasQueries.resetIsSyncing()
|
mangasQueries.resetIsSyncing()
|
||||||
chaptersQueries.resetIsSyncing()
|
chaptersQueries.resetIsSyncing()
|
||||||
|
categoriesQueries.resetIsSyncing()
|
||||||
}
|
}
|
||||||
|
|
||||||
val syncOptions = syncPreferences.getSyncSettings()
|
val syncOptions = syncPreferences.getSyncSettings()
|
||||||
@@ -119,7 +120,7 @@ class SyncManager(
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Handle sync based on the selected service
|
// Handle sync based on the selected service
|
||||||
val syncService = when (val syncService = SyncService.fromInt(syncPreferences.syncService().get())) {
|
val syncService = when (val syncService = SyncService.fromInt(syncPreferences.syncService.get())) {
|
||||||
SyncService.SYNCYOMI -> {
|
SyncService.SYNCYOMI -> {
|
||||||
SyncYomiSyncService(
|
SyncYomiSyncService(
|
||||||
context,
|
context,
|
||||||
@@ -150,21 +151,21 @@ class SyncManager(
|
|||||||
if (remoteBackup === syncData.backup) {
|
if (remoteBackup === syncData.backup) {
|
||||||
// nothing changed
|
// nothing changed
|
||||||
logcat(LogPriority.DEBUG) { "Skip restore due to remote was overwrite from local" }
|
logcat(LogPriority.DEBUG) { "Skip restore due to remote was overwrite from local" }
|
||||||
syncPreferences.lastSyncTimestamp().set(Date().time)
|
syncPreferences.lastSyncTimestamp.set(Date().time)
|
||||||
notifier.showSyncSuccess("Sync completed successfully")
|
notifier.showSyncSuccess("Sync completed successfully")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop the sync early if the remote backup is null or empty
|
// Stop the sync early if the remote backup is null or empty
|
||||||
if (remoteBackup.backupManga.size == 0) {
|
if (remoteBackup.backupManga.isEmpty() && remoteBackup.backupCategories.isEmpty() && remoteBackup.backupSources.isEmpty()) {
|
||||||
notifier.showSyncError("No data found on remote server.")
|
notifier.showSyncError("No data found on remote server.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if it's first sync based on lastSyncTimestamp
|
// Check if it's first sync based on lastSyncTimestamp
|
||||||
if (syncPreferences.lastSyncTimestamp().get() == 0L && databaseManga.isNotEmpty()) {
|
if (syncPreferences.lastSyncTimestamp.get() == 0L && databaseManga.isNotEmpty()) {
|
||||||
// It's first sync no need to restore data. (just update remote data)
|
// It's first sync no need to restore data. (just update remote data)
|
||||||
syncPreferences.lastSyncTimestamp().set(Date().time)
|
syncPreferences.lastSyncTimestamp.set(Date().time)
|
||||||
notifier.showSyncSuccess("Updated remote data successfully")
|
notifier.showSyncSuccess("Updated remote data successfully")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -185,14 +186,40 @@ class SyncManager(
|
|||||||
// SY <--
|
// SY <--
|
||||||
)
|
)
|
||||||
|
|
||||||
// It's local sync no need to restore data. (just update remote data)
|
val hasMangaChanges = filteredFavorites.isNotEmpty()
|
||||||
if (filteredFavorites.isEmpty()) {
|
val hasCategoryChanges = remoteBackup.backupCategories != backup.backupCategories
|
||||||
|
val hasSourceChanges = remoteBackup.backupSources != backup.backupSources
|
||||||
|
val hasPreferenceChanges = remoteBackup.backupPreferences != backup.backupPreferences
|
||||||
|
val hasSourcePreferenceChanges = remoteBackup.backupSourcePreferences != backup.backupSourcePreferences
|
||||||
|
val hasExtensionRepoChanges = remoteBackup.backupExtensionRepo != backup.backupExtensionRepo
|
||||||
|
val hasSavedSearchChanges = remoteBackup.backupSavedSearches != backup.backupSavedSearches
|
||||||
|
|
||||||
|
if (!hasMangaChanges && !hasCategoryChanges && !hasSourceChanges &&
|
||||||
|
!hasPreferenceChanges && !hasSourcePreferenceChanges &&
|
||||||
|
!hasExtensionRepoChanges && !hasSavedSearchChanges
|
||||||
|
) {
|
||||||
// update the sync timestamp
|
// update the sync timestamp
|
||||||
syncPreferences.lastSyncTimestamp().set(Date().time)
|
syncPreferences.lastSyncTimestamp.set(Date().time)
|
||||||
notifier.showSyncSuccess("Sync completed successfully")
|
notifier.showSyncSuccess("Sync completed successfully")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (syncOptions.categories) {
|
||||||
|
val mergedUids = newSyncData.backupCategories.map { it.uid }.toSet()
|
||||||
|
val mergedNames = newSyncData.backupCategories.map { it.name }.toSet()
|
||||||
|
val localCategories = getCategories.await().filterNot { it.id == 0L } // Exclude system category
|
||||||
|
val categoriesToDelete = localCategories.filter {
|
||||||
|
it.uid !in mergedUids && it.name !in mergedNames
|
||||||
|
}
|
||||||
|
if (categoriesToDelete.isNotEmpty()) {
|
||||||
|
handler.await(inTransaction = true) {
|
||||||
|
categoriesToDelete.forEach {
|
||||||
|
categoriesQueries.delete(it.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val backupUri = writeSyncDataToCache(context, newSyncData)
|
val backupUri = writeSyncDataToCache(context, newSyncData)
|
||||||
logcat(LogPriority.DEBUG) { "Got Backup Uri: $backupUri" }
|
logcat(LogPriority.DEBUG) { "Got Backup Uri: $backupUri" }
|
||||||
if (backupUri != null) {
|
if (backupUri != null) {
|
||||||
@@ -201,15 +228,19 @@ class SyncManager(
|
|||||||
backupUri,
|
backupUri,
|
||||||
sync = true,
|
sync = true,
|
||||||
options = RestoreOptions(
|
options = RestoreOptions(
|
||||||
appSettings = true,
|
appSettings = syncOptions.appSettings,
|
||||||
sourceSettings = true,
|
sourceSettings = syncOptions.sourceSettings,
|
||||||
libraryEntries = true,
|
libraryEntries = syncOptions.libraryEntries,
|
||||||
extensionRepoSettings = true,
|
categories = syncOptions.categories,
|
||||||
|
extensionRepoSettings = syncOptions.extensionRepoSettings,
|
||||||
|
// SY -->
|
||||||
|
savedSearches = syncOptions.savedSearches,
|
||||||
|
// SY <--
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
// update the sync timestamp
|
// update the sync timestamp
|
||||||
syncPreferences.lastSyncTimestamp().set(Date().time)
|
syncPreferences.lastSyncTimestamp.set(Date().time)
|
||||||
} else {
|
} else {
|
||||||
logcat(LogPriority.ERROR) { "Failed to write sync data to file" }
|
logcat(LogPriority.ERROR) { "Failed to write sync data to file" }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class SyncNotifier(private val context: Context) {
|
|||||||
val builder = with(progressNotificationBuilder) {
|
val builder = with(progressNotificationBuilder) {
|
||||||
setContentTitle(context.getString(R.string.syncing_library))
|
setContentTitle(context.getString(R.string.syncing_library))
|
||||||
|
|
||||||
if (!preferences.hideNotificationContent().get()) {
|
if (!preferences.hideNotificationContent.get()) {
|
||||||
setContentText(content)
|
setContentText(content)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -259,8 +259,8 @@ class GoogleDriveService(private val context: Context) {
|
|||||||
* and setting up the service using the obtained tokens.
|
* and setting up the service using the obtained tokens.
|
||||||
*/
|
*/
|
||||||
private fun initGoogleDriveService() {
|
private fun initGoogleDriveService() {
|
||||||
val accessToken = syncPreferences.googleDriveAccessToken().get()
|
val accessToken = syncPreferences.googleDriveAccessToken.get()
|
||||||
val refreshToken = syncPreferences.googleDriveRefreshToken().get()
|
val refreshToken = syncPreferences.googleDriveRefreshToken.get()
|
||||||
|
|
||||||
if (accessToken == "" || refreshToken == "") {
|
if (accessToken == "" || refreshToken == "") {
|
||||||
driveService = null
|
driveService = null
|
||||||
@@ -312,7 +312,7 @@ class GoogleDriveService(private val context: Context) {
|
|||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
internal suspend fun refreshToken() = withIOContext {
|
internal suspend fun refreshToken() = withIOContext {
|
||||||
val refreshToken = syncPreferences.googleDriveRefreshToken().get()
|
val refreshToken = syncPreferences.googleDriveRefreshToken.get()
|
||||||
|
|
||||||
val jsonFactory: JsonFactory = JacksonFactory.getDefaultInstance()
|
val jsonFactory: JsonFactory = JacksonFactory.getDefaultInstance()
|
||||||
val secrets = GoogleClientSecrets.load(
|
val secrets = GoogleClientSecrets.load(
|
||||||
@@ -336,7 +336,7 @@ class GoogleDriveService(private val context: Context) {
|
|||||||
credential.refreshToken()
|
credential.refreshToken()
|
||||||
val newAccessToken = credential.accessToken
|
val newAccessToken = credential.accessToken
|
||||||
// Save the new access token
|
// Save the new access token
|
||||||
syncPreferences.googleDriveAccessToken().set(newAccessToken)
|
syncPreferences.googleDriveAccessToken.set(newAccessToken)
|
||||||
setupGoogleDriveService(newAccessToken, credential.refreshToken)
|
setupGoogleDriveService(newAccessToken, credential.refreshToken)
|
||||||
} catch (e: TokenResponseException) {
|
} catch (e: TokenResponseException) {
|
||||||
if (e.details.error == "invalid_grant") {
|
if (e.details.error == "invalid_grant") {
|
||||||
@@ -425,8 +425,8 @@ class GoogleDriveService(private val context: Context) {
|
|||||||
val refreshToken = tokenResponse.refreshToken
|
val refreshToken = tokenResponse.refreshToken
|
||||||
|
|
||||||
// Save the tokens to SyncPreferences
|
// Save the tokens to SyncPreferences
|
||||||
syncPreferences.googleDriveAccessToken().set(accessToken)
|
syncPreferences.googleDriveAccessToken.set(accessToken)
|
||||||
syncPreferences.googleDriveRefreshToken().set(refreshToken)
|
syncPreferences.googleDriveRefreshToken.set(refreshToken)
|
||||||
|
|
||||||
setupGoogleDriveService(accessToken, refreshToken)
|
setupGoogleDriveService(accessToken, refreshToken)
|
||||||
initGoogleDriveService()
|
initGoogleDriveService()
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ import kotlinx.serialization.Serializable
|
|||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import logcat.logcat
|
import logcat.logcat
|
||||||
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
|
import kotlin.time.Duration.Companion.seconds
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class SyncData(
|
data class SyncData(
|
||||||
@@ -134,14 +136,31 @@ abstract class SyncService(
|
|||||||
"Starting merge. Local list size: ${localMangaListSafe.size}, Remote list size: ${remoteMangaListSafe.size}"
|
"Starting merge. Local list size: ${localMangaListSafe.size}, Remote list size: ${remoteMangaListSafe.size}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val lastSyncTime = syncPreferences.lastSyncTimestamp.get().milliseconds.inWholeSeconds
|
||||||
|
val syncOptions = syncPreferences.getSyncSettings()
|
||||||
|
|
||||||
val mergedList = (localMangaMap.keys + remoteMangaMap.keys).distinct().mapNotNull { compositeKey ->
|
val mergedList = (localMangaMap.keys + remoteMangaMap.keys).distinct().mapNotNull { compositeKey ->
|
||||||
val local = localMangaMap[compositeKey]
|
val local = localMangaMap[compositeKey]
|
||||||
val remote = remoteMangaMap[compositeKey]
|
val remote = remoteMangaMap[compositeKey]
|
||||||
|
|
||||||
// New version comparison logic
|
// New version comparison logic
|
||||||
when {
|
when {
|
||||||
local != null && remote == null -> updateCategories(local, localCategoriesMapByOrder)
|
local != null && remote == null -> {
|
||||||
local == null && remote != null -> updateCategories(remote, remoteCategoriesMapByOrder)
|
if (lastSyncTime == 0L || local.lastModifiedAt > lastSyncTime) {
|
||||||
|
updateCategories(local, localCategoriesMapByOrder)
|
||||||
|
} else {
|
||||||
|
logcat(LogPriority.DEBUG, logTag) { "Dropping local manga deleted on remote: ${local.title}." }
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
local == null && remote != null -> {
|
||||||
|
if (lastSyncTime == 0L || remote.lastModifiedAt > lastSyncTime) {
|
||||||
|
updateCategories(remote, remoteCategoriesMapByOrder)
|
||||||
|
} else {
|
||||||
|
logcat(LogPriority.DEBUG, logTag) { "Dropping deleted remote manga: ${remote.title}." }
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
local != null && remote != null -> {
|
local != null && remote != null -> {
|
||||||
// Compare versions to decide which manga to keep
|
// Compare versions to decide which manga to keep
|
||||||
if (local.version >= remote.version) {
|
if (local.version >= remote.version) {
|
||||||
@@ -149,7 +168,7 @@ abstract class SyncService(
|
|||||||
"Keeping local version of ${local.title} with merged chapters."
|
"Keeping local version of ${local.title} with merged chapters."
|
||||||
}
|
}
|
||||||
updateCategories(
|
updateCategories(
|
||||||
local.copy(chapters = mergeChapters(local.chapters, remote.chapters)),
|
local.copy(chapters = mergeChapters(local.chapters, remote.chapters, lastSyncTime, syncOptions.chapters)),
|
||||||
localCategoriesMapByOrder,
|
localCategoriesMapByOrder,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
@@ -157,7 +176,7 @@ abstract class SyncService(
|
|||||||
"Keeping remote version of ${remote.title} with merged chapters."
|
"Keeping remote version of ${remote.title} with merged chapters."
|
||||||
}
|
}
|
||||||
updateCategories(
|
updateCategories(
|
||||||
remote.copy(chapters = mergeChapters(local.chapters, remote.chapters)),
|
remote.copy(chapters = mergeChapters(local.chapters, remote.chapters, lastSyncTime, syncOptions.chapters)),
|
||||||
remoteCategoriesMapByOrder,
|
remoteCategoriesMapByOrder,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -197,9 +216,15 @@ abstract class SyncService(
|
|||||||
private fun mergeChapters(
|
private fun mergeChapters(
|
||||||
localChapters: List<BackupChapter>,
|
localChapters: List<BackupChapter>,
|
||||||
remoteChapters: List<BackupChapter>,
|
remoteChapters: List<BackupChapter>,
|
||||||
|
lastSyncTime: Long,
|
||||||
|
syncingChapters: Boolean,
|
||||||
): List<BackupChapter> {
|
): List<BackupChapter> {
|
||||||
val logTag = "MergeChapters"
|
val logTag = "MergeChapters"
|
||||||
|
|
||||||
|
if (!syncingChapters) {
|
||||||
|
return remoteChapters // If not syncing chapters, keep remote untouched
|
||||||
|
}
|
||||||
|
|
||||||
fun chapterCompositeKey(chapter: BackupChapter): String {
|
fun chapterCompositeKey(chapter: BackupChapter): String {
|
||||||
return "${chapter.url}|${chapter.name}|${chapter.chapterNumber}"
|
return "${chapter.url}|${chapter.name}|${chapter.chapterNumber}"
|
||||||
}
|
}
|
||||||
@@ -223,12 +248,22 @@ abstract class SyncService(
|
|||||||
|
|
||||||
when {
|
when {
|
||||||
localChapter != null && remoteChapter == null -> {
|
localChapter != null && remoteChapter == null -> {
|
||||||
logcat(LogPriority.DEBUG, logTag) { "Keeping local chapter: ${localChapter.name}." }
|
if (lastSyncTime == 0L || localChapter.lastModifiedAt > lastSyncTime) {
|
||||||
localChapter
|
logcat(LogPriority.DEBUG, logTag) { "Keeping local chapter: ${localChapter.name}." }
|
||||||
|
localChapter
|
||||||
|
} else {
|
||||||
|
logcat(LogPriority.DEBUG, logTag) { "Dropping local chapter deleted on remote: ${localChapter.name}." }
|
||||||
|
null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
localChapter == null && remoteChapter != null -> {
|
localChapter == null && remoteChapter != null -> {
|
||||||
logcat(LogPriority.DEBUG, logTag) { "Taking remote chapter: ${remoteChapter.name}." }
|
if (lastSyncTime == 0L || remoteChapter.lastModifiedAt > lastSyncTime) {
|
||||||
remoteChapter
|
logcat(LogPriority.DEBUG, logTag) { "Taking remote chapter: ${remoteChapter.name}." }
|
||||||
|
remoteChapter
|
||||||
|
} else {
|
||||||
|
logcat(LogPriority.DEBUG, logTag) { "Dropping deleted remote chapter: ${remoteChapter.name}." }
|
||||||
|
null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
localChapter != null && remoteChapter != null -> {
|
localChapter != null && remoteChapter != null -> {
|
||||||
// Use version number to decide which chapter to keep
|
// Use version number to decide which chapter to keep
|
||||||
@@ -274,37 +309,70 @@ abstract class SyncService(
|
|||||||
localCategoriesList: List<BackupCategory>?,
|
localCategoriesList: List<BackupCategory>?,
|
||||||
remoteCategoriesList: List<BackupCategory>?,
|
remoteCategoriesList: List<BackupCategory>?,
|
||||||
): List<BackupCategory> {
|
): List<BackupCategory> {
|
||||||
|
val logTag = "MergeCategories"
|
||||||
if (localCategoriesList == null) return remoteCategoriesList ?: emptyList()
|
if (localCategoriesList == null) return remoteCategoriesList ?: emptyList()
|
||||||
if (remoteCategoriesList == null) return localCategoriesList
|
if (remoteCategoriesList == null) return localCategoriesList
|
||||||
val localCategoriesMap = localCategoriesList.associateBy { it.name }
|
|
||||||
val remoteCategoriesMap = remoteCategoriesList.associateBy { it.name }
|
|
||||||
|
|
||||||
val mergedCategoriesMap = mutableMapOf<String, BackupCategory>()
|
val result = mutableListOf<BackupCategory>()
|
||||||
|
val processedLocals = mutableSetOf<BackupCategory>()
|
||||||
|
|
||||||
localCategoriesMap.forEach { (name, localCategory) ->
|
val localMapByUid = localCategoriesList.filter { it.uid != 0L }.associateBy { it.uid }
|
||||||
val remoteCategory = remoteCategoriesMap[name]
|
val localMapByName = localCategoriesList.associateBy { it.name }
|
||||||
if (remoteCategory != null) {
|
|
||||||
// Compare and merge local and remote categories
|
val lastSyncTime = syncPreferences.lastSyncTimestamp.get()
|
||||||
val mergedCategory = if (localCategory.order > remoteCategory.order) {
|
|
||||||
localCategory
|
remoteCategoriesList.forEach { remote ->
|
||||||
|
var localMatch: BackupCategory? = null
|
||||||
|
|
||||||
|
// 1. Try match by UID
|
||||||
|
if (remote.uid != 0L) {
|
||||||
|
localMatch = localMapByUid[remote.uid]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Try match by Name (fallback)
|
||||||
|
if (localMatch == null) {
|
||||||
|
localMatch = localMapByName[remote.name]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (localMatch != null) {
|
||||||
|
processedLocals.add(localMatch)
|
||||||
|
// Conflict resolution
|
||||||
|
if (localMatch.version >= remote.version) {
|
||||||
|
logcat(LogPriority.DEBUG, logTag) { "Keeping local category: ${localMatch.name} (UID: ${localMatch.uid})" }
|
||||||
|
result.add(localMatch)
|
||||||
} else {
|
} else {
|
||||||
remoteCategory
|
logcat(LogPriority.DEBUG, logTag) { "Keeping remote category: ${remote.name} (UID: ${remote.uid})" }
|
||||||
|
// Preserve Local UID if Remote was 0
|
||||||
|
if (remote.uid == 0L) {
|
||||||
|
remote.uid = localMatch.uid
|
||||||
|
}
|
||||||
|
result.add(remote)
|
||||||
}
|
}
|
||||||
mergedCategoriesMap[name] = mergedCategory
|
|
||||||
} else {
|
} else {
|
||||||
// If the category is only in the local list, add it to the merged list
|
val remoteModifiedTimeMillis = remote.lastModifiedAt.seconds.inWholeMilliseconds
|
||||||
mergedCategoriesMap[name] = localCategory
|
if (lastSyncTime == 0L || remoteModifiedTimeMillis > lastSyncTime) {
|
||||||
|
logcat(LogPriority.DEBUG, logTag) { "Adding new remote category: ${remote.name} (UID: ${remote.uid})" }
|
||||||
|
result.add(remote)
|
||||||
|
} else {
|
||||||
|
logcat(LogPriority.DEBUG, logTag) { "Dropping deleted remote category: ${remote.name} (UID: ${remote.uid})" }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add any categories from the remote list that are not in the local list
|
// Add remaining Local Categories
|
||||||
remoteCategoriesMap.forEach { (name, remoteCategory) ->
|
localCategoriesList.forEach { local ->
|
||||||
if (!mergedCategoriesMap.containsKey(name)) {
|
if (local !in processedLocals) {
|
||||||
mergedCategoriesMap[name] = remoteCategory
|
val localModifiedTimeMillis = local.lastModifiedAt.seconds.inWholeMilliseconds
|
||||||
|
if (lastSyncTime == 0L || localModifiedTimeMillis > lastSyncTime) {
|
||||||
|
logcat(LogPriority.DEBUG, logTag) { "Keeping local only category: ${local.name} (UID: ${local.uid})" }
|
||||||
|
result.add(local)
|
||||||
|
} else {
|
||||||
|
logcat(LogPriority.DEBUG, logTag) { "Dropping local category deleted on remote: ${local.name} (UID: ${local.uid})" }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return mergedCategoriesMap.values.toList()
|
return result.sortedBy { it.order }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun mergeSourcesLists(
|
private fun mergeSourcesLists(
|
||||||
@@ -341,8 +409,8 @@ abstract class SyncService(
|
|||||||
remoteSource
|
remoteSource
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
logcat(LogPriority.DEBUG, logTag) { "Remote and local is not empty: $sourceId. Skipping." }
|
logcat(LogPriority.DEBUG, logTag) { "Remote and local have the same source ID: $sourceId. Keeping local." }
|
||||||
null
|
localSource
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -387,8 +455,8 @@ abstract class SyncService(
|
|||||||
remotePreference
|
remotePreference
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
logcat(LogPriority.DEBUG, logTag) { "Both remote and local have keys. Skipping: $key" }
|
logcat(LogPriority.DEBUG, logTag) { "Both remote and local have the same preference key: $key. Keeping local." }
|
||||||
null
|
localPreference
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -507,10 +575,8 @@ abstract class SyncService(
|
|||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
logcat(LogPriority.DEBUG, logTag) {
|
logcat(LogPriority.DEBUG, logTag) { "Both remote and local have the same saved search key: $compositeKey. Keeping local." }
|
||||||
"No saved search found for composite key: $compositeKey. Skipping."
|
localSearch
|
||||||
}
|
|
||||||
null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,12 +99,12 @@ class SyncYomiSyncService(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun pullSyncData(): Pair<SyncData?, String> {
|
private suspend fun pullSyncData(): Pair<SyncData?, String> {
|
||||||
val host = syncPreferences.clientHost().get()
|
val host = syncPreferences.clientHost.get()
|
||||||
val apiKey = syncPreferences.clientAPIKey().get()
|
val apiKey = syncPreferences.clientAPIKey.get()
|
||||||
val downloadUrl = "$host/api/sync/content"
|
val downloadUrl = "$host/api/sync/content"
|
||||||
|
|
||||||
val headersBuilder = Headers.Builder().add("X-API-Token", apiKey)
|
val headersBuilder = Headers.Builder().add("X-API-Token", apiKey)
|
||||||
val lastETag = syncPreferences.lastSyncEtag().get()
|
val lastETag = syncPreferences.lastSyncEtag.get()
|
||||||
if (lastETag != "") {
|
if (lastETag != "") {
|
||||||
headersBuilder.add("If-None-Match", lastETag)
|
headersBuilder.add("If-None-Match", lastETag)
|
||||||
}
|
}
|
||||||
@@ -163,8 +163,8 @@ class SyncYomiSyncService(
|
|||||||
private suspend fun pushSyncData(syncData: SyncData, eTag: String): Boolean {
|
private suspend fun pushSyncData(syncData: SyncData, eTag: String): Boolean {
|
||||||
val backup = syncData.backup ?: return true
|
val backup = syncData.backup ?: return true
|
||||||
|
|
||||||
val host = syncPreferences.clientHost().get()
|
val host = syncPreferences.clientHost.get()
|
||||||
val apiKey = syncPreferences.clientAPIKey().get()
|
val apiKey = syncPreferences.clientAPIKey.get()
|
||||||
val uploadUrl = "$host/api/sync/content"
|
val uploadUrl = "$host/api/sync/content"
|
||||||
val timeout = 30L
|
val timeout = 30L
|
||||||
|
|
||||||
@@ -198,7 +198,7 @@ class SyncYomiSyncService(
|
|||||||
if (response.isSuccessful) {
|
if (response.isSuccessful) {
|
||||||
val newETag = response.headers["ETag"]
|
val newETag = response.headers["ETag"]
|
||||||
.takeIf { it?.isNotEmpty() == true } ?: throw SyncYomiException("Missing ETag")
|
.takeIf { it?.isNotEmpty() == true } ?: throw SyncYomiException("Missing ETag")
|
||||||
syncPreferences.lastSyncEtag().set(newETag)
|
syncPreferences.lastSyncEtag.set(newETag)
|
||||||
logcat(LogPriority.DEBUG) { "SyncYomi sync completed" }
|
logcat(LogPriority.DEBUG) { "SyncYomi sync completed" }
|
||||||
return true
|
return true
|
||||||
} else if (response.code == HttpStatus.SC_PRECONDITION_FAILED) {
|
} else if (response.code == HttpStatus.SC_PRECONDITION_FAILED) {
|
||||||
@@ -216,8 +216,8 @@ class SyncYomiSyncService(
|
|||||||
private suspend fun reportSyncEvent(event: SyncEventStatus, message: String? = null) {
|
private suspend fun reportSyncEvent(event: SyncEventStatus, message: String? = null) {
|
||||||
withContext(NonCancellable) {
|
withContext(NonCancellable) {
|
||||||
try {
|
try {
|
||||||
val host = syncPreferences.clientHost().get()
|
val host = syncPreferences.clientHost.get()
|
||||||
val apiKey = syncPreferences.clientAPIKey().get()
|
val apiKey = syncPreferences.clientAPIKey.get()
|
||||||
val url = "$host/api/sync/event"
|
val url = "$host/api/sync/event"
|
||||||
|
|
||||||
val headersBuilder = Headers.Builder().add("X-API-Token", apiKey)
|
val headersBuilder = Headers.Builder().add("X-API-Token", apiKey)
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ class Anilist(id: Long) : BaseTracker(id, "AniList"), DeletableTracker {
|
|||||||
|
|
||||||
override val supportsPrivateTracking: Boolean = true
|
override val supportsPrivateTracking: Boolean = true
|
||||||
|
|
||||||
private val scorePreference = trackPreferences.anilistScoreType()
|
private val scorePreference = trackPreferences.anilistScoreType
|
||||||
|
|
||||||
init {
|
init {
|
||||||
// If the preference is an int from APIv1, logout user to force using APIv2
|
// If the preference is an int from APIv1, logout user to force using APIv2
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ fun Track.toApiStatus() = when (status) {
|
|||||||
|
|
||||||
private val preferences: TrackPreferences by injectLazy()
|
private val preferences: TrackPreferences by injectLazy()
|
||||||
|
|
||||||
fun DomainTrack.toApiScore(): String = when (preferences.anilistScoreType().get()) {
|
fun DomainTrack.toApiScore(): String = when (preferences.anilistScoreType.get()) {
|
||||||
// 10 point
|
// 10 point
|
||||||
"POINT_10" -> (score.toInt() / 10).toString()
|
"POINT_10" -> (score.toInt() / 10).toString()
|
||||||
// 100 point
|
// 100 point
|
||||||
|
|||||||
@@ -224,6 +224,6 @@ class MangaUpdatesApi(
|
|||||||
companion object {
|
companion object {
|
||||||
private const val BASE_URL = "https://api.mangaupdates.com"
|
private const val BASE_URL = "https://api.mangaupdates.com"
|
||||||
|
|
||||||
private val CONTENT_TYPE = "application/vnd.api+json".toMediaType()
|
private val CONTENT_TYPE = "application/json".toMediaType()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ import eu.kanade.tachiyomi.data.track.myanimelist.dto.MALSearchResult
|
|||||||
import eu.kanade.tachiyomi.data.track.myanimelist.dto.MALUser
|
import eu.kanade.tachiyomi.data.track.myanimelist.dto.MALUser
|
||||||
import eu.kanade.tachiyomi.network.DELETE
|
import eu.kanade.tachiyomi.network.DELETE
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
|
import eu.kanade.tachiyomi.network.HttpException
|
||||||
import eu.kanade.tachiyomi.network.POST
|
import eu.kanade.tachiyomi.network.POST
|
||||||
|
import eu.kanade.tachiyomi.network.await
|
||||||
import eu.kanade.tachiyomi.network.awaitSuccess
|
import eu.kanade.tachiyomi.network.awaitSuccess
|
||||||
import eu.kanade.tachiyomi.network.parseAs
|
import eu.kanade.tachiyomi.network.parseAs
|
||||||
import eu.kanade.tachiyomi.util.PkceUtil
|
import eu.kanade.tachiyomi.util.PkceUtil
|
||||||
@@ -124,8 +126,23 @@ class MyAnimeListApi(
|
|||||||
.put(formBodyBuilder.build())
|
.put(formBodyBuilder.build())
|
||||||
.build()
|
.build()
|
||||||
with(json) {
|
with(json) {
|
||||||
authClient.newCall(request)
|
val response = authClient
|
||||||
.awaitSuccess()
|
.newCall(request)
|
||||||
|
.await()
|
||||||
|
|
||||||
|
if (!response.isSuccessful) {
|
||||||
|
if (response.body.string().contains("invalid_content")) {
|
||||||
|
// MAL returns unapproved titles in search but does not allow adding them to the list
|
||||||
|
// returns 400 with this body: {"message":"Invalid content","error":"invalid_content"}
|
||||||
|
// These unapproved titles cannot be filtered out in search and are also returned by the
|
||||||
|
// endpoint we use for id prefix search
|
||||||
|
throw MALTitleNotApproved()
|
||||||
|
} else {
|
||||||
|
throw HttpException(response.code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
response
|
||||||
.parseAs<MALListItemStatus>()
|
.parseAs<MALListItemStatus>()
|
||||||
.let { parseMangaItem(it, track) }
|
.let { parseMangaItem(it, track) }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,5 +80,6 @@ class MyAnimeListInterceptor(private val myanimelist: MyAnimeList) : Interceptor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class MALTitleNotApproved : IOException("MAL: This title can't be added because it is waiting for approval.")
|
||||||
class MALTokenRefreshFailed : IOException("MAL: Failed to refresh account token")
|
class MALTokenRefreshFailed : IOException("MAL: Failed to refresh account token")
|
||||||
class MALTokenExpired : IOException("MAL: Login has expired")
|
class MALTokenExpired : IOException("MAL: Login has expired")
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
package eu.kanade.tachiyomi.di
|
package eu.kanade.tachiyomi.di
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.os.Build
|
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||||
import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory
|
import androidx.sqlite.driver.bundled.BundledSQLiteDriver
|
||||||
import app.cash.sqldelight.db.SqlDriver
|
import app.cash.sqldelight.db.SqlDriver
|
||||||
import app.cash.sqldelight.driver.android.AndroidSqliteDriver
|
import app.cash.sqldelight.driver.android.AndroidSqliteDriver
|
||||||
|
import com.eygraber.sqldelight.androidx.driver.AndroidxSqliteConfiguration
|
||||||
|
import com.eygraber.sqldelight.androidx.driver.AndroidxSqliteDatabaseType
|
||||||
|
import com.eygraber.sqldelight.androidx.driver.AndroidxSqliteDriver
|
||||||
|
import com.eygraber.sqldelight.androidx.driver.FileProvider
|
||||||
import eu.kanade.domain.track.store.DelayedTrackingStore
|
import eu.kanade.domain.track.store.DelayedTrackingStore
|
||||||
import eu.kanade.tachiyomi.BuildConfig
|
import eu.kanade.tachiyomi.BuildConfig
|
||||||
import eu.kanade.tachiyomi.core.security.SecurityPreferences
|
import eu.kanade.tachiyomi.core.security.SecurityPreferences
|
||||||
@@ -25,7 +28,6 @@ import eu.kanade.tachiyomi.network.NetworkHelper
|
|||||||
import eu.kanade.tachiyomi.source.AndroidSourceManager
|
import eu.kanade.tachiyomi.source.AndroidSourceManager
|
||||||
import eu.kanade.tachiyomi.util.storage.CbzCrypto
|
import eu.kanade.tachiyomi.util.storage.CbzCrypto
|
||||||
import exh.eh.EHentaiUpdateHelper
|
import exh.eh.EHentaiUpdateHelper
|
||||||
import io.requery.android.database.sqlite.RequerySQLiteOpenHelperFactory
|
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import kotlinx.serialization.protobuf.ProtoBuf
|
import kotlinx.serialization.protobuf.ProtoBuf
|
||||||
import net.zetetic.database.sqlcipher.SupportOpenHelperFactory
|
import net.zetetic.database.sqlcipher.SupportOpenHelperFactory
|
||||||
@@ -51,58 +53,60 @@ import uy.kohesive.injekt.Injekt
|
|||||||
import uy.kohesive.injekt.api.InjektRegistrar
|
import uy.kohesive.injekt.api.InjektRegistrar
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
import java.lang.ref.WeakReference
|
||||||
|
|
||||||
// SY -->
|
private val lock = Any()
|
||||||
private const val LEGACY_DATABASE_NAME = "tachiyomi.db"
|
|
||||||
// SY <--
|
|
||||||
|
|
||||||
class AppModule(val app: Application) : InjektModule {
|
class AppModule(val app: Application) : InjektModule {
|
||||||
// SY -->
|
// SY -->
|
||||||
private val securityPreferences: SecurityPreferences by injectLazy()
|
private val securityPreferences: SecurityPreferences by injectLazy()
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
|
private var sqlDriverRef: WeakReference<SqlDriver>? = null
|
||||||
|
|
||||||
override fun InjektRegistrar.registerInjectables() {
|
override fun InjektRegistrar.registerInjectables() {
|
||||||
addSingleton(app)
|
addSingleton(app)
|
||||||
|
|
||||||
addSingletonFactory<SqlDriver> {
|
addSingletonFactory<SqlDriver> {
|
||||||
// SY -->
|
synchronized(lock) {
|
||||||
if (securityPreferences.encryptDatabase().get()) {
|
sqlDriverRef?.get()?.let { return@synchronized it }
|
||||||
System.loadLibrary("sqlcipher")
|
|
||||||
}
|
|
||||||
|
|
||||||
// SY <--
|
|
||||||
AndroidSqliteDriver(
|
|
||||||
schema = Database.Schema,
|
|
||||||
context = app,
|
|
||||||
// SY -->
|
// SY -->
|
||||||
name = if (securityPreferences.encryptDatabase().get()) {
|
if (securityPreferences.encryptDatabase.get()) {
|
||||||
CbzCrypto.DATABASE_NAME
|
System.loadLibrary("sqlcipher")
|
||||||
} else {
|
|
||||||
LEGACY_DATABASE_NAME
|
return@synchronized AndroidSqliteDriver(
|
||||||
},
|
schema = Database.Schema,
|
||||||
factory = if (securityPreferences.encryptDatabase().get()) {
|
context = app,
|
||||||
SupportOpenHelperFactory(CbzCrypto.getDecryptedPasswordSql(), null, false, 25)
|
name = CbzCrypto.DATABASE_NAME,
|
||||||
} else if (BuildConfig.DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
factory = SupportOpenHelperFactory(CbzCrypto.getDecryptedPasswordSql(), null, false, 25),
|
||||||
// Support database inspector in Android Studio
|
callback = object : AndroidSqliteDriver.Callback(Database.Schema) {
|
||||||
FrameworkSQLiteOpenHelperFactory()
|
override fun onOpen(db: SupportSQLiteDatabase) {
|
||||||
} else {
|
super.onOpen(db)
|
||||||
RequerySQLiteOpenHelperFactory()
|
setPragma(db, "foreign_keys = ON")
|
||||||
},
|
setPragma(db, "journal_mode = WAL")
|
||||||
// SY <--
|
setPragma(db, "synchronous = NORMAL")
|
||||||
callback = object : AndroidSqliteDriver.Callback(Database.Schema) {
|
}
|
||||||
override fun onOpen(db: SupportSQLiteDatabase) {
|
|
||||||
super.onOpen(db)
|
private fun setPragma(db: SupportSQLiteDatabase, pragma: String) {
|
||||||
setPragma(db, "foreign_keys = ON")
|
val cursor = db.query("PRAGMA $pragma")
|
||||||
setPragma(db, "journal_mode = WAL")
|
cursor.moveToFirst()
|
||||||
setPragma(db, "synchronous = NORMAL")
|
cursor.close()
|
||||||
}
|
}
|
||||||
private fun setPragma(db: SupportSQLiteDatabase, pragma: String) {
|
},
|
||||||
val cursor = db.query("PRAGMA $pragma")
|
).also { sqlDriverRef = WeakReference(it) }
|
||||||
cursor.moveToFirst()
|
}
|
||||||
cursor.close()
|
}
|
||||||
}
|
// SY <--
|
||||||
},
|
|
||||||
)
|
AndroidxSqliteDriver(
|
||||||
|
driver = BundledSQLiteDriver(),
|
||||||
|
databaseType = AndroidxSqliteDatabaseType.FileProvider(app, "tachiyomi.db"),
|
||||||
|
schema = Database.Schema,
|
||||||
|
configuration = AndroidxSqliteConfiguration(
|
||||||
|
isForeignKeyConstraintsEnabled = true,
|
||||||
|
),
|
||||||
|
).also { sqlDriverRef = WeakReference(it) }
|
||||||
}
|
}
|
||||||
addSingletonFactory {
|
addSingletonFactory {
|
||||||
Database(
|
Database(
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class PreferenceModule(val app: Application) : InjektModule {
|
|||||||
addSingletonFactory {
|
addSingletonFactory {
|
||||||
NetworkPreferences(
|
NetworkPreferences(
|
||||||
preferenceStore = get(),
|
preferenceStore = get(),
|
||||||
verboseLogging = isDevFlavor,
|
verboseLoggingDefault = isDevFlavor,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
addSingletonFactory {
|
addSingletonFactory {
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import kotlinx.coroutines.flow.asStateFlow
|
|||||||
import kotlinx.coroutines.flow.emptyFlow
|
import kotlinx.coroutines.flow.emptyFlow
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import tachiyomi.core.common.util.lang.withUIContext
|
import tachiyomi.core.common.util.lang.withUIContext
|
||||||
import tachiyomi.core.common.util.system.logcat
|
import tachiyomi.core.common.util.system.logcat
|
||||||
@@ -87,7 +88,7 @@ class ExtensionManager(
|
|||||||
ExtensionInstallReceiver(InstallationListener()).register(context)
|
ExtensionInstallReceiver(InstallationListener()).register(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var subLanguagesEnabledOnFirstRun = preferences.enabledLanguages().isSet()
|
private var subLanguagesEnabledOnFirstRun = preferences.enabledLanguages.isSet()
|
||||||
|
|
||||||
fun getExtensionPackage(sourceId: Long): String? {
|
fun getExtensionPackage(sourceId: Long): String? {
|
||||||
return installedExtensionsFlow.value.find { extension ->
|
return installedExtensionsFlow.value.find { extension ->
|
||||||
@@ -140,25 +141,27 @@ class ExtensionManager(
|
|||||||
* Loads and registers the installed extensions.
|
* Loads and registers the installed extensions.
|
||||||
*/
|
*/
|
||||||
private fun initExtensions() {
|
private fun initExtensions() {
|
||||||
val extensions = ExtensionLoader.loadExtensions(context)
|
scope.launch {
|
||||||
|
val extensions = ExtensionLoader.loadExtensions(context)
|
||||||
|
|
||||||
installedExtensionMapFlow.value = extensions
|
installedExtensionMapFlow.value = extensions
|
||||||
.filterIsInstance<LoadResult.Success>()
|
.filterIsInstance<LoadResult.Success>()
|
||||||
.associate { it.extension.pkgName to it.extension }
|
.associate { it.extension.pkgName to it.extension }
|
||||||
|
|
||||||
untrustedExtensionMapFlow.value = extensions
|
untrustedExtensionMapFlow.value = extensions
|
||||||
.filterIsInstance<LoadResult.Untrusted>()
|
.filterIsInstance<LoadResult.Untrusted>()
|
||||||
.associate { it.extension.pkgName to it.extension }
|
.associate { it.extension.pkgName to it.extension }
|
||||||
// SY -->
|
// SY -->
|
||||||
.filterNotBlacklisted()
|
.filterNotBlacklisted()
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
_isInitialized.value = true
|
_isInitialized.value = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// EXH -->
|
// EXH -->
|
||||||
private fun <T : Extension> Map<String, T>.filterNotBlacklisted(): Map<String, T> {
|
private fun <T : Extension> Map<String, T>.filterNotBlacklisted(): Map<String, T> {
|
||||||
val blacklistEnabled = preferences.enableSourceBlacklist().get()
|
val blacklistEnabled = preferences.enableSourceBlacklist.get()
|
||||||
return filterNot { (_, extension) ->
|
return filterNot { (_, extension) ->
|
||||||
extension.isBlacklisted(blacklistEnabled)
|
extension.isBlacklisted(blacklistEnabled)
|
||||||
.also {
|
.also {
|
||||||
@@ -167,7 +170,7 @@ class ExtensionManager(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Extension.isBlacklisted(blacklistEnabled: Boolean = preferences.enableSourceBlacklist().get()): Boolean {
|
private fun Extension.isBlacklisted(blacklistEnabled: Boolean = preferences.enableSourceBlacklist.get()): Boolean {
|
||||||
return pkgName in BlacklistedSources.BLACKLISTED_EXTENSIONS && blacklistEnabled
|
return pkgName in BlacklistedSources.BLACKLISTED_EXTENSIONS && blacklistEnabled
|
||||||
}
|
}
|
||||||
// EXH <--
|
// EXH <--
|
||||||
@@ -212,12 +215,12 @@ class ExtensionManager(
|
|||||||
.map(Extension.Available.Source::lang)
|
.map(Extension.Available.Source::lang)
|
||||||
|
|
||||||
val deviceLanguage = Locale.getDefault().language
|
val deviceLanguage = Locale.getDefault().language
|
||||||
val defaultLanguages = preferences.enabledLanguages().defaultValue()
|
val defaultLanguages = preferences.enabledLanguages.defaultValue()
|
||||||
val languagesToEnable = availableLanguages.filter {
|
val languagesToEnable = availableLanguages.filter {
|
||||||
it != deviceLanguage && it.startsWith(deviceLanguage)
|
it != deviceLanguage && it.startsWith(deviceLanguage)
|
||||||
}
|
}
|
||||||
|
|
||||||
preferences.enabledLanguages().set(defaultLanguages + languagesToEnable)
|
preferences.enabledLanguages.set(defaultLanguages + languagesToEnable)
|
||||||
subLanguagesEnabledOnFirstRun = true
|
subLanguagesEnabledOnFirstRun = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,7 +231,7 @@ class ExtensionManager(
|
|||||||
*/
|
*/
|
||||||
private fun updatedInstalledExtensionsStatuses(availableExtensions: List<Extension.Available>) {
|
private fun updatedInstalledExtensionsStatuses(availableExtensions: List<Extension.Available>) {
|
||||||
if (availableExtensions.isEmpty()) {
|
if (availableExtensions.isEmpty()) {
|
||||||
preferences.extensionUpdatesCount().set(0)
|
preferences.extensionUpdatesCount.set(0)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -426,7 +429,7 @@ class ExtensionManager(
|
|||||||
|
|
||||||
private fun updatePendingUpdatesCount() {
|
private fun updatePendingUpdatesCount() {
|
||||||
val pendingUpdateCount = installedExtensionMapFlow.value.values.count { it.hasUpdate }
|
val pendingUpdateCount = installedExtensionMapFlow.value.values.count { it.hasUpdate }
|
||||||
preferences.extensionUpdatesCount().set(pendingUpdateCount)
|
preferences.extensionUpdatesCount.set(pendingUpdateCount)
|
||||||
if (pendingUpdateCount == 0) {
|
if (pendingUpdateCount == 0) {
|
||||||
ExtensionUpdateNotifier(context).dismiss()
|
ExtensionUpdateNotifier(context).dismiss()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ internal class ExtensionApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
val blacklistEnabled = sourcePreferences.enableSourceBlacklist().get()
|
val blacklistEnabled = sourcePreferences.enableSourceBlacklist.get()
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
val installedExtensions = ExtensionLoader.loadExtensions(context)
|
val installedExtensions = ExtensionLoader.loadExtensions(context)
|
||||||
@@ -155,7 +155,7 @@ internal class ExtensionApi {
|
|||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
private fun Extension.isBlacklisted(
|
private fun Extension.isBlacklisted(
|
||||||
blacklistEnabled: Boolean = sourcePreferences.enableSourceBlacklist().get(),
|
blacklistEnabled: Boolean = sourcePreferences.enableSourceBlacklist.get(),
|
||||||
): Boolean {
|
): Boolean {
|
||||||
return pkgName in BlacklistedSources.BLACKLISTED_EXTENSIONS && blacklistEnabled
|
return pkgName in BlacklistedSources.BLACKLISTED_EXTENSIONS && blacklistEnabled
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class ExtensionUpdateNotifier(
|
|||||||
names.size,
|
names.size,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
if (!securityPreferences.hideNotificationContent().get()) {
|
if (!securityPreferences.hideNotificationContent.get()) {
|
||||||
val extNames = names.joinToString(", ")
|
val extNames = names.joinToString(", ")
|
||||||
setContentText(extNames)
|
setContentText(extNames)
|
||||||
setStyle(NotificationCompat.BigTextStyle().bigText(extNames))
|
setStyle(NotificationCompat.BigTextStyle().bigText(extNames))
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user