diff --git a/app/src/main/kotlin/com/hippo/ehviewer/Settings.kt b/app/src/main/kotlin/com/hippo/ehviewer/Settings.kt index 51ef5372a..7151d8f84 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/Settings.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/Settings.kt @@ -71,9 +71,9 @@ object Settings : DataStorePreferences(null) { var favCloudCount by intPref("fav_cloud", 0).emitTo(_favFlow) // Eh - val gallerySite = intPref("gallery_site_2", 0).observed { updateWhenGallerySiteChanges() } + val gallerySite = intPref("gallery_site_2", 0).observed(::updateWhenGallerySiteChanges) val defaultFavSlot = intPref("default_favorite_slot", -2) - val theme = intPref("theme_2", -1).observed { updateWhenThemeChanges() } + val theme = intPref("theme_2", -1).observed(::updateWhenThemeChanges) val blackDarkTheme = boolPref("black_dark_theme", false) val harmonizeCategoryColor = boolPref("harmonize_category_color", true) val launchPage = intPref("launch_page_2", 0) @@ -85,14 +85,14 @@ object Settings : DataStorePreferences(null) { val showVoteStatus = boolPref("show_vote_status", false) val showComments = boolPref("show_gallery_comments", true) val commentThreshold = intPref("comment_threshold", -100) - val showTagTranslations = boolPref("show_tag_translations", false).observed { updateWhenTagTranslationChanges() } + val showTagTranslations = boolPref("show_tag_translations", false).observed(::updateWhenTagTranslationChanges) val meteredNetworkWarning = boolPref("cellular_network_warning", false) val showJpnTitle = boolPref("show_jpn_title", false) val requestNews = boolPref("request_news", false).observed { updateWhenRequestNewsChanges() } val hideHvEvents = boolPref("hide_hv_events", false) // Download - val mediaScan = boolPref("media_scan", false).observed { updateWhenKeepMediaStatusChanges() } + val mediaScan = boolPref("media_scan", false).observed(::updateWhenKeepMediaStatusChanges) val multiThreadDownload = intPref("download_thread_2", 3) val downloadDelay = intPref("download_delay_3", 1000) val connTimeout = intPref("conn_timeout", 10) @@ -198,32 +198,28 @@ object Settings : DataStorePreferences(null) { } interface Delegate { - val flowGetter: () -> Flow + fun changesFlow(): Flow operator fun getValue(thisRef: Any?, prop: KProperty<*>?): R operator fun setValue(thisRef: Any?, prop: KProperty<*>?, value: R) } private fun intArrayPref(key: String, count: Int) = object : Delegate { - override val flowGetter: () -> Flow = { _value.asFlow().flatMapMerge { it.changesFlow() }.conflate() } - - @Suppress("ktlint:standard:backing-property-naming") - private var _value = (0 until count).map { intPref("${key}_$it", 0) }.toTypedArray() - override fun getValue(thisRef: Any?, prop: KProperty<*>?): IntArray = _value.map { it.value }.toIntArray() + private val delegates = Array(count) { intPref("${key}_$it", 0) } + override fun changesFlow(): Flow = delegates.asFlow().flatMapMerge { it.changesFlow() }.conflate() + override fun getValue(thisRef: Any?, prop: KProperty<*>?) = IntArray(delegates.size) { delegates[it].value } override fun setValue(thisRef: Any?, prop: KProperty<*>?, value: IntArray) { check(value.size == count) - edit { pref -> value.zip(_value) { v, d -> pref[d] = v } } + edit { pref -> value.zip(delegates) { v, d -> pref[d] = v } } } } private fun stringArrayPref(key: String, count: Int, defMetaValue: String) = object : Delegate> { - override val flowGetter: () -> Flow = { _value.asFlow().flatMapMerge { it.changesFlow() }.conflate() } - - @Suppress("ktlint:standard:backing-property-naming") - private var _value = (0 until count).map { stringPref("${key}_$it", "$defMetaValue $it") }.toTypedArray() - override fun getValue(thisRef: Any?, prop: KProperty<*>?): Array = _value.map { it.value }.toTypedArray() + private val delegates = Array(count) { stringPref("${key}_$it", "$defMetaValue $it") } + override fun changesFlow(): Flow = delegates.asFlow().flatMapMerge { it.changesFlow() }.conflate() + override fun getValue(thisRef: Any?, prop: KProperty<*>?) = Array(delegates.size) { delegates[it].value } override fun setValue(thisRef: Any?, prop: KProperty<*>?, value: Array) { check(value.size == count) - edit { pref -> value.zip(_value) { v, d -> pref[d] = v } } + edit { pref -> value.zip(delegates) { v, d -> pref[d] = v } } } } } diff --git a/app/src/main/kotlin/com/hippo/ehviewer/SettingsCollector.kt b/app/src/main/kotlin/com/hippo/ehviewer/SettingsCollector.kt index 4a8b1e750..d2aa21662 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/SettingsCollector.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/SettingsCollector.kt @@ -2,68 +2,73 @@ package com.hippo.ehviewer import android.app.UiModeManager import androidx.appcompat.app.AppCompatDelegate +import arrow.core.Either.Companion.catch import com.ehviewer.core.preferences.PrefDelegate import com.hippo.ehviewer.client.EhEngine import com.hippo.ehviewer.client.EhTagDatabase import com.hippo.ehviewer.dailycheck.updateDailyCheckWork import com.hippo.ehviewer.ui.keepNoMediaFileStatus import com.hippo.ehviewer.util.isAtLeastS -import eu.kanade.tachiyomi.util.lang.launchIO +import eu.kanade.tachiyomi.util.lang.withIOContext import eu.kanade.tachiyomi.util.system.logcat import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.drop +import kotlinx.coroutines.flow.emitAll import kotlinx.coroutines.launch import splitties.init.appCtx import splitties.systemservices.uiModeManager -private val collectScope = CoroutineScope(Dispatchers.Main + SupervisorJob()) -fun > R.observed(func: (Unit) -> Unit) = apply { collectScope.launch { changesFlow().collect(func) } } -fun > R.observed(func: (Unit) -> Unit) = apply { collectScope.launch { flowGetter().collect(func) } } -fun > R.emitTo(flow: MutableSharedFlow) = apply { collectScope.launch { flowGetter().collect { flow.emit(Unit) } } } -fun > R.emitTo(flow: MutableSharedFlow) = apply { collectScope.launch { changesFlow().collect { flow.emit(Unit) } } } +private const val TAG = "SettingsCollector" -fun updateWhenKeepMediaStatusChanges() { - collectScope.launchIO { - runCatching { - keepNoMediaFileStatus() +private val collectScope = CoroutineScope(Dispatchers.Main + SupervisorJob()) +fun > R.observed(func: suspend (T) -> Unit) = apply { collectScope.launch { valueFlow().drop(1).collectLatest(func) } } +fun > R.emitTo(flow: MutableSharedFlow) = apply { collectScope.launch { flow.emitAll(changesFlow()) } } +fun > R.emitTo(flow: MutableSharedFlow) = apply { collectScope.launch { flow.emitAll(changesFlow()) } } + +suspend fun updateWhenKeepMediaStatusChanges(mediaScan: Boolean) { + withIOContext { + catch { + keepNoMediaFileStatus(mediaScan = mediaScan) + }.onLeft { + logcat(TAG, it) } } } -fun updateWhenThemeChanges() { - collectScope.launch { - delay(100) // Avoid recompose being cancelled - if (isAtLeastS) { - val mode = when (Settings.theme.value) { - AppCompatDelegate.MODE_NIGHT_NO -> UiModeManager.MODE_NIGHT_NO - AppCompatDelegate.MODE_NIGHT_YES -> UiModeManager.MODE_NIGHT_YES - else -> UiModeManager.MODE_NIGHT_AUTO - } - uiModeManager.setApplicationNightMode(mode) +suspend fun updateWhenThemeChanges(theme: Int) { + delay(100) // Avoid recompose being cancelled + if (isAtLeastS) { + val mode = when (theme) { + AppCompatDelegate.MODE_NIGHT_NO -> UiModeManager.MODE_NIGHT_NO + AppCompatDelegate.MODE_NIGHT_YES -> UiModeManager.MODE_NIGHT_YES + else -> UiModeManager.MODE_NIGHT_AUTO } - AppCompatDelegate.setDefaultNightMode(Settings.theme.value) + uiModeManager.setApplicationNightMode(mode) } + AppCompatDelegate.setDefaultNightMode(theme) } fun updateWhenRequestNewsChanges() { updateDailyCheckWork(appCtx) } -fun updateWhenGallerySiteChanges() { +suspend fun updateWhenGallerySiteChanges(gallerySite: Int) { if (Settings.hasSignedIn.value) { - collectScope.launchIO { - runCatching { - EhEngine.getUConfig() - }.onFailure { - logcat(it) - } + catch { + EhEngine.getUConfig(gallerySite) + }.onLeft { + logcat(TAG, it) } } } -fun updateWhenTagTranslationChanges() { - EhTagDatabase.launchUpdate() +fun updateWhenTagTranslationChanges(enabled: Boolean) { + if (enabled) { + EhTagDatabase.launchUpdate() + } } diff --git a/app/src/main/kotlin/com/hippo/ehviewer/client/EhEngine.kt b/app/src/main/kotlin/com/hippo/ehviewer/client/EhEngine.kt index 5846f4a30..0603fde00 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/client/EhEngine.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/client/EhEngine.kt @@ -212,7 +212,8 @@ object EhEngine { return ehRequest(url, EhUrl.URL_FORUMS).fetchUsingAsByteBuffer(ProfileParser::parse) } - suspend fun getUConfig(url: String = EhUrl.uConfigUrl) { + suspend fun getUConfig(gallerySite: Int) { + val url = EhUrl.getUConfigUrl(gallerySite) runSuspendCatching { ehRequest(url).fetchUsingAsByteBuffer(UserConfigParser::parse) }.onFailure { throwable -> diff --git a/app/src/main/kotlin/com/hippo/ehviewer/client/EhUrl.kt b/app/src/main/kotlin/com/hippo/ehviewer/client/EhUrl.kt index 067a6bc88..618f9e770 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/client/EhUrl.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/client/EhUrl.kt @@ -80,12 +80,11 @@ object EhUrl { else -> ORIGIN_E } - val uConfigUrl: String - get() = when (Settings.gallerySite.value) { - SITE_E -> URL_UCONFIG_E - SITE_EX -> URL_UCONFIG_EX - else -> URL_UCONFIG_E - } + fun getUConfigUrl(gallerySite: Int = Settings.gallerySite.value) = when (gallerySite) { + SITE_E -> URL_UCONFIG_E + SITE_EX -> URL_UCONFIG_EX + else -> URL_UCONFIG_E + } val myTagsUrl: String get() = when (Settings.gallerySite.value) { diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/CommonOperations.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/CommonOperations.kt index 0c4f6d806..bcedd7ba7 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/CommonOperations.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/CommonOperations.kt @@ -100,10 +100,10 @@ private fun ensureNoMediaFile(downloadDir: Path) { private val lck = Mutex() -suspend fun keepNoMediaFileStatus(downloadDir: Path = downloadLocation) { +suspend fun keepNoMediaFileStatus(downloadDir: Path = downloadLocation, mediaScan: Boolean = Settings.mediaScan.value) { if (downloadDir.isDirectory) { lck.withLock { - if (Settings.mediaScan.value) { + if (mediaScan) { removeNoMediaFile(downloadDir) } else { ensureNoMediaFile(downloadDir) diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/login/PostLogin.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/login/PostLogin.kt index 2d9a66150..68ae604c0 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/login/PostLogin.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/login/PostLogin.kt @@ -36,7 +36,7 @@ fun postLogin() = GlobalScope.async(Dispatchers.IO) { // Get cookies for image limits launch { catch { - EhEngine.getUConfig(EhUrl.URL_UCONFIG_E) + EhEngine.getUConfig(EhUrl.SITE_E) EhCookieStore.flush() }.onLeft { logcat(it) @@ -45,7 +45,7 @@ fun postLogin() = GlobalScope.async(Dispatchers.IO) { // Sad panda check catch { - EhEngine.getUConfig(EhUrl.URL_UCONFIG_EX) + EhEngine.getUConfig(EhUrl.SITE_EX) EhCookieStore.flush() Settings.gallerySite.value = EhUrl.SITE_EX }.onLeft { diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/UConfigScreen.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/UConfigScreen.kt index 783a9cbab..7a5167d64 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/UConfigScreen.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/UConfigScreen.kt @@ -35,7 +35,7 @@ private const val APPLY_JS = "javascript:(function(){var apply = document.getEle @Destination @Composable fun AnimatedVisibilityScope.UConfigScreen(navigator: DestinationsNavigator) = Screen(navigator) { - val url = EhUrl.uConfigUrl + val url = EhUrl.getUConfigUrl() val wvNavigator = rememberWebViewNavigator() Scaffold( topBar = {