Repo created
This commit is contained in:
parent
75dc487a7a
commit
39c29d175b
6317 changed files with 388324 additions and 2 deletions
17
core/preference/impl/build.gradle.kts
Normal file
17
core/preference/impl/build.gradle.kts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
plugins {
|
||||
id(ThunderbirdPlugins.Library.kmp)
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "net.thunderbird.core.preference.impl"
|
||||
}
|
||||
|
||||
kotlin {
|
||||
sourceSets {
|
||||
commonMain.dependencies {
|
||||
api(projects.core.preference.api)
|
||||
|
||||
implementation(projects.core.logging.api)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package net.thunderbird.core.preference
|
||||
|
||||
class DefaultPreferenceChangeBroker(
|
||||
private val subscribers: MutableSet<PreferenceChangeSubscriber> = mutableSetOf(),
|
||||
) : PreferenceChangeBroker, PreferenceChangePublisher {
|
||||
|
||||
private val lock = Any()
|
||||
|
||||
override fun subscribe(subscriber: PreferenceChangeSubscriber) {
|
||||
synchronized(lock) {
|
||||
subscribers.add(subscriber)
|
||||
}
|
||||
}
|
||||
|
||||
override fun unsubscribe(subscriber: PreferenceChangeSubscriber) {
|
||||
synchronized(lock) {
|
||||
subscribers.remove(subscriber)
|
||||
}
|
||||
}
|
||||
|
||||
override fun publish() {
|
||||
val currentSubscribers = synchronized(lock) { HashSet(subscribers) }
|
||||
|
||||
for (subscriber in currentSubscribers) {
|
||||
subscriber.receive()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
package net.thunderbird.core.preference.debugging
|
||||
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import net.thunderbird.core.logging.LogLevel
|
||||
import net.thunderbird.core.logging.LogLevelManager
|
||||
import net.thunderbird.core.logging.Logger
|
||||
import net.thunderbird.core.preference.storage.Storage
|
||||
import net.thunderbird.core.preference.storage.StorageEditor
|
||||
|
||||
private const val TAG = "DefaultDebuggingSettingsPreferenceManager"
|
||||
|
||||
class DefaultDebuggingSettingsPreferenceManager(
|
||||
private val logger: Logger,
|
||||
private val storage: Storage,
|
||||
private val storageEditor: StorageEditor,
|
||||
private val logLevelManager: LogLevelManager,
|
||||
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO,
|
||||
private var scope: CoroutineScope = CoroutineScope(SupervisorJob()),
|
||||
) : DebuggingSettingsPreferenceManager {
|
||||
private val configState: MutableStateFlow<DebuggingSettings> = MutableStateFlow(value = loadConfig())
|
||||
private val mutex = Mutex()
|
||||
|
||||
override fun getConfig(): DebuggingSettings = configState.value
|
||||
override fun getConfigFlow(): Flow<DebuggingSettings> = configState
|
||||
|
||||
override fun save(config: DebuggingSettings) {
|
||||
logger.debug(TAG) { "save() called with: config = $config" }
|
||||
writeConfig(config)
|
||||
configState.update { config.also(::updateDebugLogLevel) }
|
||||
}
|
||||
|
||||
private fun loadConfig(): DebuggingSettings = DebuggingSettings(
|
||||
isDebugLoggingEnabled = storage.getBoolean(
|
||||
KEY_ENABLE_DEBUG_LOGGING,
|
||||
DEBUGGING_SETTINGS_DEFAULT_IS_DEBUGGING_LOGGING_ENABLED,
|
||||
),
|
||||
isSyncLoggingEnabled = storage.getBoolean(
|
||||
KEY_ENABLE_SYNC_DEBUG_LOGGING,
|
||||
DEBUGGING_SETTINGS_DEFAULT_IS_SYNC_LOGGING_ENABLED,
|
||||
),
|
||||
).also(::updateDebugLogLevel)
|
||||
|
||||
private fun writeConfig(config: DebuggingSettings) {
|
||||
logger.debug(TAG) { "writeConfig() called with: config = $config" }
|
||||
scope.launch(ioDispatcher) {
|
||||
mutex.withLock {
|
||||
storageEditor.putBoolean(KEY_ENABLE_DEBUG_LOGGING, config.isDebugLoggingEnabled)
|
||||
storageEditor.putBoolean(KEY_ENABLE_SYNC_DEBUG_LOGGING, config.isSyncLoggingEnabled)
|
||||
storageEditor.commit().also { commited ->
|
||||
logger.verbose(TAG) { "writeConfig: storageEditor.commit() resulted in: $commited" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateDebugLogLevel(config: DebuggingSettings) {
|
||||
if (config.isDebugLoggingEnabled) {
|
||||
logLevelManager.override(LogLevel.DEBUG)
|
||||
} else {
|
||||
logLevelManager.restoreDefault()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
package net.thunderbird.core.preference.display
|
||||
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import net.thunderbird.core.logging.Logger
|
||||
import net.thunderbird.core.preference.display.coreSettings.DisplayCoreSettingsPreferenceManager
|
||||
import net.thunderbird.core.preference.storage.Storage
|
||||
import net.thunderbird.core.preference.storage.StorageEditor
|
||||
|
||||
private const val TAG = "DefaultDisplaySettingsPreferenceManager"
|
||||
|
||||
class DefaultDisplaySettingsPreferenceManager(
|
||||
private val logger: Logger,
|
||||
private val storage: Storage,
|
||||
private val storageEditor: StorageEditor,
|
||||
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO,
|
||||
private var scope: CoroutineScope = CoroutineScope(SupervisorJob()),
|
||||
private val coreSettingsPreferenceManager: DisplayCoreSettingsPreferenceManager,
|
||||
) : DisplaySettingsPreferenceManager {
|
||||
private val configState: MutableStateFlow<DisplaySettings> = MutableStateFlow(value = loadConfig())
|
||||
private val mutex = Mutex()
|
||||
|
||||
override fun getConfig(): DisplaySettings = configState.value
|
||||
override fun getConfigFlow(): Flow<DisplaySettings> = configState
|
||||
|
||||
override fun save(config: DisplaySettings) {
|
||||
logger.debug(TAG) { "save() called with: config = $config" }
|
||||
coreSettingsPreferenceManager.save(config.coreSettings)
|
||||
writeConfig(config)
|
||||
configState.update { config }
|
||||
}
|
||||
|
||||
private fun loadConfig(): DisplaySettings = DisplaySettings(
|
||||
coreSettings = coreSettingsPreferenceManager.getConfig(),
|
||||
showRecentChanges = storage.getBoolean(
|
||||
KEY_SHOW_RECENT_CHANGES,
|
||||
DISPLAY_SETTINGS_DEFAULT_SHOW_RECENT_CHANGES,
|
||||
),
|
||||
shouldShowSetupArchiveFolderDialog = storage.getBoolean(
|
||||
KEY_SHOULD_SHOW_SETUP_ARCHIVE_FOLDER_DIALOG,
|
||||
DISPLAY_SETTINGS_DEFAULT_SHOULD_SHOW_SETUP_ARCHIVE_FOLDER_DIALOG,
|
||||
),
|
||||
isColorizeMissingContactPictures = storage.getBoolean(
|
||||
KEY_COLORIZE_MISSING_CONTACT_PICTURE,
|
||||
DISPLAY_SETTINGS_DEFAULT_IS_COLORIZE_MISSING_CONTACT_PICTURE,
|
||||
),
|
||||
isChangeContactNameColor = storage.getBoolean(
|
||||
KEY_CHANGE_REGISTERED_NAME_COLOR,
|
||||
DISPLAY_SETTINGS_DEFAULT_IS_CHANGE_CONTACT_NAME_COLOR,
|
||||
),
|
||||
isUseBackgroundAsUnreadIndicator = storage.getBoolean(
|
||||
KEY_USE_BACKGROUND_AS_UNREAD_INDICATOR,
|
||||
DISPLAY_SETTINGS_DEFAULT_IS_USE_BACKGROUND_AS_INDICATOR,
|
||||
),
|
||||
isUseMessageViewFixedWidthFont = storage.getBoolean(
|
||||
KEY_MESSAGE_VIEW_FIXED_WIDTH_FONT,
|
||||
DISPLAY_SETTINGS_DEFAULT_IS_USE_MESSAGE_VIEW_FIXED_WIDTH_FONT,
|
||||
),
|
||||
isAutoFitWidth = storage.getBoolean(
|
||||
KEY_AUTO_FIT_WIDTH,
|
||||
DISPLAY_SETTINGS_DEFAULT_IS_AUTO_FIT_WIDTH,
|
||||
),
|
||||
isShowAnimations = storage.getBoolean(
|
||||
KEY_ANIMATION,
|
||||
DISPLAY_SETTINGS_DEFAULT_IS_SHOW_ANIMATION,
|
||||
),
|
||||
isShowCorrespondentNames = storage.getBoolean(
|
||||
KEY_SHOW_CORRESPONDENT_NAMES,
|
||||
DISPLAY_SETTINGS_DEFAULT_IS_SHOW_CORRESPONDENT_NAMES,
|
||||
),
|
||||
isShowContactName = storage.getBoolean(
|
||||
KEY_SHOW_CONTACT_NAME,
|
||||
DISPLAY_SETTINGS_DEFAULT_IS_SHOW_CONTACT_NAME,
|
||||
),
|
||||
isShowContactPicture = storage.getBoolean(
|
||||
KEY_SHOW_CONTACT_PICTURE,
|
||||
DISPLAY_SETTINGS_DEFAULT_IS_SHOW_CONTACT_PICTURE,
|
||||
),
|
||||
)
|
||||
|
||||
private fun writeConfig(config: DisplaySettings) {
|
||||
logger.debug(TAG) { "writeConfig() called with: config = $config" }
|
||||
scope.launch(ioDispatcher) {
|
||||
mutex.withLock {
|
||||
storageEditor.putBoolean(
|
||||
KEY_CHANGE_REGISTERED_NAME_COLOR,
|
||||
config.isChangeContactNameColor,
|
||||
)
|
||||
storageEditor.putBoolean(
|
||||
KEY_COLORIZE_MISSING_CONTACT_PICTURE,
|
||||
config.isColorizeMissingContactPictures,
|
||||
)
|
||||
storageEditor.putBoolean(
|
||||
KEY_SHOULD_SHOW_SETUP_ARCHIVE_FOLDER_DIALOG,
|
||||
config.shouldShowSetupArchiveFolderDialog,
|
||||
)
|
||||
storageEditor.putBoolean(KEY_SHOW_CONTACT_NAME, config.isShowContactName)
|
||||
storageEditor.putBoolean(
|
||||
KEY_SHOW_CORRESPONDENT_NAMES,
|
||||
config.isShowCorrespondentNames,
|
||||
)
|
||||
storageEditor.putBoolean(KEY_SHOW_RECENT_CHANGES, config.showRecentChanges)
|
||||
storageEditor.putBoolean(KEY_ANIMATION, config.isShowAnimations)
|
||||
storageEditor.putBoolean(
|
||||
KEY_SHOW_CONTACT_PICTURE,
|
||||
config.isShowContactPicture,
|
||||
)
|
||||
storageEditor.putBoolean(
|
||||
KEY_USE_BACKGROUND_AS_UNREAD_INDICATOR,
|
||||
config.isUseBackgroundAsUnreadIndicator,
|
||||
)
|
||||
storageEditor.putBoolean(
|
||||
KEY_MESSAGE_VIEW_FIXED_WIDTH_FONT,
|
||||
config.isUseMessageViewFixedWidthFont,
|
||||
)
|
||||
storageEditor.putBoolean(KEY_AUTO_FIT_WIDTH, config.isAutoFitWidth)
|
||||
storageEditor.commit().also { commited ->
|
||||
logger.verbose(TAG) { "writeConfig: storageEditor.commit() resulted in: $commited" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
package net.thunderbird.core.preference.display.coreSettings
|
||||
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import net.thunderbird.core.logging.Logger
|
||||
import net.thunderbird.core.preference.display.KEY_THEME
|
||||
import net.thunderbird.core.preference.storage.Storage
|
||||
import net.thunderbird.core.preference.storage.StorageEditor
|
||||
import net.thunderbird.core.preference.storage.getEnumOrDefault
|
||||
import net.thunderbird.core.preference.storage.putEnum
|
||||
|
||||
private const val TAG = "DefaultDisplayCoreSettingsPreferenceManager"
|
||||
|
||||
class DefaultDisplayCoreSettingsPreferenceManager(
|
||||
private val logger: Logger,
|
||||
private val storage: Storage,
|
||||
private val storageEditor: StorageEditor,
|
||||
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO,
|
||||
private var scope: CoroutineScope = CoroutineScope(SupervisorJob()),
|
||||
) : DisplayCoreSettingsPreferenceManager {
|
||||
|
||||
private val configState: MutableStateFlow<DisplayCoreSettings> = MutableStateFlow(value = loadConfig())
|
||||
private val mutex = Mutex()
|
||||
|
||||
override fun getConfig(): DisplayCoreSettings = configState.value
|
||||
|
||||
override fun getConfigFlow(): Flow<DisplayCoreSettings> = configState
|
||||
|
||||
override fun save(config: DisplayCoreSettings) {
|
||||
logger.debug(TAG) { "save() called with: config = $config" }
|
||||
writeConfig(config)
|
||||
configState.update { config }
|
||||
}
|
||||
|
||||
private fun loadConfig(): DisplayCoreSettings = DisplayCoreSettings(
|
||||
fixedMessageViewTheme = storage.getBoolean(
|
||||
KEY_FIXED_MESSAGE_VIEW_THEME,
|
||||
DISPLAY_SETTINGS_DEFAULT_FIXED_MESSAGE_VIEW_THEME,
|
||||
),
|
||||
appTheme = storage.getEnumOrDefault(KEY_THEME, DISPLAY_SETTINGS_DEFAULT_APP_THEME),
|
||||
messageViewTheme = storage.getEnumOrDefault(
|
||||
KEY_MESSAGE_VIEW_THEME,
|
||||
DISPLAY_SETTINGS_DEFAULT_MESSAGE_VIEW_THEME,
|
||||
),
|
||||
messageComposeTheme = storage.getEnumOrDefault(
|
||||
KEY_MESSAGE_COMPOSE_THEME,
|
||||
DISPLAY_SETTINGS_DEFAULT_MESSAGE_COMPOSE_THEME,
|
||||
),
|
||||
appLanguage = storage.getStringOrDefault(
|
||||
KEY_APP_LANGUAGE,
|
||||
DISPLAY_SETTINGS_DEFAULT_APP_LANGUAGE,
|
||||
),
|
||||
splitViewMode = storage.getEnumOrDefault(
|
||||
KEY_SPLIT_VIEW_MODE,
|
||||
DISPLAY_SETTINGS_DEFAULT_SPLIT_VIEW_MODE,
|
||||
),
|
||||
)
|
||||
|
||||
private fun writeConfig(config: DisplayCoreSettings) {
|
||||
logger.debug(TAG) { "writeConfig() called with: config = $config" }
|
||||
scope.launch(ioDispatcher) {
|
||||
mutex.withLock {
|
||||
storageEditor.putEnum(KEY_THEME, config.appTheme)
|
||||
storageEditor.putEnum(KEY_MESSAGE_VIEW_THEME, config.messageViewTheme)
|
||||
storageEditor.putEnum(
|
||||
KEY_MESSAGE_COMPOSE_THEME,
|
||||
config.messageComposeTheme,
|
||||
)
|
||||
storageEditor.putBoolean(
|
||||
KEY_FIXED_MESSAGE_VIEW_THEME,
|
||||
config.fixedMessageViewTheme,
|
||||
)
|
||||
storageEditor.putString(KEY_APP_LANGUAGE, config.appLanguage)
|
||||
storageEditor.putEnum(KEY_SPLIT_VIEW_MODE, config.splitViewMode)
|
||||
storageEditor.commit().also { commited ->
|
||||
logger.verbose(TAG) { "writeConfig: storageEditor.commit() resulted in: $commited" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
package net.thunderbird.core.preference.display.inboxSettings
|
||||
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import net.thunderbird.core.logging.Logger
|
||||
import net.thunderbird.core.preference.storage.Storage
|
||||
import net.thunderbird.core.preference.storage.StorageEditor
|
||||
|
||||
private const val TAG = "DefaultDisplayInboxSettingsPreferenceManager"
|
||||
|
||||
class DefaultDisplayInboxSettingsPreferenceManager(
|
||||
private val logger: Logger,
|
||||
private val storage: Storage,
|
||||
private val storageEditor: StorageEditor,
|
||||
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO,
|
||||
private var scope: CoroutineScope = CoroutineScope(SupervisorJob()),
|
||||
) : DisplayInboxSettingsPreferenceManager {
|
||||
|
||||
private val configState: MutableStateFlow<DisplayInboxSettings> = MutableStateFlow(value = loadConfig())
|
||||
private val mutex = Mutex()
|
||||
|
||||
override fun getConfig(): DisplayInboxSettings = configState.value
|
||||
|
||||
override fun getConfigFlow(): Flow<DisplayInboxSettings> = configState
|
||||
|
||||
override fun save(config: DisplayInboxSettings) {
|
||||
logger.debug(TAG) { "save() called with: config = $config" }
|
||||
writeConfig(config)
|
||||
configState.update { config }
|
||||
}
|
||||
|
||||
private fun loadConfig(): DisplayInboxSettings = DisplayInboxSettings(
|
||||
isShowUnifiedInbox = storage.getBoolean(
|
||||
KEY_SHOW_UNIFIED_INBOX,
|
||||
DISPLAY_SETTINGS_DEFAULT_IS_SHOW_UNIFIED_INBOX,
|
||||
),
|
||||
isShowComposeButtonOnMessageList = storage.getBoolean(
|
||||
KEY_SHOW_COMPOSE_BUTTON_ON_MESSAGE_LIST,
|
||||
DISPLAY_SETTINGS_DEFAULT_IS_SHOW_COMPOSE_BUTTON_ON_MESSAGE_LIST,
|
||||
),
|
||||
isThreadedViewEnabled = storage.getBoolean(
|
||||
KEY_THREAD_VIEW_ENABLED,
|
||||
DISPLAY_SETTINGS_DEFAULT_IS_THREAD_VIEW_ENABLED,
|
||||
),
|
||||
isShowStarredCount = storage.getBoolean(
|
||||
KEY_SHOW_STAR_COUNT,
|
||||
DISPLAY_SETTINGS_DEFAULT_IS_SHOW_STAR_COUNT,
|
||||
),
|
||||
isShowMessageListStars = storage.getBoolean(
|
||||
KEY_SHOW_MESSAGE_LIST_STARS,
|
||||
DISPLAY_SETTINGS_DEFAULT_IS_SHOW_MESSAGE_LIST_STAR,
|
||||
),
|
||||
isMessageListSenderAboveSubject = storage.getBoolean(
|
||||
KEY_MESSAGE_LIST_SENDER_ABOVE_SUBJECT,
|
||||
DISPLAY_SETTINGS_DEFAULT_IS_MESSAGE_LIST_SENDER_ABOVE_SUBJECT,
|
||||
),
|
||||
)
|
||||
|
||||
private fun writeConfig(config: DisplayInboxSettings) {
|
||||
logger.debug(TAG) { "writeConfig() called with: config = $config" }
|
||||
scope.launch(ioDispatcher) {
|
||||
mutex.withLock {
|
||||
storageEditor.putBoolean(
|
||||
KEY_MESSAGE_LIST_SENDER_ABOVE_SUBJECT,
|
||||
config.isMessageListSenderAboveSubject,
|
||||
)
|
||||
storageEditor.putBoolean(
|
||||
KEY_SHOW_MESSAGE_LIST_STARS,
|
||||
config.isShowMessageListStars,
|
||||
)
|
||||
storageEditor.putBoolean(
|
||||
KEY_SHOW_COMPOSE_BUTTON_ON_MESSAGE_LIST,
|
||||
config.isShowComposeButtonOnMessageList,
|
||||
)
|
||||
storageEditor.putBoolean(
|
||||
KEY_THREAD_VIEW_ENABLED,
|
||||
config.isThreadedViewEnabled,
|
||||
)
|
||||
storageEditor.putBoolean(KEY_SHOW_UNIFIED_INBOX, config.isShowUnifiedInbox)
|
||||
storageEditor.putBoolean(KEY_SHOW_STAR_COUNT, config.isShowStarredCount)
|
||||
storageEditor.commit().also { commited ->
|
||||
logger.verbose(TAG) { "writeConfig: storageEditor.commit() resulted in: $commited" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package net.thunderbird.core.preference.network
|
||||
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import net.thunderbird.core.logging.Logger
|
||||
import net.thunderbird.core.preference.storage.Storage
|
||||
import net.thunderbird.core.preference.storage.StorageEditor
|
||||
import net.thunderbird.core.preference.storage.getEnumOrDefault
|
||||
import net.thunderbird.core.preference.storage.putEnum
|
||||
|
||||
private const val TAG = "DefaultNetworkSettingsPreferenceManager"
|
||||
|
||||
class DefaultNetworkSettingsPreferenceManager(
|
||||
private val logger: Logger,
|
||||
private val storage: Storage,
|
||||
private val storageEditor: StorageEditor,
|
||||
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO,
|
||||
private var scope: CoroutineScope = CoroutineScope(SupervisorJob()),
|
||||
) : NetworkSettingsPreferenceManager {
|
||||
private val configState: MutableStateFlow<NetworkSettings> = MutableStateFlow(value = loadConfig())
|
||||
private val mutex = Mutex()
|
||||
|
||||
override fun getConfig(): NetworkSettings = configState.value
|
||||
override fun getConfigFlow(): Flow<NetworkSettings> = configState
|
||||
|
||||
override fun save(config: NetworkSettings) {
|
||||
logger.debug(TAG) { "save() called with: config = $config" }
|
||||
writeConfig(config)
|
||||
configState.update { config }
|
||||
}
|
||||
|
||||
private fun loadConfig(): NetworkSettings = NetworkSettings(
|
||||
backgroundOps = storage.getEnumOrDefault(KEY_BG_OPS, NETWORK_SETTINGS_DEFAULT_BACKGROUND_OPS),
|
||||
)
|
||||
|
||||
private fun writeConfig(config: NetworkSettings) {
|
||||
logger.debug(TAG) { "writeConfig() called with: config = $config" }
|
||||
scope.launch(ioDispatcher) {
|
||||
mutex.withLock {
|
||||
storageEditor.putEnum(KEY_BG_OPS, config.backgroundOps)
|
||||
storageEditor.commit().also { commited ->
|
||||
logger.verbose(TAG) { "writeConfig: storageEditor.commit() resulted in: $commited" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
package net.thunderbird.core.preference.notification
|
||||
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import net.thunderbird.core.logging.Logger
|
||||
import net.thunderbird.core.preference.storage.Storage
|
||||
import net.thunderbird.core.preference.storage.StorageEditor
|
||||
|
||||
private const val TAG = "DefaultNotificationPreferenceManager"
|
||||
|
||||
class DefaultNotificationPreferenceManager(
|
||||
private val logger: Logger,
|
||||
storage: Storage,
|
||||
private val storageEditor: StorageEditor,
|
||||
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO,
|
||||
private var scope: CoroutineScope = CoroutineScope(SupervisorJob()),
|
||||
) : NotificationPreferenceManager {
|
||||
private val mutex = Mutex()
|
||||
private val configState = MutableStateFlow(
|
||||
value = NotificationPreference(
|
||||
isQuietTimeEnabled = storage.getBoolean(
|
||||
key = KEY_QUIET_TIME_ENABLED,
|
||||
defValue = NOTIFICATION_PREFERENCE_DEFAULT_IS_QUIET_TIME_ENABLED,
|
||||
),
|
||||
quietTimeStarts = storage.getStringOrDefault(
|
||||
key = KEY_QUIET_TIME_STARTS,
|
||||
defValue = NOTIFICATION_PREFERENCE_DEFAULT_QUIET_TIME_STARTS,
|
||||
),
|
||||
quietTimeEnds = storage.getStringOrDefault(
|
||||
key = KEY_QUIET_TIME_ENDS,
|
||||
defValue = NOTIFICATION_PREFERENCE_DEFAULT_QUIET_TIME_END,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
override fun getConfig(): NotificationPreference = configState.value
|
||||
override fun getConfigFlow(): Flow<NotificationPreference> = configState
|
||||
|
||||
override fun save(config: NotificationPreference) {
|
||||
logger.debug(TAG) { "writeConfig() called with: config = $config" }
|
||||
scope.launch(ioDispatcher) {
|
||||
mutex.withLock {
|
||||
storageEditor.putString(KEY_QUIET_TIME_ENDS, config.quietTimeEnds)
|
||||
storageEditor.putString(KEY_QUIET_TIME_STARTS, config.quietTimeStarts)
|
||||
storageEditor.putBoolean(
|
||||
KEY_QUIET_TIME_ENABLED,
|
||||
config.isQuietTimeEnabled,
|
||||
)
|
||||
storageEditor.commit().also { commited ->
|
||||
logger.verbose(TAG) { "writeConfig: storageEditor.commit() resulted in: $commited" }
|
||||
}
|
||||
}
|
||||
configState.update { config }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
package net.thunderbird.core.preference.privacy
|
||||
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import net.thunderbird.core.logging.Logger
|
||||
import net.thunderbird.core.preference.storage.Storage
|
||||
import net.thunderbird.core.preference.storage.StorageEditor
|
||||
|
||||
private const val TAG = "DefaultPrivacySettingsPreferenceManager"
|
||||
|
||||
class DefaultPrivacySettingsPreferenceManager(
|
||||
private val logger: Logger,
|
||||
private val storage: Storage,
|
||||
private val storageEditor: StorageEditor,
|
||||
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO,
|
||||
private var scope: CoroutineScope = CoroutineScope(SupervisorJob()),
|
||||
) : PrivacySettingsPreferenceManager {
|
||||
private val configState: MutableStateFlow<PrivacySettings> = MutableStateFlow(value = loadConfig())
|
||||
private val mutex = Mutex()
|
||||
|
||||
override fun getConfig(): PrivacySettings = configState.value
|
||||
override fun getConfigFlow(): Flow<PrivacySettings> = configState
|
||||
|
||||
override fun save(config: PrivacySettings) {
|
||||
logger.debug(TAG) { "save() called with: config = $config" }
|
||||
writeConfig(config)
|
||||
configState.update { config }
|
||||
}
|
||||
|
||||
private fun loadConfig(): PrivacySettings = PrivacySettings(
|
||||
isHideTimeZone = storage.getBoolean(
|
||||
key = KEY_HIDE_TIME_ZONE,
|
||||
defValue = PRIVACY_SETTINGS_DEFAULT_HIDE_TIME_ZONE,
|
||||
),
|
||||
isHideUserAgent = storage.getBoolean(
|
||||
key = KEY_HIDE_USER_AGENT,
|
||||
defValue = PRIVACY_SETTINGS_DEFAULT_HIDE_USER_AGENT,
|
||||
),
|
||||
)
|
||||
|
||||
private fun writeConfig(config: PrivacySettings) {
|
||||
logger.debug(TAG) { "writeConfig() called with: config = $config" }
|
||||
scope.launch(ioDispatcher) {
|
||||
mutex.withLock {
|
||||
storageEditor.putBoolean(KEY_HIDE_TIME_ZONE, config.isHideTimeZone)
|
||||
storageEditor.putBoolean(KEY_HIDE_USER_AGENT, config.isHideUserAgent)
|
||||
storageEditor.commit().also { commited ->
|
||||
logger.verbose(TAG) { "writeConfig: storageEditor.commit() resulted in: $commited" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
package net.thunderbird.core.preference.storage
|
||||
|
||||
import net.thunderbird.core.logging.Logger
|
||||
|
||||
class InMemoryStorage(
|
||||
private val values: Map<String, String>,
|
||||
private val logger: Logger,
|
||||
) : Storage {
|
||||
|
||||
override fun isEmpty(): Boolean = values.isEmpty()
|
||||
|
||||
override fun contains(key: String): Boolean = values.contains(key)
|
||||
|
||||
override fun getAll(): Map<String, String> = values
|
||||
|
||||
override fun getBoolean(key: String, defValue: Boolean): Boolean =
|
||||
values[key]
|
||||
?.toBoolean()
|
||||
?: defValue
|
||||
|
||||
override fun getInt(key: String, defValue: Int): Int {
|
||||
val value = values[key] ?: return defValue
|
||||
return try {
|
||||
value.toInt()
|
||||
} catch (e: NumberFormatException) {
|
||||
logger.error(
|
||||
message = { "Could not parse int" },
|
||||
throwable = e,
|
||||
)
|
||||
defValue
|
||||
}
|
||||
}
|
||||
|
||||
override fun getLong(key: String, defValue: Long): Long {
|
||||
val value = values[key] ?: return defValue
|
||||
return try {
|
||||
value.toLong()
|
||||
} catch (e: NumberFormatException) {
|
||||
logger.error(
|
||||
message = { "Could not parse long" },
|
||||
throwable = e,
|
||||
)
|
||||
defValue
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(NoSuchElementException::class)
|
||||
override fun getString(key: String): String =
|
||||
values.getValue(key)
|
||||
|
||||
override fun getStringOrDefault(key: String, defValue: String): String =
|
||||
getStringOrNull(key) ?: defValue
|
||||
|
||||
override fun getStringOrNull(key: String): String? =
|
||||
values[key]
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
package net.thunderbird.core.preference
|
||||
|
||||
import assertk.assertThat
|
||||
import assertk.assertions.contains
|
||||
import assertk.assertions.doesNotContain
|
||||
import assertk.assertions.isEqualTo
|
||||
import kotlin.test.Test
|
||||
|
||||
class DefaultPreferenceChangeBrokerTest {
|
||||
|
||||
@Test
|
||||
fun `subscribe should add subscriber`() {
|
||||
val subscriber = PreferenceChangeSubscriber { }
|
||||
val subscribers = mutableSetOf<PreferenceChangeSubscriber>()
|
||||
val broker = DefaultPreferenceChangeBroker(subscribers)
|
||||
|
||||
broker.subscribe(subscriber)
|
||||
|
||||
assertThat(subscribers.size).isEqualTo(1)
|
||||
assertThat(subscribers).contains(subscriber)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `unsubscribe should remove subscriber`() {
|
||||
val subscriber = PreferenceChangeSubscriber { }
|
||||
val subscribers = mutableSetOf<PreferenceChangeSubscriber>(subscriber)
|
||||
val broker = DefaultPreferenceChangeBroker(subscribers)
|
||||
|
||||
broker.unsubscribe(subscriber)
|
||||
|
||||
assertThat(subscribers.size).isEqualTo(0)
|
||||
assertThat(subscribers).doesNotContain(subscriber)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `publish should notify subscribers`() {
|
||||
var received = false
|
||||
val subscriber = PreferenceChangeSubscriber { received = true }
|
||||
var receivedOther = false
|
||||
val otherSubscriber = PreferenceChangeSubscriber { receivedOther = true }
|
||||
val subscribers = mutableSetOf<PreferenceChangeSubscriber>(subscriber, otherSubscriber)
|
||||
val broker = DefaultPreferenceChangeBroker(subscribers)
|
||||
|
||||
broker.publish()
|
||||
|
||||
assertThat(received).isEqualTo(true)
|
||||
assertThat(receivedOther).isEqualTo(true)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue