Commit 0939f5b4 authored by Mygod's avatar Mygod

Migrate to androidx.preference 1.1.0

Also allows show password. See also #1948.
parent 9e62b380
...@@ -12,7 +12,6 @@ buildscript { ...@@ -12,7 +12,6 @@ buildscript {
lifecycleVersion = '2.0.0' lifecycleVersion = '2.0.0'
roomVersion = '2.0.0' roomVersion = '2.0.0'
workVersion = '1.0.0-beta05' workVersion = '1.0.0-beta05'
preferencexVersion = '1.0.0'
junitVersion = '4.12' junitVersion = '4.12'
androidTestVersion = '1.1.1' androidTestVersion = '1.1.1'
androidEspressoVersion = '3.1.1' androidEspressoVersion = '3.1.1'
......
...@@ -43,12 +43,11 @@ dependencies { ...@@ -43,12 +43,11 @@ dependencies {
api "android.arch.work:work-runtime-ktx:$workVersion" api "android.arch.work:work-runtime-ktx:$workVersion"
api "androidx.lifecycle:lifecycle-extensions:$lifecycleVersion" api "androidx.lifecycle:lifecycle-extensions:$lifecycleVersion"
api "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleVersion" api "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleVersion"
api 'androidx.preference:preference:1.0.0' api 'androidx.preference:preference:1.1.0-alpha03'
api "androidx.room:room-runtime:$roomVersion" api "androidx.room:room-runtime:$roomVersion"
api 'com.crashlytics.sdk.android:crashlytics:2.9.9' api 'com.crashlytics.sdk.android:crashlytics:2.9.9'
api 'com.google.firebase:firebase-config:16.3.0' api 'com.google.firebase:firebase-config:16.3.0'
api 'com.google.firebase:firebase-core:16.0.7' api 'com.google.firebase:firebase-core:16.0.7'
api "com.takisoft.preferencex:preferencex:$preferencexVersion"
api 'dnsjava:dnsjava:2.1.8' api 'dnsjava:dnsjava:2.1.8'
api 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1' api 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1'
api 'org.connectbot.jsocks:jsocks:1.0.0' api 'org.connectbot.jsocks:jsocks:1.0.0'
......
/*******************************************************************************
* *
* Copyright (C) 2019 by Max Lv <max.c.lv@gmail.com> *
* Copyright (C) 2019 by Mygod Studio <contact-shadowsocks-android@mygod.be> *
* *
* 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 <http://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
package com.github.shadowsocks.preference
import android.text.InputFilter
import android.view.inputmethod.EditorInfo
import android.widget.EditText
import androidx.preference.EditTextPreference
object PortPreferenceListener : EditTextPreference.OnBindEditTextListener {
private val portLengthFilter = arrayOf(InputFilter.LengthFilter(5))
override fun onBindEditText(editText: EditText) {
editText.inputType = EditorInfo.TYPE_CLASS_NUMBER
editText.filters = portLengthFilter
editText.setSingleLine()
}
}
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
# The setting is particularly useful for tweaking memory settings. # The setting is particularly useful for tweaking memory settings.
android.enableJetifier=true android.enableJetifier=true
android.enableR8=true android.enableR8=true
# android.enableR8.fullMode=true android.enableR8.fullMode=true
android.useAndroidX=true android.useAndroidX=true
# When configured, Gradle will run in incubating parallel mode. # When configured, Gradle will run in incubating parallel mode.
......
...@@ -51,10 +51,10 @@ android { ...@@ -51,10 +51,10 @@ android {
dependencies { dependencies {
implementation project(':core') implementation project(':core')
implementation "androidx.browser:browser:1.0.0" implementation 'androidx.browser:browser:1.0.0'
implementation 'com.google.android.gms:play-services-vision:17.0.2' implementation 'com.google.android.gms:play-services-vision:17.0.2'
implementation 'com.google.firebase:firebase-ads:17.1.3' implementation 'com.google.firebase:firebase-ads:17.1.3'
implementation "com.takisoft.preferencex:preferencex-simplemenu:$preferencexVersion" implementation 'com.takisoft.preferencex:preferencex-simplemenu:1.0.0'
implementation 'com.twofortyfouram:android-plugin-api-for-locale:1.0.4' implementation 'com.twofortyfouram:android-plugin-api-for-locale:1.0.4'
implementation 'net.glxn.qrgen:android:2.0' implementation 'net.glxn.qrgen:android:2.0'
implementation 'xyz.belvi.mobilevision:barcodescanner:2.0.3' implementation 'xyz.belvi.mobilevision:barcodescanner:2.0.3'
......
...@@ -23,17 +23,12 @@ package com.github.shadowsocks ...@@ -23,17 +23,12 @@ package com.github.shadowsocks
import android.app.Application import android.app.Application
import android.content.res.Configuration import android.content.res.Configuration
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import com.github.shadowsocks.preference.BottomSheetPreferenceDialogFragment
import com.github.shadowsocks.preference.IconListPreference
import com.takisoft.preferencex.PreferenceFragmentCompat
class App : Application() { class App : Application() {
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
Core.init(this, MainActivity::class) Core.init(this, MainActivity::class)
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true) AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
PreferenceFragmentCompat.registerPreferenceFragment(IconListPreference::class.java,
BottomSheetPreferenceDialogFragment::class.java)
} }
override fun onConfigurationChanged(newConfig: Configuration) { override fun onConfigurationChanged(newConfig: Configuration) {
......
...@@ -22,22 +22,24 @@ package com.github.shadowsocks ...@@ -22,22 +22,24 @@ package com.github.shadowsocks
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import androidx.preference.EditTextPreference
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.SwitchPreference import androidx.preference.SwitchPreference
import com.github.shadowsocks.bg.BaseService import com.github.shadowsocks.bg.BaseService
import com.github.shadowsocks.preference.DataStore import com.github.shadowsocks.preference.DataStore
import com.github.shadowsocks.utils.DirectBoot import com.github.shadowsocks.utils.DirectBoot
import com.github.shadowsocks.utils.Key import com.github.shadowsocks.utils.Key
import com.github.shadowsocks.net.TcpFastOpen import com.github.shadowsocks.net.TcpFastOpen
import com.github.shadowsocks.preference.PortPreferenceListener
import com.github.shadowsocks.utils.remove import com.github.shadowsocks.utils.remove
import com.takisoft.preferencex.PreferenceFragmentCompat
class GlobalSettingsPreferenceFragment : PreferenceFragmentCompat() { class GlobalSettingsPreferenceFragment : PreferenceFragmentCompat() {
override fun onCreatePreferencesFix(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
preferenceManager.preferenceDataStore = DataStore.publicStore preferenceManager.preferenceDataStore = DataStore.publicStore
DataStore.initGlobal() DataStore.initGlobal()
addPreferencesFromResource(R.xml.pref_global) addPreferencesFromResource(R.xml.pref_global)
val boot = findPreference(Key.isAutoConnect) as SwitchPreference val boot = findPreference<SwitchPreference>(Key.isAutoConnect)
boot.setOnPreferenceChangeListener { _, value -> boot.setOnPreferenceChangeListener { _, value ->
BootReceiver.enabled = value as Boolean BootReceiver.enabled = value as Boolean
true true
...@@ -45,13 +47,13 @@ class GlobalSettingsPreferenceFragment : PreferenceFragmentCompat() { ...@@ -45,13 +47,13 @@ class GlobalSettingsPreferenceFragment : PreferenceFragmentCompat() {
boot.isChecked = BootReceiver.enabled boot.isChecked = BootReceiver.enabled
if (Build.VERSION.SDK_INT >= 24) boot.setSummary(R.string.auto_connect_summary_v24) if (Build.VERSION.SDK_INT >= 24) boot.setSummary(R.string.auto_connect_summary_v24)
val canToggleLocked = findPreference(Key.directBootAware) val canToggleLocked = findPreference<Preference>(Key.directBootAware)
if (Build.VERSION.SDK_INT >= 24) canToggleLocked.setOnPreferenceChangeListener { _, newValue -> if (Build.VERSION.SDK_INT >= 24) canToggleLocked.setOnPreferenceChangeListener { _, newValue ->
if (Core.directBootSupported && newValue as Boolean) DirectBoot.update() else DirectBoot.clean() if (Core.directBootSupported && newValue as Boolean) DirectBoot.update() else DirectBoot.clean()
true true
} else canToggleLocked.remove() } else canToggleLocked.remove()
val tfo = findPreference(Key.tfo) as SwitchPreference val tfo = findPreference<SwitchPreference>(Key.tfo)
tfo.isChecked = DataStore.tcpFastOpen tfo.isChecked = DataStore.tcpFastOpen
tfo.setOnPreferenceChangeListener { _, value -> tfo.setOnPreferenceChangeListener { _, value ->
if (value as Boolean && !TcpFastOpen.sendEnabled) { if (value as Boolean && !TcpFastOpen.sendEnabled) {
...@@ -68,10 +70,13 @@ class GlobalSettingsPreferenceFragment : PreferenceFragmentCompat() { ...@@ -68,10 +70,13 @@ class GlobalSettingsPreferenceFragment : PreferenceFragmentCompat() {
tfo.summary = getString(R.string.tcp_fastopen_summary_unsupported, System.getProperty("os.version")) tfo.summary = getString(R.string.tcp_fastopen_summary_unsupported, System.getProperty("os.version"))
} }
val serviceMode = findPreference(Key.serviceMode) val serviceMode = findPreference<Preference>(Key.serviceMode)
val portProxy = findPreference(Key.portProxy) val portProxy = findPreference<EditTextPreference>(Key.portProxy)
val portLocalDns = findPreference(Key.portLocalDns) portProxy.onBindEditTextListener = PortPreferenceListener
val portTransproxy = findPreference(Key.portTransproxy) val portLocalDns = findPreference<EditTextPreference>(Key.portLocalDns)
portLocalDns.onBindEditTextListener = PortPreferenceListener
val portTransproxy = findPreference<EditTextPreference>(Key.portTransproxy)
portTransproxy.onBindEditTextListener = PortPreferenceListener
val onServiceModeChange = Preference.OnPreferenceChangeListener { _, newValue -> val onServiceModeChange = Preference.OnPreferenceChangeListener { _, newValue ->
val (enabledLocalDns, enabledTransproxy) = when (newValue as String?) { val (enabledLocalDns, enabledTransproxy) = when (newValue as String?) {
Key.modeProxy -> Pair(false, false) Key.modeProxy -> Pair(false, false)
......
...@@ -26,10 +26,7 @@ import android.content.Intent ...@@ -26,10 +26,7 @@ import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.MenuItem import android.view.MenuItem
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.core.os.bundleOf import androidx.preference.*
import androidx.preference.Preference
import androidx.preference.PreferenceDataStore
import androidx.preference.SwitchPreference
import com.github.shadowsocks.Core.app import com.github.shadowsocks.Core.app
import com.github.shadowsocks.database.Profile import com.github.shadowsocks.database.Profile
import com.github.shadowsocks.database.ProfileManager import com.github.shadowsocks.database.ProfileManager
...@@ -37,20 +34,17 @@ import com.github.shadowsocks.plugin.PluginConfiguration ...@@ -37,20 +34,17 @@ import com.github.shadowsocks.plugin.PluginConfiguration
import com.github.shadowsocks.plugin.PluginContract import com.github.shadowsocks.plugin.PluginContract
import com.github.shadowsocks.plugin.PluginManager import com.github.shadowsocks.plugin.PluginManager
import com.github.shadowsocks.plugin.PluginOptions import com.github.shadowsocks.plugin.PluginOptions
import com.github.shadowsocks.preference.DataStore import com.github.shadowsocks.preference.*
import com.github.shadowsocks.preference.IconListPreference
import com.github.shadowsocks.preference.OnPreferenceDataStoreChangeListener
import com.github.shadowsocks.preference.PluginConfigurationDialogFragment
import com.github.shadowsocks.utils.Action import com.github.shadowsocks.utils.Action
import com.github.shadowsocks.utils.DirectBoot import com.github.shadowsocks.utils.DirectBoot
import com.github.shadowsocks.utils.Key import com.github.shadowsocks.utils.Key
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import com.takisoft.preferencex.EditTextPreference
import com.takisoft.preferencex.PreferenceFragmentCompat
class ProfileConfigFragment : PreferenceFragmentCompat(), class ProfileConfigFragment : PreferenceFragmentCompat(),
Preference.OnPreferenceChangeListener, OnPreferenceDataStoreChangeListener { Preference.OnPreferenceChangeListener, OnPreferenceDataStoreChangeListener {
companion object { private companion object PasswordSummaryProvider : Preference.SummaryProvider<EditTextPreference> {
override fun provideSummary(preference: EditTextPreference?) = "\u2022".repeat(preference?.text?.length ?: 0)
private const val REQUEST_CODE_PLUGIN_CONFIGURE = 1 private const val REQUEST_CODE_PLUGIN_CONFIGURE = 1
} }
...@@ -62,23 +56,25 @@ class ProfileConfigFragment : PreferenceFragmentCompat(), ...@@ -62,23 +56,25 @@ class ProfileConfigFragment : PreferenceFragmentCompat(),
private lateinit var receiver: BroadcastReceiver private lateinit var receiver: BroadcastReceiver
private lateinit var udpFallback: Preference private lateinit var udpFallback: Preference
override fun onCreatePreferencesFix(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
preferenceManager.preferenceDataStore = DataStore.privateStore preferenceManager.preferenceDataStore = DataStore.privateStore
val activity = requireActivity() val activity = requireActivity()
profileId = activity.intent.getLongExtra(Action.EXTRA_PROFILE_ID, -1L) profileId = activity.intent.getLongExtra(Action.EXTRA_PROFILE_ID, -1L)
addPreferencesFromResource(R.xml.pref_profile) addPreferencesFromResource(R.xml.pref_profile)
findPreference<EditTextPreference>(Key.remotePort).onBindEditTextListener = PortPreferenceListener
findPreference<EditTextPreference>(Key.password).summaryProvider = PasswordSummaryProvider
val serviceMode = DataStore.serviceMode val serviceMode = DataStore.serviceMode
findPreference(Key.remoteDns).isEnabled = serviceMode != Key.modeProxy findPreference<Preference>(Key.remoteDns).isEnabled = serviceMode != Key.modeProxy
isProxyApps = findPreference(Key.proxyApps) as SwitchPreference isProxyApps = findPreference(Key.proxyApps)
isProxyApps.isEnabled = serviceMode == Key.modeVpn isProxyApps.isEnabled = serviceMode == Key.modeVpn
isProxyApps.setOnPreferenceClickListener { isProxyApps.setOnPreferenceClickListener {
startActivity(Intent(activity, AppManager::class.java)) startActivity(Intent(activity, AppManager::class.java))
isProxyApps.isChecked = true isProxyApps.isChecked = true
false false
} }
findPreference(Key.udpdns).isEnabled = serviceMode != Key.modeProxy findPreference<Preference>(Key.udpdns).isEnabled = serviceMode != Key.modeProxy
plugin = findPreference(Key.plugin) as IconListPreference plugin = findPreference(Key.plugin)
pluginConfigure = findPreference(Key.pluginConfigure) as EditTextPreference pluginConfigure = findPreference(Key.pluginConfigure)
plugin.unknownValueSummary = getString(R.string.plugin_unknown) plugin.unknownValueSummary = getString(R.string.plugin_unknown)
plugin.setOnPreferenceChangeListener { _, newValue -> plugin.setOnPreferenceChangeListener { _, newValue ->
pluginConfiguration = PluginConfiguration(pluginConfiguration.pluginsOptions, newValue as String) pluginConfiguration = PluginConfiguration(pluginConfiguration.pluginsOptions, newValue as String)
...@@ -107,14 +103,16 @@ class ProfileConfigFragment : PreferenceFragmentCompat(), ...@@ -107,14 +103,16 @@ class ProfileConfigFragment : PreferenceFragmentCompat(),
pluginConfiguration = PluginConfiguration(DataStore.plugin) pluginConfiguration = PluginConfiguration(DataStore.plugin)
plugin.value = pluginConfiguration.selected plugin.value = pluginConfiguration.selected
plugin.init() plugin.init()
plugin.checkSummary()
pluginConfigure.isEnabled = pluginConfiguration.selected.isNotEmpty() pluginConfigure.isEnabled = pluginConfiguration.selected.isNotEmpty()
pluginConfigure.text = pluginConfiguration.selectedOptions.toString() pluginConfigure.text = pluginConfiguration.selectedOptions.toString()
} }
private fun showPluginEditor() = displayPreferenceDialog(PluginConfigurationDialogFragment(), Key.pluginConfigure, private fun showPluginEditor() {
bundleOf(Pair("key", Key.pluginConfigure), PluginConfigurationDialogFragment().apply {
Pair(PluginConfigurationDialogFragment.PLUGIN_ID_FRAGMENT_TAG, pluginConfiguration.selected))) setArg(Key.pluginConfigure, pluginConfiguration.selected)
setTargetFragment(this@ProfileConfigFragment, 0)
}.show(fragmentManager ?: return, Key.pluginConfigure)
}
fun saveAndExit() { fun saveAndExit() {
val profile = ProfileManager.getProfile(profileId) ?: Profile() val profile = ProfileManager.getProfile(profileId) ?: Profile()
...@@ -147,17 +145,27 @@ class ProfileConfigFragment : PreferenceFragmentCompat(), ...@@ -147,17 +145,27 @@ class ProfileConfigFragment : PreferenceFragmentCompat(),
} }
override fun onPreferenceDataStoreChanged(store: PreferenceDataStore, key: String?) { override fun onPreferenceDataStoreChanged(store: PreferenceDataStore, key: String?) {
if (key != Key.proxyApps && findPreference(key) != null) DataStore.dirty = true if (key != Key.proxyApps && findPreference<Preference>(key) != null) DataStore.dirty = true
} }
override fun onDisplayPreferenceDialog(preference: Preference) { override fun onDisplayPreferenceDialog(preference: Preference) {
if (preference.key == Key.pluginConfigure) { when (preference.key) {
Key.plugin -> {
BottomSheetPreferenceDialogFragment().apply {
setArg(Key.plugin)
setTargetFragment(this@ProfileConfigFragment, 0)
}.show(fragmentManager ?: return, Key.plugin)
}
Key.pluginConfigure -> {
val intent = PluginManager.buildIntent(pluginConfiguration.selected, PluginContract.ACTION_CONFIGURE) val intent = PluginManager.buildIntent(pluginConfiguration.selected, PluginContract.ACTION_CONFIGURE)
if (intent.resolveActivity(requireContext().packageManager) == null) showPluginEditor() else if (intent.resolveActivity(requireContext().packageManager) == null) showPluginEditor() else {
startActivityForResult(intent startActivityForResult(intent
.putExtra(PluginContract.EXTRA_OPTIONS, pluginConfiguration.selectedOptions.toString()), .putExtra(PluginContract.EXTRA_OPTIONS, pluginConfiguration.selectedOptions.toString()),
REQUEST_CODE_PLUGIN_CONFIGURE) REQUEST_CODE_PLUGIN_CONFIGURE)
} else super.onDisplayPreferenceDialog(preference) }
}
else -> super.onDisplayPreferenceDialog(preference)
}
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
......
...@@ -32,6 +32,7 @@ import android.view.View ...@@ -32,6 +32,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import androidx.core.os.bundleOf
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.preference.PreferenceDialogFragmentCompat import androidx.preference.PreferenceDialogFragmentCompat
import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.DefaultItemAnimator
...@@ -97,6 +98,10 @@ class BottomSheetPreferenceDialogFragment : PreferenceDialogFragmentCompat() { ...@@ -97,6 +98,10 @@ class BottomSheetPreferenceDialogFragment : PreferenceDialogFragmentCompat() {
} }
} }
fun setArg(key: String) {
arguments = bundleOf(PreferenceDialogFragmentCompat.ARG_KEY to key)
}
private val preference by lazy { getPreference() as IconListPreference } private val preference by lazy { getPreference() as IconListPreference }
private var clickedIndex = -1 private var clickedIndex = -1
......
...@@ -26,6 +26,14 @@ import android.util.AttributeSet ...@@ -26,6 +26,14 @@ import android.util.AttributeSet
import androidx.preference.ListPreference import androidx.preference.ListPreference
class IconListPreference(context: Context, attrs: AttributeSet? = null) : ListPreference(context, attrs) { class IconListPreference(context: Context, attrs: AttributeSet? = null) : ListPreference(context, attrs) {
companion object FallbackProvider : SummaryProvider<IconListPreference> {
override fun provideSummary(preference: IconListPreference?): CharSequence? {
val i = preference?.selectedEntry
return if (i != null && i < 0) preference.unknownValueSummary?.format(preference.value) else
preference?.entry
}
}
var entryIcons: Array<Drawable?>? = null var entryIcons: Array<Drawable?>? = null
val selectedEntry: Int get() = entryValues.indexOf(value) val selectedEntry: Int get() = entryValues.indexOf(value)
val entryIcon: Drawable? get() = entryIcons?.getOrNull(selectedEntry) val entryIcon: Drawable? get() = entryIcons?.getOrNull(selectedEntry)
...@@ -49,7 +57,6 @@ class IconListPreference(context: Context, attrs: AttributeSet? = null) : ListPr ...@@ -49,7 +57,6 @@ class IconListPreference(context: Context, attrs: AttributeSet? = null) : ListPr
val listener = listener val listener = listener
if (listener == null || listener.onPreferenceChange(preference, newValue)) { if (listener == null || listener.onPreferenceChange(preference, newValue)) {
value = newValue.toString() value = newValue.toString()
checkSummary()
if (entryIcons != null) icon = entryIcon if (entryIcons != null) icon = entryIcon
true true
} else false } else false
...@@ -60,13 +67,9 @@ class IconListPreference(context: Context, attrs: AttributeSet? = null) : ListPr ...@@ -60,13 +67,9 @@ class IconListPreference(context: Context, attrs: AttributeSet? = null) : ListPr
// a.recycle() // a.recycle()
} }
fun checkSummary() {
val unknownValueSummary = unknownValueSummary
if (unknownValueSummary != null) summary = if (selectedEntry < 0) unknownValueSummary.format(value) else "%s"
}
fun init() { fun init() {
icon = entryIcon icon = entryIcon
summaryProvider = FallbackProvider
} }
override fun onSetInitialValue(defaultValue: Any?) { override fun onSetInitialValue(defaultValue: Any?) {
super.onSetInitialValue(defaultValue) super.onSetInitialValue(defaultValue)
......
...@@ -23,17 +23,23 @@ package com.github.shadowsocks.preference ...@@ -23,17 +23,23 @@ package com.github.shadowsocks.preference
import android.view.View import android.view.View
import android.widget.EditText import android.widget.EditText
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.core.os.bundleOf
import androidx.preference.EditTextPreferenceDialogFragmentCompat
import androidx.preference.PreferenceDialogFragmentCompat
import com.github.shadowsocks.ProfileConfigActivity import com.github.shadowsocks.ProfileConfigActivity
import com.github.shadowsocks.plugin.PluginContract import com.github.shadowsocks.plugin.PluginContract
import com.github.shadowsocks.plugin.PluginManager import com.github.shadowsocks.plugin.PluginManager
import com.takisoft.preferencex.EditTextPreferenceDialogFragmentCompat
class PluginConfigurationDialogFragment : EditTextPreferenceDialogFragmentCompat() { class PluginConfigurationDialogFragment : EditTextPreferenceDialogFragmentCompat() {
companion object { companion object {
const val PLUGIN_ID_FRAGMENT_TAG = private const val PLUGIN_ID_FRAGMENT_TAG =
"com.github.shadowsocks.preference.PluginConfigurationDialogFragment.PLUGIN_ID" "com.github.shadowsocks.preference.PluginConfigurationDialogFragment.PLUGIN_ID"
} }
fun setArg(key: String, plugin: String) {
arguments = bundleOf(PreferenceDialogFragmentCompat.ARG_KEY to key, PLUGIN_ID_FRAGMENT_TAG to plugin)
}
private lateinit var editText: EditText private lateinit var editText: EditText
override fun onPrepareDialogBuilder(builder: AlertDialog.Builder) { override fun onPrepareDialogBuilder(builder: AlertDialog.Builder) {
......
<?xml version="1.0" encoding="utf-8"?>
<!-- Based on: https://android.googlesource.com/platform/frameworks/support/+/9b8fb51/preference/res/layout/preference_dialog_edittext.xml -->
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="48dp"
android:layout_marginBottom="48dp"
android:overScrollMode="ifContentScrolls">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@android:id/message"
style="?android:attr/textAppearanceSmall"
android:layout_marginLeft="24dp"
android:layout_marginRight="24dp"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:layout_marginBottom="48dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="?android:attr/textColorSecondary"/>
<com.google.android.material.textfield.TextInputLayout
android:orientation="vertical"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:passwordToggleEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@android:id/edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:inputType="textPassword"
android:typeface="monospace"/>
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
</ScrollView>
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" <PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:app="http://schemas.android.com/apk/res-auto"
app:initialExpandedChildrenCount="3"> app:initialExpandedChildrenCount="3">
<SwitchPreference android:key="isAutoConnect"
android:persistent="false"
android:summary="@string/auto_connect_summary"
android:title="@string/auto_connect"/>
<SwitchPreference <SwitchPreference
android:key="directBootAware" app:key="isAutoConnect"
android:icon="@drawable/ic_action_lock" app:persistent="false"
android:summary="@string/direct_boot_aware_summary" app:summary="@string/auto_connect_summary"
android:title="@string/direct_boot_aware"/> app:title="@string/auto_connect"/>
<SwitchPreference <SwitchPreference
android:key="tcp_fastopen" app:key="directBootAware"
android:icon="@drawable/ic_action_offline_bolt" app:icon="@drawable/ic_action_lock"
android:summary="@string/tcp_fastopen_summary" app:summary="@string/direct_boot_aware_summary"
android:title="TCP Fast Open"/> app:title="@string/direct_boot_aware"/>
<SwitchPreference
app:key="tcp_fastopen"
app:icon="@drawable/ic_action_offline_bolt"
app:summary="@string/tcp_fastopen_summary"
app:title="TCP Fast Open"/>
<SimpleMenuPreference <com.takisoft.preferencex.SimpleMenuPreference
android:key="serviceMode" app:key="serviceMode"
android:entries="@array/service_modes" app:entries="@array/service_modes"
android:entryValues="@array/service_mode_values" app:entryValues="@array/service_mode_values"
android:defaultValue="vpn" app:defaultValue="vpn"
android:summary="%s" app:title="@string/service_mode"
android:title="@string/service_mode"/> app:useSimpleSummaryProvider="true"/>
<AutoSummaryEditTextPreference <EditTextPreference
android:key="portProxy" app:key="portProxy"
android:inputType="number" app:title="@string/port_proxy"
android:maxLength="5" app:useSimpleSummaryProvider="true"/>
app:pref_summaryHasText="%s" <EditTextPreference
android:singleLine="true" app:key="portLocalDns"
android:title="@string/port_proxy"/> app:icon="@drawable/ic_action_dns"
<AutoSummaryEditTextPreference app:title="@string/port_local_dns"
android:key="portLocalDns" app:useSimpleSummaryProvider="true"/>
android:icon="@drawable/ic_action_dns" <EditTextPreference
android:inputType="number" app:key="portTransproxy"
android:maxLength="5" app:title="@string/port_transproxy"
app:pref_summaryHasText="%s" app:useSimpleSummaryProvider="true"/>
android:singleLine="true"
android:title="@string/port_local_dns"/>
<AutoSummaryEditTextPreference
android:key="portTransproxy"
android:inputType="number"
android:maxLength="5"
app:pref_summaryHasText="%s"
android:singleLine="true"
android:title="@string/port_transproxy"/>
</PreferenceScreen> </PreferenceScreen>
...@@ -2,95 +2,88 @@ ...@@ -2,95 +2,88 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"> xmlns:app="http://schemas.android.com/apk/res-auto">
<AutoSummaryEditTextPreference <EditTextPreference
android:key="profileName" app:key="profileName"
app:pref_summaryHasText="%s" app:title="@string/profile_name"
android:title="@string/profile_name"/> app:useSimpleSummaryProvider="true"/>
<PreferenceCategory <PreferenceCategory
android:title="@string/proxy_cat"> app:title="@string/proxy_cat">
<AutoSummaryEditTextPreference <EditTextPreference
android:key="proxy" app:key="proxy"
app:pref_summaryHasText="%s" app:singleLine="true"
android:singleLine="true" app:title="@string/proxy"
android:title="@string/proxy"/> app:useSimpleSummaryProvider="true"/>
<AutoSummaryEditTextPreference <EditTextPreference
android:key="remotePortNum" app:key="remotePortNum"
android:inputType="number" app:title="@string/remote_port"
android:maxLength="5" app:useSimpleSummaryProvider="true"/>
app:pref_summaryHasText="%s" <EditTextPreference
android:singleLine="true" app:dialogLayout="@layout/preference_dialog_password"
android:title="@string/remote_port"/> app:key="sitekey"
<AutoSummaryEditTextPreference app:title="@string/sitekey"/>
android:inputType="textPassword" <com.takisoft.preferencex.SimpleMenuPreference
android:typeface="monospace" app:key="encMethod"
app:pref_summaryPasswordSubstituteLength="0" app:icon="@drawable/ic_notification_enhanced_encryption"
android:key="sitekey" app:entries="@array/enc_method_entry"
app:pref_summaryHasText="%s" app:entryValues="@array/enc_method_value"
android:singleLine="true" app:title="@string/enc_method"
android:title="@string/sitekey"/> app:useSimpleSummaryProvider="true"/>
<SimpleMenuPreference
android:key="encMethod"
android:icon="@drawable/ic_notification_enhanced_encryption"
android:entries="@array/enc_method_entry"
android:entryValues="@array/enc_method_value"
android:summary="%s"
android:title="@string/enc_method"/>
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory <PreferenceCategory
android:title="@string/feature_cat"> app:title="@string/feature_cat">
<SimpleMenuPreference <com.takisoft.preferencex.SimpleMenuPreference
android:key="route" app:key="route"
android:entries="@array/route_entry" app:entries="@array/route_entry"
android:entryValues="@array/route_value" app:entryValues="@array/route_value"
android:summary="%s" app:title="@string/route_list"
android:title="@string/route_list"/> app:useSimpleSummaryProvider="true"/>
<AutoSummaryEditTextPreference <EditTextPreference
android:key="remoteDns" app:key="remoteDns"
android:icon="@drawable/ic_action_dns" app:icon="@drawable/ic_action_dns"
android:title="@string/remote_dns" app:title="@string/remote_dns"
app:pref_summaryHasText="%s"/> app:useSimpleSummaryProvider="true"/>
<SwitchPreference <SwitchPreference
android:key="isIpv6" app:key="isIpv6"
android:icon="@drawable/ic_image_looks_6" app:icon="@drawable/ic_image_looks_6"
android:summary="@string/ipv6_summary" app:summary="@string/ipv6_summary"
android:title="@string/ipv6"/> app:title="@string/ipv6"/>
<SwitchPreference <SwitchPreference
android:key="isProxyApps" app:key="isProxyApps"
android:icon="@drawable/ic_navigation_apps" app:icon="@drawable/ic_navigation_apps"
android:summary="@string/proxied_apps_summary" app:summary="@string/proxied_apps_summary"
android:title="@string/proxied_apps"/> app:title="@string/proxied_apps"/>
<SwitchPreference <SwitchPreference
android:key="isUdpDns" app:key="isUdpDns"
android:icon="@drawable/ic_action_dns" app:icon="@drawable/ic_action_dns"
android:summary="@string/udp_dns_summary" app:summary="@string/udp_dns_summary"
android:title="@string/udp_dns"/> app:title="@string/udp_dns"/>
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory <PreferenceCategory
android:title="@string/plugin"> app:title="@string/plugin">
<com.github.shadowsocks.preference.IconListPreference <com.github.shadowsocks.preference.IconListPreference
android:key="plugin" app:key="plugin"
android:persistent="false" app:persistent="false"
android:summary="%s" app:title="@string/plugin"
android:title="@string/plugin"/> app:useSimpleSummaryProvider="true"/>
<AutoSummaryEditTextPreference <EditTextPreference
android:key="plugin.configure" app:key="plugin.configure"
android:icon="@drawable/ic_action_settings" app:icon="@drawable/ic_action_settings"
android:persistent="false" app:persistent="false"
android:singleLine="true" app:singleLine="true"
app:pref_summaryHasText="%s" app:title="@string/plugin_configure"
android:title="@string/plugin_configure"/> app:useSimpleSummaryProvider="true"/>
<Preference <Preference
android:key="udpFallback" app:key="udpFallback"
android:title="@string/udp_fallback" app:title="@string/udp_fallback"
android:summary="@string/plugin_disabled"> app:summary="@string/plugin_disabled">
<intent android:targetPackage="com.github.shadowsocks" <intent android:targetPackage="com.github.shadowsocks"
android:targetClass="com.github.shadowsocks.UdpFallbackProfileActivity"/> android:targetClass="com.github.shadowsocks.UdpFallbackProfileActivity"/>
</Preference> </Preference>
......
...@@ -24,8 +24,8 @@ android { ...@@ -24,8 +24,8 @@ android {
} }
dependencies { dependencies {
api "androidx.core:core-ktx:1.0.1" api 'androidx.core:core-ktx:1.0.1'
api "com.google.android.material:material:1.1.0-alpha03" api 'com.google.android.material:material:1.1.0-alpha03'
api "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion" api "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"
testImplementation "junit:junit:$junitVersion" testImplementation "junit:junit:$junitVersion"
androidTestImplementation "androidx.test:runner:$androidTestVersion" androidTestImplementation "androidx.test:runner:$androidTestVersion"
......
...@@ -36,10 +36,7 @@ import androidx.leanback.preference.LeanbackPreferenceFragmentCompat ...@@ -36,10 +36,7 @@ import androidx.leanback.preference.LeanbackPreferenceFragmentCompat
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders import androidx.lifecycle.ViewModelProviders
import androidx.lifecycle.get import androidx.lifecycle.get
import androidx.preference.ListPreference import androidx.preference.*
import androidx.preference.Preference
import androidx.preference.PreferenceDataStore
import androidx.preference.SwitchPreference
import com.crashlytics.android.Crashlytics import com.crashlytics.android.Crashlytics
import com.github.shadowsocks.BootReceiver import com.github.shadowsocks.BootReceiver
import com.github.shadowsocks.Core import com.github.shadowsocks.Core
...@@ -53,6 +50,7 @@ import com.github.shadowsocks.net.HttpsTest ...@@ -53,6 +50,7 @@ import com.github.shadowsocks.net.HttpsTest
import com.github.shadowsocks.net.TcpFastOpen import com.github.shadowsocks.net.TcpFastOpen
import com.github.shadowsocks.preference.DataStore import com.github.shadowsocks.preference.DataStore
import com.github.shadowsocks.preference.OnPreferenceDataStoreChangeListener import com.github.shadowsocks.preference.OnPreferenceDataStoreChangeListener
import com.github.shadowsocks.preference.PortPreferenceListener
import com.github.shadowsocks.utils.Key import com.github.shadowsocks.utils.Key
import com.github.shadowsocks.utils.datas import com.github.shadowsocks.utils.datas
import com.github.shadowsocks.utils.printLog import com.github.shadowsocks.utils.printLog
...@@ -73,9 +71,9 @@ class MainPreferenceFragment : LeanbackPreferenceFragmentCompat(), ShadowsocksCo ...@@ -73,9 +71,9 @@ class MainPreferenceFragment : LeanbackPreferenceFragmentCompat(), ShadowsocksCo
private lateinit var serviceMode: Preference private lateinit var serviceMode: Preference
private lateinit var tfo: SwitchPreference private lateinit var tfo: SwitchPreference
private lateinit var shareOverLan: Preference private lateinit var shareOverLan: Preference
private lateinit var portProxy: Preference private lateinit var portProxy: EditTextPreference
private lateinit var portLocalDns: Preference private lateinit var portLocalDns: EditTextPreference
private lateinit var portTransproxy: Preference private lateinit var portTransproxy: EditTextPreference
private val onServiceModeChange = Preference.OnPreferenceChangeListener { _, newValue -> private val onServiceModeChange = Preference.OnPreferenceChangeListener { _, newValue ->
val (enabledLocalDns, enabledTransproxy) = when (newValue as String?) { val (enabledLocalDns, enabledTransproxy) = when (newValue as String?) {
Key.modeProxy -> Pair(false, false) Key.modeProxy -> Pair(false, false)
...@@ -157,12 +155,12 @@ class MainPreferenceFragment : LeanbackPreferenceFragmentCompat(), ShadowsocksCo ...@@ -157,12 +155,12 @@ class MainPreferenceFragment : LeanbackPreferenceFragmentCompat(), ShadowsocksCo
preferenceManager.preferenceDataStore = DataStore.publicStore preferenceManager.preferenceDataStore = DataStore.publicStore
DataStore.initGlobal() DataStore.initGlobal()
addPreferencesFromResource(R.xml.pref_main) addPreferencesFromResource(R.xml.pref_main)
fab = findPreference(Key.id) as ListPreference fab = findPreference(Key.id)
populateProfiles() populateProfiles()
stats = findPreference(Key.controlStats) stats = findPreference(Key.controlStats)
controlImport = findPreference(Key.controlImport) controlImport = findPreference(Key.controlImport)
(findPreference(Key.isAutoConnect) as SwitchPreference).apply { findPreference<SwitchPreference>(Key.isAutoConnect).apply {
setOnPreferenceChangeListener { _, value -> setOnPreferenceChangeListener { _, value ->
BootReceiver.enabled = value as Boolean BootReceiver.enabled = value as Boolean
true true
...@@ -170,7 +168,7 @@ class MainPreferenceFragment : LeanbackPreferenceFragmentCompat(), ShadowsocksCo ...@@ -170,7 +168,7 @@ class MainPreferenceFragment : LeanbackPreferenceFragmentCompat(), ShadowsocksCo
isChecked = BootReceiver.enabled isChecked = BootReceiver.enabled
} }
tfo = findPreference(Key.tfo) as SwitchPreference tfo = findPreference(Key.tfo)
tfo.isChecked = DataStore.tcpFastOpen tfo.isChecked = DataStore.tcpFastOpen
tfo.setOnPreferenceChangeListener { _, value -> tfo.setOnPreferenceChangeListener { _, value ->
if (value as Boolean && !TcpFastOpen.sendEnabled) { if (value as Boolean && !TcpFastOpen.sendEnabled) {
...@@ -190,10 +188,13 @@ class MainPreferenceFragment : LeanbackPreferenceFragmentCompat(), ShadowsocksCo ...@@ -190,10 +188,13 @@ class MainPreferenceFragment : LeanbackPreferenceFragmentCompat(), ShadowsocksCo
serviceMode = findPreference(Key.serviceMode) serviceMode = findPreference(Key.serviceMode)
shareOverLan = findPreference(Key.shareOverLan) shareOverLan = findPreference(Key.shareOverLan)
portProxy = findPreference(Key.portProxy) portProxy = findPreference(Key.portProxy)
portProxy.onBindEditTextListener = PortPreferenceListener
portLocalDns = findPreference(Key.portLocalDns) portLocalDns = findPreference(Key.portLocalDns)
portLocalDns.onBindEditTextListener = PortPreferenceListener
portTransproxy = findPreference(Key.portTransproxy) portTransproxy = findPreference(Key.portTransproxy)
portTransproxy.onBindEditTextListener = PortPreferenceListener
serviceMode.onPreferenceChangeListener = onServiceModeChange serviceMode.onPreferenceChangeListener = onServiceModeChange
findPreference(Key.about).apply { findPreference<Preference>(Key.about).apply {
summary = getString(R.string.about_title, BuildConfig.VERSION_NAME) summary = getString(R.string.about_title, BuildConfig.VERSION_NAME)
setOnPreferenceClickListener { setOnPreferenceClickListener {
Toast.makeText(requireContext(), "https://shadowsocks.org/android", Toast.LENGTH_SHORT).show() Toast.makeText(requireContext(), "https://shadowsocks.org/android", Toast.LENGTH_SHORT).show()
......
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen <PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android" app:title="@string/app_name">
xmlns:app="http://schemas.android.com/apk/res-auto"
android:title="@string/app_name">
<!-- profileId is stored in privateStore so its value needs to be populated manually --> <!-- profileId is stored in privateStore so its value needs to be populated manually -->
<ListPreference <ListPreference
android:key="profileId" app:key="profileId"
android:title="@string/connect" app:title="@string/connect"
android:summary="%s" app:persistent="false"
android:persistent="false"/> app:useSimpleSummaryProvider="true"/>
<Preference <Preference
android:key="control.stats" app:key="control.stats"
android:title="@string/connection_test_pending" app:title="@string/connection_test_pending"
android:summary="@string/stat_summary"/> app:summary="@string/stat_summary"/>
<Preference <Preference
android:key="control.import" app:key="control.import"
android:title="@string/action_import_file"/> app:title="@string/action_import_file"/>
<Preference <Preference
android:key="control.export" app:key="control.export"
android:title="@string/action_export_file"/> app:title="@string/action_export_file"/>
<PreferenceCategory <PreferenceCategory
android:title="@string/settings" app:title="@string/settings"
app:initialExpandedChildrenCount="2"> app:initialExpandedChildrenCount="2">
<SwitchPreference <SwitchPreference
android:key="isAutoConnect" app:key="isAutoConnect"
android:persistent="false" app:persistent="false"
android:summary="@string/auto_connect_summary" app:summary="@string/auto_connect_summary"
android:title="@string/auto_connect"/> app:title="@string/auto_connect"/>
<SwitchPreference <SwitchPreference
android:key="tcp_fastopen" app:key="tcp_fastopen"
android:summary="@string/tcp_fastopen_summary" app:summary="@string/tcp_fastopen_summary"
android:title="TCP Fast Open"/> app:title="TCP Fast Open"/>
<ListPreference <ListPreference
android:key="serviceMode" app:key="serviceMode"
android:entries="@array/service_modes" app:entries="@array/service_modes"
android:entryValues="@array/service_mode_values" app:entryValues="@array/service_mode_values"
android:defaultValue="vpn" app:defaultValue="vpn"
android:summary="%s" app:title="@string/service_mode"
android:title="@string/service_mode"/> app:useSimpleSummaryProvider="true"/>
<SwitchPreference <SwitchPreference
android:key="shareOverLan" app:key="shareOverLan"
android:title="@string/share_over_lan"/> app:title="@string/share_over_lan"/>
<com.takisoft.preferencex.AutoSummaryEditTextPreference <EditTextPreference
android:key="portProxy" app:key="portProxy"
android:inputType="number" app:title="@string/port_proxy"
android:maxLength="5" app:useSimpleSummaryProvider="true"/>
app:pref_summaryHasText="%s" <EditTextPreference
android:singleLine="true" app:key="portLocalDns"
android:title="@string/port_proxy"/> app:title="@string/port_local_dns"
<com.takisoft.preferencex.AutoSummaryEditTextPreference app:useSimpleSummaryProvider="true"/>
android:key="portLocalDns" <EditTextPreference
android:inputType="number" app:key="portTransproxy"
android:maxLength="5" app:title="@string/port_transproxy"
app:pref_summaryHasText="%s" app:useSimpleSummaryProvider="true"/>
android:singleLine="true"
android:title="@string/port_local_dns"/>
<com.takisoft.preferencex.AutoSummaryEditTextPreference
android:key="portTransproxy"
android:inputType="number"
android:maxLength="5"
app:pref_summaryHasText="%s"
android:singleLine="true"
android:title="@string/port_transproxy"/>
</PreferenceCategory> </PreferenceCategory>
<Preference <Preference
android:key="about" app:key="about"
android:title="@string/about"/> app:title="@string/about"/>
</PreferenceScreen> </PreferenceScreen>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment