diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/BackupRepository.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/BackupRepository.kt index 21b4940c9..28589ab9b 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/BackupRepository.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/BackupRepository.kt @@ -1,28 +1,14 @@ package org.koitharu.kotatsu.core.backup -import android.provider.Settings import androidx.room.withTransaction import org.json.JSONArray import org.json.JSONObject import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.core.db.MangaDatabase -import org.koitharu.kotatsu.core.model.ZoomMode -import org.koitharu.kotatsu.core.network.DoHProvider import org.koitharu.kotatsu.core.prefs.AppSettings -import org.koitharu.kotatsu.core.prefs.ColorScheme -import org.koitharu.kotatsu.core.prefs.ListMode -import org.koitharu.kotatsu.core.prefs.ReaderMode -import org.koitharu.kotatsu.core.util.ext.getEnumValue -import org.koitharu.kotatsu.core.util.ext.takeIfReadable -import org.koitharu.kotatsu.core.util.ext.toUriOrNull -import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.util.json.JSONIterator -import org.koitharu.kotatsu.parsers.util.json.getFloatOrDefault -import org.koitharu.kotatsu.parsers.util.json.getStringOrNull import org.koitharu.kotatsu.parsers.util.json.mapJSON -import org.koitharu.kotatsu.parsers.util.mapNotNullToSet import org.koitharu.kotatsu.parsers.util.runCatchingCancellable -import java.io.File import javax.inject.Inject private const val PAGE_SIZE = 10 @@ -85,9 +71,9 @@ class BackupRepository @Inject constructor( return entry } - suspend fun dumpSettings(): BackupEntry { + fun dumpSettings(): BackupEntry { val entry = BackupEntry(BackupEntry.SETTINGS, JSONArray()) - val json = JsonSerializer(settings).toJson() + val json = JsonSerializer(settings.getAllValues()).toJson() entry.data.put(json) return entry } @@ -157,60 +143,7 @@ class BackupRepository @Inject constructor( val result = CompositeResult() for (item in entry.data.JSONIterator()) { result += runCatchingCancellable { - settings.listMode = item.getString("list_mode").getEnumValue(ListMode.GRID) - settings.theme = item.getInt("theme") - settings.colorScheme = item.getString("color_scheme").getEnumValue(ColorScheme.default) - settings.isAmoledTheme = item.getBoolean("is_amoled_theme") - settings.gridSize = item.getInt("grid_size") - settings.readerPageSwitch = - item.getJSONArray("reader_page_switch").mapJSONToSet { it } - settings.isReaderTapsAdaptive = item.getBoolean("is_reader_taps_adaptive") - settings.isTrafficWarningEnabled = item.getBoolean("is_traffic_waring_enabled") - settings.isAllFavouritesVisible = item.getBoolean("is_all_favourites_visible") - settings.isTrackerEnabled = item.getBoolean("is_tracker_enabled") - settings.isTrackerNotificationsEnabled = item.getBoolean("is_tracker_notifications_enabled") - settings.notificationSound = - item.getString("notification_sound").toUriOrNull() ?: Settings.System.DEFAULT_NOTIFICATION_URI - settings.notificationVibrate = item.getBoolean("notification_vibrate") - settings.notificationLight = item.getBoolean("notification_light") - settings.readerAnimation = item.getBoolean("reader_animation") - settings.defaultReaderMode = item.getString("default_reader_node").getEnumValue(ReaderMode.STANDARD) - settings.isReaderModeDetectionEnabled = item.getBoolean("is_reader_mode_detection_enabled") - settings.isHistoryGroupingEnabled = item.getBoolean("is_history_grouping_enabled") - settings.isReadingIndicatorsEnabled = item.getBoolean("is_reading_indicators_enabled") - settings.isHistoryExcludeNsfw = item.getBoolean("is_history_exclude_nsfw") - settings.isIncognitoModeEnabled = item.getBoolean("is_incognito_mode_enabled") - settings.chaptersReverse = item.getBoolean("chapters_reverse") - settings.zoomMode = item.getString("zoom_mode").getEnumValue(ZoomMode.FIT_CENTER) - settings.trackSources = item.getJSONArray("track_sources").mapJSONToSet { it } - settings.isLoggingEnabled = item.getBoolean("is_logging_enabled") - settings.isMirrorSwitchingAvailable = item.getBoolean("is_mirror_switching_available") - settings.isExitConfirmationEnabled = item.getBoolean("is_exit_confirmation_enabled") - settings.isDynamicShortcutsEnabled = item.getBoolean("is_dynamic_shortcuts_enabled") - settings.isUnstableUpdatesAllowed = item.getBoolean("is_unstable_updates_allowed") - settings.sourcesOrder = item.getJSONArray("sources_order").mapJSONToArray { it } - settings.hiddenSources = item.getJSONArray("hidden_sources").mapJSONToSet { it } - settings.isSourcesGridMode = item.getBoolean("is_sources_grid_mode") - settings.userSpecifiedMangaDirectories = item.getJSONArray("user_specified_manga_directions") - .mapJSONToSet { it }.mapNotNullToSet { File(it).takeIfReadable() } - File(item.getStringOrNull("manga_storage_dir") ?: "").takeIfReadable()?.let { - settings.mangaStorageDir = it - } - settings.isDownloadsSlowdownEnabled = item.getBoolean("is_downloads_slowdown_enabled") - settings.isDownloadsWiFiOnly = item.getBoolean("is_downloads_wifi_only") - settings.isSuggestionsEnabled = item.getBoolean("is_suggestions_enabled") - settings.isSuggestionsExcludeNsfw = item.getBoolean("is_suggestions_exclude_nsfw") - settings.isSuggestionsNotificationAvailable = item.getBoolean("is_suggestions_notification_available") - settings.suggestionsTagsBlacklist = - item.getJSONArray("suggestions_tags_blacklist").mapJSONToSet { it } - settings.isReaderBarEnabled = item.getBoolean("is_reader_bar_enabled") - settings.isReaderSliderEnabled = item.getBoolean("is_reader_slider_enabled") - settings.isImagesProxyEnabled = item.getBoolean("is_images_proxy_enabled") - settings.dnsOverHttps = item.getString("dns_over_https").getEnumValue(DoHProvider.NONE) - settings.isSSLBypassEnabled = item.getBoolean("is_ssl_bypass_enabled") - settings.localListOrder = item.getString("local_list_order").getEnumValue(SortOrder.NEWEST) - settings.isWebtoonZoomEnable = item.getBoolean("is_webtoon_zoom_enabled") - settings.readerAutoscrollSpeed = item.getFloatOrDefault("reader_autoscroll_speed", 0f) + settings.restoreValuesFromMap(JsonDeserializer(item).toMap()) } } return result diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/JsonDeserializer.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/JsonDeserializer.kt index c5dc367e0..c97882cd9 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/JsonDeserializer.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/JsonDeserializer.kt @@ -1,5 +1,6 @@ package org.koitharu.kotatsu.core.backup +import org.json.JSONArray import org.json.JSONObject import org.koitharu.kotatsu.core.db.entity.MangaEntity import org.koitharu.kotatsu.core.db.entity.TagEntity @@ -65,4 +66,29 @@ class JsonDeserializer(private val json: JSONObject) { isVisibleInLibrary = json.getBooleanOrDefault("show_in_lib", true), deletedAt = 0L, ) + + fun toMap(): Map { + val map = mutableMapOf() + val keys = json.keys() + + while (keys.hasNext()) { + val key = keys.next() + val value = json.get(key) + map[key] = value + } + + return map + } } + + +fun JSONArray.mapJSONToSet(block: (K) -> T): Set { + val len = length() + val result = androidx.collection.ArraySet(len) + for (i in 0 until len) { + val jo = get(i) as K + result.add(block(jo)) + } + return result +} + diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/JsonSerializer.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/JsonSerializer.kt index 980259092..7793bb195 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/JsonSerializer.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/JsonSerializer.kt @@ -1,14 +1,11 @@ package org.koitharu.kotatsu.core.backup -import org.json.JSONArray import org.json.JSONObject import org.koitharu.kotatsu.core.db.entity.MangaEntity import org.koitharu.kotatsu.core.db.entity.TagEntity -import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.favourites.data.FavouriteCategoryEntity import org.koitharu.kotatsu.favourites.data.FavouriteEntity import org.koitharu.kotatsu.history.data.HistoryEntity -import java.util.ArrayList class JsonSerializer private constructor(private val json: JSONObject) { @@ -71,88 +68,9 @@ class JsonSerializer private constructor(private val json: JSONObject) { }, ) - constructor(e: AppSettings) : this( - JSONObject().apply { - put("list_mode", e.listMode.name) - put("theme", e.theme) - put("color_scheme", e.colorScheme.name) - put("is_amoled_theme", e.isAmoledTheme) - put("grid_size", e.gridSize) - put("reader_page_switch", JSONArray(e.readerPageSwitch)) - put("is_reader_taps_adaptive", e.isReaderTapsAdaptive) - put("is_traffic_waring_enabled", e.isTrafficWarningEnabled) - put("is_all_favourites_visible", e.isAllFavouritesVisible) - put("is_tracker_enabled", e.isTrackerEnabled) - put("is_tracker_notifications_enabled", e.isTrackerNotificationsEnabled) - put("notification_sound", e.notificationSound.toString()) - put("notification_vibrate", e.notificationVibrate) - put("notification_light", e.notificationLight) - put("reader_animation", e.readerAnimation) - put("default_reader_node", e.defaultReaderMode.name) - put("is_reader_mode_detection_enabled", e.isReaderModeDetectionEnabled) - put("is_history_grouping_enabled", e.isHistoryGroupingEnabled) - put("is_reading_indicators_enabled", e.isReadingIndicatorsEnabled) - put("is_history_exclude_nsfw", e.isHistoryExcludeNsfw) - put("is_incognito_mode_enabled", e.isIncognitoModeEnabled) // maybe we should omit this - put("chapters_reverse", e.chaptersReverse) - put("zoom_mode", e.zoomMode) - put("track_sources", JSONArray(e.trackSources)) - put("is_logging_enabled", e.isLoggingEnabled) - put("is_mirror_switching_available", e.isMirrorSwitchingAvailable) - put("is_exit_confirmation_enabled", e.isExitConfirmationEnabled) - put("is_dynamic_shortcuts_enabled", e.isDynamicShortcutsEnabled) - put("is_unstable_updates_allowed", e.isUnstableUpdatesAllowed) - put("sources_order", JSONArray(e.sourcesOrder)) - put("hidden_sources", JSONArray(e.hiddenSources)) - put("is_sources_grid_mode", e.isSourcesGridMode) - put( - "user_specified_manga_directions", - JSONArray(e.userSpecifiedMangaDirectories.map { it.absolutePath }), - ) - put("manga_storage_dir", e.mangaStorageDir?.absolutePath) - put("is_downloads_slowdown_enabled", e.isDownloadsSlowdownEnabled) - put("is_downloads_wifi_only", e.isDownloadsWiFiOnly) - put("is_suggestions_enabled", e.isSuggestionsEnabled) - put("is_suggestions_exclude_nsfw", e.isSuggestionsExcludeNsfw) - put("is_suggestions_notification_available", e.isSuggestionsNotificationAvailable) - put("suggestions_tags_blacklist", JSONArray(e.suggestionsTagsBlacklist)) - put("is_reader_bar_enabled", e.isReaderBarEnabled) - put("is_reader_slider_enabled", e.isReaderSliderEnabled) - put("is_images_proxy_enabled", e.isImagesProxyEnabled) - put("dns_over_https", e.dnsOverHttps.name) - put("is_ssl_bypass_enabled", e.isSSLBypassEnabled) - put("local_list_order", e.localListOrder.name) - put("is_webtoon_zoom_enabled", e.isWebtoonZoomEnable) - put("reader_autoscroll_speed", e.readerAutoscrollSpeed) - }, + constructor(m: Map) : this( + JSONObject(m), ) fun toJson(): JSONObject = json } - - -// I have copied these extension functions from parser library, -// because, library doesn't support mapping primitive types (string, int, float ...), -// I didn't know where to put this extension functions :( - -inline fun JSONArray.mapJSONToArray( - block: (K) -> T, -): List { - val len = length() - val result = ArrayList(len) - for (i in 0 until len) { - val jo = get(i) as K - result.add(block(jo)) - } - return result -} - -fun JSONArray.mapJSONToSet(block: (K) -> T): Set { - val len = length() - val result = androidx.collection.ArraySet(len) - for (i in 0 until len) { - val jo = get(i) as K - result.add(block(jo)) - } - return result -} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppSettings.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppSettings.kt index 354f5ee3e..c14a77871 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppSettings.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppSettings.kt @@ -13,7 +13,9 @@ import androidx.core.content.edit import androidx.core.os.LocaleListCompat import androidx.preference.PreferenceManager import dagger.hilt.android.qualifiers.ApplicationContext +import org.json.JSONArray import org.koitharu.kotatsu.BuildConfig +import org.koitharu.kotatsu.core.backup.mapJSONToSet import org.koitharu.kotatsu.core.model.ZoomMode import org.koitharu.kotatsu.core.network.DoHProvider import org.koitharu.kotatsu.core.util.ext.connectivityManager @@ -72,17 +74,14 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) { get() = prefs.getEnumValue(KEY_LIST_MODE, ListMode.GRID) set(value) = prefs.edit { putEnumValue(KEY_LIST_MODE, value) } - var theme: Int + val theme: Int get() = prefs.getString(KEY_THEME, null)?.toIntOrNull() ?: AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM - set(value) = prefs.edit { putString(KEY_THEME, value.toString()) } - var colorScheme: ColorScheme + val colorScheme: ColorScheme get() = prefs.getEnumValue(KEY_COLOR_THEME, ColorScheme.default) - set(value) = prefs.edit { putEnumValue(KEY_COLOR_THEME, value) } - var isAmoledTheme: Boolean + val isAmoledTheme: Boolean get() = prefs.getBoolean(KEY_THEME_AMOLED, false) - set(value) = prefs.edit { putBoolean(KEY_THEME_AMOLED, value) } var gridSize: Int get() = prefs.getInt(KEY_GRID_SIZE, 100) @@ -99,12 +98,11 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) { } } - var readerPageSwitch: Set + val readerPageSwitch: Set get() = prefs.getStringSet(KEY_READER_SWITCHERS, null) ?: setOf(PAGE_SWITCH_TAPS) - set(value) = prefs.edit { putStringSet(KEY_READER_SWITCHERS, value) } - var isReaderTapsAdaptive: Boolean + + val isReaderTapsAdaptive: Boolean get() = !prefs.getBoolean(KEY_READER_TAPS_LTR, false) - set(value) = prefs.edit { putBoolean(KEY_READER_TAPS_LTR, value) } var isTrafficWarningEnabled: Boolean get() = prefs.getBoolean(KEY_TRAFFIC_WARNING, true) @@ -114,50 +112,41 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) { get() = prefs.getBoolean(KEY_ALL_FAVOURITES_VISIBLE, true) set(value) = prefs.edit { putBoolean(KEY_ALL_FAVOURITES_VISIBLE, value) } - var isTrackerEnabled: Boolean + val isTrackerEnabled: Boolean get() = prefs.getBoolean(KEY_TRACKER_ENABLED, true) - set(value) = prefs.edit { putBoolean(KEY_TRACKER_ENABLED, value) } - var isTrackerNotificationsEnabled: Boolean + val isTrackerNotificationsEnabled: Boolean get() = prefs.getBoolean(KEY_TRACKER_NOTIFICATIONS, true) - set(value) = prefs.edit { putBoolean(KEY_TRACKER_NOTIFICATIONS, value) } var notificationSound: Uri get() = prefs.getString(KEY_NOTIFICATIONS_SOUND, null)?.toUriOrNull() ?: Settings.System.DEFAULT_NOTIFICATION_URI set(value) = prefs.edit { putString(KEY_NOTIFICATIONS_SOUND, value.toString()) } - var notificationVibrate: Boolean + val notificationVibrate: Boolean get() = prefs.getBoolean(KEY_NOTIFICATIONS_VIBRATE, false) - set(value) = prefs.edit { putBoolean(KEY_NOTIFICATIONS_VIBRATE, value) } - var notificationLight: Boolean + val notificationLight: Boolean get() = prefs.getBoolean(KEY_NOTIFICATIONS_LIGHT, true) - set(value) = prefs.edit { putBoolean(KEY_NOTIFICATIONS_LIGHT, value) } - var readerAnimation: Boolean + val readerAnimation: Boolean get() = prefs.getBoolean(KEY_READER_ANIMATION, false) - set(value) = prefs.edit { putBoolean(KEY_READER_ANIMATION, value) } - var defaultReaderMode: ReaderMode + val defaultReaderMode: ReaderMode get() = prefs.getEnumValue(KEY_READER_MODE, ReaderMode.STANDARD) - set(value) = prefs.edit { putEnumValue(KEY_READER_MODE, value) } - var isReaderModeDetectionEnabled: Boolean + val isReaderModeDetectionEnabled: Boolean get() = prefs.getBoolean(KEY_READER_MODE_DETECT, true) - set(value) = prefs.edit { putBoolean(KEY_READER_MODE_DETECT, value) } var isHistoryGroupingEnabled: Boolean get() = prefs.getBoolean(KEY_HISTORY_GROUPING, true) set(value) = prefs.edit { putBoolean(KEY_HISTORY_GROUPING, value) } - var isReadingIndicatorsEnabled: Boolean + val isReadingIndicatorsEnabled: Boolean get() = prefs.getBoolean(KEY_READING_INDICATORS, true) - set(value) = prefs.edit { putBoolean(KEY_READING_INDICATORS, value) } - var isHistoryExcludeNsfw: Boolean + val isHistoryExcludeNsfw: Boolean get() = prefs.getBoolean(KEY_HISTORY_EXCLUDE_NSFW, false) - set(value) = prefs.edit { putBoolean(KEY_HISTORY_EXCLUDE_NSFW, value) } var isIncognitoModeEnabled: Boolean get() = prefs.getBoolean(KEY_INCOGNITO_MODE, false) @@ -167,41 +156,34 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) { get() = prefs.getBoolean(KEY_REVERSE_CHAPTERS, false) set(value) = prefs.edit { putBoolean(KEY_REVERSE_CHAPTERS, value) } - var zoomMode: ZoomMode + val zoomMode: ZoomMode get() = prefs.getEnumValue(KEY_ZOOM_MODE, ZoomMode.FIT_CENTER) - set(value) = prefs.edit { putEnumValue(KEY_ZOOM_MODE, value) } - var trackSources: Set + val trackSources: Set get() = prefs.getStringSet(KEY_TRACK_SOURCES, null) ?: arraySetOf(TRACK_FAVOURITES, TRACK_HISTORY) - set(value) = prefs.edit { putStringSet(KEY_TRACK_SOURCES, value) } var appPassword: String? get() = prefs.getString(KEY_APP_PASSWORD, null) set(value) = prefs.edit { if (value != null) putString(KEY_APP_PASSWORD, value) else remove(KEY_APP_PASSWORD) } - var isLoggingEnabled: Boolean + val isLoggingEnabled: Boolean get() = prefs.getBoolean(KEY_LOGGING_ENABLED, false) - set(value) = prefs.edit { putBoolean(KEY_LOGGING_ENABLED, value) } var isBiometricProtectionEnabled: Boolean get() = prefs.getBoolean(KEY_PROTECT_APP_BIOMETRIC, true) set(value) = prefs.edit { putBoolean(KEY_PROTECT_APP_BIOMETRIC, value) } - var isMirrorSwitchingAvailable: Boolean + val isMirrorSwitchingAvailable: Boolean get() = prefs.getBoolean(KEY_MIRROR_SWITCHING, true) - set(value) = prefs.edit { putBoolean(KEY_MIRROR_SWITCHING, value) } - var isExitConfirmationEnabled: Boolean + val isExitConfirmationEnabled: Boolean get() = prefs.getBoolean(KEY_EXIT_CONFIRM, false) - set(value) = prefs.edit { putBoolean(KEY_EXIT_CONFIRM, value) } - var isDynamicShortcutsEnabled: Boolean + val isDynamicShortcutsEnabled: Boolean get() = prefs.getBoolean(KEY_SHORTCUTS, true) - set(value) = prefs.edit { putBoolean(KEY_SHORTCUTS, value) } - var isUnstableUpdatesAllowed: Boolean + val isUnstableUpdatesAllowed: Boolean get() = prefs.getBoolean(KEY_UPDATES_UNSTABLE, false) - set(value) = prefs.edit { putBoolean(KEY_UPDATES_UNSTABLE, value) } val isContentPrefetchEnabled: Boolean get() { @@ -282,27 +264,23 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) { } } - var isDownloadsSlowdownEnabled: Boolean + val isDownloadsSlowdownEnabled: Boolean get() = prefs.getBoolean(KEY_DOWNLOADS_SLOWDOWN, false) - set(value) = prefs.edit { putBoolean(KEY_DOWNLOADS_SLOWDOWN, value) } - var isDownloadsWiFiOnly: Boolean + val isDownloadsWiFiOnly: Boolean get() = prefs.getBoolean(KEY_DOWNLOADS_WIFI, false) - set(value) = prefs.edit { putBoolean(KEY_DOWNLOADS_WIFI, value) } var isSuggestionsEnabled: Boolean get() = prefs.getBoolean(KEY_SUGGESTIONS, false) set(value) = prefs.edit { putBoolean(KEY_SUGGESTIONS, value) } - var isSuggestionsExcludeNsfw: Boolean + val isSuggestionsExcludeNsfw: Boolean get() = prefs.getBoolean(KEY_SUGGESTIONS_EXCLUDE_NSFW, false) - set(value) = prefs.edit { putBoolean(KEY_SUGGESTIONS_EXCLUDE_NSFW, value) } - var isSuggestionsNotificationAvailable: Boolean + val isSuggestionsNotificationAvailable: Boolean get() = prefs.getBoolean(KEY_SUGGESTIONS_NOTIFICATIONS, true) - set(value) = prefs.edit { putBoolean(KEY_SUGGESTIONS_NOTIFICATIONS, value) } - var suggestionsTagsBlacklist: Set + val suggestionsTagsBlacklist: Set get() { val string = prefs.getString(KEY_SUGGESTIONS_EXCLUDE_TAGS, null)?.trimEnd(' ', ',') if (string.isNullOrEmpty()) { @@ -310,27 +288,21 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) { } return string.split(',').mapToSet { it.trim() } } - set(value) = prefs.edit { putStringSet(KEY_SUGGESTIONS_EXCLUDE_TAGS, value) } - var isReaderBarEnabled: Boolean + val isReaderBarEnabled: Boolean get() = prefs.getBoolean(KEY_READER_BAR, true) - set(value) = prefs.edit { putBoolean(KEY_READER_BAR, value) } - var isReaderSliderEnabled: Boolean + val isReaderSliderEnabled: Boolean get() = prefs.getBoolean(KEY_READER_SLIDER, true) - set(value) = prefs.edit { putBoolean(KEY_READER_SLIDER, value) } - var isImagesProxyEnabled: Boolean + val isImagesProxyEnabled: Boolean get() = prefs.getBoolean(KEY_IMAGES_PROXY, false) - set(value) = prefs.edit { putBoolean(KEY_IMAGES_PROXY, value) } - var dnsOverHttps: DoHProvider + val dnsOverHttps: DoHProvider get() = prefs.getEnumValue(KEY_DOH, DoHProvider.NONE) - set(value) = prefs.edit { putEnumValue(KEY_DOH, value) } - var isSSLBypassEnabled: Boolean + val isSSLBypassEnabled: Boolean get() = prefs.getBoolean(KEY_SSL_BYPASS, false) - set(value) = prefs.edit { putBoolean(KEY_SSL_BYPASS, value) } val proxyType: Proxy.Type get() { @@ -354,10 +326,8 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) { get() = prefs.getEnumValue(KEY_LOCAL_LIST_ORDER, SortOrder.NEWEST) set(value) = prefs.edit { putEnumValue(KEY_LOCAL_LIST_ORDER, value) } - var isWebtoonZoomEnable: Boolean + val isWebtoonZoomEnable: Boolean get() = prefs.getBoolean(KEY_WEBTOON_ZOOM, true) - set(value) = prefs.edit { putBoolean(KEY_WEBTOON_ZOOM, value) } - @get:FloatRange(from = 0.0, to = 1.0) var readerAutoscrollSpeed: Float @@ -409,6 +379,23 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) { fun observe() = prefs.observe() + fun getAllValues(): Map = prefs.all + + fun restoreValuesFromMap(m: Map) { + prefs.edit { + m.forEach { e -> + when (e.value) { + is Boolean -> putBoolean(e.key, e.value as Boolean) + is Int -> putInt(e.key, e.value as Int) + is Long -> putLong(e.key, e.value as Long) + is Float -> putFloat(e.key, e.value as Float) + is String -> putString(e.key, e.value as String) + is JSONArray -> putStringSet(e.key, (e.value as JSONArray).mapJSONToSet { it }) + } + } + } + } + private fun isBackgroundNetworkRestricted(): Boolean { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { connectivityManager.restrictBackgroundStatus == ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/UserDataSettingsFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/UserDataSettingsFragment.kt index d280e2bd0..431fdee0b 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/UserDataSettingsFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/UserDataSettingsFragment.kt @@ -8,6 +8,8 @@ import android.os.Bundle import android.view.View import androidx.activity.result.ActivityResultCallback import androidx.activity.result.contract.ActivityResultContracts +import androidx.appcompat.app.AppCompatDelegate +import androidx.core.view.postDelayed import androidx.lifecycle.Lifecycle import androidx.preference.Preference import androidx.preference.TwoStatePreference @@ -24,6 +26,7 @@ import org.koitharu.kotatsu.core.network.cookies.MutableCookieJar import org.koitharu.kotatsu.core.os.AppShortcutManager import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.ui.BasePreferenceFragment +import org.koitharu.kotatsu.core.ui.util.ActivityRecreationHandle import org.koitharu.kotatsu.core.util.FileSize import org.koitharu.kotatsu.core.util.ext.awaitStateAtLeast import org.koitharu.kotatsu.core.util.ext.getDisplayMessage @@ -61,6 +64,9 @@ class UserDataSettingsFragment : BasePreferenceFragment(R.string.data_and_privac @Inject lateinit var appShortcutManager: AppShortcutManager + @Inject + lateinit var activityRecreationHandle: ActivityRecreationHandle + private val backupSelectCall = registerForActivityResult( ActivityResultContracts.OpenDocument(), this, @@ -180,6 +186,19 @@ class UserDataSettingsFragment : BasePreferenceFragment(R.string.data_and_privac findPreference(AppSettings.KEY_PROTECT_APP) ?.isChecked = !settings.appPassword.isNullOrEmpty() } + + AppSettings.KEY_THEME -> { + AppCompatDelegate.setDefaultNightMode(settings.theme) + } + + AppSettings.KEY_COLOR_THEME, + AppSettings.KEY_THEME_AMOLED -> { + postRestart() + } + + AppSettings.KEY_APP_LOCALE -> { + AppCompatDelegate.setApplicationLocales(settings.appLocales) + } } } @@ -273,4 +292,11 @@ class UserDataSettingsFragment : BasePreferenceFragment(R.string.data_and_privac } }.show() } + + private fun postRestart() { + view?.postDelayed(400) { + activityRecreationHandle.recreateAll() + } + } + } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/RestoreDialogFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/RestoreDialogFragment.kt index 8fe3623a3..b1dbec7ba 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/RestoreDialogFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/RestoreDialogFragment.kt @@ -5,7 +5,6 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.ViewGroup import androidx.core.view.isVisible -import androidx.core.view.postDelayed import androidx.fragment.app.FragmentManager import androidx.fragment.app.viewModels import com.google.android.material.dialog.MaterialAlertDialogBuilder @@ -13,20 +12,16 @@ import dagger.hilt.android.AndroidEntryPoint import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.backup.CompositeResult import org.koitharu.kotatsu.core.ui.AlertDialogFragment -import org.koitharu.kotatsu.core.ui.util.ActivityRecreationHandle import org.koitharu.kotatsu.core.util.ext.getDisplayMessage import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.core.util.ext.observeEvent import org.koitharu.kotatsu.core.util.ext.withArgs import org.koitharu.kotatsu.databinding.DialogProgressBinding -import javax.inject.Inject import kotlin.math.roundToInt @AndroidEntryPoint class RestoreDialogFragment : AlertDialogFragment() { - @Inject - lateinit var activityRecreationHandle: ActivityRecreationHandle private val viewModel: RestoreViewModel by viewModels() @@ -76,7 +71,6 @@ class RestoreDialogFragment : AlertDialogFragment() { result.isAllSuccess -> { builder.setTitle(R.string.data_restored) .setMessage(R.string.data_restored_success) - postRestart() } result.isAllFailed -> builder.setTitle(R.string.error) @@ -94,11 +88,6 @@ class RestoreDialogFragment : AlertDialogFragment() { dismiss() } - private fun postRestart() { - view?.postDelayed(400) { - activityRecreationHandle.recreateAll() - } - } companion object {