Files
EhViewer/app/src/main/java/com/hippo/ehviewer/Settings.kt
T
2023-06-01 21:10:47 +08:00

345 lines
15 KiB
Kotlin
Executable File

/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer
import android.content.SharedPreferences
import android.net.Uri
import android.util.Log
import androidx.annotation.DimenRes
import androidx.preference.PreferenceManager
import com.hippo.ehviewer.client.data.FavListUrlBuilder
import com.hippo.ehviewer.ui.scene.GalleryListScene
import com.hippo.ehviewer.yorozuya.LayoutUtils.dp2pix
import com.hippo.ehviewer.yorozuya.NumberUtils
import com.hippo.unifile.UniFile
import splitties.experimental.ExperimentalSplittiesApi
import splitties.init.appCtx
import splitties.preferences.DefaultPreferences
import java.util.Locale
import kotlin.reflect.KProperty
@OptIn(ExperimentalSplittiesApi::class)
object Settings : DefaultPreferences() {
const val KEY_THEME = "theme"
const val KEY_ACCOUNT = "account"
const val KEY_IMAGE_LIMITS = "image_limits"
const val KEY_U_CONFIG = "uconfig"
const val KEY_MY_TAGS = "mytags"
const val KEY_BLACK_DARK_THEME = "black_dark_theme"
const val KEY_GALLERY_SITE = "gallery_site"
const val KEY_LIST_MODE = "list_mode"
const val KEY_DETAIL_SIZE = "detail_size"
const val KEY_THUMB_SIZE = "thumb_size_"
const val KEY_THUMB_RESOLUTION = "thumb_resolution"
const val KEY_SHOW_JPN_TITLE = "show_jpn_title"
const val KEY_SHOW_TAG_TRANSLATIONS = "show_tag_translations"
const val KEY_TAG_TRANSLATIONS_SOURCE = "tag_translations_source"
const val KEY_REQUEST_NEWS = "request_news"
const val KEY_REQUEST_NEWS_TIMER = "request_news_timer"
const val KEY_REQUEST_NEWS_TIMER_HOUR = "request_news_timer_hour"
const val KEY_REQUEST_NEWS_TIMER_MINUTE = "request_news_timer_minute"
const val KEY_HIDE_HV_EVENTS = "hide_hv_events"
val SIGN_IN_REQUIRED = arrayOf(
KEY_IMAGE_LIMITS,
KEY_GALLERY_SITE,
KEY_U_CONFIG,
KEY_MY_TAGS,
KEY_SHOW_JPN_TITLE,
KEY_REQUEST_NEWS,
KEY_REQUEST_NEWS_TIMER,
KEY_HIDE_HV_EVENTS,
)
const val KEY_DOWNLOAD_SAVE_SCHEME = "image_scheme"
const val KEY_DOWNLOAD_SAVE_AUTHORITY = "image_authority"
const val KEY_DOWNLOAD_SAVE_PATH = "image_path"
const val KEY_DOWNLOAD_SAVE_QUERY = "image_query"
const val KEY_DOWNLOAD_SAVE_FRAGMENT = "image_fragment"
const val KEY_MEDIA_SCAN = "media_scan"
const val INVALID_DEFAULT_FAV_SLOT = -2
const val KEY_READ_CACHE_SIZE = "read_cache_size"
const val KEY_BUILT_IN_HOSTS = "built_in_hosts_2"
const val KEY_DOMAIN_FRONTING = "domain_fronting"
const val KEY_BYPASS_VPN = "bypass_vpn"
const val KEY_LIST_THUMB_SIZE = "list_tile_size"
private val TAG = Settings::class.java.simpleName
private const val KEY_LAUNCH_PAGE = "launch_page"
private const val DEFAULT_LAUNCH_PAGE = 0
private const val KEY_FAV_CAT_0 = "fav_cat_0"
private const val KEY_FAV_CAT_1 = "fav_cat_1"
private const val KEY_FAV_CAT_2 = "fav_cat_2"
private const val KEY_FAV_CAT_3 = "fav_cat_3"
private const val KEY_FAV_CAT_4 = "fav_cat_4"
private const val KEY_FAV_CAT_5 = "fav_cat_5"
private const val KEY_FAV_CAT_6 = "fav_cat_6"
private const val KEY_FAV_CAT_7 = "fav_cat_7"
private const val KEY_FAV_CAT_8 = "fav_cat_8"
private const val KEY_FAV_CAT_9 = "fav_cat_9"
private const val DEFAULT_FAV_CAT_0 = "Favorites 0"
private const val DEFAULT_FAV_CAT_1 = "Favorites 1"
private const val DEFAULT_FAV_CAT_2 = "Favorites 2"
private const val DEFAULT_FAV_CAT_3 = "Favorites 3"
private const val DEFAULT_FAV_CAT_4 = "Favorites 4"
private const val DEFAULT_FAV_CAT_5 = "Favorites 5"
private const val DEFAULT_FAV_CAT_6 = "Favorites 6"
private const val DEFAULT_FAV_CAT_7 = "Favorites 7"
private const val DEFAULT_FAV_CAT_8 = "Favorites 8"
private const val DEFAULT_FAV_CAT_9 = "Favorites 9"
private const val KEY_FAV_COUNT_0 = "fav_count_0"
private const val KEY_FAV_COUNT_1 = "fav_count_1"
private const val KEY_FAV_COUNT_2 = "fav_count_2"
private const val KEY_FAV_COUNT_3 = "fav_count_3"
private const val KEY_FAV_COUNT_4 = "fav_count_4"
private const val KEY_FAV_COUNT_5 = "fav_count_5"
private const val KEY_FAV_COUNT_6 = "fav_count_6"
private const val KEY_FAV_COUNT_7 = "fav_count_7"
private const val KEY_FAV_COUNT_8 = "fav_count_8"
private const val KEY_FAV_COUNT_9 = "fav_count_9"
private lateinit var sSettingsPre: SharedPreferences
fun initialize() {
sSettingsPre = PreferenceManager.getDefaultSharedPreferences(appCtx)
fixDefaultValue()
}
private fun fixDefaultValue() {
if ("CN" == Locale.getDefault().country) {
// Enable domain fronting if the country is CN
if (!sSettingsPre.contains(KEY_BUILT_IN_HOSTS)) {
builtInHosts = true
}
if (!sSettingsPre.contains(KEY_DOMAIN_FRONTING)) {
dF = true
}
// Enable show tag translations if the country is CN
if (!sSettingsPre.contains(KEY_SHOW_TAG_TRANSLATIONS)) {
showTagTranslations = true
}
}
}
@JvmStatic
fun getInt(key: String, defValue: Int): Int {
return try {
sSettingsPre.getInt(key, defValue)
} catch (e: ClassCastException) {
Log.d(TAG, "Get ClassCastException when get $key value", e)
defValue
}
}
@JvmStatic
fun putInt(key: String, value: Int) {
sSettingsPre.edit().putInt(key, value).apply()
}
private fun getString(key: String, defValue: String?): String? {
return try {
sSettingsPre.getString(key, defValue)
} catch (e: ClassCastException) {
Log.d(TAG, "Get ClassCastException when get $key value", e)
defValue
}
}
private fun putString(key: String, value: String?) {
sSettingsPre.edit().putString(key, value).apply()
}
private fun getIntFromStr(key: String, defValue: Int): Int {
return try {
NumberUtils.parseIntSafely(
sSettingsPre.getString(key, defValue.toString()),
defValue,
)
} catch (e: ClassCastException) {
Log.d(TAG, "Get ClassCastException when get $key value", e)
defValue
}
}
val launchPageGalleryListSceneAction: String
get() {
return when (val value = getIntFromStr(KEY_LAUNCH_PAGE, DEFAULT_LAUNCH_PAGE)) {
0 -> GalleryListScene.ACTION_HOMEPAGE
1 -> GalleryListScene.ACTION_SUBSCRIPTION
2 -> GalleryListScene.ACTION_WHATS_HOT
3 -> GalleryListScene.ACTION_TOP_LIST
else -> throw IllegalStateException("Unexpected value: $value")
}
}
@get:DimenRes
val detailSizeResId: Int
get() = when (detailSize) {
0 -> R.dimen.gallery_list_column_width_long
1 -> R.dimen.gallery_list_column_width_short
else -> throw IllegalStateException("Unexpected value: $detailSize")
}
val thumbSize: Int
get() = dp2pix(appCtx, thumbSizeDp.toFloat())
val downloadLocation: UniFile?
get() {
val dir: UniFile?
val builder = Uri.Builder()
builder.scheme(getString(KEY_DOWNLOAD_SAVE_SCHEME, null))
builder.encodedAuthority(getString(KEY_DOWNLOAD_SAVE_AUTHORITY, null))
builder.encodedPath(getString(KEY_DOWNLOAD_SAVE_PATH, null))
builder.encodedQuery(getString(KEY_DOWNLOAD_SAVE_QUERY, null))
builder.encodedFragment(getString(KEY_DOWNLOAD_SAVE_FRAGMENT, null))
dir = UniFile.fromUri(appCtx, builder.build())
return dir ?: UniFile.fromFile(AppConfig.getDefaultDownloadDir())
}
fun putDownloadLocation(location: UniFile) {
val uri = location.uri
putString(KEY_DOWNLOAD_SAVE_SCHEME, uri.scheme)
putString(KEY_DOWNLOAD_SAVE_AUTHORITY, uri.encodedAuthority)
putString(KEY_DOWNLOAD_SAVE_PATH, uri.encodedPath)
putString(KEY_DOWNLOAD_SAVE_QUERY, uri.encodedQuery)
putString(KEY_DOWNLOAD_SAVE_FRAGMENT, uri.encodedFragment)
}
val favCat: Array<String>
get() = arrayOf(
sSettingsPre.getString(KEY_FAV_CAT_0, DEFAULT_FAV_CAT_0)!!,
sSettingsPre.getString(KEY_FAV_CAT_1, DEFAULT_FAV_CAT_1)!!,
sSettingsPre.getString(KEY_FAV_CAT_2, DEFAULT_FAV_CAT_2)!!,
sSettingsPre.getString(KEY_FAV_CAT_3, DEFAULT_FAV_CAT_3)!!,
sSettingsPre.getString(KEY_FAV_CAT_4, DEFAULT_FAV_CAT_4)!!,
sSettingsPre.getString(KEY_FAV_CAT_5, DEFAULT_FAV_CAT_5)!!,
sSettingsPre.getString(KEY_FAV_CAT_6, DEFAULT_FAV_CAT_6)!!,
sSettingsPre.getString(KEY_FAV_CAT_7, DEFAULT_FAV_CAT_7)!!,
sSettingsPre.getString(KEY_FAV_CAT_8, DEFAULT_FAV_CAT_8)!!,
sSettingsPre.getString(KEY_FAV_CAT_9, DEFAULT_FAV_CAT_9)!!,
)
fun putFavCat(value: Array<String?>) {
check(value.size == 10)
sSettingsPre.edit()
.putString(KEY_FAV_CAT_0, value[0])
.putString(KEY_FAV_CAT_1, value[1])
.putString(KEY_FAV_CAT_2, value[2])
.putString(KEY_FAV_CAT_3, value[3])
.putString(KEY_FAV_CAT_4, value[4])
.putString(KEY_FAV_CAT_5, value[5])
.putString(KEY_FAV_CAT_6, value[6])
.putString(KEY_FAV_CAT_7, value[7])
.putString(KEY_FAV_CAT_8, value[8])
.putString(KEY_FAV_CAT_9, value[9])
.apply()
}
val favCount: IntArray
get() = intArrayOf(
sSettingsPre.getInt(KEY_FAV_COUNT_0, 0),
sSettingsPre.getInt(KEY_FAV_COUNT_1, 0),
sSettingsPre.getInt(KEY_FAV_COUNT_2, 0),
sSettingsPre.getInt(KEY_FAV_COUNT_3, 0),
sSettingsPre.getInt(KEY_FAV_COUNT_4, 0),
sSettingsPre.getInt(KEY_FAV_COUNT_5, 0),
sSettingsPre.getInt(KEY_FAV_COUNT_6, 0),
sSettingsPre.getInt(KEY_FAV_COUNT_7, 0),
sSettingsPre.getInt(KEY_FAV_COUNT_8, 0),
sSettingsPre.getInt(KEY_FAV_COUNT_9, 0),
)
fun putFavCount(count: IntArray) {
check(count.size == 10)
sSettingsPre.edit()
.putInt(KEY_FAV_COUNT_0, count[0])
.putInt(KEY_FAV_COUNT_1, count[1])
.putInt(KEY_FAV_COUNT_2, count[2])
.putInt(KEY_FAV_COUNT_3, count[3])
.putInt(KEY_FAV_COUNT_4, count[4])
.putInt(KEY_FAV_COUNT_5, count[5])
.putInt(KEY_FAV_COUNT_6, count[6])
.putInt(KEY_FAV_COUNT_7, count[7])
.putInt(KEY_FAV_COUNT_8, count[8])
.putInt(KEY_FAV_COUNT_9, count[9])
.apply()
}
var archivePasswds by stringSetOrNullPref("archive_passwds")
val downloadDelay by intFromStrPref("download_delay", 0)
var gallerySite by intFromStrPref(KEY_GALLERY_SITE, 0)
val multiThreadDownload by intFromStrPref("download_thread", 3)
val preloadImage by intFromStrPref("preload_image", 5)
val theme by intFromStrPref(KEY_THEME, -1)
val listMode by intFromStrPref(KEY_LIST_MODE, 0)
val detailSize by intFromStrPref(KEY_DETAIL_SIZE, 0)
val thumbResolution by intFromStrPref(KEY_THUMB_RESOLUTION, 0)
val readCacheSize by intFromStrPref(KEY_READ_CACHE_SIZE, 640)
val showComments by boolPref("show_gallery_comments", true)
val requestNews by boolPref(KEY_REQUEST_NEWS, false)
val hideHvEvents by boolPref(KEY_HIDE_HV_EVENTS, false)
val showJpnTitle by boolPref(KEY_SHOW_JPN_TITLE, false)
val showGalleryPages by boolPref("show_gallery_pages", false)
var showTagTranslations by boolPref(KEY_SHOW_TAG_TRANSLATIONS, false)
val meteredNetworkWarning by boolPref("cellular_network_warning", false)
var appLinkVerifyTip by boolPref("app_link_verify_tip", false)
val enabledSecurity by boolPref("enable_secure", false)
val mediaScan by boolPref(KEY_MEDIA_SCAN, false)
var hasDefaultDownloadLabel by boolPref("has_default_download_label", false)
var qSSaveProgress by boolPref("qs_save_progress", true)
val saveParseErrorBody by boolPref("save_parse_error_body", true)
val saveCrashLog by boolPref("save_crash_log", true)
var security by boolPref("require_unlock", false)
var builtInHosts by boolPref(KEY_BUILT_IN_HOSTS, false)
var removeImageFiles by boolPref("include_pic", true)
var needSignIn by boolPref("need_sign_in", true)
var selectSite by boolPref("select_site", true)
val blackDarkTheme by boolPref(KEY_BLACK_DARK_THEME, false)
val preloadThumbAggressively by boolPref("preload_thumb_aggressively", false)
var dF by boolPref(KEY_DOMAIN_FRONTING, false)
val downloadOriginImage by boolPref("download_origin_image", false)
val bypassVpn by boolPref(KEY_BYPASS_VPN, true)
val thumbSizeDp by intPref(KEY_THUMB_SIZE, 120)
var favLocalCount by intPref("fav_local", 0)
var favCloudCount by intPref("fav_cloud", 0)
var recentFavCat by intPref("recent_fav_cat", FavListUrlBuilder.FAV_CAT_ALL)
var defaultFavSlot by intPref("default_favorite_2", INVALID_DEFAULT_FAV_SLOT) // -1 for local, 0 - 9 for cloud favorite, other for no default fav slot
val securityDelay by intPref("require_unlock_delay", 0)
var proxyType by intPref("proxy_type", EhProxySelector.TYPE_SYSTEM)
var proxyPort by intPref("proxy_port", -1)
var clipboardTextHashCode by intPref("clipboard_text_hash_code", 0)
val listThumbSize by intPref(KEY_LIST_THUMB_SIZE, 40)
var recentDownloadLabel by stringOrNullPref("recent_download_label", null)
var defaultDownloadLabel by stringOrNullPref("default_download_label", null)
var displayName by stringOrNullPref("display_name", null)
var avatar by stringOrNullPref("avatar", null)
var proxyIp by stringOrNullPref("proxy_ip", null)
var dohUrl by stringPref("doh_url", "")
var lastDawnDay by longPref("last_dawn_day", 0)
private fun intFromStrPref(key: String, defValue: Int) = object : Delegate<Int> {
private var _value by stringPref(key, defValue.toString())
override fun getValue(thisRef: Any?, prop: KProperty<*>?) = _value.toIntOrNull() ?: defValue
override fun setValue(thisRef: Any?, prop: KProperty<*>?, value: Int) { _value = value.toString() }
}
}
interface Delegate<R> {
operator fun getValue(thisRef: Any?, prop: KProperty<*>?): R
operator fun setValue(thisRef: Any?, prop: KProperty<*>?, value: R)
}