Compare commits

...
45 Commits
Author SHA1 Message Date
tarsin b5832fd706 Make release
CI / Build (push) Has been cancelled
Releases / Build (push) Has been cancelled
2022-08-05 22:13:38 +08:00
tarsin 93312a0714 Dependencies tweaks 2022-08-05 22:13:03 +08:00
tarsin 7e6e1f6f14 Make default label removable 2022-08-05 21:14:38 +08:00
tarsin 6cd498af6a Make downloadList qs drawer drag to rearrange position and swipe to remove 2022-08-05 20:27:43 +08:00
tarsin 2781aaca14 Make gallerylist qs drawer drag to rearrange position and swipe to remove 2022-08-05 20:03:51 +08:00
tarsin 91b9c9af40 Reimplement history swipe-to-remove 2022-08-05 19:44:12 +08:00
tarsin 5c0d10b41a Clean up readme 2022-08-05 18:14:15 +08:00
tarsin a3bdbd7a85 Drop android-advancedrecyclerview
* Actually this library is unmaintained for above a year, and drag feature we used is totally broken on Android 12 and above https://github.com/h6ah4i/android-advancedrecyclerview/issues/516 https://github.com/Ehviewer-Overhauled/Ehviewer/issues/54
2022-08-05 18:12:23 +08:00
tarsin f66151f880 Clean up proguards 2022-08-05 15:13:59 +08:00
txyyh 6c5f52995d Add mult-language README and markdown TOC (#165)
* Add mult-language README

* Add markdown TOC

* Add language selection to README

* Fix wrong branch name in README
2022-08-05 14:55:03 +08:00
tarsin d94b96a8eb Clean up 2022-08-04 13:05:47 +08:00
tarsin a5d90cc97d Make release
CI / Build (push) Has been cancelled
Releases / Build (push) Has been cancelled
2022-08-04 07:39:53 +08:00
tarsin 657d566e89 No need to merge old local db 2022-08-04 07:06:01 +08:00
tarsin 5e6d24f01e Clean up 2022-08-04 06:49:37 +08:00
tarsin e353bbe4c3 Refine database import export 2022-08-04 06:35:42 +08:00
renovate[bot] 4ee2cdf19c Update plugin com.android.application to v7.2.2 (1.8.x.x) (#162)
Update plugin com.android.application to v7.2.2

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-08-04 04:59:09 +08:00
txyyh b28831a8aa Delete useless string (#161) 2022-08-04 04:58:53 +08:00
EdwardWuandtarsin 800b64d5d3 fixup! Ehviewer: Add Chinese(Traditional) Translate (#160)
* Ehviewer: Add Chinese(Traditional) Translate

Signed-off-by: Edward Wu <bluehome.wu@gmail.com>

* fixup! Ehviewer: Add Chinese(Traditional) Translate

Signed-off-by: Edward Wu <bluehome.wu@gmail.com>

Co-authored-by: tarsin <43900799+asuka-mio@users.noreply.github.com>
2022-08-03 22:22:08 +08:00
tarsin cfa6164b5c Use ksp 2022-08-03 22:16:01 +08:00
tarsin 9cb22b6e17 Initial stub migrate to androidx room 2022-08-03 21:59:55 +08:00
tarsin 19891e6768 Fix location 2022-08-03 20:39:11 +08:00
tarsin c616410e0b Drop daogenerator first 2022-08-03 20:33:45 +08:00
EdwardWu 31e1e79ed2 Ehviewer: Add Chinese(Traditional) Translate (#158)
Signed-off-by: Edward Wu <bluehome.wu@gmail.com>
2022-08-03 19:48:22 +08:00
tarsin 6191a9827d Use Ofast 2022-08-03 19:14:11 +08:00
tarsin f373d8f293 Allow universal apk build 2022-08-03 19:07:08 +08:00
tarsin c233eb5a30 Avoid unnecessary native method calling java method 2022-08-03 18:49:00 +08:00
tarsin 360a3e9b5f Clean up 2022-08-03 18:10:30 +08:00
tarsin 01aff59d46 Re-checkout 2022-08-03 17:56:27 +08:00
tarsin f0f1dca7cb Fix build 2022-08-03 17:51:01 +08:00
tarsin 6f3bd92539 Merge native 2022-08-03 17:48:46 +08:00
tarsin a8023f7334 Minify proguard rules 2022-08-03 17:34:21 +08:00
txyyh 8c368972ec Add get-it-on-fdroid into README (#157)
* Fix wrong alt

* Add get-it-on-fdroid
2022-08-02 23:52:50 +08:00
tarsin 5aea90314a Update README.md 2022-08-02 14:02:53 +08:00
tarsin 0c8ba49d61 Update README.md 2022-08-02 14:00:40 +08:00
tarsin ea5b8b9f81 Update README.md 2022-08-02 13:52:28 +08:00
LaLucid 6b21f5082c update CI (#155)
* update CI

* do not need setup-android
2022-08-02 13:46:49 +08:00
tarsin 438d7f1b34 Use O3 optimization 2022-08-01 22:24:01 +08:00
tarsin 301797b477 Import androidx navigation 2022-08-01 10:18:36 +08:00
tarsin 2758be2462 Code clean 2022-08-01 10:14:33 +08:00
tarsin 8f03e4910d Code clean 2022-08-01 10:04:27 +08:00
tarsin a09efd3eea Fix #81 2022-08-01 09:48:56 +08:00
tarsin a66d460572 Remove warning 2022-08-01 09:35:17 +08:00
txyyh 162b88915e 1.8.0.4
CI / Build (push) Has been cancelled
Releases / Build (push) Has been cancelled
2022-07-31 23:10:42 +08:00
txyyh d014b6947c Rewrite download section in README (#150)
* Delete CI Download in README

* Add Chinese NOTE

* Add English NOTE

* Use icon for github download
2022-07-31 12:34:48 +08:00
tarsin a6188964c9 Add simple sanitize, Fix#148 2022-07-31 09:23:41 +08:00
86 changed files with 2812 additions and 2309 deletions

No files matched your search

+4 -6
View File
@@ -9,6 +9,8 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: 'recursive'
- name: Setup Java 11
uses: actions/setup-java@v3
@@ -16,18 +18,14 @@ jobs:
distribution: temurin
java-version: 11
- name: Setup Android SDK Tools
uses: android-actions/setup-android@v2
- name: Install NDK
run: |
echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;25.0.8775105" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null
- name: Gradle Build
uses: gradle/gradle-build-action@v2
- run: |
git submodule update --init --recursive
gradle assembleRelease
with:
arguments: assembleRelease
- name: Update ARM64
uses: actions/upload-artifact@v3
+4 -6
View File
@@ -9,6 +9,8 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: 'recursive'
- name: Setup Java 11
uses: actions/setup-java@v3
@@ -16,18 +18,14 @@ jobs:
distribution: temurin
java-version: 11
- name: Setup Android SDK Tools
uses: android-actions/setup-android@v2
- name: Install NDK
run: |
echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;25.0.8775105" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null
- name: Gradle Build
uses: gradle/gradle-build-action@v2
- run: |
git submodule update --init --recursive
gradle assembleRelease
with:
arguments: assembleRelease
- name: Update ARM64
uses: actions/upload-artifact@v3
+6 -7
View File
@@ -12,6 +12,8 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: 'recursive'
- name: Setup Java 11
uses: actions/setup-java@v3
@@ -19,25 +21,22 @@ jobs:
distribution: temurin
java-version: 11
- name: Setup Android SDK Tools
uses: android-actions/setup-android@v2
- name: Install NDK
run: |
echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;25.0.8775105" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null
- name: Gradle Build
uses: gradle/gradle-build-action@v2
- run: |
git submodule update --init --recursive
gradle assembleRelease
with:
arguments: assembleRelease
- name: Releases
uses: softprops/action-gh-release@v0.1.14
uses: softprops/action-gh-release@v1
with:
body: Bump Version
discussion_category_name: Announcements
files: |
app/build/outputs/apk/release/app-universal-release.apk
app/build/outputs/apk/release/app-arm64-v8a-release.apk
app/build/outputs/apk/release/app-x86_64-release.apk
app/build/outputs/apk/release/app-x86-release.apk
+6 -6
View File
@@ -1,9 +1,9 @@
[submodule "native/src/main/jni/libarchive"]
path = native/src/main/jni/libarchive
[submodule "app/src/main/cpp/libarchive"]
path = app/src/main/cpp/libarchive
url = https://github.com/Ehviewer-Overhauled/libarchive
[submodule "native/src/main/jni/liblzma"]
path = native/src/main/jni/liblzma
[submodule "app/src/main/cpp/liblzma"]
path = app/src/main/cpp/liblzma
url = https://github.com/Ehviewer-Overhauled/xz
[submodule "native/src/main/jni/nettle/nettle"]
path = native/src/main/jni/nettle/nettle
[submodule "app/src/main/cpp/nettle/nettle"]
path = app/src/main/cpp/nettle/nettle
url = https://github.com/Ehviewer-Overhauled/nettle
+44 -16
View File
@@ -1,3 +1,15 @@
<p align="right">
<strong>English<strong>
<span> | </span>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/blob/1.8.x.x/docs/README/zh-cn.md">
简体中文
</a>
<span> | <span>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/blob/1.8.x.x/docs/README/zh-tw.md">
正體中文
</a>
</p>
<h1 align="center">
<img src="art/launcher_icon-web.png" width="200">
<br>EhViewer<br>
@@ -7,7 +19,7 @@
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/actions/workflows/ci.yml">
<img src="https://github.com/Ehviewer-Overhauled/Ehviewer/actions/workflows/ci.yml/badge.svg" alt="Github Actions">
</a>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/blob/master/LICENSE">
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/blob/1.8.x.x/LICENSE">
<img src="https://img.shields.io/github/license/Ehviewer-Overhauled/Ehviewer" alt="LICENSE">
</a>
<a href="https://www.codefactor.io/repository/github/Ehviewer-Overhauled/ehviewer">
@@ -21,22 +33,42 @@
</a>
</p>
<div align="center">
<h3>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer#description">
Description
</a>
<span> | </span>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer#download">
Download
</a>
<span> | </span>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer#screenshot">
Screenshot
</a>
<span> | </span>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer#thanks">
Thanks
</a>
<span> | </span>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer#license">
License
</a>
</h3>
</div>
# Description
致力于轻量化与良好性能表现的 EhViewer 分支
已针对性适配 Material Design 3 及其动态取色系统
EhViewer fork dedicated to lightweight and high-performance
with Material Design 3 and Dynamic Color Support
# Download
[Github 下载](https://github.com/Ehviewer-Overhauled/Ehviewer/releases)
<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>
[CI 版本下载(需登录)](https://github.com/Ehviewer-Overhauled/Ehviewer/actions/workflows/ci.yml)
App is divided into two versions: 1.7 and 1.8 . Version 1.8 support Android 12 and above, also the develop mainline. Version 1.7 support Android 11 and below, drop down some spicetify functions for Android 12 to make app useable on lower Android System
# Screenshot
@@ -45,20 +77,16 @@ with Material Design 3 and Dynamic Color Support
# Thanks
本项目受到了诸多开源项目的帮助
Here is the libraries
- [AOSP](http://source.android.com/)
- [android-advancedrecyclerview](https://github.com/h6ah4i/android-advancedrecyclerview)
- [AOSP&AndroidX](http://source.android.com/)
- [FullDraggableDrawer](https://github.com/PureWriter/FullDraggableDrawer)
- [GnuTLS](https://gnutls.org/)
- [material-components-android](https://github.com/material-components/material-components-android)
- [material-design-icons](https://github.com/google/material-design-icons)
- [Apache Commons Lang](https://commons.apache.org/proper/commons-lang/)
- [greenDAO](https://github.com/greenrobot/greenDAO)
- [jsoup](https://github.com/jhy/jsoup)
- [okhttp](https://github.com/square/okhttp)
- [roaster](https://github.com/forge/roaster)
- [TapTargetView](https://github.com/KeepSafe/TapTargetView)
- [RikkaX](https://github.com/RikkaApps/RikkaX)
- [libarchive](http://www.libarchive.org/)
- [XZ Utils](https://tukaani.org/xz/)
+2 -1
View File
@@ -4,4 +4,5 @@ manifest-merger-release-report.txt
/src/main/libs
/src/main/obj
# Intellij
*.iml
*.iml
/.cxx
+26 -20
View File
@@ -1,12 +1,13 @@
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'kotlin-kapt'
id 'com.google.devtools.ksp'
}
android {
compileSdkVersion 33
buildToolsVersion "33.0.0"
ndkVersion "25.0.8775105"
Properties localProperties = new Properties()
if (project.rootProject.file('local.properties').exists()) {
@@ -18,6 +19,7 @@ android {
enable = true
reset()
include 'arm64-v8a', 'x86_64', 'armeabi-v7a', 'x86'
universalApk = true
}
}
@@ -34,11 +36,17 @@ android {
applicationId "moe.tarsin.ehviewer"
minSdkVersion 31
targetSdkVersion 33
versionCode 180003
versionName "1.8.0.3"
versionCode 180006
versionName "1.8.1.0-alpha02"
resConfigs 'zh', 'zh-rCN', 'zh-rHK', 'zh-rTW', 'es', 'ja', 'ko', 'fr', 'de', 'th'
}
externalNativeBuild {
cmake {
path 'src/main/cpp/CMakeLists.txt'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
@@ -78,26 +86,16 @@ android {
}
}
sourceSets {
main {
java.srcDirs += 'src/main/java-gen'
}
}
namespace 'com.hippo.ehviewer'
}
tasks.withType(JavaCompile) {
task -> task.dependsOn ":daogenerator:executeDaoGenerator"
}
dependencies {
def activity_version = "1.6.0-alpha05"
implementation "androidx.activity:activity:$activity_version"
implementation "androidx.activity:activity-ktx:$activity_version"
implementation "androidx.annotation:annotation:1.4.0"
implementation "androidx.annotation:annotation-experimental:1.2.0"
implementation "androidx.annotation:annotation:1.5.0-alpha01"
implementation "androidx.annotation:annotation-experimental:1.3.0-alpha01"
implementation "androidx.appcompat:appcompat:1.6.0-alpha05"
def arch_core_version = "2.1.0"
@@ -119,10 +117,9 @@ dependencies {
implementation "androidx.core:core-ktx:$core_version"
implementation "androidx.customview:customview:1.2.0-alpha01"
implementation "androidx.documentfile:documentfile:1.1.0-alpha01"
implementation "androidx.dynamicanimation:dynamicanimation:1.1.0-alpha03"
def fragment_version = "1.5.1"
def fragment_version = "1.6.0-alpha01"
implementation "androidx.fragment:fragment:$fragment_version"
implementation "androidx.fragment:fragment-ktx:$fragment_version"
@@ -135,8 +132,20 @@ dependencies {
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version"
implementation "androidx.loader:loader:1.1.0"
def nav_version = "2.5.1"
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.preference:preference:1.2.0'
implementation 'androidx.recyclerview:recyclerview:1.3.0-beta01'
def room_version = "2.5.0-alpha02"
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version"
implementation 'androidx.startup:startup-runtime:1.2.0-alpha01'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.2.0-alpha01'
implementation "androidx.transition:transition-ktx:1.4.1"
@@ -148,16 +157,13 @@ dependencies {
implementation 'com.drakeet.drawer:drawer:1.0.3'
implementation 'com.google.android.material:material:1.7.0-alpha03'
implementation 'com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:1.0.0'
implementation 'com.squareup.okhttp3:okhttp:5.0.0-alpha.10'
implementation 'dev.rikka.rikkax.core:core-ktx:1.4.1'
implementation 'dev.rikka.rikkax.insets:insets:1.3.0'
implementation 'dev.rikka.rikkax.layoutinflater:layoutinflater:1.2.0'
implementation 'dev.rikka.rikkax.preference:simplemenu-preference:1.0.3'
implementation 'dev.rikka.rikkax.material:material-preference:2.0.0'
implementation 'org.greenrobot:greendao:3.3.0'
implementation 'org.jsoup:jsoup:1.15.2'
implementation projects.native
}
configurations.all {
+8 -17
View File
@@ -7,28 +7,19 @@
public static void throw*(...);
}
-keep class com.hippo.ehviewer.ui.fragment.* extends com.hippo.ehviewer.ui.fragment.BaseFragment { }
-keep class com.hippo.ehviewer.ui.fragment.* extends com.hippo.ehviewer.ui.fragment.BasePreferenceFragment { }
-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 { }
-keepnames class com.hippo.ehviewer.ui.scene.* { }
-keep class com.hippo.ehviewer.dao.* { *; }
-keepattributes SourceFile,LineNumberTable
-renamesourcefileattribute
-repackageclasses
-allowaccessmodification
-mergeinterfacesaggressively
-overloadaggressively
-dontwarn net.sqlcipher.database.**
-dontwarn rx.**
-dontwarn org.conscrypt.ConscryptHostnameVerifier
-dontwarn org.conscrypt.Conscrypt$Version
-dontwarn org.bouncycastle.jsse.provider.BouncyCastleJsseProvider
-dontwarn org.bouncycastle.jsse.BCSSLSocket
-dontwarn org.openjsse.javax.net.ssl.SSLParameters
-dontwarn net.sqlcipher.Cursor
-dontwarn org.bouncycastle.jsse.BCSSLParameters
-dontwarn org.conscrypt.Conscrypt
-dontwarn org.openjsse.javax.net.ssl.SSLSocket
-dontwarn org.openjsse.net.ssl.OpenJSSE
+6
View File
@@ -145,6 +145,12 @@
android:label="@string/settings"
android:theme="@style/AppTheme" />
<activity
android:name="com.hippo.ehviewer.ui.SecurityActivity"
android:configChanges="screenSize"
android:label="@string/settings"
android:theme="@style/AppTheme" />
<activity
android:name="com.hippo.ehviewer.shortcuts.ShortcutsActivity"
android:excludeFromRecents="true"
@@ -1,17 +1,17 @@
project(ehviewer)
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Oz -fvisibility=hidden -fvisibility-inlines-hidden -ffunction-sections -fdata-sections -flto\
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Ofast -fvisibility=hidden -fvisibility-inlines-hidden -ffunction-sections -fdata-sections -flto \
-mllvm -polly \
-mllvm -polly-run-dce \
-mllvm -polly-run-inliner \
-mllvm -polly-run-inliner \
-mllvm -polly-isl-arg=--no-schedule-serialize-sccs \
-mllvm -polly-ast-use-context \
-mllvm -polly-ast-use-context \
-mllvm -polly-detect-keep-going \
-mllvm -polly-position=before-vectorizer \
-mllvm -polly-vectorizer=stripmine \
-mllvm -polly-vectorizer=stripmine \
-mllvm -polly-detect-profitability-min-per-loop-insts=40 \
-mllvm -polly-invariant-load-hoisting")
-mllvm -polly-invariant-load-hoisting")
# Build GNUTLS libnettle
add_subdirectory(nettle)
@@ -44,10 +44,7 @@ SET(LIBARCHIVE_CUSTOM_LIBS "liblzma" "nettle")
# Build libarchive
add_subdirectory(libarchive)
# Build hippo's image lib
add_subdirectory(image)
# Build and link our app's native lib
add_library(${PROJECT_NAME} SHARED main.c archive.c)
target_include_directories(${PROJECT_NAME} PUBLIC image/image libarchive/libarchive)
target_link_libraries(${PROJECT_NAME} image archive_static -Wl,--gc-sections)
add_library(${PROJECT_NAME} SHARED main.c archive.c image.c)
target_include_directories(${PROJECT_NAME} PUBLIC libarchive/libarchive)
target_link_libraries(${PROJECT_NAME} archive_static log jnigraphics GLESv2 -Wl,--gc-sections)
File renamed without changes.
+380
View File
@@ -0,0 +1,380 @@
/*
* 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/data_space.h>
#include <android/imagedecoder.h>
#include <android/log.h>
#include <GLES2/gl2.h>
#include "image.h"
#define TAG "ImageDecoder_wrapper"
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG ,__VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG ,__VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG ,__VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, TAG ,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG ,__VA_ARGS__)
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL, TAG ,__VA_ARGS__)
#define IMAGE_TILE_MAX_SIZE (512 * 512)
static void *tile_buffer = NULL;
bool image_onLoad() {
tile_buffer = malloc(IMAGE_TILE_MAX_SIZE * 4);
return tile_buffer != NULL;
}
void image_onUnload() {
free(tile_buffer);
tile_buffer = NULL;
}
typedef struct {
AImageDecoder *decoder;
void *srcBuffer;
size_t stride;
int fd;
} SOURCE;
typedef struct {
int32_t width;
int32_t height;
void *buffer;
int bufferLen;
bool isAnimated;
bool alpha;
int delay;
SOURCE *src;
} IMAGE;
static void recycleSource(SOURCE *src) {
if (!src)
return;
AImageDecoder_delete(src->decoder);
free(src->srcBuffer);
free(src);
}
static void recycle(IMAGE *image) {
if (!image)
return;
recycleSource(image->src);
free(image->buffer);
free(image);
}
typedef struct Memarea {
void *buffer;
long size;
} Memarea;
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;
}
void decodeCommon(IMAGE *image, SOURCE *src) {
image->src = src;
AImageDecoder *decoder = src->decoder;
image->isAnimated = AImageDecoder_isAnimated(decoder);
AImageDecoder_setDataSpace(decoder, ADATASPACE_SRGB);
AImageDecoder_setAndroidBitmapFormat(decoder, ANDROID_BITMAP_FORMAT_RGBA_8888);
const AImageDecoderHeaderInfo *headerInfo = AImageDecoder_getHeaderInfo(decoder);
image->height = AImageDecoderHeaderInfo_getHeight(headerInfo);
image->width = AImageDecoderHeaderInfo_getWidth(headerInfo);
image->alpha =
AImageDecoderHeaderInfo_getAlphaFlags(headerInfo) == ANDROID_BITMAP_FLAGS_ALPHA_PREMUL;
src->stride = AImageDecoder_getMinimumStride(decoder);
image->bufferLen = (int) (image->height * src->stride);
image->buffer = malloc(image->bufferLen);
if (image->isAnimated) {
AImageDecoder_setInternallyHandleDisposePrevious(decoder, false);
AImageDecoderFrameInfo *frameInfo = AImageDecoderFrameInfo_create();
AImageDecoder_getFrameInfo(decoder, frameInfo);
image->delay = (int) AImageDecoderFrameInfo_getDuration(frameInfo) / 1000000;
AImageDecoderFrameInfo_delete(frameInfo);
}
AImageDecoder_decodeImage(decoder, image->buffer, src->stride, image->bufferLen);
if (!image->isAnimated) {
recycleSource(image->src);
image->src = NULL;
}
}
IMAGE *createFromFd(int fd) {
AImageDecoder *decoder = NULL;
if (AImageDecoder_createFromFd(fd, &decoder) != ANDROID_IMAGE_DECODER_SUCCESS)
return NULL;
IMAGE *image = calloc(1, sizeof(IMAGE));
SOURCE *src = calloc(1, sizeof(SOURCE));
src->decoder = decoder;
src->fd = fd;
decodeCommon(image, src);
return image;
}
IMAGE *createFromAddr(void *addr, long size) {
AImageDecoder *decoder;
AImageDecoder_createFromBuffer((const void *) addr, size, &decoder);
IMAGE *image = calloc(1, sizeof(IMAGE));
SOURCE *src = calloc(1, sizeof(SOURCE));
src->decoder = decoder;
src->srcBuffer = addr;
decodeCommon(image, src);
return image;
}
IMAGE *create(int32_t width, int32_t height, const void *data) {
IMAGE *plain = calloc(1, sizeof(IMAGE));
void *buffer = NULL;
size_t length = width * height * 4;
buffer = malloc(length);
memcpy(buffer, data, length);
// plain->isAnimated = false; this is unnecessary since we use calloc
plain->width = width;
plain->height = height;
plain->buffer = buffer;
plain->bufferLen = (int) length;
return plain;
}
void render(IMAGE *image, int src_x, int src_y,
void *dst, int dst_w, int dst_h, int dst_x, int dst_y,
int width, int height) {
copy_pixels(image->buffer, image->width, image->height, src_x, src_y, dst, dst_w, dst_h, dst_x,
dst_y, width, height);
}
void advance(IMAGE *image) {
if (image->isAnimated) {
AImageDecoder_advanceFrame(image->src->decoder);
if (AImageDecoder_decodeImage(image->src->decoder, image->buffer, image->src->stride,
image->bufferLen) == ANDROID_IMAGE_DECODER_FINISHED) {
AImageDecoder_rewind(image->src->decoder);
AImageDecoder_decodeImage(image->src->decoder, image->buffer, image->src->stride,
image->bufferLen);
}
}
}
static int jniGetFDFromFileDescriptor(JNIEnv *env, jobject fileDescriptor) {
jint fd = -1;
jclass fdClass = (*env)->FindClass(env, "java/io/FileDescriptor");
if (fdClass != NULL) {
jfieldID fdClassDescriptorFieldID = (*env)->GetFieldID(env, fdClass, "descriptor", "I");
if (fdClassDescriptorFieldID != NULL && fileDescriptor != NULL) {
fd = (*env)->GetIntField(env, fileDescriptor, fdClassDescriptorFieldID);
}
}
return fd;
}
JNIEXPORT jlong JNICALL
Java_com_hippo_image_Image_nativeDecodeFdInt(JNIEnv *env, jclass clazz, jint fd) {
IMAGE *image = createFromFd(fd);
return (jlong) image;
}
JNIEXPORT jlong JNICALL
Java_com_hippo_image_Image_nativeDecode(JNIEnv *env, jclass clazz, jobject fd) {
return Java_com_hippo_image_Image_nativeDecodeFdInt(env, clazz,
jniGetFDFromFileDescriptor(env, fd));
}
JNIEXPORT jlong JNICALL
Java_com_hippo_image_Image_nativeCreate(JNIEnv *env, jclass clazz, jobject bitmap) {
AndroidBitmapInfo info;
void *pixels = NULL;
void *image = NULL;
AndroidBitmap_getInfo(env, bitmap, &info);
AndroidBitmap_lockPixels(env, bitmap, &pixels);
image = create((int)info.width, (int)info.height, pixels);
AndroidBitmap_unlockPixels(env, bitmap);
return (jlong) image;
}
JNIEXPORT void JNICALL
Java_com_hippo_image_Image_nativeRender(JNIEnv *env, jclass clazz, jlong ptr, jint src_x,
jint src_y, jobject dst, jint dst_x, jint dst_y, jint width,
jint height) {
AndroidBitmapInfo info;
void *pixels = NULL;
AndroidBitmap_getInfo(env, dst, &info);
AndroidBitmap_lockPixels(env, dst, &pixels);
render((IMAGE *) ptr, src_x, src_y, pixels, (int)info.width, (int)info.height, dst_x, dst_y, width,
height);
AndroidBitmap_unlockPixels(env, dst);
}
JNIEXPORT void JNICALL
Java_com_hippo_image_Image_nativeTexImage(JNIEnv *env, jclass clazz, jlong ptr, jboolean init,
jint src_x, jint src_y, jint width, jint height) {
if (width * height > IMAGE_TILE_MAX_SIZE)
return;
render((IMAGE *) ptr, src_x, src_y, tile_buffer, width, height, 0, 0, width, height);
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);
}
}
JNIEXPORT void JNICALL
Java_com_hippo_image_Image_nativeAdvance(JNIEnv *env, jclass clazz, jlong ptr) {
advance((IMAGE *) ptr);
}
JNIEXPORT jint JNICALL
Java_com_hippo_image_Image_nativeGetDelay(JNIEnv *env, jclass clazz, jlong ptr) {
return ((IMAGE *) ptr)->delay;
}
JNIEXPORT jboolean JNICALL
Java_com_hippo_image_Image_nativeIsOpaque(JNIEnv *env, jclass clazz, jlong ptr) {
return ((IMAGE *) ptr)->alpha;
}
JNIEXPORT void JNICALL
Java_com_hippo_image_Image_nativeRecycle(JNIEnv *env, jclass clazz, jlong ptr) {
recycle((IMAGE *) ptr);
}
JNIEXPORT jlong JNICALL
Java_com_hippo_image_Image_nativeDecodeAddr(JNIEnv *env, jclass clazz, jlong addr) {
Memarea *memarea = (Memarea *) addr;
IMAGE *image = createFromAddr(memarea->buffer, memarea->size);
free(memarea);
return (jlong) image;
}
JNIEXPORT jint JNICALL
Java_com_hippo_image_Image_nativeGetFormat(JNIEnv *env, jclass clazz, jlong native_ptr) {
return ((IMAGE *) native_ptr)->isAnimated;
}
JNIEXPORT jint JNICALL
Java_com_hippo_image_Image_nativeGetWidth(JNIEnv *env, jclass clazz, jlong native_ptr) {
return ((IMAGE *) native_ptr)->width;
}
JNIEXPORT jint JNICALL
Java_com_hippo_image_Image_nativeGetHeight(JNIEnv *env, jclass clazz, jlong native_ptr) {
return ((IMAGE *) native_ptr)->height;
}
@@ -17,20 +17,13 @@
* EhViewer. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef IMAGE_JAVA_WRAPPER_H
#define IMAGE_JAVA_WRAPPER_H
#ifndef IMAGE_IMAGE_H
#define IMAGE_IMAGE_H
#include <stdbool.h>
#define IMAGE_TILE_MAX_SIZE (512 * 512)
typedef struct Memarea {
void *buffer;
long size;
} Memarea;
bool image_onLoad();
void image_onUnload();
#endif /* IMAGE_JAVA_WRAPPER_H */
#endif /* IMAGE_IMAGE_H */
File renamed without changes.
File renamed without changes.
@@ -23,7 +23,7 @@
#include <zlib.h>
#include <nettle/config.h>
#include "image/java_wrapper.h"
#include "image.h"
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env;
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -107,7 +107,7 @@ public class EhApplication extends SceneApplication {
private static final boolean DEBUG_PRINT_IMAGE_COUNT = false;
private static final long DEBUG_PRINT_INTERVAL = 3000L;
public static boolean locked = false;
public static boolean locked = true;
private static EhApplication instance;
@@ -337,10 +337,6 @@ public class EhApplication extends SceneApplication {
EhEngine.initialize();
BitmapUtils.initialize(this);
if (EhDB.needMerge()) {
EhDB.mergeOldDB(this);
}
AppCompatDelegate.setApplicationLocales(LocaleListCompat.create(Settings.getLocale()));
AppCompatDelegate.setDefaultNightMode(Settings.getTheme());
+97 -381
View File
@@ -17,27 +17,23 @@
package com.hippo.ehviewer;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.room.Room;
import com.hippo.ehviewer.client.data.GalleryInfo;
import com.hippo.ehviewer.client.data.ListUrlBuilder;
import com.hippo.ehviewer.dao.DaoMaster;
import com.hippo.ehviewer.dao.DaoSession;
import com.hippo.ehviewer.dao.BasicDao;
import com.hippo.ehviewer.dao.DownloadDirname;
import com.hippo.ehviewer.dao.DownloadDirnameDao;
import com.hippo.ehviewer.dao.DownloadInfo;
import com.hippo.ehviewer.dao.DownloadLabel;
import com.hippo.ehviewer.dao.DownloadLabelDao;
import com.hippo.ehviewer.dao.DownloadsDao;
import com.hippo.ehviewer.dao.EhDatabase;
import com.hippo.ehviewer.dao.Filter;
import com.hippo.ehviewer.dao.FilterDao;
import com.hippo.ehviewer.dao.HistoryDao;
import com.hippo.ehviewer.dao.HistoryInfo;
import com.hippo.ehviewer.dao.LocalFavoriteInfo;
@@ -46,14 +42,8 @@ import com.hippo.ehviewer.dao.QuickSearch;
import com.hippo.ehviewer.dao.QuickSearchDao;
import com.hippo.ehviewer.download.DownloadManager;
import com.hippo.util.ExceptionUtils;
import com.hippo.util.SqlUtils;
import com.hippo.yorozuya.IOUtils;
import com.hippo.yorozuya.ObjectUtils;
import com.hippo.yorozuya.collect.SparseJLArray;
import org.greenrobot.greendao.AbstractDao;
import org.greenrobot.greendao.query.CloseableListIterator;
import org.greenrobot.greendao.query.LazyList;
import java.io.File;
import java.io.FileInputStream;
@@ -65,15 +55,11 @@ import java.util.ArrayList;
import java.util.List;
public class EhDB {
private static final String TAG = EhDB.class.getSimpleName();
private static final int CUR_DB_VER = 4;
private static final int MAX_HISTORY_COUNT = 200;
private static DaoSession sDaoSession;
private static boolean sHasOldDB;
private static boolean sNewDB;
private static EhDatabase db;
private static void upgradeDB(SQLiteDatabase db, int oldVersion) {
switch (oldVersion) {
@@ -115,219 +101,12 @@ public class EhDB {
}
public static void initialize(Context context) {
sHasOldDB = context.getDatabasePath("data").exists();
DBOpenHelper helper = new DBOpenHelper(
context.getApplicationContext(), "eh.db", null);
SQLiteDatabase db = helper.getWritableDatabase();
DaoMaster daoMaster = new DaoMaster(db);
sDaoSession = daoMaster.newSession();
}
public static boolean needMerge() {
return sNewDB && sHasOldDB;
}
public static void mergeOldDB(Context context) {
sNewDB = false;
OldDBHelper oldDBHelper = new OldDBHelper(context);
SQLiteDatabase oldDB;
try {
oldDB = oldDBHelper.getReadableDatabase();
} catch (Throwable e) {
ExceptionUtils.throwIfFatal(e);
return;
}
// Get GalleryInfo list
SparseJLArray<GalleryInfo> map = new SparseJLArray<>();
try {
Cursor cursor = oldDB.rawQuery("select * from " + OldDBHelper.TABLE_GALLERY, null);
if (cursor != null) {
if (cursor.moveToFirst()) {
while (!cursor.isAfterLast()) {
GalleryInfo gi = new GalleryInfo();
gi.gid = cursor.getInt(0);
gi.token = cursor.getString(1);
gi.title = cursor.getString(2);
gi.posted = cursor.getString(3);
gi.category = cursor.getInt(4);
gi.thumb = cursor.getString(5);
gi.uploader = cursor.getString(6);
try {
// In 0.6.x version, NaN is stored
gi.rating = cursor.getFloat(7);
} catch (Throwable e) {
ExceptionUtils.throwIfFatal(e);
gi.rating = -1.0f;
}
map.put(gi.gid, gi);
cursor.moveToNext();
}
}
cursor.close();
}
} catch (Throwable e) {
ExceptionUtils.throwIfFatal(e);
// Ignore
}
// Merge local favorites
try {
Cursor cursor = oldDB.rawQuery("select * from " + OldDBHelper.TABLE_LOCAL_FAVOURITE, null);
if (cursor != null) {
LocalFavoritesDao dao = sDaoSession.getLocalFavoritesDao();
if (cursor.moveToFirst()) {
long i = 0L;
while (!cursor.isAfterLast()) {
// Get GalleryInfo first
long gid = cursor.getInt(0);
GalleryInfo gi = map.get(gid);
if (gi == null) {
Log.e(TAG, "Can't get GalleryInfo with gid: " + gid);
cursor.moveToNext();
continue;
}
LocalFavoriteInfo info = new LocalFavoriteInfo(gi);
info.setTime(i);
dao.insert(info);
cursor.moveToNext();
i++;
}
}
cursor.close();
}
} catch (Throwable e) {
ExceptionUtils.throwIfFatal(e);
// Ignore
}
// Merge quick search
try {
Cursor cursor = oldDB.rawQuery("select * from " + OldDBHelper.TABLE_TAG, null);
if (cursor != null) {
QuickSearchDao dao = sDaoSession.getQuickSearchDao();
if (cursor.moveToFirst()) {
while (!cursor.isAfterLast()) {
QuickSearch quickSearch = new QuickSearch();
int mode = cursor.getInt(2);
String search = cursor.getString(4);
String tag = cursor.getString(7);
if (mode == ListUrlBuilder.MODE_UPLOADER && search != null &&
search.startsWith("uploader:")) {
search = search.substring("uploader:".length());
}
quickSearch.setTime(cursor.getInt(0));
quickSearch.setName(cursor.getString(1));
quickSearch.setMode(mode);
quickSearch.setCategory(cursor.getInt(3));
quickSearch.setKeyword(mode == ListUrlBuilder.MODE_TAG ? tag : search);
quickSearch.setAdvanceSearch(cursor.getInt(5));
quickSearch.setMinRating(cursor.getInt(6));
dao.insert(quickSearch);
cursor.moveToNext();
}
}
cursor.close();
}
} catch (Throwable e) {
ExceptionUtils.throwIfFatal(e);
// Ignore
}
// Merge download info
try {
Cursor cursor = oldDB.rawQuery("select * from " + OldDBHelper.TABLE_DOWNLOAD, null);
if (cursor != null) {
DownloadsDao dao = sDaoSession.getDownloadsDao();
if (cursor.moveToFirst()) {
long i = 0L;
while (!cursor.isAfterLast()) {
// Get GalleryInfo first
long gid = cursor.getInt(0);
GalleryInfo gi = map.get(gid);
if (gi == null) {
Log.e(TAG, "Can't get GalleryInfo with gid: " + gid);
cursor.moveToNext();
continue;
}
DownloadInfo info = new DownloadInfo(gi);
int state = cursor.getInt(2);
int legacy = cursor.getInt(3);
if (state == DownloadInfo.STATE_FINISH && legacy > 0) {
state = DownloadInfo.STATE_FAILED;
}
info.setState(state);
info.setLegacy(legacy);
if (cursor.getColumnCount() == 5) {
info.setTime(cursor.getLong(4));
} else {
info.setTime(i);
}
dao.insert(info);
cursor.moveToNext();
i++;
}
}
cursor.close();
}
} catch (Throwable e) {
ExceptionUtils.throwIfFatal(e);
// Ignore
}
try {
// Merge history info
Cursor cursor = oldDB.rawQuery("select * from " + OldDBHelper.TABLE_HISTORY, null);
if (cursor != null) {
HistoryDao dao = sDaoSession.getHistoryDao();
if (cursor.moveToFirst()) {
while (!cursor.isAfterLast()) {
// Get GalleryInfo first
long gid = cursor.getInt(0);
GalleryInfo gi = map.get(gid);
if (gi == null) {
Log.e(TAG, "Can't get GalleryInfo with gid: " + gid);
cursor.moveToNext();
continue;
}
HistoryInfo info = new HistoryInfo(gi);
info.setMode(cursor.getInt(1));
info.setTime(cursor.getLong(2));
dao.insert(info);
cursor.moveToNext();
}
}
cursor.close();
}
} catch (Throwable e) {
ExceptionUtils.throwIfFatal(e);
// Ignore
}
try {
oldDBHelper.close();
} catch (Throwable e) {
ExceptionUtils.throwIfFatal(e);
// Ignore
}
db = Room.databaseBuilder(context, EhDatabase.class, "eh.db").allowMainThreadQueries().build();
}
public static synchronized List<DownloadInfo> getAllDownloadInfo() {
DownloadsDao dao = sDaoSession.getDownloadsDao();
List<DownloadInfo> list = dao.queryBuilder().orderDesc(DownloadsDao.Properties.Time).list();
DownloadsDao dao = db.downloadsDao();
List<DownloadInfo> list = dao.list();
// Fix state
for (DownloadInfo info : list) {
if (info.state == DownloadInfo.STATE_WAIT || info.state == DownloadInfo.STATE_DOWNLOAD) {
@@ -339,7 +118,7 @@ public class EhDB {
// Insert or update
public static synchronized void putDownloadInfo(DownloadInfo downloadInfo) {
DownloadsDao dao = sDaoSession.getDownloadsDao();
DownloadsDao dao = db.downloadsDao();
if (null != dao.load(downloadInfo.gid)) {
// Update
dao.update(downloadInfo);
@@ -349,13 +128,13 @@ public class EhDB {
}
}
public static synchronized void removeDownloadInfo(long gid) {
sDaoSession.getDownloadsDao().deleteByKey(gid);
public static synchronized void removeDownloadInfo(DownloadInfo downloadInfo) {
db.downloadsDao().delete(downloadInfo);
}
@Nullable
public static synchronized String getDownloadDirname(long gid) {
DownloadDirnameDao dao = sDaoSession.getDownloadDirnameDao();
DownloadDirnameDao dao = db.downloadDirnameDao();
DownloadDirname raw = dao.load(gid);
if (raw != null) {
return raw.getDirname();
@@ -368,7 +147,7 @@ public class EhDB {
* Insert or update
*/
public static synchronized void putDownloadDirname(long gid, String dirname) {
DownloadDirnameDao dao = sDaoSession.getDownloadDirnameDao();
DownloadDirnameDao dao = db.downloadDirnameDao();
DownloadDirname raw = dao.load(gid);
if (raw != null) { // Update
raw.setDirname(dirname);
@@ -382,23 +161,23 @@ public class EhDB {
}
public static synchronized void removeDownloadDirname(long gid) {
DownloadDirnameDao dao = sDaoSession.getDownloadDirnameDao();
DownloadDirnameDao dao = db.downloadDirnameDao();
dao.deleteByKey(gid);
}
public static synchronized void clearDownloadDirname() {
DownloadDirnameDao dao = sDaoSession.getDownloadDirnameDao();
DownloadDirnameDao dao = db.downloadDirnameDao();
dao.deleteAll();
}
@NonNull
public static synchronized List<DownloadLabel> getAllDownloadLabelList() {
DownloadLabelDao dao = sDaoSession.getDownloadLabelDao();
return dao.queryBuilder().orderAsc(DownloadLabelDao.Properties.Time).list();
DownloadLabelDao dao = db.downloadLabelDao();
return dao.list();
}
public static synchronized DownloadLabel addDownloadLabel(String label) {
DownloadLabelDao dao = sDaoSession.getDownloadLabelDao();
DownloadLabelDao dao = db.downloadLabelDao();
DownloadLabel raw = new DownloadLabel();
raw.setLabel(label);
raw.setTime(System.currentTimeMillis());
@@ -409,13 +188,13 @@ public class EhDB {
public static synchronized DownloadLabel addDownloadLabel(DownloadLabel raw) {
// Reset id
raw.setId(null);
DownloadLabelDao dao = sDaoSession.getDownloadLabelDao();
DownloadLabelDao dao = db.downloadLabelDao();
raw.setId(dao.insert(raw));
return raw;
}
public static synchronized void updateDownloadLabel(DownloadLabel raw) {
DownloadLabelDao dao = sDaoSession.getDownloadLabelDao();
DownloadLabelDao dao = db.downloadLabelDao();
dao.update(raw);
}
@@ -428,9 +207,8 @@ public class EhDB {
int offset = reverse ? toPosition : fromPosition;
int limit = reverse ? fromPosition - toPosition + 1 : toPosition - fromPosition + 1;
DownloadLabelDao dao = sDaoSession.getDownloadLabelDao();
List<DownloadLabel> list = dao.queryBuilder().orderAsc(DownloadLabelDao.Properties.Time)
.offset(offset).limit(limit).list();
DownloadLabelDao dao = db.downloadLabelDao();
List<DownloadLabel> list = dao.list(offset, limit);
int step = reverse ? 1 : -1;
int start = reverse ? limit - 1 : 0;
@@ -441,50 +219,44 @@ public class EhDB {
}
list.get(start).setTime(toTime);
dao.updateInTx(list);
dao.update(list);
}
public static synchronized void removeDownloadLabel(DownloadLabel raw) {
DownloadLabelDao dao = sDaoSession.getDownloadLabelDao();
DownloadLabelDao dao = db.downloadLabelDao();
dao.delete(raw);
}
public static synchronized List<GalleryInfo> getAllLocalFavorites() {
LocalFavoritesDao dao = sDaoSession.getLocalFavoritesDao();
List<LocalFavoriteInfo> list = dao.queryBuilder().orderDesc(LocalFavoritesDao.Properties.Time).list();
List<GalleryInfo> result = new ArrayList<>();
result.addAll(list);
return result;
LocalFavoritesDao dao = db.localFavoritesDao();
List<LocalFavoriteInfo> list = dao.list();
return new ArrayList<>(list);
}
public static synchronized List<GalleryInfo> searchLocalFavorites(String query) {
query = SqlUtils.sqlEscapeString("%" + query + "%");
LocalFavoritesDao dao = sDaoSession.getLocalFavoritesDao();
List<LocalFavoriteInfo> list = dao.queryBuilder().orderDesc(LocalFavoritesDao.Properties.Time)
.where(LocalFavoritesDao.Properties.Title.like(query)).list();
List<GalleryInfo> result = new ArrayList<>();
result.addAll(list);
return result;
LocalFavoritesDao dao = db.localFavoritesDao();
List<LocalFavoriteInfo> list = dao.list();
return new ArrayList<>(list);
}
public static synchronized void removeLocalFavorites(long gid) {
sDaoSession.getLocalFavoritesDao().deleteByKey(gid);
db.localFavoritesDao().deleteByKey(gid);
}
public static synchronized void removeLocalFavorites(long[] gidArray) {
LocalFavoritesDao dao = sDaoSession.getLocalFavoritesDao();
LocalFavoritesDao dao = db.localFavoritesDao();
for (long gid : gidArray) {
dao.deleteByKey(gid);
}
}
public static synchronized boolean containLocalFavorites(long gid) {
LocalFavoritesDao dao = sDaoSession.getLocalFavoritesDao();
LocalFavoritesDao dao = db.localFavoritesDao();
return null != dao.load(gid);
}
public static synchronized void putLocalFavorites(GalleryInfo galleryInfo) {
LocalFavoritesDao dao = sDaoSession.getLocalFavoritesDao();
LocalFavoritesDao dao = db.localFavoritesDao();
if (null == dao.load(galleryInfo.gid)) {
LocalFavoriteInfo info;
if (galleryInfo instanceof LocalFavoriteInfo) {
@@ -504,31 +276,31 @@ public class EhDB {
}
public static synchronized List<QuickSearch> getAllQuickSearch() {
QuickSearchDao dao = sDaoSession.getQuickSearchDao();
return dao.queryBuilder().orderAsc(QuickSearchDao.Properties.Time).list();
QuickSearchDao dao = db.quickSearchDao();
return dao.list();
}
public static synchronized void insertQuickSearch(QuickSearch quickSearch) {
QuickSearchDao dao = sDaoSession.getQuickSearchDao();
QuickSearchDao dao = db.quickSearchDao();
quickSearch.id = null;
quickSearch.time = System.currentTimeMillis();
quickSearch.id = dao.insert(quickSearch);
}
public static synchronized void importQuickSearch(List<QuickSearch> quickSearchList) {
QuickSearchDao dao = sDaoSession.getQuickSearchDao();
QuickSearchDao dao = db.quickSearchDao();
for (QuickSearch quickSearch : quickSearchList) {
dao.insert(quickSearch);
}
}
public static synchronized void updateQuickSearch(QuickSearch quickSearch) {
QuickSearchDao dao = sDaoSession.getQuickSearchDao();
QuickSearchDao dao = db.quickSearchDao();
dao.update(quickSearch);
}
public static synchronized void deleteQuickSearch(QuickSearch quickSearch) {
QuickSearchDao dao = sDaoSession.getQuickSearchDao();
QuickSearchDao dao = db.quickSearchDao();
dao.delete(quickSearch);
}
@@ -541,9 +313,8 @@ public class EhDB {
int offset = reverse ? toPosition : fromPosition;
int limit = reverse ? fromPosition - toPosition + 1 : toPosition - fromPosition + 1;
QuickSearchDao dao = sDaoSession.getQuickSearchDao();
List<QuickSearch> list = dao.queryBuilder().orderAsc(QuickSearchDao.Properties.Time)
.offset(offset).limit(limit).list();
QuickSearchDao dao = db.quickSearchDao();
List<QuickSearch> list = dao.list(offset, limit);
int step = reverse ? 1 : -1;
int start = reverse ? limit - 1 : 0;
@@ -554,15 +325,15 @@ public class EhDB {
}
list.get(start).setTime(toTime);
dao.updateInTx(list);
dao.update(list);
}
public static synchronized LazyList<HistoryInfo> getHistoryLazyList() {
return sDaoSession.getHistoryDao().queryBuilder().orderDesc(HistoryDao.Properties.Time).listLazy();
public static synchronized List<HistoryInfo> getHistoryLazyList() {
return db.historyDao().list();
}
public static synchronized void putHistoryInfo(GalleryInfo galleryInfo) {
HistoryDao dao = sDaoSession.getHistoryDao();
HistoryDao dao = db.historyDao();
HistoryInfo info = dao.load(galleryInfo.gid);
if (null != info) {
// Update time
@@ -573,49 +344,47 @@ public class EhDB {
info = new HistoryInfo(galleryInfo);
info.time = System.currentTimeMillis();
dao.insert(info);
List<HistoryInfo> list = dao.queryBuilder().orderDesc(HistoryDao.Properties.Time)
.limit(-1).offset(MAX_HISTORY_COUNT).list();
dao.deleteInTx(list);
List<HistoryInfo> list = dao.list(MAX_HISTORY_COUNT, -1);
dao.delete(list);
}
}
public static synchronized void putHistoryInfo(List<HistoryInfo> historyInfoList) {
HistoryDao dao = sDaoSession.getHistoryDao();
HistoryDao dao = db.historyDao();
for (HistoryInfo info : historyInfoList) {
if (null == dao.load(info.gid)) {
dao.insert(info);
}
}
List<HistoryInfo> list = dao.queryBuilder().orderDesc(HistoryDao.Properties.Time)
.limit(-1).offset(MAX_HISTORY_COUNT).list();
dao.deleteInTx(list);
List<HistoryInfo> list = dao.list(MAX_HISTORY_COUNT, -1);
dao.delete(list);
}
public static synchronized void deleteHistoryInfo(HistoryInfo info) {
HistoryDao dao = sDaoSession.getHistoryDao();
HistoryDao dao = db.historyDao();
dao.delete(info);
}
public static synchronized void clearHistoryInfo() {
HistoryDao dao = sDaoSession.getHistoryDao();
HistoryDao dao = db.historyDao();
dao.deleteAll();
}
public static synchronized List<Filter> getAllFilter() {
return sDaoSession.getFilterDao().queryBuilder().list();
return db.filterDao().list();
}
public static synchronized boolean addFilter(Filter filter) {
Filter existFilter;
try {
existFilter = sDaoSession.getFilterDao().queryBuilder().where(FilterDao.Properties.Text.eq(filter.text), FilterDao.Properties.Mode.eq(filter.mode)).unique();
existFilter = db.filterDao().load(filter.text, filter.mode);
} catch (Exception e) {
existFilter = null;
}
if (existFilter == null) {
filter.setId(null);
filter.setId(sDaoSession.getFilterDao().insert(filter));
filter.setId(db.filterDao().insert(filter));
return true;
} else {
return false;
@@ -623,23 +392,19 @@ public class EhDB {
}
public static synchronized void deleteFilter(Filter filter) {
sDaoSession.getFilterDao().delete(filter);
db.filterDao().delete(filter);
}
public static synchronized void triggerFilter(Filter filter) {
filter.setEnable(!filter.enable);
sDaoSession.getFilterDao().update(filter);
db.filterDao().update(filter);
}
private static <T> boolean copyDao(AbstractDao<T, ?> from, AbstractDao<T, ?> to) {
try (CloseableListIterator<T> iterator = from.queryBuilder().listIterator()) {
while (iterator.hasNext()) {
to.insert(iterator.next());
}
} catch (IOException e) {
return false;
}
return true;
private static <T> boolean copyDao(BasicDao<T> from, BasicDao<T> to) {
List<T> list = from.list();
for (T item : list)
to.insert(item);
return false;
}
public static synchronized boolean exportDB(Context context, Uri uri) {
@@ -647,31 +412,24 @@ public class EhDB {
// Delete old export db
context.deleteDatabase(ehExportName);
DBOpenHelper helper = new DBOpenHelper(context.getApplicationContext(), ehExportName, null);
EhDatabase newDb = Room.databaseBuilder(context, EhDatabase.class, ehExportName).allowMainThreadQueries().build();
try {
// Copy data to a export db
try (SQLiteDatabase db = helper.getWritableDatabase()) {
DaoMaster daoMaster = new DaoMaster(db);
DaoSession exportSession = daoMaster.newSession();
if (!copyDao(sDaoSession.getDownloadsDao(), exportSession.getDownloadsDao()))
return false;
if (!copyDao(sDaoSession.getDownloadLabelDao(), exportSession.getDownloadLabelDao()))
return false;
if (!copyDao(sDaoSession.getDownloadDirnameDao(), exportSession.getDownloadDirnameDao()))
return false;
if (!copyDao(sDaoSession.getHistoryDao(), exportSession.getHistoryDao()))
return false;
if (!copyDao(sDaoSession.getQuickSearchDao(), exportSession.getQuickSearchDao()))
return false;
if (!copyDao(sDaoSession.getLocalFavoritesDao(), exportSession.getLocalFavoritesDao()))
return false;
if (!copyDao(sDaoSession.getBookmarksDao(), exportSession.getBookmarksDao()))
return false;
if (!copyDao(sDaoSession.getFilterDao(), exportSession.getFilterDao()))
return false;
}
if (copyDao(db.downloadsDao(), newDb.downloadsDao()))
return false;
if (copyDao(db.downloadLabelDao(), newDb.downloadLabelDao()))
return false;
if (copyDao(db.downloadDirnameDao(), newDb.downloadDirnameDao()))
return false;
if (copyDao(db.historyDao(), newDb.historyDao()))
return false;
if (copyDao(db.quickSearchDao(), newDb.quickSearchDao()))
return false;
if (copyDao(db.localFavoritesDao(), newDb.localFavoritesDao()))
return false;
if (copyDao(db.filterDao(), newDb.filterDao()))
return false;
// Copy export db to data dir
File dbFile = context.getDatabasePath(ehExportName);
@@ -718,42 +476,45 @@ public class EhDB {
inputStream.close();
outputStream.close();
SQLiteDatabase db = SQLiteDatabase.openDatabase(
SQLiteDatabase oldDB = SQLiteDatabase.openDatabase(
file.getPath(), null, SQLiteDatabase.NO_LOCALIZED_COLLATORS);
int newVersion = DaoMaster.SCHEMA_VERSION;
int oldVersion = db.getVersion();
int newVersion = CUR_DB_VER;
int oldVersion = oldDB.getVersion();
if (oldVersion < newVersion) {
upgradeDB(db, oldVersion);
db.setVersion(newVersion);
upgradeDB(oldDB, oldVersion);
oldDB.setVersion(newVersion);
} else if (oldVersion > newVersion) {
return context.getString(R.string.cant_read_the_file);
}
DaoMaster daoMaster = new DaoMaster(db);
DaoSession session = daoMaster.newSession();
String tmpDBName = "tmp.db";
context.deleteDatabase(tmpDBName);
EhDatabase oldRoomDatabase = Room.databaseBuilder(context, EhDatabase.class, tmpDBName)
.createFromFile(file).allowMainThreadQueries().build();
// Downloads
DownloadManager manager = EhApplication.getDownloadManager(context);
List<DownloadInfo> downloadInfoList = session.getDownloadsDao().queryBuilder().list();
List<DownloadInfo> downloadInfoList = oldRoomDatabase.downloadsDao().list();
manager.addDownload(downloadInfoList, false);
// Download label
List<DownloadLabel> downloadLabelList = session.getDownloadLabelDao().queryBuilder().list();
List<DownloadLabel> downloadLabelList = oldRoomDatabase.downloadLabelDao().list();
manager.addDownloadLabel(downloadLabelList);
// Download dirname
List<DownloadDirname> downloadDirnameList = session.getDownloadDirnameDao().queryBuilder().list();
List<DownloadDirname> downloadDirnameList = oldRoomDatabase.downloadDirnameDao().list();
for (DownloadDirname dirname : downloadDirnameList) {
putDownloadDirname(dirname.getGid(), dirname.getDirname());
}
// History
List<HistoryInfo> historyInfoList = session.getHistoryDao().queryBuilder().list();
List<HistoryInfo> historyInfoList = oldRoomDatabase.historyDao().list();
putHistoryInfo(historyInfoList);
// QuickSearch
List<QuickSearch> quickSearchList = session.getQuickSearchDao().queryBuilder().list();
List<QuickSearch> currentQuickSearchList = sDaoSession.getQuickSearchDao().queryBuilder().list();
List<QuickSearch> quickSearchList = oldRoomDatabase.quickSearchDao().list();
List<QuickSearch> currentQuickSearchList = db.quickSearchDao().list();
List<QuickSearch> importList = new ArrayList<>();
for (QuickSearch quickSearch : quickSearchList) {
String name = quickSearch.name;
@@ -772,17 +533,14 @@ public class EhDB {
importQuickSearch(importList);
// LocalFavorites
List<LocalFavoriteInfo> localFavoriteInfoList = session.getLocalFavoritesDao().queryBuilder().list();
List<LocalFavoriteInfo> localFavoriteInfoList = oldRoomDatabase.localFavoritesDao().list();
for (LocalFavoriteInfo info : localFavoriteInfoList) {
putLocalFavorites(info);
}
// Bookmarks
// TODO
// Filter
List<Filter> filterList = session.getFilterDao().queryBuilder().list();
List<Filter> currentFilterList = sDaoSession.getFilterDao().queryBuilder().list();
List<Filter> filterList = oldRoomDatabase.filterDao().list();
List<Filter> currentFilterList = db.filterDao().list();
for (Filter filter : filterList) {
if (!currentFilterList.contains(filter)) {
addFilter(filter);
@@ -796,46 +554,4 @@ public class EhDB {
return context.getString(R.string.cant_read_the_file);
}
}
private static class DBOpenHelper extends DaoMaster.OpenHelper {
public DBOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
super(context, name, factory);
}
@Override
public void onCreate(SQLiteDatabase db) {
super.onCreate(db);
sNewDB = true;
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
upgradeDB(db, oldVersion);
}
}
private static class OldDBHelper extends SQLiteOpenHelper {
private static final String DB_NAME = "data";
private static final int VERSION = 4;
private static final String TABLE_GALLERY = "gallery";
private static final String TABLE_LOCAL_FAVOURITE = "local_favourite";
private static final String TABLE_TAG = "tag";
private static final String TABLE_DOWNLOAD = "download";
private static final String TABLE_HISTORY = "history";
public OldDBHelper(Context context) {
super(context, DB_NAME, null, VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
}
@@ -20,6 +20,9 @@ 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;
@@ -108,30 +111,52 @@ public class GalleryInfo implements Parcelable {
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() {
@@ -170,6 +195,7 @@ public class GalleryInfo implements Parcelable {
}
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)) {
@@ -0,0 +1,8 @@
package com.hippo.ehviewer.dao;
import java.util.List;
public interface BasicDao<T> {
List<T> list();
long insert(T t);
}
@@ -0,0 +1,160 @@
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,20 @@
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,30 @@
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,29 @@
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,252 @@
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,40 @@
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,30 @@
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,27 @@
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,23 @@
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,67 @@
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)) {
return false;
}
Filter filter = (Filter) o;
return filter.mode == mode && ObjectUtils.equal(filter.text, text);
}
}
@@ -0,0 +1,27 @@
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 FilterDao extends BasicDao<Filter> {
@Query("SELECT * FROM FILTER")
List<Filter> list();
@Update
void update(Filter filter);
@Insert
long insert(Filter filter);
@Delete
void delete(Filter filter);
@Query("SELECT * FROM FILTER WHERE TEXT = :text AND MODE = :mode")
Filter load(String text, int mode);
}
@@ -0,0 +1,36 @@
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 HistoryDao extends BasicDao<HistoryInfo> {
@Query("SELECT * FROM HISTORY WHERE GID = :gid")
HistoryInfo load(long gid);
@Query("SELECT * FROM HISTORY ORDER BY TIME DESC")
List<HistoryInfo> list();
@Query("SELECT * FROM HISTORY ORDER BY TIME DESC LIMIT :limit OFFSET :offset")
List<HistoryInfo> list(int offset, int limit);
@Update
void update(HistoryInfo historyInfo);
@Insert
long insert(HistoryInfo historyInfo);
@Delete
void delete(HistoryInfo historyInfos);
@Delete
void delete(List<HistoryInfo> historyInfos);
@Query("DELETE FROM HISTORY")
void deleteAll();
}
@@ -0,0 +1,160 @@
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 = "HISTORY")
public class HistoryInfo extends GalleryInfo {
public static final Creator<HistoryInfo> CREATOR = new Creator<>() {
@Override
public HistoryInfo createFromParcel(Parcel source) {
return new HistoryInfo(source);
}
@Override
public HistoryInfo[] newArray(int size) {
return new HistoryInfo[size];
}
};
@ColumnInfo(name = "MODE")
public int mode;
@ColumnInfo(name = "TIME")
public long time;
protected HistoryInfo(Parcel in) {
super(in);
this.mode = in.readInt();
this.time = in.readLong();
}
public HistoryInfo(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 HistoryInfo(int mode, long time) {
this.mode = mode;
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 getMode() {
return mode;
}
public void setMode(int mode) {
this.mode = mode;
}
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.mode);
dest.writeLong(this.time);
}
}
@@ -0,0 +1,147 @@
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 = "LOCAL_FAVORITES")
public class LocalFavoriteInfo extends GalleryInfo {
public static final Creator<LocalFavoriteInfo> CREATOR = new Creator<>() {
@Override
public LocalFavoriteInfo createFromParcel(Parcel source) {
return new LocalFavoriteInfo(source);
}
@Override
public LocalFavoriteInfo[] newArray(int size) {
return new LocalFavoriteInfo[size];
}
};
@ColumnInfo(name = "TIME")
public long time;
protected LocalFavoriteInfo(Parcel in) {
super(in);
this.time = in.readLong();
}
public LocalFavoriteInfo(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 LocalFavoriteInfo() {
}
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 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.writeLong(this.time);
}
}
@@ -0,0 +1,29 @@
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 LocalFavoritesDao extends BasicDao<LocalFavoriteInfo> {
@Query("SELECT * FROM LOCAL_FAVORITES ORDER BY TIME DESC")
List<LocalFavoriteInfo> list();
@Query("SELECT * FROM LOCAL_FAVORITES WHERE TITLE LIKE :title ORDER BY TIME DESC")
List<LocalFavoriteInfo> list(String title);
@Query("SELECT * FROM LOCAL_FAVORITES WHERE GID = :gid")
LocalFavoriteInfo load(long gid);
@Insert
long insert(LocalFavoriteInfo localFavoriteInfo);
@Delete
void delete(LocalFavoriteInfo localFavoriteInfo);
@Query("DELETE FROM LOCAL_FAVORITES WHERE GID = :gid")
void deleteByKey(long gid);
}
@@ -0,0 +1,117 @@
package com.hippo.ehviewer.dao;
import androidx.annotation.NonNull;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.PrimaryKey;
@Entity(tableName = "QUICK_SEARCH")
public class QuickSearch {
@PrimaryKey
@ColumnInfo(name = "_id")
public Long id;
@ColumnInfo(name = "NAME")
public String name;
@ColumnInfo(name = "MODE")
public int mode;
@ColumnInfo(name = "CATEGORY")
public int category;
@ColumnInfo(name = "KEYWORD")
public String keyword;
@ColumnInfo(name = "ADVANCE_SEARCH")
public int advanceSearch;
@ColumnInfo(name = "MIN_RATING")
public int minRating;
@ColumnInfo(name = "PAGE_FROM")
public int pageFrom;
@ColumnInfo(name = "PAGE_TO")
public int pageTo;
@ColumnInfo(name = "TIME")
public long time;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getMode() {
return mode;
}
public void setMode(int mode) {
this.mode = mode;
}
public int getCategory() {
return category;
}
public void setCategory(int category) {
this.category = category;
}
public String getKeyword() {
return keyword;
}
public void setKeyword(String keyword) {
this.keyword = keyword;
}
public int getAdvanceSearch() {
return advanceSearch;
}
public void setAdvanceSearch(int advanceSearch) {
this.advanceSearch = advanceSearch;
}
public int getMinRating() {
return minRating;
}
public void setMinRating(int minRating) {
this.minRating = minRating;
}
public int getPageFrom() {
return pageFrom;
}
public void setPageFrom(int pageFrom) {
this.pageFrom = pageFrom;
}
public int getPageTo() {
return pageTo;
}
public void setPageTo(int pageTo) {
this.pageTo = pageTo;
}
public long getTime() {
return time;
}
public void setTime(long time) {
this.time = time;
}
@NonNull
@Override
public String toString() {
return name;
}
}
@@ -0,0 +1,30 @@
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 QuickSearchDao extends BasicDao<QuickSearch> {
@Query("SELECT * FROM QUICK_SEARCH ORDER BY TIME ASC")
List<QuickSearch> list();
@Query("SELECT * FROM QUICK_SEARCH ORDER BY TIME ASC LIMIT :limit OFFSET :offset")
List<QuickSearch> list(int offset, int limit);
@Update
void update(List<QuickSearch> downloadLabels);
@Update
void update(QuickSearch quickSearch);
@Insert
long insert(QuickSearch quickSearch);
@Delete
void delete(QuickSearch quickSearch);
}
@@ -516,7 +516,7 @@ public class DownloadManager implements SpiderQueen.OnSpiderListener {
DownloadInfo info = mAllInfoMap.get(gid);
if (info != null) {
// Remove from DB
EhDB.removeDownloadInfo(info.gid);
EhDB.removeDownloadInfo(info);
// Remove all list and map
mAllInfoList.remove(info);
@@ -552,7 +552,7 @@ public class DownloadManager implements SpiderQueen.OnSpiderListener {
}
// Remove from DB
EhDB.removeDownloadInfo(info.gid);
EhDB.removeDownloadInfo(info);
// Remove from all info map
mAllInfoList.remove(info);
@@ -17,6 +17,7 @@
package com.hippo.ehviewer.ui;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
@@ -123,6 +124,9 @@ public abstract class EhActivity extends AppCompatActivity {
@Override
protected void onResume() {
if (Settings.getSecurity() && SecurityActivity.Companion.isAuthenticationSupported(this) && EhApplication.locked) {
startActivity(new Intent(this, SecurityActivity.class));
}
super.onResume();
if (Settings.getEnabledSecurity()) {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE,
@@ -47,7 +47,6 @@ import com.google.android.material.navigation.NavigationView;
import com.google.android.material.snackbar.Snackbar;
import com.hippo.app.EditTextDialogBuilder;
import com.hippo.ehviewer.AppConfig;
import com.hippo.ehviewer.EhApplication;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.Settings;
import com.hippo.ehviewer.client.EhTagDatabase;
@@ -67,11 +66,9 @@ import com.hippo.ehviewer.ui.scene.GalleryListScene;
import com.hippo.ehviewer.ui.scene.GalleryPreviewsScene;
import com.hippo.ehviewer.ui.scene.HistoryScene;
import com.hippo.ehviewer.ui.scene.ProgressScene;
import com.hippo.ehviewer.ui.scene.SecurityScene;
import com.hippo.ehviewer.ui.scene.SelectSiteScene;
import com.hippo.ehviewer.ui.scene.SignInScene;
import com.hippo.ehviewer.ui.scene.SolidScene;
import com.hippo.ehviewer.ui.scene.WarningScene;
import com.hippo.ehviewer.ui.scene.WebViewSignInScene;
import com.hippo.ehviewer.widget.EhStageLayout;
import com.hippo.io.UniFileInputStreamPipe;
@@ -98,8 +95,6 @@ public final class MainActivity extends StageActivity
private static final String KEY_NAV_CHECKED_ITEM = "nav_checked_item";
static {
registerLaunchMode(SecurityScene.class, SceneFragment.LAUNCH_MODE_SINGLE_TASK);
registerLaunchMode(WarningScene.class, SceneFragment.LAUNCH_MODE_SINGLE_TASK);
registerLaunchMode(SignInScene.class, SceneFragment.LAUNCH_MODE_SINGLE_TASK);
registerLaunchMode(WebViewSignInScene.class, SceneFragment.LAUNCH_MODE_SINGLE_TASK);
registerLaunchMode(CookieSignInScene.class, SceneFragment.LAUNCH_MODE_SINGLE_TASK);
@@ -143,11 +138,7 @@ public final class MainActivity extends StageActivity
@NonNull
@Override
protected Announcer getLaunchAnnouncer() {
if (Settings.getSecurity() && SecurityScene.Companion.isAuthenticationSupported(this)) {
return new Announcer(SecurityScene.class);
} else if (Settings.getShowWarning()) {
return new Announcer(WarningScene.class);
} else if (EhUtils.needSignedIn(this)) {
if (EhUtils.needSignedIn(this)) {
return new Announcer(SignInScene.class);
} else if (Settings.getSelectSite()) {
return new Announcer(SelectSiteScene.class);
@@ -161,17 +152,7 @@ public final class MainActivity extends StageActivity
// Sometimes scene can't show directly
private Announcer processAnnouncer(Announcer announcer) {
if (0 == getSceneCount()) {
if (Settings.getSecurity() && SecurityScene.Companion.isAuthenticationSupported(this)) {
Bundle newArgs = new Bundle();
newArgs.putString(SecurityScene.KEY_TARGET_SCENE, announcer.getClazz().getName());
newArgs.putBundle(SecurityScene.KEY_TARGET_ARGS, announcer.getArgs());
return new Announcer(SecurityScene.class).setArgs(newArgs);
} else if (Settings.getShowWarning()) {
Bundle newArgs = new Bundle();
newArgs.putString(WarningScene.KEY_TARGET_SCENE, announcer.getClazz().getName());
newArgs.putBundle(WarningScene.KEY_TARGET_ARGS, announcer.getArgs());
return new Announcer(WarningScene.class).setArgs(newArgs);
} else if (EhUtils.needSignedIn(this)) {
if (EhUtils.needSignedIn(this)) {
Bundle newArgs = new Bundle();
newArgs.putString(SignInScene.KEY_TARGET_SCENE, announcer.getClazz().getName());
newArgs.putBundle(SignInScene.KEY_TARGET_ARGS, announcer.getArgs());
@@ -427,9 +408,6 @@ public final class MainActivity extends StageActivity
@Override
protected void onResume() {
if (Settings.getSecurity() && SecurityScene.Companion.isAuthenticationSupported(this) && EhApplication.locked) {
startScene(new Announcer(SecurityScene.class), true);
}
super.onResume();
setNavCheckedItem(mNavCheckedItem);
checkClipboardUrl();
@@ -16,10 +16,11 @@
* If not, see <https://www.gnu.org/licenses/>.
*/
package com.hippo.ehviewer.ui.scene
package com.hippo.ehviewer.ui
import android.content.Context
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.biometric.BiometricManager
import androidx.biometric.BiometricManager.Authenticators.DEVICE_CREDENTIAL
import androidx.biometric.BiometricPrompt
@@ -30,14 +31,10 @@ import androidx.fragment.app.FragmentActivity
import com.hippo.ehviewer.EhApplication
import com.hippo.ehviewer.R
class SecurityScene : SolidScene() {
override fun needShowLeftDrawer(): Boolean {
return false
}
class SecurityActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (isAuthenticationSupported(requireContext()))
if (isAuthenticationSupported(this))
startAuthentication(getString(R.string.settings_privacy_require_unlock))
else
onSuccess()
@@ -52,7 +49,7 @@ class SecurityScene : SolidScene() {
title = title,
subtitle = subtitle,
confirmationRequired = confirmationRequired,
executor = ContextCompat.getMainExecutor(requireContext()),
executor = ContextCompat.getMainExecutor(this),
callback = AuthenticationCallback()
)
}
@@ -70,7 +67,7 @@ class SecurityScene : SolidScene() {
errorCode: Int,
errString: CharSequence
) {
requireActivity().finish()
moveTaskToBack(true)
}
}
@@ -84,8 +81,6 @@ class SecurityScene : SolidScene() {
private fun onSuccess() {
EhApplication.locked = false
if (stackIndex == 0)
startSceneForCheckStep(CHECK_STEP_SECURITY, arguments)
finish()
}
}
@@ -22,7 +22,7 @@ import android.os.Bundle
import androidx.preference.SwitchPreferenceCompat
import com.hippo.ehviewer.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.ui.scene.SecurityScene.Companion.isAuthenticationSupported
import com.hippo.ehviewer.ui.SecurityActivity.Companion.isAuthenticationSupported
/**
* Created by Mo10 on 2018/2/10.
@@ -22,21 +22,17 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.Display;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
@@ -45,11 +41,11 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.PopupMenu;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat;
import androidx.core.view.ViewCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.SimpleItemAnimator;
@@ -57,12 +53,6 @@ import androidx.recyclerview.widget.StaggeredGridLayoutManager;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.h6ah4i.android.widget.advrecyclerview.animator.DraggableItemAnimator;
import com.h6ah4i.android.widget.advrecyclerview.animator.GeneralItemAnimator;
import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemAdapter;
import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange;
import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager;
import com.h6ah4i.android.widget.advrecyclerview.utils.AbstractDraggableItemViewHolder;
import com.hippo.app.CheckBoxDialogBuilder;
import com.hippo.app.EditTextDialogBuilder;
import com.hippo.conaco.DataContainer;
@@ -83,7 +73,6 @@ import com.hippo.ehviewer.download.DownloadManager;
import com.hippo.ehviewer.download.DownloadService;
import com.hippo.ehviewer.spider.SpiderDen;
import com.hippo.ehviewer.ui.GalleryActivity;
import com.hippo.ehviewer.ui.MainActivity;
import com.hippo.ehviewer.widget.SimpleRatingView;
import com.hippo.io.UniFileInputStreamPipe;
import com.hippo.scene.Announcer;
@@ -97,7 +86,6 @@ import com.hippo.widget.recyclerview.AutoStaggeredGridLayoutManager;
import com.hippo.yorozuya.AssertUtils;
import com.hippo.yorozuya.FileUtils;
import com.hippo.yorozuya.IOUtils;
import com.hippo.yorozuya.LayoutUtils;
import com.hippo.yorozuya.ObjectUtils;
import com.hippo.yorozuya.ViewUtils;
import com.hippo.yorozuya.collect.LongList;
@@ -556,20 +544,13 @@ public class DownloadsScene extends ToolbarScene
initLabels();
RecyclerViewDragDropManager dragDropManager = new RecyclerViewDragDropManager();
dragDropManager.setInitiateOnLongPress(true);
dragDropManager.setInitiateOnTouch(false);
dragDropManager.setDraggingItemAlpha(0.8f);
mLabelAdapter = new DownloadLabelAdapter(inflater);
final EasyRecyclerView recyclerView = view.findViewById(R.id.recycler_view_drawer);
recyclerView.setLayoutManager(new LinearLayoutManager(context));
mLabelAdapter.setHasStableIds(true);
final GeneralItemAnimator animator = new DraggableItemAnimator();
recyclerView.setItemAnimator(animator);
recyclerView.setAdapter(dragDropManager.createWrappedAdapter(mLabelAdapter));
dragDropManager.attachRecyclerView(recyclerView);
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new DownloadLabelItemTouchHelperCallback());
itemTouchHelper.attachToRecyclerView(recyclerView);
recyclerView.setAdapter(mLabelAdapter);
return view;
}
@@ -892,7 +873,7 @@ public class DownloadsScene extends ToolbarScene
holder.speed.setText(FileUtils.humanReadableByteCount(speed, false) + "/S");
}
private static class DownloadLabelHolder extends AbstractDraggableItemViewHolder {
private static class DownloadLabelHolder extends RecyclerView.ViewHolder {
private final TextView label;
private final ImageView option;
@@ -971,7 +952,7 @@ public class DownloadsScene extends ToolbarScene
}
}
private class DownloadLabelAdapter extends RecyclerView.Adapter<DownloadLabelHolder> implements DraggableItemAdapter<DownloadLabelHolder> {
private class DownloadLabelAdapter extends RecyclerView.Adapter<DownloadLabelHolder> {
private final LayoutInflater mInflater;
@@ -1025,36 +1006,15 @@ public class DownloadsScene extends ToolbarScene
});
if (position > 0) {
holder.option.setVisibility(View.VISIBLE);
holder.itemView.setOnLongClickListener(v -> {
holder.option.setOnClickListener(v -> {
if (context != null) {
PopupMenu popupMenu = new PopupMenu(context, holder.option);
popupMenu.inflate(R.menu.download_label_option);
popupMenu.show();
popupMenu.setOnMenuItemClickListener(item -> {
int itemId = item.getItemId();
if (itemId == R.id.menu_label_rename) {
EditTextDialogBuilder builder = new EditTextDialogBuilder(
context, label, getString(R.string.download_labels));
builder.setTitle(R.string.rename_label_title);
builder.setPositiveButton(android.R.string.ok, null);
AlertDialog dialog = builder.show();
new RenameLabelDialogHelper(builder, dialog, label);
} else if (itemId == R.id.menu_label_remove) {
new MaterialAlertDialogBuilder(requireContext())
.setTitle(getString(R.string.delete_label_title))
.setMessage(getString(R.string.delete_label_message, label))
.setPositiveButton(R.string.delete, (dialog, which) -> {
mDownloadManager.deleteLabel(label);
mLabels.remove(position);
notifyDataSetChanged();
})
.setNegativeButton(android.R.string.cancel, null)
.show();
}
return false;
});
EditTextDialogBuilder builder = new EditTextDialogBuilder(
context, label, getString(R.string.download_labels));
builder.setTitle(R.string.rename_label_title);
builder.setPositiveButton(android.R.string.ok, null);
AlertDialog dialog = builder.show();
new RenameLabelDialogHelper(builder, dialog, label);
}
return true;
});
} else {
holder.option.setVisibility(View.GONE);
@@ -1071,43 +1031,6 @@ public class DownloadsScene extends ToolbarScene
public int getItemCount() {
return mLabels != null ? mLabels.size() : 0;
}
@Override
public boolean onCheckCanStartDrag(@NonNull DownloadLabelHolder holder, int position, int x, int y) {
return position != 0 && x > holder.option.getX() && y > holder.option.getY();
}
@Override
public ItemDraggableRange onGetItemDraggableRange(@NonNull DownloadLabelHolder holder, int position) {
return new ItemDraggableRange(1, getItemCount() - 1);
}
@Override
public void onMoveItem(int fromPosition, int toPosition) {
Context context = getContext();
if (null == context || fromPosition == toPosition || toPosition == 0) {
return;
}
EhApplication.getDownloadManager(context).moveLabel(fromPosition - 1, toPosition - 1);
final String item = mLabels.remove(fromPosition);
mLabels.add(toPosition, item);
}
@Override
public boolean onCheckCanDrop(int draggingPosition, int dropPosition) {
return dropPosition != 0;
}
@Override
public void onItemDragStarted(int position) {
notifyDataSetChanged();
}
@Override
public void onItemDragFinished(int fromPosition, int toPosition, boolean result) {
notifyDataSetChanged();
}
}
private class DeleteRangeDialogHelper implements DialogInterface.OnClickListener {
@@ -1445,4 +1368,43 @@ public class DownloadsScene extends ToolbarScene
}
}
}
private class DownloadLabelItemTouchHelperCallback extends ItemTouchHelper.Callback {
@Override
public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
return makeMovementFlags(ItemTouchHelper.UP | ItemTouchHelper.DOWN, ItemTouchHelper.LEFT);
}
@SuppressLint("NotifyDataSetChanged")
@Override
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
int fromPosition = viewHolder.getBindingAdapterPosition();
int toPosition = target.getBindingAdapterPosition();
Context context = getContext();
if (null == context || fromPosition == toPosition || toPosition == 0 || fromPosition == 0) {
return false;
}
EhApplication.getDownloadManager(context).moveLabel(fromPosition - 1, toPosition - 1);
final String item = mLabels.remove(fromPosition);
mLabels.add(toPosition, item);
mLabelAdapter.notifyDataSetChanged();
return true;
}
@SuppressLint("NotifyDataSetChanged")
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
int position = viewHolder.getBindingAdapterPosition();
if (mDownloadManager == null)
return;
if (position != 0) {
String label = mLabels.get(position);
mDownloadManager.deleteLabel(label);
}
mLabels.remove(position);
mLabelAdapter.notifyDataSetChanged();
}
}
}
@@ -18,13 +18,10 @@ package com.hippo.ehviewer.ui.scene;
import android.animation.Animator;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
@@ -33,10 +30,8 @@ import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.style.ImageSpan;
import android.view.Display;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
@@ -50,23 +45,17 @@ import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.PopupMenu;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsAnimationCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.h6ah4i.android.widget.advrecyclerview.animator.DraggableItemAnimator;
import com.h6ah4i.android.widget.advrecyclerview.animator.GeneralItemAnimator;
import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemAdapter;
import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange;
import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager;
import com.h6ah4i.android.widget.advrecyclerview.utils.AbstractDraggableItemViewHolder;
import com.hippo.app.EditTextDialogBuilder;
import com.hippo.drawable.AddDeleteDrawable;
import com.hippo.drawable.DrawerArrowDrawable;
@@ -109,7 +98,6 @@ import com.hippo.widget.FabLayout;
import com.hippo.widget.SearchBarMover;
import com.hippo.yorozuya.AnimationUtils;
import com.hippo.yorozuya.AssertUtils;
import com.hippo.yorozuya.LayoutUtils;
import com.hippo.yorozuya.MathUtils;
import com.hippo.yorozuya.SimpleAnimatorListener;
import com.hippo.yorozuya.StringUtils;
@@ -753,19 +741,13 @@ public final class GalleryListScene extends BaseScene
Context context = getContext();
AssertUtils.assertNotNull(context);
RecyclerViewDragDropManager dragDropManager = new RecyclerViewDragDropManager();
dragDropManager.setInitiateOnLongPress(true);
dragDropManager.setInitiateOnTouch(false);
dragDropManager.setDraggingItemAlpha(0.8f);
final EasyRecyclerView recyclerView = view.findViewById(R.id.recycler_view_drawer);
recyclerView.setLayoutManager(new LinearLayoutManager(context));
final QsDrawerAdapter qsDrawerAdapter = new QsDrawerAdapter(inflater);
qsDrawerAdapter.setHasStableIds(true);
final GeneralItemAnimator animator = new DraggableItemAnimator();
recyclerView.setItemAnimator(animator);
recyclerView.setAdapter(dragDropManager.createWrappedAdapter(qsDrawerAdapter));
dragDropManager.attachRecyclerView(recyclerView);
recyclerView.setAdapter(qsDrawerAdapter);
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new GalleryListQSItemTouchHelperCallback(qsDrawerAdapter));
itemTouchHelper.attachToRecyclerView(recyclerView);
mQuickSearchList = EhDB.getAllQuickSearch();
tip.setText(R.string.quick_search_tip);
if (mIsTopList) {
@@ -1492,7 +1474,7 @@ public final class GalleryListScene extends BaseScene
}
}
private static class QsDrawerHolder extends AbstractDraggableItemViewHolder {
private static class QsDrawerHolder extends RecyclerView.ViewHolder {
private final TextView key;
private final ImageView option;
@@ -1537,7 +1519,7 @@ public final class GalleryListScene extends BaseScene
}
}
private class QsDrawerAdapter extends RecyclerView.Adapter<QsDrawerHolder> implements DraggableItemAdapter<QsDrawerHolder> {
private class QsDrawerAdapter extends RecyclerView.Adapter<QsDrawerHolder> {
private final LayoutInflater mInflater;
@@ -1568,34 +1550,6 @@ public final class GalleryListScene extends BaseScene
setState(STATE_NORMAL);
closeDrawer(Gravity.RIGHT);
});
holder.itemView.setOnLongClickListener(v -> {
PopupMenu popupMenu = new PopupMenu(requireContext(), holder.option);
popupMenu.inflate(R.menu.quicksearch_option);
popupMenu.show();
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
final QuickSearch quickSearch = mQuickSearchList.get(position);
@Override
public boolean onMenuItemClick(MenuItem item) {
if (item.getItemId() == R.id.menu_qs_remove) {
new MaterialAlertDialogBuilder(requireContext())
.setTitle(getString(R.string.delete_quick_search_title))
.setMessage(getString(R.string.delete_quick_search_message, quickSearch.name))
.setPositiveButton(R.string.delete, (dialog, which) -> {
EhDB.deleteQuickSearch(quickSearch);
mQuickSearchList.remove(position);
notifyDataSetChanged();
})
.setNegativeButton(android.R.string.cancel, null)
.show();
return true;
}
return false;
}
});
return true;
});
} else {
int[] keywords = {11, 12, 13, 15};
int[] toplists = {R.string.toplist_alltime, R.string.toplist_pastyear, R.string.toplist_pastmonth, R.string.toplist_yesterday};
@@ -1631,44 +1585,6 @@ public final class GalleryListScene extends BaseScene
public int getItemCount() {
return !mIsTopList ? mQuickSearchList != null ? mQuickSearchList.size() : 0 : 4;
}
@Override
public boolean onCheckCanStartDrag(@NonNull QsDrawerHolder holder, int position, int x, int y) {
return !mIsTopList && x > holder.option.getX() && y > holder.option.getY();
}
@Override
public ItemDraggableRange onGetItemDraggableRange(@NonNull QsDrawerHolder holder, int position) {
return null;
}
@Override
public void onMoveItem(int fromPosition, int toPosition) {
if (fromPosition == toPosition) {
return;
}
if (null == mQuickSearchList) {
return;
}
EhDB.moveQuickSearch(fromPosition, toPosition);
final QuickSearch item = mQuickSearchList.remove(fromPosition);
mQuickSearchList.add(toPosition, item);
}
@Override
public boolean onCheckCanDrop(int draggingPosition, int dropPosition) {
return true;
}
@Override
public void onItemDragStarted(int position) {
notifyDataSetChanged();
}
@Override
public void onItemDragFinished(int fromPosition, int toPosition, boolean result) {
notifyDataSetChanged();
}
}
private abstract class UrlSuggestion extends SearchBar.Suggestion {
@@ -1853,4 +1769,47 @@ public final class GalleryListScene extends BaseScene
}
}
}
private class GalleryListQSItemTouchHelperCallback extends ItemTouchHelper.Callback {
private final QsDrawerAdapter mAdapter;
public GalleryListQSItemTouchHelperCallback(QsDrawerAdapter adapter) {
mAdapter = adapter;
}
@Override
public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
return makeMovementFlags(ItemTouchHelper.UP | ItemTouchHelper.DOWN, ItemTouchHelper.LEFT);
}
@SuppressLint("NotifyDataSetChanged")
@Override
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
int fromPosition = viewHolder.getBindingAdapterPosition();
int toPosition = target.getBindingAdapterPosition();
if (fromPosition == toPosition) {
return false;
}
if (null == mQuickSearchList) {
return false;
}
EhDB.moveQuickSearch(fromPosition, toPosition);
final QuickSearch item = mQuickSearchList.remove(fromPosition);
mQuickSearchList.add(toPosition, item);
mAdapter.notifyDataSetChanged();
return true;
}
@SuppressLint("NotifyDataSetChanged")
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
if (mQuickSearchList == null)
return;
int position = viewHolder.getBindingAdapterPosition();
final QuickSearch quickSearch = mQuickSearchList.get(position);
EhDB.deleteQuickSearch(quickSearch);
mQuickSearchList.remove(position);
mAdapter.notifyDataSetChanged();
}
}
}
@@ -36,20 +36,11 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.core.view.ViewCompat;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.h6ah4i.android.widget.advrecyclerview.animator.GeneralItemAnimator;
import com.h6ah4i.android.widget.advrecyclerview.animator.SwipeDismissItemAnimator;
import com.h6ah4i.android.widget.advrecyclerview.swipeable.RecyclerViewSwipeManager;
import com.h6ah4i.android.widget.advrecyclerview.swipeable.SwipeableItemAdapter;
import com.h6ah4i.android.widget.advrecyclerview.swipeable.SwipeableItemConstants;
import com.h6ah4i.android.widget.advrecyclerview.swipeable.action.SwipeResultAction;
import com.h6ah4i.android.widget.advrecyclerview.swipeable.action.SwipeResultActionDefault;
import com.h6ah4i.android.widget.advrecyclerview.swipeable.action.SwipeResultActionRemoveItem;
import com.h6ah4i.android.widget.advrecyclerview.touchguard.RecyclerViewTouchActionGuardManager;
import com.h6ah4i.android.widget.advrecyclerview.utils.AbstractSwipeableItemViewHolder;
import com.hippo.easyrecyclerview.EasyRecyclerView;
import com.hippo.easyrecyclerview.FastScroller;
import com.hippo.easyrecyclerview.HandlerDrawable;
@@ -79,8 +70,6 @@ import com.hippo.widget.recyclerview.AutoStaggeredGridLayoutManager;
import com.hippo.yorozuya.AssertUtils;
import com.hippo.yorozuya.ViewUtils;
import org.greenrobot.greendao.query.LazyList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -103,7 +92,7 @@ public class HistoryScene extends ToolbarScene {
@Nullable
private RecyclerView.Adapter<?> mAdapter;
@Nullable
private LazyList<HistoryInfo> mLazyList;
private List<HistoryInfo> mLazyList;
private DownloadManager mDownloadManager;
private DownloadManager.DownloadInfoListener mDownloadInfoListener;
@@ -206,17 +195,9 @@ public class HistoryScene extends ToolbarScene {
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
mTip.setCompoundDrawables(null, drawable, null, null);
RecyclerViewTouchActionGuardManager guardManager = new RecyclerViewTouchActionGuardManager();
guardManager.setInterceptVerticalScrollingWhileAnimationRunning(true);
guardManager.setEnabled(true);
RecyclerViewSwipeManager swipeManager = new RecyclerViewSwipeManager();
mAdapter = new HistoryAdapter();
mAdapter.setHasStableIds(true);
mAdapter = swipeManager.createWrappedAdapter(mAdapter);
mRecyclerView.setAdapter(mAdapter);
final GeneralItemAnimator animator = new SwipeDismissItemAnimator();
animator.setSupportsChangeAnimations(false);
mRecyclerView.setItemAnimator(animator);
AutoStaggeredGridLayoutManager layoutManager = new AutoStaggeredGridLayoutManager(
0, StaggeredGridLayoutManager.VERTICAL);
layoutManager.setColumnSize(resources.getDimensionPixelOffset(Settings.getDetailSizeResId()));
@@ -229,9 +210,8 @@ public class HistoryScene extends ToolbarScene {
int paddingV = resources.getDimensionPixelOffset(R.dimen.gallery_list_margin_v);
MarginItemDecoration decoration = new MarginItemDecoration(interval, paddingH, paddingV, paddingH, paddingV);
mRecyclerView.addItemDecoration(decoration);
guardManager.attachRecyclerView(mRecyclerView);
swipeManager.attachRecyclerView(mRecyclerView);
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new HistoryItemTouchHelperCallback());
itemTouchHelper.attachToRecyclerView(mRecyclerView);
mFastScroller.attachToRecyclerView(mRecyclerView);
HandlerDrawable handlerDrawable = new HandlerDrawable();
handlerDrawable.setColor(ResourcesKt.resolveColor(getTheme(), com.google.android.material.R.attr.colorPrimary));
@@ -255,7 +235,6 @@ public class HistoryScene extends ToolbarScene {
super.onDestroyView();
if (null != mLazyList) {
mLazyList.close();
mLazyList = null;
if (mAdapter != null) {
mAdapter.notifyDataSetChanged();
@@ -272,11 +251,7 @@ public class HistoryScene extends ToolbarScene {
// Remember to notify
private void updateLazyList() {
LazyList<HistoryInfo> lazyList = EhDB.getHistoryLazyList();
if (mLazyList != null) {
mLazyList.close();
}
mLazyList = lazyList;
mLazyList = EhDB.getHistoryLazyList();
}
private void updateView(boolean animation) {
@@ -502,7 +477,7 @@ public class HistoryScene extends ToolbarScene {
}
}
private static class HistoryHolder extends AbstractSwipeableItemViewHolder {
private static class HistoryHolder extends RecyclerView.ViewHolder {
public final View card;
public final LoadImageView thumb;
@@ -529,12 +504,6 @@ public class HistoryScene extends ToolbarScene {
pages = itemView.findViewById(R.id.pages);
downloaded = itemView.findViewById(R.id.downloaded);
}
@NonNull
@Override
public View getSwipeableContainerView() {
return card;
}
}
private class MoveDialogHelper implements DialogInterface.OnClickListener {
@@ -570,8 +539,7 @@ public class HistoryScene extends ToolbarScene {
}
}
private class HistoryAdapter extends RecyclerView.Adapter<HistoryHolder>
implements SwipeableItemAdapter<HistoryHolder> {
private class HistoryAdapter extends RecyclerView.Adapter<HistoryHolder> {
private final LayoutInflater mInflater;
private final int mListThumbWidth;
@@ -649,55 +617,30 @@ public class HistoryScene extends ToolbarScene {
public int getItemCount() {
return null != mLazyList ? mLazyList.size() : 0;
}
@Override
public int onGetSwipeReactionType(@NonNull HistoryHolder holder, int position, int x, int y) {
return SwipeableItemConstants.REACTION_CAN_SWIPE_LEFT;
}
@Override
public void onSwipeItemStarted(@NonNull HistoryHolder holder, int position) {
}
@Override
public void onSetSwipeBackground(@NonNull HistoryHolder holder, int position, int type) {
}
@Override
public SwipeResultAction onSwipeItem(@NonNull HistoryHolder holder, int position, int result) {
switch (result) {
case SwipeableItemConstants.RESULT_SWIPED_LEFT:
return new SwipeResultActionClear(position);
case SwipeableItemConstants.RESULT_SWIPED_RIGHT:
case SwipeableItemConstants.RESULT_CANCELED:
case SwipeableItemConstants.RESULT_NONE:
case SwipeableItemConstants.RESULT_SWIPED_DOWN:
case SwipeableItemConstants.RESULT_SWIPED_UP:
default:
return new SwipeResultActionDefault();
}
}
}
private class SwipeResultActionClear extends SwipeResultActionRemoveItem {
private class HistoryItemTouchHelperCallback extends ItemTouchHelper.Callback {
private final int mPosition;
protected SwipeResultActionClear(int position) {
mPosition = position;
@Override
public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
return makeMovementFlags(0, ItemTouchHelper.LEFT);
}
@Override
protected void onPerformAction() {
super.onPerformAction();
if (null == mLazyList || null == mAdapter) {
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
return false;
}
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
int mPosition = viewHolder.getBindingAdapterPosition();
if (null == mLazyList || mAdapter == null) {
return;
}
HistoryInfo info = mLazyList.get(mPosition);
EhDB.deleteHistoryInfo(info);
updateLazyList();
mAdapter.notifyDataSetChanged();
mAdapter.notifyItemRemoved(mPosition);
updateView(true);
}
}
@@ -28,26 +28,14 @@ import com.hippo.scene.Announcer;
*/
public class SolidScene extends BaseScene {
public static final int CHECK_STEP_SECURITY = 0;
public static final int CHECK_STEP_WARNING = 1;
public static final int CHECK_STEP_SIGN_IN = 2;
public static final int CHECK_STEP_SELECT_SITE = 3;
public static final int CHECK_STEP_SIGN_IN = 1;
public static final int CHECK_STEP_SELECT_SITE = 2;
public static final String KEY_TARGET_SCENE = "target_scene";
public static final String KEY_TARGET_ARGS = "target_args";
private static final String TAG = SolidScene.class.getSimpleName();
public void startSceneForCheckStep(int checkStep, Bundle args) {
switch (checkStep) {
case CHECK_STEP_SECURITY:
if (Settings.getShowWarning()) {
startScene(new Announcer(WarningScene.class).setArgs(args), true);
break;
}
case CHECK_STEP_WARNING:
if (EhUtils.needSignedIn(getContext())) {
startScene(new Announcer(SignInScene.class).setArgs(args), true);
break;
}
case CHECK_STEP_SIGN_IN:
if (Settings.getSelectSite()) {
startScene(new Announcer(SelectSiteScene.class).setArgs(args), true);
@@ -1,85 +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.ui.scene;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.Settings;
import com.hippo.ehviewer.ui.MainActivity;
import com.hippo.ehviewer.ui.annotation.ViewLifeCircle;
import com.hippo.yorozuya.ViewUtils;
public final class WarningScene extends SolidScene implements View.OnClickListener {
@Nullable
private View mReject;
@Nullable
@ViewLifeCircle
private View mAccept;
@Override
public boolean needShowLeftDrawer() {
return false;
}
@NonNull
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.scene_warning, container, false);
mReject = ViewUtils.$$(view, R.id.reject);
mAccept = ViewUtils.$$(view, R.id.accept);
mReject.setOnClickListener(this);
mAccept.setOnClickListener(this);
return view;
}
@Override
public void onDestroyView() {
super.onDestroyView();
mReject = null;
mAccept = null;
}
@Override
public void onClick(View v) {
if (mReject == v) {
finishStage();
} else if (mAccept == v) {
// Never show this warning anymore
Settings.putShowWarning(false);
// Start new scene and finish it self
MainActivity activity = getMainActivity();
if (null != activity) {
startSceneForCheckStep(CHECK_STEP_WARNING, getArguments());
}
finish();
}
}
}
@@ -28,29 +28,24 @@ import java.util.ArrayList;
*/
public final class Image {
public static final int FORMAT_NORMAL = 0;
public static final int FORMAT_ANIMATED = 1;
private static final ArrayList<Image> imageList = new ArrayList<>();
private static boolean needEvictAll = false;
private final int mFormat;
private final int mWidth;
private final int mHeight;
private long mNativePtr;
private Image(long nativePtr, int format, int width, int height) {
private Image(long nativePtr) {
if (needEvictAll)
evictAll();
mNativePtr = nativePtr;
mFormat = format;
mWidth = width;
mHeight = height;
imageList.add(this);
}
private static Image newFromAddr(long addr) {
if (addr == 0)
return null;
return new Image(addr);
}
public static void lazyEvictAll() {
needEvictAll = true;
}
@@ -65,7 +60,7 @@ public final class Image {
*/
@Nullable
public static Image decode(FileDescriptor fd, boolean partially) {
return nativeDecode(fd);
return newFromAddr(nativeDecode(fd));
}
/**
@@ -73,7 +68,7 @@ public final class Image {
*/
@Nullable
public static Image decode(Integer fd, boolean partially) {
return nativeDecodeFdInt(fd);
return newFromAddr(nativeDecodeFdInt(fd));
}
/**
@@ -81,7 +76,7 @@ public final class Image {
*/
@Nullable
public static Image decodeAddr(Long addr, boolean partially) {
return nativeDecodeAddr(addr);
return newFromAddr(nativeDecodeAddr(addr));
}
/**
@@ -89,7 +84,7 @@ public final class Image {
*/
@Nullable
public static Image create(Bitmap bitmap) {
return nativeCreate(bitmap);
return newFromAddr(nativeCreate(bitmap));
}
/**
@@ -100,13 +95,13 @@ public final class Image {
return imageList.size();
}
private static native Image nativeDecode(FileDescriptor fd);
private static native long nativeDecode(FileDescriptor fd);
private static native Image nativeDecodeFdInt(int fd);
private static native long nativeDecodeFdInt(int fd);
private static native Image nativeDecodeAddr(long addr);
private static native long nativeDecodeAddr(long addr);
private static native Image nativeCreate(Bitmap bitmap);
private static native long nativeCreate(Bitmap bitmap);
private static native void nativeRender(long nativePtr,
int srcX, int srcY, Bitmap dst, int dstX, int dstY,
@@ -122,25 +117,34 @@ public final class Image {
private static native void nativeRecycle(long nativePtr);
private static native int nativeGetFormat(long nativePtr);
private static native int nativeGetWidth(long nativePtr);
private static native int nativeGetHeight(long nativePtr);
/**
* Return the format of the image
*/
public int getFormat() {
return mFormat;
checkRecycled();
return nativeGetFormat(mNativePtr);
}
/**
* Return the width of the image
*/
public int getWidth() {
return mWidth;
checkRecycled();
return nativeGetWidth(mNativePtr);
}
/**
* Return the height of the image
*/
public int getHeight() {
return mHeight;
checkRecycled();
return nativeGetHeight(mNativePtr);
}
private void checkRecycled() {
@@ -1,101 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2022 hathlife
~
~ 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/>.
~
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="end"
android:orientation="vertical"
app:fitsSystemWindowsInsets="top|bottom">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<LinearLayout
android:layout_width="480dp"
android:layout_height="match_parent"
android:orientation="vertical">
<Space
android:layout_width="match_parent"
android:layout_height="108dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingHorizontal="16dp"
android:paddingStart="128dp"
android:paddingTop="16dp"
android:paddingEnd="12dp"
android:text="@string/app_waring"
android:textColor="?android:attr/textColorPrimary"
android:textSize="20sp"
app:drawableTopCompat="@drawable/v_alert_red_x144" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Space
android:layout_width="match_parent"
android:layout_height="224dp"
android:layout_weight="1" />
<Button
android:id="@+id/reject"
style="@style/Widget.Material3.Button.OutlinedButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="4dp"
android:layout_weight="1"
android:insetLeft="80dp"
android:insetRight="80dp"
android:insetBottom="16dp"
android:text="@string/reject" />
<Button
android:id="@+id/accept"
style="@style/Widget.Material3.Button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="4dp"
android:layout_weight="1"
android:insetLeft="80dp"
android:insetRight="80dp"
android:insetBottom="16dp"
android:text="@string/accept" />
<Space
android:layout_width="match_parent"
android:layout_height="176dp"
android:layout_weight="1" />
</LinearLayout>
</LinearLayout>
</FrameLayout>
-82
View File
@@ -1,82 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ 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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingHorizontal="@dimen/keyline_margin"
android:paddingTop="@dimen/keyline_margin"
app:fitsSystemWindowsInsets="top|bottom">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:padding="@dimen/keyline_margin"
app:srcCompat="@drawable/v_alert_red_x48" />
<ScrollView
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
android:clipToPadding="false"
android:paddingVertical="@dimen/keyline_margin">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingHorizontal="32dp"
android:text="@string/app_waring"
android:textColor="?android:attr/textColorPrimary"
android:textSize="@dimen/text_little_small" />
</ScrollView>
<LinearLayout
android:id="@+id/buttonPanel"
style="?attr/buttonBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:gravity="bottom"
android:orientation="horizontal"
android:paddingLeft="12dp"
android:paddingTop="4dp"
android:paddingRight="12dp"
android:paddingBottom="20dp">
<Button
android:id="@+id/reject"
style="@style/Widget.Material3.Button.OutlinedButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="4dp"
android:layout_weight="1"
android:text="@string/reject" />
<Button
android:id="@+id/accept"
style="@style/Widget.Material3.Button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="4dp"
android:layout_weight="1"
android:text="@string/accept" />
</LinearLayout>
</LinearLayout>
@@ -106,7 +106,6 @@
<string name="content_layout_restore_tip">点击重试</string>
<string name="write_rationale">EhViewer 将申请设备存储空间访问权限以便下载画廊。您愿意授权吗?</string>
<string name="you_rejected_me">好痛</string>
<string name="analytics_explain">您同意让开发者收集您的设备信息与使用情况吗?这将对开发有很大帮助并将为您启用应用内更新。&lt;br&gt;&lt;br&gt;数据统计服务由 Microsoft AppCenter 提供,其隐私政策可在 &lt;a href=&quot;https://privacy.microsoft.com/zh-cn/privacystatement&quot;&gt;https://privacy.microsoft.com/zh-cn/privacystatement&lt;/a&gt; 查看。&lt;br&gt;&lt;br&gt;若您同意参与数据统计,您的设备信息与应用使用情况将会被记录,其包括但不限于:Android API 版本、设备型号、语言所在地、本应用版本号、会话时长、应用功能使用次数。开发者承诺以下信息并不会被记录:电话号码、电子邮件地址、IMEI。&lt;br&gt;&lt;br&gt;在您同意参与数据统计之前,您的信息不会被记录。&lt;br&gt;&lt;br&gt;被记录的数据会由 Microsoft AppCenter 进行分析,分析报表仅可被本应用开发者访问。</string>
<string name="get_it">知道了</string>
<string name="accept">接受</string>
<string name="reject">拒绝</string>
+73 -8
View File
@@ -19,8 +19,8 @@
<string name="app_name">EhViewer</string>
<!-- Theme -->
<string name="theme_light">亮色主題</string>
<string name="theme_dark">暗色主題</string>
<string name="theme_light">淺色主題</string>
<string name="theme_dark">深色主題</string>
<string name="theme_black">黑色主題</string>
<string name="homepage">首頁</string>
@@ -144,7 +144,7 @@
<string name="search_specify_tag">指定標籤</string>
<string name="search_enable_advance">啟用進階選項</string>
<string name="search_tip">一般搜尋:就是搜尋。\n\n訂閱搜素:在訂閱中搜索。\n\n指定上傳者:列出該上傳者上傳的圖庫。其他選項會被忽略。\n\n指定標籤:列出含有該標籤的圖庫。其他選項會被忽略。</string>
<string name="search_tip">一般搜尋:就是搜尋。\n\n訂閱搜尋:在訂閱中搜尋。\n\n指定上傳者:列出該上傳者上傳的圖庫。其他選項會被忽略。\n\n指定標籤:列出含有該標籤的圖庫。其他選項會被忽略。</string>
<string name="search_sname">搜尋圖庫</string>
<string name="search_stags">搜尋圖庫的標籤</string>
@@ -183,7 +183,7 @@
<string name="delete_quick_search_message">刪除“%s”嗎?</string>
<string name="no_quick_search">快速搜尋會顯示在這裡</string>
<string name="add_quick_search_tip">圖庫列表的狀態將被儲存為快速搜尋。如果你想儲存搜尋面板的狀態,請先進行搜尋。</string>
<string name="readme">讀我檔</string>
<string name="readme">ReadMe</string>
<string name="image_search_not_quick_search">無法將圖片搜尋加入快速搜尋</string>
<string name="duplicate_quick_search">已存在相同的快速搜尋,名稱為“%s”。</string>
<string name="duplicate_name">已經由重複的名稱了</string>
@@ -234,7 +234,10 @@
<string name="add_to_favorite_failure">無法新增至收藏</string>
<string name="remove_from_favorite_failure">無法從收藏中移除</string>
<string name="filter_the_uploader">把上傳者“%s”加入濾除列表?</string>
<string name="filter_the_tag">隱藏標籤“%s”?</string>
<string name="filter_added">已經新增篩選條件</string>
<string name="newer_version_avaliable">此圖庫有新版本可以使用。</string>
<string name="newer_version_title">%1$s, 增加於 %2$s</string>
<!-- Rating -->
<string name="rating10">太神啦!</string>
@@ -349,6 +352,7 @@
<string name="rename_label_title">重新命名標籤</string>
<string name="delete_label_title">刪除標籤</string>
<string name="delete_label_message">將 “%s”刪除?</string>
<string name="rename_label">重新命名</string>
<!-- History -->
<string name="no_history">歷史紀錄將會顯示在這裡</string>
@@ -373,6 +377,7 @@
<string name="set_pattern_protection">設定圖形解鎖</string>
<string name="set_pattern_protection_tip">繪製圖案來設定繪圖解鎖\n留白以取消圖案保護</string>
<string name="set">設定</string>
<string name="enable_biometric">允許使用生物識別解鎖</string>
<!-- UConfig Activity -->
<string name="u_config">EHentai 設定</string>
@@ -400,6 +405,7 @@
<string name="page_menu_refresh">@string/refresh</string>
<string name="page_menu_share">@string/share</string>
<string name="page_menu_save">儲存</string>
<string name="page_menu_save_to">儲存到…</string>
<string name="page_menu_add_bookmark">新增書籤</string>
<string name="gallery_menu_title">選單</string>
<string name="share_image">分享圖片</string>
@@ -422,8 +428,8 @@
<string name="settings_my_tags">我的標籤</string>
<string name="settings_my_tags_summary">EHentai 網站上的我的標籤</string>
<string name="settings_eh_theme">主題</string>
<string name="settings_eh_theme_light">亮色</string>
<string name="settings_eh_theme_dark">暗色</string>
<string name="settings_eh_theme_light">淺色</string>
<string name="settings_eh_theme_dark">深色</string>
<string name="settings_eh_theme_black">黑色</string>
<string name="settings_eh_apply_nav_bar_theme_color">導航欄應用主題配色</string>
<string name="settings_eh_gallery_site">圖庫站台</string>
@@ -465,6 +471,7 @@
<string name="settings_read_screen_rotation_default">系統預設</string>
<string name="settings_read_screen_rotation_portrait">直向</string>
<string name="settings_read_screen_rotation_landscape">橫向</string>
<string name="settings_read_screen_rotation_sensor">自動旋轉</string>
<string name="settings_read_reading_direction">閱讀方向</string>
<string name="settings_read_reading_direction_left_to_right">由左到右</string>
<string name="settings_read_reading_direction_right_to_Left">由右到左</string>
@@ -490,6 +497,7 @@
<string name="settings_read_reading_fullscreen">全螢幕</string>
<string name="settings_read_custom_screen_lightness">自訂螢幕亮度</string>
<string name="settings_read_screen_lightness">螢幕亮度</string>
<string name="settings_read_reverse_volume">翻轉音量鍵</string>
<string name="settings_download">下載</string>
<string name="settings_download_download_location">下載路徑</string>
@@ -525,7 +533,7 @@
<string name="settings_advanced">進階</string>
<string name="settings_advanced_save_parse_error_body">解析失敗時儲存網頁的內容</string>
<string name="settings_advanced_save_parse_error_body_summary">網頁內容可能含有敏感的隱私資料</string>
<string name="settings_advanced_save_crash_log">應用崩潰時儲存錯誤日誌</string>
<string name="settings_advanced_save_crash_log">應用程式崩潰時儲存錯誤日誌</string>
<string name="settings_advanced_save_crash_log_summary">錯誤日誌可以幫助開發者修正問題</string>
<string name="settings_advanced_dump_logcat">傾印log</string>
<string name="settings_advanced_dump_logcat_summary">儲存log紀錄至外接儲存裝置中</string>
@@ -591,7 +599,7 @@
<string name="rewrite">改寫</string>
<string name="language_japanese">日語</string>
<string name="language_english">英語</string>
<string name="language_chinese">漢語</string>
<string name="language_chinese">中文</string>
<string name="language_dutch">荷蘭語</string>
<string name="language_french">法語</string>
<string name="language_german">德語</string>
@@ -702,6 +710,63 @@
<string name="settings_privacy">隱私</string>
<string name="settings_privacy_secure">不允許螢幕擷取</string>
<string name="settings_privacy_secure_summary">啟用後,將無法對本程式進行螢幕擷取,同時,將不會在系統任務切換器中顯示該程式的預覽內容,重新啟動本程式以套用此變更</string>
<string name="download_service">下載服務</string>
<string name="favorite_name">收藏圖庫</string>
<string name="black_dark_theme">純黑深色主題</string>
<string name="download_filter">過濾</string>
<string name="download_all">全部</string>
<string name="download_start_all_reversed">全部開始(倒序)</string>
<string name="settings_download_download_delay">下載延時</string>
<string name="settings_download_download_delay_summary">每次下載延時 %s 毫秒</string>
<string name="no_browser_installed">請安裝一個瀏覽器。</string>
<string name="toplist_alltime">從始至終</string>
<string name="toplist_pastyear">過去一年</string>
<string name="toplist_pastmonth">過去一個月</string>
<string name="toplist_yesterday">昨日</string>
<string name="toplist">排行</string>
<string name="tag_vote_down">不,這不是</string>
<string name="tag_vote_up">是的,這很正確</string>
<string name="tag_vote_successfully">投票成功</string>
<string name="from_clipboard">從剪貼板匯入</string>
<string name="from_clipboard_error">未在剪貼板中發現 Cookies。</string>
<string name="delete_search_history">從搜索記錄中刪除“%s”?</string>
<string name="settings_advanced_dns_over_http_title">安全 DNS(DoH)</string>
<string name="settings_advanced_dns_over_http_summary">解決某些地區的 DNS 汙染問題</string>
<string name="settings_advanced_domain_fronting_title">域名前置</string>
<string name="settings_advanced_domain_fronting_summary">繞過 SNI 封鎖</string>
<string name="read_theme">色彩主題</string>
<string name="follow_app">跟隨應用</string>
<string name="settings_e_ink_mode_title">墨水屏模式</string>
<string name="settings_e_ink_mode_summary">為墨水屏做一些最佳化</string>
<string name="settings_advanced_clear_memory_cache_done">完成記憶體快取清理</string>
<string name="action_add_tag">增加標籤</string>
<string name="action_add_tag_tip">增加新標籤,用逗號「,」分割</string>
<string name="error_no_webview">WebView 不可用</string>
<string name="comment_user_uploader">%s (上傳者)</string>
<string name="settings_eh_metered_network_warning">流量計費網路警告</string>
<string name="metered_network_warning">正在使用流量計費網路</string>
<string name="read_from">從第 %d 頁閱讀</string>
<string name="settings_request_news_title">啟動時請求新聞頁面</string>
<string name="copy_trans">複製翻譯</string>
<string name="reset_download_location">恢復預設路徑</string>
<string name="pick_new_download_location">選擇新路徑</string>
<string name="dont_show_again">不再顯示</string>
<string name="open_settings">打開設置</string>
<string name="app_link_not_verified_message">對於 Android 12 及更新的版本,您需要手動增加連結到已驗證連結才能在 EhViewer 中打開 E-Hentai 連結。</string>
<string name="app_link_not_verified_title">應用連結未驗證</string>
<string name="open_by_default">預設打開</string>
<string name="show_library_version">依賴庫之版本</string>
<string name="settings_privacy_require_unlock">需要解鎖</string>
<string name="proxy_type_name">代理類型</string>
<string name="filter_label">屏蔽項類型</string>
<string name="archive_passwd">歸檔文件密碼</string>
<string name="archive_need_passwd">歸檔文件需要密碼</string>
<string name="passwd_wrong">密碼錯誤</string>
<string name="passwd_cannot_be_empty">密碼不能為空</string>
</resources>
-1
View File
@@ -148,7 +148,6 @@
<string name="content_layout_restore_tip">Tap to retry</string>
<string name="write_rationale">EhViewer will request WRITE_EXTERNAL_STORAGE permission for downloading gallery. Do you want to grant the permission?</string>
<string name="you_rejected_me">It hurts</string>
<string name="analytics_explain">Would you mind if the developer collected your device information and your usage? It will help the developer a lot.&lt;br&gt;&lt;br&gt;Data analysis service is provided by Microsoft AppCenter. Its privacy policy can be found at &lt;a href=&quot;https://privacy.microsoft.com/zh-cn/privacystatement&quot;&gt;https://privacy.microsoft.com/zh-cn/privacystatement&lt;/a&gt;.&lt;br&gt;&lt;br&gt;If you agree to join data analysis, your device information and your usage will be collected, including but not limited to Android API version, equipment model, language residence, the application version, conversion time, function times. The developer promise that these information will NOT be collected, including phone number, e-mail address, IMEI.&lt;br&gt;&lt;br&gt;Your information will not be collected until you agree to join data analysis.&lt;br&gt;&lt;br&gt;The collected information will be analyzed by Microsoft AppCenter. The analysis report can only be viewed by the developer of this application.</string>
<string name="get_it">Got it</string>
<string name="accept">Accept</string>
<string name="reject">Reject</string>
+347
View File
@@ -0,0 +1,347 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="646"
height="250"
id="svg8502"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="get-it-on.svg">
<defs
id="defs8504">
<linearGradient
inkscape:collect="always"
id="linearGradient4392">
<stop
style="stop-color:#ffffff;stop-opacity:0.09803922"
offset="0"
id="stop4394" />
<stop
style="stop-color:#ffffff;stop-opacity:0"
offset="1"
id="stop4396" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4392"
id="radialGradient4398"
cx="113"
cy="-12.889574"
fx="113"
fy="-12.889574"
r="59.661892"
gradientTransform="matrix(-4.3416142e-8,1.9610509,-1.9778119,2.8493899e-8,254.50686,78.76343)"
gradientUnits="userSpaceOnUse" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.4142136"
inkscape:cx="322.4318"
inkscape:cy="148.85197"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="1920"
inkscape:window-height="1009"
inkscape:window-x="0"
inkscape:window-y="34"
inkscape:window-maximized="1" />
<metadata
id="metadata8507">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<dc:creator>
<cc:Agent>
<dc:title>Andrew Nayenko</dc:title>
</cc:Agent>
</dc:creator>
<dc:publisher>
<cc:Agent>
<dc:title>https://f-droid.org</dc:title>
</cc:Agent>
</dc:publisher>
<cc:license
rdf:resource="http://creativecommons.org/licenses/by-sa/3.0/" />
<dc:contributor>
<cc:Agent>
<dc:title />
</cc:Agent>
</dc:contributor>
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/by-sa/3.0/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Notice" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Attribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
</cc:License>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-289,-312.36218)">
<rect
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#a6a6a6;stroke-width:4;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker:none;enable-background:accumulate"
id="rect3007"
width="560"
height="164"
x="332"
y="355.36218"
rx="20"
ry="20" />
<text
sodipodi:linespacing="100%"
id="text3013"
y="402.36697"
x="508.95129"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.39519119px;line-height:100%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';letter-spacing:0px;word-spacing:0px;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;enable-background:accumulate"
xml:space="preserve"><tspan
y="402.36697"
x="508.95129"
id="tspan3015"
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:34.125px;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans'">GET IT ON</tspan></text>
<text
xml:space="preserve"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:29.70882034px;line-height:100%;font-family:Rokkitt;-inkscape-font-specification:'Rokkitt Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;enable-background:accumulate"
x="508.21259"
y="489.36108"
id="text5902"
sodipodi:linespacing="100%"><tspan
sodipodi:role="line"
id="tspan5904"
x="508.21259"
y="489.36108"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:95px;line-height:100%;font-family:'Roboto Slab';-inkscape-font-specification:'Roboto Slab Bold';text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1">F-Droid</tspan></text>
<g
id="g4400"
transform="translate(80.999992,75.999997)">
<g
id="g5012"
transform="matrix(2.6315876,0,0,2.6315749,275.84226,-2346.4746)">
<g
transform="matrix(-1,0,0,1,47.999779,0)"
id="g4179">
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path4181"
d="m 2.5889342,1006.8622 4.25,5.5"
style="fill:#8ab000;fill-opacity:1;fill-rule:evenodd;stroke:#769616;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:0.29803922;fill-rule:evenodd;stroke:none;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 2.6113281,1005.6094 c -0.4534623,0.012 -0.7616975,0.189 -0.9807462,0.4486 2.0269314,2.4089 2.368401,2.7916 5.1354735,6.2214 1.0195329,1.319 2.0816026,0.6373 1.0620696,-0.6817 l -4.25,-5.5 c -0.2289894,-0.3056 -0.5850813,-0.478 -0.9667969,-0.4883 z"
id="path4183"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc" />
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#263238;fill-opacity:0.2;fill-rule:evenodd;stroke:none;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 1.6220992,1006.0705 c -0.1238933,0.1479 -0.561176,0.8046 -0.02249,1.5562 l 4.25,5.5 c 1.0195329,1.319 1.1498748,-0.6123 1.1498748,-0.6123 0,0 -3.7344514,-4.51 -5.3773848,-6.4439 z"
id="path4185"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#8ab000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 2.3378905,1005.8443 c -0.438175,0 -0.959862,0.1416 -0.8242183,0.7986 0.103561,0.5016 4.6608262,6.0744 4.6608262,6.0744 1.0195329,1.319 2.4934721,0.6763 1.4739391,-0.6425 l -4.234375,-5.4727 c -0.2602394,-0.29 -0.6085188,-0.7436 -1.076172,-0.7578 z"
id="path4187"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cscccc" />
</g>
<g
id="g4955">
<path
style="fill:#8ab000;fill-opacity:1;fill-rule:evenodd;stroke:#769616;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 2.5889342,1006.8622 4.25,5.5"
id="path4945"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
sodipodi:nodetypes="cccccc"
inkscape:connector-curvature="0"
id="path4947"
d="m 2.6113281,1005.6094 c -0.4534623,0.012 -0.7616975,0.189 -0.9807462,0.4486 2.0269314,2.4089 2.368401,2.7916 5.1354735,6.2214 1.0195329,1.319 2.0816026,0.6373 1.0620696,-0.6817 l -4.25,-5.5 c -0.2289894,-0.3056 -0.5850813,-0.478 -0.9667969,-0.4883 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:0.29803922;fill-rule:evenodd;stroke:none;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path4951"
d="m 1.6220992,1006.0705 c -0.1238933,0.1479 -0.561176,0.8046 -0.02249,1.5562 l 4.25,5.5 c 1.0195329,1.319 1.1498748,-0.6123 1.1498748,-0.6123 0,0 -3.7344514,-4.51 -5.3773848,-6.4439 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#263238;fill-opacity:0.2;fill-rule:evenodd;stroke:none;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<path
sodipodi:nodetypes="cscccc"
inkscape:connector-curvature="0"
id="path4925"
d="m 2.3378905,1005.8443 c -0.438175,0 -0.959862,0.1416 -0.8242183,0.7986 0.103561,0.5016 4.6608262,6.0744 4.6608262,6.0744 1.0195329,1.319 2.4934721,0.6763 1.4739391,-0.6425 l -4.234375,-5.4727 c -0.2602394,-0.29 -0.6085188,-0.7436 -1.076172,-0.7578 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#8ab000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
<g
id="g4967"
transform="translate(42,0)">
<rect
ry="3"
rx="3"
y="1010.3596"
x="-37"
height="12.92002"
width="38"
id="rect4144"
style="opacity:1;fill:#aeea00;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:3;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<rect
style="opacity:1;fill:#263238;fill-opacity:0.2;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:3;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect4961"
width="38"
height="10"
x="-37"
y="1013.2795"
rx="3"
ry="3" />
<rect
style="opacity:1;fill:#ffffff;fill-opacity:0.29803922;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:3;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect4963"
width="38"
height="10"
x="-37"
y="1010.3622"
rx="3"
ry="3" />
<rect
style="opacity:1;fill:#aeea00;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:3;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect4965"
width="38"
height="10.640781"
x="-37"
y="1011.5002"
rx="3"
ry="2.455565" />
</g>
<g
transform="translate(0,-0.10259092)"
id="g4979">
<rect
ry="3"
rx="3"
y="1024.5221"
x="5"
height="25.84004"
width="38"
id="rect4146"
style="opacity:1;fill:#1976d2;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:3;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<rect
style="opacity:1;fill:#263238;fill-opacity:0.2;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:3;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect4973"
width="38"
height="13"
x="5"
y="1037.3622"
rx="3"
ry="3" />
<rect
style="opacity:1;fill:#ffffff;fill-opacity:0.2;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:3;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect4975"
width="38"
height="13"
x="5"
y="1024.4421"
rx="3"
ry="3" />
<rect
style="opacity:1;fill:#1976d2;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:3;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect4977"
width="38"
height="23.560036"
x="5"
y="1025.6621"
rx="3"
ry="2.7184658" />
</g>
<g
id="g4211"
transform="translate(0,1013.3622)">
<path
inkscape:connector-curvature="0"
id="path4161"
d="m 24,17.75 c -2.880662,0 -5.319789,1.984685 -6.033203,4.650391 l 3.212891,0 C 21.734004,21.415044 22.774798,20.75 24,20.75 c 1.812692,0 3.25,1.437308 3.25,3.25 0,1.812693 -1.437308,3.25 -3.25,3.25 -1.307381,0 -2.411251,-0.75269 -2.929688,-1.849609 l -3.154296,0 C 18.558263,28.166146 21.04791,30.25 24,30.25 c 3.434013,0 6.25,-2.815987 6.25,-6.25 0,-3.434012 -2.815987,-6.25 -6.25,-6.25 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0d47a1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<circle
r="9.5500002"
cy="24"
cx="24"
id="path4209"
style="opacity:1;fill:none;fill-opacity:0.40392157;stroke:#0d47a1;stroke-width:1.89999998;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
</g>
<g
transform="translate(0,0.50001738)"
id="g4989">
<ellipse
ry="3.875"
rx="3.375"
style="opacity:1;fill:#263238;fill-opacity:0.2;stroke:none;stroke-width:1.89999998;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.69721117"
id="circle4985"
cx="14.375"
cy="1016.4872" />
<circle
r="3.375"
cy="1016.9872"
cx="14.375"
id="path4859"
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.89999998;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.69721117" />
</g>
<g
id="g4201"
transform="translate(19.5,0.50001738)">
<ellipse
cy="1016.4872"
cx="14.375"
id="ellipse4175"
style="opacity:1;fill:#263238;fill-opacity:0.2;stroke:none;stroke-width:1.89999998;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.69721117"
rx="3.375"
ry="3.875" />
<circle
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.89999998;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.69721117"
id="circle4177"
cx="14.375"
cy="1016.9872"
r="3.375" />
</g>
</g>
<path
inkscape:connector-curvature="0"
id="path4286"
d="m 282.71484,299.83484 a 3.2898056,3.2898056 0 0 0 -2.66211,5.33593 l 9.47461,12.26172 C 289.19237,318.31001 289,319.25869 289,320.25671 l 0,18.21094 c 0,4.37367 3.52083,7.89453 7.89453,7.89453 l 84.21094,0 c 4.3737,0 7.89453,-3.52086 7.89453,-7.89453 l 0,-18.21094 c 0,-0.99858 -0.19005,-1.94824 -0.52539,-2.82617 l 9.47266,-12.25977 a 3.2898056,3.2898056 0 0 0 -2.4336,-5.33398 3.2898056,3.2898056 0 0 0 -2.77148,1.31055 l -9.01367,11.66601 c -0.82093,-0.28771 -1.70144,-0.45117 -2.62305,-0.45117 l -84.21094,0 c -0.92137,0 -1.80035,0.1636 -2.62109,0.45117 l -9.01563,-11.66601 a 3.2898056,3.2898056 0 0 0 -2.54297,-1.3125 z m 14.17969,49.52734 c -4.3737,0 -7.89453,3.52085 -7.89453,7.89453 l 0,52.21094 c 0,4.37368 3.52083,7.89453 7.89453,7.89453 l 84.21094,0 c 4.3737,0 7.89453,-3.52085 7.89453,-7.89453 l 0,-52.21094 c 0,-4.37368 -3.52083,-7.89453 -7.89453,-7.89453 l -84.21094,0 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#radialGradient4398);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:6.57895327;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 24 KiB

+55
View File
@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="646" height="250" id="svg8502" version="1.1" inkscape:version="0.91 r13725" sodipodi:docname="get-it-on-github.svg" inkscape:export-filename="/home/nixdorf/Lokaler Speicher/Build/andOTP/assets/badges/get-it-on-github.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90">
<defs id="defs8504" />
<sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="0.50000001" inkscape:cx="-223.13537" inkscape:cy="546.37524" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" fit-margin-top="0" fit-margin-left="0" fit-margin-right="0" fit-margin-bottom="0" inkscape:window-width="1920" inkscape:window-height="1021" inkscape:window-x="0" inkscape:window-y="31" inkscape:window-maximized="1" />
<metadata id="metadata8507">
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
<dc:creator>
<cc:Agent>
<dc:title>Andrew Nayenko</dc:title>
</cc:Agent>
</dc:creator>
<dc:publisher>
<cc:Agent>
<dc:title>https://f-droid.org</dc:title>
</cc:Agent>
</dc:publisher>
<cc:license rdf:resource="http://creativecommons.org/licenses/by-sa/3.0/" />
<dc:contributor>
<cc:Agent>
<dc:title />
</cc:Agent>
</dc:contributor>
</cc:Work>
<cc:License rdf:about="http://creativecommons.org/licenses/by-sa/3.0/">
<cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:requires rdf:resource="http://creativecommons.org/ns#Notice" />
<cc:requires rdf:resource="http://creativecommons.org/ns#Attribution" />
<cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
<cc:requires rdf:resource="http://creativecommons.org/ns#ShareAlike" />
</cc:License>
</rdf:RDF>
</metadata>
<g inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1" transform="translate(-289,-312.36218)">
<rect style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#a6a6a6;stroke-width:4;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker:none;enable-background:accumulate" id="rect3007" width="560" height="164" x="332" y="355.36218" rx="20" ry="20" />
<text sodipodi:linespacing="100%" id="text3013" y="402.36697" x="508.95129" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.39519119px;line-height:100%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';letter-spacing:0px;word-spacing:0px;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;enable-background:accumulate" xml:space="preserve"><tspan y="402.36697" x="508.95129" id="tspan3015" sodipodi:role="line" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:34.125px;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans'">GET IT ON</tspan></text>
<text xml:space="preserve" style="color:black;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:29.70882034px;line-height:100%;font-family:Rokkitt;-inkscape-font-specification:'Rokkitt Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;overflow:visible;visibility:visible;fill:white;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;enable-background:accumulate" x="508.21259" y="489.36108" id="text5902" sodipodi:linespacing="100%"><tspan sodipodi:role="line" id="tspan5904" x="508.21259" y="489.36108" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:87.5px;line-height:100%;font-family:'Roboto Slab';-inkscape-font-specification:'Roboto Slab Bold';text-align:start;writing-mode:lr-tb;text-anchor:start;fill:white;fill-opacity:1">GitHub</tspan></text>
<g transform="matrix(1.0017681,0,0,1.0017681,68.770756,92.660249)" id="g5136">
<path style="fill:white;fill-opacity:1;fill-rule:evenodd;stroke:none" d="m 350.60937,282.4375 c -33.34765,0 -60.38671,27.03516 -60.38671,60.38672 0,26.67969 17.30078,49.3164 41.29687,57.30078 3.01563,0.55859 4.125,-1.30859 4.125,-2.90625 0,-1.4375 -0.0547,-6.19531 -0.082,-11.24219 -16.80078,3.65235 -20.34375,-7.125 -20.34375,-7.125 -2.75,-6.98047 -6.70703,-8.83594 -6.70703,-8.83594 -5.48047,-3.74609 0.41406,-3.67187 0.41406,-3.67187 6.0625,0.42578 9.25781,6.22266 9.25781,6.22266 5.38282,9.23437 14.125,6.5664 17.57032,5.02343 0.54296,-3.90234 2.10937,-6.57031 3.83593,-8.07812 -13.41406,-1.52735 -27.51562,-6.70313 -27.51562,-29.84375 0,-6.59375 2.35937,-11.98047 6.22265,-16.20703 -0.625,-1.52344 -2.6914,-7.66407 0.58594,-15.98047 0,0 5.07031,-1.625 16.60938,6.1875 4.82031,-1.33594 9.98437,-2.00781 15.11718,-2.03125 5.13282,0.0234 10.30079,0.69531 15.12891,2.03125 11.52344,-7.8125 16.58984,-6.1875 16.58984,-6.1875 3.28516,8.3164 1.21875,14.45703 0.58985,15.98047 3.87109,4.22656 6.21484,9.61328 6.21484,16.20703 0,23.19531 -14.125,28.30078 -27.57422,29.79687 2.16797,1.875 4.09766,5.55078 4.09766,11.1836 0,8.07812 -0.0703,14.58203 -0.0703,16.57031 0,1.60937 1.08593,3.49219 4.14843,2.89844 23.98047,-7.9961 41.26172,-30.6211 41.26172,-57.29297 0,-33.35156 -27.03515,-60.38672 -60.38672,-60.38672" id="path4937" inkscape:connector-curvature="0" />
<path style="fill:white;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 313.09375,369.14062 c -0.13281,0.30079 -0.60547,0.38672 -1.03516,0.1836 -0.4375,-0.19922 -0.68359,-0.60547 -0.54297,-0.91016 0.12891,-0.30859 0.60157,-0.39062 1.03907,-0.1875 0.4414,0.19922 0.6914,0.61328 0.53906,0.91406" id="path4939" inkscape:connector-curvature="0" />
<path style="fill:white;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 315.53906,371.86719 c -0.28906,0.26562 -0.85156,0.14453 -1.23437,-0.27735 -0.39453,-0.42187 -0.46875,-0.98437 -0.17578,-1.25781 0.29687,-0.26562 0.84375,-0.14062 1.23828,0.28125 0.39453,0.42578 0.47265,0.98438 0.17187,1.25391" id="path4941" inkscape:connector-curvature="0" />
<path style="fill:white;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 317.92187,375.34375 c -0.37109,0.25781 -0.97656,0.0156 -1.35156,-0.51953 -0.37109,-0.53906 -0.37109,-1.17969 0.008,-1.4375 0.375,-0.25781 0.97266,-0.0274 1.35157,0.5039 0.36718,0.54688 0.36718,1.19141 -0.008,1.45313" id="path4943" inkscape:connector-curvature="0" />
<path style="fill:white;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 321.18359,378.70312 c -0.33203,0.36719 -1.03906,0.26954 -1.55468,-0.23046 -0.52735,-0.48438 -0.67579,-1.17579 -0.34375,-1.54297 0.33593,-0.36328 1.04687,-0.26172 1.5664,0.23047 0.52344,0.48828 0.6836,1.18359 0.33203,1.54296" id="path4945-3" inkscape:connector-curvature="0" />
<path style="fill:white;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 325.68359,380.65625 c -0.14843,0.47266 -0.82812,0.6875 -1.51172,0.48828 -0.68359,-0.20703 -1.1289,-0.76172 -0.99218,-1.24219 0.14453,-0.47265 0.82422,-0.69922 1.51562,-0.48437 0.67969,0.20703 1.12891,0.75781 0.98828,1.23828" id="path4947-6" inkscape:connector-curvature="0" />
<path style="fill:white;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 330.625,381.01953 c 0.0156,0.49609 -0.5625,0.91016 -1.28125,0.91797 -0.72266,0.0156 -1.30859,-0.38672 -1.31641,-0.875 0,-0.50391 0.57032,-0.91406 1.28907,-0.92578 0.71875,-0.0156 1.30859,0.38672 1.30859,0.88281" id="path4949" inkscape:connector-curvature="0" />
<path style="fill:white;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 335.22266,380.23437 c 0.0859,0.48829 -0.41407,0.98438 -1.125,1.11719 -0.70313,0.12891 -1.35157,-0.17187 -1.44141,-0.65234 -0.0859,-0.5 0.42187,-0.9961 1.12109,-1.125 0.71485,-0.125 1.35547,0.16797 1.44532,0.66015" id="path4951-7" inkscape:connector-curvature="0" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.5 KiB

+3 -2
View File
@@ -1,6 +1,7 @@
plugins {
id 'com.android.application' version '7.2.1' apply false
id 'org.jetbrains.kotlin.android' version '1.7.10' apply false
id 'com.android.application' version '7.2.2' apply false
id 'org.jetbrains.kotlin.android' version '1.7.20-Beta' apply false
id 'com.google.devtools.ksp' version '1.7.20-Beta-1.0.6' apply false
}
task clean(type: Delete) {
-1
View File
@@ -1 +0,0 @@
/build
-35
View File
@@ -1,35 +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.
*/
apply plugin: 'java'
task executeDaoGenerator(type:JavaExec) {
main = 'com.hippo.ehviewer.daogenerator.Main'
classpath = sourceSets.main.runtimeClasspath
}
dependencies {
implementation 'org.greenrobot:greendao-generator:3.3.0'
def roaster_version = "2.26.0.Final"
implementation "org.jboss.forge.roaster:roaster-api:$roaster_version"
implementation "org.jboss.forge.roaster:roaster-jdt:$roaster_version"
}
java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
@@ -1,529 +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.daogenerator;
import org.jboss.forge.roaster.Roaster;
import org.jboss.forge.roaster.model.source.JavaClassSource;
import java.io.File;
import java.io.FileWriter;
import org.greenrobot.greendao.generator.DaoGenerator;
import org.greenrobot.greendao.generator.Entity;
import org.greenrobot.greendao.generator.Schema;
public class EhDaoGenerator {
private static final String PACKAGE = "com.hippo.ehviewer.dao";
private static final String OUT_DIR = "../app/src/main/java-gen";
private static final String DELETE_DIR = "../app/src/main/java-gen/com/hippo/ehviewer/dao";
private static final int VERSION = 4;
private static final String DOWNLOAD_INFO_PATH = "../app/src/main/java-gen/com/hippo/ehviewer/dao/DownloadInfo.java";
private static final String HISTORY_INFO_PATH = "../app/src/main/java-gen/com/hippo/ehviewer/dao/HistoryInfo.java";
private static final String QUICK_SEARCH_PATH = "../app/src/main/java-gen/com/hippo/ehviewer/dao/QuickSearch.java";
private static final String LOCAL_FAVORITE_INFO_PATH = "../app/src/main/java-gen/com/hippo/ehviewer/dao/LocalFavoriteInfo.java";
private static final String BOOKMARK_INFO_PATH = "../app/src/main/java-gen/com/hippo/ehviewer/dao/BookmarkInfo.java";
private static final String FILTER_PATH = "../app/src/main/java-gen/com/hippo/ehviewer/dao/Filter.java";
public static void generate() throws Exception {
Utilities.deleteContents(new File(DELETE_DIR));
File outDir = new File(OUT_DIR);
outDir.delete();
outDir.mkdirs();
Schema schema = new Schema(VERSION, PACKAGE);
addDownloads(schema);
addDownloadLabel(schema);
addDownloadDirname(schema);
addHistoryInfo(schema);
addQuickSearch(schema);
addLocalFavorites(schema);
addBookmarks(schema);
addFilter(schema);
new DaoGenerator().generateAll(schema, OUT_DIR);
adjustDownloadInfo();
adjustHistoryInfo();
adjustQuickSearch();
adjustLocalFavoriteInfo();
adjustBookmarkInfo();
adjustFilter();
}
private static void addDownloads(Schema schema) {
Entity entity = schema.addEntity("DownloadInfo");
entity.setDbName("DOWNLOADS");
entity.setClassNameDao("DownloadsDao");
entity.setSuperclass("GalleryInfo");
// GalleryInfo data
entity.addLongProperty("gid").primaryKey().notNull();
entity.addStringProperty("token");
entity.addStringProperty("title");
entity.addStringProperty("titleJpn");
entity.addStringProperty("thumb");
entity.addIntProperty("category").notNull();
entity.addStringProperty("posted");
entity.addStringProperty("uploader");
entity.addFloatProperty("rating").notNull();
entity.addStringProperty("simpleLanguage");
// DownloadInfo data
entity.addIntProperty("state").notNull();
entity.addIntProperty("legacy").notNull();
entity.addLongProperty("time").notNull();
entity.addStringProperty("label");
}
private static void addDownloadLabel(Schema schema) {
Entity entity = schema.addEntity("DownloadLabel");
entity.setDbName("DOWNLOAD_LABELS");
entity.setClassNameDao("DownloadLabelDao");
entity.addIdProperty();
entity.addStringProperty("label");
entity.addLongProperty("time").notNull();
}
private static void addDownloadDirname(Schema schema) {
Entity entity = schema.addEntity("DownloadDirname");
entity.setDbName("DOWNLOAD_DIRNAME");
entity.setClassNameDao("DownloadDirnameDao");
entity.addLongProperty("gid").primaryKey().notNull();
entity.addStringProperty("dirname");
}
private static void addHistoryInfo(Schema schema) {
Entity entity = schema.addEntity("HistoryInfo");
entity.setDbName("HISTORY");
entity.setClassNameDao("HistoryDao");
entity.setSuperclass("GalleryInfo");
// GalleryInfo data
entity.addLongProperty("gid").primaryKey().notNull();
entity.addStringProperty("token");
entity.addStringProperty("title");
entity.addStringProperty("titleJpn");
entity.addStringProperty("thumb");
entity.addIntProperty("category").notNull();
entity.addStringProperty("posted");
entity.addStringProperty("uploader");
entity.addFloatProperty("rating").notNull();
entity.addStringProperty("simpleLanguage");
// HistoryInfo data
entity.addIntProperty("mode").notNull();
entity.addLongProperty("time").notNull();
}
private static void addQuickSearch(Schema schema) {
Entity entity = schema.addEntity("QuickSearch");
entity.setDbName("QUICK_SEARCH");
entity.setClassNameDao("QuickSearchDao");
entity.addIdProperty();
entity.addStringProperty("name");
entity.addIntProperty("mode").notNull();
entity.addIntProperty("category").notNull();
entity.addStringProperty("keyword");
entity.addIntProperty("advanceSearch").notNull();
entity.addIntProperty("minRating").notNull();
// Since 4
entity.addIntProperty("pageFrom").notNull();
// Since 4
entity.addIntProperty("pageTo").notNull();
entity.addLongProperty("time").notNull();
}
private static void addLocalFavorites(Schema schema) {
Entity entity = schema.addEntity("LocalFavoriteInfo");
entity.setDbName("LOCAL_FAVORITES");
entity.setClassNameDao("LocalFavoritesDao");
entity.setSuperclass("GalleryInfo");
// GalleryInfo data
entity.addLongProperty("gid").primaryKey().notNull();
entity.addStringProperty("token");
entity.addStringProperty("title");
entity.addStringProperty("titleJpn");
entity.addStringProperty("thumb");
entity.addIntProperty("category").notNull();
entity.addStringProperty("posted");
entity.addStringProperty("uploader");
entity.addFloatProperty("rating").notNull();
entity.addStringProperty("simpleLanguage");
// LocalFavoriteInfo data
entity.addLongProperty("time").notNull();
}
private static void addBookmarks(Schema schema) {
Entity entity = schema.addEntity("BookmarkInfo");
entity.setDbName("BOOKMARKS");
entity.setClassNameDao("BookmarksDao");
entity.setSuperclass("GalleryInfo");
// GalleryInfo data
entity.addLongProperty("gid").primaryKey().notNull();
entity.addStringProperty("token");
entity.addStringProperty("title");
entity.addStringProperty("titleJpn");
entity.addStringProperty("thumb");
entity.addIntProperty("category").notNull();
entity.addStringProperty("posted");
entity.addStringProperty("uploader");
entity.addFloatProperty("rating").notNull();
entity.addStringProperty("simpleLanguage");
// Bookmark data
entity.addIntProperty("page").notNull();
entity.addLongProperty("time").notNull();
}
// Since 2
private static void addFilter(Schema schema) {
Entity entity = schema.addEntity("Filter");
entity.setDbName("FILTER");
entity.setClassNameDao("FilterDao");
entity.addIdProperty();
entity.addIntProperty("mode").notNull();
entity.addStringProperty("text");
// Since 3
entity.addBooleanProperty("enable");
}
private static void adjustDownloadInfo() throws Exception {
JavaClassSource javaClass = Roaster.parse(JavaClassSource.class, new File(DOWNLOAD_INFO_PATH));
// Remove field from GalleryInfo
javaClass.removeField(javaClass.getField("gid"));
javaClass.removeField(javaClass.getField("token"));
javaClass.removeField(javaClass.getField("title"));
javaClass.removeField(javaClass.getField("titleJpn"));
javaClass.removeField(javaClass.getField("thumb"));
javaClass.removeField(javaClass.getField("category"));
javaClass.removeField(javaClass.getField("posted"));
javaClass.removeField(javaClass.getField("uploader"));
javaClass.removeField(javaClass.getField("rating"));
javaClass.removeField(javaClass.getField("simpleLanguage"));
// Set all field public
javaClass.getField("state").setPublic();
javaClass.getField("legacy").setPublic();
javaClass.getField("time").setPublic();
javaClass.getField("label").setPublic();
// Add Parcelable stuff
javaClass.addMethod("\t@Override\n" +
"\tpublic int describeContents() {\n" +
"\t\treturn 0;\n" +
"\t}");
javaClass.addMethod("\t@Override\n" +
"\tpublic void writeToParcel(Parcel dest, int flags) {\n" +
"\t\tsuper.writeToParcel(dest, flags);\n" +
"\t\tdest.writeInt(this.state);\n" +
"\t\tdest.writeInt(this.legacy);\n" +
"\t\tdest.writeLong(this.time);\n" +
"\t\tdest.writeString(this.label);\n" +
"\t}");
javaClass.addMethod("\tprotected DownloadInfo(Parcel in) {\n" +
"\t\tsuper(in);\n" +
"\t\tthis.state = in.readInt();\n" +
"\t\tthis.legacy = in.readInt();\n" +
"\t\tthis.time = in.readLong();\n" +
"\t\tthis.label = in.readString();\n" +
"\t}").setConstructor(true);
javaClass.addField("\tpublic static final Creator<DownloadInfo> CREATOR = new Creator<DownloadInfo>() {\n" +
"\t\t@Override\n" +
"\t\tpublic DownloadInfo createFromParcel(Parcel source) {\n" +
"\t\t\treturn new DownloadInfo(source);\n" +
"\t\t}\n" +
"\n" +
"\t\t@Override\n" +
"\t\tpublic DownloadInfo[] newArray(int size) {\n" +
"\t\t\treturn new DownloadInfo[size];\n" +
"\t\t}\n" +
"\t};");
javaClass.addImport("android.os.Parcel");
// Add download info stuff
javaClass.addField("public static final int STATE_INVALID = -1");
javaClass.addField("public static final int STATE_NONE = 0");
javaClass.addField("public static final int STATE_WAIT = 1");
javaClass.addField("public static final int STATE_DOWNLOAD = 2");
javaClass.addField("public static final int STATE_FINISH = 3");
javaClass.addField("public static final int STATE_FAILED = 4");
javaClass.addField("public long speed");
javaClass.addField("public long remaining");
javaClass.addField("public int finished");
javaClass.addField("public int downloaded");
javaClass.addField("public int total");
// Add from GalleryInfo constructor
javaClass.addMethod("\tpublic DownloadInfo(GalleryInfo galleryInfo) {\n" +
"\t\tthis.gid = galleryInfo.gid;\n" +
"\t\tthis.token = galleryInfo.token;\n" +
"\t\tthis.title = galleryInfo.title;\n" +
"\t\tthis.titleJpn = galleryInfo.titleJpn;\n" +
"\t\tthis.thumb = galleryInfo.thumb;\n" +
"\t\tthis.category = galleryInfo.category;\n" +
"\t\tthis.posted = galleryInfo.posted;\n" +
"\t\tthis.uploader = galleryInfo.uploader;\n" +
"\t\tthis.rating = galleryInfo.rating;\n" +
"\t\tthis.simpleTags = galleryInfo.simpleTags;\n" +
"\t\tthis.simpleLanguage = galleryInfo.simpleLanguage;\n" +
"\t}").setConstructor(true);
javaClass.addImport("com.hippo.ehviewer.client.data.GalleryInfo");
FileWriter fileWriter = new FileWriter(DOWNLOAD_INFO_PATH);
fileWriter.write(javaClass.toString());
fileWriter.close();
}
private static void adjustHistoryInfo() throws Exception {
JavaClassSource javaClass = Roaster.parse(JavaClassSource.class, new File(HISTORY_INFO_PATH));
// Remove field from GalleryInfo
javaClass.removeField(javaClass.getField("gid"));
javaClass.removeField(javaClass.getField("token"));
javaClass.removeField(javaClass.getField("title"));
javaClass.removeField(javaClass.getField("titleJpn"));
javaClass.removeField(javaClass.getField("thumb"));
javaClass.removeField(javaClass.getField("category"));
javaClass.removeField(javaClass.getField("posted"));
javaClass.removeField(javaClass.getField("uploader"));
javaClass.removeField(javaClass.getField("rating"));
javaClass.removeField(javaClass.getField("simpleLanguage"));
// Set all field public
javaClass.getField("mode").setPublic();
javaClass.getField("time").setPublic();
// Add Parcelable stuff
javaClass.addMethod("\t@Override\n" +
"\tpublic int describeContents() {\n" +
"\t\treturn 0;\n" +
"\t}");
javaClass.addMethod("\t@Override\n" +
"\tpublic void writeToParcel(Parcel dest, int flags) {\n" +
"\t\tsuper.writeToParcel(dest, flags);\n" +
"\t\tdest.writeInt(this.mode);\n" +
"\t\tdest.writeLong(this.time);\n" +
"\t}");
javaClass.addMethod("\tprotected HistoryInfo(Parcel in) {\n" +
"\t\tsuper(in);\n" +
"\t\tthis.mode = in.readInt();\n" +
"\t\tthis.time = in.readLong();\n" +
"\t}").setConstructor(true);
javaClass.addField("\tpublic static final Creator<HistoryInfo> CREATOR = new Creator<HistoryInfo>() {\n" +
"\t\t@Override\n" +
"\t\tpublic HistoryInfo createFromParcel(Parcel source) {\n" +
"\t\t\treturn new HistoryInfo(source);\n" +
"\t\t}\n" +
"\n" +
"\t\t@Override\n" +
"\t\tpublic HistoryInfo[] newArray(int size) {\n" +
"\t\t\treturn new HistoryInfo[size];\n" +
"\t\t}\n" +
"\t};");
javaClass.addImport("android.os.Parcel");
// Add from GalleryInfo constructor
javaClass.addMethod("\tpublic HistoryInfo(GalleryInfo galleryInfo) {\n" +
"\t\tthis.gid = galleryInfo.gid;\n" +
"\t\tthis.token = galleryInfo.token;\n" +
"\t\tthis.title = galleryInfo.title;\n" +
"\t\tthis.titleJpn = galleryInfo.titleJpn;\n" +
"\t\tthis.thumb = galleryInfo.thumb;\n" +
"\t\tthis.category = galleryInfo.category;\n" +
"\t\tthis.posted = galleryInfo.posted;\n" +
"\t\tthis.uploader = galleryInfo.uploader;\n" +
"\t\tthis.rating = galleryInfo.rating;\n" +
"\t\tthis.simpleTags = galleryInfo.simpleTags;\n" +
"\t\tthis.simpleLanguage = galleryInfo.simpleLanguage;\n" +
"\t}").setConstructor(true);
javaClass.addImport("com.hippo.ehviewer.client.data.GalleryInfo");
FileWriter fileWriter = new FileWriter(HISTORY_INFO_PATH);
fileWriter.write(javaClass.toString());
fileWriter.close();
}
private static void adjustQuickSearch() throws Exception {
JavaClassSource javaClass = Roaster.parse(JavaClassSource.class, new File(QUICK_SEARCH_PATH));
// Set all field public
javaClass.getField("id").setPublic();
javaClass.getField("name").setPublic();
javaClass.getField("mode").setPublic();
javaClass.getField("category").setPublic();
javaClass.getField("keyword").setPublic();
javaClass.getField("advanceSearch").setPublic();
javaClass.getField("minRating").setPublic();
javaClass.getField("pageFrom").setPublic();
javaClass.getField("pageTo").setPublic();
javaClass.getField("time").setPublic();
javaClass.addMethod("\t@Override\n" +
"\tpublic String toString() {\n" +
"\t\treturn name;\n" +
"\t}");
FileWriter fileWriter = new FileWriter(QUICK_SEARCH_PATH);
fileWriter.write(javaClass.toString());
fileWriter.close();
}
private static void adjustLocalFavoriteInfo() throws Exception {
JavaClassSource javaClass = Roaster.parse(JavaClassSource.class, new File(LOCAL_FAVORITE_INFO_PATH));
// Remove field from GalleryInfo
javaClass.removeField(javaClass.getField("gid"));
javaClass.removeField(javaClass.getField("token"));
javaClass.removeField(javaClass.getField("title"));
javaClass.removeField(javaClass.getField("titleJpn"));
javaClass.removeField(javaClass.getField("thumb"));
javaClass.removeField(javaClass.getField("category"));
javaClass.removeField(javaClass.getField("posted"));
javaClass.removeField(javaClass.getField("uploader"));
javaClass.removeField(javaClass.getField("rating"));
javaClass.removeField(javaClass.getField("simpleLanguage"));
// Set all field public
javaClass.getField("time").setPublic();
// Add Parcelable stuff
javaClass.addMethod("\t@Override\n" +
"\tpublic int describeContents() {\n" +
"\t\treturn 0;\n" +
"\t}");
javaClass.addMethod("\t@Override\n" +
"\tpublic void writeToParcel(Parcel dest, int flags) {\n" +
"\t\tsuper.writeToParcel(dest, flags);\n" +
"\t\tdest.writeLong(this.time);\n" +
"\t}");
javaClass.addMethod("\tprotected LocalFavoriteInfo(Parcel in) {\n" +
"\t\tsuper(in);\n" +
"\t\tthis.time = in.readLong();\n" +
"\t}").setConstructor(true);
javaClass.addField("\tpublic static final Creator<LocalFavoriteInfo> CREATOR = new Creator<LocalFavoriteInfo>() {\n" +
"\t\t@Override\n" +
"\t\tpublic LocalFavoriteInfo createFromParcel(Parcel source) {\n" +
"\t\t\treturn new LocalFavoriteInfo(source);\n" +
"\t\t}\n" +
"\n" +
"\t\t@Override\n" +
"\t\tpublic LocalFavoriteInfo[] newArray(int size) {\n" +
"\t\t\treturn new LocalFavoriteInfo[size];\n" +
"\t\t}\n" +
"\t};");
javaClass.addImport("android.os.Parcel");
// Add from GalleryInfo constructor
javaClass.addMethod("\tpublic LocalFavoriteInfo(GalleryInfo galleryInfo) {\n" +
"\t\tthis.gid = galleryInfo.gid;\n" +
"\t\tthis.token = galleryInfo.token;\n" +
"\t\tthis.title = galleryInfo.title;\n" +
"\t\tthis.titleJpn = galleryInfo.titleJpn;\n" +
"\t\tthis.thumb = galleryInfo.thumb;\n" +
"\t\tthis.category = galleryInfo.category;\n" +
"\t\tthis.posted = galleryInfo.posted;\n" +
"\t\tthis.uploader = galleryInfo.uploader;\n" +
"\t\tthis.rating = galleryInfo.rating;\n" +
"\t\tthis.simpleTags = galleryInfo.simpleTags;\n" +
"\t\tthis.simpleLanguage = galleryInfo.simpleLanguage;\n" +
"\t}").setConstructor(true);
javaClass.addImport("com.hippo.ehviewer.client.data.GalleryInfo");
FileWriter fileWriter = new FileWriter(LOCAL_FAVORITE_INFO_PATH);
fileWriter.write(javaClass.toString());
fileWriter.close();
}
private static void adjustBookmarkInfo() throws Exception {
JavaClassSource javaClass = Roaster.parse(JavaClassSource.class, new File(BOOKMARK_INFO_PATH));
// Remove field from GalleryInfo
javaClass.removeField(javaClass.getField("gid"));
javaClass.removeField(javaClass.getField("token"));
javaClass.removeField(javaClass.getField("title"));
javaClass.removeField(javaClass.getField("titleJpn"));
javaClass.removeField(javaClass.getField("thumb"));
javaClass.removeField(javaClass.getField("category"));
javaClass.removeField(javaClass.getField("posted"));
javaClass.removeField(javaClass.getField("uploader"));
javaClass.removeField(javaClass.getField("rating"));
javaClass.removeField(javaClass.getField("simpleLanguage"));
// Set all field public
javaClass.getField("page").setPublic();
javaClass.getField("time").setPublic();
// Add Parcelable stuff
javaClass.addMethod("\t@Override\n" +
"\tpublic int describeContents() {\n" +
"\t\treturn 0;\n" +
"\t}");
javaClass.addMethod("\t@Override\n" +
"\tpublic void writeToParcel(Parcel dest, int flags) {\n" +
"\t\tsuper.writeToParcel(dest, flags);\n" +
"\t\tdest.writeInt(this.page);\n" +
"\t\tdest.writeLong(this.time);\n" +
"\t}");
javaClass.addMethod("\tprotected BookmarkInfo(Parcel in) {\n" +
"\t\tsuper(in);\n" +
"\t\tthis.page = in.readInt();\n" +
"\t\tthis.time = in.readLong();\n" +
"\t}").setConstructor(true);
javaClass.addField("\tpublic static final Creator<BookmarkInfo> CREATOR = new Creator<BookmarkInfo>() {\n" +
"\t\t@Override\n" +
"\t\tpublic BookmarkInfo createFromParcel(Parcel source) {\n" +
"\t\t\treturn new BookmarkInfo(source);\n" +
"\t\t}\n" +
"\n" +
"\t\t@Override\n" +
"\t\tpublic BookmarkInfo[] newArray(int size) {\n" +
"\t\t\treturn new BookmarkInfo[size];\n" +
"\t\t}\n" +
"\t};");
javaClass.addImport("android.os.Parcel");
// Add from GalleryInfo constructor
javaClass.addMethod("\tpublic BookmarkInfo(GalleryInfo galleryInfo) {\n" +
"\t\tthis.gid = galleryInfo.gid;\n" +
"\t\tthis.token = galleryInfo.token;\n" +
"\t\tthis.title = galleryInfo.title;\n" +
"\t\tthis.titleJpn = galleryInfo.titleJpn;\n" +
"\t\tthis.thumb = galleryInfo.thumb;\n" +
"\t\tthis.category = galleryInfo.category;\n" +
"\t\tthis.posted = galleryInfo.posted;\n" +
"\t\tthis.uploader = galleryInfo.uploader;\n" +
"\t\tthis.rating = galleryInfo.rating;\n" +
"\t\tthis.simpleTags = galleryInfo.simpleTags;\n" +
"\t\tthis.simpleLanguage = galleryInfo.simpleLanguage;\n" +
"\t}").setConstructor(true);
javaClass.addImport("com.hippo.ehviewer.client.data.GalleryInfo");
FileWriter fileWriter = new FileWriter(BOOKMARK_INFO_PATH);
fileWriter.write(javaClass.toString());
fileWriter.close();
}
// Since 2
private static void adjustFilter() throws Exception {
JavaClassSource javaClass = Roaster.parse(JavaClassSource.class, new File(FILTER_PATH));
// Set field public
javaClass.getField("mode").setPublic();
javaClass.getField("text").setPublic();
javaClass.getField("enable").setPublic();
// Add hashCode method and equals method
javaClass.addImport("com.hippo.util.HashCodeUtils");
javaClass.addMethod("\t@Override\n" +
"\tpublic int hashCode() {\n" +
"\t\treturn HashCodeUtils.hashCode(mode, text);\n" +
"\t}");
javaClass.addImport("com.hippo.yorozuya.ObjectUtils");
javaClass.addMethod("\t@Override\n" +
"\tpublic boolean equals(Object o) {\n" +
"\t\tif (!(o instanceof Filter)) {\n" +
"\t\t\treturn false;\n" +
"\t\t}\n" +
"\n" +
"\t\tFilter filter = (Filter) o;\n" +
"\t\treturn filter.mode == mode && ObjectUtils.equal(filter.text, text);\n" +
"\t}");
FileWriter fileWriter = new FileWriter(FILTER_PATH);
fileWriter.write(javaClass.toString());
fileWriter.close();
}
}
@@ -1,24 +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.daogenerator;
public class Main {
public static void main(String[] args) throws Exception {
EhDaoGenerator.generate();
}
}
@@ -1,38 +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.daogenerator;
import java.io.File;
public final class Utilities {
public static boolean deleteContents(File dir) {
File[] files = dir.listFiles();
boolean success = true;
if (files != null) {
for (File file : files) {
if (file.isDirectory()) {
success &= deleteContents(file);
}
if (!file.delete()) {
success = false;
}
}
}
return success;
}
}
+104
View File
@@ -0,0 +1,104 @@
<p align="right">
<strong>English<strong>
<span> | </span>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/blob/1.8.x.x/docs/README/zh-cn.md">
简体中文
</a>
<span> | <span>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/blob/1.8.x.x/docs/README/zh-tw.md">
正體中文
</a>
</p>
<h1 align="center">
<img src="../../art/launcher_icon-web.png" width="200">
<br>EhViewer<br>
</h1>
<p align="center">
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/actions/workflows/ci.yml">
<img src="https://github.com/Ehviewer-Overhauled/Ehviewer/actions/workflows/ci.yml/badge.svg" alt="Github Actions">
</a>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/blob/1.8.x.x/LICENSE">
<img src="https://img.shields.io/github/license/Ehviewer-Overhauled/Ehviewer" alt="LICENSE">
</a>
<a href="https://www.codefactor.io/repository/github/Ehviewer-Overhauled/ehviewer">
<img src="https://www.codefactor.io/repository/github/Ehviewer-Overhauled/ehviewer/badge" alt="CodeFactor">
</a>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/releases">
<img src="https://img.shields.io/github/v/release/Ehviewer-Overhauled/ehviewer?include_prereleases" alt="Release">
</a>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/issues">
<img src="https://img.shields.io/github/issues/Ehviewer-Overhauled/ehviewer" alt="Issues">
</a>
</p>
<div align="center">
<h3>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/blob/1.8.x.x/docs/README/en.md#description">
Description
</a>
<span> | </span>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/blob/1.8.x.x/docs/README/en.md#download">
Download
</a>
<span> | </span>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/blob/1.8.x.x/docs/README/en.md#screenshot">
Screenshot
</a>
<span> | </span>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/blob/1.8.x.x/docs/README/en.md#thanks">
Thanks
</a>
<span> | </span>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/blob/1.8.x.x/docs/README/en.md#license">
License
</a>
</h3>
</div>
# Description
EhViewer fork dedicated to lightweight and high-performance
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>
App is divided into two versions: 1.7 and 1.8 . Version 1.8 support Android 12 and above, also the develop mainline. Version 1.7 support Android 11 and below, drop down some spicetify functions for Android 12 to make app useable on lower Android System
# Screenshot
![screenshot-01](../../art/screenshot-01.png)
![screenshot-02](../../art/screenshot-02.png)
# Thanks
Here is the libraries
- [AOSP&AndroidX](http://source.android.com/)
- [FullDraggableDrawer](https://github.com/PureWriter/FullDraggableDrawer)
- [GnuTLS](https://gnutls.org/)
- [material-components-android](https://github.com/material-components/material-components-android)
- [material-design-icons](https://github.com/google/material-design-icons)
- [jsoup](https://github.com/jhy/jsoup)
- [okhttp](https://github.com/square/okhttp)
- [RikkaX](https://github.com/RikkaApps/RikkaX)
- [libarchive](http://www.libarchive.org/)
- [XZ Utils](https://tukaani.org/xz/)
# License
Copyright 2014-2019 Hippo Seven
Copyright 2020-2022 NekoInverter
Copyright 2022 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.
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/>.
+104
View File
@@ -0,0 +1,104 @@
<p align="right">
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/blob/1.8.x.x/docs/README/en.md">
English
</a>
<span> | </span>
<strong>简体中文<strong>
<span> | <span>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/blob/1.8.x.x/docs/README/zh-tw.md">
正體中文
</a>
</p>
<h1 align="center">
<img src="../../art/launcher_icon-web.png" width="200">
<br>EhViewer<br>
</h1>
<p align="center">
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/actions/workflows/ci.yml">
<img src="https://github.com/Ehviewer-Overhauled/Ehviewer/actions/workflows/ci.yml/badge.svg" alt="Github Actions">
</a>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/blob/1.8.x.x/LICENSE">
<img src="https://img.shields.io/github/license/Ehviewer-Overhauled/Ehviewer" alt="LICENSE">
</a>
<a href="https://www.codefactor.io/repository/github/Ehviewer-Overhauled/ehviewer">
<img src="https://www.codefactor.io/repository/github/Ehviewer-Overhauled/ehviewer/badge" alt="CodeFactor">
</a>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/releases">
<img src="https://img.shields.io/github/v/release/Ehviewer-Overhauled/ehviewer?include_prereleases" alt="Release">
</a>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/issues">
<img src="https://img.shields.io/github/issues/Ehviewer-Overhauled/ehviewer" alt="Issues">
</a>
</p>
<div align="center">
<h3>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/blob/1.8.x.x/docs/README/zh-cn.md#描述">
描述
</a>
<span> | </span>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/blob/1.8.x.x/docs/README/zh-cn.md#下载">
下载
</a>
<span> | </span>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/blob/1.8.x.x/docs/README/zh-cn.md#截图">
截图
</a>
<span> | </span>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/blob/1.8.x.x/docs/README/zh-cn.md#感谢">
感谢
</a>
<span> | </span>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/blob/1.8.x.x/docs/README/zh-cn.md#许可证">
许可证
</a>
</h3>
</div>
# 描述
致力于轻量化与良好性能表现的 EhViewer 分支
已针对性适配 Material Design 3 及其动态取色系统
# 下载
<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>
App 分为 1.8 与 1.7 两个版本。1.8 版本适配 Android 12 及以上系统,为开发主线;1.7 版本适配 Android 11 及以下版本,削减了 Android 12 及以上系统的独有功能,使其能在低版本 Android 上正常工作
# 截图
![screenshot-01](../../art/screenshot-01.png)
![screenshot-02](../../art/screenshot-02.png)
# 感谢
本项目受到了诸多开源项目的帮助
- [AOSP&AndroidX](http://source.android.com/)
- [FullDraggableDrawer](https://github.com/PureWriter/FullDraggableDrawer)
- [GnuTLS](https://gnutls.org/)
- [material-components-android](https://github.com/material-components/material-components-android)
- [material-design-icons](https://github.com/google/material-design-icons)
- [jsoup](https://github.com/jhy/jsoup)
- [okhttp](https://github.com/square/okhttp)
- [RikkaX](https://github.com/RikkaApps/RikkaX)
- [libarchive](http://www.libarchive.org/)
- [XZ Utils](https://tukaani.org/xz/)
# 许可证
Copyright 2014-2019 Hippo Seven
Copyright 2020-2022 NekoInverter
Copyright 2022 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.
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/>.
+104
View File
@@ -0,0 +1,104 @@
<p align="right">
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/blob/1.8.x.x/docs/README/en.md">
English
</a>
<span> | </span>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/blob/1.8.x.x/docs/README/zh-cn.md">
简体中文
</a>
<span> | <span>
<strong>正體中文<strong>
</p>
<h1 align="center">
<img src="../../art/launcher_icon-web.png" width="200">
<br>EhViewer<br>
</h1>
<p align="center">
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/actions/workflows/ci.yml">
<img src="https://github.com/Ehviewer-Overhauled/Ehviewer/actions/workflows/ci.yml/badge.svg" alt="Github Actions">
</a>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/blob/1.8.x.x/LICENSE">
<img src="https://img.shields.io/github/license/Ehviewer-Overhauled/Ehviewer" alt="LICENSE">
</a>
<a href="https://www.codefactor.io/repository/github/Ehviewer-Overhauled/ehviewer">
<img src="https://www.codefactor.io/repository/github/Ehviewer-Overhauled/ehviewer/badge" alt="CodeFactor">
</a>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/releases">
<img src="https://img.shields.io/github/v/release/Ehviewer-Overhauled/ehviewer?include_prereleases" alt="Release">
</a>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/issues">
<img src="https://img.shields.io/github/issues/Ehviewer-Overhauled/ehviewer" alt="Issues">
</a>
</p>
<div align="center">
<h3>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/blob/1.8.x.x/docs/README/zh-tw.md#說明">
說明
</a>
<span> | </span>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/blob/1.8.x.x/docs/README/zh-tw.md#下載">
下載
</a>
<span> | </span>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/blob/1.8.x.x/docs/README/zh-tw.md#截圖">
截圖
</a>
<span> | </span>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/blob/1.8.x.x/docs/README/zh-tw.md#感謝">
感謝
</a>
<span> | </span>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/blob/1.8.x.x/docs/README/zh-tw.md#許可證書">
許可證書
</a>
</h3>
</div>
# 說明
致力於輕量化與良好性能表現的 EhViewer 分支
已針對性適配 Material Design 3 及其動態取色系統
# 下載
<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>
App 分為 1.8 與 1.7 兩個版本。1.8 版本適配 Android 12 及以上系統,為開發主線;1.7 版本適配 Android 11 及以下版本,削減了 Android 12 及以上系統的獨有功能,使其能在低版本 Android 上正常工作
# 截圖
![screenshot-01](../../art/screenshot-01.png)
![screenshot-02](../../art/screenshot-02.png)
# 感謝
本項目受到了諸多開源項目的幫助
- [AOSP&AndroidX](http://source.android.com/)
- [FullDraggableDrawer](https://github.com/PureWriter/FullDraggableDrawer)
- [GnuTLS](https://gnutls.org/)
- [material-components-android](https://github.com/material-components/material-components-android)
- [material-design-icons](https://github.com/google/material-design-icons)
- [jsoup](https://github.com/jhy/jsoup)
- [okhttp](https://github.com/square/okhttp)
- [RikkaX](https://github.com/RikkaApps/RikkaX)
- [libarchive](http://www.libarchive.org/)
- [XZ Utils](https://tukaani.org/xz/)
# 許可證書
Copyright 2014-2019 Hippo Seven
Copyright 2020-2022 NekoInverter
Copyright 2022 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.
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/>.
+2 -1
View File
@@ -16,7 +16,8 @@
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
org.gradle.parallel=true
org.gradle.caching=true
android.useAndroidX=true
android.enableJetifier=true
android.enableAppCompileTimeRClass=true
-8
View File
@@ -1,8 +0,0 @@
/build
/src/main/java-gen
manifest-merger-release-report.txt
/src/main/libs
/src/main/obj
# Intellij
*.iml
/.cxx
-41
View File
@@ -1,41 +0,0 @@
plugins {
id 'com.android.library'
id 'org.jetbrains.kotlin.android'
}
android {
compileSdkVersion 33
buildToolsVersion "33.0.0"
ndkVersion "25.0.8775105"
defaultConfig {
minSdkVersion 31
targetSdkVersion 33
consumerProguardFiles 'proguard-rules.pro'
externalNativeBuild {
cmake {
arguments '-DANDROID_STL=none'
}
}
ndk {
abiFilters 'arm64-v8a', 'x86_64', 'armeabi-v7a', 'x86'
}
}
externalNativeBuild {
cmake {
path 'src/main/jni/CMakeLists.txt'
}
}
buildFeatures {
buildConfig false
}
namespace 'com.hippo'
}
dependencies {
compileOnly 'androidx.annotation:annotation:1.4.0'
}
-2
View File
@@ -1,2 +0,0 @@
-keep class com.hippo.* { *; }
-keep class com.hippo.image.* { *; }
-34
View File
@@ -1,34 +0,0 @@
# Copyright 2018 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.
cmake_minimum_required(VERSION 3.4.1)
project(image C)
set(IMAGE_SOURCES
image.c
image_utils.c
java_wrapper.c
)
set(IMAGE_INCLUDES
${CMAKE_CURRENT_SOURCE_DIR}
)
set(IMAGE_LIBRARIES
log
jnigraphics
GLESv2
)
add_library(image STATIC ${IMAGE_SOURCES})
target_include_directories(image PRIVATE ${IMAGE_INCLUDES})
target_link_libraries(image PRIVATE ${IMAGE_LIBRARIES})
-110
View File
@@ -1,110 +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 <android/data_space.h>
#include <stdlib.h>
#include <string.h>
#include "image.h"
#include "image_utils.h"
void decodeCommon(IMAGE *image, SOURCE *src) {
image->src = src;
AImageDecoder *decoder = src->decoder;
image->isAnimated = AImageDecoder_isAnimated(decoder);
AImageDecoder_setDataSpace(decoder, ADATASPACE_SRGB);
AImageDecoder_setAndroidBitmapFormat(decoder, ANDROID_BITMAP_FORMAT_RGBA_8888);
const AImageDecoderHeaderInfo *headerInfo = AImageDecoder_getHeaderInfo(decoder);
image->height = AImageDecoderHeaderInfo_getHeight(headerInfo);
image->width = AImageDecoderHeaderInfo_getWidth(headerInfo);
image->alpha =
AImageDecoderHeaderInfo_getAlphaFlags(headerInfo) == ANDROID_BITMAP_FLAGS_ALPHA_PREMUL;
src->stride = AImageDecoder_getMinimumStride(decoder);
image->bufferLen = (int) (image->height * src->stride);
image->buffer = malloc(image->bufferLen);
if (image->isAnimated) {
AImageDecoder_setInternallyHandleDisposePrevious(decoder, false);
AImageDecoderFrameInfo *frameInfo = AImageDecoderFrameInfo_create();
AImageDecoder_getFrameInfo(decoder, frameInfo);
image->delay = (int) AImageDecoderFrameInfo_getDuration(frameInfo) / 1000000;
AImageDecoderFrameInfo_delete(frameInfo);
}
AImageDecoder_decodeImage(decoder, image->buffer, src->stride, image->bufferLen);
if (!image->isAnimated) {
recycleSource(image->src);
image->src = NULL;
}
}
IMAGE *createFromFd(int fd) {
AImageDecoder *decoder;
AImageDecoder_createFromFd(fd, &decoder);
IMAGE *image = calloc(1, sizeof(IMAGE));
SOURCE *src = calloc(1, sizeof(SOURCE));
src->decoder = decoder;
src->fd = fd;
decodeCommon(image, src);
return image;
}
IMAGE *createFromAddr(void *addr, long size) {
AImageDecoder *decoder;
AImageDecoder_createFromBuffer((const void *) addr, size, &decoder);
IMAGE *image = calloc(1, sizeof(IMAGE));
SOURCE *src = calloc(1, sizeof(SOURCE));
src->decoder = decoder;
src->srcBuffer = addr;
decodeCommon(image, src);
return image;
}
IMAGE *create(int32_t width, int32_t height, const void *data) {
IMAGE *plain = calloc(1, sizeof(IMAGE));
void *buffer = NULL;
size_t length = width * height * 4;
buffer = malloc(length);
memcpy(buffer, data, length);
plain->width = width;
plain->height = height;
plain->buffer = buffer;
plain->bufferLen = (int) length;
return plain;
}
void render(IMAGE *image, int src_x, int src_y,
void *dst, int dst_w, int dst_h, int dst_x, int dst_y,
int width, int height) {
copy_pixels(image->buffer, image->width, image->height, src_x, src_y, dst, dst_w, dst_h, dst_x,
dst_y, width, height);
}
void advance(IMAGE *image) {
if (image->isAnimated) {
AImageDecoder_advanceFrame(image->src->decoder);
if (AImageDecoder_decodeImage(image->src->decoder, image->buffer, image->src->stride,
image->bufferLen) == ANDROID_IMAGE_DECODER_FINISHED) {
AImageDecoder_rewind(image->src->decoder);
AImageDecoder_decodeImage(image->src->decoder, image->buffer, image->src->stride,
image->bufferLen);
}
}
}
-72
View File
@@ -1,72 +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/>.
*/
#ifndef IMAGE_IMAGE_H
#define IMAGE_IMAGE_H
#include <android/imagedecoder.h>
#include <stdbool.h>
typedef struct {
AImageDecoder *decoder;
void *srcBuffer;
size_t stride;
int fd;
} SOURCE;
typedef struct {
int32_t width;
int32_t height;
void *buffer;
int bufferLen;
bool isAnimated;
bool alpha;
int delay;
SOURCE *src;
} IMAGE;
static void recycleSource(SOURCE *src) {
if (!src)
return;
AImageDecoder_delete(src->decoder);
free(src->srcBuffer);
free(src);
}
static void recycle(IMAGE *image) {
if (!image)
return;
recycleSource(image->src);
free(image->buffer);
free(image);
}
IMAGE *createFromFd(int fd);
IMAGE *createFromAddr(void *addr, long size);
IMAGE *create(int32_t width, int32_t height, const void *data);
void render(IMAGE *image, int src_x, int src_y,
void *dst, int dst_w, int dst_h, int dst_x, int dst_y,
int width, int height);
void advance(IMAGE *image);
#endif /* IMAGE_IMAGE_H */
-107
View File
@@ -1,107 +0,0 @@
/*
* Copyright 2015 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.
*/
#include "image_utils.h"
#include <stdlib.h>
#include <string.h>
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 += dst_blank_length;
memcpy(dst + dst_pos, src + src_pos, line_stride);
dst_pos += 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 += dst_blank_length;
memcpy(dst + dst_pos, src + src_pos, line_stride);
dst_pos += line_stride;
src_pos += src_stride;
}
return true;
}
-29
View File
@@ -1,29 +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/>.
*/
#ifndef IMAGE_IMAGE_UTILS_H
#define IMAGE_IMAGE_UTILS_H
#include <stdbool.h>
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);
#endif /* IMAGE_IMAGE_UTILS_H */
-148
View File
@@ -1,148 +0,0 @@
/*
* Copyright 2015 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.
*/
#include <stdlib.h>
#include <android/bitmap.h>
#include <GLES2/gl2.h>
#include <jni.h>
#include "java_wrapper.h"
#include "image.h"
#include "log.h"
static void *tile_buffer = NULL;
static int jniGetFDFromFileDescriptor(JNIEnv *env, jobject fileDescriptor) {
jint fd = -1;
jclass fdClass = (*env)->FindClass(env, "java/io/FileDescriptor");
if (fdClass != NULL) {
jfieldID fdClassDescriptorFieldID = (*env)->GetFieldID(env, fdClass, "descriptor", "I");
if (fdClassDescriptorFieldID != NULL && fileDescriptor != NULL) {
fd = (*env)->GetIntField(env, fileDescriptor, fdClassDescriptorFieldID);
}
}
return fd;
}
jobject create_image_object(JNIEnv *env, void *ptr, int format, int width, int height) {
jclass image_clazz;
jmethodID constructor;
image_clazz = (*env)->FindClass(env, "com/hippo/image/Image");
constructor = (*env)->GetMethodID(env, image_clazz, "<init>", "(JIII)V");
return (*env)->NewObject(env, image_clazz, constructor,
(jlong) (uintptr_t) ptr, (jint) format, (jint) width,
(jint) height);
}
JNIEXPORT jobject JNICALL
Java_com_hippo_image_Image_nativeDecodeFdInt(JNIEnv *env, jclass clazz, jint fd) {
IMAGE *image = createFromFd(fd);
return create_image_object(env, image, image->isAnimated, image->width, image->height);
}
JNIEXPORT jobject JNICALL
Java_com_hippo_image_Image_nativeDecode(JNIEnv *env, jclass clazz, jobject fd) {
return Java_com_hippo_image_Image_nativeDecodeFdInt(env, clazz,
jniGetFDFromFileDescriptor(env, fd));
}
JNIEXPORT jobject JNICALL
Java_com_hippo_image_Image_nativeCreate(JNIEnv *env, jclass clazz, jobject bitmap) {
AndroidBitmapInfo info;
void *pixels = NULL;
void *image = NULL;
AndroidBitmap_getInfo(env, bitmap, &info);
AndroidBitmap_lockPixels(env, bitmap, &pixels);
image = create(info.width, info.height, pixels);
AndroidBitmap_unlockPixels(env, bitmap);
return create_image_object(env, image, 0, info.width, info.height);
}
JNIEXPORT void JNICALL
Java_com_hippo_image_Image_nativeRender(JNIEnv *env, jclass clazz, jlong ptr, jint src_x,
jint src_y, jobject dst, jint dst_x, jint dst_y, jint width,
jint height) {
AndroidBitmapInfo info;
void *pixels = NULL;
AndroidBitmap_getInfo(env, dst, &info);
AndroidBitmap_lockPixels(env, dst, &pixels);
render((IMAGE *) ptr, src_x, src_y, pixels, info.width, info.height, dst_x, dst_y, width,
height);
AndroidBitmap_unlockPixels(env, dst);
}
JNIEXPORT void JNICALL
Java_com_hippo_image_Image_nativeTexImage(JNIEnv *env, jclass clazz, jlong ptr, jboolean init,
jint src_x, jint src_y, jint width, jint height) {
if (width * height > IMAGE_TILE_MAX_SIZE)
return;
render((IMAGE *) ptr, src_x, src_y, tile_buffer, width, height, 0, 0, width, height);
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);
}
}
JNIEXPORT void JNICALL
Java_com_hippo_image_Image_nativeAdvance(JNIEnv *env, jclass clazz, jlong ptr) {
advance((IMAGE *) ptr);
}
JNIEXPORT jint JNICALL
Java_com_hippo_image_Image_nativeGetDelay(JNIEnv *env, jclass clazz, jlong ptr) {
return ((IMAGE *) ptr)->delay;
}
JNIEXPORT jboolean JNICALL
Java_com_hippo_image_Image_nativeIsOpaque(JNIEnv *env, jclass clazz, jlong ptr) {
return ((IMAGE *) ptr)->alpha;
}
JNIEXPORT void JNICALL
Java_com_hippo_image_Image_nativeRecycle(JNIEnv *env, jclass clazz, jlong ptr) {
recycle((IMAGE *) ptr);
}
bool image_onLoad() {
tile_buffer = malloc(IMAGE_TILE_MAX_SIZE * 4);
return tile_buffer != NULL;
}
void image_onUnload() {
free(tile_buffer);
tile_buffer = NULL;
}
JNIEXPORT jobject JNICALL
Java_com_hippo_image_Image_nativeDecodeAddr(JNIEnv *env, jclass clazz, jlong addr) {
Memarea *memarea = (Memarea *) addr;
IMAGE *image = createFromAddr(memarea->buffer, memarea->size);
free(memarea);
return create_image_object(env, image, image->isAnimated, image->width, image->height);
}
-30
View File
@@ -1,30 +0,0 @@
/*
* Copyright 2015 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.
*/
#ifndef LOG_H
#define LOG_H
#include <android/log.h>
#define TAG "ImageDecoder_wrapper"
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG ,__VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG ,__VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG ,__VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, TAG ,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG ,__VA_ARGS__)
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL, TAG ,__VA_ARGS__)
#endif /* LOG_H */
+1 -1
View File
@@ -16,4 +16,4 @@ dependencyResolutionManagement {
}
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
rootProject.name = "EhViewer"
include ':app', ':daogenerator', ':native'
include ':app'