Merge pull request #5213 from k9mail/settings_changed_callback
This commit is contained in:
commit
af827bb1fd
11 changed files with 104 additions and 103 deletions
|
@ -2,13 +2,15 @@ package com.fsck.k9
|
|||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.os.AsyncTask
|
||||
import com.fsck.k9.Account.SortType
|
||||
import com.fsck.k9.core.BuildConfig
|
||||
import com.fsck.k9.mail.K9MailLib
|
||||
import com.fsck.k9.mailstore.LocalStore
|
||||
import com.fsck.k9.preferences.Storage
|
||||
import com.fsck.k9.preferences.StorageEditor
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import timber.log.Timber.DebugTree
|
||||
|
||||
|
@ -21,8 +23,6 @@ object K9 : EarlyInit {
|
|||
@JvmField
|
||||
val DEVELOPER_MODE = BuildConfig.DEBUG
|
||||
|
||||
private const val VERSION_MIGRATE_OPENPGP_TO_ACCOUNTS = 63
|
||||
|
||||
/**
|
||||
* Name of the [SharedPreferences] file used to store the last known version of the
|
||||
* accounts' databases.
|
||||
|
@ -105,28 +105,6 @@ object K9 : EarlyInit {
|
|||
if (cachedVersion >= LocalStore.getDbVersion()) {
|
||||
setDatabasesUpToDate(false)
|
||||
}
|
||||
|
||||
if (cachedVersion < VERSION_MIGRATE_OPENPGP_TO_ACCOUNTS) {
|
||||
migrateOpenPgpGlobalToAccountSettings()
|
||||
}
|
||||
}
|
||||
|
||||
private fun migrateOpenPgpGlobalToAccountSettings() {
|
||||
val storage = preferences.storage
|
||||
|
||||
val openPgpProvider = storage.getString("openPgpProvider", null)
|
||||
val openPgpSupportSignOnly = storage.getBoolean("openPgpSupportSignOnly", false)
|
||||
|
||||
for (account in preferences.accounts) {
|
||||
account.openPgpProvider = openPgpProvider
|
||||
account.isOpenPgpHideSignOnly = !openPgpSupportSignOnly
|
||||
preferences.saveAccount(account)
|
||||
}
|
||||
|
||||
preferences.createStorageEditor()
|
||||
.remove("openPgpProvider")
|
||||
.remove("openPgpSupportSignOnly")
|
||||
.commit()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
|
@ -409,8 +387,7 @@ object K9 : EarlyInit {
|
|||
isFixedMessageViewTheme = storage.getBoolean("fixedMessageViewTheme", true)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun save(editor: StorageEditor) {
|
||||
internal fun save(editor: StorageEditor) {
|
||||
editor.putBoolean("enableDebugLogging", isDebugLoggingEnabled)
|
||||
editor.putBoolean("enableSensitiveLogging", isSensitiveDebugLoggingEnabled)
|
||||
editor.putEnum("backgroundOperations", backgroundOps)
|
||||
|
@ -484,15 +461,9 @@ object K9 : EarlyInit {
|
|||
|
||||
@JvmStatic
|
||||
fun saveSettingsAsync() {
|
||||
object : AsyncTask<Void, Void, Void>() {
|
||||
override fun doInBackground(vararg voids: Void): Void? {
|
||||
val editor = preferences.createStorageEditor()
|
||||
save(editor)
|
||||
editor.commit()
|
||||
|
||||
return null
|
||||
}
|
||||
}.execute()
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
preferences.saveSettings()
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun <reified T : Enum<T>> Storage.getEnum(key: String, defaultValue: T): T {
|
||||
|
|
|
@ -18,7 +18,6 @@ val mainModule = module {
|
|||
context = get(),
|
||||
storagePersister = get(),
|
||||
localStoreProvider = get(),
|
||||
localKeyStoreManager = get(),
|
||||
accountPreferenceSerializer = get()
|
||||
)
|
||||
}
|
||||
|
|
|
@ -3,9 +3,7 @@ package com.fsck.k9
|
|||
import android.content.Context
|
||||
import androidx.annotation.GuardedBy
|
||||
import androidx.annotation.RestrictTo
|
||||
import com.fsck.k9.backend.BackendManager
|
||||
import com.fsck.k9.mail.MessagingException
|
||||
import com.fsck.k9.mailstore.LocalStore
|
||||
import com.fsck.k9.mailstore.LocalStoreProvider
|
||||
import com.fsck.k9.preferences.Storage
|
||||
import com.fsck.k9.preferences.StorageEditor
|
||||
|
@ -14,19 +12,14 @@ import java.util.HashMap
|
|||
import java.util.LinkedList
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
import org.koin.core.KoinComponent
|
||||
import org.koin.core.inject
|
||||
import timber.log.Timber
|
||||
|
||||
class Preferences internal constructor(
|
||||
private val context: Context,
|
||||
private val storagePersister: StoragePersister,
|
||||
private val localStoreProvider: LocalStoreProvider,
|
||||
private val localKeyStoreManager: LocalKeyStoreManager,
|
||||
private val accountPreferenceSerializer: AccountPreferenceSerializer
|
||||
) : KoinComponent {
|
||||
private val backendManager: BackendManager by inject()
|
||||
|
||||
) {
|
||||
private val accountLock = Any()
|
||||
|
||||
@GuardedBy("accountLock")
|
||||
|
@ -38,20 +31,13 @@ class Preferences internal constructor(
|
|||
@GuardedBy("accountLock")
|
||||
private var newAccount: Account? = null
|
||||
private val accountsChangeListeners = CopyOnWriteArrayList<AccountsChangeListener>()
|
||||
private val settingsChangeListeners = CopyOnWriteArrayList<SettingsChangeListener>()
|
||||
|
||||
val storage = Storage()
|
||||
|
||||
init {
|
||||
val persistedStorageValues = storagePersister.loadValues()
|
||||
storage.replaceAll(persistedStorageValues)
|
||||
|
||||
if (storage.isEmpty) {
|
||||
Timber.i("Preferences storage is zero-size, importing from Android-style preferences")
|
||||
|
||||
val editor = createStorageEditor()
|
||||
editor.copy(context.getSharedPreferences("AndroidMail.Main", Context.MODE_PRIVATE))
|
||||
editor.commit()
|
||||
}
|
||||
}
|
||||
|
||||
fun createStorageEditor(): StorageEditor {
|
||||
|
@ -138,26 +124,16 @@ class Preferences internal constructor(
|
|||
accountsMap?.remove(account.uuid)
|
||||
accountsInOrder.remove(account)
|
||||
|
||||
try {
|
||||
backendManager.removeBackend(account)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Failed to reset remote store for account %s", account.uuid)
|
||||
}
|
||||
|
||||
LocalStore.removeAccount(account)
|
||||
|
||||
val storageEditor = createStorageEditor()
|
||||
accountPreferenceSerializer.delete(storageEditor, storage, account)
|
||||
storageEditor.commit()
|
||||
|
||||
localKeyStoreManager.deleteCertificates(account)
|
||||
|
||||
if (account === newAccount) {
|
||||
newAccount = null
|
||||
}
|
||||
}
|
||||
|
||||
notifyListeners()
|
||||
notifyAccountsChangeListeners()
|
||||
}
|
||||
|
||||
var defaultAccount: Account?
|
||||
|
@ -190,7 +166,15 @@ class Preferences internal constructor(
|
|||
accountPreferenceSerializer.save(editor, storage, account)
|
||||
editor.commit()
|
||||
|
||||
notifyListeners()
|
||||
notifyAccountsChangeListeners()
|
||||
}
|
||||
|
||||
fun saveSettings() {
|
||||
val editor = createStorageEditor()
|
||||
K9.save(editor)
|
||||
editor.commit()
|
||||
|
||||
notifySettingsChangeListeners()
|
||||
}
|
||||
|
||||
private fun ensureAssignedAccountNumber(account: Account) {
|
||||
|
@ -237,10 +221,10 @@ class Preferences internal constructor(
|
|||
loadAccounts()
|
||||
}
|
||||
|
||||
notifyListeners()
|
||||
notifyAccountsChangeListeners()
|
||||
}
|
||||
|
||||
private fun notifyListeners() {
|
||||
private fun notifyAccountsChangeListeners() {
|
||||
for (listener in accountsChangeListeners) {
|
||||
listener.onAccountsChanged()
|
||||
}
|
||||
|
@ -254,6 +238,20 @@ class Preferences internal constructor(
|
|||
accountsChangeListeners.remove(accountsChangeListener)
|
||||
}
|
||||
|
||||
private fun notifySettingsChangeListeners() {
|
||||
for (listener in settingsChangeListeners) {
|
||||
listener.onSettingsChanged()
|
||||
}
|
||||
}
|
||||
|
||||
fun addSettingsChangeListener(settingsChangeListener: SettingsChangeListener) {
|
||||
settingsChangeListeners.add(settingsChangeListener)
|
||||
}
|
||||
|
||||
fun removeSettingsChangeListener(settingsChangeListener: SettingsChangeListener) {
|
||||
settingsChangeListeners.remove(settingsChangeListener)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun getPreferences(context: Context): Preferences {
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
package com.fsck.k9
|
||||
|
||||
interface SettingsChangeListener {
|
||||
fun onSettingsChanged()
|
||||
}
|
|
@ -228,18 +228,6 @@ public class LocalStore {
|
|||
return schemaDefinitionFactory.getDatabaseVersion();
|
||||
}
|
||||
|
||||
public static void removeAccount(Account account) {
|
||||
try {
|
||||
removeInstance(account);
|
||||
} catch (Exception e) {
|
||||
Timber.e(e, "Failed to reset local store for account %s", account.getUuid());
|
||||
}
|
||||
}
|
||||
|
||||
private static void removeInstance(Account account) {
|
||||
DI.get(LocalStoreProvider.class).removeInstance(account);
|
||||
}
|
||||
|
||||
public void switchLocalStorage(final String newStorageProviderId) throws MessagingException {
|
||||
database.switchProvider(newStorageProviderId);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ class StorageMigrationTo6(
|
|||
fun performLegacyMigrations() {
|
||||
rewriteKeyguardPrivacy()
|
||||
rewriteTheme()
|
||||
migrateOpenPgpGlobalToAccountSettings()
|
||||
}
|
||||
|
||||
private fun rewriteKeyguardPrivacy() {
|
||||
|
@ -39,6 +40,26 @@ class StorageMigrationTo6(
|
|||
migrationsHelper.writeValue(db, "theme", newTheme.toString())
|
||||
}
|
||||
|
||||
private fun migrateOpenPgpGlobalToAccountSettings() {
|
||||
val accountUuidsListValue = migrationsHelper.readValue(db, "accountUuids")
|
||||
if (accountUuidsListValue == null || accountUuidsListValue.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
val openPgpProvider = migrationsHelper.readValue(db, "openPgpProvider") ?: ""
|
||||
val openPgpSupportSignOnly = migrationsHelper.readValue(db, "openPgpSupportSignOnly")?.toBoolean() ?: false
|
||||
val openPgpHideSignOnly = (!openPgpSupportSignOnly).toString()
|
||||
|
||||
val accountUuids = accountUuidsListValue.split(",")
|
||||
for (accountUuid in accountUuids) {
|
||||
migrationsHelper.writeValue(db, "$accountUuid.openPgpProvider", openPgpProvider)
|
||||
migrationsHelper.writeValue(db, "$accountUuid.openPgpHideSignOnly", openPgpHideSignOnly)
|
||||
}
|
||||
|
||||
migrationsHelper.writeValue(db, "openPgpProvider", null)
|
||||
migrationsHelper.writeValue(db, "openPgpSupportSignOnly", null)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val THEME_ORDINAL_LIGHT = 0
|
||||
private const val THEME_ORDINAL_DARK = 1
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
package com.fsck.k9.account
|
||||
|
||||
import com.fsck.k9.Account
|
||||
import com.fsck.k9.Core
|
||||
import com.fsck.k9.LocalKeyStoreManager
|
||||
import com.fsck.k9.Preferences
|
||||
import com.fsck.k9.backend.BackendManager
|
||||
import com.fsck.k9.controller.MessagingController
|
||||
import com.fsck.k9.mailstore.LocalStoreProvider
|
||||
import timber.log.Timber
|
||||
|
@ -12,6 +15,8 @@ import timber.log.Timber
|
|||
class AccountRemover(
|
||||
private val localStoreProvider: LocalStoreProvider,
|
||||
private val messagingController: MessagingController,
|
||||
private val backendManager: BackendManager,
|
||||
private val localKeyStoreManager: LocalKeyStoreManager,
|
||||
private val preferences: Preferences
|
||||
) {
|
||||
|
||||
|
@ -25,19 +30,36 @@ class AccountRemover(
|
|||
val accountName = account.description
|
||||
Timber.v("Removing account '%s'…", accountName)
|
||||
|
||||
try {
|
||||
val localStore = localStoreProvider.getInstance(account)
|
||||
localStore.delete()
|
||||
} catch (e: Exception) {
|
||||
Timber.w(e, "Error removing message database for account '%s'", accountName)
|
||||
|
||||
// Ignore, this may lead to localStores on sd-cards that are currently not inserted to be left
|
||||
}
|
||||
|
||||
removeLocalStore(account)
|
||||
messagingController.deleteAccount(account)
|
||||
removeBackend(account)
|
||||
|
||||
preferences.deleteAccount(account)
|
||||
|
||||
localKeyStoreManager.deleteCertificates(account)
|
||||
Core.setServicesEnabled()
|
||||
|
||||
Timber.v("Finished removing account '%s'.", accountName)
|
||||
}
|
||||
|
||||
private fun removeLocalStore(account: Account) {
|
||||
try {
|
||||
val localStore = localStoreProvider.getInstance(account)
|
||||
localStore.delete()
|
||||
} catch (e: Exception) {
|
||||
Timber.w(e, "Error removing message database for account '%s'", account.description)
|
||||
|
||||
// Ignore, this may lead to localStores on sd-cards that are currently not inserted to be left
|
||||
}
|
||||
|
||||
localStoreProvider.removeInstance(account)
|
||||
}
|
||||
|
||||
private fun removeBackend(account: Account) {
|
||||
try {
|
||||
backendManager.removeBackend(account)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Failed to reset remote store for account %s", account.uuid)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,15 @@ package com.fsck.k9.account
|
|||
import org.koin.dsl.module
|
||||
|
||||
val accountModule = module {
|
||||
factory { AccountRemover(get(), get(), get()) }
|
||||
factory {
|
||||
AccountRemover(
|
||||
localStoreProvider = get(),
|
||||
messagingController = get(),
|
||||
backendManager = get(),
|
||||
localKeyStoreManager = get(),
|
||||
preferences = get()
|
||||
)
|
||||
}
|
||||
factory { BackgroundAccountRemover(get()) }
|
||||
factory { AccountCreator(get(), get()) }
|
||||
}
|
||||
|
|
|
@ -558,9 +558,7 @@ class MessageListFragment :
|
|||
K9.setSortAscending(this.sortType, this.sortAscending)
|
||||
sortDateAscending = K9.isSortAscending(SortType.SORT_DATE)
|
||||
|
||||
val editor = preferences.createStorageEditor()
|
||||
K9.save(editor)
|
||||
editor.commit()
|
||||
K9.saveSettingsAsync()
|
||||
}
|
||||
|
||||
reSort()
|
||||
|
|
|
@ -18,7 +18,7 @@ val settingsUiModule = module {
|
|||
single { AccountsLiveData(get()) }
|
||||
viewModel { SettingsViewModel(get()) }
|
||||
|
||||
factory { GeneralSettingsDataStore(get(), get(), get(named("SaveSettingsExecutorService")), get()) }
|
||||
factory { GeneralSettingsDataStore(jobManager = get(), themeManager = get()) }
|
||||
single(named("SaveSettingsExecutorService")) {
|
||||
Executors.newSingleThreadExecutor(NamedThreadFactory("SaveSettings"))
|
||||
}
|
||||
|
|
|
@ -5,15 +5,11 @@ import androidx.preference.PreferenceDataStore
|
|||
import com.fsck.k9.K9
|
||||
import com.fsck.k9.K9.AppTheme
|
||||
import com.fsck.k9.K9.SubTheme
|
||||
import com.fsck.k9.Preferences
|
||||
import com.fsck.k9.job.K9JobManager
|
||||
import com.fsck.k9.ui.base.ThemeManager
|
||||
import java.util.concurrent.ExecutorService
|
||||
|
||||
class GeneralSettingsDataStore(
|
||||
private val preferences: Preferences,
|
||||
private val jobManager: K9JobManager,
|
||||
private val executorService: ExecutorService,
|
||||
private val themeManager: ThemeManager
|
||||
) : PreferenceDataStore() {
|
||||
var activity: FragmentActivity? = null
|
||||
|
@ -230,12 +226,7 @@ class GeneralSettingsDataStore(
|
|||
}
|
||||
|
||||
private fun saveSettings() {
|
||||
val editor = preferences.createStorageEditor()
|
||||
K9.save(editor)
|
||||
|
||||
executorService.execute {
|
||||
editor.commit()
|
||||
}
|
||||
K9.saveSettingsAsync()
|
||||
}
|
||||
|
||||
private fun setTheme(value: String?) {
|
||||
|
|
Loading…
Reference in a new issue