Proxy settings initial commit

This commit is contained in:
Chumva 2019-04-29 12:11:35 +03:00
parent 9b4ae355be
commit 0d7a8bb642
14 changed files with 862 additions and 1 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 423 B

View file

@ -104,6 +104,35 @@
<include layout="@layout/list_item_divider"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/card_bg_color"
android:orientation="vertical">
<net.osmand.telegram.ui.views.TextViewEx
android:layout_width="match_parent"
android:layout_height="@dimen/list_header_height"
android:ellipsize="end"
android:gravity="center_vertical"
android:maxLines="1"
android:paddingLeft="@dimen/content_padding_standard"
android:paddingRight="@dimen/content_padding_standard"
android:text="@string/privacy"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/list_item_title_text_size"
app:typeface="@string/font_roboto_medium"/>
<LinearLayout
android:id="@+id/proxy_settings_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"/>
</LinearLayout>
<include layout="@layout/list_item_divider"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"

View file

@ -0,0 +1,350 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/card_bg_color">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="@dimen/action_bar_height">
<net.osmand.telegram.ui.views.TextViewEx
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:gravity="center_vertical"
android:maxLines="1"
android:text="@string/proxy_settings"
android:textColor="@color/app_bar_title_light"
android:textSize="@dimen/title_text_size"
app:typeface="@string/font_roboto_mono_bold" />
</android.support.v7.widget.Toolbar>
<View
android:layout_width="wrap_content"
android:layout_height="1dp"
android:layout_marginStart="@dimen/content_padding_standard"
android:layout_marginLeft="@dimen/content_padding_standard"
android:background="?attr/card_divider_color" />
<LinearLayout
android:id="@+id/enable_proxy_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:minHeight="50dp"
android:orientation="horizontal"
tools:background="@color/card_bg_light">
<net.osmand.telegram.ui.views.TextViewEx
android:id="@+id/title"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_vertical"
android:paddingLeft="@dimen/content_padding_standard"
android:paddingRight="@dimen/content_padding_standard"
android:text="@string/shared_string_enable"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/list_item_title_text_size"
app:typeface="@string/font_roboto_regular" />
<Switch
android:id="@+id/switcher"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@null"
android:clickable="false"
android:focusable="false"
android:paddingLeft="@dimen/content_padding_standard"
android:paddingRight="@dimen/content_padding_standard" />
</LinearLayout>
</android.support.design.widget.AppBarLayout>
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="@dimen/list_view_bottom_padding_big">
<include layout="@layout/list_item_divider" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/card_bg_color"
android:orientation="vertical">
<net.osmand.telegram.ui.views.TextViewEx
android:layout_width="match_parent"
android:layout_height="@dimen/list_header_height"
android:ellipsize="end"
android:gravity="center_vertical"
android:maxLines="1"
android:paddingLeft="@dimen/content_padding_standard"
android:paddingRight="@dimen/content_padding_standard"
android:text="@string/proxy_type"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/list_item_title_text_size"
app:typeface="@string/font_roboto_medium" />
<LinearLayout
android:id="@+id/proxy_type_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
</LinearLayout>
<include layout="@layout/list_item_divider" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/card_bg_color"
android:orientation="vertical">
<net.osmand.telegram.ui.views.TextViewEx
android:layout_width="match_parent"
android:layout_height="@dimen/list_header_height"
android:ellipsize="end"
android:gravity="center_vertical"
android:maxLines="1"
android:paddingLeft="@dimen/content_padding_standard"
android:paddingRight="@dimen/content_padding_standard"
android:text="@string/shared_string_connection"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/list_item_title_text_size"
app:typeface="@string/font_roboto_medium" />
<LinearLayout
android:id="@+id/connection_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="@dimen/content_padding_standard"
android:paddingRight="@dimen/content_padding_standard"
android:paddingBottom="@dimen/content_padding_standard">
<studio.carbonylgroup.textfieldboxes.TextFieldBoxes
android:layout_width="match_parent"
android:layout_height="@dimen/list_item_height"
android:layout_marginBottom="@dimen/content_padding_standard"
app:hasClearButton="true"
app:labelText="@string/proxy_server">
<studio.carbonylgroup.textfieldboxes.ExtendedEditText
android:id="@+id/server_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text" />
</studio.carbonylgroup.textfieldboxes.TextFieldBoxes>
<studio.carbonylgroup.textfieldboxes.TextFieldBoxes
android:layout_width="match_parent"
android:layout_height="@dimen/list_item_height"
app:hasClearButton="true"
app:labelText="@string/proxy_port">
<studio.carbonylgroup.textfieldboxes.ExtendedEditText
android:id="@+id/port_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="numberDecimal" />
</studio.carbonylgroup.textfieldboxes.TextFieldBoxes>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/proxy_sosks5_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<include layout="@layout/list_item_divider" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/card_bg_color"
android:orientation="vertical">
<net.osmand.telegram.ui.views.TextViewEx
android:layout_width="match_parent"
android:layout_height="@dimen/list_header_height"
android:ellipsize="end"
android:gravity="center_vertical"
android:maxLines="1"
android:paddingLeft="@dimen/content_padding_standard"
android:paddingRight="@dimen/content_padding_standard"
android:text="@string/proxy_credentials"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/list_item_title_text_size"
app:typeface="@string/font_roboto_medium" />
<LinearLayout
android:id="@+id/credentials_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="@dimen/content_padding_standard"
android:paddingRight="@dimen/content_padding_standard"
android:paddingBottom="@dimen/content_padding_standard">
<studio.carbonylgroup.textfieldboxes.TextFieldBoxes
android:layout_width="match_parent"
android:layout_height="@dimen/list_item_height"
android:layout_marginBottom="@dimen/content_padding_standard"
app:hasClearButton="true"
app:labelText="@string/proxy_username">
<studio.carbonylgroup.textfieldboxes.ExtendedEditText
android:id="@+id/username_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text" />
</studio.carbonylgroup.textfieldboxes.TextFieldBoxes>
<studio.carbonylgroup.textfieldboxes.TextFieldBoxes
android:layout_width="match_parent"
android:layout_height="@dimen/list_item_height"
app:hasClearButton="true"
app:labelText="@string/proxy_password">
<studio.carbonylgroup.textfieldboxes.ExtendedEditText
android:id="@+id/password_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword" />
</studio.carbonylgroup.textfieldboxes.TextFieldBoxes>
</LinearLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/proxy_mtproto_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<include layout="@layout/list_item_divider" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/card_bg_color"
android:orientation="vertical">
<net.osmand.telegram.ui.views.TextViewEx
android:layout_width="match_parent"
android:layout_height="@dimen/list_header_height"
android:ellipsize="end"
android:gravity="center_vertical"
android:maxLines="1"
android:paddingLeft="@dimen/content_padding_standard"
android:paddingRight="@dimen/content_padding_standard"
android:text="@string/proxy_credentials"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/list_item_title_text_size"
app:typeface="@string/font_roboto_medium" />
<LinearLayout
android:id="@+id/mtproto_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="@dimen/content_padding_standard"
android:paddingRight="@dimen/content_padding_standard"
android:paddingBottom="@dimen/content_padding_standard">
<studio.carbonylgroup.textfieldboxes.TextFieldBoxes
android:layout_width="match_parent"
android:layout_height="@dimen/list_item_height"
android:layout_marginBottom="@dimen/content_padding_standard"
app:hasClearButton="true"
app:labelText="@string/proxy_key">
<studio.carbonylgroup.textfieldboxes.ExtendedEditText
android:id="@+id/key_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text" />
</studio.carbonylgroup.textfieldboxes.TextFieldBoxes>
</LinearLayout>
</LinearLayout>
</LinearLayout>
<include layout="@layout/card_bottom_divider" />
</LinearLayout>
</ScrollView>
</LinearLayout>
<LinearLayout
android:id="@+id/save_button_Container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:orientation="vertical">
<android.support.v7.widget.AppCompatImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:src="?attr/bottom_nav_shadow" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="@dimen/proxy_save_button_height"
android:layout_gravity="bottom"
android:background="?attr/card_bg_color"
android:orientation="vertical"
android:paddingLeft="@dimen/content_padding_standard"
android:paddingTop="@dimen/image_button_padding"
android:paddingRight="@dimen/content_padding_standard"
android:paddingBottom="@dimen/image_button_padding">
<include layout="@layout/primary_btn" />
</LinearLayout>
</LinearLayout>
</FrameLayout>

