diff --git a/app/src/main/kotlin/com/hippo/ehviewer/client/EhUtils.kt b/app/src/main/kotlin/com/hippo/ehviewer/client/EhUtils.kt index eb928a049..54856f2a6 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/client/EhUtils.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/client/EhUtils.kt @@ -15,18 +15,32 @@ */ package com.hippo.ehviewer.client +import android.app.DownloadManager +import android.content.ActivityNotFoundException +import android.content.Context +import android.content.Intent +import android.os.Environment import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.ReadOnlyComposable import androidx.compose.runtime.Stable import androidx.compose.ui.graphics.Color +import androidx.core.net.toUri import arrow.core.memoize import com.hippo.ehviewer.Settings +import com.hippo.ehviewer.client.data.GalleryDetail import com.hippo.ehviewer.client.data.GalleryInfo +import com.hippo.ehviewer.client.parser.Archive +import com.hippo.ehviewer.spider.SpiderDen +import com.hippo.ehviewer.util.AppConfig +import com.hippo.ehviewer.util.FileUtils +import com.hippo.ehviewer.util.addTextToClipboard import com.materialkolor.hct.Hct import com.materialkolor.ktx.from import com.materialkolor.ktx.toColor +import eu.kanade.tachiyomi.util.lang.withUIContext import kotlin.math.abs +import splitties.systemservices.downloadManager object EhUtils { const val NONE = -1 // Use it for homepage @@ -84,16 +98,12 @@ object EhUtils { ) private val CATEGORY_STRINGS = CATEGORY_VALUES.entries.map { (k, v) -> v to k } - private val ImageHashRegex = Regex("[0-9a-f]{40}") - val isExHentai: Boolean get() = Settings.gallerySite.value == EhUrl.SITE_EX val isMpvAvailable get() = EhCookieStore.getHathPerks()?.contains('q') == true - fun getImageHash(thumbUrl: String) = ImageHashRegex.find(thumbUrl)?.groupValues[0] - fun getCategory(type: String?): Int { for (entry in CATEGORY_STRINGS) { for (str in entry.first) { @@ -182,4 +192,35 @@ object EhUtils { // TODO But not sure every '|' means that return title.substringBeforeLast('|').trim().ifEmpty { null } } + + context(Context) + suspend fun downloadArchive(galleryDetail: GalleryDetail, archive: Archive) { + val gid = galleryDetail.gid + EhEngine.downloadArchive(gid, galleryDetail.token, archive.res, archive.isHAtH)?.let { + val uri = it.toUri() + val intent = Intent().apply { + action = Intent.ACTION_VIEW + setDataAndType(uri, "application/zip") + } + val name = "$gid-${getSuitableTitle(galleryDetail)}.zip" + try { + startActivity(intent) + withUIContext { addTextToClipboard(name, true) } + } catch (_: ActivityNotFoundException) { + val r = DownloadManager.Request(uri) + r.setDestinationInExternalPublicDir( + Environment.DIRECTORY_DOWNLOADS, + AppConfig.APP_DIRNAME + "/" + FileUtils.sanitizeFilename(name), + ) + r.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) + downloadManager.enqueue(r) + } + if (Settings.archiveMetadata) { + SpiderDen(galleryDetail).apply { + initDownloadDir() + writeComicInfo() + } + } + } + } } diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/GalleryDetailContent.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/GalleryDetailContent.kt index ba9cf3a0a..09e15cfd8 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/GalleryDetailContent.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/GalleryDetailContent.kt @@ -26,7 +26,7 @@ import androidx.compose.foundation.lazy.grid.LazyGridScope import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.ImageSearch +import androidx.compose.material.icons.filled.FolderZip import androidx.compose.material.icons.filled.Search import androidx.compose.material3.Button import androidx.compose.material3.CircularProgressIndicator @@ -84,6 +84,8 @@ import com.hippo.ehviewer.client.data.ListUrlBuilder import com.hippo.ehviewer.client.data.TagNamespace import com.hippo.ehviewer.client.data.asGalleryDetail import com.hippo.ehviewer.client.data.findBaseInfo +import com.hippo.ehviewer.client.exception.EhException +import com.hippo.ehviewer.client.exception.NoHAtHClientException import com.hippo.ehviewer.coil.justDownload import com.hippo.ehviewer.collectAsState import com.hippo.ehviewer.dao.DownloadInfo @@ -100,6 +102,7 @@ import com.hippo.ehviewer.ui.confirmRemoveDownload import com.hippo.ehviewer.ui.destinations.GalleryCommentsScreenDestination import com.hippo.ehviewer.ui.getFavoriteIcon import com.hippo.ehviewer.ui.jumpToReaderByPage +import com.hippo.ehviewer.ui.main.ArchiveList import com.hippo.ehviewer.ui.main.EhPreviewItem import com.hippo.ehviewer.ui.main.GalleryCommentCard import com.hippo.ehviewer.ui.main.GalleryDetailErrorTip @@ -128,6 +131,7 @@ import com.hippo.ehviewer.ui.tools.rememberInVM import com.hippo.ehviewer.util.FavouriteStatusRouter import com.hippo.ehviewer.util.addTextToClipboard import com.hippo.ehviewer.util.bgWork +import com.hippo.ehviewer.util.displayString import com.hippo.ehviewer.util.flattenForEach import com.ramcosta.composedestinations.navigation.DestinationsNavigator import eu.kanade.tachiyomi.util.lang.launchIO @@ -524,18 +528,55 @@ fun BelowHeader(galleryDetail: GalleryDetail) { } }, ) - val invalidUrl = stringResource(R.string.error_invalid_url) - EhIconButton( - icon = Icons.Default.ImageSearch, - text = stringResource(id = R.string.search_cover), - onClick = { - val hash = EhUtils.getImageHash(galleryDetail.thumbKey!!) - if (hash != null) { - navigate(ListUrlBuilder(mode = ListUrlBuilder.MODE_IMAGE_SEARCH, hash = hash).asDst()) - } else { - launch { showSnackbar(invalidUrl) } + val signInFirst = stringResource(R.string.sign_in_first) + val noArchive = stringResource(R.string.no_archives) + val downloadStarted = stringResource(R.string.download_archive_started) + val downloadFailed = stringResource(R.string.download_archive_failure) + val failureNoHath = stringResource(R.string.download_archive_failure_no_hath) + val archiveResult = remember(galleryDetail) { + async(Dispatchers.IO + Job(), CoroutineStart.LAZY) { + with(galleryDetail) { + EhEngine.getArchiveList(archiveUrl!!, gid, token) } - }, + } + } + fun showArchiveDialog() { + launchIO { + if (galleryDetail.apiUid < 0) { + showSnackbar(signInFirst) + } else { + runSuspendCatching { + val (archiveList, funds) = bgWork { archiveResult.await() } + if (archiveList.isEmpty()) { + showSnackbar(noArchive) + } else { + val selected = showNoButton { + ArchiveList( + funds = funds, + items = archiveList, + onItemClick = { resume(it) }, + ) + } + EhUtils.downloadArchive(galleryDetail, selected) + showSnackbar(downloadStarted) + } + }.onFailure { + when (it) { + is NoHAtHClientException -> showSnackbar(failureNoHath) + is EhException -> showSnackbar(it.displayString()) + else -> { + logcat(it) + showSnackbar(downloadFailed) + } + } + } + } + } + } + EhIconButton( + icon = Icons.Default.FolderZip, + text = stringResource(id = R.string.archive), + onClick = ::showArchiveDialog, ) val torrentText = stringResource(R.string.torrent_count, galleryDetail.torrentCount) val noTorrents = stringResource(R.string.no_torrents) diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/GalleryDetailScreen.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/GalleryDetailScreen.kt index 43e832467..dc6decdd1 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/GalleryDetailScreen.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/GalleryDetailScreen.kt @@ -1,11 +1,6 @@ package com.hippo.ehviewer.ui.screen -import android.app.DownloadManager -import android.content.ActivityNotFoundException import android.content.Context -import android.content.Intent -import android.net.Uri -import android.os.Environment import android.os.Parcelable import androidx.activity.result.contract.ActivityResultContracts.CreateDocument import androidx.collection.SieveCache @@ -14,7 +9,6 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack -import androidx.compose.material.icons.filled.FolderZip import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material.icons.filled.Share import androidx.compose.material3.CircularProgressIndicator @@ -52,26 +46,20 @@ import com.hippo.ehviewer.client.data.BaseGalleryInfo import com.hippo.ehviewer.client.data.GalleryDetail import com.hippo.ehviewer.client.data.GalleryInfo import com.hippo.ehviewer.client.data.findBaseInfo -import com.hippo.ehviewer.client.exception.EhException -import com.hippo.ehviewer.client.exception.NoHAtHClientException import com.hippo.ehviewer.client.getImageKey import com.hippo.ehviewer.coil.justDownload import com.hippo.ehviewer.dao.DownloadInfo -import com.hippo.ehviewer.download.DownloadManager as EhDownloadManager +import com.hippo.ehviewer.download.DownloadManager import com.hippo.ehviewer.ktbuilder.imageRequest import com.hippo.ehviewer.spider.SpiderDen import com.hippo.ehviewer.ui.MainActivity import com.hippo.ehviewer.ui.composing -import com.hippo.ehviewer.ui.main.ArchiveList import com.hippo.ehviewer.ui.main.GalleryDetailErrorTip import com.hippo.ehviewer.ui.navToReader import com.hippo.ehviewer.ui.openBrowser import com.hippo.ehviewer.ui.tools.launchInVM import com.hippo.ehviewer.ui.tools.rememberInVM -import com.hippo.ehviewer.util.AppConfig import com.hippo.ehviewer.util.AppHelper -import com.hippo.ehviewer.util.FileUtils -import com.hippo.ehviewer.util.addTextToClipboard import com.hippo.ehviewer.util.awaitActivityResult import com.hippo.ehviewer.util.bgWork import com.hippo.ehviewer.util.displayString @@ -82,16 +70,9 @@ import com.ramcosta.composedestinations.annotation.RootGraph import com.ramcosta.composedestinations.navigation.DestinationsNavigator import eu.kanade.tachiyomi.util.lang.launchIO import eu.kanade.tachiyomi.util.lang.withIOContext -import eu.kanade.tachiyomi.util.lang.withUIContext import eu.kanade.tachiyomi.util.system.logcat -import kotlin.coroutines.resume -import kotlinx.coroutines.CoroutineStart -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job -import kotlinx.coroutines.async import kotlinx.parcelize.Parcelize import moe.tarsin.coroutines.runSuspendCatching -import splitties.systemservices.downloadManager val detailCache = SieveCache(25) @@ -154,78 +135,7 @@ fun AnimatedVisibilityScope.GalleryDetailScreen(args: GalleryDetailScreenArgs, n } } - val archiveResult = remember(galleryInfo) { - async(Dispatchers.IO + Job(), CoroutineStart.LAZY) { - val detail = galleryInfo as GalleryDetail - EhEngine.getArchiveList(detail.archiveUrl!!, gid, token) - } - } - - val failureNoHath = stringResource(R.string.download_archive_failure_no_hath) - val noArchive = stringResource(R.string.no_archives) - val downloadStarted = stringResource(R.string.download_archive_started) - val downloadFailed = stringResource(R.string.download_archive_failure) val signInFirst = stringResource(R.string.sign_in_first) - fun showArchiveDialog() { - val galleryDetail = galleryInfo as? GalleryDetail ?: return - launchIO { - if (galleryDetail.apiUid < 0) { - showSnackbar(signInFirst) - } else { - runSuspendCatching { - val (archiveList, funds) = bgWork { archiveResult.await() } - if (archiveList.isEmpty()) { - showSnackbar(noArchive) - } else { - val selected = showNoButton { - ArchiveList( - funds = funds, - items = archiveList, - onItemClick = { resume(it) }, - ) - } - EhEngine.downloadArchive(gid, token, selected.res, selected.isHAtH)?.let { - val uri = Uri.parse(it) - val intent = Intent().apply { - action = Intent.ACTION_VIEW - setDataAndType(uri, "application/zip") - } - val name = "$gid-${EhUtils.getSuitableTitle(galleryDetail)}.zip" - try { - startActivity(intent) - withUIContext { addTextToClipboard(name, true) } - } catch (_: ActivityNotFoundException) { - val r = DownloadManager.Request(uri) - r.setDestinationInExternalPublicDir( - Environment.DIRECTORY_DOWNLOADS, - AppConfig.APP_DIRNAME + "/" + FileUtils.sanitizeFilename(name), - ) - r.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) - downloadManager.enqueue(r) - } - if (Settings.archiveMetadata) { - SpiderDen(galleryDetail).apply { - initDownloadDir() - writeComicInfo() - } - } - } - showSnackbar(downloadStarted) - } - }.onFailure { - when (it) { - is NoHAtHClientException -> showSnackbar(failureNoHath) - is EhException -> showSnackbar(it.displayString()) - else -> { - logcat(it) - showSnackbar(downloadFailed) - } - } - } - } - } - } - Scaffold( topBar = { LargeTopAppBar( @@ -248,12 +158,6 @@ fun AnimatedVisibilityScope.GalleryDetailScreen(args: GalleryDetailScreenArgs, n }, scrollBehavior = scrollBehavior, actions = { - IconButton(onClick = ::showArchiveDialog) { - Icon( - imageVector = Icons.Default.FolderZip, - contentDescription = null, - ) - } IconButton( onClick = { AppHelper.share(implicit(), galleryDetailUrl) @@ -344,7 +248,7 @@ fun AnimatedVisibilityScope.GalleryDetailScreen(args: GalleryDetailScreenArgs, n onClick = { dropdown = false launchIO { - val downloadInfo = EhDownloadManager.getDownloadInfo(gid) + val downloadInfo = DownloadManager.getDownloadInfo(gid) val canExport = downloadInfo?.state == DownloadInfo.STATE_FINISH if (!canExport) { awaitConfirmationOrCancel( diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 9c91f7918..7eb789b7f 100755 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -286,6 +286,7 @@ Gerade Gestern Vor %d Tagen + Archivdateien Keine Archivdatei Archivdatei wird heruntergeladen Fehler beim Herunterladen der Archivdatei diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index b2b978e27..22cd20383 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -341,6 +341,7 @@ Ahora Ayer Hace %d días atrás + Archivo Sin archivos Descarga de archivos iniciada Error al descargar archivo diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 6b439ed84..4c993845d 100755 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -381,6 +381,7 @@ En ce moment Hier Il y a %d jours + Fiches archives Aucun fiche archives Téléchargement du fiche archives a commencé Téléchargement du fiche archives a échoué diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 431b0b142..8ab7ef887 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -420,6 +420,7 @@ たった今 昨日 %d 日前 + 圧縮パッケージ アーカイブなし アーカイブのダウンロードを開始しました アーカイブをダウンロードできませんでした diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index ab60d0e2c..e94a2a5cd 100755 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -354,6 +354,7 @@ 방금 어제 %d일 전 + 아카이브 아카이브 없음 아카이브 다운로드가 시작되었습니다. 아카이브 다운로드에 실패했습니다. diff --git a/app/src/main/res/values-th/strings.xml b/app/src/main/res/values-th/strings.xml index d7f3453ec..607dd39d4 100644 --- a/app/src/main/res/values-th/strings.xml +++ b/app/src/main/res/values-th/strings.xml @@ -369,6 +369,7 @@ เดี๋ยวนี้ เมื่อวาน %d วันที่ผ่านมา + การบีบอัด ยังไม่มีไฟล์บีบอัด เริ่มการดาวน์โหลดบีบอัด การดาวน์โหลดไฟล์บีบอัดล้มเหลว diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 1667614e7..14ebd3cc4 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -414,12 +414,13 @@ 刚刚 昨天 %d 天前 - 没有压缩包 - 开始下载压缩包 - 无法下载压缩包 + 压缩包 免费 原始 重采样 + 没有压缩包 + 开始下载压缩包 + 无法下载压缩包 下载压缩包需要 H@H 客户端 当前资金: 余额不足 diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index 569287454..459ac1cd9 100755 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -405,6 +405,7 @@ 剛剛 昨天 %d 天前 + 壓縮包 沒有壓縮包 開始下載壓縮包 無法下載壓縮包 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 1e2da3be4..d3c5badaf 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -410,12 +410,13 @@ 剛剛 昨天 %d 天前 - 沒有壓縮檔 - 開始下載壓縮檔 - 下載失敗 + 壓縮檔 免費 原始 重新採樣 + 沒有壓縮檔 + 開始下載壓縮檔 + 下載失敗 下載壓縮檔需要 H@H 客戶端 目前資金: 餘額不足 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 704b6ce0f..bd1482566 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -435,12 +435,13 @@ Just now Yesterday %d days ago - No Archives - Archive download started - Failed to download archive + Archive Free Original Resample + No Archives + Archive download started + Failed to download archive Need H@H client for archive download Current Funds: Insufficient Funds