Compare commits

...
54 Commits
Author SHA1 Message Date
FooIbar 70f46442c6 Prepare for release 1.11.6-RC2
Releases / build (push) Has been cancelled
2024-06-06 22:07:23 +08:00
FooIbar 13cf42437f Update Compose snapshot
https://issuetracker.google.com/343750859
2024-06-06 21:54:22 +08:00
renovate[bot] 1e29f6dcb4 Update kotlinx.serialization to v1.7.0 2024-06-06 13:52:43 +00:00
renovate[bot] f25981792f Update dependency com.google.devtools.ksp to v2.0.0-1.0.22 2024-06-06 00:09:30 +00:00
FooIbar 934c8be3e4 Anti-tamper support 2024-06-04 15:13:09 +08:00
renovate[bot] b9994eacbc Lock file maintenance 2024-06-03 01:53:41 +00:00
FooIbar 704ab0ee7e Prepare for next iteration 2024-06-02 23:38:33 +08:00
FooIbar 6d1d737f9f Prepare for release 1.11.6-RC1
Releases / build (push) Has been cancelled
2024-06-02 23:38:02 +08:00
FooIbar bc75156232 Simplify ReadableTime.getFilenamableTime 2024-06-02 22:51:58 +08:00
FooIbar 2101ea7a36 Update mime types based on Android's mime.types 2024-06-02 22:22:42 +08:00
FooIbar 26921c8ae1 Fix data export/import on Android V
The mime type mapping for sqlite files was added in
https://r.android.com/2988915.
2024-06-02 22:22:42 +08:00
FooIbar be1eecf3b5 Use official coroutines API instead of manual cast 2024-06-02 19:49:21 +08:00
FooIbar 2d4f154c9b Prevent async failure from cancelling parent scope 2024-06-02 19:49:21 +08:00
renovate[bot] d82cbe51ba Update dependency io.github.fornewid:material-motion-compose-core to v1.2.1 2024-06-02 03:13:01 +00:00
FooIbar d13ffa93ba Workaround for navigation bars padding on API < 28 2024-06-01 22:34:30 +08:00
FooIbar 2cce55953f Fix quick search and download label reordering
This is a regression introduced by 6277d7d.
2024-06-01 22:15:44 +08:00
FooIbar 07d100fcc0 Show navigation drawer only on top-level screens (#1266)
* Show navigation drawer only on top-level screens

* Remove redundant `rememberUpdatedState`
2024-06-01 18:59:16 +08:00
FooIbar cc04371181 Fix navigation drawer overlapping side sheet 2024-06-01 13:08:49 +08:00
github-actions[bot] ee50c88765 Update Chrome version for default User-Agent 2024-06-01 09:02:43 +08:00
renovate[bot] efc5b55ea7 Update dependency gradle to v8.8 2024-05-31 23:42:12 +00:00
FooIbar 94af66156a Replace invalid/consecutive whitespaces in query 2024-06-01 01:52:03 +08:00
FooIbar 4861359f9e Make secondary FAB offset density-aware 2024-06-01 01:51:40 +08:00
renovate[bot] 5af167dab4 Update compose.destinations to v2.1.0-beta09 2024-05-31 14:19:32 +00:00
renovate[bot] db1f0bc6d7 Update dependency com.android.application to v8.6.0-alpha04 2024-05-30 23:33:55 +00:00
renovate[bot] b94a843ec5 Update aboutlibraries to v11.2.1 2024-05-30 08:27:09 +00:00
FooIbar b27d214f24 Use Non-H as default category for guest mode
Don't modify the URL builder.
2024-05-30 10:57:26 +08:00
FooIbar a81eb9d17b Fix default value 2024-05-30 10:57:26 +08:00
FooIbar ec9b85f30f Refactor to not get sign-in state from cookies 2024-05-30 10:57:26 +08:00
FooIbar 8ac2f33949 Update liblzma to v5.6.2 2024-05-30 09:32:18 +08:00
FooIbar d84198ab28 Move Compose out of snapshot 2024-05-30 09:22:20 +08:00
renovate[bot] 34d339d9f1 Update compose.destinations to v2.1.0-beta08 2024-05-30 00:26:53 +00:00
renovate[bot] bcfefc7c76 Update dependency dev.chrisbanes.compose:compose-bom to v2024.05.00-alpha03 2024-05-29 21:16:26 +00:00
renovate[bot] 62539dc48e Update dependency androidx.appcompat:appcompat to v1.7.0 2024-05-29 21:15:22 +00:00
renovate[bot] 453ab11395 Update androidx.lifecycle to v2.8.1 2024-05-29 18:36:58 +00:00
renovate[bot] b2246b980a Update androidx.room to v2.7.0-alpha03 2024-05-29 18:36:07 +00:00
FooIbar 822a461acd Use All as default recent download label 2024-05-28 22:46:18 +08:00
renovate[bot] 25e5c0ab8e Lock file maintenance 2024-05-27 01:53:10 +00:00
FooIbar 2a55db95f4 Workaround for ReaderPageSheet clipped on API < 28 2024-05-26 17:17:50 +08:00
FooIbar a144866182 Use commit time instead for reproducible builds 2024-05-25 16:56:17 +08:00
FooIbar be7a04a4cb Move kotlin options to kotlin block 2024-05-24 22:18:18 +08:00
renovate[bot] fd1b861dab Update dependency com.android.application to v8.6.0-alpha03 2024-05-24 01:09:17 +00:00
FooIbar 957ebd35aa Update Compose snapshot
https://issuetracker.google.com/333584635
2024-05-23 16:31:14 +08:00
FooIbar 29d8b11771 Fix quota exceeded exceptions being swallowed 2024-05-22 18:37:28 +08:00
renovate[bot] c87059e9d7 Update Kotlin & KSP 2024-05-22 09:51:29 +08:00
renovate[bot] 4babe2eec4 Update aboutlibraries to v11.2.0 2024-05-21 23:45:18 +00:00
FooIbar 48fdaaca0c Fix race condition of ComicInfo.xml modification 2024-05-21 19:54:41 +08:00
FooIbar f0ee88b4d6 [no ci] Fix renovate config 2024-05-21 17:32:37 +08:00
FooIbar 9210780b6b Fix renovate false positive 2024-05-21 17:26:30 +08:00
FooIbar b479e28543 Initial support for importing downloaded archives 2024-05-21 14:20:57 +08:00
FooIbar f93b98fc5e Fix user input not being used when rating gallery 2024-05-20 11:51:29 +08:00
renovate[bot] 4721d1011b Lock file maintenance 2024-05-20 00:43:28 +00:00
FooIbar 4da4443e67 [no ci] Remove unused res 2024-05-20 00:25:13 +08:00
FooIbar e5343f4360 Don't package 32-bit x86 libs into universal apk 2024-05-20 00:24:05 +08:00
FooIbar 86323220dc Prepare for next iteration 2024-05-19 23:06:35 +08:00
53 changed files with 277 additions and 255 deletions

No files matched your search

+24
View File
@@ -1,5 +1,29 @@
# 变更日志
## [1.11.6-RC2] - 2024-06-06
### 改进
* 下载图片时执行完整性校验以防止文件损坏/被篡改
## [1.11.6-RC1] - 2024-06-02
### 改进
* 下载列表默认显示全部下载项目
* 替换搜索文本中的换行符为空格 [#1258](https://github.com/FooIbar/EhViewer/issues/1258)
### Bug 修复
* 评价画廊时未使用输入的评分
* 搜索时意外选择 Non-H 类别 [#1246](https://github.com/FooIbar/EhViewer/issues/1246)
* 侧边栏与导航抽屉重叠 [#1262](https://github.com/FooIbar/EhViewer/issues/1262)
* 快速搜索/下载标签排序失效 [#1267](https://github.com/FooIbar/EhViewer/issues/1267)
* 加载压缩包/种子列表出错时 UI 冻结
* 低版本 Android 上某些 UI 被遮挡
## [1.11.5] - 2024-05-19
### 重大变更
+36 -30
View File
@@ -1,6 +1,5 @@
import com.mikepenz.aboutlibraries.plugin.DuplicateMode.MERGE
import com.mikepenz.aboutlibraries.plugin.DuplicateRule.GROUP
import java.time.Instant
val isRelease: Boolean
get() = gradle.startParameter.taskNames.any { it.contains("Release") }
@@ -17,6 +16,8 @@ plugins {
alias(libs.plugins.composeCompilerReportGenerator)
}
val supportedAbis = arrayOf("arm64-v8a", "x86_64", "armeabi-v7a")
android {
compileSdk = 34
ndkVersion = "27.0.11718014-beta1"
@@ -27,7 +28,7 @@ android {
isEnable = true
reset()
if (isRelease) {
include("arm64-v8a", "x86_64", "armeabi-v7a")
include(*supportedAbis)
isUniversalApk = true
} else {
include("arm64-v8a", "x86_64")
@@ -48,6 +49,10 @@ android {
commandLine = "git rev-parse --short=7 HEAD".split(' ')
}.standardOutput.asText.get().trim()
val commitTime = providers.exec {
commandLine = "git log -1 --format=%ct".split(' ')
}.standardOutput.asText.get().trim()
val repoName = providers.exec {
commandLine = "git remote get-url origin".split(' ')
}.standardOutput.asText.get().trim().removePrefix("https://github.com/").removePrefix("git@github.com:")
@@ -61,8 +66,8 @@ android {
minSdk = 26
targetSdk = 34
versionCode = 180056
versionName = "1.11.5"
// versionNameSuffix = "-SNAPSHOT"
versionName = "1.11.6"
versionNameSuffix = "-RC2"
resourceConfigurations.addAll(
listOf(
"zh",
@@ -81,9 +86,13 @@ android {
)
buildConfigField("String", "RAW_VERSION_NAME", "\"$versionName${versionNameSuffix.orEmpty()}\"")
buildConfigField("String", "COMMIT_SHA", "\"$commitSha\"")
buildConfigField("long", "COMMIT_TIME", commitTime)
buildConfigField("String", "REPO_NAME", "\"$repoName\"")
buildConfigField("String", "CHROME_VERSION", "\"$chromeVersion\"")
ndk {
if (isRelease) {
abiFilters.addAll(supportedAbis)
}
debugSymbolLevel = "FULL"
}
externalNativeBuild {
@@ -114,30 +123,6 @@ android {
isCoreLibraryDesugaringEnabled = true
}
kotlinOptions {
freeCompilerArgs = listOf(
// https://kotlinlang.org/docs/compiler-reference.html#progressive
"-progressive",
"-Xjvm-default=all",
"-Xcontext-receivers",
"-opt-in=coil3.annotation.ExperimentalCoilApi",
"-opt-in=androidx.compose.foundation.layout.ExperimentalLayoutApi",
"-opt-in=androidx.compose.material3.ExperimentalMaterial3Api",
"-opt-in=androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi",
"-opt-in=androidx.compose.ui.ExperimentalComposeUiApi",
"-opt-in=androidx.compose.foundation.ExperimentalFoundationApi",
"-opt-in=androidx.compose.animation.ExperimentalAnimationApi",
"-opt-in=androidx.paging.ExperimentalPagingApi",
"-opt-in=kotlin.contracts.ExperimentalContracts",
"-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
"-opt-in=kotlinx.coroutines.FlowPreview",
"-opt-in=kotlinx.serialization.ExperimentalSerializationApi",
"-opt-in=splitties.experimental.ExperimentalSplittiesApi",
"-opt-in=splitties.preferences.DataStorePreferencesPreview",
)
}
lint {
disable += setOf("MissingTranslation", "MissingQuantity")
fatal += setOf("NewApi", "InlinedApi")
@@ -157,11 +142,9 @@ android {
isShrinkResources = true
proguardFiles("proguard-rules.pro")
signingConfig = signConfig
buildConfigField("long", "BUILD_TIME", "${Instant.now().epochSecond}")
}
debug {
applicationIdSuffix = ".debug"
buildConfigField("long", "BUILD_TIME", "0")
lint {
abortOnError = false
}
@@ -275,6 +258,29 @@ dependencies {
kotlin {
jvmToolchain(21)
compilerOptions {
freeCompilerArgs = listOf(
// https://kotlinlang.org/docs/compiler-reference.html#progressive
"-progressive",
"-Xjvm-default=all",
"-Xcontext-receivers",
"-opt-in=coil3.annotation.ExperimentalCoilApi",
"-opt-in=androidx.compose.foundation.layout.ExperimentalLayoutApi",
"-opt-in=androidx.compose.material3.ExperimentalMaterial3Api",
"-opt-in=androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi",
"-opt-in=androidx.compose.ui.ExperimentalComposeUiApi",
"-opt-in=androidx.compose.foundation.ExperimentalFoundationApi",
"-opt-in=androidx.compose.animation.ExperimentalAnimationApi",
"-opt-in=androidx.paging.ExperimentalPagingApi",
"-opt-in=kotlin.contracts.ExperimentalContracts",
"-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
"-opt-in=kotlinx.coroutines.FlowPreview",
"-opt-in=kotlinx.serialization.ExperimentalSerializationApi",
"-opt-in=splitties.experimental.ExperimentalSplittiesApi",
"-opt-in=splitties.preferences.DataStorePreferencesPreview",
)
}
}
ksp {
+9 -8
View File
@@ -100,23 +100,24 @@
<data android:scheme="content" />
<data android:host="*" />
<data android:mimeType="application/octet-stream" />
<data android:mimeType="application/7z" />
<data android:mimeType="application/rar" />
<data android:mimeType="application/zip" />
<data android:mimeType="application/x-7z-compressed" />
<data android:mimeType="application/x-rar-compressed" />
<data android:mimeType="application/x-zip-compressed" />
<data android:mimeType="application/x-tar" />
<data android:mimeType="application/x-xz" />
<data android:mimeType="application/gzip" />
<data android:mimeType="application/vnd.rar" />
<data android:mimeType="application/vnd.comicbook+zip" />
<data android:mimeType="application/vnd.comicbook-rar" />
<!-- unofficial -->
<data android:mimeType="application/7z" />
<data android:mimeType="application/rar" />
<data android:mimeType="application/x-cbz" />
<data android:mimeType="application/x-cbr" />
<data android:mimeType="application/x-cbt" />
<data android:mimeType="application/x-cb7" />
<!-- untested -->
<data android:mimeType="application/vnd.comicbook+zip" />
<data android:mimeType="application/vnd.comicbook-rar" />
<data android:mimeType="application/x-zip-compressed" />
<data android:mimeType="application/x-rar-compressed" />
<data android:mimeType="application/x-compressed-tar" />
<data android:mimeType="application/x-bzip-compressed-tar" />
<data android:mimeType="application/x-lzma-compressed-tar" />
+1 -1
View File
@@ -21,7 +21,7 @@ option(BUILD_TESTING OFF)
FetchContent_Declare(
liblzma
GIT_REPOSITORY https://github.com/tukaani-project/xz.git
GIT_TAG v5.6.1
GIT_TAG v5.6.2
PATCH_COMMAND git apply ${CMAKE_CURRENT_LIST_DIR}/0001-Don-t-build-other-binaries.patch || cd .
)
@@ -10,6 +10,7 @@ import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.remember
import com.hippo.ehviewer.client.CHROME_USER_AGENT
import com.hippo.ehviewer.client.EhCookieStore
import com.hippo.ehviewer.client.data.FavListUrlBuilder
import com.hippo.ehviewer.download.DownloadsFilterMode
import com.hippo.ehviewer.download.SortMode
@@ -112,6 +113,7 @@ object Settings : DataStorePreferences(null) {
val languageFilter = intPref("language_filter", -1)
val downloadSortMode = intPref("download_sort_mode", SortMode.Default.flag)
val downloadFilterMode = intPref("download_filter_mode", DownloadsFilterMode.Default.flag)
val hasSignedIn = boolPref("has_signed_in", EhCookieStore.hasSignedIn())
val meteredNetworkWarning = boolPref("cellular_network_warning", false)
val blackDarkTheme = boolPref("black_dark_theme", false)
val gridView = boolPref("grid_view", false)
@@ -120,7 +122,7 @@ object Settings : DataStorePreferences(null) {
val security = boolPref("require_unlock", false)
val animateItems = boolPref("animate_items", true)
val displayName = stringOrNullPref("display_name", null)
val recentDownloadLabel = stringOrNullPref("recent_download_label", null)
val recentDownloadLabel = stringOrNullPref("recent_download_label", "")
var downloadScheme by stringOrNullPref("image_scheme", null)
var downloadAuthority by stringOrNullPref("image_authority", null)
@@ -169,7 +171,7 @@ object Settings : DataStorePreferences(null) {
var recentToplist by stringPref("recent_toplist", "11")
var userAgent by stringPref("user_agent", CHROME_USER_AGENT)
var defaultDownloadLabel by stringOrNullPref("default_download_label", null)
var lastUpdateTime by longPref("last_update_time", BuildConfig.BUILD_TIME)
var lastUpdateTime by longPref("last_update_time", BuildConfig.COMMIT_TIME)
// Tachiyomi Reader
var newReader by boolPref("new_compose_reader", false)
@@ -2,7 +2,6 @@ package com.hippo.ehviewer
import android.app.UiModeManager
import androidx.appcompat.app.AppCompatDelegate
import com.hippo.ehviewer.client.EhCookieStore
import com.hippo.ehviewer.client.EhEngine
import com.hippo.ehviewer.client.EhTagDatabase
import com.hippo.ehviewer.dailycheck.updateDailyCheckWork
@@ -54,7 +53,7 @@ fun updateWhenRequestNewsChanges() {
}
fun updateWhenGallerySiteChanges() {
if (!Settings.needSignIn && EhCookieStore.hasSignedIn()) {
if (Settings.hasSignedIn.value) {
collectScope.launchIO {
runCatching {
EhEngine.getUConfig()
@@ -12,7 +12,7 @@ import io.ktor.http.renderSetCookieHeader
object EhCookieStore : CookiesStorage {
private val manager = CookieManager.getInstance()
fun signOut() = manager.removeAllCookies(null)
fun removeAllCookies() = manager.removeAllCookies(null)
fun contains(url: String, name: String) = load(Url(url)).fastAny { it.name == name }
fun hasSignedIn(): Boolean {
@@ -86,7 +86,7 @@ private const val REQUEST_INTERVAL = 5000L
fun Either<String, ByteBuffer>.saveParseError(e: Throwable) {
val dir = AppConfig.externalParseErrorDir ?: return
val file = File(dir, ReadableTime.getFilenamableTime(System.currentTimeMillis()) + ".txt")
val file = File(dir, ReadableTime.getFilenamableTime() + ".txt")
file.sink().buffer().use { sink ->
with(sink) {
writeUtf8(e.message + "\n")
@@ -152,8 +152,9 @@ object EhUtils {
val categoryTextColor = Color(0xffe6e0e9)
fun signOut() {
EhCookieStore.signOut()
EhCookieStore.removeAllCookies()
Settings.displayName.value = null
Settings.hasSignedIn.value = false
Settings.gallerySite = EhUrl.SITE_E
Settings.needSignIn = true
}
@@ -262,6 +262,7 @@ data class ListUrlBuilder(
fun build(): String {
return when (mode) {
MODE_NORMAL, MODE_SUBSCRIPTION -> ehUrl(EhUrl.WATCHED_PATH.takeIf { mode == MODE_SUBSCRIPTION }) {
val category = if (!Settings.hasSignedIn.value && category <= 0) EhUtils.NON_H else category
if (category > 0) {
addQueryParameter("f_cats", (category.inv() and EhUtils.ALL_CATEGORY).toString())
}
@@ -21,7 +21,6 @@ import androidx.work.WorkManager
import androidx.work.WorkerParameters
import com.hippo.ehviewer.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.EhCookieStore
import com.hippo.ehviewer.client.EhEngine
import eu.kanade.tachiyomi.util.lang.withIOContext
import eu.kanade.tachiyomi.util.system.logcat
@@ -83,7 +82,7 @@ val today
get() = (Clock.System.now().epochSeconds / 86400).toInt()
suspend fun checkDawn() = runCatching {
if (EhCookieStore.hasSignedIn() && Settings.lastDawnDays != today) {
if (Settings.hasSignedIn.value && Settings.lastDawnDays != today) {
EhEngine.getNews(true)?.let {
Settings.lastDawnDays = today
showEventNotification(it)
@@ -835,5 +835,5 @@ var downloadLocation: UniFile
}
val DownloadInfo.downloadDir get() = dirname?.let { downloadLocation / it }
val DownloadInfo.archiveFile get() = downloadDir?.findFile("$gid.cbz")
val DownloadInfo.archiveFile get() = downloadDir?.run { findFile("$gid.cbz") ?: findFile("$gid.zip") }
val GalleryInfo.tempDownloadDir get() = AppConfig.getTempDir("$gid")
@@ -55,7 +55,7 @@ class ArchivePageLoader(
private val hostJob = launch(start = CoroutineStart.LAZY) {
logcat(DEBUG_TAG) { "Open archive ${file.uri.displayPath}" }
pfd = file.openFileDescriptor("r")
size = openArchive(pfd.fd, pfd.statSize, gid == 0L)
size = openArchive(pfd.fd, pfd.statSize, gid == 0L || file.name!!.endsWith(".zip"))
if (size == 0) {
return@launch
}
@@ -43,7 +43,7 @@ import com.hippo.ehviewer.util.sendTo
import com.hippo.unifile.UniFile
import com.hippo.unifile.asUniFile
import com.hippo.unifile.openOutputStream
import eu.kanade.tachiyomi.util.lang.withNonCancellableContext
import com.hippo.unifile.sha1
import eu.kanade.tachiyomi.util.system.logcat
import io.ktor.client.plugins.onDownload
import io.ktor.client.statement.HttpResponse
@@ -196,6 +196,9 @@ class SpiderDen(val info: GalleryInfo) {
outFile.openOutputStream().use {
response.bodyAsChannel().copyTo(it.channel)
}
val expected = FileHashRegex.find(url)?.run { groupValues[0] }
val actual = outFile.sha1()
check(expected == actual) { "File hash mismatch: expected $expected, but got $actual\nURL: $url" }
}
}
@@ -276,7 +279,7 @@ class SpiderDen(val info: GalleryInfo) {
val archived = saveAsCbz && dir?.findFile(archiveName) != null
if (archived) {
dir.listFiles().parMap(concurrency = 10) {
if (it.name?.matches(filenamePattern) == true) {
if (it.name?.matches(FileNameRegex) == true) {
it.delete()
}
}
@@ -323,9 +326,7 @@ class SpiderDen(val info: GalleryInfo) {
createFile(COMIC_INFO_FILE)?.also {
runCatching {
if (info !is GalleryDetail && fetchMetadata) {
withNonCancellableContext {
EhEngine.fillGalleryListByApi(listOf(info))
}
EhEngine.fillGalleryListByApi(listOf(info))
}
info.getComicInfo().apply {
write(it)
@@ -342,7 +343,8 @@ class SpiderDen(val info: GalleryInfo) {
}
}
private val filenamePattern = Regex("^\\d{8}\\.\\w{3,4}")
private val FileNameRegex = Regex("^\\d{8}\\.\\w{3,4}")
private val FileHashRegex = Regex("[0-9a-f]{40}")
fun perFilename(index: Int, extension: String = ""): String {
return "%08d.%s".format(index + 1, extension)
@@ -244,12 +244,15 @@ class SpiderQueen private constructor(val galleryInfo: GalleryInfo) : CoroutineS
if (archiveJob.isActive) {
archiveJob.join()
}
runCatching {
if (!mSpiderDen.postArchive()) {
if (!mSpiderDen.postArchive()) {
if (mWorkerScope.isDownloadMode) {
mSpiderDen.writeComicInfo()
}
runCatching {
writeSpiderInfoToLocal()
}.onFailure {
logcat(it)
}
}.onFailure {
logcat(it)
}
queenScope.cancel()
}
@@ -483,13 +486,7 @@ class SpiderQueen private constructor(val galleryInfo: GalleryInfo) : CoroutineS
val gid = galleryInfo.gid
return (sQueenMap[gid] ?: SpiderQueen(galleryInfo).also { sQueenMap[gid] = it }).apply {
setMode(mode)
launch {
// Will create download dir if not exists
updateMode()
if (mode == MODE_DOWNLOAD) {
mSpiderDen.writeComicInfo()
}
}
launch { updateMode() }
}
}
@@ -516,7 +513,8 @@ class SpiderQueen private constructor(val galleryInfo: GalleryInfo) : CoroutineS
private val downloadTimeout = Settings.downloadTimeout.seconds
private val delayLock = Mutex()
private var lastRequestTime = TimeSource.Monotonic.markNow()
private var isDownloadMode = false
var isDownloadMode = false
private set
fun cancelDecode(index: Int) {
decoder.cancel(index)
@@ -648,15 +646,15 @@ class SpiderQueen private constructor(val galleryInfo: GalleryInfo) : CoroutineS
pToken,
localShowKey,
previousPToken,
).let {
check509(it.imageUrl)
imageUrl = it.imageUrl
skipHathKey = it.skipHathKey
originImageUrl = it.originImageUrl
}
}.onFailure {
)
}.getOrElse {
forceHtml = true
return@repeat
}.let {
check509(it.imageUrl)
imageUrl = it.imageUrl
skipHathKey = it.skipHathKey
originImageUrl = it.originImageUrl
}
}
@@ -40,7 +40,6 @@ import androidx.core.content.ContextCompat
import com.hippo.ehviewer.EhDB
import com.hippo.ehviewer.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.EhCookieStore
import com.hippo.ehviewer.client.EhEngine
import com.hippo.ehviewer.client.EhUtils
import com.hippo.ehviewer.client.data.BaseGalleryInfo
@@ -190,7 +189,7 @@ suspend fun DialogState.startDownload(
suspend fun DialogState.modifyFavorites(galleryInfo: BaseGalleryInfo): Boolean {
val localFavorited = EhDB.containLocalFavorites(galleryInfo.gid)
if (EhCookieStore.hasSignedIn()) {
if (Settings.hasSignedIn.value) {
val isFavorited = galleryInfo.favoriteSlot != NOT_FAVORITED
val defaultFavSlot = Settings.defaultFavSlot
if (defaultFavSlot == -2) {
@@ -348,15 +348,15 @@ class MainActivity : EhActivity() {
onPauseOrDispose { job.cancel() }
}
val currentDestination by navController.currentDestinationAsState()
val lockDrawerHandle = remember { mutableStateListOf<Int>() }
val drawerHandle = remember { mutableStateListOf<Int>() }
var snackbarFabPadding by remember { mutableStateOf(0.dp) }
val drawerLocked = lockDrawerHandle.isNotEmpty()
val drawerEnabled = drawerHandle.isNotEmpty()
val density = LocalDensity.current
val adaptiveInfo = currentWindowAdaptiveInfo()
CompositionLocalProvider(
LocalNavDrawerState provides navDrawerState,
LocalSideSheetState provides sideSheetState,
LocalDrawerLockHandle provides lockDrawerHandle,
LocalDrawerHandle provides drawerHandle,
LocalSnackBarHostState provides snackbarState,
LocalSnackBarFabPadding provides animateDpAsState(snackbarFabPadding, label = "SnackbarFabPadding"),
LocalWindowSizeClass provides adaptiveInfo.windowSizeClass,
@@ -415,7 +415,7 @@ class MainActivity : EhActivity() {
}
},
drawerState = navDrawerState,
gesturesEnabled = !drawerLocked || navDrawerState.isOpen,
gesturesEnabled = drawerEnabled && sideSheetState.isClosed || navDrawerState.isOpen,
) {
val sheet = sideSheet.firstOrNull()
val radius by remember {
@@ -444,7 +444,7 @@ class MainActivity : EhActivity() {
}
},
drawerState = sideSheetState,
gesturesEnabled = sheet != null && !drawerLocked,
gesturesEnabled = sheet != null && drawerEnabled,
) {
DestinationsNavHost(
navGraph = NavGraphs.root,
@@ -530,16 +530,15 @@ class MainActivity : EhActivity() {
val LocalNavDrawerState = compositionLocalOf<DrawerState> { error("CompositionLocal LocalNavDrawerState not present!") }
val LocalSideSheetState = compositionLocalOf<DrawerState2> { error("CompositionLocal LocalSideSheetState not present!") }
val LocalDrawerLockHandle = compositionLocalOf<SnapshotStateList<Int>> { error("CompositionLocal LocalDrawerLockHandle not present!") }
val LocalDrawerHandle = compositionLocalOf<SnapshotStateList<Int>> { error("CompositionLocal LocalDrawerHandle not present!") }
val LocalSnackBarHostState = compositionLocalOf<SnackbarHostState> { error("CompositionLocal LocalSnackBarHostState not present!") }
val LocalSnackBarFabPadding = compositionLocalOf<State<Dp>> { error("CompositionLocal LocalSnackBarFabPadding not present!") }
@Composable
fun LockDrawer(value: Boolean) {
val updated by rememberUpdatedState(value)
if (updated) {
fun DrawerHandle(enabled: Boolean) {
if (enabled) {
val current = currentCompositeKeyHash
val handle = LocalDrawerLockHandle.current
val handle = LocalDrawerHandle.current
DisposableEffect(current) {
handle.add(current)
onDispose {
@@ -40,5 +40,6 @@ suspend fun postLogin() = coroutineScope {
}.onFailure {
Settings.gallerySite = EhUrl.SITE_E
}
Settings.hasSignedIn.value = true
Settings.needSignIn = false
}
@@ -60,7 +60,6 @@ import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.EhEngine
import com.hippo.ehviewer.client.EhUrl
import com.hippo.ehviewer.client.EhUtils
import com.hippo.ehviewer.ui.LockDrawer
import com.hippo.ehviewer.ui.StartDestination
import com.hippo.ehviewer.ui.destinations.WebViewSignInScreenDestination
import com.hippo.ehviewer.ui.openBrowser
@@ -80,7 +79,6 @@ import kotlinx.coroutines.Job
@Destination<RootGraph>(start = true)
@Composable
fun SignInScreen(navigator: DestinationsNavigator) {
LockDrawer(true)
val windowSizeClass = LocalWindowSizeClass.current
val coroutineScope = rememberCoroutineScope()
val focusManager = LocalFocusManager.current
@@ -13,7 +13,6 @@ import com.google.accompanist.web.rememberWebViewState
import com.hippo.ehviewer.client.EhCookieStore
import com.hippo.ehviewer.client.EhUrl
import com.hippo.ehviewer.client.EhUtils
import com.hippo.ehviewer.ui.LockDrawer
import com.hippo.ehviewer.ui.StartDestination
import com.hippo.ehviewer.ui.screen.popNavigate
import com.hippo.ehviewer.util.setDefaultSettings
@@ -28,7 +27,6 @@ import io.ktor.http.Url
@Destination<RootGraph>
@Composable
fun WebViewSignInScreen(navigator: DestinationsNavigator) {
LockDrawer(true)
val coroutineScope = rememberCoroutineScope()
val state = rememberWebViewState(url = EhUrl.URL_SIGN_IN)
val client = remember {
@@ -30,6 +30,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.lerp
@@ -133,6 +134,10 @@ fun FabLayout(
transform { onEachLatest { state.waitCollapse() } }
}
val density = LocalDensity.current
val interval = remember(density) { with(density) { FabInterval.roundToPx() } }
val padding = remember(density) { with(density) { FabPadding.roundToPx() } }
if (updatedExpanded && autoCancel) {
Spacer(
modifier = Modifier.fillMaxSize().pointerInput(Unit) {
@@ -174,7 +179,7 @@ fun FabLayout(
}
},
modifier = Modifier.padding(20.dp).offset {
val distance = lerp(0, 150 * (size - index) + 50, animatedProgress)
val distance = lerp(0, interval * (size - index) + padding, animatedProgress)
IntOffset(0, -distance)
},
) {
@@ -210,4 +215,6 @@ private fun buildFab(builder: FabBuilder.() -> Unit) = buildList {
}
}
private val FabInterval = 56.dp // Small FAB height + 16 dp
private val FabPadding = 8.dp // (FAB height - small FAB height) / 2
const val FAB_ANIMATE_TIME = 300
@@ -48,7 +48,6 @@ import com.hippo.ehviewer.download.DownloadManager
import com.hippo.ehviewer.download.archiveFile
import com.hippo.ehviewer.gallery.ArchivePageLoader
import com.hippo.ehviewer.gallery.EhPageLoader
import com.hippo.ehviewer.ui.LockDrawer
import com.hippo.ehviewer.ui.composing
import com.hippo.ehviewer.ui.tools.Deferred
import com.ramcosta.composedestinations.annotation.Destination
@@ -67,7 +66,6 @@ import moe.tarsin.kt.unreachable
@Destination<RootGraph>
@Composable
fun ReaderScreen(info: BaseGalleryInfo, page: Int = -1, navigator: DestinationsNavigator) = composing(navigator) {
LockDrawer(true)
ConfigureKeepScreenOn()
val pageLoader = remember {
val archive = DownloadManager.getDownloadInfo(info.gid)?.archiveFile
@@ -96,8 +96,8 @@ import com.hippo.ehviewer.download.DownloadsFilterMode
import com.hippo.ehviewer.download.SortMode
import com.hippo.ehviewer.icons.EhIcons
import com.hippo.ehviewer.icons.big.Download
import com.hippo.ehviewer.ui.DrawerHandle
import com.hippo.ehviewer.ui.LocalSideSheetState
import com.hippo.ehviewer.ui.LockDrawer
import com.hippo.ehviewer.ui.composing
import com.hippo.ehviewer.ui.confirmRemoveDownloadRange
import com.hippo.ehviewer.ui.main.DownloadCard
@@ -139,6 +139,7 @@ fun DownloadsScreen(navigator: DestinationsNavigator) = composing(navigator) {
val filterMode by Settings.downloadFilterMode.collectAsState { DownloadsFilterMode.from(it) }
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) }
val animateItems by Settings.animateItems.collectAsState()
@@ -146,7 +147,7 @@ fun DownloadsScreen(navigator: DestinationsNavigator) = composing(navigator) {
var fabHidden by remember { mutableStateOf(false) }
val checkedInfoMap = remember { mutableStateMapOf<Long, DownloadInfo>() }
val selectMode by rememberUpdatedState(checkedInfoMap.isNotEmpty())
LockDrawer(selectMode)
DrawerHandle(!selectMode && !searchBarExpanded)
val density = LocalDensity.current
val canTranslate = Settings.showTagTranslations && EhTagDatabase.isTranslatable(implicit<Context>()) && EhTagDatabase.initialized
@@ -332,7 +333,8 @@ fun DownloadsScreen(navigator: DestinationsNavigator) = composing(navigator) {
)
}
itemsIndexed(groupList, key = { _, (id) -> id }) { index, (id, label) ->
itemsIndexed(groupList, key = { _, (id) -> id }) { itemIndex, (id, label) ->
val index by rememberUpdatedState(itemIndex)
val item by rememberUpdatedState(label)
// Not using rememberSwipeToDismissBoxState to prevent LazyColumn from reusing it
val dismissState = remember { SwipeToDismissBoxState(SwipeToDismissBoxValue.Settled, density, positionalThreshold = positionalThreshold) }
@@ -436,14 +438,15 @@ fun DownloadsScreen(navigator: DestinationsNavigator) = composing(navigator) {
}
SearchBarScreen(
onApplySearch = { filterState = filterState.copy(keyword = it) },
expanded = searchBarExpanded,
onExpandedChange = {
searchBarExpanded = it
fabHidden = it
if (it) checkedInfoMap.clear()
},
title = title,
searchFieldHint = hint,
onApplySearch = { filterState = filterState.copy(keyword = it) },
onSearchExpanded = {
checkedInfoMap.clear()
fabHidden = true
},
onSearchHidden = { fabHidden = false },
searchBarOffsetY = { searchBarOffsetY },
trailingIcon = {
var expanded by remember { mutableStateOf(false) }
@@ -57,15 +57,14 @@ import androidx.paging.filter
import com.hippo.ehviewer.EhDB
import com.hippo.ehviewer.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.EhCookieStore
import com.hippo.ehviewer.client.EhEngine
import com.hippo.ehviewer.client.data.BaseGalleryInfo
import com.hippo.ehviewer.client.data.FavListUrlBuilder
import com.hippo.ehviewer.collectAsState
import com.hippo.ehviewer.icons.EhIcons
import com.hippo.ehviewer.icons.filled.GoTo
import com.hippo.ehviewer.ui.DrawerHandle
import com.hippo.ehviewer.ui.LocalSideSheetState
import com.hippo.ehviewer.ui.LockDrawer
import com.hippo.ehviewer.ui.awaitSelectDate
import com.hippo.ehviewer.ui.composing
import com.hippo.ehviewer.ui.main.FAB_ANIMATE_TIME
@@ -100,9 +99,11 @@ fun FavouritesScreen(navigator: DestinationsNavigator) = composing(navigator) {
val localFavName = stringResource(R.string.local_favorites)
val cloudFavName = stringResource(R.string.cloud_favorites)
val animateItems by Settings.animateItems.collectAsState()
val hasSignedIn by Settings.hasSignedIn.collectAsState()
// Meta State
var urlBuilder by rememberSaveable { mutableStateOf(FavListUrlBuilder(favCat = Settings.recentFavCat)) }
var searchBarExpanded by rememberSaveable { mutableStateOf(false) }
var searchBarOffsetY by remember { mutableIntStateOf(0) }
// Derived State
@@ -192,7 +193,7 @@ fun FavouritesScreen(navigator: DestinationsNavigator) = composing(navigator) {
}
}
val localFav = stringResource(id = R.string.local_favorites) to localFavCount
val faves = if (EhCookieStore.hasSignedIn()) {
val faves = if (hasSignedIn) {
arrayOf(
localFav,
stringResource(id = R.string.cloud_favorites) to Settings.favCloudCount,
@@ -224,17 +225,18 @@ fun FavouritesScreen(navigator: DestinationsNavigator) = composing(navigator) {
var fabHidden by remember { mutableStateOf(false) }
val checkedInfoMap = remember { mutableStateMapOf<Long, BaseGalleryInfo>() }
val selectMode = checkedInfoMap.isNotEmpty()
LockDrawer(selectMode)
DrawerHandle(!selectMode && !searchBarExpanded)
SearchBarScreen(
onApplySearch = { refresh(FavListUrlBuilder(urlBuilder.favCat, it)) },
expanded = searchBarExpanded,
onExpandedChange = {
searchBarExpanded = it
fabHidden = it
if (it) checkedInfoMap.clear()
},
title = title,
searchFieldHint = searchBarHint,
onApplySearch = { refresh(FavListUrlBuilder(urlBuilder.favCat, it)) },
onSearchExpanded = {
checkedInfoMap.clear()
fabHidden = true
},
onSearchHidden = { fabHidden = false },
tagNamespace = !isLocalFav,
searchBarOffsetY = { searchBarOffsetY },
trailingIcon = {
@@ -399,7 +401,7 @@ fun FavouritesScreen(navigator: DestinationsNavigator) = composing(navigator) {
// First is local favorite, the other 10 is cloud favorite
val items = buildList {
add(localFavName)
if (EhCookieStore.hasSignedIn()) {
if (hasSignedIn) {
addAll(Settings.favCat)
}
}
@@ -74,7 +74,6 @@ import androidx.core.text.parseAsHtml
import com.hippo.ehviewer.EhApplication
import com.hippo.ehviewer.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.EhCookieStore
import com.hippo.ehviewer.client.EhEngine
import com.hippo.ehviewer.client.EhFilter.remember
import com.hippo.ehviewer.client.EhUrl
@@ -83,7 +82,6 @@ import com.hippo.ehviewer.client.data.ListUrlBuilder
import com.hippo.ehviewer.collectAsState
import com.hippo.ehviewer.dao.Filter
import com.hippo.ehviewer.dao.FilterMode
import com.hippo.ehviewer.ui.LockDrawer
import com.hippo.ehviewer.ui.composing
import com.hippo.ehviewer.ui.jumpToReaderByPage
import com.hippo.ehviewer.ui.legacy.CoilImageGetter
@@ -150,7 +148,6 @@ private val MinimumContentPaddingEditText = 88.dp
@Destination<RootGraph>
@Composable
fun GalleryCommentsScreen(gid: Long, navigator: DestinationsNavigator) = composing(navigator) {
LockDrawer(true)
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
var commenting by rememberSaveable { mutableStateOf(false) }
val animationProgress by animateFloatMergePredictiveBackAsState(enable = commenting) { commenting = false }
@@ -244,7 +241,7 @@ fun GalleryCommentsScreen(gid: Long, navigator: DestinationsNavigator) = composi
}
}
}
val hasSignedIn = remember { EhCookieStore.hasSignedIn() }
val hasSignedIn by Settings.hasSignedIn.collectAsState()
Scaffold(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = {
@@ -60,7 +60,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -113,7 +112,6 @@ import com.hippo.ehviewer.download.DownloadManager as EhDownloadManager
import com.hippo.ehviewer.ktbuilder.imageRequest
import com.hippo.ehviewer.spider.SpiderDen
import com.hippo.ehviewer.ui.GalleryInfoBottomSheet
import com.hippo.ehviewer.ui.LockDrawer
import com.hippo.ehviewer.ui.MainActivity
import com.hippo.ehviewer.ui.composing
import com.hippo.ehviewer.ui.confirmRemoveDownload
@@ -164,6 +162,7 @@ import eu.kanade.tachiyomi.util.system.logcat
import kotlin.math.roundToInt
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import kotlinx.parcelize.Parcelize
@@ -215,7 +214,6 @@ private fun List<GalleryTagGroup>.getArtistTag(): String? {
@Destination<RootGraph>
@Composable
fun GalleryDetailScreen(args: GalleryDetailScreenArgs, navigator: DestinationsNavigator) = composing(navigator) {
LockDrawer(true)
var galleryInfo by remember {
val casted = args as? GalleryInfoArgs
mutableStateOf<GalleryInfo?>(casted?.galleryInfo)
@@ -295,7 +293,7 @@ fun GalleryDetailScreen(args: GalleryDetailScreenArgs, navigator: DestinationsNa
}
val archiveResult = remember(galleryInfo) {
async(Dispatchers.IO, CoroutineStart.LAZY) {
async(Dispatchers.IO + Job(), CoroutineStart.LAZY) {
val detail = galleryInfo as GalleryDetail
EhEngine.getArchiveList(detail.archiveUrl!!, gid, token)
}
@@ -567,7 +565,7 @@ fun GalleryDetailScreen(args: GalleryDetailScreenArgs, navigator: DestinationsNa
val downloadTorrentStarted = stringResource(R.string.download_torrent_started)
val noTorrents = stringResource(R.string.no_torrents)
val torrentResult = remember(galleryDetail) {
async(Dispatchers.IO, CoroutineStart.LAZY) {
async(Dispatchers.IO + Job(), CoroutineStart.LAZY) {
EhEngine.getTorrentList(galleryDetail.torrentUrl!!, gid, token)
}
}
@@ -639,23 +637,22 @@ fun GalleryDetailScreen(args: GalleryDetailScreenArgs, navigator: DestinationsNa
showSnackbar(signInFirst)
return@launchIO
}
awaitPermissionOrCancel(title = R.string.rate) {
val pendingRating = awaitResult(galleryDetail.rating.coerceAtLeast(.5f), title = R.string.rate) {
Column(modifier = Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {
var rating by remember { mutableFloatStateOf(galleryDetail.rating.coerceAtLeast(.5f)) }
var text by remember { mutableIntStateOf(getRatingText(rating)) }
var text by remember { mutableIntStateOf(getRatingText(expectedValue)) }
Text(text = stringResource(id = text), style = MaterialTheme.typography.bodyLarge)
Spacer(modifier = Modifier.size(keylineMargin))
GalleryRatingBar(
rating = rating,
rating = expectedValue,
onRatingChange = {
rating = it.coerceAtLeast(.5f)
text = getRatingText(rating)
expectedValue = it.coerceAtLeast(.5f)
text = getRatingText(expectedValue)
},
)
}
}
galleryDetail.runSuspendCatching {
EhEngine.rateGallery(apiUid, apiKey, gid, token, rating)
EhEngine.rateGallery(apiUid, apiKey, gid, token, pendingRating)
}.onSuccess { result ->
galleryInfo = galleryDetail.apply {
rating = result.rating
@@ -1077,7 +1074,7 @@ fun GalleryDetailScreen(args: GalleryDetailScreenArgs, navigator: DestinationsNa
} else {
val info = galleryInfo!!
val uri = awaitActivityResult(
CreateDocument("application/x-cbz"),
CreateDocument("application/vnd.comicbook+zip"),
EhUtils.getSuitableTitle(info) + ".cbz",
)
val dirname = downloadInfo?.dirname
@@ -109,6 +109,7 @@ import com.hippo.ehviewer.collectAsState
import com.hippo.ehviewer.dao.QuickSearch
import com.hippo.ehviewer.icons.EhIcons
import com.hippo.ehviewer.icons.filled.GoTo
import com.hippo.ehviewer.ui.DrawerHandle
import com.hippo.ehviewer.ui.LocalSideSheetState
import com.hippo.ehviewer.ui.awaitSelectDate
import com.hippo.ehviewer.ui.composing
@@ -153,10 +154,7 @@ import sh.calvin.reorderable.rememberReorderableLazyListState
@Destination<RootGraph>
@Composable
fun HomePageScreen(navigator: DestinationsNavigator) {
val displayName by Settings.displayName.collectAsState()
GalleryListScreen(ListUrlBuilder(category = displayName?.let { EhUtils.NONE } ?: EhUtils.NON_H), navigator)
}
fun HomePageScreen(navigator: DestinationsNavigator) = GalleryListScreen(ListUrlBuilder(), navigator)
@Destination<RootGraph>
@Composable
@@ -175,6 +173,7 @@ fun ToplistScreen(navigator: DestinationsNavigator) = GalleryListScreen(ListUrlB
fun GalleryListScreen(lub: ListUrlBuilder, navigator: DestinationsNavigator) = composing(navigator) {
val searchFieldState = rememberTextFieldState()
var urlBuilder by rememberSaveable(lub) { mutableStateOf(lub) }
var searchBarExpanded by rememberSaveable { mutableStateOf(false) }
var searchBarOffsetY by remember { mutableIntStateOf(0) }
var showSearchLayout by rememberSaveable { mutableStateOf(false) }
@@ -182,6 +181,8 @@ fun GalleryListScreen(lub: ListUrlBuilder, navigator: DestinationsNavigator) = c
var advancedSearchOption by rememberMutableStateInDataStore("AdvancedSearchOption") { AdvancedSearchOption() }
var imageUri by rememberSaveable { mutableStateOf<Uri?>(null) }
DrawerHandle(!searchBarExpanded)
LaunchedEffect(urlBuilder) {
if (urlBuilder.category != EhUtils.NONE) category = urlBuilder.category
if (urlBuilder.mode != MODE_TOPLIST) {
@@ -384,7 +385,8 @@ fun GalleryListScreen(lub: ListUrlBuilder, navigator: DestinationsNavigator) = c
stickyHeader {
HorizontalDivider()
}
itemsIndexed(quickSearchList, key = { _, item -> item.id!! }) { index, item ->
itemsIndexed(quickSearchList, key = { _, item -> item.id!! }) { itemIndex, item ->
val index by rememberUpdatedState(itemIndex)
ReorderableItem(reorderableLazyListState, key = item.id!!) { isDragging ->
// Not using rememberSwipeToDismissBoxState to prevent LazyColumn from reusing it
val dismissState = remember { SwipeToDismissBoxState(SwipeToDismissBoxValue.Settled, density, positionalThreshold = positionalThreshold) }
@@ -398,11 +400,10 @@ fun GalleryListScreen(lub: ListUrlBuilder, navigator: DestinationsNavigator) = c
}.onSuccess {
EhDB.deleteQuickSearch(item)
with(quickSearchList) {
val removeIndex = indexOf(item)
subList(removeIndex + 1, size).forEach {
subList(index + 1, size).forEach {
it.position--
}
removeAt(removeIndex)
removeAt(index)
}
}.onFailure {
dismissState.reset()
@@ -541,12 +542,15 @@ fun GalleryListScreen(lub: ListUrlBuilder, navigator: DestinationsNavigator) = c
}
SearchBarScreen(
onApplySearch = ::onApplySearch,
expanded = searchBarExpanded,
onExpandedChange = {
searchBarExpanded = it
fabHidden = it
},
title = suitableTitle,
searchFieldState = searchFieldState,
searchFieldHint = searchBarHint,
onApplySearch = ::onApplySearch,
onSearchExpanded = { fabHidden = true },
onSearchHidden = { fabHidden = false },
suggestionProvider = {
GalleryDetailUrlParser.parse(it, false)?.run {
GalleryDetailUrlSuggestion(gid, token)
@@ -39,7 +39,6 @@ import com.hippo.ehviewer.coil.justDownload
import com.hippo.ehviewer.collectAsState
import com.hippo.ehviewer.ktbuilder.imageRequest
import com.hippo.ehviewer.ktbuilder.launchIn
import com.hippo.ehviewer.ui.LockDrawer
import com.hippo.ehviewer.ui.composing
import com.hippo.ehviewer.ui.main.EhPreviewItem
import com.hippo.ehviewer.ui.navToReader
@@ -59,7 +58,6 @@ import moe.tarsin.coroutines.runSuspendCatching
@Destination<RootGraph>
@Composable
fun GalleryPreviewScreen(detail: GalleryDetail, toNextPage: Boolean, navigator: DestinationsNavigator) = composing(navigator) {
LockDrawer(true)
val scrollBehaviour = TopAppBarDefaults.pinnedScrollBehavior()
val pgSize = detail.previewList.size
val state = rememberLazyGridState(initialFirstVisibleItemIndex = if (toNextPage) pgSize else 0)
@@ -47,6 +47,7 @@ import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.collectAsState
import com.hippo.ehviewer.icons.EhIcons
import com.hippo.ehviewer.icons.big.History
import com.hippo.ehviewer.ui.DrawerHandle
import com.hippo.ehviewer.ui.composing
import com.hippo.ehviewer.ui.doGalleryInfoAction
import com.hippo.ehviewer.ui.main.GalleryInfoListItem
@@ -70,9 +71,12 @@ fun HistoryScreen(navigator: DestinationsNavigator) = composing(navigator) {
val hint = stringResource(R.string.search_bar_hint, title)
val animateItems by Settings.animateItems.collectAsState()
var searchBarExpanded by rememberSaveable { mutableStateOf(false) }
var searchBarOffsetY by remember { mutableIntStateOf(0) }
var keyword by rememberSaveable { mutableStateOf("") }
DrawerHandle(!searchBarExpanded)
val density = LocalDensity.current
val historyData = rememberInVM {
Pager(config = PagingConfig(pageSize = 20, jumpThreshold = 40)) {
@@ -85,14 +89,14 @@ fun HistoryScreen(navigator: DestinationsNavigator) = composing(navigator) {
}.collectAsLazyPagingItems()
FavouriteStatusRouter.Observe(historyData)
SearchBarScreen(
title = title,
searchFieldHint = hint,
onApplySearch = {
keyword = it
historyData.refresh()
},
onSearchExpanded = {},
onSearchHidden = {},
expanded = searchBarExpanded,
onExpandedChange = { searchBarExpanded = it },
title = title,
searchFieldHint = hint,
searchBarOffsetY = { searchBarOffsetY },
trailingIcon = {
IconButton(onClick = {
@@ -24,7 +24,6 @@ import com.hippo.ehviewer.R
import com.hippo.ehviewer.client.EhEngine
import com.hippo.ehviewer.icons.EhIcons
import com.hippo.ehviewer.icons.big.SadAndroid
import com.hippo.ehviewer.ui.LockDrawer
import com.hippo.ehviewer.util.displayString
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
@@ -35,7 +34,6 @@ import moe.tarsin.coroutines.runSuspendCatching
@Destination<RootGraph>
@Composable
fun ProgressScreen(gid: Long, token: String, page: Int, navigator: DestinationsNavigator) {
LockDrawer(true)
val wrong = stringResource(id = R.string.error_something_wrong_happened)
var error by rememberSaveable { mutableStateOf("") }
LaunchedEffect(error) {
@@ -47,7 +47,6 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
@@ -67,7 +66,6 @@ import com.hippo.ehviewer.collectAsState
import com.hippo.ehviewer.dao.Search
import com.hippo.ehviewer.dao.SearchDao
import com.hippo.ehviewer.ui.LocalNavDrawerState
import com.hippo.ehviewer.ui.LockDrawer
import com.hippo.ehviewer.ui.tools.LocalDialogState
import com.hippo.ehviewer.ui.tools.rememberCompositionActiveState
import com.hippo.ehviewer.ui.tools.thenIf
@@ -99,23 +97,22 @@ suspend fun SearchDao.suggestions(prefix: String, limit: Int) =
@Composable
fun SearchBarScreen(
onApplySearch: (String) -> Unit,
expanded: Boolean,
onExpandedChange: (Boolean) -> Unit,
title: String? = null,
searchFieldState: TextFieldState = rememberTextFieldState(),
searchFieldHint: String? = null,
onApplySearch: (String) -> Unit,
onSearchExpanded: () -> Unit,
onSearchHidden: () -> Unit,
suggestionProvider: SuggestionProvider? = null,
tagNamespace: Boolean = false,
searchBarOffsetY: () -> Int,
trailingIcon: @Composable () -> Unit,
searchBarOffsetY: () -> Int = { 0 },
trailingIcon: @Composable () -> Unit = {},
filter: @Composable (() -> Unit)? = null,
floatingActionButton: @Composable () -> Unit = {},
content: @Composable (PaddingValues) -> Unit,
) {
var mSuggestionList by remember { mutableStateOf(emptyList<Suggestion>()) }
val mSearchDatabase = searchDatabase.searchDao()
var expanded by rememberSaveable { mutableStateOf(false) }
val scope = rememberCoroutineScope { Dispatchers.IO }
val context = LocalContext.current
val dialogState = LocalDialogState.current
@@ -166,19 +163,6 @@ fun SearchBarScreen(
mSuggestionList = mergedSuggestionFlow().toList()
}
var shouldLockDrawer by remember { mutableStateOf(false) }
LockDrawer(shouldLockDrawer)
fun onSearchViewExpanded() {
onSearchExpanded()
shouldLockDrawer = true
}
fun onSearchViewHidden() {
shouldLockDrawer = false
onSearchHidden()
}
if (expanded) {
LaunchedEffect(Unit) {
snapshotFlow { searchFieldState.text }.collectLatest {
@@ -188,12 +172,12 @@ fun SearchBarScreen(
}
fun hideSearchView() {
onSearchViewHidden()
expanded = false
onExpandedChange(false)
}
fun onApplySearch() {
val query = searchFieldState.text.trim().toString()
// May have invalid whitespaces if pasted from clipboard, replace them with spaces
val query = searchFieldState.text.trim().replace(WhitespaceRegex, " ")
if (query.isNotEmpty()) {
scope.launchIO {
mSearchDatabase.deleteQuery(query)
@@ -228,14 +212,6 @@ fun SearchBarScreen(
// https://issuetracker.google.com/337191298
// Workaround for can't exit SearchBar due to refocus in non-touch mode
Box(Modifier.size(1.dp).focusable())
val onExpandedChange = { v: Boolean ->
if (v) {
onSearchViewExpanded()
} else {
onSearchViewHidden()
}
expanded = v
}
val activeState = rememberCompositionActiveState()
SearchBar(
modifier = Modifier.align(Alignment.TopCenter).thenIf(!expanded) { offset { IntOffset(0, searchBarOffsetY()) } }
@@ -340,3 +316,5 @@ fun wrapTagKeyword(keyword: String, translate: Boolean = false): String {
}
}
}
private val WhitespaceRegex = Regex("\\s+")
@@ -51,7 +51,6 @@ import eu.kanade.tachiyomi.util.lang.withUIContext
import java.io.File
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.datetime.Clock
import moe.tarsin.coroutines.runSuspendCatching
private const val REPO_URL = "https://github.com/${BuildConfig.REPO_NAME}"
@@ -59,7 +58,7 @@ private const val RELEASE_URL = "$REPO_URL/releases"
@Composable
@Stable
private fun versionCode() = "${BuildConfig.VERSION_NAME} (${BuildConfig.COMMIT_SHA})\n" + stringResource(R.string.settings_about_build_time, AppConfig.buildTime)
private fun versionCode() = "${BuildConfig.VERSION_NAME} (${BuildConfig.COMMIT_SHA})\n" + stringResource(R.string.settings_about_commit_time, AppConfig.commitTime)
@Composable
@Stable
@@ -154,7 +153,7 @@ suspend fun DialogState.showNewVersion(context: Context, release: Release) {
}
}
if (Settings.backupBeforeUpdate) {
val time = ReadableTime.getFilenamableTime(Clock.System.now().toEpochMilliseconds())
val time = ReadableTime.getFilenamableTime()
downloadLocation.createFile("$time.db")?.let {
EhDB.exportDB(context, it)
}
@@ -36,9 +36,9 @@ import com.hippo.ehviewer.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.asMutableState
import com.hippo.ehviewer.client.CHROME_USER_AGENT
import com.hippo.ehviewer.client.EhCookieStore
import com.hippo.ehviewer.client.EhEngine
import com.hippo.ehviewer.client.data.FavListUrlBuilder
import com.hippo.ehviewer.collectAsState
import com.hippo.ehviewer.ui.tools.LocalDialogState
import com.hippo.ehviewer.ui.tools.observed
import com.hippo.ehviewer.util.AppConfig
@@ -46,6 +46,7 @@ import com.hippo.ehviewer.util.Crash
import com.hippo.ehviewer.util.ReadableTime
import com.hippo.ehviewer.util.getAppLanguage
import com.hippo.ehviewer.util.getLanguages
import com.hippo.ehviewer.util.isAtLeastV
import com.hippo.ehviewer.util.setAppLanguage
import com.hippo.unifile.asUniFile
import com.jamal.composeprefs3.ui.prefs.DropDownPref
@@ -107,7 +108,7 @@ fun AdvancedScreen(navigator: DestinationsNavigator) {
title = stringResource(id = R.string.settings_advanced_dump_logcat),
summary = stringResource(id = R.string.settings_advanced_dump_logcat_summary),
contract = ActivityResultContracts.CreateDocument("application/zip"),
key = "log-" + ReadableTime.getFilenamableTime(System.currentTimeMillis()) + ".zip",
key = "log-" + ReadableTime.getFilenamableTime() + ".zip",
) { uri ->
uri?.run {
context.runCatching {
@@ -123,7 +124,7 @@ fun AdvancedScreen(navigator: DestinationsNavigator) {
zipOs.putNextEntry(entry)
file.inputStream().use { it.copyTo(zipOs) }
}
val logcatEntry = ZipEntry("logcat-" + ReadableTime.getFilenamableTime(System.currentTimeMillis()) + ".txt")
val logcatEntry = ZipEntry("logcat-" + ReadableTime.getFilenamableTime() + ".txt")
zipOs.putNextEntry(logcatEntry)
Crash.collectInfo(zipOs.writer())
Runtime.getRuntime().exec("logcat -d").inputStream.use { it.copyTo(zipOs) }
@@ -179,11 +180,12 @@ fun AdvancedScreen(navigator: DestinationsNavigator) {
}
}
val exportFailed = stringResource(id = R.string.settings_advanced_export_data_failed)
val now = ReadableTime.getFilenamableTime()
LauncherPreference(
title = stringResource(id = R.string.settings_advanced_export_data),
summary = stringResource(id = R.string.settings_advanced_export_data_summary),
contract = ActivityResultContracts.CreateDocument("application/vnd.sqlite3"),
key = ReadableTime.getFilenamableTime(System.currentTimeMillis()) + ".db",
key = if (isAtLeastV) now else "$now.db",
) { uri ->
uri?.let {
context.runCatching {
@@ -202,7 +204,7 @@ fun AdvancedScreen(navigator: DestinationsNavigator) {
title = stringResource(id = R.string.settings_advanced_import_data),
summary = stringResource(id = R.string.settings_advanced_import_data_summary),
contract = ActivityResultContracts.GetContent(),
key = "application/octet-stream",
key = if (isAtLeastV) "application/vnd.sqlite3" else "application/octet-stream",
) { uri ->
uri?.let {
context.runCatching {
@@ -215,7 +217,8 @@ fun AdvancedScreen(navigator: DestinationsNavigator) {
}
}
}
if (EhCookieStore.hasSignedIn()) {
val hasSignedIn by Settings.hasSignedIn.collectAsState()
if (hasSignedIn) {
val backupNothing = stringResource(id = R.string.settings_advanced_backup_favorite_nothing)
val backupFailed = stringResource(id = R.string.settings_advanced_backup_favorite_failed)
val backupSucceed = stringResource(id = R.string.settings_advanced_backup_favorite_success)
@@ -84,7 +84,7 @@ fun EhScreen(navigator: DestinationsNavigator) {
val coroutineScope = rememberCoroutineScope { Dispatchers.IO }
val context = LocalContext.current
fun launchSnackBar(content: String) = coroutineScope.launch { snackbarHostState.showSnackbar(content) }
val signin = EhCookieStore.hasSignedIn()
val hasSignedIn by Settings.hasSignedIn.collectAsState()
val dialogState = LocalDialogState.current
Scaffold(
topBar = {
@@ -120,9 +120,9 @@ fun EhScreen(navigator: DestinationsNavigator) {
dismissText = R.string.settings_eh_clear_igneous,
showCancelButton = cookies.last().second != null,
onCancelButtonClick = { EhCookieStore.clearIgneous() },
secure = signin,
secure = hasSignedIn,
) {
if (signin) {
if (hasSignedIn) {
Column {
val warning = stringResource(id = R.string.settings_eh_identity_cookies_signed)
val str = cookies.joinToString("\n") { (k, v) -> "$k: $v" }
@@ -153,7 +153,7 @@ fun EhScreen(navigator: DestinationsNavigator) {
}
}
}
if (signin) {
if (hasSignedIn) {
val placeholder = stringResource(id = R.string.please_wait)
val resetImageLimitSucceed = stringResource(id = R.string.reset_limits_succeed)
var result by rememberSaveable { mutableStateOf<HomeParser.Result?>(null) }
@@ -263,7 +263,7 @@ fun EhScreen(navigator: DestinationsNavigator) {
val items = buildList {
add(disabled)
add(localFav)
if (signin) {
if (hasSignedIn) {
addAll(Settings.favCat)
}
}
@@ -380,7 +380,7 @@ fun EhScreen(navigator: DestinationsNavigator) {
title = stringResource(id = R.string.settings_eh_metered_network_warning),
value = Settings.meteredNetworkWarning::value,
)
if (signin) {
if (hasSignedIn) {
SwitchPreference(
title = stringResource(id = R.string.settings_eh_show_jpn_title),
summary = stringResource(id = R.string.settings_eh_show_jpn_title_summary),
@@ -16,7 +16,6 @@ import com.google.accompanist.web.WebView
import com.google.accompanist.web.rememberWebViewState
import com.hippo.ehviewer.R
import com.hippo.ehviewer.client.EhUrl
import com.hippo.ehviewer.ui.LockDrawer
import com.hippo.ehviewer.util.setDefaultSettings
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
@@ -26,7 +25,6 @@ import com.ramcosta.composedestinations.navigation.DestinationsNavigator
@Composable
fun MyTagsScreen(navigator: DestinationsNavigator) {
val url = EhUrl.myTagsUrl
LockDrawer(true)
Scaffold(
topBar = {
TopAppBar(
@@ -25,7 +25,6 @@ import com.google.accompanist.web.rememberWebViewState
import com.hippo.ehviewer.R
import com.hippo.ehviewer.client.EhCookieStore
import com.hippo.ehviewer.client.EhUrl
import com.hippo.ehviewer.ui.LockDrawer
import com.hippo.ehviewer.util.setDefaultSettings
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
@@ -36,7 +35,6 @@ private const val APPLY_JS = "javascript:(function(){var apply = document.getEle
@Destination<RootGraph>
@Composable
fun UConfigScreen(navigator: DestinationsNavigator) {
LockDrawer(true)
val url = EhUrl.uConfigUrl
val webview = remember { Atomic<WebView?>(null) }
val snackbarHostState = remember { SnackbarHostState() }
@@ -39,7 +39,7 @@ object AppConfig {
fun matchVariant(name: String) = name.contains(BuildConfig.FLAVOR) && name.contains(abi)
val buildTime = ParserUtils.formatDate(BuildConfig.BUILD_TIME * 1000)
val commitTime = ParserUtils.formatDate(BuildConfig.COMMIT_TIME * 1000)
val isSnapshot = "SNAPSHOT" in BuildConfig.VERSION_NAME
@@ -26,7 +26,7 @@ object Crash {
writer.write("VersionName=${BuildConfig.VERSION_NAME}\n")
writer.write("VersionCode=${BuildConfig.VERSION_CODE}\n")
writer.write("CommitSha=${BuildConfig.COMMIT_SHA}\n")
writer.write("BuildTime=${AppConfig.buildTime}\n")
writer.write("CommitTime=${AppConfig.commitTime}\n")
writer.write("\n")
// Device info
@@ -62,7 +62,7 @@ object Crash {
fun saveCrashLog(t: Throwable) {
val dir = AppConfig.externalCrashDir ?: return
val nowString = ReadableTime.getFilenamableTime(System.currentTimeMillis())
val nowString = ReadableTime.getFilenamableTime()
val fileName = "crash-$nowString.log"
val file = File(dir, fileName)
runCatching {
@@ -18,8 +18,8 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.DialogProperties
import com.hippo.ehviewer.R.string
import com.hippo.ehviewer.ui.tools.DialogState
import kotlin.coroutines.Continuation
import kotlin.coroutines.intrinsics.COROUTINE_SUSPENDED
import kotlin.coroutines.intrinsics.startCoroutineUninterceptedOrReturn
import kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn
@Composable
@@ -48,8 +48,7 @@ fun ProgressDialog() {
suspend fun <R> DialogState.bgWork(work: suspend () -> R) = try {
suspendCoroutineUninterceptedOrReturn { cont ->
@Suppress("UNCHECKED_CAST")
(work as (Continuation<R>) -> Any?)(cont).also { r ->
work.startCoroutineUninterceptedOrReturn(cont).also { r ->
if (r == COROUTINE_SUSPENDED) content = { ProgressDialog() }
}
}
@@ -18,6 +18,7 @@ package com.hippo.ehviewer.util
import com.hippo.ehviewer.R
import java.util.Locale
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import kotlinx.datetime.LocalDate
import kotlinx.datetime.LocalDateTime
import kotlinx.datetime.TimeZone
@@ -157,6 +158,6 @@ object ReadableTime {
}
}
fun getFilenamableTime(time: Long): String =
fun getFilenamableTime(time: Instant = Clock.System.now()): String =
FILENAMABLE_DATE_FORMAT.format(time.toLocalDateTime(TimeZone.currentSystemDefault()))
}
@@ -2,6 +2,7 @@ package com.hippo.ehviewer.util
import android.os.Build
import android.os.ext.SdkExtensions
import androidx.core.os.BuildCompat
val isAtLeastN = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
val isAtLeastO = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
@@ -12,4 +13,5 @@ val isAtLeastR = Build.VERSION.SDK_INT >= Build.VERSION_CODES.R
val isAtLeastS = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
val isAtLeastT = Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU
val isAtLeastU = Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE
val isAtLeastV = BuildCompat.isAtLeastV()
val isAtLeastSExtension7 = isAtLeastR && SdkExtensions.getExtensionVersion(Build.VERSION_CODES.S) >= 7
@@ -4,10 +4,12 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.navigationBarsIgnoringVisibility
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Check
import androidx.compose.material.icons.outlined.Settings
@@ -47,7 +49,9 @@ fun BottomReaderBar(onClickSettings: () -> Unit) {
.copy(alpha = if (isSystemInDarkTheme()) 0.9f else 0.95f)
Row(
modifier = Modifier.fillMaxWidth().background(backgroundColor).padding(8.dp).navigationBarsPadding(),
modifier = Modifier.fillMaxWidth().background(backgroundColor).padding(8.dp)
// navigationBarsPadding() does not work without SYSTEM_UI_FLAG_LAYOUT_STABLE on API < 28
.windowInsetsPadding(WindowInsets.navigationBarsIgnoringVisibility),
horizontalArrangement = Arrangement.SpaceEvenly,
verticalAlignment = Alignment.CenterVertically,
) {
@@ -5,6 +5,7 @@ import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBarsPadding
@@ -51,7 +52,10 @@ fun ReaderPageSheetMeta(
Spacer(modifier = Modifier.size(32.dp))
Text(text = stringResource(id = text))
}
Column(modifier = Modifier.verticalScroll(rememberScrollState()).navigationBarsPadding()) {
Column(
modifier = Modifier.fillMaxSize() // Workaround for https://issuetracker.google.com/341594885
.verticalScroll(rememberScrollState()).navigationBarsPadding(),
) {
Item(icon = Icons.Default.Refresh, text = R.string.refresh, onClick = retry)
Item(icon = Icons.Default.Refresh, text = R.string.refresh_original, onClick = retryOrigin)
Item(icon = Icons.Default.Share, text = R.string.action_share, onClick = share)
+1 -1
View File
@@ -383,7 +383,7 @@
<string name="settings_about_source">源码</string>
<string name="license">许可证</string>
<string name="settings_about_version">版本号</string>
<string name="settings_about_build_time">于 %s 构建</string>
<string name="settings_about_commit_time">于 %s 提交</string>
<string name="settings_about_check_for_updates">检查更新</string>
<!-- ExcludedLanguagesScene -->
<string name="please_wait">请稍候</string>
+1 -2
View File
@@ -127,7 +127,6 @@
<string name="rate_successfully">評分成功</string>
<string name="rate_failed">評分失敗</string>
<string name="no_torrents">沒有種子</string>
<string name="no_current_torrents">沒有當前版本圖庫的種子</string>
<string name="download_torrent_started">開始下載種子</string>
<string name="download_torrent_failure">無法下載種子</string>
<string name="torrents">種子</string>
@@ -383,7 +382,7 @@
<string name="settings_about_latest_release">最新版本</string>
<string name="settings_about_source">原始碼</string>
<string name="settings_about_version">版本號碼</string>
<string name="settings_about_build_time">於 %s 建置</string>
<string name="settings_about_commit_time">於 %s 提交</string>
<string name="settings_about_check_for_updates">檢查更新</string>
<string name="license">授權條款</string>
<!-- ExcludedLanguagesScene -->
+1 -1
View File
@@ -427,7 +427,7 @@
<string name="settings_about_latest_release">Latest release</string>
<string name="settings_about_source">Source</string>
<string name="settings_about_version">Build version</string>
<string name="settings_about_build_time">Built at %s</string>
<string name="settings_about_commit_time">Committed at %s</string>
<string name="settings_about_check_for_updates">Check for updates</string>
<string name="license">License</string>
<string name="cant_read_the_file">Can\'t read the file</string>
+18 -18
View File
@@ -22,9 +22,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.83"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3"
checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
[[package]]
name = "base16ct"
@@ -49,9 +49,9 @@ checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
[[package]]
name = "cc"
version = "1.0.97"
version = "1.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4"
checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f"
[[package]]
name = "cesu8"
@@ -183,9 +183,9 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.154"
version = "0.2.155"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346"
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]]
name = "log"
@@ -207,9 +207,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "proc-macro2"
version = "1.0.82"
version = "1.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b"
checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23"
dependencies = [
"unicode-ident",
]
@@ -249,9 +249,9 @@ dependencies = [
[[package]]
name = "serde"
version = "1.0.201"
version = "1.0.203"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c"
checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094"
dependencies = [
"serde_derive",
]
@@ -268,9 +268,9 @@ dependencies = [
[[package]]
name = "serde_derive"
version = "1.0.201"
version = "1.0.203"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865"
checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
dependencies = [
"proc-macro2",
"quote",
@@ -300,9 +300,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.63"
version = "2.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704"
checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
dependencies = [
"proc-macro2",
"quote",
@@ -311,18 +311,18 @@ dependencies = [
[[package]]
name = "thiserror"
version = "1.0.60"
version = "1.0.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18"
checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.60"
version = "1.0.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524"
checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
dependencies = [
"proc-macro2",
"quote",
+1 -1
View File
@@ -1 +1 @@
124.0.6367.201
125.0.6422.141
+12 -12
View File
@@ -1,9 +1,9 @@
[versions]
aboutlibraries = "11.1.4"
aboutlibraries = "11.2.1"
accompanist = "0.34.0"
agp = "8.6.0-alpha02"
agp = "8.6.0-alpha04"
androidx-activity = "1.9.0"
androidx-appcompat = "1.7.0-rc01"
androidx-appcompat = "1.7.0"
androidx-biometric = "1.2.0-alpha05"
androidx-browser = "1.8.0"
androidx-constraintlayout-compose = "1.1.0-alpha13"
@@ -11,20 +11,20 @@ androidx-core = "1.14.0-alpha01"
androidx-core-splashscreen = "1.2.0-alpha01"
androidx-datastore = "1.1.1"
androidx-graphics-path = "1.0.1"
androidx-lifecycle = "2.8.0"
androidx-lifecycle = "2.8.1"
androidx-paging = "3.3.0"
androidx-recyclerview = "1.4.0-alpha01"
androidx-room = "2.7.0-alpha02"
androidx-room = "2.7.0-alpha03"
androidx-work = "2.10.0-alpha02"
arrow = "1.2.4"
coil = "3.0.0-alpha06"
compose-bom = "2024.05.00-alpha02"
compose-destinations = "2.1.0-beta07"
kotlin = "2.0.0-RC3"
compose-bom = "2024.05.00-alpha03"
compose-destinations = "2.1.0-beta09"
kotlin = "2.0.0"
kotlinx-coroutines = "1.8.1"
kotlinx-datetime = "0.6.0"
kotlinx-serialization = "1.6.3"
ksp = "2.0.0-RC3-1.0.20"
kotlinx-serialization = "1.7.0"
ksp = "2.0.0-1.0.22"
ktor = "3.0.0-beta-1"
okio = "3.9.0"
splitties = "3.0.0"
@@ -66,7 +66,7 @@ coil-gif = { module = "io.coil-kt.coil3:coil-gif" }
coil-network = { module = "io.coil-kt.coil3:coil-network-ktor" }
compose-bom = { module = "dev.chrisbanes.compose:compose-bom", version.ref = "compose-bom" }
compose-foundation = { module = "androidx.compose.foundation:foundation", version = "1.7.0-SNAPSHOT" }
compose-foundation = { module = "androidx.compose.foundation:foundation", version = "1.8.0-SNAPSHOT" }
compose-material-icons-extended = { module = "androidx.compose.material:material-icons-extended" }
compose-material3 = { module = "androidx.compose.material3:material3", version = "1.3.0-SNAPSHOT" }
compose-material3-adaptive = { module = "androidx.compose.material3.adaptive:adaptive" }
@@ -77,7 +77,7 @@ compose-ui-util = { module = "androidx.compose.ui:ui-util" }
compose-destinations-core = { module = "io.github.raamcosta.compose-destinations:core", version.ref = "compose-destinations" }
compose-destinations-compiler = { module = "io.github.raamcosta.compose-destinations:ksp", version.ref = "compose-destinations" }
material-motion-core = "io.github.fornewid:material-motion-compose-core:1.2.0"
material-motion-core = "io.github.fornewid:material-motion-compose-core:1.2.1"
cronet-embedded = "org.chromium.net:cronet-embedded:119.6045.31"
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Vendored
+1 -1
View File
@@ -55,7 +55,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
+6 -5
View File
@@ -3,6 +3,9 @@
"extends": [
"config:base"
],
"ignorePaths": [
"app/build.gradle.kts"
],
"packageRules": [
{
"groupName": "AGP",
@@ -26,11 +29,9 @@
},
{
"groupName": "Kotlin & KSP",
"matchDepPrefixes": [
"org.jetbrains.kotlin."
],
"matchDepNames": [
"com.google.devtools.ksp"
"matchSourceUrls": [
"https://github.com/JetBrains/kotlin",
"https://github.com/google/ksp"
],
"recreateWhen": "never"
},
+2 -2
View File
@@ -12,8 +12,8 @@ dependencyResolutionManagement {
google()
mavenCentral()
maven("https://jitpack.io")
// TODO: Remove on Compose 1.7.0-beta02
maven("https://androidx.dev/snapshots/builds/11844073/artifacts/repository")
// TODO: Remove on Compose 1.8.0-alpha01
maven("https://androidx.dev/snapshots/builds/11925800/artifacts/repository")
}
}