Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0195f1c9b8 | ||
|
|
18d2d992a4 | ||
|
|
5582353c44 | ||
|
|
464568f29f | ||
|
|
213a9d56d2 | ||
|
|
f672462bcd | ||
|
|
9a0b0d2c65 | ||
|
|
fcaf4e3182 | ||
|
|
ea40fa9b05 | ||
|
|
2e3436dbe7 | ||
|
|
bd759dedea | ||
|
|
bac78ce018 | ||
|
|
dd95d7aaa2 | ||
|
|
d1bb5b1d87 | ||
|
|
67a3252b05 | ||
|
|
2df08f022f | ||
|
|
65673a0ed9 | ||
|
|
aef20e2e04 | ||
|
|
3bbfc8ac3a | ||
|
|
02e85a8c4d | ||
|
|
8cc531ccec | ||
|
|
30fc750e17 | ||
|
|
0ff40d3d38 | ||
|
|
9fa80db783 | ||
|
|
357503b403 | ||
|
|
10f7b2a7a9 | ||
|
|
99696b11db | ||
|
|
71291b8800 | ||
|
|
3532dbdcd6 | ||
|
|
589ba8432c | ||
|
|
273196bf5d | ||
|
|
a5fadeee3c | ||
|
|
3f784ec1de | ||
|
|
f7a70cdfc3 | ||
|
|
030100280f | ||
|
|
0d76ee43fd | ||
|
|
11a215f070 | ||
|
|
a6e61e07fc | ||
|
|
da94d298ce | ||
|
|
9e74db0f02 | ||
|
|
0d63c2fa3c | ||
|
|
bf44fde58e | ||
|
|
4bc119138f | ||
|
|
c7f5b86843 | ||
|
|
2aa815dce1 | ||
|
|
cf7f18351d | ||
|
|
5ed27963d7 | ||
|
|
85e539f0ba | ||
|
|
15ecb0e3f4 | ||
|
|
db5055da6e | ||
|
|
09e201f3f2 | ||
|
|
6f34083880 | ||
|
|
4e0c42c955 | ||
|
|
935b7dec0c | ||
|
|
d0b0651c7d | ||
|
|
e131a416e8 | ||
|
|
dd526d33bd | ||
|
|
4611a77e04 | ||
|
|
806560cf59 | ||
|
|
fd3f6eb124 | ||
|
|
8e14c6e57b | ||
|
|
20a4f4ab25 | ||
|
|
d4c64f6e66 | ||
|
|
cfb2f15a1e | ||
|
|
927a738f46 | ||
|
|
19482dbd77 | ||
|
|
43b7fb611a | ||
|
|
c39338efb7 | ||
|
|
dbd952eebb | ||
|
|
192039408c | ||
|
|
e38376d4b0 | ||
|
|
a4062cf4d1 | ||
|
|
3c47d36525 | ||
|
|
00090944d5 | ||
|
|
d2cafbb2a3 | ||
|
|
9847b95582 | ||
|
|
986412932b | ||
|
|
f13831cb74 | ||
|
|
5ed1203558 | ||
|
|
acf1fe43bf | ||
|
|
4761ef7416 | ||
|
|
70aaf38f94 | ||
|
|
a92aaf19c9 | ||
|
|
a5b408d316 | ||
|
|
f96a2e63d1 | ||
|
|
a0a9da68da | ||
|
|
a83be94d1f | ||
|
|
cc5dfbfa41 | ||
|
|
57b79b0b06 | ||
|
|
569130087f | ||
|
|
1a7b36b488 | ||
|
|
e8b5fd0425 | ||
|
|
626d5e7a8c | ||
|
|
4d94e84c13 | ||
|
|
863ec659ff | ||
|
|
071fdfc0a3 | ||
|
|
a137e9715a | ||
|
|
c28d1d34ff | ||
|
|
1230022d17 | ||
|
|
9a9f2a8d70 |
No files matched your search
@@ -1,5 +1,7 @@
|
||||
[*.{kt,kts}]
|
||||
ij_kotlin_imports_layout = *
|
||||
ij_kotlin_line_break_after_multiline_when_entry = false
|
||||
ktlint_code_style = intellij_idea
|
||||
ktlint_function_naming_ignore_when_annotated_with = Composable
|
||||
ktlint_standard_class-signature = disabled
|
||||
ktlint_standard_mixed-condition-operators = disabled
|
||||
@@ -1 +0,0 @@
|
||||
*.sh eol=lf
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
sudo udevadm trigger --name-match=kvm
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v5
|
||||
@@ -42,7 +42,7 @@ jobs:
|
||||
workspaces: "./app/src/main/rust"
|
||||
|
||||
- name: CMake Cache
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache/restore@v5
|
||||
with:
|
||||
path: app/.cxx
|
||||
key: cmake-
|
||||
@@ -59,7 +59,7 @@ jobs:
|
||||
|
||||
- name: Upload reports
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: reports
|
||||
path: benchmark/build/reports
|
||||
+15
-15
@@ -12,7 +12,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v5
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v5
|
||||
@@ -79,7 +79,7 @@ jobs:
|
||||
cache-encryption-key: ${{ secrets.GradleEncryptionKey }}
|
||||
|
||||
- name: CMake Cache
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: app/.cxx
|
||||
key: cmake-default-${{ hashFiles('rust-toolchain.toml', 'settings.gradle.kts', 'app/src/main/cpp/CMakeLists.txt', 'app/src/main/rust/Cargo.lock') }}
|
||||
@@ -93,32 +93,32 @@ jobs:
|
||||
run: ./gradlew assembleDefaultRelease
|
||||
|
||||
- name: Upload ARM64
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: default-arm64-v8a-${{ github.sha }}
|
||||
path: app/build/outputs/apk/default/release/app-default-arm64-v8a-release.apk
|
||||
|
||||
- name: Upload x86_64
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: default-x86_64-${{ github.sha }}
|
||||
path: app/build/outputs/apk/default/release/app-default-x86_64-release.apk
|
||||
|
||||
- name: Upload ARM32
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: default-armeabi-v7a-${{ github.sha }}
|
||||
path: app/build/outputs/apk/default/release/app-default-armeabi-v7a-release.apk
|
||||
|
||||
- name: Upload mapping
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: default-mapping-${{ github.sha }}
|
||||
path: app/build/outputs/mapping/defaultRelease
|
||||
|
||||
- name: Upload native debug symbols
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: default-native-debug-symbols-${{ github.sha }}
|
||||
path: app/build/outputs/native-debug-symbols/defaultRelease/native-debug-symbols.zip
|
||||
@@ -127,7 +127,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v5
|
||||
@@ -151,7 +151,7 @@ jobs:
|
||||
cache-encryption-key: ${{ secrets.GradleEncryptionKey }}
|
||||
|
||||
- name: CMake Cache
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: app/.cxx
|
||||
key: cmake-marshmallow-${{ hashFiles('rust-toolchain.toml', 'settings.gradle.kts', 'app/src/main/cpp/CMakeLists.txt', 'app/src/main/rust/Cargo.lock') }}
|
||||
@@ -165,32 +165,32 @@ jobs:
|
||||
run: ./gradlew assembleMarshmallowRelease
|
||||
|
||||
- name: Upload ARM64
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: marshmallow-arm64-v8a-${{ github.sha }}
|
||||
path: app/build/outputs/apk/marshmallow/release/app-marshmallow-arm64-v8a-release.apk
|
||||
|
||||
- name: Upload x86_64
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: marshmallow-x86_64-${{ github.sha }}
|
||||
path: app/build/outputs/apk/marshmallow/release/app-marshmallow-x86_64-release.apk
|
||||
|
||||
- name: Upload ARM32
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: marshmallow-armeabi-v7a-${{ github.sha }}
|
||||
path: app/build/outputs/apk/marshmallow/release/app-marshmallow-armeabi-v7a-release.apk
|
||||
|
||||
- name: Upload mapping
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: marshmallow-mapping-${{ github.sha }}
|
||||
path: app/build/outputs/mapping/marshmallowRelease
|
||||
|
||||
- name: Upload native debug symbols
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: marshmallow-native-debug-symbols-${{ github.sha }}
|
||||
path: app/build/outputs/native-debug-symbols/marshmallowRelease/native-debug-symbols.zip
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
action:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dessant/lock-threads@v5
|
||||
- uses: dessant/lock-threads@v6
|
||||
with:
|
||||
issue-inactive-days: '1'
|
||||
process-only: 'issues'
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
sudo udevadm trigger --name-match=kvm
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v5
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
workspaces: "./app/src/main/rust"
|
||||
|
||||
- name: CMake Cache
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache/restore@v5
|
||||
with:
|
||||
path: app/.cxx
|
||||
key: cmake-
|
||||
|
||||
@@ -1,5 +1,26 @@
|
||||
# 变更日志
|
||||
|
||||
## [1.14.6] - 2025-12-17
|
||||
|
||||
### 新功能
|
||||
|
||||
* 支持显示画廊阅读进度(于 EH 设置中开启) [#2277](https://github.com/FooIbar/EhViewer/issues/2277)
|
||||
|
||||
### 改进
|
||||
|
||||
* 画廊列表变化时重新显示悬浮操作按钮 [#2681](https://github.com/FooIbar/EhViewer/issues/2681)
|
||||
* 移除文件名中的尾随空格和点以兼容 Windows [#2727](https://github.com/FooIbar/EhViewer/issues/2727)
|
||||
* 长按画廊详情中的标签时显示标签名称 [#2769](https://github.com/FooIbar/EhViewer/issues/2769)
|
||||
* 杂项优化
|
||||
|
||||
### Bug 修复
|
||||
|
||||
* 对话框中的下拉菜单显示错位
|
||||
* HTTP 状态错误显示为“什么都没有找到”
|
||||
* 某些老设备无法通过 Cloudflare 验证 [#2794](https://github.com/FooIbar/EhViewer/issues/2794)
|
||||
* 杂项修复
|
||||
|
||||
|
||||
## [1.14.5] - 2025-10-19
|
||||
|
||||
### 改进
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
</p>
|
||||
|
||||
<h1 align="center">
|
||||
<img src="https://github.com/Ehviewer-Overhauled/Art/blob/master/launcher_icon-web.svg" width="200" alt="EhViewer">
|
||||
<img src="https://github.com/FooIbar/EhViewer-art/blob/master/launcher_icon-web.svg" width="200" alt="EhViewer">
|
||||
<br>EhViewer<br>
|
||||
</h1>
|
||||
|
||||
@@ -78,13 +78,13 @@ and [Dynamic Color](https://m3.material.io/styles/color/dynamic-color/overview)
|
||||
*Devices running Android 6 need to have the [ISRG Root X1](https://letsencrypt.org/certs/isrgrootx1.pem) certificate installed
|
||||
|
||||
<a href="https://github.com/FooIbar/EhViewer/releases">
|
||||
<img alt="Get it on GitHub" src="https://github.com/Ehviewer-Overhauled/Art/blob/master/get-it-on-github.svg" width="200px"/>
|
||||
<img alt="Get it on GitHub" src="https://github.com/FooIbar/EhViewer-art/blob/master/get-it-on-github.svg" width="200px"/>
|
||||
</a>
|
||||
|
||||
# Screenshot
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
# Thanks
|
||||
|
||||
|
||||
@@ -52,18 +52,15 @@ android {
|
||||
}.standardOutput.asText.get().trim().removePrefix("https://github.com/").removePrefix("git@github.com:")
|
||||
.removeSuffix(".git")
|
||||
|
||||
val chromeVersion = rootProject.layout.projectDirectory.file("chrome.version").asFile.readText().trim()
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "moe.tarsin.ehviewer"
|
||||
versionCode = 180063
|
||||
versionName = "1.14.5"
|
||||
versionName = "1.14.6"
|
||||
// versionNameSuffix = "-SNAPSHOT"
|
||||
buildConfigField("String", "RAW_VERSION_NAME", "\"$versionName${versionNameSuffix.orEmpty()}\"")
|
||||
buildConfigField("String", "COMMIT_SHA", "\"$commitSha\"")
|
||||
buildConfigField("long", "COMMIT_TIME", commitTime)
|
||||
buildConfigField("String", "REPO_NAME", "\"$repoName\"")
|
||||
buildConfigField("String", "CHROME_VERSION", "\"$chromeVersion\"")
|
||||
ndk {
|
||||
if (isRelease) {
|
||||
abiFilters.addAll(supportedAbis)
|
||||
@@ -179,10 +176,7 @@ dependencies {
|
||||
implementation(libs.androidx.appcompat)
|
||||
implementation(libs.androidx.biometric)
|
||||
implementation(libs.androidx.browser)
|
||||
|
||||
// https://developer.android.com/jetpack/androidx/releases/compose-material3
|
||||
api(platform(libs.compose.bom))
|
||||
implementation(libs.bundles.compose)
|
||||
implementation(libs.androidx.webkit)
|
||||
|
||||
implementation(libs.compose.destinations.core)
|
||||
ksp(libs.compose.destinations.compiler)
|
||||
|
||||
@@ -5,16 +5,19 @@ include(FetchContent)
|
||||
|
||||
if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
string(CONCAT CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -ffast-math -fvisibility=hidden -fvisibility-inlines-hidden -funroll-loops -flto "
|
||||
"-mllvm -polly "
|
||||
"-mllvm -polly-run-dce "
|
||||
"-mllvm -polly-run-inliner "
|
||||
"-mllvm -polly-isl-arg=--no-schedule-serialize-sccs "
|
||||
"-mllvm -polly-ast-use-context "
|
||||
"-mllvm -polly-detect-keep-going "
|
||||
"-mllvm -polly-position=before-vectorizer "
|
||||
"-mllvm -polly-vectorizer=stripmine "
|
||||
"-mllvm -polly-detect-profitability-min-per-loop-insts=40 "
|
||||
"-mllvm -polly-invariant-load-hoisting")
|
||||
"-ffile-prefix-map=${ANDROID_TOOLCHAIN_ROOT}= "
|
||||
"-ffile-prefix-map=${CMAKE_SOURCE_DIR}= "
|
||||
"-ffile-prefix-map=${CMAKE_BINARY_DIR}= "
|
||||
"-mllvm -polly "
|
||||
"-mllvm -polly-run-dce "
|
||||
"-mllvm -polly-run-inliner "
|
||||
"-mllvm -polly-isl-arg=--no-schedule-serialize-sccs "
|
||||
"-mllvm -polly-ast-use-context "
|
||||
"-mllvm -polly-detect-keep-going "
|
||||
"-mllvm -polly-position=before-vectorizer "
|
||||
"-mllvm -polly-vectorizer=stripmine "
|
||||
"-mllvm -polly-detect-profitability-min-per-loop-insts=40 "
|
||||
"-mllvm -polly-invariant-load-hoisting")
|
||||
endif (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
|
||||
option(BUILD_TESTING OFF)
|
||||
@@ -38,23 +41,25 @@ include_directories(${liblzma_SOURCE_DIR}/src/liblzma/api)
|
||||
|
||||
# Build GNUTLS libnettle
|
||||
if (CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
|
||||
execute_process(
|
||||
COMMAND wsl wslpath ${CMAKE_CURRENT_LIST_DIR}
|
||||
OUTPUT_VARIABLE CURRENT_DIR
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
set(NDK_VERSION "${ANDROID_NDK_MAJOR}.${ANDROID_NDK_MINOR}.${ANDROID_NDK_BUILD}")
|
||||
set(TOOLCHAIN "$ANDROID_HOME/ndk/${NDK_VERSION}/toolchains/llvm/prebuilt/linux-x86_64/bin")
|
||||
set(WSL wsl)
|
||||
else ()
|
||||
set(CURRENT_DIR ${CMAKE_CURRENT_LIST_DIR})
|
||||
set(TOOLCHAIN "${ANDROID_TOOLCHAIN_ROOT}/bin")
|
||||
endif ()
|
||||
set(NDK_VERSION "${ANDROID_NDK_MAJOR}.${ANDROID_NDK_MINOR}.${ANDROID_NDK_BUILD}")
|
||||
set(CONFIGURE_COMMAND ./configure --disable-public-key --disable-dependency-tracking
|
||||
"--host=${CMAKE_C_COMPILER_TARGET}"
|
||||
"CFLAGS=${CMAKE_C_FLAGS} -Qunused-arguments"
|
||||
"AR=${TOOLCHAIN}/llvm-ar"
|
||||
"CC=${TOOLCHAIN}/clang --target=${CMAKE_C_COMPILER_TARGET}"
|
||||
"RANLIB=${TOOLCHAIN}/llvm-ranlib"
|
||||
)
|
||||
ExternalProject_Add(
|
||||
nettle
|
||||
GIT_REPOSITORY https://gitlab.com/gnutls/nettle.git
|
||||
GIT_TAG nettle_3.10.2_release_20250626
|
||||
GIT_SHALLOW 1
|
||||
GIT_CONFIG core.autocrlf=input
|
||||
CONFIGURE_COMMAND bash ${CURRENT_DIR}/configure_nettle.sh ${NDK_VERSION} ${CMAKE_C_COMPILER_TARGET}
|
||||
BUILD_COMMAND bash -c "make -j4 libnettle.a CFLAGS='${CMAKE_C_FLAGS} -Qunused-arguments'"
|
||||
URL https://ftpmirror.gnu.org/nettle/nettle-3.10.2.tar.gz
|
||||
URL_MD5 b28bcbf6f045ff007940a9401673600d
|
||||
CONFIGURE_COMMAND ${WSL} ${CONFIGURE_COMMAND}
|
||||
BUILD_COMMAND ${WSL} make -j4 libnettle.a
|
||||
INSTALL_COMMAND ""
|
||||
BUILD_IN_SOURCE 1
|
||||
BUILD_BYPRODUCTS <SOURCE_DIR>/libnettle.a
|
||||
@@ -96,7 +101,7 @@ set(LIBARCHIVE_PATCH
|
||||
FetchContent_Declare(
|
||||
libarchive
|
||||
GIT_REPOSITORY https://github.com/libarchive/libarchive.git
|
||||
GIT_TAG v3.8.2
|
||||
GIT_TAG v3.8.4
|
||||
GIT_SHALLOW 1
|
||||
PATCH_COMMAND git apply --check -R ${LIBARCHIVE_PATCH} || git apply ${LIBARCHIVE_PATCH}
|
||||
)
|
||||
@@ -134,7 +139,7 @@ unset(Rust_TOOLCHAIN CACHE)
|
||||
FetchContent_Declare(
|
||||
Corrosion
|
||||
GIT_REPOSITORY https://github.com/corrosion-rs/corrosion.git
|
||||
GIT_TAG v0.5.2
|
||||
GIT_TAG v0.6
|
||||
GIT_SHALLOW 1
|
||||
)
|
||||
|
||||
@@ -145,7 +150,7 @@ corrosion_import_crate(
|
||||
FEATURES $<IF:$<VERSION_GREATER_EQUAL:${ANDROID_NATIVE_API_LEVEL},26>,android-26,android>
|
||||
FLAGS $<$<NOT:$<CONFIG:Debug>>:-Z build-std -Z build-std-features=>
|
||||
)
|
||||
corrosion_add_target_rustflags(ehviewer_rust $<$<NOT:$<CONFIG:Debug>>:-Z unstable-options -C panic=immediate-abort>)
|
||||
corrosion_add_target_rustflags(ehviewer_rust $<$<NOT:$<CONFIG:Debug>>:-Z unstable-options -C panic=immediate-abort -Z location-detail=none -Z fmt-debug=none>)
|
||||
corrosion_link_libraries(ehviewer_rust android jnigraphics log webp webpdemux)
|
||||
|
||||
# Build and link our app's native lib
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
SUFFIX=toolchains/llvm/prebuilt/$(uname -s | tr '[:upper:]' '[:lower:]')-x86_64/bin
|
||||
CI_NDK_LOCATION=$ANDROID_HOME/ndk/$1/$SUFFIX
|
||||
ARCH_NDK_LOCATION=$ANDROID_HOME/ndk-bundle/$SUFFIX
|
||||
if test -e $CI_NDK_LOCATION ;then
|
||||
TOOLCHAIN=$CI_NDK_LOCATION
|
||||
else
|
||||
TOOLCHAIN=$ARCH_NDK_LOCATION
|
||||
fi
|
||||
TARGET=$2
|
||||
./.bootstrap && ./configure --host=$TARGET --disable-public-key --disable-dependency-tracking \
|
||||
AR=$TOOLCHAIN/llvm-ar \
|
||||
CC="$TOOLCHAIN/clang -target $TARGET" \
|
||||
RANLIB=$TOOLCHAIN/llvm-ranlib
|
||||
@@ -180,7 +180,6 @@ fun WebView(
|
||||
is WebContent.Url -> {
|
||||
wv.loadUrl(content.url, content.additionalHttpHeaders)
|
||||
}
|
||||
|
||||
is WebContent.Data -> {
|
||||
wv.loadDataWithBaseURL(
|
||||
content.baseUrl,
|
||||
@@ -190,14 +189,12 @@ fun WebView(
|
||||
content.historyUrl,
|
||||
)
|
||||
}
|
||||
|
||||
is WebContent.Post -> {
|
||||
wv.postUrl(
|
||||
content.url,
|
||||
content.postData,
|
||||
)
|
||||
}
|
||||
|
||||
is WebContent.NavigatorOnly -> {
|
||||
// NO-OP
|
||||
}
|
||||
@@ -502,11 +499,9 @@ class WebViewNavigator(private val coroutineScope: CoroutineScope) {
|
||||
event.encoding,
|
||||
event.historyUrl,
|
||||
)
|
||||
|
||||
is NavigationEvent.LoadUrl -> {
|
||||
loadUrl(event.url, event.additionalHttpHeaders)
|
||||
}
|
||||
|
||||
is NavigationEvent.PostUrl -> {
|
||||
postUrl(event.url, event.postData)
|
||||
}
|
||||
|
||||
@@ -39,12 +39,12 @@ import coil3.request.crossfade
|
||||
import coil3.serviceLoaderEnabled
|
||||
import coil3.util.DebugLogger
|
||||
import com.ehviewer.core.database.SearchDatabase
|
||||
import com.ehviewer.core.database.roomDb
|
||||
import com.ehviewer.core.files.deleteContent
|
||||
import com.ehviewer.core.ui.util.initSETConnection
|
||||
import com.ehviewer.core.util.isAtLeastO
|
||||
import com.ehviewer.core.util.isAtLeastP
|
||||
import com.ehviewer.core.util.isAtLeastS
|
||||
import com.ehviewer.core.util.isAtLeastSExtension7
|
||||
import com.ehviewer.core.util.launchIO
|
||||
import com.ehviewer.core.util.logcat
|
||||
import com.ehviewer.core.util.withUIContext
|
||||
@@ -65,6 +65,7 @@ import com.hippo.ehviewer.ktbuilder.imageLoader
|
||||
import com.hippo.ehviewer.ktor.Cronet
|
||||
import com.hippo.ehviewer.ktor.configureClient
|
||||
import com.hippo.ehviewer.ktor.configureCommon
|
||||
import com.hippo.ehviewer.ktor.isCronetAvailable
|
||||
import com.hippo.ehviewer.ui.keepNoMediaFileStatus
|
||||
import com.hippo.ehviewer.ui.lockObserver
|
||||
import com.hippo.ehviewer.ui.screen.detailCache
|
||||
@@ -83,7 +84,6 @@ import logcat.LogPriority
|
||||
import logcat.LogcatLogger
|
||||
import logcat.asLog
|
||||
import okio.Path.Companion.toOkioPath
|
||||
import splitties.arch.room.roomDb
|
||||
import splitties.init.appCtx
|
||||
|
||||
private val lifecycle = ProcessLifecycleOwner.get().lifecycle
|
||||
@@ -146,6 +146,8 @@ class EhApplication : Application(), SingletonImageLoader.Factory {
|
||||
if (BuildConfig.DEBUG) {
|
||||
StrictMode.enableDefaults()
|
||||
Composer.setDiagnosticStackTraceMode(ComposeStackTraceMode.SourceInformation)
|
||||
} else {
|
||||
Composer.setDiagnosticStackTraceMode(ComposeStackTraceMode.Auto)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,7 +220,7 @@ class EhApplication : Application(), SingletonImageLoader.Factory {
|
||||
private set
|
||||
|
||||
val ktorClient by lazy {
|
||||
if (isAtLeastSExtension7 && Settings.enableCronet.value) {
|
||||
if (isCronetAvailable && Settings.enableCronet.value) {
|
||||
HttpClient(Cronet) {
|
||||
engine { configureClient(Settings.enableQuic.value) }
|
||||
configureCommon()
|
||||
|
||||
@@ -15,13 +15,14 @@
|
||||
*/
|
||||
package com.hippo.ehviewer
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import androidx.room.execSQL
|
||||
import androidx.room.useWriterConnection
|
||||
import arrow.fx.coroutines.resource
|
||||
import arrow.fx.coroutines.resourceScope
|
||||
import com.ehviewer.core.data.model.asEntity
|
||||
import com.ehviewer.core.database.EhDatabase
|
||||
import com.ehviewer.core.database.Schema17to18
|
||||
import com.ehviewer.core.database.getDatabasePath
|
||||
import com.ehviewer.core.database.model.DownloadArtist
|
||||
import com.ehviewer.core.database.model.DownloadDirname
|
||||
import com.ehviewer.core.database.model.DownloadInfo
|
||||
@@ -32,13 +33,13 @@ import com.ehviewer.core.database.model.HistoryInfo
|
||||
import com.ehviewer.core.database.model.LocalFavoriteInfo
|
||||
import com.ehviewer.core.database.model.ProgressInfo
|
||||
import com.ehviewer.core.database.model.QuickSearch
|
||||
import com.ehviewer.core.database.roomDb
|
||||
import com.ehviewer.core.files.delete
|
||||
import com.ehviewer.core.files.sendTo
|
||||
import com.ehviewer.core.model.GalleryInfo
|
||||
import com.hippo.ehviewer.download.DownloadManager
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import okio.Path
|
||||
import okio.Path.Companion.toOkioPath
|
||||
import splitties.arch.room.roomDb
|
||||
|
||||
object EhDB {
|
||||
private const val DB_NAME = "eh.db"
|
||||
@@ -277,23 +278,26 @@ object EhDB {
|
||||
db.filterDao().update(filter)
|
||||
}
|
||||
|
||||
fun exportDB(context: Context, file: Path) {
|
||||
db.query("PRAGMA wal_checkpoint(FULL)", null).use { it.moveToNext() }
|
||||
val dbFile = context.getDatabasePath(DB_NAME)
|
||||
dbFile.toOkioPath() sendTo file
|
||||
suspend fun exportDB(file: Path) {
|
||||
db.useWriterConnection { conn ->
|
||||
conn.execSQL("PRAGMA wal_checkpoint(FULL)")
|
||||
conn.execSQL("VACUUM")
|
||||
}
|
||||
val dbFile = getDatabasePath(DB_NAME)
|
||||
dbFile sendTo file
|
||||
}
|
||||
|
||||
suspend fun importDB(context: Context, uri: Uri) = resourceScope {
|
||||
suspend fun importDB(file: Path) = resourceScope {
|
||||
val tempDBName = "tmp.db"
|
||||
val dbFile = getDatabasePath(tempDBName)
|
||||
file sendTo dbFile
|
||||
val oldDB = resource {
|
||||
context.deleteDatabase(tempDBName)
|
||||
roomDb<EhDatabase>(tempDBName) {
|
||||
createFromInputStream { context.contentResolver.openInputStream(uri) }
|
||||
addMigrations(Schema17to18())
|
||||
}
|
||||
} release { db ->
|
||||
db.close()
|
||||
context.deleteDatabase(tempDBName)
|
||||
dbFile.delete()
|
||||
}
|
||||
|
||||
db.galleryDao().insertOrIgnore(oldDB.galleryDao().list())
|
||||
|
||||
@@ -9,10 +9,10 @@ import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.remember
|
||||
import com.ehviewer.core.network.EhCookieStore
|
||||
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
|
||||
import com.hippo.ehviewer.download.SortMode
|
||||
@@ -82,6 +82,7 @@ object Settings : DataStorePreferences(null) {
|
||||
val detailSize = intPref("detail_size_2", 0)
|
||||
val thumbColumns = intPref("thumb_columns", 3)
|
||||
val showGalleryPages = boolPref("show_gallery_pages", true)
|
||||
val showReadingProgress = boolPref("show_reading_progress", false)
|
||||
val showVoteStatus = boolPref("show_vote_status", false)
|
||||
val showComments = boolPref("show_gallery_comments", true)
|
||||
val commentThreshold = intPref("comment_threshold", -100)
|
||||
|
||||
@@ -24,6 +24,7 @@ import arrow.fx.coroutines.parZip
|
||||
import com.ehviewer.core.i18n.R
|
||||
import com.ehviewer.core.model.BaseGalleryInfo
|
||||
import com.ehviewer.core.model.GalleryInfo
|
||||
import com.ehviewer.core.network.EhCookieStore
|
||||
import com.ehviewer.core.util.logcat
|
||||
import com.hippo.ehviewer.EhDB
|
||||
import com.hippo.ehviewer.Settings
|
||||
@@ -31,6 +32,7 @@ import com.hippo.ehviewer.client.data.FavListUrlBuilder
|
||||
import com.hippo.ehviewer.client.data.fillInfo
|
||||
import com.hippo.ehviewer.client.data.filterComments
|
||||
import com.hippo.ehviewer.client.exception.CloudflareBypassException
|
||||
import com.hippo.ehviewer.client.exception.EhError
|
||||
import com.hippo.ehviewer.client.exception.EhException
|
||||
import com.hippo.ehviewer.client.exception.InsufficientFundsException
|
||||
import com.hippo.ehviewer.client.exception.InsufficientGpException
|
||||
@@ -69,6 +71,7 @@ import io.ktor.client.statement.HttpStatement
|
||||
import io.ktor.client.statement.bodyAsChannel
|
||||
import io.ktor.client.statement.request
|
||||
import io.ktor.http.Url
|
||||
import io.ktor.util.moveToByteArray
|
||||
import io.ktor.utils.io.pool.DirectByteBufferPool
|
||||
import io.ktor.utils.io.pool.useInstance
|
||||
import io.ktor.utils.io.readAvailable
|
||||
@@ -79,6 +82,8 @@ import kotlin.system.measureTimeMillis
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.serialization.SerializationException
|
||||
import kotlinx.serialization.cbor.Cbor
|
||||
import kotlinx.serialization.decodeFromByteArray
|
||||
import kotlinx.serialization.json.add
|
||||
import kotlinx.serialization.json.addJsonArray
|
||||
import kotlinx.serialization.json.put
|
||||
@@ -127,27 +132,30 @@ private fun rethrowExactly(response: HttpResponse, body: Either<String, ByteBuff
|
||||
throw IpBannedException(message)
|
||||
}
|
||||
|
||||
// Check parse error thrown by rust
|
||||
val cause = e.cause
|
||||
if (e is ParseException && cause is RuntimeException) {
|
||||
when (val message = cause.message) {
|
||||
"0" -> throw NoHitsFoundException()
|
||||
"1" -> throw EhException(R.string.gallery_list_empty_hit_subscription)
|
||||
"2" -> throw NotLoggedInException()
|
||||
"3" -> throw NoHathClientException()
|
||||
"4" -> throw InsufficientFundsException()
|
||||
is String if message.isNotEmpty() -> {
|
||||
when (message[0]) {
|
||||
'5' -> throw IpBannedException(message.substring(1))
|
||||
'6' -> throw EhException(message.substring(1))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Parse error from rust
|
||||
val error = body.getOrNull()?.runCatching {
|
||||
val array = moveToByteArray()
|
||||
rewind()
|
||||
Cbor.decodeFromByteArray<EhError>(array)
|
||||
}?.getOrNull()
|
||||
|
||||
// Check Gallery Not Available - 404
|
||||
if (error is EhError.GalleryUnavailable) throw EhException(error.message)
|
||||
|
||||
// Check bad response code
|
||||
response.status.ensureSuccess()
|
||||
|
||||
when (error) {
|
||||
EhError.NoHits -> throw NoHitsFoundException()
|
||||
EhError.NoWatched -> throw EhException(R.string.gallery_list_empty_hit_subscription)
|
||||
EhError.NeedLogin -> throw NotLoggedInException()
|
||||
EhError.NoHathClient -> throw NoHathClientException()
|
||||
EhError.InsufficientFunds -> throw InsufficientFundsException()
|
||||
is EhError.IpBanned -> throw IpBannedException(error.message)
|
||||
is EhError.Error -> throw EhException(error.message)
|
||||
else -> Unit
|
||||
}
|
||||
|
||||
if (e is ParseException || e is SerializationException) {
|
||||
body.onLeft { if ("<" !in it) throw IpBannedException(it) }
|
||||
if (Settings.saveParseErrorBody.value) body.saveParseError(e)
|
||||
|
||||
@@ -20,15 +20,19 @@ import android.content.ActivityNotFoundException
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Environment
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.ReadOnlyComposable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.core.net.toUri
|
||||
import arrow.core.memoize
|
||||
import com.ehviewer.core.model.GalleryDetail
|
||||
import com.ehviewer.core.model.GalleryInfo
|
||||
import com.ehviewer.core.network.EhCookieStore
|
||||
import com.ehviewer.core.util.withUIContext
|
||||
import com.hippo.ehviewer.Settings
|
||||
import com.hippo.ehviewer.client.parser.Archive
|
||||
@@ -39,6 +43,7 @@ import com.hippo.ehviewer.util.addTextToClipboard
|
||||
import com.materialkolor.hct.Hct
|
||||
import com.materialkolor.ktx.from
|
||||
import com.materialkolor.ktx.toColor
|
||||
import com.materialkolor.utils.ColorUtils.lstarFromArgb
|
||||
import splitties.systemservices.downloadManager
|
||||
|
||||
object EhUtils {
|
||||
@@ -151,7 +156,13 @@ object EhUtils {
|
||||
}
|
||||
}
|
||||
|
||||
val categoryTextColor = Color(0xffe6e0e9)
|
||||
@ReadOnlyComposable
|
||||
@Composable
|
||||
fun getCategoryTextColor(color: Color) = if (isSystemInDarkTheme() == lstarFromArgb(color.toArgb()) > 70) {
|
||||
MaterialTheme.colorScheme.surface
|
||||
} else {
|
||||
LocalContentColor.current
|
||||
}
|
||||
|
||||
val favoriteIconColor = Color(0xffff3040)
|
||||
|
||||
|
||||
@@ -212,7 +212,6 @@ data class ListUrlBuilder(
|
||||
}
|
||||
}
|
||||
}.buildString()
|
||||
|
||||
MODE_UPLOADER, MODE_TAG -> {
|
||||
val path = if (mode == MODE_UPLOADER) "uploader" else "tag"
|
||||
ehUrl(listOf(path, requireNotNull(mKeyword))) {
|
||||
@@ -222,7 +221,6 @@ data class ListUrlBuilder(
|
||||
addQueryParameterIfNotBlank("range", range.takeIf { it > 0 }?.toString())
|
||||
}.buildString()
|
||||
}
|
||||
|
||||
MODE_WHATS_HOT -> EhUrl.popularUrl
|
||||
MODE_IMAGE_SEARCH -> ehUrl {
|
||||
addQueryParameter("f_shash", requireNotNull(hash))
|
||||
@@ -231,7 +229,6 @@ data class ListUrlBuilder(
|
||||
addQueryParameter("tl", requireNotNull(mKeyword))
|
||||
addQueryParameterIfNotBlank("p", jumpTo)
|
||||
}.buildString()
|
||||
|
||||
else -> throw IllegalStateException("Unexpected value: $mode")
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.hippo.ehviewer.client.exception
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.cbor.CborArray
|
||||
|
||||
@Serializable
|
||||
sealed interface EhError {
|
||||
@CborArray
|
||||
@Serializable
|
||||
@SerialName("NoHits")
|
||||
data object NoHits : EhError
|
||||
|
||||
@CborArray
|
||||
@Serializable
|
||||
@SerialName("NoWatched")
|
||||
data object NoWatched : EhError
|
||||
|
||||
@CborArray
|
||||
@Serializable
|
||||
@SerialName("NeedLogin")
|
||||
data object NeedLogin : EhError
|
||||
|
||||
@CborArray
|
||||
@Serializable
|
||||
@SerialName("NoHathClient")
|
||||
data object NoHathClient : EhError
|
||||
|
||||
@CborArray
|
||||
@Serializable
|
||||
@SerialName("InsufficientFunds")
|
||||
data object InsufficientFunds : EhError
|
||||
|
||||
@CborArray
|
||||
@Serializable
|
||||
@SerialName("GalleryUnavailable")
|
||||
data class GalleryUnavailable(val message: String) : EhError
|
||||
|
||||
@CborArray
|
||||
@Serializable
|
||||
@SerialName("IpBanned")
|
||||
data class IpBanned(val message: String) : EhError
|
||||
|
||||
@CborArray
|
||||
@Serializable
|
||||
@SerialName("Error")
|
||||
data class Error(val message: String) : EhError
|
||||
}
|
||||
@@ -26,7 +26,7 @@ object GalleryListUrlParser {
|
||||
fun parse(urlStr: String) = Either.catch {
|
||||
val url = Url(urlStr)
|
||||
if (url.host != EhUrl.DOMAIN_E && url.host != EhUrl.DOMAIN_EX) {
|
||||
return null
|
||||
return@catch null
|
||||
}
|
||||
val segments = url.segments
|
||||
if (segments.isEmpty()) {
|
||||
@@ -42,7 +42,6 @@ object GalleryListUrlParser {
|
||||
mode = if (head == "uploader") ListUrlBuilder.MODE_UPLOADER else ListUrlBuilder.MODE_TAG
|
||||
keyword = segments[1].decodeURLQueryComponent(plusIsSpace = true)
|
||||
}
|
||||
|
||||
"toplist.php" -> {
|
||||
val tl = url.parameters["tl"]
|
||||
if (tl != null && tl in arrayOf("11", "12", "13", "15")) {
|
||||
@@ -55,7 +54,6 @@ object GalleryListUrlParser {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
val category = EhUtils.getCategory(head)
|
||||
if (category != EhUtils.UNKNOWN) {
|
||||
|
||||
@@ -148,7 +148,7 @@ object DownloadManager : OnSpiderListener, CoroutineScope {
|
||||
mCurrentTask = info
|
||||
with(info) {
|
||||
archiveFile?.let {
|
||||
return onFinish(pages, pages, pages)
|
||||
return onFinish(pages, pages, pages, failed = false)
|
||||
}
|
||||
state = DownloadInfo.STATE_DOWNLOAD
|
||||
speed = -1
|
||||
@@ -682,7 +682,7 @@ object DownloadManager : OnSpiderListener, CoroutineScope {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFinish(finished: Int, downloaded: Int, total: Int) {
|
||||
override fun onFinish(finished: Int, downloaded: Int, total: Int, failed: Boolean) {
|
||||
launch {
|
||||
mSpeedReminder.onFinish()
|
||||
mCurrentSpider?.let { spider ->
|
||||
@@ -697,11 +697,7 @@ object DownloadManager : OnSpiderListener, CoroutineScope {
|
||||
info.downloaded = downloaded
|
||||
info.total = total
|
||||
info.legacy = total - finished
|
||||
if (info.legacy == 0) {
|
||||
info.state = DownloadInfo.STATE_FINISH
|
||||
} else {
|
||||
info.state = DownloadInfo.STATE_FAILED
|
||||
}
|
||||
info.state = if (failed) DownloadInfo.STATE_FAILED else DownloadInfo.STATE_FINISH
|
||||
EhDB.putDownloadInfo(info)
|
||||
mDownloadListener?.onFinish(info)
|
||||
mutableNotifyFlow.emit(info)
|
||||
|
||||
@@ -113,14 +113,12 @@ class DownloadService :
|
||||
val label = intent.getStringExtra(KEY_LABEL)
|
||||
deferredMgr.await().startDownload(decodeFromSavedState(gi), label)
|
||||
}
|
||||
|
||||
ACTION_START_RANGE -> {
|
||||
val gidList = intent.getLongArrayExtra(KEY_GID_LIST)
|
||||
if (gidList != null) {
|
||||
deferredMgr.await().startRangeDownload(gidList)
|
||||
}
|
||||
}
|
||||
|
||||
ACTION_START_ALL -> deferredMgr.await().startAllDownload()
|
||||
ACTION_STOP_ALL -> deferredMgr.await().stopAllDownload()
|
||||
ACTION_CLEAR -> clear()
|
||||
@@ -388,7 +386,6 @@ class DownloadService :
|
||||
notifyManager.notify(id, builder.build())
|
||||
}
|
||||
}
|
||||
|
||||
Ops.Cancel -> notifyManager.cancel(id)
|
||||
Ops.StartForeground -> service.startForeground(id, builder.build())
|
||||
}
|
||||
|
||||
@@ -130,7 +130,6 @@ class Image private constructor(image: CoilImage, private val src: ImageSource)
|
||||
}
|
||||
src.right().decodeCoil(checkExtraneousAds)
|
||||
}
|
||||
|
||||
is ByteBufferSource -> {
|
||||
if (isAtLeastP && !isAtLeastU) {
|
||||
rewriteGifSource(src.source)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.hippo.ehviewer.ktor
|
||||
|
||||
import com.hippo.ehviewer.BuildConfig
|
||||
import androidx.webkit.WebViewCompat
|
||||
import com.ehviewer.core.network.EhCookieStore
|
||||
import com.hippo.ehviewer.Settings
|
||||
import com.hippo.ehviewer.client.EhCookieStore
|
||||
import io.ktor.client.HttpClientConfig
|
||||
import io.ktor.client.engine.HttpClientEngineConfig
|
||||
import io.ktor.client.plugins.HttpTimeout
|
||||
@@ -14,9 +14,12 @@ import io.ktor.client.request.header
|
||||
import io.ktor.http.HttpHeaders
|
||||
import io.ktor.http.userAgent
|
||||
import io.ktor.util.appendIfNameAbsent
|
||||
import splitties.init.appCtx
|
||||
|
||||
const val CHROME_MOBILE_USER_AGENT = "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${BuildConfig.CHROME_VERSION}.0.0.0 Mobile Safari/537.36"
|
||||
private const val CHROME_USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${BuildConfig.CHROME_VERSION}.0.0.0 Safari/537.36"
|
||||
// It's safe to assume the WebView package will always be present as we require CookieManager anyway
|
||||
private val WebViewVersion = WebViewCompat.getCurrentWebViewPackage(appCtx)!!.versionName!!.substringBefore('.')
|
||||
val CHROME_MOBILE_USER_AGENT = "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/$WebViewVersion.0.0.0 Mobile Safari/537.36"
|
||||
private val CHROME_USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/$WebViewVersion.0.0.0 Safari/537.36"
|
||||
private const val CHROME_ACCEPT = "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"
|
||||
private const val CHROME_ACCEPT_LANGUAGE = "en-US,en;q=0.9"
|
||||
|
||||
|
||||
@@ -10,9 +10,6 @@ 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
|
||||
import io.ktor.client.engine.callContext
|
||||
import io.ktor.client.plugins.HttpTimeoutCapability
|
||||
@@ -103,15 +100,6 @@ class CronetEngine(override val config: CronetConfig) : HttpClientEngineBase("Cr
|
||||
}
|
||||
|
||||
override fun onFailed(request: UrlRequest, info: UrlResponseInfo?, error: HttpException) {
|
||||
// Cronet may crash on some devices, fuck xiaomi
|
||||
// https://github.com/FooIbar/EhViewer/issues/1826
|
||||
val message = error.message.orEmpty()
|
||||
if ("ERR_FILE_NOT_FOUND" in message || "ERR_PROXY_CONNECTION_FAILED" in message) {
|
||||
Settings.edit(true) {
|
||||
it[enableCronet] = false
|
||||
}
|
||||
with(config.context) { restartApplication() }
|
||||
}
|
||||
if (continuation.isActive) {
|
||||
continuation.resumeWithException(error)
|
||||
} else {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
@file:RequiresExtension(extension = Build.VERSION_CODES.S, version = 7)
|
||||
|
||||
package com.hippo.ehviewer.ktor
|
||||
|
||||
import android.net.http.HttpEngine
|
||||
import android.os.Build
|
||||
import androidx.annotation.RequiresExtension
|
||||
import com.ehviewer.core.util.isAtLeastSExtension7
|
||||
import java.io.File
|
||||
|
||||
@RequiresExtension(extension = Build.VERSION_CODES.S, version = 7)
|
||||
fun CronetConfig.configureClient(enableQuic: Boolean) {
|
||||
config = {
|
||||
setEnableBrotli(true)
|
||||
@@ -24,3 +24,14 @@ fun CronetConfig.configureClient(enableQuic: Boolean) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val isCronetAvailable: Boolean
|
||||
get() = isAtLeastSExtension7 && !isDeviceBlocked
|
||||
|
||||
// https://github.com/FooIbar/EhViewer/issues/1826
|
||||
private val isDeviceBlocked = when (Build.VERSION.INCREMENTAL.substringBefore('.')) {
|
||||
"V816", // HyperOS 1
|
||||
"OS2", // HyperOS 2
|
||||
-> true
|
||||
else -> false
|
||||
}
|
||||
@@ -68,7 +68,6 @@ fun GalleryInfo.getComicInfo(): ComicInfo {
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
else -> simpleTags?.forEach { tagString ->
|
||||
val (namespace, tag) = tagString.split(':', limit = 2)
|
||||
.takeIf { it.size == 2 } ?: return@forEach // Ignore temp tags that don't have namespace
|
||||
|
||||
@@ -56,7 +56,6 @@ import io.ktor.client.statement.request
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import kotlin.concurrent.read
|
||||
import kotlin.concurrent.write
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import okio.Path
|
||||
|
||||
class SpiderDen(val info: GalleryInfo) {
|
||||
@@ -129,11 +128,9 @@ class SpiderDen(val info: GalleryInfo) {
|
||||
SpiderQueen.MODE_READ -> {
|
||||
containInCache(index) || containInDownloadDir(index)
|
||||
}
|
||||
|
||||
SpiderQueen.MODE_DOWNLOAD -> {
|
||||
containInDownloadDir(index) || copyFromCacheToDownloadDir(index)
|
||||
}
|
||||
|
||||
else -> {
|
||||
false
|
||||
}
|
||||
@@ -270,22 +267,18 @@ class SpiderDen(val info: GalleryInfo) {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun archive() {
|
||||
if (saveAsCbz) {
|
||||
downloadDir?.run {
|
||||
resolve(archiveName).let { file ->
|
||||
runCatching {
|
||||
archiveTo(file)
|
||||
}.onFailure {
|
||||
file.delete()
|
||||
if (it is CancellationException) throw it
|
||||
logcat(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
suspend fun archive() = saveAsCbz && downloadDir?.run {
|
||||
resolve(archiveName).let { file ->
|
||||
runCatching {
|
||||
archiveTo(file)
|
||||
}.onFailure {
|
||||
file.delete()
|
||||
logcat(it)
|
||||
}.isFailure
|
||||
}
|
||||
}
|
||||
} == true
|
||||
|
||||
// Postpone this to `SpiderQueen.stop` because files may still be in use by reader
|
||||
suspend fun postArchive(): Boolean {
|
||||
val dir = downloadDir
|
||||
val archived = saveAsCbz && dir?.find(archiveName) != null
|
||||
|
||||
@@ -134,13 +134,14 @@ class SpiderQueen private constructor(val galleryInfo: GalleryInfo) : CoroutineS
|
||||
}
|
||||
}
|
||||
|
||||
private fun notifyAllPageDownloaded() {
|
||||
private fun notifyAllPageDownloaded(failed: Boolean) {
|
||||
synchronized(mSpiderListeners) {
|
||||
mSpiderListeners.forEach {
|
||||
it.onFinish(
|
||||
mFinishedPages.load(),
|
||||
mDownloadedPages.load(),
|
||||
pageStates.size,
|
||||
failed,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -213,7 +214,10 @@ class SpiderQueen private constructor(val galleryInfo: GalleryInfo) : CoroutineS
|
||||
|
||||
private val prepareScope = CoroutineScope(coroutineContext + SupervisorJob())
|
||||
private val prepareJob = prepareScope.async { doPrepare() }
|
||||
private val archiveJob = launch(start = CoroutineStart.LAZY) { spiderDen.archive() }
|
||||
private val archiveJob = launch(start = CoroutineStart.LAZY) {
|
||||
val failed = spiderDen.archive()
|
||||
notifyAllPageDownloaded(failed)
|
||||
}
|
||||
|
||||
private suspend fun doPrepare() {
|
||||
spiderDen.initDownloadDirIfExist()
|
||||
@@ -400,8 +404,11 @@ class SpiderQueen private constructor(val galleryInfo: GalleryInfo) : CoroutineS
|
||||
notifyPageSuccess(index)
|
||||
}
|
||||
if (mDownloadedPages.load() == size) {
|
||||
if (mFinishedPages.load() == size) archiveJob.start()
|
||||
notifyAllPageDownloaded()
|
||||
if (mFinishedPages.load() == size) {
|
||||
archiveJob.start()
|
||||
} else {
|
||||
notifyAllPageDownloaded(failed = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -418,7 +425,7 @@ class SpiderQueen private constructor(val galleryInfo: GalleryInfo) : CoroutineS
|
||||
fun onPageDownload(index: Int, contentLength: Long, receivedSize: Long, bytesRead: Int) {}
|
||||
fun onPageSuccess(index: Int, finished: Int, downloaded: Int, total: Int) {}
|
||||
fun onPageFailure(index: Int, error: String?, finished: Int, downloaded: Int, total: Int) {}
|
||||
fun onFinish(finished: Int, downloaded: Int, total: Int) {}
|
||||
fun onFinish(finished: Int, downloaded: Int, total: Int, failed: Boolean) {}
|
||||
fun onPageReady(index: Int) {}
|
||||
}
|
||||
|
||||
|
||||
@@ -233,7 +233,6 @@ private suspend fun doModifyFavorites(
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
LOCAL_FAVORITED -> {
|
||||
if (localFavorited) {
|
||||
EhDB.removeLocalFavorites(galleryInfo)
|
||||
@@ -248,7 +247,6 @@ private suspend fun doModifyFavorites(
|
||||
}
|
||||
!localFavorited
|
||||
}
|
||||
|
||||
in 0..9 -> {
|
||||
EhEngine.modifyFavorites(gid, token, slot, note)
|
||||
favoriteSlot = slot
|
||||
@@ -256,7 +254,6 @@ private suspend fun doModifyFavorites(
|
||||
favoriteNote = note
|
||||
true
|
||||
}
|
||||
|
||||
else -> throw EhException("Invalid favorite slot!")
|
||||
}
|
||||
FavouriteStatusRouter.notify(galleryInfo)
|
||||
@@ -305,13 +302,11 @@ suspend fun doGalleryInfoAction(info: BaseGalleryInfo) {
|
||||
EhDB.putHistoryInfo(info)
|
||||
navToReader(info)
|
||||
}
|
||||
|
||||
1 -> if (downloaded) {
|
||||
confirmRemoveDownload(info)
|
||||
} else {
|
||||
startDownload(false, info)
|
||||
}
|
||||
|
||||
2 -> if (favorited) {
|
||||
runSuspendCatching {
|
||||
removeFromFavorites(info)
|
||||
@@ -327,7 +322,6 @@ suspend fun doGalleryInfoAction(info: BaseGalleryInfo) {
|
||||
tip(R.string.add_to_favorite_failure)
|
||||
}
|
||||
}
|
||||
|
||||
3 -> showMoveDownloadLabel(info)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package com.hippo.ehviewer.ui.login
|
||||
|
||||
import arrow.core.Either.Companion.catch
|
||||
import com.ehviewer.core.network.EhCookieStore
|
||||
import com.ehviewer.core.util.logcat
|
||||
import com.hippo.ehviewer.Settings
|
||||
import com.hippo.ehviewer.client.EhCookieStore
|
||||
import com.hippo.ehviewer.client.EhEngine
|
||||
import com.hippo.ehviewer.client.EhUrl
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
||||
@@ -6,10 +6,10 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.snapshotFlow
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.ehviewer.core.network.EhCookieStore
|
||||
import com.google.accompanist.web.WebView
|
||||
import com.google.accompanist.web.rememberWebViewState
|
||||
import com.hippo.ehviewer.Settings
|
||||
import com.hippo.ehviewer.client.EhCookieStore
|
||||
import com.hippo.ehviewer.client.EhUrl
|
||||
import com.hippo.ehviewer.client.EhUtils
|
||||
import com.hippo.ehviewer.ui.Screen
|
||||
|
||||
@@ -13,6 +13,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.DownloadDone
|
||||
import androidx.compose.material.icons.filled.Pause
|
||||
import androidx.compose.material.icons.filled.PlayArrow
|
||||
import androidx.compose.material3.Card
|
||||
@@ -26,6 +27,7 @@ import androidx.compose.material3.ShapeDefaults
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.minimumInteractiveComponentSize
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.movableContentOf
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
@@ -35,7 +37,6 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.clip
|
||||
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
|
||||
@@ -45,7 +46,7 @@ import com.ehviewer.core.ui.component.CrystalCard
|
||||
import com.ehviewer.core.ui.component.GalleryListCardRating
|
||||
import com.ehviewer.core.ui.util.TransitionsVisibilityScope
|
||||
import com.ehviewer.core.ui.util.listThumbGenerator
|
||||
import com.hippo.ehviewer.Settings
|
||||
import com.hippo.ehviewer.EhDB
|
||||
import com.hippo.ehviewer.client.EhUtils
|
||||
import com.hippo.ehviewer.download.DownloadManager
|
||||
import com.hippo.ehviewer.util.FileUtils
|
||||
@@ -60,6 +61,7 @@ fun DownloadCard(
|
||||
onStop: () -> Unit,
|
||||
info: DownloadInfo,
|
||||
selectMode: Boolean,
|
||||
showProgress: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||
) = CrystalCard(modifier = modifier, onClick = onClick, onLongClick = onLongClick, interactionSource = interactionSource) {
|
||||
@@ -99,7 +101,14 @@ fun DownloadCard(
|
||||
DownloadInfo.STATE_NONE -> stringResource(R.string.download_state_none)
|
||||
DownloadInfo.STATE_WAIT -> stringResource(R.string.download_state_wait)
|
||||
DownloadInfo.STATE_FAILED -> if (info.legacy <= 0) stateFailed else stateFailed2
|
||||
DownloadInfo.STATE_FINISH -> stringResource(R.string.download_state_finish)
|
||||
DownloadInfo.STATE_FINISH -> {
|
||||
if (showProgress) {
|
||||
val readProgress by remember { EhDB.getReadProgressFlow(info.gid) }.collectAsState(0)
|
||||
if (readProgress > 0) "${readProgress + 1}/${info.pages}P" else "${info.pages}P"
|
||||
} else {
|
||||
"${info.pages}P"
|
||||
}
|
||||
}
|
||||
else -> null // The item has been removed and this will be disposed soon
|
||||
}
|
||||
ProvideTextStyle(MaterialTheme.typography.labelLarge) {
|
||||
@@ -149,24 +158,24 @@ fun DownloadCard(
|
||||
Text(
|
||||
text = categoryText,
|
||||
modifier = Modifier.clip(ShapeDefaults.Small).background(categoryColor).padding(vertical = 2.dp, horizontal = 8.dp),
|
||||
color = if (Settings.harmonizeCategoryColor.value) Color.Unspecified else EhUtils.categoryTextColor,
|
||||
color = EhUtils.getCategoryTextColor(categoryColor),
|
||||
style = MaterialTheme.typography.labelLarge,
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
val running = downloadState == DownloadInfo.STATE_WAIT || downloadState == DownloadInfo.STATE_DOWNLOAD
|
||||
val icon = remember {
|
||||
movableContentOf<Boolean> {
|
||||
Icon(imageVector = if (it) Icons.Default.Pause else Icons.Default.PlayArrow, contentDescription = null)
|
||||
}
|
||||
val icon = when (downloadState) {
|
||||
DownloadInfo.STATE_WAIT, DownloadInfo.STATE_DOWNLOAD -> Icons.Default.Pause
|
||||
DownloadInfo.STATE_FINISH -> Icons.Default.DownloadDone
|
||||
else -> Icons.Default.PlayArrow
|
||||
}
|
||||
if (selectMode) {
|
||||
Box(modifier = Modifier.offset(4.dp).minimumInteractiveComponentSize()) {
|
||||
icon(running)
|
||||
Icon(imageVector = icon, contentDescription = null)
|
||||
}
|
||||
} else {
|
||||
IconButton(onClick = if (running) onStop else onStart, shapes = IconButtonDefaults.shapes(), modifier = Modifier.offset(4.dp)) {
|
||||
icon(running)
|
||||
Icon(imageVector = icon, contentDescription = null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,8 +23,8 @@ import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.ProvideTextStyle
|
||||
import androidx.compose.material3.ShapeDefaults
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.contentColorFor
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableFloatStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
@@ -33,7 +33,6 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.font.FontStyle
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -46,7 +45,7 @@ import com.ehviewer.core.ui.component.GalleryListCardRating
|
||||
import com.ehviewer.core.ui.util.SharedElementBox
|
||||
import com.ehviewer.core.ui.util.TransitionsVisibilityScope
|
||||
import com.ehviewer.core.ui.util.listThumbGenerator
|
||||
import com.hippo.ehviewer.Settings
|
||||
import com.hippo.ehviewer.EhDB
|
||||
import com.hippo.ehviewer.client.EhUtils
|
||||
import com.hippo.ehviewer.download.DownloadManager
|
||||
import com.hippo.ehviewer.util.FavouriteStatusRouter
|
||||
@@ -58,6 +57,7 @@ fun GalleryInfoListItem(
|
||||
onLongClick: () -> Unit,
|
||||
info: GalleryInfo,
|
||||
showPages: Boolean,
|
||||
showProgress: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
isInFavScene: Boolean = false,
|
||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||
@@ -126,7 +126,12 @@ fun GalleryInfoListItem(
|
||||
Text(text = it)
|
||||
}
|
||||
if (info.pages != 0 && showPages) {
|
||||
Text(text = "${info.pages}P")
|
||||
val readProgress = if (showProgress) {
|
||||
remember { EhDB.getReadProgressFlow(info.gid) }.collectAsState(0).value
|
||||
} else {
|
||||
0
|
||||
}
|
||||
Text(text = if (readProgress > 0) "${readProgress + 1}/${info.pages}P" else "${info.pages}P")
|
||||
}
|
||||
}
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
@@ -135,7 +140,7 @@ fun GalleryInfoListItem(
|
||||
Text(
|
||||
text = categoryText,
|
||||
modifier = Modifier.clip(ShapeDefaults.Small).background(categoryColor).padding(vertical = 2.dp, horizontal = 8.dp),
|
||||
color = if (Settings.harmonizeCategoryColor.value) Color.Unspecified else EhUtils.categoryTextColor,
|
||||
color = EhUtils.getCategoryTextColor(categoryColor),
|
||||
)
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Text(text = info.posted.orEmpty())
|
||||
@@ -154,6 +159,7 @@ fun GalleryInfoGridItem(
|
||||
modifier: Modifier = Modifier,
|
||||
showLanguage: Boolean = true,
|
||||
showPages: Boolean = true,
|
||||
showProgress: Boolean = true,
|
||||
showFavoriteStatus: Boolean = true,
|
||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||
) = ElevatedCard(
|
||||
@@ -187,11 +193,16 @@ fun GalleryInfoGridItem(
|
||||
Badge(
|
||||
modifier = Modifier.align(Alignment.TopEnd).widthIn(min = 32.dp).height(24.dp),
|
||||
containerColor = categoryColor,
|
||||
contentColor = if (Settings.harmonizeCategoryColor.value) contentColorFor(categoryColor) else EhUtils.categoryTextColor,
|
||||
contentColor = EhUtils.getCategoryTextColor(categoryColor),
|
||||
) {
|
||||
val shouldShowLanguage = showLanguage && info.simpleLanguage != null
|
||||
if (showPages && info.pages > 0) {
|
||||
Text(text = "${info.pages}")
|
||||
val readProgress = if (showProgress) {
|
||||
remember { EhDB.getReadProgressFlow(info.gid) }.collectAsState(0).value
|
||||
} else {
|
||||
0
|
||||
}
|
||||
Text(text = if (readProgress > 0) "${readProgress + 1}/${info.pages}" else "${info.pages}")
|
||||
if (shouldShowLanguage) {
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.plus
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.widthIn
|
||||
import androidx.compose.foundation.lazy.grid.GridCells
|
||||
@@ -196,7 +197,6 @@ fun GalleryList(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is LoadState.Error -> {
|
||||
Surface {
|
||||
ErrorTip(
|
||||
@@ -205,7 +205,6 @@ fun GalleryList(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
is LoadState.NotLoading -> if (data.itemCount == 0) {
|
||||
// Only for local favorites as empty gallery lists from network are treated as error
|
||||
ErrorTip(modifier = Modifier.widthIn(max = 228.dp), text = stringResource(id = R.string.gallery_list_empty_hit))
|
||||
|
||||
@@ -22,7 +22,6 @@ fun LoadStateIndicator(
|
||||
is LoadState.Loading -> {
|
||||
LinearWavyProgressIndicator(modifier = modifier)
|
||||
}
|
||||
|
||||
is LoadState.Error -> {
|
||||
Column(modifier = modifier, horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Text(text = state.error.displayString())
|
||||
@@ -31,6 +30,5 @@ fun LoadStateIndicator(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is LoadState.NotLoading -> Unit
|
||||
}
|
||||
@@ -204,20 +204,17 @@ private fun PageContainer(
|
||||
moveToNext()
|
||||
}
|
||||
}
|
||||
|
||||
NavigationRegion.PREV -> {
|
||||
val canPan = if (isRtl) panLeft(distance, bounds) else panRight(distance, bounds)
|
||||
if (!canPan) {
|
||||
moveToPrevious()
|
||||
}
|
||||
}
|
||||
|
||||
NavigationRegion.RIGHT -> {
|
||||
if (!panLeft(distance, bounds)) {
|
||||
if (isRtl) moveToPrevious() else moveToNext()
|
||||
}
|
||||
}
|
||||
|
||||
NavigationRegion.LEFT -> {
|
||||
if (!panRight(distance, bounds)) {
|
||||
if (isRtl) moveToNext() else moveToPrevious()
|
||||
|
||||
@@ -19,6 +19,7 @@ import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.only
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.plus
|
||||
import androidx.compose.foundation.layout.systemBars
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
@@ -146,6 +147,7 @@ fun AnimatedVisibilityScope.DownloadsScreen(navigator: DestinationsNavigator) =
|
||||
var gridView by Settings.gridView.asMutableState()
|
||||
var sortMode by Settings.downloadSortMode.asMutableState()
|
||||
val filterMode by Settings.downloadFilterMode.collectAsState { DownloadsFilterMode.from(it) }
|
||||
val showProgress by Settings.showReadingProgress.collectAsState()
|
||||
var filterState by rememberSerializable { mutableStateOf(DownloadsFilterState(filterMode, Settings.recentDownloadLabel.value)) }
|
||||
var invalidateKey by rememberSaveable { mutableStateOf(false) }
|
||||
var isLoading by rememberSaveable { mutableStateOf(true) }
|
||||
@@ -228,6 +230,7 @@ fun AnimatedVisibilityScope.DownloadsScreen(navigator: DestinationsNavigator) =
|
||||
fun switchLabel(label: String?) {
|
||||
Settings.recentDownloadLabel.value = label
|
||||
filterState = filterState.copy(label = label)
|
||||
fabHidden = false
|
||||
}
|
||||
|
||||
LaunchedEffect(filterState) {
|
||||
@@ -594,6 +597,7 @@ fun AnimatedVisibilityScope.DownloadsScreen(navigator: DestinationsNavigator) =
|
||||
info = info,
|
||||
modifier = Modifier.thenIf(animateItems) { animateItem() },
|
||||
showLanguage = false,
|
||||
showProgress = showProgress,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -633,6 +637,7 @@ fun AnimatedVisibilityScope.DownloadsScreen(navigator: DestinationsNavigator) =
|
||||
onStop = { launchIO { DownloadManager.stopDownload(info.gid) } },
|
||||
info = info,
|
||||
selectMode = selectMode,
|
||||
showProgress = showProgress,
|
||||
modifier = Modifier.height(height),
|
||||
interactionSource = interactionSource,
|
||||
)
|
||||
|
||||
@@ -104,6 +104,8 @@ fun AnimatedVisibilityScope.FavouritesScreen(navigator: DestinationsNavigator, v
|
||||
var urlBuilder by viewModel.urlBuilder
|
||||
var searchBarExpanded by rememberSaveable { mutableStateOf(false) }
|
||||
var searchBarOffsetY by remember { mutableIntStateOf(0) }
|
||||
var fabExpanded by remember { mutableStateOf(false) }
|
||||
var fabHidden by remember { mutableStateOf(false) }
|
||||
|
||||
// Derived State
|
||||
val keyword = urlBuilder.keyword
|
||||
@@ -163,6 +165,7 @@ fun AnimatedVisibilityScope.FavouritesScreen(navigator: DestinationsNavigator, v
|
||||
val newCat = index - 2
|
||||
refresh(FavListUrlBuilder(newCat))
|
||||
Settings.recentFavCat = newCat
|
||||
fabHidden = false
|
||||
launch { sheetState.close() }
|
||||
},
|
||||
colors = listItemOnDrawerColor(urlBuilder.favCat == index - 2),
|
||||
@@ -171,8 +174,6 @@ fun AnimatedVisibilityScope.FavouritesScreen(navigator: DestinationsNavigator, v
|
||||
}
|
||||
}
|
||||
|
||||
var fabExpanded by remember { mutableStateOf(false) }
|
||||
var fabHidden by remember { mutableStateOf(false) }
|
||||
val checkedInfoMap = remember { mutableStateMapOf<Long, BaseGalleryInfo>() }
|
||||
val selectMode = checkedInfoMap.isNotEmpty()
|
||||
DrawerHandle(!selectMode && !searchBarExpanded)
|
||||
@@ -200,6 +201,7 @@ fun AnimatedVisibilityScope.FavouritesScreen(navigator: DestinationsNavigator, v
|
||||
val listMode by Settings.listMode.collectAsState()
|
||||
val height by collectListThumbSizeAsState()
|
||||
val showPages by Settings.showGalleryPages.collectAsState()
|
||||
val showProgress by Settings.showReadingProgress.collectAsState()
|
||||
val searchBarConnection = remember {
|
||||
val slop = ViewConfiguration.get(contextOf<Context>()).scaledTouchSlop
|
||||
val topPaddingPx = with(density) { contentPadding.calculateTopPadding().roundToPx() }
|
||||
@@ -244,6 +246,7 @@ fun AnimatedVisibilityScope.FavouritesScreen(navigator: DestinationsNavigator, v
|
||||
},
|
||||
info = info,
|
||||
showPages = showPages,
|
||||
showProgress = showProgress,
|
||||
modifier = Modifier.height(height),
|
||||
isInFavScene = true,
|
||||
interactionSource = interactionSource,
|
||||
@@ -273,6 +276,7 @@ fun AnimatedVisibilityScope.FavouritesScreen(navigator: DestinationsNavigator, v
|
||||
},
|
||||
info = info,
|
||||
showPages = showPages,
|
||||
showProgress = showProgress,
|
||||
showFavoriteStatus = false,
|
||||
interactionSource = interactionSource,
|
||||
)
|
||||
|
||||
@@ -320,7 +320,6 @@ fun GalleryDetailContent(
|
||||
galleryPreview(galleryDetail, previews) { navToReader(galleryDetail.galleryInfo, it) }
|
||||
}
|
||||
}
|
||||
|
||||
else -> FastScrollLazyVerticalGrid(
|
||||
columns = GridCells.Fixed(thumbColumns),
|
||||
contentPadding = contentPadding,
|
||||
@@ -722,15 +721,17 @@ fun BelowHeader(galleryDetail: GalleryDetail, voteTag: VoteTag) {
|
||||
val upTag = stringResource(R.string.tag_vote_up)
|
||||
val downTag = stringResource(R.string.tag_vote_down)
|
||||
val withDraw = stringResource(R.string.tag_vote_withdraw)
|
||||
fun search(tag: String) = navigate(ListUrlBuilder(mode = ListUrlBuilder.MODE_TAG, mKeyword = tag).asDst())
|
||||
GalleryTags(
|
||||
tagGroups = tags,
|
||||
onTagClick = {
|
||||
navigate(ListUrlBuilder(mode = ListUrlBuilder.MODE_TAG, mKeyword = it).asDst())
|
||||
},
|
||||
onTagClick = ::search,
|
||||
onTagLongClick = { tag, translation, vote ->
|
||||
val rawValue = tag.substringAfter(':')
|
||||
launchIO {
|
||||
awaitSelectAction {
|
||||
onSelect(ctx.getString(R.string.search_bar_hint, tag)) {
|
||||
withUIContext { search(tag) }
|
||||
}
|
||||
onSelect(copy) {
|
||||
addTextToClipboard(tag)
|
||||
}
|
||||
|
||||
@@ -160,6 +160,9 @@ fun AnimatedVisibilityScope.GalleryListScreen(
|
||||
var urlBuilder by viewModel.urlBuilder
|
||||
var searchBarExpanded by rememberSaveable { mutableStateOf(false) }
|
||||
var searchBarOffsetY by remember { mutableIntStateOf(0) }
|
||||
var fabExpanded by remember { mutableStateOf(false) }
|
||||
var fabHidden by remember { mutableStateOf(false) }
|
||||
|
||||
val animateItems by Settings.animateItems.collectAsState()
|
||||
|
||||
var category by rememberMutableStateInDataStore("SearchCategory") { EhUtils.ALL_CATEGORY }
|
||||
@@ -169,15 +172,11 @@ fun AnimatedVisibilityScope.GalleryListScreen(
|
||||
|
||||
LaunchedEffect(urlBuilder) {
|
||||
if (urlBuilder.category != EhUtils.NONE) category = urlBuilder.category
|
||||
if (urlBuilder.mode != MODE_TOPLIST) {
|
||||
var keyword = urlBuilder.keyword.orEmpty()
|
||||
if (urlBuilder.mode == MODE_TAG) {
|
||||
keyword = wrapTagKeyword(keyword)
|
||||
}
|
||||
if (keyword.isNotBlank()) {
|
||||
searchFieldState.setTextAndPlaceCursorAtEnd(keyword)
|
||||
}
|
||||
var keyword = urlBuilder.keyword.takeUnless { urlBuilder.mode == MODE_TOPLIST }.orEmpty()
|
||||
if (urlBuilder.mode == MODE_TAG) {
|
||||
keyword = wrapTagKeyword(keyword)
|
||||
}
|
||||
searchFieldState.setTextAndPlaceCursorAtEnd(keyword)
|
||||
}
|
||||
|
||||
val density = LocalDensity.current
|
||||
@@ -220,6 +219,7 @@ fun AnimatedVisibilityScope.GalleryListScreen(
|
||||
Settings.recentToplist = keyword
|
||||
urlBuilder = ListUrlBuilder(MODE_TOPLIST, mKeyword = keyword)
|
||||
data.refresh()
|
||||
fabHidden = false
|
||||
launch { sheetState.close() }
|
||||
},
|
||||
headlineContent = {
|
||||
@@ -374,6 +374,7 @@ fun AnimatedVisibilityScope.GalleryListScreen(
|
||||
language = languageFilter
|
||||
}
|
||||
data.refresh()
|
||||
fabHidden = false
|
||||
}
|
||||
launch { sheetState.close() }
|
||||
},
|
||||
@@ -425,9 +426,6 @@ fun AnimatedVisibilityScope.GalleryListScreen(
|
||||
}
|
||||
}
|
||||
|
||||
var fabExpanded by remember { mutableStateOf(false) }
|
||||
var fabHidden by remember { mutableStateOf(false) }
|
||||
|
||||
val openGalleryKeyword = stringResource(R.string.gallery_list_search_bar_open_gallery)
|
||||
abstract class UrlSuggestion : Suggestion() {
|
||||
override val keyword = openGalleryKeyword
|
||||
@@ -509,6 +507,7 @@ fun AnimatedVisibilityScope.GalleryListScreen(
|
||||
) { contentPadding ->
|
||||
val height by collectListThumbSizeAsState()
|
||||
val showPages by Settings.showGalleryPages.collectAsState()
|
||||
val showProgress by Settings.showReadingProgress.collectAsState()
|
||||
val searchBarConnection = remember {
|
||||
val slop = ViewConfiguration.get(contextOf<Context>()).scaledTouchSlop
|
||||
val topPaddingPx = with(density) { contentPadding.calculateTopPadding().roundToPx() }
|
||||
@@ -537,6 +536,7 @@ fun AnimatedVisibilityScope.GalleryListScreen(
|
||||
onLongClick = { launch { doGalleryInfoAction(info) } },
|
||||
info = info,
|
||||
showPages = showPages,
|
||||
showProgress = showProgress,
|
||||
modifier = Modifier.height(height),
|
||||
)
|
||||
},
|
||||
@@ -547,6 +547,7 @@ fun AnimatedVisibilityScope.GalleryListScreen(
|
||||
onLongClick = { launch { doGalleryInfoAction(info) } },
|
||||
info = info,
|
||||
showPages = showPages,
|
||||
showProgress = showProgress,
|
||||
)
|
||||
},
|
||||
searchBarOffsetY = { searchBarOffsetY },
|
||||
|
||||
@@ -136,6 +136,7 @@ fun AnimatedVisibilityScope.HistoryScreen(navigator: DestinationsNavigator) = Sc
|
||||
val marginH = dimensionResource(id = com.hippo.ehviewer.R.dimen.gallery_list_margin_h)
|
||||
val cardHeight by collectListThumbSizeAsState()
|
||||
val showPages by Settings.showGalleryPages.collectAsState()
|
||||
val showProgress by Settings.showReadingProgress.collectAsState()
|
||||
FastScrollLazyColumn(
|
||||
modifier = Modifier.nestedScroll(searchBarConnection).fillMaxSize(),
|
||||
contentPadding = paddingValues,
|
||||
@@ -161,6 +162,7 @@ fun AnimatedVisibilityScope.HistoryScreen(navigator: DestinationsNavigator) = Sc
|
||||
onLongClick = { launch { doGalleryInfoAction(info) } },
|
||||
info = info,
|
||||
showPages = showPages,
|
||||
showProgress = showProgress,
|
||||
modifier = Modifier.height(cardHeight).padding(horizontal = marginH),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.plus
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Search
|
||||
import androidx.compose.material3.ElevatedCard
|
||||
|
||||
@@ -123,7 +123,7 @@ fun AnimatedVisibilityScope.AboutScreen(navigator: DestinationsNavigator) = Scre
|
||||
}
|
||||
}
|
||||
|
||||
context(ctx: Context, _: DialogState)
|
||||
context(_: Context, _: DialogState)
|
||||
suspend fun showNewVersion(release: Release) {
|
||||
awaitConfirmationOrCancel(
|
||||
confirmText = R.string.download,
|
||||
@@ -140,7 +140,7 @@ suspend fun showNewVersion(release: Release) {
|
||||
}
|
||||
if (Settings.backupBeforeUpdate.value) {
|
||||
val time = ReadableTime.getFilenamableTime()
|
||||
EhDB.exportDB(ctx, (downloadLocation / "$time.db"))
|
||||
EhDB.exportDB(downloadLocation / "$time.db")
|
||||
}
|
||||
// TODO: Download in the background and show progress in notification
|
||||
val path = AppConfig.tempDir / "update.apk"
|
||||
|
||||
@@ -35,7 +35,6 @@ import com.ehviewer.core.files.sendTo
|
||||
import com.ehviewer.core.files.toOkioPath
|
||||
import com.ehviewer.core.i18n.R
|
||||
import com.ehviewer.core.util.isAtLeastO
|
||||
import com.ehviewer.core.util.isAtLeastSExtension7
|
||||
import com.ehviewer.core.util.launch
|
||||
import com.ehviewer.core.util.logcat
|
||||
import com.ehviewer.core.util.withIOContext
|
||||
@@ -46,6 +45,7 @@ import com.hippo.ehviewer.asMutableState
|
||||
import com.hippo.ehviewer.client.EhEngine
|
||||
import com.hippo.ehviewer.client.data.FavListUrlBuilder
|
||||
import com.hippo.ehviewer.collectAsState
|
||||
import com.hippo.ehviewer.ktor.isCronetAvailable
|
||||
import com.hippo.ehviewer.ui.Screen
|
||||
import com.hippo.ehviewer.ui.main.NavigationIcon
|
||||
import com.hippo.ehviewer.ui.showRestartDialog
|
||||
@@ -94,15 +94,15 @@ private fun dumplog(uri: Uri): Unit = with(ctx) {
|
||||
}
|
||||
|
||||
context(ctx: Context)
|
||||
private fun exportDatabase(uri: Uri) {
|
||||
private suspend fun exportDatabase(uri: Uri) {
|
||||
ctx.grantUriPermission(BuildConfig.APPLICATION_ID, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
EhDB.exportDB(ctx, uri.toOkioPath())
|
||||
EhDB.exportDB(uri.toOkioPath())
|
||||
}
|
||||
|
||||
context(ctx: Context)
|
||||
private suspend fun importDatabase(uri: Uri) {
|
||||
ctx.grantUriPermission(BuildConfig.APPLICATION_ID, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
EhDB.importDB(ctx, uri)
|
||||
EhDB.importDB(uri.toOkioPath())
|
||||
}
|
||||
|
||||
@Destination<RootGraph>
|
||||
@@ -185,7 +185,7 @@ fun AnimatedVisibilityScope.AdvancedScreen(navigator: DestinationsNavigator) = S
|
||||
title = { Text(stringResource(id = R.string.settings_advanced_app_language_title)) },
|
||||
summary = { Text(languages[currentLanguage].orEmpty()) },
|
||||
)
|
||||
if (isAtLeastSExtension7) {
|
||||
if (isCronetAvailable) {
|
||||
val enableCronet = Settings.enableCronet.asMutableState()
|
||||
if (BuildConfig.DEBUG || !enableCronet.value) {
|
||||
SwitchPreference(
|
||||
|
||||
@@ -29,11 +29,11 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.fromHtml
|
||||
import com.ehviewer.core.i18n.R
|
||||
import com.ehviewer.core.network.EhCookieStore
|
||||
import com.ehviewer.core.util.isAtLeastT
|
||||
import com.ehviewer.core.util.launch
|
||||
import com.hippo.ehviewer.Settings
|
||||
import com.hippo.ehviewer.asMutableState
|
||||
import com.hippo.ehviewer.client.EhCookieStore
|
||||
import com.hippo.ehviewer.client.EhTagDatabase
|
||||
import com.hippo.ehviewer.client.EhUtils
|
||||
import com.hippo.ehviewer.collectAsState
|
||||
@@ -214,6 +214,11 @@ fun AnimatedVisibilityScope.EhScreen(navigator: DestinationsNavigator) = Screen(
|
||||
summary = stringResource(id = R.string.settings_eh_show_gallery_pages_summary),
|
||||
state = Settings.showGalleryPages.asMutableState(),
|
||||
)
|
||||
SwitchPreference(
|
||||
title = stringResource(id = R.string.settings_eh_show_reading_progress),
|
||||
summary = stringResource(id = R.string.settings_eh_show_reading_progress_summary),
|
||||
state = Settings.showReadingProgress.asMutableState(),
|
||||
)
|
||||
SwitchPreference(
|
||||
title = stringResource(id = R.string.settings_eh_show_vote_status),
|
||||
state = Settings.showVoteStatus.asMutableState(),
|
||||
|
||||
@@ -16,11 +16,11 @@ import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import com.ehviewer.core.i18n.R
|
||||
import com.ehviewer.core.network.EhCookieStore
|
||||
import com.ehviewer.core.util.launch
|
||||
import com.google.accompanist.web.WebView
|
||||
import com.google.accompanist.web.rememberWebViewNavigator
|
||||
import com.google.accompanist.web.rememberWebViewState
|
||||
import com.hippo.ehviewer.client.EhCookieStore
|
||||
import com.hippo.ehviewer.client.EhUrl
|
||||
import com.hippo.ehviewer.ui.Screen
|
||||
import com.hippo.ehviewer.ui.main.NavigationIcon
|
||||
|
||||
@@ -79,9 +79,9 @@ object FileUtils {
|
||||
*/
|
||||
// From https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/core/java/android/os/FileUtils.java;l=1142;drc=7b647e4ea0e92f33c19b315eaed364ee067ba0aa
|
||||
fun sanitizeFilename(name: String): String {
|
||||
if (name.isEmpty() || "." == name || ".." == name) {
|
||||
return "(invalid)"
|
||||
}
|
||||
// Windows does not support filenames ending with a space or a period
|
||||
val name = name.trimEnd(' ', '.')
|
||||
check(name.isNotEmpty()) { "Invalid filename" }
|
||||
return buildString(name.length) {
|
||||
name.forEach {
|
||||
if (isValidFatFilenameChar(it)) {
|
||||
|
||||
Generated
+144
-198
@@ -4,9 +4,9 @@ version = 4
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.3"
|
||||
version = "1.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||
checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
@@ -78,9 +78,9 @@ checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.9.4"
|
||||
version = "2.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394"
|
||||
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
@@ -102,15 +102,15 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.10.1"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
|
||||
checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.41"
|
||||
version = "1.2.49"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7"
|
||||
checksum = "90583009037521a116abf44494efecd645ba48b6622457080f080b85544e2215"
|
||||
dependencies = [
|
||||
"find-msvc-tools",
|
||||
"shlex",
|
||||
@@ -124,9 +124,9 @@ checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.3"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
@@ -136,7 +136,7 @@ checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2"
|
||||
dependencies = [
|
||||
"iana-time-zone",
|
||||
"num-traits",
|
||||
"windows-link 0.2.1",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -186,21 +186,21 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||
|
||||
[[package]]
|
||||
name = "csv"
|
||||
version = "1.3.1"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf"
|
||||
checksum = "52cd9d68cf7efc6ddfaaee42e7288d3a99d613d4b50f76ce9827ae0c6e14f938"
|
||||
dependencies = [
|
||||
"csv-core",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "csv-core"
|
||||
version = "0.1.12"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d02f3b0da4c6504f86e9cd789d8dbafab48c2321be74e9987593de5a894d93d"
|
||||
checksum = "704a3c26996a80471189265814dbc2c257598b96b8a7feae2d31ace646bb9782"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
@@ -340,9 +340,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "fancy-regex"
|
||||
version = "0.14.0"
|
||||
version = "0.16.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e24cb5a94bcae1e5408b0effca5cd7172ea3c5755049c5f3af4cd283a165298"
|
||||
checksum = "998b056554fbe42e03ae0e152895cd1a7e1002aec800fdc6635d20270260c46f"
|
||||
dependencies = [
|
||||
"bit-set",
|
||||
"regex-automata",
|
||||
@@ -357,9 +357,9 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
||||
|
||||
[[package]]
|
||||
name = "find-msvc-tools"
|
||||
version = "0.1.4"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127"
|
||||
checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844"
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
@@ -480,18 +480,17 @@ checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.16.0"
|
||||
version = "0.16.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d"
|
||||
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "1.3.1"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565"
|
||||
checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"itoa",
|
||||
]
|
||||
|
||||
@@ -526,9 +525,9 @@ checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "1.7.0"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e"
|
||||
checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11"
|
||||
dependencies = [
|
||||
"atomic-waker",
|
||||
"bytes",
|
||||
@@ -580,9 +579,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hyper-util"
|
||||
version = "0.1.17"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8"
|
||||
checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bytes",
|
||||
@@ -630,9 +629,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "icu_collections"
|
||||
version = "2.0.0"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47"
|
||||
checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"potential_utf",
|
||||
@@ -643,9 +642,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "icu_locale_core"
|
||||
version = "2.0.0"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a"
|
||||
checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"litemap",
|
||||
@@ -656,11 +655,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "icu_normalizer"
|
||||
version = "2.0.0"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979"
|
||||
checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_collections",
|
||||
"icu_normalizer_data",
|
||||
"icu_properties",
|
||||
@@ -671,42 +669,38 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "icu_normalizer_data"
|
||||
version = "2.0.0"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3"
|
||||
checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a"
|
||||
|
||||
[[package]]
|
||||
name = "icu_properties"
|
||||
version = "2.0.1"
|
||||
version = "2.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b"
|
||||
checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_collections",
|
||||
"icu_locale_core",
|
||||
"icu_properties_data",
|
||||
"icu_provider",
|
||||
"potential_utf",
|
||||
"zerotrie",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_properties_data"
|
||||
version = "2.0.1"
|
||||
version = "2.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632"
|
||||
checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af"
|
||||
|
||||
[[package]]
|
||||
name = "icu_provider"
|
||||
version = "2.0.0"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af"
|
||||
checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_locale_core",
|
||||
"stable_deref_trait",
|
||||
"tinystr",
|
||||
"writeable",
|
||||
"yoke",
|
||||
"zerofrom",
|
||||
@@ -737,9 +731,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "image"
|
||||
version = "0.25.8"
|
||||
version = "0.25.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "529feb3e6769d234375c4cf1ee2ce713682b8e76538cb13f9fc23e1400a591e7"
|
||||
checksum = "e6506c6c10786659413faa717ceebcb8f70731c0a60cbae39795fdf114519c1a"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"byteorder-lite",
|
||||
@@ -749,9 +743,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.11.4"
|
||||
version = "2.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5"
|
||||
checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
@@ -765,9 +759,9 @@ checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
|
||||
|
||||
[[package]]
|
||||
name = "iri-string"
|
||||
version = "0.7.8"
|
||||
version = "0.7.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2"
|
||||
checksum = "4f867b9d1d896b67beb18518eda36fdb77a32ea590de864f1325b294a6d14397"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"serde",
|
||||
@@ -814,9 +808,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.81"
|
||||
version = "0.3.83"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305"
|
||||
checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
@@ -830,9 +824,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.177"
|
||||
version = "0.2.178"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
|
||||
checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091"
|
||||
|
||||
[[package]]
|
||||
name = "libwebp-sys2"
|
||||
@@ -854,15 +848,15 @@ checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
|
||||
|
||||
[[package]]
|
||||
name = "litemap"
|
||||
version = "0.8.0"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
|
||||
checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.28"
|
||||
version = "0.4.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
|
||||
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
@@ -878,20 +872,20 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "1.0.4"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
|
||||
checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "moxcms"
|
||||
version = "0.7.7"
|
||||
version = "0.7.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c588e11a3082784af229e23e8e4ecf5bcc6fbe4f69101e0421ce8d79da7f0b40"
|
||||
checksum = "ac9557c559cd6fc9867e122e20d2cbefc9ca29d80d027a8e39310920ed2f0a97"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
"pxfm",
|
||||
@@ -1022,9 +1016,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "num_enum"
|
||||
version = "0.7.4"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a"
|
||||
checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c"
|
||||
dependencies = [
|
||||
"num_enum_derive",
|
||||
"rustversion",
|
||||
@@ -1032,9 +1026,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "num_enum_derive"
|
||||
version = "0.7.4"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d"
|
||||
checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
@@ -1050,9 +1044,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.73"
|
||||
version = "0.10.75"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8"
|
||||
checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
@@ -1082,9 +1076,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.109"
|
||||
version = "0.9.111"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571"
|
||||
checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
@@ -1136,9 +1130,9 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
|
||||
|
||||
[[package]]
|
||||
name = "potential_utf"
|
||||
version = "0.1.3"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a"
|
||||
checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77"
|
||||
dependencies = [
|
||||
"zerovec",
|
||||
]
|
||||
@@ -1154,36 +1148,36 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.101"
|
||||
version = "1.0.103"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
|
||||
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pxfm"
|
||||
version = "0.1.25"
|
||||
version = "0.1.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3cbdf373972bf78df4d3b518d07003938e2c7d1fb5891e55f9cb6df57009d84"
|
||||
checksum = "7186d3822593aa4393561d186d1393b3923e9d6163d3fbfd6e825e3e6cf3e6a8"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.38.3"
|
||||
version = "0.38.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42a232e7487fc2ef313d96dde7948e7a3c05101870d8985e4fd8d26aedd27b89"
|
||||
checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.41"
|
||||
version = "1.0.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1"
|
||||
checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
@@ -1237,9 +1231,9 @@ checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.12.24"
|
||||
version = "0.12.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f"
|
||||
checksum = "b6eff9328d40131d43bd911d42d79eb6a47312002a4daefc9e37f17e74a7701a"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bytes",
|
||||
@@ -1304,9 +1298,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.23.32"
|
||||
version = "0.23.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd3c25631629d034ce7cd9940adc9d45762d46de2b0f57193c4443b92c6d4d40"
|
||||
checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"rustls-pki-types",
|
||||
@@ -1317,18 +1311,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pki-types"
|
||||
version = "1.12.0"
|
||||
version = "1.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79"
|
||||
checksum = "708c0f9d5f54ba0272468c1d306a52c495b31fa155e91bc25371e6df7996908c"
|
||||
dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.103.7"
|
||||
version = "0.103.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e10b3f4191e8a80e6b43eebabfac91e5dcecebb27a71f04e820c47ec41d314bf"
|
||||
checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
@@ -1343,9 +1337,9 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
|
||||
|
||||
[[package]]
|
||||
name = "rxing"
|
||||
version = "0.8.2"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "065826c9e75902c67ce057a62d8ccd7adacf7bbc905352d9530ac6178975f584"
|
||||
checksum = "ff2e93e7068f9894c5c8f90ea377015d26cc73f7053e99ffc12453821ffa74d1"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"chrono-tz",
|
||||
@@ -1533,9 +1527,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.106"
|
||||
version = "2.0.111"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
|
||||
checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1638,9 +1632,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tinystr"
|
||||
version = "0.8.1"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b"
|
||||
checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"zerovec",
|
||||
@@ -1699,9 +1693,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.7.16"
|
||||
version = "0.7.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5"
|
||||
checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
@@ -1721,9 +1715,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.23.7"
|
||||
version = "0.23.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d"
|
||||
checksum = "5d7cbc3b4b49633d57a0509303158ca50de80ae32c265093b24c414705807832"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"toml_datetime",
|
||||
@@ -1757,9 +1751,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tower-http"
|
||||
version = "0.6.6"
|
||||
version = "0.6.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2"
|
||||
checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bytes",
|
||||
@@ -1787,9 +1781,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.41"
|
||||
version = "0.1.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
|
||||
checksum = "2d15d90a0b5c19378952d479dc858407149d7bb45a14de0142f6c534b16fc647"
|
||||
dependencies = [
|
||||
"pin-project-lite",
|
||||
"tracing-core",
|
||||
@@ -1797,9 +1791,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.34"
|
||||
version = "0.1.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
|
||||
checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
@@ -1812,9 +1806,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.19"
|
||||
version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
|
||||
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
@@ -1904,9 +1898,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.104"
|
||||
version = "0.2.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d"
|
||||
checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
@@ -1915,25 +1909,11 @@ dependencies = [
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.104"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.54"
|
||||
version = "0.4.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e038d41e478cc73bae0ff9b36c60cff1c98b8f38f8d7e8061e79ee63608ac5c"
|
||||
checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
@@ -1944,9 +1924,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.104"
|
||||
version = "0.2.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119"
|
||||
checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
@@ -1954,31 +1934,31 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.104"
|
||||
version = "0.2.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7"
|
||||
checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.104"
|
||||
version = "0.2.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1"
|
||||
checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.81"
|
||||
version = "0.3.83"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120"
|
||||
checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
@@ -2001,9 +1981,9 @@ checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
|
||||
dependencies = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-link 0.2.1",
|
||||
"windows-result 0.4.1",
|
||||
"windows-strings 0.5.1",
|
||||
"windows-link",
|
||||
"windows-result",
|
||||
"windows-strings",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2028,12 +2008,6 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
@@ -2042,22 +2016,13 @@ checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
|
||||
[[package]]
|
||||
name = "windows-registry"
|
||||
version = "0.5.3"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e"
|
||||
checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720"
|
||||
dependencies = [
|
||||
"windows-link 0.1.3",
|
||||
"windows-result 0.3.4",
|
||||
"windows-strings 0.4.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
|
||||
dependencies = [
|
||||
"windows-link 0.1.3",
|
||||
"windows-link",
|
||||
"windows-result",
|
||||
"windows-strings",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2066,16 +2031,7 @@ version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
|
||||
dependencies = [
|
||||
"windows-link 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-strings"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
|
||||
dependencies = [
|
||||
"windows-link 0.1.3",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2084,7 +2040,7 @@ version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
|
||||
dependencies = [
|
||||
"windows-link 0.2.1",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2105,15 +2061,6 @@ dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.60.2"
|
||||
@@ -2129,7 +2076,7 @@ version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
||||
dependencies = [
|
||||
"windows-link 0.2.1",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2169,7 +2116,7 @@ version = "0.53.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
|
||||
dependencies = [
|
||||
"windows-link 0.2.1",
|
||||
"windows-link",
|
||||
"windows_aarch64_gnullvm 0.53.1",
|
||||
"windows_aarch64_msvc 0.53.1",
|
||||
"windows_i686_gnu 0.53.1",
|
||||
@@ -2320,9 +2267,9 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.7.13"
|
||||
version = "0.7.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf"
|
||||
checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
@@ -2335,17 +2282,16 @@ checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
|
||||
|
||||
[[package]]
|
||||
name = "writeable"
|
||||
version = "0.6.1"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
|
||||
checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9"
|
||||
|
||||
[[package]]
|
||||
name = "yoke"
|
||||
version = "0.8.0"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc"
|
||||
checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"stable_deref_trait",
|
||||
"yoke-derive",
|
||||
"zerofrom",
|
||||
@@ -2353,9 +2299,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "yoke-derive"
|
||||
version = "0.8.0"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6"
|
||||
checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -2392,9 +2338,9 @@ checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
|
||||
|
||||
[[package]]
|
||||
name = "zerotrie"
|
||||
version = "0.2.2"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595"
|
||||
checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"yoke",
|
||||
@@ -2403,9 +2349,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zerovec"
|
||||
version = "0.11.4"
|
||||
version = "0.11.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b"
|
||||
checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002"
|
||||
dependencies = [
|
||||
"yoke",
|
||||
"zerofrom",
|
||||
@@ -2414,9 +2360,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zerovec-derive"
|
||||
version = "0.11.1"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f"
|
||||
checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
||||
@@ -257,17 +257,28 @@ where
|
||||
{
|
||||
jni_throwing(env, |env| {
|
||||
let buffer = deref_mut_direct_bytebuffer(env, str)?;
|
||||
let value = {
|
||||
// SAFETY: ktor client ensure html content is valid utf-8.
|
||||
let body = unsafe { from_utf8_unchecked(&buffer[..limit as usize]) };
|
||||
f(body)?
|
||||
};
|
||||
let mut cursor = Cursor::new(buffer);
|
||||
serde_cbor::to_writer(&mut cursor, &value)?;
|
||||
Ok(cursor.position() as i32)
|
||||
|
||||
// SAFETY: ktor client ensure html content is valid utf-8.
|
||||
let body = unsafe { from_utf8_unchecked(&buffer[..limit as usize]) };
|
||||
match f(body) {
|
||||
Ok(value) => serialize_to_buffer(buffer, &value),
|
||||
Err(err) => {
|
||||
if let Some(value) = err.downcast_ref::<EhError>() {
|
||||
serialize_to_buffer(buffer, value)
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn serialize_to_buffer<T: Serialize>(buffer: &mut [u8], value: &T) -> Result<i32> {
|
||||
let mut cursor = Cursor::new(buffer);
|
||||
serde_cbor::to_writer(&mut cursor, value)?;
|
||||
Ok(cursor.position() as i32)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
#[allow(non_snake_case)]
|
||||
pub extern "system" fn JNI_OnLoad(_: JavaVM, _: *mut c_void) -> jint {
|
||||
|
||||
@@ -5,6 +5,7 @@ mod ffi;
|
||||
pub mod img;
|
||||
pub mod parser;
|
||||
|
||||
use serde::{Serialize, Serializer, ser::SerializeTuple};
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
use tl::{Bytes, HTMLTag, Node, NodeHandle, Parser, VDom};
|
||||
|
||||
@@ -74,22 +75,47 @@ enum EhError {
|
||||
NeedLogin,
|
||||
NoHathClient,
|
||||
InsufficientFunds,
|
||||
GalleryUnavailable(String),
|
||||
IpBanned(String),
|
||||
Error(String),
|
||||
}
|
||||
|
||||
impl EhError {
|
||||
fn variant_name(&self) -> &'static str {
|
||||
match self {
|
||||
EhError::NoHits => "NoHits",
|
||||
EhError::NoWatched => "NoWatched",
|
||||
EhError::NeedLogin => "NeedLogin",
|
||||
EhError::NoHathClient => "NoHathClient",
|
||||
EhError::InsufficientFunds => "InsufficientFunds",
|
||||
EhError::GalleryUnavailable(_) => "GalleryUnavailable",
|
||||
EhError::IpBanned(_) => "IpBanned",
|
||||
EhError::Error(_) => "Error",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for EhError {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let mut tup = serializer.serialize_tuple(2)?;
|
||||
tup.serialize_element(self.variant_name())?;
|
||||
let payload = match self {
|
||||
EhError::GalleryUnavailable(s) | EhError::IpBanned(s) | EhError::Error(s) => {
|
||||
std::slice::from_ref(s)
|
||||
}
|
||||
_ => &[],
|
||||
};
|
||||
tup.serialize_element(payload)?;
|
||||
tup.end()
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for EhError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
let msg = match self {
|
||||
EhError::NoHits => "0",
|
||||
EhError::NoWatched => "1",
|
||||
EhError::NeedLogin => "2",
|
||||
EhError::NoHathClient => "3",
|
||||
EhError::InsufficientFunds => "4",
|
||||
EhError::IpBanned(s) => &format!("5{s}"),
|
||||
EhError::Error(s) => &format!("6{s}"),
|
||||
};
|
||||
f.write_str(msg)
|
||||
Debug::fmt(&self, f)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -470,11 +470,11 @@ pub fn parse_pages(dom: &VDom, parser: &Parser) -> Result<i32> {
|
||||
}
|
||||
|
||||
pub fn parse_preview_list(dom: &VDom, parser: &Parser) -> Result<Vec<GalleryPreview>> {
|
||||
// Check Gallery Not Available
|
||||
let error = get_vdom_first_element_by_class_name(dom, "d");
|
||||
if let Some(tag) = error.and_then(|n| get_first_child(n.as_tag()?, parser)) {
|
||||
let node = tag.children().top()[0].get(parser).unwrap();
|
||||
bail!(EhError::Error(node.inner_text(parser).to_string()));
|
||||
let err = EhError::GalleryUnavailable(node.inner_text(parser).to_string());
|
||||
bail!(err);
|
||||
}
|
||||
|
||||
dom.get_element_by_id("gdt")
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
141
|
||||
@@ -11,10 +11,13 @@ kotlin {
|
||||
api(projects.core.common)
|
||||
api(libs.androidx.datastore)
|
||||
api(libs.androidx.room.paging)
|
||||
implementation(libs.ktor.client.core)
|
||||
}
|
||||
}
|
||||
androidMain {
|
||||
dependencies {
|
||||
implementation(project.dependencies.platform(libs.okhttp.bom))
|
||||
implementation(libs.ktor.client.okhttp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.ehviewer.core.database
|
||||
|
||||
import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
import androidx.sqlite.driver.AndroidSQLiteDriver
|
||||
import okio.Path.Companion.toOkioPath
|
||||
import splitties.init.appCtx
|
||||
|
||||
actual inline fun <reified T : RoomDatabase> roomDb(
|
||||
name: String,
|
||||
builder: RoomDatabase.Builder<T>.() -> Unit,
|
||||
) = Room.databaseBuilder<T>(appCtx, name).setDriver(AndroidSQLiteDriver()).apply(builder).build()
|
||||
|
||||
actual fun getDatabasePath(name: String) = appCtx.getDatabasePath(name).toOkioPath()
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.ehviewer.core.network
|
||||
|
||||
import io.ktor.http.Cookie
|
||||
import io.ktor.http.Url
|
||||
import io.ktor.http.parseClientCookiesHeader
|
||||
import io.ktor.http.renderSetCookieHeader
|
||||
|
||||
class AndroidCookieManager : CookieManager {
|
||||
private val manager = android.webkit.CookieManager.getInstance()
|
||||
override fun getCookies(url: Url) = manager.getCookie(url.toString())?.let { parseClientCookiesHeader(it) }
|
||||
override fun setCookie(url: Url, cookie: Cookie) = manager.setCookie(url.toString(), renderSetCookieHeader(cookie))
|
||||
override fun removeAllCookies() = manager.removeAllCookies(null)
|
||||
override fun flush() = manager.flush()
|
||||
}
|
||||
|
||||
actual fun getCookieManager(): CookieManager = AndroidCookieManager()
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.ehviewer.core.database
|
||||
|
||||
import androidx.room.RoomDatabase
|
||||
import okio.Path
|
||||
|
||||
expect inline fun <reified T : RoomDatabase> roomDb(
|
||||
name: String,
|
||||
builder: RoomDatabase.Builder<T>.() -> Unit = {},
|
||||
): T
|
||||
|
||||
expect fun getDatabasePath(name: String): Path
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.ehviewer.core.network
|
||||
|
||||
import io.ktor.http.Cookie
|
||||
import io.ktor.http.Url
|
||||
|
||||
interface CookieManager {
|
||||
fun getCookies(url: Url): Map<String, String>?
|
||||
fun setCookie(url: Url, cookie: Cookie)
|
||||
fun removeAllCookies()
|
||||
fun flush()
|
||||
}
|
||||
|
||||
expect fun getCookieManager(): CookieManager
|
||||
+20
-22
@@ -1,17 +1,19 @@
|
||||
package com.hippo.ehviewer.client
|
||||
package com.ehviewer.core.network
|
||||
|
||||
import android.webkit.CookieManager
|
||||
import io.ktor.client.plugins.cookies.CookiesStorage
|
||||
import io.ktor.http.Cookie
|
||||
import io.ktor.http.URLBuilder
|
||||
import io.ktor.http.URLProtocol
|
||||
import io.ktor.http.Url
|
||||
import io.ktor.http.parseClientCookiesHeader
|
||||
import io.ktor.http.renderSetCookieHeader
|
||||
|
||||
object EhCookieStore : CookiesStorage {
|
||||
private val manager = CookieManager.getInstance()
|
||||
fun removeAllCookies() = manager.removeAllCookies(null)
|
||||
private val manager = getCookieManager()
|
||||
private val urlE = URLBuilder(URLProtocol.HTTPS, "e-hentai.org").build()
|
||||
private val urlEx = URLBuilder(URLProtocol.HTTPS, "exhentai.org").build()
|
||||
|
||||
fun hasSignedIn(): Boolean = getCookies(EhUrl.HOST_E)?.run {
|
||||
fun removeAllCookies() = manager.removeAllCookies()
|
||||
|
||||
fun hasSignedIn(): Boolean = manager.getCookies(urlE)?.run {
|
||||
containsKey(KEY_IPB_MEMBER_ID) && containsKey(KEY_IPB_PASS_HASH)
|
||||
} == true
|
||||
|
||||
@@ -29,18 +31,18 @@ object EhCookieStore : CookiesStorage {
|
||||
|
||||
fun clearIgneous() {
|
||||
manager.setCookie(
|
||||
EhUrl.HOST_EX,
|
||||
renderSetCookieHeader(KEY_IGNEOUS, "", maxAge = 0, domain = EhUrl.DOMAIN_EX, path = "/"),
|
||||
urlEx,
|
||||
Cookie(KEY_IGNEOUS, "", maxAge = 0, domain = urlEx.host, path = "/"),
|
||||
)
|
||||
}
|
||||
|
||||
fun getUserId() = getCookies(EhUrl.HOST_E)?.get(KEY_IPB_MEMBER_ID)
|
||||
fun getUserId() = manager.getCookies(urlE)?.get(KEY_IPB_MEMBER_ID)
|
||||
|
||||
fun getHathPerks() = getCookies(EhUrl.HOST_E)?.get(KEY_HATH_PERKS)?.substringBefore('-')
|
||||
fun getHathPerks() = manager.getCookies(urlE)?.get(KEY_HATH_PERKS)?.substringBefore('-')
|
||||
|
||||
fun getIdentityCookies(): List<Pair<String, String?>> {
|
||||
val eCookies = getCookies(EhUrl.HOST_E)
|
||||
val exCookies = getCookies(EhUrl.HOST_EX)
|
||||
val eCookies = manager.getCookies(urlE)
|
||||
val exCookies = manager.getCookies(urlEx)
|
||||
val ipbMemberId = eCookies?.get(KEY_IPB_MEMBER_ID)
|
||||
val ipbPassHash = eCookies?.get(KEY_IPB_PASS_HASH)
|
||||
val igneous = exCookies?.get(KEY_IGNEOUS)
|
||||
@@ -51,24 +53,22 @@ object EhCookieStore : CookiesStorage {
|
||||
)
|
||||
}
|
||||
|
||||
fun isCloudflareBypassed() = getCookies(EhUrl.HOST_E)?.containsKey("cf_clearance") == true
|
||||
fun isCloudflareBypassed() = manager.getCookies(urlE)?.containsKey("cf_clearance") == true
|
||||
|
||||
fun flush() = manager.flush()
|
||||
|
||||
// See https://github.com/Ehviewer-Overhauled/Ehviewer/issues/873
|
||||
override suspend fun addCookie(requestUrl: Url, cookie: Cookie) {
|
||||
if (cookie.name != KEY_UTMP_NAME) {
|
||||
manager.setCookie(requestUrl.toString(), renderSetCookieHeader(cookie))
|
||||
manager.setCookie(requestUrl, cookie)
|
||||
}
|
||||
}
|
||||
|
||||
override fun close() = Unit
|
||||
|
||||
private fun getCookies(url: String) = manager.getCookie(url)?.let { parseClientCookiesHeader(it) }
|
||||
|
||||
fun load(url: Url): List<Cookie> {
|
||||
val checkTips = EhUrl.DOMAIN_E in url.host
|
||||
return getCookies(url.toString())?.mapTo(mutableListOf()) {
|
||||
override suspend fun get(requestUrl: Url): List<Cookie> {
|
||||
val checkTips = requestUrl.host == urlE.host
|
||||
return manager.getCookies(requestUrl)?.mapTo(mutableListOf()) {
|
||||
Cookie(it.key, it.value)
|
||||
}?.apply {
|
||||
if (checkTips) {
|
||||
@@ -76,6 +76,4 @@ object EhCookieStore : CookiesStorage {
|
||||
}
|
||||
} ?: if (checkTips) listOf(sTipsCookie) else emptyList()
|
||||
}
|
||||
|
||||
override suspend fun get(requestUrl: Url) = load(requestUrl)
|
||||
}
|
||||
@@ -317,6 +317,8 @@
|
||||
<string name="settings_eh_show_jpn_title_summary">Require enabling Japanese Title in Settings on EHentai website</string>
|
||||
<string name="settings_eh_show_gallery_pages">Show gallery pages</string>
|
||||
<string name="settings_eh_show_gallery_pages_summary">Display the number of pages in the gallery list</string>
|
||||
<string name="settings_eh_show_reading_progress">Show reading progress</string>
|
||||
<string name="settings_eh_show_reading_progress_summary">Display reading progress in gallery list</string>
|
||||
<string name="settings_eh_show_vote_status">Show tag vote status</string>
|
||||
<string name="settings_eh_show_gallery_comments">Show gallery comments</string>
|
||||
<string name="settings_eh_show_gallery_comments_summary">Show comments on the gallery details page</string>
|
||||
|
||||
@@ -301,6 +301,8 @@
|
||||
<string name="settings_eh_show_jpn_title_summary">需同时在 EHentai 网站设置中启用 Japanese Title</string>
|
||||
<string name="settings_eh_show_gallery_pages">显示画廊页数</string>
|
||||
<string name="settings_eh_show_gallery_pages_summary">在画廊列表中显示页数</string>
|
||||
<string name="settings_eh_show_reading_progress">显示阅读进度</string>
|
||||
<string name="settings_eh_show_reading_progress_summary">在画廊列表中显示阅读进度</string>
|
||||
<string name="settings_eh_show_vote_status">显示标签投票状态</string>
|
||||
<string name="settings_eh_show_gallery_comments">显示画廊评论</string>
|
||||
<string name="settings_eh_show_gallery_comments_summary">在画廊详情页中显示评论</string>
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import org.jetbrains.compose.compose
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.ehviewer.multiplatform.library.compose)
|
||||
}
|
||||
@@ -9,19 +7,20 @@ kotlin {
|
||||
commonMain {
|
||||
dependencies {
|
||||
api(projects.core.common)
|
||||
api(compose.material3)
|
||||
api(compose.materialIconsExtended)
|
||||
api(libs.compose.material3)
|
||||
api(libs.compose.material.icons.extended)
|
||||
api(libs.compose.material3.adaptive)
|
||||
api(libs.androidx.lifecycle.compose)
|
||||
api(libs.androidx.lifecycle.viewmodel.compose)
|
||||
implementation(compose("org.jetbrains.compose.ui:ui-backhandler"))
|
||||
implementation(compose.preview)
|
||||
implementation(libs.compose.ui.backhandler)
|
||||
implementation(libs.compose.ui.tooling.preview)
|
||||
}
|
||||
}
|
||||
|
||||
androidMain {
|
||||
dependencies {
|
||||
api(project.dependencies.platform(libs.compose.bom))
|
||||
api(libs.compose.foundation)
|
||||
implementation(libs.androidx.activity.compose)
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -86,6 +86,7 @@ internal abstract class HorizontalDragGestureNode(
|
||||
private fun startListeningForEvents() {
|
||||
isListeningForEvents = true
|
||||
|
||||
@Suppress("ktlint:standard:kdoc")
|
||||
/**
|
||||
* To preserve the original behavior we had (before the Modifier.Node migration) we need to
|
||||
* scope the DragStopped and DragCancel methods to the node's coroutine scope instead of using
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
@file:Suppress("ktlint:standard:kdoc")
|
||||
|
||||
package androidx.compose.material3.fork
|
||||
|
||||
/**
|
||||
|
||||
+4
-4
@@ -16,7 +16,7 @@
|
||||
</p>
|
||||
|
||||
<h1 align="center">
|
||||
<img src="https://github.com/Ehviewer-Overhauled/Art/blob/master/launcher_icon-web.svg" width="200" alt="EhViewer">
|
||||
<img src="https://github.com/FooIbar/EhViewer-art/blob/master/launcher_icon-web.svg" width="200" alt="EhViewer">
|
||||
<br>EhViewer<br>
|
||||
</h1>
|
||||
|
||||
@@ -78,13 +78,13 @@
|
||||
*Android 6 のデバイスは [ISRG Root X1](https://letsencrypt.org/certs/isrgrootx1.pem) 証明書のインストールが必要です
|
||||
|
||||
<a href="https://github.com/FooIbar/EhViewer/releases">
|
||||
<img alt="Get it on GitHub" src="https://github.com/Ehviewer-Overhauled/Art/blob/master/get-it-on-github.svg" width="200px"/>
|
||||
<img alt="Get it on GitHub" src="https://github.com/FooIbar/EhViewer-art/blob/master/get-it-on-github.svg" width="200px"/>
|
||||
</a>
|
||||
|
||||
# スクリーンショット
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
# 感謝
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
</p>
|
||||
|
||||
<h1 align="center">
|
||||
<img src="https://github.com/Ehviewer-Overhauled/Art/blob/master/launcher_icon-web.svg" width="200" alt="EhViewer">
|
||||
<img src="https://github.com/FooIbar/EhViewer-art/blob/master/launcher_icon-web.svg" width="200" alt="EhViewer">
|
||||
<br>EhViewer<br>
|
||||
</h1>
|
||||
|
||||
@@ -77,13 +77,13 @@
|
||||
*运行 Android 6 的设备需安装 [ISRG Root X1](https://letsencrypt.org/certs/isrgrootx1.pem) 证书
|
||||
|
||||
<a href="https://github.com/FooIbar/EhViewer/releases">
|
||||
<img alt="Get it on GitHub" src="https://github.com/Ehviewer-Overhauled/Art/blob/master/get-it-on-github.svg" width="200px"/>
|
||||
<img alt="Get it on GitHub" src="https://github.com/FooIbar/EhViewer-art/blob/master/get-it-on-github.svg" width="200px"/>
|
||||
</a>
|
||||
|
||||
# 截图
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
# 感谢
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
</p>
|
||||
|
||||
<h1 align="center">
|
||||
<img src="https://github.com/Ehviewer-Overhauled/Art/blob/master/launcher_icon-web.svg" width="200" alt="EhViewer">
|
||||
<img src="https://github.com/FooIbar/EhViewer-art/blob/master/launcher_icon-web.svg" width="200" alt="EhViewer">
|
||||
<br>EhViewer<br>
|
||||
</h1>
|
||||
|
||||
@@ -75,13 +75,13 @@
|
||||
| Marshmallow | 6.0 | 有限支援,無保證 |
|
||||
|
||||
<a href="https://github.com/FooIbar/EhViewer/releases">
|
||||
<img alt="Get it on GitHub" src="https://github.com/Ehviewer-Overhauled/Art/blob/master/get-it-on-github.svg" width="200px"/>
|
||||
<img alt="Get it on GitHub" src="https://github.com/FooIbar/EhViewer-art/blob/master/get-it-on-github.svg" width="200px"/>
|
||||
</a>
|
||||
|
||||
# 截圖
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
# 感謝
|
||||
|
||||
|
||||
+32
-31
@@ -1,40 +1,41 @@
|
||||
[versions]
|
||||
aboutlibraries = "13.1.0"
|
||||
accompanist = "0.37.3"
|
||||
agp = "8.13.0"
|
||||
androidx-activity = "1.12.0-alpha09"
|
||||
agp = "8.13.2"
|
||||
androidx-activity = "1.12.1"
|
||||
androidx-appcompat = "1.7.1"
|
||||
androidx-biometric = "1.4.0-alpha04"
|
||||
androidx-browser = "1.9.0"
|
||||
androidx-core = "1.17.0"
|
||||
androidx-core-splashscreen = "1.2.0-rc01"
|
||||
androidx-datastore = "1.1.7"
|
||||
androidx-lifecycle = "2.10.0-alpha05"
|
||||
androidx-core-splashscreen = "1.2.0"
|
||||
androidx-datastore = "1.2.0"
|
||||
androidx-lifecycle = "2.10.0"
|
||||
androidx-paging = "3.3.6"
|
||||
androidx-room = "2.8.2"
|
||||
androidx-work = "2.11.0-rc01"
|
||||
arrow = "2.1.2"
|
||||
androidx-room = "2.8.4"
|
||||
androidx-webkit = "1.14.0"
|
||||
androidx-work = "2.11.0"
|
||||
arrow = "2.2.1.1"
|
||||
coil = "3.3.0"
|
||||
compose-bom = "2025.10.00"
|
||||
compose-multiplatform = "1.9.1"
|
||||
compose-bom = "2025.12.00"
|
||||
compose-multiplatform = "1.9.3"
|
||||
compose-destinations = "2.3.0"
|
||||
compose-preference = "2.1.0"
|
||||
kotlin = "2.2.20"
|
||||
kotlin = "2.3.0"
|
||||
kotlinx-coroutines = "1.10.2"
|
||||
kotlinx-datetime = "0.7.1"
|
||||
kotlinx-io = "0.8.0"
|
||||
kotlinx-io = "0.8.2"
|
||||
kotlinx-serialization = "1.9.0"
|
||||
ksp = "2.2.20-2.0.4"
|
||||
ktor = "3.3.1"
|
||||
moko-resources = "0.25.1"
|
||||
okhttp = "5.2.1"
|
||||
okio = "3.16.2"
|
||||
ksp = "2.3.4"
|
||||
ktor = "3.3.3"
|
||||
moko-resources = "0.25.2"
|
||||
okhttp = "5.3.2"
|
||||
okio = "3.16.4"
|
||||
splitties = "3.0.0"
|
||||
spotless = "8.0.0"
|
||||
spotless = "8.1.0"
|
||||
telephoto = "0.18.0"
|
||||
xmlutil = "0.91.2"
|
||||
xmlutil = "0.91.3"
|
||||
junit = "1.3.0"
|
||||
uiautomator = "2.4.0-alpha06"
|
||||
uiautomator = "2.4.0-alpha07"
|
||||
benchmark = "1.4.1"
|
||||
profileinstaller = "1.4.1"
|
||||
|
||||
@@ -59,6 +60,7 @@ androidx-paging-compose = { module = "androidx.paging:paging-compose", version.r
|
||||
androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "androidx-room" }
|
||||
androidx-room-paging = { module = "androidx.room:room-paging", version.ref = "androidx-room" }
|
||||
|
||||
androidx-webkit = { module = "androidx.webkit:webkit", version.ref = "androidx-webkit" }
|
||||
androidx-work-runtime = { module = "androidx.work:work-runtime", version.ref = "androidx-work" }
|
||||
|
||||
arrow-fx-coroutines = { module = "io.arrow-kt:arrow-fx-coroutines" }
|
||||
@@ -73,12 +75,12 @@ coil-network = { module = "io.coil-kt.coil3:coil-network-ktor3" }
|
||||
|
||||
compose-bom = { module = "androidx.compose:compose-bom-alpha", version.ref = "compose-bom" }
|
||||
compose-foundation = { module = "androidx.compose.foundation:foundation" }
|
||||
compose-material-icons-extended = { module = "androidx.compose.material:material-icons-extended" }
|
||||
compose-material3 = { module = "androidx.compose.material3:material3" }
|
||||
compose-material3-adaptive = { module = "org.jetbrains.compose.material3.adaptive:adaptive", version = "1.1.2" }
|
||||
compose-material-icons-extended = { module = "org.jetbrains.compose.material:material-icons-extended", version = "1.7.3" }
|
||||
compose-material3 = { module = "org.jetbrains.compose.material3:material3", version = "1.9.0" }
|
||||
compose-material3-adaptive = { module = "org.jetbrains.compose.material3.adaptive:adaptive", version = "1.2.0" }
|
||||
compose-ui-backhandler = { module = "org.jetbrains.compose.ui:ui-backhandler", version.ref = "compose-multiplatform" }
|
||||
compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling" }
|
||||
compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview" }
|
||||
compose-ui-util = { module = "androidx.compose.ui:ui-util" }
|
||||
compose-ui-tooling-preview = { module = "org.jetbrains.compose.ui:ui-tooling-preview", version.ref = "compose-multiplatform" }
|
||||
|
||||
compose-destinations-core = { module = "io.github.raamcosta.compose-destinations:core", version.ref = "compose-destinations" }
|
||||
compose-destinations-compiler = { module = "io.github.raamcosta.compose-destinations:ksp", version.ref = "compose-destinations" }
|
||||
@@ -86,20 +88,21 @@ compose-destinations-compiler = { module = "io.github.raamcosta.compose-destinat
|
||||
compose-preference = { module = "me.zhanghai.compose.preference:preference", version.ref = "compose-preference" }
|
||||
|
||||
material-motion-core = "io.github.fornewid:material-motion-compose-core:2.0.1"
|
||||
material-kolor = "com.materialkolor:material-kolor:3.0.1"
|
||||
material-kolor = "com.materialkolor:material-kolor:4.0.5"
|
||||
|
||||
desugar = "com.android.tools:desugar_jdk_libs:2.1.5"
|
||||
|
||||
diff = "io.github.petertrr:kotlin-multiplatform-diff:1.1.0"
|
||||
diff = "io.github.petertrr:kotlin-multiplatform-diff:1.2.0"
|
||||
|
||||
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" }
|
||||
kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinx-coroutines" }
|
||||
kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinx-datetime" }
|
||||
kotlinx-io = { module = "org.jetbrains.kotlinx:kotlinx-io-core", version.ref = "kotlinx-io" }
|
||||
|
||||
ktlint = "com.pinterest.ktlint:ktlint-cli:1.7.1"
|
||||
ktlint = "com.pinterest.ktlint:ktlint-cli:1.8.0"
|
||||
|
||||
okhttp-bom = { module = "com.squareup.okhttp3:okhttp-bom", version.ref = "okhttp" }
|
||||
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
|
||||
ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" }
|
||||
|
||||
logcat = "com.squareup.logcat:logcat:0.4"
|
||||
@@ -118,7 +121,6 @@ serialization-xml = { module = "io.github.pdvrieze.xmlutil:serialization", versi
|
||||
serialization-xml-io = { module = "io.github.pdvrieze.xmlutil:serialization-io", version.ref = "xmlutil" }
|
||||
|
||||
splitties-appctx = { module = "com.louiscad.splitties:splitties-appctx", version.ref = "splitties" }
|
||||
splitties-arch-room = { module = "com.louiscad.splitties:splitties-arch-room", version.ref = "splitties" }
|
||||
splitties-systemservices = { module = "com.louiscad.splitties:splitties-systemservices", version.ref = "splitties" }
|
||||
|
||||
telephoto-zoomable = { module = "me.saket.telephoto:zoomable", version.ref = "telephoto" }
|
||||
@@ -135,9 +137,8 @@ spotless-gradlePlugin = { module = "com.diffplug.spotless:spotless-plugin-gradle
|
||||
[bundles]
|
||||
arrow = ["arrow-fx-coroutines", "arrow-functions", "arrow-resilience"]
|
||||
coil = ["coil-compose", "coil-gif", "coil-network"]
|
||||
compose = ["compose-foundation", "compose-material-icons-extended", "compose-material3", "compose-material3-adaptive", "compose-ui-util"]
|
||||
kotlinx-serialization = ["serialization-cbor", "serialization-json", "serialization-json-io", "serialization-xml", "serialization-xml-io"]
|
||||
splitties = ["splitties-appctx", "splitties-arch-room", "splitties-systemservices"]
|
||||
splitties = ["splitties-appctx", "splitties-systemservices"]
|
||||
|
||||
[plugins]
|
||||
aboutlibraries = { id = "com.mikepenz.aboutlibraries.plugin", version.ref = "aboutlibraries" }
|
||||
|
||||
Vendored
BIN
Binary file not shown.
+1
-1
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
+9
-16
@@ -15,19 +15,18 @@
|
||||
"matchStrings": [
|
||||
"(?<depName>\\S*)\\s*GIT_REPOSITORY https://(?<datasource>.*?)\\.com/(?<packageName>.*?)\\.git\\s*GIT_TAG (?<currentValue>\\S*)"
|
||||
],
|
||||
"datasourceTemplate": "{{{datasource}}}-tags"
|
||||
"datasourceTemplate": "{{datasource}}-tags"
|
||||
},
|
||||
{
|
||||
"customType": "regex",
|
||||
"managerFilePatterns": [
|
||||
"chrome.version"
|
||||
"/(^|/)CMakeLists\\.txt$/"
|
||||
],
|
||||
"matchStrings": [
|
||||
"(?<currentValue>\\S+)"
|
||||
"(/(?<depName>[^/]+)){2}-(?<currentValue>.+)\\.tar\\.gz"
|
||||
],
|
||||
"depNameTemplate": "chrome",
|
||||
"datasourceTemplate": "custom.chrome",
|
||||
"extractVersionTemplate": "^(?<version>\\d+)"
|
||||
"datasourceTemplate": "custom.gnu",
|
||||
"extractVersionTemplate": "{{depName}}-(?<version>.+)\\.tar\\.gz$"
|
||||
},
|
||||
{
|
||||
"customType": "regex",
|
||||
@@ -54,10 +53,6 @@
|
||||
}
|
||||
],
|
||||
"customDatasources": {
|
||||
"chrome": {
|
||||
"defaultRegistryUrlTemplate": "https://googlechromelabs.github.io/chrome-for-testing/LATEST_RELEASE_STABLE",
|
||||
"format": "plain"
|
||||
},
|
||||
"rust-nightly": {
|
||||
"defaultRegistryUrlTemplate": "https://rust-lang.github.io/rustup-components-history/aarch64-linux-android/rust-std",
|
||||
"format": "plain"
|
||||
@@ -67,6 +62,10 @@
|
||||
"transformTemplates": [
|
||||
"{\"releases\":[{\"version\":$match(body,/ndkVersion \"([^\"]+)\"/).groups[0]}],\"changelogUrl\":html_url}"
|
||||
]
|
||||
},
|
||||
"gnu": {
|
||||
"defaultRegistryUrlTemplate": "https://ftpmirror.gnu.org/{{packageName}}/",
|
||||
"format": "html"
|
||||
}
|
||||
},
|
||||
"packageRules": [
|
||||
@@ -92,12 +91,6 @@
|
||||
],
|
||||
"allowedVersions": "!/compat$/"
|
||||
},
|
||||
{
|
||||
"matchDepNames": [
|
||||
"nettle"
|
||||
],
|
||||
"versioning": "regex:^nettle_(?<major>\\d+)\\.(?<minor>\\d+)(?:\\.(?<patch>\\d+))?(?<prerelease>rc\\d+)?"
|
||||
},
|
||||
{
|
||||
"matchDepNames": [
|
||||
"rust-nightly"
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
[toolchain]
|
||||
channel = "nightly-2025-10-05"
|
||||
channel = "nightly-2025-11-15"
|
||||
components = ["rustfmt", "clippy", "rust-src"]
|
||||
targets = ["aarch64-linux-android", "x86_64-linux-android"]
|
||||
profile = "minimal"
|
||||
+1
-1
@@ -28,7 +28,7 @@ dependencyResolutionManagement {
|
||||
}
|
||||
|
||||
plugins {
|
||||
id("com.android.settings") version "8.13.0"
|
||||
id("com.android.settings") version "8.13.2"
|
||||
}
|
||||
|
||||
android {
|
||||
|
||||
Reference in new issue
Block a user