3204: Add an account based preference store (#3205)
* 3204: Add an account based preference store * 3204: (related) reformat a bit, add todo * 3204: Use the preference data store for all three account settings * 3204: Move event handling to account settings handler * 3204: Correct includes * 3204: Appease linter * 3204: Appease linter again * 3204: Add an account based preference store * 3204: Use the preference data store for all three account settings * 3204: Move event handling to account settings handler * 3204: Correct includes * 3204: Add general "preference upgrade loop stepper"; use it for removing obsolete account settings (in shared) * 3204: Add missing spaces * 3204: Key is non-nullable * 3204: Upgrade to new settings migration code * 3204: Remove (commented) DI code
This commit is contained in:
parent
daa67632df
commit
b4d10c9613
4 changed files with 61 additions and 45 deletions
|
@ -69,9 +69,8 @@ class TuskyApplication : Application(), HasAndroidInjector {
|
||||||
|
|
||||||
AppInjector.init(this)
|
AppInjector.init(this)
|
||||||
|
|
||||||
// Migrate shared preference keys and defaults from version to version. The last
|
// Migrate shared preference keys and defaults from version to version.
|
||||||
// version that did not have a SCHEMA_VERSION was 100, so that's the default.
|
val oldVersion = sharedPreferences.getInt(PrefKeys.SCHEMA_VERSION, 0)
|
||||||
val oldVersion = sharedPreferences.getInt(PrefKeys.SCHEMA_VERSION, 100)
|
|
||||||
if (oldVersion != SCHEMA_VERSION) {
|
if (oldVersion != SCHEMA_VERSION) {
|
||||||
upgradeSharedPreferences(oldVersion, SCHEMA_VERSION)
|
upgradeSharedPreferences(oldVersion, SCHEMA_VERSION)
|
||||||
}
|
}
|
||||||
|
@ -105,7 +104,13 @@ class TuskyApplication : Application(), HasAndroidInjector {
|
||||||
Log.d(TAG, "Upgrading shared preferences: $oldVersion -> $newVersion")
|
Log.d(TAG, "Upgrading shared preferences: $oldVersion -> $newVersion")
|
||||||
val editor = sharedPreferences.edit()
|
val editor = sharedPreferences.edit()
|
||||||
|
|
||||||
// Future upgrade code goes here
|
if (oldVersion < 2023022701) {
|
||||||
|
// These preferences are (now) handled in AccountPreferenceHandler. Remove them from shared for clarity.
|
||||||
|
|
||||||
|
editor.remove(PrefKeys.ALWAYS_OPEN_SPOILER)
|
||||||
|
editor.remove(PrefKeys.ALWAYS_SHOW_SENSITIVE_MEDIA)
|
||||||
|
editor.remove(PrefKeys.MEDIA_PREVIEW_ENABLED)
|
||||||
|
}
|
||||||
|
|
||||||
editor.putInt(PrefKeys.SCHEMA_VERSION, newVersion)
|
editor.putInt(PrefKeys.SCHEMA_VERSION, newVersion)
|
||||||
editor.apply()
|
editor.apply()
|
||||||
|
|
|
@ -36,13 +36,13 @@ import com.keylesspalace.tusky.components.followedtags.FollowedTagsActivity
|
||||||
import com.keylesspalace.tusky.components.instancemute.InstanceListActivity
|
import com.keylesspalace.tusky.components.instancemute.InstanceListActivity
|
||||||
import com.keylesspalace.tusky.components.login.LoginActivity
|
import com.keylesspalace.tusky.components.login.LoginActivity
|
||||||
import com.keylesspalace.tusky.components.notifications.currentAccountNeedsMigration
|
import com.keylesspalace.tusky.components.notifications.currentAccountNeedsMigration
|
||||||
import com.keylesspalace.tusky.db.AccountEntity
|
|
||||||
import com.keylesspalace.tusky.db.AccountManager
|
import com.keylesspalace.tusky.db.AccountManager
|
||||||
import com.keylesspalace.tusky.di.Injectable
|
import com.keylesspalace.tusky.di.Injectable
|
||||||
import com.keylesspalace.tusky.entity.Account
|
import com.keylesspalace.tusky.entity.Account
|
||||||
import com.keylesspalace.tusky.entity.Filter
|
import com.keylesspalace.tusky.entity.Filter
|
||||||
import com.keylesspalace.tusky.entity.Status
|
import com.keylesspalace.tusky.entity.Status
|
||||||
import com.keylesspalace.tusky.network.MastodonApi
|
import com.keylesspalace.tusky.network.MastodonApi
|
||||||
|
import com.keylesspalace.tusky.settings.AccountPreferenceHandler
|
||||||
import com.keylesspalace.tusky.settings.PrefKeys
|
import com.keylesspalace.tusky.settings.PrefKeys
|
||||||
import com.keylesspalace.tusky.settings.listPreference
|
import com.keylesspalace.tusky.settings.listPreference
|
||||||
import com.keylesspalace.tusky.settings.makePreferenceScreen
|
import com.keylesspalace.tusky.settings.makePreferenceScreen
|
||||||
|
@ -85,7 +85,7 @@ class AccountPreferencesFragment : PreferenceFragmentCompat(), Injectable {
|
||||||
colorInt = MaterialColors.getColor(context, R.attr.iconColor, Color.BLACK)
|
colorInt = MaterialColors.getColor(context, R.attr.iconColor, Color.BLACK)
|
||||||
}
|
}
|
||||||
setOnPreferenceClickListener {
|
setOnPreferenceClickListener {
|
||||||
openNotificationPrefs()
|
openNotificationSystemPrefs()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -184,8 +184,7 @@ class AccountPreferencesFragment : PreferenceFragmentCompat(), Injectable {
|
||||||
setEntryValues(R.array.post_privacy_values)
|
setEntryValues(R.array.post_privacy_values)
|
||||||
key = PrefKeys.DEFAULT_POST_PRIVACY
|
key = PrefKeys.DEFAULT_POST_PRIVACY
|
||||||
setSummaryProvider { entry }
|
setSummaryProvider { entry }
|
||||||
val visibility = accountManager.activeAccount?.defaultPostPrivacy
|
val visibility = accountManager.activeAccount?.defaultPostPrivacy ?: Status.Visibility.PUBLIC
|
||||||
?: Status.Visibility.PUBLIC
|
|
||||||
value = visibility.serverString()
|
value = visibility.serverString()
|
||||||
setIcon(getIconForVisibility(visibility))
|
setIcon(getIconForVisibility(visibility))
|
||||||
setOnPreferenceChangeListener { _, newValue ->
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
|
@ -224,8 +223,7 @@ class AccountPreferencesFragment : PreferenceFragmentCompat(), Injectable {
|
||||||
setIcon(R.drawable.ic_eye_24dp)
|
setIcon(R.drawable.ic_eye_24dp)
|
||||||
key = PrefKeys.DEFAULT_MEDIA_SENSITIVITY
|
key = PrefKeys.DEFAULT_MEDIA_SENSITIVITY
|
||||||
isSingleLineTitle = false
|
isSingleLineTitle = false
|
||||||
val sensitivity = accountManager.activeAccount?.defaultMediaSensitivity
|
val sensitivity = accountManager.activeAccount?.defaultMediaSensitivity ?: false
|
||||||
?: false
|
|
||||||
setDefaultValue(sensitivity)
|
setDefaultValue(sensitivity)
|
||||||
setIcon(getIconForSensitivity(sensitivity))
|
setIcon(getIconForSensitivity(sensitivity))
|
||||||
setOnPreferenceChangeListener { _, newValue ->
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
|
@ -238,40 +236,29 @@ class AccountPreferencesFragment : PreferenceFragmentCompat(), Injectable {
|
||||||
}
|
}
|
||||||
|
|
||||||
preferenceCategory(R.string.pref_title_timelines) {
|
preferenceCategory(R.string.pref_title_timelines) {
|
||||||
|
// TODO having no activeAccount in this fragment does not really make sense, enforce it?
|
||||||
|
// All other locations here make it optional, however.
|
||||||
|
val accountPreferenceHandler = AccountPreferenceHandler(accountManager.activeAccount!!, accountManager, eventHub)
|
||||||
|
|
||||||
switchPreference {
|
switchPreference {
|
||||||
key = PrefKeys.MEDIA_PREVIEW_ENABLED
|
key = PrefKeys.MEDIA_PREVIEW_ENABLED
|
||||||
setTitle(R.string.pref_title_show_media_preview)
|
setTitle(R.string.pref_title_show_media_preview)
|
||||||
isSingleLineTitle = false
|
isSingleLineTitle = false
|
||||||
isChecked = accountManager.activeAccount?.mediaPreviewEnabled ?: true
|
preferenceDataStore = accountPreferenceHandler
|
||||||
setOnPreferenceChangeListener { _, newValue ->
|
|
||||||
updateAccount { it.mediaPreviewEnabled = newValue as Boolean }
|
|
||||||
eventHub.dispatch(PreferenceChangedEvent(key))
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switchPreference {
|
switchPreference {
|
||||||
key = PrefKeys.ALWAYS_SHOW_SENSITIVE_MEDIA
|
key = PrefKeys.ALWAYS_SHOW_SENSITIVE_MEDIA
|
||||||
setTitle(R.string.pref_title_alway_show_sensitive_media)
|
setTitle(R.string.pref_title_alway_show_sensitive_media)
|
||||||
isSingleLineTitle = false
|
isSingleLineTitle = false
|
||||||
isChecked = accountManager.activeAccount?.alwaysShowSensitiveMedia ?: false
|
preferenceDataStore = accountPreferenceHandler
|
||||||
setOnPreferenceChangeListener { _, newValue ->
|
|
||||||
updateAccount { it.alwaysShowSensitiveMedia = newValue as Boolean }
|
|
||||||
eventHub.dispatch(PreferenceChangedEvent(key))
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switchPreference {
|
switchPreference {
|
||||||
key = PrefKeys.ALWAYS_OPEN_SPOILER
|
key = PrefKeys.ALWAYS_OPEN_SPOILER
|
||||||
setTitle(R.string.pref_title_alway_open_spoiler)
|
setTitle(R.string.pref_title_alway_open_spoiler)
|
||||||
isSingleLineTitle = false
|
isSingleLineTitle = false
|
||||||
isChecked = accountManager.activeAccount?.alwaysOpenSpoiler ?: false
|
preferenceDataStore = accountPreferenceHandler
|
||||||
setOnPreferenceChangeListener { _, newValue ->
|
|
||||||
updateAccount { it.alwaysOpenSpoiler = newValue as Boolean }
|
|
||||||
eventHub.dispatch(PreferenceChangedEvent(key))
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,10 +266,7 @@ class AccountPreferencesFragment : PreferenceFragmentCompat(), Injectable {
|
||||||
preference {
|
preference {
|
||||||
setTitle(R.string.pref_title_public_filter_keywords)
|
setTitle(R.string.pref_title_public_filter_keywords)
|
||||||
setOnPreferenceClickListener {
|
setOnPreferenceClickListener {
|
||||||
launchFilterActivity(
|
launchFilterActivity(Filter.PUBLIC, R.string.pref_title_public_filter_keywords)
|
||||||
Filter.PUBLIC,
|
|
||||||
R.string.pref_title_public_filter_keywords
|
|
||||||
)
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -306,10 +290,7 @@ class AccountPreferencesFragment : PreferenceFragmentCompat(), Injectable {
|
||||||
preference {
|
preference {
|
||||||
setTitle(R.string.pref_title_thread_filter_keywords)
|
setTitle(R.string.pref_title_thread_filter_keywords)
|
||||||
setOnPreferenceClickListener {
|
setOnPreferenceClickListener {
|
||||||
launchFilterActivity(
|
launchFilterActivity(Filter.THREAD, R.string.pref_title_thread_filter_keywords)
|
||||||
Filter.THREAD,
|
|
||||||
R.string.pref_title_thread_filter_keywords
|
|
||||||
)
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -330,7 +311,7 @@ class AccountPreferencesFragment : PreferenceFragmentCompat(), Injectable {
|
||||||
requireActivity().setTitle(R.string.action_view_account_preferences)
|
requireActivity().setTitle(R.string.action_view_account_preferences)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun openNotificationPrefs() {
|
private fun openNotificationSystemPrefs() {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
val intent = Intent()
|
val intent = Intent()
|
||||||
intent.action = "android.settings.APP_NOTIFICATION_SETTINGS"
|
intent.action = "android.settings.APP_NOTIFICATION_SETTINGS"
|
||||||
|
@ -345,14 +326,9 @@ class AccountPreferencesFragment : PreferenceFragmentCompat(), Injectable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline fun updateAccount(changer: (AccountEntity) -> Unit) {
|
|
||||||
accountManager.activeAccount?.let { account ->
|
|
||||||
changer(account)
|
|
||||||
accountManager.saveAccount(account)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun syncWithServer(visibility: String? = null, sensitive: Boolean? = null, language: String? = null) {
|
private fun syncWithServer(visibility: String? = null, sensitive: Boolean? = null, language: String? = null) {
|
||||||
|
// TODO these could also be "datastore backed" preferences (a ServerPreferenceDataStore); follow-up of issue #3204
|
||||||
|
|
||||||
mastodonApi.accountUpdateSource(visibility, sensitive, language)
|
mastodonApi.accountUpdateSource(visibility, sensitive, language)
|
||||||
.enqueue(object : Callback<Account> {
|
.enqueue(object : Callback<Account> {
|
||||||
override fun onResponse(call: Call<Account>, response: Response<Account>) {
|
override fun onResponse(call: Call<Account>, response: Response<Account>) {
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
package com.keylesspalace.tusky.settings
|
||||||
|
|
||||||
|
import androidx.preference.PreferenceDataStore
|
||||||
|
import com.keylesspalace.tusky.appstore.EventHub
|
||||||
|
import com.keylesspalace.tusky.appstore.PreferenceChangedEvent
|
||||||
|
import com.keylesspalace.tusky.db.AccountEntity
|
||||||
|
import com.keylesspalace.tusky.db.AccountManager
|
||||||
|
|
||||||
|
class AccountPreferenceHandler(
|
||||||
|
private val account: AccountEntity,
|
||||||
|
private val accountManager: AccountManager,
|
||||||
|
private val eventHub: EventHub,
|
||||||
|
) : PreferenceDataStore() {
|
||||||
|
|
||||||
|
override fun getBoolean(key: String, defValue: Boolean): Boolean {
|
||||||
|
return when (key) {
|
||||||
|
PrefKeys.ALWAYS_SHOW_SENSITIVE_MEDIA -> account.alwaysShowSensitiveMedia
|
||||||
|
PrefKeys.ALWAYS_OPEN_SPOILER -> account.alwaysOpenSpoiler
|
||||||
|
PrefKeys.MEDIA_PREVIEW_ENABLED -> account.mediaPreviewEnabled
|
||||||
|
else -> defValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun putBoolean(key: String, value: Boolean) {
|
||||||
|
when (key) {
|
||||||
|
PrefKeys.ALWAYS_SHOW_SENSITIVE_MEDIA -> account.alwaysShowSensitiveMedia = value
|
||||||
|
PrefKeys.ALWAYS_OPEN_SPOILER -> account.alwaysOpenSpoiler = value
|
||||||
|
PrefKeys.MEDIA_PREVIEW_ENABLED -> account.mediaPreviewEnabled = value
|
||||||
|
}
|
||||||
|
|
||||||
|
accountManager.saveAccount(account)
|
||||||
|
|
||||||
|
eventHub.dispatch(PreferenceChangedEvent(key))
|
||||||
|
}
|
||||||
|
}
|
|
@ -41,7 +41,7 @@ enum class AppTheme(val value: String) {
|
||||||
*
|
*
|
||||||
* - Adding a new preference that does not change the interpretation of an existing preference
|
* - Adding a new preference that does not change the interpretation of an existing preference
|
||||||
*/
|
*/
|
||||||
const val SCHEMA_VERSION = 2023021501
|
const val SCHEMA_VERSION = 2023022701
|
||||||
|
|
||||||
object PrefKeys {
|
object PrefKeys {
|
||||||
// Note: not all of these keys are actually used as SharedPreferences keys but we must give
|
// Note: not all of these keys are actually used as SharedPreferences keys but we must give
|
||||||
|
|
Loading…
Reference in a new issue