ariane/app/src/main/java/oppen/ariane/ui/settings/SettingsFragment.kt

216 lines
8.9 KiB
Kotlin

package oppen.ariane.ui.settings
import android.content.SharedPreferences
import android.os.Bundle
import android.text.Spannable
import android.text.SpannableString
import android.text.style.ForegroundColorSpan
import android.view.inputmethod.EditorInfo
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.content.ContextCompat
import androidx.preference.*
import oppen.ariane.Ariane
import java.security.SecureRandom
import java.util.*
import javax.net.ssl.SSLContext
import javax.net.ssl.SSLSocket
import javax.net.ssl.SSLSocketFactory
class SettingsFragment: PreferenceFragmentCompat(), Preference.OnPreferenceChangeListener {
lateinit var prefs: SharedPreferences
lateinit var protocols: Array<String>
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
prefs = preferenceManager.sharedPreferences
val context = preferenceManager.context
val screen = preferenceManager.createPreferenceScreen(context)
/**
* Ariane App Settings
*/
val appCategory = PreferenceCategory(context)
appCategory.key = "app_category"
appCategory.title = "Configure Ariane"
screen.addPreference(appCategory)
//Home
val homePreference = EditTextPreference(context)
homePreference.title = "Home Capsule"
homePreference.key = "home_capsule"
val homecapsule = preferenceManager.sharedPreferences.getString("home_capsule", Ariane.DEFAULT_HOME_CAPSULE)
homePreference.summary = homecapsule
homePreference.positiveButtonText = getThemedSpan("Update")
homePreference.negativeButtonText = getThemedSpan("Cancel")
homePreference.title = getThemedSpan("Home Capsule")
homePreference.setOnPreferenceChangeListener { _, newValue ->
homePreference.summary = newValue.toString()
true
}
homePreference.setOnBindEditTextListener{ editText ->
editText.imeOptions = EditorInfo.IME_ACTION_DONE
editText.setSelection(editText.text.toString().length)//Set caret position to end
}
appCategory.addPreference(homePreference)
/**
* Day/Night Theme
*/
val themeCategory = PreferenceCategory(context)
themeCategory.key = "theme_category"
themeCategory.title = "Theme"
appCategory.addPreference(themeCategory)
val themeFollowSystemPreference = SwitchPreferenceCompat(context)
themeFollowSystemPreference.key = "theme_FollowSystem"
themeFollowSystemPreference.title = "System Default"
themeFollowSystemPreference.onPreferenceChangeListener = this
themeCategory.addPreference(themeFollowSystemPreference)
val themeLightPreference = SwitchPreferenceCompat(context)
themeLightPreference.key = "theme_Light"
themeLightPreference.title = "Light"
themeLightPreference.onPreferenceChangeListener = this
themeCategory.addPreference(themeLightPreference)
val themeDarkPreference = SwitchPreferenceCompat(context)
themeDarkPreference.key = "theme_Dark"
themeDarkPreference.title = "Dark"
themeDarkPreference.onPreferenceChangeListener = this
themeCategory.addPreference(themeDarkPreference)
val isThemePrefSet =
prefs.getBoolean("theme_FollowSystem", false) ||
prefs.getBoolean("theme_Light", false) ||
prefs.getBoolean("theme_Dark", false)
if(!isThemePrefSet) themeFollowSystemPreference.isChecked = true
/**
* TLS Settings
*/
val tlsCategory = PreferenceCategory(context)
tlsCategory.key = "tls_category"
tlsCategory.title = "TLS Config"
screen.addPreference(tlsCategory)
val tlsDefaultPreference = SwitchPreferenceCompat(context)
tlsDefaultPreference.key = "tls_Default"
tlsDefaultPreference.title = "TLS Default"
tlsDefaultPreference.onPreferenceChangeListener = this
tlsCategory.addPreference(tlsDefaultPreference)
val tlsAllSupportedPreference = SwitchPreferenceCompat(context)
tlsAllSupportedPreference.key = "tls_All_Supported"
tlsAllSupportedPreference.title = "TLS Enable all supported"
tlsAllSupportedPreference.onPreferenceChangeListener = this
tlsCategory.addPreference(tlsAllSupportedPreference)
val sslContext = SSLContext.getInstance("TLS")
sslContext.init(null, null, SecureRandom())
val factory: SSLSocketFactory = sslContext.socketFactory
val socket = factory.createSocket() as SSLSocket
protocols = socket.supportedProtocols
protocols.forEach { protocol ->
val tlsPreference = SwitchPreferenceCompat(context)
tlsPreference.key = "tls_${protocol.toLowerCase(Locale.getDefault())}"
tlsPreference.title = protocol
tlsPreference.onPreferenceChangeListener = this
tlsCategory.addPreference(tlsPreference)
}
preferenceScreen = screen
}
override fun onPreferenceChange(preference: Preference?, newValue: Any?): Boolean {
if(preference == null) return false
if(preference.key.startsWith("tls")){
tlsChangeListener(preference, newValue)
return true
}
if(preference.key.startsWith("theme")){
when(preference.key){
"theme_FollowSystem" -> {
preferenceScreen.findPreference<SwitchPreferenceCompat>("theme_Light")?.isChecked = false
preferenceScreen.findPreference<SwitchPreferenceCompat>("theme_Dark")?.isChecked = false
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
}
"theme_Light" -> {
preferenceScreen.findPreference<SwitchPreferenceCompat>("theme_FollowSystem")?.isChecked = false
preferenceScreen.findPreference<SwitchPreferenceCompat>("theme_Dark")?.isChecked = false
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
}
"theme_Dark" -> {
preferenceScreen.findPreference<SwitchPreferenceCompat>("theme_FollowSystem")?.isChecked = false
preferenceScreen.findPreference<SwitchPreferenceCompat>("theme_Light")?.isChecked = false
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
}
}
return true
}
return false
}
private fun tlsChangeListener(
preference: Preference?,
newValue: Any?
) {
if (preference is SwitchPreferenceCompat && newValue is Boolean && newValue == true) {
preference.key?.let { key ->
when {
key.startsWith("tls_") -> {
if (key != "tls_Default") {
val default = preferenceScreen.findPreference<SwitchPreferenceCompat>("tls_Default")
default?.isChecked = false
}
if (key != "tls_All_Supported") {
val all = preferenceScreen.findPreference<SwitchPreferenceCompat>("tls_All_Supported")
all?.isChecked = false
}
protocols.forEach { protocol ->
val tlsSwitchKey = "tls_${protocol.toLowerCase(Locale.getDefault())}"
if (tlsSwitchKey != key) {
val otherTLSSwitch =
preferenceScreen.findPreference<SwitchPreferenceCompat>(
tlsSwitchKey
)
otherTLSSwitch?.isChecked = false
}
}
}
}
}
when (preference.key) {
"tls_Default" -> setTLSProtocol("TLS")
"tls_All_Supported" -> setTLSProtocol("TLS_ALL")
else -> {
val prefTitle = preference.title.toString()
setTLSProtocol(prefTitle)
}
}
}
}
private fun setTLSProtocol(protocol: String) = preferenceManager.sharedPreferences.edit().putString("tls_protocol", protocol).apply()
/**
* Unfortunately it doesn't look like EditTextPreference supports Day/Night theme
* or else is otherwise broken - OR I'M MISSING SOMETHING.
* Use Spannable to set a suitable text colour for the dialog buttons
*/
private fun getThemedSpan(text: String): Spannable{
val textSpan = SpannableString(text)
textSpan.setSpan(ForegroundColorSpan(ContextCompat.getColor(requireContext(), oppen.ariane.R.color.themed_text)), 0, text.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
return textSpan
}
}