This commit is contained in:
seven332 committed 2016-01-24 00:17:57 +08:00
commit 52209017a3
198 files changed
+25167

No files matched your search

+8
View File
@@ -0,0 +1,8 @@
.gradle
/local.properties
.DS_Store
/build
/src
*.iml
.idea
/captures
+27
View File
@@ -0,0 +1,27 @@
[submodule "yorozuya"]
path = yorozuya
url = https://github.com/seven332/Yorozuya
[submodule "hotspot"]
path = hotspot
url = https://github.com/seven332/Hotspot
[submodule "vector"]
path = vector
url = https://github.com/seven332/Vector
[submodule "anani"]
path = anani
url = https://github.com/seven332/Anani
[submodule "easyrecyclerview"]
path = easyrecyclerview
url = https://github.com/seven332/EasyRecyclerView
[submodule "beerbelly"]
path = beerbelly
url = https://github.com/seven332/BeerBelly
[submodule "conaco"]
path = conaco
url = https://github.com/seven332/Conaco
[submodule "rippleold"]
path = rippleold
url = https://github.com/seven332/RippleOld
[submodule "unifile"]
path = unifile
url = https://github.com/seven332/UniFile
Submodule
+1
Submodule anani added at 07fd88b420.
+8
View File
@@ -0,0 +1,8 @@
/build
/src/main/java-gen
manifest-merger-release-report.txt
/src/main/libs
/src/main/obj
# Intellij
*.iml
+51
View File
@@ -0,0 +1,51 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig {
applicationId "com.hippo.ehviewer"
minSdkVersion 15
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
sourceSets {
main {
java.srcDirs = ['src/main/java', 'src/main/java-gen']
// Disable default NdkCompile task
jni.srcDirs = []
// Set new jni lib dir
jniLibs.srcDir 'src/main/libs'
}
}
}
dependencies {
compile project(':anani')
compile project(':beerbelly')
compile project(':conaco')
compile project(':easyrecyclerview')
compile project(':hotspot')
compile project(':okhttp3')
compile project(':rippleold')
compile project(':unifile')
compile project(':vector')
compile project(':yorozuya')
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.1.1'
compile 'com.android.support:cardview-v7:23.1.1'
compile 'com.android.support:customtabs:23.1.1'
compile 'com.android.support:design:23.1.1'
compile 'de.greenrobot:greendao:2.0.0'
}
+17
View File
@@ -0,0 +1,17 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in E:\Android\android-sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
@@ -0,0 +1,13 @@
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);
}
}
@@ -0,0 +1,53 @@
/*
* 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 com.hippo.okhttp.CookieDB;
import junit.framework.Assert;
import junit.framework.TestCase;
public class CookieDBTest extends TestCase {
private static final String[] TEST_DOMAIN = {
null,
"",
"asdfghjkl",
"asdfghjkl.sds",
"asdfghjkl.sds.sddddd",
"asdfghjkl.sds.sddddd.aaaaa",
"asdfghjkl.sds.sddddd.",
"asdfghjkl.sds..",
};
private static final String[] TEST_COOKIES_DOMAIN = {
"",
"",
"asdfghjkl",
"asdfghjkl.sds",
"sds.sddddd",
"sddddd.aaaaa",
"sddddd.",
".",
};
public void testCookiesDomain() {
for (int i = 0; i < TEST_DOMAIN.length; i++) {
Assert.assertEquals(TEST_COOKIES_DOMAIN[i], CookieDB.cookiesDomain(TEST_DOMAIN[i]));
}
}
}
+49
View File
@@ -0,0 +1,49 @@
<?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.
-->
<manifest
package="com.hippo.ehviewer"
xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:name="com.hippo.ehviewer.EhApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme">
<activity
android:name="com.hippo.ehviewer.ui.MainActivity"
android:configChanges="screenSize|uiMode"
android:screenOrientation="unspecified"
android:theme="@style/AppTheme.Main">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
</application>
</manifest>
@@ -0,0 +1,77 @@
/*
* 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 android.content.Context;
import android.support.annotation.NonNull;
import com.hippo.ehviewer.client.EhClient;
import com.hippo.ehviewer.client.EhCookieStore;
import com.hippo.network.StatusCodeException;
import com.hippo.okhttp.CookieDB;
import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
public class EhApplication extends Application {
private EhCookieStore mEhCookieStore;
private EhClient mEhClient;
private OkHttpClient mOkHttpClient;
@Override
public void onCreate() {
super.onCreate();
GetText.initialize(this);
CookieDB.initialize(this);
StatusCodeException.initialize(this);
Settings.initialize(this);
}
public static EhCookieStore getEhCookieStore(@NonNull Context context) {
EhApplication application = ((EhApplication) context.getApplicationContext());
if (application.mEhCookieStore == null) {
application.mEhCookieStore = new EhCookieStore();
}
return application.mEhCookieStore;
}
@NonNull
public static EhClient getEhClient(@NonNull Context context) {
EhApplication application = ((EhApplication) context.getApplicationContext());
if (application.mEhClient == null) {
application.mEhClient = new EhClient(application);
}
return application.mEhClient;
}
public static OkHttpClient getOkHttpClient(@NonNull Context context) {
EhApplication application = ((EhApplication) context.getApplicationContext());
if (application.mOkHttpClient == null) {
application.mOkHttpClient = new OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(15, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
.cookieJar(getEhCookieStore(application))
.build();
}
return application.mOkHttpClient;
}
}
@@ -0,0 +1,41 @@
/*
* 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.content.Context;
import android.content.res.Resources;
import android.support.annotation.NonNull;
import android.support.annotation.StringRes;
public class GetText {
private static Resources sResources;
public static void initialize(Context context) {
sResources = context.getApplicationContext().getResources();
}
@NonNull
public static String getString(@StringRes int id) {
return sResources.getString(id);
}
@NonNull
public static String getString(@StringRes int id, Object... formatArgs) {
return sResources.getString(id, formatArgs);
}
}
@@ -0,0 +1,104 @@
/*
* 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.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import com.hippo.yorozuya.NumberUtils;
public class Settings {
private static Context sContext;
private static SharedPreferences sSettingsPre;
public static void initialize(Context context) {
sContext = context.getApplicationContext();
sSettingsPre = PreferenceManager.getDefaultSharedPreferences(sContext);
}
public static boolean getBoolean(String key, boolean defValue) {
return sSettingsPre.getBoolean(key, defValue);
}
public static void putBoolean(String key, boolean value) {
sSettingsPre.edit().putBoolean(key, value).apply();
}
public static int getInt(String key, int defValue) {
return sSettingsPre.getInt(key, defValue);
}
public static void putInt(String key, int value) {
sSettingsPre.edit().putInt(key, value).apply();
}
public static long getLong(String key, long defValue) {
return sSettingsPre.getLong(key, defValue);
}
public static void putLong(String key, long value) {
sSettingsPre.edit().putLong(key, value).apply();
}
public static float getFloat(String key, float defValue) {
return sSettingsPre.getFloat(key, defValue);
}
public static void putFloat(String key, float value) {
sSettingsPre.edit().putFloat(key, value).apply();
}
public static String getString(String key, String defValue) {
return sSettingsPre.getString(key, defValue);
}
public static void putString(String key, String value) {
sSettingsPre.edit().putString(key, value).apply();
}
public static int getIntFromStr(String key, int defValue) {
return NumberUtils.parseIntSafely(sSettingsPre.getString(key, Integer.toString(defValue)), defValue);
}
public static void putIntToStr(String key, int value) {
sSettingsPre.edit().putString(key, Integer.toString(value)).apply();
}
private static final String KEY_DISPLAY_NAME = "display_name";
private static final String DEFAULT_DISPLAY_NAME = null;
public static String getDisplayName() {
return getString(KEY_DISPLAY_NAME, DEFAULT_DISPLAY_NAME);
}
public static void putDisplayName(String value) {
putString(KEY_DISPLAY_NAME, value);
}
private static final String KEY_SHOW_WARNING = "show_warning";
private static final boolean DEFAULT_SHOW_WARNING = true;
public static boolean getShowWarning() {
return getBoolean(KEY_SHOW_WARNING, DEFAULT_SHOW_WARNING);
}
public static void putShowWarning(boolean value) {
putBoolean(KEY_SHOW_WARNING, value);
}
}
@@ -0,0 +1,24 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.client;
public class CancelledException extends Exception {
public CancelledException() {
super("CANCELED");
}
}
@@ -0,0 +1,160 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.client;
import android.content.Context;
import android.os.AsyncTask;
import com.hippo.ehviewer.EhApplication;
import com.hippo.yorozuya.PriorityThreadFactory;
import com.hippo.yorozuya.SimpleHandler;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import okhttp3.Call;
import okhttp3.OkHttpClient;
public class EhClient {
public static final String TAG = EhClient.class.getSimpleName();
public static final int METHOD_SIGN_IN = 0;
private final ThreadPoolExecutor mRequestThreadPool;
private final OkHttpClient mOkHttpClient;
public EhClient(Context context) {
int poolSize = 3;
BlockingQueue<Runnable> requestWorkQueue = new LinkedBlockingQueue<>();
ThreadFactory threadFactory = new PriorityThreadFactory(TAG,
android.os.Process.THREAD_PRIORITY_BACKGROUND);
mRequestThreadPool = new ThreadPoolExecutor(poolSize, poolSize,
1L, TimeUnit.SECONDS, requestWorkQueue, threadFactory);
mOkHttpClient = EhApplication.getOkHttpClient(context);
}
public void execute(EhRequest request) {
if (!request.isCancelled()) {
Task task = new Task(request.method, request.callback);
task.executeOnExecutor(mRequestThreadPool, request.args);
request.task = task;
} else {
request.callback.onCancel();
}
}
public class Task extends AsyncTask<Object, Void, Object> {
private int mMethod;
private Callback mCallback;
private Call mCall;
private boolean mStop;
public Task(int method, Callback callback) {
mMethod = method;
mCallback = callback;
}
public void stop() {
if (!mStop) {
mStop = true;
if (mCallback != null) {
final Callback finalCallback = mCallback;
SimpleHandler.getInstance().post(new Runnable() {
@Override
public void run() {
finalCallback.onCancel();
}
});
}
Status status = getStatus();
if (status == Status.PENDING) {
cancel(false);
} else if (status == Status.RUNNING) {
if (mCall != null) {
mCall.cancel();
}
}
// Clear
mCall = null;
mCallback = null;
}
}
private Object signIn(Object... params) throws Exception {
Call call = EhEngine.prepareSignIn(mOkHttpClient, (String) params[0], (String) params[1]);
if (!mStop) {
mCall = call;
return EhEngine.doSignIn(call);
} else {
throw new CancelledException();
}
}
@Override
protected Object doInBackground(Object... params) {
try {
switch (mMethod) {
case METHOD_SIGN_IN:
return signIn(params);
default:
return new IllegalStateException("Can't detect method " + mMethod);
}
} catch (Exception e) {
return e;
}
}
@SuppressWarnings("unchecked")
@Override
protected void onPostExecute(Object result) {
if (mCallback != null) {
//noinspection StatementWithEmptyBody
if (!(result instanceof CancelledException)) {
if (result instanceof Exception) {
mCallback.onFailure((Exception) result);
} else {
mCallback.onSuccess(result);
}
} else {
// onCancel is called in stop
}
}
// Clear
mCall = null;
mCallback = null;
}
}
public interface Callback<E> {
void onSuccess(E result);
void onFailure(Exception e);
void onCancel();
}
}
@@ -0,0 +1,665 @@
/*
* Copyright 2015 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.client;
import android.text.TextUtils;
/**
* Some configurable stuff about EH. It ends up cookie.
*/
public class EhConfig implements Cloneable {
/**
* The Cookie key of uconfig
*/
public static final String KEY_UCONFIG = "uconfig";
/**
* The key of load images through the Hentai@Home Network
*/
private static final String KEY_LOAD_FROM_HAH = "uh";
/**
* The key of scale images width
*/
private static final String KEY_SCALE_WIDTH = "rx";
/**
* The key of scale images height
*/
private static final String KEY_SCALE_HEIGHT = "ry";
/**
* The key of the behavior for downloading archiver
*/
private static final String KEY_ARCHIVER_DOWNLOAD = "ar";
/**
* The key of display mode would you like to use on the front and search pages
*/
private static final String KEY_LAYOUT_MODE = "dm";
/**
* The key of categories would you like to view as default on the front page
*/
private static final String KEY_DEFAULT_CATEGORIES = "cats";
/**
* The key of exclude certain namespaces from a default tag search
*/
private static final String KEY_EXCLUDED_NAMESPACES = "xns";
/**
* The key of hide galleries in certain languages from the gallery list and searches
*/
private static final String KEY_EXCLUDED_LANGUAGES = "xl";
/**
* The key of how many results would you like per page for the index/search page and torrent search pages
*/
private static final String KEY_RESULT_COUNT = "rc";
/**
* The key of mouse-over thumb
*/
private static final String KEY_MOUSE_OVER = "tl";
/**
* The key of preview size
*/
private static final String KEY_PREVIEW_SIZE = "ts";
/**
* The key of preview row per page
*/
private static final String KEY_PREVIEW_ROW = "tr";
/**
* The key of sort order for gallery comments
*/
private static final String KEY_COMMENTS_SORT = "cs";
/**
* The key of show gallery comment votes
*/
private static final String KEY_COMMENTS_VOTES = "sc";
/**
* The key of sort order for gallery tags
*/
private static final String KEY_TAGS_SORT = "to";
/**
* The key of show gallery page numbers
*/
private static final String KEY_SHOW_GALLERY_INDEX = "pn";
/**
* The key of the IP:Port of a proxy-enabled Hentai@Home Client
* to load all images
*/
private static final String KEY_HAH_CLIENT_IP_PORT = "hp";
/**
* The key of the passkey of a proxy-enabled Hentai@Home Client
* to load all images
*/
private static final String KEY_HAH_CLIENT_PASSKEY = "hk";
/**
* The key of enable Tag Flagging
*/
private static final String KEY_ENABLE_TAG_FLAGGING = "tf";
/**
* The key of always display the original images instead of the resampled versions
*/
private static final String KEY_ALWAYS_ORIGINAL = "oi";
/**
* The key of enable the multi-Page Viewer
*/
private static final String KEY_MULTI_PAGE = "qb";
/**
* The key of multi-Page Viewer Display Style
*/
private static final String KEY_MULTI_PAGE_STYLE = "ms";
/**
* The key of multi-Page Viewer Thumbnail Pane
*/
private static final String KEY_MULTI_PAGE_THUMB = "mt";
/**
* The Cookie key of lofi resolution
*/
public static final String KEY_LOFI_RESOLUTION = "xres";
/**
* The Cookie key of show warning
*/
public static final String KEY_CONTENT_WARNING = "nw";
/**
* load images through the Hentai@Home Network
*/
public static final String LOAD_FROM_HAH_YES = "y";
/**
* do not load images through the Hentai@Home Network
*/
public static final String LOAD_FROM_HAH_NO = "n";
/**
* Manual Accept, Manual Start
*/
public static final String ARCHIVER_DOWNLOAD_MAMS = "0";
/**
* >Manual Accept, Auto Start
*/
public static final String ARCHIVER_DOWNLOAD_AAMS = "1";
/**
* Auto Accept, Manual Start
*/
public static final String ARCHIVER_DOWNLOAD_MAAS = "2";
/**
* Auto Accept, Auto Start
*/
public static final String ARCHIVER_DOWNLOAD_AAAS = "3";
/**
* List View on the front and search pages
*/
public static final String LAYOUT_MODE_LIST = "l";
/**
* Thumbnail View on the front and search pages
*/
public static final String LAYOUT_MODE_THUMB = "t";
public static final int MISC = 0x1;
public static final int DOUJINSHI = 0x2;
public static final int MANGA = 0x4;
public static final int ARTIST_CG = 0x8;
public static final int GAME_CG = 0x10;
public static final int IMAGE_SET = 0x20;
public static final int COSPLAY = 0x40;
public static final int ASIAN_PORN = 0x80;
public static final int NON_H = 0x100;
public static final int WESTERN = 0x200;
public static final int NAMESPACES_RECLASS = 0x1;
public static final int NAMESPACES_LANGUAGE = 0x2;
public static final int NAMESPACES_PARODY = 0x4;
public static final int NAMESPACES_CHARACTER = 0x8;
public static final int NAMESPACES_GROUP = 0x10;
public static final int NAMESPACES_ARTIST = 0x20;
public static final int NAMESPACES_MALE = 0x40;
public static final int NAMESPACES_FEMALE = 0x80;
public static final String JAPANESE_TRANSLATED = "1024";
public static final String JAPANESE_REWRITE = "2048";
public static final String ENGLISH_ORIGINAL = "1";
public static final String ENGLISH_TRANSLATED = "1025";
public static final String ENGLISH_REWRITE = "2049";
public static final String CHINESE_ORIGINAL = "10";
public static final String CHINESE_TRANSLATED = "1034";
public static final String CHINESE_REWRITE = "2058";
public static final String DUTCH_ORIGINAL = "20";
public static final String DUTCH_TRANSLATED = "1044";
public static final String DUTCH_REWRITE = "2068";
public static final String FRENCH_ORIGINAL = "30";
public static final String FRENCH_TRANSLATED = "1054";
public static final String FRENCH_REWRITE = "2078";
public static final String GERMAN_ORIGINAL = "40";
public static final String GERMAN_TRANSLATED = "1064";
public static final String GERMAN_REWRITE = "2088";
public static final String HUNGARIAN_ORIGINAL = "50";
public static final String HUNGARIAN_TRANSLATED = "1074";
public static final String HUNGARIAN_REWRITE = "2098";
public static final String ITALIAN_ORIGINAL = "60";
public static final String ITALIAN_TRANSLATED = "1084";
public static final String ITALIAN_REWRITE = "2108";
public static final String KOREAN_ORIGINAL = "70";
public static final String KOREAN_TRANSLATED = "1094";
public static final String KOREAN_REWRITE = "2118";
public static final String POLISH_ORIGINAL = "80";
public static final String POLISH_TRANSLATED = "1104";
public static final String POLISH_REWRITE = "2128";
public static final String PORTUGUESE_ORIGINAL = "90";
public static final String PORTUGUESE_TRANSLATED = "1114";
public static final String PORTUGUESE_REWRITE = "2138";
public static final String RUSSIAN_ORIGINAL = "100";
public static final String RUSSIAN_TRANSLATED = "1124";
public static final String RUSSIAN_REWRITE = "2148";
public static final String SPANISH_ORIGINAL = "110";
public static final String SPANISH_TRANSLATED = "1134";
public static final String SPANISH_REWRITE = "2158";
public static final String THAI_ORIGINAL = "120";
public static final String THAI_TRANSLATED = "1144";
public static final String THAI_REWRITE = "2168";
public static final String VIETNAMESE_ORIGINAL = "130";
public static final String VIETNAMESE_TRANSLATED = "1154";
public static final String VIETNAMESE_REWRITE = "2178";
public static final String NA_ORIGINAL = "254";
public static final String NA_TRANSLATED = "1278";
public static final String NA_REWRITE = "2302";
public static final String OTHER_ORIGINAL = "255";
public static final String OTHER_TRANSLATED = "1279";
public static final String OTHER_REWRITE = "2303";
/**
* 25 results per page for the index/search page and torrent search pages
*/
public static final String RESULT_COUNT_25 = "0";
/**
* 50 results per page for the index/search page and torrent search pages
*/
public static final String RESULT_COUNT_50 = "1";
/**
* 100 results per page for the index/search page and torrent search pages
*/
public static final String RESULT_COUNT_100 = "2";
/**
* 200 results per page for the index/search page and torrent search pages
*/
public static final String RESULT_COUNT_200 = "3";
/**
* On mouse-over
*/
public static final String MOUSE_OVER_YES = "m";
/**
* On page load
*/
public static final String MOUSE_OVER_NO = "p";
/**
* Preview normal size
*/
public static final String PREVIEW_SIZE_NORMAL = "m";
/**
* Preview large size
*/
public static final String PREVIEW_SIZE_LARGE = "l";
/**
* 4 row preview per page
*/
public static final String PREVIEW_ROW_4 = "2";
/**
* 10 row preview per page
*/
public static final String PREVIEW_ROW_10 = "5";
/**
* 20 row preview per page
*/
public static final String PREVIEW_ROW_20 = "10";
/**
* 40 row preview per page
*/
public static final String PREVIEW_ROW_40 = "20";
/**
* Oldest comments first
*/
public static final String COMMENTS_SORT_OLDEST_FIRST = "a";
/**
* Recent comments first
*/
public static final String COMMENTS_SORT_RECENT_FIRST = "d";
/**
* By highest score
*/
public static final String COMMENTS_SORT_HIGHEST_SCORE_FIRST = "s";
/**
* Show gallery comment votes On score hover or click
*/
public static final String COMMENTS_VOTES_POP = "0";
/**
* Always show gallery comment votes
*/
public static final String COMMENTS_VOTES_ALWAYS = "1";
/**
* Sort order for gallery tags alphabetically
*/
public static final String TAGS_SORT_ALPHABETICAL = "a";
/**
* Sort order for gallery tags by tag power
*/
public static final String TAGS_SORT_POWER = "p";
/**
* Show gallery page numbers
*/
public static final String SHOW_GALLERY_INDEX_YES = "1";
/**
* Do not show gallery page numbers
*/
public static final String SHOW_GALLERY_INDEX_NO = "0";
/**
* Enable Tag Flagging
*/
public static final String ENABLE_TAG_FLAGGING_YES = "y";
/**
* Do not enable Tag Flagging
*/
public static final String ENABLE_TAG_FLAGGING_NO = "n";
/**
* Always display the original images
*/
public static final String ALWAYS_ORIGINAL_YES = "y";
/**
* Do not Always display the original images
*/
public static final String ALWAYS_ORIGINAL_NO = "n";
/**
* Enable the Multi-Page Viewe
*/
public static final String MULTI_PAGE_YES = "y";
/**
* Do not enable the Multi-Page Viewe
*/
public static final String MULTI_PAGE_NO = "n";
/**
* Align left, only scale if image is larger than browser width
*/
public static final String MULTI_PAGE_STYLE_N = "n";
/**
* Align center, only scale if image is larger than browser width
*/
public static final String MULTI_PAGE_STYLE_C = "c";
/**
* Align center, Always scale images to fit browser width
*/
public static final String MULTI_PAGE_STYLE_Y = "y";
/**
* Show Multi-Page Viewer Thumbnail Pane
*/
public static final String MULTI_PAGE_THUMB_SHOW = "n";
/**
* Hide Multi-Page Viewer Thumbnail Pane
*/
public static final String MULTI_PAGE_THUMB_HIDE = "y";
/**
* 460x for lofi resolution
*/
public static final String LOFI_RESOLUTION_460X = "1";
/**
* 780X for lofi resolution
*/
public static final String LOFI_RESOLUTION_780X = "2";
/**
* 980X for lofi resolution
*/
public static final String LOFI_RESOLUTION_980X = "3";
/**
* show warning
*/
private static final String CONTENT_WARNING_SHOW = "0";
/**
* not show warning
*/
private static final String CONTENT_WARNING_NOT_SHOW = "1";
/**
* Load images through the Hentai@Home Network<br/>
* key: {@link #KEY_LOAD_FROM_HAH}<br/>
* value: {@link #LOAD_FROM_HAH_YES}, {@link #LOAD_FROM_HAH_NO}
*/
public String loadFromHAH = LOAD_FROM_HAH_YES;
/**
* Scale width<br/>
* key: {@link #KEY_SCALE_WIDTH}<br/>
* value: 0 for no limit
*/
public int scaleWidth = 0;
/**
* Scale height<br/>
* key: {@link #KEY_SCALE_HEIGHT}<br/>
* value: 0 for no limit
*/
public int scaleHeight = 0;
/**
* The default behavior for downloading an archiver<br/>
* key: {@link #KEY_ARCHIVER_DOWNLOAD}<br/>
* value: {@link #ARCHIVER_DOWNLOAD_MAMS}, {@link #ARCHIVER_DOWNLOAD_AAMS},
* {@link #ARCHIVER_DOWNLOAD_MAAS}, {@link #ARCHIVER_DOWNLOAD_AAAS}
*/
public String archiverDownload = ARCHIVER_DOWNLOAD_MAMS;
/**
* Display mode used on the front and search pages<br/>
* false for list, true for thumb<br/>
* key: {@link #KEY_LAYOUT_MODE}<br/>
* value: {@link #LAYOUT_MODE_LIST}, {@link #LAYOUT_MODE_THUMB}
*/
public String layoutMode = LAYOUT_MODE_LIST;
/**
* Default categories on the front page<br/>
* key: {@link #KEY_DEFAULT_CATEGORIES}<br/>
* value: the value of categories, for multiple use & operation,
* 0 for none
*/
public int defaultCategories = 0;
/**
* Certain namespaces excluded from a default tag search<br/>
* key: {@link #KEY_EXCLUDED_NAMESPACES}<br/>
* value: the value of namespaces, for multiple use & operation,
* 0 for none
*/
public int excludedNamespaces = 0;
/**
* Certain languages excluded from list and searches<br/>
* key: {@link #KEY_EXCLUDED_LANGUAGES}<br/>
* value: {@link #JAPANESE_TRANSLATED}, {@link #JAPANESE_REWRITE} ...
* For multiple languages, use <code>x<code/> to combine them, like 1x1024x2048
*/
public String excludedLanguages = "";
/**
* How many results would you like per page for the index/search page
* and torrent search pages<br/>
* key: {@link #KEY_RESULT_COUNT}<br/>
* value: {@link #RESULT_COUNT_25}, {@link #RESULT_COUNT_50},
* {@link #RESULT_COUNT_100}, {@link #RESULT_COUNT_200}<br/>
* Require <code>Hath Perk:Paging Enlargement</code>
*/
public String resultCount = RESULT_COUNT_25;
/**
* mouse-over thumb<br/>
* key: {@link #KEY_MOUSE_OVER}<br/>
* value: {@link #MOUSE_OVER_YES}, {@link #MOUSE_OVER_NO}
*/
public String mouseOver = MOUSE_OVER_YES;
/**
* Default preview mode<br/>
* key: {@link #KEY_PREVIEW_SIZE}<br/>
* value: {@link #PREVIEW_SIZE_NORMAL}, {@link #PREVIEW_SIZE_LARGE}
*/
public String previewSize = PREVIEW_SIZE_NORMAL;
/**
* Preview row<br/>
* key: {@link #KEY_PREVIEW_ROW}<br/>
* value: {@link #PREVIEW_ROW_4}, {@link #PREVIEW_ROW_10},
* {@link #PREVIEW_ROW_20}, {@link #PREVIEW_ROW_40}
*/
public String previewRow = PREVIEW_ROW_4;
/**
* Sort order for gallery comments<br/>
* key: {@link #KEY_COMMENTS_SORT}<br/>
* value: {@link #COMMENTS_SORT_OLDEST_FIRST}, {@link #COMMENTS_SORT_RECENT_FIRST},
* {@link #COMMENTS_SORT_HIGHEST_SCORE_FIRST}
*/
public String commentSort = COMMENTS_SORT_OLDEST_FIRST;
/**
* Show gallery comment votes mode<br/>
* key: {@link #KEY_COMMENTS_VOTES}<br/>
* value: {@link #COMMENTS_VOTES_POP}, {@link #COMMENTS_VOTES_ALWAYS}
*/
public String commentVotes = COMMENTS_VOTES_POP;
/**
* Sort order for gallery tags<br/>
* key: {@link #KEY_TAGS_SORT}<br/>
* value: {@link #TAGS_SORT_ALPHABETICAL}, {@link #TAGS_SORT_POWER}
*/
public String tagSort = TAGS_SORT_ALPHABETICAL;
/**
* Show gallery page numbers<br/>
* key: {@link #KEY_SHOW_GALLERY_INDEX}<br/>
* value: {@link #SHOW_GALLERY_INDEX_YES}, {@link #SHOW_GALLERY_INDEX_NO}
*/
public String showGalleryIndex = SHOW_GALLERY_INDEX_YES;
/**
* The IP of a proxy-enabled Hentai@Home Client
* to load all images<br/>
* key: {@link #KEY_HAH_CLIENT_IP_PORT}<br/>
*/
public String hahClientIp = "";
/**
* The PORT of a proxy-enabled Hentai@Home Client
* to load all images<br/>
* key: {@link #KEY_HAH_CLIENT_IP_PORT}<br/>
*/
public int hahClientPort = -1;
/**
* The passkey of a proxy-enabled Hentai@Home Client
* to load all images<br/>
* key: {@link #KEY_HAH_CLIENT_PASSKEY}<br/>
*/
public String hahClientPasskey = "";
/**
* Enable tag flagging
* key: {@link #KEY_ENABLE_TAG_FLAGGING}<br/>
* value: {@link #ENABLE_TAG_FLAGGING_YES}, {@link #ENABLE_TAG_FLAGGING_NO}<br/>
* <code>Bronze Star</code> or <code>Hath Perk: Tag Flagging</code> Required
*/
public String enableTagFlagging = ENABLE_TAG_FLAGGING_NO;
/**
* Always display the original images instead of the resampled versions<br/>
* key: {@link #KEY_ALWAYS_ORIGINAL}<br/>
* value: {@link #ALWAYS_ORIGINAL_YES}, {@link #ALWAYS_ORIGINAL_NO}<br/>
* <code>Silver Star</code> or <code>Hath Perk: Source Nexus</code> Required
*/
public String alwaysOriginal = ALWAYS_ORIGINAL_NO;
/**
* Enable the multi-Page Viewer<br/>
* key: {@link #KEY_MULTI_PAGE}<br/>
* value: {@link #MULTI_PAGE_YES}, {@link #MULTI_PAGE_NO}<br/>
* <code>Gold Star</code> or <code>Hath Perk: Multi-Page Viewer</code> Required
*/
public String multiPage = MULTI_PAGE_NO;
/**
* Multi-Page Viewer Display Style<br/>
* key: {@link #KEY_MULTI_PAGE_STYLE}<br/>
* value: {@link #MULTI_PAGE_STYLE_N}, {@link #MULTI_PAGE_STYLE_C},
* {@link #MULTI_PAGE_STYLE_Y}<br/>
* <code>Gold Star</code> or <code>Hath Perk: Multi-Page Viewer</code> Required
*/
public String multiPageStyle = MULTI_PAGE_STYLE_N;
/**
* Multi-Page Viewer Thumbnail Pane<br/>
* key: {@link #KEY_MULTI_PAGE_THUMB}<br/>
* value: {@link #MULTI_PAGE_THUMB_SHOW}, {@link #MULTI_PAGE_THUMB_HIDE}<br/>
* <code>Gold Star</code> or <code>Hath Perk: Multi-Page Viewer</code> Required
*/
public String multiPageThumb = MULTI_PAGE_THUMB_SHOW;
/**
* Lofi resolution
* key: {@link #KEY_LOFI_RESOLUTION}<br/>
* value: {@link #LOFI_RESOLUTION_460X}, {@link #LOFI_RESOLUTION_780X},
* {@link #LOFI_RESOLUTION_980X}
*/
public String lofiResolution = LOFI_RESOLUTION_980X;
/**
* Show content warning
* key: {@link #KEY_CONTENT_WARNING}<br/>
* value: {@link #CONTENT_WARNING_SHOW}, {@link #CONTENT_WARNING_NOT_SHOW}
*/
public String contentWarning = CONTENT_WARNING_NOT_SHOW;
private String mUconfig;
private boolean mDirty = true;
@Override
public EhConfig clone() {
try {
return (EhConfig) super.clone();
} catch (CloneNotSupportedException e) {
throw new IllegalStateException(e);
}
}
public void setDirty() {
mDirty = true;
}
private void updateUconfig() {
String hahClientIpPort = (TextUtils.isEmpty(hahClientIp) || hahClientPort == -1) ?
"" : hahClientIp + "%3A" + hahClientPort;
mUconfig = KEY_LOAD_FROM_HAH + "_" + loadFromHAH + "-" +
KEY_SCALE_WIDTH + "_" + scaleWidth + "-" +
KEY_SCALE_HEIGHT + "_" + scaleHeight + "-" +
KEY_ARCHIVER_DOWNLOAD + "_" + archiverDownload + "-" +
KEY_LAYOUT_MODE + "_" + layoutMode + "-" +
KEY_DEFAULT_CATEGORIES + "_" + defaultCategories + "-" +
KEY_EXCLUDED_NAMESPACES + "_" + excludedNamespaces + "-" +
KEY_EXCLUDED_LANGUAGES + "_" + excludedLanguages + "-" +
KEY_RESULT_COUNT + "_" + resultCount + "-" +
KEY_MOUSE_OVER + "_" + mouseOver + "-" +
KEY_PREVIEW_SIZE + "_" + previewSize + "-" +
KEY_PREVIEW_ROW + "_" + previewRow + "-" +
KEY_COMMENTS_SORT + "_" + commentSort + "-" +
KEY_COMMENTS_VOTES + "_" + commentVotes + "-" +
KEY_TAGS_SORT + "_" + tagSort + "-" +
KEY_SHOW_GALLERY_INDEX + "_" + showGalleryIndex + "-" +
KEY_HAH_CLIENT_IP_PORT + "_" + hahClientIpPort + "-" +
KEY_HAH_CLIENT_PASSKEY + "_" + hahClientPasskey + "-" +
KEY_ENABLE_TAG_FLAGGING + "_" + enableTagFlagging + "-" +
KEY_ALWAYS_ORIGINAL + "_" + alwaysOriginal + "-" +
KEY_MULTI_PAGE + "_" + multiPage + "-" +
KEY_MULTI_PAGE_STYLE + "_" + multiPageStyle + "-" +
KEY_MULTI_PAGE_THUMB + "_" + multiPageThumb;
}
/*
public void fillCookie(Cookie cookie) {
if (mDirty) {
mDirty = false;
updateUconfig();
}
cookie.put(KEY_UCONFIG, mUconfig);
cookie.put(KEY_LOFI_RESOLUTION, lofiResolution);
cookie.put(KEY_CONTENT_WARNING, contentWarning);
}
*/
}
@@ -0,0 +1,84 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.client;
import com.hippo.okhttp.CookieDB;
import com.hippo.okhttp.CookieDBStore;
import java.util.ArrayList;
import java.util.List;
import okhttp3.Cookie;
import okhttp3.HttpUrl;
public class EhCookieStore extends CookieDBStore {
private static final String KEY_IPD_MEMBER_ID = "ipb_member_id";
private static final String KEY_IPD_PASS_HASH = "ipb_pass_hash";
private static final String KEY_YAY = "yay";
public void cleanUpForSignIn() {
remove(EhUrl.HOST_E, KEY_IPD_MEMBER_ID);
remove(EhUrl.HOST_E, KEY_IPD_PASS_HASH);
remove(EhUrl.HOST_EX, KEY_IPD_MEMBER_ID);
remove(EhUrl.HOST_EX, KEY_IPD_PASS_HASH);
remove(EhUrl.HOST_EX, KEY_YAY);
}
public boolean hasSignedIn() {
return contain(EhUrl.HOST_EX, KEY_IPD_MEMBER_ID) &&
contain(EhUrl.HOST_EX, KEY_IPD_PASS_HASH);
}
private Cookie newCookie(Cookie cookie, String newDomain) {
Cookie.Builder builder = new Cookie.Builder();
builder.name(cookie.name());
builder.value(cookie.value());
if (cookie.persistent()) {
builder.expiresAt(cookie.expiresAt());
}
if (cookie.hostOnly()) {
builder.hostOnlyDomain(newDomain);
} else {
builder.domain(newDomain);
}
builder.path(cookie.path());
if (cookie.secure()) {
builder.secure();
}
if (cookie.httpOnly()) {
builder.httpOnly();
}
return builder.build();
}
@Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
List<Cookie> cs = new ArrayList<>(cookies.size() + 2);
for (Cookie cookie: cookies) {
cs.add(cookie);
if (EhUrl.HOST_E.equals(cookie.domain()) &&
(KEY_IPD_MEMBER_ID.equals(cookie.name()) ||
KEY_IPD_PASS_HASH.equals(cookie.name()))) {
cs.add(newCookie(cookie, CookieDB.cookiesDomain(EhUrl.HOST_EX)));
}
}
super.saveFromResponse(url, cs);
}
}
@@ -0,0 +1,85 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.client;
import android.util.Log;
import com.hippo.ehviewer.client.parser.SignInParser;
import com.hippo.network.StatusCodeException;
import okhttp3.Call;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class EhEngine {
private static final String TAG = EhEngine.class.getSimpleName();
public static final String UNKNOWN = "Unknown";
private static void throwException(Call call, int code, String body, Exception e) throws Exception {
if (call.isCanceled()) {
throw new CancelledException();
}
if (e instanceof EhException) {
if (!UNKNOWN.equals(e.getMessage())) {
throw e;
}
}
if (!body.contains("<")) {
throw new EhException(body);
}
if (code >= 400) {
throw new StatusCodeException(code);
}
}
public static Call prepareSignIn(OkHttpClient okHttpClient, String username, String password) {
FormBody.Builder builder = new FormBody.Builder()
.add("UserName", username)
.add("PassWord", password)
.add("submit", "Log me in")
.add("CookieDate", "1")
.add("temporary_https", "off");
String url = EhUrl.API_SIGN_IN;
Log.d(TAG, url);
Request request = new EhRequestBuilder(url)
.post(builder.build())
.build();
return okHttpClient.newCall(request);
}
public static String doSignIn(Call call) throws Exception {
String body = null;
int code = -1;
try {
Response response = call.execute();
code = response.code();
body = response.body().string();
return SignInParser.parse(body);
} catch (Exception e) {
throwException(call, code, body, e);
throw e;
}
}
}
@@ -0,0 +1,24 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.client;
public class EhException extends Exception {
public EhException(String detailMessage) {
super(detailMessage);
}
}
@@ -0,0 +1,57 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.client;
public class EhRequest {
int method;
Object[] args;
EhClient.Callback callback;
EhClient.Task task;
private boolean mCancel = false;
public EhRequest setMethod(int method) {
this.method = method;
return this;
}
public EhRequest setArgs(Object... args) {
this.args = args;
return this;
}
public EhRequest setCallback(EhClient.Callback callback) {
this.callback = callback;
return this;
}
public void cancel() {
if (!mCancel) {
mCancel = true;
if (task != null) {
task.stop();
task = null;
}
}
}
public boolean isCancelled() {
return mCancel;
}
}
@@ -0,0 +1,29 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.client;
import com.hippo.okhttp.ChromeRequestBuilder;
public class EhRequestBuilder extends ChromeRequestBuilder {
public EhRequestBuilder(String url) {
super(url);
}
}
@@ -0,0 +1,30 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.client;
public class EhUrl {
public static final String HOST_EX = "exhentai.org";
public static final String HOST_E = "e-hentai.org";
public static final String API_SIGN_IN = "http://forums.e-hentai.org/index.php?act=Login&CODE=01";
}
@@ -0,0 +1,30 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.client;
import android.content.Context;
import com.hippo.ehviewer.EhApplication;
import com.hippo.ehviewer.Settings;
public class EhUtils {
public static boolean hasSignedIn(Context context) {
return EhApplication.getEhCookieStore(context).hasSignedIn() &&
Settings.getDisplayName() != null;
}
}
@@ -0,0 +1,45 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.client.parser;
import com.hippo.ehviewer.client.EhEngine;
import com.hippo.ehviewer.client.EhException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class SignInParser {
private static final Pattern NAME_PATTERN = Pattern.compile("<p>You are now logged in as: (.+?)<");
private static final Pattern ERROR_PATTERN = Pattern.compile(
"(?:<h4>The error returned was:</h4>\\s*<p>(.+?)</p>)"
+ "|(?:<span class=\"postcolor\">(.+?)</span>)");
public static String parse(String body) throws Exception {
Matcher m = NAME_PATTERN.matcher(body);
if (m.find()) {
return m.group(1);
} else {
m = ERROR_PATTERN.matcher(body);
if (m.find()) {
throw new EhException(m.group(1) == null ? m.group(2) : m.group(1));
} else {
throw new EhException(EhEngine.UNKNOWN);
}
}
}
}
@@ -0,0 +1,100 @@
/*
* 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;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.NavigationView;
import android.support.v4.widget.DrawerLayout;
import android.view.MenuItem;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.Settings;
import com.hippo.ehviewer.client.EhUtils;
import com.hippo.ehviewer.ui.scene.GalleryListScene;
import com.hippo.ehviewer.ui.scene.LoginScene;
import com.hippo.ehviewer.ui.scene.WarningScene;
import com.hippo.scene.StageActivity;
public final class MainActivity extends StageActivity
implements NavigationView.OnNavigationItemSelectedListener {
private DrawerLayout mDrawerLayout;
@Override
public int getContainerViewId() {
return R.id.fragment_container;
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDrawerLayout = (DrawerLayout) findViewById(R.id.draw_view);
NavigationView navView = (NavigationView) findViewById(R.id.nav_view);
navView.setNavigationItemSelectedListener(this);
if (savedInstanceState == null) {
onInit();
}
}
public void setDrawerLayoutEnable(boolean enable) {
if (enable) {
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
} else {
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
}
}
private void onInit() {
if (Settings.getShowWarning()) {
setDrawerLayoutEnable(false);
startScene(WarningScene.class);
} else if (!EhUtils.hasSignedIn(this)) {
setDrawerLayoutEnable(false);
startScene(LoginScene.class);
} else {
setDrawerLayoutEnable(true);
startScene(GalleryListScene.class);
}
}
@Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.nav_homepage) {
} else if (id == R.id.nav_whats_hot) {
} else if (id == R.id.nav_favourite) {
} else if (id == R.id.nav_history) {
} else if (id == R.id.nav_download) {
} else if (id == R.id.nav_settings) {
}
return true;
}
}
@@ -0,0 +1,32 @@
/*
* 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.support.v4.app.FragmentActivity;
import com.hippo.ehviewer.ui.MainActivity;
import com.hippo.scene.SceneFragment;
public class BaseScene extends SceneFragment {
public void setDrawerLayoutEnable(boolean enable) {
FragmentActivity activity = getActivity();
if (activity instanceof MainActivity) {
((MainActivity) activity).setDrawerLayoutEnable(enable);
}
}
}
@@ -0,0 +1,42 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.ui.scene;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.hippo.ehviewer.R;
public class GalleryListScene extends BaseScene {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.scene_gallery_list, container, false);
return view;
}
}
@@ -0,0 +1,227 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.ui.scene;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Paint;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.TextInputLayout;
import android.support.v7.app.AlertDialog;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import com.hippo.ehviewer.EhApplication;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.Settings;
import com.hippo.ehviewer.client.EhClient;
import com.hippo.ehviewer.client.EhCookieStore;
import com.hippo.ehviewer.client.EhRequest;
import com.hippo.utils.ExceptionUtils;
public final class LoginScene extends BaseScene implements EditText.OnEditorActionListener,
View.OnClickListener {
private View mProgress;
private TextInputLayout mUsernameLayout;
private TextInputLayout mPasswordLayout;
private EditText mUsername;
private EditText mPassword;
private View mRegister;
private View mSignIn;
private TextView mSignInViaWebview;
private TextView mSignInViaCookies;
private EhClient mClient;
private EhCookieStore mCookieStore;
private EhRequest mSignInRequest;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mClient = EhApplication.getEhClient(getContext());
mCookieStore = EhApplication.getEhCookieStore(getContext());
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.scene_login, container, false);
View loginForm = view.findViewById(R.id.login_form);
mProgress = view.findViewById(R.id.progress);
mUsernameLayout = (TextInputLayout) loginForm.findViewById(R.id.username_layout);
mUsername = mUsernameLayout.getEditText();
mPasswordLayout = (TextInputLayout) loginForm.findViewById(R.id.password_layout);
mPassword = mPasswordLayout.getEditText();
mRegister = loginForm.findViewById(R.id.register);
mSignIn = loginForm.findViewById(R.id.sign_in);
mSignInViaWebview = (TextView) loginForm.findViewById(R.id.sign_in_via_webview);
mSignInViaCookies = (TextView) loginForm.findViewById(R.id.sign_in_via_cookies);
mSignInViaWebview.setPaintFlags(mSignInViaWebview.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
mSignInViaCookies.setPaintFlags(mSignInViaCookies.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
mPassword.setOnEditorActionListener(this);
mRegister.setOnClickListener(this);
mSignIn.setOnClickListener(this);
mSignInViaWebview.setOnClickListener(this);
mSignInViaCookies.setOnClickListener(this);
return view;
}
@Override
public void onDestroy() {
super.onDestroy();
if (mSignInRequest != null) {
mSignInRequest.cancel();
mSignInRequest = null;
}
}
@Override
public void onClick(View v) {
if (mRegister == v) {
} else if (mSignIn == v) {
signIn();
} else if (mSignInViaWebview == v) {
} else if (mSignInViaCookies == v) {
}
}
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (v == mPassword) {
if (actionId == EditorInfo.IME_ACTION_DONE || actionId == EditorInfo.IME_NULL) {
signIn();
return true;
}
}
return false;
}
private void signIn() {
if (mSignInRequest != null) {
return;
}
String username = mUsername.getText().toString();
String password = mPassword.getText().toString();
if (username.isEmpty()) {
mUsernameLayout.setError(getString(R.string.error_username_cannot_empty));
return;
} else {
mUsernameLayout.setError(null);
}
if (password.isEmpty()) {
mPasswordLayout.setError(getString(R.string.error_password_cannot_empty));
return;
} else {
mPasswordLayout.setError(null);
}
// Hide ime keyboard
View view = getActivity().getCurrentFocus();
if (view != null) {
InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
mProgress.setAlpha(0.0f);
mProgress.setVisibility(View.VISIBLE);
mProgress.animate().alpha(1.0f).setDuration(500).start();
// Clean up for sign in
mCookieStore.cleanUpForSignIn();
mSignInRequest = new EhRequest()
.setMethod(EhClient.METHOD_SIGN_IN)
.setArgs(username, password)
.setCallback(new EhClient.Callback<String>() {
@Override
public void onSuccess(String result) {
mSignInRequest = null;
Settings.putDisplayName(result);
if (mCookieStore.hasSignedIn()) {
// Has signed in
redirectTo();
} else {
mProgress.setVisibility(View.GONE);
whetherToSkip();
}
}
@Override
public void onFailure(Exception e) {
mSignInRequest = null;
mProgress.setVisibility(View.GONE);
Toast.makeText(getContext(), ExceptionUtils.getReadableString(getContext(), e),
Toast.LENGTH_SHORT).show();
whetherToSkip();
}
@Override
public void onCancel() {
mSignInRequest = null;
// User close this Scene
}
});
mClient.execute(mSignInRequest);
}
private void redirectTo() {
startScene(GalleryListScene.class);
finish();
// Enable drawer
setDrawerLayoutEnable(true);
}
private void whetherToSkip() {
new AlertDialog.Builder(getContext())
.setTitle(R.string.skip_signing_in)
.setMessage(R.string.skip_signing_in_plain)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == AlertDialog.BUTTON_POSITIVE) {
redirectTo();
}
}
}).show();
}
}
@@ -0,0 +1,75 @@
/*
* 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.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.Settings;
import com.hippo.ehviewer.client.EhUtils;
import com.hippo.vector.VectorDrawable;
import com.hippo.widget.SimpleImageView;
public final class WarningScene extends BaseScene implements View.OnClickListener {
private View mCancel;
private View mOk;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.scene_warning, container, false);
SimpleImageView alert = (SimpleImageView) view.findViewById(R.id.icon_alert);
mCancel = view.findViewById(R.id.cancel);
mOk = view.findViewById(R.id.ok);
Drawable drawable = VectorDrawable.create(getContext(), R.drawable.ic_alert);
alert.setDrawable(drawable);
mCancel.setOnClickListener(this);
mOk.setOnClickListener(this);
return view;
}
@Override
public void onClick(View v) {
if (mCancel == v) {
finishStage();
} else if (mOk == v) {
// Never show this warning anymore
Settings.putShowWarning(false);
if (EhUtils.hasSignedIn(getContext())) {
startScene(GalleryListScene.class);
finish();
// Enable drawer
setDrawerLayoutEnable(true);
} else {
startScene(LoginScene.class);
finish();
}
}
}
}
@@ -0,0 +1,90 @@
/*
* 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.network;
import android.content.Context;
import android.content.res.Resources;
import android.util.SparseArray;
import com.hippo.ehviewer.R;
public class StatusCodeException extends Exception {
private static final SparseArray<String> ERROR_MESSAGE_ARRAY = new SparseArray<>(24);
private static final String DEFAULT_ERROR_MESSAGE = "Error response code";
private final int mResponseCode;
private final String mMessage;
public static void initialize(Context context) {
Resources resources = context.getApplicationContext().getResources();
ERROR_MESSAGE_ARRAY.append(400, resources.getString(R.string.error_status_code_400));
ERROR_MESSAGE_ARRAY.append(401, resources.getString(R.string.error_status_code_401));
ERROR_MESSAGE_ARRAY.append(402, resources.getString(R.string.error_status_code_402));
ERROR_MESSAGE_ARRAY.append(403, resources.getString(R.string.error_status_code_403));
ERROR_MESSAGE_ARRAY.append(404, resources.getString(R.string.error_status_code_404));
ERROR_MESSAGE_ARRAY.append(405, resources.getString(R.string.error_status_code_405));
ERROR_MESSAGE_ARRAY.append(406, resources.getString(R.string.error_status_code_406));
ERROR_MESSAGE_ARRAY.append(407, resources.getString(R.string.error_status_code_407));
ERROR_MESSAGE_ARRAY.append(408, resources.getString(R.string.error_status_code_408));
ERROR_MESSAGE_ARRAY.append(409, resources.getString(R.string.error_status_code_409));
ERROR_MESSAGE_ARRAY.append(410, resources.getString(R.string.error_status_code_410));
ERROR_MESSAGE_ARRAY.append(411, resources.getString(R.string.error_status_code_411));
ERROR_MESSAGE_ARRAY.append(412, resources.getString(R.string.error_status_code_412));
ERROR_MESSAGE_ARRAY.append(413, resources.getString(R.string.error_status_code_413));
ERROR_MESSAGE_ARRAY.append(414, resources.getString(R.string.error_status_code_414));
ERROR_MESSAGE_ARRAY.append(415, resources.getString(R.string.error_status_code_415));
ERROR_MESSAGE_ARRAY.append(416, resources.getString(R.string.error_status_code_416));
ERROR_MESSAGE_ARRAY.append(417, resources.getString(R.string.error_status_code_417));
ERROR_MESSAGE_ARRAY.append(500, resources.getString(R.string.error_status_code_500));
ERROR_MESSAGE_ARRAY.append(501, resources.getString(R.string.error_status_code_501));
ERROR_MESSAGE_ARRAY.append(502, resources.getString(R.string.error_status_code_502));
ERROR_MESSAGE_ARRAY.append(503, resources.getString(R.string.error_status_code_503));
ERROR_MESSAGE_ARRAY.append(504, resources.getString(R.string.error_status_code_504));
ERROR_MESSAGE_ARRAY.append(505, resources.getString(R.string.error_status_code_505));
}
public StatusCodeException(int responseCode) {
mResponseCode = responseCode;
mMessage = ERROR_MESSAGE_ARRAY.get(responseCode, DEFAULT_ERROR_MESSAGE);
}
public StatusCodeException(int responseCode, String message) {
mResponseCode = responseCode;
mMessage = message;
}
public int getResponseCode() {
return mResponseCode;
}
public boolean isIdentifiedResponseCode() {
return !DEFAULT_ERROR_MESSAGE.equals(mMessage);
}
@Override
public String getMessage() {
return mMessage;
}
@Override
public String getLocalizedMessage() {
return getMessage();
}
}
@@ -0,0 +1,41 @@
/*
* 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.okhttp;
import java.net.MalformedURLException;
import java.net.URL;
import okhttp3.Request;
public class ChromeRequestBuilder extends Request.Builder {
private static final String CHROME_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " +
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.111 Safari/537.36";
public ChromeRequestBuilder(String url) {
URL u;
try {
u = new URL(url);
} catch (MalformedURLException e) {
throw new IllegalStateException(e);
}
url(u);
addHeader("User-Agent", CHROME_USER_AGENT);
}
}
@@ -0,0 +1,158 @@
/*
* 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.okhttp;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.text.TextUtils;
import com.hippo.okhttp.dao.DaoMaster;
import com.hippo.okhttp.dao.DaoSession;
import com.hippo.okhttp.dao.OkHttp3CookieDao;
import com.hippo.okhttp.dao.OkHttp3CookieRaw;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import okhttp3.Cookie;
public class CookieDB {
private static DaoSession sDaoSession;
public static class DBOpenHelper extends DaoMaster.OpenHelper {
public DBOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
super(context, name, factory);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
public static void initialize(Context context) {
DBOpenHelper helper = new DBOpenHelper(
context.getApplicationContext(), "okhttp3-cookie.db", null);
SQLiteDatabase db = helper.getWritableDatabase();
DaoMaster daoMaster = new DaoMaster(db);
sDaoSession = daoMaster.newSession();
}
public static String cookiesDomain(URL url) {
return cookiesDomain(url.getHost());
}
public static String cookiesDomain(String domain) {
if (TextUtils.isEmpty(domain)) {
return "";
}
int count = 0;
for (int i = domain.length() - 1; i >= 0; i--) {
char ch = domain.charAt(i);
if (ch == '.') {
count++;
}
if (count == 2) {
return domain.substring(i + 1);
}
}
return domain;
}
public static Map<String, List<CookieWithID>> getAllCookies() {
OkHttp3CookieDao dao = sDaoSession.getOkHttp3CookieDao();
List<OkHttp3CookieRaw> list = dao.queryBuilder().list();
long now = System.currentTimeMillis();
Map<String, List<CookieWithID>> result = new HashMap<>();
for (OkHttp3CookieRaw raw : list) {
// Check expired
if (!raw.getPersistent() || raw.getExpiresAt() <= now) {
dao.delete(raw);
continue;
}
// Avoid null error
String name = raw.getName();
String value = raw.getValue();
String domain = raw.getDomain();
if (name == null || value == null || domain == null) {
dao.delete(raw);
continue;
}
Cookie.Builder builder = new Cookie.Builder();
builder.name(name);
builder.value(value);
builder.expiresAt(raw.getExpiresAt());
if (raw.getHostOnly()) {
builder.hostOnlyDomain(domain);
} else {
builder.domain(raw.getDomain());
}
builder.path(raw.getPath());
if (raw.getSecure()) {
builder.secure();
}
if (raw.getHttpOnly()) {
builder.httpOnly();
}
String cookiesDomain = cookiesDomain(domain);
List<CookieWithID> cookies = result.get(cookiesDomain);
if (cookies == null) {
cookies = new ArrayList<>();
result.put(cookiesDomain, cookies);
}
cookies.add(new CookieWithID(raw.getId(), builder.build()));
}
return result;
}
public static void removeCookie(long id) {
sDaoSession.getOkHttp3CookieDao().deleteByKey(id);
}
public static long addCookie(Cookie cookie) {
OkHttp3CookieDao dao = sDaoSession.getOkHttp3CookieDao();
OkHttp3CookieRaw raw = new OkHttp3CookieRaw();
raw.setName(cookie.name());
raw.setValue(cookie.value());
raw.setExpiresAt(cookie.expiresAt());
raw.setDomain(cookie.domain());
raw.setPath(cookie.path());
raw.setSecure(cookie.secure());
raw.setHttpOnly(cookie.httpOnly());
raw.setPersistent(cookie.persistent());
raw.setHostOnly(cookie.hostOnly());
return dao.insert(raw);
}
}
@@ -0,0 +1,176 @@
/*
* 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.okhttp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import okhttp3.Cookie;
import okhttp3.CookieJar;
import okhttp3.HttpUrl;
import okhttp3.Request;
public class CookieDBStore implements CookieJar {
private final Map<String, List<CookieWithID>> map;
public CookieDBStore() {
map = CookieDB.getAllCookies();
}
private boolean hasExpired(Cookie cookie) {
return cookie.expiresAt() < System.currentTimeMillis();
}
private static CookieWithID removeCookie(List<CookieWithID> list, Cookie cookie) {
for (int i = 0, n = list.size(); i < n; i++) {
CookieWithID cwi = list.get(i);
if (cwi.cookie.name().equals(cookie.name())) {
list.remove(i);
return cwi;
}
}
return null;
}
private static CookieWithID removeCookie(List<CookieWithID> list, String name) {
for (int i = 0, n = list.size(); i < n; i++) {
CookieWithID cwi = list.get(i);
if (cwi.cookie.name().equals(name)) {
list.remove(i);
return cwi;
}
}
return null;
}
private boolean containInternal(String domain, String name) {
List<CookieWithID> cookies = map.get(domain);
if (cookies != null) {
for (int i = 0, n = cookies.size(); i < n; i++) {
CookieWithID cwi = cookies.get(i);
if (cwi.cookie.name().equals(name)) {
return true;
}
}
}
return false;
}
private synchronized void removeInternal(String domain, Cookie cookie) {
List<CookieWithID> cookies = map.get(domain);
if (cookies != null) {
// Remove from list
CookieWithID cwi = removeCookie(cookies, cookie);
if (cwi != null) {
// Remove from DB
CookieDB.removeCookie(cwi.id);
}
}
}
private synchronized void removeInternal(String domain, String name) {
List<CookieWithID> cookies = map.get(domain);
if (cookies != null) {
// Remove from list
CookieWithID cwi = removeCookie(cookies, name);
if (cwi != null) {
// Remove from DB
CookieDB.removeCookie(cwi.id);
}
}
}
private synchronized void addInternal(String domain, Cookie cookie) {
// Check expired
if (hasExpired(cookie)) {
removeInternal(domain, cookie);
return;
}
List<CookieWithID> cookies = map.get(domain);
if (cookies == null) {
cookies = new ArrayList<>();
map.put(domain, cookies);
} else {
// Remove from list
CookieWithID cwi = removeCookie(cookies, cookie);
if (cwi != null) {
// Remove from DB
CookieDB.removeCookie(cwi.id);
}
}
// Add to DB
long id = CookieDB.addCookie(cookie);
// Add to list
cookies.add(new CookieWithID(id, cookie));
}
public boolean contain(String url, String name) {
return containInternal(CookieDB.cookiesDomain(url), name);
}
public void remove(String url, String name) {
removeInternal(CookieDB.cookiesDomain(url), name);
}
public void add(Cookie cookie) {
addInternal(CookieDB.cookiesDomain(cookie.domain()), cookie);
}
public List<Cookie> get(HttpUrl url) {
List<Cookie> result = new ArrayList<>();
String domain = CookieDB.cookiesDomain(url.url());
List<CookieWithID> cookies = map.get(domain);
if (cookies != null) {
for (Iterator<CookieWithID> i = cookies.iterator(); i.hasNext();) {
CookieWithID cwi = i.next();
Cookie cookie = cwi.cookie;
// Check expired
if (hasExpired(cookie)) {
// Remove from list
i.remove();
// Remove from DB
CookieDB.removeCookie(cwi.id);
} else if (cookie.matches(url)) {
result.add(cookie);
}
}
}
return Collections.unmodifiableList(result);
}
@Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
for (Cookie cookie: cookies) {
add(cookie);
}
}
@Override
public List<Cookie> loadForRequest(HttpUrl url, Request request) {
return get(url);
}
}
@@ -0,0 +1,30 @@
/*
* 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.okhttp;
import okhttp3.Cookie;
public class CookieWithID {
public long id;
public Cookie cookie;
public CookieWithID(long id, Cookie cookie) {
this.id = id;
this.cookie = cookie;
}
}
@@ -0,0 +1,44 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.scene;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
public class SceneFragment extends Fragment {
public <T extends SceneFragment> void startScene(Class<T> clazz) {
FragmentActivity activity = getActivity();
if (activity instanceof StageActivity) {
((StageActivity) activity).startScene(clazz);
}
}
public void finish() {
FragmentActivity activity = getActivity();
if (activity instanceof StageActivity) {
((StageActivity) activity).finishScene(this);
}
}
public void finishStage() {
FragmentActivity activity = getActivity();
if (activity != null) {
activity.finish();
}
}
}
@@ -0,0 +1,163 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.scene;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import com.hippo.ehviewer.R;
import com.hippo.yorozuya.IdIntGenerator;
import java.util.ArrayList;
import java.util.Collections;
public abstract class StageActivity extends AppCompatActivity {
private static final String TAG = StageActivity.class.getSimpleName();
private static final String KEY_STAGE_ACTIVITY_SCENE_TAG_LIST = "stage_activity_scene_tag_list";
// TODO ArrayList or LinkedList
private ArrayList<String> mSceneTagList = new ArrayList<>();
private IdIntGenerator mIdGenerator = new IdIntGenerator();
public abstract int getContainerViewId();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
private <T extends SceneFragment> SceneFragment newSceneInstance(Class<T> clazz) {
try {
return clazz.newInstance();
} catch (InstantiationException e) {
throw new IllegalStateException("Can't instance " + clazz.getName(), e);
} catch (IllegalAccessException e) {
throw new IllegalStateException("The constructor of " +
clazz.getName() + " is not visible", e);
} catch (ClassCastException e) {
throw new IllegalStateException(clazz.getName() + " can not cast to scene", e);
}
}
public <T extends SceneFragment> void startScene(Class<T> clazz) {
startScene(clazz, null);
}
public <T extends SceneFragment> void startScene(Class<T> clazz, Bundle args) {
FragmentManager fragmentManager = getSupportFragmentManager();
// Old scene
Fragment old = null;
if (mSceneTagList.size() > 0) {
// Get last tag
String tag = mSceneTagList.get(mSceneTagList.size() - 1);
old = fragmentManager.findFragmentByTag(tag);
}
// New scene
SceneFragment scene = newSceneInstance(clazz);
scene.setArguments(args);
// New scene tag
String newTag = Integer.toString(mIdGenerator.nextId());
mSceneTagList.add(newTag);
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.setCustomAnimations(R.anim.fragment_translate_in, R.anim.fragment_translate_out);
if (old != null) {
transaction.detach(old);
}
transaction.add(getContainerViewId(), scene, newTag);
transaction.commit();
}
public void finishScene(SceneFragment scene) {
finishScene(scene.getTag());
}
private void finishScene(String tag) {
FragmentManager fragmentManager = getSupportFragmentManager();
// Get scene
Fragment scene = fragmentManager.findFragmentByTag(tag);
if (scene == null) {
Log.e(TAG, "finishScene: Can't find scene by tag: " + tag);
return;
}
// FIXME It will fail if mIdGenerator.nextId() called more than Integer.MAX_VALUE times
// Get scene index
int index = Collections.binarySearch(mSceneTagList, tag);
if (index < 0) {
Log.e(TAG, "finishScene: Can't find the tag in tag list: " + tag);
return;
}
if (mSceneTagList.size() == 1) {
// It is the last fragment, finish Activity now
Log.i(TAG, "finishScene: It is the last scene, finish activity now");
finish();
return;
}
Fragment next = null;
// It is first fragment, show the next one
if (index == mSceneTagList.size() - 1) {
next = fragmentManager.findFragmentByTag(mSceneTagList.get(index - 1));
}
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.setCustomAnimations(R.anim.fragment_translate_in, R.anim.fragment_translate_out);
transaction.remove(scene);
if (next != null && next.isDetached()) {
transaction.attach(next);
}
transaction.commit();
// Remove tag
mSceneTagList.remove(index);
}
@Override
public void onBackPressed() {
int size = mSceneTagList.size();
if (size > 0) {
finishScene(mSceneTagList.get(size - 1));
} else {
finish();
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putStringArrayList(KEY_STAGE_ACTIVITY_SCENE_TAG_LIST, mSceneTagList);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mSceneTagList = savedInstanceState.getStringArrayList(KEY_STAGE_ACTIVITY_SCENE_TAG_LIST);
}
}
@@ -0,0 +1,63 @@
/*
* 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.utils;
import android.content.Context;
import android.support.annotation.NonNull;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.client.EhException;
import com.hippo.network.StatusCodeException;
import org.apache.http.conn.ConnectTimeoutException;
import java.net.ProtocolException;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
public final class ExceptionUtils {
private static final String TAG = ExceptionUtils.class.getSimpleName();
@NonNull
public static String getReadableString(@NonNull Context context, @NonNull Exception e) {
if (e instanceof ConnectTimeoutException ||
e instanceof SocketTimeoutException) {
return context.getString(R.string.error_timeout);
} else if (e instanceof UnknownHostException) {
return context.getString(R.string.error_unknown_host);
} else if (e instanceof StatusCodeException) {
StatusCodeException sce = (StatusCodeException) e;
StringBuilder sb = new StringBuilder();
sb.append(context.getString(R.string.error_bad_status_code, sce.getResponseCode()));
if (sce.isIdentifiedResponseCode()) {
sb.append(", ").append(sce.getMessage());
}
return sb.toString();
} else if (e instanceof ProtocolException && e.getMessage().startsWith("Too many follow-up requests:")) {
return context.getString(R.string.error_redirection);
} else if (e instanceof ProtocolException || e instanceof SocketException) {
return context.getString(R.string.error_socket);
} else if (e instanceof EhException) {
return e.getMessage();
} else {
return context.getString(R.string.error_unknown);
}
}
}
@@ -0,0 +1,93 @@
/*
* 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.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import com.hippo.ehviewer.R;
import com.hippo.yorozuya.AssertUtils;
public class MaxSizeContainer extends ViewGroup {
private int mMaxWidth;
private int mMaxHeight;
public MaxSizeContainer(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public MaxSizeContainer(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MaxSizeContainer);
mMaxWidth = a.getDimensionPixelOffset(R.styleable.MaxSizeContainer_maxWidth, -1);
mMaxHeight = a.getDimensionPixelOffset(R.styleable.MaxSizeContainer_maxHeight, -1);
a.recycle();
}
private int getMeasureSpec(int measureSpec, int max) {
if (max < 0) {
return measureSpec;
}
int size = MeasureSpec.getSize(measureSpec);
int mode = MeasureSpec.getMode(measureSpec);
switch (mode) {
case MeasureSpec.AT_MOST:
size = Math.min(size, max);
break;
case MeasureSpec.UNSPECIFIED:
size = max;
mode = MeasureSpec.AT_MOST;
break;
}
return MeasureSpec.makeMeasureSpec(size, mode);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
AssertUtils.assertEquals("getChildCount() must be 1", 1, getChildCount());
View child = getChildAt(0);
if (child.getVisibility() != GONE) {
child.measure(getMeasureSpec(widthMeasureSpec, mMaxWidth),
getMeasureSpec(heightMeasureSpec, mMaxHeight));
setMeasuredDimension(child.getMeasuredWidth(), child.getMeasuredHeight());
} else {
setMeasuredDimension(0, 0);
}
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
AssertUtils.assertEquals("getChildCount() must be 1", 1, getChildCount());
View child = getChildAt(0);
if (child.getVisibility() != GONE) {
child.layout(0, 0, r - l, b - t);
}
}
}
@@ -0,0 +1,317 @@
/*
* Copyright 2015 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.widget;
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.support.annotation.NonNull;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import com.hippo.anani.PathInterpolator;
import com.hippo.ehviewer.R;
import com.hippo.yorozuya.ViewUtils;
import java.util.ArrayList;
// Base on android.graphics.drawable.MaterialProgressDrawable in L preview
public class ProgressView extends View {
private static final Interpolator TRIM_START_INTERPOLATOR;
private static final Interpolator TRIM_END_INTERPOLATOR;
private static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
static {
Path trimStartPath = new Path();
trimStartPath.moveTo(0.0f, 0.0f);
trimStartPath.lineTo(0.5f, 0.0f);
trimStartPath.cubicTo(0.7f, 0.0f, 0.6f, 1f, 1f, 1f);
TRIM_START_INTERPOLATOR = PathInterpolator.build(trimStartPath);
Path trimEndPath = new Path();
trimEndPath.moveTo(0.0f, 0.0f);
trimEndPath.cubicTo(0.2f, 0.0f, 0.1f, 1f, 0.5f, 1f);
trimEndPath.lineTo(1f, 1f);
TRIM_END_INTERPOLATOR = PathInterpolator.build(trimEndPath);
}
private final ArrayList<Animator> mAnimators = new ArrayList<>();
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final RectF mRectF = new RectF();
private boolean mIndeterminate;
private float mTrimStart = 0.0f;
private float mTrimEnd = 0.0f;
private float mTrimOffset = 0.0f;
private float mTrimRotation = 0.0f;
// It is a trick to avoid first sight stuck. Get it from ProgressBar
private boolean mShouldStartAnimationDrawable = false;
public ProgressView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public ProgressView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ProgressView);
int color = a.getColor(R.styleable.ProgressView_color, Color.BLACK);
mPaint.setColor(color);
mPaint.setStrokeCap(Paint.Cap.SQUARE);
mPaint.setStrokeJoin(Paint.Join.MITER);
mPaint.setStyle(Paint.Style.STROKE);
mIndeterminate = a.getBoolean(R.styleable.ProgressView_indeterminate, true);
setProgress(a.getFloat(R.styleable.ProgressView_progress, 0f));
a.recycle();
setupAnimators();
}
private void setupAnimators() {
ObjectAnimator trimStart = ObjectAnimator.ofFloat(this, "trimStart", 0.0f, 0.75f);
trimStart.setDuration(1333L);
trimStart.setInterpolator(TRIM_START_INTERPOLATOR);
trimStart.setRepeatCount(Animation.INFINITE);
ObjectAnimator trimEnd = ObjectAnimator.ofFloat(this, "trimEnd", 0.0f, 0.75f);
trimEnd.setDuration(1333L);
trimEnd.setInterpolator(TRIM_END_INTERPOLATOR);
trimEnd.setRepeatCount(Animation.INFINITE);
ObjectAnimator trimOffset = ObjectAnimator.ofFloat(this, "trimOffset", 0.0f, 0.25f);
trimOffset.setDuration(1333L);
trimOffset.setInterpolator(LINEAR_INTERPOLATOR);
trimOffset.setRepeatCount(Animation.INFINITE);
ObjectAnimator trimRotation = ObjectAnimator.ofFloat(this, "trimRotation", 0.0f, 720.0f);
trimRotation.setDuration(6665L);
trimRotation.setInterpolator(LINEAR_INTERPOLATOR);
trimRotation.setRepeatCount(Animation.INFINITE);
mAnimators.add(trimStart);
mAnimators.add(trimEnd);
mAnimators.add(trimOffset);
mAnimators.add(trimRotation);
}
private void startAnimation() {
mShouldStartAnimationDrawable = true;
postInvalidate();
}
private void startAnimationActually() {
ArrayList<Animator> animators = mAnimators;
int N = animators.size();
for (int i = 0; i < N; i++) {
Animator animator = animators.get(i);
if (!animator.isRunning()) {
animator.start();
}
}
}
private void stopAnimation() {
mShouldStartAnimationDrawable = false;
ArrayList<Animator> animators = mAnimators;
int N = animators.size();
for (int i = 0; i < N; i++) {
animators.get(i).cancel();
}
}
public boolean isRunning() {
ArrayList<Animator> animators = mAnimators;
int N = animators.size();
for (int i = 0; i < N; i++) {
Animator animator = animators.get(i);
if (animator.isRunning()) {
return true;
}
}
return false;
}
@SuppressWarnings("unused")
public float getTrimStart() {
return mTrimStart;
}
@SuppressWarnings("unused")
public void setTrimStart(float trimStart) {
mTrimStart = trimStart;
invalidate();
}
@SuppressWarnings("unused")
public float getTrimEnd() {
return mTrimEnd;
}
@SuppressWarnings("unused")
public void setTrimEnd(float trimEnd) {
mTrimEnd = trimEnd;
invalidate();
}
@SuppressWarnings("unused")
public float getTrimOffset() {
return mTrimOffset;
}
@SuppressWarnings("unused")
public void setTrimOffset(float trimOffset) {
mTrimOffset = trimOffset;
invalidate();
}
@SuppressWarnings("unused")
public float getTrimRotation() {
return mTrimRotation;
}
@SuppressWarnings("unused")
public void setTrimRotation(float trimRotation) {
mTrimRotation = trimRotation;
invalidate();
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (mIndeterminate && getVisibility() == VISIBLE) {
startAnimation();
}
}
@Override
protected void onDetachedFromWindow() {
if (mIndeterminate) {
stopAnimation();
}
// This should come after stopAnimation(), otherwise an invalidate message remains in the
// queue, which can prevent the entire view hierarchy from being GC'ed during a rotation
super.onDetachedFromWindow();
}
@Override
public void setVisibility(int v) {
if (getVisibility() != v) {
super.setVisibility(v);
if (mIndeterminate) {
if (v == GONE || v == INVISIBLE) {
stopAnimation();
} else if (ViewCompat.isAttachedToWindow(this)) {
startAnimation();
}
}
}
}
@Override
protected void onVisibilityChanged(@NonNull View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
if (mIndeterminate && ViewCompat.isAttachedToWindow(this)) {
if (visibility == GONE || visibility == INVISIBLE) {
stopAnimation();
} else if (ViewCompat.isAttachedToWindow(this)) {
startAnimation();
}
}
}
public void setColor(int color) {
mPaint.setColor(color);
invalidate();
}
public void setIndeterminate(boolean indeterminate) {
if (mIndeterminate != indeterminate) {
mIndeterminate = indeterminate;
if (indeterminate) {
if (isShown() && ViewCompat.isAttachedToWindow(this)) {
startAnimation();
}
} else {
stopAnimation();
}
}
}
public boolean isIndeterminate() {
return mIndeterminate;
}
public void setProgress(float progress) {
if (!mIndeterminate) {
mTrimStart = 0f;
mTrimEnd = progress;
mTrimOffset = 0f;
mTrimRotation = 0f;
invalidate();
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(ViewUtils.getSuitableSize(getSuggestedMinimumWidth(), widthMeasureSpec),
ViewUtils.getSuitableSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
mPaint.setStrokeWidth(Math.min(w, h) / 12.0f);
mRectF.set(0, 0, w, h);
mRectF.inset(w / 48.0f * 5.0f, h / 48.0f * 5.0f);
}
@Override
protected void onDraw(Canvas canvas) {
int saved = canvas.save();
canvas.rotate(mTrimRotation, mRectF.centerX(), mRectF.centerY());
float startAngle = (mTrimStart + mTrimOffset) * 360.0f - 90;
float sweepAngle = (mTrimEnd - mTrimStart) * 360.0f;
canvas.drawArc(mRectF, startAngle, sweepAngle, false, mPaint);
canvas.restoreToCount(saved);
if (mShouldStartAnimationDrawable) {
mShouldStartAnimationDrawable = false;
startAnimationActually();
}
}
}
@@ -0,0 +1,127 @@
/*
* Copyright (C) 2015 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.support.annotation.DrawableRes;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.view.View;
import com.hippo.yorozuya.ViewUtils;
public class SimpleImageView extends View implements Drawable.Callback {
private Drawable mDrawable;
private static final int[] LAYOUT_ATTRS = new int[] {
android.R.attr.src
};
public SimpleImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public SimpleImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
final TypedArray a = context.obtainStyledAttributes(attrs, LAYOUT_ATTRS);
setDrawable(a.getDrawable(0));
a.recycle();
// Mostly drawable is VectorDrawable, it has cache already
setWillNotCacheDrawing(true);
}
@SuppressWarnings("deprecation")
public void setDrawable(@DrawableRes int resId) {
setDrawable(getContext().getResources().getDrawable(resId));
}
public void setDrawable(Drawable drawable) {
if (mDrawable != null) {
mDrawable.setCallback(null);
}
mDrawable = drawable;
if (drawable != null) {
drawable.setCallback(this);
if (drawable.isStateful()) {
drawable.setState(getDrawableState());
}
}
requestLayout();
}
@Override
protected void drawableStateChanged() {
super.drawableStateChanged();
Drawable d = mDrawable;
if (d != null && d.isStateful()) {
d.setState(getDrawableState());
}
}
@Override
public void invalidateDrawable(@NonNull Drawable who) {
invalidate();
}
@Override
protected int getSuggestedMinimumWidth() {
int superMinWidth = super.getSuggestedMinimumWidth();
return (mDrawable == null) ? superMinWidth :
Math.max(superMinWidth, mDrawable.getMinimumWidth() + getPaddingLeft() + getPaddingRight());
}
@Override
protected int getSuggestedMinimumHeight() {
int superMinHeight = super.getSuggestedMinimumHeight();
return (mDrawable == null) ? superMinHeight :
Math.max(superMinHeight, mDrawable.getMinimumHeight() + getPaddingTop() + getPaddingBottom());
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(ViewUtils.getSuitableSize(getSuggestedMinimumWidth(), widthMeasureSpec),
ViewUtils.getSuitableSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
int width = right - left;
int height = bottom - top;
if (mDrawable != null) {
mDrawable.setBounds(getPaddingLeft(), getPaddingTop(),
width - getPaddingRight(), height - getPaddingBottom());
}
}
@Override
protected void onDraw(Canvas canvas) {
if (mDrawable != null) {
mDrawable.draw(canvas);
}
}
}
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2015 Hippo Seven
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<set>
<alpha
xmlns:android="http://schemas.android.com/apk/res/android"
android:fromAlpha="0.0"
android:toAlpha="1.0"
android:duration="300"/>
</set>
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2015 Hippo Seven
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<set>
<alpha
xmlns:android="http://schemas.android.com/apk/res/android"
android:fromAlpha="1.0"
android:toAlpha="0.0"
android:duration="300"/>
</set>
Binary file not shown.

After

Width:  |  Height:  |  Size: 151 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 365 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 325 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 396 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 348 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 387 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 413 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 564 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 447 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 557 B

+32
View File
@@ -0,0 +1,32 @@
<?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"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:width="48dp"
android:height="48dp"
app:width="48dp"
app:height="48dp"
app:viewportWidth="24"
app:viewportHeight="24">
<path
app:pathData="@string/pd_alert"
app:fillColor="@color/red_500"/>
</vector>
+41
View File
@@ -0,0 +1,41 @@
<?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.
-->
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/draw_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"/>
<android.support.design.widget.NavigationView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="left"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_main"
app:menu="@menu/nav_drawer_main"/>
</android.support.v4.widget.DrawerLayout>
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2016 Hippo Seven
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2016 Hippo Seven
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
</LinearLayout>
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2016 Hippo Seven
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="gallery list"/>
</LinearLayout>
+171
View File
@@ -0,0 +1,171 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2016 Hippo Seven
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ScrollView
android:id="@+id/login_form"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="@dimen/keyline_margin">
<com.hippo.widget.SimpleImageView
android:id="@+id/icon_alert"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:padding="@dimen/keyline_margin"
android:src="@mipmap/ic_launcher"/>
<android.support.design.widget.TextInputLayout
android:id="@+id/username_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:minWidth="@dimen/single_max_width">
<EditText
android:id="@+id/username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/username"
android:inputType="text"
android:maxLines="1"
android:singleLine="true"/>
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="@+id/password_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:minWidth="@dimen/single_max_width">
<EditText
android:id="@+id/password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/password"
android:imeOptions="actionDone"
android:inputType="textPassword"
android:maxLines="1"
android:singleLine="true"/>
</android.support.design.widget.TextInputLayout>
<android.support.v4.widget.Space
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"/>
<LinearLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<android.support.v7.widget.CardView
android:id="@+id/register"
style="@style/CardView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_margin="@dimen/keyline_margin"
android:minHeight="@dimen/button_min_height"
app:cardBackgroundColor="@color/purple_500">
<TextView
style="@style/TextAppearance.AppCompat.Medium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/register"
android:textAllCaps="true"
android:textColor="@android:color/white"/>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:id="@+id/sign_in"
style="@style/CardView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_margin="@dimen/keyline_margin"
android:minHeight="@dimen/button_min_height"
app:cardBackgroundColor="?attr/colorPrimary">
<TextView
style="@style/TextAppearance.AppCompat.Medium.Inverse"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/sign_in"
android:textAllCaps="true"
android:textColor="@android:color/white"/>
</android.support.v7.widget.CardView>
</LinearLayout>
<TextView
android:id="@+id/sign_in_via_webview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="8dp"
android:text="@string/sign_in_via_webview"
android:textColor="?attr/colorAccent"/>
<TextView
android:id="@+id/sign_in_via_cookies"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="@string/sign_in_via_cookies"
android:textColor="?attr/colorAccent"/>
</LinearLayout>
</ScrollView>
<FrameLayout
android:id="@+id/progress"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/translucent_bg"
android:clickable="true"
android:visibility="gone">
<com.hippo.widget.ProgressView
style="@style/ProgressView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"/>
</FrameLayout>
</FrameLayout>
+107
View File
@@ -0,0 +1,107 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2016 Hippo Seven
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/keyline_margin"
android:orientation="vertical">
<com.hippo.widget.SimpleImageView
android:id="@+id/icon_alert"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:padding="@dimen/keyline_margin"/>
<com.hippo.widget.MaxSizeContainer
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_gravity="center_horizontal"
app:maxWidth="@dimen/single_max_width">
<ScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="@dimen/keyline_margin"
android:paddingBottom="@dimen/keyline_margin"
android:clipToPadding="false">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/app_waring"
android:textColor="@android:color/black"
android:textSize="@dimen/text_little_small"
android:lineSpacingExtra="8dp"/>
</ScrollView>
</com.hippo.widget.MaxSizeContainer>
<LinearLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<android.support.v7.widget.CardView
android:id="@+id/cancel"
style="@style/CardView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_margin="@dimen/keyline_margin"
android:minHeight="@dimen/button_min_height"
app:cardBackgroundColor="@color/purple_500">
<TextView
style="@style/TextAppearance.AppCompat.Medium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@android:string/cancel"
android:textAllCaps="true"
android:textColor="@android:color/white"/>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:id="@+id/ok"
style="@style/CardView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_margin="@dimen/keyline_margin"
android:minHeight="@dimen/button_min_height"
app:cardBackgroundColor="?attr/colorPrimary">
<TextView
style="@style/TextAppearance.AppCompat.Medium.Inverse"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@android:string/ok"
android:textAllCaps="true"
android:textColor="@android:color/white"/>
</android.support.v7.widget.CardView>
</LinearLayout>
</LinearLayout>
+53
View File
@@ -0,0 +1,53 @@
<?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.
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:checkableBehavior="single">
<item
android:id="@+id/nav_homepage"
android:title="@string/homepage"
android:icon="@drawable/ic_homepage_x24"/>
<item
android:id="@+id/nav_whats_hot"
android:title="@string/whats_hot"
android:icon="@drawable/ic_whats_hot_x24"/>
<item
android:id="@+id/nav_favourite"
android:title="@string/favourite"
android:icon="@drawable/ic_favourite_x24"/>
<item
android:id="@+id/nav_history"
android:title="@string/history"
android:icon="@drawable/ic_history_x24"/>
<item
android:id="@+id/nav_download"
android:title="@string/download"
android:icon="@drawable/ic_download_x24"/>
<item
android:id="@+id/nav_settings"
android:title="@string/settings"
android:icon="@drawable/ic_settings_x24"/>
</group>
</menu>
Binary file not shown.

After

Width:  |  Height:  |  Size: 979 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 654 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

+25
View File
@@ -0,0 +1,25 @@
<?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>
<style name="AppTheme.Main" parent="AppTheme.NoActionBar">
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
</resources>
@@ -0,0 +1,49 @@
<?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</string>
<string name="homepage">主页</string>
<string name="whats_hot">热门</string>
<string name="favourite">收藏</string>
<string name="history">历史</string>
<string name="download">下载</string>
<string name="settings">设置</string>
<string name="username">用户名</string>
<string name="password">密码</string>
<string name="sign_in">登陆</string>
<string name="register">注册</string>
<string name="sign_in_via_webview">通过网页登陆</string>
<string name="sign_in_via_cookies">通过 Cookie 登陆</string>
<string name="error_bad_status_code">错误的状态码:%d</string>
<string name="error_timeout">超时</string>
<string name="error_unknown_host">未知主机</string>
<string name="error_redirection">太多重定向</string>
<string name="error_socket">网络错误</string>
<string name="error_unknown">奇怪的错误</string>
<string name="error_username_cannot_empty">用户名不可为空</string>
<string name="error_password_cannot_empty">密码不可为空</string>
<string name="app_waring">本应用中内容来自互联网,部分内容可能对您的生理及心理造成难以恢复的伤害。本应用作者不会对由本应用造成的后果负责。您是否愿意继续使用该应用?</string>
</resources>
@@ -0,0 +1,29 @@
<?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</string>
<string name="homepage">主頁</string>
<string name="whats_hot">熱門</string>
<string name="favourite">收藏</string>
<string name="history">歷史</string>
<string name="download">下載</string>
<string name="settings">設置</string>
</resources>
@@ -0,0 +1,29 @@
<?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</string>
<string name="homepage">主頁</string>
<string name="whats_hot">熱門</string>
<string name="favourite">收藏</string>
<string name="history">歷史</string>
<string name="download">下載</string>
<string name="settings">設定</string>
</resources>
+31
View File
@@ -0,0 +1,31 @@
<?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>
<declare-styleable name="ProgressView">
<attr name="color"/>
<attr name="indeterminate" format="boolean"/>
<attr name="progress" format="float"/>
</declare-styleable>
<declare-styleable name="MaxSizeContainer">
<attr name="maxWidth" format="dimension"/>
<attr name="maxHeight" format="dimension"/>
</declare-styleable>
</resources>
+37
View File
@@ -0,0 +1,37 @@
<?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>
<!-- primary_drawable_light 54% -->
<!-- secondary_drawable_light 26% -->
<!-- primary_drawable_dark 100% -->
<!-- secondary_drawable_dark 30% -->
<color name="red_500">#fff44336</color>
<color name="teal_500">#ff009688</color>
<color name="teal_700">#ff00796b</color>
<color name="purple_500">#ff9c27b0</color>
<color name="purple_a200">#ffe040fb</color>
<color name="colorPrimary">@color/teal_500</color>
<color name="colorPrimaryDark">@color/teal_700</color>
<color name="colorAccent">@color/purple_a200</color>
<color name="translucent_bg">#80ffffff</color>
</resources>
+34
View File
@@ -0,0 +1,34 @@
<!--
~ 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>
<dimen name="keyline_margin">16dp</dimen>
<dimen name="single_max_width">260dp</dimen>
<dimen name="button_min_height">40dp</dimen>
<!-- Text size -->
<dimen name="text_super_large">24sp</dimen>
<dimen name="text_large">22sp</dimen>
<dimen name="text_little_large">20sp</dimen>
<dimen name="text_medium">18sp</dimen>
<dimen name="text_little_small">16sp</dimen>
<dimen name="text_small">14sp</dimen>
<dimen name="text_super_small">12sp</dimen>
</resources>
+22
View File
@@ -0,0 +1,22 @@
<?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="pd_alert" translatable="false">M13,14H11V10H13M13,18H11V16H13M1,21H23L12,2L1,21Z</string>
</resources>
+80
View File
@@ -0,0 +1,80 @@
<?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</string>
<string name="homepage">Homepage</string>
<string name="whats_hot">What\'s hot</string>
<string name="favourite">Favourite</string>
<string name="history">History</string>
<string name="download">Download</string>
<string name="settings">Settings</string>
<string name="username">Username</string>
<string name="password">Password</string>
<string name="sign_in">Sign in</string>
<string name="register">Register</string>
<string name="sign_in_via_webview">Sign in via WebView</string>
<string name="sign_in_via_cookies">Sign in via cookies</string>
<string name="error_status_code_400">Bad Request</string>
<string name="error_status_code_401">Unauthorized</string>
<string name="error_status_code_402">Payment Required</string>
<string name="error_status_code_403">Forbidden</string>
<string name="error_status_code_404">Not Found</string>
<string name="error_status_code_405">Method Not Allowed</string>
<string name="error_status_code_406">Not Acceptable</string>
<string name="error_status_code_407">Proxy Authentication Required</string>
<string name="error_status_code_408">Request Timeout</string>
<string name="error_status_code_409">Conflict</string>
<string name="error_status_code_410">Gone</string>
<string name="error_status_code_411">Length Required</string>
<string name="error_status_code_412">Precondition Failed</string>
<string name="error_status_code_413">Request Entity Too Large</string>
<string name="error_status_code_414">Request-URI Too Long</string>
<string name="error_status_code_415">Unsupported Media Type</string>
<string name="error_status_code_416">Requested Range Not Satisfiable</string>
<string name="error_status_code_417">Expectation Failed</string>
<string name="error_status_code_500">Internal Server Error</string>
<string name="error_status_code_501">Not Implemented</string>
<string name="error_status_code_502">Bad Gateway</string>
<string name="error_status_code_503">Service Unavailable</string>
<string name="error_status_code_504">Gateway Timeout</string>
<string name="error_status_code_505">HTTP Version Not Supported</string>
<string name="error_bad_status_code">Bad status code: %d</string>
<string name="error_timeout">Timeout</string>
<string name="error_unknown_host">Unknown host</string>
<string name="error_redirection">Too many redirections</string>
<string name="error_socket">Network error</string>
<string name="error_unknown">Weird</string>
<string name="error_username_cannot_empty">Username cannot be an empty string</string>
<string name="error_password_cannot_empty">Password cannot be an empty string</string>
<string name="app_waring">The content of this application is from the Internet. Some of it may do physical or mental harm to you. You have learnt the risks above and would like to undertake them. Do you want to use this application?</string>
<string name="skip_signing_in">Skip signing in</string>
<string name="skip_signing_in_plain">Sign in failed. But perhaps it is a mistake due to website update. Do you want to skip signing in.</string>
</resources>
+38
View File
@@ -0,0 +1,38 @@
<?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>
<!-- Progress View -->
<style name="ProgressView">
<item name="color">?attr/colorAccent</item>
<item name="indeterminate">true</item>
<item name="android:minWidth">48dp</item>
<item name="android:minHeight">48dp</item>
</style>
<style name="ProgressView.Small">
<item name="android:minWidth">16dp</item>
<item name="android:minHeight">16dp</item>
</style>
<style name="ProgressView.Large">
<item name="android:minWidth">76dp</item>
<item name="android:minHeight">76dp</item>
</style>
</resources>
+35
View File
@@ -0,0 +1,35 @@
<?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>
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
<style name="AppTheme.Main" parent="AppTheme.NoActionBar">
</style>
</resources>
@@ -0,0 +1,15 @@
package com.hippo.ehviewer;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* To work on unit tests, switch the Test Artifact in the Build Variants view.
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2);
}
}
Submodule
+1
Submodule beerbelly added at 6163029f62.
+23
View File
@@ -0,0 +1,23 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.3.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
Submodule
+1
Submodule conaco added at 248ce509cf.
+1
View File
@@ -0,0 +1 @@
/build
+27
View File
@@ -0,0 +1,27 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
apply plugin: 'java'
task executeDaoGenerator(type:JavaExec) {
main = 'com.hippo.ehviewer.daogenerator.Main'
classpath = sourceSets.main.runtimeClasspath
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile('de.greenrobot:greendao-generator:2.0.0')
}
@@ -0,0 +1,58 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.daogenerator;
import java.io.File;
import de.greenrobot.daogenerator.DaoGenerator;
import de.greenrobot.daogenerator.Entity;
import de.greenrobot.daogenerator.Schema;
public class CookieDaoGenerator {
private static final String PACKAGE = "com.hippo.okhttp.dao";
private static final String OUT_DIR = "../app/src/main/java-gen";
private static final String DELETE_DIR = "../app/src/main/java-gen/com/hippo/okhttp/dao";
public static void generate() throws Exception {
Utilities.deleteContents(new File(DELETE_DIR));
File outDir = new File(OUT_DIR);
outDir.delete();
outDir.mkdirs();
Schema schema = new Schema(1, PACKAGE);
addOkHttp3Cookie(schema);
new DaoGenerator().generateAll(schema, OUT_DIR);
}
private static void addOkHttp3Cookie(Schema schema) {
Entity entity = schema.addEntity("OkHttp3CookieRaw");
entity.setTableName("OK_HTTP_3_COOKIE");
entity.setClassNameDao("OkHttp3CookieDao");
entity.addIdProperty();
entity.addStringProperty("name");
entity.addStringProperty("value");
entity.addLongProperty("expiresAt");
entity.addStringProperty("domain");
entity.addStringProperty("path");
entity.addBooleanProperty("secure");
entity.addBooleanProperty("httpOnly");
entity.addBooleanProperty("persistent");
entity.addBooleanProperty("hostOnly");
}
}
@@ -0,0 +1,24 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.daogenerator;
public class Main {
public static void main(String args[]) throws Exception {
CookieDaoGenerator.generate();
}
}
@@ -0,0 +1,38 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.daogenerator;
import java.io.File;
public final class Utilities {
public static boolean deleteContents(File dir) {
File[] files = dir.listFiles();
boolean success = true;
if (files != null) {
for (File file : files) {
if (file.isDirectory()) {
success &= deleteContents(file);
}
if (!file.delete()) {
success = false;
}
}
}
return success;
}
}
+1
Submodule easyrecyclerview added at afe6b32013.
+18
View File
@@ -0,0 +1,18 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
Loaded 100 of 198 files, more files were not shown because too many files have changed in this diff. Show more