Compare commits
47
Commits
1.11.5
...
1.11.6-RC1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6d1d737f9f | ||
|
|
bc75156232 | ||
|
|
2101ea7a36 | ||
|
|
26921c8ae1 | ||
|
|
be1eecf3b5 | ||
|
|
2d4f154c9b | ||
|
|
d82cbe51ba | ||
|
|
d13ffa93ba | ||
|
|
2cce55953f | ||
|
|
07d100fcc0 | ||
|
|
cc04371181 | ||
|
|
ee50c88765 | ||
|
|
efc5b55ea7 | ||
|
|
94af66156a | ||
|
|
4861359f9e | ||
|
|
5af167dab4 | ||
|
|
db1f0bc6d7 | ||
|
|
b94a843ec5 | ||
|
|
b27d214f24 | ||
|
|
a81eb9d17b | ||
|
|
ec9b85f30f | ||
|
|
8ac2f33949 | ||
|
|
d84198ab28 | ||
|
|
34d339d9f1 | ||
|
|
bcfefc7c76 | ||
|
|
62539dc48e | ||
|
|
453ab11395 | ||
|
|
b2246b980a | ||
|
|
822a461acd | ||
|
|
25e5c0ab8e | ||
|
|
2a55db95f4 | ||
|
|
a144866182 | ||
|
|
be7a04a4cb | ||
|
|
fd1b861dab | ||
|
|
957ebd35aa | ||
|
|
29d8b11771 | ||
|
|
c87059e9d7 | ||
|
|
4babe2eec4 | ||
|
|
48fdaaca0c | ||
|
|
f0ee88b4d6 | ||
|
|
9210780b6b | ||
|
|
b479e28543 | ||
|
|
f93b98fc5e | ||
|
|
4721d1011b | ||
|
|
4da4443e67 | ||
|
|
e5343f4360 | ||
|
|
86323220dc |
No files matched your search
@@ -1,5 +1,22 @@
|
||||
# 变更日志
|
||||
|
||||
## [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
@@ -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 = "-RC1"
|
||||
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 {
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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,6 @@ 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 eu.kanade.tachiyomi.util.system.logcat
|
||||
import io.ktor.client.plugins.onDownload
|
||||
import io.ktor.client.statement.HttpResponse
|
||||
@@ -323,9 +322,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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 -->
|
||||
|
||||
@@ -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>
|
||||
|
||||
Generated
+18
-18
@@ -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.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b"
|
||||
checksum = "ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6"
|
||||
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 @@
|
||||
124.0.6367.201
|
||||
125.0.6422.141
|
||||
+12
-12
@@ -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"
|
||||
ksp = "2.0.0-1.0.21"
|
||||
ktor = "3.0.0-beta-1"
|
||||
okio = "3.9.0"
|
||||
splitties = "3.0.0"
|
||||
@@ -66,9 +66,9 @@ 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" }
|
||||
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 = { module = "androidx.compose.material3:material3" }
|
||||
compose-material3-adaptive = { module = "androidx.compose.material3.adaptive:adaptive" }
|
||||
compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling" }
|
||||
compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview" }
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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"
|
||||
},
|
||||
|
||||
@@ -12,8 +12,6 @@ dependencyResolutionManagement {
|
||||
google()
|
||||
mavenCentral()
|
||||
maven("https://jitpack.io")
|
||||
// TODO: Remove on Compose 1.7.0-beta02
|
||||
maven("https://androidx.dev/snapshots/builds/11844073/artifacts/repository")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user