diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 7610bc235..bee5bb1fa 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -284,6 +284,7 @@ kotlin { "-opt-in=androidx.compose.animation.ExperimentalAnimationApi", "-opt-in=androidx.compose.animation.ExperimentalSharedTransitionApi", "-opt-in=androidx.paging.ExperimentalPagingApi", + "-opt-in=kotlin.ExperimentalStdlibApi", "-opt-in=kotlin.contracts.ExperimentalContracts", "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi", "-opt-in=kotlinx.coroutines.FlowPreview", diff --git a/app/src/main/kotlin/com/hippo/ehviewer/gallery/ArchivePageLoader.kt b/app/src/main/kotlin/com/hippo/ehviewer/gallery/ArchivePageLoader.kt index 2664f75f0..4e3255a9a 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/gallery/ArchivePageLoader.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/gallery/ArchivePageLoader.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023 Tarsin Norbin + * Copyright 2023-2024 Tarsin Norbin * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,9 +15,7 @@ */ package com.hippo.ehviewer.gallery -import arrow.fx.coroutines.autoCloseable -import arrow.fx.coroutines.closeable -import arrow.fx.coroutines.resourceScope +import arrow.autoCloseScope import com.hippo.ehviewer.Settings.archivePasswds import com.hippo.ehviewer.image.ImageSource import com.hippo.ehviewer.image.byteBufferSource @@ -29,12 +27,10 @@ import com.hippo.ehviewer.jni.needPassword import com.hippo.ehviewer.jni.openArchive import com.hippo.ehviewer.jni.providePassword import com.hippo.ehviewer.jni.releaseByteBuffer -import com.hippo.ehviewer.ui.screen.implicit import com.hippo.ehviewer.util.FileUtils import com.hippo.ehviewer.util.displayName import com.hippo.files.openFileDescriptor import eu.kanade.tachiyomi.util.system.logcat -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.coroutineScope import okio.Path @@ -49,19 +45,19 @@ suspend fun useArchivePageLoader( hasAds: Boolean = false, passwdProvider: PasswdProvider = emptyPasswdProvider, block: suspend (PageLoader) -> T, -) = coroutineScope { - resourceScope { - val pfd = closeable { file.openFileDescriptor("r") } - val size = install( +) = autoCloseScope { + coroutineScope { + val pfd = install(file.openFileDescriptor("r")) + val size = autoClose( { openArchive(pfd.fd, pfd.statSize, gid == 0L || file.name.endsWith(".zip")) }, { _, _ -> closeArchive() }, ) check(size > 0) { "Archive have no content!" } - if (needPassword() && archivePasswds.filterNotNull().none { providePassword(it) }) { - archivePasswds += passwdProvider { providePassword(it) } + if (needPassword() && archivePasswds.filterNotNull().none(::providePassword)) { + archivePasswds += passwdProvider(::providePassword) } - val loader = autoCloseable { - object : PageLoader(gid, startPage, size, hasAds, implicit()) { + val loader = install( + object : PageLoader(gid, startPage, size, hasAds) { override val title by lazy { FileUtils.getNameFromFilename(file.displayName)!! } override fun getImageExtension(index: Int) = getExtension(index) @@ -85,8 +81,8 @@ suspend fun useArchivePageLoader( override fun prefetchPages(pages: List, bounds: IntRange) = pages.forEach(::notifySourceReady) override fun onRequest(index: Int, force: Boolean, orgImg: Boolean) = notifySourceReady(index) - } - } + }, + ) loader.progressJob.join() block(loader) } diff --git a/app/src/main/kotlin/com/hippo/ehviewer/gallery/EhPageLoader.kt b/app/src/main/kotlin/com/hippo/ehviewer/gallery/EhPageLoader.kt index ee1bd639f..5b6ff7bc4 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/gallery/EhPageLoader.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/gallery/EhPageLoader.kt @@ -1,16 +1,13 @@ package com.hippo.ehviewer.gallery -import arrow.fx.coroutines.autoCloseable -import arrow.fx.coroutines.resourceScope +import arrow.autoCloseScope import com.hippo.ehviewer.client.EhUtils import com.hippo.ehviewer.client.data.GalleryInfo import com.hippo.ehviewer.spider.SpiderQueen import com.hippo.ehviewer.spider.SpiderQueen.Companion.obtainSpiderQueen import com.hippo.ehviewer.spider.SpiderQueen.Companion.releaseSpiderQueen import com.hippo.ehviewer.spider.SpiderQueen.OnSpiderListener -import com.hippo.ehviewer.ui.screen.implicit import com.hippo.ehviewer.util.hasAds -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.coroutineScope import okio.Path @@ -18,15 +15,15 @@ suspend fun useEhPageLoader( info: GalleryInfo, startPage: Int, block: suspend (PageLoader) -> T, -) = coroutineScope { - resourceScope { - val queen = install( +) = autoCloseScope { + coroutineScope { + val queen = autoClose( { obtainSpiderQueen(info, SpiderQueen.MODE_READ) }, { queen, _ -> releaseSpiderQueen(queen, SpiderQueen.MODE_READ) }, ) queen.awaitReady() - val loader = autoCloseable { - object : PageLoader(info.gid, startPage, queen.size, info.hasAds, implicit()) { + val loader = install( + object : PageLoader(info.gid, startPage, queen.size, info.hasAds) { override val title by lazy { EhUtils.getSuitableTitle(info) } override fun getImageExtension(index: Int) = queen.getExtension(index) @@ -38,8 +35,8 @@ suspend fun useEhPageLoader( override fun prefetchPages(pages: List, bounds: IntRange) = queen.preloadPages(pages, bounds) override fun onRequest(index: Int, force: Boolean, orgImg: Boolean) = queen.request(index, force, orgImg) - } - }.apply { + }, + ).apply { val listener = object : OnSpiderListener { override fun onPageDownload(index: Int, contentLength: Long, receivedSize: Long, bytesRead: Int) { if (contentLength > 0) { @@ -51,12 +48,12 @@ suspend fun useEhPageLoader( override fun onPageFailure(index: Int, error: String?, finished: Int, downloaded: Int, total: Int) = notifyPageFailed(index, error) } - install( + autoClose( { queen.addOnSpiderListener(listener) }, { _, _ -> queen.removeOnSpiderListener(listener) }, ) + progressJob.join() } - loader.progressJob.join() block(loader) } } diff --git a/app/src/main/kotlin/com/hippo/ehviewer/gallery/PageLoader.kt b/app/src/main/kotlin/com/hippo/ehviewer/gallery/PageLoader.kt index 65fad7906..5501c07b0 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/gallery/PageLoader.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/gallery/PageLoader.kt @@ -32,7 +32,8 @@ private val progressScope = CoroutineScope(Dispatchers.IO) private const val MAX_CACHE_SIZE = 512 * 1024 * 1024 private const val MIN_CACHE_SIZE = 128 * 1024 * 1024 -abstract class PageLoader(val gid: Long, var startPage: Int, val size: Int, val hasAds: Boolean = false, val scope: CoroutineScope) : AutoCloseable { +context(CoroutineScope) +abstract class PageLoader(val gid: Long, var startPage: Int, val size: Int, val hasAds: Boolean = false) : AutoCloseable { private val mutex = NamedMutex() private val semaphore = Semaphore(4) @@ -61,6 +62,7 @@ abstract class PageLoader(val gid: Long, var startPage: Int, val size: Int, val pages[index].status !is PageStatus.Blocked suspend fun atomicallyDecodeAndUpdate(index: Int) { + if (!needDecode(index)) return try { bracketCase( { openSource(index) }, @@ -171,11 +173,10 @@ abstract class PageLoader(val gid: Long, var startPage: Int, val size: Int, val fun notifySourceReady(index: Int) { if (needDecode(index)) { - scope.launch { + launch { mutex.withLock(index) { semaphore.withPermit { - // Double check - if (needDecode(index)) atomicallyDecodeAndUpdate(index) + atomicallyDecodeAndUpdate(index) } } }