diff --git a/app/src/main/java/com/hippo/ehviewer/EhApplication.kt b/app/src/main/java/com/hippo/ehviewer/EhApplication.kt index f9ec38345..6e8f12d4c 100644 --- a/app/src/main/java/com/hippo/ehviewer/EhApplication.kt +++ b/app/src/main/java/com/hippo/ehviewer/EhApplication.kt @@ -22,6 +22,7 @@ import android.os.Build import androidx.appcompat.app.AppCompatDelegate import androidx.collection.LruCache import androidx.lifecycle.ProcessLifecycleOwner +import androidx.lifecycle.coroutineScope import coil.ImageLoaderFactory import coil.decode.ImageDecoderDecoder import coil.util.DebugLogger @@ -49,7 +50,7 @@ import com.hippo.ehviewer.yorozuya.FileUtils import eu.kanade.tachiyomi.network.interceptor.CloudflareInterceptor import eu.kanade.tachiyomi.util.lang.launchIO import eu.kanade.tachiyomi.util.lang.withUIContext -import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.launch import okhttp3.AsyncDns import okhttp3.Cookie import okhttp3.android.AndroidAsyncDns @@ -57,10 +58,12 @@ import okio.Path.Companion.toOkioPath import splitties.arch.room.roomDb import splitties.init.appCtx +private val lifecycle = ProcessLifecycleOwner.get().lifecycle +private val lifecycleScope = lifecycle.coroutineScope + class EhApplication : Application(), ImageLoaderFactory { - @OptIn(DelicateCoroutinesApi::class) override fun onCreate() { - ProcessLifecycleOwner.get().lifecycle.addObserver(lockObserver) + lifecycle.addObserver(lockObserver) val handler = Thread.getDefaultUncaughtExceptionHandler() Thread.setDefaultUncaughtExceptionHandler { t, e -> try { @@ -75,13 +78,13 @@ class EhApplication : Application(), ImageLoaderFactory { System.loadLibrary("ehviewer") System.loadLibrary("ehviewer_rust") ReadableTime.initialize(this) - launchIO { + lifecycleScope.launchIO { val theme = Settings.theme withUIContext { AppCompatDelegate.setDefaultNightMode(theme) } } - launchIO { + lifecycleScope.launchIO { launchIO { migrateCookies() } @@ -190,8 +193,8 @@ class EhApplication : Application(), ImageLoaderFactory { val galleryDetailCache by lazy { LruCache(25).also { - FavouriteStatusRouter.addListener { gid, slot -> - it[gid]?.favoriteSlot = slot + lifecycleScope.launch { + FavouriteStatusRouter.globalFlow.collect { (gid, slot) -> it[gid]?.favoriteSlot = slot } } } } diff --git a/app/src/main/java/com/hippo/ehviewer/FavouriteStatusRouter.kt b/app/src/main/java/com/hippo/ehviewer/FavouriteStatusRouter.kt index 919139d00..71c632b9b 100644 --- a/app/src/main/java/com/hippo/ehviewer/FavouriteStatusRouter.kt +++ b/app/src/main/java/com/hippo/ehviewer/FavouriteStatusRouter.kt @@ -55,11 +55,11 @@ object FavouriteStatusRouter { } } - fun addListener(listener: Listener) { + private fun addListener(listener: Listener) { listeners.add(listener) } - fun removeListener(listener: Listener) { + private fun removeListener(listener: Listener) { listeners.remove(listener) } @@ -69,7 +69,7 @@ object FavouriteStatusRouter { private val listenerScope = CoroutineScope(Dispatchers.IO) - private val _stateFlow = callbackFlow { + val globalFlow = callbackFlow { val listener = Listener { gid, slot -> trySend(gid to slot) } @@ -79,5 +79,5 @@ object FavouriteStatusRouter { } }.shareIn(listenerScope, SharingStarted.Eagerly) - fun stateFlow(gid: Long) = _stateFlow.filter { (gid1) -> gid1 == gid } + fun stateFlow(gid: Long) = globalFlow.filter { (gid1) -> gid1 == gid } } diff --git a/app/src/main/java/com/hippo/ehviewer/ui/legacy/GalleryInfoContentHelper.kt b/app/src/main/java/com/hippo/ehviewer/ui/legacy/GalleryInfoContentHelper.kt index 3eed7ed17..4917ddfd5 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/legacy/GalleryInfoContentHelper.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/legacy/GalleryInfoContentHelper.kt @@ -22,6 +22,10 @@ import com.hippo.ehviewer.FavouriteStatusRouter import com.hippo.ehviewer.client.data.GalleryInfo import com.hippo.ehviewer.ui.legacy.ContentLayout.ContentHelper import com.hippo.ehviewer.yorozuya.IntIdGenerator +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.cancel +import kotlinx.coroutines.launch import java.time.Instant import java.time.ZoneOffset import java.time.format.DateTimeFormatter @@ -29,24 +33,16 @@ import java.util.Locale abstract class GalleryInfoContentHelper : ContentHelper() { var jumpTo: String? = null - private val listener: FavouriteStatusRouter.Listener + val scope = CoroutineScope(Dispatchers.IO).apply { + launch { + FavouriteStatusRouter.globalFlow.collect { (gid, slot) -> map[gid]?.favoriteSlot = slot } + } + } @SuppressLint("UseSparseArrays") private var map: MutableMap = HashMap() - init { - listener = FavouriteStatusRouter.Listener { gid: Long, slot: Int -> - val info = map[gid] - if (info != null) { - info.favoriteSlot = slot - } - } - FavouriteStatusRouter.addListener(listener) - } - - fun destroy() { - FavouriteStatusRouter.removeListener(listener) - } + fun destroy() = scope.cancel() override fun onAddData(data: List) { data.forEach { map[it.gid] = it } diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryDetailScene.kt b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryDetailScene.kt index d407d35c2..4a778970f 100755 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryDetailScene.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryDetailScene.kt @@ -82,6 +82,7 @@ import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.produceState import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue @@ -104,6 +105,7 @@ import coil.imageLoader import com.google.android.material.snackbar.Snackbar import com.hippo.ehviewer.EhApplication.Companion.galleryDetailCache import com.hippo.ehviewer.EhDB +import com.hippo.ehviewer.FavouriteStatusRouter import com.hippo.ehviewer.R import com.hippo.ehviewer.Settings import com.hippo.ehviewer.client.EhCookieStore @@ -165,6 +167,7 @@ import com.hippo.ehviewer.util.getParcelableCompat import com.hippo.ehviewer.yorozuya.FileUtils import com.hippo.ehviewer.yorozuya.collect.IntList import eu.kanade.tachiyomi.util.lang.launchIO +import eu.kanade.tachiyomi.util.lang.withIOContext import eu.kanade.tachiyomi.util.lang.withUIContext import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Job @@ -189,7 +192,6 @@ class GalleryDetailScene : BaseScene() { private var downloadButtonText by mutableStateOf("") private var ratingText by mutableStateOf("") private var torrentText by mutableStateOf("") - private var favourite by mutableStateOf(false) private var favButtonText by mutableStateOf("") private var getDetailError by mutableStateOf("") @@ -690,12 +692,19 @@ class GalleryDetailScene : BaseScene() { modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center, ) { + val favored by produceState(initialValue = false) { + val containLocalFav = withIOContext { EhDB.containLocalFavorites(galleryDetail.gid) } + value = containLocalFav || galleryDetail.favoriteSlot != -2 + FavouriteStatusRouter.stateFlow(galleryDetail.gid).collect { (_, slot) -> + value = slot != -2 + } + } FilledTertiaryIconToggleButton( - checked = favourite, + checked = favored, onCheckedChange = { modifyFavourite() }, ) { Icon( - imageVector = if (favourite) Icons.Default.Favorite else Icons.Default.FavoriteBorder, + imageVector = if (favored) Icons.Default.Favorite else Icons.Default.FavoriteBorder, contentDescription = null, ) } @@ -868,10 +877,7 @@ class GalleryDetailScene : BaseScene() { lifecycleScope.launchIO { val containLocalFav = EhDB.containLocalFavorites(gd.gid) if (gd.isFavorited || containLocalFav) { - favourite = true favButtonText = gd.favoriteName ?: getString(R.string.local_favorites) - } else { - favourite = false } } }