Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4278bf4631 | ||
|
|
7fa2dd1b74 | ||
|
|
afcd5b0d6e | ||
|
|
2f49748a3b | ||
|
|
4dffa25819 | ||
|
|
fcce3a04a6 | ||
|
|
bc38c8c135 | ||
|
|
4e462a1903 | ||
|
|
43bc5ab50c | ||
|
|
fed04784db | ||
|
|
4dbf5a45e8 | ||
|
|
5d22e70ded | ||
|
|
a3cae20478 | ||
|
|
f7cfbf1b34 | ||
|
|
4d4358f806 | ||
|
|
6ca3c3261e | ||
|
|
635a0b3af1 | ||
|
|
4288bc790d | ||
|
|
c52c91e1c0 |
No files matched your search
+11
-13
@@ -1,7 +1,7 @@
|
||||
import java.nio.file.Paths
|
||||
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'org.jetbrains.kotlin.android'
|
||||
id 'kotlin-kapt'
|
||||
}
|
||||
|
||||
android {
|
||||
@@ -16,6 +16,8 @@ android {
|
||||
splits {
|
||||
abi {
|
||||
enable = true
|
||||
reset()
|
||||
include 'arm64-v8a', 'x86_64'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,12 +34,11 @@ android {
|
||||
|
||||
defaultConfig {
|
||||
applicationId "io.github.nekoinverter.ehviewer"
|
||||
minSdkVersion 26
|
||||
minSdkVersion 31
|
||||
targetSdkVersion 32
|
||||
versionCode 100011
|
||||
versionName "1.7.26.4"
|
||||
versionCode 114516
|
||||
versionName "1.7.26.7"
|
||||
resConfigs 'zh', 'zh-rCN', 'zh-rHK', 'zh-rTW', 'es', 'ja', 'ko', 'fr', 'de', 'th'
|
||||
testOptions.unitTests.includeAndroidResources = true
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
@@ -45,6 +46,10 @@ android {
|
||||
targetCompatibility JavaVersion.VERSION_11
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = '11'
|
||||
}
|
||||
|
||||
lint {
|
||||
abortOnError true
|
||||
checkReleaseBuilds false
|
||||
@@ -106,7 +111,6 @@ dependencies {
|
||||
implementation 'androidx.webkit:webkit:1.4.0'
|
||||
implementation 'com.drakeet.drawer:drawer:1.0.3'
|
||||
implementation 'com.google.android.material:material:1.6.0'
|
||||
implementation 'com.getkeepsafe.relinker:relinker:1.4.4'
|
||||
implementation 'com.getkeepsafe.taptargetview:taptargetview:1.13.3'
|
||||
implementation 'com.github.seven332:beerbelly:0.1.4'
|
||||
implementation 'com.github.seven332:glgallery:0.1.2'
|
||||
@@ -118,9 +122,6 @@ dependencies {
|
||||
implementation 'com.github.seven332:yorozuya-thread:0.1.1'
|
||||
implementation 'com.github.seven332:yorozuya-collect:0.1.4'
|
||||
implementation 'com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:1.0.0'
|
||||
implementation 'com.microsoft.appcenter:appcenter-analytics:4.4.3'
|
||||
implementation 'com.microsoft.appcenter:appcenter-crashes:4.4.3'
|
||||
implementation 'com.microsoft.appcenter:appcenter-distribute:4.4.3'
|
||||
implementation 'com.squareup.okhttp3:okhttp:4.9.2'
|
||||
implementation 'com.squareup.okhttp3:okhttp-dnsoverhttps:4.9.2'
|
||||
implementation 'com.takisoft.preferencex:preferencex:1.1.0'
|
||||
@@ -137,9 +138,6 @@ dependencies {
|
||||
implementation 'org.greenrobot:greendao:3.3.0'
|
||||
implementation 'org.jsoup:jsoup:1.14.3'
|
||||
implementation projects.native
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
testImplementation 'org.robolectric:robolectric:4.2.1'
|
||||
testImplementation 'org.jooq:joor:0.9.6'
|
||||
}
|
||||
|
||||
configurations.all {
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
package com.hippo.ehviewer;
|
||||
|
||||
import android.app.Application;
|
||||
import android.test.ApplicationTestCase;
|
||||
|
||||
/**
|
||||
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
|
||||
*/
|
||||
public class ApplicationTest extends ApplicationTestCase<Application> {
|
||||
public ApplicationTest() {
|
||||
super(Application.class);
|
||||
}
|
||||
}
|
||||
@@ -1,164 +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;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.RectF;
|
||||
import android.os.Environment;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class CardBgTest extends TestCase {
|
||||
|
||||
private static final float[] TOP_ALPHA = {
|
||||
0f, // Dump
|
||||
0.12f,
|
||||
0.16f,
|
||||
0.19f,
|
||||
0.25f,
|
||||
0.30f,
|
||||
};
|
||||
|
||||
private static final float[] TOP_OFFSET = {
|
||||
0f, // Dump
|
||||
1f,
|
||||
3f,
|
||||
10f,
|
||||
14f,
|
||||
19f,
|
||||
};
|
||||
|
||||
private static final float[] TOP_BLUR = {
|
||||
0f, // Dump
|
||||
1.5f,
|
||||
3f,
|
||||
10f,
|
||||
14f,
|
||||
19f,
|
||||
};
|
||||
|
||||
private static final float[] BOTTOM_ALPHA = {
|
||||
0f, // Dump
|
||||
0.24f,
|
||||
0.23f,
|
||||
0.23f,
|
||||
0.22f,
|
||||
0.22f,
|
||||
};
|
||||
|
||||
private static final float[] BOTTOM_OFFSET = {
|
||||
0f, // Dump
|
||||
1f,
|
||||
3f,
|
||||
6f,
|
||||
10f,
|
||||
15f,
|
||||
};
|
||||
|
||||
private static final float[] BOTTOM_BLUR = {
|
||||
0f, // Dump
|
||||
1f,
|
||||
3f,
|
||||
3f,
|
||||
5f,
|
||||
6f,
|
||||
};
|
||||
|
||||
private static final int MAX_SIZE = 200;
|
||||
|
||||
|
||||
public void testGen() throws FileNotFoundException {
|
||||
genCardBg(Color.WHITE, 2, 2);
|
||||
}
|
||||
|
||||
private Path getPath(float radius, float base) {
|
||||
RectF rectF = new RectF();
|
||||
Path path = new Path();
|
||||
path.moveTo(base / 2, -base / 2 - radius);
|
||||
rectF.set(base / 2 - radius, -base / 2 - radius, base / 2 + radius, -base / 2 + radius);
|
||||
path.arcTo(rectF, -90, 90);
|
||||
path.lineTo(base / 2 + radius, base / 2);
|
||||
rectF.set(base / 2 - radius, base / 2 - radius, base / 2 + radius, base / 2 + radius);
|
||||
path.arcTo(rectF, 0, 90);
|
||||
path.lineTo(-base / 2, base / 2 + radius);
|
||||
rectF.set(-base / 2 - radius, base / 2 - radius, -base / 2 + radius, base / 2 + radius);
|
||||
path.arcTo(rectF, 90, 90);
|
||||
path.lineTo(-base / 2 - radius, -base / 2);
|
||||
rectF.set(-base / 2 - radius, -base / 2 - radius, -base / 2 + radius, -base / 2 + radius);
|
||||
path.arcTo(rectF, 180, 90);
|
||||
path.close();
|
||||
return path;
|
||||
}
|
||||
|
||||
private void genCardBg(int color, float radius, int elevation) throws FileNotFoundException {
|
||||
|
||||
float base = 4;
|
||||
float topAlpha = TOP_ALPHA[elevation];
|
||||
float topOffset = TOP_OFFSET[elevation];
|
||||
float topBlur = TOP_BLUR[elevation];
|
||||
float bottomAlpha = BOTTOM_ALPHA[elevation];
|
||||
float bottomOffset = BOTTOM_OFFSET[elevation];
|
||||
float bottomBlur = BOTTOM_BLUR[elevation];
|
||||
|
||||
|
||||
float ratio = 3;
|
||||
|
||||
|
||||
doGenCardBg(new FileOutputStream(new File(Environment.getExternalStorageDirectory(), "test.png")),
|
||||
color, radius * ratio, base * ratio,
|
||||
topAlpha, topOffset * ratio, topBlur * ratio,
|
||||
bottomAlpha, bottomOffset * ratio, bottomBlur * ratio);
|
||||
|
||||
|
||||
}
|
||||
|
||||
private int getColor(float alpha) {
|
||||
return Color.argb((int) (alpha * 0xff), 0, 0, 0);
|
||||
}
|
||||
|
||||
private void doGenCardBg(OutputStream os, int color, float radius, float base,
|
||||
float topAlpha, float topOffset, float topBlur,
|
||||
float bottomAlpha, float bottomOffset, float bottomBlur) throws FileNotFoundException {
|
||||
|
||||
Path path = getPath(radius, base);
|
||||
path.offset(MAX_SIZE / 2, MAX_SIZE / 2);
|
||||
|
||||
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
|
||||
paint.setColor(color);
|
||||
Bitmap bitmap = Bitmap.createBitmap(MAX_SIZE, MAX_SIZE, Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
|
||||
// Draw bottom
|
||||
paint.setShadowLayer(bottomBlur, 0, bottomOffset, getColor(bottomAlpha));
|
||||
canvas.drawPath(path, paint);
|
||||
|
||||
// Draw top
|
||||
paint.setShadowLayer(topBlur, 0, topOffset, getColor(topAlpha));
|
||||
canvas.drawPath(path, paint);
|
||||
|
||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, os);
|
||||
}
|
||||
}
|
||||
@@ -1,22 +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;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class CookieDBTest extends TestCase {
|
||||
}
|
||||
@@ -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.ehviewer;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
public class DumpTest extends TestCase {
|
||||
|
||||
|
||||
public void testDump() {
|
||||
String str = "M12.1,18.55L12,18.65L11.89,18.55C7.14,14.24 4,11.39 4,8.5C4,6.5 5.5,5 7.5,5C9.04,5 10.54,6 11.07,7.36H12.93C13.46,6 14.96,5 16.5,5C18.5,5 20,6.5 20,8.5C20,11.39 16.86,14.24 12.1,18.55";
|
||||
System.out.println(str.replaceAll("\\d+(\\.\\d+)?", "12"));
|
||||
}
|
||||
|
||||
public void testDumpURL() {
|
||||
String str1 = "http://exhentai.org/?f_doujinshi=1&f_manga=0&f_artistcg=0&f_gamecg=1&f_western=1&f_non-h=1&f_imageset=0&f_cosplay=0&f_asianporn=1&f_misc=1&f_search=&f_apply=Apply+Filter";
|
||||
String str2 = "http://exhentai.org/3?f_search=hentai&f_apply=Apply+Filter";
|
||||
try {
|
||||
URL url = new URL(str2);
|
||||
|
||||
|
||||
System.out.println(url.getHost());
|
||||
System.out.println(url.getPath());
|
||||
System.out.println(url.getQuery());
|
||||
|
||||
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,21 +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.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
|
||||
<string name="app_name">EhViewer Debug</string>
|
||||
|
||||
</resources>
|
||||
@@ -1,21 +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.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
|
||||
<string name="app_name">EhViewer Debug</string>
|
||||
|
||||
</resources>
|
||||
@@ -1,21 +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.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
|
||||
<string name="app_name">EhViewer Debug</string>
|
||||
|
||||
</resources>
|
||||
@@ -1,21 +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.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
|
||||
<string name="app_name">EhViewer Debug</string>
|
||||
|
||||
</resources>
|
||||
@@ -1,21 +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.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
|
||||
<string name="app_name">EhViewer Debug</string>
|
||||
|
||||
</resources>
|
||||
@@ -1,21 +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.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
|
||||
<string name="app_name">EhViewer Debug</string>
|
||||
|
||||
</resources>
|
||||
@@ -1,32 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<shortcut
|
||||
android:enabled="true"
|
||||
android:icon="@drawable/ic_shortcut_start"
|
||||
android:shortcutDisabledMessage="@string/download_start_all"
|
||||
android:shortcutId="start_all"
|
||||
android:shortcutLongLabel="@string/download_start_all"
|
||||
android:shortcutShortLabel="@string/download_start_all">
|
||||
<intent
|
||||
android:action="start_all"
|
||||
android:targetClass="com.hippo.ehviewer.shortcuts.ShortcutsActivity"
|
||||
android:targetPackage="io.github.nekoinverter.ehviewer.debug" />
|
||||
<categories android:name="android.shortcut.conversation" />
|
||||
</shortcut>
|
||||
|
||||
<shortcut
|
||||
android:enabled="true"
|
||||
android:icon="@drawable/ic_shortcut_stop"
|
||||
android:shortcutDisabledMessage="@string/download_stop_all"
|
||||
android:shortcutId="stop_all"
|
||||
android:shortcutLongLabel="@string/download_stop_all"
|
||||
android:shortcutShortLabel="@string/download_stop_all">
|
||||
<intent
|
||||
android:action="stop_all"
|
||||
android:targetClass="com.hippo.ehviewer.shortcuts.ShortcutsActivity"
|
||||
android:targetPackage="io.github.nekoinverter.ehviewer.debug" />
|
||||
<categories android:name="android.shortcut.conversation" />
|
||||
</shortcut>
|
||||
|
||||
</shortcuts>
|
||||
@@ -32,23 +32,24 @@
|
||||
<application
|
||||
android:name="com.hippo.ehviewer.EhApplication"
|
||||
android:allowBackup="true"
|
||||
android:appCategory="image"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:fullBackupContent="@xml/backup_scheme"
|
||||
android:hasFragileUserData="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:largeHeap="true"
|
||||
android:appCategory="image"
|
||||
android:hasFragileUserData="true"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:theme="@style/AppTheme"
|
||||
tools:ignore="UnusedAttribute">
|
||||
|
||||
<activity
|
||||
android:name="com.hippo.ehviewer.ui.MainActivity"
|
||||
android:configChanges="screenSize"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTask"
|
||||
android:windowSoftInputMode="adjustResize|stateAlwaysHidden"
|
||||
android:exported="true">
|
||||
android:windowSoftInputMode="adjustResize|stateAlwaysHidden">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
@@ -89,9 +90,9 @@
|
||||
<activity
|
||||
android:name="com.hippo.ehviewer.ui.GalleryActivity"
|
||||
android:configChanges="screenSize"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTask"
|
||||
android:theme="@style/AppTheme.Gallery"
|
||||
android:exported="true">
|
||||
android:theme="@style/AppTheme.Gallery">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
@@ -22,11 +22,10 @@ import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.CheckBox;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.hippo.ehviewer.R;
|
||||
|
||||
public class CheckBoxDialogBuilder extends AlertDialog.Builder {
|
||||
public class CheckBoxDialogBuilder extends MaterialAlertDialogBuilder {
|
||||
|
||||
private final CheckBox mCheckBox;
|
||||
|
||||
|
||||
@@ -29,10 +29,11 @@ import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.textfield.TextInputLayout;
|
||||
import com.hippo.ehviewer.R;
|
||||
|
||||
public class EditTextDialogBuilder extends AlertDialog.Builder implements EditText.OnEditorActionListener {
|
||||
public class EditTextDialogBuilder extends MaterialAlertDialogBuilder implements EditText.OnEditorActionListener {
|
||||
|
||||
private final TextInputLayout mTextInputLayout;
|
||||
private final EditText mEditText;
|
||||
|
||||
@@ -27,10 +27,11 @@ import android.widget.ListView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.yorozuya.ViewUtils;
|
||||
|
||||
public class ListCheckBoxDialogBuilder extends AlertDialog.Builder {
|
||||
public class ListCheckBoxDialogBuilder extends MaterialAlertDialogBuilder {
|
||||
|
||||
private final CheckBox mCheckBox;
|
||||
|
||||
|
||||
@@ -39,26 +39,17 @@ import okhttp3.OkHttpClient;
|
||||
@SuppressWarnings("rawtypes")
|
||||
public final class Conaco<V> {
|
||||
|
||||
private static final String TAG = Conaco.class.getSimpleName();
|
||||
|
||||
@IntDef({SOURCE_MEMORY, SOURCE_DISK, SOURCE_NETWORK})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface Source {
|
||||
}
|
||||
|
||||
public static final int SOURCE_MEMORY = 0;
|
||||
public static final int SOURCE_DISK = 1;
|
||||
public static final int SOURCE_NETWORK = 2;
|
||||
|
||||
private static final String TAG = Conaco.class.getSimpleName();
|
||||
private final ValueHelper<V> mHelper;
|
||||
private final ValueCache<V> mCache;
|
||||
private final OkHttpClient mOkHttpClient;
|
||||
private final Register<V> mRegister;
|
||||
|
||||
private final SerialThreadExecutor mDiskExecutor;
|
||||
private final ThreadPoolExecutor mNetworkExecutor;
|
||||
private final AtomicInteger mIdGenerator;
|
||||
|
||||
private final boolean mDebug;
|
||||
|
||||
private Conaco(Builder<V> builder) {
|
||||
@@ -197,6 +188,11 @@ public final class Conaco<V> {
|
||||
onUnregisterConacoTask(task);
|
||||
}
|
||||
|
||||
@IntDef({SOURCE_MEMORY, SOURCE_DISK, SOURCE_NETWORK})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface Source {
|
||||
}
|
||||
|
||||
public static class Builder<T> extends BeerBelly.BeerBellyParams {
|
||||
/**
|
||||
* The client to get image from internet
|
||||
|
||||
@@ -85,6 +85,42 @@ public final class ConacoTask<V> {
|
||||
mConaco = builder.mConaco;
|
||||
}
|
||||
|
||||
private static void putFromDiskCacheToDataContainer(String key, ValueCache cache, DataContainer container) {
|
||||
SimpleDiskCache diskCache = cache.getDiskCache();
|
||||
if (diskCache != null) {
|
||||
InputStreamPipe pipe = diskCache.getInputStreamPipe(key);
|
||||
if (pipe != null) {
|
||||
try {
|
||||
pipe.obtain();
|
||||
container.save(pipe.open(), -1L, null, null);
|
||||
} catch (IOException e) {
|
||||
Log.d(TAG, "Can't save value from disk cache to data container");
|
||||
e.printStackTrace();
|
||||
container.remove();
|
||||
} finally {
|
||||
pipe.close();
|
||||
pipe.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void putFromDataContainerToDiskCache(String key, ValueCache cache, DataContainer container) {
|
||||
InputStreamPipe pipe = container.get();
|
||||
if (pipe != null) {
|
||||
try {
|
||||
pipe.obtain();
|
||||
cache.putRawToDisk(key, pipe.open());
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, "Can't save value from data container to disk cache", e);
|
||||
cache.removeFromDisk(key);
|
||||
} finally {
|
||||
pipe.close();
|
||||
pipe.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int getId() {
|
||||
return mId;
|
||||
}
|
||||
@@ -176,39 +212,133 @@ public final class ConacoTask<V> {
|
||||
return mStop || asyncTask.isCancelled() || unikery == null || unikery.getTaskId() != mId;
|
||||
}
|
||||
|
||||
private static void putFromDiskCacheToDataContainer(String key, ValueCache cache, DataContainer container) {
|
||||
SimpleDiskCache diskCache = cache.getDiskCache();
|
||||
if (diskCache != null) {
|
||||
InputStreamPipe pipe = diskCache.getInputStreamPipe(key);
|
||||
if (pipe != null) {
|
||||
try {
|
||||
pipe.obtain();
|
||||
container.save(pipe.open(), -1L, null, null);
|
||||
} catch (IOException e) {
|
||||
Log.d(TAG, "Can't save value from disk cache to data container");
|
||||
e.printStackTrace();
|
||||
container.remove();
|
||||
} finally {
|
||||
pipe.close();
|
||||
pipe.release();
|
||||
}
|
||||
@SuppressWarnings({"unused", "UnusedReturnValue", "RedundantSuppression"})
|
||||
public static class Builder<T> {
|
||||
|
||||
private int mId;
|
||||
private Unikery<T> mUnikery;
|
||||
private String mKey;
|
||||
private String mUrl;
|
||||
private DataContainer mDataContainer;
|
||||
private boolean mUseMemoryCache = true;
|
||||
private boolean mUseDiskCache = true;
|
||||
private boolean mUseNetwork = true;
|
||||
private ValueHelper<T> mHelper;
|
||||
private ValueCache<T> mCache;
|
||||
private OkHttpClient mOkHttpClient;
|
||||
private Executor mDiskExecutor;
|
||||
private Executor mNetworkExecutor;
|
||||
private Conaco<T> mConaco;
|
||||
|
||||
public Builder<T> setId(int id) {
|
||||
mId = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Unikery<T> getUnikery() {
|
||||
return mUnikery;
|
||||
}
|
||||
|
||||
public Builder<T> setUnikery(Unikery<T> unikery) {
|
||||
mUnikery = unikery;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return mKey;
|
||||
}
|
||||
|
||||
public Builder<T> setKey(String key) {
|
||||
mKey = key;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return mUrl;
|
||||
}
|
||||
|
||||
public Builder<T> setUrl(String url) {
|
||||
mUrl = url;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder<T> setDataContainer(DataContainer dataContainer) {
|
||||
mDataContainer = dataContainer;
|
||||
return this;
|
||||
}
|
||||
|
||||
boolean isUseMemoryCache() {
|
||||
return mUseMemoryCache;
|
||||
}
|
||||
|
||||
public Builder<T> setUseMemoryCache(boolean useMemoryCache) {
|
||||
mUseMemoryCache = useMemoryCache;
|
||||
return this;
|
||||
}
|
||||
|
||||
boolean isUseDiskCache() {
|
||||
return mUseDiskCache;
|
||||
}
|
||||
|
||||
public Builder<T> setUseDiskCache(boolean useDiskCache) {
|
||||
mUseDiskCache = useDiskCache;
|
||||
return this;
|
||||
}
|
||||
|
||||
boolean isUseNetwork() {
|
||||
return mUseNetwork;
|
||||
}
|
||||
|
||||
public Builder<T> setUseNetwork(boolean useNetwork) {
|
||||
mUseNetwork = useNetwork;
|
||||
return this;
|
||||
}
|
||||
|
||||
ValueHelper<T> getHelper() {
|
||||
return mHelper;
|
||||
}
|
||||
|
||||
Builder<T> setHelper(ValueHelper<T> helper) {
|
||||
mHelper = helper;
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder<T> setCache(ValueCache<T> cache) {
|
||||
mCache = cache;
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder<T> setOkHttpClient(OkHttpClient okHttpClient) {
|
||||
mOkHttpClient = okHttpClient;
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder<T> setDiskExecutor(Executor diskExecutor) {
|
||||
mDiskExecutor = diskExecutor;
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder<T> setNetworkExecutor(Executor networkExecutor) {
|
||||
mNetworkExecutor = networkExecutor;
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder<T> setConaco(Conaco<T> conaco) {
|
||||
mConaco = conaco;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void isValid() {
|
||||
if (mUnikery == null) {
|
||||
throw new IllegalStateException("Must set unikery");
|
||||
}
|
||||
if (mKey == null && mUrl == null && mDataContainer == null) {
|
||||
throw new IllegalStateException("At least one of mKey and mUrl and mDataContainer have to not be null");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void putFromDataContainerToDiskCache(String key, ValueCache cache, DataContainer container) {
|
||||
InputStreamPipe pipe = container.get();
|
||||
if (pipe != null) {
|
||||
try {
|
||||
pipe.obtain();
|
||||
cache.putRawToDisk(key, pipe.open());
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, "Can't save value from data container to disk cache", e);
|
||||
cache.removeFromDisk(key);
|
||||
} finally {
|
||||
pipe.close();
|
||||
pipe.release();
|
||||
}
|
||||
public ConacoTask<T> build() {
|
||||
return new ConacoTask<>(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -455,134 +585,4 @@ public final class ConacoTask<V> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unused", "UnusedReturnValue", "RedundantSuppression"})
|
||||
public static class Builder<T> {
|
||||
|
||||
private int mId;
|
||||
private Unikery<T> mUnikery;
|
||||
private String mKey;
|
||||
private String mUrl;
|
||||
private DataContainer mDataContainer;
|
||||
private boolean mUseMemoryCache = true;
|
||||
private boolean mUseDiskCache = true;
|
||||
private boolean mUseNetwork = true;
|
||||
private ValueHelper<T> mHelper;
|
||||
private ValueCache<T> mCache;
|
||||
private OkHttpClient mOkHttpClient;
|
||||
private Executor mDiskExecutor;
|
||||
private Executor mNetworkExecutor;
|
||||
private Conaco<T> mConaco;
|
||||
|
||||
public Builder<T> setId(int id) {
|
||||
mId = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder<T> setUnikery(Unikery<T> unikery) {
|
||||
mUnikery = unikery;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Unikery<T> getUnikery() {
|
||||
return mUnikery;
|
||||
}
|
||||
|
||||
public Builder<T> setKey(String key) {
|
||||
mKey = key;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return mKey;
|
||||
}
|
||||
|
||||
public Builder<T> setUrl(String url) {
|
||||
mUrl = url;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return mUrl;
|
||||
}
|
||||
|
||||
public Builder<T> setDataContainer(DataContainer dataContainer) {
|
||||
mDataContainer = dataContainer;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder<T> setUseMemoryCache(boolean useMemoryCache) {
|
||||
mUseMemoryCache = useMemoryCache;
|
||||
return this;
|
||||
}
|
||||
|
||||
boolean isUseMemoryCache() {
|
||||
return mUseMemoryCache;
|
||||
}
|
||||
|
||||
public Builder<T> setUseDiskCache(boolean useDiskCache) {
|
||||
mUseDiskCache = useDiskCache;
|
||||
return this;
|
||||
}
|
||||
|
||||
boolean isUseDiskCache() {
|
||||
return mUseDiskCache;
|
||||
}
|
||||
|
||||
public Builder<T> setUseNetwork(boolean useNetwork) {
|
||||
mUseNetwork = useNetwork;
|
||||
return this;
|
||||
}
|
||||
|
||||
boolean isUseNetwork() {
|
||||
return mUseNetwork;
|
||||
}
|
||||
|
||||
Builder<T> setHelper(ValueHelper<T> helper) {
|
||||
mHelper = helper;
|
||||
return this;
|
||||
}
|
||||
|
||||
ValueHelper<T> getHelper() {
|
||||
return mHelper;
|
||||
}
|
||||
|
||||
Builder<T> setCache(ValueCache<T> cache) {
|
||||
mCache = cache;
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder<T> setOkHttpClient(OkHttpClient okHttpClient) {
|
||||
mOkHttpClient = okHttpClient;
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder<T> setDiskExecutor(Executor diskExecutor) {
|
||||
mDiskExecutor = diskExecutor;
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder<T> setNetworkExecutor(Executor networkExecutor) {
|
||||
mNetworkExecutor = networkExecutor;
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder<T> setConaco(Conaco<T> conaco) {
|
||||
mConaco = conaco;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void isValid() {
|
||||
if (mUnikery == null) {
|
||||
throw new IllegalStateException("Must set unikery");
|
||||
}
|
||||
if (mKey == null && mUrl == null && mDataContainer == null) {
|
||||
throw new IllegalStateException("At least one of mKey and mUrl and mDataContainer have to not be null");
|
||||
}
|
||||
}
|
||||
|
||||
public ConacoTask<T> build() {
|
||||
return new ConacoTask<>(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,13 +22,6 @@ public interface Unikery<V> {
|
||||
|
||||
int INVALID_ID = -1;
|
||||
|
||||
/**
|
||||
* Store the conaco task id
|
||||
*
|
||||
* @param id the conaco task id
|
||||
*/
|
||||
void setTaskId(int id);
|
||||
|
||||
/**
|
||||
* Get the conaco task id
|
||||
*
|
||||
@@ -36,6 +29,13 @@ public interface Unikery<V> {
|
||||
*/
|
||||
int getTaskId();
|
||||
|
||||
/**
|
||||
* Store the conaco task id
|
||||
*
|
||||
* @param id the conaco task id
|
||||
*/
|
||||
void setTaskId(int id);
|
||||
|
||||
/**
|
||||
* On miss in the source
|
||||
*/
|
||||
|
||||
@@ -46,9 +46,9 @@ public class MSQLiteBuilder {
|
||||
JAVA_TYPE_TO_SQLITE_TYPE.put(String.class, "TEXT");
|
||||
}
|
||||
|
||||
private final SparseArray<List<String>> statementsMap = new SparseArray<>();
|
||||
private int version = 0;
|
||||
private List<String> statements;
|
||||
private final SparseArray<List<String>> statementsMap = new SparseArray<>();
|
||||
|
||||
private static String javaTypeToSQLiteType(Class clazz) {
|
||||
String type = JAVA_TYPE_TO_SQLITE_TYPE.get(clazz);
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
|
||||
package com.hippo.easyrecyclerview;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.hardware.SensorManager;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.AttributeSet;
|
||||
@@ -24,12 +26,18 @@ import android.util.SparseBooleanArray;
|
||||
import android.view.ActionMode;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.widget.Checkable;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.collection.LongSparseArray;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.recyclerview.widget.BridgeRecyclerView;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
|
||||
|
||||
import com.hippo.ehviewer.Settings;
|
||||
import com.hippo.yorozuya.NumberUtils;
|
||||
@@ -38,7 +46,7 @@ import com.hippo.yorozuya.NumberUtils;
|
||||
* Add setChoiceMode for RecyclerView
|
||||
*/
|
||||
// Get some code from twoway-view and AbsListView.
|
||||
public class EasyRecyclerView extends ScrollLessRecyclerView {
|
||||
public class EasyRecyclerView extends BridgeRecyclerView {
|
||||
|
||||
/**
|
||||
* Represents an invalid position. All valid positions are in the range 0 to 1 less than the
|
||||
@@ -70,23 +78,27 @@ public class EasyRecyclerView extends ScrollLessRecyclerView {
|
||||
* The list allows multiple choices in custom action
|
||||
*/
|
||||
public static final int CHOICE_MODE_MULTIPLE_CUSTOM = 4;
|
||||
|
||||
/**
|
||||
* Controls if/how the user may choose/check items in the list
|
||||
*/
|
||||
private int mChoiceMode = CHOICE_MODE_NONE;
|
||||
|
||||
/**
|
||||
* Controls CHOICE_MODE_MULTIPLE_MODAL. null when inactive.
|
||||
*/
|
||||
private ActionMode mChoiceActionMode;
|
||||
|
||||
private static final float DECELERATION_RATE = (float) (Math.log(0.78) / Math.log(0.9));
|
||||
// Fling friction
|
||||
private final float mFlingFriction = ViewConfiguration.getScrollFriction();
|
||||
public float pageScrollThreshold;
|
||||
double flingMoveDistanceX;
|
||||
double flingMoveDistanceY;
|
||||
boolean canScrollVertical = true;
|
||||
boolean canScrollHorizontally = true;
|
||||
/**
|
||||
* Wrapper for the multiple choice mode callback; AbsListView needs to perform
|
||||
* a few extra actions around what application code does.
|
||||
*/
|
||||
MultiChoiceModeWrapper mMultiChoiceModeCallback;
|
||||
|
||||
/**
|
||||
* Controls if/how the user may choose/check items in the list
|
||||
*/
|
||||
private int mChoiceMode = CHOICE_MODE_NONE;
|
||||
/**
|
||||
* Controls CHOICE_MODE_MULTIPLE_MODAL. null when inactive.
|
||||
*/
|
||||
private ActionMode mChoiceActionMode;
|
||||
/**
|
||||
* Listener for custom multiple choices
|
||||
*/
|
||||
@@ -119,22 +131,40 @@ public class EasyRecyclerView extends ScrollLessRecyclerView {
|
||||
private LongSparseArray<Integer> mCheckedIdStates;
|
||||
|
||||
private Adapter<?> mAdapter;
|
||||
private boolean isScrollBefore = false;
|
||||
private int initialTouchX;
|
||||
private int initialTouchY;
|
||||
// A context-specific coefficient adjusted to physical values.
|
||||
private float mPhysicalCoeff;
|
||||
private int defaultOverflowItemScrollKeep;
|
||||
private boolean enableScroll = false;
|
||||
|
||||
public EasyRecyclerView(Context context) {
|
||||
super(context);
|
||||
EasyRecyclerView.this.init(context);
|
||||
setEnableScroll(!Settings.getEInkMode());
|
||||
}
|
||||
|
||||
public EasyRecyclerView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
EasyRecyclerView.this.init(context);
|
||||
setEnableScroll(!Settings.getEInkMode());
|
||||
}
|
||||
|
||||
public EasyRecyclerView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
EasyRecyclerView.this.init(context);
|
||||
setEnableScroll(!Settings.getEInkMode());
|
||||
}
|
||||
|
||||
public static void setViewChecked(View view, boolean checked) {
|
||||
if (view instanceof Checkable) {
|
||||
((Checkable) view).setChecked(checked);
|
||||
} else {
|
||||
view.setActivated(checked);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@@ -524,12 +554,365 @@ public class EasyRecyclerView extends ScrollLessRecyclerView {
|
||||
}
|
||||
}
|
||||
|
||||
public static void setViewChecked(View view, boolean checked) {
|
||||
if (view instanceof Checkable) {
|
||||
((Checkable) view).setChecked(checked);
|
||||
} else {
|
||||
view.setActivated(checked);
|
||||
private void init(Context context) {
|
||||
float scale = context.getResources().getDisplayMetrics().density;
|
||||
final float ppi = scale * 160.0f;
|
||||
mPhysicalCoeff = SensorManager.GRAVITY_EARTH // g (m/s^2)
|
||||
* 39.37f // inch/meter
|
||||
* ppi
|
||||
* 0.84f; // look and feel tuning
|
||||
pageScrollThreshold = scale * 80;
|
||||
}
|
||||
|
||||
public void setPageScrollThreshold(float pageScrollThreshold) {
|
||||
this.pageScrollThreshold = pageScrollThreshold;
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent e) {
|
||||
if (enableScroll) {
|
||||
return super.onTouchEvent(e);
|
||||
}
|
||||
boolean superTouchResult = super.onTouchEvent(e);
|
||||
if (superTouchResult) {
|
||||
switch (e.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
initialTouchX = (int) (e.getX() + 0.5f);
|
||||
initialTouchY = (int) (e.getY() + 0.5f);
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if (initialTouchX < 0 || initialTouchY < 0) {
|
||||
initialTouchX = (int) (e.getX() + 0.5f);
|
||||
initialTouchY = (int) (e.getY() + 0.5f);
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
if (isScrollBefore) {
|
||||
int moveDistanceX = (int) (initialTouchX - e.getX() + flingMoveDistanceX);
|
||||
int moveDistanceY = (int) (initialTouchY - e.getY() + flingMoveDistanceY);
|
||||
onTouchScroll(moveDistanceX, moveDistanceY);
|
||||
initialTouchX = initialTouchY = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
isScrollBefore = getScrollState() == SCROLL_STATE_DRAGGING;
|
||||
}
|
||||
return superTouchResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean scrollByInternal(int x, int y, MotionEvent ev, int type) {
|
||||
if (enableScroll) {
|
||||
return super.scrollByInternal(x, y, ev, type);
|
||||
}
|
||||
//disable drag scroll effect,e-ink screen don't need it
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean fling(int velocityX, int velocityY) {
|
||||
if (enableScroll) {
|
||||
return super.fling(velocityX, velocityY);
|
||||
}
|
||||
flingMoveDistanceX = getSplineFlingDistance(velocityX) * Math.signum(velocityX);
|
||||
flingMoveDistanceY = getSplineFlingDistance(velocityY) * Math.signum(velocityY);
|
||||
//disable fling scroll effect,e-ink screen don't need it
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void onTouchScroll(int dx, int dy) {
|
||||
canScrollVertical = true;
|
||||
canScrollHorizontally = true;
|
||||
LayoutManager layout = getLayoutManager();
|
||||
if (layout != null) {
|
||||
if (dy > pageScrollThreshold) {
|
||||
if (canScrollVertical && layout.canScrollVertically()) {
|
||||
canScrollVertical = false;
|
||||
onScrollDown();
|
||||
} else if (canScrollHorizontally && layout.canScrollHorizontally()) {
|
||||
canScrollHorizontally = false;
|
||||
onScrollRight();
|
||||
}
|
||||
} else if (dy < -pageScrollThreshold) {
|
||||
if (canScrollVertical && layout.canScrollVertically()) {
|
||||
canScrollVertical = false;
|
||||
onScrollUp();
|
||||
} else if (canScrollHorizontally && layout.canScrollHorizontally()) {
|
||||
canScrollHorizontally = false;
|
||||
onScrollLeft();
|
||||
}
|
||||
}
|
||||
|
||||
if (dx > pageScrollThreshold) {
|
||||
if (canScrollVertical && layout.canScrollVertically()) {
|
||||
onScrollDown();
|
||||
} else if (canScrollHorizontally && layout.canScrollHorizontally()) {
|
||||
onScrollRight();
|
||||
}
|
||||
} else if (dx < -pageScrollThreshold) {
|
||||
if (canScrollVertical && layout.canScrollVertically()) {
|
||||
onScrollUp();
|
||||
} else if (canScrollHorizontally && layout.canScrollHorizontally()) {
|
||||
onScrollLeft();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void onScrollLeft() {
|
||||
LayoutManager layout = getLayoutManager();
|
||||
if (layout instanceof LinearLayoutManager) {
|
||||
LinearLayoutManager realLayout = (LinearLayoutManager) layout;
|
||||
int firstVisiblePosition = realLayout.findFirstVisibleItemPosition();
|
||||
ViewHolder firstVisibleItem = findViewHolderForAdapterPosition(firstVisiblePosition);
|
||||
|
||||
if (firstVisibleItem == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
//when the item width overscreen, findLastCompletelyVisibleItemPosition always return NO_POSITION
|
||||
if (firstVisibleItem.itemView.getMeasuredWidth() > getMeasuredWidth()) {
|
||||
super.scrollByInternal(-getMeasuredWidth() + defaultOverflowItemScrollKeep, 0, null, ViewCompat.TYPE_TOUCH);
|
||||
} else if (firstVisibleItem.itemView.getMeasuredWidth() == getMeasuredWidth()) {
|
||||
super.scrollByInternal(-getMeasuredWidth(), 0, null, ViewCompat.TYPE_TOUCH);
|
||||
} else {
|
||||
super.scrollByInternal(firstVisibleItem.itemView.getRight() - getMeasuredWidth(), 0, null, ViewCompat.TYPE_TOUCH);
|
||||
}
|
||||
} else if (layout instanceof StaggeredGridLayoutManager) {
|
||||
StaggeredGridLayoutManager realLayout = (StaggeredGridLayoutManager) layout;
|
||||
int[] firstVisiblePosition = realLayout.findFirstVisibleItemPositions(null);
|
||||
ViewHolder[] firstVisibleItems = new ViewHolder[firstVisiblePosition.length];
|
||||
for (int i = 0; i < firstVisiblePosition.length; i++) {
|
||||
firstVisibleItems[i] = findViewHolderForAdapterPosition(firstVisiblePosition[i]);
|
||||
}
|
||||
int scrollDistance = Integer.MAX_VALUE;
|
||||
for (ViewHolder firstVisibleItem : firstVisibleItems) {
|
||||
if (firstVisibleItem != null) {
|
||||
if (firstVisibleItem.itemView.getRight() < scrollDistance) {
|
||||
scrollDistance = firstVisibleItem.itemView.getRight();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (scrollDistance == getMeasuredWidth()) {
|
||||
scrollDistance = 0;
|
||||
}
|
||||
super.scrollByInternal(scrollDistance - getMeasuredWidth(), 0, null, ViewCompat.TYPE_TOUCH);
|
||||
}
|
||||
}
|
||||
|
||||
protected void onScrollRight() {
|
||||
LayoutManager layout = getLayoutManager();
|
||||
if (layout instanceof LinearLayoutManager) {
|
||||
LinearLayoutManager realLayout = (LinearLayoutManager) layout;
|
||||
int lastVisiblePosition = realLayout.findLastVisibleItemPosition();
|
||||
ViewHolder lastVisibleItem = findViewHolderForAdapterPosition(lastVisiblePosition);
|
||||
|
||||
if (lastVisibleItem == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
//when the item width overflow screen, findLastCompletelyVisibleItemPosition always return NO_POSITION
|
||||
if (lastVisibleItem.itemView.getMeasuredWidth() > getMeasuredWidth()) {
|
||||
super.scrollByInternal(getMeasuredWidth() - defaultOverflowItemScrollKeep, 0, null, ViewCompat.TYPE_TOUCH);
|
||||
} else if (lastVisibleItem.itemView.getMeasuredWidth() == getMeasuredWidth()) {
|
||||
super.scrollByInternal(getMeasuredWidth(), 0, null, ViewCompat.TYPE_TOUCH);
|
||||
} else {
|
||||
super.scrollByInternal(lastVisibleItem.itemView.getLeft(), 0, null, ViewCompat.TYPE_TOUCH);
|
||||
}
|
||||
} else if (layout instanceof StaggeredGridLayoutManager) {
|
||||
StaggeredGridLayoutManager realLayout = (StaggeredGridLayoutManager) layout;
|
||||
int[] lastVisiblePosition = realLayout.findLastVisibleItemPositions(null);
|
||||
ViewHolder[] lastVisibleItems = new ViewHolder[lastVisiblePosition.length];
|
||||
for (int i = 0; i < lastVisiblePosition.length; i++) {
|
||||
lastVisibleItems[i] = findViewHolderForAdapterPosition(lastVisiblePosition[i]);
|
||||
}
|
||||
int scrollDistance = 0;
|
||||
for (ViewHolder lastVisibleItem : lastVisibleItems) {
|
||||
if (lastVisibleItem != null) {
|
||||
if (lastVisibleItem.itemView.getLeft() > scrollDistance) {
|
||||
scrollDistance = lastVisibleItem.itemView.getLeft();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (scrollDistance == 0) {
|
||||
scrollDistance = getMeasuredWidth();
|
||||
}
|
||||
super.scrollByInternal(scrollDistance, 0, null, ViewCompat.TYPE_TOUCH);
|
||||
}
|
||||
}
|
||||
|
||||
protected void onScrollUp() {
|
||||
LayoutManager layout = getLayoutManager();
|
||||
if (layout instanceof LinearLayoutManager) {
|
||||
LinearLayoutManager realLayout = (LinearLayoutManager) layout;
|
||||
int firstVisiblePosition = realLayout.findFirstVisibleItemPosition();
|
||||
ViewHolder firstVisibleItem = findViewHolderForAdapterPosition(firstVisiblePosition);
|
||||
|
||||
if (firstVisibleItem == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
//when the item height overscreen, findLastCompletelyVisibleItemPosition always return NO_POSITION
|
||||
if (firstVisibleItem.itemView.getMeasuredHeight() > getMeasuredHeight()) {
|
||||
super.scrollByInternal(0, -getMeasuredHeight() + defaultOverflowItemScrollKeep, null, ViewCompat.TYPE_TOUCH);
|
||||
} else if (firstVisibleItem.itemView.getMeasuredHeight() == getMeasuredHeight()) {
|
||||
super.scrollByInternal(0, -getMeasuredHeight(), null, ViewCompat.TYPE_TOUCH);
|
||||
} else {
|
||||
super.scrollByInternal(0, firstVisibleItem.itemView.getBottom() - getMeasuredHeight(), null, ViewCompat.TYPE_TOUCH);
|
||||
}
|
||||
} else if (layout instanceof StaggeredGridLayoutManager) {
|
||||
StaggeredGridLayoutManager realLayout = (StaggeredGridLayoutManager) layout;
|
||||
int[] firstVisiblePosition = realLayout.findFirstVisibleItemPositions(null);
|
||||
ViewHolder[] firstVisibleItems = new ViewHolder[firstVisiblePosition.length];
|
||||
for (int i = 0; i < firstVisiblePosition.length; i++) {
|
||||
firstVisibleItems[i] = findViewHolderForAdapterPosition(firstVisiblePosition[i]);
|
||||
}
|
||||
int scrollDistance = Integer.MAX_VALUE;
|
||||
for (ViewHolder firstVisibleItem : firstVisibleItems) {
|
||||
if (firstVisibleItem != null) {
|
||||
if (firstVisibleItem.itemView.getBottom() < scrollDistance) {
|
||||
scrollDistance = firstVisibleItem.itemView.getBaseline();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (scrollDistance == getMeasuredWidth()) {
|
||||
scrollDistance = 0;
|
||||
}
|
||||
super.scrollByInternal(0, scrollDistance - getMeasuredHeight(), null, ViewCompat.TYPE_TOUCH);
|
||||
}
|
||||
}
|
||||
|
||||
protected void onScrollDown() {
|
||||
LayoutManager layout = getLayoutManager();
|
||||
if (layout instanceof LinearLayoutManager) {
|
||||
LinearLayoutManager realLayout = (LinearLayoutManager) layout;
|
||||
int lastVisiblePosition = realLayout.findLastVisibleItemPosition();
|
||||
ViewHolder lastVisibleItem = findViewHolderForAdapterPosition(lastVisiblePosition);
|
||||
|
||||
if (lastVisibleItem == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
//when the item height overflow screen, findLastCompletelyVisibleItemPosition always return NO_POSITION
|
||||
if (lastVisibleItem.itemView.getMeasuredHeight() > getMeasuredHeight()) {
|
||||
super.scrollByInternal(0, getMeasuredHeight() - defaultOverflowItemScrollKeep, null, ViewCompat.TYPE_TOUCH);
|
||||
} else if (lastVisibleItem.itemView.getMeasuredHeight() == getMeasuredHeight()) {
|
||||
super.scrollByInternal(0, getMeasuredHeight(), null, ViewCompat.TYPE_TOUCH);
|
||||
} else {
|
||||
super.scrollByInternal(0, lastVisibleItem.itemView.getTop(), null, ViewCompat.TYPE_TOUCH);
|
||||
}
|
||||
} else if (layout instanceof StaggeredGridLayoutManager) {
|
||||
StaggeredGridLayoutManager realLayout = (StaggeredGridLayoutManager) layout;
|
||||
int[] lastVisiblePosition = realLayout.findLastVisibleItemPositions(null);
|
||||
ViewHolder[] lastVisibleItems = new ViewHolder[lastVisiblePosition.length];
|
||||
for (int i = 0; i < lastVisiblePosition.length; i++) {
|
||||
lastVisibleItems[i] = findViewHolderForAdapterPosition(lastVisiblePosition[i]);
|
||||
}
|
||||
int scrollDistance = 0;
|
||||
for (ViewHolder lastVisibleItem : lastVisibleItems) {
|
||||
if (lastVisibleItem != null) {
|
||||
if (lastVisibleItem.itemView.getTop() > scrollDistance) {
|
||||
scrollDistance = lastVisibleItem.itemView.getTop();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (scrollDistance == 0) {
|
||||
scrollDistance = getMeasuredHeight();
|
||||
}
|
||||
super.scrollByInternal(0, scrollDistance, null, ViewCompat.TYPE_TOUCH);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||
super.onSizeChanged(w, h, oldw, oldh);
|
||||
defaultOverflowItemScrollKeep = (int) (h * 0.05f);
|
||||
}
|
||||
|
||||
private double getSplineDeceleration(int velocity) {
|
||||
return Math.log(0.35f * Math.abs(velocity) / (mFlingFriction * mPhysicalCoeff));
|
||||
}
|
||||
|
||||
private double getSplineFlingDistance(int velocity) {
|
||||
final double l = getSplineDeceleration(velocity);
|
||||
final double decelMinusOne = DECELERATION_RATE - 1.0;
|
||||
return mFlingFriction * mPhysicalCoeff * Math.exp(DECELERATION_RATE / decelMinusOne * l);
|
||||
}
|
||||
|
||||
public boolean isEnableScroll() {
|
||||
return enableScroll;
|
||||
}
|
||||
|
||||
public void setEnableScroll(boolean enableScroll) {
|
||||
this.enableScroll = enableScroll;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parcelable onSaveInstanceState() {
|
||||
final SavedState ss = new SavedState(super.onSaveInstanceState());
|
||||
|
||||
ss.choiceMode = mChoiceMode;
|
||||
ss.customChoice = mCustomChoice;
|
||||
ss.checkedItemCount = mCheckedItemCount;
|
||||
ss.checkState = mCheckStates;
|
||||
ss.checkIdState = mCheckedIdStates;
|
||||
|
||||
return ss;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestoreInstanceState(Parcelable state) {
|
||||
SavedState ss = (SavedState) state;
|
||||
super.onRestoreInstanceState(ss.getSuperState());
|
||||
|
||||
setChoiceMode(ss.choiceMode);
|
||||
mCustomChoice = ss.customChoice;
|
||||
mCheckedItemCount = ss.checkedItemCount;
|
||||
if (ss.checkState != null) {
|
||||
mCheckStates = ss.checkState;
|
||||
}
|
||||
if (ss.checkIdState != null) {
|
||||
mCheckedIdStates = ss.checkIdState;
|
||||
}
|
||||
|
||||
if (mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL && mCheckedItemCount > 0) {
|
||||
mChoiceActionMode = startActionMode(mMultiChoiceModeCallback);
|
||||
}
|
||||
updateOnScreenCheckedViews();
|
||||
}
|
||||
|
||||
/**
|
||||
* A MultiChoiceModeListener receives events for {@link android.widget.AbsListView#CHOICE_MODE_MULTIPLE_MODAL}.
|
||||
* It acts as the {@link android.view.ActionMode.Callback} for the selection mode and also receives
|
||||
* {@link #onItemCheckedStateChanged(android.view.ActionMode, int, long, boolean)} events when the user
|
||||
* selects and deselects list items.
|
||||
*/
|
||||
public interface MultiChoiceModeListener extends ActionMode.Callback {
|
||||
/**
|
||||
* Called when an item is checked or unchecked during selection mode.
|
||||
*
|
||||
* @param mode The {@link android.view.ActionMode} providing the selection mode
|
||||
* @param position Adapter position of the item that was checked or unchecked
|
||||
* @param id Adapter ID of the item that was checked or unchecked
|
||||
* @param checked <code>true</code> if the item is now checked, <code>false</code>
|
||||
* if the item is now unchecked.
|
||||
*/
|
||||
void onItemCheckedStateChanged(ActionMode mode,
|
||||
int position, long id, boolean checked);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom checked
|
||||
*/
|
||||
public interface CustomChoiceListener {
|
||||
|
||||
void onIntoCustomChoice(EasyRecyclerView view);
|
||||
|
||||
void onOutOfCustomChoice(EasyRecyclerView view);
|
||||
|
||||
void onItemCheckedStateChanged(EasyRecyclerView view, int position, long id, boolean checked);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -549,13 +932,23 @@ public class EasyRecyclerView extends ScrollLessRecyclerView {
|
||||
|
||||
public static final SavedState EMPTY_STATE = new SavedState() {
|
||||
};
|
||||
public static final Parcelable.Creator<SavedState> CREATOR
|
||||
= new Parcelable.Creator<SavedState>() {
|
||||
@Override
|
||||
public SavedState createFromParcel(Parcel in) {
|
||||
return new SavedState(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SavedState[] newArray(int size) {
|
||||
return new SavedState[size];
|
||||
}
|
||||
};
|
||||
int choiceMode;
|
||||
boolean customChoice;
|
||||
int checkedItemCount;
|
||||
SparseBooleanArray checkState;
|
||||
LongSparseArray<Integer> checkIdState;
|
||||
|
||||
// This keeps the parent(RecyclerView)'s state
|
||||
Parcelable mSuperState;
|
||||
|
||||
@@ -618,73 +1011,6 @@ public class EasyRecyclerView extends ScrollLessRecyclerView {
|
||||
public Parcelable getSuperState() {
|
||||
return mSuperState;
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<SavedState> CREATOR
|
||||
= new Parcelable.Creator<SavedState>() {
|
||||
@Override
|
||||
public SavedState createFromParcel(Parcel in) {
|
||||
return new SavedState(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SavedState[] newArray(int size) {
|
||||
return new SavedState[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parcelable onSaveInstanceState() {
|
||||
final SavedState ss = new SavedState(super.onSaveInstanceState());
|
||||
|
||||
ss.choiceMode = mChoiceMode;
|
||||
ss.customChoice = mCustomChoice;
|
||||
ss.checkedItemCount = mCheckedItemCount;
|
||||
ss.checkState = mCheckStates;
|
||||
ss.checkIdState = mCheckedIdStates;
|
||||
|
||||
return ss;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestoreInstanceState(Parcelable state) {
|
||||
SavedState ss = (SavedState) state;
|
||||
super.onRestoreInstanceState(ss.getSuperState());
|
||||
|
||||
setChoiceMode(ss.choiceMode);
|
||||
mCustomChoice = ss.customChoice;
|
||||
mCheckedItemCount = ss.checkedItemCount;
|
||||
if (ss.checkState != null) {
|
||||
mCheckStates = ss.checkState;
|
||||
}
|
||||
if (ss.checkIdState != null) {
|
||||
mCheckedIdStates = ss.checkIdState;
|
||||
}
|
||||
|
||||
if (mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL && mCheckedItemCount > 0) {
|
||||
mChoiceActionMode = startActionMode(mMultiChoiceModeCallback);
|
||||
}
|
||||
updateOnScreenCheckedViews();
|
||||
}
|
||||
|
||||
/**
|
||||
* A MultiChoiceModeListener receives events for {@link android.widget.AbsListView#CHOICE_MODE_MULTIPLE_MODAL}.
|
||||
* It acts as the {@link android.view.ActionMode.Callback} for the selection mode and also receives
|
||||
* {@link #onItemCheckedStateChanged(android.view.ActionMode, int, long, boolean)} events when the user
|
||||
* selects and deselects list items.
|
||||
*/
|
||||
public interface MultiChoiceModeListener extends ActionMode.Callback {
|
||||
/**
|
||||
* Called when an item is checked or unchecked during selection mode.
|
||||
*
|
||||
* @param mode The {@link android.view.ActionMode} providing the selection mode
|
||||
* @param position Adapter position of the item that was checked or unchecked
|
||||
* @param id Adapter ID of the item that was checked or unchecked
|
||||
* @param checked <code>true</code> if the item is now checked, <code>false</code>
|
||||
* if the item is now unchecked.
|
||||
*/
|
||||
void onItemCheckedStateChanged(ActionMode mode,
|
||||
int position, long id, boolean checked);
|
||||
}
|
||||
|
||||
class MultiChoiceModeWrapper implements MultiChoiceModeListener {
|
||||
@@ -743,16 +1069,4 @@ public class EasyRecyclerView extends ScrollLessRecyclerView {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom checked
|
||||
*/
|
||||
public interface CustomChoiceListener {
|
||||
|
||||
void onIntoCustomChoice(EasyRecyclerView view);
|
||||
|
||||
void onOutOfCustomChoice(EasyRecyclerView view);
|
||||
|
||||
void onItemCheckedStateChanged(EasyRecyclerView view, int position, long id, boolean checked);
|
||||
}
|
||||
}
|
||||
@@ -28,9 +28,9 @@ import androidx.annotation.NonNull;
|
||||
|
||||
public class HandlerDrawable extends Drawable {
|
||||
|
||||
private int mColor = Color.BLACK;
|
||||
private final Paint mPaint;
|
||||
private final RectF mTemp = new RectF();
|
||||
private int mColor = Color.BLACK;
|
||||
|
||||
public HandlerDrawable() {
|
||||
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
|
||||
@@ -35,13 +35,10 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||
public class LinearDividerItemDecoration extends RecyclerView.ItemDecoration {
|
||||
public static final int HORIZONTAL = LinearLayoutManager.HORIZONTAL;
|
||||
public static final int VERTICAL = LinearLayoutManager.VERTICAL;
|
||||
|
||||
private boolean mShowFirstDivider = false;
|
||||
private boolean mShowLastDivider = false;
|
||||
|
||||
private final Rect mRect;
|
||||
private final Paint mPaint;
|
||||
|
||||
private boolean mShowFirstDivider = false;
|
||||
private boolean mShowLastDivider = false;
|
||||
private int mOrientation;
|
||||
private int mThickness;
|
||||
private int mPaddingStart = 0;
|
||||
|
||||
@@ -1,349 +0,0 @@
|
||||
package com.hippo.easyrecyclerview;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.hardware.SensorManager;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.ViewConfiguration;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.recyclerview.widget.BridgeRecyclerView;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
|
||||
|
||||
public class ScrollLessRecyclerView extends BridgeRecyclerView {
|
||||
|
||||
private boolean isScrollBefore = false;
|
||||
private int initialTouchX;
|
||||
private int initialTouchY;
|
||||
|
||||
// A context-specific coefficient adjusted to physical values.
|
||||
private float mPhysicalCoeff;
|
||||
// Fling friction
|
||||
private final float mFlingFriction = ViewConfiguration.getScrollFriction();
|
||||
private static final float DECELERATION_RATE = (float) (Math.log(0.78) / Math.log(0.9));
|
||||
|
||||
public float pageScrollThreshold;
|
||||
private int defaultOverflowItemScrollKeep;
|
||||
|
||||
private boolean enableScroll = false;
|
||||
|
||||
public ScrollLessRecyclerView(@NonNull Context context) {
|
||||
super(context);
|
||||
init(context);
|
||||
}
|
||||
|
||||
public ScrollLessRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init(context);
|
||||
}
|
||||
|
||||
public ScrollLessRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init(context);
|
||||
}
|
||||
|
||||
private void init(Context context) {
|
||||
float scale = context.getResources().getDisplayMetrics().density;
|
||||
final float ppi = scale * 160.0f;
|
||||
mPhysicalCoeff = SensorManager.GRAVITY_EARTH // g (m/s^2)
|
||||
* 39.37f // inch/meter
|
||||
* ppi
|
||||
* 0.84f; // look and feel tuning
|
||||
pageScrollThreshold = scale * 80;
|
||||
}
|
||||
|
||||
public void setPageScrollThreshold(float pageScrollThreshold) {
|
||||
this.pageScrollThreshold = pageScrollThreshold;
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent e) {
|
||||
if (enableScroll) {
|
||||
return super.onTouchEvent(e);
|
||||
}
|
||||
boolean superTouchResult = super.onTouchEvent(e);
|
||||
if (superTouchResult) {
|
||||
switch (e.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
initialTouchX = (int) (e.getX() + 0.5f);
|
||||
initialTouchY = (int) (e.getY() + 0.5f);
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if (initialTouchX < 0 || initialTouchY < 0) {
|
||||
initialTouchX = (int) (e.getX() + 0.5f);
|
||||
initialTouchY = (int) (e.getY() + 0.5f);
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
if (isScrollBefore) {
|
||||
int moveDistanceX = (int) (initialTouchX - e.getX() + flingMoveDistanceX);
|
||||
int moveDistanceY = (int) (initialTouchY - e.getY() + flingMoveDistanceY);
|
||||
onTouchScroll(moveDistanceX, moveDistanceY);
|
||||
initialTouchX = initialTouchY = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
isScrollBefore = getScrollState() == SCROLL_STATE_DRAGGING;
|
||||
}
|
||||
return superTouchResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean scrollByInternal(int x, int y, MotionEvent ev, int type) {
|
||||
if (enableScroll) {
|
||||
return super.scrollByInternal(x, y, ev, type);
|
||||
}
|
||||
//disable drag scroll effect,e-ink screen don't need it
|
||||
return false;
|
||||
}
|
||||
|
||||
double flingMoveDistanceX;
|
||||
double flingMoveDistanceY;
|
||||
|
||||
@Override
|
||||
public boolean fling(int velocityX, int velocityY) {
|
||||
if (enableScroll) {
|
||||
return super.fling(velocityX, velocityY);
|
||||
}
|
||||
flingMoveDistanceX = getSplineFlingDistance(velocityX) * Math.signum(velocityX);
|
||||
flingMoveDistanceY = getSplineFlingDistance(velocityY) * Math.signum(velocityY);
|
||||
//disable fling scroll effect,e-ink screen don't need it
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean canScrollVertical = true;
|
||||
boolean canScrollHorizontally = true;
|
||||
|
||||
protected void onTouchScroll(int dx, int dy) {
|
||||
canScrollVertical = true;
|
||||
canScrollHorizontally = true;
|
||||
LayoutManager layout = getLayoutManager();
|
||||
if (layout != null) {
|
||||
if (dy > pageScrollThreshold) {
|
||||
if (canScrollVertical && layout.canScrollVertically()) {
|
||||
canScrollVertical = false;
|
||||
onScrollDown();
|
||||
} else if (canScrollHorizontally && layout.canScrollHorizontally()) {
|
||||
canScrollHorizontally = false;
|
||||
onScrollRight();
|
||||
}
|
||||
} else if (dy < -pageScrollThreshold) {
|
||||
if (canScrollVertical && layout.canScrollVertically()) {
|
||||
canScrollVertical = false;
|
||||
onScrollUp();
|
||||
} else if (canScrollHorizontally && layout.canScrollHorizontally()) {
|
||||
canScrollHorizontally = false;
|
||||
onScrollLeft();
|
||||
}
|
||||
}
|
||||
|
||||
if (dx > pageScrollThreshold) {
|
||||
if (canScrollVertical && layout.canScrollVertically()) {
|
||||
onScrollDown();
|
||||
} else if (canScrollHorizontally && layout.canScrollHorizontally()) {
|
||||
onScrollRight();
|
||||
}
|
||||
} else if (dx < -pageScrollThreshold) {
|
||||
if (canScrollVertical && layout.canScrollVertically()) {
|
||||
onScrollUp();
|
||||
} else if (canScrollHorizontally && layout.canScrollHorizontally()) {
|
||||
onScrollLeft();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void onScrollLeft() {
|
||||
LayoutManager layout = getLayoutManager();
|
||||
if (layout instanceof LinearLayoutManager) {
|
||||
LinearLayoutManager realLayout = (LinearLayoutManager) layout;
|
||||
int firstVisiblePosition = realLayout.findFirstVisibleItemPosition();
|
||||
ViewHolder firstVisibleItem = findViewHolderForAdapterPosition(firstVisiblePosition);
|
||||
|
||||
if (firstVisibleItem == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
//when the item width overscreen, findLastCompletelyVisibleItemPosition always return NO_POSITION
|
||||
if (firstVisibleItem.itemView.getMeasuredWidth() > getMeasuredWidth()) {
|
||||
super.scrollByInternal(-getMeasuredWidth() + defaultOverflowItemScrollKeep, 0, null, ViewCompat.TYPE_TOUCH);
|
||||
} else if (firstVisibleItem.itemView.getMeasuredWidth() == getMeasuredWidth()) {
|
||||
super.scrollByInternal(-getMeasuredWidth(), 0, null, ViewCompat.TYPE_TOUCH);
|
||||
} else {
|
||||
super.scrollByInternal(firstVisibleItem.itemView.getRight() - getMeasuredWidth(), 0, null, ViewCompat.TYPE_TOUCH);
|
||||
}
|
||||
} else if (layout instanceof StaggeredGridLayoutManager) {
|
||||
StaggeredGridLayoutManager realLayout = (StaggeredGridLayoutManager) layout;
|
||||
int[] firstVisiblePosition = realLayout.findFirstVisibleItemPositions(null);
|
||||
ViewHolder[] firstVisibleItems = new ViewHolder[firstVisiblePosition.length];
|
||||
for (int i = 0; i < firstVisiblePosition.length; i++) {
|
||||
firstVisibleItems[i] = findViewHolderForAdapterPosition(firstVisiblePosition[i]);
|
||||
}
|
||||
int scrollDistance = Integer.MAX_VALUE;
|
||||
for (ViewHolder firstVisibleItem : firstVisibleItems) {
|
||||
if (firstVisibleItem != null) {
|
||||
if (firstVisibleItem.itemView.getRight() < scrollDistance) {
|
||||
scrollDistance = firstVisibleItem.itemView.getRight();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (scrollDistance == getMeasuredWidth()) {
|
||||
scrollDistance = 0;
|
||||
}
|
||||
super.scrollByInternal(scrollDistance - getMeasuredWidth(), 0, null, ViewCompat.TYPE_TOUCH);
|
||||
}
|
||||
}
|
||||
|
||||
protected void onScrollRight() {
|
||||
LayoutManager layout = getLayoutManager();
|
||||
if (layout instanceof LinearLayoutManager) {
|
||||
LinearLayoutManager realLayout = (LinearLayoutManager) layout;
|
||||
int lastVisiblePosition = realLayout.findLastVisibleItemPosition();
|
||||
ViewHolder lastVisibleItem = findViewHolderForAdapterPosition(lastVisiblePosition);
|
||||
|
||||
if (lastVisibleItem == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
//when the item width overflow screen, findLastCompletelyVisibleItemPosition always return NO_POSITION
|
||||
if (lastVisibleItem.itemView.getMeasuredWidth() > getMeasuredWidth()) {
|
||||
super.scrollByInternal(getMeasuredWidth() - defaultOverflowItemScrollKeep, 0, null, ViewCompat.TYPE_TOUCH);
|
||||
} else if (lastVisibleItem.itemView.getMeasuredWidth() == getMeasuredWidth()) {
|
||||
super.scrollByInternal(getMeasuredWidth(), 0, null, ViewCompat.TYPE_TOUCH);
|
||||
} else {
|
||||
super.scrollByInternal(lastVisibleItem.itemView.getLeft(), 0, null, ViewCompat.TYPE_TOUCH);
|
||||
}
|
||||
} else if (layout instanceof StaggeredGridLayoutManager) {
|
||||
StaggeredGridLayoutManager realLayout = (StaggeredGridLayoutManager) layout;
|
||||
int[] lastVisiblePosition = realLayout.findLastVisibleItemPositions(null);
|
||||
ViewHolder[] lastVisibleItems = new ViewHolder[lastVisiblePosition.length];
|
||||
for (int i = 0; i < lastVisiblePosition.length; i++) {
|
||||
lastVisibleItems[i] = findViewHolderForAdapterPosition(lastVisiblePosition[i]);
|
||||
}
|
||||
int scrollDistance = 0;
|
||||
for (ViewHolder lastVisibleItem : lastVisibleItems) {
|
||||
if (lastVisibleItem != null) {
|
||||
if (lastVisibleItem.itemView.getLeft() > scrollDistance) {
|
||||
scrollDistance = lastVisibleItem.itemView.getLeft();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (scrollDistance == 0) {
|
||||
scrollDistance = getMeasuredWidth();
|
||||
}
|
||||
super.scrollByInternal(scrollDistance, 0, null, ViewCompat.TYPE_TOUCH);
|
||||
}
|
||||
}
|
||||
|
||||
protected void onScrollUp() {
|
||||
LayoutManager layout = getLayoutManager();
|
||||
if (layout instanceof LinearLayoutManager) {
|
||||
LinearLayoutManager realLayout = (LinearLayoutManager) layout;
|
||||
int firstVisiblePosition = realLayout.findFirstVisibleItemPosition();
|
||||
ViewHolder firstVisibleItem = findViewHolderForAdapterPosition(firstVisiblePosition);
|
||||
|
||||
if (firstVisibleItem == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
//when the item height overscreen, findLastCompletelyVisibleItemPosition always return NO_POSITION
|
||||
if (firstVisibleItem.itemView.getMeasuredHeight() > getMeasuredHeight()) {
|
||||
super.scrollByInternal(0, -getMeasuredHeight() + defaultOverflowItemScrollKeep, null, ViewCompat.TYPE_TOUCH);
|
||||
} else if (firstVisibleItem.itemView.getMeasuredHeight() == getMeasuredHeight()) {
|
||||
super.scrollByInternal(0, -getMeasuredHeight(), null, ViewCompat.TYPE_TOUCH);
|
||||
} else {
|
||||
super.scrollByInternal(0, firstVisibleItem.itemView.getBottom() - getMeasuredHeight(), null, ViewCompat.TYPE_TOUCH);
|
||||
}
|
||||
} else if (layout instanceof StaggeredGridLayoutManager) {
|
||||
StaggeredGridLayoutManager realLayout = (StaggeredGridLayoutManager) layout;
|
||||
int[] firstVisiblePosition = realLayout.findFirstVisibleItemPositions(null);
|
||||
ViewHolder[] firstVisibleItems = new ViewHolder[firstVisiblePosition.length];
|
||||
for (int i = 0; i < firstVisiblePosition.length; i++) {
|
||||
firstVisibleItems[i] = findViewHolderForAdapterPosition(firstVisiblePosition[i]);
|
||||
}
|
||||
int scrollDistance = Integer.MAX_VALUE;
|
||||
for (ViewHolder firstVisibleItem : firstVisibleItems) {
|
||||
if (firstVisibleItem != null) {
|
||||
if (firstVisibleItem.itemView.getBottom() < scrollDistance) {
|
||||
scrollDistance = firstVisibleItem.itemView.getBaseline();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (scrollDistance == getMeasuredWidth()) {
|
||||
scrollDistance = 0;
|
||||
}
|
||||
super.scrollByInternal(0, scrollDistance - getMeasuredHeight(), null, ViewCompat.TYPE_TOUCH);
|
||||
}
|
||||
}
|
||||
|
||||
protected void onScrollDown() {
|
||||
LayoutManager layout = getLayoutManager();
|
||||
if (layout instanceof LinearLayoutManager) {
|
||||
LinearLayoutManager realLayout = (LinearLayoutManager) layout;
|
||||
int lastVisiblePosition = realLayout.findLastVisibleItemPosition();
|
||||
ViewHolder lastVisibleItem = findViewHolderForAdapterPosition(lastVisiblePosition);
|
||||
|
||||
if (lastVisibleItem == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
//when the item height overflow screen, findLastCompletelyVisibleItemPosition always return NO_POSITION
|
||||
if (lastVisibleItem.itemView.getMeasuredHeight() > getMeasuredHeight()) {
|
||||
super.scrollByInternal(0, getMeasuredHeight() - defaultOverflowItemScrollKeep, null, ViewCompat.TYPE_TOUCH);
|
||||
} else if (lastVisibleItem.itemView.getMeasuredHeight() == getMeasuredHeight()) {
|
||||
super.scrollByInternal(0, getMeasuredHeight(), null, ViewCompat.TYPE_TOUCH);
|
||||
} else {
|
||||
super.scrollByInternal(0, lastVisibleItem.itemView.getTop(), null, ViewCompat.TYPE_TOUCH);
|
||||
}
|
||||
} else if (layout instanceof StaggeredGridLayoutManager) {
|
||||
StaggeredGridLayoutManager realLayout = (StaggeredGridLayoutManager) layout;
|
||||
int[] lastVisiblePosition = realLayout.findLastVisibleItemPositions(null);
|
||||
ViewHolder[] lastVisibleItems = new ViewHolder[lastVisiblePosition.length];
|
||||
for (int i = 0; i < lastVisiblePosition.length; i++) {
|
||||
lastVisibleItems[i] = findViewHolderForAdapterPosition(lastVisiblePosition[i]);
|
||||
}
|
||||
int scrollDistance = 0;
|
||||
for (ViewHolder lastVisibleItem : lastVisibleItems) {
|
||||
if (lastVisibleItem != null) {
|
||||
if (lastVisibleItem.itemView.getTop() > scrollDistance) {
|
||||
scrollDistance = lastVisibleItem.itemView.getTop();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (scrollDistance == 0) {
|
||||
scrollDistance = getMeasuredHeight();
|
||||
}
|
||||
super.scrollByInternal(0, scrollDistance, null, ViewCompat.TYPE_TOUCH);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||
super.onSizeChanged(w, h, oldw, oldh);
|
||||
defaultOverflowItemScrollKeep = (int) (h * 0.05f);
|
||||
}
|
||||
|
||||
private double getSplineDeceleration(int velocity) {
|
||||
return Math.log(0.35f * Math.abs(velocity) / (mFlingFriction * mPhysicalCoeff));
|
||||
}
|
||||
|
||||
private double getSplineFlingDistance(int velocity) {
|
||||
final double l = getSplineDeceleration(velocity);
|
||||
final double decelMinusOne = DECELERATION_RATE - 1.0;
|
||||
return mFlingFriction * mPhysicalCoeff * Math.exp(DECELERATION_RATE / decelMinusOne * l);
|
||||
}
|
||||
|
||||
public void setEnableScroll(boolean enableScroll) {
|
||||
this.enableScroll = enableScroll;
|
||||
}
|
||||
|
||||
public boolean isEnableScroll() {
|
||||
return enableScroll;
|
||||
}
|
||||
}
|
||||
@@ -1,55 +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;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import com.hippo.scene.SceneFragment;
|
||||
import com.microsoft.appcenter.AppCenter;
|
||||
import com.microsoft.appcenter.crashes.Crashes;
|
||||
import com.microsoft.appcenter.distribute.Distribute;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public final class Analytics {
|
||||
|
||||
public static void start(Application application) {
|
||||
AppCenter.start(application, "1aa06805-037c-4f3c-8aaa-e23d1433986d", com.microsoft.appcenter.analytics.Analytics.class, Crashes.class, Distribute.class);
|
||||
AppCenter.setUserId(Settings.getUserID());
|
||||
com.microsoft.appcenter.analytics.Analytics.setEnabled(Settings.getEnableAnalytics());
|
||||
Crashes.setEnabled(!BuildConfig.DEBUG);
|
||||
Distribute.setEnabledForDebuggableBuild(false);
|
||||
}
|
||||
|
||||
public static boolean isEnabled() {
|
||||
return AppCenter.isConfigured() && Settings.getEnableAnalytics();
|
||||
}
|
||||
|
||||
public static void setEnabled(boolean enabled) {
|
||||
com.microsoft.appcenter.analytics.Analytics.setEnabled(enabled);
|
||||
}
|
||||
|
||||
public static void onSceneView(SceneFragment scene) {
|
||||
if (isEnabled()) {
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
properties.put("scene_simple_class", scene.getClass().getSimpleName());
|
||||
properties.put("scene_class", scene.getClass().getName());
|
||||
com.microsoft.appcenter.analytics.Analytics.trackEvent("scene_view", properties);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,6 +37,7 @@ import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.collection.LruCache;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.hippo.Native;
|
||||
import com.hippo.beerbelly.SimpleDiskCache;
|
||||
import com.hippo.conaco.Conaco;
|
||||
@@ -340,8 +341,6 @@ public class EhApplication extends SceneApplication {
|
||||
EhDB.mergeOldDB(this);
|
||||
}
|
||||
|
||||
Analytics.start(this);
|
||||
|
||||
LocaleDelegate.setDefaultLocale(Settings.getLocale());
|
||||
DayNightDelegate.setApplicationContext(this);
|
||||
DayNightDelegate.setDefaultNightMode(Settings.getTheme());
|
||||
@@ -431,7 +430,7 @@ public class EhApplication extends SceneApplication {
|
||||
Activity activity = getTopActivity();
|
||||
if (activity != null) {
|
||||
activity.runOnUiThread(() -> {
|
||||
AlertDialog dialog = new AlertDialog.Builder(activity)
|
||||
AlertDialog dialog = new MaterialAlertDialogBuilder(activity)
|
||||
.setMessage(Html.fromHtml(html))
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.create();
|
||||
|
||||
@@ -19,13 +19,11 @@ package com.hippo.ehviewer;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.browser.customtabs.CustomTabColorSchemeParams;
|
||||
import androidx.browser.customtabs.CustomTabsIntent;
|
||||
|
||||
import com.hippo.ehviewer.client.EhUrlOpener;
|
||||
@@ -36,8 +34,6 @@ import com.hippo.ehviewer.ui.MainActivity;
|
||||
import com.hippo.scene.Announcer;
|
||||
import com.hippo.scene.StageActivity;
|
||||
|
||||
import rikka.core.res.ResourcesKt;
|
||||
|
||||
public final class UrlOpener {
|
||||
|
||||
private UrlOpener() {
|
||||
@@ -92,14 +88,8 @@ public final class UrlOpener {
|
||||
}
|
||||
}
|
||||
|
||||
boolean isNight = (context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_YES) > 0;
|
||||
CustomTabsIntent.Builder customTabsIntent = new CustomTabsIntent.Builder();
|
||||
customTabsIntent.setShowTitle(true);
|
||||
CustomTabColorSchemeParams params = new CustomTabColorSchemeParams.Builder()
|
||||
.setToolbarColor(ResourcesKt.resolveColor(context.getTheme(), R.attr.toolbarColor))
|
||||
.build();
|
||||
customTabsIntent.setDefaultColorSchemeParams(params);
|
||||
customTabsIntent.setColorScheme(isNight ? CustomTabsIntent.COLOR_SCHEME_DARK : CustomTabsIntent.COLOR_SCHEME_LIGHT);
|
||||
try {
|
||||
customTabsIntent.build().launchUrl(context, uri);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
|
||||
@@ -15,14 +15,13 @@ public class WindowInsetsAnimationHelper extends WindowInsetsAnimationCompat.Cal
|
||||
private final View[] views;
|
||||
private final HashMap<View, Integer> startPaddings = new HashMap<>();
|
||||
private final HashMap<View, Integer> endPaddings = new HashMap<>();
|
||||
WindowInsetsAnimationCompat animation;
|
||||
|
||||
public WindowInsetsAnimationHelper(int dispatchMode, View... views) {
|
||||
super(dispatchMode);
|
||||
this.views = views;
|
||||
}
|
||||
|
||||
WindowInsetsAnimationCompat animation;
|
||||
|
||||
@Override
|
||||
public void onPrepare(@NonNull WindowInsetsAnimationCompat animation) {
|
||||
super.onPrepare(animation);
|
||||
|
||||
@@ -36,6 +36,7 @@ import com.hippo.ehviewer.client.exception.EhException;
|
||||
import com.hippo.ehviewer.client.exception.NoHAtHClientException;
|
||||
import com.hippo.ehviewer.client.exception.ParseException;
|
||||
import com.hippo.ehviewer.client.parser.ArchiveParser;
|
||||
import com.hippo.ehviewer.client.parser.EventPaneParser;
|
||||
import com.hippo.ehviewer.client.parser.FavoritesParser;
|
||||
import com.hippo.ehviewer.client.parser.ForumsParser;
|
||||
import com.hippo.ehviewer.client.parser.GalleryApiParser;
|
||||
@@ -48,7 +49,6 @@ import com.hippo.ehviewer.client.parser.GalleryTokenApiParser;
|
||||
import com.hippo.ehviewer.client.parser.ProfileParser;
|
||||
import com.hippo.ehviewer.client.parser.RateGalleryParser;
|
||||
import com.hippo.ehviewer.client.parser.SignInParser;
|
||||
import com.hippo.ehviewer.client.parser.EventPaneParser;
|
||||
import com.hippo.ehviewer.client.parser.TorrentParser;
|
||||
import com.hippo.ehviewer.client.parser.VoteCommentParser;
|
||||
import com.hippo.ehviewer.client.parser.VoteTagParser;
|
||||
@@ -971,7 +971,7 @@ public class EhEngine {
|
||||
try {
|
||||
Response response = call.execute();
|
||||
|
||||
Log.d(TAG, "" + response.request().url().toString());
|
||||
Log.d(TAG, "" + response.request().url());
|
||||
|
||||
code = response.code();
|
||||
headers = response.headers();
|
||||
|
||||
@@ -56,9 +56,9 @@ import okio.Okio;
|
||||
public class EhTagDatabase {
|
||||
|
||||
private static final Map<String, String> NAMESPACE_TO_PREFIX = new HashMap<>();
|
||||
private static volatile EhTagDatabase instance;
|
||||
// TODO more lock for different language
|
||||
private static final Lock lock = new ReentrantLock();
|
||||
private static volatile EhTagDatabase instance;
|
||||
|
||||
static {
|
||||
NAMESPACE_TO_PREFIX.put("artist", "a:");
|
||||
|
||||
@@ -36,40 +36,29 @@ public class EhUrl {
|
||||
public static final String DOMAIN_LOFI = "lofi.e-hentai.org";
|
||||
|
||||
public static final String HOST_EX = "https://" + DOMAIN_EX + "/";
|
||||
public static final String HOST_E = "https://" + DOMAIN_E + "/";
|
||||
|
||||
public static final String API_SIGN_IN = "https://forums.e-hentai.org/index.php?act=Login&CODE=01";
|
||||
|
||||
public static final String API_E = HOST_E + "api.php";
|
||||
public static final String API_EX = HOST_EX + "api.php";
|
||||
|
||||
public static final String URL_FAVORITES_EX = HOST_EX + "favorites.php";
|
||||
public static final String URL_UCONFIG_EX = HOST_EX + "uconfig.php";
|
||||
public static final String URL_MY_TAGS_EX = HOST_EX + "mytags";
|
||||
public static final String URL_WATCHED_EX = HOST_EX + "watched";
|
||||
public static final String HOST_E = "https://" + DOMAIN_E + "/";
|
||||
public static final String API_E = HOST_E + "api.php";
|
||||
public static final String URL_FAVORITES_E = HOST_E + "favorites.php";
|
||||
public static final String URL_UCONFIG_E = HOST_E + "uconfig.php";
|
||||
public static final String URL_MY_TAGS_E = HOST_E + "mytags";
|
||||
public static final String URL_WATCHED_E = HOST_E + "watched";
|
||||
public static final String API_SIGN_IN = "https://forums.e-hentai.org/index.php?act=Login&CODE=01";
|
||||
public static final String URL_POPULAR_E = "https://e-hentai.org/popular";
|
||||
public static final String URL_POPULAR_EX = "https://exhentai.org/popular";
|
||||
|
||||
public static final String URL_IMAGE_SEARCH_E = "https://upload.e-hentai.org/image_lookup.php";
|
||||
public static final String URL_IMAGE_SEARCH_EX = "https://exhentai.org/upload/image_lookup.php";
|
||||
|
||||
public static final String URL_SIGN_IN = "https://forums.e-hentai.org/index.php?act=Login";
|
||||
public static final String URL_REGISTER = "https://forums.e-hentai.org/index.php?act=Reg&CODE=00";
|
||||
public static final String URL_FAVORITES_E = HOST_E + "favorites.php";
|
||||
public static final String URL_FAVORITES_EX = HOST_EX + "favorites.php";
|
||||
public static final String URL_FORUMS = "https://forums.e-hentai.org/";
|
||||
|
||||
public static final String REFERER_EX = "https://" + DOMAIN_EX;
|
||||
public static final String REFERER_E = "https://" + DOMAIN_E;
|
||||
|
||||
public static final String ORIGIN_EX = REFERER_EX;
|
||||
public static final String REFERER_E = "https://" + DOMAIN_E;
|
||||
public static final String ORIGIN_E = REFERER_E;
|
||||
|
||||
public static final String URL_UCONFIG_E = HOST_E + "uconfig.php";
|
||||
public static final String URL_UCONFIG_EX = HOST_EX + "uconfig.php";
|
||||
|
||||
public static final String URL_MY_TAGS_E = HOST_E + "mytags";
|
||||
public static final String URL_MY_TAGS_EX = HOST_EX + "mytags";
|
||||
|
||||
public static final String URL_WATCHED_E = HOST_E + "watched";
|
||||
public static final String URL_WATCHED_EX = HOST_EX + "watched";
|
||||
|
||||
private static final String URL_PREFIX_THUMB_E = "https://ehgt.org/";
|
||||
private static final String URL_PREFIX_THUMB_EX = "https://exhentai.org/t/";
|
||||
|
||||
|
||||
@@ -40,9 +40,9 @@ import okhttp3.HttpUrl;
|
||||
|
||||
public class IdentityCookiePreference extends MessagePreference {
|
||||
|
||||
private String message;
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private final SettingsActivity mActivity;
|
||||
private String message;
|
||||
|
||||
public IdentityCookiePreference(Context context) {
|
||||
super(context);
|
||||
|
||||
@@ -143,6 +143,7 @@ public final class SpiderQueen implements Runnable {
|
||||
private final int mWorkerMaxCount;
|
||||
private final int mPreloadNumber;
|
||||
private final int mDownloadDelay;
|
||||
private final AtomicReference<String> showKey = new AtomicReference<>();
|
||||
private int mReadReference = 0;
|
||||
private int mDownloadReference = 0;
|
||||
// It mQueenThread is null, failed or stopped
|
||||
@@ -153,7 +154,6 @@ public final class SpiderQueen implements Runnable {
|
||||
private volatile int[] mPageStateArray;
|
||||
// For download, when it go to mPageStateArray.size(), done
|
||||
private volatile int mDownloadPage = -1;
|
||||
private final AtomicReference<String> showKey = new AtomicReference<>();
|
||||
|
||||
private SpiderQueen(EhApplication application, @NonNull GalleryInfo galleryInfo) {
|
||||
mHttpClient = EhApplication.getOkHttpClient(application);
|
||||
|
||||
@@ -65,6 +65,7 @@ import androidx.core.view.WindowCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
import androidx.core.view.WindowInsetsControllerCompat;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.hippo.ehviewer.AppConfig;
|
||||
import com.hippo.ehviewer.BuildConfig;
|
||||
import com.hippo.ehviewer.R;
|
||||
@@ -129,6 +130,36 @@ public class GalleryActivity extends EhActivity implements SeekBar.OnSeekBarChan
|
||||
private GalleryInfo mGalleryInfo;
|
||||
private int mPage;
|
||||
private String mCacheFileName;
|
||||
ActivityResultLauncher<String> saveImageToLauncher = registerForActivityResult(
|
||||
new ActivityResultContracts.CreateDocument(),
|
||||
uri -> {
|
||||
if (uri != null) {
|
||||
String filepath = AppConfig.getExternalTempDir() + File.separator + mCacheFileName;
|
||||
File cachefile = new File(filepath);
|
||||
|
||||
ContentResolver resolver = getContentResolver();
|
||||
|
||||
IoThreadPoolExecutor.getInstance().execute(() -> {
|
||||
InputStream is = null;
|
||||
OutputStream os = null;
|
||||
try {
|
||||
is = new FileInputStream(cachefile);
|
||||
os = resolver.openOutputStream(uri);
|
||||
IOUtils.copy(is, os);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
IOUtils.closeQuietly(is);
|
||||
IOUtils.closeQuietly(os);
|
||||
runOnUiThread(() -> Toast.makeText(GalleryActivity.this, getString(R.string.image_saved, uri.getPath()), Toast.LENGTH_SHORT).show());
|
||||
}
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
cachefile.delete();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
@Nullable
|
||||
private GLRootView mGLRootView;
|
||||
@Nullable
|
||||
@@ -190,10 +221,7 @@ public class GalleryActivity extends EhActivity implements SeekBar.OnSeekBarChan
|
||||
private int mLayoutMode;
|
||||
private int mSize;
|
||||
private int mCurrentIndex;
|
||||
|
||||
private int mSavingPage = -1;
|
||||
|
||||
ActivityResultLauncher<String> requestStoragePermissionLauncher = registerForActivityResult(
|
||||
private int mSavingPage = -1; ActivityResultLauncher<String> requestStoragePermissionLauncher = registerForActivityResult(
|
||||
new ActivityResultContracts.RequestPermission(),
|
||||
result -> {
|
||||
if (result && mSavingPage != -1) {
|
||||
@@ -203,36 +231,6 @@ public class GalleryActivity extends EhActivity implements SeekBar.OnSeekBarChan
|
||||
}
|
||||
mSavingPage = -1;
|
||||
});
|
||||
ActivityResultLauncher<String> saveImageToLauncher = registerForActivityResult(
|
||||
new ActivityResultContracts.CreateDocument(),
|
||||
uri -> {
|
||||
if (uri != null) {
|
||||
String filepath = AppConfig.getExternalTempDir() + File.separator + mCacheFileName;
|
||||
File cachefile = new File(filepath);
|
||||
|
||||
ContentResolver resolver = getContentResolver();
|
||||
|
||||
IoThreadPoolExecutor.getInstance().execute(() -> {
|
||||
InputStream is = null;
|
||||
OutputStream os = null;
|
||||
try {
|
||||
is = new FileInputStream(cachefile);
|
||||
os = resolver.openOutputStream(uri);
|
||||
IOUtils.copy(is, os);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
IOUtils.closeQuietly(is);
|
||||
IOUtils.closeQuietly(os);
|
||||
runOnUiThread(() -> Toast.makeText(GalleryActivity.this, getString(R.string.image_saved, uri.getPath()), Toast.LENGTH_SHORT).show());
|
||||
}
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
cachefile.delete();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
||||
private void buildProvider() {
|
||||
if (mGalleryProvider != null) {
|
||||
@@ -981,7 +979,7 @@ public class GalleryActivity extends EhActivity implements SeekBar.OnSeekBarChan
|
||||
|
||||
private void showPageDialog(final int page) {
|
||||
Resources resources = GalleryActivity.this.getResources();
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(GalleryActivity.this);
|
||||
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(GalleryActivity.this);
|
||||
builder.setTitle(resources.getString(R.string.page_menu_title, page + 1));
|
||||
|
||||
final CharSequence[] items;
|
||||
@@ -1022,6 +1020,29 @@ public class GalleryActivity extends EhActivity implements SeekBar.OnSeekBarChan
|
||||
});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String getGalleryDetailUrl() {
|
||||
long gid;
|
||||
String token;
|
||||
if (mGalleryInfo != null) {
|
||||
gid = mGalleryInfo.gid;
|
||||
token = mGalleryInfo.token;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return EhUrl.getGalleryDetailUrl(gid, token, 0, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProvideAssistContent(AssistContent outContent) {
|
||||
super.onProvideAssistContent(outContent);
|
||||
|
||||
String url = getGalleryDetailUrl();
|
||||
if (url != null) {
|
||||
outContent.setWebUri(Uri.parse(url));
|
||||
}
|
||||
}
|
||||
|
||||
private class GalleryMenuHelper implements DialogInterface.OnClickListener {
|
||||
|
||||
private final View mView;
|
||||
@@ -1194,7 +1215,7 @@ public class GalleryActivity extends EhActivity implements SeekBar.OnSeekBarChan
|
||||
}
|
||||
|
||||
private void onTapMenuArea() {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(GalleryActivity.this);
|
||||
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(GalleryActivity.this);
|
||||
GalleryMenuHelper helper = new GalleryMenuHelper(builder.getContext());
|
||||
builder.setTitle(R.string.gallery_menu_title)
|
||||
.setView(helper.getView())
|
||||
@@ -1282,26 +1303,5 @@ public class GalleryActivity extends EhActivity implements SeekBar.OnSeekBarChan
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String getGalleryDetailUrl() {
|
||||
long gid;
|
||||
String token;
|
||||
if (mGalleryInfo != null) {
|
||||
gid = mGalleryInfo.gid;
|
||||
token = mGalleryInfo.token;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return EhUrl.getGalleryDetailUrl(gid, token, 0, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProvideAssistContent(AssistContent outContent) {
|
||||
super.onProvideAssistContent(outContent);
|
||||
|
||||
String url = getGalleryDetailUrl();
|
||||
if (url != null) {
|
||||
outContent.setWebUri(Uri.parse(url));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,10 +43,10 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.drawerlayout.widget.DrawerLayout;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.navigation.NavigationView;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
import com.hippo.app.EditTextDialogBuilder;
|
||||
@@ -59,7 +59,6 @@ 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.GalleryPageUrlParser;
|
||||
import com.hippo.ehviewer.ui.scene.AnalyticsScene;
|
||||
import com.hippo.ehviewer.ui.scene.BaseScene;
|
||||
import com.hippo.ehviewer.ui.scene.CookieSignInScene;
|
||||
import com.hippo.ehviewer.ui.scene.DownloadsScene;
|
||||
@@ -107,7 +106,6 @@ public final class MainActivity extends StageActivity
|
||||
static {
|
||||
registerLaunchMode(SecurityScene.class, SceneFragment.LAUNCH_MODE_SINGLE_TASK);
|
||||
registerLaunchMode(WarningScene.class, SceneFragment.LAUNCH_MODE_SINGLE_TASK);
|
||||
registerLaunchMode(AnalyticsScene.class, SceneFragment.LAUNCH_MODE_SINGLE_TASK);
|
||||
registerLaunchMode(SignInScene.class, SceneFragment.LAUNCH_MODE_SINGLE_TASK);
|
||||
registerLaunchMode(WebViewSignInScene.class, SceneFragment.LAUNCH_MODE_SINGLE_TASK);
|
||||
registerLaunchMode(CookieSignInScene.class, SceneFragment.LAUNCH_MODE_SINGLE_TASK);
|
||||
@@ -159,8 +157,6 @@ public final class MainActivity extends StageActivity
|
||||
return new Announcer(SecurityScene.class);
|
||||
} else if (Settings.getShowWarning()) {
|
||||
return new Announcer(WarningScene.class);
|
||||
} else if (Settings.getAskAnalytics()) {
|
||||
return new Announcer(AnalyticsScene.class);
|
||||
} else if (EhUtils.needSignedIn(this)) {
|
||||
return new Announcer(SignInScene.class);
|
||||
} else if (Settings.getSelectSite()) {
|
||||
@@ -185,11 +181,6 @@ public final class MainActivity extends StageActivity
|
||||
newArgs.putString(WarningScene.KEY_TARGET_SCENE, announcer.getClazz().getName());
|
||||
newArgs.putBundle(WarningScene.KEY_TARGET_ARGS, announcer.getArgs());
|
||||
return new Announcer(WarningScene.class).setArgs(newArgs);
|
||||
} else if (Settings.getAskAnalytics()) {
|
||||
Bundle newArgs = new Bundle();
|
||||
newArgs.putString(AnalyticsScene.KEY_TARGET_SCENE, announcer.getClazz().getName());
|
||||
newArgs.putBundle(AnalyticsScene.KEY_TARGET_ARGS, announcer.getArgs());
|
||||
return new Announcer(AnalyticsScene.class).setArgs(newArgs);
|
||||
} else if (EhUtils.needSignedIn(this)) {
|
||||
Bundle newArgs = new Bundle();
|
||||
newArgs.putString(SignInScene.KEY_TARGET_SCENE, announcer.getClazz().getName());
|
||||
@@ -333,7 +324,7 @@ public final class MainActivity extends StageActivity
|
||||
mAvatar = (LoadImageView) ViewUtils.$$(headerLayout, R.id.avatar);
|
||||
mDisplayName = (TextView) ViewUtils.$$(headerLayout, R.id.display_name);
|
||||
ViewUtils.$$(headerLayout, R.id.night_mode).setOnClickListener(v -> {
|
||||
int theme = (getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_YES) > 0 ? AppCompatDelegate.MODE_NIGHT_NO : AppCompatDelegate.MODE_NIGHT_YES;
|
||||
int theme = (getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_YES) > 0 ? DayNightDelegate.MODE_NIGHT_NO : DayNightDelegate.MODE_NIGHT_YES;
|
||||
DayNightDelegate.setDefaultNightMode(theme);
|
||||
recreate();
|
||||
if (Settings.getTheme() != AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) {
|
||||
@@ -389,7 +380,7 @@ public final class MainActivity extends StageActivity
|
||||
break;
|
||||
}
|
||||
if (hasUnverified) {
|
||||
new AlertDialog.Builder(this)
|
||||
new MaterialAlertDialogBuilder(this)
|
||||
.setTitle(R.string.app_link_not_verified_title)
|
||||
.setMessage(R.string.app_link_not_verified_message)
|
||||
.setPositiveButton(R.string.open_settings, (dialogInterface, i) -> {
|
||||
@@ -409,7 +400,7 @@ public final class MainActivity extends StageActivity
|
||||
if (null == uniFile || uniFile.ensureDir()) {
|
||||
return;
|
||||
}
|
||||
new AlertDialog.Builder(this)
|
||||
new MaterialAlertDialogBuilder(this)
|
||||
.setTitle(R.string.waring)
|
||||
.setMessage(R.string.invalid_download_location)
|
||||
.setPositiveButton(R.string.get_it, null)
|
||||
|
||||
@@ -21,12 +21,10 @@ import android.os.Bundle;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.hippo.ehviewer.Analytics;
|
||||
import com.hippo.ehviewer.EhApplication;
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.text.Html;
|
||||
import com.hippo.util.AppHelper;
|
||||
import com.microsoft.appcenter.distribute.Distribute;
|
||||
|
||||
public class AboutFragment extends BasePreferenceFragment {
|
||||
|
||||
@@ -47,7 +45,6 @@ public class AboutFragment extends BasePreferenceFragment {
|
||||
author.setOnPreferenceClickListener(this);
|
||||
//donate.setOnPreferenceClickListener(this);
|
||||
checkForUpdate.setOnPreferenceClickListener(this);
|
||||
checkForUpdate.setVisible(Analytics.isEnabled());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -56,8 +53,6 @@ public class AboutFragment extends BasePreferenceFragment {
|
||||
if (KEY_AUTHOR.equals(key)) {
|
||||
AppHelper.sendEmail(requireActivity(), EhApplication.getDeveloperEmail(),
|
||||
"About EhViewer", null);
|
||||
} else if (KEY_CHECK_FOR_UPDATES.equals(key)) {
|
||||
Distribute.checkForUpdate();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.hippo.ehviewer.AppConfig;
|
||||
import com.hippo.ehviewer.BuildConfig;
|
||||
import com.hippo.ehviewer.EhApplication;
|
||||
@@ -76,7 +77,7 @@ public class AdvancedFragment extends BasePreferenceFragment {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
AlertDialog alertDialog = new AlertDialog.Builder(requireActivity())
|
||||
AlertDialog alertDialog = new MaterialAlertDialogBuilder(requireActivity())
|
||||
.setCancelable(false)
|
||||
.setView(R.layout.preference_dialog_task)
|
||||
.show();
|
||||
@@ -193,7 +194,7 @@ public class AdvancedFragment extends BasePreferenceFragment {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
AlertDialog alertDialog = new AlertDialog.Builder(requireActivity())
|
||||
AlertDialog alertDialog = new MaterialAlertDialogBuilder(requireActivity())
|
||||
.setCancelable(false)
|
||||
.setView(R.layout.preference_dialog_task)
|
||||
.show();
|
||||
|
||||
@@ -23,9 +23,9 @@ import android.os.Bundle;
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.hippo.ehviewer.AppConfig;
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.ehviewer.Settings;
|
||||
@@ -99,7 +99,7 @@ public class DownloadFragment extends BasePreferenceFragment {
|
||||
if (KEY_DOWNLOAD_LOCATION.equals(key)) {
|
||||
UniFile file = Settings.getDownloadLocation();
|
||||
if (file != null && !UniFile.isFileUri(Settings.getDownloadLocation().getUri())) {
|
||||
new AlertDialog.Builder(requireContext())
|
||||
new MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.settings_download_download_location)
|
||||
.setMessage(file.getUri().toString())
|
||||
.setPositiveButton(R.string.pick_new_download_location, (dialogInterface, i) -> openDirPickerL())
|
||||
|
||||
@@ -24,6 +24,7 @@ import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.checkbox.MaterialCheckBox;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.google.android.material.textfield.TextInputLayout;
|
||||
import com.hippo.easyrecyclerview.EasyRecyclerView;
|
||||
@@ -137,7 +138,7 @@ public class FilterFragment extends BaseFragment {
|
||||
}
|
||||
|
||||
private void showTipDialog() {
|
||||
new AlertDialog.Builder(requireActivity())
|
||||
new MaterialAlertDialogBuilder(requireActivity())
|
||||
.setTitle(R.string.filter)
|
||||
.setMessage(R.string.filter_tip)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
@@ -145,7 +146,7 @@ public class FilterFragment extends BaseFragment {
|
||||
}
|
||||
|
||||
private void showAddFilterDialog() {
|
||||
AlertDialog dialog = new AlertDialog.Builder(requireActivity())
|
||||
AlertDialog dialog = new MaterialAlertDialogBuilder(requireActivity())
|
||||
.setTitle(R.string.add_filter)
|
||||
.setView(R.layout.dialog_add_filter)
|
||||
.setPositiveButton(R.string.add, null)
|
||||
@@ -157,7 +158,7 @@ public class FilterFragment extends BaseFragment {
|
||||
|
||||
private void showDeleteFilterDialog(final Filter filter) {
|
||||
String message = getString(R.string.delete_filter, filter.text);
|
||||
new AlertDialog.Builder(requireActivity())
|
||||
new MaterialAlertDialogBuilder(requireActivity())
|
||||
.setMessage(message)
|
||||
.setPositiveButton(R.string.delete, (dialog, which) -> {
|
||||
if (DialogInterface.BUTTON_POSITIVE != which || null == mFilterList) {
|
||||
@@ -173,6 +174,25 @@ public class FilterFragment extends BaseFragment {
|
||||
.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFragmentTitle() {
|
||||
return R.string.filter;
|
||||
}
|
||||
|
||||
private static class FilterHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private final MaterialCheckBox checkbox;
|
||||
private final TextView text;
|
||||
private final ImageView delete;
|
||||
|
||||
public FilterHolder(View itemView) {
|
||||
super(itemView);
|
||||
checkbox = itemView.findViewById(R.id.checkbox);
|
||||
text = itemView.findViewById(R.id.text);
|
||||
delete = itemView.findViewById(R.id.delete);
|
||||
}
|
||||
}
|
||||
|
||||
private class AddFilterDialogHelper implements View.OnClickListener {
|
||||
|
||||
@Nullable
|
||||
@@ -234,20 +254,6 @@ public class FilterFragment extends BaseFragment {
|
||||
}
|
||||
}
|
||||
|
||||
private static class FilterHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private final MaterialCheckBox checkbox;
|
||||
private final TextView text;
|
||||
private final ImageView delete;
|
||||
|
||||
public FilterHolder(View itemView) {
|
||||
super(itemView);
|
||||
checkbox = itemView.findViewById(R.id.checkbox);
|
||||
text = itemView.findViewById(R.id.text);
|
||||
delete = itemView.findViewById(R.id.delete);
|
||||
}
|
||||
}
|
||||
|
||||
private class FilterAdapter extends RecyclerView.Adapter<FilterHolder> {
|
||||
|
||||
private static final int TYPE_ITEM = 0;
|
||||
@@ -456,9 +462,4 @@ public class FilterFragment extends BaseFragment {
|
||||
mEhFilter.triggerFilter(filter);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFragmentTitle() {
|
||||
return R.string.filter;
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ import androidx.fragment.app.DialogFragment;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.google.android.material.textfield.TextInputLayout;
|
||||
import com.hippo.easyrecyclerview.LinearDividerItemDecoration;
|
||||
@@ -117,6 +118,11 @@ public class HostsFragment extends BaseFragment
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFragmentTitle() {
|
||||
return R.string.hosts;
|
||||
}
|
||||
|
||||
public abstract static class HostDialogFragment extends DialogFragment {
|
||||
|
||||
private HostsFragment hostsFragment;
|
||||
@@ -135,7 +141,7 @@ public class HostsFragment extends BaseFragment
|
||||
ip.setText(arguments.getString(KEY_IP));
|
||||
}
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(requireContext()).setView(view);
|
||||
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireContext()).setView(view);
|
||||
onCreateDialogBuilder(builder);
|
||||
AlertDialog dialog = builder.create();
|
||||
dialog.setOnShowListener(d -> onCreateDialog((AlertDialog) d));
|
||||
@@ -265,9 +271,4 @@ public class HostsFragment extends BaseFragment
|
||||
return data.size();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFragmentTitle() {
|
||||
return R.string.hosts;
|
||||
}
|
||||
}
|
||||
@@ -72,6 +72,11 @@ public class MyTagsFragment extends BaseFragment {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFragmentTitle() {
|
||||
return R.string.my_tags;
|
||||
}
|
||||
|
||||
private class MyTagsWebViewClient extends WebViewClient {
|
||||
@Override
|
||||
public boolean shouldOverrideUrlLoading(WebView view, String url) {
|
||||
@@ -89,9 +94,4 @@ public class MyTagsFragment extends BaseFragment {
|
||||
progress.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFragmentTitle() {
|
||||
return R.string.my_tags;
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@ import android.text.TextUtils;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.hippo.ehviewer.Analytics;
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.ehviewer.Settings;
|
||||
|
||||
@@ -20,9 +19,6 @@ public class PrivacyFragment extends BasePreferenceFragment {
|
||||
@Override
|
||||
public void onCreatePreferencesFix(@Nullable Bundle savedInstanceState, String rootKey) {
|
||||
addPreferencesFromResource(R.xml.privacy_settings);
|
||||
Preference enableAnalytics = findPreference(Settings.KEY_ENABLE_ANALYTICS);
|
||||
|
||||
enableAnalytics.setOnPreferenceChangeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -34,17 +30,6 @@ public class PrivacyFragment extends BasePreferenceFragment {
|
||||
R.string.settings_privacy_pattern_protection_set);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
String key = preference.getKey();
|
||||
if (Settings.KEY_ENABLE_ANALYTICS.equals(key)) {
|
||||
if (newValue instanceof Boolean && (Boolean) newValue) {
|
||||
Analytics.start(getActivity().getApplication());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFragmentTitle() {
|
||||
return R.string.settings_privacy;
|
||||
|
||||
@@ -146,6 +146,16 @@ public class UConfigFragment extends BaseFragment {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFragmentTitle() {
|
||||
return R.string.u_config;
|
||||
}
|
||||
|
||||
private class UConfigWebViewClient extends WebViewClient {
|
||||
|
||||
@Override
|
||||
@@ -166,14 +176,4 @@ public class UConfigFragment extends BaseFragment {
|
||||
loaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFragmentTitle() {
|
||||
return R.string.u_config;
|
||||
}
|
||||
}
|
||||
@@ -1,96 +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.os.Bundle;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.hippo.ehviewer.Analytics;
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.ehviewer.Settings;
|
||||
import com.hippo.ehviewer.ui.MainActivity;
|
||||
import com.hippo.text.Html;
|
||||
import com.hippo.yorozuya.ViewUtils;
|
||||
|
||||
public class AnalyticsScene extends SolidScene implements View.OnClickListener {
|
||||
|
||||
@Nullable
|
||||
private View mReject;
|
||||
@Nullable
|
||||
private View mAccept;
|
||||
|
||||
@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_analytics, container, false);
|
||||
|
||||
mReject = ViewUtils.$$(view, R.id.reject);
|
||||
mAccept = ViewUtils.$$(view, R.id.accept);
|
||||
TextView text = (TextView) ViewUtils.$$(view, R.id.text);
|
||||
|
||||
text.setText(Html.fromHtml(getString(R.string.analytics_explain)));
|
||||
text.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
|
||||
mReject.setOnClickListener(this);
|
||||
mAccept.setOnClickListener(this);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
|
||||
mReject = null;
|
||||
mAccept = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Context context = getContext();
|
||||
MainActivity activity = getMainActivity();
|
||||
if (context == null || activity == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mReject == v) {
|
||||
Settings.putEnableAnalytics(false);
|
||||
} else if (mAccept == v) {
|
||||
Settings.putEnableAnalytics(true);
|
||||
}
|
||||
Analytics.setEnabled(Settings.getEnableAnalytics());
|
||||
Settings.putAskAnalytics(false);
|
||||
|
||||
// Start new scene and finish it self
|
||||
startSceneForCheckStep(CHECK_STEP_ANALYTICS, getArguments());
|
||||
finish();
|
||||
}
|
||||
}
|
||||
@@ -39,10 +39,8 @@ import androidx.core.view.WindowInsetsControllerCompat;
|
||||
import androidx.drawerlayout.widget.DrawerLayout;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
|
||||
import com.hippo.ehviewer.Analytics;
|
||||
import com.hippo.ehviewer.ui.MainActivity;
|
||||
import com.hippo.scene.SceneFragment;
|
||||
import com.hippo.util.AppHelper;
|
||||
|
||||
public abstract class BaseScene extends SceneFragment {
|
||||
|
||||
@@ -274,12 +272,6 @@ public abstract class BaseScene extends SceneFragment {
|
||||
return insetsController;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
Analytics.onSceneView(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
@@ -30,8 +30,8 @@ import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.textfield.TextInputLayout;
|
||||
import com.hippo.ehviewer.EhApplication;
|
||||
import com.hippo.ehviewer.R;
|
||||
@@ -217,7 +217,7 @@ public class CookieSignInScene extends SolidScene implements EditText.OnEditorAc
|
||||
hideSoftInput();
|
||||
|
||||
if (!checkIpbMemberId(ipbMemberId) || !(checkIpbPassHash(ipbPassHash))) {
|
||||
new AlertDialog.Builder(context).setTitle(R.string.waring)
|
||||
new MaterialAlertDialogBuilder(context).setTitle(R.string.waring)
|
||||
.setMessage(R.string.wrong_cookie_warning)
|
||||
.setPositiveButton(R.string.i_will_check_it, null)
|
||||
.setNegativeButton(R.string.i_dont_think_so, (dialog, which) -> {
|
||||
|
||||
@@ -58,6 +58,7 @@ import androidx.recyclerview.widget.StaggeredGridLayoutManager;
|
||||
|
||||
import com.getkeepsafe.taptargetview.TapTarget;
|
||||
import com.getkeepsafe.taptargetview.TapTargetView;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.h6ah4i.android.widget.advrecyclerview.animator.DraggableItemAnimator;
|
||||
import com.h6ah4i.android.widget.advrecyclerview.animator.GeneralItemAnimator;
|
||||
@@ -377,12 +378,12 @@ public class DownloadsScene extends ToolbarScene
|
||||
mRecyclerView.scrollToPosition(mInitPosition);
|
||||
mInitPosition = -1;
|
||||
}
|
||||
RecyclerViewKt.addEdgeSpacing(mRecyclerView, 4,4,4,4, TypedValue.COMPLEX_UNIT_DIP);
|
||||
RecyclerViewKt.addEdgeSpacing(mRecyclerView, 4, 4, 4, 4, TypedValue.COMPLEX_UNIT_DIP);
|
||||
RecyclerViewKt.fixEdgeEffect(mRecyclerView, false, true);
|
||||
|
||||
mFastScroller.attachToRecyclerView(mRecyclerView);
|
||||
HandlerDrawable handlerDrawable = new HandlerDrawable();
|
||||
handlerDrawable.setColor(ResourcesKt.resolveColor(getTheme(), R.attr.widgetColorThemeAccent));
|
||||
handlerDrawable.setColor(com.google.android.material.R.color.material_dynamic_neutral100);
|
||||
mFastScroller.setHandlerDrawable(handlerDrawable);
|
||||
mFastScroller.setOnDragHandlerListener(this);
|
||||
|
||||
@@ -436,8 +437,8 @@ public class DownloadsScene extends ToolbarScene
|
||||
|
||||
TapTargetView.showFor(requireActivity(),
|
||||
TapTarget.forView(((DownloadHolder) holder).thumb,
|
||||
getString(R.string.guide_download_thumb_title),
|
||||
getString(R.string.guide_download_thumb_text))
|
||||
getString(R.string.guide_download_thumb_title),
|
||||
getString(R.string.guide_download_thumb_text))
|
||||
.transparentTarget(true),
|
||||
new TapTargetView.Listener() {
|
||||
@Override
|
||||
@@ -465,8 +466,8 @@ public class DownloadsScene extends ToolbarScene
|
||||
|
||||
TapTargetView.showFor(requireActivity(),
|
||||
TapTarget.forBounds(bounds,
|
||||
getString(R.string.guide_download_labels_title),
|
||||
getString(R.string.guide_download_labels_text))
|
||||
getString(R.string.guide_download_labels_title),
|
||||
getString(R.string.guide_download_labels_text))
|
||||
.outerCircleColor(R.color.colorPrimary)
|
||||
.transparentTarget(true),
|
||||
new TapTargetView.Listener() {
|
||||
@@ -525,7 +526,7 @@ public class DownloadsScene extends ToolbarScene
|
||||
|
||||
int id = item.getItemId();
|
||||
if (id == R.id.action_filter) {
|
||||
new AlertDialog.Builder(requireActivity())
|
||||
new MaterialAlertDialogBuilder(requireActivity())
|
||||
.setSingleChoiceItems(R.array.download_state, mType + 1, (dialog, which) -> {
|
||||
mType = which - 1;
|
||||
updateForLabel();
|
||||
@@ -548,7 +549,7 @@ public class DownloadsScene extends ToolbarScene
|
||||
openDrawer(Gravity.RIGHT);
|
||||
return true;
|
||||
} else if (id == R.id.action_reset_reading_progress) {
|
||||
new AlertDialog.Builder(getContext())
|
||||
new MaterialAlertDialogBuilder(getContext())
|
||||
.setMessage(R.string.reset_reading_progress_message)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
|
||||
@@ -621,7 +622,7 @@ public class DownloadsScene extends ToolbarScene
|
||||
for (int i = 0, n = list.size(); i < n; i++) {
|
||||
items[i + 2] = list.get(i).getLabel();
|
||||
}
|
||||
new AlertDialog.Builder(context)
|
||||
new MaterialAlertDialogBuilder(context)
|
||||
.setTitle(R.string.default_download_label)
|
||||
.setItems(items, (dialog1, which) -> {
|
||||
if (which == 0) {
|
||||
@@ -821,7 +822,7 @@ public class DownloadsScene extends ToolbarScene
|
||||
|
||||
MoveDialogHelper helper = new MoveDialogHelper(labels, downloadInfoList);
|
||||
|
||||
new AlertDialog.Builder(context)
|
||||
new MaterialAlertDialogBuilder(context)
|
||||
.setTitle(R.string.download_move_dialog_title)
|
||||
.setItems(labels, helper)
|
||||
.show();
|
||||
@@ -998,6 +999,73 @@ public class DownloadsScene extends ToolbarScene
|
||||
}
|
||||
}
|
||||
|
||||
private static class ThumbDataContainer implements DataContainer {
|
||||
|
||||
private final DownloadInfo mInfo;
|
||||
@Nullable
|
||||
private UniFile mFile;
|
||||
|
||||
public ThumbDataContainer(@NonNull DownloadInfo info) {
|
||||
mInfo = info;
|
||||
}
|
||||
|
||||
private void ensureFile() {
|
||||
if (mFile == null) {
|
||||
UniFile dir = SpiderDen.getGalleryDownloadDir(mInfo);
|
||||
if (dir != null && dir.isDirectory()) {
|
||||
mFile = dir.createFile(".thumb");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
ensureFile();
|
||||
return mFile != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUrlMoved(String requestUrl, String responseUrl) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean save(InputStream is, long length, String mediaType, ProgressNotifier notify) {
|
||||
ensureFile();
|
||||
if (mFile == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
OutputStream os = null;
|
||||
try {
|
||||
os = mFile.openOutputStream();
|
||||
IOUtils.copy(is, os);
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
} finally {
|
||||
IOUtils.closeQuietly(os);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStreamPipe get() {
|
||||
ensureFile();
|
||||
if (mFile != null) {
|
||||
return new UniFileInputStreamPipe(mFile);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
if (mFile != null) {
|
||||
mFile.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class DownloadLabelAdapter extends RecyclerView.Adapter<DownloadLabelHolder> implements DraggableItemAdapter<DownloadLabelHolder> {
|
||||
|
||||
private final LayoutInflater mInflater;
|
||||
@@ -1067,7 +1135,7 @@ public class DownloadsScene extends ToolbarScene
|
||||
AlertDialog dialog = builder.show();
|
||||
new RenameLabelDialogHelper(builder, dialog, label);
|
||||
} else if (itemId == R.id.menu_label_remove) {
|
||||
new AlertDialog.Builder(requireContext())
|
||||
new MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(getString(R.string.delete_label_title))
|
||||
.setMessage(getString(R.string.delete_label_message, label))
|
||||
.setPositiveButton(R.string.delete, (dialog, which) -> {
|
||||
@@ -1391,73 +1459,6 @@ public class DownloadsScene extends ToolbarScene
|
||||
}
|
||||
}
|
||||
|
||||
private static class ThumbDataContainer implements DataContainer {
|
||||
|
||||
private final DownloadInfo mInfo;
|
||||
@Nullable
|
||||
private UniFile mFile;
|
||||
|
||||
public ThumbDataContainer(@NonNull DownloadInfo info) {
|
||||
mInfo = info;
|
||||
}
|
||||
|
||||
private void ensureFile() {
|
||||
if (mFile == null) {
|
||||
UniFile dir = SpiderDen.getGalleryDownloadDir(mInfo);
|
||||
if (dir != null && dir.isDirectory()) {
|
||||
mFile = dir.createFile(".thumb");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
ensureFile();
|
||||
return mFile != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUrlMoved(String requestUrl, String responseUrl) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean save(InputStream is, long length, String mediaType, ProgressNotifier notify) {
|
||||
ensureFile();
|
||||
if (mFile == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
OutputStream os = null;
|
||||
try {
|
||||
os = mFile.openOutputStream();
|
||||
IOUtils.copy(is, os);
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
} finally {
|
||||
IOUtils.closeQuietly(os);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStreamPipe get() {
|
||||
ensureFile();
|
||||
if (mFile != null) {
|
||||
return new UniFileInputStreamPipe(mFile);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
if (mFile != null) {
|
||||
mFile.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class RenameLabelDialogHelper implements View.OnClickListener {
|
||||
|
||||
private final EditTextDialogBuilder mBuilder;
|
||||
|
||||
@@ -27,7 +27,6 @@ import android.os.Bundle;
|
||||
import android.text.InputType;
|
||||
import android.text.TextUtils;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.util.TypedValue;
|
||||
import android.view.Display;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -48,6 +47,7 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.getkeepsafe.taptargetview.TapTarget;
|
||||
import com.getkeepsafe.taptargetview.TapTargetView;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.hippo.annotation.Implemented;
|
||||
import com.hippo.app.EditTextDialogBuilder;
|
||||
@@ -90,7 +90,6 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import rikka.core.res.ResourcesKt;
|
||||
import rikka.recyclerview.RecyclerViewKt;
|
||||
|
||||
// TODO Get favorite, modify favorite, add favorite, what a mess!
|
||||
@SuppressLint("RtlHardcoded")
|
||||
@@ -120,6 +119,19 @@ public class FavoritesScene extends BaseScene implements
|
||||
@Nullable
|
||||
@ViewLifeCircle
|
||||
private FabLayout mFabLayout;
|
||||
private final Runnable showNormalFabsRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mFabLayout != null) {
|
||||
mFabLayout.setSecondaryFabVisibilityAt(0, true);
|
||||
mFabLayout.setSecondaryFabVisibilityAt(1, true);
|
||||
mFabLayout.setSecondaryFabVisibilityAt(2, true);
|
||||
mFabLayout.setSecondaryFabVisibilityAt(3, false);
|
||||
mFabLayout.setSecondaryFabVisibilityAt(4, false);
|
||||
mFabLayout.setSecondaryFabVisibilityAt(5, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
@Nullable
|
||||
@ViewLifeCircle
|
||||
private FavoritesAdapter mAdapter;
|
||||
@@ -165,20 +177,6 @@ public class FavoritesScene extends BaseScene implements
|
||||
// For modify action
|
||||
private boolean mModifyAdd;
|
||||
|
||||
private final Runnable showNormalFabsRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mFabLayout != null) {
|
||||
mFabLayout.setSecondaryFabVisibilityAt(0, true);
|
||||
mFabLayout.setSecondaryFabVisibilityAt(1, true);
|
||||
mFabLayout.setSecondaryFabVisibilityAt(2, true);
|
||||
mFabLayout.setSecondaryFabVisibilityAt(3, false);
|
||||
mFabLayout.setSecondaryFabVisibilityAt(4, false);
|
||||
mFabLayout.setSecondaryFabVisibilityAt(5, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public int getNavCheckedItem() {
|
||||
return R.id.nav_favourite;
|
||||
@@ -334,8 +332,8 @@ public class FavoritesScene extends BaseScene implements
|
||||
|
||||
TapTargetView.showFor(requireActivity(),
|
||||
TapTarget.forBounds(bounds,
|
||||
getString(R.string.guide_collections_title),
|
||||
getString(R.string.guide_collections_text))
|
||||
getString(R.string.guide_collections_title),
|
||||
getString(R.string.guide_collections_text))
|
||||
.outerCircleColor(R.color.colorPrimary)
|
||||
.transparentTarget(true),
|
||||
new TapTargetView.Listener() {
|
||||
@@ -438,7 +436,7 @@ public class FavoritesScene extends BaseScene implements
|
||||
items[1] = getString(R.string.local_favorites);
|
||||
String[] favCat = Settings.getFavCat();
|
||||
System.arraycopy(favCat, 0, items, 2, 10);
|
||||
new AlertDialog.Builder(context)
|
||||
new MaterialAlertDialogBuilder(context)
|
||||
.setTitle(R.string.default_favorites_collection)
|
||||
.setItems(items, (dialog, which) -> Settings.putDefaultFavSlot(which - 2)).show();
|
||||
return true;
|
||||
@@ -777,7 +775,7 @@ public class FavoritesScene extends BaseScene implements
|
||||
}
|
||||
case 4: { // Delete
|
||||
DeleteDialogHelper helper = new DeleteDialogHelper();
|
||||
new AlertDialog.Builder(context)
|
||||
new MaterialAlertDialogBuilder(context)
|
||||
.setTitle(R.string.delete_favorites_dialog_title)
|
||||
.setMessage(getString(R.string.delete_favorites_dialog_message, mModifyGiList.size()))
|
||||
.setPositiveButton(android.R.string.ok, helper)
|
||||
@@ -791,7 +789,7 @@ public class FavoritesScene extends BaseScene implements
|
||||
String[] array = new String[11];
|
||||
array[0] = getString(R.string.local_favorites);
|
||||
System.arraycopy(Settings.getFavCat(), 0, array, 1, 10);
|
||||
new AlertDialog.Builder(context)
|
||||
new MaterialAlertDialogBuilder(context)
|
||||
.setTitle(R.string.move_favorites_dialog_title)
|
||||
.setItems(array, helper)
|
||||
.setOnCancelListener(helper)
|
||||
|
||||
@@ -60,11 +60,11 @@ abstract class GalleryAdapter extends RecyclerView.Adapter<GalleryHolder> {
|
||||
private final int mPaddingTopSB;
|
||||
private final int mListThumbWidth;
|
||||
private final int mListThumbHeight;
|
||||
private final boolean mShowFavourited;
|
||||
private final DownloadManager mDownloadManager;
|
||||
private MarginItemDecoration mListDecoration;
|
||||
private MarginItemDecoration mGirdDecoration;
|
||||
private int mType = TYPE_INVALID;
|
||||
private final boolean mShowFavourited;
|
||||
private final DownloadManager mDownloadManager;
|
||||
|
||||
public GalleryAdapter(@NonNull LayoutInflater inflater, @NonNull Resources resources,
|
||||
@NonNull RecyclerView recyclerView, int type, boolean showFavourited) {
|
||||
|
||||
@@ -45,7 +45,6 @@ import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.WindowInsetsAnimationCompat;
|
||||
@@ -54,6 +53,7 @@ import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.hippo.easyrecyclerview.EasyRecyclerView;
|
||||
import com.hippo.easyrecyclerview.LinearDividerItemDecoration;
|
||||
@@ -223,7 +223,7 @@ public final class GalleryCommentsScene extends ToolbarScene
|
||||
if (itemAnimator instanceof DefaultItemAnimator) {
|
||||
((DefaultItemAnimator) itemAnimator).setSupportsChangeAnimations(false);
|
||||
}
|
||||
RecyclerViewKt.addEdgeSpacing(mRecyclerView, 0,0,0,80, TypedValue.COMPLEX_UNIT_DIP);
|
||||
RecyclerViewKt.addEdgeSpacing(mRecyclerView, 0, 0, 0, 80, TypedValue.COMPLEX_UNIT_DIP);
|
||||
|
||||
mSendImage.setOnClickListener(this);
|
||||
mFab.setOnClickListener(this);
|
||||
@@ -308,7 +308,7 @@ public final class GalleryCommentsScene extends ToolbarScene
|
||||
}
|
||||
}
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(context);
|
||||
context = builder.getContext();
|
||||
final LayoutInflater inflater = LayoutInflater.from(context);
|
||||
EasyRecyclerView rv = (EasyRecyclerView) inflater.inflate(R.layout.dialog_recycler_view, null);
|
||||
@@ -370,7 +370,7 @@ public final class GalleryCommentsScene extends ToolbarScene
|
||||
menuId.add(R.id.check_vote_status);
|
||||
}
|
||||
|
||||
new AlertDialog.Builder(context)
|
||||
new MaterialAlertDialogBuilder(context)
|
||||
.setItems(menu.toArray(new String[0]), (dialog, which) -> {
|
||||
if (which < 0 || which >= menuId.size()) {
|
||||
return;
|
||||
@@ -471,27 +471,27 @@ public final class GalleryCommentsScene extends ToolbarScene
|
||||
mFab.animate().x(fabEndX).y(fabEndY).scaleX(0.0f).scaleY(0.0f)
|
||||
.setInterpolator(AnimationUtils.SLOW_FAST_SLOW_INTERPOLATOR)
|
||||
.setDuration(300L).setListener(new SimpleAnimatorListener() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
if (null == mFab || null == mEditPanel) {
|
||||
return;
|
||||
}
|
||||
|
||||
((View) mFab).setVisibility(View.INVISIBLE);
|
||||
mEditPanel.setVisibility(View.VISIBLE);
|
||||
int halfW = mEditPanel.getWidth() / 2;
|
||||
int halfH = mEditPanel.getHeight() / 2;
|
||||
Animator animator = ViewAnimationUtils.createCircularReveal(mEditPanel, halfW, halfH, 0,
|
||||
(float) Math.hypot(halfW, halfH)).setDuration(300L);
|
||||
animator.addListener(new SimpleAnimatorListener() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator a) {
|
||||
mInAnimation = false;
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
if (null == mFab || null == mEditPanel) {
|
||||
return;
|
||||
}
|
||||
|
||||
((View) mFab).setVisibility(View.INVISIBLE);
|
||||
mEditPanel.setVisibility(View.VISIBLE);
|
||||
int halfW = mEditPanel.getWidth() / 2;
|
||||
int halfH = mEditPanel.getHeight() / 2;
|
||||
Animator animator = ViewAnimationUtils.createCircularReveal(mEditPanel, halfW, halfH, 0,
|
||||
(float) Math.hypot(halfW, halfH)).setDuration(300L);
|
||||
animator.addListener(new SimpleAnimatorListener() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator a) {
|
||||
mInAnimation = false;
|
||||
}
|
||||
});
|
||||
animator.start();
|
||||
}
|
||||
});
|
||||
animator.start();
|
||||
}
|
||||
}).start();
|
||||
}).start();
|
||||
}
|
||||
|
||||
private void showEditPanel(boolean animation) {
|
||||
@@ -543,11 +543,11 @@ public final class GalleryCommentsScene extends ToolbarScene
|
||||
mFab.animate().translationX(0.0f).translationY(0.0f).scaleX(1.0f).scaleY(1.0f).rotation(0.0f)
|
||||
.setInterpolator(AnimationUtils.SLOW_FAST_SLOW_INTERPOLATOR)
|
||||
.setDuration(300L).setListener(new SimpleAnimatorListener() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
mInAnimation = false;
|
||||
}
|
||||
}).start();
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
mInAnimation = false;
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
});
|
||||
animator.start();
|
||||
@@ -847,6 +847,18 @@ public final class GalleryCommentsScene extends ToolbarScene
|
||||
}
|
||||
}
|
||||
|
||||
private static class MoreCommentHolder extends CommentHolder {
|
||||
public MoreCommentHolder(LayoutInflater inflater, ViewGroup parent) {
|
||||
super(inflater, R.layout.item_gallery_comment_more, parent);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ProgressCommentHolder extends CommentHolder {
|
||||
public ProgressCommentHolder(LayoutInflater inflater, ViewGroup parent) {
|
||||
super(inflater, R.layout.item_gallery_comment_progress, parent);
|
||||
}
|
||||
}
|
||||
|
||||
private class ActualCommentHolder extends CommentHolder {
|
||||
|
||||
private final TextView user;
|
||||
@@ -901,18 +913,6 @@ public final class GalleryCommentsScene extends ToolbarScene
|
||||
}
|
||||
}
|
||||
|
||||
private static class MoreCommentHolder extends CommentHolder {
|
||||
public MoreCommentHolder(LayoutInflater inflater, ViewGroup parent) {
|
||||
super(inflater, R.layout.item_gallery_comment_more, parent);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ProgressCommentHolder extends CommentHolder {
|
||||
public ProgressCommentHolder(LayoutInflater inflater, ViewGroup parent) {
|
||||
super(inflater, R.layout.item_gallery_comment_progress, parent);
|
||||
}
|
||||
}
|
||||
|
||||
private class CommentAdapter extends RecyclerView.Adapter<CommentHolder> {
|
||||
|
||||
private final LayoutInflater mInflater;
|
||||
|
||||
@@ -66,6 +66,7 @@ import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
import androidx.transition.TransitionInflater;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.progressindicator.CircularProgressIndicator;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
import com.hippo.app.EditTextDialogBuilder;
|
||||
@@ -264,18 +265,12 @@ public class GalleryDetailScene extends BaseScene implements View.OnClickListene
|
||||
private GalleryDetail mGalleryDetail;
|
||||
private int mRequestId = IntIdGenerator.INVALID_ID;
|
||||
private Pair<String, String>[] mTorrentList;
|
||||
private String mArchiveFormParamOr;
|
||||
private Pair<String, String>[] mArchiveList;
|
||||
@State
|
||||
private int mState = STATE_INIT;
|
||||
private boolean mModifingFavorites;
|
||||
|
||||
ActivityResultLauncher<String> requestStoragePermissionLauncher = registerForActivityResult(
|
||||
new ActivityResultContracts.RequestPermission(),
|
||||
result -> {
|
||||
if (result && mGalleryDetail != null) {
|
||||
TorrentListDialogHelper helper = new TorrentListDialogHelper();
|
||||
Dialog dialog = new AlertDialog.Builder(requireActivity())
|
||||
Dialog dialog = new MaterialAlertDialogBuilder(requireActivity())
|
||||
.setTitle(R.string.torrents)
|
||||
.setView(R.layout.dialog_torrent_list)
|
||||
.setOnDismissListener(helper)
|
||||
@@ -283,6 +278,24 @@ public class GalleryDetailScene extends BaseScene implements View.OnClickListene
|
||||
helper.setDialog(dialog, mGalleryDetail.torrentUrl);
|
||||
}
|
||||
});
|
||||
private String mArchiveFormParamOr;
|
||||
private Pair<String, String>[] mArchiveList;
|
||||
@State
|
||||
private int mState = STATE_INIT;
|
||||
private boolean mModifingFavorites;
|
||||
|
||||
@Nullable
|
||||
private static String getArtist(GalleryTagGroup[] tagGroups) {
|
||||
if (null == tagGroups) {
|
||||
return null;
|
||||
}
|
||||
for (GalleryTagGroup tagGroup : tagGroups) {
|
||||
if ("artist".equals(tagGroup.groupName) && tagGroup.size() > 0) {
|
||||
return tagGroup.getTagAt(0);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@StringRes
|
||||
private int getRatingText(float rating) {
|
||||
@@ -329,19 +342,6 @@ public class GalleryDetailScene extends BaseScene implements View.OnClickListene
|
||||
return resId;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getArtist(GalleryTagGroup[] tagGroups) {
|
||||
if (null == tagGroups) {
|
||||
return null;
|
||||
}
|
||||
for (GalleryTagGroup tagGroup : tagGroups) {
|
||||
if ("artist".equals(tagGroup.groupName) && tagGroup.size() > 0) {
|
||||
return tagGroup.getTagAt(0);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void handleArgs(Bundle args) {
|
||||
if (args == null) {
|
||||
return;
|
||||
@@ -1231,7 +1231,7 @@ public class GalleryDetailScene extends BaseScene implements View.OnClickListene
|
||||
if (EhApplication.getDownloadManager(context).getDownloadState(galleryInfo.gid) == DownloadInfo.STATE_INVALID) {
|
||||
CommonOperations.startDownload(activity, galleryInfo, false);
|
||||
} else {
|
||||
new AlertDialog.Builder(context)
|
||||
new MaterialAlertDialogBuilder(context)
|
||||
.setTitle(R.string.download_remove_dialog_title)
|
||||
.setMessage(getString(R.string.download_remove_dialog_message, galleryInfo.title))
|
||||
.setPositiveButton(android.R.string.ok, (dialog1, which1) -> EhApplication.getDownloadManager(context).deleteDownload(galleryInfo.gid))
|
||||
@@ -1257,7 +1257,7 @@ public class GalleryDetailScene extends BaseScene implements View.OnClickListene
|
||||
for (GalleryInfo newerVersion : mGalleryDetail.newerVersions) {
|
||||
titles.add(getString(R.string.newer_version_title, newerVersion.title, newerVersion.posted));
|
||||
}
|
||||
new AlertDialog.Builder(requireContext())
|
||||
new MaterialAlertDialogBuilder(requireContext())
|
||||
.setItems(titles.toArray(new CharSequence[0]), (dialog, which) -> {
|
||||
GalleryInfo newerVersion = mGalleryDetail.newerVersions.get(which);
|
||||
Bundle args = new Bundle();
|
||||
@@ -1303,7 +1303,7 @@ public class GalleryDetailScene extends BaseScene implements View.OnClickListene
|
||||
requestStoragePermissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
||||
} else {
|
||||
TorrentListDialogHelper helper = new TorrentListDialogHelper();
|
||||
Dialog dialog = new AlertDialog.Builder(context)
|
||||
Dialog dialog = new MaterialAlertDialogBuilder(context)
|
||||
.setTitle(R.string.torrents)
|
||||
.setView(R.layout.dialog_torrent_list)
|
||||
.setOnDismissListener(helper)
|
||||
@@ -1320,7 +1320,7 @@ public class GalleryDetailScene extends BaseScene implements View.OnClickListene
|
||||
return;
|
||||
}
|
||||
ArchiveListDialogHelper helper = new ArchiveListDialogHelper();
|
||||
Dialog dialog = new AlertDialog.Builder(context)
|
||||
Dialog dialog = new MaterialAlertDialogBuilder(context)
|
||||
.setTitle(R.string.dialog_archive_title)
|
||||
.setView(R.layout.dialog_archive_list)
|
||||
.setOnDismissListener(helper)
|
||||
@@ -1335,7 +1335,7 @@ public class GalleryDetailScene extends BaseScene implements View.OnClickListene
|
||||
return;
|
||||
}
|
||||
RateDialogHelper helper = new RateDialogHelper();
|
||||
Dialog dialog = new AlertDialog.Builder(context)
|
||||
Dialog dialog = new MaterialAlertDialogBuilder(context)
|
||||
.setTitle(R.string.rate)
|
||||
.setView(R.layout.dialog_rate)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
@@ -1397,7 +1397,7 @@ public class GalleryDetailScene extends BaseScene implements View.OnClickListene
|
||||
return;
|
||||
}
|
||||
|
||||
new AlertDialog.Builder(context)
|
||||
new MaterialAlertDialogBuilder(context)
|
||||
.setMessage(getString(R.string.filter_the_uploader, uploader))
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
|
||||
Filter filter = new Filter();
|
||||
@@ -1417,7 +1417,7 @@ public class GalleryDetailScene extends BaseScene implements View.OnClickListene
|
||||
return;
|
||||
}
|
||||
|
||||
new AlertDialog.Builder(context)
|
||||
new MaterialAlertDialogBuilder(context)
|
||||
.setMessage(getString(R.string.filter_the_tag, tag))
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
|
||||
Filter filter = new Filter();
|
||||
@@ -1466,7 +1466,7 @@ public class GalleryDetailScene extends BaseScene implements View.OnClickListene
|
||||
menuId.add(R.id.vote_down);
|
||||
}
|
||||
|
||||
new AlertDialog.Builder(context)
|
||||
new MaterialAlertDialogBuilder(context)
|
||||
.setTitle(tag)
|
||||
.setItems(menu.toArray(new String[0]), (dialog, which) -> {
|
||||
if (which < 0 || which >= menuId.size()) {
|
||||
@@ -1709,6 +1709,16 @@ public class GalleryDetailScene extends BaseScene implements View.OnClickListene
|
||||
mModifingFavorites = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProvideAssistContent(AssistContent outContent) {
|
||||
super.onProvideAssistContent(outContent);
|
||||
|
||||
String url = getGalleryDetailUrl(false);
|
||||
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 {
|
||||
@@ -2222,14 +2232,4 @@ public class GalleryDetailScene extends BaseScene implements View.OnClickListene
|
||||
EhApplication.getEhClient(context).execute(request);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProvideAssistContent(AssistContent outContent) {
|
||||
super.onProvideAssistContent(outContent);
|
||||
|
||||
String url = getGalleryDetailUrl(false);
|
||||
if (url != null) {
|
||||
outContent.setWebUri(Uri.parse(url));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,6 +61,7 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.getkeepsafe.taptargetview.TapTarget;
|
||||
import com.getkeepsafe.taptargetview.TapTargetView;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.h6ah4i.android.widget.advrecyclerview.animator.DraggableItemAnimator;
|
||||
import com.h6ah4i.android.widget.advrecyclerview.animator.GeneralItemAnimator;
|
||||
@@ -164,6 +165,9 @@ public final class GalleryListScene extends BaseScene
|
||||
private EasyRecyclerView mRecyclerView;
|
||||
@Nullable
|
||||
private SearchLayout mSearchLayout;
|
||||
ActivityResultLauncher<String[]> selectImageLauncher = registerForActivityResult(
|
||||
new ActivityResultContracts.OpenDocument(),
|
||||
result -> mSearchLayout.setImageUri(result));
|
||||
@Nullable
|
||||
private SearchBar mSearchBar;
|
||||
@Nullable
|
||||
@@ -235,10 +239,6 @@ public final class GalleryListScene extends BaseScene
|
||||
private FavouriteStatusRouter.Listener mFavouriteStatusRouterListener;
|
||||
private boolean mIsTopList = false;
|
||||
|
||||
ActivityResultLauncher<String[]> selectImageLauncher = registerForActivityResult(
|
||||
new ActivityResultContracts.OpenDocument(),
|
||||
result -> mSearchLayout.setImageUri(result));
|
||||
|
||||
@Nullable
|
||||
private static String getSuitableTitleForUrlBuilder(
|
||||
Resources resources, ListUrlBuilder urlBuilder, boolean appName) {
|
||||
@@ -656,8 +656,8 @@ public final class GalleryListScene extends BaseScene
|
||||
|
||||
TapTargetView.showFor(requireActivity(),
|
||||
TapTarget.forBounds(bounds,
|
||||
getString(R.string.guide_quick_search_title),
|
||||
getString(R.string.guide_quick_search_text))
|
||||
getString(R.string.guide_quick_search_title),
|
||||
getString(R.string.guide_quick_search_text))
|
||||
.outerCircleColor(R.color.colorPrimary)
|
||||
.transparentTarget(true),
|
||||
new TapTargetView.Listener() {
|
||||
@@ -1043,7 +1043,7 @@ public final class GalleryListScene extends BaseScene
|
||||
favourited ? R.drawable.v_heart_broken_x24 : R.drawable.v_heart_x24,
|
||||
};
|
||||
|
||||
new AlertDialog.Builder(context)
|
||||
new MaterialAlertDialogBuilder(context)
|
||||
.setTitle(EhUtils.getSuitableTitle(gi))
|
||||
.setAdapter(new SelectItemWithIconAdapter(context, items, icons), (dialog, which) -> {
|
||||
switch (which) {
|
||||
@@ -1055,7 +1055,7 @@ public final class GalleryListScene extends BaseScene
|
||||
break;
|
||||
case 1: // Download
|
||||
if (downloaded) {
|
||||
new AlertDialog.Builder(context)
|
||||
new MaterialAlertDialogBuilder(context)
|
||||
.setTitle(R.string.download_remove_dialog_title)
|
||||
.setMessage(getString(R.string.download_remove_dialog_message, gi.title))
|
||||
.setPositiveButton(android.R.string.ok, (dialog1, which1) -> mDownloadManager.deleteDownload(gi.gid))
|
||||
@@ -1082,7 +1082,7 @@ public final class GalleryListScene extends BaseScene
|
||||
|
||||
MoveDialogHelper helper = new MoveDialogHelper(labels, gi);
|
||||
|
||||
new AlertDialog.Builder(context)
|
||||
new MaterialAlertDialogBuilder(context)
|
||||
.setTitle(R.string.download_move_dialog_title)
|
||||
.setItems(labels, helper)
|
||||
.show();
|
||||
@@ -1092,39 +1092,6 @@ public final class GalleryListScene extends BaseScene
|
||||
return true;
|
||||
}
|
||||
|
||||
private class MoveDialogHelper implements DialogInterface.OnClickListener {
|
||||
|
||||
private final String[] mLabels;
|
||||
private final GalleryInfo mGi;
|
||||
|
||||
public MoveDialogHelper(String[] labels, GalleryInfo gi) {
|
||||
mLabels = labels;
|
||||
mGi = gi;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
// Cancel check mode
|
||||
Context context = getContext();
|
||||
if (null == context) {
|
||||
return;
|
||||
}
|
||||
if (null != mRecyclerView) {
|
||||
mRecyclerView.outOfCustomChoiceMode();
|
||||
}
|
||||
|
||||
DownloadManager downloadManager = EhApplication.getDownloadManager(context);
|
||||
DownloadInfo downloadInfo = downloadManager.getDownloadInfo(mGi.gid);
|
||||
if (downloadInfo == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String label = which == 0 ? null : mLabels[which];
|
||||
|
||||
downloadManager.changeLabel(Collections.singletonList(downloadInfo), label);
|
||||
}
|
||||
}
|
||||
|
||||
private void showActionFab() {
|
||||
if (null != mFabLayout && STATE_NORMAL == mState && !mShowActionFab) {
|
||||
mShowActionFab = true;
|
||||
@@ -1613,6 +1580,39 @@ public final class GalleryListScene extends BaseScene
|
||||
}
|
||||
}
|
||||
|
||||
private class MoveDialogHelper implements DialogInterface.OnClickListener {
|
||||
|
||||
private final String[] mLabels;
|
||||
private final GalleryInfo mGi;
|
||||
|
||||
public MoveDialogHelper(String[] labels, GalleryInfo gi) {
|
||||
mLabels = labels;
|
||||
mGi = gi;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
// Cancel check mode
|
||||
Context context = getContext();
|
||||
if (null == context) {
|
||||
return;
|
||||
}
|
||||
if (null != mRecyclerView) {
|
||||
mRecyclerView.outOfCustomChoiceMode();
|
||||
}
|
||||
|
||||
DownloadManager downloadManager = EhApplication.getDownloadManager(context);
|
||||
DownloadInfo downloadInfo = downloadManager.getDownloadInfo(mGi.gid);
|
||||
if (downloadInfo == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String label = which == 0 ? null : mLabels[which];
|
||||
|
||||
downloadManager.changeLabel(Collections.singletonList(downloadInfo), label);
|
||||
}
|
||||
}
|
||||
|
||||
private class QsDrawerAdapter extends RecyclerView.Adapter<QsDrawerHolder> implements DraggableItemAdapter<QsDrawerHolder> {
|
||||
|
||||
private final LayoutInflater mInflater;
|
||||
@@ -1655,7 +1655,7 @@ public final class GalleryListScene extends BaseScene
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
if (item.getItemId() == R.id.menu_qs_remove) {
|
||||
new AlertDialog.Builder(requireContext())
|
||||
new MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(getString(R.string.delete_quick_search_title))
|
||||
.setMessage(getString(R.string.delete_quick_search_message, quickSearch.name))
|
||||
.setPositiveButton(R.string.delete, (dialog, which) -> {
|
||||
|
||||
@@ -35,6 +35,7 @@ import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.hippo.easyrecyclerview.EasyRecyclerView;
|
||||
import com.hippo.easyrecyclerview.MarginItemDecoration;
|
||||
import com.hippo.ehviewer.EhApplication;
|
||||
@@ -210,7 +211,7 @@ public class GalleryPreviewsScene extends ToolbarScene {
|
||||
int pages = mHelper.getPages();
|
||||
if (pages > 0 && mHelper.canGoTo()) {
|
||||
GoToDialogHelper helper = new GoToDialogHelper(pages, mHelper.getPageForTop());
|
||||
AlertDialog dialog = new AlertDialog.Builder(context).setTitle(R.string.go_to)
|
||||
AlertDialog dialog = new MaterialAlertDialogBuilder(context).setTitle(R.string.go_to)
|
||||
.setView(R.layout.dialog_go_to)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.create();
|
||||
|
||||
@@ -35,12 +35,12 @@ import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.h6ah4i.android.widget.advrecyclerview.animator.GeneralItemAnimator;
|
||||
import com.h6ah4i.android.widget.advrecyclerview.animator.SwipeDismissItemAnimator;
|
||||
import com.h6ah4i.android.widget.advrecyclerview.swipeable.RecyclerViewSwipeManager;
|
||||
@@ -86,7 +86,6 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import rikka.core.res.ResourcesKt;
|
||||
import rikka.recyclerview.RecyclerViewKt;
|
||||
|
||||
public class HistoryScene extends ToolbarScene {
|
||||
@@ -234,11 +233,11 @@ public class HistoryScene extends ToolbarScene {
|
||||
guardManager.attachRecyclerView(mRecyclerView);
|
||||
swipeManager.attachRecyclerView(mRecyclerView);
|
||||
RecyclerViewKt.fixEdgeEffect(mRecyclerView, false, true);
|
||||
RecyclerViewKt.addEdgeSpacing(mRecyclerView, 4,4,4,4, TypedValue.COMPLEX_UNIT_DIP);
|
||||
RecyclerViewKt.addEdgeSpacing(mRecyclerView, 4, 4, 4, 4, TypedValue.COMPLEX_UNIT_DIP);
|
||||
|
||||
mFastScroller.attachToRecyclerView(mRecyclerView);
|
||||
HandlerDrawable handlerDrawable = new HandlerDrawable();
|
||||
handlerDrawable.setColor(ResourcesKt.resolveColor(getTheme(), R.attr.widgetColorThemeAccent));
|
||||
handlerDrawable.setColor(com.google.android.material.R.color.material_dynamic_neutral100);
|
||||
mFastScroller.setHandlerDrawable(handlerDrawable);
|
||||
|
||||
updateLazyList();
|
||||
@@ -307,7 +306,7 @@ public class HistoryScene extends ToolbarScene {
|
||||
}
|
||||
|
||||
private void showClearAllDialog() {
|
||||
new AlertDialog.Builder(requireContext())
|
||||
new MaterialAlertDialogBuilder(requireContext())
|
||||
.setMessage(R.string.clear_all_history)
|
||||
.setPositiveButton(R.string.clear_all, (dialog, which) -> {
|
||||
if (DialogInterface.BUTTON_POSITIVE != which || null == mAdapter) {
|
||||
@@ -398,7 +397,7 @@ public class HistoryScene extends ToolbarScene {
|
||||
R.drawable.v_delete_x24,
|
||||
};
|
||||
|
||||
new AlertDialog.Builder(context)
|
||||
new MaterialAlertDialogBuilder(context)
|
||||
.setTitle(EhUtils.getSuitableTitle(gi))
|
||||
.setAdapter(new SelectItemWithIconAdapter(context, items, icons), (dialog, which) -> {
|
||||
switch (which) {
|
||||
@@ -410,7 +409,7 @@ public class HistoryScene extends ToolbarScene {
|
||||
break;
|
||||
case 1: // Download
|
||||
if (downloaded) {
|
||||
new AlertDialog.Builder(context)
|
||||
new MaterialAlertDialogBuilder(context)
|
||||
.setTitle(R.string.download_remove_dialog_title)
|
||||
.setMessage(getString(R.string.download_remove_dialog_message, gi.title))
|
||||
.setPositiveButton(android.R.string.ok, (dialog1, which1) -> mDownloadManager.deleteDownload(gi.gid))
|
||||
@@ -448,7 +447,7 @@ public class HistoryScene extends ToolbarScene {
|
||||
|
||||
MoveDialogHelper helper = new MoveDialogHelper(labels, gi);
|
||||
|
||||
new AlertDialog.Builder(context)
|
||||
new MaterialAlertDialogBuilder(context)
|
||||
.setTitle(R.string.download_move_dialog_title)
|
||||
.setItems(labels, helper)
|
||||
.show();
|
||||
@@ -458,39 +457,6 @@ public class HistoryScene extends ToolbarScene {
|
||||
return true;
|
||||
}
|
||||
|
||||
private class MoveDialogHelper implements DialogInterface.OnClickListener {
|
||||
|
||||
private final String[] mLabels;
|
||||
private final GalleryInfo mGi;
|
||||
|
||||
public MoveDialogHelper(String[] labels, GalleryInfo gi) {
|
||||
mLabels = labels;
|
||||
mGi = gi;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
// Cancel check mode
|
||||
Context context = getContext();
|
||||
if (null == context) {
|
||||
return;
|
||||
}
|
||||
if (null != mRecyclerView) {
|
||||
mRecyclerView.outOfCustomChoiceMode();
|
||||
}
|
||||
|
||||
DownloadManager downloadManager = EhApplication.getDownloadManager(context);
|
||||
DownloadInfo downloadInfo = downloadManager.getDownloadInfo(mGi.gid);
|
||||
if (downloadInfo == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String label = which == 0 ? null : mLabels[which];
|
||||
|
||||
downloadManager.changeLabel(Collections.singletonList(downloadInfo), label);
|
||||
}
|
||||
}
|
||||
|
||||
private static class AddToFavoriteListener extends EhCallback<GalleryListScene, Void> {
|
||||
|
||||
public AddToFavoriteListener(Context context, int stageId, String sceneTag) {
|
||||
@@ -578,6 +544,39 @@ public class HistoryScene extends ToolbarScene {
|
||||
}
|
||||
}
|
||||
|
||||
private class MoveDialogHelper implements DialogInterface.OnClickListener {
|
||||
|
||||
private final String[] mLabels;
|
||||
private final GalleryInfo mGi;
|
||||
|
||||
public MoveDialogHelper(String[] labels, GalleryInfo gi) {
|
||||
mLabels = labels;
|
||||
mGi = gi;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
// Cancel check mode
|
||||
Context context = getContext();
|
||||
if (null == context) {
|
||||
return;
|
||||
}
|
||||
if (null != mRecyclerView) {
|
||||
mRecyclerView.outOfCustomChoiceMode();
|
||||
}
|
||||
|
||||
DownloadManager downloadManager = EhApplication.getDownloadManager(context);
|
||||
DownloadInfo downloadInfo = downloadManager.getDownloadInfo(mGi.gid);
|
||||
if (downloadInfo == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String label = which == 0 ? null : mLabels[which];
|
||||
|
||||
downloadManager.changeLabel(Collections.singletonList(downloadInfo), label);
|
||||
}
|
||||
}
|
||||
|
||||
private class HistoryAdapter extends RecyclerView.Adapter<HistoryHolder>
|
||||
implements SwipeableItemAdapter<HistoryHolder> {
|
||||
|
||||
|
||||
@@ -32,7 +32,6 @@ import androidx.biometric.BiometricPrompt;
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.ehviewer.Settings;
|
||||
import com.hippo.ehviewer.ui.MainActivity;
|
||||
import com.hippo.hardware.ShakeDetector;
|
||||
import com.hippo.widget.lockpattern.LockPatternUtils;
|
||||
import com.hippo.widget.lockpattern.LockPatternView;
|
||||
import com.hippo.yorozuya.ObjectUtils;
|
||||
@@ -42,7 +41,7 @@ import java.util.List;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class SecurityScene extends SolidScene implements
|
||||
LockPatternView.OnPatternListener, ShakeDetector.OnShakeListener {
|
||||
LockPatternView.OnPatternListener {
|
||||
|
||||
private static final int MAX_RETRY_TIMES = 5;
|
||||
private static final String KEY_RETRY_TIMES = "retry_times";
|
||||
@@ -52,7 +51,6 @@ public class SecurityScene extends SolidScene implements
|
||||
|
||||
private SensorManager mSensorManager;
|
||||
private Sensor mAccelerometer;
|
||||
private ShakeDetector mShakeDetector;
|
||||
private BiometricPrompt.PromptInfo promptInfo;
|
||||
private BiometricPrompt biometricPrompt;
|
||||
private boolean canAuthenticate = false;
|
||||
@@ -72,10 +70,6 @@ public class SecurityScene extends SolidScene implements
|
||||
mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
|
||||
if (null != mSensorManager) {
|
||||
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
|
||||
if (null != mAccelerometer) {
|
||||
mShakeDetector = new ShakeDetector();
|
||||
mShakeDetector.setOnShakeListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
if (null == savedInstanceState) {
|
||||
@@ -116,17 +110,12 @@ public class SecurityScene extends SolidScene implements
|
||||
|
||||
mSensorManager = null;
|
||||
mAccelerometer = null;
|
||||
mShakeDetector = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
if (null != mShakeDetector) {
|
||||
mSensorManager.registerListener(mShakeDetector, mAccelerometer, SensorManager.SENSOR_DELAY_UI);
|
||||
}
|
||||
|
||||
if (canAuthenticate) {
|
||||
startBiometricPrompt();
|
||||
}
|
||||
@@ -139,10 +128,6 @@ public class SecurityScene extends SolidScene implements
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
|
||||
if (null != mShakeDetector) {
|
||||
mSensorManager.unregisterListener(mShakeDetector);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -205,17 +190,4 @@ public class SecurityScene extends SolidScene implements
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShake(int count) {
|
||||
if (count == 10) {
|
||||
MainActivity activity = getMainActivity();
|
||||
if (null == activity) {
|
||||
return;
|
||||
}
|
||||
Settings.putSecurity("");
|
||||
startSceneForCheckStep(CHECK_STEP_SECURITY, getArguments());
|
||||
finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,8 +29,8 @@ import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.textfield.TextInputLayout;
|
||||
import com.hippo.ehviewer.EhApplication;
|
||||
import com.hippo.ehviewer.R;
|
||||
@@ -333,7 +333,7 @@ public final class SignInScene extends SolidScene implements EditText.OnEditorAc
|
||||
return;
|
||||
}
|
||||
|
||||
new AlertDialog.Builder(context)
|
||||
new MaterialAlertDialogBuilder(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)
|
||||
|
||||
@@ -30,9 +30,8 @@ public class SolidScene extends BaseScene {
|
||||
|
||||
public static final int CHECK_STEP_SECURITY = 0;
|
||||
public static final int CHECK_STEP_WARNING = 1;
|
||||
public static final int CHECK_STEP_ANALYTICS = 2;
|
||||
public static final int CHECK_STEP_SIGN_IN = 3;
|
||||
public static final int CHECK_STEP_SELECT_SITE = 4;
|
||||
public static final int CHECK_STEP_SIGN_IN = 2;
|
||||
public static final int CHECK_STEP_SELECT_SITE = 3;
|
||||
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();
|
||||
@@ -45,11 +44,6 @@ public class SolidScene extends BaseScene {
|
||||
break;
|
||||
}
|
||||
case CHECK_STEP_WARNING:
|
||||
if (Settings.getAskAnalytics()) {
|
||||
startScene(new Announcer(AnalyticsScene.class).setArgs(args), true);
|
||||
break;
|
||||
}
|
||||
case CHECK_STEP_ANALYTICS:
|
||||
if (EhUtils.needSignedIn(getContext())) {
|
||||
startScene(new Announcer(SignInScene.class).setArgs(args), true);
|
||||
break;
|
||||
|
||||
@@ -26,8 +26,7 @@ import android.webkit.WebView;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.hippo.ehviewer.R;
|
||||
|
||||
public class DialogWebChromeClient extends WebChromeClient {
|
||||
@@ -40,7 +39,7 @@ public class DialogWebChromeClient extends WebChromeClient {
|
||||
|
||||
@Override
|
||||
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
|
||||
new AlertDialog.Builder(view.getContext())
|
||||
new MaterialAlertDialogBuilder(view.getContext())
|
||||
.setMessage(message)
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> result.confirm())
|
||||
.setOnCancelListener(dialog -> result.cancel())
|
||||
@@ -50,7 +49,7 @@ public class DialogWebChromeClient extends WebChromeClient {
|
||||
|
||||
@Override
|
||||
public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
|
||||
new AlertDialog.Builder(view.getContext())
|
||||
new MaterialAlertDialogBuilder(view.getContext())
|
||||
.setMessage(message)
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> result.confirm())
|
||||
.setNegativeButton(android.R.string.cancel, (dialog, which) -> result.cancel())
|
||||
@@ -68,7 +67,7 @@ public class DialogWebChromeClient extends WebChromeClient {
|
||||
final EditText valueView = promptView.findViewById(R.id.value);
|
||||
valueView.setText(defaultValue);
|
||||
|
||||
new AlertDialog.Builder(context)
|
||||
new MaterialAlertDialogBuilder(context)
|
||||
.setView(promptView)
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> result.confirm(valueView.getText().toString()))
|
||||
.setOnCancelListener(dialog -> result.cancel())
|
||||
|
||||
@@ -32,19 +32,15 @@ import com.hippo.yorozuya.ObjectUtils;
|
||||
|
||||
public class GalleryHeader extends ViewGroup {
|
||||
|
||||
private DisplayCutoutCompat displayCutout;
|
||||
private int topInsets = 0;
|
||||
|
||||
private View battery;
|
||||
private View progress;
|
||||
private View clock;
|
||||
|
||||
private final Rect batteryRect = new Rect();
|
||||
private final Rect progressRect = new Rect();
|
||||
private final Rect clockRect = new Rect();
|
||||
|
||||
private final int[] location = new int[2];
|
||||
|
||||
private DisplayCutoutCompat displayCutout;
|
||||
private int topInsets = 0;
|
||||
private View battery;
|
||||
private View progress;
|
||||
private View clock;
|
||||
private int lastX = 0;
|
||||
private int lastY = 0;
|
||||
|
||||
|
||||
@@ -33,10 +33,9 @@ import java.util.Map;
|
||||
public abstract class GalleryInfoContentHelper extends ContentLayout.ContentHelper<GalleryInfo> {
|
||||
|
||||
private static final String KEY_DATA_MAP = "data_map";
|
||||
|
||||
private final FavouriteStatusRouter.Listener listener;
|
||||
@SuppressLint("UseSparseArrays")
|
||||
private Map<Long, GalleryInfo> map = new HashMap<>();
|
||||
private final FavouriteStatusRouter.Listener listener;
|
||||
|
||||
public GalleryInfoContentHelper() {
|
||||
listener = (gid, slot) -> {
|
||||
|
||||
@@ -40,12 +40,12 @@ import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.core.util.Pair;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.card.MaterialCardView;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.hippo.easyrecyclerview.EasyRecyclerView;
|
||||
import com.hippo.easyrecyclerview.LinearDividerItemDecoration;
|
||||
import com.hippo.ehviewer.R;
|
||||
@@ -490,6 +490,27 @@ public class SearchBar extends MaterialCardView implements View.OnClickListener,
|
||||
}
|
||||
}
|
||||
|
||||
private String wrapTagKeyword(String keyword) {
|
||||
keyword = keyword.trim();
|
||||
|
||||
int index1 = keyword.indexOf(':');
|
||||
if (index1 == -1 || index1 >= keyword.length() - 1) {
|
||||
// Can't find :, or : is the last char
|
||||
return keyword;
|
||||
}
|
||||
if (keyword.charAt(index1 + 1) == '"') {
|
||||
// The char after : is ", the word must be quoted
|
||||
return keyword;
|
||||
}
|
||||
int index2 = keyword.indexOf(' ');
|
||||
if (index2 <= index1) {
|
||||
// Can't find space, or space is before :
|
||||
return keyword;
|
||||
}
|
||||
|
||||
return keyword.substring(0, index1 + 1) + "\"" + keyword.substring(index1 + 1) + "$\"";
|
||||
}
|
||||
|
||||
public interface Helper {
|
||||
void onClickTitle();
|
||||
|
||||
@@ -654,7 +675,7 @@ public class SearchBar extends MaterialCardView implements View.OnClickListener,
|
||||
|
||||
@Override
|
||||
public boolean onLongClick() {
|
||||
new AlertDialog.Builder(getContext())
|
||||
new MaterialAlertDialogBuilder(getContext())
|
||||
.setMessage(getContext().getString(R.string.delete_search_history, mKeyword))
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setPositiveButton(R.string.delete, (dialog, which) -> {
|
||||
@@ -665,25 +686,4 @@ public class SearchBar extends MaterialCardView implements View.OnClickListener,
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private String wrapTagKeyword(String keyword) {
|
||||
keyword = keyword.trim();
|
||||
|
||||
int index1 = keyword.indexOf(':');
|
||||
if (index1 == -1 || index1 >= keyword.length() - 1) {
|
||||
// Can't find :, or : is the last char
|
||||
return keyword;
|
||||
}
|
||||
if (keyword.charAt(index1 + 1) == '"') {
|
||||
// The char after : is ", the word must be quoted
|
||||
return keyword;
|
||||
}
|
||||
int index2 = keyword.indexOf(' ');
|
||||
if (index2 <= index1) {
|
||||
// Can't find space, or space is before :
|
||||
return keyword;
|
||||
}
|
||||
|
||||
return keyword.substring(0, index1 + 1) + "\"" + keyword.substring(index1 + 1) + "$\"";
|
||||
}
|
||||
}
|
||||
@@ -35,11 +35,11 @@ import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.recyclerview.widget.DefaultItemAnimator;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import com.hippo.easyrecyclerview.EasyRecyclerView;
|
||||
import com.hippo.easyrecyclerview.MarginItemDecoration;
|
||||
@@ -52,7 +52,6 @@ import com.hippo.yorozuya.ViewUtils;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.Objects;
|
||||
|
||||
public class SearchLayout extends EasyRecyclerView implements CompoundButton.OnCheckedChangeListener,
|
||||
View.OnClickListener, ImageSearchLayout.Helper, TabLayout.OnTabSelectedListener {
|
||||
@@ -113,7 +112,7 @@ public class SearchLayout extends EasyRecyclerView implements CompoundButton.OnC
|
||||
setAdapter(mAdapter);
|
||||
setHasFixedSize(true);
|
||||
setClipToPadding(false);
|
||||
((DefaultItemAnimator) Objects.requireNonNull(getItemAnimator())).setSupportsChangeAnimations(false);
|
||||
((DefaultItemAnimator) getItemAnimator()).setSupportsChangeAnimations(false);
|
||||
int interval = resources.getDimensionPixelOffset(R.dimen.search_layout_interval);
|
||||
int paddingH = resources.getDimensionPixelOffset(R.dimen.search_layout_margin_h);
|
||||
int paddingV = resources.getDimensionPixelOffset(R.dimen.search_layout_margin_v);
|
||||
@@ -268,7 +267,7 @@ public class SearchLayout extends EasyRecyclerView implements CompoundButton.OnC
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (mNormalSearchModeHelp == v) {
|
||||
new AlertDialog.Builder(getContext())
|
||||
new MaterialAlertDialogBuilder(getContext())
|
||||
.setMessage(R.string.search_tip)
|
||||
.show();
|
||||
}
|
||||
@@ -315,6 +314,22 @@ public class SearchLayout extends EasyRecyclerView implements CompoundButton.OnC
|
||||
void onSelectImage();
|
||||
}
|
||||
|
||||
static class SearchLayoutManager extends LinearLayoutManager {
|
||||
|
||||
public SearchLayoutManager(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
|
||||
try {
|
||||
super.onLayoutChildren(recycler, state);
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class SearchAdapter extends EasyRecyclerView.Adapter<SimpleHolder> {
|
||||
|
||||
@Override
|
||||
@@ -385,20 +400,4 @@ public class SearchLayout extends EasyRecyclerView implements CompoundButton.OnC
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
static class SearchLayoutManager extends LinearLayoutManager {
|
||||
|
||||
public SearchLayoutManager(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
|
||||
try {
|
||||
super.onLayoutChildren(recycler, state);
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,8 +31,8 @@ import com.hippo.yorozuya.ViewUtils;
|
||||
|
||||
public class SeekBarPanel extends LinearLayout {
|
||||
|
||||
private SeekBar mSeekBar;
|
||||
private final int[] mLocation = new int[2];
|
||||
private SeekBar mSeekBar;
|
||||
|
||||
public SeekBarPanel(Context context) {
|
||||
super(context);
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
package com.hippo.hardware;
|
||||
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
|
||||
// http://jasonmcreynolds.com/?p=388
|
||||
public class ShakeDetector implements SensorEventListener {
|
||||
|
||||
/*
|
||||
* The gForce that is necessary to register as shake.
|
||||
* Must be greater than 1G (one earth gravity unit).
|
||||
* You can install "G-Force", by Blake La Pierre
|
||||
* from the Google Play Store and run it to see how
|
||||
* many G's it takes to register a shake
|
||||
*/
|
||||
private static final float SHAKE_THRESHOLD_GRAVITY = 2.7F;
|
||||
private static final int SHAKE_SLOP_TIME_MS = 500;
|
||||
private static final int SHAKE_COUNT_RESET_TIME_MS = 3000;
|
||||
|
||||
private OnShakeListener mListener;
|
||||
private long mShakeTimestamp;
|
||||
private int mShakeCount;
|
||||
|
||||
public void setOnShakeListener(OnShakeListener listener) {
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAccuracyChanged(Sensor sensor, int accuracy) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSensorChanged(SensorEvent event) {
|
||||
|
||||
if (mListener != null) {
|
||||
float x = event.values[0];
|
||||
float y = event.values[1];
|
||||
float z = event.values[2];
|
||||
|
||||
float gX = x / SensorManager.GRAVITY_EARTH;
|
||||
float gY = y / SensorManager.GRAVITY_EARTH;
|
||||
float gZ = z / SensorManager.GRAVITY_EARTH;
|
||||
|
||||
// gForce will be close to 1 when there is no movement.
|
||||
float gForce = (float) Math.sqrt(gX * gX + gY * gY + gZ * gZ);
|
||||
|
||||
if (gForce > SHAKE_THRESHOLD_GRAVITY) {
|
||||
final long now = System.currentTimeMillis();
|
||||
// ignore shake events too close to each other (500ms)
|
||||
if (mShakeTimestamp + SHAKE_SLOP_TIME_MS > now) {
|
||||
return;
|
||||
}
|
||||
|
||||
// reset the shake count after 3 seconds of no shakes
|
||||
if (mShakeTimestamp + SHAKE_COUNT_RESET_TIME_MS < now) {
|
||||
mShakeCount = 0;
|
||||
}
|
||||
|
||||
mShakeTimestamp = now;
|
||||
mShakeCount++;
|
||||
|
||||
mListener.onShake(mShakeCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnShakeListener {
|
||||
void onShake(int count);
|
||||
}
|
||||
}
|
||||
@@ -37,6 +37,7 @@ import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.hippo.ehviewer.R;
|
||||
|
||||
/**
|
||||
@@ -254,7 +255,7 @@ public abstract class DialogPreference extends Preference implements
|
||||
|
||||
mWhichButtonClicked = DialogInterface.BUTTON_NEGATIVE;
|
||||
|
||||
mBuilder = new AlertDialog.Builder(context)
|
||||
mBuilder = new MaterialAlertDialogBuilder(context)
|
||||
.setTitle(mDialogTitle)
|
||||
.setIcon(mDialogIcon)
|
||||
.setPositiveButton(mPositiveButtonText, this)
|
||||
|
||||
@@ -36,7 +36,6 @@ public final class ReadableTime {
|
||||
public static final long DAY_MILLIS = 24 * HOUR_MILLIS;
|
||||
public static final long WEEK_MILLIS = 7 * DAY_MILLIS;
|
||||
public static final long YEAR_MILLIS = 365 * DAY_MILLIS;
|
||||
public static final int SIZE = 5;
|
||||
public static final long[] MULTIPLES = {
|
||||
YEAR_MILLIS,
|
||||
DAY_MILLIS,
|
||||
@@ -44,6 +43,7 @@ public final class ReadableTime {
|
||||
MINUTE_MILLIS,
|
||||
SECOND_MILLIS
|
||||
};
|
||||
public static final int SIZE = 5;
|
||||
public static final int[] UNITS = {
|
||||
R.plurals.year,
|
||||
R.plurals.day,
|
||||
|
||||
@@ -26,12 +26,9 @@ public class ViewTransition {
|
||||
protected static final long ANIMATE_TIME = 300L;
|
||||
|
||||
private final View[] mViews;
|
||||
|
||||
private int mShownView = -1;
|
||||
|
||||
protected ViewPropertyAnimator mAnimator1;
|
||||
protected ViewPropertyAnimator mAnimator2;
|
||||
|
||||
private int mShownView = -1;
|
||||
private OnShowViewListener mOnShowViewListener;
|
||||
|
||||
public ViewTransition(View... views) {
|
||||
|
||||
@@ -167,8 +167,8 @@ public class AutoWrapLayout extends ViewGroup {
|
||||
// If it is first item in line, try to show it all
|
||||
if (lineEndIndex == lineStartIndex) {
|
||||
child.measure(MeasureSpec.makeMeasureSpec(
|
||||
maxWidth - paddingLeft - paddingRight
|
||||
- lp.leftMargin - lp.rightMargin, MeasureSpec.AT_MOST),
|
||||
maxWidth - paddingLeft - paddingRight
|
||||
- lp.leftMargin - lp.rightMargin, MeasureSpec.AT_MOST),
|
||||
MeasureSpec.UNSPECIFIED);
|
||||
childWidth = child.getMeasuredWidth();
|
||||
childHeight = child.getMeasuredHeight();
|
||||
|
||||
@@ -41,7 +41,7 @@ public class BatteryView extends AppCompatTextView {
|
||||
private boolean mCharging = false;
|
||||
|
||||
private BatteryDrawable mDrawable;
|
||||
private final Runnable mCharger = new Runnable() {
|
||||
private boolean mAttached = false; private final Runnable mCharger = new Runnable() {
|
||||
|
||||
private int level = 0;
|
||||
|
||||
@@ -55,9 +55,14 @@ public class BatteryView extends AppCompatTextView {
|
||||
getHandler().postDelayed(mCharger, 200);
|
||||
}
|
||||
};
|
||||
private boolean mAttached = false;
|
||||
private boolean mIsChargerWorking = false;
|
||||
private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
|
||||
public BatteryView(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
public BatteryView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
} private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
|
||||
|
||||
@Override
|
||||
@SuppressLint("SetTextI18n")
|
||||
@@ -88,15 +93,6 @@ public class BatteryView extends AppCompatTextView {
|
||||
}
|
||||
};
|
||||
|
||||
public BatteryView(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public BatteryView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public BatteryView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
|
||||
@@ -173,4 +169,8 @@ public class BatteryView extends AppCompatTextView {
|
||||
private void unregisterReceiver() {
|
||||
getContext().unregisterReceiver(mIntentReceiver);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -33,17 +33,12 @@ import com.hippo.ehviewer.R;
|
||||
|
||||
public class CheckTextView extends AppCompatCheckedTextView implements View.OnClickListener {
|
||||
|
||||
private Drawable mForeground;
|
||||
|
||||
private final Rect mSelfBounds = new Rect();
|
||||
|
||||
private final Rect mOverlayBounds = new Rect();
|
||||
|
||||
private int mForegroundGravity = Gravity.FILL;
|
||||
|
||||
protected boolean mForegroundInPadding = true;
|
||||
|
||||
boolean mForegroundBoundsChanged = false;
|
||||
private Drawable mForeground;
|
||||
private int mForegroundGravity = Gravity.FILL;
|
||||
|
||||
public CheckTextView(Context context) {
|
||||
this(context, null);
|
||||
@@ -136,6 +131,16 @@ public class CheckTextView extends AppCompatCheckedTextView implements View.OnCl
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the drawable used as the foreground of this FrameLayout. The
|
||||
* foreground drawable, if non-null, is always drawn on top of the children.
|
||||
*
|
||||
* @return A Drawable or null if no foreground was set.
|
||||
*/
|
||||
public Drawable getForeground() {
|
||||
return mForeground;
|
||||
}
|
||||
|
||||
/**
|
||||
* Supply a Drawable that is to be rendered on top of all of the child
|
||||
* views in the frame layout. Any padding in the Drawable will be taken
|
||||
@@ -171,16 +176,6 @@ public class CheckTextView extends AppCompatCheckedTextView implements View.OnCl
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the drawable used as the foreground of this FrameLayout. The
|
||||
* foreground drawable, if non-null, is always drawn on top of the children.
|
||||
*
|
||||
* @return A Drawable or null if no foreground was set.
|
||||
*/
|
||||
public Drawable getForeground() {
|
||||
return mForeground;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
|
||||
@@ -56,7 +56,6 @@ import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import rikka.core.res.ResourcesKt;
|
||||
import rikka.recyclerview.RecyclerViewKt;
|
||||
|
||||
public class ContentLayout extends FrameLayout {
|
||||
@@ -106,7 +105,7 @@ public class ContentLayout extends FrameLayout {
|
||||
|
||||
mFastScroller.attachToRecyclerView(mRecyclerView);
|
||||
HandlerDrawable drawable = new HandlerDrawable();
|
||||
drawable.setColor(ResourcesKt.resolveColor(context.getTheme(), R.attr.widgetColorThemeAccent));
|
||||
drawable.setColor(com.google.android.material.R.color.material_dynamic_neutral100);
|
||||
mFastScroller.setHandlerDrawable(drawable);
|
||||
|
||||
mRefreshLayout.setColorSchemeResources(
|
||||
@@ -125,7 +124,7 @@ public class ContentLayout extends FrameLayout {
|
||||
resources.getColor(R.color.loading_indicator_orange));
|
||||
mBottomProgress.setIndeterminateAnimationType(LinearProgressIndicator.INDETERMINATE_ANIMATION_TYPE_CONTIGUOUS);
|
||||
|
||||
RecyclerViewKt.addEdgeSpacing(mRecyclerView, 4,4,4,4, TypedValue.COMPLEX_UNIT_DIP);
|
||||
RecyclerViewKt.addEdgeSpacing(mRecyclerView, 4, 4, 4, 4, TypedValue.COMPLEX_UNIT_DIP);
|
||||
RecyclerViewKt.fixEdgeEffect(mRecyclerView, false, true);
|
||||
|
||||
mRecyclerViewOriginBottom = mRecyclerView.getPaddingBottom();
|
||||
@@ -263,8 +262,6 @@ public class ContentLayout extends FrameLayout {
|
||||
private int mCurrentTaskId;
|
||||
private int mCurrentTaskType;
|
||||
private int mCurrentTaskPage;
|
||||
private int mNextPageScrollSize;
|
||||
private String mEmptyString = "No hint";
|
||||
private final SwipeRefreshLayout.OnRefreshListener mOnRefreshListener = new SwipeRefreshLayout.OnRefreshListener() {
|
||||
@Override
|
||||
public void onRefresh() {
|
||||
@@ -278,6 +275,8 @@ public class ContentLayout extends FrameLayout {
|
||||
}
|
||||
}
|
||||
};
|
||||
private int mNextPageScrollSize;
|
||||
private String mEmptyString = "No hint";
|
||||
private final RecyclerView.OnScrollListener mOnScrollListener = new RecyclerView.OnScrollListener() {
|
||||
@Override
|
||||
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
|
||||
|
||||
@@ -134,10 +134,8 @@ public class Slider extends View {
|
||||
setProgress(a.getInteger(R.styleable.Slider_slider_progress, 0));
|
||||
mThickness = a.getDimension(R.styleable.Slider_thickness, 2);
|
||||
mRadius = a.getDimension(R.styleable.Slider_radius, 6);
|
||||
setColor(a.getColor(R.styleable.Slider_color, Color.BLACK));
|
||||
|
||||
mBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
mBgPaint.setColor(a.getBoolean(R.styleable.Slider_dark, false) ? 0x4dffffff : 0x42000000);
|
||||
|
||||
a.recycle();
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ public class TextClock extends AppCompatTextView {
|
||||
private boolean mAttached;
|
||||
|
||||
private Calendar mTime;
|
||||
private final Runnable mTicker = new Runnable() {
|
||||
private String mTimeZone; private final Runnable mTicker = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
onTimeChanged();
|
||||
@@ -66,7 +66,16 @@ public class TextClock extends AppCompatTextView {
|
||||
getHandler().postAtTime(mTicker, next);
|
||||
}
|
||||
};
|
||||
private final ContentObserver mFormatChangeObserver = new ContentObserver(new Handler()) {
|
||||
private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (mTimeZone == null && Intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
|
||||
final String timeZone = intent.getStringExtra("time-zone");
|
||||
createTime(timeZone);
|
||||
}
|
||||
onTimeChanged();
|
||||
}
|
||||
}; private final ContentObserver mFormatChangeObserver = new ContentObserver(new Handler()) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
chooseFormat();
|
||||
@@ -79,22 +88,9 @@ public class TextClock extends AppCompatTextView {
|
||||
onTimeChanged();
|
||||
}
|
||||
};
|
||||
private String mTimeZone;
|
||||
private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (mTimeZone == null && Intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
|
||||
final String timeZone = intent.getStringExtra("time-zone");
|
||||
createTime(timeZone);
|
||||
}
|
||||
onTimeChanged();
|
||||
}
|
||||
};
|
||||
|
||||
public TextClock(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public TextClock(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
@@ -261,4 +257,8 @@ public class TextClock extends AppCompatTextView {
|
||||
mTime.setTimeInMillis(System.currentTimeMillis());
|
||||
setText(DateFormat.format(mFormat, mTime));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -58,9 +58,6 @@ public class LockPatternView extends View {
|
||||
private static final int ASPECT_SQUARE = 0; // View will be the minimum of width/height
|
||||
private static final int ASPECT_LOCK_WIDTH = 1; // Fixed width; height will be minimum of (w,h)
|
||||
private static final int ASPECT_LOCK_HEIGHT = 2; // Fixed height; width will be minimum of (w,h)
|
||||
|
||||
private final Cell[][] mCells;
|
||||
|
||||
private static final boolean PROFILE_DRAWING = false;
|
||||
/**
|
||||
* How many milliseconds we spend animating each circle of a lock pattern
|
||||
@@ -73,6 +70,7 @@ public class LockPatternView extends View {
|
||||
* It didn't seem to have much impact on the devices tested, so currently set to 0.
|
||||
*/
|
||||
private static final float DRAG_THRESHOLD = 0.0f;
|
||||
private final Cell[][] mCells;
|
||||
private final CellState[][] mCellStates;
|
||||
private final int mDotSize;
|
||||
private final int mDotSizeActivated;
|
||||
@@ -181,6 +179,66 @@ public class LockPatternView extends View {
|
||||
mLinearOutSlowInInterpolator = new LinearOutSlowInInterpolator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the greatest common divisor of {@code a, b}. Returns {@code 0} if
|
||||
* {@code a == 0 && b == 0}.
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code a < 0} or {@code b < 0}
|
||||
*/
|
||||
private static int gcd(int a, int b) {
|
||||
|
||||
/*
|
||||
* The reason we require both arguments to be >= 0 is because otherwise, what do you return
|
||||
* on gcd(0, Integer.MIN_VALUE)? BigInteger.gcd would return positive 2^31, but positive
|
||||
* 2^31 isn't an int.
|
||||
*/
|
||||
//checkNonNegative("a", a);
|
||||
if (a < 0) {
|
||||
throw new IllegalArgumentException("a (" + a + ") must be >= 0");
|
||||
}
|
||||
//checkNonNegative("b", b);
|
||||
if (b < 0) {
|
||||
throw new IllegalArgumentException("b (" + b + ") must be >= 0");
|
||||
}
|
||||
|
||||
if (a == 0) {
|
||||
// 0 % b == 0, so b divides a, but the converse doesn't hold.
|
||||
// BigInteger.gcd is consistent with this decision.
|
||||
return b;
|
||||
} else if (b == 0) {
|
||||
return a; // similar logic
|
||||
}
|
||||
/*
|
||||
* Uses the binary GCD algorithm; see http://en.wikipedia.org/wiki/Binary_GCD_algorithm.
|
||||
* This is >40% faster than the Euclidean algorithm in benchmarks.
|
||||
*/
|
||||
int aTwos = Integer.numberOfTrailingZeros(a);
|
||||
a >>= aTwos; // divide out all 2s
|
||||
int bTwos = Integer.numberOfTrailingZeros(b);
|
||||
b >>= bTwos; // divide out all 2s
|
||||
while (a != b) { // both a, b are odd
|
||||
|
||||
// The key to the binary GCD algorithm is as follows:
|
||||
// Both a and b are odd. Assume a > b; then gcd(a - b, b) = gcd(a, b).
|
||||
// But in gcd(a - b, b), a - b is even and b is odd, so we can divide out powers of two.
|
||||
|
||||
// We bend over backwards to avoid branching, adapting a technique from
|
||||
// http://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax
|
||||
|
||||
int delta = a - b; // can't overflow, since a and b are nonnegative
|
||||
|
||||
int minDeltaOrZero = delta & (delta >> (Integer.SIZE - 1));
|
||||
// equivalent to Math.min(delta, 0)
|
||||
|
||||
a = delta - minDeltaOrZero - minDeltaOrZero; // sets a to Math.abs(a - b)
|
||||
// a is now nonnegative and even
|
||||
|
||||
b += minDeltaOrZero; // sets b to min(old a, b)
|
||||
a >>= Integer.numberOfTrailingZeros(a); // divide out all 2s, since 2 doesn't divide b
|
||||
}
|
||||
return a << Math.min(aTwos, bTwos);
|
||||
}
|
||||
|
||||
public int getCellSize() {
|
||||
return mPattern.size();
|
||||
}
|
||||
@@ -333,6 +391,9 @@ public class LockPatternView extends View {
|
||||
setMeasuredDimension(viewWidth, viewHeight);
|
||||
}
|
||||
|
||||
// From
|
||||
// https://github.com/google/guava/blob/c462d69329709f72a17a64cb229d15e76e72199c/guava/src/com/google/common/math/IntMath.java
|
||||
|
||||
/**
|
||||
* Determines whether the point x, y will add a new point to the current
|
||||
* pattern (in addition to finding the cell, also makes heuristic choices
|
||||
@@ -376,69 +437,6 @@ public class LockPatternView extends View {
|
||||
return null;
|
||||
}
|
||||
|
||||
// From
|
||||
// https://github.com/google/guava/blob/c462d69329709f72a17a64cb229d15e76e72199c/guava/src/com/google/common/math/IntMath.java
|
||||
|
||||
/**
|
||||
* Returns the greatest common divisor of {@code a, b}. Returns {@code 0} if
|
||||
* {@code a == 0 && b == 0}.
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code a < 0} or {@code b < 0}
|
||||
*/
|
||||
private static int gcd(int a, int b) {
|
||||
|
||||
/*
|
||||
* The reason we require both arguments to be >= 0 is because otherwise, what do you return
|
||||
* on gcd(0, Integer.MIN_VALUE)? BigInteger.gcd would return positive 2^31, but positive
|
||||
* 2^31 isn't an int.
|
||||
*/
|
||||
//checkNonNegative("a", a);
|
||||
if (a < 0) {
|
||||
throw new IllegalArgumentException("a (" + a + ") must be >= 0");
|
||||
}
|
||||
//checkNonNegative("b", b);
|
||||
if (b < 0) {
|
||||
throw new IllegalArgumentException("b (" + b + ") must be >= 0");
|
||||
}
|
||||
|
||||
if (a == 0) {
|
||||
// 0 % b == 0, so b divides a, but the converse doesn't hold.
|
||||
// BigInteger.gcd is consistent with this decision.
|
||||
return b;
|
||||
} else if (b == 0) {
|
||||
return a; // similar logic
|
||||
}
|
||||
/*
|
||||
* Uses the binary GCD algorithm; see http://en.wikipedia.org/wiki/Binary_GCD_algorithm.
|
||||
* This is >40% faster than the Euclidean algorithm in benchmarks.
|
||||
*/
|
||||
int aTwos = Integer.numberOfTrailingZeros(a);
|
||||
a >>= aTwos; // divide out all 2s
|
||||
int bTwos = Integer.numberOfTrailingZeros(b);
|
||||
b >>= bTwos; // divide out all 2s
|
||||
while (a != b) { // both a, b are odd
|
||||
|
||||
// The key to the binary GCD algorithm is as follows:
|
||||
// Both a and b are odd. Assume a > b; then gcd(a - b, b) = gcd(a, b).
|
||||
// But in gcd(a - b, b), a - b is even and b is odd, so we can divide out powers of two.
|
||||
|
||||
// We bend over backwards to avoid branching, adapting a technique from
|
||||
// http://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax
|
||||
|
||||
int delta = a - b; // can't overflow, since a and b are nonnegative
|
||||
|
||||
int minDeltaOrZero = delta & (delta >> (Integer.SIZE - 1));
|
||||
// equivalent to Math.min(delta, 0)
|
||||
|
||||
a = delta - minDeltaOrZero - minDeltaOrZero; // sets a to Math.abs(a - b)
|
||||
// a is now nonnegative and even
|
||||
|
||||
b += minDeltaOrZero; // sets b to min(old a, b)
|
||||
a >>= Integer.numberOfTrailingZeros(a); // divide out all 2s, since 2 doesn't divide b
|
||||
}
|
||||
return a << Math.min(aTwos, bTwos);
|
||||
}
|
||||
|
||||
private void addCellToPattern(Cell newCell) {
|
||||
mPatternDrawLookup[newCell.getRow()][newCell.getColumn()] = true;
|
||||
mPattern.add(newCell);
|
||||
@@ -1040,14 +1038,14 @@ public class LockPatternView extends View {
|
||||
}
|
||||
|
||||
public static class CellState {
|
||||
public float lineEndX = Float.MIN_VALUE;
|
||||
public float lineEndY = Float.MIN_VALUE;
|
||||
public ValueAnimator lineAnimator;
|
||||
int row;
|
||||
int col;
|
||||
float radius;
|
||||
float translationY;
|
||||
float alpha = 1f;
|
||||
public float lineEndX = Float.MIN_VALUE;
|
||||
public float lineEndY = Float.MIN_VALUE;
|
||||
public ValueAnimator lineAnimator;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright 2018 Hippo Seven
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:color="@color/primary_text_disabled_material_black" android:state_enabled="false" />
|
||||
<item android:color="@color/primary_text_default_material_black" />
|
||||
</selector>
|
||||
@@ -17,9 +17,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="120dp"
|
||||
android:height="120dp"
|
||||
android:tint="?drawableColorSecondary"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?drawableColorSecondary">
|
||||
android:viewportHeight="24">
|
||||
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="120dp"
|
||||
android:height="120dp"
|
||||
android:tint="?drawableColorSecondary"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?drawableColorSecondary">
|
||||
android:viewportHeight="24">
|
||||
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="120dp"
|
||||
android:height="120dp"
|
||||
android:tint="?drawableColorSecondary"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?drawableColorSecondary">
|
||||
android:viewportHeight="24">
|
||||
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="120dp"
|
||||
android:height="120dp"
|
||||
android:tint="?drawableColorSecondary"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?drawableColorSecondary">
|
||||
android:viewportHeight="24">
|
||||
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<color android:color="@android:color/white" />
|
||||
<color android:color="@android:color/system_neutral1_50" />
|
||||
</item>
|
||||
<item android:drawable="?android:attr/selectableItemBackground" />
|
||||
</layer-list>
|
||||
@@ -1,23 +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.
|
||||
-->
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<solid android:color="@color/divider" />
|
||||
|
||||
<size android:height="1dp" />
|
||||
|
||||
</shape>
|
||||
@@ -1,23 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright 2018 Hippo Seven
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<solid android:color="@color/divider_black" />
|
||||
|
||||
<size android:height="1dp" />
|
||||
|
||||
</shape>
|
||||
@@ -1,10 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12,3c-4.97,0 -9,4.03 -9,9s4.03,9 9,9s9,-4.03 9,-9c0,-0.46 -0.04,-0.92 -0.1,-1.36c-0.98,1.37 -2.58,2.26 -4.4,2.26c-2.98,0 -5.4,-2.42 -5.4,-5.4c0,-1.81 0.89,-3.42 2.26,-4.4C12.92,3.04 12.46,3 12,3L12,3z"/>
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12,3c-4.97,0 -9,4.03 -9,9s4.03,9 9,9s9,-4.03 9,-9c0,-0.46 -0.04,-0.92 -0.1,-1.36c-0.98,1.37 -2.58,2.26 -4.4,2.26c-2.98,0 -5.4,-2.42 -5.4,-5.4c0,-1.81 0.89,-3.42 2.26,-4.4C12.92,3.04 12.46,3 12,3L12,3z" />
|
||||
</vector>
|
||||
@@ -1,9 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M2,17h2v0.5L3,17.5v1h1v0.5L2,19v1h3v-4L2,16v1zM3,8h1L4,4L2,4v1h1v3zM2,11h1.8L2,13.1v0.9h3v-1L3.2,13L5,10.9L5,10L2,10v1zM7,5v2h14L21,5L7,5zM7,19h14v-2L7,17v2zM7,13h14v-2L7,11v2z" />
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M17.63,5.84C17.27,5.33 16.67,5 16,5L5,5.01C3.9,5.01 3,5.9 3,7v10c0,1.1 0.9,1.99 2,1.99L16,19c0.67,0 1.27,-0.33 1.63,-0.84L22,12l-4.37,-6.16z" />
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M3,18h18v-2L3,16v2zM3,13h18v-2L3,11v2zM3,6v2h18L21,6L3,6z"/>
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M3,18h18v-2L3,16v2zM3,13h18v-2L3,11v2zM3,6v2h18L21,6L3,6z" />
|
||||
</vector>
|
||||
@@ -1,9 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M3,15h18v-2L3,13v2zM3,19h18v-2L3,17v2zM3,11h18L21,9L3,9v2zM3,5v2h18L21,5L3,5z" />
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M1,21h22L12,2 1,21zM13,18h-2v-2h2v2zM13,14h-2v-4h2v4z" />
|
||||
|
||||
@@ -9,12 +9,12 @@
|
||||
android:translateX="35.1"
|
||||
android:translateY="39.584126">
|
||||
<path
|
||||
android:pathData="M39.893,68.066L39.893,75.977L0,75.977L0,4.59L39.893,4.59L39.893,12.5L8.984,12.5L8.984,34.766L38.086,34.766L38.086,42.578L8.984,42.578L8.984,68.066L39.893,68.066Z"
|
||||
android:fillColor="@color/ic_launcher_foreground"
|
||||
android:fillType="evenOdd" />
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M39.893,68.066L39.893,75.977L0,75.977L0,4.59L39.893,4.59L39.893,12.5L8.984,12.5L8.984,34.766L38.086,34.766L38.086,42.578L8.984,42.578L8.984,68.066L39.893,68.066Z" />
|
||||
<path
|
||||
android:pathData="M99.609,75.977L90.918,75.977L90.918,41.699A23.436,23.436 0,0 0,90.662 38.109Q90.055,34.207 88.013,31.958Q85.629,29.334 81.028,28.863A20.84,20.84 0,0 0,78.906 28.76A23.134,23.134 0,0 0,74.45 29.16Q71.926,29.656 69.994,30.767A11.122,11.122 0,0 0,66.968 33.301A13.32,13.32 0,0 0,64.756 37.276Q63.399,40.971 63.213,46.495A53.517,53.517 0,0 0,63.184 48.291L63.184,75.977L54.395,75.977L54.395,0L63.184,0L63.184,22.266A66.935,66.935 0,0 1,63.115 25.383Q63.043,26.914 62.897,28.251A33.547,33.547 0,0 1,62.695 29.785L63.281,29.785A16.11,16.11 0,0 1,69.394 24.035A19.448,19.448 0,0 1,70.068 23.682A20.88,20.88 0,0 1,77.292 21.622A25.763,25.763 0,0 1,79.98 21.484A32.643,32.643 0,0 1,85.483 21.917Q91.249,22.905 94.678,26.147Q98.472,29.735 99.347,36.631A35.274,35.274 0,0 1,99.609 41.064L99.609,75.977Z"
|
||||
android:fillColor="@color/ic_launcher_foreground"
|
||||
android:fillType="evenOdd" />
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M99.609,75.977L90.918,75.977L90.918,41.699A23.436,23.436 0,0 0,90.662 38.109Q90.055,34.207 88.013,31.958Q85.629,29.334 81.028,28.863A20.84,20.84 0,0 0,78.906 28.76A23.134,23.134 0,0 0,74.45 29.16Q71.926,29.656 69.994,30.767A11.122,11.122 0,0 0,66.968 33.301A13.32,13.32 0,0 0,64.756 37.276Q63.399,40.971 63.213,46.495A53.517,53.517 0,0 0,63.184 48.291L63.184,75.977L54.395,75.977L54.395,0L63.184,0L63.184,22.266A66.935,66.935 0,0 1,63.115 25.383Q63.043,26.914 62.897,28.251A33.547,33.547 0,0 1,62.695 29.785L63.281,29.785A16.11,16.11 0,0 1,69.394 24.035A19.448,19.448 0,0 1,70.068 23.682A20.88,20.88 0,0 1,77.292 21.622A25.763,25.763 0,0 1,79.98 21.484A32.643,32.643 0,0 1,85.483 21.917Q91.249,22.905 94.678,26.147Q98.472,29.735 99.347,36.631A35.274,35.274 0,0 1,99.609 41.064L99.609,75.977Z" />
|
||||
</group>
|
||||
</vector>
|
||||
@@ -17,9 +17,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="48dp"
|
||||
android:height="48dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="@string/pd_file_image" />
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?drawableColorThemePrimary"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?drawableColorThemePrimary">
|
||||
android:viewportHeight="24">
|
||||
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="48dp"
|
||||
android:height="48dp"
|
||||
android:tint="@color/red_500"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="@color/red_500">
|
||||
android:viewportHeight="24">
|
||||
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="48dp"
|
||||
android:height="48dp"
|
||||
android:tint="?drawableColorThemePrimary"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0"
|
||||
android:tint="?drawableColorThemePrimary">
|
||||
android:viewportHeight="24.0">
|
||||
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?colorControlNormal">
|
||||
android:viewportHeight="24">
|
||||
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?drawableColorThemePrimary"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?drawableColorThemePrimary">
|
||||
android:viewportHeight="24">
|
||||
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="@string/pd_book_open" />
|
||||
|
||||
@@ -1,28 +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.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="48dp"
|
||||
android:height="48dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?colorAccent">
|
||||
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="@string/pd_chart" />
|
||||
|
||||
</vector>
|
||||
@@ -17,9 +17,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="@string/pd_check_all" />
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="@string/pd_check" />
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="@string/pd_clear_all" />
|
||||
|
||||
Loaded 100 of 231 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user