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 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("theme_Light")?.isChecked = false preferenceScreen.findPreference("theme_Dark")?.isChecked = false AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) } "theme_Light" -> { preferenceScreen.findPreference("theme_FollowSystem")?.isChecked = false preferenceScreen.findPreference("theme_Dark")?.isChecked = false AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) } "theme_Dark" -> { preferenceScreen.findPreference("theme_FollowSystem")?.isChecked = false preferenceScreen.findPreference("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("tls_Default") default?.isChecked = false } if (key != "tls_All_Supported") { val all = preferenceScreen.findPreference("tls_All_Supported") all?.isChecked = false } protocols.forEach { protocol -> val tlsSwitchKey = "tls_${protocol.toLowerCase(Locale.getDefault())}" if (tlsSwitchKey != key) { val otherTLSSwitch = preferenceScreen.findPreference( 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 } }