diff --git a/app/src/main/java/com/hippo/ehviewer/Settings.java b/app/src/main/java/com/hippo/ehviewer/Settings.java
index 785a3eedc..e16c93ada 100644
--- a/app/src/main/java/com/hippo/ehviewer/Settings.java
+++ b/app/src/main/java/com/hippo/ehviewer/Settings.java
@@ -298,6 +298,72 @@ public class Settings {
putString(KEY_EXCLUDED_LANGUAGES, value);
}
+ private static final String KEY_HATH_PROXY = "hath_proxy";
+ private static final boolean DEFAULT_HATH_PROXY = false;
+
+ public static boolean getHathProxy() {
+ return getBoolean(KEY_HATH_PROXY, DEFAULT_HATH_PROXY);
+ }
+
+ public static void putHathProxy(boolean value) {
+ if (value) {
+ sEhConfig.hahClientIp = Settings.getHathIp();
+ sEhConfig.hahClientPort = Settings.getHathPort();
+ sEhConfig.hahClientPasskey = Settings.getHathPasskey();
+ } else {
+ sEhConfig.hahClientIp = DEFAULT_HATH_IP;
+ sEhConfig.hahClientPort = DEFAULT_HATH_PORT;
+ sEhConfig.hahClientPasskey = DEFAULT_HATH_PASSKEY;
+ }
+ sEhConfig.setDirty();
+ putBoolean(KEY_HATH_PROXY, value);
+ }
+
+ private static final String KEY_HATH_IP = "hath_ip";
+ private static final String DEFAULT_HATH_IP = null;
+
+ public static String getHathIp() {
+ return getString(KEY_HATH_IP, DEFAULT_HATH_IP);
+ }
+
+ public static void putHathIp(String value) {
+ if (Settings.getHathProxy()) {
+ sEhConfig.hahClientIp = value;
+ sEhConfig.setDirty();
+ }
+ putString(KEY_HATH_IP, value);
+ }
+
+ private static final String KEY_HATH_PORT = "hath_port";
+ private static final int DEFAULT_HATH_PORT = -1;
+
+ public static int getHathPort() {
+ return getInt(KEY_HATH_PORT, DEFAULT_HATH_PORT);
+ }
+
+ public static void putHathPort(int value) {
+ if (Settings.getHathProxy()) {
+ sEhConfig.hahClientPort = value;
+ sEhConfig.setDirty();
+ }
+ putInt(KEY_HATH_PORT, value);
+ }
+
+ private static final String KEY_HATH_PASSKEY = "hath_passkey";
+ private static final String DEFAULT_HATH_PASSKEY = null;
+
+ public static String getHathPasskey() {
+ return getString(KEY_HATH_PASSKEY, DEFAULT_HATH_PASSKEY);
+ }
+
+ public static void putHathPasskey(String value) {
+ if (Settings.getHathProxy()) {
+ sEhConfig.hahClientPasskey = value;
+ sEhConfig.setDirty();
+ }
+ putString(KEY_HATH_PASSKEY, value);
+ }
+
/********************
****** Read
********************/
diff --git a/app/src/main/java/com/hippo/ehviewer/client/EhConfig.java b/app/src/main/java/com/hippo/ehviewer/client/EhConfig.java
index dd4e0c651..792913306 100644
--- a/app/src/main/java/com/hippo/ehviewer/client/EhConfig.java
+++ b/app/src/main/java/com/hippo/ehviewer/client/EhConfig.java
@@ -16,7 +16,7 @@
package com.hippo.ehviewer.client;
-import android.text.TextUtils;
+import com.hippo.network.InetValidator;
/**
* Some configurable stuff about EH. It ends up cookie.
@@ -623,8 +623,10 @@ public class EhConfig implements Cloneable {
}
private void updateUconfig() {
- String hahClientIpPort = (TextUtils.isEmpty(hahClientIp) || hahClientPort == -1) ?
- "" : hahClientIp + "%3A" + hahClientPort;
+ String hahClientIpPort = (InetValidator.isValidInet4Address(hahClientIp) &&
+ InetValidator.isValidInetPort(hahClientPort)) ?
+ hahClientIp + "%3A" + hahClientPort : "";
+ String hahClientPasskey = null == this.hahClientPasskey ? "" : this.hahClientPasskey;
mUconfig = KEY_LOAD_FROM_HAH + "_" + loadFromHAH + "-" +
KEY_SCALE_WIDTH + "_" + scaleWidth + "-" +
KEY_SCALE_HEIGHT + "_" + scaleHeight + "-" +
diff --git a/app/src/main/java/com/hippo/ehviewer/preference/HatHProxyPreference.java b/app/src/main/java/com/hippo/ehviewer/preference/HatHProxyPreference.java
new file mode 100644
index 000000000..8f745ef2d
--- /dev/null
+++ b/app/src/main/java/com/hippo/ehviewer/preference/HatHProxyPreference.java
@@ -0,0 +1,197 @@
+/*
+ * 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.preference;
+
+import android.annotation.SuppressLint;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.support.annotation.Nullable;
+import android.support.design.widget.TextInputLayout;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.widget.SwitchCompat;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.EditText;
+
+import com.hippo.ehviewer.R;
+import com.hippo.ehviewer.Settings;
+import com.hippo.network.InetValidator;
+import com.hippo.preference.DialogPreference;
+import com.hippo.yorozuya.ViewUtils;
+
+public class HatHProxyPreference extends DialogPreference implements View.OnClickListener {
+
+ @Nullable
+ private SwitchCompat mEnable;
+ @Nullable
+ private TextInputLayout mIpInputLayout;
+ @Nullable
+ private EditText mIp;
+ @Nullable
+ private TextInputLayout mPortInputLayout;
+ @Nullable
+ private EditText mPort;
+ @Nullable
+ private TextInputLayout mPasskeyInputLayout;
+ @Nullable
+ private EditText mPasskey;
+
+ public HatHProxyPreference(Context context) {
+ super(context);
+ init();
+ }
+
+ public HatHProxyPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ public HatHProxyPreference(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init();
+ }
+
+ public HatHProxyPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ init();
+ }
+
+ private void init() {
+ setDialogLayoutResource(R.layout.preference_dialog_hath_proxy);
+ updateSummary(Settings.getHathProxy(), Settings.getHathIp(), Settings.getHathPort());
+ }
+
+ private void updateSummary(boolean hathProxy, String hathIp, int hathPort) {
+ if (InetValidator.isValidInet4Address(hathIp) && InetValidator.isValidInetPort(hathPort)) {
+ Context context = getContext();
+ setSummary(context.getString(R.string.settings_eh_hath_proxy_summary_1,
+ context.getString(hathProxy ? R.string.enabled : R.string.disabled), hathIp, hathPort));
+ } else {
+ setSummary(R.string.settings_eh_hath_proxy_summary_2);
+ }
+ }
+
+ @Override
+ protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
+ super.onPrepareDialogBuilder(builder);
+ builder.setPositiveButton(android.R.string.ok, null);
+ }
+
+ @Override
+ @SuppressLint("SetTextI18n")
+ protected void onDialogCreated(AlertDialog dialog) {
+ super.onDialogCreated(dialog);
+
+ dialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(this);
+
+ mEnable = (SwitchCompat) ViewUtils.$$(dialog, R.id.enable);
+ mIpInputLayout = (TextInputLayout) ViewUtils.$$(dialog, R.id.ip_input_layout);
+ mIp = (EditText) ViewUtils.$$(dialog, R.id.ip);
+ mPortInputLayout = (TextInputLayout) ViewUtils.$$(dialog, R.id.port_input_layout);
+ mPort = (EditText) ViewUtils.$$(dialog, R.id.port);
+ mPasskeyInputLayout = (TextInputLayout) ViewUtils.$$(dialog, R.id.passkey_input_layout);
+ mPasskey = (EditText) ViewUtils.$$(dialog, R.id.passkey);
+
+ mEnable.setChecked(Settings.getHathProxy());
+ String ip = Settings.getHathIp();
+ if (!InetValidator.isValidInet4Address(ip)) {
+ ip = null;
+ }
+ String portString;
+ int port = Settings.getHathPort();
+ if (!InetValidator.isValidInetPort(port)) {
+ portString = null;
+ } else {
+ portString = Integer.toString(Settings.getHathPort());
+ }
+ mIp.setText(ip);
+ mPort.setText(portString);
+ mPasskey.setText(Settings.getHathPasskey());
+ }
+
+ @Override
+ protected void onDialogClosed(boolean positiveResult) {
+ super.onDialogClosed(positiveResult);
+ mEnable = null;
+ mIpInputLayout = null;
+ mIp = null;
+ mPortInputLayout = null;
+ mPort = null;
+ mPasskeyInputLayout = null;
+ mPasskey = null;
+ }
+
+ @Override
+ public void onClick(View v) {
+ Dialog dialog = getDialog();
+ Context context = getContext();
+ if (null == dialog || null == context || null == mEnable ||
+ null == mIpInputLayout || null == mIp ||
+ null == mPortInputLayout || null == mPort ||
+ null == mPasskeyInputLayout || null == mPasskey) {
+ return;
+ }
+
+ boolean enable = mEnable.isChecked();
+
+ String ip = mIp.getText().toString().trim();
+ if (ip.isEmpty()) {
+ if (enable) {
+ mIpInputLayout.setError(context.getString(R.string.text_is_empty));
+ return;
+ }
+ } else if (!InetValidator.isValidInet4Address(ip)) {
+ mIpInputLayout.setError(context.getString(R.string.domain_not_supported));
+ return;
+ } else {
+ mIpInputLayout.setError(null);
+ }
+
+ int port;
+ String portString = mPort.getText().toString().trim();
+ if (portString.isEmpty()) {
+ if (enable) {
+ mPortInputLayout.setError(context.getString(R.string.text_is_empty));
+ return;
+ } else {
+ port = -1;
+ }
+ } else {
+ try {
+ port = Integer.parseInt(portString);
+ } catch (NumberFormatException e) {
+ port = -1;
+ }
+ if (!InetValidator.isValidInetPort(port)) {
+ mPortInputLayout.setError(context.getString(R.string.invalid_port));
+ return;
+ }
+ }
+
+ String passkey = mPasskey.getText().toString();
+
+ Settings.putHathProxy(enable);
+ Settings.putHathIp(ip);
+ Settings.putHathPort(port);
+ Settings.putHathPasskey(passkey);
+
+ updateSummary(enable, ip, port);
+
+ dialog.dismiss();
+ }
+}
diff --git a/app/src/main/java/com/hippo/network/InetValidator.java b/app/src/main/java/com/hippo/network/InetValidator.java
new file mode 100644
index 000000000..540f3a105
--- /dev/null
+++ b/app/src/main/java/com/hippo/network/InetValidator.java
@@ -0,0 +1,66 @@
+/*
+ * 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 java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public final class InetValidator {
+
+ private static final String IPV4_REGEX =
+ "^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$";
+
+ private static final Pattern IPV4_PATTERN = Pattern.compile(IPV4_REGEX);
+
+ public static boolean isValidInet4Address(String inet4Address) {
+ if (null == inet4Address) {
+ return false;
+ }
+
+ Matcher matcher = IPV4_PATTERN.matcher(inet4Address);
+ if (!matcher.find()) {
+ return false;
+ }
+
+ // verify that address subgroups are legal
+ for (int i = 1; i <= 4; i++) {
+ String ipSegment = matcher.group(i);
+ if (ipSegment == null || ipSegment.length() == 0) {
+ return false;
+ }
+ int iIpSegment;
+ try {
+ iIpSegment = Integer.parseInt(ipSegment);
+ } catch(NumberFormatException e) {
+ return false;
+ }
+ if (iIpSegment > 255) {
+ return false;
+ }
+ if (ipSegment.length() > 1 && ipSegment.startsWith("0")) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static boolean isValidInetPort(int inetPort) {
+ return inetPort >= 0 && inetPort <= 65535;
+ }
+
+ private InetValidator() {}
+}
diff --git a/app/src/main/res/layout/preference_dialog_hath_proxy.xml b/app/src/main/res/layout/preference_dialog_hath_proxy.xml
new file mode 100644
index 000000000..7f22fee42
--- /dev/null
+++ b/app/src/main/res/layout/preference_dialog_hath_proxy.xml
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml
index 461b08d9c..0d01fbda5 100644
--- a/app/src/main/res/values-zh-rCN/strings.xml
+++ b/app/src/main/res/values-zh-rCN/strings.xml
@@ -332,6 +332,9 @@
在默认搜索中排除指定标签组
排除语言
在主页与搜索中隐藏指定语言的画廊
+ H@H
+ %1$s %2$s:%3$d
+ 未设置
显示日文标题
尝试显示日文标题。这会使获取画廊列表花费更多时间
显示默认标题。一般是英文标题
@@ -438,6 +441,15 @@
N/A
其他
+ 启用
+ 已启用
+ 未启用
+ IP
+ 端口
+ 密钥
+ 不支持域名
+ 无效的端口
+
开源许可
diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml
index 4fa4ac74a..ae9b2c795 100644
--- a/app/src/main/res/values-zh-rHK/strings.xml
+++ b/app/src/main/res/values-zh-rHK/strings.xml
@@ -332,6 +332,9 @@
在默認搜索中排除指定標籤組
排除語言
在主頁與搜索中隱藏指定語言的畫廊
+ H@H
+ %1$s %2$s:%3$d
+ 未設置
顯示日文標題
嘗試顯示日文標題。這會使獲取畫廊列表花費更多時間
顯示默認標題。一般是英文標題
@@ -438,6 +441,15 @@
N/A
其他
+ 啟用
+ 已啟用
+ 未啟用
+ IP
+ 端口
+ 密鑰
+ 不支持域名
+ 無效的端口
+
開源許可
diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml
index f22d57077..92ce36173 100644
--- a/app/src/main/res/values-zh-rTW/strings.xml
+++ b/app/src/main/res/values-zh-rTW/strings.xml
@@ -332,6 +332,9 @@
在預設搜尋中排除指定標籤組
排除語言
在主頁與搜尋中隱藏指定語言的畫廊
+ H@H
+ %1$s %2$s:%3$d
+ 未設定
顯示日文標題
嘗試顯示日文標題。這會使獲取畫廊列表花費更多時間
顯示預設標題。一般是英文標題
@@ -438,6 +441,15 @@
N/A
其他
+ 啟用
+ 已啟用
+ 未啟用
+ IP
+ 埠
+ 金鑰
+ 不支援域名
+ 無效的埠
+
開源許可
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 57e156436..8943d9c0b 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -374,6 +374,9 @@
Hide galleries in certain languages from the gallery list and searches
Excluded tag namespaces
Exclude certain namespaces from a default tag search
+ H@H proxy
+ %1$s %2$s:%3$d
+ None
Show Japanese title
Try to show Japanese title. It takes more time to get gallery list
Show default title. It is usually English title
@@ -458,6 +461,15 @@
Beta update channel
Beta release might be broken on your devices
+ Enable
+ Enabled
+ Disabled
+ IP
+ Port
+ Passkey
+ Domain is not supported
+ Invalid port
+
Excluded languages
All
diff --git a/app/src/main/res/xml/eh_settings.xml b/app/src/main/res/xml/eh_settings.xml
index 5e27d84da..1f35c943a 100644
--- a/app/src/main/res/xml/eh_settings.xml
+++ b/app/src/main/res/xml/eh_settings.xml
@@ -56,6 +56,10 @@
android:summary="@string/settings_eh_excluded_languages_summary"
app:activity="com.hippo.ehviewer.ui.ExcludedLanguagesActivity"/>
+
+