Implement HTTP proxy summary as a SummaryProvider (#3091)

* Handle preference fragments using the framework

The previous code started new preference "screens" as activities, even though
each one hosted a single fragment.

Modify this to use the framework's support for swapping in/out different
preference fragments.

PreferencesActivity:
- Remove the code for launching tab and proxy preferences
- Remove the code for setting titles, each fragment is responsible for that
- Implement OnPreferenceStartFragmentCallback to swap fragments in/out with
  the correct animation

PreferencesFragment:
- Use `fragment` property instead of `setOnPreferenceClickListener`
- Set the activity title when resuming

Everything else:
- Set the activity title when resuming

* Implement HTTP proxy summary as a SummaryProvider

Uses the frameworks's support for setting summaries instead of rolling our
own.

Also fix a tiny bug -- the minimum port number to connect to should be 1,
not 0.

* Lint
This commit is contained in:
Nik Clayton 2023-01-13 19:28:46 +01:00 committed by GitHub
parent 9cf4882f41
commit aa96d02923
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 39 additions and 28 deletions

View file

@ -32,7 +32,6 @@ import com.keylesspalace.tusky.settings.preferenceCategory
import com.keylesspalace.tusky.settings.switchPreference import com.keylesspalace.tusky.settings.switchPreference
import com.keylesspalace.tusky.util.LocaleManager import com.keylesspalace.tusky.util.LocaleManager
import com.keylesspalace.tusky.util.deserialize import com.keylesspalace.tusky.util.deserialize
import com.keylesspalace.tusky.util.getNonNullString
import com.keylesspalace.tusky.util.makeIcon import com.keylesspalace.tusky.util.makeIcon
import com.keylesspalace.tusky.util.serialize import com.keylesspalace.tusky.util.serialize
import com.mikepenz.iconics.IconicsDrawable import com.mikepenz.iconics.IconicsDrawable
@ -49,7 +48,6 @@ class PreferencesFragment : PreferenceFragmentCompat(), Injectable {
lateinit var localeManager: LocaleManager lateinit var localeManager: LocaleManager
private val iconSize by lazy { resources.getDimensionPixelSize(R.dimen.preference_icon_size) } private val iconSize by lazy { resources.getDimensionPixelSize(R.dimen.preference_icon_size) }
private var httpProxyPref: Preference? = null
enum class ReadingOrder { enum class ReadingOrder {
/** User scrolls up, reading statuses oldest to newest */ /** User scrolls up, reading statuses oldest to newest */
@ -236,7 +234,7 @@ class PreferencesFragment : PreferenceFragmentCompat(), Injectable {
preferenceCategory(R.string.pref_title_timeline_filters) { preferenceCategory(R.string.pref_title_timeline_filters) {
preference { preference {
setTitle(R.string.pref_title_post_tabs) setTitle(R.string.pref_title_post_tabs)
fragment = "com.keylesspalace.tusky.components.preference.TabFilterPreferencesFragment" fragment = TabFilterPreferencesFragment::class.qualifiedName
} }
} }
@ -280,9 +278,10 @@ class PreferencesFragment : PreferenceFragmentCompat(), Injectable {
} }
preferenceCategory(R.string.pref_title_proxy_settings) { preferenceCategory(R.string.pref_title_proxy_settings) {
httpProxyPref = preference { preference {
setTitle(R.string.pref_title_http_proxy_settings) setTitle(R.string.pref_title_http_proxy_settings)
fragment = "com.keylesspalace.tusky.components.preference.ProxyPreferencesFragment" fragment = ProxyPreferencesFragment::class.qualifiedName
summaryProvider = ProxyPreferencesFragment.SummaryProvider
} }
} }
} }
@ -295,28 +294,6 @@ class PreferencesFragment : PreferenceFragmentCompat(), Injectable {
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
requireActivity().setTitle(R.string.action_view_preferences) requireActivity().setTitle(R.string.action_view_preferences)
updateHttpProxySummary()
}
private fun updateHttpProxySummary() {
preferenceManager.sharedPreferences?.let { sharedPreferences ->
val httpProxyEnabled = sharedPreferences.getBoolean(PrefKeys.HTTP_PROXY_ENABLED, false)
val httpServer = sharedPreferences.getNonNullString(PrefKeys.HTTP_PROXY_SERVER, "")
try {
val httpPort = sharedPreferences.getNonNullString(PrefKeys.HTTP_PROXY_PORT, "-1")
.toInt()
if (httpProxyEnabled && httpServer.isNotBlank() && httpPort > 0 && httpPort < 65535) {
httpProxyPref?.summary = "$httpServer:$httpPort"
return
}
} catch (e: NumberFormatException) {
// user has entered wrong port, fall back to empty summary
}
httpProxyPref?.summary = ""
}
} }
override fun onDisplayPreferenceDialog(preference: Preference) { override fun onDisplayPreferenceDialog(preference: Preference) {

View file

@ -16,14 +16,18 @@
package com.keylesspalace.tusky.components.preference package com.keylesspalace.tusky.components.preference
import android.os.Bundle import android.os.Bundle
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import com.keylesspalace.tusky.R import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.settings.PrefKeys import com.keylesspalace.tusky.settings.PrefKeys
import com.keylesspalace.tusky.settings.ProxyConfiguration import com.keylesspalace.tusky.settings.ProxyConfiguration
import com.keylesspalace.tusky.settings.ProxyConfiguration.Companion.MAX_PROXY_PORT
import com.keylesspalace.tusky.settings.ProxyConfiguration.Companion.MIN_PROXY_PORT
import com.keylesspalace.tusky.settings.makePreferenceScreen import com.keylesspalace.tusky.settings.makePreferenceScreen
import com.keylesspalace.tusky.settings.preferenceCategory import com.keylesspalace.tusky.settings.preferenceCategory
import com.keylesspalace.tusky.settings.switchPreference import com.keylesspalace.tusky.settings.switchPreference
import com.keylesspalace.tusky.settings.validatedEditTextPreference import com.keylesspalace.tusky.settings.validatedEditTextPreference
import com.keylesspalace.tusky.util.getNonNullString
import kotlin.system.exitProcess import kotlin.system.exitProcess
class ProxyPreferencesFragment : PreferenceFragmentCompat() { class ProxyPreferencesFragment : PreferenceFragmentCompat() {
@ -78,6 +82,33 @@ class ProxyPreferencesFragment : PreferenceFragmentCompat() {
} }
} }
object SummaryProvider : Preference.SummaryProvider<Preference> {
override fun provideSummary(preference: Preference): CharSequence {
val sharedPreferences = preference.sharedPreferences
sharedPreferences ?: return ""
if (!sharedPreferences.getBoolean(PrefKeys.HTTP_PROXY_ENABLED, false)) {
return preference.context.getString(R.string.pref_summary_http_proxy_disabled)
}
val missing = preference.context.getString(R.string.pref_summary_http_proxy_missing)
val server = sharedPreferences.getNonNullString(PrefKeys.HTTP_PROXY_SERVER, missing)
val port = try {
sharedPreferences.getNonNullString(PrefKeys.HTTP_PROXY_PORT, "-1").toInt()
} catch (e: NumberFormatException) {
-1
}
if (port < MIN_PROXY_PORT || port > MAX_PROXY_PORT) {
val invalid = preference.context.getString(R.string.pref_summary_http_proxy_invalid)
return "$server:$invalid"
}
return "$server:$port"
}
}
companion object { companion object {
fun newInstance(): ProxyPreferencesFragment { fun newInstance(): ProxyPreferencesFragment {
return ProxyPreferencesFragment() return ProxyPreferencesFragment()

View file

@ -22,7 +22,7 @@ class ProxyConfiguration private constructor(
} }
fun isValidHostname(hostname: String): Boolean = fun isValidHostname(hostname: String): Boolean =
IP_ADDRESS_REGEX.matches(hostname) || HOSTNAME_REGEX.matches(hostname) IP_ADDRESS_REGEX.matches(hostname) || HOSTNAME_REGEX.matches(hostname)
const val MIN_PROXY_PORT = 0 const val MIN_PROXY_PORT = 1
const val MAX_PROXY_PORT = 65535 const val MAX_PROXY_PORT = 65535
} }
} }

View file

@ -291,6 +291,9 @@
<string name="pref_title_http_proxy_server">HTTP proxy server</string> <string name="pref_title_http_proxy_server">HTTP proxy server</string>
<string name="pref_title_http_proxy_port">HTTP proxy port</string> <string name="pref_title_http_proxy_port">HTTP proxy port</string>
<string name="pref_title_http_proxy_port_message">Port should be between %d and %d</string> <string name="pref_title_http_proxy_port_message">Port should be between %d and %d</string>
<string name="pref_summary_http_proxy_disabled">Disabled</string>
<string name="pref_summary_http_proxy_missing">&lt;not set></string>
<string name="pref_summary_http_proxy_invalid">&lt;invalid></string>
<string name="pref_default_post_privacy">Default post privacy</string> <string name="pref_default_post_privacy">Default post privacy</string>
<string name="pref_default_post_language">Default posting language</string> <string name="pref_default_post_language">Default posting language</string>