diff --git a/build.gradle b/build.gradle index 9b7114fe48..ecb9f27a62 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,6 @@ buildscript { sdkVersion = 28 compileSdkVersion = 28 buildToolsVersion = '28.0.3' - preferencexVersion = '1.0.0' junitVersion = '4.12' androidTestVersion = '1.1.1' androidEspressoVersion = '3.1.1' diff --git a/core/build.gradle b/core/build.gradle index 6dadaa10d1..709b969b05 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -51,12 +51,11 @@ dependencies { api "android.arch.work:work-runtime-ktx:$workVersion" api "androidx.lifecycle:lifecycle-extensions:$lifecycleVersion" api "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleVersion" - api 'androidx.preference:preference:1.0.0' + api 'androidx.preference:preference:1.1.0-alpha04' api "androidx.room:room-runtime:$roomVersion" api 'com.crashlytics.sdk.android:crashlytics:2.9.9' api 'com.google.firebase:firebase-config:16.1.3' api 'com.google.firebase:firebase-core:16.0.7' - api "com.takisoft.preferencex:preferencex:$preferencexVersion" api 'dnsjava:dnsjava:2.1.8' api 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1' api 'org.connectbot.jsocks:jsocks:1.0.0' diff --git a/core/src/main/java/com/github/shadowsocks/preference/DataStore.kt b/core/src/main/java/com/github/shadowsocks/preference/DataStore.kt index eb45995a48..8d92b82612 100644 --- a/core/src/main/java/com/github/shadowsocks/preference/DataStore.kt +++ b/core/src/main/java/com/github/shadowsocks/preference/DataStore.kt @@ -42,7 +42,7 @@ object DataStore : OnPreferenceDataStoreChangeListener { publicStore.registerChangeListener(this) } - override fun onPreferenceDataStoreChanged(store: PreferenceDataStore, key: String?) { + override fun onPreferenceDataStoreChanged(store: PreferenceDataStore, key: String) { when (key) { Key.id -> if (DataStore.directBootAware) DirectBoot.update() } diff --git a/core/src/main/java/com/github/shadowsocks/preference/OnPreferenceDataStoreChangeListener.kt b/core/src/main/java/com/github/shadowsocks/preference/OnPreferenceDataStoreChangeListener.kt index bd5c1599ab..e18484b335 100644 --- a/core/src/main/java/com/github/shadowsocks/preference/OnPreferenceDataStoreChangeListener.kt +++ b/core/src/main/java/com/github/shadowsocks/preference/OnPreferenceDataStoreChangeListener.kt @@ -23,5 +23,5 @@ package com.github.shadowsocks.preference import androidx.preference.PreferenceDataStore interface OnPreferenceDataStoreChangeListener { - fun onPreferenceDataStoreChanged(store: PreferenceDataStore, key: String?) + fun onPreferenceDataStoreChanged(store: PreferenceDataStore, key: String) } diff --git a/core/src/main/java/com/github/shadowsocks/preference/PortPreferenceListener.kt b/core/src/main/java/com/github/shadowsocks/preference/PortPreferenceListener.kt new file mode 100644 index 0000000000..8e2a41749e --- /dev/null +++ b/core/src/main/java/com/github/shadowsocks/preference/PortPreferenceListener.kt @@ -0,0 +1,36 @@ +/******************************************************************************* + * * + * Copyright (C) 2019 by Max Lv * + * Copyright (C) 2019 by Mygod Studio * + * * + * 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 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() + } +} diff --git a/gradle.properties b/gradle.properties index 00a8c31dfd..b96cc2fa3d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,7 +11,7 @@ # The setting is particularly useful for tweaking memory settings. android.enableJetifier=true android.enableR8=true -# android.enableR8.fullMode=true +android.enableR8.fullMode=true android.useAndroidX=true # When configured, Gradle will run in incubating parallel mode. diff --git a/mobile/build.gradle b/mobile/build.gradle index 7978d883ba..f5c10ec1a4 100644 --- a/mobile/build.gradle +++ b/mobile/build.gradle @@ -56,11 +56,11 @@ androidExtensions { dependencies { implementation project(':core') - implementation "androidx.browser:browser:1.0.0" + implementation 'androidx.browser:browser:1.0.0' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'com.google.android.gms:play-services-vision:17.0.2' implementation 'com.google.firebase:firebase-ads:17.2.0' - 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 'net.glxn.qrgen:android:2.0' implementation 'xyz.belvi.mobilevision:barcodescanner:2.0.3' diff --git a/mobile/src/main/java/com/github/shadowsocks/App.kt b/mobile/src/main/java/com/github/shadowsocks/App.kt index 399bcb07b2..13c58c9182 100644 --- a/mobile/src/main/java/com/github/shadowsocks/App.kt +++ b/mobile/src/main/java/com/github/shadowsocks/App.kt @@ -23,17 +23,12 @@ package com.github.shadowsocks import android.app.Application import android.content.res.Configuration 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() { override fun onCreate() { super.onCreate() Core.init(this, MainActivity::class) AppCompatDelegate.setCompatVectorFromResourcesEnabled(true) - PreferenceFragmentCompat.registerPreferenceFragment(IconListPreference::class.java, - BottomSheetPreferenceDialogFragment::class.java) } override fun onConfigurationChanged(newConfig: Configuration) { diff --git a/mobile/src/main/java/com/github/shadowsocks/GlobalSettingsPreferenceFragment.kt b/mobile/src/main/java/com/github/shadowsocks/GlobalSettingsPreferenceFragment.kt index 7d35072d8a..f9340420e1 100644 --- a/mobile/src/main/java/com/github/shadowsocks/GlobalSettingsPreferenceFragment.kt +++ b/mobile/src/main/java/com/github/shadowsocks/GlobalSettingsPreferenceFragment.kt @@ -22,22 +22,24 @@ package com.github.shadowsocks import android.os.Build import android.os.Bundle +import androidx.preference.EditTextPreference import androidx.preference.Preference +import androidx.preference.PreferenceFragmentCompat import androidx.preference.SwitchPreference import com.github.shadowsocks.bg.BaseService import com.github.shadowsocks.preference.DataStore import com.github.shadowsocks.utils.DirectBoot import com.github.shadowsocks.utils.Key import com.github.shadowsocks.net.TcpFastOpen +import com.github.shadowsocks.preference.PortPreferenceListener import com.github.shadowsocks.utils.remove -import com.takisoft.preferencex.PreferenceFragmentCompat class GlobalSettingsPreferenceFragment : PreferenceFragmentCompat() { - override fun onCreatePreferencesFix(savedInstanceState: Bundle?, rootKey: String?) { + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { preferenceManager.preferenceDataStore = DataStore.publicStore DataStore.initGlobal() addPreferencesFromResource(R.xml.pref_global) - val boot = findPreference(Key.isAutoConnect) as SwitchPreference + val boot = findPreference(Key.isAutoConnect)!! boot.setOnPreferenceChangeListener { _, value -> BootReceiver.enabled = value as Boolean true @@ -45,13 +47,13 @@ class GlobalSettingsPreferenceFragment : PreferenceFragmentCompat() { boot.isChecked = BootReceiver.enabled if (Build.VERSION.SDK_INT >= 24) boot.setSummary(R.string.auto_connect_summary_v24) - val canToggleLocked = findPreference(Key.directBootAware) + val canToggleLocked = findPreference(Key.directBootAware)!! if (Build.VERSION.SDK_INT >= 24) canToggleLocked.setOnPreferenceChangeListener { _, newValue -> if (Core.directBootSupported && newValue as Boolean) DirectBoot.update() else DirectBoot.clean() true } else canToggleLocked.remove() - val tfo = findPreference(Key.tfo) as SwitchPreference + val tfo = findPreference(Key.tfo)!! tfo.isChecked = DataStore.tcpFastOpen tfo.setOnPreferenceChangeListener { _, value -> if (value as Boolean && !TcpFastOpen.sendEnabled) { @@ -68,10 +70,13 @@ class GlobalSettingsPreferenceFragment : PreferenceFragmentCompat() { tfo.summary = getString(R.string.tcp_fastopen_summary_unsupported, System.getProperty("os.version")) } - val serviceMode = findPreference(Key.serviceMode) - val portProxy = findPreference(Key.portProxy) - val portLocalDns = findPreference(Key.portLocalDns) - val portTransproxy = findPreference(Key.portTransproxy) + val serviceMode = findPreference(Key.serviceMode)!! + val portProxy = findPreference(Key.portProxy)!! + portProxy.onBindEditTextListener = PortPreferenceListener + val portLocalDns = findPreference(Key.portLocalDns)!! + portLocalDns.onBindEditTextListener = PortPreferenceListener + val portTransproxy = findPreference(Key.portTransproxy)!! + portTransproxy.onBindEditTextListener = PortPreferenceListener val onServiceModeChange = Preference.OnPreferenceChangeListener { _, newValue -> val (enabledLocalDns, enabledTransproxy) = when (newValue as String?) { Key.modeProxy -> Pair(false, false) diff --git a/mobile/src/main/java/com/github/shadowsocks/MainActivity.kt b/mobile/src/main/java/com/github/shadowsocks/MainActivity.kt index 1e511509cf..5159a556a5 100644 --- a/mobile/src/main/java/com/github/shadowsocks/MainActivity.kt +++ b/mobile/src/main/java/com/github/shadowsocks/MainActivity.kt @@ -209,7 +209,7 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Callback, OnPref else ImportProfilesDialogFragment().withArg(ProfilesArg(profiles)).show(supportFragmentManager, null) } - override fun onPreferenceDataStoreChanged(store: PreferenceDataStore, key: String?) { + override fun onPreferenceDataStoreChanged(store: PreferenceDataStore, key: String) { when (key) { Key.serviceMode -> handler.post { connection.disconnect(this) diff --git a/mobile/src/main/java/com/github/shadowsocks/ProfileConfigFragment.kt b/mobile/src/main/java/com/github/shadowsocks/ProfileConfigFragment.kt index 18f24c5145..e4eba5e2d8 100644 --- a/mobile/src/main/java/com/github/shadowsocks/ProfileConfigFragment.kt +++ b/mobile/src/main/java/com/github/shadowsocks/ProfileConfigFragment.kt @@ -28,30 +28,24 @@ import android.os.Bundle import android.os.Parcelable import android.view.MenuItem import androidx.appcompat.app.AlertDialog -import androidx.core.os.bundleOf -import androidx.preference.Preference -import androidx.preference.PreferenceDataStore -import androidx.preference.SwitchPreference +import androidx.preference.* import com.github.shadowsocks.Core.app import com.github.shadowsocks.database.Profile import com.github.shadowsocks.database.ProfileManager import com.github.shadowsocks.plugin.* -import com.github.shadowsocks.preference.DataStore -import com.github.shadowsocks.preference.IconListPreference -import com.github.shadowsocks.preference.OnPreferenceDataStoreChangeListener -import com.github.shadowsocks.preference.PluginConfigurationDialogFragment +import com.github.shadowsocks.preference.* import com.github.shadowsocks.utils.Action import com.github.shadowsocks.utils.DirectBoot import com.github.shadowsocks.utils.Key import com.github.shadowsocks.utils.readableMessage import com.google.android.material.snackbar.Snackbar -import com.takisoft.preferencex.EditTextPreference -import com.takisoft.preferencex.PreferenceFragmentCompat import kotlinx.android.parcel.Parcelize class ProfileConfigFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChangeListener, OnPreferenceDataStoreChangeListener { - companion object { + companion object PasswordSummaryProvider : Preference.SummaryProvider { + override fun provideSummary(preference: EditTextPreference?) = "\u2022".repeat(preference?.text?.length ?: 0) + private const val REQUEST_CODE_PLUGIN_CONFIGURE = 1 const val REQUEST_UNSAVED_CHANGES = 2 } @@ -77,23 +71,25 @@ class ProfileConfigFragment : PreferenceFragmentCompat(), private lateinit var receiver: BroadcastReceiver private lateinit var udpFallback: Preference - override fun onCreatePreferencesFix(savedInstanceState: Bundle?, rootKey: String?) { + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { preferenceManager.preferenceDataStore = DataStore.privateStore val activity = requireActivity() profileId = activity.intent.getLongExtra(Action.EXTRA_PROFILE_ID, -1L) addPreferencesFromResource(R.xml.pref_profile) + findPreference(Key.remotePort)!!.onBindEditTextListener = PortPreferenceListener + findPreference(Key.password)!!.summaryProvider = PasswordSummaryProvider val serviceMode = DataStore.serviceMode - findPreference(Key.remoteDns).isEnabled = serviceMode != Key.modeProxy - isProxyApps = findPreference(Key.proxyApps) as SwitchPreference + findPreference(Key.remoteDns)!!.isEnabled = serviceMode != Key.modeProxy + isProxyApps = findPreference(Key.proxyApps)!! isProxyApps.isEnabled = serviceMode == Key.modeVpn isProxyApps.setOnPreferenceClickListener { startActivity(Intent(activity, AppManager::class.java)) isProxyApps.isChecked = true false } - findPreference(Key.udpdns).isEnabled = serviceMode != Key.modeProxy - plugin = findPreference(Key.plugin) as IconListPreference - pluginConfigure = findPreference(Key.pluginConfigure) as EditTextPreference + findPreference(Key.udpdns)!!.isEnabled = serviceMode != Key.modeProxy + plugin = findPreference(Key.plugin)!! + pluginConfigure = findPreference(Key.pluginConfigure)!! plugin.unknownValueSummary = getString(R.string.plugin_unknown) plugin.setOnPreferenceChangeListener { _, newValue -> pluginConfiguration = PluginConfiguration(pluginConfiguration.pluginsOptions, newValue as String) @@ -109,7 +105,7 @@ class ProfileConfigFragment : PreferenceFragmentCompat(), pluginConfigure.onPreferenceChangeListener = this initPlugins() receiver = Core.listenForPackageChanges(false) { initPlugins() } - udpFallback = findPreference(Key.udpFallback) + udpFallback = findPreference(Key.udpFallback)!! DataStore.privateStore.registerChangeListener(this) } @@ -122,14 +118,16 @@ class ProfileConfigFragment : PreferenceFragmentCompat(), pluginConfiguration = PluginConfiguration(DataStore.plugin) plugin.value = pluginConfiguration.selected plugin.init() - plugin.checkSummary() pluginConfigure.isEnabled = pluginConfiguration.selected.isNotEmpty() pluginConfigure.text = pluginConfiguration.selectedOptions.toString() } - private fun showPluginEditor() = displayPreferenceDialog(PluginConfigurationDialogFragment(), Key.pluginConfigure, - bundleOf(Pair("key", Key.pluginConfigure), - Pair(PluginConfigurationDialogFragment.PLUGIN_ID_FRAGMENT_TAG, pluginConfiguration.selected))) + private fun showPluginEditor() { + PluginConfigurationDialogFragment().apply { + setArg(Key.pluginConfigure, pluginConfiguration.selected) + setTargetFragment(this@ProfileConfigFragment, 0) + }.show(fragmentManager ?: return, Key.pluginConfigure) + } private fun saveAndExit() { val profile = ProfileManager.getProfile(profileId) ?: Profile() @@ -161,18 +159,26 @@ class ProfileConfigFragment : PreferenceFragmentCompat(), false } - override fun onPreferenceDataStoreChanged(store: PreferenceDataStore, key: String?) { - if (key != Key.proxyApps && findPreference(key) != null) DataStore.dirty = true + override fun onPreferenceDataStoreChanged(store: PreferenceDataStore, key: String) { + if (key != Key.proxyApps && findPreference(key) != null) DataStore.dirty = true } override fun onDisplayPreferenceDialog(preference: Preference) { - if (preference.key == Key.pluginConfigure) { - val intent = PluginManager.buildIntent(pluginConfiguration.selected, PluginContract.ACTION_CONFIGURE) - if (intent.resolveActivity(requireContext().packageManager) == null) showPluginEditor() else - startActivityForResult(intent - .putExtra(PluginContract.EXTRA_OPTIONS, pluginConfiguration.selectedOptions.toString()), - REQUEST_CODE_PLUGIN_CONFIGURE) - } else super.onDisplayPreferenceDialog(preference) + 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) + if (intent.resolveActivity(requireContext().packageManager) == null) showPluginEditor() else { + startActivityForResult(intent + .putExtra(PluginContract.EXTRA_OPTIONS, pluginConfiguration.selectedOptions.toString()), + REQUEST_CODE_PLUGIN_CONFIGURE) + } + } + else -> super.onDisplayPreferenceDialog(preference) + } } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { diff --git a/mobile/src/main/java/com/github/shadowsocks/preference/BottomSheetPreferenceDialogFragment.kt b/mobile/src/main/java/com/github/shadowsocks/preference/BottomSheetPreferenceDialogFragment.kt index 9f0f226cf2..487bbf60e0 100644 --- a/mobile/src/main/java/com/github/shadowsocks/preference/BottomSheetPreferenceDialogFragment.kt +++ b/mobile/src/main/java/com/github/shadowsocks/preference/BottomSheetPreferenceDialogFragment.kt @@ -32,6 +32,7 @@ import android.view.View import android.view.ViewGroup import android.widget.ImageView import android.widget.TextView +import androidx.core.os.bundleOf import androidx.core.view.isVisible import androidx.preference.PreferenceDialogFragmentCompat import androidx.recyclerview.widget.DefaultItemAnimator @@ -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 var clickedIndex = -1 diff --git a/mobile/src/main/java/com/github/shadowsocks/preference/IconListPreference.kt b/mobile/src/main/java/com/github/shadowsocks/preference/IconListPreference.kt index ac9b2c4d1d..76718a3ee2 100644 --- a/mobile/src/main/java/com/github/shadowsocks/preference/IconListPreference.kt +++ b/mobile/src/main/java/com/github/shadowsocks/preference/IconListPreference.kt @@ -26,6 +26,14 @@ import android.util.AttributeSet import androidx.preference.ListPreference class IconListPreference(context: Context, attrs: AttributeSet? = null) : ListPreference(context, attrs) { + companion object FallbackProvider : SummaryProvider { + 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? = null val selectedEntry: Int get() = entryValues.indexOf(value) val entryIcon: Drawable? get() = entryIcons?.getOrNull(selectedEntry) @@ -49,7 +57,6 @@ class IconListPreference(context: Context, attrs: AttributeSet? = null) : ListPr val listener = listener if (listener == null || listener.onPreferenceChange(preference, newValue)) { value = newValue.toString() - checkSummary() if (entryIcons != null) icon = entryIcon true } else false @@ -60,13 +67,9 @@ class IconListPreference(context: Context, attrs: AttributeSet? = null) : ListPr // a.recycle() } - fun checkSummary() { - val unknownValueSummary = unknownValueSummary - if (unknownValueSummary != null) summary = if (selectedEntry < 0) unknownValueSummary.format(value) else "%s" - } - fun init() { icon = entryIcon + summaryProvider = FallbackProvider } override fun onSetInitialValue(defaultValue: Any?) { super.onSetInitialValue(defaultValue) diff --git a/mobile/src/main/java/com/github/shadowsocks/preference/PluginConfigurationDialogFragment.kt b/mobile/src/main/java/com/github/shadowsocks/preference/PluginConfigurationDialogFragment.kt index 253397717f..902fd70202 100644 --- a/mobile/src/main/java/com/github/shadowsocks/preference/PluginConfigurationDialogFragment.kt +++ b/mobile/src/main/java/com/github/shadowsocks/preference/PluginConfigurationDialogFragment.kt @@ -23,17 +23,23 @@ package com.github.shadowsocks.preference import android.view.View import android.widget.EditText 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.plugin.PluginContract import com.github.shadowsocks.plugin.PluginManager -import com.takisoft.preferencex.EditTextPreferenceDialogFragmentCompat class PluginConfigurationDialogFragment : EditTextPreferenceDialogFragmentCompat() { companion object { - const val PLUGIN_ID_FRAGMENT_TAG = + private const val PLUGIN_ID_FRAGMENT_TAG = "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 override fun onPrepareDialogBuilder(builder: AlertDialog.Builder) { diff --git a/mobile/src/main/res/layout/preference_dialog_password.xml b/mobile/src/main/res/layout/preference_dialog_password.xml new file mode 100644 index 0000000000..1dfe01de86 --- /dev/null +++ b/mobile/src/main/res/layout/preference_dialog_password.xml @@ -0,0 +1,44 @@ + + + + + + + + + + diff --git a/mobile/src/main/res/xml/pref_global.xml b/mobile/src/main/res/xml/pref_global.xml index d7199b27cd..953aed77b9 100644 --- a/mobile/src/main/res/xml/pref_global.xml +++ b/mobile/src/main/res/xml/pref_global.xml @@ -1,49 +1,40 @@ - - + app:key="isAutoConnect" + app:persistent="false" + app:summary="@string/auto_connect_summary" + app:title="@string/auto_connect"/> + app:key="directBootAware" + app:icon="@drawable/ic_action_lock" + app:summary="@string/direct_boot_aware_summary" + app:title="@string/direct_boot_aware"/> + - - - - + + + + diff --git a/mobile/src/main/res/xml/pref_profile.xml b/mobile/src/main/res/xml/pref_profile.xml index 626d333c0e..89149f50ab 100644 --- a/mobile/src/main/res/xml/pref_profile.xml +++ b/mobile/src/main/res/xml/pref_profile.xml @@ -2,95 +2,88 @@ - + + app:title="@string/proxy_cat"> - - - - + + + + + app:title="@string/feature_cat"> - - + + + app:key="isIpv6" + app:icon="@drawable/ic_image_looks_6" + app:summary="@string/ipv6_summary" + app:title="@string/ipv6"/> + app:key="isProxyApps" + app:icon="@drawable/ic_navigation_apps" + app:summary="@string/proxied_apps_summary" + app:title="@string/proxied_apps"/> + app:key="isUdpDns" + app:icon="@drawable/ic_action_dns" + app:summary="@string/udp_dns_summary" + app:title="@string/udp_dns"/> + app:title="@string/plugin"> - + app:key="plugin" + app:persistent="false" + app:title="@string/plugin" + app:useSimpleSummaryProvider="true"/> + + app:key="udpFallback" + app:title="@string/udp_fallback" + app:summary="@string/plugin_disabled"> diff --git a/tv/src/main/java/com/github/shadowsocks/tv/MainFragment.kt b/tv/src/main/java/com/github/shadowsocks/tv/MainFragment.kt index df10c729dd..88d8981b65 100644 --- a/tv/src/main/java/com/github/shadowsocks/tv/MainFragment.kt +++ b/tv/src/main/java/com/github/shadowsocks/tv/MainFragment.kt @@ -20,11 +20,7 @@ package com.github.shadowsocks.tv -import android.os.Bundle -import android.view.View -import android.view.ViewGroup import androidx.core.os.bundleOf -import androidx.core.view.updateLayoutParams import androidx.leanback.preference.LeanbackPreferenceDialogFragmentCompat import androidx.leanback.preference.LeanbackSettingsFragmentCompat import androidx.preference.* @@ -59,11 +55,4 @@ class MainFragment : LeanbackSettingsFragmentCompat() { } return super.onPreferenceDisplayDialog(caller, pref) } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - view.findViewById(R.id.settings_preference_fragment_container).updateLayoutParams { - width = ViewGroup.LayoutParams.MATCH_PARENT - } - } } diff --git a/tv/src/main/java/com/github/shadowsocks/tv/MainPreferenceFragment.kt b/tv/src/main/java/com/github/shadowsocks/tv/MainPreferenceFragment.kt index 05039b330b..83381d2e9f 100644 --- a/tv/src/main/java/com/github/shadowsocks/tv/MainPreferenceFragment.kt +++ b/tv/src/main/java/com/github/shadowsocks/tv/MainPreferenceFragment.kt @@ -35,10 +35,7 @@ import androidx.leanback.preference.LeanbackPreferenceFragmentCompat import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProviders import androidx.lifecycle.get -import androidx.preference.ListPreference -import androidx.preference.Preference -import androidx.preference.PreferenceDataStore -import androidx.preference.SwitchPreference +import androidx.preference.* import com.crashlytics.android.Crashlytics import com.github.shadowsocks.BootReceiver import com.github.shadowsocks.Core @@ -51,6 +48,7 @@ import com.github.shadowsocks.net.HttpsTest import com.github.shadowsocks.net.TcpFastOpen import com.github.shadowsocks.preference.DataStore import com.github.shadowsocks.preference.OnPreferenceDataStoreChangeListener +import com.github.shadowsocks.preference.PortPreferenceListener import com.github.shadowsocks.utils.Key import com.github.shadowsocks.utils.datas import com.github.shadowsocks.utils.printLog @@ -71,9 +69,9 @@ class MainPreferenceFragment : LeanbackPreferenceFragmentCompat(), ShadowsocksCo private lateinit var serviceMode: Preference private lateinit var tfo: SwitchPreference private lateinit var shareOverLan: Preference - private lateinit var portProxy: Preference - private lateinit var portLocalDns: Preference - private lateinit var portTransproxy: Preference + private lateinit var portProxy: EditTextPreference + private lateinit var portLocalDns: EditTextPreference + private lateinit var portTransproxy: EditTextPreference private val onServiceModeChange = Preference.OnPreferenceChangeListener { _, newValue -> val (enabledLocalDns, enabledTransproxy) = when (newValue as String?) { Key.modeProxy -> Pair(false, false) @@ -155,12 +153,12 @@ class MainPreferenceFragment : LeanbackPreferenceFragmentCompat(), ShadowsocksCo preferenceManager.preferenceDataStore = DataStore.publicStore DataStore.initGlobal() addPreferencesFromResource(R.xml.pref_main) - fab = findPreference(Key.id) as ListPreference + fab = findPreference(Key.id)!! populateProfiles() - stats = findPreference(Key.controlStats) - controlImport = findPreference(Key.controlImport) + stats = findPreference(Key.controlStats)!! + controlImport = findPreference(Key.controlImport)!! - (findPreference(Key.isAutoConnect) as SwitchPreference).apply { + findPreference(Key.isAutoConnect)!!.apply { setOnPreferenceChangeListener { _, value -> BootReceiver.enabled = value as Boolean true @@ -168,7 +166,7 @@ class MainPreferenceFragment : LeanbackPreferenceFragmentCompat(), ShadowsocksCo isChecked = BootReceiver.enabled } - tfo = findPreference(Key.tfo) as SwitchPreference + tfo = findPreference(Key.tfo)!! tfo.isChecked = DataStore.tcpFastOpen tfo.setOnPreferenceChangeListener { _, value -> if (value as Boolean && !TcpFastOpen.sendEnabled) { @@ -185,13 +183,16 @@ class MainPreferenceFragment : LeanbackPreferenceFragmentCompat(), ShadowsocksCo tfo.summary = getString(R.string.tcp_fastopen_summary_unsupported, System.getProperty("os.version")) } - serviceMode = findPreference(Key.serviceMode) - shareOverLan = findPreference(Key.shareOverLan) - portProxy = findPreference(Key.portProxy) - portLocalDns = findPreference(Key.portLocalDns) - portTransproxy = findPreference(Key.portTransproxy) + serviceMode = findPreference(Key.serviceMode)!! + shareOverLan = findPreference(Key.shareOverLan)!! + portProxy = findPreference(Key.portProxy)!! + portProxy.onBindEditTextListener = PortPreferenceListener + portLocalDns = findPreference(Key.portLocalDns)!! + portLocalDns.onBindEditTextListener = PortPreferenceListener + portTransproxy = findPreference(Key.portTransproxy)!! + portTransproxy.onBindEditTextListener = PortPreferenceListener serviceMode.onPreferenceChangeListener = onServiceModeChange - findPreference(Key.about).apply { + findPreference(Key.about)!!.apply { summary = getString(R.string.about_title, BuildConfig.VERSION_NAME) setOnPreferenceClickListener { Toast.makeText(requireContext(), "https://shadowsocks.org/android", Toast.LENGTH_SHORT).show() @@ -235,7 +236,7 @@ class MainPreferenceFragment : LeanbackPreferenceFragmentCompat(), ShadowsocksCo } } - override fun onPreferenceDataStoreChanged(store: PreferenceDataStore, key: String?) { + override fun onPreferenceDataStoreChanged(store: PreferenceDataStore, key: String) { when (key) { Key.serviceMode -> handler.post { connection.disconnect(requireContext()) diff --git a/tv/src/main/res/values/styles.xml b/tv/src/main/res/values/styles.xml index d96fdd4613..b7e3e05261 100644 --- a/tv/src/main/res/values/styles.xml +++ b/tv/src/main/res/values/styles.xml @@ -5,6 +5,9 @@ @color/material_accent_200 @color/color_primary @color/color_primary_dark + true + @android:color/transparent + true @style/PreferenceThemeOverlay.v14.Leanback diff --git a/tv/src/main/res/xml/pref_main.xml b/tv/src/main/res/xml/pref_main.xml index 11621cd30b..cc79b34386 100644 --- a/tv/src/main/res/xml/pref_main.xml +++ b/tv/src/main/res/xml/pref_main.xml @@ -1,72 +1,61 @@ - + + app:key="profileId" + app:title="@string/connect" + app:persistent="false" + app:useSimpleSummaryProvider="true"/> + app:key="control.stats" + app:title="@string/connection_test_pending" + app:summary="@string/stat_summary"/> + app:key="control.import" + app:title="@string/action_replace_file"/> + app:key="control.export" + app:title="@string/action_export_file"/> + app:key="isAutoConnect" + app:persistent="false" + app:summary="@string/auto_connect_summary" + app:title="@string/auto_connect"/> + app:key="tcp_fastopen" + app:summary="@string/tcp_fastopen_summary" + app:title="TCP Fast Open"/> + app:key="serviceMode" + app:entries="@array/service_modes" + app:entryValues="@array/service_mode_values" + app:defaultValue="vpn" + app:title="@string/service_mode" + app:useSimpleSummaryProvider="true"/> - - - + app:key="shareOverLan" + app:title="@string/share_over_lan"/> + + + + app:key="about" + app:title="@string/about"/>