From 0939f5b4b81a03b107a9cc03350f503d7a541469 Mon Sep 17 00:00:00 2001 From: Mygod Date: Tue, 12 Feb 2019 23:05:25 +0800 Subject: [PATCH 1/6] Migrate to androidx.preference 1.1.0 Also allows show password. See also #1948. --- build.gradle | 1 - core/build.gradle | 3 +- .../preference/PortPreferenceListener.kt | 36 +++++ gradle.properties | 2 +- mobile/build.gradle | 4 +- .../main/java/com/github/shadowsocks/App.kt | 5 - .../GlobalSettingsPreferenceFragment.kt | 23 +-- .../shadowsocks/ProfileConfigFragment.kt | 66 +++++---- .../BottomSheetPreferenceDialogFragment.kt | 5 + .../preference/IconListPreference.kt | 15 +- .../PluginConfigurationDialogFragment.kt | 10 +- .../res/layout/preference_dialog_password.xml | 44 ++++++ mobile/src/main/res/xml/pref_global.xml | 77 +++++----- mobile/src/main/res/xml/pref_profile.xml | 135 +++++++++--------- plugin/build.gradle | 4 +- .../shadowsocks/tv/MainPreferenceFragment.kt | 23 +-- tv/src/main/res/xml/pref_main.xml | 97 ++++++------- 17 files changed, 312 insertions(+), 238 deletions(-) create mode 100644 core/src/main/java/com/github/shadowsocks/preference/PortPreferenceListener.kt create mode 100644 mobile/src/main/res/layout/preference_dialog_password.xml diff --git a/build.gradle b/build.gradle index d781942c97..1ec7a98dee 100644 --- a/build.gradle +++ b/build.gradle @@ -12,7 +12,6 @@ buildscript { lifecycleVersion = '2.0.0' roomVersion = '2.0.0' workVersion = '1.0.0-beta05' - 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 d21bc2d811..f579e87592 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -43,12 +43,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-alpha03' api "androidx.room:room-runtime:$roomVersion" api 'com.crashlytics.sdk.android:crashlytics:2.9.9' api 'com.google.firebase:firebase-config:16.3.0' 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/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 f87dc1290e..aac8046a69 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 d9ea8c2ae6..3cf1a50ed3 100644 --- a/mobile/build.gradle +++ b/mobile/build.gradle @@ -51,10 +51,10 @@ android { dependencies { 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.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 '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 4fddc5a78d..3911c05538 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/ProfileConfigFragment.kt b/mobile/src/main/java/com/github/shadowsocks/ProfileConfigFragment.kt index 9e0d4cbe3b..4adac29e9d 100644 --- a/mobile/src/main/java/com/github/shadowsocks/ProfileConfigFragment.kt +++ b/mobile/src/main/java/com/github/shadowsocks/ProfileConfigFragment.kt @@ -26,10 +26,7 @@ import android.content.Intent import android.os.Bundle 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 @@ -37,20 +34,17 @@ import com.github.shadowsocks.plugin.PluginConfiguration import com.github.shadowsocks.plugin.PluginContract import com.github.shadowsocks.plugin.PluginManager import com.github.shadowsocks.plugin.PluginOptions -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.google.android.material.snackbar.Snackbar -import com.takisoft.preferencex.EditTextPreference -import com.takisoft.preferencex.PreferenceFragmentCompat class ProfileConfigFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChangeListener, OnPreferenceDataStoreChangeListener { - companion object { + private companion object PasswordSummaryProvider : Preference.SummaryProvider { + override fun provideSummary(preference: EditTextPreference?) = "\u2022".repeat(preference?.text?.length ?: 0) + private const val REQUEST_CODE_PLUGIN_CONFIGURE = 1 } @@ -62,23 +56,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) @@ -107,14 +103,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) + } fun saveAndExit() { val profile = ProfileManager.getProfile(profileId) ?: Profile() @@ -147,17 +145,27 @@ class ProfileConfigFragment : PreferenceFragmentCompat(), } override fun onPreferenceDataStoreChanged(store: PreferenceDataStore, key: String?) { - if (key != Key.proxyApps && findPreference(key) != null) DataStore.dirty = true + 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/plugin/build.gradle b/plugin/build.gradle index cd67827b8b..57b55d0191 100644 --- a/plugin/build.gradle +++ b/plugin/build.gradle @@ -24,8 +24,8 @@ android { } dependencies { - api "androidx.core:core-ktx:1.0.1" - api "com.google.android.material:material:1.1.0-alpha03" + api 'androidx.core:core-ktx:1.0.1' + api 'com.google.android.material:material:1.1.0-alpha03' api "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion" testImplementation "junit:junit:$junitVersion" androidTestImplementation "androidx.test:runner:$androidTestVersion" 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 d5b4ed6482..047e98d272 100644 --- a/tv/src/main/java/com/github/shadowsocks/tv/MainPreferenceFragment.kt +++ b/tv/src/main/java/com/github/shadowsocks/tv/MainPreferenceFragment.kt @@ -36,10 +36,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 @@ -53,6 +50,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 @@ -73,9 +71,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) @@ -157,12 +155,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) - (findPreference(Key.isAutoConnect) as SwitchPreference).apply { + findPreference(Key.isAutoConnect).apply { setOnPreferenceChangeListener { _, value -> BootReceiver.enabled = value as Boolean true @@ -170,7 +168,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) { @@ -190,10 +188,13 @@ class MainPreferenceFragment : LeanbackPreferenceFragmentCompat(), ShadowsocksCo 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() diff --git a/tv/src/main/res/xml/pref_main.xml b/tv/src/main/res/xml/pref_main.xml index 7f6bb33eb4..ef2219dd84 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_import_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"/> From 046d9fe6f7db10ed56df5a835b8e875462b0f5a9 Mon Sep 17 00:00:00 2001 From: Mygod Date: Wed, 13 Feb 2019 12:28:37 +0800 Subject: [PATCH 2/6] Refine code style --- .../com/github/shadowsocks/ProfileConfigFragment.kt | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/mobile/src/main/java/com/github/shadowsocks/ProfileConfigFragment.kt b/mobile/src/main/java/com/github/shadowsocks/ProfileConfigFragment.kt index 4adac29e9d..58a58e4ec7 100644 --- a/mobile/src/main/java/com/github/shadowsocks/ProfileConfigFragment.kt +++ b/mobile/src/main/java/com/github/shadowsocks/ProfileConfigFragment.kt @@ -150,12 +150,10 @@ class ProfileConfigFragment : PreferenceFragmentCompat(), override fun onDisplayPreferenceDialog(preference: Preference) { when (preference.key) { - Key.plugin -> { - BottomSheetPreferenceDialogFragment().apply { - setArg(Key.plugin) - setTargetFragment(this@ProfileConfigFragment, 0) - }.show(fragmentManager ?: return, Key.plugin) - } + 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 { From 57b846d22a85a446f5503709d16e822dd7ef8e52 Mon Sep 17 00:00:00 2001 From: Mygod Date: Tue, 12 Feb 2019 20:05:51 +0800 Subject: [PATCH 3/6] Revert "Revert "Revert "Make app fullscreen to match guidelines""" This reverts commit e508915829deeff5d2ee9ad2e64419b1d6339c55. --- .../java/com/github/shadowsocks/tv/MainFragment.kt | 11 ----------- tv/src/main/res/values/styles.xml | 3 +++ 2 files changed, 3 insertions(+), 11 deletions(-) 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 f43b9b057c..4716b5c3e9 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/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 From f41717118c360487f82ddb681c98789032bea654 Mon Sep 17 00:00:00 2001 From: Mygod Date: Sun, 17 Feb 2019 14:03:08 +0800 Subject: [PATCH 4/6] Shrink RAM usage --- .circleci/config.yml | 1 - gradle.properties | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index c0f09a255b..ea79ae8c86 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -5,7 +5,6 @@ jobs: docker: - image: circleci/android:api-28-ndk environment: - JVM_OPTS: -Xmx3500m GRADLE_OPTS: -Dorg.gradle.workers.max=1 -Dorg.gradle.daemon=false -Dkotlin.compiler.execution.strategy="in-process" steps: - checkout diff --git a/gradle.properties b/gradle.properties index aac8046a69..b96cc2fa3d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -18,4 +18,4 @@ android.useAndroidX=true # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true -org.gradle.jvmargs=-Xmx3500m +org.gradle.jvmargs=-Xmx1536m From ef1ee897f9ff8eae6f55943834ff9e4aa721fbe5 Mon Sep 17 00:00:00 2001 From: Mygod Date: Sat, 23 Feb 2019 22:15:48 +0800 Subject: [PATCH 5/6] Fix private issue --- .../main/java/com/github/shadowsocks/ProfileConfigFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile/src/main/java/com/github/shadowsocks/ProfileConfigFragment.kt b/mobile/src/main/java/com/github/shadowsocks/ProfileConfigFragment.kt index 08544b92af..c4f2431bcd 100644 --- a/mobile/src/main/java/com/github/shadowsocks/ProfileConfigFragment.kt +++ b/mobile/src/main/java/com/github/shadowsocks/ProfileConfigFragment.kt @@ -43,7 +43,7 @@ import kotlinx.android.parcel.Parcelize class ProfileConfigFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChangeListener, OnPreferenceDataStoreChangeListener { - private companion object PasswordSummaryProvider : Preference.SummaryProvider { + companion object PasswordSummaryProvider : Preference.SummaryProvider { override fun provideSummary(preference: EditTextPreference?) = "\u2022".repeat(preference?.text?.length ?: 0) private const val REQUEST_CODE_PLUGIN_CONFIGURE = 1 From 5493bcea36773d8fa136e55a41d85a3198110729 Mon Sep 17 00:00:00 2001 From: Mygod Date: Fri, 15 Mar 2019 15:35:53 +0800 Subject: [PATCH 6/6] Update to preference 1.1.0-alpha04 --- core/build.gradle | 2 +- .../shadowsocks/preference/DataStore.kt | 2 +- .../OnPreferenceDataStoreChangeListener.kt | 2 +- .../GlobalSettingsPreferenceFragment.kt | 14 +++++------ .../com/github/shadowsocks/MainActivity.kt | 2 +- .../shadowsocks/ProfileConfigFragment.kt | 18 +++++++------- .../shadowsocks/tv/MainPreferenceFragment.kt | 24 +++++++++---------- 7 files changed, 32 insertions(+), 32 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index 8219cd6bc7..709b969b05 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -51,7 +51,7 @@ 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.1.0-alpha03' + 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' 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/mobile/src/main/java/com/github/shadowsocks/GlobalSettingsPreferenceFragment.kt b/mobile/src/main/java/com/github/shadowsocks/GlobalSettingsPreferenceFragment.kt index b8ea87af55..f9340420e1 100644 --- a/mobile/src/main/java/com/github/shadowsocks/GlobalSettingsPreferenceFragment.kt +++ b/mobile/src/main/java/com/github/shadowsocks/GlobalSettingsPreferenceFragment.kt @@ -39,7 +39,7 @@ class GlobalSettingsPreferenceFragment : PreferenceFragmentCompat() { preferenceManager.preferenceDataStore = DataStore.publicStore DataStore.initGlobal() addPreferencesFromResource(R.xml.pref_global) - val boot = findPreference(Key.isAutoConnect) + val boot = findPreference(Key.isAutoConnect)!! boot.setOnPreferenceChangeListener { _, value -> BootReceiver.enabled = value as Boolean true @@ -47,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) + val tfo = findPreference(Key.tfo)!! tfo.isChecked = DataStore.tcpFastOpen tfo.setOnPreferenceChangeListener { _, value -> if (value as Boolean && !TcpFastOpen.sendEnabled) { @@ -70,12 +70,12 @@ 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 serviceMode = findPreference(Key.serviceMode)!! + val portProxy = findPreference(Key.portProxy)!! portProxy.onBindEditTextListener = PortPreferenceListener - val portLocalDns = findPreference(Key.portLocalDns) + val portLocalDns = findPreference(Key.portLocalDns)!! portLocalDns.onBindEditTextListener = PortPreferenceListener - val portTransproxy = findPreference(Key.portTransproxy) + val portTransproxy = findPreference(Key.portTransproxy)!! portTransproxy.onBindEditTextListener = PortPreferenceListener val onServiceModeChange = Preference.OnPreferenceChangeListener { _, newValue -> val (enabledLocalDns, enabledTransproxy) = when (newValue as String?) { 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 c4f2431bcd..e4eba5e2d8 100644 --- a/mobile/src/main/java/com/github/shadowsocks/ProfileConfigFragment.kt +++ b/mobile/src/main/java/com/github/shadowsocks/ProfileConfigFragment.kt @@ -76,20 +76,20 @@ class ProfileConfigFragment : PreferenceFragmentCompat(), 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 + 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) + 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) - pluginConfigure = findPreference(Key.pluginConfigure) + 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) @@ -105,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) } @@ -159,7 +159,7 @@ class ProfileConfigFragment : PreferenceFragmentCompat(), false } - override fun onPreferenceDataStoreChanged(store: PreferenceDataStore, key: String?) { + override fun onPreferenceDataStoreChanged(store: PreferenceDataStore, key: String) { if (key != Key.proxyApps && findPreference(key) != null) DataStore.dirty = true } 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 b09238e1b6..83381d2e9f 100644 --- a/tv/src/main/java/com/github/shadowsocks/tv/MainPreferenceFragment.kt +++ b/tv/src/main/java/com/github/shadowsocks/tv/MainPreferenceFragment.kt @@ -153,12 +153,12 @@ class MainPreferenceFragment : LeanbackPreferenceFragmentCompat(), ShadowsocksCo preferenceManager.preferenceDataStore = DataStore.publicStore DataStore.initGlobal() addPreferencesFromResource(R.xml.pref_main) - fab = findPreference(Key.id) + fab = findPreference(Key.id)!! populateProfiles() - stats = findPreference(Key.controlStats) - controlImport = findPreference(Key.controlImport) + stats = findPreference(Key.controlStats)!! + controlImport = findPreference(Key.controlImport)!! - findPreference(Key.isAutoConnect).apply { + findPreference(Key.isAutoConnect)!!.apply { setOnPreferenceChangeListener { _, value -> BootReceiver.enabled = value as Boolean true @@ -166,7 +166,7 @@ class MainPreferenceFragment : LeanbackPreferenceFragmentCompat(), ShadowsocksCo isChecked = BootReceiver.enabled } - tfo = findPreference(Key.tfo) + tfo = findPreference(Key.tfo)!! tfo.isChecked = DataStore.tcpFastOpen tfo.setOnPreferenceChangeListener { _, value -> if (value as Boolean && !TcpFastOpen.sendEnabled) { @@ -183,16 +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) + serviceMode = findPreference(Key.serviceMode)!! + shareOverLan = findPreference(Key.shareOverLan)!! + 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 - 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() @@ -236,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())