From c2e53cc8b915672b7f8b9b7df7749f449a5db2f0 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Sat, 24 May 2025 00:21:11 +0800 Subject: [PATCH] Revert "Migrate from Parcelize to kotlinx.serialization" (#2356) This reverts commit 857b1d9b570c5a26643b7ddb9b29bb9ab3f00f8b. Reason for revert: https://github.com/FooIbar/EhViewer/issues/2355 --- app/build.gradle.kts | 1 + .../ehviewer/client/data/BaseGalleryInfo.kt | 5 +++- .../ehviewer/client/data/FavListUrlBuilder.kt | 7 +++-- .../ehviewer/client/data/GalleryComment.kt | 6 +++- .../client/data/GalleryCommentList.kt | 6 +++- .../ehviewer/client/data/GalleryDetail.kt | 5 +++- .../ehviewer/client/data/GalleryPreview.kt | 6 +++- .../hippo/ehviewer/client/data/GalleryTag.kt | 6 +++- .../ehviewer/client/data/GalleryTagGroup.kt | 6 +++- .../ehviewer/client/data/ListUrlBuilder.kt | 7 +++-- .../ehviewer/client/data/TagNamespace.kt | 6 +++- .../ehviewer/client/parser/HomeParser.kt | 13 +++++++-- .../ehviewer/download/DownloadService.kt | 28 ++++--------------- .../ehviewer/shortcuts/ShortcutsActivity.kt | 6 ++-- .../com/hippo/ehviewer/ui/CommonOperations.kt | 22 ++++++++++++--- .../com/hippo/ehviewer/ui/MainActivity.kt | 16 +++++------ .../hippo/ehviewer/ui/main/AdvanceTable.kt | 5 +++- .../hippo/ehviewer/ui/reader/ReaderScreen.kt | 17 +++++------ .../ui/screen/DownloadsFilterState.kt | 7 +++-- .../ehviewer/ui/screen/DownloadsScreen.kt | 25 +++++++++++++---- .../ehviewer/ui/screen/FavoritesScreen.kt | 3 +- .../ui/screen/GalleryCommentsScreen.kt | 2 +- .../ehviewer/ui/screen/GalleryDetailScreen.kt | 10 +++---- .../ehviewer/ui/screen/GalleryListScreen.kt | 3 +- .../com/hippo/ehviewer/ui/tools/State.kt | 12 -------- build.gradle.kts | 1 + gradle/libs.versions.toml | 1 + 27 files changed, 138 insertions(+), 94 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index c76c5837c..b6bc75ee4 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -10,6 +10,7 @@ plugins { alias(libs.plugins.android.application) alias(libs.plugins.kotlin.android) alias(libs.plugins.kotlin.compose) + alias(libs.plugins.kotlin.parcelize) alias(libs.plugins.kotlin.serialization) alias(libs.plugins.ksp) alias(libs.plugins.spotless) diff --git a/app/src/main/kotlin/com/hippo/ehviewer/client/data/BaseGalleryInfo.kt b/app/src/main/kotlin/com/hippo/ehviewer/client/data/BaseGalleryInfo.kt index 99b954fec..8ba2b13dc 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/client/data/BaseGalleryInfo.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/client/data/BaseGalleryInfo.kt @@ -15,6 +15,7 @@ */ package com.hippo.ehviewer.client.data +import android.os.Parcelable import androidx.room.ColumnInfo import androidx.room.Entity import androidx.room.Ignore @@ -22,8 +23,10 @@ import androidx.room.PrimaryKey import androidx.room.TypeConverter import androidx.room.TypeConverters import com.hippo.ehviewer.client.data.GalleryInfo.Companion.NOT_FAVORITED +import kotlinx.parcelize.Parcelize import kotlinx.serialization.Serializable +@Parcelize @Serializable @Entity(tableName = "GALLERIES") @TypeConverters(SimpleTagsConverter::class) @@ -85,7 +88,7 @@ data class BaseGalleryInfo( @Ignore override var favoriteNote: String? = null, -) : GalleryInfo +) : GalleryInfo, Parcelable class SimpleTagsConverter { @TypeConverter diff --git a/app/src/main/kotlin/com/hippo/ehviewer/client/data/FavListUrlBuilder.kt b/app/src/main/kotlin/com/hippo/ehviewer/client/data/FavListUrlBuilder.kt index 25a17449c..493b811c1 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/client/data/FavListUrlBuilder.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/client/data/FavListUrlBuilder.kt @@ -15,20 +15,21 @@ */ package com.hippo.ehviewer.client.data +import android.os.Parcelable import com.hippo.ehviewer.client.EhUrl import com.hippo.ehviewer.client.addQueryParameter import com.hippo.ehviewer.client.addQueryParameterIfNotBlank import com.hippo.ehviewer.client.ehUrl -import kotlinx.serialization.Serializable +import kotlinx.parcelize.Parcelize -@Serializable +@Parcelize data class FavListUrlBuilder( val favCat: Int = FAV_CAT_ALL, val keyword: String? = null, var jumpTo: String? = null, var prev: String? = null, var next: String? = null, -) { +) : Parcelable { fun setIndex(index: String?, isNext: Boolean) { next = index.takeIf { isNext } prev = index.takeUnless { isNext } diff --git a/app/src/main/kotlin/com/hippo/ehviewer/client/data/GalleryComment.kt b/app/src/main/kotlin/com/hippo/ehviewer/client/data/GalleryComment.kt index 8941f4d2d..15af5f588 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/client/data/GalleryComment.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/client/data/GalleryComment.kt @@ -15,6 +15,10 @@ */ package com.hippo.ehviewer.client.data +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize data class GalleryComment( val id: Long, val score: Int, @@ -29,4 +33,4 @@ data class GalleryComment( val user: String?, val comment: String, val lastEdited: Long, -) +) : Parcelable diff --git a/app/src/main/kotlin/com/hippo/ehviewer/client/data/GalleryCommentList.kt b/app/src/main/kotlin/com/hippo/ehviewer/client/data/GalleryCommentList.kt index 71fbd18bb..a0901f751 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/client/data/GalleryCommentList.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/client/data/GalleryCommentList.kt @@ -15,7 +15,11 @@ */ package com.hippo.ehviewer.client.data +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize data class GalleryCommentList( val comments: List, val hasMore: Boolean, -) +) : Parcelable diff --git a/app/src/main/kotlin/com/hippo/ehviewer/client/data/GalleryDetail.kt b/app/src/main/kotlin/com/hippo/ehviewer/client/data/GalleryDetail.kt index e50aaed91..28cfabdca 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/client/data/GalleryDetail.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/client/data/GalleryDetail.kt @@ -15,8 +15,10 @@ */ package com.hippo.ehviewer.client.data +import android.os.Parcelable import androidx.compose.ui.util.fastFlatMap import com.hippo.ehviewer.client.data.GalleryInfo.Companion.S_LANGS +import kotlinx.parcelize.Parcelize private val LANGUAGES = arrayOf( "English", @@ -35,6 +37,7 @@ private val LANGUAGES = arrayOf( "Dutch", ) +@Parcelize data class GalleryDetail( val galleryInfo: BaseGalleryInfo = BaseGalleryInfo(), var apiUid: Long = -1L, @@ -52,7 +55,7 @@ data class GalleryDetail( val tagGroups: List, var comments: GalleryCommentList, val previewList: List, -) : GalleryInfo by galleryInfo { +) : GalleryInfo by galleryInfo, Parcelable { fun fillInfo() { val index = LANGUAGES.indexOf(language) if (index != -1) simpleLanguage = S_LANGS[index] diff --git a/app/src/main/kotlin/com/hippo/ehviewer/client/data/GalleryPreview.kt b/app/src/main/kotlin/com/hippo/ehviewer/client/data/GalleryPreview.kt index 50c373c39..9b1a8822f 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/client/data/GalleryPreview.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/client/data/GalleryPreview.kt @@ -15,14 +15,17 @@ */ package com.hippo.ehviewer.client.data +import android.os.Parcelable import com.hippo.ehviewer.client.keyToUrl +import kotlinx.parcelize.Parcelize -sealed interface GalleryPreview { +sealed interface GalleryPreview : Parcelable { val url: String val imageKey: String val position: Int } +@Parcelize data class V1GalleryPreview( override val imageKey: String, override val position: Int, @@ -30,6 +33,7 @@ data class V1GalleryPreview( override val url get() = keyToUrl(imageKey) } +@Parcelize data class V2GalleryPreview( override val url: String, override val imageKey: String, diff --git a/app/src/main/kotlin/com/hippo/ehviewer/client/data/GalleryTag.kt b/app/src/main/kotlin/com/hippo/ehviewer/client/data/GalleryTag.kt index 7abd23d15..04b348678 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/client/data/GalleryTag.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/client/data/GalleryTag.kt @@ -1,5 +1,8 @@ package com.hippo.ehviewer.client.data +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + enum class VoteStatus(val display: String) { NONE(""), UP("+1"), @@ -12,8 +15,9 @@ enum class PowerStatus { WEAK, } +@Parcelize data class GalleryTag( val text: String, val power: PowerStatus, val vote: VoteStatus, -) +) : Parcelable diff --git a/app/src/main/kotlin/com/hippo/ehviewer/client/data/GalleryTagGroup.kt b/app/src/main/kotlin/com/hippo/ehviewer/client/data/GalleryTagGroup.kt index e05cfebcc..1ac423e1f 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/client/data/GalleryTagGroup.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/client/data/GalleryTagGroup.kt @@ -15,7 +15,11 @@ */ package com.hippo.ehviewer.client.data +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize data class GalleryTagGroup( val nameSpace: TagNamespace, val tags: List, -) +) : Parcelable diff --git a/app/src/main/kotlin/com/hippo/ehviewer/client/data/ListUrlBuilder.kt b/app/src/main/kotlin/com/hippo/ehviewer/client/data/ListUrlBuilder.kt index 3b3591b29..3ffc375e0 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/client/data/ListUrlBuilder.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/client/data/ListUrlBuilder.kt @@ -15,6 +15,7 @@ */ package com.hippo.ehviewer.client.data +import android.os.Parcelable import com.hippo.ehviewer.Settings import com.hippo.ehviewer.client.EhUrl import com.hippo.ehviewer.client.EhUtils @@ -25,9 +26,9 @@ import com.hippo.ehviewer.dao.QuickSearch import com.hippo.ehviewer.ui.main.AdvanceTable import io.ktor.http.Parameters import kotlin.text.toIntOrNull -import kotlinx.serialization.Serializable +import kotlinx.parcelize.Parcelize -@Serializable +@Parcelize data class ListUrlBuilder( var mode: Int = MODE_NORMAL, private var prev: String? = null, @@ -43,7 +44,7 @@ data class ListUrlBuilder( var minRating: Int = -1, var pageFrom: Int = -1, var pageTo: Int = -1, -) { +) : Parcelable { fun setIndex(index: String, isNext: Boolean = true) { next = index.takeIf { isNext } diff --git a/app/src/main/kotlin/com/hippo/ehviewer/client/data/TagNamespace.kt b/app/src/main/kotlin/com/hippo/ehviewer/client/data/TagNamespace.kt index 10c2bc253..78c80a35c 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/client/data/TagNamespace.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/client/data/TagNamespace.kt @@ -1,6 +1,10 @@ package com.hippo.ehviewer.client.data -sealed class TagNamespace(val value: String, val prefix: String?) { +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +sealed class TagNamespace(val value: String, val prefix: String?) : Parcelable { object Artist : TagNamespace("artist", "a") object Cosplayer : TagNamespace("cosplayer", "cos") object Character : TagNamespace("character", "c") diff --git a/app/src/main/kotlin/com/hippo/ehviewer/client/parser/HomeParser.kt b/app/src/main/kotlin/com/hippo/ehviewer/client/parser/HomeParser.kt index 7a6a866a6..165720fa6 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/client/parser/HomeParser.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/client/parser/HomeParser.kt @@ -1,9 +1,12 @@ package com.hippo.ehviewer.client.parser +import android.os.Parcelable import com.hippo.ehviewer.client.exception.InsufficientFundsException import com.hippo.ehviewer.client.exception.ParseException import java.nio.ByteBuffer import kotlin.random.Random +import kotlinx.parcelize.Parcelize +import kotlinx.serialization.Serializable object HomeParser { private val TorrentKeyRegex = Regex("Your current key is: <[^>]*>([^<]*)<") @@ -32,11 +35,15 @@ object HomeParser { throw ParseException("Parse funds error") } - data class Result(val limits: Limits, val funds: Funds, private val id: Int = Random.nextInt()) + @Parcelize + data class Result(val limits: Limits, val funds: Funds, private val id: Int = Random.nextInt()) : Parcelable } -data class Funds(val gp: Int, val credit: Int) +@Parcelize +data class Funds(val gp: Int, val credit: Int) : Parcelable -data class Limits(val current: Int, val maximum: Int, val resetCost: Int) +@Parcelize +@Serializable +data class Limits(val current: Int, val maximum: Int, val resetCost: Int) : Parcelable private external fun parseLimit(body: ByteBuffer, limit: Int = body.limit()): Int diff --git a/app/src/main/kotlin/com/hippo/ehviewer/download/DownloadService.kt b/app/src/main/kotlin/com/hippo/ehviewer/download/DownloadService.kt index 16a7cd417..fe8d2aa0f 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/download/DownloadService.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/download/DownloadService.kt @@ -18,7 +18,6 @@ package com.hippo.ehviewer.download import android.Manifest import android.app.PendingIntent import android.app.Service -import android.content.Context import android.content.Intent import android.content.pm.PackageManager import android.os.Bundle @@ -28,9 +27,6 @@ import androidx.core.app.NotificationChannelCompat import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat import androidx.core.app.ServiceCompat -import androidx.core.content.ContextCompat -import androidx.savedstate.serialization.decodeFromSavedState -import androidx.savedstate.serialization.encodeToSavedState import com.hippo.ehviewer.R import com.hippo.ehviewer.client.EhUtils import com.hippo.ehviewer.client.data.BaseGalleryInfo @@ -38,6 +34,7 @@ import com.hippo.ehviewer.dao.DownloadInfo import com.hippo.ehviewer.ui.MainActivity import com.hippo.ehviewer.util.FileUtils import com.hippo.ehviewer.util.ReadableTime +import com.hippo.ehviewer.util.getParcelableExtraCompat import com.hippo.ehviewer.util.unsafeLazy import eu.kanade.tachiyomi.util.system.logcat import kotlinx.coroutines.CoroutineScope @@ -98,9 +95,11 @@ class DownloadService : private suspend fun handleIntent(intent: Intent?) { when (intent?.action) { ACTION_START -> { - val gi = intent.getBundleExtra(KEY_GALLERY_INFO) ?: return + val gi = intent.getParcelableExtraCompat(KEY_GALLERY_INFO) val label = intent.getStringExtra(KEY_LABEL) - deferredMgr.await().startDownload(decodeFromSavedState(gi), label) + if (gi != null) { + deferredMgr.await().startDownload(gi, label) + } } ACTION_START_RANGE -> { @@ -455,23 +454,6 @@ class DownloadService : private var sFinishedCount = 0 private var sDownloadedCount = 0 - context(ctx: Context) - inline fun startService(action: String, intentBuilder: Intent.() -> Unit = {}) { - val intent = Intent(ctx, DownloadService::class.java).setAction(action).apply(intentBuilder) - ContextCompat.startForegroundService(ctx, intent) - } - - context(_: Context) - fun startDownload(info: BaseGalleryInfo, label: String? = null) = startService(ACTION_START) { - putExtra(KEY_GALLERY_INFO, encodeToSavedState(info)) - label?.let { putExtra(KEY_LABEL, it) } - } - - context(_: Context) - fun startRangeDownload(gidList: LongArray) = startService(ACTION_START_RANGE) { - putExtra(KEY_GID_LIST, gidList) - } - fun clear() { sFailedCount = 0 sFinishedCount = 0 diff --git a/app/src/main/kotlin/com/hippo/ehviewer/shortcuts/ShortcutsActivity.kt b/app/src/main/kotlin/com/hippo/ehviewer/shortcuts/ShortcutsActivity.kt index f57b05ee0..b1eafe5c0 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/shortcuts/ShortcutsActivity.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/shortcuts/ShortcutsActivity.kt @@ -15,8 +15,10 @@ */ package com.hippo.ehviewer.shortcuts +import android.content.Intent import android.os.Bundle import androidx.appcompat.app.AppCompatActivity +import androidx.core.content.ContextCompat import com.hippo.ehviewer.download.DownloadService /** @@ -25,8 +27,8 @@ import com.hippo.ehviewer.download.DownloadService class ShortcutsActivity : AppCompatActivity() { public override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - when (val action = intent?.action) { - DownloadService.ACTION_START_ALL, DownloadService.ACTION_STOP_ALL -> DownloadService.startService(action) + when (intent?.action) { + DownloadService.ACTION_START_ALL, DownloadService.ACTION_STOP_ALL -> ContextCompat.startForegroundService(this, Intent(this, DownloadService::class.java).setAction(intent.action)) } finish() } 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 e2a627c7a..02445eaa0 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/CommonOperations.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/CommonOperations.kt @@ -17,6 +17,8 @@ package com.hippo.ehviewer.ui import android.Manifest import android.content.Context +import android.content.Intent +import android.net.Uri import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth @@ -35,6 +37,7 @@ import androidx.compose.material3.Text import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp +import androidx.core.content.ContextCompat import com.hippo.ehviewer.EhDB import com.hippo.ehviewer.R import com.hippo.ehviewer.Settings @@ -121,8 +124,11 @@ suspend fun startDownload(forceDefault: Boolean, vararg galleryInfos: BaseGaller } val (toStart, toAdd) = galleryInfos.partition { DownloadManager.containDownloadInfo(it.gid) } if (toStart.isNotEmpty()) { + val intent = Intent(context, DownloadService::class.java) + intent.action = DownloadService.ACTION_START_RANGE val list = toStart.mapToLongArray(GalleryInfo::gid) - DownloadService.startRangeDownload(list) + intent.putExtra(DownloadService.KEY_GID_LIST, list) + ContextCompat.startForegroundService(context, intent) } if (toAdd.isEmpty()) { return tip(R.string.added_to_download_list) @@ -142,7 +148,11 @@ suspend fun startDownload(forceDefault: Boolean, vararg galleryInfos: BaseGaller if (justStart) { // Got default label for (gi in toAdd) { - DownloadService.startDownload(gi, label) + val intent = Intent(context, DownloadService::class.java) + intent.action = DownloadService.ACTION_START + intent.putExtra(DownloadService.KEY_LABEL, label) + intent.putExtra(DownloadService.KEY_GALLERY_INFO, gi) + ContextCompat.startForegroundService(context, intent) } // Notify tip(R.string.added_to_download_list) @@ -163,7 +173,11 @@ suspend fun startDownload(forceDefault: Boolean, vararg galleryInfos: BaseGaller val label1 = if (selected == 0) null else items[selected].takeIf { DownloadManager.containLabel(it) } // Start download for (gi in toAdd) { - DownloadService.startDownload(gi, label1) + val intent = Intent(context, DownloadService::class.java) + intent.action = DownloadService.ACTION_START + intent.putExtra(DownloadService.KEY_LABEL, label1) + intent.putExtra(DownloadService.KEY_GALLERY_INFO, gi) + ContextCompat.startForegroundService(context, intent) } // Save settings if (checked) { @@ -272,7 +286,7 @@ context(_: DestinationsNavigator) fun navToReader(info: BaseGalleryInfo, page: Int = -1) = navToReader(ReaderScreenArgs.Gallery(info, page)) context(_: DestinationsNavigator) -fun navToReader(path: String) = navToReader(ReaderScreenArgs.Archive(path)) +fun navToReader(uri: Uri) = navToReader(ReaderScreenArgs.Archive(uri)) context(nav: DestinationsNavigator) private fun navToReader(args: ReaderScreenArgs) = nav.navigate(ReaderScreenDestination(args)) { launchSingleTop = true } diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/MainActivity.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/MainActivity.kt index 97ac08b8b..4918a0593 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/MainActivity.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/MainActivity.kt @@ -258,32 +258,32 @@ class MainActivity : EhActivity() { LaunchedEffect(Unit) { intentFlow.collect { intent -> when (intent.action) { - Intent.ACTION_VIEW -> with(navigator) { + Intent.ACTION_VIEW -> { val uri = intent.data ?: return@collect when (uri.scheme) { - SCHEME_FILE -> navToReader(uri.path!!) - SCHEME_CONTENT -> navToReader(uri.toString()) + SCHEME_CONTENT, SCHEME_FILE -> with(navigator) { navToReader(uri) } + else -> { val url = uri.toString() - if (!navWithUrl(url)) { + if (!with(navigator) { navWithUrl(url) }) { val new = awaitInputText(initial = url, title = cannotParse) addTextToClipboard(new) } } } } - Intent.ACTION_SEND -> with(navigator) { + Intent.ACTION_SEND -> { val type = intent.type if ("text/plain" == type) { val keyword = intent.getStringExtra(Intent.EXTRA_TEXT) - if (keyword != null && !navWithUrl(keyword)) { - navigate(ListUrlBuilder(mKeyword = keyword).asDst()) + if (keyword != null && !with(navigator) { navWithUrl(keyword) }) { + navigator.navigate(ListUrlBuilder(mKeyword = keyword).asDst()) } } else if (type != null && type.startsWith("image/")) { val uri = intent.getParcelableExtraCompat(Intent.EXTRA_STREAM) if (null != uri) { val hash = withIOContext { uri.toOkioPath().sha1() } - navigate( + navigator.navigate( ListUrlBuilder( mode = ListUrlBuilder.MODE_IMAGE_SEARCH, hash = hash, diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/main/AdvanceTable.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/main/AdvanceTable.kt index 154db399c..5787cb876 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/main/AdvanceTable.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/main/AdvanceTable.kt @@ -1,5 +1,7 @@ package com.hippo.ehviewer.ui.main +import android.os.Parcelable +import kotlinx.parcelize.Parcelize import kotlinx.serialization.Serializable import kotlinx.serialization.Transient @@ -11,6 +13,7 @@ object AdvanceTable { const val SFT = 0x10 } +@Parcelize @Serializable data class AdvancedSearchOption( @Transient @@ -18,4 +21,4 @@ data class AdvancedSearchOption( val minRating: Int = 0, val fromPage: Int = 0, val toPage: Int = 0, -) +) : Parcelable diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/ReaderScreen.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/ReaderScreen.kt index baf8de85e..3b6a2d6a9 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/ReaderScreen.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/ReaderScreen.kt @@ -1,6 +1,8 @@ package com.hippo.ehviewer.ui.reader import android.content.Context +import android.net.Uri +import android.os.Parcelable import androidx.compose.animation.AnimatedVisibilityScope import androidx.compose.animation.animateColorAsState import androidx.compose.foundation.background @@ -81,6 +83,7 @@ import com.hippo.ehviewer.ui.tools.dialog import com.hippo.ehviewer.ui.tools.thenIf import com.hippo.ehviewer.util.displayString import com.hippo.ehviewer.util.hasAds +import com.hippo.files.toOkioPath import com.ramcosta.composedestinations.annotation.Destination import com.ramcosta.composedestinations.annotation.RootGraph import com.ramcosta.composedestinations.navigation.DestinationsNavigator @@ -97,19 +100,17 @@ import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onCompletion import kotlinx.coroutines.flow.sample import kotlinx.coroutines.suspendCancellableCoroutine -import kotlinx.serialization.Serializable +import kotlinx.parcelize.Parcelize import moe.tarsin.kt.unreachable import moe.tarsin.launch import moe.tarsin.string -import okio.Path.Companion.toPath -@Serializable -sealed interface ReaderScreenArgs { - @Serializable +sealed interface ReaderScreenArgs : Parcelable { + @Parcelize data class Gallery(val info: BaseGalleryInfo, val page: Int) : ReaderScreenArgs - @Serializable - data class Archive(val path: String) : ReaderScreenArgs + @Parcelize + data class Archive(val uri: Uri) : ReaderScreenArgs } @Composable @@ -381,7 +382,7 @@ suspend inline fun usePageLoader(args: ReaderScreenArgs, crossinline block: } } is ReaderScreenArgs.Archive -> useArchivePageLoader( - args.path.toPath(), + args.uri.toOkioPath(), passwdProvider = { invalidator -> awaitInputText( title = string(R.string.archive_need_passwd), diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/DownloadsFilterState.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/DownloadsFilterState.kt index af461a3b8..7676ee209 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/DownloadsFilterState.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/DownloadsFilterState.kt @@ -1,17 +1,18 @@ package com.hippo.ehviewer.ui.screen +import android.os.Parcelable import com.hippo.ehviewer.dao.DownloadInfo import com.hippo.ehviewer.download.DownloadsFilterMode import com.hippo.ehviewer.util.containsIgnoreCase -import kotlinx.serialization.Serializable +import kotlinx.parcelize.Parcelize -@Serializable +@Parcelize data class DownloadsFilterState( val mode: DownloadsFilterMode, val label: String?, val state: Int = -1, val keyword: String = "", -) +) : Parcelable fun DownloadsFilterState.take(info: DownloadInfo) = mode.take(info, label) && (state == -1 || info.state == state) && diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/DownloadsScreen.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/DownloadsScreen.kt index 63ba50d41..0c738c460 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/DownloadsScreen.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/DownloadsScreen.kt @@ -1,6 +1,8 @@ package com.hippo.ehviewer.ui.screen +import android.app.Activity import android.content.Context +import android.content.Intent import android.view.ViewConfiguration import androidx.compose.animation.AnimatedVisibilityScope import androidx.compose.animation.Crossfade @@ -77,6 +79,7 @@ import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp +import androidx.core.content.ContextCompat import arrow.core.partially1 import com.hippo.ehviewer.EhDB import com.hippo.ehviewer.R @@ -118,7 +121,6 @@ import com.hippo.ehviewer.ui.tools.awaitSelectItemWithCheckBox import com.hippo.ehviewer.ui.tools.awaitSingleChoice import com.hippo.ehviewer.ui.tools.rememberHapticFeedback import com.hippo.ehviewer.ui.tools.rememberInVM -import com.hippo.ehviewer.ui.tools.rememberSerializable import com.hippo.ehviewer.ui.tools.thenIf import com.hippo.ehviewer.util.mapToLongArray import com.hippo.ehviewer.util.takeAndClear @@ -143,7 +145,7 @@ fun AnimatedVisibilityScope.DownloadsScreen(navigator: DestinationsNavigator) = var gridView by Settings.gridView.asMutableState() var sortMode by Settings.downloadSortMode.asMutableState() val filterMode by Settings.downloadFilterMode.collectAsState { DownloadsFilterMode.from(it) } - var filterState by rememberSerializable { mutableStateOf(DownloadsFilterState(filterMode, Settings.recentDownloadLabel.value)) } + var filterState by rememberSaveable { mutableStateOf(DownloadsFilterState(filterMode, Settings.recentDownloadLabel.value)) } var invalidateKey by rememberSaveable { mutableStateOf(false) } var searchBarExpanded by rememberSaveable { mutableStateOf(false) } var searchBarOffsetY by remember { mutableIntStateOf(0) } @@ -481,7 +483,9 @@ fun AnimatedVisibilityScope.DownloadsScreen(navigator: DestinationsNavigator) = text = { Text(text = stringResource(id = R.string.download_start_all)) }, onClick = { expanded = false - DownloadService.startService(DownloadService.ACTION_START_ALL) + val intent = Intent(contextOf(), DownloadService::class.java) + intent.action = DownloadService.ACTION_START_ALL + ContextCompat.startForegroundService(contextOf(), intent) }, ) DropdownMenuItem( @@ -513,7 +517,10 @@ fun AnimatedVisibilityScope.DownloadsScreen(navigator: DestinationsNavigator) = onClick = { expanded = false val gidList = list.filter { it.state != DownloadInfo.STATE_FINISH }.asReversed().mapToLongArray(DownloadInfo::gid) - DownloadService.startRangeDownload(gidList) + val intent = Intent(contextOf(), DownloadService::class.java) + intent.action = DownloadService.ACTION_START_RANGE + intent.putExtra(DownloadService.KEY_GID_LIST, gidList) + ContextCompat.startForegroundService(contextOf(), intent) }, ) } @@ -595,7 +602,10 @@ fun AnimatedVisibilityScope.DownloadsScreen(navigator: DestinationsNavigator) = checkedInfoMap[info.gid] = info }, onStart = { - DownloadService.startDownload(info.galleryInfo) + val intent = Intent(contextOf(), DownloadService::class.java) + intent.action = DownloadService.ACTION_START + intent.putExtra(DownloadService.KEY_GALLERY_INFO, info.galleryInfo) + ContextCompat.startForegroundService(contextOf(), intent) }, onStop = { launchIO { DownloadManager.stopDownload(info.gid) } }, info = info, @@ -686,7 +696,10 @@ fun AnimatedVisibilityScope.DownloadsScreen(navigator: DestinationsNavigator) = } onClick(Icons.Default.PlayArrow) { val gidList = checkedInfoMap.takeAndClear().mapToLongArray(DownloadInfo::gid) - DownloadService.startRangeDownload(gidList) + val intent = Intent(contextOf(), DownloadService::class.java) + intent.action = DownloadService.ACTION_START_RANGE + intent.putExtra(DownloadService.KEY_GID_LIST, gidList) + ContextCompat.startForegroundService(contextOf(), intent) } onClick(Icons.Default.Pause) { val gidList = checkedInfoMap.takeAndClear().mapToLongArray(DownloadInfo::gid) diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/FavoritesScreen.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/FavoritesScreen.kt index 24c3e295b..1e8d43937 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/FavoritesScreen.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/FavoritesScreen.kt @@ -85,7 +85,6 @@ import com.hippo.ehviewer.ui.tools.awaitConfirmationOrCancel import com.hippo.ehviewer.ui.tools.awaitSelectItem import com.hippo.ehviewer.ui.tools.foldToLoadResult import com.hippo.ehviewer.ui.tools.rememberInVM -import com.hippo.ehviewer.ui.tools.rememberSerializable import com.hippo.ehviewer.ui.tools.thenIf import com.hippo.ehviewer.util.mapToLongArray import com.hippo.ehviewer.util.takeAndClear @@ -113,7 +112,7 @@ fun AnimatedVisibilityScope.FavouritesScreen(navigator: DestinationsNavigator) = val hasSignedIn by Settings.hasSignedIn.collectAsState() // Meta State - var urlBuilder by rememberSerializable { mutableStateOf(FavListUrlBuilder(favCat = Settings.recentFavCat)) } + var urlBuilder by rememberSaveable { mutableStateOf(FavListUrlBuilder(favCat = Settings.recentFavCat)) } var searchBarExpanded by rememberSaveable { mutableStateOf(false) } var searchBarOffsetY by remember { mutableIntStateOf(0) } diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/GalleryCommentsScreen.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/GalleryCommentsScreen.kt index 2529600d3..a14c66ea7 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/GalleryCommentsScreen.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/GalleryCommentsScreen.kt @@ -186,7 +186,7 @@ fun AnimatedVisibilityScope.GalleryCommentsScreen(gid: Long, navigator: Destinat val userCommentBackField = remember { mutableStateOf(TextFieldValue()) } var userComment by userCommentBackField var commentId by remember { mutableLongStateOf(-1) } - var comments by remember(galleryDetail) { mutableStateOf(galleryDetail.comments) } + var comments by rememberSaveable { mutableStateOf(galleryDetail.comments) } LaunchedEffect(comments) { galleryDetail.comments = comments } 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 8143d0a30..e660a9dd7 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,5 +1,6 @@ package com.hippo.ehviewer.ui.screen +import android.os.Parcelable import androidx.activity.result.contract.ActivityResultContracts.CreateDocument import androidx.collection.SieveCache import androidx.compose.animation.AnimatedVisibilityScope @@ -74,7 +75,7 @@ import com.ramcosta.composedestinations.annotation.RootGraph import com.ramcosta.composedestinations.navigation.DestinationsNavigator import eu.kanade.tachiyomi.util.lang.withIOContext import eu.kanade.tachiyomi.util.system.logcat -import kotlinx.serialization.Serializable +import kotlinx.parcelize.Parcelize import moe.tarsin.coroutines.runSuspendCatching import moe.tarsin.launchIO import moe.tarsin.snackbar @@ -84,15 +85,14 @@ typealias VoteTag = suspend GalleryDetail.(String, Int) -> Unit val detailCache = SieveCache(25) -@Serializable -sealed interface GalleryDetailScreenArgs +sealed interface GalleryDetailScreenArgs : Parcelable -@Serializable +@Parcelize data class GalleryInfoArgs( val galleryInfo: BaseGalleryInfo, ) : GalleryDetailScreenArgs -@Serializable +@Parcelize data class TokenArgs( val gid: Long, val token: String, diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/GalleryListScreen.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/GalleryListScreen.kt index 5e5b75a33..e4409e50f 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/GalleryListScreen.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/GalleryListScreen.kt @@ -121,7 +121,6 @@ import com.hippo.ehviewer.ui.tools.foldToLoadResult import com.hippo.ehviewer.ui.tools.rememberHapticFeedback import com.hippo.ehviewer.ui.tools.rememberInVM import com.hippo.ehviewer.ui.tools.rememberMutableStateInDataStore -import com.hippo.ehviewer.ui.tools.rememberSerializable import com.hippo.ehviewer.ui.tools.thenIf import com.hippo.ehviewer.util.FavouriteStatusRouter import com.ramcosta.composedestinations.annotation.Destination @@ -163,7 +162,7 @@ fun AnimatedVisibilityScope.ToplistScreen(navigator: DestinationsNavigator) = Ga @Composable fun AnimatedVisibilityScope.GalleryListScreen(lub: ListUrlBuilder, navigator: DestinationsNavigator) = Screen(navigator) { val searchFieldState = rememberTextFieldState() - var urlBuilder by rememberSerializable { mutableStateOf(lub) } + var urlBuilder by rememberSaveable { mutableStateOf(lub) } var searchBarExpanded by rememberSaveable { mutableStateOf(false) } var searchBarOffsetY by remember { mutableIntStateOf(0) } val animateItems by Settings.animateItems.collectAsState() diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/tools/State.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/tools/State.kt index c83a56697..aacfbef6e 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/tools/State.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/tools/State.kt @@ -5,12 +5,8 @@ import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue -import androidx.savedstate.serialization.SavedStateConfiguration import kotlin.reflect.KMutableProperty0 -import kotlinx.serialization.KSerializer -import kotlinx.serialization.serializer val KMutableProperty0.observed: MutableState @Composable @@ -33,11 +29,3 @@ val MutableState.rememberedAccessor: KMutableProperty0 var value by this@rememberedAccessor }::value } - -@Composable -inline fun rememberSerializable( - vararg inputs: Any?, - stateSerializer: KSerializer = serializer(), - configuration: SavedStateConfiguration = SavedStateConfiguration.DEFAULT, - noinline init: () -> MutableState, -) = rememberSaveable(inputs = inputs, stateSerializer, configuration, init) diff --git a/build.gradle.kts b/build.gradle.kts index bb85bc7db..3db8dadc9 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,6 +2,7 @@ plugins { alias(libs.plugins.android.application) apply false alias(libs.plugins.kotlin.android) apply false alias(libs.plugins.kotlin.compose) apply false + alias(libs.plugins.kotlin.parcelize) apply false alias(libs.plugins.kotlin.serialization) apply false alias(libs.plugins.ksp) apply false alias(libs.plugins.spotless) apply false diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e58ed23e9..751a5720d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -136,6 +136,7 @@ android-application = { id = "com.android.application", version.ref = "agp" } composeCompilerReportGenerator = { id = "dev.shreyaspatil.compose-compiler-report-generator", version = "1.4.2" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } +kotlin-parcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref = "kotlin" } kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } spotless = { id = "com.diffplug.spotless", version = "7.0.3" }