View file

@ -50,6 +50,18 @@
</LinearLayout>
<ImageView
android:id="@+id/icon_right"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="?attr/selectableItemBackground"
android:paddingLeft="@dimen/image_button_padding"
android:paddingRight="@dimen/image_button_padding"
android:visibility="gone"
tools:src="@drawable/ic_action_additional_option"
tools:tint="@color/icon_light"
tools:visibility="visible" />
<Switch
android:id="@+id/switcher"
android:layout_width="wrap_content"

View file

@ -44,6 +44,7 @@
<dimen name="list_item_baseline_to_top_height_big">28dp</dimen>
<dimen name="list_view_bottom_padding">52dp</dimen>
<dimen name="list_view_bottom_padding_big">140dp</dimen>
<dimen name="card_divider_bottom_margin">6dp</dimen>
@ -73,6 +74,8 @@
<dimen name="list_popup_window_height">300dp</dimen>
<dimen name="proxy_save_button_height">60dp</dimen>
<!-- Text sizes -->
<dimen name="dialog_title_text_size">22sp</dimen>

View file

@ -1,5 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="proxy_key">Key</string>
<string name="proxy_password">Password</string>
<string name="proxy_username">Username</string>
<string name="proxy_credentials">Credentials</string>
<string name="proxy_port">Port</string>
<string name="proxy_server">Server</string>
<string name="shared_string_connection">Connection</string>
<string name="shared_string_enable">Enable</string>
<string name="proxy_type">Proxy type</string>
<string name="proxy_connected">Connected</string>
<string name="proxy_disconnected">Disconnected</string>
<string name="proxy_settings">Proxy Settings</string>
<string name="proxy">Proxy</string>
<string name="privacy">Privacy</string>
<string name="direction">Direction</string>
<string name="precision">Precision</string>
<string name="altitude">Altitude</string>

