Compare commits
219
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ce008f5576 | ||
|
|
25f7e8b35c | ||
|
|
109398d955 | ||
|
|
4a8551087b | ||
|
|
34febe3545 | ||
|
|
53a0307a8e | ||
|
|
1c6f624fd1 | ||
|
|
780e5f08f9 | ||
|
|
1bb73b1147 | ||
|
|
09b0d4d6c4 | ||
|
|
7e3856fa05 | ||
|
|
fbcb3f5436 | ||
|
|
324b4ced06 | ||
|
|
79c2abe790 | ||
|
|
cdab9168fc | ||
|
|
ce272724de | ||
|
|
2fa0a19d3b | ||
|
|
38b9a6e04a | ||
|
|
22d3c2b6bf | ||
|
|
218a8397c4 | ||
|
|
fd990da71e | ||
|
|
4a70c89a4d | ||
|
|
7e3143678f | ||
|
|
d80e09dfba | ||
|
|
3b3b251c21 | ||
|
|
1e848bd70f | ||
|
|
fab2295445 | ||
|
|
a913bccc9e | ||
|
|
57e7f89814 | ||
|
|
f98fd5e5f1 | ||
|
|
e6af2e5c6b | ||
|
|
d219989ec7 | ||
|
|
b9daf608ff | ||
|
|
869da61fd0 | ||
|
|
9f79e2505c | ||
|
|
3000b36dbd | ||
|
|
1d21b0e5c4 | ||
|
|
8d6b0926d6 | ||
|
|
4c39d13c80 | ||
|
|
327dd1c73f | ||
|
|
b36b8f3234 | ||
|
|
5f6da284fb | ||
|
|
83d27e18cb | ||
|
|
e291bd58a8 | ||
|
|
23acdb6492 | ||
|
|
3b5e56b049 | ||
|
|
57d4967f2a | ||
|
|
80fcda149b | ||
|
|
1a86eef52c | ||
|
|
98d401f9c3 | ||
|
|
0f2fae886e | ||
|
|
f30a9093af | ||
|
|
b4334da202 | ||
|
|
416fb3bda9 | ||
|
|
7e0fc2e364 | ||
|
|
540d290be2 | ||
|
|
53974ad88d | ||
|
|
cd9b5e5a44 | ||
|
|
d9959bbcb2 | ||
|
|
d7dfd53244 | ||
|
|
84489bf61b | ||
|
|
3fdb56390e | ||
|
|
a34e766f70 | ||
|
|
d74023d4fa | ||
|
|
41572e98ba | ||
|
|
063087c87e | ||
|
|
4a5d53d713 | ||
|
|
9a262525ec | ||
|
|
e327b4e84b | ||
|
|
c128a2b518 | ||
|
|
a3263ab4af | ||
|
|
4a4efe4725 | ||
|
|
89d2433369 | ||
|
|
023175ce6d | ||
|
|
21c8d24d57 | ||
|
|
e49f5c95f4 | ||
|
|
6912e578ca | ||
|
|
8680cff2b2 | ||
|
|
aea75d44e3 | ||
|
|
80481f1778 | ||
|
|
3ea7ff8202 | ||
|
|
b5979c0528 | ||
|
|
f0f79a52b8 | ||
|
|
b549acc1de | ||
|
|
2505cc5d00 | ||
|
|
d5af66b3fc | ||
|
|
f680dc7e46 | ||
|
|
ffd8bbb1ce | ||
|
|
216a043094 | ||
|
|
021eb5f828 | ||
|
|
f3bf8849e9 | ||
|
|
128f7100d7 | ||
|
|
2cf53dd00f | ||
|
|
4a674e46e6 | ||
|
|
f6b0134fdb | ||
|
|
675a6b863e | ||
|
|
b570eeef93 | ||
|
|
71a8b4e607 | ||
|
|
89b866b0fc | ||
|
|
bcce20d9ac | ||
|
|
420e760fb3 | ||
|
|
a168c95d79 | ||
|
|
d8ccec45f9 | ||
|
|
1316875602 | ||
|
|
a85387c7c8 | ||
|
|
d357e83d06 | ||
|
|
51546f6fea | ||
|
|
b4aa5ec593 | ||
|
|
909380f592 | ||
|
|
d5f26643bf | ||
|
|
a15dc4afdf | ||
|
|
b317bc334e | ||
|
|
d0a8d08b26 | ||
|
|
f73a922a8e | ||
|
|
c6682ce718 | ||
|
|
764d1137ae | ||
|
|
02fc972a79 | ||
|
|
7fc727cf2e | ||
|
|
d77e1e6820 | ||
|
|
241d9daae9 | ||
|
|
462e0257a9 | ||
|
|
66fbc7e821 | ||
|
|
3c37f22027 | ||
|
|
0d24bc6602 | ||
|
|
5a50df8179 | ||
|
|
f1251fd150 | ||
|
|
16202efc7b | ||
|
|
26c6052286 | ||
|
|
7ce386a7b8 | ||
|
|
e43cd0a039 | ||
|
|
70be405032 | ||
|
|
9f3ad8142a | ||
|
|
51d9ece30c | ||
|
|
d8e79f879f | ||
|
|
76d50b56ee | ||
|
|
c8d1e957a1 | ||
|
|
b287af4824 | ||
|
|
416ef8d6d7 | ||
|
|
7c71abb985 | ||
|
|
900f2462a7 | ||
|
|
dd982c6cb9 | ||
|
|
927a011c9d | ||
|
|
ad0ad47a40 | ||
|
|
71a424c15d | ||
|
|
145b7049a8 | ||
|
|
323d258bc2 | ||
|
|
56ba52d7b9 | ||
|
|
54bd6f6ed8 | ||
|
|
f06167ba4b | ||
|
|
60438ae1ed | ||
|
|
1b87750b87 | ||
|
|
40cdc566c8 | ||
|
|
428ae07e7f | ||
|
|
481ad22b53 | ||
|
|
65f58b93ed | ||
|
|
45411fa14d | ||
|
|
8ba1ba4fb1 | ||
|
|
8427e1b3a5 | ||
|
|
32f0f2a0cf | ||
|
|
8b94997cde | ||
|
|
bd2d54f774 | ||
|
|
34be285510 | ||
|
|
7b906f3c3e | ||
|
|
82ba22cda2 | ||
|
|
b1a9601ae9 | ||
|
|
7c1a297a99 | ||
|
|
a8195c0e7c | ||
|
|
08713e3922 | ||
|
|
0485d52e3e | ||
|
|
8b1723e19b | ||
|
|
9cb683dc55 | ||
|
|
dce1589c19 | ||
|
|
107cf16d36 | ||
|
|
2bab97c829 | ||
|
|
5242d825c2 | ||
|
|
11d3799b03 | ||
|
|
55c7f6b896 | ||
|
|
a09d607177 | ||
|
|
626a101208 | ||
|
|
f4ca3acbf6 | ||
|
|
86835a3bd7 | ||
|
|
0ef46e2e11 | ||
|
|
04878447b7 | ||
|
|
3669d5d90e | ||
|
|
ee5e222a13 | ||
|
|
9ea44ff59a | ||
|
|
0474e2c0f5 | ||
|
|
4a909d4b93 | ||
|
|
8dbe24ab55 | ||
|
|
25f7b005cb | ||
|
|
23f55ea208 | ||
|
|
5f19fa0f1f | ||
|
|
58fbdcfcdd | ||
|
|
e33cca9fd9 | ||
|
|
b25e3d5454 | ||
|
|
583f272daa | ||
|
|
2a83ad63be | ||
|
|
6fdc908ad1 | ||
|
|
5213caac49 | ||
|
|
ca0518c747 | ||
|
|
298cd29537 | ||
|
|
1a963a3239 | ||
|
|
683c8dc5c5 | ||
|
|
2087970de6 | ||
|
|
5bd270fe6a | ||
|
|
0992fcfcb0 | ||
|
|
fc12395f7e | ||
|
|
57b291a4e8 | ||
|
|
3adf391478 | ||
|
|
a859941845 | ||
|
|
8d1fc85638 | ||
|
|
51ece1c472 | ||
|
|
45f67ec37f | ||
|
|
85b559c989 | ||
|
|
1382050b5f | ||
|
|
fb970752fd | ||
|
|
3d256a402f | ||
|
|
a677d95d34 | ||
|
|
452c0f2846 |
No files matched your search
@@ -56,3 +56,10 @@ jobs:
|
||||
with:
|
||||
name: x86-${{ github.sha }}
|
||||
path: app/build/outputs/apk/release/app-x86-release.apk
|
||||
|
||||
- name: Update mapping
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: mapping-${{ github.sha }}
|
||||
path: app/build/outputs/mapping/release/mapping.txt
|
||||
retention-days: 5
|
||||
@@ -49,6 +49,7 @@ jobs:
|
||||
app/build/outputs/apk/release/EhViewer-x86_64.apk
|
||||
app/build/outputs/apk/release/EhViewer-x86.apk
|
||||
app/build/outputs/apk/release/EhViewer-armeabi-v7a.apk
|
||||
app/build/outputs/mapping/release/mapping.txt
|
||||
|
||||
- name: Collect Apks
|
||||
run: |
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
</p>
|
||||
|
||||
<h1 align="center">
|
||||
<img src="art/launcher_icon-web.svg" width="200">
|
||||
<img src="https://github.com/Ehviewer-Overhauled/Art/blob/master/launcher_icon-web.svg" width="200">
|
||||
<br>EhViewer<br>
|
||||
</h1>
|
||||
|
||||
@@ -66,12 +66,12 @@ with Material Design 3 and Dynamic Color Support
|
||||
|
||||
# Download
|
||||
|
||||
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/releases"><img alt="Get it on GitHub" src="art/get-it-on-github.svg" width="200px"/></a> <a href="https://github.com/Ehviewer-Overhauled/fdroid-repo"><img alt="Git it on F-Droid" src="art/get-it-on-fdroid.svg" width="200px"/></a>
|
||||
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/releases"><img alt="Get it on GitHub" src="https://github.com/Ehviewer-Overhauled/Art/blob/master/get-it-on-github.svg" width="200px"/></a> <a href="https://github.com/Ehviewer-Overhauled/fdroid-repo"><img alt="Git it on F-Droid" src="https://github.com/Ehviewer-Overhauled/Art/blob/master/get-it-on-fdroid.svg" width="200px"/></a>
|
||||
|
||||
# Screenshot
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
# Thanks
|
||||
|
||||
@@ -94,7 +94,7 @@ Here is the libraries
|
||||
|
||||
Copyright 2014-2019 Hippo Seven
|
||||
Copyright 2020-2022 NekoInverter
|
||||
Copyright 2022 Tarsin Norbin
|
||||
Copyright 2022-2023 Tarsin Norbin
|
||||
|
||||
EhViewer is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
|
||||
+27
-27
@@ -1,6 +1,7 @@
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'org.jetbrains.kotlin.android'
|
||||
id 'kotlin-android'
|
||||
id 'kotlin-parcelize'
|
||||
id 'com.google.devtools.ksp'
|
||||
}
|
||||
|
||||
@@ -31,8 +32,8 @@ android {
|
||||
applicationId "moe.tarsin.ehviewer"
|
||||
minSdkVersion 28
|
||||
targetSdkVersion 33
|
||||
versionCode 180026
|
||||
versionName "1.8.4.0-alpha02"
|
||||
versionCode 180030
|
||||
versionName "1.8.5.3-alpha02"
|
||||
resConfigs 'zh', 'zh-rCN', 'zh-rHK', 'zh-rTW', 'es', 'ja', 'ko', 'fr', 'de', 'th'
|
||||
}
|
||||
|
||||
@@ -52,10 +53,6 @@ android {
|
||||
freeCompilerArgs += [
|
||||
// https://kotlinlang.org/docs/compiler-reference.html#progressive
|
||||
"-progressive",
|
||||
// Generate smaller bytecode by not generating runtime not-null assertions.
|
||||
"-Xno-call-assertions",
|
||||
"-Xno-param-assertions",
|
||||
"-Xno-receiver-assertions",
|
||||
"-P",
|
||||
"plugin:androidx.compose.compiler.plugins.kotlin:suppressKotlinVersionCompatibilityCheck=true"
|
||||
]
|
||||
@@ -94,6 +91,7 @@ android {
|
||||
buildFeatures {
|
||||
buildConfig true
|
||||
compose true
|
||||
viewBinding true
|
||||
}
|
||||
|
||||
composeOptions {
|
||||
@@ -105,12 +103,11 @@ android {
|
||||
|
||||
dependencies {
|
||||
def activity_version = "1.6.1"
|
||||
implementation "androidx.activity:activity:$activity_version"
|
||||
implementation "androidx.activity:activity-ktx:$activity_version"
|
||||
|
||||
implementation "androidx.annotation:annotation:1.5.0"
|
||||
implementation "androidx.annotation:annotation-experimental:1.3.0"
|
||||
implementation "androidx.appcompat:appcompat:1.6.0-rc01"
|
||||
implementation "androidx.appcompat:appcompat:1.7.0-alpha01"
|
||||
|
||||
def arch_core_version = "2.1.0"
|
||||
implementation "androidx.arch.core:core-common:$arch_core_version"
|
||||
@@ -123,28 +120,25 @@ dependencies {
|
||||
implementation "androidx.collection:collection:$collection_version"
|
||||
implementation "androidx.collection:collection-ktx:$collection_version"
|
||||
|
||||
def compose_version = "1.3.1"
|
||||
implementation "androidx.compose.animation:animation:$compose_version"
|
||||
implementation "androidx.compose.foundation:foundation:$compose_version"
|
||||
implementation "androidx.compose.foundation:foundation-layout:$compose_version"
|
||||
implementation "androidx.compose.runtime:runtime:$compose_version"
|
||||
implementation "androidx.compose.runtime:runtime-saveable:$compose_version"
|
||||
implementation "androidx.compose.ui:ui:$compose_version"
|
||||
|
||||
implementation "androidx.compose.material3:material3:1.0.1"
|
||||
implementation platform("androidx.compose:compose-bom:2022.12.00")
|
||||
implementation "androidx.compose.animation:animation"
|
||||
implementation "androidx.compose.foundation:foundation"
|
||||
implementation "androidx.compose.foundation:foundation-layout"
|
||||
implementation "androidx.compose.material3:material3"
|
||||
implementation "androidx.compose.runtime:runtime"
|
||||
implementation "androidx.compose.runtime:runtime-saveable"
|
||||
implementation "androidx.compose.ui:ui"
|
||||
|
||||
implementation "androidx.constraintlayout:constraintlayout:2.2.0-alpha05"
|
||||
implementation "androidx.coordinatorlayout:coordinatorlayout:1.2.0"
|
||||
|
||||
def core_version = "1.9.0"
|
||||
implementation "androidx.core:core:$core_version"
|
||||
implementation "androidx.core:core-ktx:$core_version"
|
||||
|
||||
implementation "androidx.customview:customview:1.2.0-alpha02"
|
||||
implementation "androidx.dynamicanimation:dynamicanimation:1.1.0-alpha03"
|
||||
|
||||
def fragment_version = "1.6.0-alpha04"
|
||||
implementation "androidx.fragment:fragment:$fragment_version"
|
||||
implementation "androidx.fragment:fragment-ktx:$fragment_version"
|
||||
|
||||
def lifecycle_version = "2.6.0-alpha03"
|
||||
@@ -158,19 +152,17 @@ dependencies {
|
||||
implementation "androidx.loader:loader:1.1.0"
|
||||
|
||||
def nav_version = "2.5.3"
|
||||
implementation "androidx.navigation:navigation-fragment:$nav_version"
|
||||
implementation "androidx.navigation:navigation-ui:$nav_version"
|
||||
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
|
||||
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
|
||||
|
||||
implementation "androidx.paging:paging-runtime:3.2.0-alpha03"
|
||||
implementation "androidx.paging:paging-runtime-ktx:3.2.0-alpha03"
|
||||
|
||||
implementation 'androidx.preference:preference:1.2.0'
|
||||
implementation 'androidx.preference:preference-ktx:1.2.0'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.3.0-rc01'
|
||||
|
||||
def room_version = "2.5.0-rc01"
|
||||
implementation "androidx.room:room-runtime:$room_version"
|
||||
annotationProcessor "androidx.room:room-compiler:$room_version"
|
||||
ksp "androidx.room:room-compiler:$room_version"
|
||||
implementation "androidx.room:room-paging:$room_version"
|
||||
|
||||
implementation 'androidx.startup:startup-runtime:1.2.0-alpha01'
|
||||
@@ -182,10 +174,11 @@ dependencies {
|
||||
implementation 'androidx.viewpager2:viewpager2:1.1.0-beta01'
|
||||
|
||||
implementation 'com.drakeet.drawer:drawer:1.0.3'
|
||||
implementation 'com.google.android.material:material:1.8.0-SNAPSHOT'
|
||||
implementation 'com.google.android.material:material:1.8.0-beta01'
|
||||
|
||||
implementation 'com.squareup.okhttp3:okhttp-bom:5.0.0-alpha.10'
|
||||
implementation 'com.squareup.okhttp3:okhttp-bom:5.0.0-alpha.11'
|
||||
implementation 'com.squareup.okhttp3:okhttp'
|
||||
implementation 'com.squareup.okhttp3:okhttp-coroutines'
|
||||
|
||||
implementation 'dev.rikka.rikkax.core:core-ktx:1.4.1'
|
||||
implementation 'dev.rikka.rikkax.insets:insets:1.3.0'
|
||||
@@ -195,10 +188,17 @@ dependencies {
|
||||
implementation 'io.coil-kt:coil:2.2.2'
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'
|
||||
implementation 'org.jsoup:jsoup:1.15.3'
|
||||
|
||||
// Tachiyomi Reader
|
||||
implementation 'com.github.chrisbanes:PhotoView:2.3.0'
|
||||
implementation 'dev.chrisbanes.insetter:insetter:0.6.1'
|
||||
}
|
||||
|
||||
configurations.all {
|
||||
exclude group: 'dev.rikka.rikkax.appcompat', module: 'appcompat'
|
||||
exclude group: 'dev.rikka.rikkax.material', module: 'material'
|
||||
exclude group: 'androidx.compose.material'
|
||||
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-android-extensions-runtime'
|
||||
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk7'
|
||||
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk8'
|
||||
}
|
||||
Vendored
+4
-9
@@ -2,20 +2,15 @@
|
||||
public static final ** CREATOR;
|
||||
}
|
||||
|
||||
-assumenosideeffects class kotlin.jvm.internal.Intrinsics {
|
||||
public static void check*(...);
|
||||
public static void throw*(...);
|
||||
}
|
||||
|
||||
-keepclasseswithmembernames,includedescriptorclasses class * {
|
||||
native <methods>;
|
||||
}
|
||||
|
||||
-keep,allowoptimization class com.hippo.ehviewer.ui.fragment.* extends com.hippo.ehviewer.ui.fragment.BaseFragment { }
|
||||
-keep,allowoptimization class com.hippo.ehviewer.ui.fragment.* extends com.hippo.ehviewer.ui.fragment.BasePreferenceFragment { }
|
||||
-keep class androidx.viewpager.widget.ViewPager$LayoutParams { int position; }
|
||||
|
||||
-keepattributes LineNumberTable,SourceFile
|
||||
-renamesourcefileattribute SourceFile
|
||||
|
||||
-renamesourcefileattribute
|
||||
-repackageclasses
|
||||
-allowaccessmodification
|
||||
-mergeinterfacesaggressively
|
||||
-overloadaggressively
|
||||
@@ -14,7 +14,8 @@
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-feature
|
||||
android:name="android.software.leanback"
|
||||
@@ -32,10 +33,6 @@
|
||||
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="28" />
|
||||
|
||||
<uses-feature
|
||||
android:glEsVersion="0x00020000"
|
||||
android:required="true" />
|
||||
|
||||
<application
|
||||
android:name="com.hippo.ehviewer.EhApplication"
|
||||
android:allowBackup="true"
|
||||
@@ -45,12 +42,13 @@
|
||||
android:fullBackupContent="@xml/backup_scheme"
|
||||
android:hasFragileUserData="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:supportsRtl="true"
|
||||
android:label="@string/app_name"
|
||||
android:largeHeap="true"
|
||||
android:localeConfig="@xml/locales_config"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:theme="@style/AppTheme">
|
||||
android:theme="@style/AppTheme"
|
||||
tools:targetApi="tiramisu">
|
||||
|
||||
<activity
|
||||
android:name="com.hippo.ehviewer.ui.MainActivity"
|
||||
@@ -102,7 +100,7 @@
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="com.hippo.ehviewer.ui.GalleryActivity"
|
||||
android:name="eu.kanade.tachiyomi.ui.reader.ReaderActivity"
|
||||
android:configChanges="screenSize"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTask">
|
||||
@@ -160,6 +158,15 @@
|
||||
android:taskAffinity=""
|
||||
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
|
||||
|
||||
<service
|
||||
android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
|
||||
android:enabled="false"
|
||||
android:exported="false">
|
||||
<meta-data
|
||||
android:name="autoStoreLocales"
|
||||
android:value="true" />
|
||||
</service>
|
||||
|
||||
<service
|
||||
android:name="com.hippo.ehviewer.download.DownloadService"
|
||||
android:foregroundServiceType="dataSync"
|
||||
|
||||
@@ -45,6 +45,6 @@ SET(LIBARCHIVE_CUSTOM_LIBS "liblzma" "nettle")
|
||||
add_subdirectory(libarchive)
|
||||
|
||||
# Build and link our app's native lib
|
||||
add_library(${PROJECT_NAME} SHARED archive.c image.c fdutils.c)
|
||||
add_library(${PROJECT_NAME} SHARED archive.c fdutils.c)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC libarchive/libarchive)
|
||||
target_link_libraries(${PROJECT_NAME} archive_static log jnigraphics GLESv2 -Wl,--gc-sections)
|
||||
target_link_libraries(${PROJECT_NAME} archive_static log -Wl,--gc-sections)
|
||||
@@ -43,6 +43,11 @@ typedef struct {
|
||||
struct archive_entry *entry;
|
||||
} archive_ctx;
|
||||
|
||||
typedef struct {
|
||||
const char *filename;
|
||||
int index;
|
||||
} entry;
|
||||
|
||||
pthread_mutex_t ctx_lock;
|
||||
static archive_ctx **ctx_pool;
|
||||
#define CTX_POOL_SIZE 20
|
||||
@@ -51,6 +56,8 @@ static bool need_encrypt = false;
|
||||
static char *passwd = NULL;
|
||||
static void *archiveAddr = NULL;
|
||||
static size_t archiveSize = 0;
|
||||
static entry *entries = NULL;
|
||||
static size_t entryCount = 0;
|
||||
|
||||
#define POPULATE_THRESHOLD (512 * 1024 * 1024) // 512 MiB
|
||||
|
||||
@@ -77,6 +84,30 @@ static inline int filename_is_playable_file(const char *name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline int compare_entries(const void *a, const void *b) {
|
||||
const char *fa = ((entry *) a)->filename;
|
||||
const char *fb = ((entry *) b)->filename;
|
||||
int a_len = (int) strlen(fa);
|
||||
int b_len = (int) strlen(fb);
|
||||
return a_len == b_len ? strcmp(fa, fb) : a_len - b_len;
|
||||
}
|
||||
|
||||
static long archive_map_entries_index(archive_ctx *ctx) {
|
||||
long count = 0;
|
||||
while (archive_read_next_header(ctx->arc, &ctx->entry) == ARCHIVE_OK) {
|
||||
const char *name = archive_entry_pathname(ctx->entry);
|
||||
if (filename_is_playable_file(name)) {
|
||||
entries[count].filename = strdup(name);
|
||||
entries[count].index = count;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (!count)
|
||||
LOGE("%s", archive_error_string(ctx->arc));
|
||||
qsort(entries, entryCount, sizeof(entry), compare_entries);
|
||||
return count;
|
||||
}
|
||||
|
||||
static long archive_list_all_entries(archive_ctx *ctx) {
|
||||
long count = 0;
|
||||
while (archive_read_next_header(ctx->arc, &ctx->entry) == ARCHIVE_OK)
|
||||
@@ -221,10 +252,9 @@ Java_com_hippo_UriArchiveAccessor_openArchive(JNIEnv *env, jobject thiz, jint fd
|
||||
if (r) {
|
||||
if (r == -ENOMEM)
|
||||
LOGE("%s", "Mem alloc failed");
|
||||
r = 0;
|
||||
LOGE("%s%s", "Archive open failed:", archive_error_string(ctx->arc));
|
||||
} else {
|
||||
r = archive_list_all_entries(ctx);
|
||||
entryCount = archive_list_all_entries(ctx);
|
||||
LOGI("%s%ld%s", "Found ", r, " image entries in archive");
|
||||
|
||||
// We must read through the file|vm then we can know whether it is encrypted
|
||||
@@ -251,6 +281,19 @@ Java_com_hippo_UriArchiveAccessor_openArchive(JNIEnv *env, jobject thiz, jint fd
|
||||
}
|
||||
}
|
||||
|
||||
archive_release_ctx(ctx);
|
||||
|
||||
r = archive_alloc_ctx(&ctx);
|
||||
if (r) {
|
||||
if (r == -ENOMEM)
|
||||
LOGE("%s", "Mem alloc failed");
|
||||
r = 0;
|
||||
LOGE("%s%s", "Archive open failed:", archive_error_string(ctx->arc));
|
||||
} else {
|
||||
entries = calloc(entryCount, sizeof(entry));
|
||||
r = archive_map_entries_index(ctx);
|
||||
}
|
||||
|
||||
archive_release_ctx(ctx);
|
||||
return r;
|
||||
}
|
||||
@@ -259,6 +302,7 @@ JNIEXPORT jobject JNICALL
|
||||
Java_com_hippo_UriArchiveAccessor_extractToByteBuffer(JNIEnv *env, jobject thiz, jint index) {
|
||||
EH_UNUSED(env);
|
||||
EH_UNUSED(thiz);
|
||||
index = entries[index].index;
|
||||
archive_ctx *ctx = NULL;
|
||||
int ret;
|
||||
ret = archive_get_ctx(&ctx, index);
|
||||
@@ -295,6 +339,10 @@ Java_com_hippo_UriArchiveAccessor_closeArchive(JNIEnv *env, jobject thiz) {
|
||||
passwd = NULL;
|
||||
need_encrypt = false;
|
||||
munmap(archiveAddr, archiveSize);
|
||||
for (int i = 0; i < entryCount; ++i) {
|
||||
free((void *) entries[i].filename);
|
||||
}
|
||||
free(entries);
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
@@ -338,6 +386,7 @@ JNIEXPORT jstring JNICALL
|
||||
Java_com_hippo_UriArchiveAccessor_getFilename(JNIEnv *env, jobject thiz, jint index) {
|
||||
EH_UNUSED(env);
|
||||
EH_UNUSED(thiz);
|
||||
index = entries[index].index;
|
||||
archive_ctx *ctx = NULL;
|
||||
int ret;
|
||||
ret = archive_get_ctx(&ctx, index);
|
||||
@@ -352,6 +401,7 @@ JNIEXPORT void JNICALL
|
||||
Java_com_hippo_UriArchiveAccessor_extractToFd(JNIEnv *env, jobject thiz, jint index, jint fd) {
|
||||
EH_UNUSED(env);
|
||||
EH_UNUSED(thiz);
|
||||
index = entries[index].index;
|
||||
archive_ctx *ctx = NULL;
|
||||
int ret;
|
||||
ret = archive_get_ctx(&ctx, index);
|
||||
@@ -363,6 +413,7 @@ Java_com_hippo_UriArchiveAccessor_extractToFd(JNIEnv *env, jobject thiz, jint in
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_hippo_UriArchiveAccessor_releaseByteBuffer(JNIEnv *env, jobject thiz, jobject buffer) {
|
||||
EH_UNUSED(thiz);
|
||||
void *addr = (*env)->GetDirectBufferAddress(env, buffer);
|
||||
free(addr);
|
||||
}
|
||||
@@ -1,143 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 Tarsin Norbin
|
||||
*
|
||||
* This file is part of EhViewer
|
||||
*
|
||||
* EhViewer is free software: you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* EhViewer is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* EhViewer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <android/bitmap.h>
|
||||
#include <android/data_space.h>
|
||||
#include <android/log.h>
|
||||
|
||||
#include <GLES2/gl2.h>
|
||||
#include <jni.h>
|
||||
|
||||
#define TAG "ImageDecoder_wrapper"
|
||||
|
||||
#include "ehviewer.h"
|
||||
|
||||
#define IMAGE_TILE_MAX_SIZE (512 * 512)
|
||||
|
||||
static char tile_buffer[IMAGE_TILE_MAX_SIZE * 4];
|
||||
|
||||
bool copy_pixels(const void *src, int src_w, int src_h, int src_x, int src_y,
|
||||
void *dst, int dst_w, int dst_h, int dst_x, int dst_y,
|
||||
int width, int height) {
|
||||
int left;
|
||||
int line;
|
||||
size_t line_stride;
|
||||
int src_stride;
|
||||
int src_pos;
|
||||
int dst_pos;
|
||||
size_t dst_blank_length;
|
||||
|
||||
// Sanitize
|
||||
if (src_x < 0) {
|
||||
width -= src_x;
|
||||
dst_x -= src_x;
|
||||
src_x = 0;
|
||||
}
|
||||
if (dst_x < 0) {
|
||||
width -= dst_x;
|
||||
src_x -= dst_x;
|
||||
dst_x = 0;
|
||||
}
|
||||
if (width <= 0) {
|
||||
return false;
|
||||
}
|
||||
if (src_y < 0) {
|
||||
height -= src_y;
|
||||
dst_y -= src_y;
|
||||
src_y = 0;
|
||||
}
|
||||
if (dst_y < 0) {
|
||||
height -= dst_y;
|
||||
src_y -= dst_y;
|
||||
dst_y = 0;
|
||||
}
|
||||
if (height <= 0) {
|
||||
return false;
|
||||
}
|
||||
left = src_x + width - src_w;
|
||||
if (left > 0) {
|
||||
width -= left;
|
||||
}
|
||||
left = dst_x + width - dst_w;
|
||||
if (left > 0) {
|
||||
width -= left;
|
||||
}
|
||||
if (width <= 0) {
|
||||
return false;
|
||||
}
|
||||
left = src_y + height - src_h;
|
||||
if (left > 0) {
|
||||
height -= left;
|
||||
}
|
||||
left = dst_y + height - dst_h;
|
||||
if (left > 0) {
|
||||
height -= left;
|
||||
}
|
||||
if (height <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Init
|
||||
line_stride = (size_t) (width * 4);
|
||||
src_stride = src_w * 4;
|
||||
src_pos = src_y * src_stride + src_x * 4;
|
||||
dst_pos = 0;
|
||||
|
||||
dst_blank_length = (size_t) (dst_y * dst_w + dst_x) * 4;
|
||||
|
||||
// First line
|
||||
dst_pos += (int) dst_blank_length;
|
||||
memcpy(dst + dst_pos, src + src_pos, line_stride);
|
||||
dst_pos += (int) line_stride;
|
||||
src_pos += src_stride;
|
||||
|
||||
// Other lines
|
||||
dst_blank_length = (size_t) ((dst_w - width) * 4);
|
||||
for (line = 1; line < height; line++) {
|
||||
dst_pos += (int) dst_blank_length;
|
||||
memcpy(dst + dst_pos, src + src_pos, line_stride);
|
||||
dst_pos += (int) line_stride;
|
||||
src_pos += src_stride;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_hippo_image_Image_nativeTexImage(JNIEnv *env, jclass clazz, jobject bitmap, jboolean init,
|
||||
jint offset_x, jint offset_y, jint width, jint height) {
|
||||
if (width * height > IMAGE_TILE_MAX_SIZE)
|
||||
return;
|
||||
AndroidBitmapInfo info;
|
||||
void *pixels = NULL;
|
||||
AndroidBitmap_lockPixels(env, bitmap, &pixels);
|
||||
AndroidBitmap_getInfo(env, bitmap, &info);
|
||||
copy_pixels(pixels, info.width, info.height, offset_x, offset_y, tile_buffer, width, height, 0, 0, width, height);
|
||||
AndroidBitmap_unlockPixels(env, bitmap);
|
||||
if (init) {
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
tile_buffer);
|
||||
} else {
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
tile_buffer);
|
||||
}
|
||||
}
|
||||
Submodule app/src/main/cpp/libarchive updated: 67b9c960d2...c9298fd6dc.
+1
-1
Submodule app/src/main/cpp/liblzma updated: 12b86bd8ca...b35079d589.
@@ -0,0 +1,25 @@
|
||||
package androidx.swiperefreshlayout.widget
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.ShapeDrawable
|
||||
import android.util.AttributeSet
|
||||
import androidx.core.graphics.ColorUtils
|
||||
import rikka.core.res.resolveColor
|
||||
|
||||
|
||||
@SuppressLint("PrivateResource")
|
||||
class ThemedSwipeRefreshLayout @JvmOverloads constructor(
|
||||
context: Context, attrs: AttributeSet? = null
|
||||
) : SwipeRefreshLayout(context, attrs) {
|
||||
|
||||
init {
|
||||
val surfaceColor =
|
||||
context.theme.resolveColor(com.google.android.material.R.attr.colorSurface)
|
||||
val overlayColor =
|
||||
context.getColor(com.google.android.material.R.color.m3_popupmenu_overlay_color)
|
||||
val backgroundColor = ColorUtils.compositeColors(overlayColor, surfaceColor)
|
||||
(mCircleView.background as ShapeDrawable).paint.color = backgroundColor
|
||||
setColorSchemeColors(context.theme.resolveColor(com.google.android.material.R.attr.colorAccent))
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,160 @@
|
||||
package com.davemorrissey.labs.subscaleview
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Rect
|
||||
import android.net.Uri
|
||||
import com.davemorrissey.labs.subscaleview.provider.AssetInputProvider
|
||||
import com.davemorrissey.labs.subscaleview.provider.InputProvider
|
||||
import com.davemorrissey.labs.subscaleview.provider.OpenStreamProvider
|
||||
import com.davemorrissey.labs.subscaleview.provider.ResourceInputProvider
|
||||
import com.davemorrissey.labs.subscaleview.provider.UriInputProvider
|
||||
import java.io.InputStream
|
||||
|
||||
/**
|
||||
* Helper class used to set the source and additional attributes from a variety of sources. Supports
|
||||
* use of a bitmap, asset, resource, external file or any other URI.
|
||||
*
|
||||
*
|
||||
* When you are using a preview image, you must set the dimensions of the full size image on the
|
||||
* ImageSource object for the full size image using the [.dimensions] method.
|
||||
*/
|
||||
class ImageSource {
|
||||
val bitmap: Bitmap?
|
||||
val provider: InputProvider?
|
||||
|
||||
private var sWidth = 0
|
||||
private var sHeight = 0
|
||||
|
||||
var sRegion = Rect(0, 0, 0, 0)
|
||||
private set
|
||||
var isCached = false
|
||||
private set
|
||||
|
||||
private constructor(bitmap: Bitmap, cached: Boolean) {
|
||||
this.bitmap = bitmap
|
||||
provider = null
|
||||
sWidth = bitmap.width
|
||||
sHeight = bitmap.height
|
||||
isCached = cached
|
||||
}
|
||||
|
||||
private constructor(provider: InputProvider) {
|
||||
bitmap = null
|
||||
this.provider = provider
|
||||
}
|
||||
|
||||
/**
|
||||
* Use a region of the source image. Region must be set independently for the full size image and the preview if
|
||||
* you are using one.
|
||||
*
|
||||
* @param sRegion the region of the source image to be displayed.
|
||||
* @return this instance for chaining.
|
||||
*/
|
||||
fun region(sRegion: Rect): ImageSource {
|
||||
this.sRegion = sRegion
|
||||
setInvariants()
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Declare the dimensions of the image. This is only required for a full size image, when you are specifying a URI
|
||||
* and also a preview image. When displaying a bitmap object, or not using a preview, you do not need to declare
|
||||
* the image dimensions. Note if the declared dimensions are found to be incorrect, the view will reset.
|
||||
*
|
||||
* @param sWidth width of the source image.
|
||||
* @param sHeight height of the source image.
|
||||
* @return this instance for chaining.
|
||||
*/
|
||||
fun dimensions(sWidth: Int, sHeight: Int): ImageSource {
|
||||
if (bitmap == null) {
|
||||
this.sWidth = sWidth
|
||||
this.sHeight = sHeight
|
||||
}
|
||||
setInvariants()
|
||||
return this
|
||||
}
|
||||
|
||||
private fun setInvariants() {
|
||||
if (!sRegion.isEmpty) {
|
||||
sWidth = sRegion.width()
|
||||
sHeight = sRegion.height()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Create an instance from a resource. The correct resource for the device screen resolution will be used.
|
||||
*
|
||||
* @param resId resource ID.
|
||||
* @return an [ImageSource] instance.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun resource(context: Context, resId: Int): ImageSource {
|
||||
return ImageSource(ResourceInputProvider(context, resId))
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance from an asset name.
|
||||
*
|
||||
* @param assetName asset name.
|
||||
* @return an [ImageSource] instance.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun asset(context: Context, assetName: String): ImageSource {
|
||||
return ImageSource(AssetInputProvider(context, assetName))
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance from a URI.
|
||||
*
|
||||
* @param uri image URI.
|
||||
* @return an [ImageSource] instance.
|
||||
*/
|
||||
fun uri(context: Context, uri: Uri): ImageSource {
|
||||
return ImageSource(UriInputProvider(context, uri))
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance from an input provider.
|
||||
*
|
||||
* @param provider input stream provider.
|
||||
* @return an [ImageSource] instance.
|
||||
*/
|
||||
fun provider(provider: InputProvider): ImageSource {
|
||||
return ImageSource(provider)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance from an input stream.
|
||||
*
|
||||
* @param stream open input stream.
|
||||
* @return an [ImageSource] instance.
|
||||
*/
|
||||
fun inputStream(stream: InputStream): ImageSource {
|
||||
return ImageSource(OpenStreamProvider(stream))
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a loaded bitmap for display.
|
||||
*
|
||||
* @param bitmap bitmap to be displayed.
|
||||
* @return an [ImageSource] instance.
|
||||
*/
|
||||
fun bitmap(bitmap: Bitmap): ImageSource {
|
||||
return ImageSource(bitmap, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a loaded and cached bitmap for display. This bitmap will not be recycled when it is no
|
||||
* longer needed. Use this method if you loaded the bitmap with an image loader such as Picasso
|
||||
* or Volley.
|
||||
*
|
||||
* @param bitmap bitmap to be displayed.
|
||||
* @return an [ImageSource] instance.
|
||||
*/
|
||||
fun cachedBitmap(bitmap: Bitmap): ImageSource {
|
||||
return ImageSource(bitmap, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.davemorrissey.labs.subscaleview
|
||||
|
||||
import android.graphics.PointF
|
||||
import java.io.Serializable
|
||||
|
||||
/**
|
||||
* Wraps the scale, center and orientation of a displayed image for easy restoration on screen rotate.
|
||||
*/
|
||||
class ImageViewState(val scale: Float, center: PointF) : Serializable {
|
||||
private val centerX: Float = center.x
|
||||
private val centerY: Float = center.y
|
||||
|
||||
val center: PointF
|
||||
get() = PointF(centerX, centerY)
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,53 @@
|
||||
package com.davemorrissey.labs.subscaleview.decoder
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Point
|
||||
import android.graphics.Rect
|
||||
import kotlin.Throws
|
||||
import com.davemorrissey.labs.subscaleview.provider.InputProvider
|
||||
import java.lang.Exception
|
||||
|
||||
/**
|
||||
* Interface for image decoding classes.
|
||||
*/
|
||||
interface Decoder {
|
||||
/**
|
||||
* Initialise the decoder. When possible, perform initial setup work once in this method. The
|
||||
* dimensions of the image must be returned.
|
||||
*
|
||||
* @param context Application context. A reference may be held, but must be cleared on recycle.
|
||||
* @param provider Provider of the image.
|
||||
* @return Dimensions of the image.
|
||||
* @throws Exception if initialisation fails.
|
||||
*/
|
||||
@Throws(Exception::class)
|
||||
fun init(context: Context, provider: InputProvider): Point
|
||||
|
||||
/**
|
||||
* Decode a region of the image with the given sample size. This method is called off the UI
|
||||
* thread so it can safely load the image on the current thread. It is called from
|
||||
* [android.os.AsyncTask]s running in an executor that may have multiple threads, so
|
||||
* implementations must be thread safe. Adding `synchronized` to the method signature
|
||||
* is the simplest way to achieve this, but bear in mind the [.recycle] method can be
|
||||
* called concurrently.
|
||||
*
|
||||
* @param sRect Source image rectangle to decode.
|
||||
* @param sampleSize Sample size.
|
||||
* @return The decoded region. It is safe to return null if decoding fails.
|
||||
*/
|
||||
fun decodeRegion(sRect: Rect, sampleSize: Int): Bitmap
|
||||
|
||||
/**
|
||||
* Status check. Should return false before initialisation and after recycle.
|
||||
*
|
||||
* @return true if the decoder is ready to be used.
|
||||
*/
|
||||
val isReady: Boolean
|
||||
|
||||
/**
|
||||
* This method will be called when the decoder is no longer required. It should clean up any
|
||||
* resources still in use.
|
||||
*/
|
||||
fun recycle()
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.davemorrissey.labs.subscaleview.decoder
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Point
|
||||
import android.graphics.Rect
|
||||
import kotlin.Throws
|
||||
import com.davemorrissey.labs.subscaleview.provider.InputProvider
|
||||
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
|
||||
import java.lang.Exception
|
||||
|
||||
class ImageDecoder @JvmOverloads constructor(
|
||||
private val cropBorders: Boolean,
|
||||
bitmapConfig: Bitmap.Config? = null
|
||||
) : Decoder {
|
||||
init {
|
||||
val globalBitmapConfig = SubsamplingScaleImageView.preferredBitmapConfig
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise the decoder. When possible, perform initial setup work once in this method. The
|
||||
* dimensions of the image must be returned.
|
||||
*
|
||||
* @param context Application context. A reference may be held, but must be cleared on recycle.
|
||||
* @param provider Provider of the image.
|
||||
* @return Dimensions of the image.
|
||||
* @throws Exception if initialisation fails.
|
||||
*/
|
||||
@Throws(Exception::class)
|
||||
override fun init(context: Context, provider: InputProvider): Point {
|
||||
TODO()
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a region of the image with the given sample size. This method is called off the UI
|
||||
* thread so it can safely load the image on the current thread. It is called from
|
||||
* [android.os.AsyncTask]s running in an executor that may have multiple threads, so
|
||||
* implementations must be thread safe. Adding `synchronized` to the method signature
|
||||
* is the simplest way to achieve this, but bear in mind the [.recycle] method can be
|
||||
* called concurrently.
|
||||
*
|
||||
* @param sRect Source image rectangle to decode.
|
||||
* @param sampleSize Sample size.
|
||||
* @return The decoded region. It is safe to return null if decoding fails.
|
||||
*/
|
||||
override fun decodeRegion(sRect: Rect, sampleSize: Int): Bitmap {
|
||||
TODO()
|
||||
}
|
||||
|
||||
/**
|
||||
* Status check. Should return false before initialisation and after recycle.
|
||||
*
|
||||
* @return true if the decoder is ready to be used.
|
||||
*/
|
||||
override val isReady: Boolean = TODO()
|
||||
|
||||
/**
|
||||
* This method will be called when the decoder is no longer required. It should clean up any
|
||||
* resources still in use.
|
||||
*/
|
||||
override fun recycle() {
|
||||
TODO()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.davemorrissey.labs.subscaleview.provider
|
||||
|
||||
import android.content.Context
|
||||
import java.io.IOException
|
||||
|
||||
class AssetInputProvider(context: Context, val assetName: String) : InputProvider {
|
||||
private val assets = context.assets
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun openStream() = assets.open(assetName)
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.davemorrissey.labs.subscaleview.provider
|
||||
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import kotlin.Throws
|
||||
|
||||
interface InputProvider {
|
||||
@Throws(IOException::class)
|
||||
fun openStream(): InputStream?
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.davemorrissey.labs.subscaleview.provider
|
||||
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import kotlin.Throws
|
||||
|
||||
/**
|
||||
* Provider from an already open input stream.
|
||||
*
|
||||
*
|
||||
* Please keep in mind this provider is not reusable.
|
||||
*/
|
||||
class OpenStreamProvider(private val stream: InputStream) : InputProvider {
|
||||
@Throws(IOException::class)
|
||||
override fun openStream() = stream
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package com.davemorrissey.labs.subscaleview.provider
|
||||
|
||||
import android.content.Context
|
||||
import java.io.IOException
|
||||
|
||||
class ResourceInputProvider(context: Context, val resource: Int) : InputProvider {
|
||||
private val resources = context.resources
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun openStream() = resources.openRawResource(resource)
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.davemorrissey.labs.subscaleview.provider
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import java.io.IOException
|
||||
import kotlin.Throws
|
||||
|
||||
class UriInputProvider(context: Context, val uri: Uri) : InputProvider {
|
||||
private val resolver = context.contentResolver
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun openStream() = resolver.openInputStream(uri)
|
||||
}
|
||||
@@ -29,8 +29,6 @@ class UriArchiveAccessor(ctx: Context, uri: Uri) {
|
||||
|
||||
private external fun openArchive(fd: Int, size: Long): Int
|
||||
external fun extractToByteBuffer(index: Int): ByteBuffer?
|
||||
|
||||
external fun releaseByteBuffer(buffer: ByteBuffer)
|
||||
external fun extractToFd(index: Int, fd: Int)
|
||||
external fun getFilename(index: Int): String
|
||||
external fun needPassword(): Boolean
|
||||
@@ -40,4 +38,9 @@ class UriArchiveAccessor(ctx: Context, uri: Uri) {
|
||||
closeArchive()
|
||||
pfd.close()
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
external fun releaseByteBuffer(buffer: ByteBuffer)
|
||||
}
|
||||
}
|
||||
@@ -250,21 +250,7 @@ public final class DiskLruCache implements Closeable {
|
||||
|
||||
private static String inputStreamToString(InputStream in) throws IOException {
|
||||
return Util.readFully(new InputStreamReader(in, Util.UTF_8));
|
||||
} private final Callable<Void> cleanupCallable = new Callable<>() {
|
||||
public Void call() throws Exception {
|
||||
synchronized (DiskLruCache.this) {
|
||||
if (journalWriter == null) {
|
||||
return null; // Closed.
|
||||
}
|
||||
trimToSize();
|
||||
if (journalRebuildRequired()) {
|
||||
rebuildJournal();
|
||||
redundantOpCount = 0;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void readJournal() throws IOException {
|
||||
StrictLineReader reader = new StrictLineReader(new FileInputStream(journalFile), Util.US_ASCII);
|
||||
@@ -366,7 +352,21 @@ public final class DiskLruCache implements Closeable {
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
} private final Callable<Void> cleanupCallable = new Callable<>() {
|
||||
public Void call() throws Exception {
|
||||
synchronized (DiskLruCache.this) {
|
||||
if (journalWriter == null) {
|
||||
return null; // Closed.
|
||||
}
|
||||
trimToSize();
|
||||
if (journalRebuildRequired()) {
|
||||
rebuildJournal();
|
||||
redundantOpCount = 0;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new journal that omits redundant information. This replaces the
|
||||
|
||||
@@ -23,6 +23,7 @@ import androidx.annotation.Nullable;
|
||||
|
||||
import com.hippo.streampipe.InputStreamPipe;
|
||||
import com.hippo.streampipe.OutputStreamPipe;
|
||||
import com.hippo.util.HashCodeUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -85,32 +86,13 @@ public class SimpleDiskCache {
|
||||
try {
|
||||
final MessageDigest digest = MessageDigest.getInstance("MD5");
|
||||
digest.update(key.getBytes());
|
||||
cacheKey = bytesToHexString(digest.digest());
|
||||
cacheKey = HashCodeUtils.bytesToHexString(digest.digest());
|
||||
} catch (final NoSuchAlgorithmException e) {
|
||||
cacheKey = String.valueOf(key.hashCode());
|
||||
}
|
||||
return cacheKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* http://stackoverflow.com/questions/332079
|
||||
*
|
||||
* @param bytes The bytes to convert.
|
||||
* @return A {@link String} converted from the bytes of a hashable key used
|
||||
* to store a filename on the disk, to hex digits.
|
||||
*/
|
||||
private static String bytesToHexString(final byte[] bytes) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
for (final byte b : bytes) {
|
||||
final String hex = Integer.toHexString(0xFF & b);
|
||||
if (hex.length() == 1) {
|
||||
builder.append('0');
|
||||
}
|
||||
builder.append(hex);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public synchronized boolean isValid() {
|
||||
return mDiskLruCache != null;
|
||||
}
|
||||
|
||||
@@ -1,176 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.drawable;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
import com.hippo.yorozuya.MathUtils;
|
||||
|
||||
public class BatteryDrawable extends Drawable {
|
||||
|
||||
public static final int WARN_LIMIT = 15;
|
||||
@SuppressWarnings("unused")
|
||||
private static final String TAG = BatteryDrawable.class.getSimpleName();
|
||||
private final Paint mPaint;
|
||||
private final Rect mTopRect;
|
||||
private final Rect mBottomRect;
|
||||
private final Rect mRightRect;
|
||||
private final Rect mHeadRect;
|
||||
private final Rect mElectRect;
|
||||
private int mColor = Color.WHITE;
|
||||
private int mWarningColor = Color.RED;
|
||||
private int mElect = -1;
|
||||
private int mStart;
|
||||
private int mStop;
|
||||
|
||||
public BatteryDrawable() {
|
||||
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
|
||||
mPaint.setStyle(Paint.Style.FILL);
|
||||
|
||||
mTopRect = new Rect();
|
||||
mBottomRect = new Rect();
|
||||
mRightRect = new Rect();
|
||||
mHeadRect = new Rect();
|
||||
mElectRect = new Rect();
|
||||
updatePaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("SuspiciousNameCombination")
|
||||
protected void onBoundsChange(Rect bounds) {
|
||||
int width = bounds.width();
|
||||
int height = bounds.height();
|
||||
int strokeWidth = (int) (Math.sqrt(width * width + height * height) * 0.06f);
|
||||
int turn1 = width * 6 / 7;
|
||||
int turn2 = height / 3;
|
||||
int secBottom = height - strokeWidth;
|
||||
mStart = strokeWidth;
|
||||
mStop = turn1 - strokeWidth;
|
||||
|
||||
mTopRect.set(0, 0, turn1, strokeWidth);
|
||||
mBottomRect.set(0, secBottom, turn1, height);
|
||||
mRightRect.set(turn1 - strokeWidth, strokeWidth, turn1, secBottom);
|
||||
mHeadRect.set(turn1, turn2, width, height - turn2);
|
||||
mElectRect.set(0, strokeWidth, mStop, secBottom);
|
||||
}
|
||||
|
||||
/**
|
||||
* How to draw:<br>
|
||||
* |------------------------------|<br>
|
||||
* |\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\|<br>
|
||||
* |------------------------------|---|<br>
|
||||
* |/////////////////| |//|\\\|<br>
|
||||
* |/////////////////| |//|\\\|<br>
|
||||
* |------------------------------|---|<br>
|
||||
* |\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\|<br>
|
||||
* |------------------------------|
|
||||
*/
|
||||
@Override
|
||||
public void draw(Canvas canvas) {
|
||||
if (mElect == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
mElectRect.right = MathUtils.lerp(mStart, mStop, mElect / 100.0f);
|
||||
|
||||
canvas.drawRect(mTopRect, mPaint);
|
||||
canvas.drawRect(mBottomRect, mPaint);
|
||||
canvas.drawRect(mRightRect, mPaint);
|
||||
canvas.drawRect(mHeadRect, mPaint);
|
||||
canvas.drawRect(mElectRect, mPaint);
|
||||
}
|
||||
|
||||
private boolean isWarn() {
|
||||
return mElect <= WARN_LIMIT;
|
||||
}
|
||||
|
||||
public void setColor(int color) {
|
||||
if (mColor == color) {
|
||||
return;
|
||||
}
|
||||
|
||||
mColor = color;
|
||||
if (!isWarn()) {
|
||||
mPaint.setColor(mColor);
|
||||
invalidateSelf();
|
||||
}
|
||||
}
|
||||
|
||||
public void setWarningColor(int color) {
|
||||
if (mWarningColor == color) {
|
||||
return;
|
||||
}
|
||||
|
||||
mWarningColor = color;
|
||||
if (isWarn()) {
|
||||
mPaint.setColor(mWarningColor);
|
||||
invalidateSelf();
|
||||
}
|
||||
}
|
||||
|
||||
public void setElect(int elect) {
|
||||
if (mElect == elect) {
|
||||
return;
|
||||
}
|
||||
|
||||
mElect = elect;
|
||||
updatePaint();
|
||||
}
|
||||
|
||||
public void setElect(int elect, boolean warn) {
|
||||
if (mElect == elect) {
|
||||
return;
|
||||
}
|
||||
|
||||
mElect = elect;
|
||||
updatePaint(warn);
|
||||
}
|
||||
|
||||
private void updatePaint() {
|
||||
updatePaint(isWarn());
|
||||
}
|
||||
|
||||
private void updatePaint(boolean warn) {
|
||||
if (warn) {
|
||||
mPaint.setColor(mWarningColor);
|
||||
} else {
|
||||
mPaint.setColor(mColor);
|
||||
}
|
||||
invalidateSelf();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(int alpha) {
|
||||
mPaint.setAlpha(alpha);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColorFilter(ColorFilter cf) {
|
||||
mPaint.setColorFilter(cf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpacity() {
|
||||
return PixelFormat.TRANSLUCENT;
|
||||
}
|
||||
}
|
||||
@@ -18,29 +18,28 @@ package com.hippo.ehviewer
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.app.ActivityManager
|
||||
import android.content.ComponentCallbacks2
|
||||
import android.os.Build
|
||||
import android.text.Html
|
||||
import android.text.method.LinkMovementMethod
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.collection.LruCache
|
||||
import androidx.core.os.LocaleListCompat
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.ProcessLifecycleOwner
|
||||
import coil.Coil
|
||||
import coil.ImageLoader
|
||||
import coil.ImageLoaderFactory
|
||||
import coil.disk.DiskCache
|
||||
import com.hippo.Native
|
||||
import com.hippo.app.BaseDialogBuilder
|
||||
import com.hippo.beerbelly.SimpleDiskCache
|
||||
import com.hippo.ehviewer.client.EhClient
|
||||
import com.hippo.ehviewer.client.EhCookieStore
|
||||
import com.hippo.ehviewer.client.EhDns
|
||||
import com.hippo.ehviewer.client.EhEngine
|
||||
import com.hippo.ehviewer.client.EhRequestBuilder
|
||||
import com.hippo.ehviewer.client.EhSSLSocketFactory
|
||||
import com.hippo.ehviewer.client.EhTagDatabase
|
||||
import com.hippo.ehviewer.client.EhUrl
|
||||
import com.hippo.ehviewer.client.EhX509TrustManager
|
||||
import com.hippo.ehviewer.client.data.GalleryDetail
|
||||
@@ -52,24 +51,29 @@ import com.hippo.ehviewer.ui.EhActivity
|
||||
import com.hippo.scene.SceneApplication
|
||||
import com.hippo.util.BitmapUtils
|
||||
import com.hippo.util.ExceptionUtils
|
||||
import com.hippo.util.IoThreadPoolExecutor
|
||||
import com.hippo.util.ReadableTime
|
||||
import com.hippo.yorozuya.FileUtils
|
||||
import com.hippo.yorozuya.IntIdGenerator
|
||||
import eu.kanade.tachiyomi.core.preference.AndroidPreferenceStore
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import okhttp3.Cache
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.File
|
||||
import java.net.Proxy
|
||||
import java.security.KeyStore
|
||||
import java.util.Arrays
|
||||
import javax.net.ssl.TrustManagerFactory
|
||||
import javax.net.ssl.X509TrustManager
|
||||
|
||||
class EhApplication : SceneApplication() {
|
||||
class EhApplication : SceneApplication(), DefaultLifecycleObserver, ImageLoaderFactory {
|
||||
private val mIdGenerator = IntIdGenerator()
|
||||
private val mGlobalStuffMap = HashMap<Int, Any>()
|
||||
private val mActivityList = ArrayList<Activity>()
|
||||
private var initialized = false
|
||||
val topActivity: EhActivity?
|
||||
get() = if (mActivityList.isNotEmpty()) {
|
||||
mActivityList[mActivityList.size - 1] as EhActivity
|
||||
@@ -81,9 +85,10 @@ class EhApplication : SceneApplication() {
|
||||
mActivityList.forEach { it.recreate() }
|
||||
}
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
override fun onCreate() {
|
||||
ProcessLifecycleOwner.get().lifecycle.addObserver(EhlifecycleObserver())
|
||||
ProcessLifecycleOwner.get().lifecycle.addObserver(this)
|
||||
application = this
|
||||
val handler = Thread.getDefaultUncaughtExceptionHandler()
|
||||
Thread.setDefaultUncaughtExceptionHandler { t, e ->
|
||||
@@ -95,47 +100,51 @@ class EhApplication : SceneApplication() {
|
||||
}
|
||||
handler?.uncaughtException(t, e)
|
||||
}
|
||||
super.onCreate()
|
||||
super<SceneApplication>.onCreate()
|
||||
Native.initialize()
|
||||
GetText.initialize(this)
|
||||
Settings.initialize(this)
|
||||
Settings.initialize()
|
||||
ReadableTime.initialize(this)
|
||||
AppConfig.initialize(this)
|
||||
SpiderDen.initialize(this)
|
||||
EhDB.initialize(this)
|
||||
EhEngine.initialize()
|
||||
BitmapUtils.initialize(this)
|
||||
Coil.setImageLoader(ImageLoader.Builder(this).okHttpClient(okHttpClient).build())
|
||||
|
||||
// Locales can be managed by system automatically above Snow Cone v2
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU)
|
||||
AppCompatDelegate.setApplicationLocales(LocaleListCompat.create(Settings.getLocale()))
|
||||
EhTagDatabase.update()
|
||||
AppCompatDelegate.setDefaultNightMode(Settings.getTheme())
|
||||
|
||||
IoThreadPoolExecutor.getInstance().execute {
|
||||
try {
|
||||
val downloadLocation = Settings.getDownloadLocation()
|
||||
if (Settings.getMediaScan()) {
|
||||
CommonOperations.removeNoMediaFile(downloadLocation)
|
||||
} else {
|
||||
CommonOperations.ensureNoMediaFile(downloadLocation)
|
||||
}
|
||||
} catch (t: Throwable) {
|
||||
t.printStackTrace()
|
||||
ExceptionUtils.throwIfFatal(t)
|
||||
launchIO {
|
||||
launchIO {
|
||||
downloadManager
|
||||
}
|
||||
|
||||
// Clear temp files
|
||||
try {
|
||||
clearTempDir()
|
||||
} catch (t: Throwable) {
|
||||
t.printStackTrace()
|
||||
ExceptionUtils.throwIfFatal(t)
|
||||
launchIO {
|
||||
cleanupDownload()
|
||||
}
|
||||
launchIO {
|
||||
theDawnOfNewDay()
|
||||
}
|
||||
}
|
||||
mIdGenerator.setNextId(Settings.getInt(KEY_GLOBAL_STUFF_NEXT_ID, 0))
|
||||
initialized = true
|
||||
theDawnOfNewDay()
|
||||
}
|
||||
|
||||
private fun cleanupDownload() {
|
||||
try {
|
||||
val downloadLocation = Settings.getDownloadLocation()
|
||||
if (Settings.getMediaScan()) {
|
||||
CommonOperations.removeNoMediaFile(downloadLocation)
|
||||
} else {
|
||||
CommonOperations.ensureNoMediaFile(downloadLocation)
|
||||
}
|
||||
} catch (t: Throwable) {
|
||||
t.printStackTrace()
|
||||
ExceptionUtils.throwIfFatal(t)
|
||||
}
|
||||
|
||||
// Clear temp files
|
||||
try {
|
||||
clearTempDir()
|
||||
} catch (t: Throwable) {
|
||||
t.printStackTrace()
|
||||
ExceptionUtils.throwIfFatal(t)
|
||||
}
|
||||
}
|
||||
|
||||
private fun theDawnOfNewDay() {
|
||||
@@ -150,28 +159,27 @@ class EhApplication : SceneApplication() {
|
||||
EhCookieStore.KEY_IPD_PASS_HASH
|
||||
)
|
||||
) {
|
||||
IoThreadPoolExecutor.getInstance().execute {
|
||||
val referer = EhUrl.REFERER_E
|
||||
val request = EhRequestBuilder(EhUrl.HOST_E + "news.php", referer).build()
|
||||
val call = okHttpClient.newCall(request)
|
||||
try {
|
||||
val response = call.execute()
|
||||
val referer = EhUrl.REFERER_E
|
||||
val request = EhRequestBuilder(EhUrl.HOST_E + "news.php", referer).build()
|
||||
val call = okHttpClient.newCall(request)
|
||||
try {
|
||||
call.execute().use { response ->
|
||||
val responseBody = response.body
|
||||
val body = responseBody.string()
|
||||
val html = EventPaneParser.parse(body)
|
||||
if (html != null) {
|
||||
showEventPane(html)
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun showEventPane(html: String) {
|
||||
if (Settings.getHideHvEvents() && html.contains("You have encountered a monster!")) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
val activity = topActivity
|
||||
activity?.runOnUiThread {
|
||||
@@ -242,12 +250,22 @@ class EhApplication : SceneApplication() {
|
||||
mActivityList.remove(activity)
|
||||
}
|
||||
|
||||
internal class EhlifecycleObserver : DefaultLifecycleObserver {
|
||||
override fun onPause(owner: LifecycleOwner) {
|
||||
if (!locked)
|
||||
locked_last_leave_time = System.currentTimeMillis() / 1000
|
||||
locked = true
|
||||
}
|
||||
override fun onPause(owner: LifecycleOwner) {
|
||||
if (!locked)
|
||||
locked_last_leave_time = System.currentTimeMillis() / 1000
|
||||
locked = true
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
override fun newImageLoader(): ImageLoader {
|
||||
return ImageLoader.Builder(this).apply {
|
||||
okHttpClient(okHttpClient)
|
||||
allowRgb565(getSystemService<ActivityManager>()!!.isLowRamDevice)
|
||||
// Coil spawns a new thread for every image load by default
|
||||
fetcherDispatcher(Dispatchers.IO.limitedParallelism(8))
|
||||
decoderDispatcher(Dispatchers.IO.limitedParallelism(2))
|
||||
transformationDispatcher(Dispatchers.IO.limitedParallelism(2))
|
||||
}.build()
|
||||
}
|
||||
|
||||
companion object {
|
||||
@@ -262,9 +280,6 @@ class EhApplication : SceneApplication() {
|
||||
@JvmStatic
|
||||
val ehCookieStore by lazy { EhCookieStore(application) }
|
||||
|
||||
@JvmStatic
|
||||
val ehClient by lazy { EhClient(application) }
|
||||
|
||||
@JvmStatic
|
||||
val ehProxySelector by lazy { EhProxySelector() }
|
||||
|
||||
@@ -273,7 +288,7 @@ class EhApplication : SceneApplication() {
|
||||
val builder = OkHttpClient.Builder()
|
||||
.cookieJar(ehCookieStore)
|
||||
.cache(Cache(File(application.cacheDir, "http_cache"), 50L * 1024L * 1024L))
|
||||
.dns(EhDns())
|
||||
.dns(EhDns)
|
||||
.proxySelector(ehProxySelector)
|
||||
|
||||
if (Settings.getDF()) {
|
||||
@@ -292,10 +307,11 @@ class EhApplication : SceneApplication() {
|
||||
trustManager = trustManagers[0] as X509TrustManager
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
trustManager = EhX509TrustManager()
|
||||
trustManager = EhX509TrustManager
|
||||
}
|
||||
|
||||
builder.sslSocketFactory(EhSSLSocketFactory(), trustManager)
|
||||
builder.sslSocketFactory(EhSSLSocketFactory, trustManager)
|
||||
builder.proxy(Proxy.NO_PROXY)
|
||||
}
|
||||
builder.build()
|
||||
}
|
||||
@@ -311,19 +327,20 @@ class EhApplication : SceneApplication() {
|
||||
|
||||
@JvmStatic
|
||||
val spiderInfoCache by lazy {
|
||||
SimpleDiskCache(
|
||||
File(application.cacheDir, "spider_info"),
|
||||
20 * 1024 * 1024
|
||||
)
|
||||
DiskCache.Builder().directory(File(application.cacheDir, "spider_info"))
|
||||
.maxSizeBytes(20 * 1024 * 1024).build()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
val downloadManager by lazy { DownloadManager(application) }
|
||||
val downloadManager by lazy { DownloadManager() }
|
||||
|
||||
@JvmStatic
|
||||
val hosts by lazy { Hosts(application, "hosts.db") }
|
||||
|
||||
@JvmStatic
|
||||
val favouriteStatusRouter by lazy { FavouriteStatusRouter() }
|
||||
|
||||
@JvmStatic
|
||||
val readerPreferences by lazy { ReaderPreferences(AndroidPreferenceStore(application)) }
|
||||
}
|
||||
}
|
||||
@@ -234,7 +234,7 @@ public class EhDB {
|
||||
|
||||
public static synchronized List<GalleryInfo> searchLocalFavorites(String query) {
|
||||
LocalFavoritesDao dao = db.localFavoritesDao();
|
||||
List<LocalFavoriteInfo> list = dao.list();
|
||||
List<LocalFavoriteInfo> list = dao.list("%" + query + "%");
|
||||
return new ArrayList<>(list);
|
||||
}
|
||||
|
||||
@@ -281,9 +281,9 @@ public class EhDB {
|
||||
|
||||
public static synchronized void insertQuickSearch(QuickSearch quickSearch) {
|
||||
QuickSearchDao dao = db.quickSearchDao();
|
||||
quickSearch.id = null;
|
||||
quickSearch.time = System.currentTimeMillis();
|
||||
quickSearch.id = dao.insert(quickSearch);
|
||||
quickSearch.setId(null);
|
||||
quickSearch.setTime(System.currentTimeMillis());
|
||||
quickSearch.setId(dao.insert(quickSearch));
|
||||
}
|
||||
|
||||
public static synchronized void importQuickSearch(List<QuickSearch> quickSearchList) {
|
||||
@@ -293,11 +293,6 @@ public class EhDB {
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized void updateQuickSearch(QuickSearch quickSearch) {
|
||||
QuickSearchDao dao = db.quickSearchDao();
|
||||
dao.update(quickSearch);
|
||||
}
|
||||
|
||||
public static synchronized void deleteQuickSearch(QuickSearch quickSearch) {
|
||||
QuickSearchDao dao = db.quickSearchDao();
|
||||
dao.delete(quickSearch);
|
||||
@@ -327,25 +322,22 @@ public class EhDB {
|
||||
dao.update(list);
|
||||
}
|
||||
|
||||
public static synchronized List<HistoryInfo> getHistoryList() {
|
||||
return db.historyDao().list();
|
||||
}
|
||||
|
||||
public static synchronized PagingSource<Integer, HistoryInfo> getHistoryLazyList() {
|
||||
return db.historyDao().listLazy();
|
||||
}
|
||||
|
||||
public static synchronized void putHistoryInfo(GalleryInfo galleryInfo) {
|
||||
HistoryDao dao = db.historyDao();
|
||||
HistoryInfo info = dao.load(galleryInfo.gid);
|
||||
if (null != info) {
|
||||
// Update time
|
||||
info.time = System.currentTimeMillis();
|
||||
HistoryInfo info;
|
||||
if (galleryInfo instanceof HistoryInfo) {
|
||||
info = (HistoryInfo) galleryInfo;
|
||||
} else {
|
||||
info = new HistoryInfo(galleryInfo);
|
||||
}
|
||||
info.time = System.currentTimeMillis();
|
||||
if (null != dao.load(info.gid)) {
|
||||
dao.update(info);
|
||||
} else {
|
||||
// New history
|
||||
info = new HistoryInfo(galleryInfo);
|
||||
info.time = System.currentTimeMillis();
|
||||
dao.insert(info);
|
||||
}
|
||||
}
|
||||
@@ -394,7 +386,7 @@ public class EhDB {
|
||||
}
|
||||
|
||||
public static synchronized void triggerFilter(Filter filter) {
|
||||
filter.setEnable(!filter.enable);
|
||||
filter.enable = !filter.enable;
|
||||
db.filterDao().update(filter);
|
||||
}
|
||||
|
||||
@@ -529,9 +521,9 @@ public class EhDB {
|
||||
List<QuickSearch> currentQuickSearchList = db.quickSearchDao().list();
|
||||
List<QuickSearch> importList = new ArrayList<>();
|
||||
for (QuickSearch quickSearch : quickSearchList) {
|
||||
String name = quickSearch.name;
|
||||
String name = quickSearch.getName();
|
||||
for (QuickSearch q : currentQuickSearchList) {
|
||||
if (ObjectUtils.equal(q.name, name)) {
|
||||
if (ObjectUtils.equal(q.getName(), name)) {
|
||||
// The same name
|
||||
name = null;
|
||||
break;
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package com.hippo.ehviewer;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
@@ -27,19 +26,13 @@ import androidx.annotation.Nullable;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import com.hippo.ehviewer.client.EhConfig;
|
||||
import com.hippo.ehviewer.client.EhUtils;
|
||||
import com.hippo.ehviewer.client.data.FavListUrlBuilder;
|
||||
import com.hippo.ehviewer.ui.CommonOperations;
|
||||
import com.hippo.ehviewer.ui.scene.GalleryListScene;
|
||||
import com.hippo.glgallery.GalleryView;
|
||||
import com.hippo.unifile.UniFile;
|
||||
import com.hippo.util.ExceptionUtils;
|
||||
import com.hippo.yorozuya.AssertUtils;
|
||||
import com.hippo.yorozuya.FileUtils;
|
||||
import com.hippo.yorozuya.MathUtils;
|
||||
import com.hippo.yorozuya.NumberUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -53,10 +46,7 @@ public class Settings {
|
||||
|
||||
public static final String KEY_ACCOUNT = "account";
|
||||
public static final String KEY_BLACK_DARK_THEME = "black_dark_theme";
|
||||
public static final int THEME_LIGHT = 1;
|
||||
public static final int THEME_SYSTEM = -1;
|
||||
public static final int THEME_BLACK = 2;
|
||||
public static final String KEY_APPLY_NAV_BAR_THEME_COLOR = "apply_nav_bar_theme_color";
|
||||
public static final String KEY_GALLERY_SITE = "gallery_site";
|
||||
public static final String KEY_LIST_MODE = "list_mode";
|
||||
public static final String KEY_DETAIL_SIZE = "detail_size";
|
||||
@@ -67,8 +57,6 @@ public class Settings {
|
||||
public static final int DEFAULT_DEFAULT_CATEGORIES = EhConfig.ALL_CATEGORY;
|
||||
public static final String KEY_EXCLUDED_TAG_NAMESPACES = "excluded_tag_namespaces";
|
||||
public static final String KEY_EXCLUDED_LANGUAGES = "excluded_languages";
|
||||
private static final String KEY_HIDE_HV_EVENTS = "hide_hv_events";
|
||||
private static final boolean DEFAULT_HIDE_HV_EVENTS = true;
|
||||
/********************
|
||||
****** Privacy and Security
|
||||
********************/
|
||||
@@ -87,45 +75,35 @@ public class Settings {
|
||||
public static final String KEY_IMAGE_RESOLUTION = "image_size";
|
||||
public static final String DEFAULT_IMAGE_RESOLUTION = EhConfig.IMAGE_SIZE_AUTO;
|
||||
public static final int INVALID_DEFAULT_FAV_SLOT = -2;
|
||||
public static final String KEY_ENABLE_ANALYTICS = "enable_analytics";
|
||||
/********************
|
||||
****** Advanced
|
||||
********************/
|
||||
public static final String KEY_SAVE_PARSE_ERROR_BODY = "save_parse_error_body";
|
||||
public static final String KEY_SECURITY = "require_unlock";
|
||||
public static final String KEY_SECURITY_DELAY = "require_unlock_delay";
|
||||
public static final String DEFAULT_SECURITY = "";
|
||||
public static final String KEY_ENABLE_FINGERPRINT = "enable_fingerprint";
|
||||
public static final String KEY_READ_CACHE_SIZE = "read_cache_size";
|
||||
public static final int DEFAULT_READ_CACHE_SIZE = 320;
|
||||
public static final String KEY_BUILT_IN_HOSTS = "built_in_hosts_2";
|
||||
public static final String KEY_DOMAIN_FRONTING = "domain_fronting";
|
||||
public static final String KEY_APP_LANGUAGE = "app_language";
|
||||
public static final String KEY_LIST_THUMB_SIZE = "list_tile_size";
|
||||
private static final String KEY_HIDE_HV_EVENTS = "hide_hv_events";
|
||||
private static final boolean DEFAULT_HIDE_HV_EVENTS = true;
|
||||
private static final String KEY_SHOW_COMMENTS = "show_gallery_comments";
|
||||
private static final boolean DEFAULT_SHOW_COMMENTS = true;
|
||||
private static final String KEY_PREVIEW_NUM = "preview_num";
|
||||
private static final int DEFAULT_PREVIEW_NUM = 60;
|
||||
private static final String TAG = Settings.class.getSimpleName();
|
||||
private static final String KEY_VERSION_CODE = "version_code";
|
||||
private static final int DEFAULT_VERSION_CODE = 0;
|
||||
private static final String KEY_DISPLAY_NAME = "display_name";
|
||||
private static final String DEFAULT_DISPLAY_NAME = null;
|
||||
private static final int DEFAULT_LIST_THUMB_SIZE = 40;
|
||||
private static final String KEY_AVATAR = "avatar";
|
||||
private static final String DEFAULT_AVATAR = null;
|
||||
private static final String KEY_SHOW_WARNING = "show_warning";
|
||||
private static final boolean DEFAULT_SHOW_WARNING = true;
|
||||
private static final String KEY_REMOVE_IMAGE_FILES = "include_pic";
|
||||
private static final boolean DEFAULT_REMOVE_IMAGE_FILES = true;
|
||||
private static final String KEY_NEED_SIGN_IN = "need_sign_in";
|
||||
private static final boolean DEFAULT_NEED_SIGN_IN = true;
|
||||
private static final String KEY_SELECT_SITE = "select_site";
|
||||
private static final boolean DEFAULT_SELECT_SITE = true;
|
||||
private static final String KEY_QUICK_SEARCH_TIP = "quick_search_tip";
|
||||
private static final boolean DEFAULT_QUICK_SEARCH_TIP = true;
|
||||
private static final int DEFAULT_THEME = THEME_SYSTEM;
|
||||
private static final boolean DEFAULT_APPLY_NAV_BAR_THEME_COLOR = true;
|
||||
private static final int DEFAULT_GALLERY_SITE = 1;
|
||||
private static final String KEY_LAUNCH_PAGE = "launch_page";
|
||||
private static final int DEFAULT_LAUNCH_PAGE = 0;
|
||||
@@ -144,41 +122,6 @@ public class Settings {
|
||||
private static final boolean DEFAULT_METERED_NETWORK_WARNING = false;
|
||||
private static final String KEY_APP_LINK_VERIFY_TIP = "app_link_verify_tip";
|
||||
private static final boolean DEFAULT_APP_LINK_VERIFY_TIP = false;
|
||||
private static final String KEY_NIGHT_MODE = "night_mode";
|
||||
private static final String DEFAULT_NIGHT_MODE = "-1";
|
||||
private static final String KEY_E_INK_MODE = "e_ink_mode_2";
|
||||
private static final boolean DEFAULT_E_INK_MODE = false;
|
||||
/********************
|
||||
****** Read
|
||||
********************/
|
||||
private static final String KEY_SCREEN_ROTATION = "screen_rotation";
|
||||
private static final int DEFAULT_SCREEN_ROTATION = 0;
|
||||
private static final String KEY_READING_DIRECTION = "reading_direction";
|
||||
private static final int DEFAULT_READING_DIRECTION = GalleryView.LAYOUT_RIGHT_TO_LEFT;
|
||||
private static final String KEY_PAGE_SCALING = "page_scaling";
|
||||
private static final int DEFAULT_PAGE_SCALING = GalleryView.SCALE_FIT;
|
||||
private static final String KEY_START_POSITION = "start_position";
|
||||
private static final int DEFAULT_START_POSITION = GalleryView.START_POSITION_TOP_RIGHT;
|
||||
private static final String KEY_KEEP_SCREEN_ON = "keep_screen_on";
|
||||
private static final boolean DEFAULT_KEEP_SCREEN_ON = false;
|
||||
private static final String KEY_SHOW_CLOCK = "gallery_show_clock";
|
||||
private static final boolean DEFAULT_SHOW_CLOCK = true;
|
||||
private static final String KEY_SHOW_PROGRESS = "gallery_show_progress";
|
||||
private static final boolean DEFAULT_SHOW_PROGRESS = true;
|
||||
private static final String KEY_SHOW_BATTERY = "gallery_show_battery";
|
||||
private static final boolean DEFAULT_SHOW_BATTERY = true;
|
||||
private static final String KEY_SHOW_PAGE_INTERVAL = "gallery_show_page_interval";
|
||||
private static final boolean DEFAULT_SHOW_PAGE_INTERVAL = true;
|
||||
private static final String KEY_VOLUME_PAGE = "volume_page";
|
||||
private static final boolean DEFAULT_VOLUME_PAGE = false;
|
||||
private static final String KEY_REVERSE_VOLUME_PAGE = "reserve_volume_page";
|
||||
private static final boolean DEFAULT_REVERSE_VOLUME_PAGE = false;
|
||||
private static final String KEY_READING_FULLSCREEN = "reading_fullscreen";
|
||||
private static final boolean VALUE_READING_FULLSCREEN = true;
|
||||
private static final String KEY_CUSTOM_SCREEN_LIGHTNESS = "custom_screen_lightness";
|
||||
private static final boolean DEFAULT_CUSTOM_SCREEN_LIGHTNESS = false;
|
||||
private static final String KEY_SCREEN_LIGHTNESS = "screen_lightness";
|
||||
private static final int DEFAULT_SCREEN_LIGHTNESS = 50;
|
||||
private static final boolean DEFAULT_MEDIA_SCAN = false;
|
||||
private static final String KEY_RECENT_DOWNLOAD_LABEL = "recent_download_label";
|
||||
private static final String DEFAULT_RECENT_DOWNLOAD_LABEL = null;
|
||||
@@ -192,8 +135,6 @@ public class Settings {
|
||||
private static final int DEFAULT_PRELOAD_IMAGE = 5;
|
||||
private static final String KEY_DOWNLOAD_ORIGIN_IMAGE = "download_origin_image";
|
||||
private static final boolean DEFAULT_DOWNLOAD_ORIGIN_IMAGE = false;
|
||||
private static final String KEY_READ_THEME = "read_theme";
|
||||
private static final int DEFAULT_READ_THEME = 1;
|
||||
/********************
|
||||
****** Favorites
|
||||
********************/
|
||||
@@ -235,46 +176,17 @@ public class Settings {
|
||||
// -1 for local, 0 - 9 for cloud favorite, other for no default fav slot
|
||||
private static final String KEY_DEFAULT_FAV_SLOT = "default_favorite_2";
|
||||
private static final int DEFAULT_DEFAULT_FAV_SLOT = INVALID_DEFAULT_FAV_SLOT;
|
||||
/********************
|
||||
****** Analytics
|
||||
********************/
|
||||
private static final String KEY_ASK_ANALYTICS = "ask_analytics";
|
||||
private static final boolean DEFAULT_ASK_ANALYTICS = true;
|
||||
private static final boolean DEFAULT_ENABLE_ANALYTICS = false;
|
||||
private static final String KEY_USER_ID = "user_id";
|
||||
private static final String FILENAME_USER_ID = ".user_id";
|
||||
private static final int LENGTH_USER_ID = 32;
|
||||
/********************
|
||||
****** Update
|
||||
********************/
|
||||
private static final String KEY_BETA_UPDATE_CHANNEL = "beta_update_channel";
|
||||
private static final String KEY_SKIP_UPDATE_VERSION = "skip_update_version";
|
||||
private static final int DEFAULT_SKIP_UPDATE_VERSION = 0;
|
||||
private static final boolean DEFAULT_SAVE_PARSE_ERROR_BODY = true;
|
||||
private static final String KEY_SAVE_CRASH_LOG = "save_crash_log";
|
||||
private static final boolean DEFAULT_SAVE_CRASH_LOG = true;
|
||||
private static final boolean DEFAULT_BUILT_IN_HOSTS = false;
|
||||
private static final boolean DEFAULT_FRONTING = false;
|
||||
private static final String DEFAULT_APP_LANGUAGE = "system";
|
||||
private static final String KEY_PROXY_TYPE = "proxy_type";
|
||||
private static final int DEFAULT_PROXY_TYPE = EhProxySelector.TYPE_SYSTEM;
|
||||
private static final String KEY_PROXY_IP = "proxy_ip";
|
||||
private static final String DEFAULT_PROXY_IP = null;
|
||||
private static final String KEY_PROXY_PORT = "proxy_port";
|
||||
private static final int DEFAULT_PROXY_PORT = -1;
|
||||
/********************
|
||||
****** Guide
|
||||
********************/
|
||||
private static final String KEY_GUIDE_QUICK_SEARCH = "guide_quick_search";
|
||||
private static final boolean DEFAULT_GUIDE_QUICK_SEARCH = true;
|
||||
private static final String KEY_GUIDE_COLLECTIONS = "guide_collections";
|
||||
private static final boolean DEFAULT_GUIDE_COLLECTIONS = true;
|
||||
private static final String KEY_GUIDE_DOWNLOAD_THUMB = "guide_download_thumb";
|
||||
private static final boolean DEFAULT_GUIDE_DOWNLOAD_THUMB = true;
|
||||
private static final String KEY_GUIDE_DOWNLOAD_LABELS = "guide_download_labels";
|
||||
private static final boolean DEFAULT_GUIDE_DOWNLOAD_LABELS = true;
|
||||
private static final String KEY_GUIDE_GALLERY = "guide_gallery";
|
||||
private static final boolean DEFAULT_GUIDE_GALLERY = true;
|
||||
private static final String KEY_CLIPBOARD_TEXT_HASH_CODE = "clipboard_text_hash_code";
|
||||
private static final int DEFAULT_CLIPBOARD_TEXT_HASH_CODE = 0;
|
||||
private static final String KEY_DOWNLOAD_DELAY = "download_delay";
|
||||
@@ -282,20 +194,20 @@ public class Settings {
|
||||
private static final String KEY_REQUEST_NEWS = "request_news";
|
||||
private static final boolean DEFAULT_REQUEST_NEWS = true;
|
||||
private static final String KEY_ARCHIVE_PASSWDS = "archive_passwds";
|
||||
private static final String KEY_QS_SAVE_PROGRESS = "qs_save_progress";
|
||||
private static final boolean DEFAULT_QS_SAVE_PROGRESS = true;
|
||||
public static boolean LIST_THUMB_SIZE_INITED = false;
|
||||
public static SharedPreferences sSettingsPre;
|
||||
private static int LIST_THUMB_SIZE = 40;
|
||||
private static Context sContext;
|
||||
private static SharedPreferences sSettingsPre;
|
||||
private static EhConfig sEhConfig;
|
||||
|
||||
public static void initialize(Context context) {
|
||||
sContext = context.getApplicationContext();
|
||||
sSettingsPre = PreferenceManager.getDefaultSharedPreferences(sContext);
|
||||
public static void initialize() {
|
||||
sSettingsPre = PreferenceManager.getDefaultSharedPreferences(EhApplication.getApplication());
|
||||
sEhConfig = loadEhConfig();
|
||||
fixDefaultValue(context);
|
||||
fixDefaultValue();
|
||||
}
|
||||
|
||||
private static void fixDefaultValue(Context context) {
|
||||
private static void fixDefaultValue() {
|
||||
if ("CN".equals(Locale.getDefault().getCountry())) {
|
||||
// Enable domain fronting if the country is CN
|
||||
if (!sSettingsPre.contains(KEY_BUILT_IN_HOSTS)) {
|
||||
@@ -312,16 +224,6 @@ public class Settings {
|
||||
}
|
||||
}
|
||||
|
||||
public static Locale getLocale() {
|
||||
Locale locale = null;
|
||||
String language = Settings.getAppLanguage();
|
||||
if (language != null && !language.equals("system")) {
|
||||
return Locale.forLanguageTag(language);
|
||||
} else {
|
||||
return Locale.getDefault();
|
||||
}
|
||||
}
|
||||
|
||||
private static EhConfig loadEhConfig() {
|
||||
EhConfig ehConfig = new EhConfig();
|
||||
ehConfig.imageSize = getImageResolution();
|
||||
@@ -358,32 +260,6 @@ public class Settings {
|
||||
sSettingsPre.edit().putInt(key, value).apply();
|
||||
}
|
||||
|
||||
public static long getLong(String key, long defValue) {
|
||||
try {
|
||||
return sSettingsPre.getLong(key, defValue);
|
||||
} catch (ClassCastException e) {
|
||||
Log.d(TAG, "Get ClassCastException when get " + key + " value", e);
|
||||
return defValue;
|
||||
}
|
||||
}
|
||||
|
||||
public static void putLong(String key, long value) {
|
||||
sSettingsPre.edit().putLong(key, value).apply();
|
||||
}
|
||||
|
||||
public static float getFloat(String key, float defValue) {
|
||||
try {
|
||||
return sSettingsPre.getFloat(key, defValue);
|
||||
} catch (ClassCastException e) {
|
||||
Log.d(TAG, "Get ClassCastException when get " + key + " value", e);
|
||||
return defValue;
|
||||
}
|
||||
}
|
||||
|
||||
public static void putFloat(String key, float value) {
|
||||
sSettingsPre.edit().putFloat(key, value).apply();
|
||||
}
|
||||
|
||||
public static String getString(String key, String defValue) {
|
||||
try {
|
||||
return sSettingsPre.getString(key, defValue);
|
||||
@@ -434,22 +310,10 @@ public class Settings {
|
||||
putString(KEY_DISPLAY_NAME, value);
|
||||
}
|
||||
|
||||
public static String getAvatar() {
|
||||
return getString(KEY_AVATAR, DEFAULT_AVATAR);
|
||||
}
|
||||
|
||||
public static void putAvatar(String value) {
|
||||
putString(KEY_AVATAR, value);
|
||||
}
|
||||
|
||||
public static boolean getShowWarning() {
|
||||
return getBoolean(KEY_SHOW_WARNING, DEFAULT_SHOW_WARNING);
|
||||
}
|
||||
|
||||
public static void putShowWarning(boolean value) {
|
||||
putBoolean(KEY_SHOW_WARNING, value);
|
||||
}
|
||||
|
||||
public static boolean getRemoveImageFiles() {
|
||||
return getBoolean(KEY_REMOVE_IMAGE_FILES, DEFAULT_REMOVE_IMAGE_FILES);
|
||||
}
|
||||
@@ -482,14 +346,6 @@ public class Settings {
|
||||
return getIntFromStr(KEY_THEME, DEFAULT_THEME);
|
||||
}
|
||||
|
||||
public static void putTheme(int theme) {
|
||||
putIntToStr(KEY_THEME, theme);
|
||||
}
|
||||
|
||||
public static boolean getApplyNavBarThemeColor() {
|
||||
return getBoolean(KEY_APPLY_NAV_BAR_THEME_COLOR, DEFAULT_APPLY_NAV_BAR_THEME_COLOR);
|
||||
}
|
||||
|
||||
public static int getGallerySite() {
|
||||
return getIntFromStr(KEY_GALLERY_SITE, DEFAULT_GALLERY_SITE);
|
||||
}
|
||||
@@ -500,17 +356,13 @@ public class Settings {
|
||||
|
||||
public static String getLaunchPageGalleryListSceneAction() {
|
||||
int value = getIntFromStr(KEY_LAUNCH_PAGE, DEFAULT_LAUNCH_PAGE);
|
||||
switch (value) {
|
||||
default:
|
||||
case 0:
|
||||
return GalleryListScene.ACTION_HOMEPAGE;
|
||||
case 1:
|
||||
return GalleryListScene.ACTION_SUBSCRIPTION;
|
||||
case 2:
|
||||
return GalleryListScene.ACTION_WHATS_HOT;
|
||||
case 3:
|
||||
return GalleryListScene.ACTION_TOP_LIST;
|
||||
}
|
||||
return switch (value) {
|
||||
case 0 -> GalleryListScene.ACTION_HOMEPAGE;
|
||||
case 1 -> GalleryListScene.ACTION_SUBSCRIPTION;
|
||||
case 2 -> GalleryListScene.ACTION_WHATS_HOT;
|
||||
case 3 -> GalleryListScene.ACTION_TOP_LIST;
|
||||
default -> throw new IllegalStateException("Unexpected value: " + value);
|
||||
};
|
||||
}
|
||||
|
||||
public static int getListMode() {
|
||||
@@ -523,13 +375,11 @@ public class Settings {
|
||||
|
||||
@DimenRes
|
||||
public static int getDetailSizeResId() {
|
||||
switch (getDetailSize()) {
|
||||
default:
|
||||
case 0:
|
||||
return R.dimen.gallery_list_column_width_long;
|
||||
case 1:
|
||||
return R.dimen.gallery_list_column_width_short;
|
||||
}
|
||||
return switch (getDetailSize()) {
|
||||
case 0 -> R.dimen.gallery_list_column_width_long;
|
||||
case 1 -> R.dimen.gallery_list_column_width_short;
|
||||
default -> throw new IllegalStateException("Unexpected value: " + getDetailSize());
|
||||
};
|
||||
}
|
||||
|
||||
public static int getThumbSize() {
|
||||
@@ -537,7 +387,7 @@ public class Settings {
|
||||
}
|
||||
|
||||
public static int dip2px(int dpValue) {
|
||||
final float scale = sContext.getResources().getDisplayMetrics().density;
|
||||
final float scale = EhApplication.getApplication().getResources().getDisplayMetrics().density;
|
||||
return (int) (dpValue * scale + 0.5f);
|
||||
}
|
||||
|
||||
@@ -581,32 +431,14 @@ public class Settings {
|
||||
return getInt(KEY_DEFAULT_CATEGORIES, DEFAULT_DEFAULT_CATEGORIES);
|
||||
}
|
||||
|
||||
public static void putDefaultCategories(int value) {
|
||||
sEhConfig.defaultCategories = value;
|
||||
sEhConfig.setDirty();
|
||||
putInt(KEY_DEFAULT_CATEGORIES, value);
|
||||
}
|
||||
|
||||
public static int getExcludedTagNamespaces() {
|
||||
return getInt(KEY_EXCLUDED_TAG_NAMESPACES, DEFAULT_EXCLUDED_TAG_NAMESPACES);
|
||||
}
|
||||
|
||||
public static void putExcludedTagNamespaces(int value) {
|
||||
sEhConfig.excludedNamespaces = value;
|
||||
sEhConfig.setDirty();
|
||||
putInt(KEY_EXCLUDED_TAG_NAMESPACES, value);
|
||||
}
|
||||
|
||||
public static String getExcludedLanguages() {
|
||||
return getString(KEY_EXCLUDED_LANGUAGES, DEFAULT_EXCLUDED_LANGUAGES);
|
||||
}
|
||||
|
||||
public static void putExcludedLanguages(String value) {
|
||||
sEhConfig.excludedLanguages = value;
|
||||
sEhConfig.setDirty();
|
||||
putString(KEY_EXCLUDED_LANGUAGES, value);
|
||||
}
|
||||
|
||||
public static boolean getMeteredNetworkWarning() {
|
||||
return getBoolean(KEY_METERED_NETWORK_WARNING, DEFAULT_METERED_NETWORK_WARNING);
|
||||
}
|
||||
@@ -619,152 +451,20 @@ public class Settings {
|
||||
putBoolean(KEY_APP_LINK_VERIFY_TIP, value);
|
||||
}
|
||||
|
||||
public static int getScreenRotation() {
|
||||
return getIntFromStr(KEY_SCREEN_ROTATION, DEFAULT_SCREEN_ROTATION);
|
||||
}
|
||||
|
||||
public static void putScreenRotation(int value) {
|
||||
putIntToStr(KEY_SCREEN_ROTATION, value);
|
||||
}
|
||||
|
||||
@GalleryView.LayoutMode
|
||||
public static int getReadingDirection() {
|
||||
return GalleryView.sanitizeLayoutMode(getIntFromStr(KEY_READING_DIRECTION, DEFAULT_READING_DIRECTION));
|
||||
}
|
||||
|
||||
public static void putReadingDirection(int value) {
|
||||
putIntToStr(KEY_READING_DIRECTION, value);
|
||||
}
|
||||
|
||||
@GalleryView.ScaleMode
|
||||
public static int getPageScaling() {
|
||||
return GalleryView.sanitizeScaleMode(getIntFromStr(KEY_PAGE_SCALING, DEFAULT_PAGE_SCALING));
|
||||
}
|
||||
|
||||
public static void putPageScaling(int value) {
|
||||
putIntToStr(KEY_PAGE_SCALING, value);
|
||||
}
|
||||
|
||||
@GalleryView.StartPosition
|
||||
public static int getStartPosition() {
|
||||
return GalleryView.sanitizeStartPosition(getIntFromStr(KEY_START_POSITION, DEFAULT_START_POSITION));
|
||||
}
|
||||
|
||||
public static void putStartPosition(int value) {
|
||||
putIntToStr(KEY_START_POSITION, value);
|
||||
}
|
||||
|
||||
public static boolean getKeepScreenOn() {
|
||||
return getBoolean(KEY_KEEP_SCREEN_ON, DEFAULT_KEEP_SCREEN_ON);
|
||||
}
|
||||
|
||||
public static void putKeepScreenOn(boolean value) {
|
||||
putBoolean(KEY_KEEP_SCREEN_ON, value);
|
||||
}
|
||||
|
||||
public static boolean getShowClock() {
|
||||
return getBoolean(KEY_SHOW_CLOCK, DEFAULT_SHOW_CLOCK);
|
||||
}
|
||||
|
||||
public static void putShowClock(boolean value) {
|
||||
putBoolean(KEY_SHOW_CLOCK, value);
|
||||
}
|
||||
|
||||
public static boolean getShowProgress() {
|
||||
return getBoolean(KEY_SHOW_PROGRESS, DEFAULT_SHOW_PROGRESS);
|
||||
}
|
||||
|
||||
public static void putShowProgress(boolean value) {
|
||||
putBoolean(KEY_SHOW_PROGRESS, value);
|
||||
}
|
||||
|
||||
public static boolean getShowBattery() {
|
||||
return getBoolean(KEY_SHOW_BATTERY, DEFAULT_SHOW_BATTERY);
|
||||
}
|
||||
|
||||
public static void putShowBattery(boolean value) {
|
||||
putBoolean(KEY_SHOW_BATTERY, value);
|
||||
}
|
||||
|
||||
public static boolean getShowPageInterval() {
|
||||
return getBoolean(KEY_SHOW_PAGE_INTERVAL, DEFAULT_SHOW_PAGE_INTERVAL);
|
||||
}
|
||||
|
||||
public static void putShowPageInterval(boolean value) {
|
||||
putBoolean(KEY_SHOW_PAGE_INTERVAL, value);
|
||||
}
|
||||
|
||||
public static boolean getVolumePage() {
|
||||
return getBoolean(KEY_VOLUME_PAGE, DEFAULT_VOLUME_PAGE);
|
||||
}
|
||||
|
||||
public static void putVolumePage(boolean value) {
|
||||
putBoolean(KEY_VOLUME_PAGE, value);
|
||||
}
|
||||
|
||||
public static boolean getReverseVolumePage() {
|
||||
return getBoolean(KEY_REVERSE_VOLUME_PAGE, DEFAULT_REVERSE_VOLUME_PAGE);
|
||||
}
|
||||
|
||||
public static void putReverseVolumePage(boolean value) {
|
||||
putBoolean(KEY_REVERSE_VOLUME_PAGE, value);
|
||||
}
|
||||
|
||||
public static boolean getReadingFullscreen() {
|
||||
return getBoolean(KEY_READING_FULLSCREEN, VALUE_READING_FULLSCREEN);
|
||||
}
|
||||
|
||||
public static void putReadingFullscreen(boolean value) {
|
||||
putBoolean(KEY_READING_FULLSCREEN, value);
|
||||
}
|
||||
|
||||
public static boolean getCustomScreenLightness() {
|
||||
return getBoolean(KEY_CUSTOM_SCREEN_LIGHTNESS, DEFAULT_CUSTOM_SCREEN_LIGHTNESS);
|
||||
}
|
||||
|
||||
public static void putCustomScreenLightness(boolean value) {
|
||||
putBoolean(KEY_CUSTOM_SCREEN_LIGHTNESS, value);
|
||||
}
|
||||
|
||||
public static int getScreenLightness() {
|
||||
return getInt(KEY_SCREEN_LIGHTNESS, DEFAULT_SCREEN_LIGHTNESS);
|
||||
}
|
||||
|
||||
public static void putScreenLightness(int value) {
|
||||
putInt(KEY_SCREEN_LIGHTNESS, value);
|
||||
}
|
||||
|
||||
public static int getReadTheme() {
|
||||
return getIntFromStr(KEY_READ_THEME, DEFAULT_READ_THEME);
|
||||
}
|
||||
|
||||
public static void putReadTheme(int value) {
|
||||
putIntToStr(KEY_READ_THEME, value);
|
||||
}
|
||||
|
||||
public static boolean getEnabledSecurity() {
|
||||
return getBoolean(KEY_SEC_SECURITY, VALUE_SEC_SECURITY);
|
||||
}
|
||||
|
||||
public static void putEnabledSecurity(boolean value) {
|
||||
putBoolean(KEY_READING_FULLSCREEN, value);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static UniFile getDownloadLocation() {
|
||||
UniFile dir = null;
|
||||
try {
|
||||
Uri.Builder builder = new Uri.Builder();
|
||||
builder.scheme(getString(KEY_DOWNLOAD_SAVE_SCHEME, null));
|
||||
builder.encodedAuthority(getString(KEY_DOWNLOAD_SAVE_AUTHORITY, null));
|
||||
builder.encodedPath(getString(KEY_DOWNLOAD_SAVE_PATH, null));
|
||||
builder.encodedQuery(getString(KEY_DOWNLOAD_SAVE_QUERY, null));
|
||||
builder.encodedFragment(getString(KEY_DOWNLOAD_SAVE_FRAGMENT, null));
|
||||
dir = UniFile.fromUri(sContext, builder.build());
|
||||
} catch (Throwable e) {
|
||||
ExceptionUtils.throwIfFatal(e);
|
||||
// Ignore
|
||||
}
|
||||
UniFile dir;
|
||||
Uri.Builder builder = new Uri.Builder();
|
||||
builder.scheme(getString(KEY_DOWNLOAD_SAVE_SCHEME, null));
|
||||
builder.encodedAuthority(getString(KEY_DOWNLOAD_SAVE_AUTHORITY, null));
|
||||
builder.encodedPath(getString(KEY_DOWNLOAD_SAVE_PATH, null));
|
||||
builder.encodedQuery(getString(KEY_DOWNLOAD_SAVE_QUERY, null));
|
||||
builder.encodedFragment(getString(KEY_DOWNLOAD_SAVE_FRAGMENT, null));
|
||||
dir = UniFile.fromUri(EhApplication.getApplication(), builder.build());
|
||||
return dir != null ? dir : UniFile.fromFile(AppConfig.getDefaultDownloadDir());
|
||||
}
|
||||
|
||||
@@ -815,26 +515,14 @@ public class Settings {
|
||||
return getIntFromStr(KEY_MULTI_THREAD_DOWNLOAD, DEFAULT_MULTI_THREAD_DOWNLOAD);
|
||||
}
|
||||
|
||||
public static void putMultiThreadDownload(int value) {
|
||||
putIntToStr(KEY_MULTI_THREAD_DOWNLOAD, value);
|
||||
}
|
||||
|
||||
public static int getDownloadDelay() {
|
||||
return getIntFromStr(KEY_DOWNLOAD_DELAY, DEFAULT_DOWNLOAD_DELAY);
|
||||
}
|
||||
|
||||
public static void putDownloadDelay(int value) {
|
||||
putIntToStr(KEY_DOWNLOAD_DELAY, value);
|
||||
}
|
||||
|
||||
public static int getPreloadImage() {
|
||||
return getIntFromStr(KEY_PRELOAD_IMAGE, DEFAULT_PRELOAD_IMAGE);
|
||||
}
|
||||
|
||||
public static void putPreloadImage(int value) {
|
||||
putIntToStr(KEY_PRELOAD_IMAGE, value);
|
||||
}
|
||||
|
||||
public static String getImageResolution() {
|
||||
return getString(KEY_IMAGE_RESOLUTION, DEFAULT_IMAGE_RESOLUTION);
|
||||
}
|
||||
@@ -849,10 +537,6 @@ public class Settings {
|
||||
return getBoolean(KEY_DOWNLOAD_ORIGIN_IMAGE, DEFAULT_DOWNLOAD_ORIGIN_IMAGE);
|
||||
}
|
||||
|
||||
public static void putDownloadOriginImage(boolean value) {
|
||||
putBoolean(KEY_DOWNLOAD_ORIGIN_IMAGE, value);
|
||||
}
|
||||
|
||||
public static String[] getFavCat() {
|
||||
String[] favCat = new String[10];
|
||||
favCat[0] = sSettingsPre.getString(KEY_FAV_CAT_0, DEFAULT_FAV_CAT_0);
|
||||
@@ -947,100 +631,18 @@ public class Settings {
|
||||
putInt(KEY_DEFAULT_FAV_SLOT, value);
|
||||
}
|
||||
|
||||
public static boolean getAskAnalytics() {
|
||||
return getBoolean(KEY_ASK_ANALYTICS, DEFAULT_ASK_ANALYTICS);
|
||||
public static boolean getQSSaveProgress() {
|
||||
return getBoolean(KEY_QS_SAVE_PROGRESS, DEFAULT_QS_SAVE_PROGRESS);
|
||||
}
|
||||
|
||||
public static void putAskAnalytics(boolean value) {
|
||||
putBoolean(KEY_ASK_ANALYTICS, value);
|
||||
}
|
||||
|
||||
public static boolean getEnableAnalytics() {
|
||||
return getBoolean(KEY_ENABLE_ANALYTICS, DEFAULT_ENABLE_ANALYTICS);
|
||||
}
|
||||
|
||||
public static void putEnableAnalytics(boolean value) {
|
||||
putBoolean(KEY_ENABLE_ANALYTICS, value);
|
||||
}
|
||||
|
||||
public static String getUserID() {
|
||||
boolean writeXml = false;
|
||||
boolean writeFile = false;
|
||||
String userID = getString(KEY_USER_ID, null);
|
||||
File file = AppConfig.getFileInExternalAppDir(FILENAME_USER_ID);
|
||||
if (!isValidUserID(userID)) {
|
||||
writeXml = true;
|
||||
// Get use ID from out sd card file
|
||||
userID = FileUtils.read(file);
|
||||
if (!isValidUserID(userID)) {
|
||||
writeFile = true;
|
||||
userID = generateUserID();
|
||||
}
|
||||
} else {
|
||||
writeFile = true;
|
||||
}
|
||||
|
||||
if (writeXml) {
|
||||
putString(KEY_USER_ID, userID);
|
||||
}
|
||||
if (writeFile) {
|
||||
FileUtils.write(file, userID);
|
||||
}
|
||||
|
||||
return userID;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static String generateUserID() {
|
||||
int length = LENGTH_USER_ID;
|
||||
StringBuilder sb = new StringBuilder(length);
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (MathUtils.random(0, ('9' - '0' + 1) + ('z' - 'a' + 1)) <= '9' - '0') {
|
||||
sb.append((char) MathUtils.random('0', '9' + 1));
|
||||
} else {
|
||||
sb.append((char) MathUtils.random('a', 'z' + 1));
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static boolean isValidUserID(@Nullable String userID) {
|
||||
if (null == userID || LENGTH_USER_ID != userID.length()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < LENGTH_USER_ID; i++) {
|
||||
char ch = userID.charAt(i);
|
||||
if (!(ch >= '0' && ch <= '9') && !(ch >= 'a' && ch <= 'z')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void putBetaUpdateChannel(boolean value) {
|
||||
putBoolean(KEY_BETA_UPDATE_CHANNEL, value);
|
||||
}
|
||||
|
||||
public static int getSkipUpdateVersion() {
|
||||
return getInt(KEY_SKIP_UPDATE_VERSION, DEFAULT_SKIP_UPDATE_VERSION);
|
||||
}
|
||||
|
||||
public static void putSkipUpdateVersion(int value) {
|
||||
putInt(KEY_SKIP_UPDATE_VERSION, value);
|
||||
public static void putQSSaveProgress(boolean value) {
|
||||
putBoolean(KEY_QS_SAVE_PROGRESS, value);
|
||||
}
|
||||
|
||||
public static boolean getSaveParseErrorBody() {
|
||||
return getBoolean(KEY_SAVE_PARSE_ERROR_BODY, DEFAULT_SAVE_PARSE_ERROR_BODY);
|
||||
}
|
||||
|
||||
public static void putSaveParseErrorBody(boolean value) {
|
||||
putBoolean(KEY_SAVE_PARSE_ERROR_BODY, value);
|
||||
}
|
||||
|
||||
public static boolean getSaveCrashLog() {
|
||||
return getBoolean(KEY_SAVE_CRASH_LOG, DEFAULT_SAVE_CRASH_LOG);
|
||||
}
|
||||
@@ -1057,10 +659,6 @@ public class Settings {
|
||||
return getInt(KEY_SECURITY_DELAY, 0);
|
||||
}
|
||||
|
||||
public static boolean getEnableFingerprint() {
|
||||
return getBoolean(KEY_ENABLE_FINGERPRINT, true);
|
||||
}
|
||||
|
||||
public static int getReadCacheSize() {
|
||||
return getIntFromStr(KEY_READ_CACHE_SIZE, DEFAULT_READ_CACHE_SIZE);
|
||||
}
|
||||
@@ -1081,14 +679,6 @@ public class Settings {
|
||||
putBoolean(KEY_DOMAIN_FRONTING, value);
|
||||
}
|
||||
|
||||
public static String getAppLanguage() {
|
||||
return getString(KEY_APP_LANGUAGE, DEFAULT_APP_LANGUAGE);
|
||||
}
|
||||
|
||||
public static void putAppLanguage(String value) {
|
||||
putString(KEY_APP_LANGUAGE, value);
|
||||
}
|
||||
|
||||
public static int getProxyType() {
|
||||
return getInt(KEY_PROXY_TYPE, DEFAULT_PROXY_TYPE);
|
||||
}
|
||||
@@ -1113,46 +703,6 @@ public class Settings {
|
||||
putInt(KEY_PROXY_PORT, value);
|
||||
}
|
||||
|
||||
public static boolean getGuideQuickSearch() {
|
||||
return getBoolean(KEY_GUIDE_QUICK_SEARCH, DEFAULT_GUIDE_QUICK_SEARCH);
|
||||
}
|
||||
|
||||
public static void putGuideQuickSearch(boolean value) {
|
||||
putBoolean(KEY_GUIDE_QUICK_SEARCH, value);
|
||||
}
|
||||
|
||||
public static boolean getGuideCollections() {
|
||||
return getBoolean(KEY_GUIDE_COLLECTIONS, DEFAULT_GUIDE_COLLECTIONS);
|
||||
}
|
||||
|
||||
public static void putGuideCollections(boolean value) {
|
||||
putBoolean(KEY_GUIDE_COLLECTIONS, value);
|
||||
}
|
||||
|
||||
public static boolean getGuideDownloadThumb() {
|
||||
return getBoolean(KEY_GUIDE_DOWNLOAD_THUMB, DEFAULT_GUIDE_DOWNLOAD_THUMB);
|
||||
}
|
||||
|
||||
public static void putGuideDownloadThumb(boolean value) {
|
||||
putBoolean(KEY_GUIDE_DOWNLOAD_THUMB, value);
|
||||
}
|
||||
|
||||
public static boolean getGuideDownloadLabels() {
|
||||
return getBoolean(KEY_GUIDE_DOWNLOAD_LABELS, DEFAULT_GUIDE_DOWNLOAD_LABELS);
|
||||
}
|
||||
|
||||
public static void puttGuideDownloadLabels(boolean value) {
|
||||
putBoolean(KEY_GUIDE_DOWNLOAD_LABELS, value);
|
||||
}
|
||||
|
||||
public static boolean getGuideGallery() {
|
||||
return getBoolean(KEY_GUIDE_GALLERY, DEFAULT_GUIDE_GALLERY);
|
||||
}
|
||||
|
||||
public static void putGuideGallery(boolean value) {
|
||||
putBoolean(KEY_GUIDE_GALLERY, value);
|
||||
}
|
||||
|
||||
public static int getClipboardTextHashCode() {
|
||||
return getInt(KEY_CLIPBOARD_TEXT_HASH_CODE, DEFAULT_CLIPBOARD_TEXT_HASH_CODE);
|
||||
}
|
||||
|
||||
@@ -29,11 +29,12 @@ import androidx.browser.customtabs.CustomTabsIntent;
|
||||
import com.hippo.ehviewer.client.EhUrlOpener;
|
||||
import com.hippo.ehviewer.client.data.GalleryDetail;
|
||||
import com.hippo.ehviewer.client.parser.GalleryPageUrlParser;
|
||||
import com.hippo.ehviewer.ui.GalleryActivity;
|
||||
import com.hippo.ehviewer.ui.MainActivity;
|
||||
import com.hippo.scene.Announcer;
|
||||
import com.hippo.scene.StageActivity;
|
||||
|
||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity;
|
||||
|
||||
public final class UrlOpener {
|
||||
|
||||
private UrlOpener() {
|
||||
@@ -56,19 +57,19 @@ public final class UrlOpener {
|
||||
GalleryPageUrlParser.Result result = GalleryPageUrlParser.parse(url);
|
||||
if (result != null) {
|
||||
if (result.gid == galleryDetail.gid) {
|
||||
intent = new Intent(context, GalleryActivity.class);
|
||||
intent.setAction(GalleryActivity.ACTION_EH);
|
||||
intent.putExtra(GalleryActivity.KEY_GALLERY_INFO, galleryDetail);
|
||||
intent.putExtra(GalleryActivity.KEY_PAGE, result.page);
|
||||
intent = new Intent(context, ReaderActivity.class);
|
||||
intent.setAction(ReaderActivity.ACTION_EH);
|
||||
intent.putExtra(ReaderActivity.KEY_GALLERY_INFO, galleryDetail);
|
||||
intent.putExtra(ReaderActivity.KEY_PAGE, result.page);
|
||||
context.startActivity(intent);
|
||||
return;
|
||||
}
|
||||
} else if (url.startsWith("#c")) {
|
||||
try {
|
||||
intent = new Intent(context, GalleryActivity.class);
|
||||
intent.setAction(GalleryActivity.ACTION_EH);
|
||||
intent.putExtra(GalleryActivity.KEY_GALLERY_INFO, galleryDetail);
|
||||
intent.putExtra(GalleryActivity.KEY_PAGE, Integer.parseInt(url.replace("#c", "")) - 1);
|
||||
intent = new Intent(context, ReaderActivity.class);
|
||||
intent.setAction(ReaderActivity.ACTION_EH);
|
||||
intent.putExtra(ReaderActivity.KEY_GALLERY_INFO, galleryDetail);
|
||||
intent.putExtra(ReaderActivity.KEY_PAGE, Integer.parseInt(url.replace("#c", "")) - 1);
|
||||
context.startActivity(intent);
|
||||
return;
|
||||
} catch (NumberFormatException e) {
|
||||
|
||||
@@ -1,212 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.ehviewer.client;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import com.hippo.ehviewer.EhApplication;
|
||||
import com.hippo.ehviewer.client.exception.CancelledException;
|
||||
import com.hippo.util.ExceptionUtils;
|
||||
import com.hippo.util.IoThreadPoolExecutor;
|
||||
import com.hippo.yorozuya.SimpleHandler;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import okhttp3.Call;
|
||||
import okhttp3.OkHttpClient;
|
||||
|
||||
public class EhClient {
|
||||
|
||||
public static final String TAG = EhClient.class.getSimpleName();
|
||||
|
||||
public static final int METHOD_SIGN_IN = 0;
|
||||
public static final int METHOD_GET_GALLERY_LIST = 1;
|
||||
public static final int METHOD_GET_GALLERY_DETAIL = 3;
|
||||
public static final int METHOD_GET_PREVIEW_SET = 4;
|
||||
public static final int METHOD_GET_RATE_GALLERY = 5;
|
||||
public static final int METHOD_GET_COMMENT_GALLERY = 6;
|
||||
public static final int METHOD_GET_GALLERY_TOKEN = 7;
|
||||
public static final int METHOD_GET_FAVORITES = 8;
|
||||
public static final int METHOD_ADD_FAVORITES = 9;
|
||||
public static final int METHOD_ADD_FAVORITES_RANGE = 10;
|
||||
public static final int METHOD_MODIFY_FAVORITES = 11;
|
||||
public static final int METHOD_GET_TORRENT_LIST = 12;
|
||||
public static final int METHOD_GET_PROFILE = 14;
|
||||
public static final int METHOD_VOTE_COMMENT = 15;
|
||||
public static final int METHOD_IMAGE_SEARCH = 16;
|
||||
public static final int METHOD_ARCHIVE_LIST = 17;
|
||||
public static final int METHOD_DOWNLOAD_ARCHIVE = 18;
|
||||
public static final int METHOD_VOTE_TAG = 19;
|
||||
|
||||
private final ThreadPoolExecutor mRequestThreadPool;
|
||||
private final OkHttpClient mOkHttpClient;
|
||||
|
||||
public EhClient(Context context) {
|
||||
mRequestThreadPool = IoThreadPoolExecutor.getInstance();
|
||||
mOkHttpClient = EhApplication.getOkHttpClient();
|
||||
}
|
||||
|
||||
public void execute(EhRequest request) {
|
||||
if (!request.isCancelled()) {
|
||||
Task task = new Task(request.getMethod(), request.getCallback(), request.getEhConfig());
|
||||
task.executeOnExecutor(mRequestThreadPool, request.getArgs());
|
||||
request.task = task;
|
||||
} else {
|
||||
request.getCallback().onCancel();
|
||||
}
|
||||
}
|
||||
|
||||
public interface Callback<E> {
|
||||
|
||||
void onSuccess(E result);
|
||||
|
||||
void onFailure(Exception e);
|
||||
|
||||
void onCancel();
|
||||
}
|
||||
|
||||
public class Task extends AsyncTask<Object, Void, Object> {
|
||||
|
||||
private final int mMethod;
|
||||
private final AtomicReference<Call> mCall = new AtomicReference<>();
|
||||
private final AtomicBoolean mStop = new AtomicBoolean();
|
||||
private Callback mCallback;
|
||||
private EhConfig mEhConfig;
|
||||
|
||||
public Task(int method, Callback callback, EhConfig ehConfig) {
|
||||
mMethod = method;
|
||||
mCallback = callback;
|
||||
mEhConfig = ehConfig;
|
||||
}
|
||||
|
||||
// Called in Job thread
|
||||
public void setCall(Call call) throws CancelledException {
|
||||
if (mStop.get()) {
|
||||
// Stopped Job thread
|
||||
throw new CancelledException();
|
||||
} else {
|
||||
mCall.lazySet(call);
|
||||
}
|
||||
}
|
||||
|
||||
public EhConfig getEhConfig() {
|
||||
return mEhConfig;
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if (!mStop.get()) {
|
||||
mStop.lazySet(true);
|
||||
|
||||
if (mCallback != null) {
|
||||
// TODO Avoid new runnable
|
||||
SimpleHandler.getInstance().post(mCallback::onCancel);
|
||||
}
|
||||
|
||||
Status status = getStatus();
|
||||
if (status == Status.PENDING) {
|
||||
cancel(false);
|
||||
} else if (status == Status.RUNNING) {
|
||||
// It is running, cancel call if it is created
|
||||
Call call = mCall.get();
|
||||
if (call != null) {
|
||||
call.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
// Clear
|
||||
mCallback = null;
|
||||
mEhConfig = null;
|
||||
mCall.lazySet(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object doInBackground(Object... params) {
|
||||
try {
|
||||
switch (mMethod) {
|
||||
case METHOD_SIGN_IN:
|
||||
return EhEngine.signIn(this, mOkHttpClient, (String) params[0], (String) params[1]);
|
||||
case METHOD_GET_GALLERY_LIST:
|
||||
return EhEngine.getGalleryList(this, mOkHttpClient, (String) params[0]);
|
||||
case METHOD_GET_GALLERY_DETAIL:
|
||||
return EhEngine.getGalleryDetail(this, mOkHttpClient, (String) params[0]);
|
||||
case METHOD_GET_PREVIEW_SET:
|
||||
return EhEngine.getPreviewSet(this, mOkHttpClient, (String) params[0]);
|
||||
case METHOD_GET_RATE_GALLERY:
|
||||
return EhEngine.rateGallery(this, mOkHttpClient, (Long) params[0], (String) params[1], (Long) params[2], (String) params[3], (Float) params[4]);
|
||||
case METHOD_GET_COMMENT_GALLERY:
|
||||
return EhEngine.commentGallery(this, mOkHttpClient, (String) params[0], (String) params[1], (String) params[2]);
|
||||
case METHOD_GET_GALLERY_TOKEN:
|
||||
return EhEngine.getGalleryToken(this, mOkHttpClient, (Long) params[0], (String) params[1], (Integer) params[2]);
|
||||
case METHOD_GET_FAVORITES:
|
||||
return EhEngine.getFavorites(this, mOkHttpClient, (String) params[0], (Boolean) params[1]);
|
||||
case METHOD_ADD_FAVORITES:
|
||||
return EhEngine.addFavorites(this, mOkHttpClient, (Long) params[0], (String) params[1], (Integer) params[2], (String) params[3]);
|
||||
case METHOD_ADD_FAVORITES_RANGE:
|
||||
return EhEngine.addFavoritesRange(this, mOkHttpClient, (long[]) params[0], (String[]) params[1], (Integer) params[2]);
|
||||
case METHOD_MODIFY_FAVORITES:
|
||||
return EhEngine.modifyFavorites(this, mOkHttpClient, (String) params[0], (long[]) params[1], (Integer) params[2], (Boolean) params[3]);
|
||||
case METHOD_GET_TORRENT_LIST:
|
||||
return EhEngine.getTorrentList(this, mOkHttpClient, (String) params[0], (Long) params[1], (String) params[2]);
|
||||
case METHOD_GET_PROFILE:
|
||||
return EhEngine.getProfile(this, mOkHttpClient);
|
||||
case METHOD_VOTE_COMMENT:
|
||||
return EhEngine.voteComment(this, mOkHttpClient, (Long) params[0], (String) params[1], (Long) params[2], (String) params[3], (Long) params[4], (Integer) params[5]);
|
||||
case METHOD_IMAGE_SEARCH:
|
||||
return EhEngine.imageSearch(this, mOkHttpClient, (File) params[0], (Boolean) params[1], (Boolean) params[2], (Boolean) params[3]);
|
||||
case METHOD_ARCHIVE_LIST:
|
||||
return EhEngine.getArchiveList(this, mOkHttpClient, (String) params[0], (Long) params[1], (String) params[2]);
|
||||
case METHOD_DOWNLOAD_ARCHIVE:
|
||||
return EhEngine.downloadArchive(this, mOkHttpClient, (Long) params[0], (String) params[1], (String) params[2], (String) params[3]);
|
||||
case METHOD_VOTE_TAG:
|
||||
return EhEngine.voteTag(this, mOkHttpClient, (Long) params[0], (String) params[1], (Long) params[2], (String) params[3], (String) params[4], (Integer) params[5]);
|
||||
default:
|
||||
return new IllegalStateException("Can't detect method " + mMethod);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
ExceptionUtils.throwIfFatal(e);
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected void onPostExecute(Object result) {
|
||||
if (mCallback != null) {
|
||||
//noinspection StatementWithEmptyBody
|
||||
if (!(result instanceof CancelledException)) {
|
||||
if (result instanceof Exception) {
|
||||
mCallback.onFailure((Exception) result);
|
||||
} else {
|
||||
mCallback.onSuccess(result);
|
||||
}
|
||||
} else {
|
||||
// onCancel is called in stop
|
||||
}
|
||||
}
|
||||
|
||||
// Clear
|
||||
mCallback = null;
|
||||
mEhConfig = null;
|
||||
mCall.lazySet(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.hippo.ehviewer.client
|
||||
|
||||
import com.hippo.ehviewer.EhApplication.Companion.okHttpClient
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import eu.kanade.tachiyomi.util.lang.withUIContext
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import java.io.File
|
||||
|
||||
object EhClient {
|
||||
internal fun enqueue(request: EhRequest, scope: CoroutineScope) {
|
||||
check(!request.isActive) // Abort if attempt to execute an active request
|
||||
request.job = scope.launchIO {
|
||||
val method = request.method
|
||||
val params = request.args
|
||||
val callback: Callback<Any?>? = request.callback
|
||||
try {
|
||||
val result: Any? = when (method) {
|
||||
METHOD_SIGN_IN -> EhEngine.signIn(
|
||||
mOkHttpClient,
|
||||
params!![0] as String,
|
||||
params[1] as String
|
||||
)
|
||||
|
||||
METHOD_GET_GALLERY_LIST -> EhEngine.getGalleryList(
|
||||
mOkHttpClient,
|
||||
params!![0] as String
|
||||
)
|
||||
|
||||
METHOD_GET_GALLERY_DETAIL -> EhEngine.getGalleryDetail(
|
||||
mOkHttpClient,
|
||||
params!![0] as String?
|
||||
)
|
||||
|
||||
METHOD_GET_PREVIEW_SET -> EhEngine.getPreviewSet(
|
||||
mOkHttpClient,
|
||||
params!![0] as String?
|
||||
)
|
||||
|
||||
METHOD_GET_RATE_GALLERY -> EhEngine.rateGallery(
|
||||
mOkHttpClient,
|
||||
params!![0] as Long,
|
||||
params[1] as String?,
|
||||
params[2] as Long,
|
||||
params[3] as String?,
|
||||
params[4] as Float
|
||||
)
|
||||
|
||||
METHOD_GET_COMMENT_GALLERY -> EhEngine.commentGallery(
|
||||
mOkHttpClient,
|
||||
params!![0] as String?,
|
||||
params[1] as String,
|
||||
params[2] as String?
|
||||
)
|
||||
|
||||
METHOD_GET_GALLERY_TOKEN -> EhEngine.getGalleryToken(
|
||||
mOkHttpClient,
|
||||
params!![0] as Long,
|
||||
params[1] as String?,
|
||||
params[2] as Int
|
||||
)
|
||||
|
||||
METHOD_GET_FAVORITES -> EhEngine.getFavorites(
|
||||
mOkHttpClient,
|
||||
params!![0] as String
|
||||
)
|
||||
|
||||
METHOD_ADD_FAVORITES -> EhEngine.addFavorites(
|
||||
mOkHttpClient,
|
||||
params!![0] as Long,
|
||||
params[1] as String?,
|
||||
params[2] as Int,
|
||||
params[3] as String?
|
||||
)
|
||||
|
||||
METHOD_ADD_FAVORITES_RANGE -> @Suppress("UNCHECKED_CAST") EhEngine.addFavoritesRange(
|
||||
mOkHttpClient,
|
||||
params!![0] as LongArray,
|
||||
params[1] as Array<String?>,
|
||||
params[2] as Int
|
||||
)
|
||||
|
||||
METHOD_MODIFY_FAVORITES -> EhEngine.modifyFavorites(
|
||||
mOkHttpClient,
|
||||
params!![0] as String,
|
||||
params[1] as LongArray,
|
||||
params[2] as Int
|
||||
)
|
||||
|
||||
METHOD_GET_TORRENT_LIST -> EhEngine.getTorrentList(
|
||||
mOkHttpClient,
|
||||
params!![0] as String?,
|
||||
params[1] as Long,
|
||||
params[2] as String?
|
||||
)
|
||||
|
||||
METHOD_GET_PROFILE -> EhEngine.getProfile(mOkHttpClient)
|
||||
METHOD_VOTE_COMMENT -> EhEngine.voteComment(
|
||||
mOkHttpClient,
|
||||
params!![0] as Long,
|
||||
params[1] as String?,
|
||||
params[2] as Long,
|
||||
params[3] as String?,
|
||||
params[4] as Long,
|
||||
params[5] as Int
|
||||
)
|
||||
|
||||
METHOD_IMAGE_SEARCH -> EhEngine.imageSearch(
|
||||
mOkHttpClient,
|
||||
params!![0] as File,
|
||||
params[1] as Boolean,
|
||||
params[2] as Boolean,
|
||||
params[3] as Boolean
|
||||
)
|
||||
|
||||
METHOD_ARCHIVE_LIST -> EhEngine.getArchiveList(
|
||||
mOkHttpClient,
|
||||
params!![0] as String?,
|
||||
params[1] as Long,
|
||||
params[2] as String?
|
||||
)
|
||||
|
||||
METHOD_DOWNLOAD_ARCHIVE -> EhEngine.downloadArchive(
|
||||
mOkHttpClient,
|
||||
params!![0] as Long,
|
||||
params[1] as String?,
|
||||
params[2] as String?,
|
||||
params[3] as String?,
|
||||
params[4] as Boolean
|
||||
)
|
||||
|
||||
METHOD_VOTE_TAG -> EhEngine.voteTag(
|
||||
mOkHttpClient,
|
||||
params!![0] as Long,
|
||||
params[1] as String?,
|
||||
params[2] as Long,
|
||||
params[3] as String?,
|
||||
params[4] as String?,
|
||||
params[5] as Int
|
||||
)
|
||||
|
||||
METHOD_GET_UCONFIG -> EhEngine.getUConfig(mOkHttpClient)
|
||||
else -> throw IllegalStateException("Can't detect method $method")
|
||||
}
|
||||
withUIContext { callback?.onSuccess(result) }
|
||||
} catch (e: Exception) {
|
||||
if (e is CancellationException)
|
||||
throw e // Don't catch coroutine CancellationException
|
||||
e.printStackTrace()
|
||||
withUIContext { callback?.onFailure(e) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface Callback<E> {
|
||||
fun onSuccess(result: E)
|
||||
fun onFailure(e: Exception)
|
||||
fun onCancel()
|
||||
}
|
||||
|
||||
const val METHOD_SIGN_IN = 0
|
||||
const val METHOD_GET_GALLERY_LIST = 1
|
||||
const val METHOD_GET_GALLERY_DETAIL = 3
|
||||
const val METHOD_GET_PREVIEW_SET = 4
|
||||
const val METHOD_GET_RATE_GALLERY = 5
|
||||
const val METHOD_GET_COMMENT_GALLERY = 6
|
||||
const val METHOD_GET_GALLERY_TOKEN = 7
|
||||
const val METHOD_GET_FAVORITES = 8
|
||||
const val METHOD_ADD_FAVORITES = 9
|
||||
const val METHOD_ADD_FAVORITES_RANGE = 10
|
||||
const val METHOD_MODIFY_FAVORITES = 11
|
||||
const val METHOD_GET_TORRENT_LIST = 12
|
||||
const val METHOD_GET_PROFILE = 14
|
||||
const val METHOD_VOTE_COMMENT = 15
|
||||
const val METHOD_IMAGE_SEARCH = 16
|
||||
const val METHOD_ARCHIVE_LIST = 17
|
||||
const val METHOD_DOWNLOAD_ARCHIVE = 18
|
||||
const val METHOD_VOTE_TAG = 19
|
||||
const val METHOD_GET_UCONFIG = 20
|
||||
private val mOkHttpClient = okHttpClient
|
||||
}
|
||||
@@ -22,7 +22,7 @@ import okhttp3.Dns
|
||||
import java.net.InetAddress
|
||||
import java.net.UnknownHostException
|
||||
|
||||
class EhDns : Dns {
|
||||
object EhDns : Dns {
|
||||
private val hosts = EhApplication.hosts
|
||||
private val builtInHosts: MutableMap<String, List<InetAddress>> = mutableMapOf()
|
||||
|
||||
@@ -42,7 +42,7 @@ class EhDns : Dns {
|
||||
put(
|
||||
builtInHosts,
|
||||
"e-hentai.org",
|
||||
Pair("104.20.134.21", true),
|
||||
Pair("104.20.134.21", false),
|
||||
Pair("104.20.135.21", false),
|
||||
Pair("172.67.0.127", false),
|
||||
)
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -18,12 +18,16 @@ package com.hippo.ehviewer.client;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.hippo.ehviewer.EhDB;
|
||||
import com.hippo.ehviewer.client.data.GalleryInfo;
|
||||
import com.hippo.ehviewer.dao.Filter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public final class EhFilter {
|
||||
|
||||
@@ -31,41 +35,43 @@ public final class EhFilter {
|
||||
public static final int MODE_UPLOADER = 1;
|
||||
public static final int MODE_TAG = 2;
|
||||
public static final int MODE_TAG_NAMESPACE = 3;
|
||||
public static final int MODE_COMMENTER = 4;
|
||||
public static final int MODE_COMMENT = 5;
|
||||
private static final String TAG = EhFilter.class.getSimpleName();
|
||||
private static EhFilter sInstance;
|
||||
private final List<Filter> mTitleFilterList = new ArrayList<>();
|
||||
private final List<Filter> mUploaderFilterList = new ArrayList<>();
|
||||
private final List<Filter> mTagFilterList = new ArrayList<>();
|
||||
private final List<Filter> mTagNamespaceFilterList = new ArrayList<>();
|
||||
private final List<Filter> mCommenterFilterList = new ArrayList<>();
|
||||
private final List<Filter> mCommentFilterList = new ArrayList<>();
|
||||
|
||||
private EhFilter() {
|
||||
List<Filter> list = EhDB.getAllFilter();
|
||||
for (int i = 0, n = list.size(); i < n; i++) {
|
||||
Filter filter = list.get(i);
|
||||
switch (filter.mode) {
|
||||
case MODE_TITLE:
|
||||
case MODE_TITLE -> {
|
||||
filter.text = filter.text.toLowerCase();
|
||||
mTitleFilterList.add(filter);
|
||||
break;
|
||||
case MODE_UPLOADER:
|
||||
mUploaderFilterList.add(filter);
|
||||
break;
|
||||
case MODE_TAG:
|
||||
}
|
||||
case MODE_TAG -> {
|
||||
filter.text = filter.text.toLowerCase();
|
||||
mTagFilterList.add(filter);
|
||||
break;
|
||||
case MODE_TAG_NAMESPACE:
|
||||
}
|
||||
case MODE_TAG_NAMESPACE -> {
|
||||
filter.text = filter.text.toLowerCase();
|
||||
mTagNamespaceFilterList.add(filter);
|
||||
break;
|
||||
default:
|
||||
Log.d(TAG, "Unknown mode: " + filter.mode);
|
||||
break;
|
||||
}
|
||||
case MODE_UPLOADER -> mUploaderFilterList.add(filter);
|
||||
case MODE_COMMENTER -> mCommenterFilterList.add(filter);
|
||||
case MODE_COMMENT -> mCommentFilterList.add(filter);
|
||||
default -> Log.d(TAG, "Unknown mode: " + filter.mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static EhFilter getInstance() {
|
||||
public static @NonNull EhFilter getInstance() {
|
||||
if (sInstance == null) {
|
||||
sInstance = new EhFilter();
|
||||
}
|
||||
@@ -88,30 +94,36 @@ public final class EhFilter {
|
||||
return mTagNamespaceFilterList;
|
||||
}
|
||||
|
||||
public List<Filter> getCommenterFilterList() {
|
||||
return mCommenterFilterList;
|
||||
}
|
||||
|
||||
public List<Filter> getCommentFilterList() {
|
||||
return mCommentFilterList;
|
||||
}
|
||||
|
||||
public synchronized boolean addFilter(Filter filter) {
|
||||
// enable filter by default before it is added to database
|
||||
filter.enable = true;
|
||||
if (!EhDB.addFilter(filter)) return false;
|
||||
|
||||
switch (filter.mode) {
|
||||
case MODE_TITLE:
|
||||
case MODE_TITLE -> {
|
||||
filter.text = filter.text.toLowerCase();
|
||||
mTitleFilterList.add(filter);
|
||||
break;
|
||||
case MODE_UPLOADER:
|
||||
mUploaderFilterList.add(filter);
|
||||
break;
|
||||
case MODE_TAG:
|
||||
}
|
||||
case MODE_TAG -> {
|
||||
filter.text = filter.text.toLowerCase();
|
||||
mTagFilterList.add(filter);
|
||||
break;
|
||||
case MODE_TAG_NAMESPACE:
|
||||
}
|
||||
case MODE_TAG_NAMESPACE -> {
|
||||
filter.text = filter.text.toLowerCase();
|
||||
mTagNamespaceFilterList.add(filter);
|
||||
break;
|
||||
default:
|
||||
Log.d(TAG, "Unknown mode: " + filter.mode);
|
||||
break;
|
||||
}
|
||||
case MODE_UPLOADER -> mUploaderFilterList.add(filter);
|
||||
case MODE_COMMENTER -> mCommenterFilterList.add(filter);
|
||||
case MODE_COMMENT -> mCommentFilterList.add(filter);
|
||||
default -> Log.d(TAG, "Unknown mode: " + filter.mode);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -124,21 +136,13 @@ public final class EhFilter {
|
||||
EhDB.deleteFilter(filter);
|
||||
|
||||
switch (filter.mode) {
|
||||
case MODE_TITLE:
|
||||
mTitleFilterList.remove(filter);
|
||||
break;
|
||||
case MODE_UPLOADER:
|
||||
mUploaderFilterList.remove(filter);
|
||||
break;
|
||||
case MODE_TAG:
|
||||
mTagFilterList.remove(filter);
|
||||
break;
|
||||
case MODE_TAG_NAMESPACE:
|
||||
mTagNamespaceFilterList.remove(filter);
|
||||
break;
|
||||
default:
|
||||
Log.d(TAG, "Unknown mode: " + filter.mode);
|
||||
break;
|
||||
case MODE_TITLE -> mTitleFilterList.remove(filter);
|
||||
case MODE_TAG -> mTagFilterList.remove(filter);
|
||||
case MODE_TAG_NAMESPACE -> mTagNamespaceFilterList.remove(filter);
|
||||
case MODE_UPLOADER -> mUploaderFilterList.remove(filter);
|
||||
case MODE_COMMENTER -> mCommenterFilterList.remove(filter);
|
||||
case MODE_COMMENT -> mCommentFilterList.remove(filter);
|
||||
default -> Log.d(TAG, "Unknown mode: " + filter.mode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,4 +276,40 @@ public final class EhFilter {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public synchronized boolean filterCommenter(String commenter) {
|
||||
if (null == commenter) {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<Filter> filters = mCommenterFilterList;
|
||||
if (filters.size() > 0) {
|
||||
for (int i = 0, n = filters.size(); i < n; i++) {
|
||||
if (filters.get(i).enable && commenter.equals(filters.get(i).text)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public synchronized boolean filterComment(String comment) {
|
||||
if (null == comment) {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<Filter> filters = mCommentFilterList;
|
||||
if (filters.size() > 0) {
|
||||
for (int i = 0, n = filters.size(); i < n; i++) {
|
||||
if (filters.get(i).enable) {
|
||||
Pattern p = Pattern.compile(filters.get(i).text);
|
||||
Matcher m = p.matcher(comment);
|
||||
if (m.find()) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.ehviewer.client;
|
||||
|
||||
import com.hippo.ehviewer.Settings;
|
||||
|
||||
public class EhRequest {
|
||||
|
||||
EhClient.Task task;
|
||||
private int mMethod;
|
||||
private Object[] mArgs;
|
||||
private EhClient.Callback mCallback;
|
||||
private EhConfig mEhConfig;
|
||||
private boolean mCancel = false;
|
||||
|
||||
public int getMethod() {
|
||||
return mMethod;
|
||||
}
|
||||
|
||||
public EhRequest setMethod(int method) {
|
||||
mMethod = method;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Object[] getArgs() {
|
||||
return mArgs;
|
||||
}
|
||||
|
||||
public EhRequest setArgs(Object... args) {
|
||||
mArgs = args;
|
||||
return this;
|
||||
}
|
||||
|
||||
public EhClient.Callback getCallback() {
|
||||
return mCallback;
|
||||
}
|
||||
|
||||
public EhRequest setCallback(EhClient.Callback callback) {
|
||||
mCallback = callback;
|
||||
return this;
|
||||
}
|
||||
|
||||
public EhConfig getEhConfig() {
|
||||
return mEhConfig != null ? mEhConfig : Settings.getEhConfig();
|
||||
}
|
||||
|
||||
public EhRequest setEhConfig(EhConfig ehConfig) {
|
||||
mEhConfig = ehConfig;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
if (!mCancel) {
|
||||
mCancel = true;
|
||||
if (task != null) {
|
||||
task.stop();
|
||||
task = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isCancelled() {
|
||||
return mCancel;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.hippo.ehviewer.client
|
||||
|
||||
import android.app.Activity
|
||||
import androidx.annotation.MainThread
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.Job
|
||||
|
||||
class EhRequest {
|
||||
internal var job: Job? = null
|
||||
val isActive
|
||||
get() = job?.isActive ?: false
|
||||
var method = 0
|
||||
private set
|
||||
var args: Array<out Any>? = null
|
||||
private set
|
||||
var callback: EhClient.Callback<Any?>? = null
|
||||
private set
|
||||
|
||||
fun setMethod(method: Int): EhRequest {
|
||||
this.method = method
|
||||
return this
|
||||
}
|
||||
|
||||
fun setArgs(vararg args: Any): EhRequest {
|
||||
this.args = args
|
||||
return this
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun setCallback(callback: EhClient.Callback<*>?): EhRequest {
|
||||
this.callback = callback as EhClient.Callback<Any?>?
|
||||
return this
|
||||
}
|
||||
|
||||
fun enqueue(scope: CoroutineScope) {
|
||||
EhClient.enqueue(this, scope)
|
||||
}
|
||||
|
||||
@DelicateCoroutinesApi
|
||||
fun enqueue() {
|
||||
EhClient.enqueue(this, GlobalScope)
|
||||
}
|
||||
|
||||
fun enqueue(fragment: Fragment) {
|
||||
enqueue(fragment.lifecycleScope)
|
||||
}
|
||||
|
||||
fun enqueue(activity: Activity) {
|
||||
check(activity is FragmentActivity)
|
||||
enqueue(activity.lifecycleScope)
|
||||
}
|
||||
|
||||
@MainThread
|
||||
fun cancel() {
|
||||
if (isActive) {
|
||||
job?.cancel()
|
||||
callback?.onCancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ import java.net.Socket
|
||||
import javax.net.ssl.SSLSocket
|
||||
import javax.net.ssl.SSLSocketFactory
|
||||
|
||||
class EhSSLSocketFactory : SSLSocketFactory() {
|
||||
object EhSSLSocketFactory : SSLSocketFactory() {
|
||||
private val sslSocketFactory = getDefault() as SSLSocketFactory
|
||||
override fun getDefaultCipherSuites(): Array<String> {
|
||||
return sslSocketFactory.defaultCipherSuites
|
||||
|
||||
@@ -1,436 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.ehviewer.client;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Base64;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.util.Pair;
|
||||
|
||||
import com.hippo.ehviewer.AppConfig;
|
||||
import com.hippo.ehviewer.EhApplication;
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.util.ExceptionUtils;
|
||||
import com.hippo.util.IoThreadPoolExecutor;
|
||||
import com.hippo.yorozuya.FileUtils;
|
||||
import com.hippo.yorozuya.IOUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import okhttp3.Call;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
import okio.BufferedSource;
|
||||
import okio.Okio;
|
||||
|
||||
public class EhTagDatabase {
|
||||
|
||||
private static final Map<String, String> NAMESPACE_TO_PREFIX = new HashMap<>();
|
||||
// TODO more lock for different language
|
||||
private static final Lock lock = new ReentrantLock();
|
||||
private static volatile EhTagDatabase instance;
|
||||
|
||||
static {
|
||||
NAMESPACE_TO_PREFIX.put("artist", "a:");
|
||||
NAMESPACE_TO_PREFIX.put("cosplayer", "cos:");
|
||||
NAMESPACE_TO_PREFIX.put("character", "c:");
|
||||
NAMESPACE_TO_PREFIX.put("female", "f:");
|
||||
NAMESPACE_TO_PREFIX.put("group", "g:");
|
||||
NAMESPACE_TO_PREFIX.put("language", "l:");
|
||||
NAMESPACE_TO_PREFIX.put("male", "m:");
|
||||
NAMESPACE_TO_PREFIX.put("mixed", "x:");
|
||||
NAMESPACE_TO_PREFIX.put("other", "o:");
|
||||
NAMESPACE_TO_PREFIX.put("parody", "p:");
|
||||
NAMESPACE_TO_PREFIX.put("reclass", "r:");
|
||||
}
|
||||
|
||||
private final String name;
|
||||
private final byte[] tags;
|
||||
|
||||
public EhTagDatabase(String name, BufferedSource source) throws IOException {
|
||||
this.name = name;
|
||||
String[] tmp;
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
source.readInt();
|
||||
for (String i : source.readUtf8().split("\n")) {
|
||||
tmp = i.split("\r", 2);
|
||||
buffer.append(tmp[0]);
|
||||
buffer.append("\r");
|
||||
try {
|
||||
buffer.append(new String(Base64.decode(tmp[1], Base64.DEFAULT), StandardCharsets.UTF_8));
|
||||
} catch (Exception e) {
|
||||
buffer.append(tmp[1]);
|
||||
}
|
||||
buffer.append("\n");
|
||||
}
|
||||
byte[] b = buffer.toString().getBytes(StandardCharsets.UTF_8);
|
||||
int totalBytes = b.length;
|
||||
tags = new byte[totalBytes];
|
||||
System.arraycopy(b, 0, tags, 0, totalBytes);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static EhTagDatabase getInstance(Context context) {
|
||||
if (isPossible(context)) {
|
||||
return instance;
|
||||
} else {
|
||||
instance = null;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String namespaceToPrefix(String namespace) {
|
||||
return NAMESPACE_TO_PREFIX.get(namespace);
|
||||
}
|
||||
|
||||
private static String[] getMetadata(Context context) {
|
||||
String[] metadata = context.getResources().getStringArray(R.array.tag_translation_metadata);
|
||||
if (metadata.length == 4) {
|
||||
return metadata;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isPossible(Context context) {
|
||||
return getMetadata(context) != null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static byte[] getFileContent(File file, int length) {
|
||||
try (BufferedSource source = Okio.buffer(Okio.source(file))) {
|
||||
byte[] content = new byte[length];
|
||||
source.readFully(content);
|
||||
return content;
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static byte[] getFileSha1(File file) {
|
||||
try (InputStream is = new FileInputStream(file)) {
|
||||
MessageDigest digest = MessageDigest.getInstance("SHA-1");
|
||||
int n;
|
||||
byte[] buffer = new byte[4 * 1024];
|
||||
while ((n = is.read(buffer)) != -1) {
|
||||
digest.update(buffer, 0, n);
|
||||
}
|
||||
return digest.digest();
|
||||
} catch (IOException | NoSuchAlgorithmException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean equals(byte[] b1, byte[] b2) {
|
||||
if (b1 == null && b2 == null) {
|
||||
return true;
|
||||
}
|
||||
if (b1 == null || b2 == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (b1.length != b2.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < b1.length; i++) {
|
||||
if (b1[i] != b2[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean checkData(File sha1File, File dataFile) {
|
||||
byte[] s1 = getFileContent(sha1File, 20);
|
||||
if (s1 == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
byte[] s2 = getFileSha1(dataFile);
|
||||
if (s2 == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return equals(s1, s2);
|
||||
}
|
||||
|
||||
private static boolean save(OkHttpClient client, String url, File file) {
|
||||
Request request = new Request.Builder().url(url).build();
|
||||
Call call = client.newCall(request);
|
||||
try (Response response = call.execute()) {
|
||||
if (!response.isSuccessful()) {
|
||||
return false;
|
||||
}
|
||||
ResponseBody body = response.body();
|
||||
if (body == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try (InputStream is = body.byteStream(); OutputStream os = new FileOutputStream(file)) {
|
||||
IOUtils.copy(is, os);
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
ExceptionUtils.throwIfFatal(t);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void update(Context context) {
|
||||
String[] urls = getMetadata(context);
|
||||
if (urls == null || urls.length != 4) {
|
||||
// Clear tags if it's not possible
|
||||
instance = null;
|
||||
return;
|
||||
}
|
||||
|
||||
String sha1Name = urls[0];
|
||||
String sha1Url = urls[1];
|
||||
String dataName = urls[2];
|
||||
String dataUrl = urls[3];
|
||||
|
||||
// Clear tags if name if different
|
||||
EhTagDatabase tmp = instance;
|
||||
if (tmp != null && !tmp.name.equals(dataName)) {
|
||||
instance = null;
|
||||
}
|
||||
|
||||
IoThreadPoolExecutor.getInstance().execute(() -> {
|
||||
if (!lock.tryLock()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
File dir = AppConfig.getFilesDir("tag-translations");
|
||||
if (dir == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check current sha1 and current data
|
||||
File sha1File = new File(dir, sha1Name);
|
||||
File dataFile = new File(dir, dataName);
|
||||
if (!checkData(sha1File, dataFile)) {
|
||||
FileUtils.delete(sha1File);
|
||||
FileUtils.delete(dataFile);
|
||||
}
|
||||
|
||||
// Read current EhTagDatabase
|
||||
if (instance == null && dataFile.exists()) {
|
||||
try (BufferedSource source = Okio.buffer(Okio.source(dataFile))) {
|
||||
instance = new EhTagDatabase(dataName, source);
|
||||
} catch (IOException e) {
|
||||
FileUtils.delete(sha1File);
|
||||
FileUtils.delete(dataFile);
|
||||
}
|
||||
}
|
||||
|
||||
OkHttpClient client = EhApplication.getOkHttpClient();
|
||||
|
||||
// Save new sha1
|
||||
File tempSha1File = new File(dir, sha1Name + ".tmp");
|
||||
if (!save(client, sha1Url, tempSha1File)) {
|
||||
FileUtils.delete(tempSha1File);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check new sha1 and current data
|
||||
if (checkData(tempSha1File, dataFile)) {
|
||||
// The data is the same
|
||||
FileUtils.delete(tempSha1File);
|
||||
return;
|
||||
}
|
||||
|
||||
// Save new data
|
||||
File tempDataFile = new File(dir, dataName + ".tmp");
|
||||
if (!save(client, dataUrl, tempDataFile)) {
|
||||
FileUtils.delete(tempDataFile);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check new sha1 and new data
|
||||
if (!checkData(tempSha1File, tempDataFile)) {
|
||||
FileUtils.delete(tempSha1File);
|
||||
FileUtils.delete(tempDataFile);
|
||||
return;
|
||||
}
|
||||
|
||||
// Replace current sha1 and current data with new sha1 and new data
|
||||
FileUtils.delete(sha1File);
|
||||
FileUtils.delete(dataFile);
|
||||
tempSha1File.renameTo(sha1File);
|
||||
tempDataFile.renameTo(dataFile);
|
||||
|
||||
// Read new EhTagDatabase
|
||||
try (BufferedSource source = Okio.buffer(Okio.source(dataFile))) {
|
||||
instance = new EhTagDatabase(dataName, source);
|
||||
} catch (IOException e) {
|
||||
// Ignore
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public String getTranslation(String tag) {
|
||||
return search(tags, tag.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String search(byte[] tags, byte[] tag) {
|
||||
int low = 0;
|
||||
int high = tags.length;
|
||||
while (low < high) {
|
||||
int start = (low + high) / 2;
|
||||
// Look for the starting '\n'
|
||||
while (start > -1 && tags[start] != '\n') {
|
||||
start--;
|
||||
}
|
||||
start++;
|
||||
|
||||
// Look for the middle '\r'.
|
||||
int middle = 1;
|
||||
while (tags[start + middle] != '\r') {
|
||||
middle++;
|
||||
}
|
||||
|
||||
// Look for the ending '\n'
|
||||
int end = middle + 1;
|
||||
while (tags[start + end] != '\n') {
|
||||
end++;
|
||||
}
|
||||
|
||||
int compare;
|
||||
int tagIndex = 0;
|
||||
int curIndex = start;
|
||||
|
||||
for (; ; ) {
|
||||
int tagByte = tag[tagIndex] & 0xff;
|
||||
int curByte = tags[curIndex] & 0xff;
|
||||
compare = tagByte - curByte;
|
||||
if (compare != 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
tagIndex++;
|
||||
curIndex++;
|
||||
if (tagIndex == tag.length && curIndex == start + middle) {
|
||||
break;
|
||||
}
|
||||
if (tagIndex == tag.length) {
|
||||
compare = -1;
|
||||
break;
|
||||
}
|
||||
if (curIndex == start + middle) {
|
||||
compare = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (compare < 0) {
|
||||
high = start - 1;
|
||||
} else if (compare > 0) {
|
||||
low = start + end + 1;
|
||||
} else {
|
||||
return new String(tags, start + middle + 1, end - middle - 1, StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ArrayList<Pair<String, String>> suggest(String keyword) {
|
||||
return searchTag(tags, keyword);
|
||||
}
|
||||
|
||||
private ArrayList<Pair<String, String>> searchTag(byte[] tags, String keyword) {
|
||||
ArrayList<Pair<String, String>> searchHints = new ArrayList<>();
|
||||
int begin = 0;
|
||||
while (begin < tags.length - 1) {
|
||||
int start = begin;
|
||||
// Look for the starting '\n'
|
||||
while (tags[start] != '\n') {
|
||||
start++;
|
||||
}
|
||||
|
||||
// Look for the middle '\r'.
|
||||
int middle = 1;
|
||||
while (tags[start + middle] != '\r') {
|
||||
middle++;
|
||||
}
|
||||
|
||||
// Look for the ending '\n'
|
||||
int end = middle + 1;
|
||||
while (tags[start + end] != '\n') {
|
||||
end++;
|
||||
}
|
||||
|
||||
begin = start + end;
|
||||
|
||||
byte[] hintBytes = new byte[end - middle - 1];
|
||||
System.arraycopy(tags, start + middle + 1, hintBytes, 0, end - middle - 1);
|
||||
String hint = new String(hintBytes, StandardCharsets.UTF_8);
|
||||
byte[] tagBytes = new byte[middle];
|
||||
System.arraycopy(tags, start + 1, tagBytes, 0, middle);
|
||||
String tag = new String(tagBytes, StandardCharsets.UTF_8);
|
||||
int index = tag.indexOf(':');
|
||||
boolean keywordMatches;
|
||||
if (index == -1 || index >= tag.length() - 1 || keyword.length() > 2) {
|
||||
keywordMatches = containsIgnoreSpace(tag, keyword);
|
||||
} else {
|
||||
keywordMatches = containsIgnoreSpace(tag.substring(index + 1), keyword);
|
||||
}
|
||||
|
||||
if (keywordMatches || containsIgnoreSpace(hint, keyword)) {
|
||||
Pair<String, String> pair = new Pair<>(hint, tag);
|
||||
if (!searchHints.contains(pair)) {
|
||||
searchHints.add(pair);
|
||||
}
|
||||
}
|
||||
if (searchHints.size() > 20) {
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return searchHints;
|
||||
}
|
||||
|
||||
private boolean containsIgnoreSpace(String text, String key) {
|
||||
return text.replace(" ", "").contains(key.replace(" ", ""));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,269 @@
|
||||
/*
|
||||
* Copyright 2019 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.hippo.ehviewer.client
|
||||
|
||||
import android.content.Context
|
||||
import com.hippo.ehviewer.AppConfig
|
||||
import com.hippo.ehviewer.EhApplication
|
||||
import com.hippo.ehviewer.EhApplication.Companion.okHttpClient
|
||||
import com.hippo.ehviewer.R
|
||||
import com.hippo.util.ExceptionUtils
|
||||
import com.hippo.util.HashCodeUtils
|
||||
import com.hippo.yorozuya.FileUtils
|
||||
import com.hippo.yorozuya.IOUtils
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okio.BufferedSource
|
||||
import okio.buffer
|
||||
import okio.source
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileOutputStream
|
||||
import java.io.IOException
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.security.MessageDigest
|
||||
import java.security.NoSuchAlgorithmException
|
||||
|
||||
object EhTagDatabase {
|
||||
private lateinit var tags: JSONObject
|
||||
private lateinit var tagList: ArrayList<Pair<String, String>>
|
||||
|
||||
fun isInitialized(): Boolean {
|
||||
return this::tags.isInitialized && this::tagList.isInitialized
|
||||
}
|
||||
|
||||
private fun updateData(source: BufferedSource) {
|
||||
try {
|
||||
val tmpTags = JSONObject(source.readString(StandardCharsets.UTF_8))
|
||||
val tmpTagList = arrayListOf<Pair<String, String>>()
|
||||
tmpTags.keys().forEachRemaining { prefix: String ->
|
||||
val values = tmpTags.optJSONObject(prefix)
|
||||
values?.let {
|
||||
it.keys().forEachRemaining { tag: String ->
|
||||
tmpTagList.add(Pair("$prefix:$tag", values.optString(tag)))
|
||||
}
|
||||
}
|
||||
}
|
||||
tags = tmpTags
|
||||
tagList = tmpTagList
|
||||
} catch (e: JSONException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
fun getTranslation(prefix: String?, tag: String?): String? {
|
||||
return tags.optJSONObject(prefix)?.optString(tag)?.trim()?.takeIf { it.isNotEmpty() }
|
||||
}
|
||||
|
||||
/* Construct a cold flow for tag database suggestions */
|
||||
fun suggestFlow(
|
||||
keyword: String,
|
||||
translate: Boolean,
|
||||
exactly: Boolean = false
|
||||
): Flow<Pair<String?, String>> = flow {
|
||||
tagList.forEach {
|
||||
val tag = it.first
|
||||
val hint = if (translate) it.second else null
|
||||
val index = tag.indexOf(':')
|
||||
if (tag.substring(index + 1).trim() == keyword) {
|
||||
if (exactly)
|
||||
emit(Pair(hint, tag))
|
||||
return@forEach
|
||||
}
|
||||
if (exactly)
|
||||
return@forEach
|
||||
val keywordMatches: Boolean =
|
||||
if (index == -1 || index >= tag.length - 1 || keyword.length > 2) {
|
||||
containsIgnoreSpace(tag, keyword)
|
||||
} else {
|
||||
containsIgnoreSpace(tag.substring(index + 1), keyword)
|
||||
}
|
||||
if (keywordMatches || containsIgnoreSpace(hint, keyword)) {
|
||||
emit(Pair(hint, tag))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun containsIgnoreSpace(text: String?, key: String): Boolean {
|
||||
return text != null && text.replace(" ", "").contains(key.replace(" ", ""))
|
||||
}
|
||||
|
||||
private val NAMESPACE_TO_PREFIX = HashMap<String, String>().also {
|
||||
it["artist"] = "a"
|
||||
it["cosplayer"] = "cos"
|
||||
it["character"] = "c"
|
||||
it["female"] = "f"
|
||||
it["group"] = "g"
|
||||
it["language"] = "l"
|
||||
it["male"] = "m"
|
||||
it["mixed"] = "x"
|
||||
it["other"] = "o"
|
||||
it["parody"] = "p"
|
||||
it["reclass"] = "r"
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun namespaceToPrefix(namespace: String): String? {
|
||||
return NAMESPACE_TO_PREFIX[namespace]
|
||||
}
|
||||
|
||||
private fun getMetadata(context: Context): Array<String>? {
|
||||
return context.resources.getStringArray(R.array.tag_translation_metadata)
|
||||
.takeIf { it.size == 4 }
|
||||
}
|
||||
|
||||
fun isTranslatable(context: Context): Boolean {
|
||||
return context.resources.getBoolean(R.bool.tag_translatable)
|
||||
}
|
||||
|
||||
private fun getFileContent(file: File): String? {
|
||||
try {
|
||||
file.source().buffer().use { return it.readString(StandardCharsets.UTF_8) }
|
||||
} catch (e: IOException) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
private fun getFileSha1(file: File): String? {
|
||||
try {
|
||||
FileInputStream(file).use { stream ->
|
||||
val digest = MessageDigest.getInstance("SHA-1")
|
||||
var n: Int
|
||||
val buffer = ByteArray(4 * 1024)
|
||||
while (stream.read(buffer).also { n = it } != -1) {
|
||||
digest.update(buffer, 0, n)
|
||||
}
|
||||
return HashCodeUtils.bytesToHexString(digest.digest())
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
return null
|
||||
} catch (e: NoSuchAlgorithmException) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkData(sha1File: File, dataFile: File): Boolean {
|
||||
val s1 = getFileContent(sha1File) ?: return false
|
||||
val s2 = getFileSha1(dataFile) ?: return false
|
||||
return s1 == s2
|
||||
}
|
||||
|
||||
private fun save(client: OkHttpClient, url: String, file: File): Boolean {
|
||||
val request: Request = Request.Builder().url(url).build()
|
||||
val call = client.newCall(request)
|
||||
try {
|
||||
call.execute().use { response ->
|
||||
if (!response.isSuccessful) {
|
||||
return false
|
||||
}
|
||||
val body = response.body
|
||||
body.byteStream()
|
||||
.use { ins -> FileOutputStream(file).use { os -> IOUtils.copy(ins, os) } }
|
||||
return true
|
||||
}
|
||||
} catch (t: Throwable) {
|
||||
FileUtils.delete(file)
|
||||
t.printStackTrace()
|
||||
ExceptionUtils.throwIfFatal(t)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
@JvmStatic
|
||||
fun update() {
|
||||
launchIO {
|
||||
updateInternal()
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
private fun updateInternal() {
|
||||
val urls = getMetadata(EhApplication.application)
|
||||
urls?.let {
|
||||
val sha1Name = urls[0]
|
||||
val sha1Url = urls[1]
|
||||
val dataName = urls[2]
|
||||
val dataUrl = urls[3]
|
||||
|
||||
try {
|
||||
val dir = AppConfig.getFilesDir("tag-translations")
|
||||
checkNotNull(dir)
|
||||
|
||||
// Check current sha1 and current data
|
||||
val sha1File = File(dir, sha1Name)
|
||||
val dataFile = File(dir, dataName)
|
||||
if (!checkData(sha1File, dataFile)) {
|
||||
FileUtils.delete(sha1File)
|
||||
FileUtils.delete(dataFile)
|
||||
}
|
||||
|
||||
// Read current EhTagDatabase
|
||||
if (!isInitialized() && dataFile.exists()) {
|
||||
try {
|
||||
dataFile.source().buffer().use { updateData(it) }
|
||||
} catch (e: IOException) {
|
||||
FileUtils.delete(sha1File)
|
||||
FileUtils.delete(dataFile)
|
||||
}
|
||||
}
|
||||
val client = okHttpClient
|
||||
|
||||
// Save new sha1
|
||||
val tempSha1File = File(dir, "$sha1Name.tmp")
|
||||
check(save(client, sha1Url, tempSha1File))
|
||||
|
||||
// Check new sha1 and current data
|
||||
if (checkData(tempSha1File, dataFile)) {
|
||||
// The data is the same
|
||||
FileUtils.delete(tempSha1File)
|
||||
return
|
||||
}
|
||||
|
||||
// Save new data
|
||||
val tempDataFile = File(dir, "$dataName.tmp")
|
||||
check(save(client, dataUrl, tempDataFile))
|
||||
|
||||
// Check new sha1 and new data
|
||||
if (!checkData(tempSha1File, tempDataFile)) {
|
||||
FileUtils.delete(tempSha1File)
|
||||
FileUtils.delete(tempDataFile)
|
||||
return
|
||||
}
|
||||
|
||||
// Replace current sha1 and current data with new sha1 and new data
|
||||
FileUtils.delete(sha1File)
|
||||
FileUtils.delete(dataFile)
|
||||
tempSha1File.renameTo(sha1File)
|
||||
tempDataFile.renameTo(dataFile)
|
||||
|
||||
// Read new EhTagDatabase
|
||||
try {
|
||||
dataFile.source().buffer().use { updateData(it) }
|
||||
} catch (_: IOException) {
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package com.hippo.ehviewer.client;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.text.TextUtils;
|
||||
|
||||
@@ -49,10 +48,10 @@ public class EhUtils {
|
||||
|
||||
// Remove [XXX], (XXX), {XXX}, ~XXX~ stuff
|
||||
public static final Pattern PATTERN_TITLE_PREFIX = Pattern.compile(
|
||||
"^(?:(?:\\([^\\)]*\\))|(?:\\[[^\\]]*\\])|(?:\\{[^\\}]*\\})|(?:~[^~]*~)|\\s+)*");
|
||||
"^(?:\\([^)]*\\)|\\[[^]]*]|\\{[^}]*\\}|~[^~]*~|\\s+)*");
|
||||
// Remove [XXX], (XXX), {XXX}, ~XXX~ stuff and something like ch. 1-23
|
||||
public static final Pattern PATTERN_TITLE_SUFFIX = Pattern.compile(
|
||||
"(?:\\s+ch.[\\s\\d-]+)?(?:(?:\\([^\\)]*\\))|(?:\\[[^\\]]*\\])|(?:\\{[^\\}]*\\})|(?:~[^~]*~)|\\s+)*$",
|
||||
"(?:\\s+ch.[\\s\\d-]+)?(?:\\([^)]*\\)|\\[[^]]*]|\\{[^}]*\\}|~[^~]*~|\\s+)*$",
|
||||
Pattern.CASE_INSENSITIVE);
|
||||
|
||||
private static final int[] CATEGORY_VALUES = {
|
||||
@@ -106,40 +105,29 @@ public class EhUtils {
|
||||
}
|
||||
|
||||
public static int getCategoryColor(int category) {
|
||||
switch (category) {
|
||||
case EhConfig.DOUJINSHI:
|
||||
return BG_COLOR_DOUJINSHI;
|
||||
case EhConfig.MANGA:
|
||||
return BG_COLOR_MANGA;
|
||||
case EhConfig.ARTIST_CG:
|
||||
return BG_COLOR_ARTIST_CG;
|
||||
case EhConfig.GAME_CG:
|
||||
return BG_COLOR_GAME_CG;
|
||||
case EhConfig.WESTERN:
|
||||
return BG_COLOR_WESTERN;
|
||||
case EhConfig.NON_H:
|
||||
return BG_COLOR_NON_H;
|
||||
case EhConfig.IMAGE_SET:
|
||||
return BG_COLOR_IMAGE_SET;
|
||||
case EhConfig.COSPLAY:
|
||||
return BG_COLOR_COSPLAY;
|
||||
case EhConfig.ASIAN_PORN:
|
||||
return BG_COLOR_ASIAN_PORN;
|
||||
case EhConfig.MISC:
|
||||
return BG_COLOR_MISC;
|
||||
default:
|
||||
return BG_COLOR_UNKNOWN;
|
||||
}
|
||||
return switch (category) {
|
||||
case EhConfig.DOUJINSHI -> BG_COLOR_DOUJINSHI;
|
||||
case EhConfig.MANGA -> BG_COLOR_MANGA;
|
||||
case EhConfig.ARTIST_CG -> BG_COLOR_ARTIST_CG;
|
||||
case EhConfig.GAME_CG -> BG_COLOR_GAME_CG;
|
||||
case EhConfig.WESTERN -> BG_COLOR_WESTERN;
|
||||
case EhConfig.NON_H -> BG_COLOR_NON_H;
|
||||
case EhConfig.IMAGE_SET -> BG_COLOR_IMAGE_SET;
|
||||
case EhConfig.COSPLAY -> BG_COLOR_COSPLAY;
|
||||
case EhConfig.ASIAN_PORN -> BG_COLOR_ASIAN_PORN;
|
||||
case EhConfig.MISC -> BG_COLOR_MISC;
|
||||
default -> BG_COLOR_UNKNOWN;
|
||||
};
|
||||
}
|
||||
|
||||
public static void signOut(Context context) {
|
||||
public static void signOut() {
|
||||
EhApplication.getEhCookieStore().signOut();
|
||||
Settings.putAvatar(null);
|
||||
Settings.putDisplayName(null);
|
||||
Settings.putNeedSignIn(true);
|
||||
}
|
||||
|
||||
public static boolean needSignedIn(Context context) {
|
||||
public static boolean needSignedIn() {
|
||||
return Settings.getNeedSignIn() && !EhApplication.getEhCookieStore().hasSignedIn();
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ import java.security.cert.X509Certificate
|
||||
import javax.net.ssl.X509TrustManager
|
||||
|
||||
@SuppressLint("CustomX509TrustManager")
|
||||
class EhX509TrustManager : X509TrustManager {
|
||||
object EhX509TrustManager : X509TrustManager {
|
||||
@SuppressLint("TrustAllX509TrustManager")
|
||||
override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String) {
|
||||
}
|
||||
|
||||
@@ -1,150 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.ehviewer.client.data;
|
||||
|
||||
import android.os.Build;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.hippo.ehviewer.client.EhUrl;
|
||||
import com.hippo.network.UrlBuilder;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class FavListUrlBuilder implements Parcelable {
|
||||
|
||||
public static final int FAV_CAT_ALL = -1;
|
||||
public static final int FAV_CAT_LOCAL = -2;
|
||||
public static final Parcelable.Creator<FavListUrlBuilder> CREATOR = new Parcelable.Creator<FavListUrlBuilder>() {
|
||||
|
||||
@Override
|
||||
public FavListUrlBuilder createFromParcel(Parcel source) {
|
||||
return new FavListUrlBuilder(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FavListUrlBuilder[] newArray(int size) {
|
||||
return new FavListUrlBuilder[size];
|
||||
}
|
||||
};
|
||||
private static final String TAG = FavListUrlBuilder.class.getSimpleName();
|
||||
private String mPrev;
|
||||
private String mNext;
|
||||
private String mJumpTo;
|
||||
private String mKeyword;
|
||||
private int mFavCat = FAV_CAT_ALL;
|
||||
|
||||
public FavListUrlBuilder() {
|
||||
}
|
||||
|
||||
protected FavListUrlBuilder(Parcel in) {
|
||||
this.mPrev = in.readString();
|
||||
this.mNext = in.readString();
|
||||
this.mJumpTo = in.readString();
|
||||
this.mKeyword = in.readString();
|
||||
this.mFavCat = in.readInt();
|
||||
}
|
||||
|
||||
public static boolean isValidFavCat(int favCat) {
|
||||
return favCat >= 0 && favCat <= 9;
|
||||
}
|
||||
|
||||
public void setPrev(String prev) {
|
||||
mPrev = prev;
|
||||
}
|
||||
|
||||
public void setNext(String next) {
|
||||
mNext = next;
|
||||
}
|
||||
|
||||
public void setJumpTo(String jumpTo) {
|
||||
mJumpTo = jumpTo;
|
||||
}
|
||||
|
||||
public String getKeyword() {
|
||||
return mKeyword;
|
||||
}
|
||||
|
||||
public void setKeyword(String keyword) {
|
||||
mKeyword = keyword;
|
||||
}
|
||||
|
||||
public int getFavCat() {
|
||||
return mFavCat;
|
||||
}
|
||||
|
||||
public void setFavCat(int favCat) {
|
||||
mFavCat = favCat;
|
||||
}
|
||||
|
||||
public boolean isLocalFavCat() {
|
||||
return mFavCat == FAV_CAT_LOCAL;
|
||||
}
|
||||
|
||||
public String build() {
|
||||
UrlBuilder ub = new UrlBuilder(EhUrl.getFavoritesUrl());
|
||||
if (isValidFavCat(mFavCat)) {
|
||||
ub.addQuery("favcat", Integer.toString(mFavCat));
|
||||
} else if (mFavCat == FAV_CAT_ALL) {
|
||||
ub.addQuery("favcat", "all");
|
||||
}
|
||||
if (!TextUtils.isEmpty(mKeyword)) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
ub.addQuery("f_search", URLEncoder.encode(mKeyword, StandardCharsets.UTF_8));
|
||||
} else {
|
||||
try {
|
||||
ub.addQuery("f_search", URLEncoder.encode(mKeyword, StandardCharsets.UTF_8.displayName()));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
// Name
|
||||
ub.addQuery("sn", "on");
|
||||
// Tags
|
||||
ub.addQuery("st", "on");
|
||||
// Note
|
||||
ub.addQuery("sf", "on");
|
||||
}
|
||||
if (mPrev != null && !mPrev.isEmpty()) {
|
||||
ub.addQuery("prev", mPrev);
|
||||
}
|
||||
if (mNext != null && !mNext.isEmpty()) {
|
||||
ub.addQuery("next", mNext);
|
||||
}
|
||||
if (mJumpTo != null && !mJumpTo.isEmpty()) {
|
||||
ub.addQuery("seek", mJumpTo);
|
||||
}
|
||||
return ub.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(this.mPrev);
|
||||
dest.writeString(this.mNext);
|
||||
dest.writeString(this.mJumpTo);
|
||||
dest.writeString(this.mKeyword);
|
||||
dest.writeInt(this.mFavCat);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.hippo.ehviewer.client.data
|
||||
|
||||
import android.os.Parcelable
|
||||
import com.hippo.ehviewer.client.EhUrl
|
||||
import com.hippo.network.UrlBuilder
|
||||
import com.hippo.util.encodeUTF8
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
class FavListUrlBuilder(
|
||||
private var mPrev: String? = null,
|
||||
private var mNext: String? = null,
|
||||
var jumpTo: String? = null,
|
||||
var keyword: String? = null,
|
||||
var favCat: Int = FAV_CAT_ALL,
|
||||
) : Parcelable {
|
||||
fun setIndex(index: String?, isNext: Boolean) {
|
||||
mNext = index.takeIf { isNext }
|
||||
mPrev = index.takeUnless { isNext }
|
||||
}
|
||||
|
||||
fun build(): String {
|
||||
val ub = UrlBuilder(EhUrl.getFavoritesUrl())
|
||||
if (isValidFavCat(favCat)) {
|
||||
ub.addQuery("favcat", favCat.toString())
|
||||
} else if (favCat == FAV_CAT_ALL) {
|
||||
ub.addQuery("favcat", "all")
|
||||
}
|
||||
keyword?.takeIf { it.isNotBlank() }?.let { ub.addQuery("f_search", encodeUTF8(it)) }
|
||||
mPrev?.takeIf { it.isNotEmpty() }?.let { ub.addQuery("prev", it) }
|
||||
mNext?.takeIf { it.isNotEmpty() }?.let { ub.addQuery("next", it) }
|
||||
jumpTo?.takeIf { it.isNotEmpty() }?.let { ub.addQuery("seek", it) }
|
||||
return ub.build()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val FAV_CAT_ALL = -1
|
||||
const val FAV_CAT_LOCAL = -2
|
||||
fun isValidFavCat(favCat: Int): Boolean {
|
||||
return favCat in 0..9
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.ehviewer.client.data;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public class GalleryApiInfo implements Parcelable {
|
||||
|
||||
public static final Parcelable.Creator<GalleryApiInfo> CREATOR = new Parcelable.Creator<GalleryApiInfo>() {
|
||||
@Override
|
||||
public GalleryApiInfo createFromParcel(Parcel source) {
|
||||
return new GalleryApiInfo(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GalleryApiInfo[] newArray(int size) {
|
||||
return new GalleryApiInfo[size];
|
||||
}
|
||||
};
|
||||
public long gid;
|
||||
public String token;
|
||||
public String archiverKey;
|
||||
public String title;
|
||||
public String titleJpn;
|
||||
public int category;
|
||||
public String thumb;
|
||||
public String uploader;
|
||||
public long posted;
|
||||
public int filecount;
|
||||
public long filesize;
|
||||
public boolean expunged;
|
||||
public float rating;
|
||||
public int torrentcount;
|
||||
@Nullable
|
||||
public String[] tags;
|
||||
|
||||
public GalleryApiInfo() {
|
||||
}
|
||||
|
||||
protected GalleryApiInfo(Parcel in) {
|
||||
this.gid = in.readLong();
|
||||
this.token = in.readString();
|
||||
this.archiverKey = in.readString();
|
||||
this.title = in.readString();
|
||||
this.titleJpn = in.readString();
|
||||
this.category = in.readInt();
|
||||
this.thumb = in.readString();
|
||||
this.uploader = in.readString();
|
||||
this.posted = in.readLong();
|
||||
this.filecount = in.readInt();
|
||||
this.filesize = in.readLong();
|
||||
this.expunged = in.readByte() != 0;
|
||||
this.rating = in.readFloat();
|
||||
this.torrentcount = in.readInt();
|
||||
this.tags = in.createStringArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeLong(this.gid);
|
||||
dest.writeString(this.token);
|
||||
dest.writeString(this.archiverKey);
|
||||
dest.writeString(this.title);
|
||||
dest.writeString(this.titleJpn);
|
||||
dest.writeInt(this.category);
|
||||
dest.writeString(this.thumb);
|
||||
dest.writeString(this.uploader);
|
||||
dest.writeLong(this.posted);
|
||||
dest.writeInt(this.filecount);
|
||||
dest.writeLong(this.filesize);
|
||||
dest.writeByte(expunged ? (byte) 1 : (byte) 0);
|
||||
dest.writeFloat(this.rating);
|
||||
dest.writeInt(this.torrentcount);
|
||||
dest.writeStringArray(this.tags);
|
||||
}
|
||||
}
|
||||
+21
-19
@@ -13,24 +13,26 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.hippo.ehviewer.client.data
|
||||
|
||||
package com.hippo.ehviewer.ui.fragment;
|
||||
import android.os.Parcelable
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.hippo.ehviewer.R;
|
||||
|
||||
public class ReadFragment extends BasePreferenceFragment {
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) {
|
||||
addPreferencesFromResource(R.xml.read_settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFragmentTitle() {
|
||||
return R.string.settings_read;
|
||||
}
|
||||
}
|
||||
@Parcelize
|
||||
class GalleryApiInfo(
|
||||
var gid: Long = 0,
|
||||
var token: String? = null,
|
||||
var archiverKey: String? = null,
|
||||
var title: String? = null,
|
||||
var titleJpn: String? = null,
|
||||
var category: Int = 0,
|
||||
var thumb: String? = null,
|
||||
var uploader: String? = null,
|
||||
var posted: Long = 0,
|
||||
var filecount: Int = 0,
|
||||
var filesize: Long = 0,
|
||||
var expunged: Boolean = false,
|
||||
var rating: Float = 0f,
|
||||
var torrentcount: Int = 0,
|
||||
var tags: Array<String>?
|
||||
) : Parcelable
|
||||
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.ehviewer.client.data;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
public class GalleryComment implements Parcelable {
|
||||
|
||||
public static final Creator<GalleryComment> CREATOR = new Creator<GalleryComment>() {
|
||||
@Override
|
||||
public GalleryComment createFromParcel(Parcel source) {
|
||||
return new GalleryComment(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GalleryComment[] newArray(int size) {
|
||||
return new GalleryComment[size];
|
||||
}
|
||||
};
|
||||
// 0 for uploader comment. can't vote
|
||||
public long id;
|
||||
public int score;
|
||||
public boolean editable;
|
||||
public boolean voteUpAble;
|
||||
public boolean voteUpEd;
|
||||
public boolean voteDownAble;
|
||||
public boolean voteDownEd;
|
||||
public boolean uploader;
|
||||
public String voteState;
|
||||
public long time;
|
||||
public String user;
|
||||
public String comment;
|
||||
public long lastEdited;
|
||||
|
||||
public GalleryComment() {
|
||||
}
|
||||
|
||||
protected GalleryComment(Parcel in) {
|
||||
this.id = in.readLong();
|
||||
this.score = in.readInt();
|
||||
this.editable = in.readByte() != 0;
|
||||
this.voteUpAble = in.readByte() != 0;
|
||||
this.voteUpEd = in.readByte() != 0;
|
||||
this.voteDownAble = in.readByte() != 0;
|
||||
this.voteDownEd = in.readByte() != 0;
|
||||
this.uploader = in.readByte() != 0;
|
||||
this.voteState = in.readString();
|
||||
this.time = in.readLong();
|
||||
this.user = in.readString();
|
||||
this.comment = in.readString();
|
||||
this.lastEdited = in.readLong();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeLong(this.id);
|
||||
dest.writeInt(this.score);
|
||||
dest.writeByte(editable ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(voteUpAble ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(voteUpEd ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(voteDownAble ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(voteDownEd ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(uploader ? (byte) 1 : (byte) 0);
|
||||
dest.writeString(this.voteState);
|
||||
dest.writeLong(this.time);
|
||||
dest.writeString(this.user);
|
||||
dest.writeString(this.comment);
|
||||
dest.writeLong(this.lastEdited);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.hippo.ehviewer.client.data
|
||||
|
||||
import android.os.Parcelable
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
class GalleryComment(
|
||||
// 0 for uploader comment. can't vote
|
||||
@JvmField
|
||||
var id: Long = 0,
|
||||
@JvmField
|
||||
var score: Int = 0,
|
||||
@JvmField
|
||||
var editable: Boolean = false,
|
||||
@JvmField
|
||||
var voteUpAble: Boolean = false,
|
||||
@JvmField
|
||||
var voteUpEd: Boolean = false,
|
||||
@JvmField
|
||||
var voteDownAble: Boolean = false,
|
||||
@JvmField
|
||||
var voteDownEd: Boolean = false,
|
||||
@JvmField
|
||||
var uploader: Boolean = false,
|
||||
@JvmField
|
||||
var voteState: String? = null,
|
||||
@JvmField
|
||||
var time: Long = 0,
|
||||
@JvmField
|
||||
var user: String? = null,
|
||||
@JvmField
|
||||
var comment: String? = null,
|
||||
@JvmField
|
||||
var lastEdited: Long = 0
|
||||
) : Parcelable
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.ehviewer.client.data;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class GalleryCommentList implements Parcelable {
|
||||
|
||||
public static final Creator<GalleryCommentList> CREATOR = new Creator<GalleryCommentList>() {
|
||||
@Override
|
||||
public GalleryCommentList createFromParcel(Parcel in) {
|
||||
return new GalleryCommentList(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GalleryCommentList[] newArray(int size) {
|
||||
return new GalleryCommentList[size];
|
||||
}
|
||||
};
|
||||
public GalleryComment[] comments;
|
||||
public boolean hasMore;
|
||||
|
||||
public GalleryCommentList(GalleryComment[] comments, boolean hasMore) {
|
||||
this.comments = comments;
|
||||
this.hasMore = hasMore;
|
||||
}
|
||||
|
||||
protected GalleryCommentList(Parcel in) {
|
||||
Parcelable[] array = in.readParcelableArray(getClass().getClassLoader());
|
||||
if (array != null) {
|
||||
comments = Arrays.copyOf(array, array.length, GalleryComment[].class);
|
||||
} else {
|
||||
comments = null;
|
||||
}
|
||||
hasMore = in.readByte() != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeParcelableArray(comments, flags);
|
||||
dest.writeByte(hasMore ? (byte) 1 : (byte) 0);
|
||||
}
|
||||
}
|
||||
+11
-12
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
* Copyright 2019 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -13,16 +13,15 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.hippo.ehviewer.client.data
|
||||
|
||||
package com.hippo.ehviewer.client.exception;
|
||||
import android.os.Parcelable
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
public class EhException extends Exception {
|
||||
|
||||
public EhException(String detailMessage) {
|
||||
super(detailMessage);
|
||||
}
|
||||
|
||||
public EhException(String detailMessage, Throwable cause) {
|
||||
super(detailMessage, cause);
|
||||
}
|
||||
}
|
||||
@Parcelize
|
||||
class GalleryCommentList(
|
||||
@JvmField
|
||||
var comments: Array<GalleryComment>?,
|
||||
@JvmField
|
||||
var hasMore: Boolean
|
||||
) : Parcelable
|
||||
@@ -1,111 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.ehviewer.client.data;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class GalleryDetail extends GalleryInfo {
|
||||
|
||||
public static final Creator<GalleryDetail> CREATOR = new Creator<GalleryDetail>() {
|
||||
@Override
|
||||
public GalleryDetail createFromParcel(Parcel source) {
|
||||
return new GalleryDetail(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GalleryDetail[] newArray(int size) {
|
||||
return new GalleryDetail[size];
|
||||
}
|
||||
};
|
||||
public long apiUid = -1L;
|
||||
public String apiKey;
|
||||
public int torrentCount;
|
||||
public String torrentUrl;
|
||||
public String archiveUrl;
|
||||
public String parent;
|
||||
public ArrayList<GalleryInfo> newerVersions = new ArrayList<>();
|
||||
public String visible;
|
||||
public String language;
|
||||
public String size;
|
||||
public int pages;
|
||||
public int favoriteCount;
|
||||
public boolean isFavorited;
|
||||
public int ratingCount;
|
||||
public GalleryTagGroup[] tags;
|
||||
public GalleryCommentList comments;
|
||||
public int previewPages;
|
||||
public PreviewSet previewSet;
|
||||
|
||||
public GalleryDetail() {
|
||||
}
|
||||
|
||||
protected GalleryDetail(Parcel in) {
|
||||
super(in);
|
||||
this.torrentCount = in.readInt();
|
||||
this.torrentUrl = in.readString();
|
||||
this.archiveUrl = in.readString();
|
||||
this.parent = in.readString();
|
||||
//noinspection unchecked
|
||||
this.newerVersions = in.readArrayList(GalleryInfo.class.getClassLoader());
|
||||
this.visible = in.readString();
|
||||
this.language = in.readString();
|
||||
this.size = in.readString();
|
||||
this.pages = in.readInt();
|
||||
this.favoriteCount = in.readInt();
|
||||
this.isFavorited = in.readByte() != 0;
|
||||
this.ratingCount = in.readInt();
|
||||
Parcelable[] array = in.readParcelableArray(GalleryTagGroup.class.getClassLoader());
|
||||
if (array != null) {
|
||||
this.tags = Arrays.copyOf(array, array.length, GalleryTagGroup[].class);
|
||||
} else {
|
||||
this.tags = null;
|
||||
}
|
||||
this.comments = in.readParcelable(getClass().getClassLoader());
|
||||
this.previewPages = in.readInt();
|
||||
this.previewSet = in.readParcelable(PreviewSet.class.getClassLoader());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeInt(this.torrentCount);
|
||||
dest.writeString(this.torrentUrl);
|
||||
dest.writeString(this.archiveUrl);
|
||||
dest.writeString(this.parent);
|
||||
dest.writeList(this.newerVersions);
|
||||
dest.writeString(this.visible);
|
||||
dest.writeString(this.language);
|
||||
dest.writeString(this.size);
|
||||
dest.writeInt(this.pages);
|
||||
dest.writeInt(this.favoriteCount);
|
||||
dest.writeByte(isFavorited ? (byte) 1 : (byte) 0);
|
||||
dest.writeInt(this.ratingCount);
|
||||
dest.writeParcelableArray(this.tags, flags);
|
||||
dest.writeParcelable(this.comments, flags);
|
||||
dest.writeInt(this.previewPages);
|
||||
dest.writeParcelable(previewSet, flags);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.hippo.ehviewer.client.data
|
||||
|
||||
// This is wrong Parcelize usage, TODO: use delegate and move galleryinfo to primary constructor
|
||||
class GalleryDetail(
|
||||
@JvmField
|
||||
var apiUid: Long = -1L,
|
||||
|
||||
@JvmField
|
||||
var apiKey: String? = null,
|
||||
|
||||
@JvmField
|
||||
var torrentCount: Int = 0,
|
||||
|
||||
@JvmField
|
||||
var torrentUrl: String? = null,
|
||||
|
||||
@JvmField
|
||||
var archiveUrl: String? = null,
|
||||
|
||||
@JvmField
|
||||
var parent: String? = null,
|
||||
|
||||
@JvmField
|
||||
var newerVersions: ArrayList<GalleryInfo> = ArrayList(),
|
||||
|
||||
@JvmField
|
||||
var visible: String? = null,
|
||||
|
||||
@JvmField
|
||||
var language: String? = null,
|
||||
|
||||
@JvmField
|
||||
var size: String? = null,
|
||||
|
||||
@JvmField
|
||||
var favoriteCount: Int = 0,
|
||||
|
||||
@JvmField
|
||||
var isFavorited: Boolean = false,
|
||||
|
||||
@JvmField
|
||||
var ratingCount: Int = 0,
|
||||
|
||||
@JvmField
|
||||
var tags: Array<GalleryTagGroup>? = null,
|
||||
|
||||
@JvmField
|
||||
var comments: GalleryCommentList? = null,
|
||||
|
||||
@JvmField
|
||||
var previewPages: Int = 0,
|
||||
|
||||
@JvmField
|
||||
var previewSet: PreviewSet? = null,
|
||||
) : GalleryInfo()
|
||||
@@ -1,247 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.ehviewer.client.data;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.room.ColumnInfo;
|
||||
import androidx.room.Ignore;
|
||||
import androidx.room.PrimaryKey;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class GalleryInfo implements Parcelable {
|
||||
|
||||
/**
|
||||
* ISO 639-1
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static final String S_LANG_JA = "JA";
|
||||
public static final String S_LANG_EN = "EN";
|
||||
public static final String S_LANG_ZH = "ZH";
|
||||
public static final String S_LANG_NL = "NL";
|
||||
public static final String S_LANG_FR = "FR";
|
||||
public static final String S_LANG_DE = "DE";
|
||||
public static final String S_LANG_HU = "HU";
|
||||
public static final String S_LANG_IT = "IT";
|
||||
public static final String S_LANG_KO = "KO";
|
||||
public static final String S_LANG_PL = "PL";
|
||||
public static final String S_LANG_PT = "PT";
|
||||
public static final String S_LANG_RU = "RU";
|
||||
public static final String S_LANG_ES = "ES";
|
||||
public static final String S_LANG_TH = "TH";
|
||||
public static final String S_LANG_VI = "VI";
|
||||
|
||||
public static final String[] S_LANGS = {
|
||||
S_LANG_EN,
|
||||
S_LANG_ZH,
|
||||
S_LANG_ES,
|
||||
S_LANG_KO,
|
||||
S_LANG_RU,
|
||||
S_LANG_FR,
|
||||
S_LANG_PT,
|
||||
S_LANG_TH,
|
||||
S_LANG_DE,
|
||||
S_LANG_IT,
|
||||
S_LANG_VI,
|
||||
S_LANG_PL,
|
||||
S_LANG_HU,
|
||||
S_LANG_NL,
|
||||
};
|
||||
|
||||
public static final Pattern[] S_LANG_PATTERNS = {
|
||||
Pattern.compile("[(\\[]eng(?:lish)?[)\\]]|英訳", Pattern.CASE_INSENSITIVE),
|
||||
// [((\[]ch(?:inese)?[))\]]|[汉漢]化|中[国國][语語]|中文|中国翻訳
|
||||
Pattern.compile("[(\uFF08\\[]ch(?:inese)?[)\uFF09\\]]|[汉漢]化|中[国國][语語]|中文|中国翻訳", Pattern.CASE_INSENSITIVE),
|
||||
Pattern.compile("[(\\[]spanish[)\\]]|[(\\[]Español[)\\]]|スペイン翻訳", Pattern.CASE_INSENSITIVE),
|
||||
Pattern.compile("[(\\[]korean?[)\\]]|韓国翻訳", Pattern.CASE_INSENSITIVE),
|
||||
Pattern.compile("[(\\[]rus(?:sian)?[)\\]]|ロシア翻訳", Pattern.CASE_INSENSITIVE),
|
||||
Pattern.compile("[(\\[]fr(?:ench)?[)\\]]|フランス翻訳", Pattern.CASE_INSENSITIVE),
|
||||
Pattern.compile("[(\\[]portuguese|ポルトガル翻訳", Pattern.CASE_INSENSITIVE),
|
||||
Pattern.compile("[(\\[]thai(?: ภาษาไทย)?[)\\]]|แปลไทย|タイ翻訳", Pattern.CASE_INSENSITIVE),
|
||||
Pattern.compile("[(\\[]german[)\\]]|ドイツ翻訳", Pattern.CASE_INSENSITIVE),
|
||||
Pattern.compile("[(\\[]italiano?[)\\]]|イタリア翻訳", Pattern.CASE_INSENSITIVE),
|
||||
Pattern.compile("[(\\[]vietnamese(?: Tiếng Việt)?[)\\]]|ベトナム翻訳", Pattern.CASE_INSENSITIVE),
|
||||
Pattern.compile("[(\\[]polish[)\\]]|ポーランド翻訳", Pattern.CASE_INSENSITIVE),
|
||||
Pattern.compile("[(\\[]hun(?:garian)?[)\\]]|ハンガリー翻訳", Pattern.CASE_INSENSITIVE),
|
||||
Pattern.compile("[(\\[]dutch[)\\]]|オランダ翻訳", Pattern.CASE_INSENSITIVE),
|
||||
};
|
||||
|
||||
public static final String[] S_LANG_TAGS = {
|
||||
"language:english",
|
||||
"language:chinese",
|
||||
"language:spanish",
|
||||
"language:korean",
|
||||
"language:russian",
|
||||
"language:french",
|
||||
"language:portuguese",
|
||||
"language:thai",
|
||||
"language:german",
|
||||
"language:italian",
|
||||
"language:vietnamese",
|
||||
"language:polish",
|
||||
"language:hungarian",
|
||||
"language:dutch",
|
||||
};
|
||||
public static final Parcelable.Creator<GalleryInfo> CREATOR = new Parcelable.Creator<GalleryInfo>() {
|
||||
|
||||
@Override
|
||||
public GalleryInfo createFromParcel(Parcel source) {
|
||||
return new GalleryInfo(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GalleryInfo[] newArray(int size) {
|
||||
return new GalleryInfo[size];
|
||||
}
|
||||
};
|
||||
@PrimaryKey
|
||||
@ColumnInfo(name = "GID")
|
||||
public long gid;
|
||||
@ColumnInfo(name = "TOKEN")
|
||||
public String token;
|
||||
@ColumnInfo(name = "TITLE")
|
||||
public String title;
|
||||
@ColumnInfo(name = "TITLE_JPN")
|
||||
public String titleJpn;
|
||||
@ColumnInfo(name = "THUMB")
|
||||
public String thumb;
|
||||
@ColumnInfo(name = "CATEGORY")
|
||||
public int category;
|
||||
@ColumnInfo(name = "POSTED")
|
||||
public String posted;
|
||||
@ColumnInfo(name = "UPLOADER")
|
||||
public String uploader;
|
||||
@Ignore
|
||||
public boolean disowned;
|
||||
@ColumnInfo(name = "RATING")
|
||||
public float rating;
|
||||
@Ignore
|
||||
public boolean rated;
|
||||
@Nullable
|
||||
@Ignore
|
||||
public String[] simpleTags;
|
||||
@Ignore
|
||||
public int pages;
|
||||
@Ignore
|
||||
public int thumbWidth;
|
||||
@Ignore
|
||||
public int thumbHeight;
|
||||
@Ignore
|
||||
public int spanSize;
|
||||
@Ignore
|
||||
public int spanIndex;
|
||||
@Ignore
|
||||
public int spanGroupIndex;
|
||||
/**
|
||||
* language from title
|
||||
*/
|
||||
@ColumnInfo(name = "SIMPLE_LANGUAGE")
|
||||
public String simpleLanguage;
|
||||
@Ignore
|
||||
public int favoriteSlot = -2;
|
||||
@Ignore
|
||||
public String favoriteName;
|
||||
|
||||
public GalleryInfo() {
|
||||
}
|
||||
|
||||
protected GalleryInfo(Parcel in) {
|
||||
this.gid = in.readLong();
|
||||
this.token = in.readString();
|
||||
this.title = in.readString();
|
||||
this.titleJpn = in.readString();
|
||||
this.thumb = in.readString();
|
||||
this.category = in.readInt();
|
||||
this.posted = in.readString();
|
||||
this.uploader = in.readString();
|
||||
this.rating = in.readFloat();
|
||||
this.rated = in.readByte() != 0;
|
||||
this.simpleLanguage = in.readString();
|
||||
this.simpleTags = in.createStringArray();
|
||||
this.thumbWidth = in.readInt();
|
||||
this.thumbHeight = in.readInt();
|
||||
this.spanSize = in.readInt();
|
||||
this.spanIndex = in.readInt();
|
||||
this.spanGroupIndex = in.readInt();
|
||||
this.favoriteSlot = in.readInt();
|
||||
this.favoriteName = in.readString();
|
||||
this.disowned = in.readByte() != 0;
|
||||
}
|
||||
|
||||
public final void generateSLang() {
|
||||
if (simpleTags != null) {
|
||||
generateSLangFromTags();
|
||||
}
|
||||
if (simpleLanguage == null && title != null) {
|
||||
generateSLangFromTitle();
|
||||
}
|
||||
}
|
||||
|
||||
private void generateSLangFromTags() {
|
||||
assert simpleTags != null;
|
||||
for (String tag : simpleTags) {
|
||||
for (int i = 0; i < S_LANGS.length; i++) {
|
||||
if (S_LANG_TAGS[i].equals(tag)) {
|
||||
simpleLanguage = S_LANGS[i];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void generateSLangFromTitle() {
|
||||
for (int i = 0; i < S_LANGS.length; i++) {
|
||||
if (S_LANG_PATTERNS[i].matcher(title).find()) {
|
||||
simpleLanguage = S_LANGS[i];
|
||||
return;
|
||||
}
|
||||
}
|
||||
simpleLanguage = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeLong(this.gid);
|
||||
dest.writeString(this.token);
|
||||
dest.writeString(this.title);
|
||||
dest.writeString(this.titleJpn);
|
||||
dest.writeString(this.thumb);
|
||||
dest.writeInt(this.category);
|
||||
dest.writeString(this.posted);
|
||||
dest.writeString(this.uploader);
|
||||
dest.writeFloat(this.rating);
|
||||
dest.writeByte(this.rated ? (byte) 1 : (byte) 0);
|
||||
dest.writeString(this.simpleLanguage);
|
||||
dest.writeStringArray(this.simpleTags);
|
||||
dest.writeInt(this.thumbWidth);
|
||||
dest.writeInt(this.thumbHeight);
|
||||
dest.writeInt(this.spanSize);
|
||||
dest.writeInt(this.spanIndex);
|
||||
dest.writeInt(this.spanGroupIndex);
|
||||
dest.writeInt(this.favoriteSlot);
|
||||
dest.writeString(this.favoriteName);
|
||||
dest.writeByte(this.disowned ? (byte) 1 : (byte) 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.hippo.ehviewer.client.data
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Ignore
|
||||
import androidx.room.PrimaryKey
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import java.util.regex.Pattern
|
||||
|
||||
@Parcelize
|
||||
open class GalleryInfo(
|
||||
@JvmField
|
||||
@PrimaryKey
|
||||
@ColumnInfo(name = "GID")
|
||||
var gid: Long = 0,
|
||||
|
||||
@JvmField
|
||||
@ColumnInfo(name = "TOKEN")
|
||||
var token: String? = null,
|
||||
|
||||
@JvmField
|
||||
@ColumnInfo(name = "TITLE")
|
||||
var title: String? = null,
|
||||
|
||||
@JvmField
|
||||
@ColumnInfo(name = "TITLE_JPN")
|
||||
var titleJpn: String? = null,
|
||||
|
||||
@JvmField
|
||||
@ColumnInfo(name = "THUMB")
|
||||
var thumb: String? = null,
|
||||
|
||||
@JvmField
|
||||
@ColumnInfo(name = "CATEGORY")
|
||||
var category: Int = 0,
|
||||
|
||||
@JvmField
|
||||
@ColumnInfo(name = "POSTED")
|
||||
var posted: String? = null,
|
||||
|
||||
@JvmField
|
||||
@ColumnInfo(name = "UPLOADER")
|
||||
var uploader: String? = null,
|
||||
|
||||
@JvmField
|
||||
@Ignore
|
||||
var disowned: Boolean = false,
|
||||
|
||||
@JvmField
|
||||
@ColumnInfo(name = "RATING")
|
||||
var rating: Float = 0f,
|
||||
|
||||
@JvmField
|
||||
@Ignore
|
||||
var rated: Boolean = false,
|
||||
|
||||
@JvmField
|
||||
@Ignore
|
||||
var simpleTags: Array<String>? = null,
|
||||
|
||||
@JvmField
|
||||
@Ignore
|
||||
var pages: Int = 0,
|
||||
|
||||
@JvmField
|
||||
@Ignore
|
||||
var thumbWidth: Int = 0,
|
||||
|
||||
@JvmField
|
||||
@Ignore
|
||||
var thumbHeight: Int = 0,
|
||||
|
||||
@Ignore
|
||||
var spanSize: Int = 0,
|
||||
|
||||
@Ignore
|
||||
var spanIndex: Int = 0,
|
||||
|
||||
@Ignore
|
||||
var spanGroupIndex: Int = 0,
|
||||
|
||||
/**
|
||||
* language from title
|
||||
*/
|
||||
@JvmField
|
||||
@ColumnInfo(name = "SIMPLE_LANGUAGE")
|
||||
var simpleLanguage: String? = null,
|
||||
|
||||
@JvmField
|
||||
@Ignore
|
||||
var favoriteSlot: Int = -2,
|
||||
|
||||
@JvmField
|
||||
@Ignore
|
||||
var favoriteName: String? = null
|
||||
|
||||
) : Parcelable {
|
||||
fun generateSLang() {
|
||||
simpleLanguage = simpleTags?.let { generateSLangFromTags(it) } ?: title?.let { generateSLangFromTitle(it) }
|
||||
}
|
||||
|
||||
private fun generateSLangFromTags(simpleTags: Array<String>): String? {
|
||||
for (tag in simpleTags) {
|
||||
for (i in S_LANGS.indices) {
|
||||
if (S_LANG_TAGS[i] == tag) {
|
||||
return S_LANGS[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun generateSLangFromTitle(title: String): String? {
|
||||
for (i in S_LANGS.indices) {
|
||||
if (S_LANG_PATTERNS[i].matcher(title).find()) {
|
||||
return S_LANGS[i]
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* ISO 639-1
|
||||
*/
|
||||
const val S_LANG_JA = "JA"
|
||||
const val S_LANG_EN = "EN"
|
||||
const val S_LANG_ZH = "ZH"
|
||||
const val S_LANG_NL = "NL"
|
||||
const val S_LANG_FR = "FR"
|
||||
const val S_LANG_DE = "DE"
|
||||
const val S_LANG_HU = "HU"
|
||||
const val S_LANG_IT = "IT"
|
||||
const val S_LANG_KO = "KO"
|
||||
const val S_LANG_PL = "PL"
|
||||
const val S_LANG_PT = "PT"
|
||||
const val S_LANG_RU = "RU"
|
||||
const val S_LANG_ES = "ES"
|
||||
const val S_LANG_TH = "TH"
|
||||
const val S_LANG_VI = "VI"
|
||||
|
||||
@JvmField
|
||||
val S_LANGS = arrayOf(
|
||||
S_LANG_EN,
|
||||
S_LANG_ZH,
|
||||
S_LANG_ES,
|
||||
S_LANG_KO,
|
||||
S_LANG_RU,
|
||||
S_LANG_FR,
|
||||
S_LANG_PT,
|
||||
S_LANG_TH,
|
||||
S_LANG_DE,
|
||||
S_LANG_IT,
|
||||
S_LANG_VI,
|
||||
S_LANG_PL,
|
||||
S_LANG_HU,
|
||||
S_LANG_NL
|
||||
)
|
||||
val S_LANG_PATTERNS = arrayOf(
|
||||
Pattern.compile(
|
||||
"[(\\[]eng(?:lish)?[)\\]]|英訳",
|
||||
Pattern.CASE_INSENSITIVE
|
||||
), // [((\[]ch(?:inese)?[))\]]|[汉漢]化|中[国國][语語]|中文|中国翻訳
|
||||
Pattern.compile(
|
||||
"[(\uFF08\\[]ch(?:inese)?[)\uFF09\\]]|[汉漢]化|中[国國][语語]|中文|中国翻訳",
|
||||
Pattern.CASE_INSENSITIVE
|
||||
),
|
||||
Pattern.compile(
|
||||
"[(\\[]spanish[)\\]]|[(\\[]Español[)\\]]|スペイン翻訳",
|
||||
Pattern.CASE_INSENSITIVE
|
||||
),
|
||||
Pattern.compile("[(\\[]korean?[)\\]]|韓国翻訳", Pattern.CASE_INSENSITIVE),
|
||||
Pattern.compile("[(\\[]rus(?:sian)?[)\\]]|ロシア翻訳", Pattern.CASE_INSENSITIVE),
|
||||
Pattern.compile("[(\\[]fr(?:ench)?[)\\]]|フランス翻訳", Pattern.CASE_INSENSITIVE),
|
||||
Pattern.compile("[(\\[]portuguese|ポルトガル翻訳", Pattern.CASE_INSENSITIVE),
|
||||
Pattern.compile(
|
||||
"[(\\[]thai(?: ภาษาไทย)?[)\\]]|แปลไทย|タイ翻訳",
|
||||
Pattern.CASE_INSENSITIVE
|
||||
),
|
||||
Pattern.compile("[(\\[]german[)\\]]|ドイツ翻訳", Pattern.CASE_INSENSITIVE),
|
||||
Pattern.compile("[(\\[]italiano?[)\\]]|イタリア翻訳", Pattern.CASE_INSENSITIVE),
|
||||
Pattern.compile(
|
||||
"[(\\[]vietnamese(?: Tiếng Việt)?[)\\]]|ベトナム翻訳",
|
||||
Pattern.CASE_INSENSITIVE
|
||||
),
|
||||
Pattern.compile("[(\\[]polish[)\\]]|ポーランド翻訳", Pattern.CASE_INSENSITIVE),
|
||||
Pattern.compile("[(\\[]hun(?:garian)?[)\\]]|ハンガリー翻訳", Pattern.CASE_INSENSITIVE),
|
||||
Pattern.compile("[(\\[]dutch[)\\]]|オランダ翻訳", Pattern.CASE_INSENSITIVE)
|
||||
)
|
||||
val S_LANG_TAGS = arrayOf(
|
||||
"language:english",
|
||||
"language:chinese",
|
||||
"language:spanish",
|
||||
"language:korean",
|
||||
"language:russian",
|
||||
"language:french",
|
||||
"language:portuguese",
|
||||
"language:thai",
|
||||
"language:german",
|
||||
"language:italian",
|
||||
"language:vietnamese",
|
||||
"language:polish",
|
||||
"language:hungarian",
|
||||
"language:dutch"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.ehviewer.client.data;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.hippo.widget.LoadImageView;
|
||||
|
||||
public class GalleryPreview implements Parcelable {
|
||||
|
||||
public static final Parcelable.Creator<GalleryPreview> CREATOR = new Parcelable.Creator<GalleryPreview>() {
|
||||
@Override
|
||||
public GalleryPreview createFromParcel(Parcel source) {
|
||||
return new GalleryPreview(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GalleryPreview[] newArray(int size) {
|
||||
return new GalleryPreview[size];
|
||||
}
|
||||
};
|
||||
String imageKey;
|
||||
String imageUrl;
|
||||
String pageUrl;
|
||||
int position;
|
||||
int offsetX = Integer.MIN_VALUE;
|
||||
int offsetY = Integer.MIN_VALUE;
|
||||
int clipWidth = Integer.MIN_VALUE;
|
||||
int clipHeight = Integer.MIN_VALUE;
|
||||
|
||||
public GalleryPreview() {
|
||||
}
|
||||
|
||||
protected GalleryPreview(Parcel in) {
|
||||
this.imageUrl = in.readString();
|
||||
this.pageUrl = in.readString();
|
||||
this.position = in.readInt();
|
||||
this.offsetX = in.readInt();
|
||||
this.offsetY = in.readInt();
|
||||
this.clipWidth = in.readInt();
|
||||
this.clipHeight = in.readInt();
|
||||
}
|
||||
|
||||
public int getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public void load(LoadImageView view) {
|
||||
view.setClip(offsetX, offsetY, clipWidth, clipHeight);
|
||||
view.load(imageKey, imageUrl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(this.imageUrl);
|
||||
dest.writeString(this.pageUrl);
|
||||
dest.writeInt(this.position);
|
||||
dest.writeInt(this.offsetX);
|
||||
dest.writeInt(this.offsetY);
|
||||
dest.writeInt(this.clipWidth);
|
||||
dest.writeInt(this.clipHeight);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.hippo.ehviewer.client.data
|
||||
|
||||
import android.os.Parcelable
|
||||
import com.hippo.widget.LoadImageView
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
class GalleryPreview(
|
||||
@JvmField
|
||||
var imageKey: String? = null,
|
||||
@JvmField
|
||||
var imageUrl: String? = null,
|
||||
@JvmField
|
||||
var pageUrl: String? = null,
|
||||
@JvmField
|
||||
var position: Int = 0,
|
||||
@JvmField
|
||||
var offsetX: Int = Int.MIN_VALUE,
|
||||
@JvmField
|
||||
var offsetY: Int = Int.MIN_VALUE,
|
||||
@JvmField
|
||||
var clipWidth: Int = Int.MIN_VALUE,
|
||||
@JvmField
|
||||
var clipHeight: Int = Int.MIN_VALUE,
|
||||
) : Parcelable {
|
||||
fun load(view: LoadImageView) {
|
||||
view.setClip(offsetX, offsetY, clipWidth, clipHeight)
|
||||
view.load(imageKey!!, imageUrl!!)
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.ehviewer.client.data;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
// TODO Add url field?
|
||||
public class GalleryTagGroup implements Parcelable {
|
||||
|
||||
public static final Parcelable.Creator<GalleryTagGroup> CREATOR = new Parcelable.Creator<GalleryTagGroup>() {
|
||||
@Override
|
||||
public GalleryTagGroup createFromParcel(Parcel source) {
|
||||
return new GalleryTagGroup(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GalleryTagGroup[] newArray(int size) {
|
||||
return new GalleryTagGroup[size];
|
||||
}
|
||||
};
|
||||
private final ArrayList<String> mTagList;
|
||||
public String groupName;
|
||||
|
||||
public GalleryTagGroup() {
|
||||
mTagList = new ArrayList<>();
|
||||
}
|
||||
|
||||
protected GalleryTagGroup(Parcel in) {
|
||||
this.groupName = in.readString();
|
||||
this.mTagList = in.createStringArrayList();
|
||||
}
|
||||
|
||||
public void addTag(String tag) {
|
||||
mTagList.add(tag);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return mTagList.size();
|
||||
}
|
||||
|
||||
public String getTagAt(int position) {
|
||||
return mTagList.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(this.groupName);
|
||||
dest.writeStringList(this.mTagList);
|
||||
}
|
||||
}
|
||||
+16
-14
@@ -13,24 +13,26 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.hippo.ehviewer.client.data
|
||||
|
||||
package com.hippo.ehviewer.client.exception;
|
||||
import android.os.Parcelable
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
public class ParseException extends EhException {
|
||||
|
||||
private final String mBody;
|
||||
|
||||
public ParseException(String detailMessage, String body) {
|
||||
super(detailMessage);
|
||||
mBody = body;
|
||||
@Parcelize
|
||||
class GalleryTagGroup(
|
||||
private val mTagList: ArrayList<String> = arrayListOf(),
|
||||
@JvmField
|
||||
var groupName: String? = null
|
||||
) : Parcelable {
|
||||
fun addTag(tag: String) {
|
||||
mTagList.add(tag)
|
||||
}
|
||||
|
||||
public ParseException(String detailMessage, String body, Throwable cause) {
|
||||
super(detailMessage, cause);
|
||||
mBody = body;
|
||||
fun size(): Int {
|
||||
return mTagList.size
|
||||
}
|
||||
|
||||
public String getBody() {
|
||||
return mBody;
|
||||
fun getTagAt(position: Int): String {
|
||||
return mTagList[position]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.ehviewer.client.data;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.hippo.ehviewer.client.EhCacheKeyFactory;
|
||||
import com.hippo.widget.LoadImageView;
|
||||
import com.hippo.yorozuya.collect.IntList;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class LargePreviewSet extends PreviewSet {
|
||||
|
||||
public static final Parcelable.Creator<LargePreviewSet> CREATOR = new Parcelable.Creator<LargePreviewSet>() {
|
||||
@Override
|
||||
public LargePreviewSet createFromParcel(Parcel source) {
|
||||
return new LargePreviewSet(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LargePreviewSet[] newArray(int size) {
|
||||
return new LargePreviewSet[size];
|
||||
}
|
||||
};
|
||||
private final IntList mPositionList;
|
||||
private final ArrayList<String> mImageUrlList;
|
||||
private final ArrayList<String> mPageUrlList;
|
||||
|
||||
public LargePreviewSet() {
|
||||
mPositionList = new IntList();
|
||||
mImageUrlList = new ArrayList<>();
|
||||
mPageUrlList = new ArrayList<>();
|
||||
}
|
||||
|
||||
protected LargePreviewSet(Parcel in) {
|
||||
this.mPositionList = in.readParcelable(IntList.class.getClassLoader());
|
||||
this.mImageUrlList = in.createStringArrayList();
|
||||
this.mPageUrlList = in.createStringArrayList();
|
||||
}
|
||||
|
||||
public void addItem(int index, String imageUrl, String pageUrl) {
|
||||
mPositionList.add(index);
|
||||
mImageUrlList.add(imageUrl);
|
||||
mPageUrlList.add(pageUrl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return mImageUrlList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPosition(int index) {
|
||||
return mPositionList.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPageUrlAt(int index) {
|
||||
return mPageUrlList.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GalleryPreview getGalleryPreview(long gid, int index) {
|
||||
GalleryPreview galleryPreview = new GalleryPreview();
|
||||
galleryPreview.position = mPositionList.get(index);
|
||||
galleryPreview.imageKey = EhCacheKeyFactory.getLargePreviewKey(gid, galleryPreview.position);
|
||||
galleryPreview.imageUrl = mImageUrlList.get(index);
|
||||
galleryPreview.pageUrl = mPageUrlList.get(index);
|
||||
return galleryPreview;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(LoadImageView view, long gid, int index) {
|
||||
view.resetClip();
|
||||
view.load(EhCacheKeyFactory.getLargePreviewKey(gid, mPositionList.get(index)),
|
||||
mImageUrlList.get(index));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeParcelable(this.mPositionList, flags);
|
||||
dest.writeStringList(this.mImageUrlList);
|
||||
dest.writeStringList(this.mPageUrlList);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.hippo.ehviewer.client.data
|
||||
|
||||
import com.hippo.ehviewer.client.EhCacheKeyFactory
|
||||
import com.hippo.widget.LoadImageView
|
||||
import com.hippo.yorozuya.collect.IntList
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
class LargePreviewSet(
|
||||
private val mPositionList: IntList = IntList(),
|
||||
private val mImageUrlList: ArrayList<String> = ArrayList(),
|
||||
private val mPageUrlList: ArrayList<String> = ArrayList()
|
||||
) : PreviewSet() {
|
||||
|
||||
fun addItem(index: Int, imageUrl: String, pageUrl: String) {
|
||||
mPositionList.add(index)
|
||||
mImageUrlList.add(imageUrl)
|
||||
mPageUrlList.add(pageUrl)
|
||||
}
|
||||
|
||||
override fun size(): Int {
|
||||
return mImageUrlList.size
|
||||
}
|
||||
|
||||
override fun getPosition(index: Int): Int {
|
||||
return mPositionList[index]
|
||||
}
|
||||
|
||||
override fun getPageUrlAt(index: Int): String {
|
||||
return mPageUrlList[index]
|
||||
}
|
||||
|
||||
override fun getGalleryPreview(gid: Long, index: Int): GalleryPreview {
|
||||
val galleryPreview = GalleryPreview()
|
||||
galleryPreview.position = mPositionList[index]
|
||||
galleryPreview.imageKey = EhCacheKeyFactory.getLargePreviewKey(gid, galleryPreview.position)
|
||||
galleryPreview.imageUrl = mImageUrlList[index]
|
||||
galleryPreview.pageUrl = mPageUrlList[index]
|
||||
return galleryPreview
|
||||
}
|
||||
|
||||
override fun load(view: LoadImageView, gid: Long, index: Int) {
|
||||
view.resetClip()
|
||||
view.load(
|
||||
EhCacheKeyFactory.getLargePreviewKey(gid, mPositionList[index]),
|
||||
mImageUrlList[index]
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -15,9 +15,7 @@
|
||||
*/
|
||||
package com.hippo.ehviewer.client.data
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import android.os.Parcelable.Creator
|
||||
import android.text.TextUtils
|
||||
import androidx.annotation.IntDef
|
||||
import com.hippo.ehviewer.client.EhConfig
|
||||
@@ -26,54 +24,36 @@ import com.hippo.ehviewer.client.EhUtils
|
||||
import com.hippo.ehviewer.dao.QuickSearch
|
||||
import com.hippo.ehviewer.widget.AdvanceSearchTable
|
||||
import com.hippo.network.UrlBuilder
|
||||
import com.hippo.util.encodeUTF8
|
||||
import com.hippo.yorozuya.NumberUtils
|
||||
import com.hippo.yorozuya.StringUtils
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import java.io.UnsupportedEncodingException
|
||||
import java.net.URLDecoder
|
||||
import java.net.URLEncoder
|
||||
|
||||
open class ListUrlBuilder : Cloneable, Parcelable {
|
||||
@get:Mode
|
||||
@Mode
|
||||
var mode = MODE_NORMAL
|
||||
private var mPrevGid = 0
|
||||
private var mNextGid = 0
|
||||
private var mJumpTo: String? = null
|
||||
var category = EhUtils.NONE
|
||||
private var mKeyword: String? = null
|
||||
private var mSHash: String? = null
|
||||
var advanceSearch = -1
|
||||
var minRating = -1
|
||||
var pageFrom = -1
|
||||
var pageTo = -1
|
||||
var imagePath: String? = null
|
||||
var isUseSimilarityScan = false
|
||||
var isOnlySearchCovers = false
|
||||
var isShowExpunged = false
|
||||
|
||||
constructor()
|
||||
protected constructor(parcel: Parcel) {
|
||||
mode = parcel.readInt()
|
||||
mPrevGid = parcel.readInt()
|
||||
mNextGid = parcel.readInt()
|
||||
mJumpTo = parcel.readString()
|
||||
this.category = parcel.readInt()
|
||||
mKeyword = parcel.readString()
|
||||
advanceSearch = parcel.readInt()
|
||||
minRating = parcel.readInt()
|
||||
pageFrom = parcel.readInt()
|
||||
pageTo = parcel.readInt()
|
||||
imagePath = parcel.readString()
|
||||
isUseSimilarityScan = parcel.readByte().toInt() != 0
|
||||
isOnlySearchCovers = parcel.readByte().toInt() != 0
|
||||
isShowExpunged = parcel.readByte().toInt() != 0
|
||||
mSHash = parcel.readString()
|
||||
}
|
||||
@Parcelize
|
||||
open class ListUrlBuilder(
|
||||
@get:Mode @Mode var mode: Int = MODE_NORMAL,
|
||||
private var mPrev: String? = null,
|
||||
private var mNext: String? = null,
|
||||
private var mJumpTo: String? = null,
|
||||
var category: Int = EhUtils.NONE,
|
||||
private var mKeyword: String? = null,
|
||||
private var mSHash: String? = null,
|
||||
var advanceSearch: Int = -1,
|
||||
var minRating: Int = -1,
|
||||
var pageFrom: Int = -1,
|
||||
var pageTo: Int = -1,
|
||||
var imagePath: String? = null,
|
||||
var isUseSimilarityScan: Boolean = false,
|
||||
var isOnlySearchCovers: Boolean = false,
|
||||
var isShowExpunged: Boolean = false,
|
||||
) : Cloneable, Parcelable {
|
||||
|
||||
fun reset() {
|
||||
mode = MODE_NORMAL
|
||||
mPrevGid = 0
|
||||
mNextGid = 0
|
||||
mPrev = null
|
||||
mNext = null
|
||||
mJumpTo = null
|
||||
this.category = EhUtils.NONE
|
||||
mKeyword = null
|
||||
@@ -88,20 +68,9 @@ open class ListUrlBuilder : Cloneable, Parcelable {
|
||||
mSHash = null
|
||||
}
|
||||
|
||||
public override fun clone(): ListUrlBuilder {
|
||||
return try {
|
||||
super.clone() as ListUrlBuilder
|
||||
} catch (e: CloneNotSupportedException) {
|
||||
throw IllegalStateException(e)
|
||||
}
|
||||
}
|
||||
|
||||
fun setPrevGid(prevGid: Int) {
|
||||
mPrevGid = prevGid
|
||||
}
|
||||
|
||||
fun setNextGid(nextGid: Int) {
|
||||
mNextGid = nextGid
|
||||
fun setIndex(index: String?, isNext: Boolean = true) {
|
||||
mNext = index?.takeIf { isNext }
|
||||
mPrev = index?.takeUnless { isNext }
|
||||
}
|
||||
|
||||
fun setJumpTo(jumpTo: String?) {
|
||||
@@ -121,8 +90,8 @@ open class ListUrlBuilder : Cloneable, Parcelable {
|
||||
*/
|
||||
fun set(lub: ListUrlBuilder) {
|
||||
mode = lub.mode
|
||||
mPrevGid = lub.mPrevGid
|
||||
mNextGid = lub.mNextGid
|
||||
mPrev = lub.mPrev
|
||||
mNext = lub.mNext
|
||||
mJumpTo = lub.mJumpTo
|
||||
this.category = lub.category
|
||||
mKeyword = lub.mKeyword
|
||||
@@ -196,7 +165,7 @@ open class ListUrlBuilder : Cloneable, Parcelable {
|
||||
if (TextUtils.isEmpty(query)) {
|
||||
return
|
||||
}
|
||||
val querys = StringUtils.split(query, '&')
|
||||
val queries = StringUtils.split(query, '&')
|
||||
var category = 0
|
||||
var keyword: String? = null
|
||||
var enableAdvanceSearch = false
|
||||
@@ -206,7 +175,7 @@ open class ListUrlBuilder : Cloneable, Parcelable {
|
||||
var enablePage = false
|
||||
var pageFrom = -1
|
||||
var pageTo = -1
|
||||
for (str in querys) {
|
||||
for (str in queries) {
|
||||
val index = str.indexOf('=')
|
||||
if (index < 0) {
|
||||
continue
|
||||
@@ -338,29 +307,23 @@ open class ListUrlBuilder : Cloneable, Parcelable {
|
||||
ub.addQuery("f_cats", category.inv() and EhConfig.ALL_CATEGORY)
|
||||
}
|
||||
// Search key
|
||||
if (mKeyword != null) {
|
||||
val keyword = mKeyword!!.trim { it <= ' ' }
|
||||
mKeyword?.run {
|
||||
val keyword = trim { it <= ' ' }
|
||||
if (keyword.isNotEmpty()) {
|
||||
try {
|
||||
ub.addQuery("f_search", URLEncoder.encode(mKeyword, "UTF-8"))
|
||||
} catch (e: UnsupportedEncodingException) {
|
||||
// Empty
|
||||
}
|
||||
ub.addQuery("f_search", encodeUTF8(this))
|
||||
}
|
||||
}
|
||||
if (mSHash != null) {
|
||||
ub.addQuery("f_shash", mSHash!!)
|
||||
mSHash?.let {
|
||||
ub.addQuery("f_shash", it)
|
||||
}
|
||||
mJumpTo?.let {
|
||||
ub.addQuery("seek", mJumpTo!!)
|
||||
mPrevGid = 0
|
||||
mNextGid = 0
|
||||
ub.addQuery("seek", it)
|
||||
}
|
||||
if (mPrevGid != 0) {
|
||||
ub.addQuery("prev", mPrevGid)
|
||||
mPrev?.let {
|
||||
ub.addQuery("prev", it)
|
||||
}
|
||||
if (mNextGid != 0) {
|
||||
ub.addQuery("next", mNextGid)
|
||||
mNext?.let {
|
||||
ub.addQuery("next", it)
|
||||
}
|
||||
// Advance search
|
||||
if (advanceSearch != -1) {
|
||||
@@ -387,40 +350,36 @@ open class ListUrlBuilder : Cloneable, Parcelable {
|
||||
|
||||
MODE_UPLOADER -> {
|
||||
val sb = StringBuilder(EhUrl.getHost())
|
||||
sb.append("uploader/")
|
||||
try {
|
||||
sb.append(URLEncoder.encode(mKeyword, "UTF-8"))
|
||||
} catch (e: UnsupportedEncodingException) {
|
||||
// Empty
|
||||
mKeyword?.let {
|
||||
sb.append("uploader/")
|
||||
sb.append(encodeUTF8(it))
|
||||
}
|
||||
if (mPrevGid != 0) {
|
||||
sb.append("?prev=").append(mPrevGid)
|
||||
mPrev?.let {
|
||||
sb.append("?prev=").append(it)
|
||||
}
|
||||
if (mNextGid != 0) {
|
||||
sb.append("?next=").append(mNextGid)
|
||||
mNext?.let {
|
||||
sb.append("?next=").append(it)
|
||||
}
|
||||
if (mJumpTo != null) {
|
||||
sb.append("&seek=").append(mJumpTo)
|
||||
mJumpTo?.let {
|
||||
sb.append("&seek=").append(it)
|
||||
}
|
||||
sb.toString()
|
||||
}
|
||||
|
||||
MODE_TAG -> {
|
||||
val sb = StringBuilder(EhUrl.getHost())
|
||||
sb.append("tag/")
|
||||
try {
|
||||
sb.append(URLEncoder.encode(mKeyword, "UTF-8"))
|
||||
} catch (e: UnsupportedEncodingException) {
|
||||
// Empty
|
||||
mKeyword?.let {
|
||||
sb.append("tag/")
|
||||
sb.append(encodeUTF8(it))
|
||||
}
|
||||
if (mPrevGid != 0) {
|
||||
sb.append("?prev=").append(mPrevGid)
|
||||
mPrev?.let {
|
||||
sb.append("?prev=").append(it)
|
||||
}
|
||||
if (mNextGid != 0) {
|
||||
sb.append("?next=").append(mNextGid)
|
||||
mNext?.let {
|
||||
sb.append("?next=").append(it)
|
||||
}
|
||||
if (mJumpTo != null) {
|
||||
sb.append("&seek=").append(mJumpTo)
|
||||
mJumpTo?.let {
|
||||
sb.append("&seek=").append(it)
|
||||
}
|
||||
sb.toString()
|
||||
}
|
||||
@@ -430,89 +389,19 @@ open class ListUrlBuilder : Cloneable, Parcelable {
|
||||
MODE_TOPLIST -> {
|
||||
val sb = StringBuilder(EhUrl.HOST_E)
|
||||
sb.append("toplist.php?tl=")
|
||||
try {
|
||||
sb.append(URLEncoder.encode(mKeyword, "UTF-8"))
|
||||
} catch (e: UnsupportedEncodingException) {
|
||||
// Empty
|
||||
mKeyword.orEmpty().let {
|
||||
sb.append(encodeUTF8(it))
|
||||
}
|
||||
if (mNextGid != 0) {
|
||||
sb.append("&p=").append(mNextGid)
|
||||
mJumpTo?.let {
|
||||
sb.append("&p=").append(it)
|
||||
}
|
||||
sb.toString()
|
||||
}
|
||||
|
||||
else -> {
|
||||
val url: String = if (mode == MODE_NORMAL) {
|
||||
EhUrl.getHost()
|
||||
} else {
|
||||
EhUrl.getWatchedUrl()
|
||||
}
|
||||
val ub = UrlBuilder(url)
|
||||
if (this.category != EhUtils.NONE) {
|
||||
ub.addQuery("f_cats", category.inv() and EhConfig.ALL_CATEGORY)
|
||||
}
|
||||
if (mKeyword != null) {
|
||||
val keyword = mKeyword!!.trim { it <= ' ' }
|
||||
if (keyword.isNotEmpty()) {
|
||||
try {
|
||||
ub.addQuery("f_search", URLEncoder.encode(mKeyword, "UTF-8"))
|
||||
} catch (_: UnsupportedEncodingException) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mSHash != null) {
|
||||
ub.addQuery("f_shash", mSHash!!)
|
||||
}
|
||||
if (mPrevGid != 0) {
|
||||
ub.addQuery("prev", mPrevGid)
|
||||
}
|
||||
if (mNextGid != 0) {
|
||||
ub.addQuery("next", mNextGid)
|
||||
}
|
||||
if (advanceSearch != -1) {
|
||||
ub.addQuery("advsearch", "1")
|
||||
if (advanceSearch and AdvanceSearchTable.SH != 0) ub.addQuery("f_sh", "on")
|
||||
if (advanceSearch and AdvanceSearchTable.STO != 0) ub.addQuery("f_sto", "on")
|
||||
if (advanceSearch and AdvanceSearchTable.SFL != 0) ub.addQuery("f_sfl", "on")
|
||||
if (advanceSearch and AdvanceSearchTable.SFU != 0) ub.addQuery("f_sfu", "on")
|
||||
if (advanceSearch and AdvanceSearchTable.SFT != 0) ub.addQuery("f_sft", "on")
|
||||
if (minRating != -1) {
|
||||
ub.addQuery("f_sr", "on")
|
||||
ub.addQuery("f_srdd", minRating)
|
||||
}
|
||||
if (pageFrom != -1 || pageTo != -1) {
|
||||
ub.addQuery("f_sp", "on")
|
||||
ub.addQuery("f_spf", if (pageFrom != -1) pageFrom.toString() else "")
|
||||
ub.addQuery("f_spt", if (pageTo != -1) pageTo.toString() else "")
|
||||
}
|
||||
}
|
||||
ub.build()
|
||||
}
|
||||
else -> throw IllegalStateException("Unexpected value: $mode")
|
||||
}
|
||||
}
|
||||
|
||||
override fun describeContents(): Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
override fun writeToParcel(dest: Parcel, flags: Int) {
|
||||
dest.writeInt(mode)
|
||||
dest.writeInt(mPrevGid)
|
||||
dest.writeInt(mNextGid)
|
||||
dest.writeString(mJumpTo)
|
||||
dest.writeInt(this.category)
|
||||
dest.writeString(mKeyword)
|
||||
dest.writeInt(advanceSearch)
|
||||
dest.writeInt(minRating)
|
||||
dest.writeInt(pageFrom)
|
||||
dest.writeInt(pageTo)
|
||||
dest.writeString(imagePath)
|
||||
dest.writeByte(if (isUseSimilarityScan) 1.toByte() else 0.toByte())
|
||||
dest.writeByte(if (isOnlySearchCovers) 1.toByte() else 0.toByte())
|
||||
dest.writeByte(if (isShowExpunged) 1.toByte() else 0.toByte())
|
||||
dest.writeString(mSHash)
|
||||
}
|
||||
|
||||
@IntDef(
|
||||
MODE_NORMAL,
|
||||
MODE_UPLOADER,
|
||||
@@ -532,16 +421,5 @@ open class ListUrlBuilder : Cloneable, Parcelable {
|
||||
const val MODE_IMAGE_SEARCH = 0x4
|
||||
const val MODE_SUBSCRIPTION = 0x5
|
||||
const val MODE_TOPLIST = 0x6
|
||||
|
||||
@JvmField
|
||||
val CREATOR: Creator<ListUrlBuilder> = object : Creator<ListUrlBuilder> {
|
||||
override fun createFromParcel(source: Parcel): ListUrlBuilder {
|
||||
return ListUrlBuilder(source)
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<ListUrlBuilder?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.ehviewer.client.data;
|
||||
|
||||
import android.os.Parcel;
|
||||
|
||||
import com.hippo.widget.LoadImageView;
|
||||
import com.hippo.yorozuya.collect.IntList;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class NormalPreviewSet extends PreviewSet {
|
||||
|
||||
public static final Creator<NormalPreviewSet> CREATOR = new Creator<NormalPreviewSet>() {
|
||||
@Override
|
||||
public NormalPreviewSet createFromParcel(Parcel source) {
|
||||
return new NormalPreviewSet(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NormalPreviewSet[] newArray(int size) {
|
||||
return new NormalPreviewSet[size];
|
||||
}
|
||||
};
|
||||
private IntList mPositionList = new IntList();
|
||||
private ArrayList<String> mImageKeyList = new ArrayList<>();
|
||||
private ArrayList<String> mImageUrlList = new ArrayList<>();
|
||||
private IntList mOffsetXList = new IntList();
|
||||
private IntList mOffsetYList = new IntList();
|
||||
private IntList mClipWidthList = new IntList();
|
||||
private IntList mClipHeightList = new IntList();
|
||||
private ArrayList<String> mPageUrlList = new ArrayList<>();
|
||||
|
||||
public NormalPreviewSet() {
|
||||
}
|
||||
|
||||
protected NormalPreviewSet(Parcel in) {
|
||||
this.mPositionList = in.readParcelable(IntList.class.getClassLoader());
|
||||
this.mImageKeyList = in.createStringArrayList();
|
||||
this.mImageUrlList = in.createStringArrayList();
|
||||
this.mOffsetXList = in.readParcelable(IntList.class.getClassLoader());
|
||||
this.mOffsetYList = in.readParcelable(IntList.class.getClassLoader());
|
||||
this.mClipWidthList = in.readParcelable(IntList.class.getClassLoader());
|
||||
this.mClipHeightList = in.readParcelable(IntList.class.getClassLoader());
|
||||
this.mPageUrlList = in.createStringArrayList();
|
||||
}
|
||||
|
||||
private String getImageKey(String imageUrl) {
|
||||
int index = imageUrl.indexOf('/');
|
||||
if (index >= 0) {
|
||||
return imageUrl.substring(index + 1);
|
||||
} else {
|
||||
return imageUrl;
|
||||
}
|
||||
}
|
||||
|
||||
public void addItem(int position, String imageUrl, int xOffset, int yOffset, int width,
|
||||
int height, String pageUrl) {
|
||||
mPositionList.add(position);
|
||||
mImageKeyList.add(getImageKey(imageUrl));
|
||||
mImageUrlList.add(imageUrl);
|
||||
mOffsetXList.add(xOffset);
|
||||
mOffsetYList.add(yOffset);
|
||||
mClipWidthList.add(width);
|
||||
mClipHeightList.add(height);
|
||||
mPageUrlList.add(pageUrl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return mPositionList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPosition(int index) {
|
||||
return mPositionList.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPageUrlAt(int index) {
|
||||
return mPageUrlList.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GalleryPreview getGalleryPreview(long gid, int index) {
|
||||
GalleryPreview galleryPreview = new GalleryPreview();
|
||||
galleryPreview.position = mPositionList.get(index);
|
||||
galleryPreview.imageKey = mImageKeyList.get(index);
|
||||
galleryPreview.imageUrl = mImageUrlList.get(index);
|
||||
galleryPreview.pageUrl = mPageUrlList.get(index);
|
||||
galleryPreview.offsetX = mOffsetXList.get(index);
|
||||
galleryPreview.offsetY = mOffsetYList.get(index);
|
||||
galleryPreview.clipWidth = mClipWidthList.get(index);
|
||||
galleryPreview.clipHeight = mClipHeightList.get(index);
|
||||
return galleryPreview;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(LoadImageView view, long gid, int index) {
|
||||
view.setClip(mOffsetXList.get(index), mOffsetYList.get(index),
|
||||
mClipWidthList.get(index), mClipHeightList.get(index));
|
||||
view.load(mImageKeyList.get(index), mImageUrlList.get(index));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeParcelable(this.mPositionList, flags);
|
||||
dest.writeStringList(this.mImageKeyList);
|
||||
dest.writeStringList(this.mImageUrlList);
|
||||
dest.writeParcelable(this.mOffsetXList, flags);
|
||||
dest.writeParcelable(this.mOffsetYList, flags);
|
||||
dest.writeParcelable(this.mClipWidthList, flags);
|
||||
dest.writeParcelable(this.mClipHeightList, flags);
|
||||
dest.writeStringList(this.mPageUrlList);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.hippo.ehviewer.client.data
|
||||
|
||||
import com.hippo.widget.LoadImageView
|
||||
import com.hippo.yorozuya.collect.IntList
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
class NormalPreviewSet(
|
||||
private var mPositionList: IntList = IntList(),
|
||||
private var mImageKeyList: ArrayList<String> = ArrayList(),
|
||||
private var mImageUrlList: ArrayList<String> = ArrayList(),
|
||||
private var mOffsetXList: IntList = IntList(),
|
||||
private var mOffsetYList: IntList = IntList(),
|
||||
private var mClipWidthList: IntList = IntList(),
|
||||
private var mClipHeightList: IntList = IntList(),
|
||||
private var mPageUrlList: ArrayList<String> = ArrayList()
|
||||
) : PreviewSet() {
|
||||
|
||||
private fun getImageKey(imageUrl: String): String {
|
||||
val index = imageUrl.indexOf('/')
|
||||
return if (index >= 0) {
|
||||
imageUrl.substring(index + 1)
|
||||
} else {
|
||||
imageUrl
|
||||
}
|
||||
}
|
||||
|
||||
fun addItem(
|
||||
position: Int, imageUrl: String, xOffset: Int, yOffset: Int, width: Int,
|
||||
height: Int, pageUrl: String
|
||||
) {
|
||||
mPositionList.add(position)
|
||||
mImageKeyList.add(getImageKey(imageUrl))
|
||||
mImageUrlList.add(imageUrl)
|
||||
mOffsetXList.add(xOffset)
|
||||
mOffsetYList.add(yOffset)
|
||||
mClipWidthList.add(width)
|
||||
mClipHeightList.add(height)
|
||||
mPageUrlList.add(pageUrl)
|
||||
}
|
||||
|
||||
override fun size(): Int {
|
||||
return mPositionList.size()
|
||||
}
|
||||
|
||||
override fun getPosition(index: Int): Int {
|
||||
return mPositionList[index]
|
||||
}
|
||||
|
||||
override fun getPageUrlAt(index: Int): String {
|
||||
return mPageUrlList[index]
|
||||
}
|
||||
|
||||
override fun getGalleryPreview(gid: Long, index: Int): GalleryPreview {
|
||||
val galleryPreview = GalleryPreview()
|
||||
galleryPreview.position = mPositionList[index]
|
||||
galleryPreview.imageKey = mImageKeyList[index]
|
||||
galleryPreview.imageUrl = mImageUrlList[index]
|
||||
galleryPreview.pageUrl = mPageUrlList[index]
|
||||
galleryPreview.offsetX = mOffsetXList[index]
|
||||
galleryPreview.offsetY = mOffsetYList[index]
|
||||
galleryPreview.clipWidth = mClipWidthList[index]
|
||||
galleryPreview.clipHeight = mClipHeightList[index]
|
||||
return galleryPreview
|
||||
}
|
||||
|
||||
override fun load(view: LoadImageView, gid: Long, index: Int) {
|
||||
view.setClip(
|
||||
mOffsetXList[index], mOffsetYList[index],
|
||||
mClipWidthList[index], mClipHeightList[index]
|
||||
)
|
||||
view.load(mImageKeyList[index], mImageUrlList[index])
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.ehviewer.client.data;
|
||||
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.hippo.widget.LoadImageView;
|
||||
|
||||
public abstract class PreviewSet implements Parcelable {
|
||||
|
||||
public abstract int size();
|
||||
|
||||
public abstract int getPosition(int index);
|
||||
|
||||
public abstract String getPageUrlAt(int index);
|
||||
|
||||
public abstract GalleryPreview getGalleryPreview(long gid, int index);
|
||||
|
||||
public abstract void load(LoadImageView view, long gid, int index);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.hippo.ehviewer.client.data
|
||||
|
||||
import android.os.Parcelable
|
||||
import com.hippo.widget.LoadImageView
|
||||
|
||||
abstract class PreviewSet : Parcelable {
|
||||
abstract fun size(): Int
|
||||
abstract fun getPosition(index: Int): Int
|
||||
abstract fun getPageUrlAt(index: Int): String
|
||||
abstract fun getGalleryPreview(gid: Long, index: Int): GalleryPreview
|
||||
abstract fun load(view: LoadImageView, gid: Long, index: Int)
|
||||
}
|
||||
+5
-9
@@ -13,13 +13,9 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.hippo.ehviewer.client.exception
|
||||
|
||||
package com.hippo.ehviewer.client.exception;
|
||||
|
||||
public class NoHAtHClientException extends EhException {
|
||||
|
||||
public NoHAtHClientException(String detailMessage) {
|
||||
super(detailMessage);
|
||||
}
|
||||
|
||||
}
|
||||
open class EhException : Exception {
|
||||
constructor(detailMessage: String?) : super(detailMessage)
|
||||
constructor(detailMessage: String?, cause: Throwable?) : super(detailMessage, cause)
|
||||
}
|
||||
+2
-8
@@ -13,12 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.hippo.ehviewer.client.exception
|
||||
|
||||
package com.hippo.ehviewer.client.exception;
|
||||
|
||||
public class Image509Exception extends EhException {
|
||||
|
||||
public Image509Exception() {
|
||||
super("509");
|
||||
}
|
||||
}
|
||||
class Image509Exception : EhException("509")
|
||||
+2
-8
@@ -13,12 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.hippo.ehviewer.client.exception
|
||||
|
||||
package com.hippo.ehviewer.client.exception;
|
||||
|
||||
public class CancelledException extends Exception {
|
||||
|
||||
public CancelledException() {
|
||||
super("CANCELED");
|
||||
}
|
||||
}
|
||||
class NoHAtHClientException(detailMessage: String?) : EhException(detailMessage)
|
||||
+2
-8
@@ -13,15 +13,9 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.ehviewer.client.exception;
|
||||
package com.hippo.ehviewer.client.exception
|
||||
|
||||
/**
|
||||
* It is an exception for get offensive tip for g.e-hentai.org
|
||||
*/
|
||||
public class OffensiveException extends EhException {
|
||||
|
||||
public OffensiveException() {
|
||||
super("OFFENSIVE");
|
||||
}
|
||||
}
|
||||
class OffensiveException : EhException("OFFENSIVE")
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.hippo.ehviewer.client.exception
|
||||
|
||||
class ParseException : EhException {
|
||||
val body: String
|
||||
|
||||
constructor(detailMessage: String?, body: String) : super(detailMessage) {
|
||||
this.body = body
|
||||
}
|
||||
|
||||
constructor(detailMessage: String?, body: String, cause: Throwable?) : super(
|
||||
detailMessage,
|
||||
cause
|
||||
) {
|
||||
this.body = body
|
||||
}
|
||||
}
|
||||
+2
-8
@@ -13,12 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.hippo.ehviewer.client.exception
|
||||
|
||||
package com.hippo.ehviewer.client.exception;
|
||||
|
||||
public class PiningException extends EhException {
|
||||
|
||||
public PiningException() {
|
||||
super("pining for the fjords");
|
||||
}
|
||||
}
|
||||
class PiningException : EhException("pining for the fjords")
|
||||
@@ -16,33 +16,193 @@
|
||||
|
||||
package com.hippo.ehviewer.client.parser;
|
||||
|
||||
import android.util.Pair;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.ehviewer.client.exception.NoHAtHClientException;
|
||||
|
||||
import org.jsoup.Jsoup;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.IntFunction;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class ArchiveParser {
|
||||
|
||||
private static final Pattern PATTERN_FORM = Pattern.compile("<form id=\"hathdl_form\" action=\"[^\"]*?or=([^=\"]*?)\" method=\"post\">");
|
||||
private static final Pattern PATTERN_ARCHIVE = Pattern.compile("<a href=\"[^\"]*\" onclick=\"return do_hathdl\\('([0-9]+|org)'\\)\">([^<]+)</a>");
|
||||
private static final Pattern PATTERN_ARCHIVE_URL = Pattern.compile("<strong>(.*)</strong>.*<a href=\"([^\"]*)\">Click Here To Start Downloading</a>");
|
||||
private static final Pattern PATTERN_HATH_FORM = Pattern.compile("<form id=\"hathdl_form\" action=\"[^\"]*?or=([^=\"]*?)\" method=\"post\">");
|
||||
private static final Pattern PATTERN_HATH_ARCHIVE = Pattern.compile("<p><a href=\"[^\"]*\" onclick=\"return do_hathdl\\('([0-9]+|org)'\\)\">([^<]+)</a></p>\\s*<p>([\\w. ]+)</p>\\s*<p>([\\w. ]+)</p>");
|
||||
private static final Pattern PATTERN_NEED_HATH_CLIENT = Pattern.compile("You must have a H@H client assigned to your account to use this feature\\.");
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Pair<String, Pair<String, String>[]> parse(String body) {
|
||||
Matcher m = PATTERN_FORM.matcher(body);
|
||||
public static Result parse(String body) {
|
||||
Matcher m = PATTERN_HATH_FORM.matcher(body);
|
||||
if (!m.find()) {
|
||||
return new Pair<String, Pair<String, String>[]>("", new Pair[0]);
|
||||
return new Result(null, null);
|
||||
}
|
||||
String paramOr = m.group(1);
|
||||
List<Pair<String, String>> archiveList = new ArrayList<>();
|
||||
m = PATTERN_ARCHIVE.matcher(body);
|
||||
|
||||
var archiveList = new ArrayList<Archive>();
|
||||
var d = Jsoup.parse(body);
|
||||
var es = d.select("#db>div>div");
|
||||
for (var e : es) {
|
||||
try {
|
||||
var res = e.selectFirst("form>input").attr("value");
|
||||
var name = e.selectFirst("form>div>input").attr("value");
|
||||
var size = e.selectFirst("p>strong").text();
|
||||
var cost = e.selectFirst("div>strong").text();
|
||||
var item = new Archive(res, name, size, cost, false);
|
||||
archiveList.add(item);
|
||||
} catch (NullPointerException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
m = PATTERN_HATH_ARCHIVE.matcher(body);
|
||||
while (m.find()) {
|
||||
String res = ParserUtils.trim(m.group(1));
|
||||
String name = ParserUtils.trim(m.group(2));
|
||||
Pair<String, String> item = new Pair<>(res, name);
|
||||
String size = ParserUtils.trim(m.group(3));
|
||||
String cost = ParserUtils.trim(m.group(4));
|
||||
var item = new Archive(res, name, size, cost, true);
|
||||
archiveList.add(item);
|
||||
}
|
||||
return new Pair<>(paramOr, archiveList.toArray(new Pair[0]));
|
||||
|
||||
return new Result(paramOr, archiveList);
|
||||
}
|
||||
|
||||
public static String parseArchiveUrl(String body) throws NoHAtHClientException {
|
||||
Matcher m = PATTERN_NEED_HATH_CLIENT.matcher(body);
|
||||
if (m.find()) {
|
||||
throw new NoHAtHClientException("No H@H client");
|
||||
}
|
||||
|
||||
var d = Jsoup.parse(body);
|
||||
var a = d.selectFirst("#continue>a[href]");
|
||||
if (a != null) {
|
||||
return a.attr("href") + "?start=1";
|
||||
}
|
||||
|
||||
// TODO: Check more errors
|
||||
return null;
|
||||
}
|
||||
|
||||
public static final class Archive {
|
||||
private final String res;
|
||||
private final String name;
|
||||
private final String size;
|
||||
private final String cost;
|
||||
private final boolean isHAtH;
|
||||
|
||||
public Archive(String res, String name, String size, String cost, boolean isHAtH) {
|
||||
this.res = res;
|
||||
this.name = name;
|
||||
this.size = size;
|
||||
this.cost = cost;
|
||||
this.isHAtH = isHAtH;
|
||||
}
|
||||
|
||||
public String format(IntFunction<String> getString) {
|
||||
if (isHAtH) {
|
||||
var costStr = cost.equals("Free") ? getString.apply(R.string.archive_free) : cost;
|
||||
return String.format("[H@H] %s [%s] [%s]", name, size, costStr);
|
||||
} else {
|
||||
var nameStr = getString.apply(res.equals("org") ? R.string.archive_original : R.string.archive_resample);
|
||||
var costStr = cost.equals("Free!") ? getString.apply(R.string.archive_free) : cost;
|
||||
return String.format("%s [%s] [%s]", nameStr, size, costStr);
|
||||
}
|
||||
}
|
||||
|
||||
public String res() {
|
||||
return res;
|
||||
}
|
||||
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public String cost() {
|
||||
return cost;
|
||||
}
|
||||
|
||||
public boolean isHAtH() {
|
||||
return isHAtH;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) return true;
|
||||
if (obj == null || obj.getClass() != this.getClass()) return false;
|
||||
var that = (Archive) obj;
|
||||
return Objects.equals(this.res, that.res) &&
|
||||
Objects.equals(this.name, that.name) &&
|
||||
Objects.equals(this.size, that.size) &&
|
||||
Objects.equals(this.cost, that.cost) &&
|
||||
this.isHAtH == that.isHAtH;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(res, name, size, cost, isHAtH);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Archive[" +
|
||||
"res=" + res + ", " +
|
||||
"name=" + name + ", " +
|
||||
"size=" + size + ", " +
|
||||
"cost=" + cost + ", " +
|
||||
"isHAtH=" + isHAtH + ']';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static final class Result {
|
||||
private final String paramOr;
|
||||
private final List<Archive> archiveList;
|
||||
|
||||
public Result(String paramOr, List<Archive> archiveList) {
|
||||
this.paramOr = paramOr;
|
||||
this.archiveList = archiveList;
|
||||
}
|
||||
|
||||
public String paramOr() {
|
||||
return paramOr;
|
||||
}
|
||||
|
||||
public List<Archive> archiveList() {
|
||||
return archiveList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) return true;
|
||||
if (obj == null || obj.getClass() != this.getClass()) return false;
|
||||
var that = (Result) obj;
|
||||
return Objects.equals(this.paramOr, that.paramOr) &&
|
||||
Objects.equals(this.archiveList, that.archiveList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(paramOr, archiveList);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Result[" +
|
||||
"paramOr=" + paramOr + ", " +
|
||||
"archiveList=" + archiveList + ']';
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -31,22 +31,17 @@ import org.jsoup.nodes.Element;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class FavoritesParser {
|
||||
private static final Pattern PATTERN_PREV_PAGE = Pattern.compile("prev=(\\d+(-\\d+)?)");
|
||||
private static final Pattern PATTERN_NEXT_PAGE = Pattern.compile("next=(\\d+(-\\d+)?)");
|
||||
|
||||
public static Result parse(String body) throws Exception {
|
||||
if (body.contains("This page requires you to log on.</p>")) {
|
||||
throw new EhException(GetText.getString(R.string.need_sign_in));
|
||||
}
|
||||
Document d = Jsoup.parse(body);
|
||||
|
||||
String[] catArray = new String[10];
|
||||
int[] countArray = new int[10];
|
||||
try {
|
||||
Document d = Jsoup.parse(body);
|
||||
Element ido = JsoupUtils.getElementByClass(d, "ido");
|
||||
//noinspection ConstantConditions
|
||||
Elements fps = ido.getElementsByClass("fp");
|
||||
@@ -64,24 +59,13 @@ public class FavoritesParser {
|
||||
throw new ParseException("Parse favorites error", body);
|
||||
}
|
||||
|
||||
Result re = new Result();
|
||||
try {
|
||||
Element prev = d.getElementById("uprev");
|
||||
Element next = d.getElementById("unext");
|
||||
assert prev != null;
|
||||
assert next != null;
|
||||
Matcher matcherPrev = PATTERN_PREV_PAGE.matcher(prev.attr("href"));
|
||||
Matcher matcherNext = PATTERN_NEXT_PAGE.matcher(next.attr("href"));
|
||||
if (matcherPrev.find()) re.prevPage = matcherPrev.group(1);
|
||||
if (matcherNext.find()) re.nextPage = matcherNext.group(1);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
GalleryListParser.Result result = GalleryListParser.parse(body);
|
||||
|
||||
Result re = new Result();
|
||||
re.catArray = catArray;
|
||||
re.countArray = countArray;
|
||||
re.prev = result.prev;
|
||||
re.next = result.next;
|
||||
re.galleryInfoList = result.galleryInfoList;
|
||||
|
||||
return re;
|
||||
@@ -90,8 +74,8 @@ public class FavoritesParser {
|
||||
public static class Result {
|
||||
public String[] catArray; // Size 10
|
||||
public int[] countArray; // Size 10
|
||||
public String prevPage;
|
||||
public String nextPage;
|
||||
public String prev;
|
||||
public String next;
|
||||
public List<GalleryInfo> galleryInfoList;
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,8 @@ package com.hippo.ehviewer.client.parser;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.hippo.ehviewer.EhDB;
|
||||
import com.hippo.ehviewer.client.EhFilter;
|
||||
import com.hippo.ehviewer.client.EhUtils;
|
||||
import com.hippo.ehviewer.client.data.GalleryComment;
|
||||
import com.hippo.ehviewer.client.data.GalleryCommentList;
|
||||
@@ -67,6 +69,7 @@ public class GalleryDetailParser {
|
||||
private static final Pattern PATTERN_NORMAL_PREVIEW = Pattern.compile("<div class=\"gdtm\"[^<>]*><div[^<>]*width:(\\d+)[^<>]*height:(\\d+)[^<>]*\\((.+?)\\)[^<>]*-(\\d+)px[^<>]*><a[^<>]*href=\"(.+?)\"[^<>]*><img alt=\"([\\d,]+)\"");
|
||||
private static final Pattern PATTERN_LARGE_PREVIEW = Pattern.compile("<div class=\"gdtl\".+?<a href=\"(.+?)\"><img alt=\"([\\d,]+)\".+?src=\"(.+?)\"");
|
||||
private static final Pattern PATTERN_NEWER_DATE = Pattern.compile(", added (.+?)<br />");
|
||||
private static final Pattern PATTERN_FAVORITE_SLOT = Pattern.compile("/fav.png\\); background-position:0px -(\\d+)px");
|
||||
|
||||
private static final GalleryTagGroup[] EMPTY_GALLERY_TAG_GROUP_ARRAY = new GalleryTagGroup[0];
|
||||
private static final GalleryCommentList EMPTY_GALLERY_COMMENT_ARRAY = new GalleryCommentList(new GalleryComment[0], false);
|
||||
@@ -78,6 +81,23 @@ public class GalleryDetailParser {
|
||||
private static final String PINING_STRING =
|
||||
"<p>This gallery is pining for the fjords.</p>";
|
||||
|
||||
private static final String[] LANGUAGES = {
|
||||
"English",
|
||||
"Chinese",
|
||||
"Spanish",
|
||||
"Korean",
|
||||
"Russian",
|
||||
"French",
|
||||
"Portuguese",
|
||||
"Thai",
|
||||
"German",
|
||||
"Italian",
|
||||
"Vietnamese",
|
||||
"Polish",
|
||||
"Hungarian",
|
||||
"Dutch",
|
||||
};
|
||||
|
||||
public static GalleryDetail parse(String body) throws EhException {
|
||||
if (body.contains(OFFENSIVE_STRING)) {
|
||||
throw new OffensiveException();
|
||||
@@ -100,6 +120,15 @@ public class GalleryDetailParser {
|
||||
galleryDetail.comments = parseComments(document);
|
||||
galleryDetail.previewPages = parsePreviewPages(document, body);
|
||||
galleryDetail.previewSet = parsePreviewSet(document, body);
|
||||
|
||||
// Generate simpleLanguage for local favorites
|
||||
for (int i = 0; i < LANGUAGES.length; i++) {
|
||||
if (galleryDetail.language.equals(LANGUAGES[i])) {
|
||||
galleryDetail.simpleLanguage = GalleryInfo.S_LANGS[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return galleryDetail;
|
||||
}
|
||||
|
||||
@@ -191,14 +220,9 @@ public class GalleryDetailParser {
|
||||
gd.size = "";
|
||||
gd.pages = 0;
|
||||
gd.favoriteCount = 0;
|
||||
try {
|
||||
Elements es = gdd.child(0).child(0).children();
|
||||
for (int i = 0, n = es.size(); i < n; i++) {
|
||||
parseDetailInfo(gd, es.get(i));
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
ExceptionUtils.throwIfFatal(e);
|
||||
// Ignore
|
||||
Elements es = gdd.child(0).child(0).children();
|
||||
for (int i = 0, n = es.size(); i < n; i++) {
|
||||
parseDetailInfo(gd, es.get(i));
|
||||
}
|
||||
|
||||
// Rating count
|
||||
@@ -230,15 +254,24 @@ public class GalleryDetailParser {
|
||||
|
||||
// isFavorited
|
||||
Element gdf = gm.getElementById("gdf");
|
||||
gd.isFavorited = null != gdf && !StringUtils.trim(gdf.text()).equals("Add to Favorites");
|
||||
gd.isFavorited = false;
|
||||
if (gdf != null) {
|
||||
final String favoriteName = StringUtils.trim(gdf.text());
|
||||
if (favoriteName.equals("Add to Favorites")) {
|
||||
gd.favoriteName = null;
|
||||
} else {
|
||||
gd.isFavorited = true;
|
||||
gd.favoriteName = StringUtils.trim(gdf.text());
|
||||
|
||||
matcher = PATTERN_FAVORITE_SLOT.matcher(body);
|
||||
if (matcher.find()) {
|
||||
gd.favoriteSlot = (NumberUtils.parseIntSafely(matcher.group(1), 2) - 2) / 19;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (gd.favoriteSlot == -2 && EhDB.containLocalFavorites(gd.gid)) {
|
||||
gd.favoriteSlot = -1;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
ExceptionUtils.throwIfFatal(e);
|
||||
throw new ParseException("Can't parse gallery detail", body);
|
||||
@@ -441,6 +474,13 @@ public class GalleryDetailParser {
|
||||
comment.user = c3.child(0).text();
|
||||
// comment
|
||||
comment.comment = JsoupUtils.getElementByClass(element, "c6").html();
|
||||
// filter comment
|
||||
if (!comment.uploader) {
|
||||
EhFilter sEhFilter = EhFilter.getInstance();
|
||||
if (!sEhFilter.filterCommenter(comment.user) || !sEhFilter.filterComment(comment.comment)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// last edited
|
||||
Element c8 = JsoupUtils.getElementByClass(element, "c8");
|
||||
if (c8 != null) {
|
||||
|
||||
@@ -50,8 +50,9 @@ public class GalleryListParser {
|
||||
private static final Pattern PATTERN_THUMB_SIZE = Pattern.compile("height:(\\d+)px;width:(\\d+)px");
|
||||
private static final Pattern PATTERN_FAVORITE_SLOT = Pattern.compile("background-color:rgba\\((\\d+),(\\d+),(\\d+),");
|
||||
private static final Pattern PATTERN_PAGES = Pattern.compile("(\\d+) page");
|
||||
private static final Pattern PATTERN_PREV_PAGE = Pattern.compile("prev=(\\d+)");
|
||||
private static final Pattern PATTERN_NEXT_PAGE = Pattern.compile("next=(\\d+)");
|
||||
private static final Pattern PATTERN_NEXT_PAGE = Pattern.compile("p=(\\d+)");
|
||||
private static final Pattern PATTERN_PREV = Pattern.compile("prev=(\\d+(-\\d+)?)");
|
||||
private static final Pattern PATTERN_NEXT = Pattern.compile("next=(\\d+(-\\d+)?)");
|
||||
|
||||
private static final String[][] FAVORITE_SLOT_RGB = new String[][]{
|
||||
new String[]{"0", "0", "0"},
|
||||
@@ -256,11 +257,7 @@ public class GalleryListParser {
|
||||
if (div != null) {
|
||||
gi.disowned = div.attr("style").contains("opacity:0.5");
|
||||
Element a = div.children().first();
|
||||
if (a != null) {
|
||||
gi.uploader = a.text().trim();
|
||||
} else {
|
||||
gi.uploader = div.text().trim();
|
||||
}
|
||||
gi.uploader = a == null ? div.text().trim() : a.text().trim();
|
||||
}
|
||||
}
|
||||
if (children.size() > pagesIndex) {
|
||||
@@ -296,28 +293,44 @@ public class GalleryListParser {
|
||||
Element next = d.getElementById("unext");
|
||||
assert prev != null;
|
||||
assert next != null;
|
||||
Matcher matcherPrev = PATTERN_PREV_PAGE.matcher(prev.attr("href"));
|
||||
Matcher matcherNext = PATTERN_NEXT_PAGE.matcher(next.attr("href"));
|
||||
Matcher matcherPrev = PATTERN_PREV.matcher(prev.attr("href"));
|
||||
Matcher matcherNext = PATTERN_NEXT.matcher(next.attr("href"));
|
||||
if (matcherPrev.find())
|
||||
result.prevGid = NumberUtils.parseIntSafely(matcherPrev.group(1), 0);
|
||||
result.prev = matcherPrev.group(1);
|
||||
if (matcherNext.find())
|
||||
result.nextGid = NumberUtils.parseIntSafely(matcherNext.group(1), 0);
|
||||
result.founds = Integer.MAX_VALUE;
|
||||
result.next = matcherNext.group(1);
|
||||
} catch (Throwable e) {
|
||||
ExceptionUtils.throwIfFatal(e);
|
||||
result.noWatchedTags = body.contains("<p>You do not have any watched tags");
|
||||
if (body.contains("No hits found</p>")) {
|
||||
result.founds = 0;
|
||||
//noinspection unchecked
|
||||
result.galleryInfoList = Collections.EMPTY_LIST;
|
||||
return result;
|
||||
} else if (d.getElementsByClass("ptt").isEmpty()) {
|
||||
result.founds = 1;
|
||||
} else {
|
||||
result.founds = Integer.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
try { // For toplists
|
||||
Element ptt = d.getElementsByClass("ptt").first();
|
||||
if (ptt != null) {
|
||||
Elements es = ptt.child(0).child(0).children();
|
||||
result.pages = Integer.parseInt(es.get(es.size() - 2).text().trim());
|
||||
|
||||
Element e = es.get(es.size() - 1);
|
||||
if (e != null) {
|
||||
e = e.children().first();
|
||||
if (e != null) {
|
||||
String href = e.attr("href");
|
||||
Matcher matcher = PATTERN_NEXT_PAGE.matcher(href);
|
||||
if (matcher.find()) {
|
||||
result.nextPage = NumberUtils.parseIntSafely(matcher.group(1), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
try {
|
||||
Element itg = d.getElementsByClass("itg").first();
|
||||
Elements es;
|
||||
@@ -350,9 +363,10 @@ public class GalleryListParser {
|
||||
}
|
||||
|
||||
public static class Result {
|
||||
public int founds;
|
||||
public int prevGid;
|
||||
public int nextGid;
|
||||
public int pages;
|
||||
public int nextPage;
|
||||
public String prev;
|
||||
public String next;
|
||||
public boolean noWatchedTags;
|
||||
public List<GalleryInfo> galleryInfoList;
|
||||
}
|
||||
|
||||
@@ -16,27 +16,132 @@
|
||||
|
||||
package com.hippo.ehviewer.client.parser;
|
||||
|
||||
import android.util.Pair;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.jsoup.Jsoup;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.IntFunction;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class TorrentParser {
|
||||
|
||||
private static final Pattern PATTERN_TORRENT = Pattern.compile("<td colspan=\"5\"> <a href=\".*\" onclick=\"document.location='([^\"]+)'[^<]+>([^<]+)</a></td>");
|
||||
private static final Pattern PATTERN_TORRENT = Pattern.compile("</span> ([0-9-]+) [0-9:]+</td>[\\s\\S]+</span> ([0-9\\.]+ [KMGT]B)</td>[\\s\\S]+</span> ([0-9]+)</td>[\\s\\S]+</span> ([0-9]+)</td>[\\s\\S]+</span> ([0-9]+)</td>[\\s\\S]+</span>([^<]+)</td>[\\s\\S]+onclick=\"document.location='([^\"]+)'[^<]+>([^<]+)</a>");
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Pair<String, String>[] parse(String body) {
|
||||
List<Pair<String, String>> torrentList = new ArrayList<>();
|
||||
Matcher m = PATTERN_TORRENT.matcher(body);
|
||||
while (m.find()) {
|
||||
String url = ParserUtils.trim(m.group(1));
|
||||
String name = ParserUtils.trim(m.group(2));
|
||||
Pair<String, String> item = new Pair<>(url, name);
|
||||
torrentList.add(item);
|
||||
public static List<Result> parse(String body) {
|
||||
var torrentList = new ArrayList<Result>();
|
||||
var d = Jsoup.parse(body);
|
||||
var es = d.select("form>div>table");
|
||||
for (var e : es) {
|
||||
Matcher m = PATTERN_TORRENT.matcher(e.html());
|
||||
if (m.find()) {
|
||||
String posted = m.group(1);
|
||||
String size = m.group(2);
|
||||
int seeds = Integer.parseInt(m.group(3));
|
||||
int peers = Integer.parseInt(m.group(4));
|
||||
int downloads = Integer.parseInt(m.group(5));
|
||||
String uploader = ParserUtils.trim(m.group(6));
|
||||
String url = ParserUtils.trim(m.group(7));
|
||||
String name = ParserUtils.trim(m.group(8));
|
||||
var item = new Result(posted, size, seeds, peers, downloads, uploader, url, name);
|
||||
torrentList.add(item);
|
||||
}
|
||||
}
|
||||
return torrentList;
|
||||
}
|
||||
|
||||
public static final class Result {
|
||||
private final String posted;
|
||||
private final String size;
|
||||
private final int seeds;
|
||||
private final int peers;
|
||||
private final int downloads;
|
||||
private final String uploader;
|
||||
private final String url;
|
||||
private final String name;
|
||||
|
||||
public Result(String posted, String size, int seeds, int peers, int downloads, String uploader, String url, String name) {
|
||||
this.posted = posted;
|
||||
this.size = size;
|
||||
this.seeds = seeds;
|
||||
this.peers = peers;
|
||||
this.downloads = downloads;
|
||||
this.uploader = uploader;
|
||||
this.url = url;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String format(IntFunction<String> getString) {
|
||||
return String.format("[%s] %s [%s] [↑%s ↓%s ✓%s]", posted, name, size, seeds, peers, downloads);
|
||||
}
|
||||
|
||||
public String posted() {
|
||||
return posted;
|
||||
}
|
||||
|
||||
public String size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public int seeds() {
|
||||
return seeds;
|
||||
}
|
||||
|
||||
public int peers() {
|
||||
return peers;
|
||||
}
|
||||
|
||||
public int downloads() {
|
||||
return downloads;
|
||||
}
|
||||
|
||||
public String uploader() {
|
||||
return uploader;
|
||||
}
|
||||
|
||||
public String url() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) return true;
|
||||
if (obj == null || obj.getClass() != this.getClass()) return false;
|
||||
var that = (Result) obj;
|
||||
return Objects.equals(this.posted, that.posted) &&
|
||||
Objects.equals(this.size, that.size) &&
|
||||
this.seeds == that.seeds &&
|
||||
this.peers == that.peers &&
|
||||
this.downloads == that.downloads &&
|
||||
Objects.equals(this.uploader, that.uploader) &&
|
||||
Objects.equals(this.url, that.url) &&
|
||||
Objects.equals(this.name, that.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(posted, size, seeds, peers, downloads, uploader, url, name);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Result[" +
|
||||
"posted=" + posted + ", " +
|
||||
"size=" + size + ", " +
|
||||
"seeds=" + seeds + ", " +
|
||||
"peers=" + peers + ", " +
|
||||
"downloads=" + downloads + ", " +
|
||||
"uploader=" + uploader + ", " +
|
||||
"url=" + url + ", " +
|
||||
"name=" + name + ']';
|
||||
}
|
||||
return torrentList.toArray(new Pair[0]);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package com.hippo.ehviewer.dao;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface BasicDao<T> {
|
||||
List<T> list();
|
||||
|
||||
long insert(T t);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.hippo.ehviewer.dao
|
||||
|
||||
interface BasicDao<T> {
|
||||
fun list(): List<T>
|
||||
fun insert(t: T): Long
|
||||
}
|
||||
@@ -1,160 +0,0 @@
|
||||
package com.hippo.ehviewer.dao;
|
||||
|
||||
import android.os.Parcel;
|
||||
|
||||
import androidx.room.ColumnInfo;
|
||||
import androidx.room.Entity;
|
||||
|
||||
import com.hippo.ehviewer.client.data.GalleryInfo;
|
||||
|
||||
@Entity(tableName = "BOOKMARKS")
|
||||
public class BookmarkInfo extends GalleryInfo {
|
||||
public static final Creator<BookmarkInfo> CREATOR = new Creator<>() {
|
||||
@Override
|
||||
public BookmarkInfo createFromParcel(Parcel source) {
|
||||
return new BookmarkInfo(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BookmarkInfo[] newArray(int size) {
|
||||
return new BookmarkInfo[size];
|
||||
}
|
||||
};
|
||||
@ColumnInfo(name = "PAGE")
|
||||
public int page;
|
||||
@ColumnInfo(name = "TIME")
|
||||
public long time;
|
||||
|
||||
protected BookmarkInfo(Parcel in) {
|
||||
super(in);
|
||||
this.page = in.readInt();
|
||||
this.time = in.readLong();
|
||||
}
|
||||
|
||||
public BookmarkInfo(GalleryInfo galleryInfo) {
|
||||
this.gid = galleryInfo.gid;
|
||||
this.token = galleryInfo.token;
|
||||
this.title = galleryInfo.title;
|
||||
this.titleJpn = galleryInfo.titleJpn;
|
||||
this.thumb = galleryInfo.thumb;
|
||||
this.category = galleryInfo.category;
|
||||
this.posted = galleryInfo.posted;
|
||||
this.uploader = galleryInfo.uploader;
|
||||
this.rating = galleryInfo.rating;
|
||||
this.simpleTags = galleryInfo.simpleTags;
|
||||
this.simpleLanguage = galleryInfo.simpleLanguage;
|
||||
}
|
||||
|
||||
public BookmarkInfo(int page, long time) {
|
||||
this.page = page;
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
public long getGid() {
|
||||
return gid;
|
||||
}
|
||||
|
||||
public void setGid(long gid) {
|
||||
this.gid = gid;
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public void setToken(String token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getTitleJpn() {
|
||||
return titleJpn;
|
||||
}
|
||||
|
||||
public void setTitleJpn(String titleJpn) {
|
||||
this.titleJpn = titleJpn;
|
||||
}
|
||||
|
||||
public String getThumb() {
|
||||
return thumb;
|
||||
}
|
||||
|
||||
public void setThumb(String thumb) {
|
||||
this.thumb = thumb;
|
||||
}
|
||||
|
||||
public int getCategory() {
|
||||
return category;
|
||||
}
|
||||
|
||||
public void setCategory(int category) {
|
||||
this.category = category;
|
||||
}
|
||||
|
||||
public String getPosted() {
|
||||
return posted;
|
||||
}
|
||||
|
||||
public void setPosted(String posted) {
|
||||
this.posted = posted;
|
||||
}
|
||||
|
||||
public String getUploader() {
|
||||
return uploader;
|
||||
}
|
||||
|
||||
public void setUploader(String uploader) {
|
||||
this.uploader = uploader;
|
||||
}
|
||||
|
||||
public float getRating() {
|
||||
return rating;
|
||||
}
|
||||
|
||||
public void setRating(float rating) {
|
||||
this.rating = rating;
|
||||
}
|
||||
|
||||
public String getSimpleLanguage() {
|
||||
return simpleLanguage;
|
||||
}
|
||||
|
||||
public void setSimpleLanguage(String simpleLanguage) {
|
||||
this.simpleLanguage = simpleLanguage;
|
||||
}
|
||||
|
||||
public int getPage() {
|
||||
return page;
|
||||
}
|
||||
|
||||
public void setPage(int page) {
|
||||
this.page = page;
|
||||
}
|
||||
|
||||
public long getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
public void setTime(long time) {
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeInt(this.page);
|
||||
dest.writeLong(this.time);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.hippo.ehviewer.dao
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import com.hippo.ehviewer.client.data.GalleryInfo
|
||||
|
||||
@Entity(tableName = "BOOKMARKS")
|
||||
class BookmarkInfo : GalleryInfo() {
|
||||
@JvmField
|
||||
@ColumnInfo(name = "PAGE")
|
||||
var page = 0
|
||||
|
||||
@JvmField
|
||||
@ColumnInfo(name = "TIME")
|
||||
var time: Long = 0
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package com.hippo.ehviewer.dao;
|
||||
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Delete;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.Query;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Dao
|
||||
public interface BookmarksDao extends BasicDao<BookmarkInfo> {
|
||||
@Insert
|
||||
long insert(BookmarkInfo bookmark);
|
||||
|
||||
@Delete
|
||||
void delete(BookmarkInfo bookmark);
|
||||
|
||||
@Query("SELECT * FROM BOOKMARKS ORDER BY TIME DESC")
|
||||
List<BookmarkInfo> list();
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.hippo.ehviewer.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
|
||||
@Dao
|
||||
interface BookmarksDao : BasicDao<BookmarkInfo> {
|
||||
@Insert
|
||||
override fun insert(t: BookmarkInfo): Long
|
||||
|
||||
@Delete
|
||||
fun delete(bookmark: BookmarkInfo)
|
||||
|
||||
@Query("SELECT * FROM BOOKMARKS ORDER BY TIME DESC")
|
||||
override fun list(): List<BookmarkInfo>
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package com.hippo.ehviewer.dao;
|
||||
|
||||
import androidx.room.ColumnInfo;
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.PrimaryKey;
|
||||
|
||||
@Entity(tableName = "DOWNLOAD_DIRNAME")
|
||||
public class DownloadDirname {
|
||||
@PrimaryKey
|
||||
@ColumnInfo(name = "GID")
|
||||
private long gid;
|
||||
@ColumnInfo(name = "DIRNAME")
|
||||
private String dirname;
|
||||
|
||||
public long getGid() {
|
||||
return gid;
|
||||
}
|
||||
|
||||
public void setGid(long gid) {
|
||||
this.gid = gid;
|
||||
}
|
||||
|
||||
public String getDirname() {
|
||||
return dirname;
|
||||
}
|
||||
|
||||
public void setDirname(String dirname) {
|
||||
this.dirname = dirname;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.hippo.ehviewer.dao
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "DOWNLOAD_DIRNAME")
|
||||
data class DownloadDirname(
|
||||
@PrimaryKey
|
||||
@ColumnInfo(name = "GID")
|
||||
var gid: Long = 0,
|
||||
|
||||
@ColumnInfo(name = "DIRNAME")
|
||||
var dirname: String? = null
|
||||
)
|
||||
@@ -1,29 +0,0 @@
|
||||
package com.hippo.ehviewer.dao;
|
||||
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.Query;
|
||||
import androidx.room.Update;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Dao
|
||||
public interface DownloadDirnameDao extends BasicDao<DownloadDirname> {
|
||||
@Query("SELECT * FROM DOWNLOAD_DIRNAME WHERE GID = :gid")
|
||||
DownloadDirname load(long gid);
|
||||
|
||||
@Update
|
||||
void update(DownloadDirname downloadDirname);
|
||||
|
||||
@Insert
|
||||
long insert(DownloadDirname downloadDirname);
|
||||
|
||||
@Query("DELETE FROM DOWNLOAD_DIRNAME WHERE GID = :gid")
|
||||
void deleteByKey(long gid);
|
||||
|
||||
@Query("DELETE FROM DOWNLOAD_DIRNAME")
|
||||
void deleteAll();
|
||||
|
||||
@Query("SELECT * FROM DOWNLOAD_DIRNAME")
|
||||
List<DownloadDirname> list();
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.hippo.ehviewer.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import androidx.room.Update
|
||||
|
||||
@Dao
|
||||
interface DownloadDirnameDao : BasicDao<DownloadDirname> {
|
||||
@Query("SELECT * FROM DOWNLOAD_DIRNAME WHERE GID = :gid")
|
||||
fun load(gid: Long): DownloadDirname?
|
||||
|
||||
@Update
|
||||
fun update(downloadDirname: DownloadDirname)
|
||||
|
||||
@Insert
|
||||
override fun insert(t: DownloadDirname): Long
|
||||
|
||||
@Query("DELETE FROM DOWNLOAD_DIRNAME WHERE GID = :gid")
|
||||
fun deleteByKey(gid: Long)
|
||||
|
||||
@Query("DELETE FROM DOWNLOAD_DIRNAME")
|
||||
fun deleteAll()
|
||||
|
||||
@Query("SELECT * FROM DOWNLOAD_DIRNAME")
|
||||
override fun list(): List<DownloadDirname>
|
||||
}
|
||||
@@ -1,252 +0,0 @@
|
||||
package com.hippo.ehviewer.dao;
|
||||
|
||||
import android.os.Parcel;
|
||||
|
||||
import androidx.room.ColumnInfo;
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.Ignore;
|
||||
|
||||
import com.hippo.ehviewer.client.data.GalleryInfo;
|
||||
|
||||
@Entity(tableName = "DOWNLOADS")
|
||||
public class DownloadInfo extends GalleryInfo {
|
||||
public static final Creator<DownloadInfo> CREATOR = new Creator<>() {
|
||||
@Override
|
||||
public DownloadInfo createFromParcel(Parcel source) {
|
||||
return new DownloadInfo(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DownloadInfo[] newArray(int size) {
|
||||
return new DownloadInfo[size];
|
||||
}
|
||||
};
|
||||
public static final int STATE_INVALID = -1;
|
||||
public static final int STATE_NONE = 0;
|
||||
public static final int STATE_WAIT = 1;
|
||||
public static final int STATE_DOWNLOAD = 2;
|
||||
public static final int STATE_FINISH = 3;
|
||||
public static final int STATE_FAILED = 4;
|
||||
@ColumnInfo(name = "STATE")
|
||||
public int state;
|
||||
@ColumnInfo(name = "LEGACY")
|
||||
public int legacy;
|
||||
@ColumnInfo(name = "TIME")
|
||||
public long time;
|
||||
@ColumnInfo(name = "LABEL")
|
||||
public String label;
|
||||
@Ignore
|
||||
public long speed;
|
||||
@Ignore
|
||||
public long remaining;
|
||||
@Ignore
|
||||
public int finished;
|
||||
@Ignore
|
||||
public int downloaded;
|
||||
@Ignore
|
||||
public int total;
|
||||
|
||||
DownloadInfo() {
|
||||
}
|
||||
|
||||
protected DownloadInfo(Parcel in) {
|
||||
super(in);
|
||||
this.state = in.readInt();
|
||||
this.legacy = in.readInt();
|
||||
this.time = in.readLong();
|
||||
this.label = in.readString();
|
||||
}
|
||||
|
||||
public DownloadInfo(GalleryInfo galleryInfo) {
|
||||
this.gid = galleryInfo.gid;
|
||||
this.token = galleryInfo.token;
|
||||
this.title = galleryInfo.title;
|
||||
this.titleJpn = galleryInfo.titleJpn;
|
||||
this.thumb = galleryInfo.thumb;
|
||||
this.category = galleryInfo.category;
|
||||
this.posted = galleryInfo.posted;
|
||||
this.uploader = galleryInfo.uploader;
|
||||
this.rating = galleryInfo.rating;
|
||||
this.simpleTags = galleryInfo.simpleTags;
|
||||
this.simpleLanguage = galleryInfo.simpleLanguage;
|
||||
}
|
||||
|
||||
public DownloadInfo(int state, int legacy, long time, String label, long speed, long remaining,
|
||||
int finished, int downloaded, int total) {
|
||||
this.state = state;
|
||||
this.legacy = legacy;
|
||||
this.time = time;
|
||||
this.label = label;
|
||||
this.speed = speed;
|
||||
this.remaining = remaining;
|
||||
this.finished = finished;
|
||||
this.downloaded = downloaded;
|
||||
this.total = total;
|
||||
}
|
||||
|
||||
public long getGid() {
|
||||
return gid;
|
||||
}
|
||||
|
||||
public void setGid(long gid) {
|
||||
this.gid = gid;
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public void setToken(String token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getTitleJpn() {
|
||||
return titleJpn;
|
||||
}
|
||||
|
||||
public void setTitleJpn(String titleJpn) {
|
||||
this.titleJpn = titleJpn;
|
||||
}
|
||||
|
||||
public String getThumb() {
|
||||
return thumb;
|
||||
}
|
||||
|
||||
public void setThumb(String thumb) {
|
||||
this.thumb = thumb;
|
||||
}
|
||||
|
||||
public int getCategory() {
|
||||
return category;
|
||||
}
|
||||
|
||||
public void setCategory(int category) {
|
||||
this.category = category;
|
||||
}
|
||||
|
||||
public String getPosted() {
|
||||
return posted;
|
||||
}
|
||||
|
||||
public void setPosted(String posted) {
|
||||
this.posted = posted;
|
||||
}
|
||||
|
||||
public String getUploader() {
|
||||
return uploader;
|
||||
}
|
||||
|
||||
public void setUploader(String uploader) {
|
||||
this.uploader = uploader;
|
||||
}
|
||||
|
||||
public float getRating() {
|
||||
return rating;
|
||||
}
|
||||
|
||||
public void setRating(float rating) {
|
||||
this.rating = rating;
|
||||
}
|
||||
|
||||
public String getSimpleLanguage() {
|
||||
return simpleLanguage;
|
||||
}
|
||||
|
||||
public void setSimpleLanguage(String simpleLanguage) {
|
||||
this.simpleLanguage = simpleLanguage;
|
||||
}
|
||||
|
||||
public int getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(int state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public int getLegacy() {
|
||||
return legacy;
|
||||
}
|
||||
|
||||
public void setLegacy(int legacy) {
|
||||
this.legacy = legacy;
|
||||
}
|
||||
|
||||
public long getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
public void setTime(long time) {
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public void setLabel(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeInt(this.state);
|
||||
dest.writeInt(this.legacy);
|
||||
dest.writeLong(this.time);
|
||||
dest.writeString(this.label);
|
||||
}
|
||||
|
||||
public long getSpeed() {
|
||||
return this.speed;
|
||||
}
|
||||
|
||||
public void setSpeed(long speed) {
|
||||
this.speed = speed;
|
||||
}
|
||||
|
||||
public long getRemaining() {
|
||||
return this.remaining;
|
||||
}
|
||||
|
||||
public void setRemaining(long remaining) {
|
||||
this.remaining = remaining;
|
||||
}
|
||||
|
||||
public int getFinished() {
|
||||
return this.finished;
|
||||
}
|
||||
|
||||
public void setFinished(int finished) {
|
||||
this.finished = finished;
|
||||
}
|
||||
|
||||
public int getDownloaded() {
|
||||
return this.downloaded;
|
||||
}
|
||||
|
||||
public void setDownloaded(int downloaded) {
|
||||
this.downloaded = downloaded;
|
||||
}
|
||||
|
||||
public int getTotal() {
|
||||
return this.total;
|
||||
}
|
||||
|
||||
public void setTotal(int total) {
|
||||
this.total = total;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.hippo.ehviewer.dao
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.Ignore
|
||||
import com.hippo.ehviewer.client.data.GalleryInfo
|
||||
|
||||
@Entity(tableName = "DOWNLOADS")
|
||||
class DownloadInfo() : GalleryInfo() {
|
||||
@JvmField
|
||||
@ColumnInfo(name = "STATE")
|
||||
var state = 0
|
||||
|
||||
@JvmField
|
||||
@ColumnInfo(name = "LEGACY")
|
||||
var legacy = 0
|
||||
|
||||
@JvmField
|
||||
@ColumnInfo(name = "TIME")
|
||||
var time: Long = 0
|
||||
|
||||
@JvmField
|
||||
@ColumnInfo(name = "LABEL")
|
||||
var label: String? = null
|
||||
|
||||
@JvmField
|
||||
@Ignore
|
||||
var speed: Long = 0
|
||||
|
||||
@JvmField
|
||||
@Ignore
|
||||
var remaining: Long = 0
|
||||
|
||||
@JvmField
|
||||
@Ignore
|
||||
var finished = 0
|
||||
|
||||
@JvmField
|
||||
@Ignore
|
||||
var downloaded = 0
|
||||
|
||||
@JvmField
|
||||
@Ignore
|
||||
var total = 0
|
||||
|
||||
constructor(galleryInfo: GalleryInfo) : this() {
|
||||
gid = galleryInfo.gid
|
||||
token = galleryInfo.token
|
||||
title = galleryInfo.title
|
||||
titleJpn = galleryInfo.titleJpn
|
||||
thumb = galleryInfo.thumb
|
||||
this.category = galleryInfo.category
|
||||
posted = galleryInfo.posted
|
||||
uploader = galleryInfo.uploader
|
||||
rating = galleryInfo.rating
|
||||
simpleTags = galleryInfo.simpleTags
|
||||
simpleLanguage = galleryInfo.simpleLanguage
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val STATE_INVALID = -1
|
||||
const val STATE_NONE = 0
|
||||
const val STATE_WAIT = 1
|
||||
const val STATE_DOWNLOAD = 2
|
||||
const val STATE_FINISH = 3
|
||||
const val STATE_FAILED = 4
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package com.hippo.ehviewer.dao;
|
||||
|
||||
import androidx.room.ColumnInfo;
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.PrimaryKey;
|
||||
|
||||
@Entity(tableName = "DOWNLOAD_LABELS")
|
||||
public class DownloadLabel {
|
||||
@PrimaryKey
|
||||
@ColumnInfo(name = "_id")
|
||||
private Long id;
|
||||
@ColumnInfo(name = "LABEL")
|
||||
private String label;
|
||||
@ColumnInfo(name = "TIME")
|
||||
private long time;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public void setLabel(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public long getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
public void setTime(long time) {
|
||||
this.time = time;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.hippo.ehviewer.dao
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "DOWNLOAD_LABELS")
|
||||
data class DownloadLabel(
|
||||
@PrimaryKey
|
||||
@ColumnInfo(name = "_id")
|
||||
var id: Long? = null,
|
||||
|
||||
@ColumnInfo(name = "LABEL")
|
||||
var label: String? = null,
|
||||
|
||||
@ColumnInfo(name = "TIME")
|
||||
var time: Long = 0
|
||||
)
|
||||
@@ -1,30 +0,0 @@
|
||||
package com.hippo.ehviewer.dao;
|
||||
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Delete;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.Query;
|
||||
import androidx.room.Update;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Dao
|
||||
public interface DownloadLabelDao extends BasicDao<DownloadLabel> {
|
||||
@Query("SELECT * FROM DOWNLOAD_LABELS ORDER BY TIME ASC")
|
||||
List<DownloadLabel> list();
|
||||
|
||||
@Query("SELECT * FROM DOWNLOAD_LABELS ORDER BY TIME ASC LIMIT :limit OFFSET :offset")
|
||||
List<DownloadLabel> list(int offset, int limit);
|
||||
|
||||
@Update
|
||||
void update(List<DownloadLabel> downloadLabels);
|
||||
|
||||
@Update
|
||||
void update(DownloadLabel downloadLabel);
|
||||
|
||||
@Insert
|
||||
long insert(DownloadLabel downloadLabel);
|
||||
|
||||
@Delete
|
||||
void delete(DownloadLabel downloadLabel);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.hippo.ehviewer.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import androidx.room.Update
|
||||
|
||||
@Dao
|
||||
interface DownloadLabelDao : BasicDao<DownloadLabel> {
|
||||
@Query("SELECT * FROM DOWNLOAD_LABELS ORDER BY TIME ASC")
|
||||
override fun list(): List<DownloadLabel>
|
||||
|
||||
@Query("SELECT * FROM DOWNLOAD_LABELS ORDER BY TIME ASC LIMIT :limit OFFSET :offset")
|
||||
fun list(offset: Int, limit: Int): List<DownloadLabel>
|
||||
|
||||
@Update
|
||||
fun update(downloadLabels: List<DownloadLabel>)
|
||||
|
||||
@Update
|
||||
fun update(downloadLabel: DownloadLabel)
|
||||
|
||||
@Insert
|
||||
override fun insert(t: DownloadLabel): Long
|
||||
|
||||
@Delete
|
||||
fun delete(downloadLabel: DownloadLabel)
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package com.hippo.ehviewer.dao;
|
||||
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Delete;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.Query;
|
||||
import androidx.room.Update;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Dao
|
||||
public interface DownloadsDao extends BasicDao<DownloadInfo> {
|
||||
@Query("SELECT * FROM DOWNLOADS ORDER BY TIME DESC")
|
||||
List<DownloadInfo> list();
|
||||
|
||||
@Query("SELECT * FROM DOWNLOADS WHERE GID = :gid")
|
||||
DownloadInfo load(long gid);
|
||||
|
||||
@Update
|
||||
void update(DownloadInfo downloadInfo);
|
||||
|
||||
@Insert
|
||||
long insert(DownloadInfo downloadInfo);
|
||||
|
||||
@Delete
|
||||
void delete(DownloadInfo downloadInfo);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.hippo.ehviewer.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import androidx.room.Update
|
||||
|
||||
@Dao
|
||||
interface DownloadsDao : BasicDao<DownloadInfo> {
|
||||
@Query("SELECT * FROM DOWNLOADS ORDER BY TIME DESC")
|
||||
override fun list(): List<DownloadInfo>
|
||||
|
||||
@Query("SELECT * FROM DOWNLOADS WHERE GID = :gid")
|
||||
fun load(gid: Long): DownloadInfo?
|
||||
|
||||
@Update
|
||||
fun update(downloadInfo: DownloadInfo)
|
||||
|
||||
@Insert
|
||||
override fun insert(downloadInfo: DownloadInfo): Long
|
||||
|
||||
@Delete
|
||||
fun delete(downloadInfo: DownloadInfo)
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package com.hippo.ehviewer.dao;
|
||||
|
||||
import androidx.room.Database;
|
||||
import androidx.room.RoomDatabase;
|
||||
|
||||
@Database(entities = {BookmarkInfo.class, DownloadInfo.class, DownloadLabel.class, DownloadDirname.class, Filter.class, HistoryInfo.class, LocalFavoriteInfo.class, QuickSearch.class}, version = 4, exportSchema = false)
|
||||
public abstract class EhDatabase extends RoomDatabase {
|
||||
public abstract BookmarksDao bookmarksBao();
|
||||
|
||||
public abstract DownloadDirnameDao downloadDirnameDao();
|
||||
|
||||
public abstract DownloadLabelDao downloadLabelDao();
|
||||
|
||||
public abstract DownloadsDao downloadsDao();
|
||||
|
||||
public abstract FilterDao filterDao();
|
||||
|
||||
public abstract HistoryDao historyDao();
|
||||
|
||||
public abstract LocalFavoritesDao localFavoritesDao();
|
||||
|
||||
public abstract QuickSearchDao quickSearchDao();
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.hippo.ehviewer.dao
|
||||
|
||||
import androidx.room.Database
|
||||
import androidx.room.RoomDatabase
|
||||
|
||||
@Database(
|
||||
entities = [BookmarkInfo::class, DownloadInfo::class, DownloadLabel::class, DownloadDirname::class, Filter::class, HistoryInfo::class, LocalFavoriteInfo::class, QuickSearch::class],
|
||||
version = 4,
|
||||
exportSchema = false
|
||||
)
|
||||
abstract class EhDatabase : RoomDatabase() {
|
||||
abstract fun bookmarksBao(): BookmarksDao
|
||||
abstract fun downloadDirnameDao(): DownloadDirnameDao
|
||||
abstract fun downloadLabelDao(): DownloadLabelDao
|
||||
abstract fun downloadsDao(): DownloadsDao
|
||||
abstract fun filterDao(): FilterDao
|
||||
abstract fun historyDao(): HistoryDao
|
||||
abstract fun localFavoritesDao(): LocalFavoritesDao
|
||||
abstract fun quickSearchDao(): QuickSearchDao
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
package com.hippo.ehviewer.dao;
|
||||
|
||||
import androidx.room.ColumnInfo;
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.PrimaryKey;
|
||||
|
||||
import com.hippo.util.HashCodeUtils;
|
||||
import com.hippo.yorozuya.ObjectUtils;
|
||||
|
||||
@Entity(tableName = "FILTER")
|
||||
public class Filter {
|
||||
@ColumnInfo(name = "MODE")
|
||||
public int mode;
|
||||
@ColumnInfo(name = "TEXT")
|
||||
public String text;
|
||||
@ColumnInfo(name = "ENABLE")
|
||||
public Boolean enable;
|
||||
@PrimaryKey
|
||||
@ColumnInfo(name = "_id")
|
||||
private Long id;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public int getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
public void setMode(int mode) {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public Boolean getEnable() {
|
||||
return enable;
|
||||
}
|
||||
|
||||
public void setEnable(Boolean enable) {
|
||||
this.enable = enable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return HashCodeUtils.hashCode(mode, text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof Filter filter)) {
|
||||
return false;
|
||||
}
|
||||
return filter.mode == mode && ObjectUtils.equal(filter.text, text);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.hippo.ehviewer.dao
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "FILTER")
|
||||
data class Filter(
|
||||
@JvmField
|
||||
@ColumnInfo(name = "MODE")
|
||||
var mode: Int = 0,
|
||||
|
||||
@JvmField
|
||||
@ColumnInfo(name = "TEXT")
|
||||
var text: String? = null,
|
||||
|
||||
@JvmField
|
||||
@ColumnInfo(name = "ENABLE")
|
||||
var enable: Boolean? = null,
|
||||
|
||||
@PrimaryKey
|
||||
@ColumnInfo(name = "_id")
|
||||
var id: Long? = null
|
||||
)
|
||||
Loaded 100 of 442 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user