diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 27eb8daf7..75b9a314f 100755 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -132,6 +132,12 @@ android:theme="@style/AppTheme.NoActionBar" android:label="@string/set_pattern_protection"/> + + diff --git a/app/src/main/java/com/hippo/ehviewer/client/EhUrl.java b/app/src/main/java/com/hippo/ehviewer/client/EhUrl.java index d7e1bf2b8..1ee8516aa 100644 --- a/app/src/main/java/com/hippo/ehviewer/client/EhUrl.java +++ b/app/src/main/java/com/hippo/ehviewer/client/EhUrl.java @@ -52,6 +52,9 @@ public class EhUrl { public static final String URL_FAVORITES_EX = HOST_EX + "favorites.php"; public static final String URL_FORUMS = "https://forums.e-hentai.org/"; + public static final String UCONFIG_E = HOST_E + "uconfig.php"; + public static final String UCONFIG_EX = HOST_EX + "uconfig.php"; + private static final String URL_PREFIX_THUMB_E = "https://ehgt.org/t/"; private static final String URL_PREFIX_THUMB_EX = "https://exhentai.org/t/"; @@ -89,6 +92,16 @@ public class EhUrl { } } + public static String getUConfigUrl() { + switch (Settings.getGallerySite()) { + default: + case SITE_E: + return UCONFIG_E; + case SITE_EX: + return UCONFIG_EX; + } + } + public static String getGalleryDetailUrl(long gid, String token, int index, boolean allComment) { UrlBuilder builder = new UrlBuilder(getHost() + "g/" + gid + '/' + token + '/'); if (index != 0) { diff --git a/app/src/main/java/com/hippo/ehviewer/ui/UConfigActivity.java b/app/src/main/java/com/hippo/ehviewer/ui/UConfigActivity.java new file mode 100644 index 000000000..3a68f2f8d --- /dev/null +++ b/app/src/main/java/com/hippo/ehviewer/ui/UConfigActivity.java @@ -0,0 +1,255 @@ +/* + * Copyright 2018 Hippo Seven + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.hippo.ehviewer.ui; + +/* + * Created by Hippo on 2018/2/9. + */ + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.DialogInterface; +import android.graphics.Bitmap; +import android.os.Build; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v7.app.AlertDialog; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.webkit.CookieManager; +import android.webkit.CookieSyncManager; +import android.webkit.JsPromptResult; +import android.webkit.JsResult; +import android.webkit.WebChromeClient; +import android.webkit.WebView; +import android.webkit.WebViewClient; +import android.widget.EditText; +import android.widget.TextView; +import com.hippo.ehviewer.EhApplication; +import com.hippo.ehviewer.R; +import com.hippo.ehviewer.client.EhCookieStore; +import com.hippo.ehviewer.client.EhUrl; +import com.hippo.widget.ProgressView; +import okhttp3.Cookie; +import okhttp3.HttpUrl; + +public class UConfigActivity extends ToolbarActivity { + + private WebView webView; + private ProgressView progress; + private String url; + private boolean loaded; + + @SuppressLint("SetJavaScriptEnabled") + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // http://stackoverflow.com/questions/32284642/how-to-handle-an-uncatched-exception + CookieManager cookieManager = CookieManager.getInstance(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + cookieManager.flush(); + cookieManager.removeAllCookies(null); + cookieManager.removeSessionCookies(null); + } else { + CookieSyncManager cookieSyncManager = CookieSyncManager.createInstance(this); + cookieSyncManager.startSync(); + cookieManager.removeAllCookie(); + cookieManager.removeSessionCookie(); + cookieSyncManager.stopSync(); + } + + // Copy cookies from okhttp cookie store to CookieManager + url = EhUrl.getUConfigUrl(); + EhCookieStore store = EhApplication.getEhCookieStore(this); + for (Cookie cookie : store.getCookies(HttpUrl.parse(url))) { + cookieManager.setCookie(url, cookie.toString()); + } + + setContentView(R.layout.activity_u_config); + webView = (WebView) findViewById(R.id.webview); + webView.getSettings().setJavaScriptEnabled(true); + webView.setWebViewClient(new UConfigWebViewClient()); + webView.setWebChromeClient(new UConfigWebChromeClient()); + webView.loadUrl(url); + progress = (ProgressView) findViewById(R.id.progress); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + super.onCreateOptionsMenu(menu); + getMenuInflater().inflate(R.menu.activity_u_config, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + finish(); + return true; + case R.id.action_apply: + if (loaded) { + webView.loadUrl("javascript:" + + "(function() {\n" + + " var apply = document.getElementById(\"apply\").children[0];\n" + + " apply.click();\n" + + "})();"); + } + return true; + default: + return super.onOptionsItemSelected(item); + } + } + + private Cookie longLive(Cookie cookie) { + return new Cookie.Builder() + .name(cookie.name()) + .value(cookie.value()) + .domain(cookie.domain()) + .path(cookie.path()) + .expiresAt(Long.MAX_VALUE) + .build(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + webView.destroy(); + + // Put cookies back to okhttp cookie store + CookieManager cookieManager = CookieManager.getInstance(); + String cookiesString = cookieManager.getCookie(url); + + if (cookiesString != null && !cookiesString.isEmpty()) { + EhCookieStore store = EhApplication.getEhCookieStore(this); + HttpUrl eUrl = HttpUrl.parse(EhUrl.HOST_E); + HttpUrl exUrl = HttpUrl.parse(EhUrl.HOST_EX); + + // The cookies saved in the uconfig page should be shared between e and ex + for (String header : cookiesString.split(";")) { + Cookie eCookie = Cookie.parse(eUrl, header); + if (eCookie != null) { + store.addCookie(longLive(eCookie)); + } + + Cookie exCookie = Cookie.parse(exUrl, header); + if (exCookie != null) { + store.addCookie(longLive(exCookie)); + } + } + } + } + + private class UConfigWebViewClient extends WebViewClient { + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + // Never load other urls + return true; + } + + @Override + public void onPageStarted(WebView view, String url, Bitmap favicon) { + progress.setVisibility(View.VISIBLE); + loaded = false; + } + + @Override + public void onPageFinished(WebView view, String url) { + progress.setVisibility(View.GONE); + loaded = true; + } + } + + private class UConfigWebChromeClient extends WebChromeClient { + + private Context context = UConfigActivity.this; + + @Override + public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, + final JsPromptResult result) { + + View promptView = UConfigActivity.this.getLayoutInflater() + .inflate(R.layout.dialog_js_prompt, null, false); + TextView messageView = (TextView) promptView.findViewById(R.id.message); + messageView.setText(message); + final EditText valueView = (EditText) promptView.findViewById(R.id.value); + valueView.setText(defaultValue); + + new AlertDialog.Builder(context) + .setView(promptView) + .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + result.confirm(valueView.getText().toString()); + } + }) + .setOnCancelListener(new DialogInterface.OnCancelListener() { + @Override + public void onCancel(DialogInterface dialog) { + result.cancel(); + } + }) + .show(); + + return true; + } + + @Override + public boolean onJsAlert(WebView view, String url, String message, final JsResult result) { + new AlertDialog.Builder(context) + .setMessage(message) + .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + result.confirm(); + } + }) + .setOnCancelListener(new DialogInterface.OnCancelListener() { + @Override + public void onCancel(DialogInterface dialog) { + result.cancel(); + } + }) + .show(); + + return true; + } + + @Override + public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) { + new AlertDialog.Builder(context) + .setMessage(message) + .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + result.confirm(); + } + }) + .setOnCancelListener(new DialogInterface.OnCancelListener() { + @Override + public void onCancel(DialogInterface dialog) { + result.cancel(); + } + }) + .show(); + + return true; + } + } +} diff --git a/app/src/main/res/drawable/v_check_dark_x24.xml b/app/src/main/res/drawable/v_check_dark_x24.xml new file mode 100644 index 000000000..695620ecf --- /dev/null +++ b/app/src/main/res/drawable/v_check_dark_x24.xml @@ -0,0 +1,29 @@ + + + + + + + + diff --git a/app/src/main/res/layout/activity_u_config.xml b/app/src/main/res/layout/activity_u_config.xml new file mode 100644 index 000000000..841181f7f --- /dev/null +++ b/app/src/main/res/layout/activity_u_config.xml @@ -0,0 +1,38 @@ + + + + + + + + + + diff --git a/app/src/main/res/layout/dialog_js_prompt.xml b/app/src/main/res/layout/dialog_js_prompt.xml new file mode 100644 index 000000000..691f8b9f8 --- /dev/null +++ b/app/src/main/res/layout/dialog_js_prompt.xml @@ -0,0 +1,38 @@ + + + + + + + + + + diff --git a/app/src/main/res/menu/activity_u_config.xml b/app/src/main/res/menu/activity_u_config.xml new file mode 100644 index 000000000..a24c1244a --- /dev/null +++ b/app/src/main/res/menu/activity_u_config.xml @@ -0,0 +1,28 @@ + + + + + + + + diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index f52b945e9..4dededdb7 100755 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -348,6 +348,10 @@ 设置 允许使用指纹解锁 + + EHentai 设置 + 应用 + 第 %d 页 @string/refresh @@ -365,6 +369,8 @@ 天哪,我的老伙计,你要退出登录吗?我是说,你真的要退出登录吗? 是的,我是说,真的 已退出登录,重启应用以便再次登录 + EHentai 设置 + EHentai 网站上的设置 画廊站点 列表模式 详情 diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index e510553ae..fadf73abd 100755 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -348,6 +348,10 @@ 設置 允許使用指紋解鎖 + + EHentai 設置 + 應用 + 第 %d 頁 @string/refresh @@ -365,6 +369,8 @@ 天哪,我的老夥計,你要退出登錄嗎?我是説,你真的要退出登錄嗎? 是的,我是説,真的 已退出登錄,重啟應用以便再次登錄 + EHentai 設置 + EHentai 網站上的設置 畫廊站點 列表模式 詳情 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 13e2bf6ec..4e2c00bae 100755 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -348,6 +348,10 @@ 設定 允許使用指紋解鎖 + + EHentai 設定 + 應用 + 第 %d 頁 @string/refresh @@ -365,6 +369,8 @@ 天哪,老兄,你真的要登出嗎?我是說,你真的要登出嗎? 沒錯,我是說,對 已登出,重新啟動程式以再次登入 + EHentai 設定 + EHentai 網站上的設定 圖庫站台 列表模式 詳細資料 diff --git a/app/src/main/res/values/pathdata.xml b/app/src/main/res/values/pathdata.xml index a13598bb4..c85e6adb1 100644 --- a/app/src/main/res/values/pathdata.xml +++ b/app/src/main/res/values/pathdata.xml @@ -60,6 +60,7 @@ M2,20L17,10L22,22M14,9L2,8L11,2Z M17.65,6.35C16.2,4.9 14.21,4 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20C15.73,20 18.84,17.45 19.73,14H17.65C16.83,16.33 14.61,18 12,18A6,6 0 0,1 6,12A6,6 0 0,1 12,6C13.66,6 15.14,6.69 16.22,7.78L13,11H20V4L17.65,6.35Z M9,13A3,3 0 0,0 12,16A3,3 0 0,0 15,13A3,3 0 0,0 12,10A3,3 0 0,0 9,13M20,19.59V8L14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18C18.45,22 18.85,21.85 19.19,21.6L14.76,17.17C13.96,17.69 13,18 12,18A5,5 0 0,1 7,13A5,5 0 0,1 12,8A5,5 0 0,1 17,13C17,14 16.69,14.96 16.17,15.75L20,19.59Z + M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z M12.88,2H4V11L14.97,22.14L24,13.1L12.88,2ZM7.26,5.26C7.96,4.58,9.06,4.58,9.74,5.26C10.42,5.96,10.42,7.06,9.74,7.74S7.94,8.42,7.26,7.74S6.58,5.94,7.26,5.26ZM14.98,19.3L8.76,12.95L14.88,6.83L21.18,13.11L14.98,19.31ZM11.6,21.56L10.23,23L0,12.74V5H2V11.9L11.6,21.56Z M20.46,14.65C21.86,16.15,20.31,18.6,18.32,17.87C19.78,17.57,20.79,16.37,20.46,14.65ZM4.32,17.87C6.32,18.6,7.86,16.17,6.46,14.65C6.79,16.38,5.78,17.55,4.32,17.87ZM16.87,4.3C16.6,3.56,15.87,3,15,3C13.7,3,12.7,4.24,13.1,5.58C14.2,5.18,15.44,4.48,16.87,4.31ZM24,16C24,18.76,21.76,21,19,21C14.96,21,14.84,16.88,12,16.88S9.04,21,5,21C2.24,21,0,18.76,0,16C0,13.87,1.53,11.43,3.94,7.18C5.84,3.81,8.69,5.92,10.76,6.58C11.54,6.85,12.41,6.88,13.24,6.58C15.3,5.92,18.14,3.81,20.06,7.18C22.46,11.43,24,13.88,24,16ZM8,16C8,14.35,6.65,13,5,13S2,14.35,2,16S3.35,19,5,19S8,17.65,8,16ZM13,14C13,13.45,12.55,13,12,13S11,13.45,11,14S11.45,15,12,15S13,14.55,13,14ZM22,16C22,14.35,20.65,13,19,13S16,14.35,16,16S17.35,19,19,19S22,17.65,22,16ZM9,3C8.14,3,7.4,3.55,7.13,4.3C8.56,4.48,9.79,5.2,10.9,5.58C11.3,4.24,10.3,3,9,3Z diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8498acbe8..9a9e1bd5c 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -392,6 +392,10 @@ Set Also allow unlock with fingerprint + + EHentai settings + Apply + Page %d @string/refresh @@ -408,6 +412,8 @@ Do you really want to sign out? @android:string/ok Signed out, restart the application to sign in + EHentai settings + Settings on EHentai website Gallery site List mode Detail diff --git a/app/src/main/res/xml/eh_settings.xml b/app/src/main/res/xml/eh_settings.xml index 7c79a0969..8c1d24a8a 100644 --- a/app/src/main/res/xml/eh_settings.xml +++ b/app/src/main/res/xml/eh_settings.xml @@ -32,6 +32,12 @@ app:entryValues="@array/gallery_site_entry_values" android:defaultValue="1"/> + + - - - - - - - -