Compare commits
93
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac20755c45 | ||
|
|
610202bbbd | ||
|
|
58ce7134e1 | ||
|
|
71f91cd79e | ||
|
|
8c821ecad3 | ||
|
|
c704940462 | ||
|
|
6a7cd1b89a | ||
|
|
e29da0ba13 | ||
|
|
7791fa10f5 | ||
|
|
48ed3c8f31 | ||
|
|
7ad7a9b94e | ||
|
|
54b929ba24 | ||
|
|
7b655c6260 | ||
|
|
4e8d41b145 | ||
|
|
f036774e07 | ||
|
|
97d1bd7685 | ||
|
|
8e39449856 | ||
|
|
30f1a5a6eb | ||
|
|
627abb047c | ||
|
|
9284008afe | ||
|
|
9159f4616f | ||
|
|
73296b1430 | ||
|
|
c74e622d69 | ||
|
|
f48eb55516 | ||
|
|
b01f6ef8d3 | ||
|
|
167185ef45 | ||
|
|
777a8ffeaa | ||
|
|
b2b3e6c485 | ||
|
|
613d502fc1 | ||
|
|
79da457db4 | ||
|
|
b1a431ed82 | ||
|
|
b0f2776a23 | ||
|
|
900c346ee8 | ||
|
|
7541a87b21 | ||
|
|
2547c67ebd | ||
|
|
5ae6a0b287 | ||
|
|
f718fc0c89 | ||
|
|
57e69ba7be | ||
|
|
6168b3e047 | ||
|
|
3e500500e0 | ||
|
|
42f06ff84a | ||
|
|
a7824fc473 | ||
|
|
67e7fd6928 | ||
|
|
450e8badba | ||
|
|
704c211e11 | ||
|
|
0ad871cb5b | ||
|
|
9920605570 | ||
|
|
b1e8678dbf | ||
|
|
e2cd2ddc0d | ||
|
|
a3be0dfddf | ||
|
|
4b615ffc0b | ||
|
|
64cbd189ad | ||
|
|
0fae5a128f | ||
|
|
518b44216f | ||
|
|
9ef4512ef9 | ||
|
|
8bb5f1e955 | ||
|
|
8f8932f617 | ||
|
|
23fd1d75c4 | ||
|
|
593dcef550 | ||
|
|
d769fe9074 | ||
|
|
77a8fec790 | ||
|
|
34440edfaa | ||
|
|
3c3d8784ad | ||
|
|
1591abc92c | ||
|
|
0ffa0c34f0 | ||
|
|
c7dc94b61b | ||
|
|
a8b83871a4 | ||
|
|
6f547984ff | ||
|
|
3979c11317 | ||
|
|
2a1ec985f4 | ||
|
|
2a1d49e945 | ||
|
|
7b7e6140d2 | ||
|
|
907cfd9694 | ||
|
|
b51b1d1ec6 | ||
|
|
6a026300e4 | ||
|
|
8511907390 | ||
|
|
05a5be336e | ||
|
|
5434b1ce19 | ||
|
|
c2d4a4367c | ||
|
|
de2f277513 | ||
|
|
283e522037 | ||
|
|
caebe4c23b | ||
|
|
b195277c9a | ||
|
|
6b99cb6253 | ||
|
|
a822bb670a | ||
|
|
af7cc11647 | ||
|
|
0afe331d3d | ||
|
|
7af40f0cd7 | ||
|
|
52dc699ee2 | ||
|
|
ec28e21897 | ||
|
|
3283851dc4 | ||
|
|
ec5e0c7b25 | ||
|
|
13660cb70a |
No files matched your search
@@ -17,12 +17,14 @@ body:
|
||||
attributes:
|
||||
label: 复现步骤 / Step to reproduce
|
||||
description: |
|
||||
在此处写下复现的方式
|
||||
Describe how to reproduce here
|
||||
请从全新安装应用开始,在此处写下复现的方式。请尽量附带录屏
|
||||
Describe how to reproduce here with fresh installation, with screen recording if possible.
|
||||
placeholder: |
|
||||
0. 重新安装应用 / Fresh install
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
[录屏] / [Screen recording]
|
||||
validations:
|
||||
required: true
|
||||
|
||||
@@ -111,15 +113,6 @@ body:
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: log
|
||||
attributes:
|
||||
label: 应用日志 / App logs
|
||||
description: 您可以通过设置-高级-导出日志来获得日志文件 / You can get logs file in Settings - Advanced - Dump logcat
|
||||
placeholder: 06-15 17:44:53.704 23382 23382 E ...
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: checkboxes
|
||||
id: check
|
||||
attributes:
|
||||
|
||||
+12
-11
@@ -33,7 +33,7 @@ android {
|
||||
minSdkVersion 28
|
||||
targetSdkVersion 33
|
||||
versionCode 180030
|
||||
versionName "1.8.5.3-alpha02"
|
||||
versionName "1.8.5.3-alpha04"
|
||||
resConfigs 'zh', 'zh-rCN', 'zh-rHK', 'zh-rTW', 'es', 'ja', 'ko', 'fr', 'de', 'th'
|
||||
}
|
||||
|
||||
@@ -104,6 +104,7 @@ android {
|
||||
dependencies {
|
||||
def activity_version = "1.6.1"
|
||||
implementation "androidx.activity:activity-ktx:$activity_version"
|
||||
implementation "androidx.activity:activity-compose:$activity_version"
|
||||
|
||||
implementation "androidx.annotation:annotation:1.5.0"
|
||||
implementation "androidx.annotation:annotation-experimental:1.3.0"
|
||||
@@ -121,13 +122,9 @@ dependencies {
|
||||
implementation "androidx.collection:collection-ktx:$collection_version"
|
||||
|
||||
implementation platform("androidx.compose:compose-bom:2022.12.00")
|
||||
implementation "androidx.compose.animation:animation"
|
||||
implementation "androidx.compose.foundation:foundation"
|
||||
implementation "androidx.compose.foundation:foundation-layout"
|
||||
implementation "androidx.compose.material:material-icons-extended"
|
||||
implementation "androidx.compose.material3:material3"
|
||||
implementation "androidx.compose.runtime:runtime"
|
||||
implementation "androidx.compose.runtime:runtime-saveable"
|
||||
implementation "androidx.compose.ui:ui"
|
||||
implementation 'androidx.compose.ui:ui-tooling-preview'
|
||||
|
||||
implementation "androidx.constraintlayout:constraintlayout:2.2.0-alpha05"
|
||||
implementation "androidx.coordinatorlayout:coordinatorlayout:1.2.0"
|
||||
@@ -141,7 +138,7 @@ dependencies {
|
||||
def fragment_version = "1.6.0-alpha04"
|
||||
implementation "androidx.fragment:fragment-ktx:$fragment_version"
|
||||
|
||||
def lifecycle_version = "2.6.0-alpha03"
|
||||
def lifecycle_version = "2.6.0-alpha04"
|
||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
|
||||
implementation "androidx.lifecycle:lifecycle-livedata-core-ktx:$lifecycle_version"
|
||||
implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version"
|
||||
@@ -154,6 +151,7 @@ dependencies {
|
||||
def nav_version = "2.5.3"
|
||||
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
|
||||
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
|
||||
implementation "androidx.navigation:navigation-compose:$nav_version"
|
||||
|
||||
implementation "androidx.paging:paging-runtime-ktx:3.2.0-alpha03"
|
||||
|
||||
@@ -165,7 +163,7 @@ dependencies {
|
||||
ksp "androidx.room:room-compiler:$room_version"
|
||||
implementation "androidx.room:room-paging:$room_version"
|
||||
|
||||
implementation 'androidx.startup:startup-runtime:1.2.0-alpha01'
|
||||
implementation 'androidx.startup:startup-runtime:1.2.0-alpha02'
|
||||
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.2.0-alpha01'
|
||||
implementation "androidx.transition:transition-ktx:1.4.1"
|
||||
implementation "androidx.vectordrawable:vectordrawable:1.2.0-beta01"
|
||||
@@ -174,7 +172,11 @@ dependencies {
|
||||
implementation 'androidx.viewpager2:viewpager2:1.1.0-beta01'
|
||||
|
||||
implementation 'com.drakeet.drawer:drawer:1.0.3'
|
||||
implementation 'com.google.android.material:material:1.8.0-beta01'
|
||||
|
||||
def accompanist_version = "0.28.0"
|
||||
implementation "com.google.accompanist:accompanist-themeadapter-material3:$accompanist_version"
|
||||
|
||||
implementation 'com.google.android.material:material:1.8.0-rc01'
|
||||
|
||||
implementation 'com.squareup.okhttp3:okhttp-bom:5.0.0-alpha.11'
|
||||
implementation 'com.squareup.okhttp3:okhttp'
|
||||
@@ -197,7 +199,6 @@ dependencies {
|
||||
configurations.all {
|
||||
exclude group: 'dev.rikka.rikkax.appcompat', module: 'appcompat'
|
||||
exclude group: 'dev.rikka.rikkax.material', module: 'material'
|
||||
exclude group: 'androidx.compose.material'
|
||||
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-android-extensions-runtime'
|
||||
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk7'
|
||||
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk8'
|
||||
|
||||
@@ -1,19 +1,4 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
@@ -28,13 +13,12 @@
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
|
||||
<uses-permission
|
||||
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="28" />
|
||||
|
||||
<application
|
||||
android:name="com.hippo.ehviewer.EhApplication"
|
||||
android:name=".EhApplication"
|
||||
android:allowBackup="true"
|
||||
android:appCategory="image"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
@@ -42,29 +26,33 @@
|
||||
android:fullBackupContent="@xml/backup_scheme"
|
||||
android:hasFragileUserData="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:supportsRtl="true"
|
||||
android:label="@string/app_name"
|
||||
android:localeConfig="@xml/locales_config"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme"
|
||||
tools:targetApi="tiramisu">
|
||||
|
||||
<activity
|
||||
android:name="com.hippo.ehviewer.ui.MainActivity"
|
||||
android:name=".ui.LoginActivity"
|
||||
android:exported="false"
|
||||
android:theme="@style/AppTheme"
|
||||
android:windowSoftInputMode="adjustResize"/>
|
||||
<activity
|
||||
android:name=".ui.MainActivity"
|
||||
android:banner="@mipmap/ic_leanback_banner"
|
||||
android:configChanges="screenSize"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTask"
|
||||
android:windowSoftInputMode="adjustResize|stateAlwaysHidden">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
@@ -85,26 +73,26 @@
|
||||
<data android:host="g.e-hentai.org" />
|
||||
<data android:host="lofi.e-hentai.org" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter android:label="@string/keyword_search">
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
|
||||
<data android:mimeType="text/plain" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter android:label="@string/image_search">
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
|
||||
<data android:mimeType="image/*" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="eu.kanade.tachiyomi.ui.reader.ReaderActivity"
|
||||
android:configChanges="screenSize"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTask">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
@@ -138,21 +126,18 @@
|
||||
<data android:mimeType="application/x-xz-compressed-tar" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="com.hippo.ehviewer.ui.SettingsActivity"
|
||||
android:name=".ui.SettingsActivity"
|
||||
android:configChanges="screenSize"
|
||||
android:label="@string/settings"
|
||||
android:theme="@style/AppTheme" />
|
||||
|
||||
<activity
|
||||
android:name="com.hippo.ehviewer.ui.SecurityActivity"
|
||||
android:name=".ui.SecurityActivity"
|
||||
android:configChanges="screenSize"
|
||||
android:label="@string/settings"
|
||||
android:theme="@style/AppTheme" />
|
||||
|
||||
<activity
|
||||
android:name="com.hippo.ehviewer.shortcuts.ShortcutsActivity"
|
||||
android:name=".shortcuts.ShortcutsActivity"
|
||||
android:excludeFromRecents="true"
|
||||
android:launchMode="singleTask"
|
||||
android:taskAffinity=""
|
||||
@@ -166,9 +151,8 @@
|
||||
android:name="autoStoreLocales"
|
||||
android:value="true" />
|
||||
</service>
|
||||
|
||||
<service
|
||||
android:name="com.hippo.ehviewer.download.DownloadService"
|
||||
android:name=".download.DownloadService"
|
||||
android:foregroundServiceType="dataSync"
|
||||
android:label="@string/download_service_label" />
|
||||
|
||||
@@ -177,11 +161,10 @@
|
||||
android:authorities="${applicationId}.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/filepaths" />
|
||||
|
||||
</provider>
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
</manifest>
|
||||
+1
-1
Submodule app/src/main/cpp/liblzma updated: b35079d589...fc9fb0ea24.
@@ -352,21 +352,7 @@ public final class DiskLruCache implements Closeable {
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
} private final Callable<Void> cleanupCallable = new Callable<>() {
|
||||
public Void call() throws Exception {
|
||||
synchronized (DiskLruCache.this) {
|
||||
if (journalWriter == null) {
|
||||
return null; // Closed.
|
||||
}
|
||||
trimToSize();
|
||||
if (journalRebuildRequired()) {
|
||||
rebuildJournal();
|
||||
redundantOpCount = 0;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new journal that omits redundant information. This replaces the
|
||||
@@ -406,7 +392,21 @@ public final class DiskLruCache implements Closeable {
|
||||
|
||||
journalWriter = new BufferedWriter(
|
||||
new OutputStreamWriter(new FileOutputStream(journalFile, true), Util.US_ASCII));
|
||||
}
|
||||
} private final Callable<Void> cleanupCallable = new Callable<>() {
|
||||
public Void call() throws Exception {
|
||||
synchronized (DiskLruCache.this) {
|
||||
if (journalWriter == null) {
|
||||
return null; // Closed.
|
||||
}
|
||||
trimToSize();
|
||||
if (journalRebuildRequired()) {
|
||||
rebuildJournal();
|
||||
redundantOpCount = 0;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Return {@code true} if it contains the key
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package com.hippo.ehviewer;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
@@ -25,7 +24,6 @@ import android.os.Debug;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.hippo.scene.StageActivity;
|
||||
import com.hippo.util.PackageUtils;
|
||||
import com.hippo.util.ReadableTime;
|
||||
import com.hippo.yorozuya.FileUtils;
|
||||
@@ -78,27 +76,10 @@ public final class Crash {
|
||||
|
||||
// Runtime
|
||||
String topActivityClazzName = "null";
|
||||
String topSceneClazzName = "null";
|
||||
try {
|
||||
Activity topActivity = ((EhApplication) context.getApplicationContext()).getTopActivity();
|
||||
if (null != topActivity) {
|
||||
topActivityClazzName = topActivity.getClass().getName();
|
||||
if (topActivity instanceof StageActivity) {
|
||||
Class<?> clazz = ((StageActivity) topActivity).getTopSceneClass();
|
||||
if (clazz != null) {
|
||||
topSceneClazzName = clazz.getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
// Ignore
|
||||
}
|
||||
fw.write("======== Runtime ========\r\n");
|
||||
fw.write("TopActivity=");
|
||||
fw.write(avoidNull(topActivityClazzName));
|
||||
fw.write("\r\n");
|
||||
fw.write("TopScene=");
|
||||
fw.write(avoidNull(topSceneClazzName));
|
||||
fw.write("\r\n");
|
||||
fw.write("\r\n");
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.hippo.ehviewer
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.app.ActivityManager
|
||||
import android.app.Application
|
||||
import android.content.ComponentCallbacks2
|
||||
import android.text.Html
|
||||
import android.text.method.LinkMovementMethod
|
||||
@@ -44,11 +45,11 @@ import com.hippo.ehviewer.client.EhUrl
|
||||
import com.hippo.ehviewer.client.EhX509TrustManager
|
||||
import com.hippo.ehviewer.client.data.GalleryDetail
|
||||
import com.hippo.ehviewer.client.parser.EventPaneParser
|
||||
import com.hippo.ehviewer.dao.buildMainDB
|
||||
import com.hippo.ehviewer.download.DownloadManager
|
||||
import com.hippo.ehviewer.spider.SpiderDen
|
||||
import com.hippo.ehviewer.ui.CommonOperations
|
||||
import com.hippo.ehviewer.ui.EhActivity
|
||||
import com.hippo.scene.SceneApplication
|
||||
import com.hippo.util.BitmapUtils
|
||||
import com.hippo.util.ExceptionUtils
|
||||
import com.hippo.util.ReadableTime
|
||||
@@ -70,7 +71,7 @@ import java.util.Arrays
|
||||
import javax.net.ssl.TrustManagerFactory
|
||||
import javax.net.ssl.X509TrustManager
|
||||
|
||||
class EhApplication : SceneApplication(), DefaultLifecycleObserver, ImageLoaderFactory {
|
||||
class EhApplication : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
|
||||
private val mIdGenerator = IntIdGenerator()
|
||||
private val mGlobalStuffMap = HashMap<Int, Any>()
|
||||
private val mActivityList = ArrayList<Activity>()
|
||||
@@ -100,18 +101,20 @@ class EhApplication : SceneApplication(), DefaultLifecycleObserver, ImageLoaderF
|
||||
}
|
||||
handler?.uncaughtException(t, e)
|
||||
}
|
||||
super<SceneApplication>.onCreate()
|
||||
super<Application>.onCreate()
|
||||
Native.initialize()
|
||||
GetText.initialize(this)
|
||||
Settings.initialize()
|
||||
ReadableTime.initialize(this)
|
||||
AppConfig.initialize(this)
|
||||
SpiderDen.initialize(this)
|
||||
EhDB.initialize(this)
|
||||
BitmapUtils.initialize(this)
|
||||
EhTagDatabase.update()
|
||||
AppCompatDelegate.setDefaultNightMode(Settings.getTheme())
|
||||
launchIO {
|
||||
launchIO {
|
||||
ehDatabase
|
||||
}
|
||||
launchIO {
|
||||
downloadManager
|
||||
}
|
||||
@@ -342,5 +345,8 @@ class EhApplication : SceneApplication(), DefaultLifecycleObserver, ImageLoaderF
|
||||
|
||||
@JvmStatic
|
||||
val readerPreferences by lazy { ReaderPreferences(AndroidPreferenceStore(application)) }
|
||||
|
||||
@JvmStatic
|
||||
val ehDatabase by lazy { buildMainDB(application) }
|
||||
}
|
||||
}
|
||||
@@ -58,7 +58,7 @@ import java.util.List;
|
||||
public class EhDB {
|
||||
private static final int CUR_DB_VER = 4;
|
||||
|
||||
private static EhDatabase db;
|
||||
private static final EhDatabase db = EhApplication.getEhDatabase();
|
||||
|
||||
private static void upgradeDB(SQLiteDatabase db, int oldVersion) {
|
||||
switch (oldVersion) {
|
||||
@@ -99,10 +99,6 @@ public class EhDB {
|
||||
}
|
||||
}
|
||||
|
||||
public static void initialize(Context context) {
|
||||
db = Room.databaseBuilder(context, EhDatabase.class, "eh.db").allowMainThreadQueries().build();
|
||||
}
|
||||
|
||||
public static synchronized List<DownloadInfo> getAllDownloadInfo() {
|
||||
DownloadsDao dao = db.downloadsDao();
|
||||
List<DownloadInfo> list = dao.list();
|
||||
@@ -115,10 +111,34 @@ public class EhDB {
|
||||
return list;
|
||||
}
|
||||
|
||||
public static synchronized void moveDownloadInfo(int fromPosition, int toPosition) {
|
||||
if (fromPosition == toPosition) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean reverse = fromPosition > toPosition;
|
||||
int offset = reverse ? toPosition : fromPosition;
|
||||
int limit = reverse ? fromPosition - toPosition + 1 : toPosition - fromPosition + 1;
|
||||
|
||||
DownloadsDao dao = db.downloadsDao();
|
||||
List<DownloadInfo> list = dao.list(offset, limit);
|
||||
|
||||
int step = reverse ? 1 : -1;
|
||||
int start = reverse ? limit - 1 : 0;
|
||||
int end = reverse ? 0 : limit - 1;
|
||||
long toTime = list.get(end).time;
|
||||
for (int i = end; reverse ? i < start : i > start; i += step) {
|
||||
list.get(i).time = list.get(i + step).time;
|
||||
}
|
||||
list.get(start).time = toTime;
|
||||
|
||||
dao.update(list);
|
||||
}
|
||||
|
||||
// Insert or update
|
||||
public static synchronized void putDownloadInfo(DownloadInfo downloadInfo) {
|
||||
DownloadsDao dao = db.downloadsDao();
|
||||
if (null != dao.load(downloadInfo.gid)) {
|
||||
if (null != dao.load(downloadInfo.getGid())) {
|
||||
// Update
|
||||
dao.update(downloadInfo);
|
||||
} else {
|
||||
@@ -256,7 +276,7 @@ public class EhDB {
|
||||
|
||||
public static synchronized void putLocalFavorites(GalleryInfo galleryInfo) {
|
||||
LocalFavoritesDao dao = db.localFavoritesDao();
|
||||
if (null == dao.load(galleryInfo.gid)) {
|
||||
if (null == dao.load(galleryInfo.getGid())) {
|
||||
LocalFavoriteInfo info;
|
||||
if (galleryInfo instanceof LocalFavoriteInfo) {
|
||||
info = (LocalFavoriteInfo) galleryInfo;
|
||||
@@ -335,7 +355,7 @@ public class EhDB {
|
||||
info = new HistoryInfo(galleryInfo);
|
||||
}
|
||||
info.time = System.currentTimeMillis();
|
||||
if (null != dao.load(info.gid)) {
|
||||
if (null != dao.load(info.getGid())) {
|
||||
dao.update(info);
|
||||
} else {
|
||||
dao.insert(info);
|
||||
@@ -345,7 +365,7 @@ public class EhDB {
|
||||
public static synchronized void putHistoryInfo(List<HistoryInfo> historyInfoList) {
|
||||
HistoryDao dao = db.historyDao();
|
||||
for (HistoryInfo info : historyInfoList) {
|
||||
if (null == dao.load(info.gid)) {
|
||||
if (null == dao.load(info.getGid())) {
|
||||
dao.insert(info);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ public class FavouriteStatusRouter {
|
||||
for (Map<Long, GalleryInfo> map : maps.values()) {
|
||||
GalleryInfo info = map.get(gid);
|
||||
if (info != null) {
|
||||
info.favoriteSlot = slot;
|
||||
info.setFavoriteSlot(slot);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,12 +26,8 @@ import android.widget.Toast;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.browser.customtabs.CustomTabsIntent;
|
||||
|
||||
import com.hippo.ehviewer.client.EhUrlOpener;
|
||||
import com.hippo.ehviewer.client.data.GalleryDetail;
|
||||
import com.hippo.ehviewer.client.parser.GalleryPageUrlParser;
|
||||
import com.hippo.ehviewer.ui.MainActivity;
|
||||
import com.hippo.scene.Announcer;
|
||||
import com.hippo.scene.StageActivity;
|
||||
|
||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity;
|
||||
|
||||
@@ -56,7 +52,7 @@ public final class UrlOpener {
|
||||
if (galleryDetail != null) {
|
||||
GalleryPageUrlParser.Result result = GalleryPageUrlParser.parse(url);
|
||||
if (result != null) {
|
||||
if (result.gid == galleryDetail.gid) {
|
||||
if (result.gid == galleryDetail.getGid()) {
|
||||
intent = new Intent(context, ReaderActivity.class);
|
||||
intent.setAction(ReaderActivity.ACTION_EH);
|
||||
intent.putExtra(ReaderActivity.KEY_GALLERY_INFO, galleryDetail);
|
||||
@@ -77,16 +73,6 @@ public final class UrlOpener {
|
||||
}
|
||||
}
|
||||
}
|
||||
Announcer announcer = EhUrlOpener.parseUrl(url);
|
||||
if (null != announcer) {
|
||||
intent = new Intent(context, MainActivity.class);
|
||||
intent.setAction(StageActivity.ACTION_START_SCENE);
|
||||
intent.putExtra(StageActivity.KEY_SCENE_NAME, announcer.getClazz().getName());
|
||||
intent.putExtra(StageActivity.KEY_SCENE_ARGS, announcer.getArgs());
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
context.startActivity(intent);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
CustomTabsIntent.Builder customTabsIntent = new CustomTabsIntent.Builder();
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package com.hippo.ehviewer.client
|
||||
|
||||
import com.hippo.ehviewer.EhApplication.Companion.okHttpClient
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import eu.kanade.tachiyomi.util.lang.withUIContext
|
||||
import kotlinx.coroutines.CancellationException
|
||||
@@ -26,136 +25,13 @@ object EhClient {
|
||||
internal fun enqueue(request: EhRequest, scope: CoroutineScope) {
|
||||
check(!request.isActive) // Abort if attempt to execute an active request
|
||||
request.job = scope.launchIO {
|
||||
val method = request.method
|
||||
val params = request.args
|
||||
val callback: Callback<Any?>? = request.callback
|
||||
try {
|
||||
val result: Any? = when (method) {
|
||||
METHOD_SIGN_IN -> EhEngine.signIn(
|
||||
mOkHttpClient,
|
||||
params!![0] as String,
|
||||
params[1] as String
|
||||
)
|
||||
|
||||
METHOD_GET_GALLERY_LIST -> EhEngine.getGalleryList(
|
||||
mOkHttpClient,
|
||||
params!![0] as String
|
||||
)
|
||||
|
||||
METHOD_GET_GALLERY_DETAIL -> EhEngine.getGalleryDetail(
|
||||
mOkHttpClient,
|
||||
params!![0] as String?
|
||||
)
|
||||
|
||||
METHOD_GET_PREVIEW_SET -> EhEngine.getPreviewSet(
|
||||
mOkHttpClient,
|
||||
params!![0] as String?
|
||||
)
|
||||
|
||||
METHOD_GET_RATE_GALLERY -> EhEngine.rateGallery(
|
||||
mOkHttpClient,
|
||||
params!![0] as Long,
|
||||
params[1] as String?,
|
||||
params[2] as Long,
|
||||
params[3] as String?,
|
||||
params[4] as Float
|
||||
)
|
||||
|
||||
METHOD_GET_COMMENT_GALLERY -> EhEngine.commentGallery(
|
||||
mOkHttpClient,
|
||||
params!![0] as String?,
|
||||
params[1] as String,
|
||||
params[2] as String?
|
||||
)
|
||||
|
||||
METHOD_GET_GALLERY_TOKEN -> EhEngine.getGalleryToken(
|
||||
mOkHttpClient,
|
||||
params!![0] as Long,
|
||||
params[1] as String?,
|
||||
params[2] as Int
|
||||
)
|
||||
|
||||
METHOD_GET_FAVORITES -> EhEngine.getFavorites(
|
||||
mOkHttpClient,
|
||||
params!![0] as String
|
||||
)
|
||||
|
||||
METHOD_ADD_FAVORITES -> EhEngine.addFavorites(
|
||||
mOkHttpClient,
|
||||
params!![0] as Long,
|
||||
params[1] as String?,
|
||||
params[2] as Int,
|
||||
params[3] as String?
|
||||
)
|
||||
|
||||
METHOD_ADD_FAVORITES_RANGE -> @Suppress("UNCHECKED_CAST") EhEngine.addFavoritesRange(
|
||||
mOkHttpClient,
|
||||
params!![0] as LongArray,
|
||||
params[1] as Array<String?>,
|
||||
params[2] as Int
|
||||
)
|
||||
|
||||
METHOD_MODIFY_FAVORITES -> EhEngine.modifyFavorites(
|
||||
mOkHttpClient,
|
||||
params!![0] as String,
|
||||
params[1] as LongArray,
|
||||
params[2] as Int
|
||||
)
|
||||
|
||||
METHOD_GET_TORRENT_LIST -> EhEngine.getTorrentList(
|
||||
mOkHttpClient,
|
||||
params!![0] as String?,
|
||||
params[1] as Long,
|
||||
params[2] as String?
|
||||
)
|
||||
|
||||
METHOD_GET_PROFILE -> EhEngine.getProfile(mOkHttpClient)
|
||||
METHOD_VOTE_COMMENT -> EhEngine.voteComment(
|
||||
mOkHttpClient,
|
||||
params!![0] as Long,
|
||||
params[1] as String?,
|
||||
params[2] as Long,
|
||||
params[3] as String?,
|
||||
params[4] as Long,
|
||||
params[5] as Int
|
||||
)
|
||||
|
||||
METHOD_IMAGE_SEARCH -> EhEngine.imageSearch(
|
||||
mOkHttpClient,
|
||||
params!![0] as File,
|
||||
params[1] as Boolean,
|
||||
params[2] as Boolean,
|
||||
params[3] as Boolean
|
||||
)
|
||||
|
||||
METHOD_ARCHIVE_LIST -> EhEngine.getArchiveList(
|
||||
mOkHttpClient,
|
||||
params!![0] as String?,
|
||||
params[1] as Long,
|
||||
params[2] as String?
|
||||
)
|
||||
|
||||
METHOD_DOWNLOAD_ARCHIVE -> EhEngine.downloadArchive(
|
||||
mOkHttpClient,
|
||||
params!![0] as Long,
|
||||
params[1] as String?,
|
||||
params[2] as String?,
|
||||
params[3] as String?,
|
||||
params[4] as Boolean
|
||||
)
|
||||
|
||||
METHOD_VOTE_TAG -> EhEngine.voteTag(
|
||||
mOkHttpClient,
|
||||
params!![0] as Long,
|
||||
params[1] as String?,
|
||||
params[2] as Long,
|
||||
params[3] as String?,
|
||||
params[4] as String?,
|
||||
params[5] as Int
|
||||
)
|
||||
|
||||
METHOD_GET_UCONFIG -> EhEngine.getUConfig(mOkHttpClient)
|
||||
else -> throw IllegalStateException("Can't detect method $method")
|
||||
val result: Any? = request.run {
|
||||
if (args == null)
|
||||
execute(method)
|
||||
else
|
||||
execute(method, *args!!)
|
||||
}
|
||||
withUIContext { callback?.onSuccess(result) }
|
||||
} catch (e: Exception) {
|
||||
@@ -167,6 +43,119 @@ object EhClient {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun execute(method: Int, vararg params: Any?): Any? {
|
||||
return when (method) {
|
||||
METHOD_SIGN_IN -> EhEngine.signIn(
|
||||
params[0] as String,
|
||||
params[1] as String
|
||||
)
|
||||
|
||||
METHOD_GET_GALLERY_LIST -> EhEngine.getGalleryList(
|
||||
params[0] as String
|
||||
)
|
||||
|
||||
METHOD_GET_GALLERY_DETAIL -> EhEngine.getGalleryDetail(
|
||||
params[0] as String?
|
||||
)
|
||||
|
||||
METHOD_GET_PREVIEW_SET -> EhEngine.getPreviewSet(
|
||||
params[0] as String?
|
||||
)
|
||||
|
||||
METHOD_GET_RATE_GALLERY -> EhEngine.rateGallery(
|
||||
params[0] as Long,
|
||||
params[1] as String?,
|
||||
params[2] as Long,
|
||||
params[3] as String?,
|
||||
params[4] as Float
|
||||
)
|
||||
|
||||
METHOD_GET_COMMENT_GALLERY -> EhEngine.commentGallery(
|
||||
params[0] as String?,
|
||||
params[1] as String,
|
||||
params[2] as String?
|
||||
)
|
||||
|
||||
METHOD_GET_GALLERY_TOKEN -> EhEngine.getGalleryToken(
|
||||
params[0] as Long,
|
||||
params[1] as String?,
|
||||
params[2] as Int
|
||||
)
|
||||
|
||||
METHOD_GET_FAVORITES -> EhEngine.getFavorites(
|
||||
params[0] as String
|
||||
)
|
||||
|
||||
METHOD_ADD_FAVORITES -> EhEngine.addFavorites(
|
||||
params[0] as Long,
|
||||
params[1] as String?,
|
||||
params[2] as Int,
|
||||
params[3] as String?
|
||||
)
|
||||
|
||||
METHOD_ADD_FAVORITES_RANGE -> @Suppress("UNCHECKED_CAST") EhEngine.addFavoritesRange(
|
||||
params[0] as LongArray,
|
||||
params[1] as Array<String?>,
|
||||
params[2] as Int
|
||||
)
|
||||
|
||||
METHOD_MODIFY_FAVORITES -> EhEngine.modifyFavorites(
|
||||
params[0] as String,
|
||||
params[1] as LongArray,
|
||||
params[2] as Int
|
||||
)
|
||||
|
||||
METHOD_GET_TORRENT_LIST -> EhEngine.getTorrentList(
|
||||
params[0] as String?,
|
||||
params[1] as Long,
|
||||
params[2] as String?
|
||||
)
|
||||
|
||||
METHOD_GET_PROFILE -> EhEngine.getProfile()
|
||||
METHOD_VOTE_COMMENT -> EhEngine.voteComment(
|
||||
params[0] as Long,
|
||||
params[1] as String?,
|
||||
params[2] as Long,
|
||||
params[3] as String?,
|
||||
params[4] as Long,
|
||||
params[5] as Int
|
||||
)
|
||||
|
||||
METHOD_IMAGE_SEARCH -> EhEngine.imageSearch(
|
||||
params[0] as File,
|
||||
params[1] as Boolean,
|
||||
params[2] as Boolean,
|
||||
params[3] as Boolean
|
||||
)
|
||||
|
||||
METHOD_ARCHIVE_LIST -> EhEngine.getArchiveList(
|
||||
params[0] as String?,
|
||||
params[1] as Long,
|
||||
params[2] as String?
|
||||
)
|
||||
|
||||
METHOD_DOWNLOAD_ARCHIVE -> EhEngine.downloadArchive(
|
||||
params[0] as Long,
|
||||
params[1] as String?,
|
||||
params[2] as String?,
|
||||
params[3] as String?,
|
||||
params[4] as Boolean
|
||||
)
|
||||
|
||||
METHOD_VOTE_TAG -> EhEngine.voteTag(
|
||||
params[0] as Long,
|
||||
params[1] as String?,
|
||||
params[2] as Long,
|
||||
params[3] as String?,
|
||||
params[4] as String?,
|
||||
params[5] as Int
|
||||
)
|
||||
|
||||
METHOD_GET_UCONFIG -> EhEngine.getUConfig()
|
||||
else -> throw IllegalStateException("Can't detect method $method")
|
||||
}
|
||||
}
|
||||
|
||||
interface Callback<E> {
|
||||
fun onSuccess(result: E)
|
||||
fun onFailure(e: Exception)
|
||||
@@ -192,5 +181,4 @@ object EhClient {
|
||||
const val METHOD_DOWNLOAD_ARCHIVE = 18
|
||||
const val METHOD_VOTE_TAG = 19
|
||||
const val METHOD_GET_UCONFIG = 20
|
||||
private val mOkHttpClient = okHttpClient
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import android.text.TextUtils
|
||||
import android.util.Log
|
||||
import android.util.Pair
|
||||
import com.hippo.ehviewer.AppConfig
|
||||
import com.hippo.ehviewer.EhApplication
|
||||
import com.hippo.ehviewer.EhApplication.Companion.application
|
||||
import com.hippo.ehviewer.GetText
|
||||
import com.hippo.ehviewer.R
|
||||
@@ -55,7 +56,6 @@ import okhttp3.Headers
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.MultipartBody
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.RequestBody
|
||||
import okhttp3.RequestBody.Companion.asRequestBody
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
@@ -76,6 +76,7 @@ object EhEngine {
|
||||
private const val KOKOMADE_URL = "https://exhentai.org/img/kokomade.jpg"
|
||||
private val MEDIA_TYPE_JPEG: MediaType = "image/jpeg".toMediaType()
|
||||
private var sEhFilter = EhFilter.getInstance()
|
||||
private val okHttpClient = EhApplication.okHttpClient
|
||||
|
||||
private fun transformException(code: Int, headers: Headers?, body: String?, e: Throwable?) {
|
||||
// Check sad panda
|
||||
@@ -116,7 +117,7 @@ object EhEngine {
|
||||
}
|
||||
|
||||
@Throws(Throwable::class)
|
||||
suspend fun signIn(okHttpClient: OkHttpClient, username: String, password: String): String {
|
||||
suspend fun signIn(username: String, password: String): String {
|
||||
val referer = "https://forums.e-hentai.org/index.php?act=Login&CODE=00"
|
||||
val builder = FormBody.Builder()
|
||||
.add("referer", referer)
|
||||
@@ -151,7 +152,6 @@ object EhEngine {
|
||||
|
||||
@Throws(Throwable::class)
|
||||
private suspend fun fillGalleryList(
|
||||
okHttpClient: OkHttpClient,
|
||||
list: MutableList<GalleryInfo>,
|
||||
url: String,
|
||||
filter: Boolean
|
||||
@@ -188,7 +188,7 @@ object EhEngine {
|
||||
filter && sEhFilter.needTags() && !hasTags || Settings.getShowGalleryPages() && !hasPages ||
|
||||
hasRated
|
||||
if (needApi) {
|
||||
fillGalleryListByApi(okHttpClient, list, url)
|
||||
fillGalleryListByApi(list, url)
|
||||
}
|
||||
|
||||
// Filter tag
|
||||
@@ -212,7 +212,7 @@ object EhEngine {
|
||||
}
|
||||
|
||||
@Throws(Throwable::class)
|
||||
suspend fun getGalleryList(okHttpClient: OkHttpClient, url: String): GalleryListParser.Result {
|
||||
suspend fun getGalleryList(url: String): GalleryListParser.Result {
|
||||
val referer = EhUrl.getReferer()
|
||||
Log.d(TAG, url)
|
||||
val request = EhRequestBuilder(url, referer).build()
|
||||
@@ -234,7 +234,7 @@ object EhEngine {
|
||||
transformException(code, headers, body, e)
|
||||
throw e
|
||||
}
|
||||
fillGalleryList(okHttpClient, result.galleryInfoList, url, true)
|
||||
fillGalleryList(result.galleryInfoList, url, true)
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -242,7 +242,6 @@ object EhEngine {
|
||||
@JvmStatic
|
||||
@Throws(Throwable::class)
|
||||
suspend fun fillGalleryListByApi(
|
||||
okHttpClient: OkHttpClient,
|
||||
galleryInfoList: List<GalleryInfo>,
|
||||
referer: String
|
||||
): List<GalleryInfo> {
|
||||
@@ -252,7 +251,7 @@ object EhEngine {
|
||||
while (i < size) {
|
||||
requestItems.add(galleryInfoList[i])
|
||||
if (requestItems.size == MAX_REQUEST_SIZE || i == size - 1) {
|
||||
doFillGalleryListByApi(okHttpClient, requestItems, referer)
|
||||
doFillGalleryListByApi(requestItems, referer)
|
||||
requestItems.clear()
|
||||
}
|
||||
i++
|
||||
@@ -262,7 +261,6 @@ object EhEngine {
|
||||
|
||||
@Throws(Throwable::class)
|
||||
suspend fun doFillGalleryListByApi(
|
||||
okHttpClient: OkHttpClient,
|
||||
galleryInfoList: List<GalleryInfo>,
|
||||
referer: String
|
||||
) {
|
||||
@@ -307,7 +305,7 @@ object EhEngine {
|
||||
}
|
||||
|
||||
@Throws(Throwable::class)
|
||||
suspend fun getGalleryDetail(okHttpClient: OkHttpClient, url: String?): GalleryDetail {
|
||||
suspend fun getGalleryDetail(url: String?): GalleryDetail {
|
||||
val referer = EhUrl.getReferer()
|
||||
Log.d(TAG, url!!)
|
||||
val request = EhRequestBuilder(url, referer).build()
|
||||
@@ -335,7 +333,7 @@ object EhEngine {
|
||||
}
|
||||
|
||||
@Throws(Throwable::class)
|
||||
suspend fun getPreviewSet(okHttpClient: OkHttpClient, url: String?): Pair<PreviewSet, Int> {
|
||||
suspend fun getPreviewSet(url: String?): Pair<PreviewSet, Int> {
|
||||
val referer = EhUrl.getReferer()
|
||||
Log.d(TAG, url!!)
|
||||
val request = EhRequestBuilder(url, referer).build()
|
||||
@@ -363,7 +361,6 @@ object EhEngine {
|
||||
|
||||
@Throws(Throwable::class)
|
||||
suspend fun rateGallery(
|
||||
okHttpClient: OkHttpClient,
|
||||
apiUid: Long, apiKey: String?, gid: Long, token: String?,
|
||||
rating: Float
|
||||
): RateGalleryParser.Result {
|
||||
@@ -403,7 +400,6 @@ object EhEngine {
|
||||
|
||||
@Throws(Throwable::class)
|
||||
suspend fun commentGallery(
|
||||
okHttpClient: OkHttpClient,
|
||||
url: String?, comment: String, id: String?
|
||||
): GalleryCommentList {
|
||||
val builder = FormBody.Builder()
|
||||
@@ -444,7 +440,7 @@ object EhEngine {
|
||||
|
||||
@Throws(Throwable::class)
|
||||
suspend fun getGalleryToken(
|
||||
okHttpClient: OkHttpClient, gid: Long,
|
||||
gid: Long,
|
||||
gtoken: String?, page: Int
|
||||
): String {
|
||||
val json = JSONObject()
|
||||
@@ -482,7 +478,7 @@ object EhEngine {
|
||||
|
||||
@Throws(Throwable::class)
|
||||
suspend fun getFavorites(
|
||||
okHttpClient: OkHttpClient, url: String
|
||||
url: String
|
||||
): FavoritesParser.Result {
|
||||
val referer = EhUrl.getReferer()
|
||||
Log.d(TAG, url)
|
||||
@@ -505,7 +501,7 @@ object EhEngine {
|
||||
transformException(code, headers, body, e)
|
||||
throw e
|
||||
}
|
||||
fillGalleryList(okHttpClient, result.galleryInfoList, url, false)
|
||||
fillGalleryList(result.galleryInfoList, url, false)
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -515,7 +511,7 @@ object EhEngine {
|
||||
*/
|
||||
@Throws(Throwable::class)
|
||||
suspend fun addFavorites(
|
||||
okHttpClient: OkHttpClient, gid: Long,
|
||||
gid: Long,
|
||||
token: String?, dstCat: Int, note: String?
|
||||
): Void? {
|
||||
val catStr: String = when (dstCat) {
|
||||
@@ -564,14 +560,14 @@ object EhEngine {
|
||||
|
||||
@Throws(Throwable::class)
|
||||
suspend fun addFavoritesRange(
|
||||
okHttpClient: OkHttpClient, gidArray: LongArray,
|
||||
gidArray: LongArray,
|
||||
tokenArray: Array<String?>, dstCat: Int
|
||||
): Void? {
|
||||
AssertUtils.assertEquals(gidArray.size, tokenArray.size)
|
||||
var i = 0
|
||||
val n = gidArray.size
|
||||
while (i < n) {
|
||||
addFavorites(okHttpClient, gidArray[i], tokenArray[i], dstCat, null)
|
||||
addFavorites(gidArray[i], tokenArray[i], dstCat, null)
|
||||
i++
|
||||
}
|
||||
return null
|
||||
@@ -579,7 +575,7 @@ object EhEngine {
|
||||
|
||||
@Throws(Throwable::class)
|
||||
suspend fun modifyFavorites(
|
||||
okHttpClient: OkHttpClient, url: String,
|
||||
url: String,
|
||||
gidArray: LongArray, dstCat: Int
|
||||
): FavoritesParser.Result {
|
||||
val catStr: String = when (dstCat) {
|
||||
@@ -623,13 +619,13 @@ object EhEngine {
|
||||
transformException(code, headers, body, e)
|
||||
throw e
|
||||
}
|
||||
fillGalleryList(okHttpClient, result.galleryInfoList, url, false)
|
||||
fillGalleryList(result.galleryInfoList, url, false)
|
||||
return result
|
||||
}
|
||||
|
||||
@Throws(Throwable::class)
|
||||
suspend fun getTorrentList(
|
||||
okHttpClient: OkHttpClient, url: String?,
|
||||
url: String?,
|
||||
gid: Long, token: String?
|
||||
): List<TorrentParser.Result> {
|
||||
val referer = EhUrl.getGalleryDetailUrl(gid, token)
|
||||
@@ -657,7 +653,7 @@ object EhEngine {
|
||||
|
||||
@Throws(Throwable::class)
|
||||
suspend fun getArchiveList(
|
||||
okHttpClient: OkHttpClient, url: String?,
|
||||
url: String?,
|
||||
gid: Long, token: String?
|
||||
): ArchiveParser.Result {
|
||||
val referer = EhUrl.getGalleryDetailUrl(gid, token)
|
||||
@@ -685,7 +681,7 @@ object EhEngine {
|
||||
|
||||
@Throws(Throwable::class)
|
||||
suspend fun downloadArchive(
|
||||
okHttpClient: OkHttpClient, gid: Long,
|
||||
gid: Long,
|
||||
token: String?, or: String?, res: String?, isHAtH: Boolean
|
||||
): String? {
|
||||
if (or.isNullOrEmpty()) {
|
||||
@@ -756,7 +752,6 @@ object EhEngine {
|
||||
|
||||
@Throws(Throwable::class)
|
||||
private suspend fun getProfileInternal(
|
||||
okHttpClient: OkHttpClient,
|
||||
url: String, referer: String
|
||||
): ProfileParser.Result {
|
||||
Log.d(TAG, url)
|
||||
@@ -780,9 +775,7 @@ object EhEngine {
|
||||
}
|
||||
|
||||
@Throws(Throwable::class)
|
||||
suspend fun getProfile(
|
||||
okHttpClient: OkHttpClient
|
||||
): ProfileParser.Result {
|
||||
suspend fun getProfile(): ProfileParser.Result {
|
||||
val url = EhUrl.URL_FORUMS
|
||||
Log.d(TAG, url)
|
||||
val request = EhRequestBuilder(url, null).build()
|
||||
@@ -795,7 +788,7 @@ object EhEngine {
|
||||
code = response.code
|
||||
headers = response.headers
|
||||
body = response.body.string()
|
||||
return getProfileInternal(okHttpClient, ForumsParser.parse(body), url)
|
||||
return getProfileInternal(ForumsParser.parse(body), url)
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
ExceptionUtils.throwIfFatal(e)
|
||||
@@ -805,9 +798,7 @@ object EhEngine {
|
||||
}
|
||||
|
||||
@Throws(Throwable::class)
|
||||
suspend fun getUConfig(
|
||||
okHttpClient: OkHttpClient
|
||||
): Void? {
|
||||
suspend fun getUConfig(): Void? {
|
||||
val url = EhUrl.getUConfigUrl()
|
||||
Log.d(TAG, url)
|
||||
var request = EhRequestBuilder(url, null).build()
|
||||
@@ -852,7 +843,7 @@ object EhEngine {
|
||||
|
||||
@Throws(Throwable::class)
|
||||
suspend fun voteComment(
|
||||
okHttpClient: OkHttpClient, apiUid: Long,
|
||||
apiUid: Long,
|
||||
apiKey: String?, gid: Long, token: String?, commentId: Long, commentVote: Int
|
||||
): VoteCommentParser.Result {
|
||||
val json = JSONObject()
|
||||
@@ -891,7 +882,7 @@ object EhEngine {
|
||||
|
||||
@Throws(Throwable::class)
|
||||
suspend fun voteTag(
|
||||
okHttpClient: OkHttpClient, apiUid: Long,
|
||||
apiUid: Long,
|
||||
apiKey: String?, gid: Long, token: String?, tags: String?, vote: Int
|
||||
): VoteTagParser.Result {
|
||||
val json = JSONObject()
|
||||
@@ -933,7 +924,7 @@ object EhEngine {
|
||||
*/
|
||||
@Throws(Throwable::class)
|
||||
suspend fun imageSearch(
|
||||
okHttpClient: OkHttpClient, image: File,
|
||||
image: File,
|
||||
uss: Boolean, osc: Boolean, se: Boolean
|
||||
): GalleryListParser.Result {
|
||||
val builder = MultipartBody.Builder()
|
||||
@@ -992,14 +983,13 @@ object EhEngine {
|
||||
transformException(code, headers, body, e)
|
||||
throw e
|
||||
}
|
||||
fillGalleryList(okHttpClient, result.galleryInfoList, url, true)
|
||||
fillGalleryList(result.galleryInfoList, url, true)
|
||||
return result
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@Throws(Throwable::class)
|
||||
fun getGalleryPage(
|
||||
okHttpClient: OkHttpClient,
|
||||
url: String?,
|
||||
gid: Long,
|
||||
token: String?
|
||||
@@ -1029,7 +1019,6 @@ object EhEngine {
|
||||
@JvmStatic
|
||||
@Throws(Throwable::class)
|
||||
fun getGalleryPageApi(
|
||||
okHttpClient: OkHttpClient,
|
||||
gid: Long,
|
||||
index: Int,
|
||||
pToken: String?,
|
||||
|
||||
@@ -156,7 +156,7 @@ public final class EhFilter {
|
||||
}
|
||||
|
||||
// Title
|
||||
String title = info.title;
|
||||
String title = info.getTitle();
|
||||
List<Filter> filters = mTitleFilterList;
|
||||
if (null != title && filters.size() > 0) {
|
||||
for (int i = 0, n = filters.size(); i < n; i++) {
|
||||
@@ -175,7 +175,7 @@ public final class EhFilter {
|
||||
}
|
||||
|
||||
// Uploader
|
||||
String uploader = info.uploader;
|
||||
String uploader = info.getUploader();
|
||||
List<Filter> filters = mUploaderFilterList;
|
||||
if (null != uploader && filters.size() > 0) {
|
||||
for (int i = 0, n = filters.size(); i < n; i++) {
|
||||
@@ -227,7 +227,7 @@ public final class EhFilter {
|
||||
}
|
||||
|
||||
// Tag
|
||||
String[] tags = info.simpleTags;
|
||||
String[] tags = info.getSimpleTags();
|
||||
List<Filter> filters = mTagFilterList;
|
||||
if (null != tags && filters.size() > 0) {
|
||||
for (String tag : tags) {
|
||||
@@ -262,7 +262,7 @@ public final class EhFilter {
|
||||
return false;
|
||||
}
|
||||
|
||||
String[] tags = info.simpleTags;
|
||||
String[] tags = info.getSimpleTags();
|
||||
List<Filter> filters = mTagNamespaceFilterList;
|
||||
if (null != tags && filters.size() > 0) {
|
||||
for (String tag : tags) {
|
||||
|
||||
@@ -62,7 +62,7 @@ class EhRequest {
|
||||
}
|
||||
|
||||
fun enqueue(fragment: Fragment) {
|
||||
enqueue(fragment.lifecycleScope)
|
||||
enqueue(fragment.viewLifecycleOwner.lifecycleScope)
|
||||
}
|
||||
|
||||
fun enqueue(activity: Activity) {
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.ehviewer.client;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.hippo.ehviewer.client.data.ListUrlBuilder;
|
||||
import com.hippo.ehviewer.client.parser.GalleryDetailUrlParser;
|
||||
import com.hippo.ehviewer.client.parser.GalleryListUrlParser;
|
||||
import com.hippo.ehviewer.client.parser.GalleryPageUrlParser;
|
||||
import com.hippo.ehviewer.ui.scene.GalleryDetailScene;
|
||||
import com.hippo.ehviewer.ui.scene.GalleryListScene;
|
||||
import com.hippo.ehviewer.ui.scene.ProgressScene;
|
||||
import com.hippo.scene.Announcer;
|
||||
|
||||
public class EhUrlOpener {
|
||||
|
||||
private static final String TAG = EhUrlOpener.class.getSimpleName();
|
||||
|
||||
@Nullable
|
||||
public static Announcer parseUrl(String url) {
|
||||
if (TextUtils.isEmpty(url)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ListUrlBuilder listUrlBuilder = GalleryListUrlParser.parse(url);
|
||||
if (listUrlBuilder != null) {
|
||||
Bundle args = new Bundle();
|
||||
args.putString(GalleryListScene.KEY_ACTION, GalleryListScene.ACTION_LIST_URL_BUILDER);
|
||||
args.putParcelable(GalleryListScene.KEY_LIST_URL_BUILDER, listUrlBuilder);
|
||||
return new Announcer(GalleryListScene.class).setArgs(args);
|
||||
}
|
||||
|
||||
GalleryDetailUrlParser.Result result1 = GalleryDetailUrlParser.parse(url);
|
||||
if (result1 != null) {
|
||||
Bundle args = new Bundle();
|
||||
args.putString(GalleryDetailScene.KEY_ACTION, GalleryDetailScene.ACTION_GID_TOKEN);
|
||||
args.putLong(GalleryDetailScene.KEY_GID, result1.gid);
|
||||
args.putString(GalleryDetailScene.KEY_TOKEN, result1.token);
|
||||
return new Announcer(GalleryDetailScene.class).setArgs(args);
|
||||
}
|
||||
|
||||
GalleryPageUrlParser.Result result2 = GalleryPageUrlParser.parse(url);
|
||||
if (result2 != null) {
|
||||
Bundle args = new Bundle();
|
||||
args.putString(ProgressScene.KEY_ACTION, ProgressScene.ACTION_GALLERY_TOKEN);
|
||||
args.putLong(ProgressScene.KEY_GID, result2.gid);
|
||||
args.putString(ProgressScene.KEY_PTOKEN, result2.pToken);
|
||||
args.putInt(ProgressScene.KEY_PAGE, result2.page);
|
||||
return new Announcer(ProgressScene.class).setArgs(args);
|
||||
}
|
||||
|
||||
Log.i(TAG, "Can't parse url: " + url);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -133,9 +133,9 @@ public class EhUtils {
|
||||
|
||||
public static String getSuitableTitle(GalleryInfo gi) {
|
||||
if (Settings.getShowJpnTitle()) {
|
||||
return TextUtils.isEmpty(gi.titleJpn) ? gi.title : gi.titleJpn;
|
||||
return TextUtils.isEmpty(gi.getTitleJpn()) ? gi.getTitle() : gi.getTitleJpn();
|
||||
} else {
|
||||
return TextUtils.isEmpty(gi.title) ? gi.titleJpn : gi.title;
|
||||
return TextUtils.isEmpty(gi.getTitle()) ? gi.getTitleJpn() : gi.getTitle();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.hippo.ehviewer.client.data
|
||||
|
||||
interface AbstractGalleryInfo {
|
||||
var gid: Long
|
||||
var token: String?
|
||||
var title: String?
|
||||
var titleJpn: String?
|
||||
var thumb: String?
|
||||
var category: Int
|
||||
var posted: String?
|
||||
var uploader: String?
|
||||
var disowned: Boolean
|
||||
var rating: Float
|
||||
var rated: Boolean
|
||||
var simpleTags: Array<String>?
|
||||
var pages: Int
|
||||
var thumbWidth: Int
|
||||
var thumbHeight: Int
|
||||
var spanSize: Int
|
||||
var spanIndex: Int
|
||||
var spanGroupIndex: Int
|
||||
var simpleLanguage: String?
|
||||
var favoriteSlot: Int
|
||||
var favoriteName: String?
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.hippo.ehviewer.client.data
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Ignore
|
||||
import androidx.room.PrimaryKey
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
open class BaseGalleryInfo(
|
||||
@PrimaryKey
|
||||
@ColumnInfo(name = "GID")
|
||||
override var gid: Long = 0,
|
||||
|
||||
@ColumnInfo(name = "TOKEN")
|
||||
override var token: String? = null,
|
||||
|
||||
@ColumnInfo(name = "TITLE")
|
||||
override var title: String? = null,
|
||||
|
||||
@ColumnInfo(name = "TITLE_JPN")
|
||||
override var titleJpn: String? = null,
|
||||
|
||||
@ColumnInfo(name = "THUMB")
|
||||
override var thumb: String? = null,
|
||||
|
||||
@ColumnInfo(name = "CATEGORY")
|
||||
override var category: Int = 0,
|
||||
|
||||
@ColumnInfo(name = "POSTED")
|
||||
override var posted: String? = null,
|
||||
|
||||
@ColumnInfo(name = "UPLOADER")
|
||||
override var uploader: String? = null,
|
||||
|
||||
@Ignore
|
||||
override var disowned: Boolean = false,
|
||||
|
||||
@ColumnInfo(name = "RATING")
|
||||
override var rating: Float = 0f,
|
||||
|
||||
@Ignore
|
||||
override var rated: Boolean = false,
|
||||
|
||||
@Ignore
|
||||
override var simpleTags: Array<String>? = null,
|
||||
|
||||
@Ignore
|
||||
override var pages: Int = 0,
|
||||
|
||||
@Ignore
|
||||
override var thumbWidth: Int = 0,
|
||||
|
||||
@Ignore
|
||||
override var thumbHeight: Int = 0,
|
||||
|
||||
@Ignore
|
||||
override var spanSize: Int = 0,
|
||||
|
||||
@Ignore
|
||||
override var spanIndex: Int = 0,
|
||||
|
||||
@Ignore
|
||||
override var spanGroupIndex: Int = 0,
|
||||
|
||||
@ColumnInfo(name = "SIMPLE_LANGUAGE")
|
||||
override var simpleLanguage: String? = null,
|
||||
|
||||
@Ignore
|
||||
override var favoriteSlot: Int = -2,
|
||||
|
||||
@Ignore
|
||||
override var favoriteName: String? = null
|
||||
|
||||
) : GalleryInfo
|
||||
@@ -15,8 +15,13 @@
|
||||
*/
|
||||
package com.hippo.ehviewer.client.data
|
||||
|
||||
// This is wrong Parcelize usage, TODO: use delegate and move galleryinfo to primary constructor
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
class GalleryDetail(
|
||||
@JvmField
|
||||
val galleryInfo: GalleryInfo = BaseGalleryInfo(),
|
||||
|
||||
@JvmField
|
||||
var apiUid: Long = -1L,
|
||||
|
||||
@@ -67,4 +72,4 @@ class GalleryDetail(
|
||||
|
||||
@JvmField
|
||||
var previewSet: PreviewSet? = null,
|
||||
) : GalleryInfo()
|
||||
) : AbstractGalleryInfo by galleryInfo, GalleryInfo
|
||||
@@ -16,102 +16,12 @@
|
||||
package com.hippo.ehviewer.client.data
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Ignore
|
||||
import androidx.room.PrimaryKey
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import java.util.regex.Pattern
|
||||
|
||||
@Parcelize
|
||||
open class GalleryInfo(
|
||||
@JvmField
|
||||
@PrimaryKey
|
||||
@ColumnInfo(name = "GID")
|
||||
var gid: Long = 0,
|
||||
|
||||
@JvmField
|
||||
@ColumnInfo(name = "TOKEN")
|
||||
var token: String? = null,
|
||||
|
||||
@JvmField
|
||||
@ColumnInfo(name = "TITLE")
|
||||
var title: String? = null,
|
||||
|
||||
@JvmField
|
||||
@ColumnInfo(name = "TITLE_JPN")
|
||||
var titleJpn: String? = null,
|
||||
|
||||
@JvmField
|
||||
@ColumnInfo(name = "THUMB")
|
||||
var thumb: String? = null,
|
||||
|
||||
@JvmField
|
||||
@ColumnInfo(name = "CATEGORY")
|
||||
var category: Int = 0,
|
||||
|
||||
@JvmField
|
||||
@ColumnInfo(name = "POSTED")
|
||||
var posted: String? = null,
|
||||
|
||||
@JvmField
|
||||
@ColumnInfo(name = "UPLOADER")
|
||||
var uploader: String? = null,
|
||||
|
||||
@JvmField
|
||||
@Ignore
|
||||
var disowned: Boolean = false,
|
||||
|
||||
@JvmField
|
||||
@ColumnInfo(name = "RATING")
|
||||
var rating: Float = 0f,
|
||||
|
||||
@JvmField
|
||||
@Ignore
|
||||
var rated: Boolean = false,
|
||||
|
||||
@JvmField
|
||||
@Ignore
|
||||
var simpleTags: Array<String>? = null,
|
||||
|
||||
@JvmField
|
||||
@Ignore
|
||||
var pages: Int = 0,
|
||||
|
||||
@JvmField
|
||||
@Ignore
|
||||
var thumbWidth: Int = 0,
|
||||
|
||||
@JvmField
|
||||
@Ignore
|
||||
var thumbHeight: Int = 0,
|
||||
|
||||
@Ignore
|
||||
var spanSize: Int = 0,
|
||||
|
||||
@Ignore
|
||||
var spanIndex: Int = 0,
|
||||
|
||||
@Ignore
|
||||
var spanGroupIndex: Int = 0,
|
||||
|
||||
/**
|
||||
* language from title
|
||||
*/
|
||||
@JvmField
|
||||
@ColumnInfo(name = "SIMPLE_LANGUAGE")
|
||||
var simpleLanguage: String? = null,
|
||||
|
||||
@JvmField
|
||||
@Ignore
|
||||
var favoriteSlot: Int = -2,
|
||||
|
||||
@JvmField
|
||||
@Ignore
|
||||
var favoriteName: String? = null
|
||||
|
||||
) : Parcelable {
|
||||
interface GalleryInfo : AbstractGalleryInfo, Parcelable {
|
||||
fun generateSLang() {
|
||||
simpleLanguage = simpleTags?.let { generateSLangFromTags(it) } ?: title?.let { generateSLangFromTitle(it) }
|
||||
simpleLanguage = simpleTags?.let { generateSLangFromTags(it) }
|
||||
?: title?.let { generateSLangFromTitle(it) }
|
||||
}
|
||||
|
||||
private fun generateSLangFromTags(simpleTags: Array<String>): String? {
|
||||
@@ -154,7 +64,6 @@ open class GalleryInfo(
|
||||
const val S_LANG_TH = "TH"
|
||||
const val S_LANG_VI = "VI"
|
||||
|
||||
@JvmField
|
||||
val S_LANGS = arrayOf(
|
||||
S_LANG_EN,
|
||||
S_LANG_ZH,
|
||||
|
||||
@@ -32,7 +32,7 @@ import java.io.UnsupportedEncodingException
|
||||
import java.net.URLDecoder
|
||||
|
||||
@Parcelize
|
||||
open class ListUrlBuilder(
|
||||
data class ListUrlBuilder(
|
||||
@get:Mode @Mode var mode: Int = MODE_NORMAL,
|
||||
private var mPrev: String? = null,
|
||||
private var mNext: String? = null,
|
||||
@@ -48,7 +48,7 @@ open class ListUrlBuilder(
|
||||
var isUseSimilarityScan: Boolean = false,
|
||||
var isOnlySearchCovers: Boolean = false,
|
||||
var isShowExpunged: Boolean = false,
|
||||
) : Cloneable, Parcelable {
|
||||
) : Parcelable {
|
||||
|
||||
fun reset() {
|
||||
mode = MODE_NORMAL
|
||||
@@ -83,29 +83,6 @@ open class ListUrlBuilder(
|
||||
mKeyword = keyword
|
||||
}
|
||||
|
||||
/**
|
||||
* Make them the same
|
||||
*
|
||||
* @param lub The template
|
||||
*/
|
||||
fun set(lub: ListUrlBuilder) {
|
||||
mode = lub.mode
|
||||
mPrev = lub.mPrev
|
||||
mNext = lub.mNext
|
||||
mJumpTo = lub.mJumpTo
|
||||
this.category = lub.category
|
||||
mKeyword = lub.mKeyword
|
||||
advanceSearch = lub.advanceSearch
|
||||
minRating = lub.minRating
|
||||
pageFrom = lub.pageFrom
|
||||
pageTo = lub.pageTo
|
||||
imagePath = lub.imagePath
|
||||
isUseSimilarityScan = lub.isUseSimilarityScan
|
||||
isOnlySearchCovers = lub.isOnlySearchCovers
|
||||
isShowExpunged = lub.isShowExpunged
|
||||
mSHash = lub.mSHash
|
||||
}
|
||||
|
||||
fun set(q: QuickSearch) {
|
||||
mode = q.mode
|
||||
this.category = q.category
|
||||
|
||||
@@ -39,13 +39,13 @@ public class GalleryApiParser {
|
||||
if (gi == null) {
|
||||
continue;
|
||||
}
|
||||
gi.title = ParserUtils.trim(g.getString("title"));
|
||||
gi.titleJpn = ParserUtils.trim(g.getString("title_jpn"));
|
||||
gi.category = EhUtils.getCategory(g.getString("category"));
|
||||
gi.thumb = EhUtils.handleThumbUrlResolution(g.getString("thumb"));
|
||||
gi.uploader = g.getString("uploader");
|
||||
gi.posted = ParserUtils.formatDate(ParserUtils.parseLong(g.getString("posted"), 0) * 1000);
|
||||
gi.rating = NumberUtils.parseFloatSafely(g.getString("rating"), 0.0f);
|
||||
gi.setTitle(ParserUtils.trim(g.getString("title")));
|
||||
gi.setTitleJpn(ParserUtils.trim(g.getString("title_jpn")));
|
||||
gi.setCategory(EhUtils.getCategory(g.getString("category")));
|
||||
gi.setThumb(EhUtils.handleThumbUrlResolution(g.getString("thumb")));
|
||||
gi.setUploader(g.getString("uploader"));
|
||||
gi.setPosted(ParserUtils.formatDate(ParserUtils.parseLong(g.getString("posted"), 0) * 1000));
|
||||
gi.setRating(NumberUtils.parseFloatSafely(g.getString("rating"), 0.0f));
|
||||
// tags
|
||||
JSONArray tagJa = g.getJSONArray("tags");
|
||||
int tagLength = tagJa.length();
|
||||
@@ -53,8 +53,8 @@ public class GalleryApiParser {
|
||||
for (int j = 0; j < tagLength; j++) {
|
||||
tags[j] = tagJa.getString(j);
|
||||
}
|
||||
gi.simpleTags = tags;
|
||||
gi.pages = NumberUtils.parseIntSafely(g.getString("filecount"), 0);
|
||||
gi.setSimpleTags(tags);
|
||||
gi.setPages(NumberUtils.parseIntSafely(g.getString("filecount"), 0));
|
||||
gi.generateSLang();
|
||||
}
|
||||
}
|
||||
@@ -62,7 +62,7 @@ public class GalleryApiParser {
|
||||
private static GalleryInfo getGalleryInfoByGid(List<GalleryInfo> galleryInfoList, long gid) {
|
||||
for (int i = 0, size = galleryInfoList.size(); i < size; i++) {
|
||||
GalleryInfo gi = galleryInfoList.get(i);
|
||||
if (gi.gid == gid) {
|
||||
if (gi.getGid() == gid) {
|
||||
return gi;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import androidx.annotation.Nullable;
|
||||
import com.hippo.ehviewer.EhDB;
|
||||
import com.hippo.ehviewer.client.EhFilter;
|
||||
import com.hippo.ehviewer.client.EhUtils;
|
||||
import com.hippo.ehviewer.client.data.BaseGalleryInfo;
|
||||
import com.hippo.ehviewer.client.data.GalleryComment;
|
||||
import com.hippo.ehviewer.client.data.GalleryCommentList;
|
||||
import com.hippo.ehviewer.client.data.GalleryDetail;
|
||||
@@ -124,7 +125,7 @@ public class GalleryDetailParser {
|
||||
// Generate simpleLanguage for local favorites
|
||||
for (int i = 0; i < LANGUAGES.length; i++) {
|
||||
if (galleryDetail.language.equals(LANGUAGES[i])) {
|
||||
galleryDetail.simpleLanguage = GalleryInfo.S_LANGS[i];
|
||||
galleryDetail.setSimpleLanguage(GalleryInfo.Companion.getS_LANGS()[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -136,14 +137,14 @@ public class GalleryDetailParser {
|
||||
private static void parseDetail(GalleryDetail gd, Document d, String body) throws ParseException {
|
||||
Matcher matcher = PATTERN_DETAIL.matcher(body);
|
||||
if (matcher.find()) {
|
||||
gd.gid = NumberUtils.parseLongSafely(matcher.group(1), -1L);
|
||||
gd.token = matcher.group(2);
|
||||
gd.setGid(NumberUtils.parseLongSafely(matcher.group(1), -1L));
|
||||
gd.setToken(matcher.group(2));
|
||||
gd.apiUid = NumberUtils.parseLongSafely(matcher.group(3), -1L);
|
||||
gd.apiKey = matcher.group(4);
|
||||
} else {
|
||||
throw new ParseException("Can't parse gallery detail", body);
|
||||
}
|
||||
if (gd.gid == -1L) {
|
||||
if (gd.getGid() == -1L) {
|
||||
throw new ParseException("Can't parse gallery detail", body);
|
||||
}
|
||||
|
||||
@@ -169,26 +170,26 @@ public class GalleryDetailParser {
|
||||
// Thumb url
|
||||
Element gd1 = gm.getElementById("gd1");
|
||||
try {
|
||||
gd.thumb = parseCoverStyle(StringUtils.trim(gd1.child(0).attr("style")));
|
||||
gd.setThumb(parseCoverStyle(StringUtils.trim(gd1.child(0).attr("style"))));
|
||||
} catch (Throwable e) {
|
||||
ExceptionUtils.throwIfFatal(e);
|
||||
gd.thumb = "";
|
||||
gd.setThumb("");
|
||||
}
|
||||
|
||||
// Title
|
||||
Element gn = gm.getElementById("gn");
|
||||
if (null != gn) {
|
||||
gd.title = StringUtils.trim(gn.text());
|
||||
gd.setTitle(StringUtils.trim(gn.text()));
|
||||
} else {
|
||||
gd.title = "";
|
||||
gd.setTitle("");
|
||||
}
|
||||
|
||||
// Jpn title
|
||||
Element gj = gm.getElementById("gj");
|
||||
if (null != gj) {
|
||||
gd.titleJpn = StringUtils.trim(gj.text());
|
||||
gd.setTitleJpn(StringUtils.trim(gj.text()));
|
||||
} else {
|
||||
gd.titleJpn = "";
|
||||
gd.setTitleJpn("");
|
||||
}
|
||||
|
||||
// Category
|
||||
@@ -198,27 +199,27 @@ public class GalleryDetailParser {
|
||||
if (ce == null) {
|
||||
ce = JsoupUtils.getElementByClass(gdc, "cs");
|
||||
}
|
||||
gd.category = EhUtils.getCategory(ce.text());
|
||||
gd.setCategory(EhUtils.getCategory(ce.text()));
|
||||
} catch (Throwable e) {
|
||||
ExceptionUtils.throwIfFatal(e);
|
||||
gd.category = EhUtils.UNKNOWN;
|
||||
gd.setCategory(EhUtils.UNKNOWN);
|
||||
}
|
||||
|
||||
// Uploader
|
||||
Element gdn = gm.getElementById("gdn");
|
||||
if (null != gdn) {
|
||||
gd.disowned = gdn.attr("style").contains("opacity:0.5");
|
||||
gd.uploader = StringUtils.trim(gdn.text());
|
||||
gd.setDisowned(gdn.attr("style").contains("opacity:0.5"));
|
||||
gd.setUploader(StringUtils.trim(gdn.text()));
|
||||
} else {
|
||||
gd.uploader = "";
|
||||
gd.setUploader("");
|
||||
}
|
||||
|
||||
Element gdd = gm.getElementById("gdd");
|
||||
gd.posted = "";
|
||||
gd.setPosted("");
|
||||
gd.parent = "";
|
||||
gd.visible = "";
|
||||
gd.size = "";
|
||||
gd.pages = 0;
|
||||
gd.setPages(0);
|
||||
gd.favoriteCount = 0;
|
||||
Elements es = gdd.child(0).child(0).children();
|
||||
for (int i = 0, n = es.size(); i < n; i++) {
|
||||
@@ -239,17 +240,17 @@ public class GalleryDetailParser {
|
||||
if (null != rating_label) {
|
||||
String ratingStr = StringUtils.trim(rating_label.text());
|
||||
if ("Not Yet Rated".equals(ratingStr)) {
|
||||
gd.rating = -1.0f;
|
||||
gd.setRating(-1.0f);
|
||||
} else {
|
||||
int index = ratingStr.indexOf(' ');
|
||||
if (index == -1 || index >= ratingStr.length()) {
|
||||
gd.rating = 0f;
|
||||
gd.setRating(0f);
|
||||
} else {
|
||||
gd.rating = NumberUtils.parseFloatSafely(ratingStr.substring(index + 1), 0f);
|
||||
gd.setRating(NumberUtils.parseFloatSafely(ratingStr.substring(index + 1), 0f));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
gd.rating = -1.0f;
|
||||
gd.setRating(-1.0f);
|
||||
}
|
||||
|
||||
// isFavorited
|
||||
@@ -258,19 +259,19 @@ public class GalleryDetailParser {
|
||||
if (gdf != null) {
|
||||
final String favoriteName = StringUtils.trim(gdf.text());
|
||||
if (favoriteName.equals("Add to Favorites")) {
|
||||
gd.favoriteName = null;
|
||||
gd.setFavoriteName(null);
|
||||
} else {
|
||||
gd.isFavorited = true;
|
||||
gd.favoriteName = StringUtils.trim(gdf.text());
|
||||
gd.setFavoriteName(StringUtils.trim(gdf.text()));
|
||||
|
||||
matcher = PATTERN_FAVORITE_SLOT.matcher(body);
|
||||
if (matcher.find()) {
|
||||
gd.favoriteSlot = (NumberUtils.parseIntSafely(matcher.group(1), 2) - 2) / 19;
|
||||
gd.setFavoriteSlot((NumberUtils.parseIntSafely(matcher.group(1), 2) - 2) / 19);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (gd.favoriteSlot == -2 && EhDB.containLocalFavorites(gd.gid)) {
|
||||
gd.favoriteSlot = -1;
|
||||
if (gd.getFavoriteSlot() == -2 && EhDB.containLocalFavorites(gd.getGid())) {
|
||||
gd.setFavoriteSlot(-1);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
ExceptionUtils.throwIfFatal(e);
|
||||
@@ -289,13 +290,13 @@ public class GalleryDetailParser {
|
||||
Elements elements = gnd.select("a");
|
||||
for (int i = 0; i < elements.size(); i++) {
|
||||
Element element = elements.get(i);
|
||||
GalleryInfo gi = new GalleryInfo();
|
||||
GalleryInfo gi = new BaseGalleryInfo();
|
||||
GalleryDetailUrlParser.Result result = GalleryDetailUrlParser.parse(element.attr("href"));
|
||||
if (result != null) {
|
||||
gi.gid = result.gid;
|
||||
gi.token = result.token;
|
||||
gi.title = StringUtils.trim(element.text());
|
||||
gi.posted = dates.get(i);
|
||||
gi.setGid(result.gid);
|
||||
gi.setToken(result.token);
|
||||
gi.setTitle(StringUtils.trim(element.text()));
|
||||
gi.setPosted(dates.get(i));
|
||||
gd.newerVersions.add(gi);
|
||||
}
|
||||
}
|
||||
@@ -324,7 +325,7 @@ public class GalleryDetailParser {
|
||||
String key = StringUtils.trim(es.get(0).text());
|
||||
String value = StringUtils.trim(es.get(1).ownText());
|
||||
if (key.startsWith("Posted")) {
|
||||
gd.posted = value;
|
||||
gd.setPosted(value);
|
||||
} else if (key.startsWith("Parent")) {
|
||||
Element a = es.get(1).children().first();
|
||||
if (a != null) {
|
||||
@@ -339,9 +340,9 @@ public class GalleryDetailParser {
|
||||
} else if (key.startsWith("Length")) {
|
||||
int index = value.indexOf(' ');
|
||||
if (index >= 0) {
|
||||
gd.pages = NumberUtils.parseIntSafely(value.substring(0, index), 1);
|
||||
gd.setPages(NumberUtils.parseIntSafely(value.substring(0, index), 1));
|
||||
} else {
|
||||
gd.pages = 1;
|
||||
gd.setPages(1);
|
||||
}
|
||||
} else if (key.startsWith("Favorited")) {
|
||||
switch (value) {
|
||||
|
||||
@@ -23,6 +23,7 @@ import androidx.annotation.NonNull;
|
||||
|
||||
import com.hippo.ehviewer.EhDB;
|
||||
import com.hippo.ehviewer.client.EhUtils;
|
||||
import com.hippo.ehviewer.client.data.BaseGalleryInfo;
|
||||
import com.hippo.ehviewer.client.data.GalleryInfo;
|
||||
import com.hippo.ehviewer.client.exception.ParseException;
|
||||
import com.hippo.util.ExceptionUtils;
|
||||
@@ -110,7 +111,7 @@ public class GalleryListParser {
|
||||
}
|
||||
|
||||
private static GalleryInfo parseGalleryInfo(Element e) {
|
||||
GalleryInfo gi = new GalleryInfo();
|
||||
GalleryInfo gi = new BaseGalleryInfo();
|
||||
|
||||
// Title, gid, token (required), tags
|
||||
Element glname = JsoupUtils.getElementByClass(e, "glname");
|
||||
@@ -125,8 +126,8 @@ public class GalleryListParser {
|
||||
if (a != null) {
|
||||
GalleryDetailUrlParser.Result result = GalleryDetailUrlParser.parse(a.attr("href"));
|
||||
if (result != null) {
|
||||
gi.gid = result.gid;
|
||||
gi.token = result.token;
|
||||
gi.setGid(result.gid);
|
||||
gi.setToken(result.token);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,9 +137,9 @@ public class GalleryListParser {
|
||||
child = children.get(0);
|
||||
children = child.children();
|
||||
}
|
||||
gi.title = child.text().trim();
|
||||
gi.setTitle(child.text().trim());
|
||||
}
|
||||
if (gi.title == null) {
|
||||
if (gi.getTitle() == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -149,17 +150,17 @@ public class GalleryListParser {
|
||||
for (Element gt : gts) {
|
||||
tags.add(gt.attr("title"));
|
||||
}
|
||||
gi.simpleTags = tags.toArray(new String[0]);
|
||||
gi.setSimpleTags(tags.toArray(new String[0]));
|
||||
}
|
||||
|
||||
// Category
|
||||
gi.category = EhUtils.UNKNOWN;
|
||||
gi.setCategory(EhUtils.UNKNOWN);
|
||||
Element ce = JsoupUtils.getElementByClass(e, "cn");
|
||||
if (ce == null) {
|
||||
ce = JsoupUtils.getElementByClass(e, "cs");
|
||||
}
|
||||
if (ce != null) {
|
||||
gi.category = EhUtils.getCategory(ce.text());
|
||||
gi.setCategory(EhUtils.getCategory(ce.text()));
|
||||
}
|
||||
|
||||
// Thumb
|
||||
@@ -170,12 +171,12 @@ public class GalleryListParser {
|
||||
// Thumb size
|
||||
Matcher m = PATTERN_THUMB_SIZE.matcher(img.attr("style"));
|
||||
if (m.find()) {
|
||||
gi.thumbWidth = NumberUtils.parseIntSafely(m.group(2), 0);
|
||||
gi.thumbHeight = NumberUtils.parseIntSafely(m.group(1), 0);
|
||||
gi.setThumbWidth(NumberUtils.parseIntSafely(m.group(2), 0));
|
||||
gi.setThumbHeight(NumberUtils.parseIntSafely(m.group(1), 0));
|
||||
} else {
|
||||
Log.w(TAG, "Can't parse gallery info thumb size");
|
||||
gi.thumbWidth = 0;
|
||||
gi.thumbHeight = 0;
|
||||
gi.setThumbWidth(0);
|
||||
gi.setThumbHeight(0);
|
||||
}
|
||||
// Thumb url
|
||||
String url = img.attr("data-src");
|
||||
@@ -185,7 +186,7 @@ public class GalleryListParser {
|
||||
if (TextUtils.isEmpty(url)) {
|
||||
url = null;
|
||||
}
|
||||
gi.thumb = EhUtils.handleThumbUrlResolution(url);
|
||||
gi.setThumb(EhUtils.handleThumbUrlResolution(url));
|
||||
}
|
||||
|
||||
// Pages
|
||||
@@ -193,12 +194,12 @@ public class GalleryListParser {
|
||||
if (div != null) {
|
||||
Matcher matcher = PATTERN_PAGES.matcher(div.text());
|
||||
if (matcher.find()) {
|
||||
gi.pages = NumberUtils.parseIntSafely(matcher.group(1), 0);
|
||||
gi.setPages(NumberUtils.parseIntSafely(matcher.group(1), 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Try extended and thumbnail version
|
||||
if (gi.thumb == null) {
|
||||
if (gi.getThumb() == null) {
|
||||
Element gl = JsoupUtils.getElementByClass(e, "gl1e");
|
||||
if (gl == null) {
|
||||
gl = JsoupUtils.getElementByClass(e, "gl3t");
|
||||
@@ -209,35 +210,35 @@ public class GalleryListParser {
|
||||
// Thumb size
|
||||
Matcher m = PATTERN_THUMB_SIZE.matcher(img.attr("style"));
|
||||
if (m.find()) {
|
||||
gi.thumbWidth = NumberUtils.parseIntSafely(m.group(2), 0);
|
||||
gi.thumbHeight = NumberUtils.parseIntSafely(m.group(1), 0);
|
||||
gi.setThumbWidth(NumberUtils.parseIntSafely(m.group(2), 0));
|
||||
gi.setThumbHeight(NumberUtils.parseIntSafely(m.group(1), 0));
|
||||
} else {
|
||||
Log.w(TAG, "Can't parse gallery info thumb size");
|
||||
gi.thumbWidth = 0;
|
||||
gi.thumbHeight = 0;
|
||||
gi.setThumbWidth(0);
|
||||
gi.setThumbHeight(0);
|
||||
}
|
||||
gi.thumb = EhUtils.handleThumbUrlResolution(img.attr("src"));
|
||||
gi.setThumb(EhUtils.handleThumbUrlResolution(img.attr("src")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Posted
|
||||
gi.favoriteSlot = -2;
|
||||
Element posted = e.getElementById("posted_" + gi.gid);
|
||||
gi.setFavoriteSlot(-2);
|
||||
Element posted = e.getElementById("posted_" + gi.getGid());
|
||||
if (posted != null) {
|
||||
gi.posted = posted.text().trim();
|
||||
gi.favoriteSlot = parseFavoriteSlot(posted.attr("style"));
|
||||
gi.setPosted(posted.text().trim());
|
||||
gi.setFavoriteSlot(parseFavoriteSlot(posted.attr("style")));
|
||||
}
|
||||
if (gi.favoriteSlot == -2) {
|
||||
gi.favoriteSlot = EhDB.containLocalFavorites(gi.gid) ? -1 : -2;
|
||||
if (gi.getFavoriteSlot() == -2) {
|
||||
gi.setFavoriteSlot(EhDB.containLocalFavorites(gi.getGid()) ? -1 : -2);
|
||||
}
|
||||
|
||||
// Rating
|
||||
Element ir = JsoupUtils.getElementByClass(e, "ir");
|
||||
if (ir != null) {
|
||||
gi.rating = NumberUtils.parseFloatSafely(parseRating(ir.attr("style")), -1.0f);
|
||||
gi.setRating(NumberUtils.parseFloatSafely(parseRating(ir.attr("style")), -1.0f));
|
||||
// TODO The gallery may be rated even if it doesn't has one of these classes
|
||||
gi.rated = ir.hasClass("irr") || ir.hasClass("irg") || ir.hasClass("irb");
|
||||
gi.setRated(ir.hasClass("irr") || ir.hasClass("irg") || ir.hasClass("irb"));
|
||||
}
|
||||
|
||||
// Uploader and pages
|
||||
@@ -255,15 +256,15 @@ public class GalleryListParser {
|
||||
if (children.size() > uploaderIndex) {
|
||||
Element div = children.get(uploaderIndex);
|
||||
if (div != null) {
|
||||
gi.disowned = div.attr("style").contains("opacity:0.5");
|
||||
gi.setDisowned(div.attr("style").contains("opacity:0.5"));
|
||||
Element a = div.children().first();
|
||||
gi.uploader = a == null ? div.text().trim() : a.text().trim();
|
||||
gi.setUploader(a == null ? div.text().trim() : a.text().trim());
|
||||
}
|
||||
}
|
||||
if (children.size() > pagesIndex) {
|
||||
Matcher matcher = PATTERN_PAGES.matcher(children.get(pagesIndex).text());
|
||||
if (matcher.find()) {
|
||||
gi.pages = NumberUtils.parseIntSafely(matcher.group(1), 0);
|
||||
gi.setPages(NumberUtils.parseIntSafely(matcher.group(1), 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -274,7 +275,7 @@ public class GalleryListParser {
|
||||
if (div != null) {
|
||||
Matcher matcher = PATTERN_PAGES.matcher(div.text());
|
||||
if (matcher.find()) {
|
||||
gi.pages = NumberUtils.parseIntSafely(matcher.group(1), 0);
|
||||
gi.setPages(NumberUtils.parseIntSafely(matcher.group(1), 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@ package com.hippo.ehviewer.dao
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import com.hippo.ehviewer.client.data.GalleryInfo
|
||||
import com.hippo.ehviewer.client.data.BaseGalleryInfo
|
||||
|
||||
@Entity(tableName = "BOOKMARKS")
|
||||
class BookmarkInfo : GalleryInfo() {
|
||||
class BookmarkInfo : BaseGalleryInfo() {
|
||||
@JvmField
|
||||
@ColumnInfo(name = "PAGE")
|
||||
var page = 0
|
||||
|
||||
@@ -3,10 +3,11 @@ package com.hippo.ehviewer.dao
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.Ignore
|
||||
import com.hippo.ehviewer.client.data.BaseGalleryInfo
|
||||
import com.hippo.ehviewer.client.data.GalleryInfo
|
||||
|
||||
@Entity(tableName = "DOWNLOADS")
|
||||
class DownloadInfo() : GalleryInfo() {
|
||||
class DownloadInfo() : BaseGalleryInfo() {
|
||||
@JvmField
|
||||
@ColumnInfo(name = "STATE")
|
||||
var state = 0
|
||||
|
||||
@@ -11,14 +11,20 @@ interface DownloadsDao : BasicDao<DownloadInfo> {
|
||||
@Query("SELECT * FROM DOWNLOADS ORDER BY TIME DESC")
|
||||
override fun list(): List<DownloadInfo>
|
||||
|
||||
@Query("SELECT * FROM DOWNLOADS ORDER BY TIME DESC LIMIT :limit OFFSET :offset")
|
||||
fun list(offset: Int, limit: Int): List<DownloadInfo>
|
||||
|
||||
@Query("SELECT * FROM DOWNLOADS WHERE GID = :gid")
|
||||
fun load(gid: Long): DownloadInfo?
|
||||
|
||||
@Update
|
||||
fun update(downloadInfos: List<DownloadInfo>)
|
||||
|
||||
@Update
|
||||
fun update(downloadInfo: DownloadInfo)
|
||||
|
||||
@Insert
|
||||
override fun insert(downloadInfo: DownloadInfo): Long
|
||||
override fun insert(t: DownloadInfo): Long
|
||||
|
||||
@Delete
|
||||
fun delete(downloadInfo: DownloadInfo)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.hippo.ehviewer.dao
|
||||
|
||||
import android.content.Context
|
||||
import androidx.room.Database
|
||||
import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
|
||||
@Database(
|
||||
@@ -18,3 +20,9 @@ abstract class EhDatabase : RoomDatabase() {
|
||||
abstract fun localFavoritesDao(): LocalFavoritesDao
|
||||
abstract fun quickSearchDao(): QuickSearchDao
|
||||
}
|
||||
|
||||
fun buildMainDB(context: Context): EhDatabase {
|
||||
// TODO: Remove allowMainThreadQueries
|
||||
return Room.databaseBuilder(context, EhDatabase::class.java, "eh.db").allowMainThreadQueries()
|
||||
.build()
|
||||
}
|
||||
@@ -2,10 +2,11 @@ package com.hippo.ehviewer.dao
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import com.hippo.ehviewer.client.data.BaseGalleryInfo
|
||||
import com.hippo.ehviewer.client.data.GalleryInfo
|
||||
|
||||
@Entity(tableName = "HISTORY")
|
||||
class HistoryInfo() : GalleryInfo() {
|
||||
class HistoryInfo() : BaseGalleryInfo() {
|
||||
@JvmField
|
||||
@ColumnInfo(name = "TIME")
|
||||
var time: Long = 0
|
||||
|
||||
@@ -2,10 +2,11 @@ package com.hippo.ehviewer.dao
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import com.hippo.ehviewer.client.data.BaseGalleryInfo
|
||||
import com.hippo.ehviewer.client.data.GalleryInfo
|
||||
|
||||
@Entity(tableName = "LOCAL_FAVORITES")
|
||||
class LocalFavoriteInfo() : GalleryInfo() {
|
||||
class LocalFavoriteInfo() : BaseGalleryInfo() {
|
||||
@JvmField
|
||||
@ColumnInfo(name = "TIME")
|
||||
var time: Long = 0
|
||||
|
||||
@@ -24,6 +24,7 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.hippo.ehviewer.EhDB;
|
||||
import com.hippo.ehviewer.client.data.BaseGalleryInfo;
|
||||
import com.hippo.ehviewer.client.data.GalleryInfo;
|
||||
import com.hippo.ehviewer.dao.DownloadInfo;
|
||||
import com.hippo.ehviewer.dao.DownloadLabel;
|
||||
@@ -53,7 +54,7 @@ import java.util.Map;
|
||||
public class DownloadManager implements SpiderQueen.OnSpiderListener {
|
||||
|
||||
private static final String TAG = DownloadManager.class.getSimpleName();
|
||||
private static final Comparator<DownloadInfo> DATE_DESC_COMPARATOR = (lhs, rhs) -> (int) (rhs.time - lhs.time);
|
||||
private static final Comparator<DownloadInfo> DATE_DESC_COMPARATOR = (lhs, rhs) -> lhs.time == rhs.time ? 0 : lhs.time - rhs.time > 0 ? -1 : 1;
|
||||
// All download info list
|
||||
private final LinkedList<DownloadInfo> mAllInfoList;
|
||||
// All download info map
|
||||
@@ -104,7 +105,7 @@ public class DownloadManager implements SpiderQueen.OnSpiderListener {
|
||||
DownloadInfo info = allInfoList.get(i);
|
||||
|
||||
// Add to all info map
|
||||
allInfoMap.put(info.gid, info);
|
||||
allInfoMap.put(info.getGid(), info);
|
||||
|
||||
// Add to each label list
|
||||
LinkedList<DownloadInfo> list = getInfoListForLabel(info.label);
|
||||
@@ -232,13 +233,13 @@ public class DownloadManager implements SpiderQueen.OnSpiderListener {
|
||||
}
|
||||
|
||||
void startDownload(GalleryInfo galleryInfo, @Nullable String label) {
|
||||
if (mCurrentTask != null && mCurrentTask.gid == galleryInfo.gid) {
|
||||
if (mCurrentTask != null && mCurrentTask.getGid() == galleryInfo.getGid()) {
|
||||
// It is current task
|
||||
return;
|
||||
}
|
||||
|
||||
// Check in download list
|
||||
DownloadInfo info = mAllInfoMap.get(galleryInfo.gid);
|
||||
DownloadInfo info = mAllInfoMap.get(galleryInfo.getGid());
|
||||
if (info != null) { // Get it in download list
|
||||
if (info.state != DownloadInfo.STATE_WAIT) {
|
||||
// Set state DownloadInfo.STATE_WAIT
|
||||
@@ -274,7 +275,7 @@ public class DownloadManager implements SpiderQueen.OnSpiderListener {
|
||||
|
||||
// Add to all download list and map
|
||||
mAllInfoList.addFirst(info);
|
||||
mAllInfoMap.put(galleryInfo.gid, info);
|
||||
mAllInfoMap.put(galleryInfo.getGid(), info);
|
||||
|
||||
// Add to wait list
|
||||
mWaitList.add(info);
|
||||
@@ -359,7 +360,7 @@ public class DownloadManager implements SpiderQueen.OnSpiderListener {
|
||||
|
||||
public void addDownload(List<DownloadInfo> downloadInfoList, boolean notify) {
|
||||
for (DownloadInfo info : downloadInfoList) {
|
||||
if (containDownloadInfo(info.gid)) {
|
||||
if (containDownloadInfo(info.getGid())) {
|
||||
// Contain
|
||||
return;
|
||||
}
|
||||
@@ -387,7 +388,7 @@ public class DownloadManager implements SpiderQueen.OnSpiderListener {
|
||||
|
||||
// Add to all download list and map
|
||||
mAllInfoList.add(info);
|
||||
mAllInfoMap.put(info.gid, info);
|
||||
mAllInfoMap.put(info.getGid(), info);
|
||||
|
||||
// Save to
|
||||
EhDB.putDownloadInfo(info);
|
||||
@@ -415,7 +416,7 @@ public class DownloadManager implements SpiderQueen.OnSpiderListener {
|
||||
}
|
||||
|
||||
public void addDownload(GalleryInfo galleryInfo, @Nullable String label) {
|
||||
if (containDownloadInfo(galleryInfo.gid)) {
|
||||
if (containDownloadInfo(galleryInfo.getGid())) {
|
||||
// Contain
|
||||
return;
|
||||
}
|
||||
@@ -436,7 +437,7 @@ public class DownloadManager implements SpiderQueen.OnSpiderListener {
|
||||
|
||||
// Add to all download list and map
|
||||
mAllInfoList.addFirst(info);
|
||||
mAllInfoMap.put(galleryInfo.gid, info);
|
||||
mAllInfoMap.put(galleryInfo.getGid(), info);
|
||||
|
||||
// Save to
|
||||
EhDB.putDownloadInfo(info);
|
||||
@@ -516,7 +517,7 @@ public class DownloadManager implements SpiderQueen.OnSpiderListener {
|
||||
|
||||
// Remove all list and map
|
||||
mAllInfoList.remove(info);
|
||||
mAllInfoMap.remove(info.gid);
|
||||
mAllInfoMap.remove(info.getGid());
|
||||
|
||||
// Remove label list
|
||||
LinkedList<DownloadInfo> list = getInfoListForLabel(info.label);
|
||||
@@ -552,7 +553,7 @@ public class DownloadManager implements SpiderQueen.OnSpiderListener {
|
||||
|
||||
// Remove from all info map
|
||||
mAllInfoList.remove(info);
|
||||
mAllInfoMap.remove(info.gid);
|
||||
mAllInfoMap.remove(info.getGid());
|
||||
|
||||
// Remove from label list
|
||||
LinkedList<DownloadInfo> list = getInfoListForLabel(info.label);
|
||||
@@ -577,18 +578,18 @@ public class DownloadManager implements SpiderQueen.OnSpiderListener {
|
||||
new AsyncTask<Void, Void, Void>() {
|
||||
@Override
|
||||
protected Void doInBackground(Void... voids) {
|
||||
GalleryInfo galleryInfo = new GalleryInfo();
|
||||
GalleryInfo galleryInfo = new BaseGalleryInfo();
|
||||
for (DownloadInfo downloadInfo : list) {
|
||||
galleryInfo.gid = downloadInfo.gid;
|
||||
galleryInfo.token = downloadInfo.token;
|
||||
galleryInfo.title = downloadInfo.title;
|
||||
galleryInfo.thumb = downloadInfo.thumb;
|
||||
galleryInfo.category = downloadInfo.category;
|
||||
galleryInfo.posted = downloadInfo.posted;
|
||||
galleryInfo.uploader = downloadInfo.uploader;
|
||||
galleryInfo.rating = downloadInfo.rating;
|
||||
galleryInfo.setGid(downloadInfo.getGid());
|
||||
galleryInfo.setToken(downloadInfo.getToken());
|
||||
galleryInfo.setTitle(downloadInfo.getTitle());
|
||||
galleryInfo.setThumb(downloadInfo.getThumb());
|
||||
galleryInfo.setCategory(downloadInfo.getCategory());
|
||||
galleryInfo.setPosted(downloadInfo.getPosted());
|
||||
galleryInfo.setUploader(downloadInfo.getUploader());
|
||||
galleryInfo.setRating(downloadInfo.getRating());
|
||||
|
||||
UniFile downloadDir = SpiderDen.getGalleryDownloadDir(galleryInfo.gid);
|
||||
UniFile downloadDir = SpiderDen.getGalleryDownloadDir(galleryInfo.getGid());
|
||||
if (downloadDir == null) {
|
||||
continue;
|
||||
}
|
||||
@@ -618,14 +619,14 @@ public class DownloadManager implements SpiderQueen.OnSpiderListener {
|
||||
// No ensureDownload
|
||||
private DownloadInfo stopDownloadInternal(long gid) {
|
||||
// Check current task
|
||||
if (mCurrentTask != null && mCurrentTask.gid == gid) {
|
||||
if (mCurrentTask != null && mCurrentTask.getGid() == gid) {
|
||||
// Stop current
|
||||
return stopCurrentDownloadInternal();
|
||||
}
|
||||
|
||||
for (Iterator<DownloadInfo> iterator = mWaitList.iterator(); iterator.hasNext(); ) {
|
||||
DownloadInfo info = iterator.next();
|
||||
if (info.gid == gid) {
|
||||
if (info.getGid() == gid) {
|
||||
// Remove from wait list
|
||||
iterator.remove();
|
||||
// Update state
|
||||
@@ -677,7 +678,7 @@ public class DownloadManager implements SpiderQueen.OnSpiderListener {
|
||||
}
|
||||
} else {
|
||||
// Check current task
|
||||
if (mCurrentTask != null && gidList.contains(mCurrentTask.gid)) {
|
||||
if (mCurrentTask != null && gidList.contains(mCurrentTask.getGid())) {
|
||||
// Stop current
|
||||
stopCurrentDownloadInternal();
|
||||
}
|
||||
@@ -685,7 +686,7 @@ public class DownloadManager implements SpiderQueen.OnSpiderListener {
|
||||
// Check all in wait list
|
||||
for (Iterator<DownloadInfo> iterator = mWaitList.iterator(); iterator.hasNext(); ) {
|
||||
DownloadInfo info = iterator.next();
|
||||
if (gidList.contains(info.gid)) {
|
||||
if (gidList.contains(info.getGid())) {
|
||||
// Remove from wait list
|
||||
iterator.remove();
|
||||
// Update state
|
||||
|
||||
@@ -36,7 +36,6 @@ import com.hippo.ehviewer.client.data.GalleryInfo
|
||||
import com.hippo.ehviewer.dao.DownloadInfo
|
||||
import com.hippo.ehviewer.ui.MainActivity
|
||||
import com.hippo.ehviewer.ui.scene.DownloadsScene
|
||||
import com.hippo.scene.StageActivity
|
||||
import com.hippo.util.ReadableTime
|
||||
import com.hippo.yorozuya.FileUtils
|
||||
import com.hippo.yorozuya.SimpleHandler
|
||||
@@ -186,9 +185,8 @@ class DownloadService : Service(), DownloadManager.DownloadListener {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(DownloadsScene.KEY_ACTION, DownloadsScene.ACTION_CLEAR_DOWNLOAD_SERVICE)
|
||||
val activityIntent = Intent(this, MainActivity::class.java)
|
||||
activityIntent.action = StageActivity.ACTION_START_SCENE
|
||||
activityIntent.putExtra(StageActivity.KEY_SCENE_NAME, DownloadsScene::class.java.name)
|
||||
activityIntent.putExtra(StageActivity.KEY_SCENE_ARGS, bundle)
|
||||
activityIntent.action = ACTION_START_DOWNLOADSCENE
|
||||
activityIntent.putExtra(ACTION_START_DOWNLOADSCENE_ARGS, bundle)
|
||||
val piActivity = PendingIntent.getActivity(
|
||||
this@DownloadService, 0,
|
||||
activityIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
||||
@@ -241,9 +239,8 @@ class DownloadService : Service(), DownloadManager.DownloadListener {
|
||||
val bundle = Bundle()
|
||||
bundle.putLong(DownloadsScene.KEY_GID, info.gid)
|
||||
val activityIntent = Intent(this, MainActivity::class.java)
|
||||
activityIntent.action = StageActivity.ACTION_START_SCENE
|
||||
activityIntent.putExtra(StageActivity.KEY_SCENE_NAME, DownloadsScene::class.java.name)
|
||||
activityIntent.putExtra(StageActivity.KEY_SCENE_ARGS, bundle)
|
||||
activityIntent.action = ACTION_START_DOWNLOADSCENE
|
||||
activityIntent.putExtra(ACTION_START_DOWNLOADSCENE_ARGS, bundle)
|
||||
val piActivity = PendingIntent.getActivity(
|
||||
this@DownloadService, 0,
|
||||
activityIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
||||
@@ -516,6 +513,9 @@ class DownloadService : Service(), DownloadManager.DownloadListener {
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ACTION_START_DOWNLOADSCENE = "start_download_scene"
|
||||
const val ACTION_START_DOWNLOADSCENE_ARGS = "start_download_scene_args"
|
||||
|
||||
const val ACTION_START = "start"
|
||||
const val ACTION_START_RANGE = "start_range"
|
||||
const val ACTION_START_ALL = "start_all"
|
||||
|
||||
@@ -71,7 +71,7 @@ public class EhPageLoader extends PageLoader2 implements SpiderQueen.OnSpiderLis
|
||||
@NonNull
|
||||
@Override
|
||||
public String getImageFilename(int index) {
|
||||
return String.format(Locale.US, "%d-%s-%08d", mGalleryInfo.gid, mGalleryInfo.token, index + 1);
|
||||
return String.format(Locale.US, "%d-%s-%08d", mGalleryInfo.getGid(), mGalleryInfo.getToken(), index + 1);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@@ -80,10 +80,10 @@ public class EhPageLoader extends PageLoader2 implements SpiderQueen.OnSpiderLis
|
||||
if (null != mSpiderQueen) {
|
||||
String extension = mSpiderQueen.getExtension(index);
|
||||
if (extension != null) {
|
||||
return String.format(Locale.US, "%d-%s-%08d.%s", mGalleryInfo.gid, mGalleryInfo.token, index + 1, extension);
|
||||
return String.format(Locale.US, "%d-%s-%08d.%s", mGalleryInfo.getGid(), mGalleryInfo.getToken(), index + 1, extension);
|
||||
}
|
||||
}
|
||||
return String.format(Locale.US, "%d-%s-%08d", mGalleryInfo.gid, mGalleryInfo.token, index + 1);
|
||||
return String.format(Locale.US, "%d-%s-%08d", mGalleryInfo.getGid(), mGalleryInfo.getToken(), index + 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -20,13 +20,12 @@ import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import androidx.preference.Preference
|
||||
import com.hippo.ehviewer.EhApplication.Companion.downloadManager
|
||||
import com.hippo.ehviewer.EhApplication.Companion.okHttpClient
|
||||
import com.hippo.ehviewer.EhDB
|
||||
import com.hippo.ehviewer.R
|
||||
import com.hippo.ehviewer.Settings
|
||||
import com.hippo.ehviewer.client.EhEngine.fillGalleryListByApi
|
||||
import com.hippo.ehviewer.client.EhUrl
|
||||
import com.hippo.ehviewer.client.data.GalleryInfo
|
||||
import com.hippo.ehviewer.client.data.BaseGalleryInfo
|
||||
import com.hippo.ehviewer.download.DownloadManager
|
||||
import com.hippo.ehviewer.spider.SpiderInfo
|
||||
import com.hippo.ehviewer.spider.SpiderQueen
|
||||
@@ -35,7 +34,6 @@ import com.hippo.unifile.UniFile
|
||||
import com.hippo.util.ExceptionUtils
|
||||
import com.hippo.yorozuya.IOUtils
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.util.Collections
|
||||
@@ -49,7 +47,6 @@ class RestoreDownloadPreference constructor(
|
||||
|
||||
private class RestoreTask(context: Context) : Task(context) {
|
||||
private val mManager: DownloadManager = downloadManager
|
||||
private val mHttpClient: OkHttpClient = okHttpClient
|
||||
private var restoreDirCount = 0
|
||||
private fun getRestoreItem(file: UniFile?): RestoreItem? {
|
||||
if (null == file || !file.isDirectory) {
|
||||
@@ -99,7 +96,6 @@ class RestoreDownloadPreference constructor(
|
||||
} else try {
|
||||
runBlocking {
|
||||
fillGalleryListByApi(
|
||||
mHttpClient,
|
||||
ArrayList(restoreItemList),
|
||||
EhUrl.getReferer()
|
||||
)
|
||||
@@ -163,7 +159,7 @@ class RestoreDownloadPreference constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private class RestoreItem : GalleryInfo() {
|
||||
private class RestoreItem : BaseGalleryInfo() {
|
||||
var dirname: String? = null
|
||||
}
|
||||
}
|
||||
@@ -56,8 +56,8 @@ public final class SpiderDen {
|
||||
|
||||
public SpiderDen(GalleryInfo galleryInfo) {
|
||||
mGalleryInfo = galleryInfo;
|
||||
mGid = galleryInfo.gid;
|
||||
mDownloadDir = getGalleryDownloadDir(galleryInfo.gid);
|
||||
mGid = galleryInfo.getGid();
|
||||
mDownloadDir = getGalleryDownloadDir(galleryInfo.getGid());
|
||||
}
|
||||
|
||||
public static void initialize(Context context) {
|
||||
|
||||
@@ -179,10 +179,10 @@ public final class SpiderQueen implements Runnable {
|
||||
public static SpiderQueen obtainSpiderQueen(@NonNull GalleryInfo galleryInfo, @Mode int mode) {
|
||||
OSUtils.checkMainLoop();
|
||||
|
||||
SpiderQueen queen = sQueenMap.get(galleryInfo.gid);
|
||||
SpiderQueen queen = sQueenMap.get(galleryInfo.getGid());
|
||||
if (queen == null) {
|
||||
queen = new SpiderQueen(galleryInfo);
|
||||
sQueenMap.put(galleryInfo.gid, queen);
|
||||
sQueenMap.put(galleryInfo.getGid(), queen);
|
||||
// Set mode
|
||||
queen.setMode(mode);
|
||||
queen.start();
|
||||
@@ -203,7 +203,7 @@ public final class SpiderQueen implements Runnable {
|
||||
if (queen.mReadReference == 0 && queen.mDownloadReference == 0) {
|
||||
// Stop and remove if there is no reference
|
||||
queen.stop();
|
||||
sQueenMap.remove(queen.mGalleryInfo.gid);
|
||||
sQueenMap.remove(queen.mGalleryInfo.getGid());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -697,19 +697,19 @@ public final class SpiderQueen implements Runnable {
|
||||
if (downloadDir != null) {
|
||||
UniFile file = downloadDir.findFile(SPIDER_INFO_FILENAME);
|
||||
spiderInfo = SpiderInfo.read(file);
|
||||
if (spiderInfo != null && spiderInfo.gid == mGalleryInfo.gid &&
|
||||
spiderInfo.token.equals(mGalleryInfo.token)) {
|
||||
if (spiderInfo != null && spiderInfo.gid == mGalleryInfo.getGid() &&
|
||||
spiderInfo.token.equals(mGalleryInfo.getToken())) {
|
||||
return spiderInfo;
|
||||
}
|
||||
}
|
||||
|
||||
// Read from cache
|
||||
var entry = mSpiderInfoCache.get(Long.toString(mGalleryInfo.gid));
|
||||
var entry = mSpiderInfoCache.get(Long.toString(mGalleryInfo.getGid()));
|
||||
if (entry == null) return null;
|
||||
try (entry; InputStream is = new FileInputStream(entry.getData().toFile())) {
|
||||
spiderInfo = SpiderInfo.read(is);
|
||||
if (spiderInfo != null && spiderInfo.gid == mGalleryInfo.gid &&
|
||||
spiderInfo.token.equals(mGalleryInfo.token)) {
|
||||
if (spiderInfo != null && spiderInfo.gid == mGalleryInfo.getGid() &&
|
||||
spiderInfo.token.equals(mGalleryInfo.getToken())) {
|
||||
return spiderInfo;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
@@ -744,11 +744,11 @@ public final class SpiderQueen implements Runnable {
|
||||
|
||||
private SpiderInfo readSpiderInfoFromInternet() {
|
||||
SpiderInfo spiderInfo = new SpiderInfo();
|
||||
spiderInfo.gid = mGalleryInfo.gid;
|
||||
spiderInfo.token = mGalleryInfo.token;
|
||||
spiderInfo.gid = mGalleryInfo.getGid();
|
||||
spiderInfo.token = mGalleryInfo.getToken();
|
||||
|
||||
Request request = new EhRequestBuilder(EhUrl.getGalleryDetailUrl(
|
||||
mGalleryInfo.gid, mGalleryInfo.token, 0, false), EhUrl.getReferer()).build();
|
||||
mGalleryInfo.getGid(), mGalleryInfo.getToken(), 0, false), EhUrl.getReferer()).build();
|
||||
try (Response response = mHttpClient.newCall(request).execute()) {
|
||||
String body = response.body().string();
|
||||
|
||||
@@ -769,7 +769,7 @@ public final class SpiderQueen implements Runnable {
|
||||
}
|
||||
|
||||
String url = EhUrl.getGalleryMultiPageViewerUrl(
|
||||
mGalleryInfo.gid, mGalleryInfo.token);
|
||||
mGalleryInfo.getGid(), mGalleryInfo.getToken());
|
||||
if (DEBUG_PTOKEN) {
|
||||
Log.d(TAG, "getPTokenFromMultiPageViewer index " + index + ", url " + url);
|
||||
}
|
||||
@@ -815,7 +815,7 @@ public final class SpiderQueen implements Runnable {
|
||||
}
|
||||
|
||||
String url = EhUrl.getGalleryDetailUrl(
|
||||
mGalleryInfo.gid, mGalleryInfo.token, previewIndex, false);
|
||||
mGalleryInfo.getGid(), mGalleryInfo.getToken(), previewIndex, false);
|
||||
String referer = EhUrl.getReferer();
|
||||
if (DEBUG_PTOKEN) {
|
||||
Log.d(TAG, "index " + index + ", previewIndex " + previewIndex +
|
||||
@@ -861,7 +861,7 @@ public final class SpiderQueen implements Runnable {
|
||||
}
|
||||
|
||||
// Write to cache
|
||||
var editor = mSpiderInfoCache.edit(Long.toString(mGalleryInfo.gid));
|
||||
var editor = mSpiderInfoCache.edit(Long.toString(mGalleryInfo.getGid()));
|
||||
if (editor == null) return;
|
||||
try (OutputStream os = new FileOutputStream(editor.getData().toFile())) {
|
||||
spiderInfo.write(os);
|
||||
@@ -1097,7 +1097,7 @@ public final class SpiderQueen implements Runnable {
|
||||
private final long mGid;
|
||||
|
||||
public SpiderWorker() {
|
||||
mGid = mGalleryInfo.gid;
|
||||
mGid = mGalleryInfo.getGid();
|
||||
}
|
||||
|
||||
private String getPageUrl(long gid, int index, String pToken,
|
||||
@@ -1115,7 +1115,7 @@ public final class SpiderQueen implements Runnable {
|
||||
}
|
||||
|
||||
private GalleryPageParser.Result fetchPageResultFromHtml(int index, String pageUrl) throws Throwable {
|
||||
GalleryPageParser.Result result = EhEngine.getGalleryPage(mHttpClient, pageUrl, mGalleryInfo.gid, mGalleryInfo.token);
|
||||
GalleryPageParser.Result result = EhEngine.getGalleryPage(pageUrl, mGalleryInfo.getGid(), mGalleryInfo.getToken());
|
||||
if (StringUtils.endsWith(result.imageUrl, URL_509_SUFFIX_ARRAY)) {
|
||||
// Get 509
|
||||
// Notify listeners
|
||||
@@ -1127,7 +1127,7 @@ public final class SpiderQueen implements Runnable {
|
||||
}
|
||||
|
||||
private GalleryPageApiParser.Result fetchPageResultFromApi(long gid, int index, String pToken, String showKey, String previousPToken) throws Throwable {
|
||||
GalleryPageApiParser.Result result = EhEngine.getGalleryPageApi(mHttpClient, gid, index, pToken, showKey, previousPToken);
|
||||
GalleryPageApiParser.Result result = EhEngine.getGalleryPageApi(gid, index, pToken, showKey, previousPToken);
|
||||
if (StringUtils.endsWith(result.imageUrl, URL_509_SUFFIX_ARRAY)) {
|
||||
// Get 509
|
||||
// Notify listeners
|
||||
@@ -1395,11 +1395,13 @@ public final class SpiderQueen implements Runnable {
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Thread.sleep(0); // to make allow to catch InterruptedException
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
error = GetText.getString(R.string.error_socket);
|
||||
forceHtml = true;
|
||||
} catch (InterruptedException ignored) {
|
||||
} finally {
|
||||
IOUtils.closeQuietly(is);
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ public final class CommonOperations {
|
||||
EhClient client = EhClient.INSTANCE;
|
||||
EhRequest request = new EhRequest();
|
||||
request.setMethod(EhClient.METHOD_ADD_FAVORITES);
|
||||
request.setArgs(galleryInfo.gid, galleryInfo.token, slot, "");
|
||||
request.setArgs(galleryInfo.getGid(), galleryInfo.getToken(), slot, "");
|
||||
request.setCallback(listener);
|
||||
request.enqueue(activity);
|
||||
} else {
|
||||
@@ -99,11 +99,11 @@ public final class CommonOperations {
|
||||
|
||||
public static void removeFromFavorites(Activity activity, GalleryInfo galleryInfo,
|
||||
final EhClient.Callback<Void> listener) {
|
||||
EhDB.removeLocalFavorites(galleryInfo.gid);
|
||||
EhDB.removeLocalFavorites(galleryInfo.getGid());
|
||||
EhClient client = EhClient.INSTANCE;
|
||||
EhRequest request = new EhRequest();
|
||||
request.setMethod(EhClient.METHOD_ADD_FAVORITES);
|
||||
request.setArgs(galleryInfo.gid, galleryInfo.token, -1, "");
|
||||
request.setArgs(galleryInfo.getGid(), galleryInfo.getToken(), -1, "");
|
||||
request.setCallback(new DelegateFavoriteCallback(listener, galleryInfo, null, -2));
|
||||
request.enqueue(activity);
|
||||
}
|
||||
@@ -125,8 +125,8 @@ public final class CommonOperations {
|
||||
LongList toStart = new LongList();
|
||||
List<GalleryInfo> toAdd = new ArrayList<>();
|
||||
for (GalleryInfo gi : galleryInfos) {
|
||||
if (dm.containDownloadInfo(gi.gid)) {
|
||||
toStart.add(gi.gid);
|
||||
if (dm.containDownloadInfo(gi.getGid())) {
|
||||
toStart.add(gi.getGid());
|
||||
} else {
|
||||
toAdd.add(gi);
|
||||
}
|
||||
@@ -259,10 +259,10 @@ public final class CommonOperations {
|
||||
|
||||
@Override
|
||||
public void onSuccess(Void result) {
|
||||
info.favoriteName = newFavoriteName;
|
||||
info.favoriteSlot = slot;
|
||||
info.setFavoriteName(newFavoriteName);
|
||||
info.setFavoriteSlot(slot);
|
||||
delegate.onSuccess(result);
|
||||
EhApplication.getFavouriteStatusRouter().modifyFavourites(info.gid, slot);
|
||||
EhApplication.getFavouriteStatusRouter().modifyFavourites(info.getGid(), slot);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.hippo.ehviewer.ui
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.navigation.ActivityNavigator
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import com.google.accompanist.themeadapter.material3.Mdc3Theme
|
||||
import com.hippo.ehviewer.ui.compose.CookieSignInScene
|
||||
import com.hippo.ehviewer.ui.compose.SelectSiteScreen
|
||||
import com.hippo.ehviewer.ui.compose.SignInScreen
|
||||
import com.hippo.ehviewer.ui.compose.WebviewSignInScreen
|
||||
|
||||
class LoginActivity : ComponentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContent {
|
||||
Mdc3Theme {
|
||||
val navController = rememberNavController()
|
||||
|
||||
NavHost(navController = navController, startDestination = SIGN_IN_ROUTE_NAME) {
|
||||
composable(SIGN_IN_ROUTE_NAME) {
|
||||
SignInScreen(navController)
|
||||
}
|
||||
|
||||
composable(WEBVIEW_SIGN_IN_ROUTE_NAME) {
|
||||
WebviewSignInScreen(navController)
|
||||
}
|
||||
|
||||
composable(COOKIE_SIGN_IN_ROUTE_NAME) {
|
||||
CookieSignInScene(navController)
|
||||
}
|
||||
|
||||
composable(SELECT_SITE_ROUTE_NAME) {
|
||||
SelectSiteScreen {
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun finish() {
|
||||
super.finish()
|
||||
ActivityNavigator.applyPopAnimationsToPendingTransition(this)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val SIGN_IN_ROUTE_NAME = "SignIn"
|
||||
const val WEBVIEW_SIGN_IN_ROUTE_NAME = "WebViewSignIn"
|
||||
const val COOKIE_SIGN_IN_ROUTE_NAME = "CookieSignIn"
|
||||
const val SELECT_SITE_ROUTE_NAME = "SelectSite"
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
package com.hippo.ehviewer.ui
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.assist.AssistContent
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
@@ -26,113 +27,56 @@ import android.net.ConnectivityManager
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.PersistableBundle
|
||||
import android.view.MenuItem
|
||||
import android.text.TextUtils
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.annotation.IdRes
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.core.view.GravityCompat
|
||||
import androidx.drawerlayout.widget.DrawerLayout
|
||||
import androidx.drawerlayout.widget.DrawerLayout.DrawerListener
|
||||
import com.google.android.material.navigation.NavigationView
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.fragment.NavHostFragment
|
||||
import androidx.navigation.ui.setupWithNavController
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.hippo.app.BaseDialogBuilder
|
||||
import com.hippo.app.EditTextDialogBuilder
|
||||
import com.hippo.ehviewer.AppConfig
|
||||
import com.hippo.ehviewer.R
|
||||
import com.hippo.ehviewer.Settings
|
||||
import com.hippo.ehviewer.client.EhUrlOpener
|
||||
import com.hippo.ehviewer.client.EhUtils
|
||||
import com.hippo.ehviewer.client.data.ListUrlBuilder
|
||||
import com.hippo.ehviewer.client.parser.GalleryDetailUrlParser
|
||||
import com.hippo.ehviewer.client.parser.GalleryListUrlParser
|
||||
import com.hippo.ehviewer.client.parser.GalleryPageUrlParser
|
||||
import com.hippo.ehviewer.databinding.ActivityMainBinding
|
||||
import com.hippo.ehviewer.download.DownloadService
|
||||
import com.hippo.ehviewer.ui.scene.BaseScene
|
||||
import com.hippo.ehviewer.ui.scene.CookieSignInScene
|
||||
import com.hippo.ehviewer.ui.scene.DownloadsScene
|
||||
import com.hippo.ehviewer.ui.scene.FavoritesScene
|
||||
import com.hippo.ehviewer.ui.scene.GalleryCommentsScene
|
||||
import com.hippo.ehviewer.ui.scene.GalleryDetailScene
|
||||
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.SelectSiteScene
|
||||
import com.hippo.ehviewer.ui.scene.SignInScene
|
||||
import com.hippo.ehviewer.ui.scene.SolidScene
|
||||
import com.hippo.ehviewer.ui.scene.WebViewSignInScene
|
||||
import com.hippo.ehviewer.widget.EhStageLayout
|
||||
import com.hippo.io.UniFileInputStreamPipe
|
||||
import com.hippo.scene.Announcer
|
||||
import com.hippo.scene.SceneFragment
|
||||
import com.hippo.scene.StageActivity
|
||||
import com.hippo.unifile.UniFile
|
||||
import com.hippo.util.BitmapUtils
|
||||
import com.hippo.util.addTextToClipboard
|
||||
import com.hippo.util.getClipboardManager
|
||||
import com.hippo.util.getUrlFromClipboard
|
||||
import com.hippo.widget.DrawerView
|
||||
import com.hippo.yorozuya.IOUtils
|
||||
import com.hippo.yorozuya.SimpleHandler
|
||||
import com.hippo.yorozuya.ViewUtils
|
||||
import eu.kanade.tachiyomi.util.lang.launchUI
|
||||
import eu.kanade.tachiyomi.util.lang.withUIContext
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.io.IOException
|
||||
import java.io.OutputStream
|
||||
|
||||
class MainActivity : StageActivity(), NavigationView.OnNavigationItemSelectedListener {
|
||||
private var settingsLauncher =
|
||||
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||
if (it.resultCode == RESULT_OK) refreshTopScene()
|
||||
}
|
||||
|
||||
/*---------------
|
||||
Whole life cycle
|
||||
---------------*/
|
||||
private var mDrawerLayout: DrawerLayout? = null
|
||||
private var mStageLayout: EhStageLayout? = null
|
||||
private var mNavView: NavigationView? = null
|
||||
private var mRightDrawer: DrawerView? = null
|
||||
private var mNavCheckedItem = 0
|
||||
override fun getContainerViewId(): Int {
|
||||
return R.id.fragment_container
|
||||
}
|
||||
|
||||
override fun getLaunchAnnouncer(): Announcer {
|
||||
return if (EhUtils.needSignedIn()) {
|
||||
Announcer(SignInScene::class.java)
|
||||
} else if (Settings.getSelectSite()) {
|
||||
Announcer(SelectSiteScene::class.java)
|
||||
} else {
|
||||
val args = Bundle()
|
||||
args.putString(
|
||||
GalleryListScene.KEY_ACTION,
|
||||
Settings.getLaunchPageGalleryListSceneAction()
|
||||
)
|
||||
Announcer(GalleryListScene::class.java).setArgs(args)
|
||||
}
|
||||
}
|
||||
|
||||
// Sometimes scene can't show directly
|
||||
private fun processAnnouncer(announcer: Announcer): Announcer {
|
||||
if (0 == sceneCount) {
|
||||
if (EhUtils.needSignedIn()) {
|
||||
val newArgs = Bundle()
|
||||
newArgs.putString(SignInScene.KEY_TARGET_SCENE, announcer.clazz.name)
|
||||
newArgs.putBundle(SignInScene.KEY_TARGET_ARGS, announcer.args)
|
||||
return Announcer(SignInScene::class.java).setArgs(newArgs)
|
||||
} else if (Settings.getSelectSite()) {
|
||||
val newArgs = Bundle()
|
||||
newArgs.putString(SelectSiteScene.KEY_TARGET_SCENE, announcer.clazz.name)
|
||||
newArgs.putBundle(SelectSiteScene.KEY_TARGET_ARGS, announcer.args)
|
||||
return Announcer(SelectSiteScene::class.java).setArgs(newArgs)
|
||||
}
|
||||
}
|
||||
return announcer
|
||||
}
|
||||
class MainActivity : EhActivity() {
|
||||
private lateinit var binding: ActivityMainBinding
|
||||
private lateinit var navController: NavController
|
||||
|
||||
private fun saveImageToTempFile(file: UniFile?): File? {
|
||||
file ?: return null
|
||||
@@ -166,16 +110,68 @@ class MainActivity : StageActivity(), NavigationView.OnNavigationItemSelectedLis
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleIntent(intent: Intent?): Boolean {
|
||||
if (intent == null) {
|
||||
return false
|
||||
override fun onNewIntent(intent: Intent?) {
|
||||
super.onNewIntent(intent)
|
||||
lifecycleScope.launchUI {
|
||||
if (!handleIntent(intent)) {
|
||||
if (intent != null && Intent.ACTION_VIEW == intent.action) {
|
||||
if (intent.data != null) {
|
||||
val url = intent.data.toString()
|
||||
EditTextDialogBuilder(this@MainActivity, url, "")
|
||||
.setTitle(R.string.error_cannot_parse_the_url)
|
||||
.setPositiveButton(android.R.string.copy) { _: DialogInterface?, _: Int ->
|
||||
this@MainActivity.addTextToClipboard(
|
||||
url,
|
||||
false
|
||||
)
|
||||
}
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleIntent(intent: Intent?): Boolean {
|
||||
intent ?: return false
|
||||
val action = intent.action
|
||||
if (Intent.ACTION_VIEW == action) {
|
||||
val uri = intent.data ?: return false
|
||||
val announcer = EhUrlOpener.parseUrl(uri.toString())
|
||||
if (announcer != null) {
|
||||
startScene(processAnnouncer(announcer))
|
||||
val url = uri.toString()
|
||||
if (TextUtils.isEmpty(url)) {
|
||||
return false
|
||||
}
|
||||
|
||||
val listUrlBuilder = GalleryListUrlParser.parse(url)
|
||||
if (listUrlBuilder != null) {
|
||||
val args = Bundle()
|
||||
args.putString(
|
||||
GalleryListScene.KEY_ACTION,
|
||||
GalleryListScene.ACTION_LIST_URL_BUILDER
|
||||
)
|
||||
args.putParcelable(GalleryListScene.KEY_LIST_URL_BUILDER, listUrlBuilder)
|
||||
navController.navigate(R.id.galleryListScene, args)
|
||||
return true
|
||||
}
|
||||
|
||||
val result1 = GalleryDetailUrlParser.parse(url)
|
||||
if (result1 != null) {
|
||||
val args = Bundle()
|
||||
args.putString(GalleryDetailScene.KEY_ACTION, GalleryDetailScene.ACTION_GID_TOKEN)
|
||||
args.putLong(GalleryDetailScene.KEY_GID, result1.gid)
|
||||
args.putString(GalleryDetailScene.KEY_TOKEN, result1.token)
|
||||
navController.navigate(R.id.galleryDetailScene, args)
|
||||
return true
|
||||
}
|
||||
|
||||
val result2 = GalleryPageUrlParser.parse(url)
|
||||
if (result2 != null) {
|
||||
val args = Bundle()
|
||||
args.putString(ProgressScene.KEY_ACTION, ProgressScene.ACTION_GALLERY_TOKEN)
|
||||
args.putLong(ProgressScene.KEY_GID, result2.gid)
|
||||
args.putString(ProgressScene.KEY_PTOKEN, result2.pToken)
|
||||
args.putInt(ProgressScene.KEY_PAGE, result2.page)
|
||||
navController.navigate(R.id.progressScene, args)
|
||||
return true
|
||||
}
|
||||
} else if (Intent.ACTION_SEND == action) {
|
||||
@@ -183,7 +179,10 @@ class MainActivity : StageActivity(), NavigationView.OnNavigationItemSelectedLis
|
||||
if ("text/plain" == type) {
|
||||
val builder = ListUrlBuilder()
|
||||
builder.keyword = intent.getStringExtra(Intent.EXTRA_TEXT)
|
||||
startScene(processAnnouncer(GalleryListScene.getStartAnnouncer(builder)))
|
||||
navController.navigate(
|
||||
R.id.galleryListScene,
|
||||
GalleryListScene.getStartArgs(builder)
|
||||
)
|
||||
return true
|
||||
} else if (type != null && type.startsWith("image/")) {
|
||||
val uri = intent.getParcelableExtra<Uri>(Intent.EXTRA_STREAM)
|
||||
@@ -195,69 +194,47 @@ class MainActivity : StageActivity(), NavigationView.OnNavigationItemSelectedLis
|
||||
builder.mode = ListUrlBuilder.MODE_IMAGE_SEARCH
|
||||
builder.imagePath = temp.path
|
||||
builder.isUseSimilarityScan = true
|
||||
startScene(processAnnouncer(GalleryListScene.getStartAnnouncer(builder)))
|
||||
navController.navigate(
|
||||
R.id.galleryListScene,
|
||||
GalleryListScene.getStartArgs(builder)
|
||||
)
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (action == DownloadService.ACTION_START_DOWNLOADSCENE) {
|
||||
val args = intent.getBundleExtra(DownloadService.ACTION_START_DOWNLOADSCENE_ARGS)
|
||||
navController.navigate(R.id.nav_downloads, args)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onUnrecognizedIntent(intent: Intent?) {
|
||||
val clazz = topSceneClass
|
||||
if (clazz != null && SolidScene::class.java.isAssignableFrom(clazz)) {
|
||||
// TODO the intent lost
|
||||
return
|
||||
}
|
||||
if (!handleIntent(intent)) {
|
||||
var handleUrl = false
|
||||
if (intent != null && Intent.ACTION_VIEW == intent.action) {
|
||||
handleUrl = true
|
||||
if (intent.data != null) {
|
||||
val url = intent.data.toString()
|
||||
EditTextDialogBuilder(this, url, "")
|
||||
.setTitle(R.string.error_cannot_parse_the_url)
|
||||
.setPositiveButton(android.R.string.copy) { _: DialogInterface?, _: Int ->
|
||||
this.addTextToClipboard(
|
||||
url,
|
||||
false
|
||||
)
|
||||
}
|
||||
.show()
|
||||
}
|
||||
}
|
||||
if (0 == sceneCount) {
|
||||
if (handleUrl) {
|
||||
finish()
|
||||
} else {
|
||||
val args = Bundle()
|
||||
args.putString(
|
||||
GalleryListScene.KEY_ACTION,
|
||||
Settings.getLaunchPageGalleryListSceneAction()
|
||||
)
|
||||
startScene(processAnnouncer(Announcer(GalleryListScene::class.java).setArgs(args)))
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
if (EhUtils.needSignedIn())
|
||||
startActivity(Intent(this, LoginActivity::class.java))
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
val navHostFragment =
|
||||
supportFragmentManager.findFragmentById(R.id.fragment_container) as NavHostFragment
|
||||
navController = navHostFragment.navController
|
||||
navController.apply {
|
||||
graph = navInflater.inflate(R.navigation.nav_graph).apply {
|
||||
when (Settings.getLaunchPageGalleryListSceneAction()) {
|
||||
GalleryListScene.ACTION_HOMEPAGE -> setStartDestination(R.id.nav_homepage)
|
||||
GalleryListScene.ACTION_SUBSCRIPTION -> setStartDestination(R.id.nav_subscription)
|
||||
GalleryListScene.ACTION_WHATS_HOT -> setStartDestination(R.id.nav_whats_hot)
|
||||
GalleryListScene.ACTION_TOP_LIST -> setStartDestination(R.id.nav_toplist)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStartSceneFromIntent(clazz: Class<*>, args: Bundle?): Announcer {
|
||||
return processAnnouncer(Announcer(clazz).setArgs(args))
|
||||
}
|
||||
|
||||
override fun onCreate2(savedInstanceState: Bundle?) {
|
||||
setContentView(R.layout.activity_main)
|
||||
mStageLayout = ViewUtils.`$$`(this, R.id.fragment_container) as EhStageLayout
|
||||
mDrawerLayout = ViewUtils.`$$`(this, R.id.draw_view) as DrawerLayout
|
||||
mNavView = ViewUtils.`$$`(this, R.id.nav_view) as NavigationView
|
||||
mRightDrawer = ViewUtils.`$$`(this, R.id.right_drawer) as DrawerView
|
||||
mDrawerLayout?.addDrawerListener(mDrawerOnBackPressedCallback)
|
||||
onBackPressedDispatcher.addCallback(mDrawerOnBackPressedCallback)
|
||||
if (mNavView != null) {
|
||||
mNavView!!.setNavigationItemSelectedListener(this)
|
||||
}
|
||||
binding.drawView.addDrawerListener(mDrawerOnBackPressedCallback)
|
||||
binding.navView.setupWithNavController(navController)
|
||||
if (savedInstanceState == null) {
|
||||
if (intent.action != Intent.ACTION_MAIN) {
|
||||
onNewIntent(intent)
|
||||
}
|
||||
checkDownloadLocation()
|
||||
if (Settings.getMeteredNetworkWarning()) {
|
||||
checkMeteredNetwork()
|
||||
@@ -270,8 +247,6 @@ class MainActivity : StageActivity(), NavigationView.OnNavigationItemSelectedLis
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
onRestore(savedInstanceState)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,9 +310,9 @@ class MainActivity : StageActivity(), NavigationView.OnNavigationItemSelectedLis
|
||||
private fun checkMeteredNetwork() {
|
||||
val cm = getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||
if (cm.isActiveNetworkMetered) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && mDrawerLayout != null) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
Snackbar.make(
|
||||
mDrawerLayout!!,
|
||||
binding.drawView,
|
||||
R.string.metered_network_warning,
|
||||
Snackbar.LENGTH_LONG
|
||||
)
|
||||
@@ -353,110 +328,72 @@ class MainActivity : StageActivity(), NavigationView.OnNavigationItemSelectedLis
|
||||
}
|
||||
}
|
||||
|
||||
private fun onRestore(savedInstanceState: Bundle) {
|
||||
mNavCheckedItem = savedInstanceState.getInt(KEY_NAV_CHECKED_ITEM)
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle, outPersistentState: PersistableBundle) {
|
||||
super.onSaveInstanceState(outState, outPersistentState)
|
||||
outState.putInt(KEY_NAV_CHECKED_ITEM, mNavCheckedItem)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
mDrawerLayout = null
|
||||
mNavView = null
|
||||
mRightDrawer = null
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
setNavCheckedItem(mNavCheckedItem)
|
||||
checkClipboardUrl()
|
||||
}
|
||||
|
||||
override fun onTransactScene() {
|
||||
super.onTransactScene()
|
||||
checkClipboardUrl()
|
||||
}
|
||||
|
||||
private fun checkClipboardUrl() {
|
||||
SimpleHandler.getInstance().postDelayed({
|
||||
if (!isSolid) {
|
||||
checkClipboardUrlInternal()
|
||||
}
|
||||
}, 300)
|
||||
}
|
||||
|
||||
private val isSolid: Boolean
|
||||
get() {
|
||||
val topClass = topSceneClass
|
||||
return topClass == null || SolidScene::class.java.isAssignableFrom(topClass)
|
||||
lifecycleScope.launch {
|
||||
delay(100)
|
||||
// delay 100ms to make sure it take precedence over androidx navigation's callback
|
||||
mDrawerOnBackPressedCallback.remove()
|
||||
onBackPressedDispatcher.addCallback(mDrawerOnBackPressedCallback)
|
||||
delay(200)
|
||||
checkClipboardUrl()
|
||||
}
|
||||
|
||||
private fun createAnnouncerFromClipboardUrl(url: String): Announcer? {
|
||||
val result1 = GalleryDetailUrlParser.parse(url, false)
|
||||
if (result1 != null) {
|
||||
val args = Bundle()
|
||||
args.putString(GalleryDetailScene.KEY_ACTION, GalleryDetailScene.ACTION_GID_TOKEN)
|
||||
args.putLong(GalleryDetailScene.KEY_GID, result1.gid)
|
||||
args.putString(GalleryDetailScene.KEY_TOKEN, result1.token)
|
||||
return Announcer(GalleryDetailScene::class.java).setArgs(args)
|
||||
}
|
||||
val result2 = GalleryPageUrlParser.parse(url, false)
|
||||
if (result2 != null) {
|
||||
val args = Bundle()
|
||||
args.putString(ProgressScene.KEY_ACTION, ProgressScene.ACTION_GALLERY_TOKEN)
|
||||
args.putLong(ProgressScene.KEY_GID, result2.gid)
|
||||
args.putString(ProgressScene.KEY_PTOKEN, result2.pToken)
|
||||
args.putInt(ProgressScene.KEY_PAGE, result2.page)
|
||||
return Announcer(ProgressScene::class.java).setArgs(args)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun checkClipboardUrlInternal() {
|
||||
private suspend fun checkClipboardUrl() {
|
||||
val text = this.getClipboardManager().getUrlFromClipboard(this)
|
||||
val hashCode = text?.hashCode() ?: 0
|
||||
if (text != null && hashCode != 0 && Settings.getClipboardTextHashCode() != hashCode) {
|
||||
val announcer = createAnnouncerFromClipboardUrl(text)
|
||||
if (announcer != null && mDrawerLayout != null) {
|
||||
val snackbar = Snackbar.make(
|
||||
mDrawerLayout!!,
|
||||
R.string.clipboard_gallery_url_snack_message,
|
||||
Snackbar.LENGTH_SHORT
|
||||
)
|
||||
snackbar.setAction(R.string.clipboard_gallery_url_snack_action) {
|
||||
startScene(
|
||||
announcer
|
||||
val result1 = GalleryDetailUrlParser.parse(text, false)
|
||||
var launch: (() -> Unit)? = null
|
||||
if (result1 != null) {
|
||||
val args = Bundle()
|
||||
args.putString(GalleryDetailScene.KEY_ACTION, GalleryDetailScene.ACTION_GID_TOKEN)
|
||||
args.putLong(GalleryDetailScene.KEY_GID, result1.gid)
|
||||
args.putString(GalleryDetailScene.KEY_TOKEN, result1.token)
|
||||
launch = { navController.navigate(R.id.galleryDetailScene, args) }
|
||||
}
|
||||
val result2 = GalleryPageUrlParser.parse(text, false)
|
||||
if (result2 != null) {
|
||||
val args = Bundle()
|
||||
args.putString(ProgressScene.KEY_ACTION, ProgressScene.ACTION_GALLERY_TOKEN)
|
||||
args.putLong(ProgressScene.KEY_GID, result2.gid)
|
||||
args.putString(ProgressScene.KEY_PTOKEN, result2.pToken)
|
||||
args.putInt(ProgressScene.KEY_PAGE, result2.page)
|
||||
launch = { navController.navigate(R.id.progressScene, args) }
|
||||
}
|
||||
launch?.let {
|
||||
withUIContext {
|
||||
val snackbar = Snackbar.make(
|
||||
binding.drawView,
|
||||
R.string.clipboard_gallery_url_snack_message,
|
||||
Snackbar.LENGTH_SHORT
|
||||
)
|
||||
snackbar.setAction(R.string.clipboard_gallery_url_snack_action) {
|
||||
it()
|
||||
}
|
||||
snackbar.show()
|
||||
}
|
||||
snackbar.show()
|
||||
}
|
||||
}
|
||||
Settings.putClipboardTextHashCode(hashCode)
|
||||
}
|
||||
|
||||
override fun onSceneViewCreated(scene: SceneFragment, savedInstanceState: Bundle?) {
|
||||
super.onSceneViewCreated(scene, savedInstanceState)
|
||||
createDrawerView(scene)
|
||||
}
|
||||
|
||||
@SuppressLint("RtlHardcoded")
|
||||
fun createDrawerView(scene: SceneFragment?) {
|
||||
if (scene is BaseScene && mRightDrawer != null && mDrawerLayout != null) {
|
||||
mRightDrawer!!.removeAllViews()
|
||||
fun createDrawerView(scene: Fragment?) {
|
||||
if (scene is BaseScene) {
|
||||
binding.rightDrawer.removeAllViews()
|
||||
val drawerView = scene.createDrawerView(
|
||||
scene.layoutInflater, mRightDrawer, null
|
||||
scene.layoutInflater, binding.rightDrawer, null
|
||||
)
|
||||
if (drawerView != null) {
|
||||
mRightDrawer!!.addView(drawerView)
|
||||
mDrawerLayout!!.setDrawerLockMode(
|
||||
binding.rightDrawer.addView(drawerView)
|
||||
binding.drawView.setDrawerLockMode(
|
||||
DrawerLayout.LOCK_MODE_UNLOCKED,
|
||||
GravityCompat.END
|
||||
)
|
||||
} else {
|
||||
mDrawerLayout!!.setDrawerLockMode(
|
||||
binding.drawView.setDrawerLockMode(
|
||||
DrawerLayout.LOCK_MODE_LOCKED_CLOSED,
|
||||
GravityCompat.END
|
||||
)
|
||||
@@ -464,39 +401,32 @@ class MainActivity : StageActivity(), NavigationView.OnNavigationItemSelectedLis
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSceneViewDestroyed(scene: SceneFragment) {
|
||||
super.onSceneViewDestroyed(scene)
|
||||
if (scene is BaseScene) {
|
||||
scene.destroyDrawerView()
|
||||
}
|
||||
}
|
||||
|
||||
fun addAboveSnackView(view: View?) {
|
||||
mStageLayout?.addAboveSnackView(view)
|
||||
binding.absnacker.addAboveSnackView(view)
|
||||
}
|
||||
|
||||
fun removeAboveSnackView(view: View?) {
|
||||
mStageLayout?.removeAboveSnackView(view)
|
||||
binding.absnacker.removeAboveSnackView(view)
|
||||
}
|
||||
|
||||
fun setDrawerLockMode(lockMode: Int, edgeGravity: Int) {
|
||||
mDrawerLayout?.setDrawerLockMode(lockMode, edgeGravity)
|
||||
binding.drawView.setDrawerLockMode(lockMode, edgeGravity)
|
||||
}
|
||||
|
||||
fun getDrawerLockMode(edgeGravity: Int): Int? {
|
||||
return mDrawerLayout?.getDrawerLockMode(edgeGravity)
|
||||
fun getDrawerLockMode(edgeGravity: Int): Int {
|
||||
return binding.drawView.getDrawerLockMode(edgeGravity)
|
||||
}
|
||||
|
||||
fun openDrawer(drawerGravity: Int) {
|
||||
mDrawerLayout?.openDrawer(drawerGravity)
|
||||
binding.drawView.openDrawer(drawerGravity)
|
||||
}
|
||||
|
||||
fun closeDrawer(drawerGravity: Int) {
|
||||
mDrawerLayout?.closeDrawer(drawerGravity)
|
||||
binding.drawView.closeDrawer(drawerGravity)
|
||||
}
|
||||
|
||||
fun toggleDrawer(drawerGravity: Int) {
|
||||
mDrawerLayout?.run {
|
||||
binding.drawView.run {
|
||||
if (isDrawerOpen(drawerGravity)) {
|
||||
closeDrawer(drawerGravity)
|
||||
} else {
|
||||
@@ -505,17 +435,6 @@ class MainActivity : StageActivity(), NavigationView.OnNavigationItemSelectedLis
|
||||
}
|
||||
}
|
||||
|
||||
fun setNavCheckedItem(@IdRes resId: Int) {
|
||||
mNavCheckedItem = resId
|
||||
mNavView?.run {
|
||||
if (resId == 0) {
|
||||
setCheckedItem(R.id.nav_stub)
|
||||
} else {
|
||||
setCheckedItem(resId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun showTip(@StringRes id: Int, length: Int, useToast: Boolean = false) {
|
||||
showTip(getString(id), length, useToast)
|
||||
@@ -537,77 +456,17 @@ class MainActivity : StageActivity(), NavigationView.OnNavigationItemSelectedLis
|
||||
).show()
|
||||
}
|
||||
|
||||
override fun onNavigationItemSelected(item: MenuItem): Boolean {
|
||||
// Don't select twice
|
||||
if (item.isChecked) {
|
||||
return false
|
||||
}
|
||||
val id = item.itemId
|
||||
when (id) {
|
||||
R.id.nav_homepage -> {
|
||||
val args = Bundle()
|
||||
args.putString(GalleryListScene.KEY_ACTION, GalleryListScene.ACTION_HOMEPAGE)
|
||||
startSceneFirstly(
|
||||
Announcer(GalleryListScene::class.java)
|
||||
.setArgs(args)
|
||||
)
|
||||
}
|
||||
|
||||
R.id.nav_subscription -> {
|
||||
val args = Bundle()
|
||||
args.putString(GalleryListScene.KEY_ACTION, GalleryListScene.ACTION_SUBSCRIPTION)
|
||||
startSceneFirstly(
|
||||
Announcer(GalleryListScene::class.java)
|
||||
.setArgs(args)
|
||||
)
|
||||
}
|
||||
|
||||
R.id.nav_whats_hot -> {
|
||||
val args = Bundle()
|
||||
args.putString(GalleryListScene.KEY_ACTION, GalleryListScene.ACTION_WHATS_HOT)
|
||||
startSceneFirstly(
|
||||
Announcer(GalleryListScene::class.java)
|
||||
.setArgs(args)
|
||||
)
|
||||
}
|
||||
|
||||
R.id.nav_toplist -> {
|
||||
val args = Bundle()
|
||||
args.putString(GalleryListScene.KEY_ACTION, GalleryListScene.ACTION_TOP_LIST)
|
||||
startSceneFirstly(
|
||||
Announcer(GalleryListScene::class.java)
|
||||
.setArgs(args)
|
||||
)
|
||||
}
|
||||
|
||||
R.id.nav_favourite -> {
|
||||
startScene(Announcer(FavoritesScene::class.java))
|
||||
}
|
||||
|
||||
R.id.nav_history -> {
|
||||
startScene(Announcer(HistoryScene::class.java))
|
||||
}
|
||||
|
||||
R.id.nav_downloads -> {
|
||||
startScene(Announcer(DownloadsScene::class.java))
|
||||
}
|
||||
|
||||
R.id.nav_settings -> {
|
||||
val intent = Intent(this, SettingsActivity::class.java)
|
||||
settingsLauncher.launch(intent)
|
||||
}
|
||||
}
|
||||
if (id != R.id.nav_stub) {
|
||||
mDrawerLayout?.closeDrawers()
|
||||
}
|
||||
return true
|
||||
var mShareUrl: String? = null
|
||||
override fun onProvideAssistContent(outContent: AssistContent?) {
|
||||
super.onProvideAssistContent(outContent)
|
||||
mShareUrl?.let { outContent?.webUri = Uri.parse(mShareUrl) }
|
||||
}
|
||||
|
||||
private val mDrawerOnBackPressedCallback =
|
||||
object : OnBackPressedCallback(false), DrawerListener {
|
||||
val slideThreshold = 0.05
|
||||
override fun handleOnBackPressed() {
|
||||
mDrawerLayout?.closeDrawers()
|
||||
binding.drawView.closeDrawers()
|
||||
}
|
||||
|
||||
override fun onDrawerSlide(drawerView: View, slideOffset: Float) {
|
||||
@@ -618,26 +477,4 @@ class MainActivity : StageActivity(), NavigationView.OnNavigationItemSelectedLis
|
||||
override fun onDrawerClosed(drawerView: View) {}
|
||||
override fun onDrawerStateChanged(newState: Int) {}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val KEY_NAV_CHECKED_ITEM = "nav_checked_item"
|
||||
|
||||
init {
|
||||
registerLaunchMode(SignInScene::class.java, SceneFragment.LAUNCH_MODE_SINGLE_TASK)
|
||||
registerLaunchMode(
|
||||
WebViewSignInScene::class.java,
|
||||
SceneFragment.LAUNCH_MODE_SINGLE_TASK
|
||||
)
|
||||
registerLaunchMode(CookieSignInScene::class.java, SceneFragment.LAUNCH_MODE_SINGLE_TASK)
|
||||
registerLaunchMode(SelectSiteScene::class.java, SceneFragment.LAUNCH_MODE_SINGLE_TASK)
|
||||
registerLaunchMode(GalleryListScene::class.java, SceneFragment.LAUNCH_MODE_SINGLE_TOP)
|
||||
registerLaunchMode(GalleryDetailScene::class.java, SceneFragment.LAUNCH_MODE_STANDARD)
|
||||
registerLaunchMode(GalleryCommentsScene::class.java, SceneFragment.LAUNCH_MODE_STANDARD)
|
||||
registerLaunchMode(GalleryPreviewsScene::class.java, SceneFragment.LAUNCH_MODE_STANDARD)
|
||||
registerLaunchMode(DownloadsScene::class.java, SceneFragment.LAUNCH_MODE_SINGLE_TASK)
|
||||
registerLaunchMode(FavoritesScene::class.java, SceneFragment.LAUNCH_MODE_SINGLE_TASK)
|
||||
registerLaunchMode(HistoryScene::class.java, SceneFragment.LAUNCH_MODE_SINGLE_TOP)
|
||||
registerLaunchMode(ProgressScene::class.java, SceneFragment.LAUNCH_MODE_STANDARD)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import android.view.MenuItem
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.fragment.app.FragmentTransaction
|
||||
import androidx.navigation.ActivityNavigator
|
||||
import com.google.android.material.appbar.AppBarLayout
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
@@ -78,4 +79,9 @@ class SettingsActivity : EhActivity() {
|
||||
fun resetAppbarLiftStatus() {
|
||||
mAppbarLayout?.setExpanded(true)
|
||||
}
|
||||
|
||||
override fun finish() {
|
||||
super.finish()
|
||||
ActivityNavigator.applyPopAnimationsToPendingTransition(this)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,313 @@
|
||||
package com.hippo.ehviewer.ui.compose
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Info
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalClipboardManager
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.res.dimensionResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.style.TextDecoration
|
||||
import androidx.compose.ui.text.withStyle
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.navigation.NavController
|
||||
import com.hippo.ehviewer.EhApplication
|
||||
import com.hippo.ehviewer.R
|
||||
import com.hippo.ehviewer.client.EhClient
|
||||
import com.hippo.ehviewer.client.EhClient.METHOD_GET_PROFILE
|
||||
import com.hippo.ehviewer.client.EhCookieStore
|
||||
import com.hippo.ehviewer.client.EhUrl
|
||||
import com.hippo.ehviewer.client.EhUtils
|
||||
import com.hippo.ehviewer.ui.LoginActivity.Companion.SELECT_SITE_ROUTE_NAME
|
||||
import com.hippo.util.ExceptionUtils
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import eu.kanade.tachiyomi.util.lang.withUIContext
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import okhttp3.Cookie
|
||||
import java.util.Locale
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun CookieSignInScene(navController: NavController) {
|
||||
val clipboardManager = LocalClipboardManager.current
|
||||
val focusManager = LocalFocusManager.current
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
var isProgressIndicatorVisible by rememberSaveable { mutableStateOf(false) }
|
||||
|
||||
var ipbMemberId by rememberSaveable { mutableStateOf("") }
|
||||
var ipbPassHash by rememberSaveable { mutableStateOf("") }
|
||||
var igneous by rememberSaveable { mutableStateOf("") }
|
||||
|
||||
var ipbMemberIdErrorState by rememberSaveable { mutableStateOf(false) }
|
||||
var ipbPassHashErrorState by rememberSaveable { mutableStateOf(false) }
|
||||
|
||||
var signInJob by remember { mutableStateOf<Job?>(null) }
|
||||
|
||||
var showErrorDialog by rememberSaveable { mutableStateOf(false) }
|
||||
var loginErrorException by remember { mutableStateOf<Throwable?>(null) }
|
||||
|
||||
val noCookies = stringResource(R.string.from_clipboard_error)
|
||||
|
||||
fun newCookie(name: String, value: String, domain: String): Cookie {
|
||||
return Cookie.Builder().name(name).value(value).domain(domain).expiresAt(Long.MAX_VALUE)
|
||||
.build()
|
||||
}
|
||||
|
||||
fun storeCookie(id: String, hash: String, igneous: String) {
|
||||
EhUtils.signOut()
|
||||
val store = EhApplication.ehCookieStore
|
||||
store.addCookie(newCookie(EhCookieStore.KEY_IPD_MEMBER_ID, id, EhUrl.DOMAIN_E))
|
||||
store.addCookie(newCookie(EhCookieStore.KEY_IPD_MEMBER_ID, id, EhUrl.DOMAIN_EX))
|
||||
store.addCookie(newCookie(EhCookieStore.KEY_IPD_PASS_HASH, hash, EhUrl.DOMAIN_E))
|
||||
store.addCookie(newCookie(EhCookieStore.KEY_IPD_PASS_HASH, hash, EhUrl.DOMAIN_EX))
|
||||
if (igneous.isBlank()) return
|
||||
store.addCookie(newCookie(EhCookieStore.KEY_IGNEOUS, igneous, EhUrl.DOMAIN_E))
|
||||
store.addCookie(newCookie(EhCookieStore.KEY_IGNEOUS, igneous, EhUrl.DOMAIN_EX))
|
||||
}
|
||||
|
||||
fun login() {
|
||||
signInJob?.cancel()
|
||||
if (ipbMemberId.isBlank()) {
|
||||
ipbMemberIdErrorState = true
|
||||
return
|
||||
} else {
|
||||
ipbMemberIdErrorState = false
|
||||
}
|
||||
if (ipbPassHash.isBlank()) {
|
||||
ipbPassHashErrorState = true
|
||||
return
|
||||
} else {
|
||||
ipbPassHashErrorState = false
|
||||
}
|
||||
focusManager.clearFocus()
|
||||
storeCookie(ipbMemberId, ipbPassHash, igneous)
|
||||
isProgressIndicatorVisible = true
|
||||
signInJob = coroutineScope.launchIO {
|
||||
runCatching {
|
||||
EhClient.execute(METHOD_GET_PROFILE)
|
||||
}.onSuccess {
|
||||
withUIContext {
|
||||
navController.navigate(SELECT_SITE_ROUTE_NAME)
|
||||
}
|
||||
}.onFailure {
|
||||
EhApplication.ehCookieStore.signOut()
|
||||
if (it !is CancellationException) {
|
||||
loginErrorException = it
|
||||
showErrorDialog = true
|
||||
isProgressIndicatorVisible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun fillCookiesFromClipboard() {
|
||||
focusManager.clearFocus()
|
||||
val text = clipboardManager.getText()
|
||||
if (text == null) {
|
||||
coroutineScope.launch { snackbarHostState.showSnackbar(noCookies) }
|
||||
return
|
||||
}
|
||||
runCatching {
|
||||
val kvs: Array<String> = if (text.contains(";")) {
|
||||
text.split(";".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||
} else if (text.contains("\n")) {
|
||||
text.split("\n".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||
} else {
|
||||
coroutineScope.launch { snackbarHostState.showSnackbar(noCookies) }
|
||||
return
|
||||
}
|
||||
if (kvs.size < 3) {
|
||||
coroutineScope.launch { snackbarHostState.showSnackbar(noCookies) }
|
||||
return
|
||||
}
|
||||
for (s in kvs) {
|
||||
val kv: Array<String> = if (s.contains("=")) {
|
||||
s.split("=".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||
} else if (s.contains(":")) {
|
||||
s.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
if (kv.size != 2) {
|
||||
continue
|
||||
}
|
||||
when (kv[0].trim { it <= ' ' }.lowercase(Locale.getDefault())) {
|
||||
"ipb_member_id" -> ipbMemberId = kv[1].trim { it <= ' ' }
|
||||
"ipb_pass_hash" -> ipbPassHash = kv[1].trim { it <= ' ' }
|
||||
"igneous" -> igneous = kv[1].trim { it <= ' ' }
|
||||
}
|
||||
}
|
||||
login()
|
||||
}.onFailure {
|
||||
it.printStackTrace()
|
||||
coroutineScope.launch { snackbarHostState.showSnackbar(noCookies) }
|
||||
}
|
||||
}
|
||||
|
||||
Box(
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Scaffold(
|
||||
snackbarHost = {
|
||||
SnackbarHost(hostState = snackbarHostState)
|
||||
}
|
||||
) { padding ->
|
||||
Column(
|
||||
Modifier
|
||||
.padding(dimensionResource(id = R.dimen.keyline_margin))
|
||||
.padding(padding)
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState()),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.v_cookie_brown_x48),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.padding(dimensionResource(id = R.dimen.keyline_margin))
|
||||
)
|
||||
Text(
|
||||
text = stringResource(id = R.string.cookie_explain),
|
||||
modifier = Modifier
|
||||
.padding(
|
||||
horizontal = 32.dp,
|
||||
vertical = dimensionResource(id = R.dimen.keyline_margin)
|
||||
),
|
||||
fontSize = 16.sp
|
||||
)
|
||||
OutlinedTextField(
|
||||
value = ipbMemberId,
|
||||
onValueChange = { ipbMemberId = it.trim { char -> char <= ' ' } },
|
||||
Modifier.width(dimensionResource(id = R.dimen.single_max_width)),
|
||||
label = { Text(text = "ipb_member_id") },
|
||||
keyboardOptions = KeyboardOptions(
|
||||
imeAction = ImeAction.Next
|
||||
),
|
||||
supportingText = { if (ipbMemberIdErrorState) Text(stringResource(R.string.text_is_empty)) },
|
||||
trailingIcon = {
|
||||
if (ipbMemberIdErrorState) Icon(
|
||||
imageVector = Icons.Filled.Info,
|
||||
contentDescription = null
|
||||
)
|
||||
},
|
||||
isError = ipbMemberIdErrorState,
|
||||
singleLine = true
|
||||
)
|
||||
OutlinedTextField(
|
||||
value = ipbPassHash,
|
||||
onValueChange = { ipbPassHash = it.trim { char -> char <= ' ' } },
|
||||
Modifier.width(dimensionResource(id = R.dimen.single_max_width)),
|
||||
label = { Text(text = "ipb_pass_hash") },
|
||||
keyboardOptions = KeyboardOptions(
|
||||
imeAction = ImeAction.Next
|
||||
),
|
||||
supportingText = { if (ipbPassHashErrorState) Text(stringResource(R.string.text_is_empty)) },
|
||||
trailingIcon = {
|
||||
if (ipbPassHashErrorState) Icon(
|
||||
imageVector = Icons.Filled.Info,
|
||||
contentDescription = null
|
||||
)
|
||||
},
|
||||
isError = ipbPassHashErrorState,
|
||||
singleLine = true
|
||||
)
|
||||
OutlinedTextField(
|
||||
value = igneous,
|
||||
onValueChange = { igneous = it.trim { char -> char <= ' ' } },
|
||||
Modifier.width(dimensionResource(id = R.dimen.single_max_width)),
|
||||
label = { Text(text = "igneous") },
|
||||
keyboardActions = KeyboardActions(
|
||||
onDone = { login() }
|
||||
),
|
||||
singleLine = true
|
||||
)
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Button(
|
||||
onClick = { login() },
|
||||
Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text(text = stringResource(id = android.R.string.ok))
|
||||
}
|
||||
TextButton(onClick = { fillCookiesFromClipboard() }) {
|
||||
Text(
|
||||
text = buildAnnotatedString {
|
||||
withStyle(
|
||||
style = SpanStyle(textDecoration = TextDecoration.Underline)
|
||||
) {
|
||||
append(stringResource(id = R.string.from_clipboard))
|
||||
}
|
||||
},
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 8.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isProgressIndicatorVisible)
|
||||
CircularProgressIndicator()
|
||||
if (showErrorDialog) {
|
||||
AlertDialog(
|
||||
onDismissRequest = {
|
||||
showErrorDialog = false
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(onClick = {
|
||||
showErrorDialog = false
|
||||
}) {
|
||||
Text(text = stringResource(id = R.string.get_it))
|
||||
}
|
||||
},
|
||||
title = {
|
||||
Text(text = stringResource(id = R.string.sign_in_failed))
|
||||
},
|
||||
text = {
|
||||
Text(
|
||||
text =
|
||||
"""
|
||||
${ExceptionUtils.getReadableString(loginErrorException!!)}
|
||||
${stringResource(R.string.wrong_cookie_warning)}
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
package com.hippo.ehviewer.ui.compose
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.IntrinsicSize
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Divider
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.res.dimensionResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.hippo.ehviewer.EhApplication
|
||||
import com.hippo.ehviewer.R
|
||||
import com.hippo.ehviewer.Settings
|
||||
import com.hippo.ehviewer.client.EhClient
|
||||
import com.hippo.ehviewer.client.EhUrl
|
||||
import com.hippo.ehviewer.client.parser.ProfileParser
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
|
||||
@Composable
|
||||
fun SelectSiteScreen(finish: () -> Unit) {
|
||||
var site by remember { mutableStateOf(EhApplication.ehCookieStore.hasSignedIn()) } // false for e, true for ex
|
||||
|
||||
Column(
|
||||
Modifier
|
||||
.padding(horizontal = dimensionResource(R.dimen.keyline_margin))
|
||||
.padding(top = dimensionResource(R.dimen.keyline_margin))
|
||||
.fillMaxSize(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.select_scene),
|
||||
style = MaterialTheme.typography.titleMedium
|
||||
)
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
// TODO: Replace this dummy impl with official one when available
|
||||
// See https://m3.material.io/components/segmented-buttons/overview
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.height(IntrinsicSize.Min)
|
||||
.border(
|
||||
1.dp,
|
||||
MaterialTheme.colorScheme.outline,
|
||||
RoundedCornerShape(90f, 90f, 90f, 90f)
|
||||
)
|
||||
.clip(RoundedCornerShape(90f, 90f, 90f, 90f))
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.background(if (!site) MaterialTheme.colorScheme.secondaryContainer else MaterialTheme.colorScheme.surface)
|
||||
.clickable { site = false }
|
||||
.size(100.dp, 40.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.site_e),
|
||||
style = MaterialTheme.typography.labelLarge
|
||||
)
|
||||
}
|
||||
|
||||
Divider(
|
||||
color = MaterialTheme.colorScheme.outline, modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.width(1.dp)
|
||||
)
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.background(if (site) MaterialTheme.colorScheme.secondaryContainer else MaterialTheme.colorScheme.surface)
|
||||
.clickable { site = true }
|
||||
.size(100.dp, 40.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.site_ex),
|
||||
style = MaterialTheme.typography.labelLarge
|
||||
)
|
||||
}
|
||||
}
|
||||
// Dummy impl end
|
||||
|
||||
Text(
|
||||
text = stringResource(id = R.string.select_scene_explain),
|
||||
modifier = Modifier.padding(top = 16.dp)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 12.dp)
|
||||
.padding(top = 4.dp, bottom = 20.dp)
|
||||
.fillMaxWidth()
|
||||
) {
|
||||
Button(onClick = {
|
||||
Settings.putSelectSite(false)
|
||||
Settings.putNeedSignIn(false)
|
||||
if (!site)
|
||||
Settings.putGallerySite(EhUrl.SITE_E)
|
||||
else
|
||||
Settings.putGallerySite(EhUrl.SITE_EX)
|
||||
GlobalScope.launchIO {
|
||||
getProfile()
|
||||
}
|
||||
finish()
|
||||
}, Modifier.fillMaxWidth()) {
|
||||
Text(text = stringResource(id = android.R.string.ok))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getProfile() {
|
||||
runCatching {
|
||||
(EhClient.execute(EhClient.METHOD_GET_PROFILE) as ProfileParser.Result).run {
|
||||
Settings.putDisplayName(displayName)
|
||||
Settings.putAvatar(avatar)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,300 @@
|
||||
package com.hippo.ehviewer.ui.compose
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.widthIn
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Info
|
||||
import androidx.compose.material.icons.filled.Visibility
|
||||
import androidx.compose.material.icons.filled.VisibilityOff
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.res.dimensionResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||
import androidx.compose.ui.text.input.VisualTransformation
|
||||
import androidx.compose.ui.text.style.TextDecoration
|
||||
import androidx.compose.ui.text.withStyle
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavController
|
||||
import com.hippo.ehviewer.R
|
||||
import com.hippo.ehviewer.Settings
|
||||
import com.hippo.ehviewer.UrlOpener
|
||||
import com.hippo.ehviewer.client.EhClient
|
||||
import com.hippo.ehviewer.client.EhUrl
|
||||
import com.hippo.ehviewer.client.EhUtils
|
||||
import com.hippo.ehviewer.ui.LoginActivity.Companion.COOKIE_SIGN_IN_ROUTE_NAME
|
||||
import com.hippo.ehviewer.ui.LoginActivity.Companion.SELECT_SITE_ROUTE_NAME
|
||||
import com.hippo.ehviewer.ui.LoginActivity.Companion.WEBVIEW_SIGN_IN_ROUTE_NAME
|
||||
import com.hippo.util.ExceptionUtils
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import eu.kanade.tachiyomi.util.lang.withUIContext
|
||||
import kotlinx.coroutines.Job
|
||||
import rikka.core.util.ContextUtils.requireActivity
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun SignInScreen(navController: NavController) {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val focusManager = LocalFocusManager.current
|
||||
var isProgressIndicatorVisible by rememberSaveable { mutableStateOf(false) }
|
||||
var showUsernameError by rememberSaveable { mutableStateOf(false) }
|
||||
var showPasswordError by rememberSaveable { mutableStateOf(false) }
|
||||
var showErrorDialog by rememberSaveable { mutableStateOf(false) }
|
||||
var loginErrorException by remember { mutableStateOf<Throwable?>(null) }
|
||||
var username by rememberSaveable { mutableStateOf("") }
|
||||
var password by rememberSaveable { mutableStateOf("") }
|
||||
var passwordHidden by rememberSaveable { mutableStateOf(true) }
|
||||
val context = LocalContext.current
|
||||
var signInJob by remember { mutableStateOf<Job?>(null) }
|
||||
|
||||
// Basic login request
|
||||
fun signIn() {
|
||||
if (signInJob?.isActive == true) return
|
||||
if (username.isEmpty()) {
|
||||
showUsernameError = true
|
||||
return
|
||||
} else {
|
||||
showUsernameError = false
|
||||
}
|
||||
if (password.isEmpty()) {
|
||||
showPasswordError = true
|
||||
return
|
||||
} else {
|
||||
showPasswordError = false
|
||||
}
|
||||
focusManager.clearFocus()
|
||||
isProgressIndicatorVisible = true
|
||||
|
||||
EhUtils.signOut()
|
||||
signInJob = coroutineScope.launchIO {
|
||||
runCatching {
|
||||
(EhClient.execute(EhClient.METHOD_SIGN_IN, username, password) as String).let {
|
||||
Settings.putDisplayName(it)
|
||||
}
|
||||
}.onFailure {
|
||||
it.printStackTrace()
|
||||
withUIContext {
|
||||
focusManager.clearFocus()
|
||||
isProgressIndicatorVisible = false
|
||||
loginErrorException = it
|
||||
showErrorDialog = true
|
||||
}
|
||||
}.onSuccess {
|
||||
withUIContext {
|
||||
navController.navigate(SELECT_SITE_ROUTE_NAME)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Box(
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Column(
|
||||
Modifier
|
||||
.padding(dimensionResource(id = R.dimen.keyline_margin))
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState()),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.ic_launcher_foreground),
|
||||
contentDescription = null,
|
||||
Modifier.padding(dimensionResource(id = R.dimen.keyline_margin))
|
||||
)
|
||||
|
||||
OutlinedTextField(
|
||||
value = username,
|
||||
onValueChange = { username = it },
|
||||
Modifier.width(dimensionResource(id = R.dimen.single_max_width)),
|
||||
label = { Text(stringResource(R.string.username)) },
|
||||
supportingText = { if (showUsernameError) Text(stringResource(R.string.error_username_cannot_empty)) },
|
||||
trailingIcon = {
|
||||
if (showUsernameError) Icon(
|
||||
imageVector = Icons.Filled.Info,
|
||||
contentDescription = null
|
||||
)
|
||||
},
|
||||
keyboardOptions = KeyboardOptions(
|
||||
imeAction = ImeAction.Next
|
||||
),
|
||||
singleLine = true,
|
||||
isError = showUsernameError
|
||||
)
|
||||
|
||||
OutlinedTextField(
|
||||
value = password,
|
||||
onValueChange = { password = it },
|
||||
Modifier.width(dimensionResource(id = R.dimen.single_max_width)),
|
||||
label = { Text(stringResource(R.string.password)) },
|
||||
visualTransformation = if (passwordHidden) PasswordVisualTransformation() else VisualTransformation.None,
|
||||
supportingText = { if (showPasswordError) Text(stringResource(R.string.error_password_cannot_empty)) },
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
|
||||
keyboardActions = KeyboardActions(
|
||||
onDone = { signIn() }
|
||||
),
|
||||
trailingIcon = {
|
||||
if (showPasswordError)
|
||||
Icon(imageVector = Icons.Filled.Info, contentDescription = null)
|
||||
else
|
||||
IconButton(onClick = { passwordHidden = !passwordHidden }) {
|
||||
val visibilityIcon =
|
||||
if (passwordHidden) Icons.Filled.Visibility else Icons.Filled.VisibilityOff
|
||||
Icon(imageVector = visibilityIcon, contentDescription = null)
|
||||
}
|
||||
},
|
||||
singleLine = true,
|
||||
isError = showPasswordError
|
||||
)
|
||||
|
||||
Text(
|
||||
text = stringResource(id = R.string.app_waring),
|
||||
Modifier
|
||||
.widthIn(max = dimensionResource(id = R.dimen.single_max_width))
|
||||
.padding(top = 24.dp),
|
||||
style = MaterialTheme.typography.labelLarge
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
Row {
|
||||
OutlinedButton(
|
||||
onClick = {
|
||||
UrlOpener.openUrl(
|
||||
requireActivity(context),
|
||||
EhUrl.URL_REGISTER,
|
||||
false
|
||||
)
|
||||
},
|
||||
Modifier
|
||||
.weight(1f)
|
||||
.padding(horizontal = 4.dp)
|
||||
) {
|
||||
Text(text = stringResource(id = R.string.register))
|
||||
}
|
||||
|
||||
Button(
|
||||
onClick = { signIn() },
|
||||
Modifier
|
||||
.weight(1f)
|
||||
.padding(horizontal = 4.dp)
|
||||
) {
|
||||
Text(text = stringResource(id = R.string.sign_in))
|
||||
}
|
||||
}
|
||||
|
||||
Row(
|
||||
Modifier.padding(horizontal = 4.dp)
|
||||
) {
|
||||
TextButton(
|
||||
onClick = { navController.navigate(WEBVIEW_SIGN_IN_ROUTE_NAME) },
|
||||
Modifier.padding(horizontal = 8.dp)
|
||||
) {
|
||||
Text(
|
||||
text = buildAnnotatedString {
|
||||
withStyle(
|
||||
style = SpanStyle(textDecoration = TextDecoration.Underline)
|
||||
) {
|
||||
append(stringResource(id = R.string.sign_in_via_webview))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
TextButton(
|
||||
onClick = { navController.navigate(COOKIE_SIGN_IN_ROUTE_NAME) },
|
||||
Modifier.padding(horizontal = 8.dp)
|
||||
) {
|
||||
Text(
|
||||
text = buildAnnotatedString {
|
||||
withStyle(
|
||||
style = SpanStyle(textDecoration = TextDecoration.Underline)
|
||||
) {
|
||||
append(stringResource(id = R.string.sign_in_via_cookies))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
TextButton(
|
||||
onClick = { navController.navigate(SELECT_SITE_ROUTE_NAME) },
|
||||
) {
|
||||
Text(
|
||||
text = buildAnnotatedString {
|
||||
withStyle(
|
||||
style = SpanStyle(textDecoration = TextDecoration.Underline)
|
||||
) {
|
||||
append(stringResource(id = R.string.tourist_mode))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
if (isProgressIndicatorVisible) {
|
||||
CircularProgressIndicator()
|
||||
}
|
||||
if (showErrorDialog) {
|
||||
AlertDialog(
|
||||
onDismissRequest = {
|
||||
showErrorDialog = false
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(onClick = {
|
||||
showErrorDialog = false
|
||||
}) {
|
||||
Text(text = stringResource(id = R.string.get_it))
|
||||
}
|
||||
},
|
||||
title = {
|
||||
Text(text = stringResource(id = R.string.sign_in_failed))
|
||||
},
|
||||
text = {
|
||||
Text(
|
||||
text =
|
||||
"""
|
||||
${ExceptionUtils.getReadableString(loginErrorException!!)}
|
||||
${stringResource(R.string.sign_in_failed_tip)}
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package com.hippo.ehviewer.ui.compose
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.graphics.Color
|
||||
import android.view.ViewGroup
|
||||
import android.webkit.CookieManager
|
||||
import android.webkit.WebView
|
||||
import android.webkit.WebViewClient
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.navigation.NavController
|
||||
import com.hippo.ehviewer.EhApplication
|
||||
import com.hippo.ehviewer.client.EhCookieStore
|
||||
import com.hippo.ehviewer.client.EhUrl
|
||||
import com.hippo.ehviewer.client.EhUtils
|
||||
import com.hippo.ehviewer.ui.LoginActivity.Companion.SELECT_SITE_ROUTE_NAME
|
||||
import com.hippo.ehviewer.widget.DialogWebChromeClient
|
||||
import okhttp3.Cookie
|
||||
import okhttp3.HttpUrl
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
@Composable
|
||||
fun WebviewSignInScreen(navController: NavController) {
|
||||
val context = LocalContext.current
|
||||
AndroidView(factory = {
|
||||
EhUtils.signOut()
|
||||
|
||||
// http://stackoverflow.com/questions/32284642/how-to-handle-an-uncatched-exception
|
||||
CookieManager.getInstance().apply {
|
||||
flush()
|
||||
removeAllCookies(null)
|
||||
removeSessionCookies(null)
|
||||
}
|
||||
WebView(context).apply {
|
||||
layoutParams = ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
setBackgroundColor(Color.TRANSPARENT)
|
||||
settings.run {
|
||||
builtInZoomControls = true
|
||||
displayZoomControls = true
|
||||
javaScriptEnabled = true
|
||||
}
|
||||
webViewClient = object : WebViewClient() {
|
||||
private var present = false
|
||||
fun parseCookies(url: HttpUrl?, cookieStrings: String?): List<Cookie> {
|
||||
if (cookieStrings == null) {
|
||||
return emptyList()
|
||||
}
|
||||
var cookies: MutableList<Cookie>? = null
|
||||
val pieces =
|
||||
cookieStrings.split(";".toRegex()).dropLastWhile { it.isEmpty() }
|
||||
.toTypedArray()
|
||||
for (piece in pieces) {
|
||||
val cookie = Cookie.parse(url!!, piece) ?: continue
|
||||
if (cookies == null) {
|
||||
cookies = ArrayList()
|
||||
}
|
||||
cookies.add(cookie)
|
||||
}
|
||||
return cookies ?: emptyList()
|
||||
}
|
||||
|
||||
fun addCookie(domain: String, cookie: Cookie) {
|
||||
EhApplication.ehCookieStore.addCookie(
|
||||
EhCookieStore.newCookie(
|
||||
cookie,
|
||||
domain,
|
||||
true,
|
||||
true,
|
||||
true
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun onPageFinished(view: WebView, url: String) {
|
||||
if (present) {
|
||||
view.destroy()
|
||||
return
|
||||
}
|
||||
val httpUrl = url.toHttpUrlOrNull() ?: return
|
||||
val cookieString = CookieManager.getInstance().getCookie(EhUrl.HOST_E)
|
||||
val cookies = parseCookies(httpUrl, cookieString)
|
||||
var getId = false
|
||||
var getHash = false
|
||||
for (cookie in cookies) {
|
||||
if (EhCookieStore.KEY_IPD_MEMBER_ID == cookie.name) {
|
||||
getId = true
|
||||
} else if (EhCookieStore.KEY_IPD_PASS_HASH == cookie.name) {
|
||||
getHash = true
|
||||
}
|
||||
addCookie(EhUrl.DOMAIN_EX, cookie)
|
||||
addCookie(EhUrl.DOMAIN_E, cookie)
|
||||
}
|
||||
if (getId && getHash) {
|
||||
present = true
|
||||
navController.navigate(SELECT_SITE_ROUTE_NAME)
|
||||
}
|
||||
}
|
||||
}
|
||||
webChromeClient = DialogWebChromeClient(context)
|
||||
loadUrl(EhUrl.URL_SIGN_IN)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,281 +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.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.util.SparseArray;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
|
||||
import androidx.annotation.IdRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.core.view.GravityCompat;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
import androidx.core.view.WindowInsetsControllerCompat;
|
||||
import androidx.drawerlayout.widget.DrawerLayout;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
|
||||
import com.hippo.ehviewer.ui.MainActivity;
|
||||
import com.hippo.scene.SceneFragment;
|
||||
|
||||
public abstract class BaseScene extends SceneFragment {
|
||||
|
||||
public static final int LENGTH_SHORT = 0;
|
||||
public static final int LENGTH_LONG = 1;
|
||||
|
||||
public static final String KEY_DRAWER_VIEW_STATE =
|
||||
"com.hippo.ehviewer.ui.scene.BaseScene:DRAWER_VIEW_STATE";
|
||||
|
||||
private WindowInsetsControllerCompat insetsController;
|
||||
|
||||
@Nullable
|
||||
private View drawerView;
|
||||
@Nullable
|
||||
private SparseArray<Parcelable> drawerViewState;
|
||||
|
||||
public void addAboveSnackView(View view) {
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity instanceof MainActivity) {
|
||||
((MainActivity) activity).addAboveSnackView(view);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeAboveSnackView(View view) {
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity instanceof MainActivity) {
|
||||
((MainActivity) activity).removeAboveSnackView(view);
|
||||
}
|
||||
}
|
||||
|
||||
public void setDrawerLockMode(int lockMode, int edgeGravity) {
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity instanceof MainActivity) {
|
||||
((MainActivity) activity).setDrawerLockMode(lockMode, edgeGravity);
|
||||
}
|
||||
}
|
||||
|
||||
public Integer getDrawerLockMode(int edgeGravity) {
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity instanceof MainActivity) {
|
||||
return ((MainActivity) activity).getDrawerLockMode(edgeGravity);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void openDrawer(int drawerGravity) {
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity instanceof MainActivity) {
|
||||
((MainActivity) activity).openDrawer(drawerGravity);
|
||||
}
|
||||
}
|
||||
|
||||
public void closeDrawer(int drawerGravity) {
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity instanceof MainActivity) {
|
||||
((MainActivity) activity).closeDrawer(drawerGravity);
|
||||
}
|
||||
}
|
||||
|
||||
public void toggleDrawer(int drawerGravity) {
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity instanceof MainActivity) {
|
||||
((MainActivity) activity).toggleDrawer(drawerGravity);
|
||||
}
|
||||
}
|
||||
|
||||
public void showTip(CharSequence message, int length) {
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity instanceof MainActivity) {
|
||||
((MainActivity) activity).showTip(message, length);
|
||||
}
|
||||
}
|
||||
|
||||
public void showTip(@StringRes int id, int length) {
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity instanceof MainActivity) {
|
||||
((MainActivity) activity).showTip(id, length);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean needShowLeftDrawer() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public int getNavCheckedItem() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param resId 0 for clear
|
||||
*/
|
||||
public void setNavCheckedItem(@IdRes int resId) {
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity instanceof MainActivity) {
|
||||
((MainActivity) activity).setNavCheckedItem(resId);
|
||||
}
|
||||
}
|
||||
|
||||
public void recreateDrawerView() {
|
||||
MainActivity activity = getMainActivity();
|
||||
if (activity != null) {
|
||||
activity.createDrawerView(this);
|
||||
}
|
||||
}
|
||||
|
||||
public final View createDrawerView(LayoutInflater inflater,
|
||||
@Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
drawerView = onCreateDrawerView(inflater, container, savedInstanceState);
|
||||
|
||||
if (drawerView != null) {
|
||||
SparseArray<Parcelable> saved = drawerViewState;
|
||||
if (saved == null && savedInstanceState != null) {
|
||||
saved = savedInstanceState.getSparseParcelableArray(KEY_DRAWER_VIEW_STATE);
|
||||
}
|
||||
if (saved != null) {
|
||||
drawerView.restoreHierarchyState(saved);
|
||||
}
|
||||
}
|
||||
|
||||
return drawerView;
|
||||
}
|
||||
|
||||
public View onCreateDrawerView(LayoutInflater inflater,
|
||||
@Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public final void destroyDrawerView() {
|
||||
if (drawerView != null) {
|
||||
drawerViewState = new SparseArray<>();
|
||||
drawerView.saveHierarchyState(drawerViewState);
|
||||
}
|
||||
|
||||
onDestroyDrawerView();
|
||||
|
||||
drawerView = null;
|
||||
}
|
||||
|
||||
public void onDestroyDrawerView() {
|
||||
}
|
||||
|
||||
@SuppressLint("RtlHardcoded")
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
postponeEnterTransition();
|
||||
view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
|
||||
@Override
|
||||
public boolean onPreDraw() {
|
||||
view.getViewTreeObserver().removeOnPreDrawListener(this);
|
||||
startPostponedEnterTransition();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
// Update left drawer locked state
|
||||
if (needShowLeftDrawer()) {
|
||||
setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, GravityCompat.START);
|
||||
} else {
|
||||
setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, GravityCompat.START);
|
||||
}
|
||||
|
||||
// Update nav checked item
|
||||
setNavCheckedItem(getNavCheckedItem());
|
||||
|
||||
// Hide soft ime
|
||||
hideSoftInput();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Resources getResourcesOrNull() {
|
||||
Context context = getContext();
|
||||
if (context != null) {
|
||||
return context.getResources();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public MainActivity getMainActivity() {
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity instanceof MainActivity) {
|
||||
return (MainActivity) activity;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void hideSoftInput() {
|
||||
var insetsController = getInsetsController();
|
||||
if (insetsController != null) {
|
||||
insetsController.hide(WindowInsetsCompat.Type.ime());
|
||||
}
|
||||
}
|
||||
|
||||
public void showSoftInput(@Nullable View view) {
|
||||
if (view != null) {
|
||||
view.requestFocus();
|
||||
view.post(() -> {
|
||||
var insetsController = getInsetsController();
|
||||
if (insetsController != null) {
|
||||
insetsController.show(WindowInsetsCompat.Type.ime());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public WindowInsetsControllerCompat getInsetsController() {
|
||||
if (insetsController == null) {
|
||||
var activity = getActivity();
|
||||
if (activity != null) {
|
||||
insetsController = ViewCompat.getWindowInsetsController(activity.getWindow().getDecorView());
|
||||
}
|
||||
}
|
||||
return insetsController;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
insetsController = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
|
||||
if (drawerView != null) {
|
||||
drawerViewState = new SparseArray<>();
|
||||
drawerView.saveHierarchyState(drawerViewState);
|
||||
outState.putSparseParcelableArray(KEY_DRAWER_VIEW_STATE, drawerViewState);
|
||||
}
|
||||
}
|
||||
|
||||
public Resources.Theme getTheme() {
|
||||
return requireActivity().getTheme();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
* 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.annotation.SuppressLint
|
||||
import android.content.res.Resources
|
||||
import android.content.res.Resources.Theme
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.util.SparseArray
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.core.view.GravityCompat
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.WindowInsetsControllerCompat
|
||||
import androidx.drawerlayout.widget.DrawerLayout
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.navigation.NavOptions
|
||||
import androidx.navigation.fragment.NavHostFragment
|
||||
import com.hippo.ehviewer.R
|
||||
import com.hippo.ehviewer.ui.MainActivity
|
||||
import rikka.core.res.resolveDrawable
|
||||
|
||||
abstract class BaseScene : Fragment() {
|
||||
private var insetsController: WindowInsetsControllerCompat? = null
|
||||
private var drawerView: View? = null
|
||||
private var drawerViewState: SparseArray<Parcelable?>? = null
|
||||
fun addAboveSnackView(view: View?) {
|
||||
val activity = activity
|
||||
if (activity is MainActivity) {
|
||||
activity.addAboveSnackView(view)
|
||||
}
|
||||
}
|
||||
|
||||
fun removeAboveSnackView(view: View?) {
|
||||
val activity = activity
|
||||
if (activity is MainActivity) {
|
||||
activity.removeAboveSnackView(view)
|
||||
}
|
||||
}
|
||||
|
||||
fun setDrawerLockMode(lockMode: Int, edgeGravity: Int) {
|
||||
val activity = activity
|
||||
if (activity is MainActivity) {
|
||||
activity.setDrawerLockMode(lockMode, edgeGravity)
|
||||
}
|
||||
}
|
||||
|
||||
fun getDrawerLockMode(edgeGravity: Int): Int? {
|
||||
val activity = activity
|
||||
return if (activity is MainActivity) {
|
||||
activity.getDrawerLockMode(edgeGravity)
|
||||
} else null
|
||||
}
|
||||
|
||||
fun openDrawer(drawerGravity: Int) {
|
||||
val activity = activity
|
||||
if (activity is MainActivity) {
|
||||
activity.openDrawer(drawerGravity)
|
||||
}
|
||||
}
|
||||
|
||||
fun closeDrawer(drawerGravity: Int) {
|
||||
val activity = activity
|
||||
if (activity is MainActivity) {
|
||||
activity.closeDrawer(drawerGravity)
|
||||
}
|
||||
}
|
||||
|
||||
fun toggleDrawer(drawerGravity: Int) {
|
||||
val activity = activity
|
||||
if (activity is MainActivity) {
|
||||
activity.toggleDrawer(drawerGravity)
|
||||
}
|
||||
}
|
||||
|
||||
fun showTip(message: CharSequence?, length: Int) {
|
||||
val activity = activity
|
||||
if (activity is MainActivity) {
|
||||
activity.showTip(message!!, length)
|
||||
}
|
||||
}
|
||||
|
||||
fun showTip(@StringRes id: Int, length: Int) {
|
||||
val activity = activity
|
||||
if (activity is MainActivity) {
|
||||
activity.showTip(id, length)
|
||||
}
|
||||
}
|
||||
|
||||
open fun needShowLeftDrawer(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
fun recreateDrawerView() {
|
||||
val activity = mainActivity
|
||||
activity?.createDrawerView(this)
|
||||
}
|
||||
|
||||
fun createDrawerView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?, savedInstanceState: Bundle?
|
||||
): View? {
|
||||
drawerView = onCreateDrawerView(inflater, container, savedInstanceState)
|
||||
if (drawerView != null) {
|
||||
var saved = drawerViewState
|
||||
if (saved == null && savedInstanceState != null) {
|
||||
saved = savedInstanceState.getSparseParcelableArray(KEY_DRAWER_VIEW_STATE)
|
||||
}
|
||||
if (saved != null) {
|
||||
drawerView!!.restoreHierarchyState(saved)
|
||||
}
|
||||
}
|
||||
return drawerView
|
||||
}
|
||||
|
||||
open fun onCreateDrawerView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?, savedInstanceState: Bundle?
|
||||
): View? {
|
||||
return null
|
||||
}
|
||||
|
||||
private fun destroyDrawerView() {
|
||||
if (drawerView != null) {
|
||||
drawerViewState = SparseArray()
|
||||
drawerView!!.saveHierarchyState(drawerViewState)
|
||||
}
|
||||
onDestroyDrawerView()
|
||||
drawerView = null
|
||||
}
|
||||
|
||||
open fun onDestroyDrawerView() {}
|
||||
|
||||
@SuppressLint("RtlHardcoded")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
view.background = requireActivity().theme.resolveDrawable(android.R.attr.windowBackground)
|
||||
|
||||
// Update left drawer locked state
|
||||
if (needShowLeftDrawer()) {
|
||||
setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, GravityCompat.START)
|
||||
} else {
|
||||
setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, GravityCompat.START)
|
||||
}
|
||||
|
||||
// Hide soft ime
|
||||
hideSoftInput()
|
||||
mainActivity!!.createDrawerView(this)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
destroyDrawerView()
|
||||
}
|
||||
|
||||
val resourcesOrNull: Resources?
|
||||
get() {
|
||||
val context = context
|
||||
return context?.resources
|
||||
}
|
||||
val mainActivity: MainActivity?
|
||||
get() {
|
||||
val activity = activity
|
||||
return if (activity is MainActivity) {
|
||||
activity
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun hideSoftInput() {
|
||||
val insetsController = getInsetsController()
|
||||
insetsController?.hide(WindowInsetsCompat.Type.ime())
|
||||
}
|
||||
|
||||
fun showSoftInput(view: View?) {
|
||||
if (view != null) {
|
||||
view.requestFocus()
|
||||
view.post(Runnable {
|
||||
val insetsController = getInsetsController()
|
||||
insetsController?.show(WindowInsetsCompat.Type.ime())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun getInsetsController(): WindowInsetsControllerCompat? {
|
||||
if (insetsController == null) {
|
||||
val activity = activity
|
||||
if (activity != null) {
|
||||
insetsController = ViewCompat.getWindowInsetsController(activity.window.decorView)
|
||||
}
|
||||
}
|
||||
return insetsController
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
insetsController = null
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
if (drawerView != null) {
|
||||
drawerViewState = SparseArray()
|
||||
drawerView!!.saveHierarchyState(drawerViewState)
|
||||
outState.putSparseParcelableArray(KEY_DRAWER_VIEW_STATE, drawerViewState)
|
||||
}
|
||||
}
|
||||
|
||||
val theme: Theme
|
||||
get() = requireActivity().theme
|
||||
|
||||
@JvmOverloads
|
||||
fun navigate(id: Int, args: Bundle?, singleTop: Boolean = false) {
|
||||
val options: NavOptions = NavOptions.Builder().setLaunchSingleTop(singleTop)
|
||||
.setEnterAnim(R.anim.scene_open_enter).setExitAnim(R.anim.scene_open_exit)
|
||||
.setPopEnterAnim(R.anim.scene_close_enter).setPopExitAnim(R.anim.scene_close_exit)
|
||||
.build()
|
||||
NavHostFragment.findNavController(this).navigate(id, args, options)
|
||||
}
|
||||
|
||||
fun navigateToTop() {
|
||||
val navController = NavHostFragment.findNavController(this)
|
||||
val id = navController.graph.startDestinationId
|
||||
val options: NavOptions = NavOptions.Builder()
|
||||
.setEnterAnim(R.anim.scene_open_enter).setExitAnim(R.anim.scene_open_exit)
|
||||
.setPopEnterAnim(R.anim.scene_close_enter).setPopExitAnim(R.anim.scene_close_exit)
|
||||
.setPopUpTo(id, true)
|
||||
.build()
|
||||
navController.navigate(id, null, options)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val LENGTH_SHORT = 0
|
||||
const val LENGTH_LONG = 1
|
||||
const val KEY_DRAWER_VIEW_STATE = "com.hippo.ehviewer.ui.scene.BaseScene:DRAWER_VIEW_STATE"
|
||||
}
|
||||
}
|
||||
@@ -1,305 +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.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Paint;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.google.android.material.textfield.TextInputLayout;
|
||||
import com.hippo.app.BaseDialogBuilder;
|
||||
import com.hippo.ehviewer.EhApplication;
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.ehviewer.client.EhClient;
|
||||
import com.hippo.ehviewer.client.EhCookieStore;
|
||||
import com.hippo.ehviewer.client.EhRequest;
|
||||
import com.hippo.ehviewer.client.EhUrl;
|
||||
import com.hippo.ehviewer.client.EhUtils;
|
||||
import com.hippo.util.ClipboardUtilKt;
|
||||
import com.hippo.util.ExceptionUtils;
|
||||
import com.hippo.yorozuya.AssertUtils;
|
||||
import com.hippo.yorozuya.ViewUtils;
|
||||
|
||||
import okhttp3.Cookie;
|
||||
|
||||
public class CookieSignInScene extends SolidScene implements EditText.OnEditorActionListener,
|
||||
View.OnClickListener {
|
||||
|
||||
/*---------------
|
||||
View life cycle
|
||||
---------------*/
|
||||
@Nullable
|
||||
private TextInputLayout mIpbMemberIdLayout;
|
||||
@Nullable
|
||||
private TextInputLayout mIpbPassHashLayout;
|
||||
@Nullable
|
||||
private TextInputLayout mIgneousLayout;
|
||||
@Nullable
|
||||
private EditText mIpbMemberId;
|
||||
@Nullable
|
||||
private EditText mIpbPassHash;
|
||||
@Nullable
|
||||
private EditText mIgneous;
|
||||
@Nullable
|
||||
private View mOk;
|
||||
@Nullable
|
||||
private TextView mFromClipboard;
|
||||
|
||||
private static Cookie newCookie(String name, String value, String domain) {
|
||||
return new Cookie.Builder().name(name).value(value)
|
||||
.domain(domain).expiresAt(Long.MAX_VALUE).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needShowLeftDrawer() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||
@Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.scene_cookie_sign_in, container, false);
|
||||
mIpbMemberIdLayout = (TextInputLayout) ViewUtils.$$(view, R.id.ipb_member_id_layout);
|
||||
mIpbMemberId = mIpbMemberIdLayout.getEditText();
|
||||
AssertUtils.assertNotNull(mIpbMemberId);
|
||||
mIpbPassHashLayout = (TextInputLayout) ViewUtils.$$(view, R.id.ipb_pass_hash_layout);
|
||||
mIpbPassHash = mIpbPassHashLayout.getEditText();
|
||||
AssertUtils.assertNotNull(mIpbPassHash);
|
||||
mIgneousLayout = (TextInputLayout) ViewUtils.$$(view, R.id.igneous_layout);
|
||||
mIgneous = mIgneousLayout.getEditText();
|
||||
AssertUtils.assertNotNull(mIgneous);
|
||||
mOk = ViewUtils.$$(view, R.id.ok);
|
||||
mFromClipboard = (TextView) ViewUtils.$$(view, R.id.from_clipboard);
|
||||
|
||||
mFromClipboard.setPaintFlags(mFromClipboard.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG);
|
||||
|
||||
mIpbPassHash.setOnEditorActionListener(this);
|
||||
|
||||
mOk.setOnClickListener(this);
|
||||
mFromClipboard.setOnClickListener(this);
|
||||
|
||||
// Try to get old version cookie info
|
||||
Context context = getContext();
|
||||
AssertUtils.assertNotNull(context);
|
||||
SharedPreferences sharedPreferences = context.getSharedPreferences("eh_info", 0);
|
||||
String ipbMemberId = sharedPreferences.getString("ipb_member_id", null);
|
||||
String ipbPassHash = sharedPreferences.getString("ipb_pass_hash", null);
|
||||
String igneous = sharedPreferences.getString("igneous", null);
|
||||
boolean getIt = false;
|
||||
if (!TextUtils.isEmpty(ipbMemberId)) {
|
||||
mIpbMemberId.setText(ipbMemberId);
|
||||
getIt = true;
|
||||
}
|
||||
if (!TextUtils.isEmpty(ipbPassHash)) {
|
||||
mIpbPassHash.setText(ipbPassHash);
|
||||
getIt = true;
|
||||
}
|
||||
if (!TextUtils.isEmpty(igneous)) {
|
||||
mIgneous.setText(igneous);
|
||||
getIt = true;
|
||||
}
|
||||
if (getIt) {
|
||||
showTip(R.string.found_cookies, LENGTH_SHORT);
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
showSoftInput(mIpbMemberId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
|
||||
mIpbMemberIdLayout = null;
|
||||
mIpbPassHashLayout = null;
|
||||
mIgneousLayout = null;
|
||||
mIpbMemberId = null;
|
||||
mIpbPassHash = null;
|
||||
mIgneous = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (mOk == v) {
|
||||
enter();
|
||||
} else if (mFromClipboard == v) {
|
||||
fillCookiesFromClipboard();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
||||
if (mIpbPassHash == v) {
|
||||
enter();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void enter() {
|
||||
Context context = getContext();
|
||||
if (null == context || null == mIpbMemberIdLayout || null == mIpbPassHashLayout ||
|
||||
null == mIgneousLayout || null == mIpbMemberId || null == mIpbPassHash ||
|
||||
null == mIgneous) {
|
||||
return;
|
||||
}
|
||||
|
||||
final String ipbMemberId = mIpbMemberId.getText().toString().trim();
|
||||
final String ipbPassHash = mIpbPassHash.getText().toString().trim();
|
||||
final String igneous = mIgneous.getText().toString().trim();
|
||||
|
||||
if (TextUtils.isEmpty(ipbMemberId)) {
|
||||
mIpbMemberIdLayout.setError(getString(R.string.text_is_empty));
|
||||
return;
|
||||
} else {
|
||||
mIpbMemberIdLayout.setError(null);
|
||||
}
|
||||
if (TextUtils.isEmpty(ipbPassHash)) {
|
||||
mIpbPassHashLayout.setError(getString(R.string.text_is_empty));
|
||||
return;
|
||||
} else {
|
||||
mIpbPassHashLayout.setError(null);
|
||||
}
|
||||
|
||||
hideSoftInput();
|
||||
|
||||
storeCookie(ipbMemberId, ipbPassHash, igneous);
|
||||
|
||||
EhRequest request = new EhRequest()
|
||||
.setMethod(EhClient.METHOD_GET_PROFILE)
|
||||
.setCallback(new CookieSignInListener());
|
||||
request.enqueue(this);
|
||||
}
|
||||
|
||||
private void storeCookie(String id, String hash, String igneous) {
|
||||
Context context = getContext();
|
||||
if (null == context) {
|
||||
return;
|
||||
}
|
||||
|
||||
EhUtils.signOut();
|
||||
|
||||
EhCookieStore store = EhApplication.getEhCookieStore();
|
||||
store.addCookie(newCookie(EhCookieStore.KEY_IPD_MEMBER_ID, id, EhUrl.DOMAIN_E));
|
||||
store.addCookie(newCookie(EhCookieStore.KEY_IPD_MEMBER_ID, id, EhUrl.DOMAIN_EX));
|
||||
store.addCookie(newCookie(EhCookieStore.KEY_IPD_PASS_HASH, hash, EhUrl.DOMAIN_E));
|
||||
store.addCookie(newCookie(EhCookieStore.KEY_IPD_PASS_HASH, hash, EhUrl.DOMAIN_EX));
|
||||
if (!igneous.isEmpty()) {
|
||||
store.addCookie(newCookie(EhCookieStore.KEY_IGNEOUS, igneous, EhUrl.DOMAIN_E));
|
||||
store.addCookie(newCookie(EhCookieStore.KEY_IGNEOUS, igneous, EhUrl.DOMAIN_EX));
|
||||
}
|
||||
}
|
||||
|
||||
private void fillCookiesFromClipboard() {
|
||||
Context context = requireContext();
|
||||
|
||||
hideSoftInput();
|
||||
String text = ClipboardUtilKt.getTextFromClipboard(
|
||||
ClipboardUtilKt.getClipboardManager(context), context);
|
||||
if (text == null) {
|
||||
showTip(R.string.from_clipboard_error, LENGTH_SHORT);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
String[] kvs;
|
||||
if (text.contains(";")) {
|
||||
kvs = text.split(";");
|
||||
} else if (text.contains("\n")) {
|
||||
kvs = text.split("\n");
|
||||
} else {
|
||||
showTip(R.string.from_clipboard_error, LENGTH_SHORT);
|
||||
return;
|
||||
}
|
||||
if (kvs.length < 3) {
|
||||
showTip(R.string.from_clipboard_error, LENGTH_SHORT);
|
||||
return;
|
||||
}
|
||||
for (String s : kvs) {
|
||||
String[] kv;
|
||||
if (s.contains("=")) {
|
||||
kv = s.split("=");
|
||||
} else if (s.contains(":")) {
|
||||
kv = s.split(":");
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
if (kv.length != 2) {
|
||||
continue;
|
||||
}
|
||||
switch (kv[0].trim().toLowerCase()) {
|
||||
case "ipb_member_id":
|
||||
if (mIpbMemberId != null) {
|
||||
mIpbMemberId.setText(kv[1].trim());
|
||||
}
|
||||
break;
|
||||
case "ipb_pass_hash":
|
||||
if (mIpbPassHash != null) {
|
||||
mIpbPassHash.setText(kv[1].trim());
|
||||
}
|
||||
break;
|
||||
case "igneous":
|
||||
if (mIgneous != null) {
|
||||
mIgneous.setText(kv[1].trim());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
enter();
|
||||
} catch (Exception e) {
|
||||
ExceptionUtils.throwIfFatal(e);
|
||||
e.printStackTrace();
|
||||
showTip(R.string.from_clipboard_error, LENGTH_SHORT);
|
||||
}
|
||||
}
|
||||
|
||||
private class CookieSignInListener implements EhClient.Callback<Object> {
|
||||
@Override
|
||||
public void onSuccess(Object result) {
|
||||
setResult(RESULT_OK, null);
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
EhApplication.getEhCookieStore().signOut();
|
||||
new BaseDialogBuilder(requireContext()).setTitle(R.string.sign_in_failed)
|
||||
.setMessage(ExceptionUtils.getReadableString(e) + "\n\n" + getString(R.string.wrong_cookie_warning))
|
||||
.setPositiveButton(R.string.get_it, null).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
EhApplication.getEhCookieStore().signOut();
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -20,29 +20,23 @@ import android.content.Context;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.hippo.ehviewer.EhApplication;
|
||||
import com.hippo.ehviewer.client.EhClient;
|
||||
import com.hippo.ehviewer.ui.EhActivity;
|
||||
import com.hippo.ehviewer.ui.MainActivity;
|
||||
import com.hippo.scene.SceneFragment;
|
||||
import com.hippo.scene.StageActivity;
|
||||
|
||||
public abstract class EhCallback<E extends SceneFragment, T> implements EhClient.Callback<T> {
|
||||
public abstract class EhCallback<E extends Fragment, T> implements EhClient.Callback<T> {
|
||||
|
||||
private final EhApplication mApplication;
|
||||
private final int mStageId;
|
||||
private final String mSceneTag;
|
||||
|
||||
public EhCallback(Context context, int stageId, String sceneTag) {
|
||||
public EhCallback(Context context) {
|
||||
mApplication = (EhApplication) context.getApplicationContext();
|
||||
mStageId = stageId;
|
||||
mSceneTag = sceneTag;
|
||||
}
|
||||
|
||||
public abstract boolean isInstance(SceneFragment scene);
|
||||
|
||||
public Context getContent() {
|
||||
Context context = getStageActivity();
|
||||
Context context = mApplication.getTopActivity();
|
||||
if (context == null) {
|
||||
context = getApplication();
|
||||
}
|
||||
@@ -53,26 +47,8 @@ public abstract class EhCallback<E extends SceneFragment, T> implements EhClient
|
||||
return mApplication;
|
||||
}
|
||||
|
||||
public StageActivity getStageActivity() {
|
||||
return mApplication.findStageActivityById(mStageId);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public E getScene() {
|
||||
StageActivity stage = mApplication.findStageActivityById(mStageId);
|
||||
if (stage == null) {
|
||||
return null;
|
||||
}
|
||||
SceneFragment scene = stage.findSceneByTag(mSceneTag);
|
||||
if (isInstance(scene)) {
|
||||
return (E) scene;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void showTip(@StringRes int id, int length) {
|
||||
StageActivity activity = getStageActivity();
|
||||
EhActivity activity = mApplication.getTopActivity();
|
||||
if (activity instanceof MainActivity) {
|
||||
((MainActivity) activity).showTip(id, length);
|
||||
} else {
|
||||
@@ -82,7 +58,7 @@ public abstract class EhCallback<E extends SceneFragment, T> implements EhClient
|
||||
}
|
||||
|
||||
public void showTip(String tip, int length) {
|
||||
StageActivity activity = getStageActivity();
|
||||
EhActivity activity = mApplication.getTopActivity();
|
||||
if (activity instanceof MainActivity) {
|
||||
((MainActivity) activity).showTip(tip, length);
|
||||
} else {
|
||||
|
||||
@@ -65,8 +65,6 @@ import com.hippo.ehviewer.ui.annotation.DrawerLifeCircle;
|
||||
import com.hippo.ehviewer.ui.annotation.ViewLifeCircle;
|
||||
import com.hippo.ehviewer.ui.annotation.WholeLifeCircle;
|
||||
import com.hippo.ehviewer.widget.GalleryInfoContentHelper;
|
||||
import com.hippo.scene.Announcer;
|
||||
import com.hippo.scene.SceneFragment;
|
||||
import com.hippo.widget.ContentLayout;
|
||||
import com.hippo.widget.FabLayout;
|
||||
import com.hippo.yorozuya.AssertUtils;
|
||||
@@ -156,11 +154,6 @@ public class FavoritesScene extends SearchBarScene implements
|
||||
// For modify action
|
||||
private boolean mModifyAdd;
|
||||
|
||||
@Override
|
||||
public int getNavCheckedItem() {
|
||||
return R.id.nav_favourite;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@@ -460,8 +453,7 @@ public class FavoritesScene extends SearchBarScene implements
|
||||
Bundle args = new Bundle();
|
||||
args.putString(GalleryDetailScene.KEY_ACTION, GalleryDetailScene.ACTION_GALLERY_INFO);
|
||||
args.putParcelable(GalleryDetailScene.KEY_GALLERY_INFO, gi);
|
||||
Announcer announcer = new Announcer(GalleryDetailScene.class).setArgs(args);
|
||||
startScene(announcer);
|
||||
navigate(R.id.galleryDetailScene, args);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -727,15 +719,26 @@ public class FavoritesScene extends SearchBarScene implements
|
||||
}
|
||||
}
|
||||
|
||||
private static class AddFavoritesListener extends EhCallback<FavoritesScene, Void> {
|
||||
private static class FavDrawerHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private final TextView key;
|
||||
private final TextView value;
|
||||
|
||||
private FavDrawerHolder(View itemView) {
|
||||
super(itemView);
|
||||
key = (TextView) ViewUtils.$$(itemView, R.id.key);
|
||||
value = (TextView) ViewUtils.$$(itemView, R.id.value);
|
||||
}
|
||||
}
|
||||
|
||||
private class AddFavoritesListener extends EhCallback<FavoritesScene, Void> {
|
||||
|
||||
private final int mTaskId;
|
||||
private final String mKeyword;
|
||||
private final List<GalleryInfo> mBackup;
|
||||
|
||||
private AddFavoritesListener(Context context, int stageId,
|
||||
String sceneTag, int taskId, String keyword, List<GalleryInfo> backup) {
|
||||
super(context, stageId, sceneTag);
|
||||
private AddFavoritesListener(Context context, int taskId, String keyword, List<GalleryInfo> backup) {
|
||||
super(context);
|
||||
mTaskId = taskId;
|
||||
mKeyword = keyword;
|
||||
mBackup = backup;
|
||||
@@ -743,10 +746,8 @@ public class FavoritesScene extends SearchBarScene implements
|
||||
|
||||
@Override
|
||||
public void onSuccess(Void result) {
|
||||
FavoritesScene scene = getScene();
|
||||
if (scene != null) {
|
||||
scene.onGetFavoritesLocal(mKeyword, mTaskId);
|
||||
}
|
||||
FavoritesScene scene = FavoritesScene.this;
|
||||
scene.onGetFavoritesLocal(mKeyword, mTaskId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -755,32 +756,24 @@ public class FavoritesScene extends SearchBarScene implements
|
||||
// But how to known which one is failed?
|
||||
EhDB.putLocalFavorites(mBackup);
|
||||
|
||||
FavoritesScene scene = getScene();
|
||||
if (scene != null) {
|
||||
scene.onGetFavoritesLocal(mKeyword, mTaskId);
|
||||
}
|
||||
FavoritesScene scene = FavoritesScene.this;
|
||||
scene.onGetFavoritesLocal(mKeyword, mTaskId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInstance(SceneFragment scene) {
|
||||
return scene instanceof FavoritesScene;
|
||||
}
|
||||
}
|
||||
|
||||
private static class GetFavoritesListener extends EhCallback<FavoritesScene, FavoritesParser.Result> {
|
||||
private class GetFavoritesListener extends EhCallback<FavoritesScene, FavoritesParser.Result> {
|
||||
|
||||
private final int mTaskId;
|
||||
// Local fav is shown now, but operation need be done for cloud fav
|
||||
private final boolean mLocal;
|
||||
private final String mKeyword;
|
||||
|
||||
private GetFavoritesListener(Context context, int stageId,
|
||||
String sceneTag, int taskId, boolean local, String keyword) {
|
||||
super(context, stageId, sceneTag);
|
||||
private GetFavoritesListener(Context context, int taskId, boolean local, String keyword) {
|
||||
super(context);
|
||||
mTaskId = taskId;
|
||||
mLocal = local;
|
||||
mKeyword = keyword;
|
||||
@@ -791,49 +784,28 @@ public class FavoritesScene extends SearchBarScene implements
|
||||
// Put fav cat
|
||||
Settings.putFavCat(result.catArray);
|
||||
Settings.putFavCount(result.countArray);
|
||||
FavoritesScene scene = getScene();
|
||||
if (scene != null) {
|
||||
if (mLocal) {
|
||||
scene.onGetFavoritesLocal(mKeyword, mTaskId);
|
||||
} else {
|
||||
scene.onGetFavoritesSuccess(result, mTaskId);
|
||||
}
|
||||
FavoritesScene scene = FavoritesScene.this;
|
||||
if (mLocal) {
|
||||
scene.onGetFavoritesLocal(mKeyword, mTaskId);
|
||||
} else {
|
||||
scene.onGetFavoritesSuccess(result, mTaskId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
FavoritesScene scene = getScene();
|
||||
if (scene != null) {
|
||||
if (mLocal) {
|
||||
e.printStackTrace();
|
||||
scene.onGetFavoritesLocal(mKeyword, mTaskId);
|
||||
} else {
|
||||
scene.onGetFavoritesFailure(e, mTaskId);
|
||||
}
|
||||
FavoritesScene scene = FavoritesScene.this;
|
||||
if (mLocal) {
|
||||
e.printStackTrace();
|
||||
scene.onGetFavoritesLocal(mKeyword, mTaskId);
|
||||
} else {
|
||||
scene.onGetFavoritesFailure(e, mTaskId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInstance(SceneFragment scene) {
|
||||
return scene instanceof FavoritesScene;
|
||||
}
|
||||
}
|
||||
|
||||
private static class FavDrawerHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private final TextView key;
|
||||
private final TextView value;
|
||||
|
||||
private FavDrawerHolder(View itemView) {
|
||||
super(itemView);
|
||||
key = (TextView) ViewUtils.$$(itemView, R.id.key);
|
||||
value = (TextView) ViewUtils.$$(itemView, R.id.value);
|
||||
}
|
||||
}
|
||||
|
||||
private class FavDrawerAdapter extends RecyclerView.Adapter<FavDrawerHolder> {
|
||||
@@ -905,7 +877,7 @@ public class FavoritesScene extends SearchBarScene implements
|
||||
if (mUrlBuilder.getFavCat() == FavListUrlBuilder.FAV_CAT_LOCAL) { // Delete local fav
|
||||
long[] gidArray = new long[mModifyGiList.size()];
|
||||
for (int i = 0, n = mModifyGiList.size(); i < n; i++) {
|
||||
gidArray[i] = mModifyGiList.get(i).gid;
|
||||
gidArray[i] = mModifyGiList.get(i).getGid();
|
||||
}
|
||||
EhDB.removeLocalFavorites(gidArray);
|
||||
mModifyGiList.clear();
|
||||
@@ -948,7 +920,7 @@ public class FavoritesScene extends SearchBarScene implements
|
||||
if (srcCat == FavListUrlBuilder.FAV_CAT_LOCAL) { // Move from local to cloud
|
||||
long[] gidArray = new long[mModifyGiList.size()];
|
||||
for (int i = 0, n = mModifyGiList.size(); i < n; i++) {
|
||||
gidArray[i] = mModifyGiList.get(i).gid;
|
||||
gidArray[i] = mModifyGiList.get(i).getGid();
|
||||
}
|
||||
EhDB.removeLocalFavorites(gidArray);
|
||||
mEnableModify = true;
|
||||
@@ -1031,22 +1003,20 @@ public class FavoritesScene extends SearchBarScene implements
|
||||
String[] tokenArray = new String[mModifyGiList.size()];
|
||||
for (int i = 0, n = mModifyGiList.size(); i < n; i++) {
|
||||
GalleryInfo gi = mModifyGiList.get(i);
|
||||
gidArray[i] = gi.gid;
|
||||
tokenArray[i] = gi.token;
|
||||
gidArray[i] = gi.getGid();
|
||||
tokenArray[i] = gi.getToken();
|
||||
}
|
||||
List<GalleryInfo> modifyGiListBackup = new ArrayList<>(mModifyGiList);
|
||||
mModifyGiList.clear();
|
||||
|
||||
EhRequest request = new EhRequest();
|
||||
request.setMethod(EhClient.METHOD_ADD_FAVORITES_RANGE);
|
||||
request.setCallback(new AddFavoritesListener(getContext(),
|
||||
activity.getStageId(), getTag(),
|
||||
taskId, mUrlBuilder.getKeyword(), modifyGiListBackup));
|
||||
request.setCallback(new AddFavoritesListener(getContext(), taskId, mUrlBuilder.getKeyword(), modifyGiListBackup));
|
||||
request.setArgs(gidArray, tokenArray, mModifyFavCat);
|
||||
request.enqueue(FavoritesScene.this);
|
||||
} else {
|
||||
for (int i = 0, n = mModifyGiList.size(); i < n; i++) {
|
||||
gidArray[i] = mModifyGiList.get(i).gid;
|
||||
gidArray[i] = mModifyGiList.get(i).getGid();
|
||||
}
|
||||
mModifyGiList.clear();
|
||||
|
||||
@@ -1062,7 +1032,6 @@ public class FavoritesScene extends SearchBarScene implements
|
||||
EhRequest request = new EhRequest();
|
||||
request.setMethod(EhClient.METHOD_MODIFY_FAVORITES);
|
||||
request.setCallback(new GetFavoritesListener(getContext(),
|
||||
activity.getStageId(), getTag(),
|
||||
taskId, local, mUrlBuilder.getKeyword()));
|
||||
request.setArgs(url, gidArray, mModifyFavCat);
|
||||
request.enqueue(FavoritesScene.this);
|
||||
@@ -1077,7 +1046,6 @@ public class FavoritesScene extends SearchBarScene implements
|
||||
EhRequest request = new EhRequest();
|
||||
request.setMethod(EhClient.METHOD_GET_FAVORITES);
|
||||
request.setCallback(new GetFavoritesListener(getContext(),
|
||||
activity.getStageId(), getTag(),
|
||||
taskId, false, mUrlBuilder.getKeyword()));
|
||||
request.setArgs(url);
|
||||
request.enqueue(FavoritesScene.this);
|
||||
@@ -1115,7 +1083,7 @@ public class FavoritesScene extends SearchBarScene implements
|
||||
|
||||
@Override
|
||||
protected boolean isDuplicate(GalleryInfo d1, GalleryInfo d2) {
|
||||
return d1.gid == d2.gid;
|
||||
return d1.getGid() == d2.getGid();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -189,53 +189,53 @@ abstract class GalleryAdapter extends RecyclerView.Adapter<GalleryHolder> {
|
||||
|
||||
switch (mType) {
|
||||
case TYPE_LIST -> {
|
||||
holder.thumb.load(EhCacheKeyFactory.getThumbKey(gi.gid), gi.thumb);
|
||||
holder.thumb.load(EhCacheKeyFactory.getThumbKey(gi.getGid()), gi.getThumb());
|
||||
holder.title.setText(EhUtils.getSuitableTitle(gi));
|
||||
holder.uploader.setText(gi.uploader);
|
||||
holder.uploader.setAlpha(gi.disowned ? .5f : 1f);
|
||||
holder.rating.setRating(gi.rating);
|
||||
holder.uploader.setText(gi.getUploader());
|
||||
holder.uploader.setAlpha(gi.getDisowned() ? .5f : 1f);
|
||||
holder.rating.setRating(gi.getRating());
|
||||
TextView category = holder.category;
|
||||
String newCategoryText = EhUtils.getCategory(gi.category);
|
||||
String newCategoryText = EhUtils.getCategory(gi.getCategory());
|
||||
if (!newCategoryText.equals(category.getText().toString())) {
|
||||
category.setText(newCategoryText);
|
||||
category.setBackgroundColor(EhUtils.getCategoryColor(gi.category));
|
||||
category.setBackgroundColor(EhUtils.getCategoryColor(gi.getCategory()));
|
||||
}
|
||||
holder.posted.setText(gi.posted);
|
||||
if (gi.pages == 0 || !Settings.getShowGalleryPages()) {
|
||||
holder.posted.setText(gi.getPosted());
|
||||
if (gi.getPages() == 0 || !Settings.getShowGalleryPages()) {
|
||||
holder.pages.setText(null);
|
||||
holder.pages.setVisibility(View.GONE);
|
||||
} else {
|
||||
holder.pages.setText(gi.pages + "P");
|
||||
holder.pages.setText(gi.getPages() + "P");
|
||||
holder.pages.setVisibility(View.VISIBLE);
|
||||
}
|
||||
if (TextUtils.isEmpty(gi.simpleLanguage)) {
|
||||
if (TextUtils.isEmpty(gi.getSimpleLanguage())) {
|
||||
holder.simpleLanguage.setText(null);
|
||||
holder.simpleLanguage.setVisibility(View.GONE);
|
||||
} else {
|
||||
holder.simpleLanguage.setText(gi.simpleLanguage);
|
||||
holder.simpleLanguage.setText(gi.getSimpleLanguage());
|
||||
holder.simpleLanguage.setVisibility(View.VISIBLE);
|
||||
}
|
||||
holder.favourited.setVisibility((mShowFavourited && gi.favoriteSlot >= -1 && gi.favoriteSlot <= 10) ? View.VISIBLE : View.GONE);
|
||||
holder.downloaded.setVisibility(mDownloadManager.containDownloadInfo(gi.gid) ? View.VISIBLE : View.GONE);
|
||||
holder.favourited.setVisibility((mShowFavourited && gi.getFavoriteSlot() >= -1 && gi.getFavoriteSlot() <= 10) ? View.VISIBLE : View.GONE);
|
||||
holder.downloaded.setVisibility(mDownloadManager.containDownloadInfo(gi.getGid()) ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
case TYPE_GRID -> {
|
||||
((TileThumb) holder.thumb).setThumbSize(gi.thumbWidth, gi.thumbHeight);
|
||||
holder.thumb.load(EhCacheKeyFactory.getThumbKey(gi.gid), gi.thumb);
|
||||
((TileThumb) holder.thumb).setThumbSize(gi.getThumbWidth(), gi.getThumbHeight());
|
||||
holder.thumb.load(EhCacheKeyFactory.getThumbKey(gi.getGid()), gi.getThumb());
|
||||
View category = holder.category;
|
||||
Drawable drawable = category.getBackground();
|
||||
int color = EhUtils.getCategoryColor(gi.category);
|
||||
int color = EhUtils.getCategoryColor(gi.getCategory());
|
||||
if (!(drawable instanceof TriangleDrawable)) {
|
||||
drawable = new TriangleDrawable(color);
|
||||
category.setBackground(drawable);
|
||||
} else {
|
||||
((TriangleDrawable) drawable).setColor(color);
|
||||
}
|
||||
holder.simpleLanguage.setText(gi.simpleLanguage);
|
||||
holder.simpleLanguage.setText(gi.getSimpleLanguage());
|
||||
}
|
||||
}
|
||||
|
||||
// Update transition name
|
||||
ViewCompat.setTransitionName(holder.thumb, TransitionNameFactory.getThumbTransitionName(gi.gid));
|
||||
ViewCompat.setTransitionName(holder.thumb, TransitionNameFactory.getThumbTransitionName(gi.getGid()));
|
||||
}
|
||||
|
||||
@IntDef({TYPE_LIST, TYPE_GRID})
|
||||
|
||||
@@ -72,7 +72,6 @@ import com.hippo.ehviewer.client.data.ListUrlBuilder;
|
||||
import com.hippo.ehviewer.client.parser.VoteCommentParser;
|
||||
import com.hippo.ehviewer.dao.Filter;
|
||||
import com.hippo.ehviewer.ui.MainActivity;
|
||||
import com.hippo.scene.SceneFragment;
|
||||
import com.hippo.text.URLImageGetter;
|
||||
import com.hippo.util.ClipboardUtilKt;
|
||||
import com.hippo.util.ExceptionUtils;
|
||||
@@ -312,9 +311,8 @@ public final class GalleryCommentsScene extends BaseToolbarScene
|
||||
|
||||
EhRequest request = new EhRequest()
|
||||
.setMethod(EhClient.METHOD_VOTE_COMMENT)
|
||||
.setArgs(mGalleryDetail.apiUid, mGalleryDetail.apiKey, mGalleryDetail.gid, mGalleryDetail.token, id, vote)
|
||||
.setCallback(new VoteCommentListener(context,
|
||||
activity.getStageId(), getTag()));
|
||||
.setArgs(mGalleryDetail.apiUid, mGalleryDetail.apiKey, mGalleryDetail.getGid(), mGalleryDetail.getToken(), id, vote)
|
||||
.setCallback(new VoteCommentListener(context));
|
||||
request.enqueue(this);
|
||||
}
|
||||
|
||||
@@ -450,7 +448,7 @@ public final class GalleryCommentsScene extends BaseToolbarScene
|
||||
EhRequest request = new EhRequest()
|
||||
.setMethod(EhClient.METHOD_GET_GALLERY_DETAIL)
|
||||
.setArgs(url)
|
||||
.setCallback(new RefreshCommentListener(activity, activity.getStageId(), getTag()));
|
||||
.setCallback(new RefreshCommentListener(activity));
|
||||
request.enqueue(this);
|
||||
}
|
||||
}
|
||||
@@ -599,8 +597,8 @@ public final class GalleryCommentsScene extends BaseToolbarScene
|
||||
|
||||
@Nullable
|
||||
private String getGalleryDetailUrl() {
|
||||
if (mGalleryDetail != null && mGalleryDetail.gid != -1 && mGalleryDetail.token != null) {
|
||||
return EhUrl.getGalleryDetailUrl(mGalleryDetail.gid, mGalleryDetail.token, 0, mShowAllComments);
|
||||
if (mGalleryDetail != null && mGalleryDetail.getGid() != -1 && mGalleryDetail.getToken() != null) {
|
||||
return EhUrl.getGalleryDetailUrl(mGalleryDetail.getGid(), mGalleryDetail.getToken(), 0, mShowAllComments);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
@@ -634,8 +632,7 @@ public final class GalleryCommentsScene extends BaseToolbarScene
|
||||
EhRequest request = new EhRequest()
|
||||
.setMethod(EhClient.METHOD_GET_COMMENT_GALLERY)
|
||||
.setArgs(url, comment, mCommentId != 0 ? Long.toString(mCommentId) : null)
|
||||
.setCallback(new CommentGalleryListener(context,
|
||||
activity.getStageId(), getTag(), mCommentId));
|
||||
.setCallback(new CommentGalleryListener(context, mCommentId));
|
||||
request.enqueue(this);
|
||||
hideSoftInput();
|
||||
hideEditPanel(true);
|
||||
@@ -654,10 +651,6 @@ public final class GalleryCommentsScene extends BaseToolbarScene
|
||||
mAdapter.notifyDataSetChanged();
|
||||
|
||||
updateView(true);
|
||||
|
||||
Bundle re = new Bundle();
|
||||
re.putParcelable(KEY_COMMENT_LIST, result);
|
||||
setResult(SceneFragment.RESULT_OK, re);
|
||||
}
|
||||
|
||||
private void onRefreshGalleryFailure() {
|
||||
@@ -680,9 +673,6 @@ public final class GalleryCommentsScene extends BaseToolbarScene
|
||||
|
||||
mGalleryDetail.comments = result;
|
||||
mAdapter.notifyDataSetChanged();
|
||||
Bundle re = new Bundle();
|
||||
re.putParcelable(KEY_COMMENT_LIST, result);
|
||||
setResult(SceneFragment.RESULT_OK, re);
|
||||
|
||||
// Remove text
|
||||
if (mEditText != null) {
|
||||
@@ -723,10 +713,6 @@ public final class GalleryCommentsScene extends BaseToolbarScene
|
||||
}
|
||||
|
||||
mAdapter.notifyItemChanged(position);
|
||||
|
||||
Bundle re = new Bundle();
|
||||
re.putParcelable(KEY_COMMENT_LIST, mGalleryDetail.comments);
|
||||
setResult(SceneFragment.RESULT_OK, re);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -741,112 +727,12 @@ public final class GalleryCommentsScene extends BaseToolbarScene
|
||||
EhRequest request = new EhRequest()
|
||||
.setMethod(EhClient.METHOD_GET_GALLERY_DETAIL)
|
||||
.setArgs(url)
|
||||
.setCallback(new RefreshCommentListener(activity, activity.getStageId(), getTag()));
|
||||
.setCallback(new RefreshCommentListener(activity));
|
||||
request.enqueue(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class RefreshCommentListener extends EhCallback<GalleryCommentsScene, GalleryDetail> {
|
||||
|
||||
public RefreshCommentListener(Context context, int stageId, String sceneTag) {
|
||||
super(context, stageId, sceneTag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(GalleryDetail result) {
|
||||
GalleryCommentsScene scene = getScene();
|
||||
if (scene != null) {
|
||||
scene.onRefreshGallerySuccess(result.comments);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
GalleryCommentsScene scene = getScene();
|
||||
if (scene != null) {
|
||||
scene.onRefreshGalleryFailure();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInstance(SceneFragment scene) {
|
||||
return scene instanceof GalleryCommentsScene;
|
||||
}
|
||||
}
|
||||
|
||||
private static class CommentGalleryListener extends EhCallback<GalleryCommentsScene, GalleryCommentList> {
|
||||
|
||||
private final long mCommentId;
|
||||
|
||||
public CommentGalleryListener(Context context, int stageId, String sceneTag, long commentId) {
|
||||
super(context, stageId, sceneTag);
|
||||
mCommentId = commentId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(GalleryCommentList result) {
|
||||
showTip(mCommentId != 0 ? R.string.edit_comment_successfully : R.string.comment_successfully, LENGTH_SHORT);
|
||||
|
||||
GalleryCommentsScene scene = getScene();
|
||||
if (scene != null) {
|
||||
scene.onCommentGallerySuccess(result);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
showTip(getContent().getString(mCommentId != 0 ? R.string.edit_comment_failed : R.string.comment_failed) + "\n" + ExceptionUtils.getReadableString(e), LENGTH_LONG);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInstance(SceneFragment scene) {
|
||||
return scene instanceof GalleryCommentsScene;
|
||||
}
|
||||
}
|
||||
|
||||
private static class VoteCommentListener extends EhCallback<GalleryCommentsScene, VoteCommentParser.Result> {
|
||||
|
||||
public VoteCommentListener(Context context, int stageId, String sceneTag) {
|
||||
super(context, stageId, sceneTag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(VoteCommentParser.Result result) {
|
||||
showTip(result.expectVote > 0 ?
|
||||
(0 != result.vote ? R.string.vote_up_successfully : R.string.cancel_vote_up_successfully) :
|
||||
(0 != result.vote ? R.string.vote_down_successfully : R.string.cancel_vote_down_successfully),
|
||||
LENGTH_SHORT);
|
||||
|
||||
GalleryCommentsScene scene = getScene();
|
||||
if (scene != null) {
|
||||
scene.onVoteCommentSuccess(result);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
showTip(R.string.vote_failed, LENGTH_LONG);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInstance(SceneFragment scene) {
|
||||
return scene instanceof GalleryCommentsScene;
|
||||
}
|
||||
}
|
||||
|
||||
private static class InfoHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private final TextView key;
|
||||
@@ -877,6 +763,83 @@ public final class GalleryCommentsScene extends BaseToolbarScene
|
||||
}
|
||||
}
|
||||
|
||||
private class RefreshCommentListener extends EhCallback<GalleryCommentsScene, GalleryDetail> {
|
||||
|
||||
public RefreshCommentListener(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(GalleryDetail result) {
|
||||
GalleryCommentsScene scene = GalleryCommentsScene.this;
|
||||
scene.onRefreshGallerySuccess(result.comments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
GalleryCommentsScene scene = GalleryCommentsScene.this;
|
||||
scene.onRefreshGalleryFailure();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
}
|
||||
}
|
||||
|
||||
private class CommentGalleryListener extends EhCallback<GalleryCommentsScene, GalleryCommentList> {
|
||||
|
||||
private final long mCommentId;
|
||||
|
||||
public CommentGalleryListener(Context context, long commentId) {
|
||||
super(context);
|
||||
mCommentId = commentId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(GalleryCommentList result) {
|
||||
showTip(mCommentId != 0 ? R.string.edit_comment_successfully : R.string.comment_successfully, LENGTH_SHORT);
|
||||
|
||||
GalleryCommentsScene scene = GalleryCommentsScene.this;
|
||||
scene.onCommentGallerySuccess(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
showTip(getContent().getString(mCommentId != 0 ? R.string.edit_comment_failed : R.string.comment_failed) + "\n" + ExceptionUtils.getReadableString(e), LENGTH_LONG);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
}
|
||||
}
|
||||
|
||||
private class VoteCommentListener extends EhCallback<GalleryCommentsScene, VoteCommentParser.Result> {
|
||||
|
||||
public VoteCommentListener(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(VoteCommentParser.Result result) {
|
||||
showTip(result.expectVote > 0 ?
|
||||
(0 != result.vote ? R.string.vote_up_successfully : R.string.cancel_vote_up_successfully) :
|
||||
(0 != result.vote ? R.string.vote_down_successfully : R.string.cancel_vote_down_successfully),
|
||||
LENGTH_SHORT);
|
||||
|
||||
GalleryCommentsScene scene = GalleryCommentsScene.this;
|
||||
scene.onVoteCommentSuccess(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
showTip(R.string.vote_failed, LENGTH_LONG);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
}
|
||||
}
|
||||
|
||||
private class ActualCommentHolder extends CommentHolder {
|
||||
|
||||
private final TextView user;
|
||||
@@ -925,7 +888,7 @@ public final class GalleryCommentsScene extends BaseToolbarScene
|
||||
ListUrlBuilder lub = new ListUrlBuilder();
|
||||
lub.setMode(ListUrlBuilder.MODE_UPLOADER);
|
||||
lub.setKeyword(value.user);
|
||||
GalleryListScene.startScene(GalleryCommentsScene.this, lub);
|
||||
navigate(R.id.galleryListScene, GalleryListScene.getStartArgs(lub), true);
|
||||
});
|
||||
time.setText(ReadableTime.getTimeAgo(value.time));
|
||||
comment.setText(generateComment(comment.getContext(), comment, value));
|
||||
|
||||
@@ -21,7 +21,6 @@ import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.app.DownloadManager;
|
||||
import android.app.assist.AssistContent;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
@@ -76,7 +75,6 @@ import com.hippo.ehviewer.client.EhTagDatabase;
|
||||
import com.hippo.ehviewer.client.EhUrl;
|
||||
import com.hippo.ehviewer.client.EhUtils;
|
||||
import com.hippo.ehviewer.client.data.GalleryComment;
|
||||
import com.hippo.ehviewer.client.data.GalleryCommentList;
|
||||
import com.hippo.ehviewer.client.data.GalleryDetail;
|
||||
import com.hippo.ehviewer.client.data.GalleryInfo;
|
||||
import com.hippo.ehviewer.client.data.GalleryTagGroup;
|
||||
@@ -97,8 +95,6 @@ import com.hippo.ehviewer.ui.GalleryInfoBottomSheet;
|
||||
import com.hippo.ehviewer.ui.MainActivity;
|
||||
import com.hippo.ehviewer.ui.annotation.WholeLifeCircle;
|
||||
import com.hippo.ehviewer.widget.GalleryRatingBar;
|
||||
import com.hippo.scene.Announcer;
|
||||
import com.hippo.scene.SceneFragment;
|
||||
import com.hippo.text.URLImageGetter;
|
||||
import com.hippo.unifile.UniFile;
|
||||
import com.hippo.util.AppHelper;
|
||||
@@ -335,11 +331,11 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
long gid;
|
||||
String token;
|
||||
if (mGalleryDetail != null) {
|
||||
gid = mGalleryDetail.gid;
|
||||
token = mGalleryDetail.token;
|
||||
gid = mGalleryDetail.getGid();
|
||||
token = mGalleryDetail.getToken();
|
||||
} else if (mGalleryInfo != null) {
|
||||
gid = mGalleryInfo.gid;
|
||||
token = mGalleryInfo.token;
|
||||
gid = mGalleryInfo.getGid();
|
||||
token = mGalleryInfo.getToken();
|
||||
} else if (ACTION_GID_TOKEN.equals(mAction)) {
|
||||
gid = mGid;
|
||||
token = mToken;
|
||||
@@ -352,9 +348,9 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
// -1 for error
|
||||
private long getGid() {
|
||||
if (mGalleryDetail != null) {
|
||||
return mGalleryDetail.gid;
|
||||
return mGalleryDetail.getGid();
|
||||
} else if (mGalleryInfo != null) {
|
||||
return mGalleryInfo.gid;
|
||||
return mGalleryInfo.getGid();
|
||||
} else if (ACTION_GID_TOKEN.equals(mAction)) {
|
||||
return mGid;
|
||||
} else {
|
||||
@@ -364,9 +360,9 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
|
||||
private String getUploader() {
|
||||
if (mGalleryDetail != null) {
|
||||
return mGalleryDetail.uploader;
|
||||
return mGalleryDetail.getUploader();
|
||||
} else if (mGalleryInfo != null) {
|
||||
return mGalleryInfo.uploader;
|
||||
return mGalleryInfo.getUploader();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
@@ -380,9 +376,9 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
// -1 for error
|
||||
private int getCategory() {
|
||||
if (mGalleryDetail != null) {
|
||||
return mGalleryDetail.category;
|
||||
return mGalleryDetail.getCategory();
|
||||
} else if (mGalleryInfo != null) {
|
||||
return mGalleryInfo.category;
|
||||
return mGalleryInfo.getCategory();
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
@@ -624,6 +620,7 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
}
|
||||
|
||||
EhApplication.getDownloadManager().addDownloadInfoListener(this);
|
||||
((MainActivity) requireActivity()).setMShareUrl(getGalleryDetailUrl());
|
||||
|
||||
return view;
|
||||
}
|
||||
@@ -635,6 +632,7 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
Context context = getContext();
|
||||
AssertUtils.assertNotNull(context);
|
||||
EhApplication.getDownloadManager().removeDownloadInfoListener(this);
|
||||
((MainActivity) requireActivity()).setMShareUrl(null);
|
||||
|
||||
mTip = null;
|
||||
mViewTransition = null;
|
||||
@@ -720,8 +718,7 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
return false;
|
||||
}
|
||||
|
||||
EhClient.Callback<?> callback = new GetGalleryDetailListener(context,
|
||||
activity.getStageId(), getTag());
|
||||
EhClient.Callback<?> callback = new GetGalleryDetailListener(context);
|
||||
mRequestId = ((EhApplication) context.getApplicationContext()).putGlobalStuff(callback);
|
||||
EhRequest request = new EhRequest()
|
||||
.setMethod(EhClient.METHOD_GET_GALLERY_DETAIL)
|
||||
@@ -776,12 +773,12 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
|
||||
if (ACTION_GALLERY_INFO.equals(mAction) && mGalleryInfo != null) {
|
||||
GalleryInfo gi = mGalleryInfo;
|
||||
mThumb.load(EhCacheKeyFactory.getThumbKey(gi.gid), gi.thumb);
|
||||
mThumb.load(EhCacheKeyFactory.getThumbKey(gi.getGid()), gi.getThumb());
|
||||
setTitle(EhUtils.getSuitableTitle(gi));
|
||||
mUploader.setText(gi.uploader);
|
||||
mUploader.setAlpha(gi.disowned ? .5f : 1f);
|
||||
mCategory.setText(EhUtils.getCategory(gi.category));
|
||||
mCategory.setTextColor(EhUtils.getCategoryColor(gi.category));
|
||||
mUploader.setText(gi.getUploader());
|
||||
mUploader.setAlpha(gi.getDisowned() ? .5f : 1f);
|
||||
mCategory.setText(EhUtils.getCategory(gi.getCategory()));
|
||||
mCategory.setTextColor(EhUtils.getCategoryColor(gi.getCategory()));
|
||||
updateDownloadText();
|
||||
}
|
||||
}
|
||||
@@ -795,12 +792,12 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
return;
|
||||
}
|
||||
|
||||
if (gd.isFavorited || EhDB.containLocalFavorites(gd.gid)) {
|
||||
if (gd.isFavorited || EhDB.containLocalFavorites(gd.getGid())) {
|
||||
mHeart.setVisibility(View.VISIBLE);
|
||||
if (gd.favoriteName == null) {
|
||||
if (gd.getFavoriteName() == null) {
|
||||
mHeart.setText(R.string.local_favorites);
|
||||
} else {
|
||||
mHeart.setText(gd.favoriteName);
|
||||
mHeart.setText(gd.getFavoriteName());
|
||||
}
|
||||
mHeartOutline.setVisibility(View.GONE);
|
||||
} else {
|
||||
@@ -833,26 +830,26 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
|
||||
Resources resources = getResources();
|
||||
|
||||
mThumb.load(EhCacheKeyFactory.getThumbKey(gd.gid), gd.thumb, true);
|
||||
mThumb.load(EhCacheKeyFactory.getThumbKey(gd.getGid()), gd.getThumb(), true);
|
||||
setTitle(EhUtils.getSuitableTitle(gd));
|
||||
mUploader.setText(gd.uploader);
|
||||
mUploader.setAlpha(gd.disowned ? .5f : 1f);
|
||||
mCategory.setText(EhUtils.getCategory(gd.category));
|
||||
mCategory.setTextColor(EhUtils.getCategoryColor(gd.category));
|
||||
mUploader.setText(gd.getUploader());
|
||||
mUploader.setAlpha(gd.getDisowned() ? .5f : 1f);
|
||||
mCategory.setText(EhUtils.getCategory(gd.getCategory()));
|
||||
mCategory.setTextColor(EhUtils.getCategoryColor(gd.getCategory()));
|
||||
updateDownloadText();
|
||||
|
||||
mLanguage.setText(gd.language);
|
||||
mPages.setText(resources.getQuantityString(
|
||||
R.plurals.page_count, gd.pages, gd.pages));
|
||||
R.plurals.page_count, gd.getPages(), gd.getPages()));
|
||||
mSize.setText(gd.size);
|
||||
mPosted.setText(gd.posted);
|
||||
mPosted.setText(gd.getPosted());
|
||||
mFavoredTimes.setText(resources.getString(R.string.favored_times, gd.favoriteCount));
|
||||
if (gd.newerVersions != null && gd.newerVersions.size() != 0) {
|
||||
mNewerVersion.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
mRatingText.setText(getAllRatingText(gd.rating, gd.ratingCount));
|
||||
mRating.setRating(gd.rating);
|
||||
mRatingText.setText(getAllRatingText(gd.getRating(), gd.ratingCount));
|
||||
mRating.setRating(gd.getRating());
|
||||
|
||||
updateFavoriteDrawable();
|
||||
|
||||
@@ -985,7 +982,7 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
mGridLayout.addView(view);
|
||||
|
||||
LoadImageView image = view.findViewById(R.id.image);
|
||||
previewSet.load(image, gd.gid, i);
|
||||
previewSet.load(image, gd.getGid(), i);
|
||||
image.setTag(R.id.index, i);
|
||||
image.setOnClickListener(this);
|
||||
TextView text = view.findViewById(R.id.text);
|
||||
@@ -1002,12 +999,12 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
if (null == gd) {
|
||||
return;
|
||||
}
|
||||
String keyword = EhUtils.extractTitle(gd.title);
|
||||
String keyword = EhUtils.extractTitle(gd.getTitle());
|
||||
if (null != keyword) {
|
||||
ListUrlBuilder lub = new ListUrlBuilder();
|
||||
lub.setMode(ListUrlBuilder.MODE_NORMAL);
|
||||
lub.setKeyword("\"" + keyword + "\"");
|
||||
GalleryListScene.startScene(this, lub);
|
||||
navigate(R.id.galleryListScene, GalleryListScene.getStartArgs(lub), true);
|
||||
return;
|
||||
}
|
||||
String artist = getArtist(gd.tags);
|
||||
@@ -1015,14 +1012,14 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
ListUrlBuilder lub = new ListUrlBuilder();
|
||||
lub.setMode(ListUrlBuilder.MODE_TAG);
|
||||
lub.setKeyword("artist:" + artist);
|
||||
GalleryListScene.startScene(this, lub);
|
||||
navigate(R.id.galleryListScene, GalleryListScene.getStartArgs(lub), true);
|
||||
return;
|
||||
}
|
||||
if (null != gd.uploader) {
|
||||
if (null != gd.getUploader()) {
|
||||
ListUrlBuilder lub = new ListUrlBuilder();
|
||||
lub.setMode(ListUrlBuilder.MODE_UPLOADER);
|
||||
lub.setKeyword(gd.uploader);
|
||||
GalleryListScene.startScene(this, lub);
|
||||
lub.setKeyword(gd.getUploader());
|
||||
navigate(R.id.galleryListScene, GalleryListScene.getStartArgs(lub), true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1042,7 +1039,7 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
lub.setMode(ListUrlBuilder.MODE_IMAGE_SEARCH);
|
||||
lub.setImagePath(path.toString());
|
||||
lub.setUseSimilarityScan(true);
|
||||
GalleryListScene.startScene(this, lub);
|
||||
navigate(R.id.galleryListScene, GalleryListScene.getStartArgs(lub), true);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -1068,7 +1065,7 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
ListUrlBuilder lub = new ListUrlBuilder();
|
||||
lub.setMode(ListUrlBuilder.MODE_UPLOADER);
|
||||
lub.setKeyword(uploader);
|
||||
GalleryListScene.startScene(this, lub);
|
||||
navigate(R.id.galleryListScene, GalleryListScene.getStartArgs(lub), true);
|
||||
} else if (mCategory == v) {
|
||||
int category = getCategory();
|
||||
if (category == EhUtils.NONE || category == EhUtils.PRIVATE || category == EhUtils.UNKNOWN) {
|
||||
@@ -1076,15 +1073,15 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
}
|
||||
ListUrlBuilder lub = new ListUrlBuilder();
|
||||
lub.setCategory(category);
|
||||
GalleryListScene.startScene(this, lub);
|
||||
navigate(R.id.galleryListScene, GalleryListScene.getStartArgs(lub), true);
|
||||
} else if (mDownload == v) {
|
||||
GalleryInfo galleryInfo = getGalleryInfo();
|
||||
if (galleryInfo != null) {
|
||||
if (EhApplication.getDownloadManager().getDownloadState(galleryInfo.gid) == DownloadInfo.STATE_INVALID) {
|
||||
if (EhApplication.getDownloadManager().getDownloadState(galleryInfo.getGid()) == DownloadInfo.STATE_INVALID) {
|
||||
CommonOperations.startDownload(activity, galleryInfo, false);
|
||||
} else {
|
||||
CheckBoxDialogBuilder builder = new CheckBoxDialogBuilder(context,
|
||||
getString(R.string.download_remove_dialog_message, galleryInfo.title),
|
||||
getString(R.string.download_remove_dialog_message, galleryInfo.getTitle()),
|
||||
getString(R.string.download_remove_dialog_check_text),
|
||||
Settings.getRemoveImageFiles());
|
||||
DeleteDialogHelper helper = new DeleteDialogHelper(
|
||||
@@ -1111,16 +1108,16 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
if (mGalleryDetail != null) {
|
||||
ArrayList<CharSequence> titles = new ArrayList<>();
|
||||
for (GalleryInfo newerVersion : mGalleryDetail.newerVersions) {
|
||||
titles.add(getString(R.string.newer_version_title, newerVersion.title, newerVersion.posted));
|
||||
titles.add(getString(R.string.newer_version_title, newerVersion.getTitle(), newerVersion.getPosted()));
|
||||
}
|
||||
new BaseDialogBuilder(requireContext())
|
||||
.setItems(titles.toArray(new CharSequence[0]), (dialog, which) -> {
|
||||
GalleryInfo newerVersion = mGalleryDetail.newerVersions.get(which);
|
||||
Bundle args = new Bundle();
|
||||
args.putString(GalleryDetailScene.KEY_ACTION, GalleryDetailScene.ACTION_GID_TOKEN);
|
||||
args.putLong(GalleryDetailScene.KEY_GID, newerVersion.gid);
|
||||
args.putString(GalleryDetailScene.KEY_TOKEN, newerVersion.token);
|
||||
startScene(new Announcer(GalleryDetailScene.class).setArgs(args));
|
||||
args.putLong(GalleryDetailScene.KEY_GID, newerVersion.getGid());
|
||||
args.putString(GalleryDetailScene.KEY_TOKEN, newerVersion.getToken());
|
||||
navigate(R.id.galleryDetailScene, args);
|
||||
})
|
||||
.show();
|
||||
}
|
||||
@@ -1131,18 +1128,16 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
} else if (mHeart == v || mHeartOutline == v) {
|
||||
if (mGalleryDetail != null && !mModifyingFavorites) {
|
||||
boolean remove = false;
|
||||
if (EhDB.containLocalFavorites(mGalleryDetail.gid) || mGalleryDetail.isFavorited) {
|
||||
if (EhDB.containLocalFavorites(mGalleryDetail.getGid()) || mGalleryDetail.isFavorited) {
|
||||
mModifyingFavorites = true;
|
||||
CommonOperations.removeFromFavorites(activity, mGalleryDetail,
|
||||
new ModifyFavoritesListener(context,
|
||||
activity.getStageId(), getTag(), true));
|
||||
new ModifyFavoritesListener(context, true));
|
||||
remove = true;
|
||||
}
|
||||
if (!remove) {
|
||||
mModifyingFavorites = true;
|
||||
CommonOperations.addToFavorites(activity, mGalleryDetail,
|
||||
new ModifyFavoritesListener(context,
|
||||
activity.getStageId(), getTag(), false));
|
||||
new ModifyFavoritesListener(context, false));
|
||||
}
|
||||
// Update UI
|
||||
updateFavoriteDrawable();
|
||||
@@ -1197,7 +1192,7 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setPositiveButton(android.R.string.ok, helper)
|
||||
.show();
|
||||
helper.setDialog(dialog, mGalleryDetail.rating);
|
||||
helper.setDialog(dialog, mGalleryDetail.getRating());
|
||||
} else if (mSimilar == v) {
|
||||
showSimilarGalleryList();
|
||||
} else if (mSearchCover == v) {
|
||||
@@ -1209,18 +1204,16 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
Bundle args = new Bundle();
|
||||
args.putLong(GalleryCommentsScene.KEY_API_UID, mGalleryDetail.apiUid);
|
||||
args.putString(GalleryCommentsScene.KEY_API_KEY, mGalleryDetail.apiKey);
|
||||
args.putLong(GalleryCommentsScene.KEY_GID, mGalleryDetail.gid);
|
||||
args.putString(GalleryCommentsScene.KEY_TOKEN, mGalleryDetail.token);
|
||||
args.putLong(GalleryCommentsScene.KEY_GID, mGalleryDetail.getGid());
|
||||
args.putString(GalleryCommentsScene.KEY_TOKEN, mGalleryDetail.getToken());
|
||||
args.putParcelable(GalleryCommentsScene.KEY_COMMENT_LIST, mGalleryDetail.comments);
|
||||
args.putParcelable(GalleryCommentsScene.KEY_GALLERY_DETAIL, mGalleryDetail);
|
||||
startScene(new Announcer(GalleryCommentsScene.class)
|
||||
.setArgs(args)
|
||||
.setRequestCode(this, REQUEST_CODE_COMMENT_GALLERY));
|
||||
navigate(R.id.galleryCommentsScene, args);
|
||||
} else if (mPreviews == v) {
|
||||
if (null != mGalleryDetail) {
|
||||
Bundle args = new Bundle();
|
||||
args.putParcelable(GalleryPreviewsScene.KEY_GALLERY_INFO, mGalleryDetail);
|
||||
startScene(new Announcer(GalleryPreviewsScene.class).setArgs(args));
|
||||
navigate(R.id.galleryPreviewsScene, args);
|
||||
}
|
||||
} else {
|
||||
Object o = v.getTag(R.id.tag);
|
||||
@@ -1228,7 +1221,7 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
ListUrlBuilder lub = new ListUrlBuilder();
|
||||
lub.setMode(ListUrlBuilder.MODE_TAG);
|
||||
lub.setKeyword(tag);
|
||||
GalleryListScene.startScene(this, lub);
|
||||
navigate(R.id.galleryListScene, GalleryListScene.getStartArgs(lub), true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1353,9 +1346,8 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
|
||||
EhRequest request = new EhRequest()
|
||||
.setMethod(EhClient.METHOD_VOTE_TAG)
|
||||
.setArgs(mGalleryDetail.apiUid, mGalleryDetail.apiKey, mGalleryDetail.gid, mGalleryDetail.token, tag, vote)
|
||||
.setCallback(new VoteTagListener(context,
|
||||
activity.getStageId(), getTag()));
|
||||
.setArgs(mGalleryDetail.apiUid, mGalleryDetail.apiKey, mGalleryDetail.getGid(), mGalleryDetail.getToken(), tag, vote)
|
||||
.setCallback(new VoteTagListener(context));
|
||||
request.enqueue(this);
|
||||
}
|
||||
|
||||
@@ -1380,18 +1372,16 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
} else if (mHeart == v || mHeartOutline == v) {
|
||||
if (mGalleryDetail != null && !mModifyingFavorites) {
|
||||
boolean remove = false;
|
||||
if (EhDB.containLocalFavorites(mGalleryDetail.gid) || mGalleryDetail.isFavorited) {
|
||||
if (EhDB.containLocalFavorites(mGalleryDetail.getGid()) || mGalleryDetail.isFavorited) {
|
||||
mModifyingFavorites = true;
|
||||
CommonOperations.removeFromFavorites(activity, mGalleryDetail,
|
||||
new ModifyFavoritesListener(activity,
|
||||
activity.getStageId(), getTag(), true));
|
||||
new ModifyFavoritesListener(activity, true));
|
||||
remove = true;
|
||||
}
|
||||
if (!remove) {
|
||||
mModifyingFavorites = true;
|
||||
CommonOperations.addToFavorites(activity, mGalleryDetail,
|
||||
new ModifyFavoritesListener(activity,
|
||||
activity.getStageId(), getTag(), false), true);
|
||||
new ModifyFavoritesListener(activity, false), true);
|
||||
}
|
||||
// Update UI
|
||||
updateFavoriteDrawable();
|
||||
@@ -1406,23 +1396,6 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSceneResult(int requestCode, int resultCode, Bundle data) {
|
||||
if (requestCode == REQUEST_CODE_COMMENT_GALLERY) {
|
||||
if (resultCode != RESULT_OK || data == null) {
|
||||
return;
|
||||
}
|
||||
GalleryCommentList comments = data.getParcelable(GalleryCommentsScene.KEY_COMMENT_LIST);
|
||||
if (mGalleryDetail == null && comments == null) {
|
||||
return;
|
||||
}
|
||||
mGalleryDetail.comments = comments;
|
||||
bindComments(comments.comments);
|
||||
} else {
|
||||
super.onSceneResult(requestCode, resultCode, data);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateDownloadText() {
|
||||
if (null == mDownload) {
|
||||
return;
|
||||
@@ -1510,7 +1483,7 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
|
||||
private void onRateGallerySuccess(RateGalleryParser.Result result) {
|
||||
if (mGalleryDetail != null) {
|
||||
mGalleryDetail.rating = result.rating;
|
||||
mGalleryDetail.setRating(result.rating);
|
||||
mGalleryDetail.ratingCount = result.ratingCount;
|
||||
}
|
||||
|
||||
@@ -1524,7 +1497,7 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
private void onModifyFavoritesSuccess(boolean addOrRemove) {
|
||||
mModifyingFavorites = false;
|
||||
if (mGalleryDetail != null) {
|
||||
mGalleryDetail.isFavorited = !addOrRemove && mGalleryDetail.favoriteName != null;
|
||||
mGalleryDetail.isFavorited = !addOrRemove && mGalleryDetail.getFavoriteName() != null;
|
||||
updateFavoriteDrawable();
|
||||
}
|
||||
}
|
||||
@@ -1537,68 +1510,15 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
mModifyingFavorites = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProvideAssistContent(AssistContent outContent) {
|
||||
super.onProvideAssistContent(outContent);
|
||||
|
||||
String url = getGalleryDetailUrl();
|
||||
if (url != null) {
|
||||
outContent.setWebUri(Uri.parse(url));
|
||||
}
|
||||
}
|
||||
|
||||
@IntDef({STATE_INIT, STATE_NORMAL, STATE_REFRESH, STATE_REFRESH_HEADER, STATE_FAILED})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
private @interface State {
|
||||
}
|
||||
|
||||
private static class GetGalleryDetailListener extends EhCallback<GalleryDetailScene, GalleryDetail> {
|
||||
|
||||
public GetGalleryDetailListener(Context context, int stageId, String sceneTag) {
|
||||
super(context, stageId, sceneTag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(GalleryDetail result) {
|
||||
getApplication().removeGlobalStuff(this);
|
||||
|
||||
// Put gallery detail to cache
|
||||
EhApplication.getGalleryDetailCache().put(result.gid, result);
|
||||
|
||||
// Add history
|
||||
EhDB.putHistoryInfo(result);
|
||||
|
||||
// Notify success
|
||||
GalleryDetailScene scene = getScene();
|
||||
if (scene != null) {
|
||||
scene.onGetGalleryDetailSuccess(result);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
getApplication().removeGlobalStuff(this);
|
||||
GalleryDetailScene scene = getScene();
|
||||
if (scene != null) {
|
||||
scene.onGetGalleryDetailFailure(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
getApplication().removeGlobalStuff(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInstance(SceneFragment scene) {
|
||||
return scene instanceof GalleryDetailScene;
|
||||
}
|
||||
}
|
||||
|
||||
private static class VoteTagListener extends EhCallback<GalleryDetailScene, VoteTagParser.Result> {
|
||||
|
||||
public VoteTagListener(Context context, int stageId, String sceneTag) {
|
||||
super(context, stageId, sceneTag);
|
||||
public VoteTagListener(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1618,99 +1538,6 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
@Override
|
||||
public void onCancel() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInstance(SceneFragment scene) {
|
||||
return scene instanceof GalleryDetailScene;
|
||||
}
|
||||
}
|
||||
|
||||
private static class RateGalleryListener extends EhCallback<GalleryDetailScene, RateGalleryParser.Result> {
|
||||
|
||||
private final long mGid;
|
||||
|
||||
public RateGalleryListener(Context context, int stageId, String sceneTag, long gid) {
|
||||
super(context, stageId, sceneTag);
|
||||
mGid = gid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(RateGalleryParser.Result result) {
|
||||
showTip(R.string.rate_successfully, LENGTH_SHORT);
|
||||
|
||||
GalleryDetailScene scene = getScene();
|
||||
if (scene != null) {
|
||||
scene.onRateGallerySuccess(result);
|
||||
} else {
|
||||
// Update rating in cache
|
||||
GalleryDetail gd = EhApplication.getGalleryDetailCache().get(mGid);
|
||||
if (gd != null) {
|
||||
gd.rating = result.rating;
|
||||
gd.ratingCount = result.ratingCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
e.printStackTrace();
|
||||
showTip(R.string.rate_failed, LENGTH_LONG);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInstance(SceneFragment scene) {
|
||||
return scene instanceof GalleryDetailScene;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ModifyFavoritesListener extends EhCallback<GalleryDetailScene, Void> {
|
||||
|
||||
private final boolean mAddOrRemove;
|
||||
|
||||
/**
|
||||
* @param addOrRemove false for add, true for remove
|
||||
*/
|
||||
public ModifyFavoritesListener(Context context, int stageId, String sceneTag, boolean addOrRemove) {
|
||||
super(context, stageId, sceneTag);
|
||||
mAddOrRemove = addOrRemove;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Void result) {
|
||||
showTip(mAddOrRemove ? R.string.remove_from_favorite_success :
|
||||
R.string.add_to_favorite_success, LENGTH_SHORT);
|
||||
GalleryDetailScene scene = getScene();
|
||||
if (scene != null) {
|
||||
scene.onModifyFavoritesSuccess(mAddOrRemove);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
showTip(mAddOrRemove ? R.string.remove_from_favorite_failure :
|
||||
R.string.add_to_favorite_failure, LENGTH_LONG);
|
||||
GalleryDetailScene scene = getScene();
|
||||
if (scene != null) {
|
||||
scene.onModifyFavoritesFailure();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
GalleryDetailScene scene = getScene();
|
||||
if (scene != null) {
|
||||
scene.onModifyFavoritesCancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInstance(SceneFragment scene) {
|
||||
return scene instanceof GalleryDetailScene;
|
||||
}
|
||||
}
|
||||
|
||||
private static class DownloadArchiveListener extends EhCallback<GalleryDetailScene, String> {
|
||||
@@ -1718,7 +1545,7 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
private final GalleryInfo mGalleryInfo;
|
||||
|
||||
public DownloadArchiveListener(Context context, int stageId, String sceneTag, GalleryInfo galleryInfo) {
|
||||
super(context, stageId, sceneTag);
|
||||
super(context);
|
||||
mGalleryInfo = galleryInfo;
|
||||
}
|
||||
|
||||
@@ -1727,7 +1554,7 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
if (result != null) {
|
||||
// TODO: Don't use buggy system download service
|
||||
DownloadManager.Request r = new DownloadManager.Request(Uri.parse(result));
|
||||
var name = mGalleryInfo.gid + "-" + EhUtils.getSuitableTitle(mGalleryInfo) + ".zip";
|
||||
var name = mGalleryInfo.getGid() + "-" + EhUtils.getSuitableTitle(mGalleryInfo) + ".zip";
|
||||
r.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS,
|
||||
FileUtils.sanitizeFilename(name));
|
||||
r.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
|
||||
@@ -1756,11 +1583,6 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
@Override
|
||||
public void onCancel() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInstance(SceneFragment scene) {
|
||||
return scene instanceof GalleryDetailScene;
|
||||
}
|
||||
}
|
||||
|
||||
private static class DeleteDialogHelper implements DialogInterface.OnClickListener {
|
||||
@@ -1783,20 +1605,117 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
|
||||
// Delete
|
||||
if (null != mDownloadManager) {
|
||||
mDownloadManager.deleteDownload(mGalleryInfo.gid);
|
||||
mDownloadManager.deleteDownload(mGalleryInfo.getGid());
|
||||
}
|
||||
|
||||
// Delete image files
|
||||
boolean checked = mBuilder.isChecked();
|
||||
Settings.putRemoveImageFiles(checked);
|
||||
if (checked) {
|
||||
UniFile file = SpiderDen.getGalleryDownloadDir(mGalleryInfo.gid);
|
||||
EhDB.removeDownloadDirname(mGalleryInfo.gid);
|
||||
UniFile file = SpiderDen.getGalleryDownloadDir(mGalleryInfo.getGid());
|
||||
EhDB.removeDownloadDirname(mGalleryInfo.getGid());
|
||||
deleteFileAsync(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class GetGalleryDetailListener extends EhCallback<GalleryDetailScene, GalleryDetail> {
|
||||
|
||||
public GetGalleryDetailListener(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(GalleryDetail result) {
|
||||
getApplication().removeGlobalStuff(this);
|
||||
|
||||
// Put gallery detail to cache
|
||||
EhApplication.getGalleryDetailCache().put(result.getGid(), result);
|
||||
|
||||
// Add history
|
||||
EhDB.putHistoryInfo(result);
|
||||
|
||||
// Notify success
|
||||
GalleryDetailScene scene = GalleryDetailScene.this;
|
||||
scene.onGetGalleryDetailSuccess(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
getApplication().removeGlobalStuff(this);
|
||||
GalleryDetailScene scene = GalleryDetailScene.this;
|
||||
scene.onGetGalleryDetailFailure(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
getApplication().removeGlobalStuff(this);
|
||||
}
|
||||
}
|
||||
|
||||
private class RateGalleryListener extends EhCallback<GalleryDetailScene, RateGalleryParser.Result> {
|
||||
|
||||
private final long mGid;
|
||||
|
||||
public RateGalleryListener(Context context, int stageId, String sceneTag, long gid) {
|
||||
super(context);
|
||||
mGid = gid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(RateGalleryParser.Result result) {
|
||||
showTip(R.string.rate_successfully, LENGTH_SHORT);
|
||||
|
||||
GalleryDetailScene scene = GalleryDetailScene.this;
|
||||
scene.onRateGallerySuccess(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
e.printStackTrace();
|
||||
showTip(R.string.rate_failed, LENGTH_LONG);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
}
|
||||
}
|
||||
|
||||
private class ModifyFavoritesListener extends EhCallback<GalleryDetailScene, Void> {
|
||||
|
||||
private final boolean mAddOrRemove;
|
||||
|
||||
/**
|
||||
* @param addOrRemove false for add, true for remove
|
||||
*/
|
||||
public ModifyFavoritesListener(Context context, boolean addOrRemove) {
|
||||
super(context);
|
||||
mAddOrRemove = addOrRemove;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Void result) {
|
||||
showTip(mAddOrRemove ? R.string.remove_from_favorite_success :
|
||||
R.string.add_to_favorite_success, LENGTH_SHORT);
|
||||
GalleryDetailScene scene = GalleryDetailScene.this;
|
||||
scene.onModifyFavoritesSuccess(mAddOrRemove);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
showTip(mAddOrRemove ? R.string.remove_from_favorite_failure :
|
||||
R.string.add_to_favorite_failure, LENGTH_LONG);
|
||||
GalleryDetailScene scene = GalleryDetailScene.this;
|
||||
scene.onModifyFavoritesFailure();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
GalleryDetailScene scene = GalleryDetailScene.this;
|
||||
scene.onModifyFavoritesCancel();
|
||||
}
|
||||
}
|
||||
|
||||
private class ArchiveListDialogHelper implements AdapterView.OnItemClickListener,
|
||||
DialogInterface.OnDismissListener, EhClient.Callback<ArchiveParser.Result> {
|
||||
|
||||
@@ -1861,8 +1780,8 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
boolean isHAtH = mArchiveList.get(position).isHAtH();
|
||||
EhRequest request = new EhRequest();
|
||||
request.setMethod(EhClient.METHOD_DOWNLOAD_ARCHIVE);
|
||||
request.setArgs(mGalleryDetail.gid, mGalleryDetail.token, mArchiveFormParamOr, res, isHAtH);
|
||||
request.setCallback(new DownloadArchiveListener(context, activity.getStageId(), getTag(), mGalleryDetail));
|
||||
request.setArgs(mGalleryDetail.getGid(), mGalleryDetail.getToken(), mArchiveFormParamOr, res, isHAtH);
|
||||
request.setCallback(new DownloadArchiveListener(context, 1, getTag(), mGalleryDetail));
|
||||
request.enqueue(GalleryDetailScene.this);
|
||||
}
|
||||
|
||||
@@ -1984,9 +1903,11 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
if (dm != null) {
|
||||
try {
|
||||
dm.enqueue(r);
|
||||
showTip(R.string.download_torrent_started, LENGTH_SHORT);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
ExceptionUtils.throwIfFatal(e);
|
||||
showTip(R.string.download_torrent_failure, LENGTH_SHORT);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2071,9 +1992,9 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
EhRequest request = new EhRequest()
|
||||
.setMethod(EhClient.METHOD_GET_RATE_GALLERY)
|
||||
.setArgs(mGalleryDetail.apiUid, mGalleryDetail.apiKey,
|
||||
mGalleryDetail.gid, mGalleryDetail.token, mRatingBar.getRating())
|
||||
mGalleryDetail.getGid(), mGalleryDetail.getToken(), mRatingBar.getRating())
|
||||
.setCallback(new RateGalleryListener(context,
|
||||
activity.getStageId(), getTag(), mGalleryDetail.gid));
|
||||
1, getTag(), mGalleryDetail.getGid()));
|
||||
request.enqueue(GalleryDetailScene.this);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -49,7 +49,6 @@ import com.hippo.ehviewer.client.data.GalleryPreview;
|
||||
import com.hippo.ehviewer.client.data.PreviewSet;
|
||||
import com.hippo.ehviewer.client.exception.EhException;
|
||||
import com.hippo.ehviewer.ui.MainActivity;
|
||||
import com.hippo.scene.SceneFragment;
|
||||
import com.hippo.widget.ContentLayout;
|
||||
import com.hippo.widget.LoadImageView;
|
||||
import com.hippo.widget.recyclerview.AutoGridLayoutManager;
|
||||
@@ -238,7 +237,7 @@ public class GalleryPreviewsScene extends BaseToolbarScene {
|
||||
int size = previewSet.size();
|
||||
ArrayList<GalleryPreview> list = new ArrayList<>(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
list.add(previewSet.getGalleryPreview(mGalleryInfo.gid, i));
|
||||
list.add(previewSet.getGalleryPreview(mGalleryInfo.getGid(), i));
|
||||
}
|
||||
|
||||
mHelper.onGetPageData(taskId, result.second, 0, null, null, list);
|
||||
@@ -251,42 +250,6 @@ public class GalleryPreviewsScene extends BaseToolbarScene {
|
||||
}
|
||||
}
|
||||
|
||||
private static class GetPreviewSetListener extends EhCallback<GalleryPreviewsScene, Pair<PreviewSet, Integer>> {
|
||||
|
||||
private final int mTaskId;
|
||||
|
||||
public GetPreviewSetListener(Context context, int stageId, String sceneTag, int taskId) {
|
||||
super(context, stageId, sceneTag);
|
||||
mTaskId = taskId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Pair<PreviewSet, Integer> result) {
|
||||
GalleryPreviewsScene scene = getScene();
|
||||
if (scene != null) {
|
||||
scene.onGetPreviewSetSuccess(result, mTaskId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
GalleryPreviewsScene scene = getScene();
|
||||
if (scene != null) {
|
||||
scene.onGetPreviewSetFailure(e, mTaskId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInstance(SceneFragment scene) {
|
||||
return scene instanceof GalleryPreviewsScene;
|
||||
}
|
||||
}
|
||||
|
||||
private static class GalleryPreviewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
public LoadImageView image;
|
||||
@@ -300,6 +263,33 @@ public class GalleryPreviewsScene extends BaseToolbarScene {
|
||||
}
|
||||
}
|
||||
|
||||
private class GetPreviewSetListener extends EhCallback<GalleryPreviewsScene, Pair<PreviewSet, Integer>> {
|
||||
|
||||
private final int mTaskId;
|
||||
|
||||
public GetPreviewSetListener(Context context, int stageId, String sceneTag, int taskId) {
|
||||
super(context);
|
||||
mTaskId = taskId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Pair<PreviewSet, Integer> result) {
|
||||
GalleryPreviewsScene scene = GalleryPreviewsScene.this;
|
||||
scene.onGetPreviewSetSuccess(result, mTaskId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
GalleryPreviewsScene scene = GalleryPreviewsScene.this;
|
||||
scene.onGetPreviewSetFailure(e, mTaskId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private class GalleryPreviewAdapter extends RecyclerView.Adapter<GalleryPreviewHolder> {
|
||||
|
||||
private final LayoutInflater mInflater;
|
||||
@@ -344,11 +334,11 @@ public class GalleryPreviewsScene extends BaseToolbarScene {
|
||||
return;
|
||||
}
|
||||
|
||||
String url = EhUrl.getGalleryDetailUrl(mGalleryInfo.gid, mGalleryInfo.token, page, false);
|
||||
String url = EhUrl.getGalleryDetailUrl(mGalleryInfo.getGid(), mGalleryInfo.getToken(), page, false);
|
||||
EhRequest request = new EhRequest();
|
||||
request.setMethod(EhClient.METHOD_GET_PREVIEW_SET);
|
||||
request.setCallback(new GetPreviewSetListener(getContext(),
|
||||
activity.getStageId(), getTag(), taskId));
|
||||
1, getTag(), taskId));
|
||||
request.setArgs(url);
|
||||
request.enqueue(GalleryPreviewsScene.this);
|
||||
}
|
||||
|
||||
@@ -48,13 +48,13 @@ import com.hippo.ehviewer.download.DownloadManager.DownloadInfoListener
|
||||
import com.hippo.ehviewer.ui.CommonOperations
|
||||
import com.hippo.ehviewer.ui.dialog.SelectItemWithIconAdapter
|
||||
import com.hippo.ehviewer.widget.SimpleRatingView
|
||||
import com.hippo.scene.Announcer
|
||||
import com.hippo.scene.SceneFragment
|
||||
import com.hippo.view.ViewTransition
|
||||
import com.hippo.widget.LoadImageView
|
||||
import com.hippo.widget.recyclerview.AutoStaggeredGridLayoutManager
|
||||
import com.hippo.yorozuya.ViewUtils
|
||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import eu.kanade.tachiyomi.util.lang.withUIContext
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import rikka.core.res.resolveColor
|
||||
@@ -112,10 +112,6 @@ class HistoryScene : BaseToolbarScene() {
|
||||
mFavouriteStatusRouter.removeListener(mFavouriteStatusRouterListener)
|
||||
}
|
||||
|
||||
override fun getNavCheckedItem(): Int {
|
||||
return R.id.nav_history
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@@ -196,9 +192,13 @@ class HistoryScene : BaseToolbarScene() {
|
||||
if (DialogInterface.BUTTON_POSITIVE != which) {
|
||||
return@setPositiveButton
|
||||
}
|
||||
EhDB.clearHistoryInfo()
|
||||
mAdapter.refresh()
|
||||
mAdapter.notifyDataSetChanged()
|
||||
lifecycleScope.launchIO {
|
||||
EhDB.clearHistoryInfo()
|
||||
withUIContext {
|
||||
mAdapter.refresh()
|
||||
mAdapter.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show()
|
||||
@@ -217,8 +217,7 @@ class HistoryScene : BaseToolbarScene() {
|
||||
val args = Bundle()
|
||||
args.putString(GalleryDetailScene.KEY_ACTION, GalleryDetailScene.ACTION_GALLERY_INFO)
|
||||
args.putParcelable(GalleryDetailScene.KEY_GALLERY_INFO, gi)
|
||||
val announcer = Announcer(GalleryDetailScene::class.java).setArgs(args)
|
||||
startScene(announcer)
|
||||
navigate(R.id.galleryDetailScene, args)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -287,13 +286,13 @@ class HistoryScene : BaseToolbarScene() {
|
||||
CommonOperations.removeFromFavorites(
|
||||
activity,
|
||||
gi,
|
||||
RemoveFromFavoriteListener(context, activity.stageId, tag)
|
||||
RemoveFromFavoriteListener(context)
|
||||
)
|
||||
} else {
|
||||
CommonOperations.addToFavorites(
|
||||
activity,
|
||||
gi,
|
||||
AddToFavoriteListener(context, activity.stageId, tag)
|
||||
AddToFavoriteListener(context)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -319,8 +318,8 @@ class HistoryScene : BaseToolbarScene() {
|
||||
return true
|
||||
}
|
||||
|
||||
private class AddToFavoriteListener(context: Context?, stageId: Int, sceneTag: String?) :
|
||||
EhCallback<GalleryListScene?, Void?>(context, stageId, sceneTag) {
|
||||
private class AddToFavoriteListener(context: Context?) :
|
||||
EhCallback<GalleryListScene?, Void?>(context) {
|
||||
override fun onSuccess(result: Void?) {
|
||||
showTip(R.string.add_to_favorite_success, LENGTH_SHORT)
|
||||
}
|
||||
@@ -330,13 +329,10 @@ class HistoryScene : BaseToolbarScene() {
|
||||
}
|
||||
|
||||
override fun onCancel() {}
|
||||
override fun isInstance(scene: SceneFragment): Boolean {
|
||||
return scene is GalleryListScene
|
||||
}
|
||||
}
|
||||
|
||||
private class RemoveFromFavoriteListener(context: Context?, stageId: Int, sceneTag: String?) :
|
||||
EhCallback<GalleryListScene?, Void?>(context, stageId, sceneTag) {
|
||||
private class RemoveFromFavoriteListener(context: Context?) :
|
||||
EhCallback<GalleryListScene?, Void?>(context) {
|
||||
override fun onSuccess(result: Void?) {
|
||||
showTip(R.string.remove_from_favorite_success, LENGTH_SHORT)
|
||||
}
|
||||
@@ -346,9 +342,6 @@ class HistoryScene : BaseToolbarScene() {
|
||||
}
|
||||
|
||||
override fun onCancel() {}
|
||||
override fun isInstance(scene: SceneFragment): Boolean {
|
||||
return scene is GalleryListScene
|
||||
}
|
||||
}
|
||||
|
||||
private class HistoryHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
@@ -450,9 +443,13 @@ class HistoryScene : BaseToolbarScene() {
|
||||
|
||||
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
|
||||
val mPosition = viewHolder.bindingAdapterPosition
|
||||
val info: HistoryInfo? = mAdapter.peek(mPosition)
|
||||
info?.let { EhDB.deleteHistoryInfo(info) }
|
||||
mAdapter.refresh()
|
||||
lifecycleScope.launchIO {
|
||||
val info: HistoryInfo? = mAdapter.peek(mPosition)
|
||||
info?.let { EhDB.deleteHistoryInfo(info) }
|
||||
withUIContext {
|
||||
mAdapter.refresh()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,8 +32,6 @@ import com.hippo.ehviewer.R;
|
||||
import com.hippo.ehviewer.client.EhClient;
|
||||
import com.hippo.ehviewer.client.EhRequest;
|
||||
import com.hippo.ehviewer.ui.MainActivity;
|
||||
import com.hippo.scene.Announcer;
|
||||
import com.hippo.scene.SceneFragment;
|
||||
import com.hippo.util.ExceptionUtils;
|
||||
import com.hippo.view.ViewTransition;
|
||||
import com.hippo.yorozuya.AssertUtils;
|
||||
@@ -97,7 +95,7 @@ public final class ProgressScene extends BaseScene implements View.OnClickListen
|
||||
.setMethod(EhClient.METHOD_GET_GALLERY_TOKEN)
|
||||
.setArgs(mGid, mPToken, mPage)
|
||||
.setCallback(new GetGalleryTokenListener(context,
|
||||
activity.getStageId(), getTag()));
|
||||
1, getTag()));
|
||||
request.enqueue(this);
|
||||
return true;
|
||||
}
|
||||
@@ -209,8 +207,7 @@ public final class ProgressScene extends BaseScene implements View.OnClickListen
|
||||
arg.putLong(GalleryDetailScene.KEY_GID, mGid);
|
||||
arg.putString(GalleryDetailScene.KEY_TOKEN, result);
|
||||
arg.putInt(GalleryDetailScene.KEY_PAGE, mPage);
|
||||
startScene(new Announcer(GalleryDetailScene.class).setArgs(arg));
|
||||
finish();
|
||||
navigate(R.id.galleryDetailScene, arg);
|
||||
}
|
||||
|
||||
private void onGetGalleryTokenFailure(Exception e) {
|
||||
@@ -226,35 +223,26 @@ public final class ProgressScene extends BaseScene implements View.OnClickListen
|
||||
}
|
||||
}
|
||||
|
||||
private static class GetGalleryTokenListener extends EhCallback<ProgressScene, String> {
|
||||
private class GetGalleryTokenListener extends EhCallback<ProgressScene, String> {
|
||||
|
||||
public GetGalleryTokenListener(Context context, int stageId, String sceneTag) {
|
||||
super(context, stageId, sceneTag);
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(String result) {
|
||||
ProgressScene scene = getScene();
|
||||
if (scene != null) {
|
||||
scene.onGetGalleryTokenSuccess(result);
|
||||
}
|
||||
ProgressScene scene = ProgressScene.this;
|
||||
scene.onGetGalleryTokenSuccess(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
ProgressScene scene = getScene();
|
||||
if (scene != null) {
|
||||
scene.onGetGalleryTokenFailure(e);
|
||||
}
|
||||
ProgressScene scene = ProgressScene.this;
|
||||
scene.onGetGalleryTokenFailure(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInstance(SceneFragment scene) {
|
||||
return scene instanceof ProgressScene;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,97 +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.google.android.material.button.MaterialButton;
|
||||
import com.google.android.material.button.MaterialButtonToggleGroup;
|
||||
import com.hippo.ehviewer.EhApplication;
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.ehviewer.Settings;
|
||||
import com.hippo.ehviewer.client.EhUrl;
|
||||
import com.hippo.ehviewer.ui.MainActivity;
|
||||
import com.hippo.yorozuya.ViewUtils;
|
||||
|
||||
public class SelectSiteScene extends SolidScene implements View.OnClickListener {
|
||||
|
||||
private MaterialButtonToggleGroup mButtonGroup;
|
||||
private View mOk;
|
||||
|
||||
@Override
|
||||
public boolean needShowLeftDrawer() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.scene_select_site, container, false);
|
||||
|
||||
mButtonGroup = (MaterialButtonToggleGroup) ViewUtils.$$(view, R.id.button_group);
|
||||
if (EhApplication.getEhCookieStore().hasSignedIn()) {
|
||||
((MaterialButton) view.findViewById(R.id.site_ex)).setChecked(true);
|
||||
} else {
|
||||
((MaterialButton) view.findViewById(R.id.site_e)).setChecked(true);
|
||||
}
|
||||
mOk = ViewUtils.$$(view, R.id.ok);
|
||||
|
||||
mOk.setOnClickListener(this);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
|
||||
mButtonGroup = null;
|
||||
mOk = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
MainActivity activity = getMainActivity();
|
||||
if (null == activity || null == mButtonGroup) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (v == mOk) {
|
||||
int id = mButtonGroup.getCheckedButtonId();
|
||||
if (id == R.id.site_e) {
|
||||
Settings.putSelectSite(false);
|
||||
Settings.putGallerySite(EhUrl.SITE_E);
|
||||
startSceneForCheckStep(CHECK_STEP_SELECT_SITE, getArguments());
|
||||
finish();
|
||||
} else if (id == R.id.site_ex) {
|
||||
Settings.putSelectSite(false);
|
||||
Settings.putGallerySite(EhUrl.SITE_EX);
|
||||
startSceneForCheckStep(CHECK_STEP_SELECT_SITE, getArguments());
|
||||
finish();
|
||||
} else {
|
||||
showTip(R.string.no_select, LENGTH_SHORT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,438 +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.content.Context;
|
||||
import android.graphics.Paint;
|
||||
import android.os.Bundle;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.google.android.material.textfield.TextInputLayout;
|
||||
import com.hippo.app.BaseDialogBuilder;
|
||||
import com.hippo.ehviewer.EhApplication;
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.ehviewer.Settings;
|
||||
import com.hippo.ehviewer.UrlOpener;
|
||||
import com.hippo.ehviewer.client.EhClient;
|
||||
import com.hippo.ehviewer.client.EhRequest;
|
||||
import com.hippo.ehviewer.client.EhUrl;
|
||||
import com.hippo.ehviewer.client.EhUtils;
|
||||
import com.hippo.ehviewer.client.parser.ProfileParser;
|
||||
import com.hippo.ehviewer.ui.MainActivity;
|
||||
import com.hippo.scene.Announcer;
|
||||
import com.hippo.scene.SceneFragment;
|
||||
import com.hippo.util.ExceptionUtils;
|
||||
import com.hippo.yorozuya.AssertUtils;
|
||||
import com.hippo.yorozuya.IntIdGenerator;
|
||||
import com.hippo.yorozuya.ViewUtils;
|
||||
|
||||
public final class SignInScene extends SolidScene implements EditText.OnEditorActionListener,
|
||||
View.OnClickListener {
|
||||
|
||||
private static final String KEY_REQUEST_ID = "request_id";
|
||||
|
||||
private static final int REQUEST_CODE_WEBVIEW = 0;
|
||||
private static final int REQUEST_CODE_COOKIE = 0;
|
||||
|
||||
/*---------------
|
||||
View life cycle
|
||||
---------------*/
|
||||
@Nullable
|
||||
private View mProgress;
|
||||
@Nullable
|
||||
private TextInputLayout mUsernameLayout;
|
||||
@Nullable
|
||||
private TextInputLayout mPasswordLayout;
|
||||
@Nullable
|
||||
private EditText mUsername;
|
||||
@Nullable
|
||||
private EditText mPassword;
|
||||
@Nullable
|
||||
private View mRegister;
|
||||
@Nullable
|
||||
private View mSignIn;
|
||||
@Nullable
|
||||
private TextView mSignInViaWebView;
|
||||
@Nullable
|
||||
private TextView mSignInViaCookies;
|
||||
@Nullable
|
||||
private TextView mSkipSigningIn;
|
||||
|
||||
private boolean mSigningIn;
|
||||
private int mRequestId = IntIdGenerator.INVALID_ID;
|
||||
|
||||
@Override
|
||||
public boolean needShowLeftDrawer() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
onInit();
|
||||
} else {
|
||||
onRestore(savedInstanceState);
|
||||
}
|
||||
}
|
||||
|
||||
private void onInit() {
|
||||
}
|
||||
|
||||
private void onRestore(Bundle savedInstanceState) {
|
||||
mRequestId = savedInstanceState.getInt(KEY_REQUEST_ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putInt(KEY_REQUEST_ID, mRequestId);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.scene_login, container, false);
|
||||
|
||||
View loginForm = ViewUtils.$$(view, R.id.login_form);
|
||||
mProgress = ViewUtils.$$(view, R.id.progress);
|
||||
mUsernameLayout = (TextInputLayout) ViewUtils.$$(loginForm, R.id.username_layout);
|
||||
mUsername = mUsernameLayout.getEditText();
|
||||
AssertUtils.assertNotNull(mUsername);
|
||||
mPasswordLayout = (TextInputLayout) ViewUtils.$$(loginForm, R.id.password_layout);
|
||||
mPassword = mPasswordLayout.getEditText();
|
||||
AssertUtils.assertNotNull(mPassword);
|
||||
mRegister = ViewUtils.$$(loginForm, R.id.register);
|
||||
mSignIn = ViewUtils.$$(loginForm, R.id.sign_in);
|
||||
mSignInViaWebView = (TextView) ViewUtils.$$(loginForm, R.id.sign_in_via_webview);
|
||||
mSignInViaCookies = (TextView) ViewUtils.$$(loginForm, R.id.sign_in_via_cookies);
|
||||
mSkipSigningIn = (TextView) ViewUtils.$$(loginForm, R.id.tourist_mode);
|
||||
|
||||
mSignInViaWebView.setPaintFlags(mSignInViaWebView.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG);
|
||||
mSignInViaCookies.setPaintFlags(mSignInViaCookies.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG);
|
||||
mSkipSigningIn.setPaintFlags(mSignInViaCookies.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG);
|
||||
|
||||
mPassword.setOnEditorActionListener(this);
|
||||
|
||||
mRegister.setOnClickListener(this);
|
||||
mSignIn.setOnClickListener(this);
|
||||
mSignInViaWebView.setOnClickListener(this);
|
||||
mSignInViaCookies.setOnClickListener(this);
|
||||
mSkipSigningIn.setOnClickListener(this);
|
||||
|
||||
Context context = getContext();
|
||||
AssertUtils.assertNotNull(context);
|
||||
EhApplication application = (EhApplication) context.getApplicationContext();
|
||||
if (application.containGlobalStuff(mRequestId)) {
|
||||
mSigningIn = true;
|
||||
// request exist
|
||||
showProgress(false);
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
// Show IME
|
||||
if (mProgress != null && View.INVISIBLE != mProgress.getVisibility()) {
|
||||
showSoftInput(mUsername);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
|
||||
mProgress = null;
|
||||
mUsernameLayout = null;
|
||||
mPasswordLayout = null;
|
||||
mUsername = null;
|
||||
mPassword = null;
|
||||
mRegister = null;
|
||||
mSignIn = null;
|
||||
mSignInViaWebView = null;
|
||||
mSignInViaCookies = null;
|
||||
mSkipSigningIn = null;
|
||||
}
|
||||
|
||||
private void showProgress(boolean animation) {
|
||||
if (null != mProgress && View.VISIBLE != mProgress.getVisibility()) {
|
||||
if (animation) {
|
||||
mProgress.setAlpha(0.0f);
|
||||
mProgress.setVisibility(View.VISIBLE);
|
||||
mProgress.animate().alpha(1.0f).setDuration(500).start();
|
||||
} else {
|
||||
mProgress.setAlpha(1.0f);
|
||||
mProgress.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void hideProgress() {
|
||||
if (null != mProgress) {
|
||||
mProgress.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSceneResult(int requestCode, int resultCode, Bundle data) {
|
||||
if (REQUEST_CODE_WEBVIEW == requestCode) {
|
||||
if (RESULT_OK == resultCode) {
|
||||
getProfile();
|
||||
}
|
||||
} else {
|
||||
super.onSceneResult(requestCode, resultCode, data);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
MainActivity activity = getMainActivity();
|
||||
if (null == activity) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mRegister == v) {
|
||||
UrlOpener.openUrl(activity, EhUrl.URL_REGISTER, false);
|
||||
} else if (mSignIn == v) {
|
||||
signIn();
|
||||
} else if (mSignInViaWebView == v) {
|
||||
startScene(new Announcer(WebViewSignInScene.class).setRequestCode(this, REQUEST_CODE_WEBVIEW));
|
||||
} else if (mSignInViaCookies == v) {
|
||||
startScene(new Announcer(CookieSignInScene.class).setRequestCode(this, REQUEST_CODE_COOKIE));
|
||||
} else if (mSkipSigningIn == v) {
|
||||
// Set gallery size SITE_E if skip sign in
|
||||
Settings.putGallerySite(EhUrl.SITE_E);
|
||||
redirectTo();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
||||
if (v == mPassword) {
|
||||
if (actionId == EditorInfo.IME_ACTION_DONE || actionId == EditorInfo.IME_NULL) {
|
||||
signIn();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void signIn() {
|
||||
if (mSigningIn) {
|
||||
return;
|
||||
}
|
||||
|
||||
Context context = getContext();
|
||||
MainActivity activity = getMainActivity();
|
||||
if (null == context || null == activity || null == mUsername || null == mPassword || null == mUsernameLayout ||
|
||||
null == mPasswordLayout) {
|
||||
return;
|
||||
}
|
||||
|
||||
String username = mUsername.getText().toString();
|
||||
String password = mPassword.getText().toString();
|
||||
|
||||
if (username.isEmpty()) {
|
||||
mUsernameLayout.setError(getString(R.string.error_username_cannot_empty));
|
||||
return;
|
||||
} else {
|
||||
mUsernameLayout.setError(null);
|
||||
}
|
||||
|
||||
if (password.isEmpty()) {
|
||||
mPasswordLayout.setError(getString(R.string.error_password_cannot_empty));
|
||||
return;
|
||||
} else {
|
||||
mPasswordLayout.setError(null);
|
||||
}
|
||||
|
||||
hideSoftInput();
|
||||
showProgress(true);
|
||||
|
||||
// Clean up for sign in
|
||||
EhUtils.signOut();
|
||||
|
||||
EhCallback<?, ?> callback = new SignInListener(context,
|
||||
activity.getStageId(), getTag());
|
||||
mRequestId = ((EhApplication) context.getApplicationContext()).putGlobalStuff(callback);
|
||||
EhRequest request = new EhRequest()
|
||||
.setMethod(EhClient.METHOD_SIGN_IN)
|
||||
.setArgs(username, password)
|
||||
.setCallback(callback);
|
||||
request.enqueue(this);
|
||||
|
||||
mSigningIn = true;
|
||||
}
|
||||
|
||||
private void getProfile() {
|
||||
Context context = getContext();
|
||||
MainActivity activity = getMainActivity();
|
||||
if (null == context || null == activity) {
|
||||
return;
|
||||
}
|
||||
|
||||
hideSoftInput();
|
||||
showProgress(true);
|
||||
|
||||
EhCallback<?, ?> callback = new GetProfileListener(context,
|
||||
activity.getStageId(), getTag());
|
||||
mRequestId = ((EhApplication) context.getApplicationContext()).putGlobalStuff(callback);
|
||||
EhRequest request = new EhRequest()
|
||||
.setMethod(EhClient.METHOD_GET_PROFILE)
|
||||
.setCallback(callback);
|
||||
request.enqueue();
|
||||
|
||||
new EhRequest().setMethod(EhClient.METHOD_GET_UCONFIG).enqueue();
|
||||
}
|
||||
|
||||
private void redirectTo() {
|
||||
Settings.putNeedSignIn(false);
|
||||
MainActivity activity = getMainActivity();
|
||||
if (null != activity) {
|
||||
startSceneForCheckStep(CHECK_STEP_SIGN_IN, getArguments());
|
||||
}
|
||||
finish();
|
||||
}
|
||||
|
||||
private void whetherToSkip(Exception e) {
|
||||
Context context = getContext();
|
||||
if (null == context) {
|
||||
return;
|
||||
}
|
||||
|
||||
new BaseDialogBuilder(context)
|
||||
.setTitle(R.string.sign_in_failed)
|
||||
.setMessage(ExceptionUtils.getReadableString(e) + "\n\n" + getString(R.string.sign_in_failed_tip))
|
||||
.setPositiveButton(R.string.get_it, null)
|
||||
.show();
|
||||
}
|
||||
|
||||
public void onSignInEnd(Exception e) {
|
||||
Context context = getContext();
|
||||
if (null == context) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (EhApplication.getEhCookieStore().hasSignedIn()) {
|
||||
getProfile();
|
||||
} else {
|
||||
mSigningIn = false;
|
||||
hideProgress();
|
||||
whetherToSkip(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void onGetProfileEnd() {
|
||||
mSigningIn = false;
|
||||
redirectTo();
|
||||
}
|
||||
|
||||
private static class SignInListener extends EhCallback<SignInScene, String> {
|
||||
|
||||
public SignInListener(Context context, int stageId, String sceneTag) {
|
||||
super(context, stageId, sceneTag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(String result) {
|
||||
getApplication().removeGlobalStuff(this);
|
||||
Settings.putDisplayName(result);
|
||||
|
||||
SignInScene scene = getScene();
|
||||
if (scene != null) {
|
||||
scene.onSignInEnd(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
getApplication().removeGlobalStuff(this);
|
||||
e.printStackTrace();
|
||||
|
||||
SignInScene scene = getScene();
|
||||
if (scene != null) {
|
||||
scene.onSignInEnd(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
getApplication().removeGlobalStuff(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInstance(SceneFragment scene) {
|
||||
return scene instanceof SignInScene;
|
||||
}
|
||||
}
|
||||
|
||||
private static class GetProfileListener extends EhCallback<SignInScene, ProfileParser.Result> {
|
||||
|
||||
public GetProfileListener(Context context, int stageId, String sceneTag) {
|
||||
super(context, stageId, sceneTag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(ProfileParser.Result result) {
|
||||
getApplication().removeGlobalStuff(this);
|
||||
Settings.putDisplayName(result.displayName);
|
||||
Settings.putAvatar(result.avatar);
|
||||
|
||||
SignInScene scene = getScene();
|
||||
if (scene != null) {
|
||||
scene.onGetProfileEnd();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
getApplication().removeGlobalStuff(this);
|
||||
e.printStackTrace();
|
||||
|
||||
SignInScene scene = getScene();
|
||||
if (scene != null) {
|
||||
scene.onGetProfileEnd();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
getApplication().removeGlobalStuff(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInstance(SceneFragment scene) {
|
||||
return scene instanceof SignInScene;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,70 +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.util.Log;
|
||||
|
||||
import com.hippo.ehviewer.Settings;
|
||||
import com.hippo.scene.Announcer;
|
||||
|
||||
/**
|
||||
* Scene for safety, can't be covered
|
||||
*/
|
||||
public class SolidScene extends BaseScene {
|
||||
|
||||
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_SIGN_IN:
|
||||
if (Settings.getSelectSite()) {
|
||||
startScene(new Announcer(SelectSiteScene.class).setArgs(args), true);
|
||||
break;
|
||||
}
|
||||
case CHECK_STEP_SELECT_SITE:
|
||||
String targetScene = null;
|
||||
Bundle targetArgs = null;
|
||||
if (null != args) {
|
||||
targetScene = args.getString(KEY_TARGET_SCENE);
|
||||
targetArgs = args.getBundle(KEY_TARGET_ARGS);
|
||||
}
|
||||
|
||||
Class<?> clazz = null;
|
||||
if (targetScene != null) {
|
||||
try {
|
||||
clazz = Class.forName(targetScene);
|
||||
} catch (ClassNotFoundException e) {
|
||||
Log.e(TAG, "Can't find class with name: " + targetScene);
|
||||
}
|
||||
}
|
||||
|
||||
if (clazz != null) {
|
||||
startScene(new Announcer(clazz).setArgs(targetArgs));
|
||||
} else {
|
||||
Bundle newArgs = new Bundle();
|
||||
newArgs.putString(GalleryListScene.KEY_ACTION, Settings.getLaunchPageGalleryListSceneAction());
|
||||
startScene(new Announcer(GalleryListScene.class).setArgs(newArgs));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,155 +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.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.webkit.CookieManager;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.hippo.ehviewer.EhApplication;
|
||||
import com.hippo.ehviewer.client.EhCookieStore;
|
||||
import com.hippo.ehviewer.client.EhUrl;
|
||||
import com.hippo.ehviewer.client.EhUtils;
|
||||
import com.hippo.ehviewer.widget.DialogWebChromeClient;
|
||||
import com.hippo.yorozuya.AssertUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import okhttp3.Cookie;
|
||||
import okhttp3.HttpUrl;
|
||||
import rikka.core.res.ResourcesKt;
|
||||
|
||||
public class WebViewSignInScene extends SolidScene {
|
||||
|
||||
/*---------------
|
||||
View life cycle
|
||||
---------------*/
|
||||
@Nullable
|
||||
private WebView mWebView;
|
||||
|
||||
@Override
|
||||
public boolean needShowLeftDrawer() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||
@Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
Context context = getContext();
|
||||
AssertUtils.assertNotNull(context);
|
||||
|
||||
EhUtils.signOut();
|
||||
|
||||
// http://stackoverflow.com/questions/32284642/how-to-handle-an-uncatched-exception
|
||||
CookieManager cookieManager = CookieManager.getInstance();
|
||||
cookieManager.flush();
|
||||
cookieManager.removeAllCookies(null);
|
||||
cookieManager.removeSessionCookies(null);
|
||||
|
||||
mWebView = new WebView(context);
|
||||
mWebView.setBackgroundColor(ResourcesKt.resolveColor(getTheme(), android.R.attr.colorBackground));
|
||||
mWebView.getSettings().setBuiltInZoomControls(true);
|
||||
mWebView.getSettings().setDisplayZoomControls(false);
|
||||
mWebView.getSettings().setJavaScriptEnabled(true);
|
||||
mWebView.setWebViewClient(new LoginWebViewClient());
|
||||
mWebView.setWebChromeClient(new DialogWebChromeClient(context));
|
||||
mWebView.loadUrl(EhUrl.URL_SIGN_IN);
|
||||
return mWebView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
|
||||
if (null != mWebView) {
|
||||
mWebView.destroy();
|
||||
mWebView = null;
|
||||
}
|
||||
}
|
||||
|
||||
private class LoginWebViewClient extends WebViewClient {
|
||||
|
||||
public List<Cookie> parseCookies(HttpUrl url, String cookieStrings) {
|
||||
if (cookieStrings == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<Cookie> cookies = null;
|
||||
String[] pieces = cookieStrings.split(";");
|
||||
for (String piece : pieces) {
|
||||
Cookie cookie = Cookie.parse(url, piece);
|
||||
if (cookie == null) {
|
||||
continue;
|
||||
}
|
||||
if (cookies == null) {
|
||||
cookies = new ArrayList<>();
|
||||
}
|
||||
cookies.add(cookie);
|
||||
}
|
||||
|
||||
return cookies != null ? cookies : Collections.emptyList();
|
||||
}
|
||||
|
||||
private void addCookie(String domain, Cookie cookie) {
|
||||
EhApplication.getEhCookieStore().addCookie(EhCookieStore.newCookie(cookie, domain, true, true, true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageFinished(WebView view, String url) {
|
||||
Context context = getContext();
|
||||
if (context == null) {
|
||||
return;
|
||||
}
|
||||
HttpUrl httpUrl = HttpUrl.parse(url);
|
||||
if (httpUrl == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String cookieString = CookieManager.getInstance().getCookie(EhUrl.HOST_E);
|
||||
List<Cookie> cookies = parseCookies(httpUrl, cookieString);
|
||||
boolean getId = false;
|
||||
boolean getHash = false;
|
||||
for (Cookie cookie : cookies) {
|
||||
if (EhCookieStore.KEY_IPD_MEMBER_ID.equals(cookie.name())) {
|
||||
getId = true;
|
||||
} else if (EhCookieStore.KEY_IPD_PASS_HASH.equals(cookie.name())) {
|
||||
getHash = true;
|
||||
}
|
||||
addCookie(EhUrl.DOMAIN_EX, cookie);
|
||||
addCookie(EhUrl.DOMAIN_E, cookie);
|
||||
}
|
||||
|
||||
if (getId && getHash) {
|
||||
setResult(RESULT_OK, null);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
package com.hippo.ehviewer.widget;
|
||||
|
||||
import static androidx.core.util.ObjectsCompat.requireNonNull;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Gravity;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewParent;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
||||
import androidx.core.math.MathUtils;
|
||||
import androidx.core.view.GravityCompat;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.drawerlayout.widget.DrawerLayout;
|
||||
import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
|
||||
|
||||
import com.drakeet.drawer.FullDraggableHelper;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
import com.hippo.yorozuya.LayoutUtils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class AboveSnackerLayout extends FrameLayout implements CoordinatorLayout.AttachedBehavior, FullDraggableHelper.Callback {
|
||||
@NonNull
|
||||
private final FullDraggableHelper helper;
|
||||
|
||||
private DrawerLayout drawerLayout;
|
||||
|
||||
private List<View> mAboveSnackViewList;
|
||||
|
||||
public AboveSnackerLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
helper = new FullDraggableHelper(context, this);
|
||||
}
|
||||
|
||||
public AboveSnackerLayout(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
helper = new FullDraggableHelper(context, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
ensureDrawerLayout();
|
||||
}
|
||||
|
||||
private void ensureDrawerLayout() {
|
||||
ViewParent parent = getParent().getParent();
|
||||
if (!(parent instanceof DrawerLayout)) {
|
||||
throw new IllegalStateException("This " + this + " must be added to a DrawerLayout");
|
||||
}
|
||||
drawerLayout = (DrawerLayout) parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent event) {
|
||||
return helper.onInterceptTouchEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
return helper.onTouchEvent(event);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public View getDrawerMainContainer() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDrawerOpen(int gravity) {
|
||||
return drawerLayout.isDrawerOpen(gravity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasEnabledDrawer(int gravity) {
|
||||
return drawerLayout.getDrawerLockMode(gravity) == DrawerLayout.LOCK_MODE_UNLOCKED
|
||||
&& findDrawerWithGravity(gravity) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offsetDrawer(int gravity, float offset) {
|
||||
setDrawerToOffset(gravity, offset);
|
||||
drawerLayout.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void smoothOpenDrawer(int gravity) {
|
||||
drawerLayout.openDrawer(gravity, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void smoothCloseDrawer(int gravity) {
|
||||
drawerLayout.closeDrawer(gravity, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDrawerDragging() {
|
||||
List<DrawerLayout.DrawerListener> drawerListeners = getDrawerListeners();
|
||||
if (drawerListeners != null) {
|
||||
int listenerCount = drawerListeners.size();
|
||||
for (int i = listenerCount - 1; i >= 0; --i) {
|
||||
drawerListeners.get(i).onDrawerStateChanged(DrawerLayout.STATE_DRAGGING);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected List<DrawerLayout.DrawerListener> getDrawerListeners() {
|
||||
try {
|
||||
Field field = DrawerLayout.class.getDeclaredField("mListeners");
|
||||
field.setAccessible(true);
|
||||
// noinspection unchecked
|
||||
return (List<DrawerLayout.DrawerListener>) field.get(drawerLayout);
|
||||
} catch (Exception e) {
|
||||
// throw to let developer know the api is changed
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void setDrawerToOffset(int gravity, float offset) {
|
||||
View drawerView = findDrawerWithGravity(gravity);
|
||||
float slideOffsetPercent = MathUtils.clamp(offset / requireNonNull(drawerView).getWidth(), 0f, 1f);
|
||||
try {
|
||||
Method method = DrawerLayout.class.getDeclaredMethod("moveDrawerToOffset", View.class, float.class);
|
||||
method.setAccessible(true);
|
||||
method.invoke(drawerLayout, drawerView, slideOffsetPercent);
|
||||
drawerView.setVisibility(VISIBLE);
|
||||
} catch (Exception e) {
|
||||
// throw to let developer know the api is changed
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Copied from DrawerLayout
|
||||
@Nullable
|
||||
private View findDrawerWithGravity(int gravity) {
|
||||
final int absHorizontalGravity = GravityCompat.getAbsoluteGravity(gravity, ViewCompat.getLayoutDirection(drawerLayout)) & Gravity.HORIZONTAL_GRAVITY_MASK;
|
||||
final int childCount = drawerLayout.getChildCount();
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
final View child = drawerLayout.getChildAt(i);
|
||||
final int childAbsGravity = getDrawerViewAbsoluteGravity(child);
|
||||
if ((childAbsGravity & Gravity.HORIZONTAL_GRAVITY_MASK) == absHorizontalGravity) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Copied from DrawerLayout
|
||||
private int getDrawerViewAbsoluteGravity(View drawerView) {
|
||||
final int gravity = ((DrawerLayout.LayoutParams) drawerView.getLayoutParams()).gravity;
|
||||
return GravityCompat.getAbsoluteGravity(gravity, ViewCompat.getLayoutDirection(drawerLayout));
|
||||
}
|
||||
|
||||
public void addAboveSnackView(View view) {
|
||||
if (null == mAboveSnackViewList) {
|
||||
mAboveSnackViewList = new ArrayList<>();
|
||||
}
|
||||
mAboveSnackViewList.add(view);
|
||||
}
|
||||
|
||||
public void removeAboveSnackView(View view) {
|
||||
if (null == mAboveSnackViewList) {
|
||||
return;
|
||||
}
|
||||
mAboveSnackViewList.remove(view);
|
||||
}
|
||||
|
||||
public int getAboveSnackViewCount() {
|
||||
return null == mAboveSnackViewList ? 0 : mAboveSnackViewList.size();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public View getAboveSnackViewAt(int index) {
|
||||
if (null == mAboveSnackViewList || index < 0 || index >= mAboveSnackViewList.size()) {
|
||||
return null;
|
||||
} else {
|
||||
return mAboveSnackViewList.get(index);
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public AboveSnackerLayout.Behavior getBehavior() {
|
||||
return new AboveSnackerLayout.Behavior();
|
||||
}
|
||||
|
||||
public static class Behavior extends CoordinatorLayout.Behavior<AboveSnackerLayout> {
|
||||
|
||||
@Override
|
||||
public boolean layoutDependsOn(@NonNull CoordinatorLayout parent, @NonNull AboveSnackerLayout child, @NonNull View dependency) {
|
||||
return dependency instanceof Snackbar.SnackbarLayout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDependentViewChanged(@NonNull CoordinatorLayout parent, AboveSnackerLayout child, @NonNull View dependency) {
|
||||
for (int i = 0, n = child.getAboveSnackViewCount(); i < n; i++) {
|
||||
View view = child.getAboveSnackViewAt(i);
|
||||
if (view != null) {
|
||||
float translationY = Math.min(0, dependency.getTranslationY() - dependency.getHeight() - LayoutUtils.dp2pix(view.getContext(), 8));
|
||||
ViewCompat.animate(view).setInterpolator(new FastOutSlowInInterpolator()).translationY(translationY).setDuration(150).start();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDependentViewRemoved(@NonNull CoordinatorLayout parent, @NonNull AboveSnackerLayout child, @NonNull View dependency) {
|
||||
for (int i = 0, n = child.getAboveSnackViewCount(); i < n; i++) {
|
||||
View view = child.getAboveSnackViewAt(i);
|
||||
if (view != null) {
|
||||
ViewCompat.animate(view).setInterpolator(new FastOutSlowInInterpolator()).translationY(0).setDuration(75).start();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,112 +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/>.
|
||||
*/
|
||||
|
||||
package com.hippo.ehviewer.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
|
||||
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
import com.hippo.scene.StageLayout;
|
||||
import com.hippo.yorozuya.LayoutUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class EhStageLayout extends StageLayout implements CoordinatorLayout.AttachedBehavior {
|
||||
|
||||
private List<View> mAboveSnackViewList;
|
||||
|
||||
public EhStageLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public EhStageLayout(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
}
|
||||
|
||||
public void addAboveSnackView(View view) {
|
||||
if (null == mAboveSnackViewList) {
|
||||
mAboveSnackViewList = new ArrayList<>();
|
||||
}
|
||||
mAboveSnackViewList.add(view);
|
||||
}
|
||||
|
||||
public void removeAboveSnackView(View view) {
|
||||
if (null == mAboveSnackViewList) {
|
||||
return;
|
||||
}
|
||||
mAboveSnackViewList.remove(view);
|
||||
}
|
||||
|
||||
public int getAboveSnackViewCount() {
|
||||
return null == mAboveSnackViewList ? 0 : mAboveSnackViewList.size();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public View getAboveSnackViewAt(int index) {
|
||||
if (null == mAboveSnackViewList || index < 0 || index >= mAboveSnackViewList.size()) {
|
||||
return null;
|
||||
} else {
|
||||
return mAboveSnackViewList.get(index);
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public EhStageLayout.Behavior getBehavior() {
|
||||
return new EhStageLayout.Behavior();
|
||||
}
|
||||
|
||||
public static class Behavior extends CoordinatorLayout.Behavior<EhStageLayout> {
|
||||
|
||||
@Override
|
||||
public boolean layoutDependsOn(@NonNull CoordinatorLayout parent, @NonNull EhStageLayout child, @NonNull View dependency) {
|
||||
return dependency instanceof Snackbar.SnackbarLayout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDependentViewChanged(@NonNull CoordinatorLayout parent, EhStageLayout child, @NonNull View dependency) {
|
||||
for (int i = 0, n = child.getAboveSnackViewCount(); i < n; i++) {
|
||||
View view = child.getAboveSnackViewAt(i);
|
||||
if (view != null) {
|
||||
float translationY = Math.min(0, dependency.getTranslationY() - dependency.getHeight() - LayoutUtils.dp2pix(view.getContext(), 8));
|
||||
ViewCompat.animate(view).setInterpolator(new FastOutSlowInInterpolator()).translationY(translationY).setDuration(150).start();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDependentViewRemoved(@NonNull CoordinatorLayout parent, @NonNull EhStageLayout child, @NonNull View dependency) {
|
||||
for (int i = 0, n = child.getAboveSnackViewCount(); i < n; i++) {
|
||||
View view = child.getAboveSnackViewAt(i);
|
||||
if (view != null) {
|
||||
ViewCompat.animate(view).setInterpolator(new FastOutSlowInInterpolator()).translationY(0).setDuration(75).start();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,50 +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.scene;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
public final class Announcer {
|
||||
|
||||
Class<?> clazz;
|
||||
Bundle args;
|
||||
SceneFragment requestFrom;
|
||||
int requestCode;
|
||||
|
||||
public Announcer(Class<?> clazz) {
|
||||
this.clazz = clazz;
|
||||
}
|
||||
|
||||
public Class<?> getClazz() {
|
||||
return clazz;
|
||||
}
|
||||
|
||||
public Bundle getArgs() {
|
||||
return args;
|
||||
}
|
||||
|
||||
public Announcer setArgs(Bundle args) {
|
||||
this.args = args;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Announcer setRequestCode(SceneFragment requestFrom, int requestCode) {
|
||||
this.requestFrom = requestFrom;
|
||||
this.requestCode = requestCode;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -1,56 +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.scene;
|
||||
|
||||
import android.app.Application;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.hippo.yorozuya.IntIdGenerator;
|
||||
|
||||
public abstract class SceneApplication extends Application {
|
||||
|
||||
private final IntIdGenerator mIdGenerator = new IntIdGenerator();
|
||||
private final SparseArray<StageActivity> mStageMap = new SparseArray<>();
|
||||
|
||||
void registerStageActivity(StageActivity stage) {
|
||||
int id = mIdGenerator.nextId();
|
||||
mStageMap.put(id, stage);
|
||||
stage.onRegister(id);
|
||||
}
|
||||
|
||||
void registerStageActivity(StageActivity stage, int id) {
|
||||
if (mStageMap.indexOfKey(id) >= 0) {
|
||||
throw new IllegalStateException("The id exists: " + id);
|
||||
}
|
||||
|
||||
mStageMap.put(id, stage);
|
||||
stage.onRegister(id);
|
||||
}
|
||||
|
||||
void unregisterStageActivity(int id) {
|
||||
int index = mStageMap.indexOfKey(id);
|
||||
if (index >= 0) {
|
||||
StageActivity stage = mStageMap.valueAt(index);
|
||||
mStageMap.remove(id);
|
||||
stage.onUnregister();
|
||||
}
|
||||
}
|
||||
|
||||
public StageActivity findStageActivityById(int id) {
|
||||
return mStageMap.get(id);
|
||||
}
|
||||
}
|
||||
@@ -1,169 +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.scene;
|
||||
|
||||
import android.app.assist.AssistContent;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.yorozuya.collect.IntList;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import rikka.core.res.ResourcesKt;
|
||||
|
||||
public class SceneFragment extends Fragment {
|
||||
|
||||
public static final int LAUNCH_MODE_STANDARD = 0;
|
||||
public static final int LAUNCH_MODE_SINGLE_TOP = 1;
|
||||
public static final int LAUNCH_MODE_SINGLE_TASK = 2;
|
||||
/**
|
||||
* Standard scene result: operation canceled.
|
||||
*/
|
||||
public static final int RESULT_CANCELED = 0;
|
||||
/**
|
||||
* Standard scene result: operation succeeded.
|
||||
*/
|
||||
public static final int RESULT_OK = -1;
|
||||
int resultCode = RESULT_CANCELED;
|
||||
Bundle result = null;
|
||||
List<String> mRequestSceneTagList = new ArrayList<>(0);
|
||||
IntList mRequestCodeList = new IntList(0);
|
||||
|
||||
public void onNewArguments(@NonNull Bundle args) {
|
||||
}
|
||||
|
||||
public void startScene(Announcer announcer, boolean horizontal) {
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity instanceof StageActivity) {
|
||||
((StageActivity) activity).startScene(announcer, horizontal);
|
||||
}
|
||||
}
|
||||
|
||||
public void startScene(Announcer announcer) {
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity instanceof StageActivity) {
|
||||
((StageActivity) activity).startScene(announcer);
|
||||
}
|
||||
}
|
||||
|
||||
public void finish() {
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity instanceof StageActivity) {
|
||||
((StageActivity) activity).finishScene(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void finishStage() {
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity != null) {
|
||||
activity.finish();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return negative for error
|
||||
*/
|
||||
public int getStackIndex() {
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity instanceof StageActivity) {
|
||||
return ((StageActivity) activity).getSceneIndex(this);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public void onProvideAssistContent(AssistContent outContent) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
view.setTag(R.id.fragment_tag, getTag());
|
||||
view.setBackground(ResourcesKt.resolveDrawable(requireActivity().getTheme(), android.R.attr.windowBackground));
|
||||
|
||||
// Notify
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity instanceof StageActivity) {
|
||||
((StageActivity) activity).onSceneViewCreated(this, savedInstanceState);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
|
||||
// Notify
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity instanceof StageActivity) {
|
||||
((StageActivity) activity).onSceneViewDestroyed(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity instanceof StageActivity) {
|
||||
((StageActivity) activity).onSceneDestroyed(this);
|
||||
}
|
||||
}
|
||||
|
||||
void addRequest(String requestSceneTag, int requestCode) {
|
||||
mRequestSceneTagList.add(requestSceneTag);
|
||||
mRequestCodeList.add(requestCode);
|
||||
}
|
||||
|
||||
void returnResult(StageActivity stage) {
|
||||
for (int i = 0, size = Math.min(mRequestSceneTagList.size(), mRequestCodeList.size()); i < size; i++) {
|
||||
String tag = mRequestSceneTagList.get(i);
|
||||
int code = mRequestCodeList.get(i);
|
||||
SceneFragment scene = stage.findSceneByTag(tag);
|
||||
if (scene != null) {
|
||||
scene.onSceneResult(code, resultCode, result);
|
||||
}
|
||||
}
|
||||
mRequestSceneTagList.clear();
|
||||
mRequestCodeList.clear();
|
||||
}
|
||||
|
||||
protected void onSceneResult(int requestCode, int resultCode, Bundle data) {
|
||||
}
|
||||
|
||||
public void setResult(int resultCode, Bundle result) {
|
||||
this.resultCode = resultCode;
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
@IntDef({LAUNCH_MODE_STANDARD, LAUNCH_MODE_SINGLE_TOP, LAUNCH_MODE_SINGLE_TASK})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface LaunchMode {
|
||||
}
|
||||
}
|
||||
@@ -1,655 +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.scene;
|
||||
|
||||
import android.app.assist.AssistContent;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.activity.OnBackPressedCallback;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.ehviewer.ui.EhActivity;
|
||||
import com.hippo.yorozuya.AssertUtils;
|
||||
import com.hippo.yorozuya.IntIdGenerator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public abstract class StageActivity extends EhActivity {
|
||||
|
||||
public static final String ACTION_START_SCENE = "start_scene";
|
||||
public static final String KEY_SCENE_NAME = "stage_activity_scene_name";
|
||||
public static final String KEY_SCENE_ARGS = "stage_activity_scene_args";
|
||||
private static final String TAG = StageActivity.class.getSimpleName();
|
||||
private static final String KEY_STAGE_ID = "stage_activity_stage_id";
|
||||
private static final String KEY_SCENE_TAG_LIST = "stage_activity_scene_tag_list";
|
||||
private static final String KEY_NEXT_ID = "stage_activity_next_id";
|
||||
private static final Map<Class<?>, Integer> sLaunchModeMap = new HashMap<>();
|
||||
private final ArrayList<String> mSceneTagList = new ArrayList<>();
|
||||
private final ArrayList<String> mDelaySceneTagList = new ArrayList<>();
|
||||
private final AtomicInteger mIdGenerator = new AtomicInteger();
|
||||
private final SceneViewComparator mSceneViewComparator = new SceneViewComparator();
|
||||
private final OnBackPressedCallback callback = new BackPressCallBack();
|
||||
private int mStageId = IntIdGenerator.INVALID_ID;
|
||||
|
||||
public static void registerLaunchMode(Class<?> clazz, @SceneFragment.LaunchMode int launchMode) {
|
||||
if (launchMode != SceneFragment.LAUNCH_MODE_STANDARD &&
|
||||
launchMode != SceneFragment.LAUNCH_MODE_SINGLE_TOP &&
|
||||
launchMode != SceneFragment.LAUNCH_MODE_SINGLE_TASK) {
|
||||
throw new IllegalStateException("Invalid launch mode: " + launchMode);
|
||||
}
|
||||
sLaunchModeMap.put(clazz, launchMode);
|
||||
}
|
||||
|
||||
public abstract int getContainerViewId();
|
||||
|
||||
/**
|
||||
* @return {@code true} for start scene
|
||||
*/
|
||||
private boolean startSceneFromIntent(Intent intent) {
|
||||
String clazzStr = intent.getStringExtra(KEY_SCENE_NAME);
|
||||
if (null == clazzStr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Class<?> clazz;
|
||||
try {
|
||||
clazz = Class.forName(clazzStr);
|
||||
} catch (ClassNotFoundException e) {
|
||||
Log.e(TAG, "Can't find class " + clazzStr, e);
|
||||
return false;
|
||||
}
|
||||
|
||||
Bundle args = intent.getBundleExtra(KEY_SCENE_ARGS);
|
||||
|
||||
Announcer announcer = onStartSceneFromIntent(clazz, args);
|
||||
if (announcer == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
startScene(announcer);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start scene from {@code Intent}, it might be not safe,
|
||||
* Correct it here.
|
||||
*
|
||||
* @return {@code null} for do not start scene
|
||||
*/
|
||||
@Nullable
|
||||
protected Announcer onStartSceneFromIntent(@NonNull Class<?> clazz, @Nullable Bundle args) {
|
||||
return new Announcer(clazz).setArgs(args);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
|
||||
if (intent == null || !ACTION_START_SCENE.equals(intent.getAction()) ||
|
||||
!startSceneFromIntent(intent)) {
|
||||
onUnrecognizedIntent(intent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when launch with action {@code android.intent.action.MAIN}
|
||||
*/
|
||||
@Nullable
|
||||
protected abstract Announcer getLaunchAnnouncer();
|
||||
|
||||
/**
|
||||
* Can't recognize intent in first time {@code onCreate} and {@code onNewIntent},
|
||||
* null included.
|
||||
*/
|
||||
protected void onUnrecognizedIntent(@Nullable Intent intent) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Call {@code setContentView} here. Do <b>NOT</b> call {@code startScene} here
|
||||
*/
|
||||
protected abstract void onCreate2(@Nullable Bundle savedInstanceState);
|
||||
|
||||
@Override
|
||||
protected final void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
getOnBackPressedDispatcher().addCallback(callback);
|
||||
if (savedInstanceState != null) {
|
||||
mStageId = savedInstanceState.getInt(KEY_STAGE_ID, IntIdGenerator.INVALID_ID);
|
||||
ArrayList<String> list = savedInstanceState.getStringArrayList(KEY_SCENE_TAG_LIST);
|
||||
if (list != null) {
|
||||
mSceneTagList.addAll(list);
|
||||
mDelaySceneTagList.addAll(list);
|
||||
}
|
||||
mIdGenerator.lazySet(savedInstanceState.getInt(KEY_NEXT_ID));
|
||||
updateBackPressCallBackStatus();
|
||||
}
|
||||
|
||||
if (mStageId == IntIdGenerator.INVALID_ID) {
|
||||
((SceneApplication) getApplicationContext()).registerStageActivity(this);
|
||||
} else {
|
||||
((SceneApplication) getApplicationContext()).registerStageActivity(this, mStageId);
|
||||
}
|
||||
|
||||
// Create layout
|
||||
onCreate2(savedInstanceState);
|
||||
|
||||
Intent intent = getIntent();
|
||||
if (savedInstanceState == null) {
|
||||
if (intent != null) {
|
||||
String action = intent.getAction();
|
||||
if (Intent.ACTION_MAIN.equals(action)) {
|
||||
Announcer announcer = getLaunchAnnouncer();
|
||||
if (announcer != null) {
|
||||
startScene(announcer);
|
||||
return;
|
||||
}
|
||||
} else if (ACTION_START_SCENE.equals(action)) {
|
||||
if (startSceneFromIntent(intent)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Can't recognize intent
|
||||
onUnrecognizedIntent(intent);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putInt(KEY_STAGE_ID, mStageId);
|
||||
outState.putStringArrayList(KEY_SCENE_TAG_LIST, mSceneTagList);
|
||||
outState.putInt(KEY_NEXT_ID, mIdGenerator.getAndIncrement());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
((SceneApplication) getApplicationContext()).unregisterStageActivity(mStageId);
|
||||
}
|
||||
|
||||
public void onSceneViewCreated(SceneFragment scene, Bundle savedInstanceState) {
|
||||
}
|
||||
|
||||
public void onSceneViewDestroyed(SceneFragment scene) {
|
||||
}
|
||||
|
||||
void onSceneDestroyed(SceneFragment scene) {
|
||||
mDelaySceneTagList.remove(scene.getTag());
|
||||
}
|
||||
|
||||
protected void onRegister(int id) {
|
||||
mStageId = id;
|
||||
}
|
||||
|
||||
protected void onUnregister() {
|
||||
}
|
||||
|
||||
protected void onTransactScene() {
|
||||
}
|
||||
|
||||
public int getStageId() {
|
||||
return mStageId;
|
||||
}
|
||||
|
||||
public int getSceneCount() {
|
||||
return mSceneTagList.size();
|
||||
}
|
||||
|
||||
public int getSceneLaunchMode(Class<?> clazz) {
|
||||
Integer integer = sLaunchModeMap.get(clazz);
|
||||
if (integer == null) {
|
||||
throw new RuntimeException("Not register " + clazz.getName());
|
||||
} else {
|
||||
return integer;
|
||||
}
|
||||
}
|
||||
|
||||
private SceneFragment newSceneInstance(Class<?> clazz) {
|
||||
try {
|
||||
return (SceneFragment) clazz.newInstance();
|
||||
} catch (InstantiationException e) {
|
||||
throw new IllegalStateException("Can't instance " + clazz.getName(), e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new IllegalStateException("The constructor of " +
|
||||
clazz.getName() + " is not visible", e);
|
||||
} catch (ClassCastException e) {
|
||||
throw new IllegalStateException(clazz.getName() + " can not cast to scene", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void startScene(Announcer announcer) {
|
||||
startScene(announcer, false);
|
||||
}
|
||||
|
||||
public void startScene(Announcer announcer, boolean horizontal) {
|
||||
startSceneInternal(announcer, horizontal);
|
||||
updateBackPressCallBackStatus();
|
||||
}
|
||||
|
||||
public void startSceneInternal(Announcer announcer, boolean horizontal) {
|
||||
Class<?> clazz = announcer.clazz;
|
||||
Bundle args = announcer.args;
|
||||
FragmentManager fragmentManager = getSupportFragmentManager();
|
||||
int launchMode = getSceneLaunchMode(clazz);
|
||||
|
||||
// Check LAUNCH_MODE_SINGLE_TASK
|
||||
if (launchMode == SceneFragment.LAUNCH_MODE_SINGLE_TASK) {
|
||||
for (int i = 0, n = mSceneTagList.size(); i < n; i++) {
|
||||
String tag = mSceneTagList.get(i);
|
||||
Fragment fragment = fragmentManager.findFragmentByTag(tag);
|
||||
if (fragment == null) {
|
||||
Log.e(TAG, "Can't find fragment with tag: " + tag);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (clazz.isInstance(fragment)) { // Get it
|
||||
FragmentTransaction transaction = fragmentManager.beginTransaction();
|
||||
|
||||
// Use default animation
|
||||
if (horizontal) {
|
||||
transaction.setCustomAnimations(R.anim.scene_open_enter_horizontal, R.anim.scene_open_exit);
|
||||
} else {
|
||||
transaction.setCustomAnimations(R.anim.scene_open_enter, R.anim.scene_open_exit);
|
||||
}
|
||||
|
||||
// Remove top fragments
|
||||
for (int j = i + 1; j < n; j++) {
|
||||
String topTag = mSceneTagList.get(j);
|
||||
Fragment topFragment = fragmentManager.findFragmentByTag(topTag);
|
||||
if (null == topFragment) {
|
||||
Log.e(TAG, "Can't find fragment with tag: " + topTag);
|
||||
continue;
|
||||
}
|
||||
// Clear shared element
|
||||
topFragment.setSharedElementEnterTransition(null);
|
||||
topFragment.setSharedElementReturnTransition(null);
|
||||
topFragment.setEnterTransition(null);
|
||||
topFragment.setExitTransition(null);
|
||||
// Remove it
|
||||
transaction.remove(topFragment);
|
||||
}
|
||||
|
||||
// Remove tag from index i+1
|
||||
mSceneTagList.subList(i + 1, mSceneTagList.size()).clear();
|
||||
mDelaySceneTagList.subList(i + 1, mDelaySceneTagList.size()).clear();
|
||||
|
||||
// Attach fragment
|
||||
if (fragment.isDetached()) {
|
||||
transaction.attach(fragment);
|
||||
}
|
||||
|
||||
// Commit
|
||||
transaction.commitAllowingStateLoss();
|
||||
onTransactScene();
|
||||
|
||||
// New arguments
|
||||
if (args != null && fragment instanceof SceneFragment) {
|
||||
// TODO Call onNewArguments when view created ?
|
||||
((SceneFragment) fragment).onNewArguments(args);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get current fragment
|
||||
SceneFragment currentScene = null;
|
||||
if (mSceneTagList.size() > 0) {
|
||||
// Get last tag
|
||||
String tag = mSceneTagList.get(mSceneTagList.size() - 1);
|
||||
Fragment fragment = fragmentManager.findFragmentByTag(tag);
|
||||
if (fragment != null) {
|
||||
AssertUtils.assertTrue(fragment instanceof SceneFragment);
|
||||
currentScene = (SceneFragment) fragment;
|
||||
}
|
||||
}
|
||||
|
||||
// Check LAUNCH_MODE_SINGLE_TASK
|
||||
if (clazz.isInstance(currentScene) && launchMode == SceneFragment.LAUNCH_MODE_SINGLE_TOP) {
|
||||
if (args != null) {
|
||||
currentScene.onNewArguments(args);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Create new scene
|
||||
SceneFragment newScene = newSceneInstance(clazz);
|
||||
newScene.setArguments(args);
|
||||
|
||||
// Create new scene tag
|
||||
String newTag = Integer.toString(mIdGenerator.getAndIncrement());
|
||||
|
||||
// Add new tag to list
|
||||
mSceneTagList.add(newTag);
|
||||
mDelaySceneTagList.add(newTag);
|
||||
|
||||
FragmentTransaction transaction = fragmentManager.beginTransaction();
|
||||
// Animation
|
||||
if (currentScene != null) {
|
||||
// Clear shared item
|
||||
currentScene.setSharedElementEnterTransition(null);
|
||||
currentScene.setSharedElementReturnTransition(null);
|
||||
currentScene.setEnterTransition(null);
|
||||
currentScene.setExitTransition(null);
|
||||
newScene.setSharedElementEnterTransition(null);
|
||||
newScene.setSharedElementReturnTransition(null);
|
||||
newScene.setEnterTransition(null);
|
||||
newScene.setExitTransition(null);
|
||||
// Set default animation
|
||||
if (horizontal) {
|
||||
transaction.setCustomAnimations(R.anim.scene_open_enter_horizontal, R.anim.scene_open_exit);
|
||||
} else {
|
||||
transaction.setCustomAnimations(R.anim.scene_open_enter, R.anim.scene_open_exit);
|
||||
}
|
||||
// Detach current scene
|
||||
if (!currentScene.isDetached()) {
|
||||
transaction.detach(currentScene);
|
||||
} else {
|
||||
Log.e(TAG, "Current scene is detached");
|
||||
}
|
||||
}
|
||||
|
||||
// Add new scene
|
||||
transaction.add(getContainerViewId(), newScene, newTag);
|
||||
|
||||
// Commit
|
||||
transaction.commitAllowingStateLoss();
|
||||
onTransactScene();
|
||||
|
||||
// Check request
|
||||
if (announcer.requestFrom != null) {
|
||||
newScene.addRequest(announcer.requestFrom.getTag(), announcer.requestCode);
|
||||
}
|
||||
}
|
||||
|
||||
public void startSceneFirstly(Announcer announcer) {
|
||||
Class<?> clazz = announcer.clazz;
|
||||
Bundle args = announcer.args;
|
||||
FragmentManager fragmentManager = getSupportFragmentManager();
|
||||
int launchMode = getSceneLaunchMode(clazz);
|
||||
boolean forceNewScene = launchMode == SceneFragment.LAUNCH_MODE_STANDARD;
|
||||
boolean createNewScene = true;
|
||||
boolean findScene = false;
|
||||
SceneFragment scene = null;
|
||||
|
||||
FragmentTransaction transaction = fragmentManager.beginTransaction();
|
||||
|
||||
// Set default animation
|
||||
transaction.setCustomAnimations(R.anim.scene_open_enter, R.anim.scene_open_exit);
|
||||
|
||||
String findSceneTag = null;
|
||||
for (int i = 0, n = mSceneTagList.size(); i < n; i++) {
|
||||
String tag = mSceneTagList.get(i);
|
||||
Fragment fragment = fragmentManager.findFragmentByTag(tag);
|
||||
if (fragment == null) {
|
||||
Log.e(TAG, "Can't find fragment with tag: " + tag);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Clear shared element
|
||||
fragment.setSharedElementEnterTransition(null);
|
||||
fragment.setSharedElementReturnTransition(null);
|
||||
fragment.setEnterTransition(null);
|
||||
fragment.setExitTransition(null);
|
||||
|
||||
// Check is target scene
|
||||
if (!forceNewScene && !findScene && clazz.isInstance(fragment) &&
|
||||
(launchMode == SceneFragment.LAUNCH_MODE_SINGLE_TASK || !fragment.isDetached())) {
|
||||
scene = (SceneFragment) fragment;
|
||||
findScene = true;
|
||||
createNewScene = false;
|
||||
findSceneTag = tag;
|
||||
if (fragment.isDetached()) {
|
||||
transaction.attach(fragment);
|
||||
}
|
||||
} else {
|
||||
// Remove it
|
||||
transaction.remove(fragment);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle tag list
|
||||
mSceneTagList.clear();
|
||||
if (null != findSceneTag) {
|
||||
mSceneTagList.add(findSceneTag);
|
||||
}
|
||||
|
||||
if (createNewScene) {
|
||||
scene = newSceneInstance(clazz);
|
||||
scene.setArguments(args);
|
||||
|
||||
// Create scene tag
|
||||
String tag = Integer.toString(mIdGenerator.getAndIncrement());
|
||||
|
||||
// Add tag to list
|
||||
mSceneTagList.add(tag);
|
||||
mDelaySceneTagList.add(tag);
|
||||
|
||||
// Add scene
|
||||
transaction.add(getContainerViewId(), scene, tag);
|
||||
}
|
||||
|
||||
// Commit
|
||||
transaction.commitAllowingStateLoss();
|
||||
onTransactScene();
|
||||
|
||||
if (!createNewScene && args != null) {
|
||||
// TODO Call onNewArguments when view created ?
|
||||
scene.onNewArguments(args);
|
||||
}
|
||||
updateBackPressCallBackStatus();
|
||||
}
|
||||
|
||||
int getSceneIndex(SceneFragment scene) {
|
||||
return getTagIndex(scene.getTag());
|
||||
}
|
||||
|
||||
int getTagIndex(String tag) {
|
||||
return mSceneTagList.indexOf(tag);
|
||||
}
|
||||
|
||||
void sortSceneViews(List<View> views) {
|
||||
views.sort(mSceneViewComparator);
|
||||
}
|
||||
|
||||
public void finishScene(SceneFragment scene) {
|
||||
finishScene(scene.getTag());
|
||||
updateBackPressCallBackStatus();
|
||||
}
|
||||
|
||||
private void finishScene(String tag) {
|
||||
FragmentManager fragmentManager = getSupportFragmentManager();
|
||||
|
||||
// Get scene
|
||||
Fragment scene = fragmentManager.findFragmentByTag(tag);
|
||||
if (scene == null) {
|
||||
Log.e(TAG, "finishScene: Can't find scene by tag: " + tag);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get scene index
|
||||
int index = mSceneTagList.indexOf(tag);
|
||||
if (index < 0) {
|
||||
Log.e(TAG, "finishScene: Can't find the tag in tag list: " + tag);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mSceneTagList.size() == 1) {
|
||||
// It is the last fragment, finish Activity now
|
||||
Log.i(TAG, "finishScene: It is the last scene, finish activity now");
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
Fragment next = null;
|
||||
if (index == mSceneTagList.size() - 1) {
|
||||
// It is first fragment, show the next one
|
||||
next = fragmentManager.findFragmentByTag(mSceneTagList.get(index - 1));
|
||||
}
|
||||
|
||||
FragmentTransaction transaction = fragmentManager.beginTransaction();
|
||||
if (next != null) {
|
||||
// Clear shared item
|
||||
scene.setSharedElementEnterTransition(null);
|
||||
scene.setSharedElementReturnTransition(null);
|
||||
scene.setEnterTransition(null);
|
||||
scene.setExitTransition(null);
|
||||
next.setSharedElementEnterTransition(null);
|
||||
next.setSharedElementReturnTransition(null);
|
||||
next.setEnterTransition(null);
|
||||
next.setExitTransition(null);
|
||||
// Do not show animate if it is not the first fragment
|
||||
transaction.setCustomAnimations(R.anim.scene_close_enter, R.anim.scene_close_exit);
|
||||
// Attach fragment
|
||||
transaction.attach(next);
|
||||
}
|
||||
transaction.remove(scene);
|
||||
transaction.commitAllowingStateLoss();
|
||||
onTransactScene();
|
||||
|
||||
// Remove tag
|
||||
mSceneTagList.remove(index);
|
||||
|
||||
// Return result
|
||||
if (scene instanceof SceneFragment) {
|
||||
((SceneFragment) scene).returnResult(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void refreshTopScene() {
|
||||
int index = mSceneTagList.size() - 1;
|
||||
if (index < 0) {
|
||||
return;
|
||||
}
|
||||
String tag = mSceneTagList.get(index);
|
||||
|
||||
FragmentManager fragmentManager = getSupportFragmentManager();
|
||||
Fragment fragment = fragmentManager.findFragmentByTag(tag);
|
||||
|
||||
if (fragment == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
fragmentManager.beginTransaction().detach(fragment).commitAllowingStateLoss();
|
||||
fragmentManager.beginTransaction().attach(fragment).commitAllowingStateLoss();
|
||||
updateBackPressCallBackStatus();
|
||||
}
|
||||
|
||||
public void updateBackPressCallBackStatus() {
|
||||
callback.setEnabled(mSceneTagList.size() > 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProvideAssistContent(AssistContent outContent) {
|
||||
super.onProvideAssistContent(outContent);
|
||||
int size = mSceneTagList.size();
|
||||
String tag = mSceneTagList.get(size - 1);
|
||||
Fragment fragment = getSupportFragmentManager().findFragmentByTag(tag);
|
||||
if (fragment == null) {
|
||||
Log.e(TAG, "onProvideAssistContent: Can't find scene by tag: " + tag);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fragment instanceof SceneFragment scene) {
|
||||
scene.onProvideAssistContent(outContent);
|
||||
} else {
|
||||
Log.e(TAG, "onProvideAssistContent: The fragment is not SceneFragment");
|
||||
}
|
||||
}
|
||||
|
||||
public SceneFragment findSceneByTag(String tag) {
|
||||
FragmentManager fragmentManager = getSupportFragmentManager();
|
||||
Fragment fragment = fragmentManager.findFragmentByTag(tag);
|
||||
if (fragment != null) {
|
||||
return (SceneFragment) fragment;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Class<?> getTopSceneClass() {
|
||||
int index = mSceneTagList.size() - 1;
|
||||
if (index < 0) {
|
||||
return null;
|
||||
}
|
||||
String tag = mSceneTagList.get(index);
|
||||
Fragment fragment = getSupportFragmentManager().findFragmentByTag(tag);
|
||||
if (null == fragment) {
|
||||
return null;
|
||||
}
|
||||
return fragment.getClass();
|
||||
}
|
||||
|
||||
class BackPressCallBack extends OnBackPressedCallback {
|
||||
public BackPressCallBack() {
|
||||
super(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleOnBackPressed() {
|
||||
int size = mSceneTagList.size();
|
||||
String tag = mSceneTagList.get(size - 1);
|
||||
SceneFragment scene;
|
||||
Fragment fragment = getSupportFragmentManager().findFragmentByTag(tag);
|
||||
if (fragment == null) {
|
||||
Log.e(TAG, "onBackPressed: Can't find scene by tag: " + tag);
|
||||
return;
|
||||
}
|
||||
if (!(fragment instanceof SceneFragment)) {
|
||||
Log.e(TAG, "onBackPressed: The fragment is not SceneFragment");
|
||||
return;
|
||||
}
|
||||
|
||||
scene = (SceneFragment) fragment;
|
||||
finishScene(scene);
|
||||
}
|
||||
}
|
||||
|
||||
private final class SceneViewComparator implements Comparator<View> {
|
||||
|
||||
private int getIndex(View view) {
|
||||
Object o = view.getTag(R.id.fragment_tag);
|
||||
if (o instanceof String) {
|
||||
return mDelaySceneTagList.indexOf(o);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(View lhs, View rhs) {
|
||||
return getIndex(lhs) - getIndex(rhs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,156 +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.scene;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.hippo.ehviewer.R;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class StageLayout extends FrameLayout {
|
||||
|
||||
private Field mDisappearingChildrenField;
|
||||
private ArrayList<View> mSuperDisappearingChildren;
|
||||
private ArrayList<View> mSortedScenes;
|
||||
private View mDumpView;
|
||||
private boolean mDoTrick;
|
||||
|
||||
public StageLayout(Context context) {
|
||||
super(context);
|
||||
init(context);
|
||||
}
|
||||
|
||||
public StageLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init(context);
|
||||
}
|
||||
|
||||
public StageLayout(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init(context);
|
||||
}
|
||||
|
||||
private void init(Context context) {
|
||||
try {
|
||||
mDisappearingChildrenField = ViewGroup.class.getDeclaredField("mDisappearingChildren");
|
||||
mDisappearingChildrenField.setAccessible(true);
|
||||
} catch (NoSuchFieldException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (mDisappearingChildrenField != null) {
|
||||
mDumpView = new View(context);
|
||||
addView(mDumpView, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void getSuperDisappearingChildren() {
|
||||
if (mDisappearingChildrenField == null || mSuperDisappearingChildren != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
mSuperDisappearingChildren = (ArrayList<View>) mDisappearingChildrenField.get(this);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean beforeDispatchDraw() {
|
||||
getSuperDisappearingChildren();
|
||||
|
||||
if (mSuperDisappearingChildren == null ||
|
||||
mSuperDisappearingChildren.size() <= 0 || getChildCount() <= 1) { // only dump view
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get stage
|
||||
StageActivity stage = null;
|
||||
Context context = getContext();
|
||||
if (context instanceof StageActivity) {
|
||||
stage = (StageActivity) context;
|
||||
}
|
||||
if (stage == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (null == mSortedScenes) {
|
||||
mSortedScenes = new ArrayList<>();
|
||||
}
|
||||
|
||||
// Add all scene view to mSortedScenes
|
||||
ArrayList<View> disappearingChildren = mSuperDisappearingChildren;
|
||||
ArrayList<View> sortedScenes = mSortedScenes;
|
||||
for (int i = 1, n = getChildCount(); i < n; i++) { // Skip dump view
|
||||
View view = getChildAt(i);
|
||||
if (null != view.getTag(R.id.fragment_tag)) {
|
||||
sortedScenes.add(view);
|
||||
}
|
||||
}
|
||||
for (int i = 0, n = disappearingChildren.size(); i < n; i++) {
|
||||
View view = disappearingChildren.get(i);
|
||||
if (null != view.getTag(R.id.fragment_tag)) {
|
||||
sortedScenes.add(view);
|
||||
}
|
||||
}
|
||||
|
||||
stage.sortSceneViews(sortedScenes);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void afterDispatchDraw() {
|
||||
if (null != mSortedScenes) {
|
||||
mSortedScenes.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dispatchDraw(Canvas canvas) {
|
||||
mDoTrick = beforeDispatchDraw();
|
||||
super.dispatchDraw(canvas);
|
||||
afterDispatchDraw();
|
||||
mDoTrick = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
|
||||
if (mDoTrick) {
|
||||
ArrayList<View> sortedScenes = mSortedScenes;
|
||||
if (child == mDumpView) {
|
||||
boolean more = false;
|
||||
for (int i = 0, n = sortedScenes.size(); i < n; i++) {
|
||||
more |= super.drawChild(canvas, sortedScenes.get(i), drawingTime);
|
||||
}
|
||||
return more;
|
||||
} else if (sortedScenes.contains(child)) {
|
||||
// Skip
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return super.drawChild(canvas, child, drawingTime);
|
||||
}
|
||||
}
|
||||
-47
@@ -1,47 +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/>.
|
||||
*/
|
||||
|
||||
package com.hippo.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.WindowInsets;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.drakeet.drawer.FullDraggableContainer;
|
||||
|
||||
public class IgnoreFitsSystemWindowsFullyDraggableDrawerContentLayout extends FullDraggableContainer {
|
||||
public IgnoreFitsSystemWindowsFullyDraggableDrawerContentLayout(@NonNull Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public IgnoreFitsSystemWindowsFullyDraggableDrawerContentLayout(@NonNull Context context, @Nullable @org.jetbrains.annotations.Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public IgnoreFitsSystemWindowsFullyDraggableDrawerContentLayout(@NonNull Context context, @Nullable @org.jetbrains.annotations.Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
|
||||
return insets;
|
||||
}
|
||||
}
|
||||
@@ -174,7 +174,7 @@ open class ReaderPageImageView @JvmOverloads constructor(
|
||||
(pageView as? SubsamplingScaleImageView)?.let { view ->
|
||||
RectF().let {
|
||||
view.getPanRemaining(it)
|
||||
return fn(it) > 0
|
||||
return fn(it) > 1
|
||||
}
|
||||
}
|
||||
return false
|
||||
|
||||
@@ -1,38 +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.
|
||||
-->
|
||||
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shareInterpolator="false">
|
||||
|
||||
<alpha
|
||||
android:duration="200"
|
||||
android:fillAfter="true"
|
||||
android:fillBefore="false"
|
||||
android:fillEnabled="true"
|
||||
android:fromAlpha="0.0"
|
||||
android:interpolator="@anim/decelerate_quart"
|
||||
android:toAlpha="1.0" />
|
||||
|
||||
<translate
|
||||
android:duration="350"
|
||||
android:fillAfter="true"
|
||||
android:fillBefore="true"
|
||||
android:fillEnabled="true"
|
||||
android:fromXDelta="8%"
|
||||
android:interpolator="@anim/decelerate_quint"
|
||||
android:toXDelta="0" />
|
||||
|
||||
</set>
|
||||
@@ -1,166 +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"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
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="80dp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingHorizontal="32dp"
|
||||
android:text="@string/cookie_explain"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textSize="@dimen/text_little_small"
|
||||
app:drawableTopCompat="@drawable/v_cookie_brown_x256" />
|
||||
</LinearLayout>
|
||||
|
||||
<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="vertical"
|
||||
android:paddingLeft="12dp"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingRight="12dp"
|
||||
android:paddingBottom="4dp">
|
||||
|
||||
<Space
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="80dp" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/ipb_member_id_layout"
|
||||
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="@dimen/keyline_margin"
|
||||
android:hint="ipb_member_id"
|
||||
android:minWidth="@dimen/single_max_width">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/ipb_member_id"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:imeOptions="actionNext"
|
||||
android:inputType="text"
|
||||
android:maxLines="1"
|
||||
android:singleLine="true"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/ipb_pass_hash_layout"
|
||||
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:hint="ipb_pass_hash"
|
||||
android:minWidth="@dimen/single_max_width">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/ipb_pass_hash"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:imeOptions="actionNext"
|
||||
android:inputType="text"
|
||||
android:maxLines="1"
|
||||
android:singleLine="true"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/igneous_layout"
|
||||
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:hint="igneous"
|
||||
android:minWidth="@dimen/single_max_width">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/igneous"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:imeOptions="actionDone"
|
||||
android:inputType="text"
|
||||
android:maxLines="1"
|
||||
android:singleLine="true"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
<Space
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="64dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/ok"
|
||||
style="@style/Widget.Material3.Button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:insetLeft="80dp"
|
||||
android:insetRight="80dp"
|
||||
android:text="@android:string/ok" />
|
||||
|
||||
<Space
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/from_clipboard"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:background="?selectableItemBackground"
|
||||
android:paddingHorizontal="8dp"
|
||||
android:text="@string/from_clipboard" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</FrameLayout>
|
||||
@@ -1,188 +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:orientation="vertical"
|
||||
app:fitsSystemWindowsInsets="top|bottom">
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/login_form"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal"
|
||||
android:padding="@dimen/keyline_margin">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="480dp"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="257dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:padding="@dimen/keyline_margin"
|
||||
app:srcCompat="@drawable/ic_launcher_foreground" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<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="vertical"
|
||||
android:paddingLeft="12dp"
|
||||
android:paddingTop="100dp"
|
||||
android:paddingRight="12dp"
|
||||
android:paddingBottom="4dp">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/username_layout"
|
||||
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:hint="@string/username"
|
||||
android:minWidth="@dimen/single_max_width">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/username"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:autofillHints="username"
|
||||
android:imeOptions="actionNext"
|
||||
android:inputType="text"
|
||||
android:maxLines="1"
|
||||
android:singleLine="true" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/password_layout"
|
||||
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:hint="@string/password"
|
||||
android:minWidth="@dimen/single_max_width"
|
||||
app:passwordToggleEnabled="true">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/password"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:autofillHints="password"
|
||||
android:imeOptions="actionDone"
|
||||
android:inputType="textPassword"
|
||||
android:maxLines="1"
|
||||
android:singleLine="true" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<TextView
|
||||
style="@style/TextAppearance.Material3.LabelLarge"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:maxWidth="@dimen/single_max_width"
|
||||
android:paddingTop="24dp"
|
||||
android:text="@string/app_waring" />
|
||||
|
||||
<Space
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/sign_in"
|
||||
style="@style/Widget.Material3.Button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:insetLeft="80dp"
|
||||
android:insetRight="80dp"
|
||||
android:text="@string/sign_in" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/register"
|
||||
style="@style/Widget.Material3.Button.OutlinedButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:insetLeft="80dp"
|
||||
android:insetRight="80dp"
|
||||
android:text="@string/register" />
|
||||
|
||||
<Space
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sign_in_via_webview"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:background="?selectableItemBackground"
|
||||
android:paddingHorizontal="8dp"
|
||||
android:text="@string/sign_in_via_webview" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sign_in_via_cookies"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:background="?selectableItemBackground"
|
||||
android:paddingHorizontal="8dp"
|
||||
android:text="@string/sign_in_via_cookies" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tourist_mode"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:background="?selectableItemBackground"
|
||||
android:paddingHorizontal="8dp"
|
||||
android:text="@string/tourist_mode" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/progress"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clickable="true"
|
||||
android:visibility="gone">
|
||||
|
||||
<com.google.android.material.progressindicator.CircularProgressIndicator
|
||||
style="@style/ProgressView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</FrameLayout>
|
||||
@@ -1,125 +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: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="96dp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="128dp"
|
||||
android:paddingTop="100dp"
|
||||
android:paddingEnd="12dp"
|
||||
android:text="@string/select_scene"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Title" />
|
||||
|
||||
<Space
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="32dp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="128dp"
|
||||
android:paddingTop="100dp"
|
||||
android:paddingEnd="12dp"
|
||||
android:text="@string/select_scene_explain" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<Space
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="160dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<com.google.android.material.button.MaterialButtonToggleGroup
|
||||
android:id="@+id/button_group"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginBottom="@dimen/keyline_margin"
|
||||
app:selectionRequired="true"
|
||||
app:singleSelection="true">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/site_e"
|
||||
style="?attr/materialButtonOutlinedStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:text="@string/site_e" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/site_ex"
|
||||
style="?attr/materialButtonOutlinedStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:text="@string/site_ex" />
|
||||
</com.google.android.material.button.MaterialButtonToggleGroup>
|
||||
|
||||
<Space
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="77dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/ok"
|
||||
style="@style/Widget.Material3.Button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:insetLeft="80dp"
|
||||
android:insetRight="80dp"
|
||||
android:text="@android:string/ok" />
|
||||
|
||||
<Space
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="96dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</FrameLayout>
|
||||
@@ -14,8 +14,9 @@
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/draw_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipChildren="false"
|
||||
@@ -23,45 +24,40 @@
|
||||
app:edgeToEdge="true"
|
||||
app:fitsSystemWindowsInsets="start|end">
|
||||
|
||||
<androidx.drawerlayout.widget.DrawerLayout
|
||||
android:id="@+id/draw_view"
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/snackbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.hippo.widget.IgnoreFitsSystemWindowsFullyDraggableDrawerContentLayout
|
||||
<com.hippo.ehviewer.widget.AboveSnackerLayout
|
||||
android:id="@+id/absnacker"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/snackbar"
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/fragment_container"
|
||||
android:name="androidx.navigation.fragment.NavHostFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
app:defaultNavHost="true"
|
||||
app:navGraph="@navigation/nav_graph" />
|
||||
</com.hippo.ehviewer.widget.AboveSnackerLayout>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
<com.hippo.ehviewer.widget.EhStageLayout
|
||||
android:id="@+id/fragment_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
<com.google.android.material.navigation.NavigationView
|
||||
android:id="@+id/nav_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="start"
|
||||
app:headerLayout="@layout/nav_header_main"
|
||||
app:menu="@menu/nav_drawer_main" />
|
||||
|
||||
</com.hippo.widget.IgnoreFitsSystemWindowsFullyDraggableDrawerContentLayout>
|
||||
<com.hippo.widget.DrawerView
|
||||
android:id="@+id/right_drawer"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="end"
|
||||
android:fitsSystemWindows="true"
|
||||
android:maxWidth="@dimen/drawer_max_width" />
|
||||
|
||||
<com.google.android.material.navigation.NavigationView
|
||||
android:id="@+id/nav_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="start"
|
||||
app:headerLayout="@layout/nav_header_main"
|
||||
app:menu="@menu/nav_drawer_main" />
|
||||
|
||||
<com.hippo.widget.DrawerView
|
||||
android:id="@+id/right_drawer"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="end"
|
||||
android:fitsSystemWindows="false"
|
||||
android:maxWidth="@dimen/drawer_max_width" />
|
||||
|
||||
</androidx.drawerlayout.widget.DrawerLayout>
|
||||
</FrameLayout>
|
||||
</androidx.drawerlayout.widget.DrawerLayout>
|
||||
@@ -1,160 +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"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="@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_cookie_brown_x48" />
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:clipToPadding="false"
|
||||
android:paddingVertical="@dimen/keyline_margin">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingHorizontal="32dp"
|
||||
android:text="@string/cookie_explain"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textSize="@dimen/text_little_small" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/ipb_member_id_layout"
|
||||
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="@dimen/keyline_margin"
|
||||
android:hint="ipb_member_id"
|
||||
android:minWidth="@dimen/single_max_width">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/ipb_member_id"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:imeOptions="actionNext"
|
||||
android:inputType="text"
|
||||
android:maxLines="1"
|
||||
android:singleLine="true"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/ipb_pass_hash_layout"
|
||||
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:hint="ipb_pass_hash"
|
||||
android:minWidth="@dimen/single_max_width">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/ipb_pass_hash"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:imeOptions="actionNext"
|
||||
android:inputType="text"
|
||||
android:maxLines="1"
|
||||
android:singleLine="true"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/igneous_layout"
|
||||
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:hint="igneous"
|
||||
android:minWidth="@dimen/single_max_width">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/igneous"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:imeOptions="actionDone"
|
||||
android:inputType="text"
|
||||
android:maxLines="1"
|
||||
android:singleLine="true"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
</LinearLayout>
|
||||
</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="4dp">
|
||||
|
||||
<Button
|
||||
android:id="@+id/ok"
|
||||
style="@style/Widget.Material3.Button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@android:string/ok" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipToPadding="false"
|
||||
android:gravity="bottom|center_horizontal"
|
||||
android:orientation="horizontal"
|
||||
android:paddingLeft="12dp"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingRight="12dp"
|
||||
android:paddingBottom="4dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/from_clipboard"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingHorizontal="8dp"
|
||||
android:text="@string/from_clipboard" />
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@@ -1,188 +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.
|
||||
-->
|
||||
|
||||
<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:orientation="vertical"
|
||||
app:fitsSystemWindowsInsets="top|bottom">
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/login_form"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fillViewport="true">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/keyline_margin">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:padding="@dimen/keyline_margin"
|
||||
app:srcCompat="@drawable/ic_launcher_foreground" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/username_layout"
|
||||
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:hint="@string/username"
|
||||
android:minWidth="@dimen/single_max_width">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/username"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:autofillHints="username"
|
||||
android:imeOptions="actionNext"
|
||||
android:inputType="text"
|
||||
android:maxLines="1"
|
||||
android:singleLine="true" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/password_layout"
|
||||
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:hint="@string/password"
|
||||
android:minWidth="@dimen/single_max_width"
|
||||
app:passwordToggleEnabled="true">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/password"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:autofillHints="password"
|
||||
android:imeOptions="actionDone"
|
||||
android:inputType="textPassword"
|
||||
android:maxLines="1"
|
||||
android:singleLine="true" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<TextView
|
||||
style="@style/TextAppearance.Material3.LabelLarge"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:maxWidth="@dimen/single_max_width"
|
||||
android:paddingTop="24dp"
|
||||
android:text="@string/app_waring" />
|
||||
|
||||
<Space
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<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="4dp">
|
||||
|
||||
<Button
|
||||
android:id="@+id/register"
|
||||
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/register" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/sign_in"
|
||||
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/sign_in" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipToPadding="false"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="horizontal"
|
||||
android:paddingLeft="12dp"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingRight="12dp"
|
||||
android:paddingBottom="4dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sign_in_via_webview"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?selectableItemBackground"
|
||||
android:paddingHorizontal="8dp"
|
||||
android:text="@string/sign_in_via_webview" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sign_in_via_cookies"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?selectableItemBackground"
|
||||
android:paddingHorizontal="8dp"
|
||||
android:text="@string/sign_in_via_cookies" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tourist_mode"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:background="?selectableItemBackground"
|
||||
android:paddingHorizontal="8dp"
|
||||
android:text="@string/tourist_mode" />
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/progress"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clickable="true"
|
||||
android:visibility="gone">
|
||||
|
||||
<com.google.android.material.progressindicator.CircularProgressIndicator
|
||||
style="@style/ProgressView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</FrameLayout>
|
||||
@@ -1,112 +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">
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_weight="1"
|
||||
android:clipToPadding="false"
|
||||
android:fillViewport="true"
|
||||
android:paddingVertical="@dimen/keyline_margin">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/select_scene"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Title" />
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<com.google.android.material.button.MaterialButtonToggleGroup
|
||||
android:id="@+id/button_group"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginBottom="@dimen/keyline_margin"
|
||||
app:selectionRequired="true"
|
||||
app:singleSelection="true">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/site_e"
|
||||
style="?attr/materialButtonOutlinedStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:text="@string/site_e" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/site_ex"
|
||||
style="?attr/materialButtonOutlinedStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:text="@string/site_ex" />
|
||||
</com.google.android.material.button.MaterialButtonToggleGroup>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/select_scene_explain" />
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
</LinearLayout>
|
||||
</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/ok"
|
||||
style="@style/Widget.Material3.Button"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@android:string/ok" />
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,79 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/nav_graph"
|
||||
app:startDestination="@id/galleryListScene">
|
||||
|
||||
<fragment
|
||||
android:id="@+id/galleryListScene"
|
||||
android:name="com.hippo.ehviewer.ui.scene.GalleryListScene"
|
||||
android:label="GalleryListScene" />
|
||||
<fragment
|
||||
android:id="@+id/nav_homepage"
|
||||
android:name="com.hippo.ehviewer.ui.scene.GalleryListScene"
|
||||
android:label="GalleryListScene">
|
||||
<argument
|
||||
android:name="action"
|
||||
android:defaultValue="action_homepage"
|
||||
app:argType="string" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/nav_subscription"
|
||||
android:name="com.hippo.ehviewer.ui.scene.GalleryListScene"
|
||||
android:label="GalleryListScene">
|
||||
<argument
|
||||
android:name="action"
|
||||
android:defaultValue="action_subscription"
|
||||
app:argType="string" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/nav_whats_hot"
|
||||
android:name="com.hippo.ehviewer.ui.scene.GalleryListScene"
|
||||
android:label="GalleryListScene">
|
||||
<argument
|
||||
android:name="action"
|
||||
android:defaultValue="action_whats_hot"
|
||||
app:argType="string" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/nav_toplist"
|
||||
android:name="com.hippo.ehviewer.ui.scene.GalleryListScene"
|
||||
android:label="GalleryListScene">
|
||||
<argument
|
||||
android:name="action"
|
||||
android:defaultValue="action_top_list"
|
||||
app:argType="string" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/galleryDetailScene"
|
||||
android:name="com.hippo.ehviewer.ui.scene.GalleryDetailScene"
|
||||
android:label="GalleryDetailScene" />
|
||||
<fragment
|
||||
android:id="@+id/galleryCommentsScene"
|
||||
android:name="com.hippo.ehviewer.ui.scene.GalleryCommentsScene"
|
||||
android:label="GalleryCommentsScene" />
|
||||
<fragment
|
||||
android:id="@+id/galleryPreviewsScene"
|
||||
android:name="com.hippo.ehviewer.ui.scene.GalleryPreviewsScene"
|
||||
android:label="GalleryPreviewsScene" />
|
||||
<fragment
|
||||
android:id="@+id/nav_favourite"
|
||||
android:name="com.hippo.ehviewer.ui.scene.FavoritesScene"
|
||||
android:label="FavoritesScene" />
|
||||
<fragment
|
||||
android:id="@+id/nav_history"
|
||||
android:name="com.hippo.ehviewer.ui.scene.HistoryScene"
|
||||
android:label="HistoryScene" />
|
||||
<fragment
|
||||
android:id="@+id/nav_downloads"
|
||||
android:name="com.hippo.ehviewer.ui.scene.DownloadsScene"
|
||||
android:label="DownloadsScene" />
|
||||
<activity
|
||||
android:id="@+id/nav_settings"
|
||||
android:name="com.hippo.ehviewer.ui.SettingsActivity"
|
||||
android:label="SettingsActivity" />
|
||||
<fragment
|
||||
android:id="@+id/progressScene"
|
||||
android:name="com.hippo.ehviewer.ui.scene.ProgressScene"
|
||||
android:label="ProgressScene" />
|
||||
</navigation>
|
||||
@@ -35,7 +35,6 @@
|
||||
<string name="text_is_empty">Der Text wird nicht eingegeben</string>
|
||||
<string name="waring">Achtung</string>
|
||||
<string name="wrong_cookie_warning">Die eingegebenen Cookies sehen korrekt nicht aus. Überprüfe sie.</string>
|
||||
<string name="found_cookies">Cookies werden gefunden</string>
|
||||
<string name="invalid_download_location">Der Downloadpfad ist nicht verfügbar. Geh zu die Einstellungen und stelle einen neue Pfad fest.</string>
|
||||
<string name="error_bad_status_code">Inkorrekter Statuscode: %d</string>
|
||||
<string name="error_timeout">Timeout</string>
|
||||
@@ -60,7 +59,6 @@
|
||||
<string name="get_it">Verstanden</string>
|
||||
<string name="select_scene">Wähle eine Galerie-Webseite aus.</string>
|
||||
<string name="select_scene_explain">e-hentai: für jeden verfügbar\nexhentai: nur für diejenigen verfügbar, die sich angemeldet haben</string>
|
||||
<string name="no_select">Wähle eine Webseite aus.</string>
|
||||
<string name="gallery_list_search_bar_hint_exhentai">ExHentai durchsuchen</string>
|
||||
<string name="gallery_list_search_bar_hint_e_hentai">E-Hentai durchsuchen</string>
|
||||
<string name="gallery_list_empty_hit">Die Welt ist so groß und der Panda sitzt ganz allein</string>
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
<string name="text_is_empty">El texto está vacío</string>
|
||||
<string name="waring">Advertencia</string>
|
||||
<string name="wrong_cookie_warning">Parece que las cookies que ingresaste son incorrectas. Debe revisarlos.</string>
|
||||
<string name="found_cookies">¡Cookies encontradas!</string>
|
||||
|
||||
<string name="invalid_download_location">Parece que la ubicación de descarga no está disponible. Establece la ubicación en Configuración.</string>
|
||||
|
||||
@@ -74,7 +73,6 @@
|
||||
<!-- Select scene -->
|
||||
<string name="select_scene">¿Qué galería deseas seleccionar?</string>
|
||||
<string name="select_scene_explain">e-hentai: Disponible para cualquiera .\nexhentai: Solo para usuarios que han iniciado sesión</string>
|
||||
<string name="no_select">Por favor seleccione un sitio</string>
|
||||
|
||||
<!-- Update -->
|
||||
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
<string name="text_is_empty">Entrez le texte.</string>
|
||||
<string name="waring">Attention</string>
|
||||
<string name="wrong_cookie_warning">Les cookies entrés n\'ont pas l\'air corrects. Vérifiez-les.</string>
|
||||
<string name="found_cookies">Cookies trouvés</string>
|
||||
|
||||
<string name="invalid_download_location">La location de téléchargement actuelle n\'est pas disponible. Choissez-en une à nouveau dans les Paramétres.</string>
|
||||
|
||||
@@ -76,7 +75,6 @@
|
||||
<!-- Select scene -->
|
||||
<string name="select_scene">Sélectionnez un site galerie.</string>
|
||||
<string name="select_scene_explain">e-hentai : disponible pour tout le monde\nexhentai : disponible pour ce qui s\'est connecté(e)</string>
|
||||
<string name="no_select">Sélectionnez un site</string>
|
||||
|
||||
<!-- Update -->
|
||||
|
||||
|
||||
@@ -39,7 +39,6 @@
|
||||
<string name="text_is_empty">テキストを入力してください</string>
|
||||
<string name="waring">警告</string>
|
||||
<string name="wrong_cookie_warning">入力したCookieは正しくないようです。確認してください。</string>
|
||||
<string name="found_cookies">Cookieが見つかりました</string>
|
||||
|
||||
<string name="invalid_download_location">ダウンロードパスは現在利用できません。ダウンロードパスを設定してください。</string>
|
||||
|
||||
@@ -74,7 +73,6 @@
|
||||
<!-- Select scene -->
|
||||
<string name="select_scene">ギャラリーサイトを選択してください</string>
|
||||
<string name="select_scene_explain">e-hentai:誰にも公開です\nexhentai:ログインしないとアクセスできません</string>
|
||||
<string name="no_select">サイトを選択してください</string>
|
||||
|
||||
<!-- Update -->
|
||||
|
||||
|
||||
@@ -40,7 +40,6 @@
|
||||
<string name="text_is_empty">텍스트가 비어 있습니다.</string>
|
||||
<string name="waring">경고</string>
|
||||
<string name="wrong_cookie_warning">입력한 쿠키가 잘못된 것 같습니다. 확인해 보는 게 좋겠어요.</string>
|
||||
<string name="found_cookies">쿠키를 찾았어요!</string>
|
||||
|
||||
<string name="invalid_download_location">다운로드 위치가 잘못되었습니다. 설정을 확인하세요.</string>
|
||||
|
||||
@@ -77,7 +76,6 @@
|
||||
<!-- Select scene -->
|
||||
<string name="select_scene">어느 갤러리 사이트를 사용하시겠습니까?</string>
|
||||
<string name="select_scene_explain">e-hentai: 모든 사람들이 사용할 수 있음\nexhentai: 로그인한 사람만 사용할 수 있음</string>
|
||||
<string name="no_select">두 사이트 중 하나를 선택하세요.</string>
|
||||
|
||||
<!-- Update -->
|
||||
|
||||
|
||||
@@ -40,7 +40,6 @@
|
||||
<string name="text_is_empty">ข้อความห้ามเว้นว่างไว้</string>
|
||||
<string name="waring">คำเตือน</string>
|
||||
<string name="wrong_cookie_warning">ดูเหมือนว่าคุกกี้ที่คุณกรอกมานั้นมันผิด คุณลองตรวจสอบใหม่ดูอีกรอบ</string>
|
||||
<string name="found_cookies">พบคุกกี้แล้ว!</string>
|
||||
|
||||
<string name="invalid_download_location">ดูเหมือนที่อยู่ในการดาวน์โหลดนั้นไม่พร้อมใช้งาน โปรดตั้งค่าในเมนูการตั้งค่า</string>
|
||||
|
||||
@@ -77,7 +76,6 @@
|
||||
<!-- Select scene -->
|
||||
<string name="select_scene">เว็บแกลเลอรี่ไหนที่คุณอยากเข้าชม?</string>
|
||||
<string name="select_scene_explain">e-hentai: เขตแดนที่ทุกๆคนสามารถเข้าถึงได้\nexhentai: เขตแดนอันแสนศักศิทธิ์สำหรับคนที่ลงชื่อเข้าใช้ระบบแล้วเท่านั้นที่จะเข้าไปได้</string>
|
||||
<string name="no_select">โปรดเลือกหนึ่งเว็บไซต์</string>
|
||||
|
||||
<!-- Update -->
|
||||
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
<string name="text_is_empty">文本为空</string>
|
||||
<string name="waring">警告</string>
|
||||
<string name="wrong_cookie_warning">看起来您输入的 Cookie 是错误的,最好检查一下。</string>
|
||||
<string name="found_cookies">找到旧版 Cookie</string>
|
||||
|
||||
<string name="invalid_download_location">似乎下载路径不可用。请到重新设置下载路径。</string>
|
||||
|
||||
@@ -83,7 +82,6 @@
|
||||
<!-- Select scene -->
|
||||
<string name="select_scene">你想选择哪个画廊站点?</string>
|
||||
<string name="select_scene_explain">e-hentai:对任何人开放\nexhentai:仅对登录用户开放</string>
|
||||
<string name="no_select">请选择一个站点</string>
|
||||
|
||||
<!-- Update -->
|
||||
|
||||
@@ -143,6 +141,7 @@
|
||||
<string name="duplicate_quick_search">已存在相同的快速搜索,名称为“%s”。</string>
|
||||
<string name="duplicate_name">已存在相同名称</string>
|
||||
<string name="save_progress">保存进度</string>
|
||||
<string name="delete_quick_search">删除快速搜索“%s”?</string>
|
||||
|
||||
<string name="go_to_hint">第 %1$d 页,共 %2$d 页</string>
|
||||
|
||||
@@ -178,6 +177,8 @@
|
||||
<string name="rate_successfully">评分成功</string>
|
||||
<string name="rate_failed">评分失败</string>
|
||||
<string name="no_torrents">没有种子</string>
|
||||
<string name="download_torrent_started">开始下载种子</string>
|
||||
<string name="download_torrent_failure">无法下载种子</string>
|
||||
<string name="torrents">种子</string>
|
||||
<string name="favorited">已收藏</string>
|
||||
<string name="not_favorited">未收藏</string>
|
||||
@@ -304,6 +305,7 @@
|
||||
<string name="label_text_is_invalid">“默认”是无效标签</string>
|
||||
<string name="label_text_exist">标签已存在</string>
|
||||
<string name="rename_label_title">重命名标签</string>
|
||||
<string name="delete_label">删除标签“%s”?</string>
|
||||
|
||||
<!-- History -->
|
||||
<string name="no_history">这里是阅读历史</string>
|
||||
@@ -557,8 +559,8 @@
|
||||
<string name="from_clipboard">从剪贴板导入</string>
|
||||
<string name="from_clipboard_error">未在剪贴板中发现 Cookies。</string>
|
||||
<string name="delete_search_history">从搜索记录中删除“%s”?</string>
|
||||
<string name="settings_advanced_domain_fronting_title">域名前置</string>
|
||||
<string name="settings_advanced_domain_fronting_summary">绕过 SNI 封锁</string>
|
||||
<string name="settings_advanced_domain_fronting_title">域名前置(重启应用后生效)</string>
|
||||
<string name="settings_advanced_domain_fronting_summary">绕过 SNI 封锁\n启用时会禁用代理</string>
|
||||
<string name="action_add_tag">添加标签</string>
|
||||
<string name="action_add_tag_tip">添加新标签,用逗号「,」分割</string>
|
||||
<string name="comment_user_uploader">%s (上传者)</string>
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
<string name="text_is_empty">文本為空</string>
|
||||
<string name="waring">警告</string>
|
||||
<string name="wrong_cookie_warning">看起來您輸入的 Cookie 是錯誤的,最好檢查一下。</string>
|
||||
<string name="found_cookies">找到舊版 Cookie</string>
|
||||
|
||||
<string name="invalid_download_location">似乎下載路徑不可用。請到重新設置下載路徑。</string>
|
||||
|
||||
@@ -83,7 +82,6 @@
|
||||
<!-- Select scene -->
|
||||
<string name="select_scene">你想選擇哪個畫廊站點?</string>
|
||||
<string name="select_scene_explain">e-hentai:對任何人開放\nexhentai:僅對登錄用户開放</string>
|
||||
<string name="no_select">請選擇一個站點</string>
|
||||
|
||||
<!-- Update -->
|
||||
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
<string name="text_is_empty">文字是空的</string>
|
||||
<string name="waring">警告</string>
|
||||
<string name="wrong_cookie_warning">看來您輸入的 Cookie 是錯誤的,最好再檢查一下。</string>
|
||||
<string name="found_cookies">找到 Cookie了!</string>
|
||||
|
||||
<string name="invalid_download_location">看來下載路徑似乎沒辦法使用。請至設定重新設定下載路徑。</string>
|
||||
|
||||
@@ -83,7 +82,6 @@
|
||||
<!-- Select scene -->
|
||||
<string name="select_scene">你想選擇哪個圖庫站台?</string>
|
||||
<string name="select_scene_explain">e-hentai:對任何人開放\nexhentai:僅對登入使用者開放</string>
|
||||
<string name="no_select">請選擇一個站台</string>
|
||||
|
||||
<!-- Update -->
|
||||
|
||||
|
||||
@@ -57,7 +57,6 @@
|
||||
<string name="text_is_empty">Text is empty</string>
|
||||
<string name="waring">Warning</string>
|
||||
<string name="wrong_cookie_warning">It seems that the cookies you entered are wrong. You\'d better check them.</string>
|
||||
<string name="found_cookies">Found cookies!</string>
|
||||
|
||||
<string name="invalid_download_location">It seems download location is not available. Please set it in Settings.</string>
|
||||
|
||||
@@ -125,7 +124,6 @@
|
||||
<!-- Select scene -->
|
||||
<string name="select_scene">Which gallery site do you want to visit?</string>
|
||||
<string name="select_scene_explain">e-hentai: available for anyone\nexhentai: available for who has signed in</string>
|
||||
<string name="no_select">Please select one site</string>
|
||||
|
||||
<!-- Update -->
|
||||
|
||||
@@ -187,6 +185,7 @@
|
||||
<string name="duplicate_quick_search">A duplicate quick search exists. The name is \"%s\".</string>
|
||||
<string name="duplicate_name">This name is already in use.</string>
|
||||
<string name="save_progress">Save progress</string>
|
||||
<string name="delete_quick_search">Delete quick search \"%s\"?</string>
|
||||
|
||||
<string name="go_to_hint">Page %1$d, total %2$d pages</string>
|
||||
|
||||
@@ -223,6 +222,8 @@
|
||||
<string name="rate_successfully">Rate successfully</string>
|
||||
<string name="rate_failed">Rate failed</string>
|
||||
<string name="no_torrents">No torrents</string>
|
||||
<string name="download_torrent_started">Torrent download started</string>
|
||||
<string name="download_torrent_failure">Failed to download torrent</string>
|
||||
<string name="torrents">Torrents</string>
|
||||
<string name="favorited">Favorited</string>
|
||||
<string name="not_favorited">Not favorited</string>
|
||||
@@ -350,6 +351,7 @@
|
||||
<string name="label_text_is_invalid">\"Default\" is an invalid label</string>
|
||||
<string name="label_text_exist">Label exists</string>
|
||||
<string name="rename_label_title">Rename label</string>
|
||||
<string name="delete_label">Delete label \"%s\"?</string>
|
||||
|
||||
<!-- History -->
|
||||
<string name="no_history">Viewed galleries will be shown here</string>
|
||||
|
||||
Reference in new issue
Block a user