diff --git a/mobile/build.gradle b/mobile/build.gradle index e9dd55ba..d8957929 100644 --- a/mobile/build.gradle +++ b/mobile/build.gradle @@ -66,14 +66,13 @@ dependencies { implementation "androidx.core:core-ktx:1.0.1" implementation "androidx.lifecycle:lifecycle-extensions:$lifecycleVersion" implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleVersion" - implementation "androidx.preference:preference:1.0.0" + implementation "androidx.preference:preference:1.1.0-alpha02" implementation "androidx.room:room-runtime:$roomVersion" implementation 'com.github.luongvo:BadgeView:1.1.5' implementation 'com.github.topjohnwu:libsu:2.1.2' implementation "com.google.android.material:material:1.0.0" implementation 'com.jakewharton.timber:timber:4.7.1' implementation 'com.linkedin.dexmaker:dexmaker-mockito:2.19.1' - implementation 'com.takisoft.preferencex:preferencex:1.0.0' implementation 'com.takisoft.preferencex:preferencex-simplemenu:1.0.0' implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion" baseImplementation 'com.android.billingclient:billing:1.2' diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/AlertDialogFragment.kt b/mobile/src/main/java/be/mygod/vpnhotspot/AlertDialogFragment.kt index 19c3a939..583f98f0 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/AlertDialogFragment.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/AlertDialogFragment.kt @@ -25,7 +25,7 @@ abstract class AlertDialogFragment : DialogFragment(), DialogInterface.OnClickLi targetFragment?.onActivityResult(targetRequestCode, which, data) } - override fun onDismiss(dialog: DialogInterface?) { + override fun onDismiss(dialog: DialogInterface) { super.onDismiss(dialog) targetFragment?.onActivityResult(targetRequestCode, Activity.RESULT_CANCELED, null) } diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/SettingsPreferenceFragment.kt b/mobile/src/main/java/be/mygod/vpnhotspot/SettingsPreferenceFragment.kt index 2b251ba2..1316111b 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/SettingsPreferenceFragment.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/SettingsPreferenceFragment.kt @@ -6,8 +6,8 @@ import android.os.Build import android.os.Bundle import androidx.core.content.FileProvider import androidx.core.net.toUri -import androidx.core.os.bundleOf import androidx.preference.Preference +import androidx.preference.PreferenceFragmentCompat import androidx.preference.SwitchPreference import be.mygod.vpnhotspot.App.Companion.app import be.mygod.vpnhotspot.net.Routing @@ -17,9 +17,9 @@ import be.mygod.vpnhotspot.net.monitor.IpMonitor import be.mygod.vpnhotspot.net.monitor.UpstreamMonitor import be.mygod.vpnhotspot.preference.AlwaysAutoCompleteEditTextPreferenceDialogFragmentCompat import be.mygod.vpnhotspot.preference.SharedPreferenceDataStore +import be.mygod.vpnhotspot.preference.SummaryFallbackProvider import be.mygod.vpnhotspot.util.RootSession import be.mygod.vpnhotspot.widget.SmartSnackbar -import com.takisoft.preferencex.PreferenceFragmentCompat import timber.log.Timber import java.io.File import java.io.IOException @@ -28,7 +28,7 @@ import java.net.NetworkInterface import java.net.SocketException class SettingsPreferenceFragment : PreferenceFragmentCompat() { - override fun onCreatePreferencesFix(savedInstanceState: Bundle?, rootKey: String?) { + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { preferenceManager.preferenceDataStore = SharedPreferenceDataStore(app.pref) addPreferencesFromResource(R.xml.pref_settings) val boot = findPreference("service.repeater.startOnBoot") as SwitchPreference @@ -39,7 +39,7 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() { } boot.isChecked = BootReceiver.enabled } else boot.parent!!.removePreference(boot) - findPreference("service.clean").setOnPreferenceClickListener { + findPreference("service.clean").setOnPreferenceClickListener { app.onPreCleanRoutings() val cleaned = try { Routing.clean() @@ -52,11 +52,12 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() { if (cleaned) app.onRoutingsCleaned() true } - findPreference(IpMonitor.KEY).setOnPreferenceChangeListener { _, _ -> + SummaryFallbackProvider(findPreference(Routing.KEY_DNS)) + findPreference(IpMonitor.KEY).setOnPreferenceChangeListener { _, _ -> SmartSnackbar.make(R.string.settings_restart_required).show() true } - findPreference("misc.logcat").setOnPreferenceClickListener { + findPreference("misc.logcat").setOnPreferenceClickListener { val context = requireContext() val logDir = File(context.cacheDir, "log") logDir.mkdir() @@ -118,28 +119,31 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() { getString(R.string.abc_shareactionprovider_share_with))) true } - findPreference("misc.source").setOnPreferenceClickListener { + findPreference("misc.source").setOnPreferenceClickListener { (activity as MainActivity).launchUrl("https://github.com/Mygod/VPNHotspot/blob/master/README.md".toUri()) true } - findPreference("misc.donate").setOnPreferenceClickListener { + findPreference("misc.donate").setOnPreferenceClickListener { EBegFragment().show(fragmentManager ?: return@setOnPreferenceClickListener false, "EBegFragment") true } } - override fun onDisplayPreferenceDialog(preference: Preference) = when (preference.key) { - UpstreamMonitor.KEY, FallbackUpstreamMonitor.KEY -> displayPreferenceDialog( - AlwaysAutoCompleteEditTextPreferenceDialogFragmentCompat(), preference.key, - bundleOf(Pair(AlwaysAutoCompleteEditTextPreferenceDialogFragmentCompat.KEY_SUGGESTIONS, - try { - NetworkInterface.getNetworkInterfaces().asSequence() - .filter { it.isUp && !it.isLoopback && it.interfaceAddresses.isNotEmpty() } - .map { it.name }.sorted().toList().toTypedArray() - } catch (e: SocketException) { - Timber.w(e) - emptyArray() - }))) - else -> super.onDisplayPreferenceDialog(preference) + override fun onDisplayPreferenceDialog(preference: Preference) { + when (preference.key) { + UpstreamMonitor.KEY, FallbackUpstreamMonitor.KEY -> + AlwaysAutoCompleteEditTextPreferenceDialogFragmentCompat().apply { + setArguments(preference.key, try { + NetworkInterface.getNetworkInterfaces().asSequence() + .filter { it.isUp && !it.isLoopback && it.interfaceAddresses.isNotEmpty() } + .map { it.name }.sorted().toList().toTypedArray() + } catch (e: SocketException) { + Timber.w(e) + emptyArray() + }) + setTargetFragment(this@SettingsPreferenceFragment, 0) + }.show(fragmentManager ?: return, preference.key) + else -> super.onDisplayPreferenceDialog(preference) + } } } diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/client/ClientsFragment.kt b/mobile/src/main/java/be/mygod/vpnhotspot/client/ClientsFragment.kt index 2c9abb27..1f3ef85d 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/client/ClientsFragment.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/client/ClientsFragment.kt @@ -59,7 +59,7 @@ class ClientsFragment : Fragment() { override fun onClick(di: DialogInterface?, which: Int) { AppDatabase.instance.clientRecordDao.lookup(mac.macToLong()).apply { - nickname = dialog.findViewById(android.R.id.edit).text + nickname = dialog!!.findViewById(android.R.id.edit).text AppDatabase.instance.clientRecordDao.update(this) } IpNeighbourMonitor.instance?.flush() diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/manage/RepeaterManager.kt b/mobile/src/main/java/be/mygod/vpnhotspot/manage/RepeaterManager.kt index 9e72edc9..f1b0d783 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/manage/RepeaterManager.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/manage/RepeaterManager.kt @@ -124,7 +124,7 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic setNeutralButton(R.string.repeater_wps_dialog_pbc, listener) } override val data: Intent get() = Intent() - .putExtra(KEY_PIN, dialog.findViewById(android.R.id.edit)?.text?.toString()) + .putExtra(KEY_PIN, dialog!!.findViewById(android.R.id.edit)?.text?.toString()) override fun onCreateDialog(savedInstanceState: Bundle?) = super.onCreateDialog(savedInstanceState).apply { window!!.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE) diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/net/Routing.kt b/mobile/src/main/java/be/mygod/vpnhotspot/net/Routing.kt index 3f61d02b..001857b9 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/net/Routing.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/net/Routing.kt @@ -43,6 +43,7 @@ class Routing(val downstream: String, ownerAddress: InterfaceAddress? = null) : * Source: https://android.googlesource.com/platform/external/iptables/+/android-5.0.0_r1/iptables/iptables.c#1574 */ val IPTABLES = if (Build.VERSION.SDK_INT >= 26) "iptables -w 1" else "iptables -w" + const val KEY_DNS = "service.dns" fun clean() { TrafficRecorder.clean() @@ -212,7 +213,7 @@ class Routing(val downstream: String, ownerAddress: InterfaceAddress? = null) : private var currentDns: DnsRoute? = null private fun updateDnsRoute() { var dns = (upstream.dns + fallbackUpstream.dns).firstOrNull { it is Inet4Address }?.hostAddress - ?: app.pref.getString("service.dns", null) + ?: app.pref.getString(KEY_DNS, null) if (dns.isNullOrBlank()) dns = "8.8.8.8" if (dns != currentDns?.dns) { currentDns?.transaction?.revert() diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiP2pDialogFragment.kt b/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiP2pDialogFragment.kt index 7412b024..07fa1831 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiP2pDialogFragment.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiP2pDialogFragment.kt @@ -61,9 +61,7 @@ class WifiP2pDialogFragment : AlertDialogFragment(), TextWatcher, DialogInterfac mPassword.addTextChangedListener(this@WifiP2pDialogFragment) } - override val data get() = Intent().apply { - putExtra(KEY_CONFIGURATION, config) - } + override val data get() = Intent().putExtra(KEY_CONFIGURATION, config) override fun onStart() { super.onStart() diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/preference/AlwaysAutoCompleteEditTextPreference.kt b/mobile/src/main/java/be/mygod/vpnhotspot/preference/AlwaysAutoCompleteEditTextPreference.kt index 43a29ac4..cb01b24f 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/preference/AlwaysAutoCompleteEditTextPreference.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/preference/AlwaysAutoCompleteEditTextPreference.kt @@ -3,17 +3,18 @@ package be.mygod.vpnhotspot.preference import android.content.Context import android.text.TextUtils import android.util.AttributeSet +import androidx.preference.EditTextPreference import be.mygod.vpnhotspot.R import be.mygod.vpnhotspot.widget.AlwaysAutoCompleteEditText -import com.takisoft.preferencex.AutoSummaryEditTextPreference open class AlwaysAutoCompleteEditTextPreference @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = R.attr.editTextPreferenceStyle, - defStyleRes: Int = 0) : AutoSummaryEditTextPreference(context, attrs, defStyleAttr, defStyleRes) { + defStyleRes: Int = 0) : EditTextPreference(context, attrs, defStyleAttr, defStyleRes) { val editText = AlwaysAutoCompleteEditText(context, attrs) init { editText.id = android.R.id.edit + SummaryFallbackProvider(this) } override fun setText(text: String?) { diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/preference/AlwaysAutoCompleteEditTextPreferenceDialogFragmentCompat.kt b/mobile/src/main/java/be/mygod/vpnhotspot/preference/AlwaysAutoCompleteEditTextPreferenceDialogFragmentCompat.kt index da1554cb..14c7a495 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/preference/AlwaysAutoCompleteEditTextPreferenceDialogFragmentCompat.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/preference/AlwaysAutoCompleteEditTextPreferenceDialogFragmentCompat.kt @@ -5,11 +5,16 @@ import android.view.ViewGroup import android.widget.ArrayAdapter import android.widget.EditText import androidx.appcompat.widget.AppCompatAutoCompleteTextView +import androidx.core.os.bundleOf import androidx.preference.PreferenceDialogFragmentCompat open class AlwaysAutoCompleteEditTextPreferenceDialogFragmentCompat : PreferenceDialogFragmentCompat() { companion object { - const val KEY_SUGGESTIONS = "suggestions" + private const val ARG_SUGGESTIONS = "suggestions" + } + + fun setArguments(key: String, suggestions: Array) { + arguments = bundleOf(Pair(ARG_KEY, key), Pair(ARG_SUGGESTIONS, suggestions)) } private lateinit var editText: AppCompatAutoCompleteTextView @@ -19,12 +24,13 @@ open class AlwaysAutoCompleteEditTextPreferenceDialogFragmentCompat : Preference super.onBindDialogView(view) editText = editTextPreference.editText + editText.hint = (editTextPreference.summaryProvider as SummaryFallbackProvider).fallback editText.setText(this.editTextPreference.text) val text = editText.text if (text != null) editText.setSelection(text.length, text.length) - val suggestions = arguments?.getStringArray(KEY_SUGGESTIONS) + val suggestions = arguments?.getStringArray(ARG_SUGGESTIONS) if (suggestions != null) editText.setAdapter(ArrayAdapter(view.context, android.R.layout.select_dialog_item, suggestions)) diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/preference/SummaryFallbackProvider.kt b/mobile/src/main/java/be/mygod/vpnhotspot/preference/SummaryFallbackProvider.kt new file mode 100644 index 00000000..d52b8320 --- /dev/null +++ b/mobile/src/main/java/be/mygod/vpnhotspot/preference/SummaryFallbackProvider.kt @@ -0,0 +1,15 @@ +package be.mygod.vpnhotspot.preference + +import androidx.preference.EditTextPreference +import androidx.preference.Preference + +class SummaryFallbackProvider(preference: Preference) : Preference.SummaryProvider { + val fallback = preference.summary + init { + preference.summaryProvider = this + } + + override fun provideSummary(preference: EditTextPreference) = preference.text.let { + if (it.isNullOrEmpty()) fallback else it + } +} diff --git a/mobile/src/main/res/xml/pref_settings.xml b/mobile/src/main/res/xml/pref_settings.xml index 15d1ccad..5cd4a895 100644 --- a/mobile/src/main/res/xml/pref_settings.xml +++ b/mobile/src/main/res/xml/pref_settings.xml @@ -1,91 +1,87 @@ - + + app:key="service.clean" + app:icon="@drawable/ic_action_settings_backup_restore" + app:title="@string/settings_service_clean" + app:summary="@string/settings_service_clean_summary"/> + app:title="@string/settings_upstream"> + app:key="service.upstream" + app:icon="@drawable/ic_action_settings_ethernet" + app:title="@string/settings_service_upstream" + app:summary="@string/settings_service_upstream_auto"/> + app:key="service.upstream.fallback" + app:icon="@drawable/ic_action_settings_input_component" + app:title="@string/settings_upstream_fallback" + app:summary="@string/settings_upstream_fallback_auto"/> + app:key="service.masquerade" + app:icon="@drawable/ic_social_people" + app:title="@string/settings_service_masquerade" + app:summary="@string/settings_service_masquerade_summary" + app:defaultValue="true"/> + app:title="@string/settings_downstream"> - + app:key="service.disableIpv6" + app:icon="@drawable/ic_image_looks_6" + app:title="@string/settings_service_disable_ipv6" + app:summary="@string/settings_service_disable_ipv6_summary"/> + + app:key="service.dhcpWorkaround" + app:icon="@drawable/ic_action_build" + app:title="@string/settings_service_dhcp_workaround" + app:summary="@string/settings_service_dhcp_workaround_summary"/> - + app:title="@string/settings_misc"> + - + app:key="service.repeater.startOnBoot" + app:icon="@drawable/ic_action_autorenew" + app:title="@string/settings_service_repeater_start_on_boot"/> + + app:title="@string/settings_help"> + app:key="misc.source" + app:icon="@drawable/ic_toggle_star" + app:title="@string/settings_misc_source" + app:summary="@string/settings_misc_source_summary"/> + app:key="misc.logcat" + app:icon="@drawable/ic_action_bug_report" + app:title="@string/settings_misc_logcat" + app:summary="@string/settings_misc_logcat_summary"/> + app:key="misc.donate" + app:icon="@drawable/ic_action_card_giftcard" + app:title="@string/settings_misc_donate" + app:summary="@string/settings_misc_donate_summary"/>