View file

@ -85,6 +85,9 @@ private const val MONITORING_ENABLED = "monitoring_enabled"
private const val SHOW_GPS_POINTS = "show_gps_points"
private const val PROXY_ENABLED = "proxy_enabled"
private const val PROXY_PREFERENCES_KEY = "proxy_preferences"
private const val SHARING_INITIALIZATION_TIME = 60 * 2L // 2 minutes
private const val WAITING_TDLIB_TIME = 30 // 2 seconds
@ -103,6 +106,9 @@ class TelegramSettings(private val app: TelegramApplication) {
var currentSharingMode = ""
private set
var currentProxyPref: ProxyPref = ProxySOCKS5Pref(-1, "", -1, "", "")
private set
var metricsConstants = MetricsConstants.KILOMETERS_AND_METERS
var speedConstants = SpeedConstants.KILOMETERS_PER_HOUR
@ -124,9 +130,12 @@ class TelegramSettings(private val app: TelegramApplication) {
var showGpsPoints = false
var proxyEnabled = false
init {
updatePrefs()
read()
applyProxyPref()
}
fun hasAnyChatToShareLocation() = shareChatsInfo.isNotEmpty()
@ -202,6 +211,30 @@ class TelegramSettings(private val app: TelegramApplication) {
currentSharingMode = sharingMode
}
fun updateCurrentProxyPref(proxyPref: ProxyPref, proxyEnabled: Boolean) {
this.proxyEnabled = proxyEnabled
currentProxyPref = proxyPref
applyProxyPref()
}
fun updateProxySetting(enable: Boolean) {
this.proxyEnabled = enable
if (enable) {
app.telegramHelper.enableProxy(currentProxyPref.id)
} else {
app.telegramHelper.disableProxy()
}
}
fun applyProxyPref() {
val proxyId = currentProxyPref.id
if (proxyId != -1) {
app.telegramHelper.editProxyPref(currentProxyPref, proxyEnabled)
} else {
app.telegramHelper.addProxyPref(currentProxyPref, proxyEnabled)
}
}
fun prepareForSharingNewMessages() {
shareChatsInfo.forEach { (_, shareInfo) ->
prepareForSharingNewMessages(shareInfo)
@ -536,6 +569,8 @@ class TelegramSettings(private val app: TelegramApplication) {
edit.putBoolean(SHOW_GPS_POINTS, showGpsPoints)
edit.putBoolean(PROXY_ENABLED, proxyEnabled)
val jArray = convertShareChatsInfoToJson()
if (jArray != null) {
edit.putString(SHARE_CHATS_INFO_KEY, jArray.toString())
@ -546,6 +581,11 @@ class TelegramSettings(private val app: TelegramApplication) {
edit.putString(SHARE_DEVICES_KEY, jsonObject.toString())
}
val jsonObjectProxy = convertProxyPrefToJson()
if (jsonObjectProxy != null) {
edit.putString(PROXY_PREFERENCES_KEY, jsonObjectProxy.toString())
}
edit.apply()
}
@ -598,6 +638,13 @@ class TelegramSettings(private val app: TelegramApplication) {
monitoringEnabled = prefs.getBoolean(MONITORING_ENABLED,false)
showGpsPoints = prefs.getBoolean(SHOW_GPS_POINTS, false)
proxyEnabled = prefs.getBoolean(PROXY_ENABLED, false)
try {
parseProxyPreferences(JSONObject(prefs.getString(PROXY_PREFERENCES_KEY, "")))
} catch (e: JSONException) {
e.printStackTrace()
}
}
private fun convertShareDevicesToJson():JSONObject?{
@ -621,6 +668,27 @@ class TelegramSettings(private val app: TelegramApplication) {
}
}
private fun convertProxyPrefToJson(): JSONObject? {
return try {
val proxyPref = currentProxyPref
JSONObject().apply {
put(ProxyPref.PROXY_ID, proxyPref.id)
put(ProxyPref.TYPE_ID, proxyPref.type)
put(ProxyPref.SERVER_ID, proxyPref.server)
put(ProxyPref.PORT_ID, proxyPref.port)
if (proxyPref is ProxyMTProtoPref) {
put(ProxyMTProtoPref.KEY_ID, proxyPref.key)
} else if (proxyPref is ProxySOCKS5Pref) {
put(ProxySOCKS5Pref.LOGIN_ID, proxyPref.login)
put(ProxySOCKS5Pref.PASSWORD_ID, proxyPref.password)
}
}
} catch (e: JSONException) {
e.printStackTrace()
null
}
}
private fun convertShareChatsInfoToJson(): JSONArray? {
return try {
val jArray = JSONArray()
@ -678,6 +746,28 @@ class TelegramSettings(private val app: TelegramApplication) {
}
}
private fun parseProxyPreferences(jsonObject: JSONObject) {
val proxyId = jsonObject.optInt(ProxyPref.PROXY_ID)
val typeString = jsonObject.optString(ProxyPref.TYPE_ID)
val server = jsonObject.optString(ProxyPref.SERVER_ID)
val port = jsonObject.optInt(ProxyPref.PORT_ID)
val proxyPref = when {
ProxyType.valueOf(typeString) == ProxyType.MTPROTO -> {
val key = jsonObject.optString(ProxyMTProtoPref.KEY_ID)
ProxyMTProtoPref(proxyId, server, port, key)
}
ProxyType.valueOf(typeString) == ProxyType.SOCKS5 -> {
val login = jsonObject.optString(ProxySOCKS5Pref.LOGIN_ID)
val password = jsonObject.optString(ProxySOCKS5Pref.PASSWORD_ID)
ProxySOCKS5Pref(proxyId, server, port, login, password)
}
else -> null
}
if (proxyPref != null) {
currentProxyPref = proxyPref
}
}
private fun parseShareDevices(json: String) {
shareDevices = OsmandApiUtils.parseJsonContents(json).toHashSet()
}
@ -926,6 +1016,45 @@ class TelegramSettings(private val app: TelegramApplication) {
}
}
enum class ProxyType {
MTPROTO, SOCKS5
}
abstract class ProxyPref(
var id: Int,
var type: ProxyType,
open var server: String,
open var port: Int
) {
companion object {
internal const val PROXY_ID = "proxyId"
internal const val TYPE_ID = "type"
internal const val SERVER_ID = "serverId"
internal const val PORT_ID = "portId"
}
}
class ProxyMTProtoPref(id: Int, server: String, port: Int, var key: String) :
ProxyPref(id, ProxyType.MTPROTO, server, port) {
companion object {
internal const val KEY_ID = "key"
}
}
class ProxySOCKS5Pref(
id: Int,
server: String,
port: Int,
var login: String,
var password: String
) :
ProxyPref(id, ProxyType.SOCKS5, server, port) {
companion object {
internal const val LOGIN_ID = "login"
internal const val PASSWORD_ID = "password"
}
}
class SharingStatus {
var title: String = ""

View file

@ -683,6 +683,80 @@ class TelegramHelper private constructor() {
}
}
fun disableProxy() {
client?.send(TdApi.DisableProxy()) { obj ->
when (obj.constructor) {
TdApi.Error.CONSTRUCTOR -> {
val error = obj as TdApi.Error
if (error.code != IGNORED_ERROR_CODE) {
listener?.onTelegramError(error.code, error.message)
}
}
TdApi.Ok.CONSTRUCTOR -> {
}
}
}
}
fun enableProxy(proxyId: Int) {
client?.send(TdApi.EnableProxy(proxyId)) { obj ->
when (obj.constructor) {
TdApi.Error.CONSTRUCTOR -> {
val error = obj as TdApi.Error
if (error.code != IGNORED_ERROR_CODE) {
listener?.onTelegramError(error.code, error.message)
}
}
TdApi.Ok.CONSTRUCTOR -> {
}
}
}
}
fun addProxyPref(proxyPref: TelegramSettings.ProxyPref, enable: Boolean) {
val proxyType: TdApi.ProxyType? = when (proxyPref) {
is TelegramSettings.ProxyMTProtoPref -> TdApi.ProxyTypeMtproto(proxyPref.key)
is TelegramSettings.ProxySOCKS5Pref -> TdApi.ProxyTypeSocks5(proxyPref.login, proxyPref.password)
else -> null
}
client?.send(TdApi.AddProxy(proxyPref.server, proxyPref.port, enable, proxyType)) { obj ->
when (obj.constructor) {
TdApi.Error.CONSTRUCTOR -> {
val error = obj as TdApi.Error
if (error.code != IGNORED_ERROR_CODE) {
listener?.onTelegramError(error.code, error.message)
}
}
TdApi.Proxy.CONSTRUCTOR -> {
val proxy = (obj as TdApi.Proxy)
proxyPref.id = proxy.id
}
}
}
}
fun editProxyPref(proxyPref: TelegramSettings.ProxyPref, enable: Boolean) {
val proxyType: TdApi.ProxyType? = when (proxyPref) {
is TelegramSettings.ProxyMTProtoPref -> TdApi.ProxyTypeMtproto(proxyPref.key)
is TelegramSettings.ProxySOCKS5Pref -> TdApi.ProxyTypeSocks5(proxyPref.login, proxyPref.password)
else -> null
}
client?.send(TdApi.EditProxy(proxyPref.id, proxyPref.server, proxyPref.port, enable, proxyType)) { obj ->
when (obj.constructor) {
TdApi.Error.CONSTRUCTOR -> {
val error = obj as TdApi.Error
if (error.code != IGNORED_ERROR_CODE) {
listener?.onTelegramError(error.code, error.message)
}
}
TdApi.Proxy.CONSTRUCTOR -> {
val proxy = (obj as TdApi.Proxy)
proxyPref.id = proxy.id
}
}
}
}
fun createPrivateChatWithUser(
userId: Int,
shareInfo: TelegramSettings.ShareChatInfo,

View file

@ -0,0 +1,218 @@
package net.osmand.telegram.ui
import android.os.Build
import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v4.app.FragmentManager
import android.support.v4.content.ContextCompat
import android.support.v7.widget.Toolbar
import android.text.Editable
import android.text.TextWatcher
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.widget.*
import net.osmand.telegram.R
import net.osmand.telegram.TelegramSettings.ProxyType
import net.osmand.telegram.TelegramSettings.ProxyPref
import net.osmand.telegram.TelegramSettings.ProxyMTProtoPref
import net.osmand.telegram.TelegramSettings.ProxySOCKS5Pref
class ProxySettingsDialogFragment : BaseDialogFragment() {
private val uiUtils get() = app.uiUtils
private lateinit var mainView: View
private lateinit var proxyEnableSwitcher: Switch
private lateinit var saveButtonContainer: LinearLayout
private lateinit var selectedProxyType: ProxyType
private lateinit var serverEditText: EditText
private lateinit var portEditText: EditText
override fun onCreateView(
inflater: LayoutInflater,
parent: ViewGroup?,
savedInstanceState: Bundle?
): View {
mainView = inflater.inflate(R.layout.fragment_proxy_settings_dialog, parent)
val window = dialog.window
if (window != null) {
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)
if (Build.VERSION.SDK_INT >= 21) {
window.statusBarColor = ContextCompat.getColor(app, R.color.card_bg_light)
}
}
mainView.findViewById<Toolbar>(R.id.toolbar).apply {
navigationIcon = uiUtils.getThemedIcon(R.drawable.ic_arrow_back)
setNavigationOnClickListener { dismiss() }
}
selectedProxyType = settings.currentProxyPref.type
mainView.findViewById<ViewGroup>(R.id.enable_proxy_btn).apply {
val title = findViewById<TextView>(R.id.title).apply {
text = if (settings.proxyEnabled) getText(R.string.shared_string_disable) else getText(
R.string.shared_string_enable
)
}
proxyEnableSwitcher = findViewById<Switch>(R.id.switcher).apply {
isChecked = settings.proxyEnabled
}
setOnClickListener {
val checked = !proxyEnableSwitcher.isChecked
proxyEnableSwitcher.isChecked = checked
title.text = if (checked) getText(R.string.shared_string_disable) else getText(R.string.shared_string_enable)
updateSaveButtonVisibility(checked == settings.proxyEnabled)
}
}
val container = mainView.findViewById<ViewGroup>(R.id.proxy_type_container)
ProxyType.values().forEach {
addItemToContainer(inflater, container, it)
}
serverEditText = mainView.findViewById<EditText>(R.id.server_edit_text).apply {
val server = settings.currentProxyPref.server
setText(server)
setSelection(server.length)
addTextChangedListener(object :
TextWatcher {
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun afterTextChanged(s: Editable) {
updateSaveButtonVisibility(s.isNotEmpty() && portEditText.text.isNotEmpty())
}
})
}
portEditText = mainView.findViewById<EditText>(R.id.port_edit_text).apply {
val port = settings.currentProxyPref.port
setText(if (port != -1) port.toString() else "")
addTextChangedListener(object :
TextWatcher {
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun afterTextChanged(s: Editable) {
updateSaveButtonVisibility(s.isNotEmpty() && serverEditText.text.isNotEmpty())
}
})
}
saveButtonContainer = mainView.findViewById<LinearLayout>(R.id.save_button_Container).apply {
findViewById<TextView>(R.id.primary_btn).apply {
text = getString(R.string.shared_string_save)
setOnClickListener {
saveChanges()
updateSaveButtonVisibility(false)
targetFragment?.also { target ->
target.onActivityResult(targetRequestCode, PROXY_PREFERENCES_UPDATED_REQUEST_CODE, null)
}
dismiss()
}
}
}
updateSelectedProxyType()
updateEditingMode()
updateProxyPrefInfo()
updateSaveButtonVisibility(false)
return mainView
}
private fun updateSaveButtonVisibility(visible: Boolean) {
saveButtonContainer.visibility = if (visible) View.VISIBLE else View.GONE
}
private fun saveChanges() {
val proxyPref = getSelectedProxyPref()
settings.updateCurrentProxyPref(proxyPref, proxyEnableSwitcher.isChecked)
}
private fun updateProxyPrefInfo() {
val proxyPref = settings.currentProxyPref
if (proxyPref is ProxyMTProtoPref) {
mainView.findViewById<TextView>(R.id.key_text).text = proxyPref.key
} else if (proxyPref is ProxySOCKS5Pref) {
mainView.findViewById<TextView>(R.id.username_text).text = proxyPref.login
mainView.findViewById<TextView>(R.id.password_text).text = proxyPref.password
}
}
private fun getSelectedProxyPref(): ProxyPref {
val server = serverEditText.text.toString()
val port = portEditText.text.toString().toIntOrNull() ?: -1
return when (selectedProxyType) {
ProxyType.MTPROTO -> {
val key = mainView.findViewById<TextView>(R.id.key_text).text.toString()
ProxyMTProtoPref(settings.currentProxyPref.id, server, port, key)
}
ProxyType.SOCKS5 -> {
val username = mainView.findViewById<TextView>(R.id.username_text).text.toString()
val password = mainView.findViewById<TextView>(R.id.password_text).text.toString()
ProxySOCKS5Pref(settings.currentProxyPref.id, server, port, username, password)
}
}
}
private fun updateSelectedProxyType() {
view?.findViewById<ViewGroup>(R.id.proxy_type_container)?.apply {
for (i in 0 until childCount) {
getChildAt(i).apply {
findViewById<RadioButton>(R.id.radio_button).isChecked = tag == selectedProxyType
}
}
}
}
private fun updateEditingMode() {
mainView.findViewById<LinearLayout>(R.id.proxy_sosks5_container)?.visibility =
if (selectedProxyType == ProxyType.SOCKS5) View.VISIBLE else View.GONE
mainView.findViewById<LinearLayout>(R.id.proxy_mtproto_container)?.visibility =
if (selectedProxyType == ProxyType.MTPROTO) View.VISIBLE else View.GONE
}
private fun addItemToContainer(
inflater: LayoutInflater,
container: ViewGroup,
proxyTypeTag: ProxyType
) {
inflater.inflate(R.layout.item_with_rb_and_btn, container, false).apply {
findViewById<TextView>(R.id.title).text = proxyTypeTag.name
findViewById<View>(R.id.primary_btn).visibility = View.GONE
findViewById<View>(R.id.icon).visibility = View.GONE
findViewById<RadioButton>(R.id.radio_button).isChecked = selectedProxyType == proxyTypeTag
setOnClickListener {
selectedProxyType = proxyTypeTag
updateSelectedProxyType()
updateEditingMode()
updateSaveButtonVisibility(true)
}
this.tag = proxyTypeTag
container.addView(this)
}
}
companion object {
private const val TAG = "ProxySettingsDialogFragment"
const val PROXY_PREFERENCES_UPDATED_REQUEST_CODE = 6
fun showInstance(fm: FragmentManager, target: Fragment): Boolean {
return try {
ProxySettingsDialogFragment().apply {
setTargetFragment(target, PROXY_PREFERENCES_UPDATED_REQUEST_CODE)
show(fm, TAG)
}
true
} catch (e: RuntimeException) {
false
}
}
}
}

View file

@ -92,6 +92,32 @@ class SettingsDialogFragment : BaseDialogFragment() {
container.addView(this)
}
container = mainView.findViewById<ViewGroup>(R.id.proxy_settings_container)
inflater.inflate(R.layout.item_with_descr_and_right_switch, container, false).apply {
findViewById<ImageView>(R.id.icon).setImageDrawable(uiUtils.getThemedIcon(R.drawable.ic_action_proxy))
findViewById<ImageView>(R.id.icon_right).apply {
visibility = View.VISIBLE
setImageDrawable(uiUtils.getThemedIcon(R.drawable.ic_action_additional_option))
setOnClickListener {
activity?.supportFragmentManager?.also { ProxySettingsDialogFragment.showInstance(it, this@SettingsDialogFragment) }
}
}
findViewById<TextView>(R.id.title).text = getText(R.string.proxy)
val description = findViewById<TextView>(R.id.description).apply {
text = if (settings.proxyEnabled) getText(R.string.proxy_connected) else getText(R.string.proxy_disconnected)
}
val switcher = findViewById<Switch>(R.id.switcher).apply {
isChecked = app.settings.proxyEnabled
}
setOnClickListener {
val checked = !app.settings.proxyEnabled
switcher.isChecked = checked
settings.updateProxySetting(checked)
description.text = if (checked) getText(R.string.proxy_connected) else getText(R.string.proxy_disconnected)
}
container.addView(this)
}
shareAsDescription = mainView.findViewById<TextView>(R.id.share_as_description).apply {
text = getText(R.string.share_location_as_description)
setOnClickListener {
@ -214,6 +240,12 @@ class SettingsDialogFragment : BaseDialogFragment() {
}
}
}
ProxySettingsDialogFragment.PROXY_PREFERENCES_UPDATED_REQUEST_CODE -> {
view?.findViewById<ViewGroup>(R.id.proxy_settings_container)?.apply {
findViewById<TextView>(R.id.description)?.text = if (settings.proxyEnabled) getText(R.string.proxy_connected) else getText(R.string.proxy_disconnected)
findViewById<Switch>(R.id.switcher)?.isChecked = app.settings.proxyEnabled
}
}
}
}