Compare commits

..
31 Commits
Author SHA1 Message Date
FooIbar 43ddf6ccc4 Prepare for release 1.14.2
Releases / build (push) Has been cancelled
2025-08-16 22:23:45 +08:00
FooIbar b55da640e1 Prepare changelog for 1.14.2 2025-08-16 22:19:58 +08:00
FooIbar 90534c3c9f Remove confusing connect timeout configuration 2025-08-16 22:19:58 +08:00
FooIbar 88c9e5e902 Support new tag namespace: "location:"
Treat it as "other:".
2025-08-16 17:21:53 +08:00
FooIbar ac41117a78 [no ci] Tweak Rust toolchain update schedule 2025-08-15 17:51:31 +08:00
renovate[bot] 2418c5f625 Update dependency rust-nightly to v2025-08-15 (#2554)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-15 08:33:52 +00:00
FooIbar 52156aa9ff [no ci] Let renovate update NDK 2025-08-15 16:23:17 +08:00
renovate[bot]andFooIbar 6010fb69a4 Update dependency rust-nightly to v2025-08-14 (#2553)
* Update dependency rust-nightly to v2025-08-14

* Fix build

* Fix build

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: FooIbar <118464521+FooIbar@users.noreply.github.com>
2025-08-15 04:59:20 +00:00
FooIbar d5abbb3584 Stop speed tracker immediately if download is done
Subsequent disk I/O will make the reported download speed inaccurate.
2025-08-14 19:25:03 +08:00
FooIbar 8c27504ee2 Update Rust nightly toolchain every ~6 weeks
Follow the stable release cycle.

[no ci]
2025-08-14 15:48:47 +08:00
FooIbar 8a20525da3 Remove obsolete workaround 2025-08-14 11:14:33 +08:00
renovate[bot] c7b8326b52 Update dependency androidx.core:core-ktx to v1.17.0 (#2550)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-14 00:53:52 +00:00
renovate[bot] ee8b80651e Update dependency androidx.compose:compose-bom-alpha to v2025.08.00 (#2549)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-14 00:53:37 +00:00
renovate[bot] 589676c52a Update dependency androidx.test.uiautomator:uiautomator to v2.4.0-alpha06 (#2548)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-13 22:54:04 +00:00
FooIbar 83085d5f9a Allow disabling download speed check 2025-08-13 20:37:43 +08:00
FooIbar a1a204d0d5 Refactor settings observation 2025-08-13 00:42:20 +08:00
FooIbar 9a43c36758 KMP DataStorePreferences 2025-08-12 10:40:45 +08:00
renovate[bot] e017efe35f Update actions/checkout action to v5 (#2542)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-11 13:57:50 +00:00
renovate[bot] 1645c17ab7 Lock file maintenance (#2541)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-11 02:33:12 +00:00
FooIbar 075b800932 Exclude CMP resources dependency 2025-08-08 17:19:50 +08:00
FooIbar 56f9138db4 Misc updates 2025-08-08 17:19:50 +08:00
FooIbar 20c1b7acdb Migrate to moko-resources 2025-08-07 10:40:21 +08:00
FooIbar a10022d797 Move plural string resources to their own files 2025-08-07 10:40:21 +08:00
renovate[bot] aafbbbec38 Update dependency chrome to v139 (#2538)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-05 21:43:41 +00:00
FooIbar 028a994070 Hack for type-safe accessors in convention plugins 2025-08-05 22:58:52 +08:00
renovate[bot] 581125db62 Lock file maintenance (#2535)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-04 03:00:33 +00:00
FooIbar 295770002a Extract common build logic to convention plugins 2025-08-03 10:39:03 +08:00
renovate[bot] 1a66d84bd0 Update dependency gradle to v9 (#2532)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-01 01:45:06 +00:00
renovate[bot] cd3f51b66d Update AGP to v8.12.0 (#2531)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-31 18:04:05 +00:00
renovate[bot] 6d8ac4c3da Update dependency com.google.devtools.ksp to v2.2.20-Beta2-2.0.2 (#2530)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-31 18:01:43 +00:00
FooIbar 156382eaad Prepare for next iteration 2025-07-31 18:35:19 +08:00
144 changed files with 1300 additions and 764 deletions

No files matched your search

+2 -2
View File
@@ -25,7 +25,7 @@ jobs:
sudo udevadm trigger --name-match=kvm
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Setup Java
uses: actions/setup-java@v4
@@ -34,7 +34,7 @@ jobs:
java-version: 21
- name: Install Rust Toolchain
run: rustup target add armv7-linux-androideabi aarch64-linux-android x86_64-linux-android
run: rustup target add armv7-linux-androideabi
- name: Rust Cache
uses: Swatinem/rust-cache@v2
+11 -8
View File
@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Setup Java
uses: actions/setup-java@v4
@@ -21,7 +21,7 @@ jobs:
java-version: 21
- name: Install Rust Toolchain
run: rustup target add armv7-linux-androideabi aarch64-linux-android x86_64-linux-android
run: rustup target add armv7-linux-androideabi
- name: Rust Cache
uses: Swatinem/rust-cache@v2
@@ -42,6 +42,9 @@ jobs:
with:
cache-read-only: true
- name: Check build-logic
run: ./gradlew :build-logic:convention:check
- name: Spotless Check
run: ./gradlew spotlessCheck
@@ -52,7 +55,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Setup Java
uses: actions/setup-java@v4
@@ -61,7 +64,7 @@ jobs:
java-version: 21
- name: Install Rust Toolchain
run: rustup target add armv7-linux-androideabi aarch64-linux-android x86_64-linux-android
run: rustup target add armv7-linux-androideabi
- name: Rust Cache
uses: Swatinem/rust-cache@v2
@@ -79,7 +82,7 @@ jobs:
uses: actions/cache@v4
with:
path: app/.cxx
key: cmake-default-${{ hashFiles('settings.gradle.kts', 'app/src/main/cpp/CMakeLists.txt', 'app/src/main/rust/Cargo.lock') }}
key: cmake-default-${{ hashFiles('rust-toolchain.toml', 'settings.gradle.kts', 'app/src/main/cpp/CMakeLists.txt', 'app/src/main/rust/Cargo.lock') }}
restore-keys: cmake-default-
- name: Build
@@ -120,7 +123,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Setup Java
uses: actions/setup-java@v4
@@ -129,7 +132,7 @@ jobs:
java-version: 21
- name: Install Rust Toolchain
run: rustup target add armv7-linux-androideabi aarch64-linux-android x86_64-linux-android
run: rustup target add armv7-linux-androideabi
- name: Rust Cache
uses: Swatinem/rust-cache@v2
@@ -147,7 +150,7 @@ jobs:
uses: actions/cache@v4
with:
path: app/.cxx
key: cmake-marshmallow-${{ hashFiles('settings.gradle.kts', 'app/src/main/cpp/CMakeLists.txt', 'app/src/main/rust/Cargo.lock') }}
key: cmake-marshmallow-${{ hashFiles('rust-toolchain.toml', 'settings.gradle.kts', 'app/src/main/cpp/CMakeLists.txt', 'app/src/main/rust/Cargo.lock') }}
restore-keys: cmake-marshmallow-
- name: Build
+2 -2
View File
@@ -19,7 +19,7 @@ jobs:
sudo udevadm trigger --name-match=kvm
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Setup Java
uses: actions/setup-java@v4
@@ -28,7 +28,7 @@ jobs:
java-version: 21
- name: Install Rust Toolchain
run: rustup target add armv7-linux-androideabi aarch64-linux-android x86_64-linux-android
run: rustup target add armv7-linux-androideabi
- name: Rust Cache
uses: Swatinem/rust-cache@v2
+3 -2
View File
@@ -1,8 +1,9 @@
.gradle
/local.properties
.DS_Store
/build
/.kotlin
build
.cxx
.kotlin
*.iml
.idea
.vscode
+13
View File
@@ -1,5 +1,18 @@
# 变更日志
## [1.14.2] - 2025-08-16
### 改进
* [下载] 支持将最低下载速度设为 0 [#2545](https://github.com/FooIbar/EhViewer/issues/2545)
* [下载] 移除令人困惑的连接超时设置 [#2556](https://github.com/FooIbar/EhViewer/issues/2556)
### Bug 修复
* 下载速度计算不准确导致下载失败误报 [#2545](https://github.com/FooIbar/EhViewer/issues/2545)
* 无法解析带有 location: 标签的画廊
## [1.14.1] - 2025-07-31
### 改进
-2
View File
@@ -1,2 +0,0 @@
/build
/.cxx
+12 -56
View File
@@ -1,20 +1,15 @@
import com.mikepenz.aboutlibraries.plugin.DuplicateMode
import com.mikepenz.aboutlibraries.plugin.DuplicateRule
import java.util.regex.Pattern
import org.jetbrains.kotlin.gradle.dsl.JvmDefaultMode
val isRelease: Boolean
get() = gradle.startParameter.taskNames.any { it.contains("Release") }
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.compose)
alias(libs.plugins.ehviewer.android.application)
alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.ksp)
alias(libs.plugins.spotless)
alias(libs.plugins.aboutlibrariesPlugin)
alias(libs.plugins.composeCompilerReportGenerator)
alias(libs.plugins.baselineprofile)
}
@@ -61,7 +56,7 @@ android {
defaultConfig {
applicationId = "moe.tarsin.ehviewer"
versionCode = 180063
versionName = "1.14.1"
versionName = "1.14.2"
// versionNameSuffix = "-SNAPSHOT"
buildConfigField("String", "RAW_VERSION_NAME", "\"$versionName${versionNameSuffix.orEmpty()}\"")
buildConfigField("String", "COMMIT_SHA", "\"$commitSha\"")
@@ -79,9 +74,10 @@ android {
flavorDimensions += "api"
productFlavors {
create("default")
create("default") {
minSdk = 26
}
create("marshmallow") {
minSdk = 23
applicationIdSuffix = ".m"
versionNameSuffix = "-M"
}
@@ -97,12 +93,6 @@ android {
isCoreLibraryDesugaringEnabled = true
}
lint {
checkReleaseBuilds = false
disable += setOf("MissingTranslation", "MissingQuantity")
error += setOf("InlinedApi")
}
packaging {
dex {
useLegacyPackaging = false
@@ -176,6 +166,9 @@ baselineProfile {
}
dependencies {
implementation(projects.core.data)
implementation(projects.core.i18n)
// https://developer.android.com/jetpack/androidx/releases/activity
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.appcompat)
@@ -189,7 +182,10 @@ dependencies {
implementation(libs.compose.destinations.core)
ksp(libs.compose.destinations.compiler)
implementation(libs.compose.preference)
implementation(libs.compose.preference) {
// R8 won't remove it because it adds a content provider
exclude(group = "org.jetbrains.compose.components", module = "components-resources")
}
implementation(libs.androidx.core)
implementation(libs.androidx.core.splashscreen)
@@ -254,38 +250,11 @@ dependencies {
}
kotlin {
jvmToolchain(21)
// https://kotlinlang.org/docs/gradle-compiler-options.html#all-compiler-options
compilerOptions {
jvmDefault = JvmDefaultMode.NO_COMPATIBILITY
progressiveMode = true
optIn.addAll(
"coil3.annotation.ExperimentalCoilApi",
"androidx.compose.foundation.layout.ExperimentalLayoutApi",
"androidx.compose.material3.ExperimentalMaterial3Api",
"androidx.compose.material3.ExperimentalMaterial3ExpressiveApi",
"androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi",
"androidx.compose.ui.ExperimentalComposeUiApi",
"androidx.compose.foundation.ExperimentalFoundationApi",
"androidx.compose.animation.ExperimentalAnimationApi",
"androidx.compose.animation.ExperimentalSharedTransitionApi",
"androidx.compose.runtime.ExperimentalComposeRuntimeApi",
"androidx.paging.ExperimentalPagingApi",
"kotlin.ExperimentalStdlibApi",
"kotlin.concurrent.atomics.ExperimentalAtomicApi",
"kotlin.contracts.ExperimentalContracts",
"kotlin.time.ExperimentalTime",
"kotlinx.coroutines.ExperimentalCoroutinesApi",
"kotlinx.coroutines.FlowPreview",
"kotlinx.serialization.ExperimentalSerializationApi",
"splitties.experimental.ExperimentalSplittiesApi",
"splitties.preferences.DataStorePreferencesPreview",
)
freeCompilerArgs.addAll(
"-Xcontext-parameters",
"-Xwhen-expressions=indy",
"-Xannotation-default-target=param-property",
)
}
}
@@ -305,16 +274,3 @@ aboutLibraries {
duplicationRule = DuplicateRule.GROUP
}
}
val ktlintVersion = libs.ktlint.get().version
spotless {
kotlin {
// https://github.com/diffplug/spotless/issues/111
target("src/**/*.kt")
ktlint(ktlintVersion)
}
kotlinGradle {
ktlint(ktlintVersion)
}
}
+2
View File
@@ -129,6 +129,8 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Android")
set(ANDROID 1)
endif ()
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ../../../../rust-toolchain.toml)
unset(Rust_TOOLCHAIN CACHE)
FetchContent_Declare(
Corrosion
GIT_REPOSITORY https://github.com/corrosion-rs/corrosion.git
@@ -130,7 +130,7 @@ class EhApplication :
launchIO { dataStateFlow.value }
launchIO { OSUtils.totalMemory }
launch {
if (DownloadManager.labelList.isNotEmpty() && Settings.downloadFilterMode.key !in Settings.prefs) {
if (DownloadManager.labelList.isNotEmpty() && Settings.downloadFilterMode !in Settings.snapshot()) {
Settings.downloadFilterMode.value = DownloadsFilterMode.CUSTOM.flag
}
DownloadManager.readMetadataFromLocal()
@@ -9,6 +9,9 @@ import androidx.compose.runtime.Stable
import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.remember
import com.ehviewer.core.preferences.DataStorePreferences
import com.ehviewer.core.preferences.PrefDelegate
import com.ehviewer.core.preferences.edit
import com.hippo.ehviewer.client.EhCookieStore
import com.hippo.ehviewer.client.data.FavListUrlBuilder
import com.hippo.ehviewer.download.DownloadsFilterMode
@@ -25,47 +28,12 @@ import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.flatMapMerge
import kotlinx.coroutines.flow.map
import splitties.preferences.BoolPref
import splitties.preferences.DataStorePreferences
import splitties.preferences.FloatPref
import splitties.preferences.IntPref
import splitties.preferences.LongPref
import splitties.preferences.PrefDelegate
import splitties.preferences.StringOrNullPref
import splitties.preferences.StringPref
import splitties.preferences.StringSetOrNullPref
import splitties.preferences.StringSetPref
import splitties.preferences.edit
@Suppress("IMPLICIT_CAST_TO_ANY", "UNCHECKED_CAST")
fun <T> PrefDelegate<T>.getValue(): T = when (this) {
is BoolPref -> value
is IntPref -> value
is FloatPref -> value
is LongPref -> value
is StringPref -> value
is StringOrNullPref -> value
is StringSetPref -> value
is StringSetOrNullPref -> value
} as T
@Suppress("UNCHECKED_CAST")
fun <T> PrefDelegate<T>.setValue(newValue: T) = when (this) {
is BoolPref -> value = newValue as Boolean
is IntPref -> value = newValue as Int
is FloatPref -> value = newValue as Float
is LongPref -> value = newValue as Long
is StringPref -> value = newValue as String
is StringOrNullPref -> value = newValue as? String
is StringSetPref -> value = newValue as Set<String?>
is StringSetOrNullPref -> value = newValue as? Set<String?>
}
@Stable
@Composable
inline fun <R, T> PrefDelegate<T>.collectAsState(crossinline transform: @DisallowComposableCalls (T) -> R): State<R> {
val flow = remember { valueFlow().map { transform(it) } }
val init = getValue()
val init = value
return flow.collectAsState(transform(init))
}
@@ -73,32 +41,28 @@ inline fun <R, T> PrefDelegate<T>.collectAsState(crossinline transform: @Disallo
@Composable
fun <T> PrefDelegate<T>.collectAsState(): State<T> {
val flow = remember { valueFlow() }
val init = getValue()
val init = value
return flow.collectAsState(init)
}
@Stable
@Composable
fun <T> PrefDelegate<T>.asMutableState(): MutableState<T> {
val flow = remember { valueFlow() }
val init = getValue()
val readOnly = flow.collectAsState(init)
val readOnly = collectAsState()
return remember {
object : MutableState<T> {
override var value: T
get() = readOnly.value
set(value) {
setValue(value)
this@asMutableState.value = value
}
override fun component1() = readOnly.value
override fun component2() = ::setValue
override fun component2() = this@asMutableState::value::set
}
}
}
object Settings : DataStorePreferences(null) {
private const val KEY_SHOW_TAG_TRANSLATIONS = "show_tag_translations"
@Suppress("ktlint:standard:backing-property-naming")
private val _favFlow = MutableSharedFlow<Unit>()
val favChangesFlow = _favFlow.debounce(1000)
@@ -107,9 +71,9 @@ object Settings : DataStorePreferences(null) {
var favCloudCount by intPref("fav_cloud", 0).emitTo(_favFlow)
// Eh
val gallerySite = intPref("gallery_site_2", 0).observed { updateWhenGallerySiteChanges() }
val gallerySite = intPref("gallery_site_2", 0).observed(::updateWhenGallerySiteChanges)
val defaultFavSlot = intPref("default_favorite_slot", -2)
val theme = intPref("theme_2", -1).observed { updateWhenThemeChanges() }
val theme = intPref("theme_2", -1).observed(::updateWhenThemeChanges)
val blackDarkTheme = boolPref("black_dark_theme", false)
val harmonizeCategoryColor = boolPref("harmonize_category_color", true)
val launchPage = intPref("launch_page_2", 0)
@@ -121,17 +85,16 @@ object Settings : DataStorePreferences(null) {
val showVoteStatus = boolPref("show_vote_status", false)
val showComments = boolPref("show_gallery_comments", true)
val commentThreshold = intPref("comment_threshold", -100)
val showTagTranslations = boolPref(KEY_SHOW_TAG_TRANSLATIONS, false).observed { updateWhenTagTranslationChanges() }
val showTagTranslations = boolPref("show_tag_translations", false).observed(::updateWhenTagTranslationChanges)
val meteredNetworkWarning = boolPref("cellular_network_warning", false)
val showJpnTitle = boolPref("show_jpn_title", false)
val requestNews = boolPref("request_news", false).observed { updateWhenRequestNewsChanges() }
val hideHvEvents = boolPref("hide_hv_events", false)
// Download
val mediaScan = boolPref("media_scan", false).observed { updateWhenKeepMediaStatusChanges() }
val mediaScan = boolPref("media_scan", false).observed(::updateWhenKeepMediaStatusChanges)
val multiThreadDownload = intPref("download_thread_2", 3)
val downloadDelay = intPref("download_delay_3", 1000)
val connTimeout = intPref("conn_timeout", 10)
val timeoutSpeed = intPref("timeout_speed_level", 6)
val preloadImage = intPref("preload_image_2", 5)
val downloadOriginImage = boolPref("download_origin_image", false)
@@ -167,15 +130,15 @@ object Settings : DataStorePreferences(null) {
val needSignIn = boolPref("need_sign_in", true)
val gridView = boolPref("grid_view", false)
val qSSaveProgress = boolPref("qs_save_progress", true)
val displayName = stringOrNullPref("display_name", null)
val avatar = stringOrNullPref("avatar", null)
val recentDownloadLabel = stringOrNullPref("recent_download_label", null)
val displayName = stringOrNullPref("display_name")
val avatar = stringOrNullPref("avatar")
val recentDownloadLabel = stringOrNullPref("recent_download_label")
var downloadScheme by stringOrNullPref("image_scheme", null)
var downloadAuthority by stringOrNullPref("image_authority", null)
var downloadPath by stringOrNullPref("image_path", null)
var downloadQuery by stringOrNullPref("image_query", null)
var downloadFragment by stringOrNullPref("image_fragment", null)
var downloadScheme by stringOrNullPref("image_scheme")
var downloadAuthority by stringOrNullPref("image_authority")
var downloadPath by stringOrNullPref("image_path")
var downloadQuery by stringOrNullPref("image_query")
var downloadFragment by stringOrNullPref("image_fragment")
var archivePasswds by stringSetPref("archive_passwds")
var appLinkVerifyTip by boolPref("app_link_verify_tip", false)
var hasDefaultDownloadLabel by boolPref("has_default_download_label", false)
@@ -185,7 +148,7 @@ object Settings : DataStorePreferences(null) {
var requestNewsTime by intPref("request_news_time", 0).observed { updateWhenRequestNewsChanges() }
var lastDawnDays by intPref("last_dawn_days", 0)
var recentToplist by stringPref("recent_toplist", "11")
var defaultDownloadLabel by stringOrNullPref("default_download_label", null)
var defaultDownloadLabel by stringOrNullPref("default_download_label")
var lastUpdateTime by longPref("last_update_time", BuildConfig.COMMIT_TIME)
// Reader
@@ -223,43 +186,39 @@ object Settings : DataStorePreferences(null) {
val stripExtraneousAds = boolPref("strip_extraneous_ads", false)
init {
if ("CN" == Locale.getDefault().country) {
edit {
if (KEY_SHOW_TAG_TRANSLATIONS !in prefs) showTagTranslations.value = true
edit { pref ->
if ("CN" == Locale.getDefault().country) {
if (showTagTranslations !in pref) pref[showTagTranslations] = true
}
if (pref[downloadFilterMode] == DownloadsFilterMode.ARTIST.flag && pref[recentDownloadLabel] == null) {
pref[recentDownloadLabel] = ""
}
}
if (downloadFilterMode.value == DownloadsFilterMode.ARTIST.flag && recentDownloadLabel.value == null) {
recentDownloadLabel.value = ""
}
}
interface Delegate<R> {
val flowGetter: () -> Flow<Unit>
fun changesFlow(): Flow<Unit>
operator fun getValue(thisRef: Any?, prop: KProperty<*>?): R
operator fun setValue(thisRef: Any?, prop: KProperty<*>?, value: R)
}
private fun intArrayPref(key: String, count: Int) = object : Delegate<IntArray> {
override val flowGetter: () -> Flow<Unit> = { _value.asFlow().flatMapMerge { it.changesFlow() }.conflate() }
@Suppress("ktlint:standard:backing-property-naming")
private var _value = (0 until count).map { intPref("${key}_$it", 0) }.toTypedArray()
override fun getValue(thisRef: Any?, prop: KProperty<*>?): IntArray = _value.map { it.value }.toIntArray()
private val delegates = Array(count) { intPref("${key}_$it", 0) }
override fun changesFlow(): Flow<Unit> = delegates.asFlow().flatMapMerge { it.changesFlow() }.conflate()
override fun getValue(thisRef: Any?, prop: KProperty<*>?) = IntArray(delegates.size) { delegates[it].value }
override fun setValue(thisRef: Any?, prop: KProperty<*>?, value: IntArray) {
check(value.size == count)
edit { value.zip(_value) { v, d -> d.value = v } }
edit { pref -> value.zip(delegates) { v, d -> pref[d] = v } }
}
}
private fun stringArrayPref(key: String, count: Int, defMetaValue: String) = object : Delegate<Array<String>> {
override val flowGetter: () -> Flow<Unit> = { _value.asFlow().flatMapMerge { it.changesFlow() }.conflate() }
@Suppress("ktlint:standard:backing-property-naming")
private var _value = (0 until count).map { stringPref("${key}_$it", "$defMetaValue $it") }.toTypedArray()
override fun getValue(thisRef: Any?, prop: KProperty<*>?): Array<String> = _value.map { it.value }.toTypedArray()
private val delegates = Array(count) { stringPref("${key}_$it", "$defMetaValue $it") }
override fun changesFlow(): Flow<Unit> = delegates.asFlow().flatMapMerge { it.changesFlow() }.conflate()
override fun getValue(thisRef: Any?, prop: KProperty<*>?) = Array(delegates.size) { delegates[it].value }
override fun setValue(thisRef: Any?, prop: KProperty<*>?, value: Array<String>) {
check(value.size == count)
edit { value.zip(_value) { v, d -> d.value = v } }
edit { pref -> value.zip(delegates) { v, d -> pref[d] = v } }
}
}
}
@@ -2,68 +2,73 @@ package com.hippo.ehviewer
import android.app.UiModeManager
import androidx.appcompat.app.AppCompatDelegate
import arrow.core.Either.Companion.catch
import com.ehviewer.core.preferences.PrefDelegate
import com.hippo.ehviewer.client.EhEngine
import com.hippo.ehviewer.client.EhTagDatabase
import com.hippo.ehviewer.dailycheck.updateDailyCheckWork
import com.hippo.ehviewer.ui.keepNoMediaFileStatus
import com.hippo.ehviewer.util.isAtLeastS
import eu.kanade.tachiyomi.util.lang.launchIO
import eu.kanade.tachiyomi.util.lang.withIOContext
import eu.kanade.tachiyomi.util.system.logcat
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.emitAll
import kotlinx.coroutines.launch
import splitties.init.appCtx
import splitties.preferences.PrefDelegate
import splitties.systemservices.uiModeManager
private val collectScope = CoroutineScope(Dispatchers.Main + SupervisorJob())
fun <T, R : PrefDelegate<T>> R.observed(func: (Unit) -> Unit) = apply { collectScope.launch { changesFlow().collect(func) } }
fun <T, R : Settings.Delegate<T>> R.observed(func: (Unit) -> Unit) = apply { collectScope.launch { flowGetter().collect(func) } }
fun <T, R : Settings.Delegate<T>> R.emitTo(flow: MutableSharedFlow<Unit>) = apply { collectScope.launch { flowGetter().collect { flow.emit(Unit) } } }
fun <T, R : PrefDelegate<T>> R.emitTo(flow: MutableSharedFlow<Unit>) = apply { collectScope.launch { changesFlow().collect { flow.emit(Unit) } } }
private const val TAG = "SettingsCollector"
fun updateWhenKeepMediaStatusChanges() {
collectScope.launchIO {
runCatching {
keepNoMediaFileStatus()
private val collectScope = CoroutineScope(Dispatchers.Main + SupervisorJob())
fun <T, R : PrefDelegate<T>> R.observed(func: suspend (T) -> Unit) = apply { collectScope.launch { valueFlow().drop(1).collectLatest(func) } }
fun <T, R : Settings.Delegate<T>> R.emitTo(flow: MutableSharedFlow<Unit>) = apply { collectScope.launch { flow.emitAll(changesFlow()) } }
fun <T, R : PrefDelegate<T>> R.emitTo(flow: MutableSharedFlow<Unit>) = apply { collectScope.launch { flow.emitAll(changesFlow()) } }
suspend fun updateWhenKeepMediaStatusChanges(mediaScan: Boolean) {
withIOContext {
catch {
keepNoMediaFileStatus(mediaScan = mediaScan)
}.onLeft {
logcat(TAG, it)
}
}
}
fun updateWhenThemeChanges() {
collectScope.launch {
delay(100) // Avoid recompose being cancelled
if (isAtLeastS) {
val mode = when (Settings.theme.value) {
AppCompatDelegate.MODE_NIGHT_NO -> UiModeManager.MODE_NIGHT_NO
AppCompatDelegate.MODE_NIGHT_YES -> UiModeManager.MODE_NIGHT_YES
else -> UiModeManager.MODE_NIGHT_AUTO
}
uiModeManager.setApplicationNightMode(mode)
suspend fun updateWhenThemeChanges(theme: Int) {
delay(100) // Avoid recompose being cancelled
if (isAtLeastS) {
val mode = when (theme) {
AppCompatDelegate.MODE_NIGHT_NO -> UiModeManager.MODE_NIGHT_NO
AppCompatDelegate.MODE_NIGHT_YES -> UiModeManager.MODE_NIGHT_YES
else -> UiModeManager.MODE_NIGHT_AUTO
}
AppCompatDelegate.setDefaultNightMode(Settings.theme.value)
uiModeManager.setApplicationNightMode(mode)
}
AppCompatDelegate.setDefaultNightMode(theme)
}
fun updateWhenRequestNewsChanges() {
updateDailyCheckWork(appCtx)
}
fun updateWhenGallerySiteChanges() {
suspend fun updateWhenGallerySiteChanges(gallerySite: Int) {
if (Settings.hasSignedIn.value) {
collectScope.launchIO {
runCatching {
EhEngine.getUConfig()
}.onFailure {
logcat(it)
}
catch {
EhEngine.getUConfig(gallerySite)
}.onLeft {
logcat(TAG, it)
}
}
}
fun updateWhenTagTranslationChanges() {
EhTagDatabase.launchUpdate()
fun updateWhenTagTranslationChanges(enabled: Boolean) {
if (enabled) {
EhTagDatabase.launchUpdate()
}
}
@@ -21,8 +21,8 @@ import arrow.core.partially2
import arrow.core.right
import arrow.fx.coroutines.parMap
import arrow.fx.coroutines.parZip
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.EhDB
import com.hippo.ehviewer.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.data.BaseGalleryInfo
import com.hippo.ehviewer.client.data.FavListUrlBuilder
@@ -212,7 +212,8 @@ object EhEngine {
return ehRequest(url, EhUrl.URL_FORUMS).fetchUsingAsByteBuffer(ProfileParser::parse)
}
suspend fun getUConfig(url: String = EhUrl.uConfigUrl) {
suspend fun getUConfig(gallerySite: Int) {
val url = EhUrl.getUConfigUrl(gallerySite)
runSuspendCatching {
ehRequest(url).fetchUsingAsByteBuffer(UserConfigParser::parse)
}.onFailure { throwable ->
@@ -68,6 +68,7 @@ object EhTagDatabase : CoroutineScope {
// Copied from https://github.com/EhTagTranslation/EhSyringe/blob/c0cf88da04081072492829673aca34380b14dae6/src/plugin/suggest.ts#L37
// TODO: Optimize
private val nsScore = mapOf(
TagNamespace.Location.prefix to 10f,
TagNamespace.Other.prefix to 10f,
TagNamespace.Female.prefix to 9f,
TagNamespace.Male.prefix to 8.5f,
@@ -80,12 +80,11 @@ object EhUrl {
else -> ORIGIN_E
}
val uConfigUrl: String
get() = when (Settings.gallerySite.value) {
SITE_E -> URL_UCONFIG_E
SITE_EX -> URL_UCONFIG_EX
else -> URL_UCONFIG_E
}
fun getUConfigUrl(gallerySite: Int = Settings.gallerySite.value) = when (gallerySite) {
SITE_E -> URL_UCONFIG_E
SITE_EX -> URL_UCONFIG_EX
else -> URL_UCONFIG_E
}
val myTagsUrl: String
get() = when (Settings.gallerySite.value) {
@@ -16,6 +16,7 @@ sealed class TagNamespace(val value: String, val prefix: String?) {
object Female : TagNamespace("female", "f")
object Group : TagNamespace("group", "g")
object Language : TagNamespace("language", "l")
object Location : TagNamespace("location", "loc")
object Male : TagNamespace("male", "m")
object Mixed : TagNamespace("mixed", "x")
object Other : TagNamespace("other", "o")
@@ -31,6 +32,7 @@ sealed class TagNamespace(val value: String, val prefix: String?) {
Female.value -> Female
Group.value -> Group
Language.value -> Language
Location.value -> Location
Male.value -> Male
Mixed.value -> Mixed
Other.value -> Other
@@ -1,5 +1,5 @@
package com.hippo.ehviewer.client.exception
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
class CloudflareBypassException : EhException(R.string.cloudflare_bypass_failed)
@@ -1,5 +1,5 @@
package com.hippo.ehviewer.client.exception
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
class InsufficientFundsException : EhException(R.string.insufficient_funds)
@@ -15,6 +15,6 @@
*/
package com.hippo.ehviewer.client.exception
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
class NoHathClientException() : EhException(R.string.download_archive_failure_no_hath)
@@ -1,5 +1,5 @@
package com.hippo.ehviewer.client.exception
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
class NoHitsFoundException : EhException(R.string.gallery_list_empty_hit)
@@ -1,5 +1,5 @@
package com.hippo.ehviewer.client.exception
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
class NotLoggedInException : EhException(R.string.sign_in_first)
@@ -1,5 +1,5 @@
package com.hippo.ehviewer.client.exception
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
class QuotaExceededException : EhException(R.string.error_509)
@@ -5,6 +5,7 @@ import androidx.room.Delete
import androidx.room.Insert
import androidx.room.MapColumn
import androidx.room.Query
import androidx.room.RoomWarnings
import androidx.room.Transaction
import androidx.room.Update
import androidx.room.Upsert
@@ -12,11 +13,12 @@ import kotlinx.coroutines.flow.Flow
@Dao
interface DownloadsDao {
@Suppress("ktlint:standard:annotation")
// https://issuetracker.google.com/327583152
@Suppress("ktlint:standard:annotation", RoomWarnings.UNNECESSARY_NULLABILITY_IN_DAO_RETURN_TYPE)
@Query("SELECT LABEL, COUNT(*) AS COUNT FROM DOWNLOADS LEFT JOIN DOWNLOAD_LABELS USING(LABEL) GROUP BY LABEL")
fun countByLabel(): Flow<Map<@MapColumn("LABEL") String?, @MapColumn("COUNT") Int>>
@Suppress("ktlint:standard:annotation")
@Suppress("ktlint:standard:annotation", RoomWarnings.UNNECESSARY_NULLABILITY_IN_DAO_RETURN_TYPE)
@Query("SELECT ARTIST, COUNT(*) AS COUNT FROM DOWNLOADS LEFT JOIN DOWNLOAD_ARTISTS USING(GID) GROUP BY ARTIST ORDER BY COUNT DESC, ARTIST")
fun countByArtist(): Flow<Map<@MapColumn("ARTIST") String?, @MapColumn("COUNT") Int>>
@@ -26,6 +26,7 @@ import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.core.util.size
import arrow.fx.coroutines.parMapNotNull
import com.ehviewer.core.preferences.edit
import com.hippo.ehviewer.EhDB
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.data.BaseGalleryInfo
@@ -64,7 +65,6 @@ import logcat.LogPriority
import okio.Path
import okio.Path.Companion.toOkioPath
import okio.Path.Companion.toPath
import splitties.preferences.edit
object DownloadManager : OnSpiderListener, CoroutineScope {
override val coroutineContext = Dispatchers.IO + Job()
@@ -711,9 +711,7 @@ object DownloadManager : OnSpiderListener, CoroutineScope {
fun start() {
if (currentJob == null) {
currentJob = launch {
tracker.speedFlow().collect { speed ->
updateSpeed(speed.toLong())
}
tracker.speedFlow().collect(::updateSpeed)
}
}
}
@@ -31,7 +31,7 @@ import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import androidx.savedstate.serialization.decodeFromSavedState
import androidx.savedstate.serialization.encodeToSavedState
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.client.EhUtils
import com.hippo.ehviewer.client.data.BaseGalleryInfo
import com.hippo.ehviewer.dao.DownloadInfo
@@ -137,7 +137,7 @@ class DownloadService :
.setAutoCancel(false)
.setCategory(NotificationCompat.CATEGORY_PROGRESS)
.addAction(
R.drawable.v_pause_x24,
com.hippo.ehviewer.R.drawable.v_pause_x24,
getString(R.string.stat_download_action_stop_all),
piStopAll,
)
@@ -174,7 +174,7 @@ class DownloadService :
private fun init509Notification(): NotificationHandler {
val builder = NotificationCompat.Builder(applicationContext, channelId)
.setSmallIcon(R.drawable.ic_baseline_warning_24)
.setSmallIcon(com.hippo.ehviewer.R.drawable.ic_baseline_warning_24)
.setContentTitle(getString(R.string.stat_509_alert_title))
.setContentText(getString(R.string.stat_509_alert_text))
.setStyle(
@@ -53,7 +53,7 @@ suspend inline fun <T> useArchivePageLoader(
{ _, _ -> closeArchive() },
)
check(size > 0) { "Archive have no content!" }
if (needPassword() && archivePasswds.filterNotNull().none(::providePassword)) {
if (needPassword() && archivePasswds.none(::providePassword)) {
archivePasswds += passwdProvider(::providePassword)
}
val loader = install(
@@ -10,6 +10,7 @@ import android.net.http.UrlRequest
import android.net.http.UrlResponseInfo
import android.os.Build
import androidx.annotation.RequiresExtension
import com.ehviewer.core.preferences.edit
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.util.restartApplication
import io.ktor.client.engine.HttpClientEngineBase
@@ -40,7 +41,6 @@ import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.consumeEach
import kotlinx.coroutines.job
import kotlinx.coroutines.suspendCancellableCoroutine
import splitties.preferences.edit
class CronetEngine(override val config: CronetConfig) : HttpClientEngineBase("Cronet") {
// Limit thread to 1 since we are async & non-blocking
@@ -108,7 +108,7 @@ class CronetEngine(override val config: CronetConfig) : HttpClientEngineBase("Cr
val message = error.message.orEmpty()
if ("ERR_FILE_NOT_FOUND" in message || "ERR_PROXY_CONNECTION_FAILED" in message) {
Settings.edit(true) {
enableCronet.value = false
it[enableCronet] = false
}
with(config.context) { restartApplication() }
}
@@ -12,6 +12,7 @@ import com.hippo.ehviewer.client.data.TagNamespace.Character
import com.hippo.ehviewer.client.data.TagNamespace.Cosplayer
import com.hippo.ehviewer.client.data.TagNamespace.Female
import com.hippo.ehviewer.client.data.TagNamespace.Group
import com.hippo.ehviewer.client.data.TagNamespace.Location
import com.hippo.ehviewer.client.data.TagNamespace.Male
import com.hippo.ehviewer.client.data.TagNamespace.Mixed
import com.hippo.ehviewer.client.data.TagNamespace.Other
@@ -60,7 +61,7 @@ fun GalleryInfo.getComicInfo(): ComicInfo {
Group -> groups.addAll(list)
Character -> characters.addAll(list)
Parody -> parodies.addAll(list)
Other -> otherTags.addAll(list)
Location, Other -> otherTags.addAll(list)
Female, Male, Mixed -> ns.prefix.let { prefix ->
list.forEach { tag -> otherTags.add("$prefix:$tag") }
}
@@ -76,7 +77,7 @@ fun GalleryInfo.getComicInfo(): ComicInfo {
Group -> groups.add(tag)
Character -> characters.add(tag)
Parody -> if (tag != TAG_ORIGINAL) parodies.add(tag)
Other -> otherTags.add(tag)
Location, Other -> otherTags.add(tag)
Female, Male, Mixed -> ns.prefix.let { otherTags.add("$it:$tag") }
else -> Unit
}
@@ -24,7 +24,7 @@ import kotlin.time.Duration.Companion.seconds
import kotlin.time.Instant
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
@@ -47,7 +47,7 @@ class SpeedTracker(val window: Duration = 1.seconds) {
}
}
fun speedFlow(sample: Duration = 1.seconds) = fixedRate(sample).map {
fun speedFlow(sample: Duration = 1.seconds) = fixedRate(sample).mapNotNull {
mutex.withLock {
start?.let { start ->
val now = Clock.System.now()
@@ -55,8 +55,8 @@ class SpeedTracker(val window: Duration = 1.seconds) {
val window = passed.coerceIn(10.milliseconds, window)
val cutoff = now - window
received.removeIf { time, _ -> time < cutoff }
received.fold(0) { total, _, v -> total + v } / (window / 1.seconds)
} ?: 0.0
(received.fold(0) { total, _, v -> total + v } / (window / 1.seconds)).toLong()
}
}
}
}
@@ -72,16 +72,21 @@ suspend inline fun <R> timeoutBySpeed(
) = coroutineScope {
val onTimeout = AtomicReference<OnTimeout?>(t).let { { e: IOException -> it.exchange(null)?.invoke(e) } }
val watchdog = launch {
delay(Settings.connTimeout.value.seconds)
onTimeout(ConnectTimeoutException(url, Settings.connTimeout.value * 1000L))
val timeout = 10.seconds
delay(timeout)
onTimeout(ConnectTimeoutException(url, timeout.inWholeMilliseconds))
}
val tracker = SpeedTracker(2.seconds)
request {
var prev = 0L
onDownload { done, total ->
val bytesRead = (done - prev).toInt()
tracker.track(bytesRead)
l(total!!, done, bytesRead)
if (done == total!!) {
tracker.reset()
} else {
tracker.track(bytesRead)
}
l(total, done, bytesRead)
prev = done
}
timeout { reset() }
@@ -89,10 +94,10 @@ suspend inline fun <R> timeoutBySpeed(
watchdog.cancel()
resp.status.ensureSuccess()
val speedWatchdog = launch {
val timeoutSpeed = speedLevelToSpeed(Settings.timeoutSpeed.value) * 1024.0
tracker.speedFlow(1.seconds).collect { speed ->
if (timeoutSpeed != 0.0 && speed < timeoutSpeed) {
onTimeout(LowSpeedException(url, speed.toLong()))
val timeoutSpeed = speedLevelToSpeed(Settings.timeoutSpeed.value) * 1024L
tracker.speedFlow().collect { speed ->
if (speed < timeoutSpeed) {
onTimeout(LowSpeedException(url, speed))
}
}
}
@@ -104,7 +109,9 @@ suspend inline fun <R> timeoutBySpeed(
}
}
fun speedLevelToSpeed(level: Int) = 2f.pow(level).roundToInt()
const val MIN_SPEED_LEVEL = 3
fun speedLevelToSpeed(level: Int) = if (level == MIN_SPEED_LEVEL) 0 else 2f.pow(level).roundToInt()
inline fun <T, R> MutableObjectIntMap<T>.fold(initial: R, operation: (acc: R, T, Int) -> R): R {
var accumulator = initial
@@ -20,7 +20,7 @@ import androidx.annotation.IntDef
import arrow.core.Either
import arrow.core.getOrElse
import arrow.core.partially1
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.EhEngine
import com.hippo.ehviewer.client.EhUrl
@@ -35,8 +35,8 @@ import androidx.compose.material3.Text
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.EhDB
import com.hippo.ehviewer.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.EhEngine
import com.hippo.ehviewer.client.EhUtils
@@ -100,10 +100,10 @@ private fun ensureNoMediaFile(downloadDir: Path) {
private val lck = Mutex()
suspend fun keepNoMediaFileStatus(downloadDir: Path = downloadLocation) {
suspend fun keepNoMediaFileStatus(downloadDir: Path = downloadLocation, mediaScan: Boolean = Settings.mediaScan.value) {
if (downloadDir.isDirectory) {
lck.withLock {
if (Settings.mediaScan.value) {
if (mediaScan) {
removeNoMediaFile(downloadDir)
} else {
ensureNoMediaFile(downloadDir)
@@ -24,7 +24,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.EhUrl
import com.hippo.ehviewer.client.EhUtils
@@ -76,7 +76,7 @@ fun GalleryInfoBottomSheet(detail: GalleryDetail) {
LazyColumn(contentPadding = WindowInsets.systemBars.only(WindowInsetsSides.Bottom).asPaddingValues()) {
itemsIndexed(data) { index, (key, content) ->
Row(
modifier = Modifier.padding(horizontal = dimensionResource(id = R.dimen.keyline_margin)).clickable {
modifier = Modifier.padding(horizontal = dimensionResource(id = com.hippo.ehviewer.R.dimen.keyline_margin)).clickable {
if (index == INDEX_PARENT) {
if (content != null) {
navWithUrl(content)
@@ -104,7 +104,7 @@ import androidx.core.net.toUri
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.lifecycle.compose.LifecycleResumeEffect
import androidx.navigation.compose.rememberNavController
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.data.ListUrlBuilder
import com.hippo.ehviewer.client.parser.GalleryDetailUrlParser
@@ -394,7 +394,7 @@ class MainActivity : EhActivity() {
.windowInsetsPadding(WindowInsets.systemBars.only(WindowInsetsSides.Bottom)),
) {
Image(
painter = painterResource(id = R.drawable.sadpanda_low_poly),
painter = painterResource(id = com.hippo.ehviewer.R.drawable.sadpanda_low_poly),
contentDescription = null,
modifier = Modifier.fillMaxWidth().padding(bottom = 8.dp),
contentScale = ContentScale.FillWidth,
@@ -29,7 +29,7 @@ import androidx.biometric.BiometricManager.Authenticators.DEVICE_CREDENTIAL
import androidx.biometric.registerForAuthenticationResult
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.Settings
context(ctx: Context)
@@ -20,7 +20,7 @@ import android.content.Context
import android.widget.Toast
import androidx.browser.customtabs.CustomTabsIntent
import androidx.core.net.toUri
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.client.data.GalleryDetail
import com.hippo.ehviewer.client.parser.GalleryPageUrlParser
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
@@ -32,7 +32,7 @@ fun openBrowser(url: String) {
if (url.isEmpty()) return
try {
intent.launchUrl(ctx, url.toUri())
} catch (e: ActivityNotFoundException) {
} catch (_: ActivityNotFoundException) {
Toast.makeText(ctx, R.string.no_browser_installed, Toast.LENGTH_LONG).show()
}
}
@@ -36,7 +36,7 @@ fun postLogin() = GlobalScope.async(Dispatchers.IO) {
// Get cookies for image limits
launch {
catch {
EhEngine.getUConfig(EhUrl.URL_UCONFIG_E)
EhEngine.getUConfig(EhUrl.SITE_E)
EhCookieStore.flush()
}.onLeft {
logcat(it)
@@ -45,7 +45,7 @@ fun postLogin() = GlobalScope.async(Dispatchers.IO) {
// Sad panda check
catch {
EhEngine.getUConfig(EhUrl.URL_UCONFIG_EX)
EhEngine.getUConfig(EhUrl.SITE_EX)
EhCookieStore.flush()
Settings.gallerySite.value = EhUrl.SITE_EX
}.onLeft {
@@ -58,7 +58,7 @@ import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.dp
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.EhEngine
import com.hippo.ehviewer.client.EhUrl
@@ -142,7 +142,7 @@ fun AnimatedVisibilityScope.SignInScreen(navigator: DestinationsNavigator) = Scr
fun UsernameAndPasswordTextField() {
OutlinedTextField(
state = username,
modifier = Modifier.width(dimensionResource(id = R.dimen.single_max_width))
modifier = Modifier.width(dimensionResource(id = com.hippo.ehviewer.R.dimen.single_max_width))
.semantics { contentType = ContentType.Username }
.thenIf(!showUsernameError) { padding(bottom = 16.dp) },
label = { Text(stringResource(R.string.username)) },
@@ -154,7 +154,7 @@ fun AnimatedVisibilityScope.SignInScreen(navigator: DestinationsNavigator) = Scr
)
OutlinedSecureTextField(
state = password,
modifier = Modifier.width(dimensionResource(id = R.dimen.single_max_width))
modifier = Modifier.width(dimensionResource(id = com.hippo.ehviewer.R.dimen.single_max_width))
.semantics { contentType = ContentType.Password }
.thenIf(!showPasswordError) { padding(bottom = 16.dp) },
label = { Text(stringResource(R.string.password)) },
@@ -180,27 +180,27 @@ fun AnimatedVisibilityScope.SignInScreen(navigator: DestinationsNavigator) = Scr
when {
!windowSizeClass.isExpanded -> {
Column(
modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).systemBarsPadding().padding(dimensionResource(id = R.dimen.keyline_margin)),
modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).systemBarsPadding().padding(dimensionResource(id = com.hippo.ehviewer.R.dimen.keyline_margin)),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Image(
painter = painterResource(id = R.drawable.ic_launcher_foreground),
painter = painterResource(id = com.hippo.ehviewer.R.drawable.ic_launcher_foreground),
contentDescription = null,
modifier = Modifier.padding(dimensionResource(id = R.dimen.keyline_margin)),
modifier = Modifier.padding(dimensionResource(id = com.hippo.ehviewer.R.dimen.keyline_margin)),
)
UsernameAndPasswordTextField()
Text(
text = stringResource(id = R.string.app_waring),
modifier = Modifier.widthIn(max = dimensionResource(id = R.dimen.single_max_width)).padding(top = 24.dp),
modifier = Modifier.widthIn(max = dimensionResource(id = com.hippo.ehviewer.R.dimen.single_max_width)).padding(top = 24.dp),
style = MaterialTheme.typography.titleMedium,
)
Text(
text = stringResource(id = R.string.app_waring_2),
modifier = Modifier.widthIn(max = dimensionResource(id = R.dimen.single_max_width)).padding(top = 12.dp),
modifier = Modifier.widthIn(max = dimensionResource(id = com.hippo.ehviewer.R.dimen.single_max_width)).padding(top = 12.dp),
style = MaterialTheme.typography.titleLarge,
)
Spacer(modifier = Modifier.height(dimensionResource(id = R.dimen.keyline_margin)))
Row(modifier = Modifier.padding(top = dimensionResource(R.dimen.keyline_margin))) {
Spacer(modifier = Modifier.height(dimensionResource(id = com.hippo.ehviewer.R.dimen.keyline_margin)))
Row(modifier = Modifier.padding(top = dimensionResource(com.hippo.ehviewer.R.dimen.keyline_margin))) {
FilledTonalButton(
onClick = { openBrowser(EhUrl.URL_REGISTER) },
shapes = ButtonDefaults.shapes(),
@@ -255,18 +255,18 @@ fun AnimatedVisibilityScope.SignInScreen(navigator: DestinationsNavigator) = Scr
}
else -> {
Row(
modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).systemBarsPadding().padding(dimensionResource(id = R.dimen.keyline_margin)),
modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).systemBarsPadding().padding(dimensionResource(id = com.hippo.ehviewer.R.dimen.keyline_margin)),
verticalAlignment = Alignment.CenterVertically,
) {
Column(
modifier = Modifier.width(dimensionResource(id = R.dimen.signinscreen_landscape_caption_frame_width)).padding(dimensionResource(id = R.dimen.keyline_margin)),
modifier = Modifier.width(dimensionResource(id = com.hippo.ehviewer.R.dimen.signinscreen_landscape_caption_frame_width)).padding(dimensionResource(id = com.hippo.ehviewer.R.dimen.keyline_margin)),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Image(
painter = painterResource(id = R.drawable.ic_launcher_foreground),
painter = painterResource(id = com.hippo.ehviewer.R.drawable.ic_launcher_foreground),
contentDescription = null,
alignment = Alignment.Center,
modifier = Modifier.padding(dimensionResource(id = R.dimen.keyline_margin)),
modifier = Modifier.padding(dimensionResource(id = com.hippo.ehviewer.R.dimen.keyline_margin)),
)
Text(
text = stringResource(id = R.string.app_waring),
@@ -22,7 +22,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.client.parser.Archive
import com.hippo.ehviewer.client.parser.Funds
@@ -43,7 +43,7 @@ import arrow.core.none
import arrow.core.some
import coil3.compose.AsyncImage
import coil3.network.HttpException
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.EhEngine
import com.hippo.ehviewer.client.EhUtils
@@ -107,7 +107,7 @@ fun AvatarIcon() {
horizontalAlignment = Alignment.CenterHorizontally,
) {
CircularWavyProgressIndicator()
Spacer(modifier = Modifier.size(dimensionResource(id = R.dimen.keyline_margin)))
Spacer(modifier = Modifier.size(dimensionResource(id = com.hippo.ehviewer.R.dimen.keyline_margin)))
Text(text = placeholder)
}
}
@@ -39,7 +39,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.EhUtils
import com.hippo.ehviewer.dao.DownloadInfo
@@ -156,7 +156,7 @@ fun FabLayout(
}
}
onExpandChanged(false)
} catch (e: CancellationException) {
} catch (_: CancellationException) {
launch { state.expand() }
}
}
@@ -23,7 +23,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.text.parseAsHtml
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.client.data.GalleryComment
import com.hippo.ehviewer.ui.legacy.CoilImageGetter
import com.hippo.ehviewer.ui.legacy.LinkifyTextView
@@ -50,7 +50,7 @@ fun GalleryCommentCard(
},
modifier = modifier,
) {
val margin = dimensionResource(id = R.dimen.keyline_margin)
val margin = dimensionResource(id = com.hippo.ehviewer.R.dimen.keyline_margin)
Row(
modifier = Modifier.padding(horizontal = margin, vertical = 8.dp).fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
@@ -32,7 +32,7 @@ import androidx.compose.ui.res.pluralStringResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.client.EhUtils
import com.hippo.ehviewer.client.data.GalleryDetail
import com.hippo.ehviewer.client.data.GalleryInfo
@@ -91,21 +91,21 @@ fun GalleryDetailHeaderCard(
EhThumbCard(
key = remember(info.gid) { info },
modifier = Modifier.size(
dimensionResource(id = R.dimen.gallery_detail_thumb_width),
dimensionResource(id = R.dimen.gallery_detail_thumb_height),
dimensionResource(id = com.hippo.ehviewer.R.dimen.gallery_detail_thumb_width),
dimensionResource(id = com.hippo.ehviewer.R.dimen.gallery_detail_thumb_height),
),
)
}
Spacer(modifier = Modifier.weight(0.5F))
Column(
modifier = Modifier.height(dimensionResource(id = R.dimen.gallery_detail_thumb_height)),
modifier = Modifier.height(dimensionResource(id = com.hippo.ehviewer.R.dimen.gallery_detail_thumb_height)),
horizontalAlignment = Alignment.End,
) {
(info as? GalleryDetail)?.let {
GalleryDetailHeaderInfoCard(
detail = it,
onClick = onInfoCardClick,
modifier = Modifier.padding(top = 8.dp, end = dimensionResource(id = R.dimen.keyline_margin)),
modifier = Modifier.padding(top = 8.dp, end = dimensionResource(id = com.hippo.ehviewer.R.dimen.keyline_margin)),
)
}
Spacer(modifier = Modifier.weight(1F))
@@ -113,7 +113,7 @@ fun GalleryDetailHeaderCard(
AssistChip(
onClick = onCategoryChipClick,
label = { Text(text = categoryText, overflow = TextOverflow.Visible, softWrap = false, maxLines = 1) },
modifier = Modifier.padding(horizontal = dimensionResource(id = R.dimen.keyline_margin)),
modifier = Modifier.padding(horizontal = dimensionResource(id = com.hippo.ehviewer.R.dimen.keyline_margin)),
leadingIcon = {
Icon(
imageVector = Icons.AutoMirrored.Default.Label,
@@ -125,7 +125,7 @@ fun GalleryDetailHeaderCard(
AssistChip(
onClick = onUploaderChipClick,
label = { Text(text = uploaderText, overflow = TextOverflow.Visible, softWrap = false, maxLines = 1) },
modifier = Modifier.padding(horizontal = dimensionResource(id = R.dimen.keyline_margin)),
modifier = Modifier.padding(horizontal = dimensionResource(id = com.hippo.ehviewer.R.dimen.keyline_margin)),
leadingIcon = {
Icon(
imageVector = Icons.Default.NoAccounts,
@@ -51,7 +51,7 @@ import androidx.paging.LoadState
import androidx.paging.compose.LazyPagingItems
import androidx.paging.compose.itemContentType
import androidx.paging.compose.itemKey
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.data.BaseGalleryInfo
import com.hippo.ehviewer.client.exception.NoHitsFoundException
@@ -95,8 +95,8 @@ fun GalleryList(
onRefresh: () -> Unit,
onLoading: () -> Unit,
) {
val marginH = dimensionResource(id = R.dimen.gallery_list_margin_h)
val marginV = dimensionResource(id = R.dimen.gallery_list_margin_v)
val marginH = dimensionResource(id = com.hippo.ehviewer.R.dimen.gallery_list_margin_h)
val marginV = dimensionResource(id = com.hippo.ehviewer.R.dimen.gallery_list_margin_v)
var isRefreshing by remember { mutableStateOf(false) }
val refreshState = rememberPullToRefreshState()
@@ -132,8 +132,8 @@ fun GalleryList(
modifier = contentModifier.fillMaxSize(),
state = detailListState,
contentPadding = contentPadding + PaddingValues(marginH, marginV),
verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.gallery_list_interval)),
horizontalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.gallery_list_interval)),
verticalArrangement = Arrangement.spacedBy(dimensionResource(com.hippo.ehviewer.R.dimen.gallery_list_interval)),
horizontalArrangement = Arrangement.spacedBy(dimensionResource(com.hippo.ehviewer.R.dimen.gallery_list_interval)),
) {
items(
count = data.itemCount,
@@ -155,7 +155,7 @@ fun GalleryList(
}
}
} else {
val gridInterval = dimensionResource(R.dimen.gallery_grid_interval)
val gridInterval = dimensionResource(com.hippo.ehviewer.R.dimen.gallery_grid_interval)
val thumbColumns by Settings.thumbColumns.collectAsState()
FastScrollLazyVerticalStaggeredGrid(
columns = StaggeredGridCells.Fixed(thumbColumns),
@@ -17,7 +17,7 @@ import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import coil3.compose.AsyncImage
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
@Composable
fun ImageSearch(
@@ -29,7 +29,7 @@ fun ImageSearch(
) {
AnimatedVisibility(visible = image != null, modifier = Modifier.align(Alignment.CenterHorizontally)) {
Card {
val maxSize = dimensionResource(id = R.dimen.image_search_max_size)
val maxSize = dimensionResource(id = com.hippo.ehviewer.R.dimen.image_search_max_size)
AsyncImage(
model = image,
contentDescription = null,
@@ -10,7 +10,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.paging.LoadState
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.util.displayString
@Composable
@@ -33,7 +33,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp
import arrow.core.raise.ensure
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.EhTagDatabase
import com.hippo.ehviewer.client.EhUtils
@@ -117,7 +117,7 @@ fun SearchFilter(
selectedItemIndex = language + 1,
onSelectedItemIndexChange = { onLanguageChange(it - 1) },
)
val minRatingItems = stringArrayResource(id = R.array.search_min_rating)
val minRatingItems = stringArrayResource(id = com.hippo.ehviewer.R.array.search_min_rating)
val minRatingStr = stringResource(id = R.string.search_sr)
DropdownFilterChip(
label = minRatingStr,
@@ -22,7 +22,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.client.parser.Torrent
import com.hippo.ehviewer.client.parser.format
@@ -21,7 +21,7 @@ import androidx.core.graphics.alpha
import androidx.core.graphics.blue
import androidx.core.graphics.green
import androidx.core.graphics.red
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.asMutableState
import com.hippo.ehviewer.ui.main.RollingNumber
@@ -87,7 +87,7 @@ fun ColorFilterSetting() = Column(modifier = Modifier.verticalScroll(rememberScr
}
SpinnerChoice(
title = stringResource(id = R.string.pref_color_filter_mode),
entries = stringArrayResource(id = R.array.color_filter_modes),
entries = stringArrayResource(id = com.hippo.ehviewer.R.array.color_filter_modes),
values = arrayOf("0", "1", "2", "3", "4", "5"),
field = Settings.colorFilterMode.asMutableState(),
)
@@ -13,8 +13,8 @@ import android.webkit.MimeTypeMap
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.material3.SnackbarHostState
import androidx.core.content.FileProvider
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.BuildConfig.APPLICATION_ID
import com.hippo.ehviewer.R
import com.hippo.ehviewer.client.EhUrl
import com.hippo.ehviewer.client.data.GalleryInfo
import com.hippo.ehviewer.gallery.Page
@@ -121,7 +121,7 @@ suspend fun save(page: Page) {
try {
ctx.contentResolver.delete(imageUri, null, null)
} catch (e: Exception) {
e.logcat(e)
logcat("SavePage", e)
}
snackbar(cannotSave)
} else if (isAtLeastQ) {
@@ -37,8 +37,8 @@ import coil3.DrawableImage
import coil3.compose.AsyncImagePainter
import coil3.compose.SubcomposeAsyncImage
import coil3.compose.SubcomposeAsyncImageContent
import com.ehviewer.core.i18n.R
import com.google.accompanist.drawablepainter.DrawablePainter
import com.hippo.ehviewer.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.collectAsState
import com.hippo.ehviewer.gallery.Page
@@ -11,7 +11,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.stringArrayResource
import androidx.compose.ui.res.stringResource
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.asMutableState
import com.hippo.ehviewer.util.isAtLeastP
@@ -20,8 +20,8 @@ import com.hippo.ehviewer.util.isAtLeastP
fun ReaderGeneralSetting() = Column(modifier = Modifier.verticalScroll(rememberScrollState()).navigationBarsPadding()) {
SpinnerChoice(
title = stringResource(id = R.string.pref_reader_theme),
entries = stringArrayResource(id = R.array.reader_themes),
values = stringArrayResource(id = R.array.reader_themes_values),
entries = stringArrayResource(id = com.hippo.ehviewer.R.array.reader_themes),
values = stringArrayResource(id = com.hippo.ehviewer.R.array.reader_themes_values),
field = Settings.readerTheme.asMutableState(),
)
SwitchChoice(
@@ -17,7 +17,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringArrayResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.asMutableState
import com.hippo.ehviewer.collectAsState
@@ -27,13 +27,13 @@ import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
fun ReaderModeSetting() = Column(modifier = Modifier.verticalScroll(rememberScrollState()).navigationBarsPadding()) {
SpinnerChoice(
title = stringResource(id = R.string.pref_category_reading_mode),
entries = stringArrayResource(id = R.array.viewers_selector),
entries = stringArrayResource(id = com.hippo.ehviewer.R.array.viewers_selector),
values = arrayOf("0", "1", "2", "3", "4", "5"),
field = Settings.readingMode.asMutableState(),
)
SpinnerChoice(
title = stringResource(id = R.string.rotation_type),
entries = stringArrayResource(id = R.array.rotation_type),
entries = stringArrayResource(id = com.hippo.ehviewer.R.array.rotation_type),
values = arrayOf("0", "8", "16", "24", "32", "40", "48"),
field = Settings.orientationMode.asMutableState(),
)
@@ -60,7 +60,7 @@ private fun PagerSetting() = Column {
val pagerNav = Settings.readerPagerNav.asMutableState()
SpinnerChoice(
title = stringResource(id = R.string.pref_viewer_nav),
entries = stringArrayResource(id = R.array.pager_nav),
entries = stringArrayResource(id = com.hippo.ehviewer.R.array.pager_nav),
values = arrayOf("0", "1", "2", "3", "4", "5"),
field = pagerNav,
)
@@ -68,7 +68,7 @@ private fun PagerSetting() = Column {
Column {
SpinnerChoice(
title = stringResource(id = R.string.pref_read_with_tapping_inverted),
entries = stringArrayResource(id = R.array.invert_tapping_mode),
entries = stringArrayResource(id = com.hippo.ehviewer.R.array.invert_tapping_mode),
values = arrayOf("0", "1", "2", "3"),
field = Settings.readerPagerNavInverted.asMutableState(),
)
@@ -81,7 +81,7 @@ private fun PagerSetting() = Column {
val scaleType = Settings.imageScaleType.asMutableState()
SpinnerChoice(
title = stringResource(id = R.string.pref_image_scale_type),
entries = stringArrayResource(id = R.array.image_scale_type),
entries = stringArrayResource(id = com.hippo.ehviewer.R.array.image_scale_type),
values = arrayOf("1", "2", "3", "4", "5", "6"),
field = scaleType,
)
@@ -93,7 +93,7 @@ private fun PagerSetting() = Column {
}
SpinnerChoice(
title = stringResource(id = R.string.pref_zoom_start),
entries = stringArrayResource(id = R.array.zoom_start),
entries = stringArrayResource(id = com.hippo.ehviewer.R.array.zoom_start),
values = arrayOf("1", "2", "3", "4"),
field = Settings.zoomStart.asMutableState(),
)
@@ -113,22 +113,22 @@ private fun WebtoonSetting() = Column {
val webtoonNav = Settings.readerWebtoonNav.asMutableState()
SpinnerChoice(
title = stringResource(id = R.string.pref_viewer_nav),
entries = stringArrayResource(id = R.array.webtoon_nav),
entries = stringArrayResource(id = com.hippo.ehviewer.R.array.webtoon_nav),
values = arrayOf("0", "1", "2", "3", "4", "5"),
field = webtoonNav,
)
AnimatedVisibility(visible = webtoonNav.value != 5) {
SpinnerChoice(
title = stringResource(id = R.string.pref_read_with_tapping_inverted),
entries = stringArrayResource(id = R.array.invert_tapping_mode),
entries = stringArrayResource(id = com.hippo.ehviewer.R.array.invert_tapping_mode),
values = arrayOf("0", "1", "2", "3"),
field = Settings.readerWebtoonNavInverted.asMutableState(),
)
}
SpinnerChoice(
title = stringResource(id = R.string.pref_webtoon_side_padding),
entries = stringArrayResource(id = R.array.webtoon_side_padding),
values = stringArrayResource(id = R.array.webtoon_side_padding_values),
entries = stringArrayResource(id = com.hippo.ehviewer.R.array.webtoon_side_padding),
values = stringArrayResource(id = com.hippo.ehviewer.R.array.webtoon_side_padding_values),
field = Settings.webtoonSidePadding.asMutableState(),
)
SwitchChoice(
@@ -59,9 +59,9 @@ import arrow.core.Either
import arrow.core.Either.Companion.catch
import arrow.core.raise.ensure
import arrow.core.right
import com.ehviewer.core.i18n.R
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import com.hippo.ehviewer.EhDB
import com.hippo.ehviewer.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.data.BaseGalleryInfo
import com.hippo.ehviewer.collectAsState
@@ -407,7 +407,7 @@ suspend inline fun <T> usePageLoader(args: ReaderScreenArgs, crossinline block:
@Composable
private fun collectBackgroundColorAsState(): State<Color> {
val grey = colorResource(R.color.reader_background_dark)
val grey = colorResource(com.hippo.ehviewer.R.color.reader_background_dark)
val dark = isSystemInDarkTheme()
return Settings.readerTheme.collectAsState { theme ->
when (theme) {
@@ -15,7 +15,7 @@ import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import kotlinx.coroutines.launch
private val tabs = intArrayOf(
@@ -80,8 +80,8 @@ import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import arrow.core.partially1
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.EhDB
import com.hippo.ehviewer.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.asMutableState
import com.hippo.ehviewer.client.EhTagDatabase
@@ -523,7 +523,7 @@ fun AnimatedVisibilityScope.DownloadsScreen(navigator: DestinationsNavigator) =
},
) { contentPadding ->
val height by collectListThumbSizeAsState()
val realPadding = contentPadding + PaddingValues(dimensionResource(id = R.dimen.gallery_list_margin_h), dimensionResource(id = R.dimen.gallery_list_margin_v))
val realPadding = contentPadding + PaddingValues(dimensionResource(id = com.hippo.ehviewer.R.dimen.gallery_list_margin_h), dimensionResource(id = com.hippo.ehviewer.R.dimen.gallery_list_margin_v))
val searchBarConnection = remember {
val slop = ViewConfiguration.get(contextOf<Context>()).scaledTouchSlop
val topPaddingPx = with(density) { contentPadding.calculateTopPadding().roundToPx() }
@@ -548,7 +548,7 @@ fun AnimatedVisibilityScope.DownloadsScreen(navigator: DestinationsNavigator) =
Crossfade(targetState = gridView, label = "Downloads") { showGridView ->
if (showGridView) {
val gridInterval = dimensionResource(R.dimen.gallery_grid_interval)
val gridInterval = dimensionResource(com.hippo.ehviewer.R.dimen.gallery_grid_interval)
val thumbColumns by Settings.thumbColumns.collectAsState()
FastScrollLazyVerticalStaggeredGrid(
columns = StaggeredGridCells.Fixed(thumbColumns),
@@ -571,7 +571,7 @@ fun AnimatedVisibilityScope.DownloadsScreen(navigator: DestinationsNavigator) =
FastScrollLazyColumn(
modifier = Modifier.nestedScroll(searchBarConnection).fillMaxSize(),
contentPadding = realPadding,
verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.gallery_list_interval)),
verticalArrangement = Arrangement.spacedBy(dimensionResource(com.hippo.ehviewer.R.dimen.gallery_list_interval)),
) {
items(list, key = { it.gid }) { info ->
val checked = info.gid in checkedInfoMap
@@ -660,7 +660,7 @@ fun AnimatedVisibilityScope.DownloadsScreen(navigator: DestinationsNavigator) =
}
onClick(Icons.AutoMirrored.Default.Sort) {
val oldMode = SortMode.from(sortMode)
val sortModes = contextOf<Context>().resources.getStringArray(R.array.download_sort_modes).toList()
val sortModes = contextOf<Context>().resources.getStringArray(com.hippo.ehviewer.R.array.download_sort_modes).toList()
val (selected, checked) = awaitSelectItemWithCheckBox(
sortModes,
R.string.sort_by,
@@ -674,7 +674,7 @@ fun AnimatedVisibilityScope.DownloadsScreen(navigator: DestinationsNavigator) =
invalidateKey = !invalidateKey
}
onClick(Icons.Default.FilterList) {
val downloadStates = contextOf<Context>().resources.getStringArray(R.array.download_state).toList()
val downloadStates = contextOf<Context>().resources.getStringArray(com.hippo.ehviewer.R.array.download_state).toList()
val state = awaitSingleChoice(
downloadStates,
filterState.state + 1,
@@ -53,8 +53,8 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.paging.compose.collectAsLazyPagingItems
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.EhDB
import com.hippo.ehviewer.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.EhEngine
import com.hippo.ehviewer.client.data.BaseGalleryInfo
@@ -84,7 +84,7 @@ import androidx.core.text.buildSpannedString
import androidx.core.text.getSpans
import androidx.core.text.inSpans
import androidx.core.text.parseAsHtml
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.EhEngine
import com.hippo.ehviewer.client.EhFilter.remember
@@ -298,7 +298,7 @@ fun AnimatedVisibilityScope.GalleryCommentsScreen(gid: Long, navigator: Destinat
}
},
) { paddingValues ->
val keylineMargin = dimensionResource(id = R.dimen.keyline_margin)
val keylineMargin = dimensionResource(id = com.hippo.ehviewer.R.dimen.keyline_margin)
var editTextMeasured by remember { mutableStateOf(MinimumContentPaddingEditText) }
var isRefreshing by remember { mutableStateOf(false) }
val refreshState = rememberPullToRefreshState()
@@ -68,8 +68,8 @@ import androidx.paging.compose.itemKey
import arrow.core.partially1
import arrow.fx.coroutines.parMap
import arrow.fx.coroutines.parZip
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.EhDB
import com.hippo.ehviewer.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.EhEngine
import com.hippo.ehviewer.client.EhFilter.remember
@@ -174,7 +174,7 @@ fun GalleryDetailContent(
voteTag: VoteTag,
modifier: Modifier,
) {
val keylineMargin = dimensionResource(R.dimen.keyline_margin)
val keylineMargin = dimensionResource(com.hippo.ehviewer.R.dimen.keyline_margin)
val galleryDetail = galleryInfo.asGalleryDetail()
val windowSizeClass = LocalWindowSizeClass.current
val thumbColumns by Settings.thumbColumns.collectAsState()
@@ -262,8 +262,8 @@ fun GalleryDetailContent(
columns = GridCells.Fixed(thumbColumns),
contentPadding = contentPadding,
modifier = modifier.padding(horizontal = keylineMargin),
horizontalArrangement = Arrangement.spacedBy(dimensionResource(id = R.dimen.strip_item_padding)),
verticalArrangement = Arrangement.spacedBy(dimensionResource(id = R.dimen.strip_item_padding_v)),
horizontalArrangement = Arrangement.spacedBy(dimensionResource(id = com.hippo.ehviewer.R.dimen.strip_item_padding)),
verticalArrangement = Arrangement.spacedBy(dimensionResource(id = com.hippo.ehviewer.R.dimen.strip_item_padding_v)),
) {
item(
key = "header",
@@ -325,8 +325,8 @@ fun GalleryDetailContent(
columns = GridCells.Fixed(thumbColumns),
contentPadding = contentPadding,
modifier = modifier.padding(horizontal = keylineMargin),
horizontalArrangement = Arrangement.spacedBy(dimensionResource(id = R.dimen.strip_item_padding)),
verticalArrangement = Arrangement.spacedBy(dimensionResource(id = R.dimen.strip_item_padding_v)),
horizontalArrangement = Arrangement.spacedBy(dimensionResource(id = com.hippo.ehviewer.R.dimen.strip_item_padding)),
verticalArrangement = Arrangement.spacedBy(dimensionResource(id = com.hippo.ehviewer.R.dimen.strip_item_padding_v)),
) {
item(
key = "header",
@@ -340,7 +340,7 @@ fun GalleryDetailContent(
onUploaderChipClick = ::onUploaderChipClick.partially1(galleryInfo),
onBlockUploaderIconClick = ::showFilterUploaderDialog.partially1(galleryInfo),
onCategoryChipClick = ::onCategoryChipClick,
modifier = Modifier.width(dimensionResource(id = R.dimen.gallery_detail_card_landscape_width)).padding(vertical = keylineMargin),
modifier = Modifier.width(dimensionResource(id = com.hippo.ehviewer.R.dimen.gallery_detail_card_landscape_width)).padding(vertical = keylineMargin),
)
Column(
modifier = Modifier.fillMaxSize(),
@@ -443,7 +443,7 @@ fun BelowHeader(galleryDetail: GalleryDetail, voteTag: VoteTag) {
Box(
modifier = Modifier
.fillMaxWidth()
.padding(bottom = dimensionResource(id = R.dimen.strip_item_padding_v))
.padding(bottom = dimensionResource(id = com.hippo.ehviewer.R.dimen.strip_item_padding_v))
.clip(RoundedCornerShape(16.dp))
.clickable(onClick = ::navigateToCommentScreen),
contentAlignment = Alignment.Center,
@@ -463,7 +463,7 @@ fun BelowHeader(galleryDetail: GalleryDetail, voteTag: VoteTag) {
navigate(info.gid asDstWith info.token)
}
}
val keylineMargin = dimensionResource(R.dimen.keyline_margin)
val keylineMargin = dimensionResource(com.hippo.ehviewer.R.dimen.keyline_margin)
Spacer(modifier = Modifier.size(keylineMargin))
if (galleryDetail.newerVersions.isNotEmpty()) {
Box(contentAlignment = Alignment.Center) {
@@ -765,7 +765,7 @@ fun BelowHeader(galleryDetail: GalleryDetail, voteTag: VoteTag) {
Spacer(modifier = Modifier.size(keylineMargin))
if (Settings.showComments.value) {
GalleryDetailComment(galleryDetail.comments.comments)
Spacer(modifier = Modifier.size(dimensionResource(id = R.dimen.strip_item_padding_v)))
Spacer(modifier = Modifier.size(dimensionResource(id = com.hippo.ehviewer.R.dimen.strip_item_padding_v)))
}
}
@@ -34,9 +34,9 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.util.fastJoinToString
import androidx.lifecycle.viewModelScope
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.EhApplication.Companion.imageCache
import com.hippo.ehviewer.EhDB
import com.hippo.ehviewer.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.EhEngine
import com.hippo.ehviewer.client.EhUrl
@@ -249,7 +249,7 @@ fun AnimatedVisibilityScope.GalleryDetailScreen(args: GalleryDetailScreenArgs, n
) {
Text(text = stringResource(id = R.string.clear_image_cache_confirm))
}
(0..<gd.pages).forEach {
repeat(gd.pages) {
val key = getImageKey(gd.gid, it)
imageCache.remove(key)
}
@@ -69,8 +69,8 @@ import androidx.paging.LoadState
import androidx.paging.compose.collectAsLazyPagingItems
import arrow.core.raise.ensure
import arrow.core.raise.ensureNotNull
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.EhDB
import com.hippo.ehviewer.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.asMutableState
import com.hippo.ehviewer.client.EhTagDatabase
@@ -194,8 +194,8 @@ fun AnimatedVisibilityScope.GalleryListScreen(
FavouriteStatusRouter.Observe(data)
val listMode by Settings.listMode.collectAsState()
val entries = stringArrayResource(id = R.array.toplist_entries)
val values = stringArrayResource(id = R.array.toplist_values)
val entries = stringArrayResource(id = com.hippo.ehviewer.R.array.toplist_entries)
val values = stringArrayResource(id = com.hippo.ehviewer.R.array.toplist_values)
val toplists = remember { entries zip values }
val quickSearchName = getSuitableTitleForUrlBuilder(urlBuilder, false)
var saveProgress by Settings.qSSaveProgress.asMutableState()
@@ -42,8 +42,8 @@ import androidx.paging.compose.collectAsLazyPagingItems
import androidx.paging.compose.itemContentType
import androidx.paging.compose.itemKey
import androidx.paging.map
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.EhDB
import com.hippo.ehviewer.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.collectAsState
import com.hippo.ehviewer.icons.EhIcons
@@ -133,13 +133,13 @@ fun AnimatedVisibilityScope.HistoryScreen(navigator: DestinationsNavigator) = Sc
}
}
}
val marginH = dimensionResource(id = R.dimen.gallery_list_margin_h)
val marginH = dimensionResource(id = com.hippo.ehviewer.R.dimen.gallery_list_margin_h)
val cardHeight by collectListThumbSizeAsState()
val showPages by Settings.showGalleryPages.collectAsState()
FastScrollLazyColumn(
modifier = Modifier.nestedScroll(searchBarConnection).fillMaxSize(),
contentPadding = paddingValues,
verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.gallery_list_interval)),
verticalArrangement = Arrangement.spacedBy(dimensionResource(com.hippo.ehviewer.R.dimen.gallery_list_interval)),
) {
items(
count = historyData.itemCount,
@@ -27,7 +27,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.client.data.ListUrlBuilder
import com.hippo.ehviewer.client.data.ListUrlBuilder.Companion.MODE_IMAGE_SEARCH
import com.hippo.ehviewer.ui.Screen
@@ -50,8 +50,8 @@ import moe.tarsin.snackbar
@Composable
fun AnimatedVisibilityScope.ImageSearchScreen(navigator: DestinationsNavigator) = Screen(navigator) {
val selectImageFirst = stringResource(R.string.select_image_first)
val marginH = dimensionResource(id = R.dimen.gallery_list_margin_h)
val marginV = dimensionResource(id = R.dimen.gallery_list_margin_v)
val marginH = dimensionResource(id = com.hippo.ehviewer.R.dimen.gallery_list_margin_h)
val marginV = dimensionResource(id = com.hippo.ehviewer.R.dimen.gallery_list_margin_v)
var imageUri by rememberSaveable { mutableStateOf<Uri?>(null) }
Scaffold(
@@ -87,19 +87,19 @@ fun AnimatedVisibilityScope.ImageSearchScreen(navigator: DestinationsNavigator)
modifier = Modifier.padding(
paddingValues = contentPadding + PaddingValues(marginH, marginV),
).padding(
vertical = dimensionResource(id = R.dimen.search_layout_margin_v),
vertical = dimensionResource(id = com.hippo.ehviewer.R.dimen.search_layout_margin_v),
),
) {
Column(
modifier = Modifier.padding(
horizontal = dimensionResource(id = R.dimen.search_category_padding_h),
vertical = dimensionResource(id = R.dimen.search_category_padding_v),
horizontal = dimensionResource(id = com.hippo.ehviewer.R.dimen.search_category_padding_h),
vertical = dimensionResource(id = com.hippo.ehviewer.R.dimen.search_category_padding_v),
).fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
text = stringResource(id = R.string.search_image),
modifier = Modifier.height(dimensionResource(id = R.dimen.search_category_title_height)),
modifier = Modifier.height(dimensionResource(id = com.hippo.ehviewer.R.dimen.search_category_title_height)),
fontWeight = FontWeight.Bold,
style = MaterialTheme.typography.titleMedium,
)
@@ -21,7 +21,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.client.EhEngine
import com.hippo.ehviewer.icons.EhIcons
import com.hippo.ehviewer.icons.big.SadAndroid
@@ -65,8 +65,8 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.coerceAtMost
import androidx.compose.ui.unit.dp
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.EhApplication.Companion.searchDatabase
import com.hippo.ehviewer.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.EhTagDatabase
import com.hippo.ehviewer.client.data.TagNamespace
@@ -21,9 +21,9 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.fromHtml
import androidx.compose.ui.unit.dp
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.BuildConfig
import com.hippo.ehviewer.EhDB
import com.hippo.ehviewer.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.asMutableState
import com.hippo.ehviewer.download.downloadLocation
@@ -108,8 +108,8 @@ fun AnimatedVisibilityScope.AboutScreen(navigator: DestinationsNavigator) = Scre
)
SimpleMenuPreferenceInt(
title = stringResource(id = R.string.auto_updates),
entry = R.array.update_frequency,
entryValueRes = R.array.update_frequency_values,
entry = com.hippo.ehviewer.R.array.update_frequency,
entryValueRes = com.hippo.ehviewer.R.array.update_frequency_values,
state = Settings.updateIntervalDays.asMutableState(),
)
WorkPreference(title = stringResource(id = R.string.settings_about_check_for_updates)) {
@@ -30,9 +30,9 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.stringResource
import androidx.core.net.toUri
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.BuildConfig
import com.hippo.ehviewer.EhDB
import com.hippo.ehviewer.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.asMutableState
import com.hippo.ehviewer.client.EhEngine
@@ -169,8 +169,8 @@ fun AnimatedVisibilityScope.AdvancedScreen(navigator: DestinationsNavigator) = S
}
SimpleMenuPreferenceInt(
title = stringResource(id = R.string.settings_advanced_read_cache_size),
entry = R.array.read_cache_size_entries,
entryValueRes = R.array.read_cache_size_entry_values,
entry = com.hippo.ehviewer.R.array.read_cache_size_entries,
entryValueRes = com.hippo.ehviewer.R.array.read_cache_size_entry_values,
state = Settings.readCacheSize.asMutableState(),
)
var currentLanguage by remember { mutableStateOf(getAppLanguage()) }
@@ -29,8 +29,8 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import arrow.fx.coroutines.parMap
import arrow.fx.coroutines.parMapNotNull
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.EhDB
import com.hippo.ehviewer.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.asMutableState
import com.hippo.ehviewer.client.EhEngine.fillGalleryListByApi
@@ -44,6 +44,7 @@ import com.hippo.ehviewer.download.DownloadManager
import com.hippo.ehviewer.download.downloadDir
import com.hippo.ehviewer.download.downloadLocation
import com.hippo.ehviewer.spider.COMIC_INFO_FILE
import com.hippo.ehviewer.spider.MIN_SPEED_LEVEL
import com.hippo.ehviewer.spider.SpiderDen
import com.hippo.ehviewer.spider.SpiderQueen.Companion.SPIDER_INFO_FILENAME
import com.hippo.ehviewer.spider.readComicInfo
@@ -178,29 +179,21 @@ fun AnimatedVisibilityScope.DownloadScreen(navigator: DestinationsNavigator) = S
SimpleMenuPreferenceInt(
title = stringResource(id = R.string.settings_download_concurrency),
summary = stringResource(id = R.string.settings_download_concurrency_summary, multiThreadDownload.value),
entry = R.array.multi_thread_download_entries,
entryValueRes = R.array.multi_thread_download_entry_values,
entry = com.hippo.ehviewer.R.array.multi_thread_download_entries,
entryValueRes = com.hippo.ehviewer.R.array.multi_thread_download_entry_values,
state = multiThreadDownload,
)
val downloadDelay = Settings.downloadDelay.asMutableState()
SimpleMenuPreferenceInt(
title = stringResource(id = R.string.settings_download_download_delay),
summary = stringResource(id = R.string.settings_download_download_delay_summary, downloadDelay.value),
entry = R.array.download_delay_entries,
entryValueRes = R.array.download_delay_entry_values,
entry = com.hippo.ehviewer.R.array.download_delay_entries,
entryValueRes = com.hippo.ehviewer.R.array.download_delay_entry_values,
state = downloadDelay,
)
IntSliderPreference(
maxValue = 10,
minValue = 2,
step = 7,
title = stringResource(id = R.string.settings_download_connection_timeout),
state = Settings.connTimeout.asMutableState(),
)
IntSliderPreference(
maxValue = 10,
minValue = 4,
step = 5,
minValue = MIN_SPEED_LEVEL,
title = stringResource(id = R.string.settings_download_timeout_speed),
state = Settings.timeoutSpeed.asMutableState(),
display = ::speedLevelToSpeed,
@@ -209,8 +202,8 @@ fun AnimatedVisibilityScope.DownloadScreen(navigator: DestinationsNavigator) = S
SimpleMenuPreferenceInt(
title = stringResource(id = R.string.settings_download_preload_image),
summary = stringResource(id = R.string.settings_download_preload_image_summary, preloadImage.value),
entry = R.array.preload_image_entries,
entryValueRes = R.array.preload_image_entry_values,
entry = com.hippo.ehviewer.R.array.preload_image_entries,
entryValueRes = com.hippo.ehviewer.R.array.preload_image_entry_values,
state = preloadImage,
)
SwitchPreference(
@@ -28,7 +28,7 @@ import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.fromHtml
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.asMutableState
import com.hippo.ehviewer.client.EhCookieStore
@@ -94,7 +94,7 @@ fun AnimatedVisibilityScope.EhScreen(navigator: DestinationsNavigator) = Screen(
val warning = stringResource(id = R.string.settings_eh_identity_cookies_signed)
val state = rememberTextFieldState(cookies.joinToString("\n") { (k, v) -> "$k: $v" })
Text(text = AnnotatedString.fromHtml(warning))
Spacer(modifier = Modifier.size(dimensionResource(id = R.dimen.keyline_margin)))
Spacer(modifier = Modifier.size(dimensionResource(id = com.hippo.ehviewer.R.dimen.keyline_margin)))
OutlinedTextField(
state = state,
readOnly = true,
@@ -119,8 +119,8 @@ fun AnimatedVisibilityScope.EhScreen(navigator: DestinationsNavigator) = Screen(
val gallerySite = Settings.gallerySite.asMutableState()
SimpleMenuPreferenceInt(
title = stringResource(id = R.string.settings_eh_gallery_site),
entry = R.array.gallery_site_entries,
entryValueRes = R.array.gallery_site_entry_values,
entry = com.hippo.ehviewer.R.array.gallery_site_entries,
entryValueRes = com.hippo.ehviewer.R.array.gallery_site_entry_values,
state = gallerySite,
)
Preference(
@@ -161,8 +161,8 @@ fun AnimatedVisibilityScope.EhScreen(navigator: DestinationsNavigator) = Screen(
}
SimpleMenuPreferenceInt(
title = stringResource(id = R.string.dark_theme),
entry = R.array.night_mode_entries,
entryValueRes = R.array.night_mode_values,
entry = com.hippo.ehviewer.R.array.night_mode_entries,
entryValueRes = com.hippo.ehviewer.R.array.night_mode_values,
state = Settings.theme.asMutableState(),
)
SwitchPreference(
@@ -175,15 +175,15 @@ fun AnimatedVisibilityScope.EhScreen(navigator: DestinationsNavigator) = Screen(
)
SimpleMenuPreferenceInt(
title = stringResource(id = R.string.settings_eh_launch_page),
entry = R.array.launch_page_entries,
entryValueRes = R.array.launch_page_entry_values,
entry = com.hippo.ehviewer.R.array.launch_page_entries,
entryValueRes = com.hippo.ehviewer.R.array.launch_page_entry_values,
state = Settings.launchPage.asMutableState(),
)
val listMode = Settings.listMode.asMutableState()
SimpleMenuPreferenceInt(
title = stringResource(id = R.string.settings_eh_list_mode),
entry = R.array.list_mode_entries,
entryValueRes = R.array.list_mode_entry_values,
entry = com.hippo.ehviewer.R.array.list_mode_entries,
entryValueRes = com.hippo.ehviewer.R.array.list_mode_entry_values,
state = listMode,
)
AnimatedVisibility(visible = listMode.value == 0) {
@@ -197,8 +197,8 @@ fun AnimatedVisibilityScope.EhScreen(navigator: DestinationsNavigator) = Screen(
)
SimpleMenuPreferenceInt(
title = stringResource(id = R.string.settings_eh_detail_size),
entry = R.array.detail_size_entries,
entryValueRes = R.array.detail_size_entry_values,
entry = com.hippo.ehviewer.R.array.detail_size_entries,
entryValueRes = com.hippo.ehviewer.R.array.detail_size_entry_values,
state = Settings.detailSize.asMutableState(),
)
}
@@ -53,7 +53,7 @@ import androidx.compose.ui.res.stringArrayResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.unit.dp
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.EhFilter
import com.hippo.ehviewer.client.EhFilter.forget
@@ -88,7 +88,7 @@ fun AnimatedVisibilityScope.FilterScreen(navigator: DestinationsNavigator) = Scr
fun addFilter() {
launch {
dialog { cont ->
val types = stringArrayResource(id = R.array.filter_entries)
val types = stringArrayResource(id = com.hippo.ehviewer.R.array.filter_entries)
val type = rememberTextFieldState(types[0])
val state = rememberTextFieldState()
var error by remember { mutableStateOf<String?>(null) }
@@ -13,7 +13,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.ui.Screen
import com.hippo.ehviewer.ui.main.NavigationIcon
import com.hippo.ehviewer.ui.openBrowser
@@ -37,7 +37,7 @@ fun AnimatedVisibilityScope.LicenseScreen(navigator: DestinationsNavigator) = Sc
)
},
) { paddingValues ->
val libraries by rememberLibraries(R.raw.aboutlibraries)
val libraries by rememberLibraries(com.hippo.ehviewer.R.raw.aboutlibraries)
LibrariesContainer(
libraries = libraries,
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
@@ -9,9 +9,9 @@ import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import com.ehviewer.core.i18n.R
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.Screen
import com.hippo.ehviewer.ui.main.NavigationIcon
@@ -12,8 +12,8 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.stringResource
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.EhApplication.Companion.searchDatabase
import com.hippo.ehviewer.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.asMutableState
import com.hippo.ehviewer.ui.Screen
@@ -16,7 +16,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.stringResource
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.icons.EhIcons
import com.hippo.ehviewer.icons.filled.SadPanda
import com.hippo.ehviewer.ui.Screen
@@ -1,6 +1,5 @@
package com.hippo.ehviewer.ui.settings
import android.webkit.WebView
import androidx.compose.animation.AnimatedVisibilityScope
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
@@ -16,10 +15,10 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import com.ehviewer.core.i18n.R
import com.google.accompanist.web.WebView
import com.google.accompanist.web.rememberWebViewNavigator
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.Screen
@@ -36,7 +35,7 @@ private const val APPLY_JS = "javascript:(function(){var apply = document.getEle
@Destination<RootGraph>
@Composable
fun AnimatedVisibilityScope.UConfigScreen(navigator: DestinationsNavigator) = Screen(navigator) {
val url = EhUrl.uConfigUrl
val url = EhUrl.getUConfigUrl()
val wvNavigator = rememberWebViewNavigator()
Scaffold(
topBar = {
@@ -4,11 +4,11 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisallowComposableCalls
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.datastore.dataStoreFile
import androidx.datastore.preferences.core.PreferenceDataStoreFactory
import androidx.datastore.preferences.core.byteArrayPreferencesKey
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.emptyPreferences
import androidx.datastore.preferences.preferencesDataStoreFile
import androidx.lifecycle.compose.LifecycleResumeEffect
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -22,7 +22,7 @@ import kotlinx.serialization.serializer
import splitties.init.appCtx
val dataStoreScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
val dataStore = PreferenceDataStoreFactory.create { appCtx.dataStoreFile("Remembered.preferences_pb") }
val dataStore = PreferenceDataStoreFactory.create { appCtx.preferencesDataStoreFile("Remembered") }
val dataStateFlow = dataStore.data.stateIn(dataStoreScope, SharingStarted.Eagerly, emptyPreferences())
// Find out how make this work with any generic `Serializable` type
@@ -93,7 +93,7 @@ import arrow.core.Either
import arrow.core.raise.Raise
import arrow.core.raise.either
import arrow.core.right
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.client.EhTagDatabase
import com.hippo.ehviewer.client.EhTagDatabase.suggestion
import com.jamal.composeprefs3.ui.ifNotNullThen
@@ -75,7 +75,7 @@ fun animateFloatMergePredictiveBackAsState(
animatable.snapTo(transformed)
}
onBack()
} catch (e: CancellationException) {
} catch (_: CancellationException) {
channel.trySend(0f)
}
}
@@ -20,7 +20,7 @@ import android.content.Intent
import android.widget.Toast
import arrow.core.Either
import arrow.core.getOrElse
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
object AppHelper {
fun share(from: Activity, text: String?): Boolean {
@@ -24,7 +24,7 @@ import android.content.Context
import android.os.Build
import android.view.textclassifier.TextClassifier
import androidx.core.os.persistableBundleOf
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.ui.MainActivity
import moe.tarsin.tip
import splitties.systemservices.clipboardManager
@@ -15,7 +15,7 @@
*/
package com.hippo.ehviewer.util
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import eu.kanade.tachiyomi.util.system.logcat
import io.ktor.client.network.sockets.ConnectTimeoutException
import io.ktor.client.network.sockets.SocketTimeoutException
@@ -20,9 +20,6 @@ import io.ktor.utils.io.ByteReadChannel
import io.ktor.utils.io.InternalAPI
import io.ktor.utils.io.rethrowCloseCauseIfNeeded
import java.io.File
import java.util.Locale
import kotlin.math.ln
import kotlin.math.pow
import okio.Path
object FileUtils {
@@ -38,15 +35,15 @@ object FileUtils {
* @param bytes the bytes to convert
* @return the human readable string
*/
// http://stackoverflow.com/questions/3758606/
fun humanReadableByteCount(bytes: Long): String {
if (bytes < 1024) return "$bytes B"
val exp = (ln(bytes.toDouble()) / ln(1024f)).toInt()
return "%.1f %sB".format(
Locale.US,
bytes / 1024.toDouble().pow(exp.toDouble()),
("KMGTPE")[exp - 1].toString() + "i",
)
val units = "KMGTPE"
var exp = -1
var result = bytes.toDouble()
while (result >= 1024.0 && exp < units.length - 1) {
exp++
result /= 1024.0
}
return if (exp == -1) "$bytes B" else "%.1f %siB".format(result, units[exp])
}
fun cleanupDirectory(dir: File?, maxFiles: Int = 10) {
@@ -3,13 +3,13 @@ package com.hippo.ehviewer.util
import android.content.Context
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.os.LocaleListCompat
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import org.xmlpull.v1.XmlPullParser
context(ctx: Context)
fun getLanguages(): Map<String, String> = with(ctx) {
val languages = mutableMapOf("system" to getString(R.string.app_language_system))
resources.getXml(R.xml._generated_res_locale_config).use { parser ->
resources.getXml(com.hippo.ehviewer.R.xml._generated_res_locale_config).use { parser ->
var event = parser.eventType
while (event != XmlPullParser.END_DOCUMENT) {
if (event == XmlPullParser.START_TAG && parser.name == "locale") {
@@ -21,7 +21,7 @@ import androidx.core.net.toUri
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import eu.kanade.tachiyomi.util.lang.withUIContext
import java.io.File
import kotlin.concurrent.atomics.AtomicInt
@@ -15,7 +15,7 @@
*/
package com.hippo.ehviewer.util
import android.os.Looper
import com.ehviewer.core.mainthread.checkNotMainThread
import eu.kanade.tachiyomi.util.system.logcat
import java.io.File
import kotlinx.coroutines.CoroutineScope
@@ -51,11 +51,4 @@ object OSUtils {
}
}
val isMainThread: Boolean
get() = Looper.getMainLooper().thread === Thread.currentThread()
fun assertNotMainThread() {
check(!isMainThread) { "Cannot access database on the main thread since" + " it may potentially lock the UI for a long period of time." }
}
fun <T> runAssertingNotMainThread(block: suspend CoroutineScope.() -> T) = assertNotMainThread().run { runBlocking(block = block) }
fun <T> runAssertingNotMainThread(block: suspend CoroutineScope.() -> T) = checkNotMainThread().run { runBlocking(block = block) }
@@ -16,7 +16,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.DialogProperties
import com.hippo.ehviewer.R.string
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.ui.tools.DialogState
import kotlin.coroutines.intrinsics.COROUTINE_SUSPENDED
import kotlin.coroutines.intrinsics.startCoroutineUninterceptedOrReturn
@@ -40,7 +40,7 @@ fun ProgressDialog() {
) {
CircularWavyProgressIndicator()
Spacer(modifier = Modifier.size(18.dp))
Text(text = stringResource(id = string.please_wait))
Text(text = stringResource(id = R.string.please_wait))
}
}
}
@@ -18,7 +18,7 @@ package com.hippo.ehviewer.util
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.pluralStringResource
import androidx.compose.ui.res.stringResource
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import java.util.Locale
import kotlin.time.Clock
import kotlin.time.Instant
@@ -26,7 +26,7 @@ import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.asMutableState
import com.hippo.ehviewer.collectAsState
@@ -26,7 +26,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import moe.tarsin.kt.andThen
@Composable
@@ -2,7 +2,7 @@ package eu.kanade.tachiyomi.ui.reader.setting
import android.content.pm.ActivityInfo
import androidx.compose.ui.graphics.vector.ImageVector
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.icons.EhIcons
import com.hippo.ehviewer.icons.reader.Landscape
import com.hippo.ehviewer.icons.reader.LandscapeLocked
@@ -2,7 +2,7 @@ package eu.kanade.tachiyomi.ui.reader.setting
import androidx.compose.runtime.Stable
import androidx.compose.ui.graphics.vector.ImageVector
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.icons.EhIcons
import com.hippo.ehviewer.icons.reader.ContinuousVertical
import com.hippo.ehviewer.icons.reader.Default
@@ -3,7 +3,7 @@ package eu.kanade.tachiyomi.ui.reader.viewer
import androidx.annotation.StringRes
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
import com.hippo.ehviewer.R
import com.ehviewer.core.i18n.R
import eu.kanade.tachiyomi.ui.reader.setting.TappingInvertMode
import eu.kanade.tachiyomi.ui.reader.viewer.navigation.DisabledNavigation
import eu.kanade.tachiyomi.ui.reader.viewer.navigation.EdgeNavigation
@@ -14,11 +14,11 @@ import eu.kanade.tachiyomi.util.lang.invert
abstract class ViewerNavigation {
sealed class NavigationRegion(@StringRes val nameRes: Int, val colorRes: Int) {
data object MENU : NavigationRegion(R.string.action_menu, R.color.navigation_menu)
data object PREV : NavigationRegion(R.string.nav_zone_prev, R.color.navigation_prev)
data object NEXT : NavigationRegion(R.string.nav_zone_next, R.color.navigation_next)
data object LEFT : NavigationRegion(R.string.nav_zone_left, R.color.navigation_left)
data object RIGHT : NavigationRegion(R.string.nav_zone_right, R.color.navigation_right)
data object MENU : NavigationRegion(R.string.action_menu, com.hippo.ehviewer.R.color.navigation_menu)
data object PREV : NavigationRegion(R.string.nav_zone_prev, com.hippo.ehviewer.R.color.navigation_prev)
data object NEXT : NavigationRegion(R.string.nav_zone_next, com.hippo.ehviewer.R.color.navigation_next)
data object LEFT : NavigationRegion(R.string.nav_zone_left, com.hippo.ehviewer.R.color.navigation_left)
data object RIGHT : NavigationRegion(R.string.nav_zone_right, com.hippo.ehviewer.R.color.navigation_right)
}
data class Region(val rect: Rect, val type: NavigationRegion) {
+30 -29
View File
@@ -126,9 +126,9 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
[[package]]
name = "bytemuck"
version = "1.23.1"
version = "1.23.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422"
checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677"
[[package]]
name = "byteorder-lite"
@@ -144,9 +144,9 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
[[package]]
name = "cc"
version = "1.2.30"
version = "1.2.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7"
checksum = "2352e5597e9c544d5e6d9c95190d5d27738ade584fa8db0a16e130e5c2b5296e"
dependencies = [
"shlex",
]
@@ -491,9 +491,9 @@ checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
[[package]]
name = "h2"
version = "0.4.11"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17da50a276f1e01e0ba6c029e47b7100754904ee8a278f886546e98575380785"
checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386"
dependencies = [
"atomic-waker",
"bytes",
@@ -516,9 +516,9 @@ checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403"
[[package]]
name = "hashbrown"
version = "0.15.4"
version = "0.15.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
[[package]]
name = "http"
@@ -1206,18 +1206,18 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.95"
version = "1.0.96"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
checksum = "beef09f85ae72cea1ef96ba6870c51e6382ebfa4f0e85b643459331f3daa5be0"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quick-xml"
version = "0.38.0"
version = "0.38.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8927b0664f5c5a98265138b7e3f90aa19a6b21353182469ace36d4ac527b7b1b"
checksum = "9845d9dccf565065824e69f9f235fafba1587031eda353c1f1561cd6a6be78f4"
dependencies = [
"memchr",
]
@@ -1353,9 +1353,9 @@ dependencies = [
[[package]]
name = "rustls"
version = "0.23.30"
version = "0.23.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "069a8df149a16b1a12dcc31497c3396a173844be3cac4bd40c9e7671fef96671"
checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc"
dependencies = [
"once_cell",
"rustls-pki-types",
@@ -1386,9 +1386,9 @@ dependencies = [
[[package]]
name = "rustversion"
version = "1.0.21"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
[[package]]
name = "rxing"
@@ -1501,9 +1501,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.141"
version = "1.0.142"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3"
checksum = "030fedb782600dcbd6f02d479bf0d817ac3bb40d644745b769d6a96bc3afc5a7"
dependencies = [
"itoa",
"memchr",
@@ -1537,9 +1537,9 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
[[package]]
name = "slab"
version = "0.4.10"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d"
checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589"
[[package]]
name = "smallvec"
@@ -1691,9 +1691,9 @@ source = "git+https://github.com/y21/tl.git?rev=13ed128e35ce04c4f16c41cb1e38347d
[[package]]
name = "tokio"
version = "1.47.0"
version = "1.47.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43864ed400b6043a4757a25c7a64a8efde741aed79a056a2fb348a406701bb35"
checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038"
dependencies = [
"backtrace",
"bytes",
@@ -1740,9 +1740,9 @@ dependencies = [
[[package]]
name = "tokio-util"
version = "0.7.15"
version = "0.7.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df"
checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5"
dependencies = [
"bytes",
"futures-core",
@@ -2122,7 +2122,7 @@ version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
dependencies = [
"windows-targets 0.53.2",
"windows-targets 0.53.3",
]
[[package]]
@@ -2158,10 +2158,11 @@ dependencies = [
[[package]]
name = "windows-targets"
version = "0.53.2"
version = "0.53.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef"
checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91"
dependencies = [
"windows-link",
"windows_aarch64_gnullvm 0.53.0",
"windows_aarch64_msvc 0.53.0",
"windows_i686_gnu 0.53.0",
@@ -2398,9 +2399,9 @@ dependencies = [
[[package]]
name = "zerovec"
version = "0.11.2"
version = "0.11.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428"
checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b"
dependencies = [
"yoke",
"zerofrom",
-1
View File
@@ -1 +0,0 @@
/build
+46
View File
@@ -0,0 +1,46 @@
plugins {
`kotlin-dsl`
alias(libs.plugins.spotless)
}
dependencies {
compileOnly(libs.android.gradlePlugin)
compileOnly(libs.kotlin.gradlePlugin)
compileOnly(libs.spotless.gradlePlugin)
// https://github.com/gradle/gradle/issues/15383#issuecomment-779893192
compileOnly(files(libs::class.java.superclass.protectionDomain.codeSource.location))
}
gradlePlugin {
plugins {
register("androidApplication") {
id = libs.plugins.ehviewer.android.application.get().pluginId
implementationClass = "AndroidApplicationConventionPlugin"
}
register("multiplatformLibrary") {
id = libs.plugins.ehviewer.multiplatform.library.asProvider().get().pluginId
implementationClass = "MultiplatformLibraryConventionPlugin"
}
register("multiplatformLibraryCompose") {
id = libs.plugins.ehviewer.multiplatform.library.compose.get().pluginId
implementationClass = "MultiplatformLibraryComposeConventionPlugin"
}
}
}
kotlin {
jvmToolchain(21)
}
spotless {
val ktlintVersion = libs.ktlint.get().version
kotlin {
// https://github.com/diffplug/spotless/issues/111
target("src/**/*.kt")
ktlint(ktlintVersion)
}
kotlinGradle {
ktlint(ktlintVersion)
}
}
@@ -0,0 +1,37 @@
import com.android.build.api.dsl.ApplicationExtension
import com.android.build.api.dsl.Lint
import com.ehviewer.configureKotlin
import com.ehviewer.configureKotlinCompose
import com.ehviewer.configureLint
import com.ehviewer.configureSpotless
import com.ehviewer.libs
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.assign
import org.gradle.kotlin.dsl.configure
import org.jetbrains.kotlin.gradle.dsl.JvmDefaultMode
import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidExtension
@Suppress("unused")
class AndroidApplicationConventionPlugin : Plugin<Project> {
override fun apply(target: Project) = with(target) {
apply(plugin = libs.plugins.kotlin.android.get().pluginId)
apply(plugin = libs.plugins.android.application.get().pluginId)
apply(plugin = libs.plugins.compose.compiler.get().pluginId)
apply(plugin = libs.plugins.composeCompilerReportGenerator.get().pluginId)
configure<KotlinAndroidExtension> {
jvmToolchain(21)
compilerOptions {
configureKotlin()
configureKotlinCompose()
jvmDefault = JvmDefaultMode.NO_COMPATIBILITY
}
}
configure<ApplicationExtension> {
lint(Lint::configureLint)
}
configureSpotless()
}
}
@@ -0,0 +1,23 @@
import com.ehviewer.configureKotlinCompose
import com.ehviewer.libs
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.configure
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
@Suppress("unused")
class MultiplatformLibraryComposeConventionPlugin : Plugin<Project> {
override fun apply(target: Project) = with(target) {
apply<MultiplatformLibraryConventionPlugin>()
apply(plugin = libs.plugins.compose.compiler.get().pluginId)
apply(plugin = libs.plugins.compose.multiplatform.get().pluginId)
apply(plugin = libs.plugins.composeCompilerReportGenerator.get().pluginId)
configure<KotlinMultiplatformExtension> {
compilerOptions {
configureKotlinCompose()
}
}
}
}
@@ -0,0 +1,66 @@
import com.android.build.api.dsl.KotlinMultiplatformAndroidLibraryTarget
import com.android.build.api.dsl.Lint
import com.android.build.api.dsl.androidLibrary
import com.ehviewer.configureKotlin
import com.ehviewer.configureLint
import com.ehviewer.configureSpotless
import com.ehviewer.libs
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.assign
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.dependencies
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
import org.jetbrains.kotlin.gradle.dsl.JvmDefaultMode
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
@OptIn(ExperimentalKotlinGradlePluginApi::class)
class MultiplatformLibraryConventionPlugin : Plugin<Project> {
override fun apply(target: Project) = with(target) {
apply(plugin = libs.plugins.kotlin.multiplatform.get().pluginId)
apply(plugin = libs.plugins.android.kotlin.multiplatform.library.get().pluginId)
apply(plugin = libs.plugins.android.lint.get().pluginId)
configure<KotlinMultiplatformExtension> {
jvmToolchain(21)
compilerOptions {
configureKotlin()
}
applyHierarchyTemplate {
common {
group("jvm") {
withCompilations { it.target is KotlinMultiplatformAndroidLibraryTarget }
withJvm()
}
}
}
// jvm("desktop") {
// compilerOptions {
// jvmDefault = JvmDefaultMode.NO_COMPATIBILITY
// }
// }
androidLibrary {
namespace = "com.ehviewer${path.replace(':', '.')}"
withHostTestBuilder {
}
enableCoreLibraryDesugaring = true
compilerOptions {
jvmDefault = JvmDefaultMode.NO_COMPATIBILITY
}
}
}
configure<Lint>(Lint::configureLint)
configureSpotless()
dependencies {
"coreLibraryDesugaring"(libs.desugar)
}
}
}
@@ -0,0 +1,37 @@
package com.ehviewer
import org.gradle.kotlin.dsl.assign
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonCompilerOptions
// https://kotlinlang.org/docs/gradle-compiler-options.html#all-compiler-options
internal fun KotlinCommonCompilerOptions.configureKotlin() {
progressiveMode = true
allWarningsAsErrors = true
optIn.addAll(
"kotlin.ExperimentalStdlibApi",
"kotlin.concurrent.atomics.ExperimentalAtomicApi",
"kotlin.contracts.ExperimentalContracts",
"kotlin.time.ExperimentalTime",
"kotlinx.coroutines.ExperimentalCoroutinesApi",
"kotlinx.coroutines.FlowPreview",
)
freeCompilerArgs.addAll(
"-Xcontext-parameters",
"-Xwhen-expressions=indy",
"-Xannotation-default-target=param-property",
)
}
internal fun KotlinCommonCompilerOptions.configureKotlinCompose() {
optIn.addAll(
"androidx.compose.animation.ExperimentalAnimationApi",
"androidx.compose.animation.ExperimentalSharedTransitionApi",
"androidx.compose.foundation.ExperimentalFoundationApi",
"androidx.compose.foundation.layout.ExperimentalLayoutApi",
"androidx.compose.material3.ExperimentalMaterial3Api",
"androidx.compose.material3.ExperimentalMaterial3ExpressiveApi",
"androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi",
"androidx.compose.runtime.ExperimentalComposeRuntimeApi",
"androidx.compose.ui.ExperimentalComposeUiApi",
)
}
@@ -0,0 +1,9 @@
package com.ehviewer
import com.android.build.api.dsl.Lint
internal fun Lint.configureLint() {
checkReleaseBuilds = false
disable += setOf("MissingTranslation", "MissingQuantity")
error += setOf("InlinedApi")
}
@@ -0,0 +1,8 @@
package com.ehviewer
import org.gradle.accessors.dm.LibrariesForLibs
import org.gradle.api.Project
import org.gradle.kotlin.dsl.the
internal val Project.libs
get(): LibrariesForLibs = the()
Loaded 100 of 144 files, more files were not shown because too many files have changed in this diff. Show more