From 69a9d63e1d51213b4316c204519bdb8dab82e4af Mon Sep 17 00:00:00 2001 From: Pupil Date: Sat, 15 Feb 2020 12:40:10 +0900 Subject: [PATCH] Proxy added --- app/build.gradle | 2 +- .../pupil/ui/dialog/DefaultQueryDialog.kt | 20 ++- .../pupil/ui/dialog/DownloadLocationDialog.kt | 21 +-- .../quaver/pupil/ui/dialog/MirrorDialog.kt | 11 +- .../xyz/quaver/pupil/ui/dialog/ProxyDialog.kt | 127 ++++++++++++++++++ .../pupil/ui/fragment/SettingsFragment.kt | 28 +++- .../main/java/xyz/quaver/pupil/util/proxy.kt | 63 +++++++++ app/src/main/res/layout/dialog_proxy.xml | 123 +++++++++++++++++ app/src/main/res/values-ja/arrays.xml | 26 ++++ app/src/main/res/values-ja/strings.xml | 8 ++ app/src/main/res/values-ko/arrays.xml | 26 ++++ app/src/main/res/values-ko/strings.xml | 8 ++ app/src/main/res/values/arrays.xml | 6 + app/src/main/res/values/strings.xml | 10 ++ app/src/main/res/xml/root_preferences.xml | 4 + 15 files changed, 450 insertions(+), 33 deletions(-) create mode 100644 app/src/main/java/xyz/quaver/pupil/ui/dialog/ProxyDialog.kt create mode 100644 app/src/main/java/xyz/quaver/pupil/util/proxy.kt create mode 100644 app/src/main/res/layout/dialog_proxy.xml create mode 100644 app/src/main/res/values-ja/arrays.xml create mode 100644 app/src/main/res/values-ko/arrays.xml diff --git a/app/build.gradle b/app/build.gradle index ee89e59f..d97d70da 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -20,7 +20,7 @@ android { minSdkVersion 16 targetSdkVersion 29 versionCode 42 - versionName "4.6-beta3" + versionName "4.6-beta4" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" multiDexEnabled true vectorDrawables.useSupportLibrary = true diff --git a/app/src/main/java/xyz/quaver/pupil/ui/dialog/DefaultQueryDialog.kt b/app/src/main/java/xyz/quaver/pupil/ui/dialog/DefaultQueryDialog.kt index 125fa48b..3d39c6e4 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/dialog/DefaultQueryDialog.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/dialog/DefaultQueryDialog.kt @@ -46,16 +46,12 @@ class DefaultQueryDialog(context : Context) : AlertDialog(context) { private val excludeBL = "-male:yaoi" private val excludeGuro = listOf("-female:guro", "-male:guro") - private lateinit var dialogView : View - var onPositiveButtonClickListener : ((Tags) -> (Unit))? = null @SuppressLint("InflateParams") override fun onCreate(savedInstanceState: Bundle?) { - initDialog() - setTitle(R.string.default_query_dialog_title) - setView(dialogView) + setView(build()) setButton(Dialog.BUTTON_POSITIVE, context.getString(android.R.string.ok)) { _, _ -> val newTags = Tags.parse(default_query_dialog_edittext.text.toString()) @@ -79,15 +75,15 @@ class DefaultQueryDialog(context : Context) : AlertDialog(context) { } @SuppressLint("InflateParams") - private fun initDialog() { + private fun build() : View { val preferences = PreferenceManager.getDefaultSharedPreferences(context) val tags = Tags.parse( preferences.getString("default_query", "") ?: "" ) - dialogView = LayoutInflater.from(context).inflate(R.layout.dialog_default_query, null) + val view = LayoutInflater.from(context).inflate(R.layout.dialog_default_query, null) - with(dialogView.default_query_dialog_language_selector) { + with(view.default_query_dialog_language_selector) { adapter = ArrayAdapter( context, @@ -110,13 +106,13 @@ class DefaultQueryDialog(context : Context) : AlertDialog(context) { } } - with(dialogView.default_query_dialog_BL_checkbox) { + with(view.default_query_dialog_BL_checkbox) { isChecked = tags.contains(excludeBL) if (tags.contains(excludeBL)) tags.remove(excludeBL) } - with(dialogView.default_query_dialog_guro_checkbox) { + with(view.default_query_dialog_guro_checkbox) { isChecked = excludeGuro.all { tags.contains(it) } if (excludeGuro.all { tags.contains(it) }) excludeGuro.forEach { @@ -124,7 +120,7 @@ class DefaultQueryDialog(context : Context) : AlertDialog(context) { } } - with(dialogView.default_query_dialog_edittext) { + with(view.default_query_dialog_edittext) { setText(tags.toString(), android.widget.TextView.BufferType.EDITABLE) addTextChangedListener(object : TextWatcher { override fun beforeTextChanged( @@ -149,6 +145,8 @@ class DefaultQueryDialog(context : Context) : AlertDialog(context) { } }) } + + return view } } \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/ui/dialog/DownloadLocationDialog.kt b/app/src/main/java/xyz/quaver/pupil/ui/dialog/DownloadLocationDialog.kt index b394b50a..d4f5a2a5 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/dialog/DownloadLocationDialog.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/dialog/DownloadLocationDialog.kt @@ -26,6 +26,7 @@ import android.content.Intent import android.content.pm.PackageManager import android.os.Build import android.os.Bundle +import android.view.View import android.widget.LinearLayout import android.widget.RadioButton import androidx.appcompat.app.AlertDialog @@ -46,6 +47,16 @@ class DownloadLocationDialog(val activity: Activity) : AlertDialog(activity) { private val buttons = mutableListOf>() override fun onCreate(savedInstanceState: Bundle?) { + setTitle(R.string.settings_dl_location) + + setView(build()) + + setButton(Dialog.BUTTON_POSITIVE, context.getText(android.R.string.ok)) { _, _ -> } + + super.onCreate(savedInstanceState) + } + + private fun build() : View { val view = layoutInflater.inflate(R.layout.dialog_dl_location, null) as LinearLayout val externalFilesDirs = ContextCompat.getExternalFilesDirs(context, null) @@ -118,15 +129,7 @@ class DownloadLocationDialog(val activity: Activity) : AlertDialog(activity) { buttons[index].first.isChecked = true } - setTitle(R.string.settings_dl_location) - - setView(view) - - setButton(Dialog.BUTTON_POSITIVE, context.getText(android.R.string.ok)) { _, _ -> - dismiss() - } - - super.onCreate(savedInstanceState) + return view } } \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/ui/dialog/MirrorDialog.kt b/app/src/main/java/xyz/quaver/pupil/ui/dialog/MirrorDialog.kt index 1a2f0351..d20b61df 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/dialog/MirrorDialog.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/dialog/MirrorDialog.kt @@ -22,6 +22,7 @@ import android.annotation.SuppressLint import android.app.Dialog import android.content.Context import android.os.Bundle +import android.view.View import androidx.appcompat.app.AlertDialog import androidx.preference.PreferenceManager import androidx.recyclerview.widget.DividerItemDecoration @@ -56,21 +57,17 @@ class MirrorDialog(context: Context) : AlertDialog(context) { } } - private lateinit var recyclerView: RecyclerView - @SuppressLint("InflateParams") override fun onCreate(savedInstanceState: Bundle?) { - initDialog() - setTitle(R.string.settings_mirror_title) - setView(recyclerView) + setView(build()) setButton(Dialog.BUTTON_POSITIVE, context.getString(android.R.string.ok)) { _, _ -> } super.onCreate(savedInstanceState) } - private fun initDialog() { - recyclerView = RecyclerView(context).apply recyclerview@{ + private fun build() : View { + return RecyclerView(context).apply recyclerview@{ addItemDecoration(DividerItemDecoration(context, DividerItemDecoration.VERTICAL)) layoutManager = LinearLayoutManager(context) adapter = MirrorAdapter(context).apply adapter@{ diff --git a/app/src/main/java/xyz/quaver/pupil/ui/dialog/ProxyDialog.kt b/app/src/main/java/xyz/quaver/pupil/ui/dialog/ProxyDialog.kt new file mode 100644 index 00000000..645d6929 --- /dev/null +++ b/app/src/main/java/xyz/quaver/pupil/ui/dialog/ProxyDialog.kt @@ -0,0 +1,127 @@ +/* + * Pupil, Hitomi.la viewer for Android + * Copyright (C) 2020 tom5079 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package xyz.quaver.pupil.ui.dialog + +import android.annotation.SuppressLint +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.AdapterView +import android.widget.ArrayAdapter +import androidx.preference.PreferenceManager +import kotlinx.android.synthetic.main.dialog_proxy.view.* +import xyz.quaver.pupil.R +import xyz.quaver.pupil.util.ProxyInfo +import xyz.quaver.pupil.util.getProxyInfo +import xyz.quaver.pupil.util.json +import java.net.Proxy + +class ProxyDialog(context: Context) : Dialog(context) { + + override fun onCreate(savedInstanceState: Bundle?) { + val view = build() + + setTitle(R.string.settings_proxy_title) + setContentView(view) + + window?.attributes?.width = ViewGroup.LayoutParams.MATCH_PARENT + + super.onCreate(savedInstanceState) + } + + @SuppressLint("InflateParams") + private fun build() : View { + val proxyInfo = getProxyInfo(context) + + val view = LayoutInflater.from(context).inflate(R.layout.dialog_proxy, null) + + val enabler = { enable: Boolean -> + view?.proxy_addr?.isEnabled = enable + view?.proxy_port?.isEnabled = enable + view?.proxy_username?.isEnabled = enable + view?.proxy_password?.isEnabled = enable + + if (!enable) { + view?.proxy_addr?.text = null + view?.proxy_port?.text = null + view?.proxy_username?.text = null + view?.proxy_password?.text = null + } + } + + with(view.proxy_type_selector) { + adapter = ArrayAdapter( + context, + android.R.layout.simple_spinner_dropdown_item, + context.resources.getStringArray(R.array.proxy_type) + ) + + setSelection(proxyInfo.type.ordinal) + + onItemSelectedListener = object: AdapterView.OnItemSelectedListener { + override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { + enabler.invoke(position != 0) + } + + override fun onNothingSelected(parent: AdapterView<*>?) {} + } + } + + view.proxy_addr.setText(proxyInfo.host) + view.proxy_port.setText(proxyInfo.port?.toString()) + view.proxy_username.setText(proxyInfo.username) + view.proxy_password.setText(proxyInfo.password) + + enabler.invoke(proxyInfo.type != Proxy.Type.DIRECT) + + view.proxy_cancel.setOnClickListener { + dismiss() + } + + view.proxy_ok.setOnClickListener { + val type = Proxy.Type.values()[view.proxy_type_selector.selectedItemPosition] + val addr = view.proxy_addr.text?.toString() + val port = view.proxy_port.text?.toString()?.toIntOrNull() + val username = view.proxy_username.text?.toString() + val password = view.proxy_password.text?.toString() + + if (type != Proxy.Type.DIRECT) { + if (addr == null || addr.isEmpty()) + view.proxy_addr.error = context.getText(R.string.proxy_dialog_error) + if (port == null) + view.proxy_port.error = context.getText(R.string.proxy_dialog_error) + + if (addr == null || addr.isEmpty() || port == null) + return@setOnClickListener + } + + PreferenceManager.getDefaultSharedPreferences(context).edit().putString("proxy", + json.stringify(ProxyInfo.serializer(), ProxyInfo(type, addr, port, username, password)) + ).apply() + + dismiss() + } + + return view + } + +} \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/ui/fragment/SettingsFragment.kt b/app/src/main/java/xyz/quaver/pupil/ui/fragment/SettingsFragment.kt index f3d88dad..3a3bcdbd 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/fragment/SettingsFragment.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/fragment/SettingsFragment.kt @@ -36,6 +36,7 @@ import xyz.quaver.pupil.ui.SettingsActivity import xyz.quaver.pupil.ui.dialog.DefaultQueryDialog import xyz.quaver.pupil.ui.dialog.DownloadLocationDialog import xyz.quaver.pupil.ui.dialog.MirrorDialog +import xyz.quaver.pupil.ui.dialog.ProxyDialog import xyz.quaver.pupil.util.* import java.io.File @@ -146,6 +147,10 @@ class SettingsFragment : MirrorDialog(context) .show() } + "proxy" -> { + ProxyDialog(context) + .show() + } "backup" -> { File(ContextCompat.getDataDir(context), "favorites.json").copyTo( File(getDownloadDirectory(context), "favorites.json"), @@ -189,9 +194,18 @@ class SettingsFragment : } override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { - when (key) { - "dl_location" -> { - findPreference(key)?.summary = getDownloadDirectory(context!!).canonicalPath + key ?: return + + with(findPreference(key)) { + this ?: return + + when (key) { + "proxy" -> { + summary = getProxyInfo(context).type.name + } + "dl_location" -> { + summary = getDownloadDirectory(context!!).canonicalPath + } } } } @@ -245,8 +259,7 @@ class SettingsFragment : onPreferenceClickListener = this@SettingsFragment } "default_query" -> { - val preferences = PreferenceManager.getDefaultSharedPreferences(context) - summary = preferences.getString("default_query", "") ?: "" + summary = PreferenceManager.getDefaultSharedPreferences(context).getString("default_query", "") ?: "" onPreferenceClickListener = this@SettingsFragment } @@ -270,6 +283,11 @@ class SettingsFragment : "mirrors" -> { onPreferenceClickListener = this@SettingsFragment } + "proxy" -> { + summary = getProxyInfo(context).type.name + + onPreferenceClickListener = this@SettingsFragment + } "dark_mode" -> { onPreferenceChangeListener = this@SettingsFragment } diff --git a/app/src/main/java/xyz/quaver/pupil/util/proxy.kt b/app/src/main/java/xyz/quaver/pupil/util/proxy.kt new file mode 100644 index 00000000..229c5e90 --- /dev/null +++ b/app/src/main/java/xyz/quaver/pupil/util/proxy.kt @@ -0,0 +1,63 @@ +/* + * Pupil, Hitomi.la viewer for Android + * Copyright (C) 2020 tom5079 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package xyz.quaver.pupil.util + +import android.content.Context +import androidx.preference.PreferenceManager +import kotlinx.serialization.Serializable +import okhttp3.Authenticator +import okhttp3.Credentials +import java.net.InetSocketAddress +import java.net.Proxy + +@Serializable +data class ProxyInfo( + val type: Proxy.Type, + val host: String? = null, + val port: Int? = null, + val username: String? = null, + val password: String? = null +) { + fun proxy() : Proxy { + return if (host == null || port == null) + return Proxy.NO_PROXY + else + Proxy(type, InetSocketAddress.createUnresolved(host, port)) + } + + fun authenticator() = Authenticator { _, response -> + val credential = Credentials.basic(username, password) + + response.request().newBuilder() + .header("Proxy-Authorization", credential) + .build() + } + +} + +fun getProxy(context: Context) = + getProxyInfo(context).proxy() + +fun getProxyInfo(context: Context) = + PreferenceManager.getDefaultSharedPreferences(context).getString("proxy", null).let { + if (it == null) + ProxyInfo(Proxy.Type.DIRECT) + else + json.parse(ProxyInfo.serializer(), it) + } \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_proxy.xml b/app/src/main/res/layout/dialog_proxy.xml new file mode 100644 index 00000000..5765d86e --- /dev/null +++ b/app/src/main/res/layout/dialog_proxy.xml @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +