|
|
|
@ -2,6 +2,7 @@ package org.koitharu.kotatsu.core.prefs
|
|
|
|
|
|
|
|
|
|
|
|
import android.content.Context
|
|
|
|
import android.content.Context
|
|
|
|
import android.content.SharedPreferences
|
|
|
|
import android.content.SharedPreferences
|
|
|
|
|
|
|
|
import android.net.Uri
|
|
|
|
import android.os.Build
|
|
|
|
import android.os.Build
|
|
|
|
import android.provider.Settings
|
|
|
|
import android.provider.Settings
|
|
|
|
import androidx.appcompat.app.AppCompatDelegate
|
|
|
|
import androidx.appcompat.app.AppCompatDelegate
|
|
|
|
@ -13,106 +14,113 @@ import kotlinx.coroutines.channels.awaitClose
|
|
|
|
import kotlinx.coroutines.channels.trySendBlocking
|
|
|
|
import kotlinx.coroutines.channels.trySendBlocking
|
|
|
|
import kotlinx.coroutines.flow.callbackFlow
|
|
|
|
import kotlinx.coroutines.flow.callbackFlow
|
|
|
|
import org.koitharu.kotatsu.core.model.ZoomMode
|
|
|
|
import org.koitharu.kotatsu.core.model.ZoomMode
|
|
|
|
import org.koitharu.kotatsu.utils.delegates.prefs.*
|
|
|
|
import org.koitharu.kotatsu.utils.ext.toUriOrNull
|
|
|
|
import java.io.File
|
|
|
|
import java.io.File
|
|
|
|
import java.text.DateFormat
|
|
|
|
import java.text.DateFormat
|
|
|
|
import java.text.SimpleDateFormat
|
|
|
|
import java.text.SimpleDateFormat
|
|
|
|
import java.util.*
|
|
|
|
import java.util.*
|
|
|
|
|
|
|
|
|
|
|
|
class AppSettings private constructor(private val prefs: SharedPreferences) :
|
|
|
|
class AppSettings(context: Context) {
|
|
|
|
SharedPreferences by prefs {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constructor(context: Context) : this(
|
|
|
|
private val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
|
|
|
PreferenceManager.getDefaultSharedPreferences(context)
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var listMode by EnumPreferenceDelegate(
|
|
|
|
var listMode: ListMode
|
|
|
|
ListMode::class.java,
|
|
|
|
get() = prefs.getString(KEY_LIST_MODE, null)?.findEnumValue(ListMode.values()) ?: ListMode.DETAILED_LIST
|
|
|
|
KEY_LIST_MODE,
|
|
|
|
set(value) = prefs.edit { putString(KEY_LIST_MODE, value.name) }
|
|
|
|
ListMode.DETAILED_LIST
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var defaultSection by IntEnumPreferenceDelegate(
|
|
|
|
var defaultSection: AppSection
|
|
|
|
AppSection::class.java,
|
|
|
|
get() = prefs.getString(KEY_APP_SECTION, null)?.findEnumValue(AppSection.values()) ?: AppSection.HISTORY
|
|
|
|
KEY_APP_SECTION,
|
|
|
|
set(value) = prefs.edit { putString(KEY_APP_SECTION, value.name) }
|
|
|
|
AppSection.HISTORY
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
val theme by StringIntPreferenceDelegate(
|
|
|
|
val theme: Int
|
|
|
|
KEY_THEME,
|
|
|
|
get() = prefs.getString(KEY_THEME, null)?.toIntOrNull() ?: AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
|
|
|
|
AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
val isDynamicTheme by BoolPreferenceDelegate(KEY_DYNAMIC_THEME, defaultValue = false)
|
|
|
|
val isDynamicTheme: Boolean
|
|
|
|
|
|
|
|
get() = prefs.getBoolean(KEY_DYNAMIC_THEME, false)
|
|
|
|
|
|
|
|
|
|
|
|
val isAmoledTheme by BoolPreferenceDelegate(KEY_THEME_AMOLED, defaultValue = false)
|
|
|
|
val isAmoledTheme: Boolean
|
|
|
|
|
|
|
|
get() = prefs.getBoolean(KEY_THEME_AMOLED, false)
|
|
|
|
|
|
|
|
|
|
|
|
val isToolbarHideWhenScrolling by BoolPreferenceDelegate(KEY_HIDE_TOOLBAR, defaultValue = true)
|
|
|
|
val isToolbarHideWhenScrolling: Boolean
|
|
|
|
|
|
|
|
get() = prefs.getBoolean(KEY_HIDE_TOOLBAR, true)
|
|
|
|
|
|
|
|
|
|
|
|
var gridSize by IntPreferenceDelegate(KEY_GRID_SIZE, defaultValue = 100)
|
|
|
|
var gridSize: Int
|
|
|
|
|
|
|
|
get() = prefs.getInt(KEY_GRID_SIZE, 100)
|
|
|
|
|
|
|
|
set(value) = prefs.edit { putInt(KEY_GRID_SIZE, value) }
|
|
|
|
|
|
|
|
|
|
|
|
val readerPageSwitch by StringSetPreferenceDelegate(
|
|
|
|
val readerPageSwitch: Set<String>
|
|
|
|
KEY_READER_SWITCHERS,
|
|
|
|
get() = prefs.getStringSet(KEY_READER_SWITCHERS, null) ?: setOf(PAGE_SWITCH_TAPS)
|
|
|
|
arraySetOf(PAGE_SWITCH_TAPS)
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var isTrafficWarningEnabled by BoolPreferenceDelegate(KEY_TRAFFIC_WARNING, defaultValue = true)
|
|
|
|
var isTrafficWarningEnabled: Boolean
|
|
|
|
|
|
|
|
get() = prefs.getBoolean(KEY_TRAFFIC_WARNING, true)
|
|
|
|
|
|
|
|
set(value) = prefs.edit { putBoolean(KEY_TRAFFIC_WARNING, value) }
|
|
|
|
|
|
|
|
|
|
|
|
val appUpdateAuto by BoolPreferenceDelegate(KEY_APP_UPDATE_AUTO, defaultValue = true)
|
|
|
|
val appUpdateAuto: Boolean
|
|
|
|
|
|
|
|
get() = prefs.getBoolean(KEY_APP_UPDATE_AUTO, true)
|
|
|
|
|
|
|
|
|
|
|
|
var appUpdate by LongPreferenceDelegate(KEY_APP_UPDATE, defaultValue = 0L)
|
|
|
|
var appUpdate: Long
|
|
|
|
|
|
|
|
get() = prefs.getLong(KEY_APP_UPDATE, 0L)
|
|
|
|
|
|
|
|
set(value) = prefs.edit { putLong(KEY_APP_UPDATE, value) }
|
|
|
|
|
|
|
|
|
|
|
|
val trackerNotifications by BoolPreferenceDelegate(
|
|
|
|
val trackerNotifications: Boolean
|
|
|
|
KEY_TRACKER_NOTIFICATIONS,
|
|
|
|
get() = prefs.getBoolean(KEY_TRACKER_NOTIFICATIONS, true)
|
|
|
|
defaultValue = true
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var notificationSound by StringPreferenceDelegate(
|
|
|
|
var notificationSound: Uri
|
|
|
|
KEY_NOTIFICATIONS_SOUND,
|
|
|
|
get() = prefs.getString(KEY_NOTIFICATIONS_SOUND, null)?.toUriOrNull()
|
|
|
|
Settings.System.DEFAULT_NOTIFICATION_URI.toString()
|
|
|
|
?: Settings.System.DEFAULT_NOTIFICATION_URI
|
|
|
|
)
|
|
|
|
set(value) = prefs.edit { putString(KEY_NOTIFICATIONS_SOUND, value.toString()) }
|
|
|
|
|
|
|
|
|
|
|
|
val notificationVibrate by BoolPreferenceDelegate(KEY_NOTIFICATIONS_VIBRATE, false)
|
|
|
|
val notificationVibrate: Boolean
|
|
|
|
|
|
|
|
get() = prefs.getBoolean(KEY_NOTIFICATIONS_VIBRATE, false)
|
|
|
|
|
|
|
|
|
|
|
|
val notificationLight by BoolPreferenceDelegate(KEY_NOTIFICATIONS_LIGHT, true)
|
|
|
|
val notificationLight: Boolean
|
|
|
|
|
|
|
|
get() = prefs.getBoolean(KEY_NOTIFICATIONS_LIGHT, true)
|
|
|
|
|
|
|
|
|
|
|
|
val readerAnimation by BoolPreferenceDelegate(KEY_READER_ANIMATION, false)
|
|
|
|
val readerAnimation: Boolean
|
|
|
|
|
|
|
|
get() = prefs.getBoolean(KEY_READER_ANIMATION, false)
|
|
|
|
|
|
|
|
|
|
|
|
val isPreferRtlReader by BoolPreferenceDelegate(KEY_READER_PREFER_RTL, false)
|
|
|
|
val isPreferRtlReader: Boolean
|
|
|
|
|
|
|
|
get() = prefs.getBoolean(KEY_READER_PREFER_RTL, false)
|
|
|
|
|
|
|
|
|
|
|
|
var historyGrouping by BoolPreferenceDelegate(KEY_HISTORY_GROUPING, true)
|
|
|
|
var historyGrouping: Boolean
|
|
|
|
|
|
|
|
get() = prefs.getBoolean(KEY_HISTORY_GROUPING, true)
|
|
|
|
|
|
|
|
set(value) = prefs.edit { putBoolean(KEY_HISTORY_GROUPING, value) }
|
|
|
|
|
|
|
|
|
|
|
|
var isHistoryExcludeNsfw by BoolPreferenceDelegate(KEY_HISTORY_EXCLUDE_NSFW, false)
|
|
|
|
val isHistoryExcludeNsfw: Boolean
|
|
|
|
|
|
|
|
get() = prefs.getBoolean(KEY_HISTORY_EXCLUDE_NSFW, false)
|
|
|
|
|
|
|
|
|
|
|
|
var chaptersReverse by BoolPreferenceDelegate(KEY_REVERSE_CHAPTERS, false)
|
|
|
|
var chaptersReverse: Boolean
|
|
|
|
|
|
|
|
get() = prefs.getBoolean(KEY_REVERSE_CHAPTERS, false)
|
|
|
|
|
|
|
|
set(value) = prefs.edit { putBoolean(KEY_REVERSE_CHAPTERS, value) }
|
|
|
|
|
|
|
|
|
|
|
|
val zoomMode by EnumPreferenceDelegate(
|
|
|
|
val zoomMode: ZoomMode
|
|
|
|
ZoomMode::class.java,
|
|
|
|
get() = prefs.getString(KEY_ZOOM_MODE, null)?.findEnumValue(ZoomMode.values()) ?: ZoomMode.FIT_CENTER
|
|
|
|
KEY_ZOOM_MODE,
|
|
|
|
|
|
|
|
ZoomMode.FIT_CENTER
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
val trackSources by StringSetPreferenceDelegate(
|
|
|
|
val trackSources: Set<String>
|
|
|
|
KEY_TRACK_SOURCES,
|
|
|
|
get() = prefs.getStringSet(KEY_TRACK_SOURCES, null) ?: arraySetOf(TRACK_FAVOURITES, TRACK_HISTORY)
|
|
|
|
arraySetOf(TRACK_FAVOURITES, TRACK_HISTORY)
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var appPassword by NullableStringPreferenceDelegate(KEY_APP_PASSWORD)
|
|
|
|
var appPassword: String?
|
|
|
|
|
|
|
|
get() = prefs.getString(KEY_APP_PASSWORD, null)
|
|
|
|
private var sourcesOrderStr by NullableStringPreferenceDelegate(KEY_SOURCES_ORDER)
|
|
|
|
set(value) = prefs.edit { if (value != null) putString(KEY_APP_PASSWORD, value) else remove(KEY_APP_PASSWORD) }
|
|
|
|
|
|
|
|
|
|
|
|
var sourcesOrder: List<Int>
|
|
|
|
var sourcesOrder: List<Int>
|
|
|
|
get() = sourcesOrderStr?.split('|')?.mapNotNull(String::toIntOrNull).orEmpty()
|
|
|
|
get() = prefs.getString(KEY_SOURCES_ORDER, null)
|
|
|
|
set(value) {
|
|
|
|
?.split('|')
|
|
|
|
sourcesOrderStr = value.joinToString("|")
|
|
|
|
?.mapNotNull(String::toIntOrNull)
|
|
|
|
|
|
|
|
.orEmpty()
|
|
|
|
|
|
|
|
set(value) = prefs.edit {
|
|
|
|
|
|
|
|
putString(KEY_SOURCES_ORDER, value.joinToString("|"))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var hiddenSources by StringSetPreferenceDelegate(KEY_SOURCES_HIDDEN)
|
|
|
|
var hiddenSources: Set<String>
|
|
|
|
|
|
|
|
get() = prefs.getStringSet(KEY_SOURCES_HIDDEN, null) ?: emptySet()
|
|
|
|
|
|
|
|
set(value) = prefs.edit { putStringSet(KEY_SOURCES_HIDDEN, value) }
|
|
|
|
|
|
|
|
|
|
|
|
val isSourcesSelected: Boolean
|
|
|
|
val isSourcesSelected: Boolean
|
|
|
|
get() = KEY_SOURCES_HIDDEN in prefs
|
|
|
|
get() = KEY_SOURCES_HIDDEN in prefs
|
|
|
|
|
|
|
|
|
|
|
|
val isPagesNumbersEnabled by BoolPreferenceDelegate(KEY_PAGES_NUMBERS, false)
|
|
|
|
val isPagesNumbersEnabled: Boolean
|
|
|
|
|
|
|
|
get() = prefs.getBoolean(KEY_PAGES_NUMBERS, false)
|
|
|
|
|
|
|
|
|
|
|
|
fun getFallbackStorageDir(): File? {
|
|
|
|
fun getFallbackStorageDir(): File? {
|
|
|
|
return prefs.getString(KEY_LOCAL_STORAGE, null)?.let {
|
|
|
|
return prefs.getString(KEY_LOCAL_STORAGE, null)?.let {
|
|
|
|
@ -131,7 +139,7 @@ class AppSettings private constructor(private val prefs: SharedPreferences) :
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fun dateFormat(format: String? = prefs.getString(KEY_DATE_FORMAT, "")): DateFormat =
|
|
|
|
fun getDateFormat(format: String = prefs.getString(KEY_DATE_FORMAT, "").orEmpty()): DateFormat =
|
|
|
|
when (format) {
|
|
|
|
when (format) {
|
|
|
|
"" -> DateFormat.getDateInstance(DateFormat.SHORT)
|
|
|
|
"" -> DateFormat.getDateInstance(DateFormat.SHORT)
|
|
|
|
else -> SimpleDateFormat(format, Locale.getDefault())
|
|
|
|
else -> SimpleDateFormat(format, Locale.getDefault())
|
|
|
|
@ -156,6 +164,10 @@ class AppSettings private constructor(private val prefs: SharedPreferences) :
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private fun <E : Enum<E>> String.findEnumValue(values: Array<E>): E? {
|
|
|
|
|
|
|
|
return values.find { it.name == this }
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
companion object {
|
|
|
|
companion object {
|
|
|
|
|
|
|
|
|
|
|
|
const val PAGE_SWITCH_TAPS = "taps"
|
|
|
|
const val PAGE_SWITCH_TAPS = "taps"
|
|
|
|
@ -165,7 +177,7 @@ class AppSettings private constructor(private val prefs: SharedPreferences) :
|
|
|
|
const val TRACK_FAVOURITES = "favourites"
|
|
|
|
const val TRACK_FAVOURITES = "favourites"
|
|
|
|
|
|
|
|
|
|
|
|
const val KEY_LIST_MODE = "list_mode_2"
|
|
|
|
const val KEY_LIST_MODE = "list_mode_2"
|
|
|
|
const val KEY_APP_SECTION = "app_section"
|
|
|
|
const val KEY_APP_SECTION = "app_section_2"
|
|
|
|
const val KEY_THEME = "theme"
|
|
|
|
const val KEY_THEME = "theme"
|
|
|
|
const val KEY_DYNAMIC_THEME = "dynamic_theme"
|
|
|
|
const val KEY_DYNAMIC_THEME = "dynamic_theme"
|
|
|
|
const val KEY_THEME_AMOLED = "amoled_theme"
|
|
|
|
const val KEY_THEME_AMOLED = "amoled_theme"
|
|
|
|
@ -215,7 +227,7 @@ class AppSettings private constructor(private val prefs: SharedPreferences) :
|
|
|
|
|
|
|
|
|
|
|
|
val isDynamicColorAvailable: Boolean
|
|
|
|
val isDynamicColorAvailable: Boolean
|
|
|
|
get() = DynamicColors.isDynamicColorAvailable() ||
|
|
|
|
get() = DynamicColors.isDynamicColorAvailable() ||
|
|
|
|
(isSamsung && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
|
|
|
|
(isSamsung && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
|
|
|
|
|
|
|
|
|
|
|
|
private val isSamsung
|
|
|
|
private val isSamsung
|
|
|
|
get() = Build.MANUFACTURER.equals("samsung", ignoreCase = true)
|
|
|
|
get() = Build.MANUFACTURER.equals("samsung", ignoreCase = true)
|
|
|
|
|