diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/DesktopModule.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/DesktopModule.kt index 8256634c1bda95b34816c0a59b2a1a1f09e81b96..bb0b796eb3f5c54b64770ee5db7b5af86e2bb9b4 100644 --- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/DesktopModule.kt +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/DesktopModule.kt @@ -57,6 +57,9 @@ import org.briarproject.briar.desktop.notification.StubNotificationProvider import org.briarproject.briar.desktop.notification.linux.LibnotifyNotificationProvider import org.briarproject.briar.desktop.settings.Configuration import org.briarproject.briar.desktop.settings.ConfigurationImpl +import org.briarproject.briar.desktop.settings.EncryptedSettings +import org.briarproject.briar.desktop.settings.EncryptedSettingsImpl +import org.briarproject.briar.desktop.settings.EncryptedSettingsReadOnly import org.briarproject.briar.desktop.settings.UnencryptedSettings import org.briarproject.briar.desktop.settings.UnencryptedSettingsImpl import org.briarproject.briar.desktop.settings.UnencryptedSettingsReadOnly @@ -117,6 +120,15 @@ internal class DesktopModule( // provide [UnencryptedSettings] singleton itself as provided above to use same object fun provideUnencryptedSettingsReadOnly(settings: UnencryptedSettings): UnencryptedSettingsReadOnly = settings + @Provides + @Singleton + fun provideEncryptedSettings(settings: EncryptedSettingsImpl): EncryptedSettings = settings + + @Provides + @Singleton + // provide [EncryptedSettings] singleton itself as provided above to use same object + fun provideEncryptedSettingsReadOnly(settings: EncryptedSettings): EncryptedSettingsReadOnly = settings + @Provides @Singleton @EventExecutor diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/settings/Configuration.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/settings/Configuration.kt index aa042a5aa487757435932848e0a9db245c9525cb..c784324c0faf35b6a5d0adae8e7c7e741ae55e0e 100644 --- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/settings/Configuration.kt +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/settings/Configuration.kt @@ -21,4 +21,4 @@ package org.briarproject.briar.desktop.settings import org.briarproject.bramble.api.FeatureFlags import org.briarproject.briar.desktop.DesktopFeatureFlags -interface Configuration : UnencryptedSettingsReadOnly, FeatureFlags, DesktopFeatureFlags +interface Configuration : UnencryptedSettingsReadOnly, EncryptedSettingsReadOnly, FeatureFlags, DesktopFeatureFlags diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/settings/ConfigurationImpl.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/settings/ConfigurationImpl.kt index db7eabe9d80537dfa2efa114c5105d4aad78e913..bd5b019c4dc38b9adea65e285961cff3564f2e68 100644 --- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/settings/ConfigurationImpl.kt +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/settings/ConfigurationImpl.kt @@ -25,9 +25,11 @@ import javax.inject.Inject class ConfigurationImpl @Inject internal constructor( unencryptedSettings: UnencryptedSettingsReadOnly, + encryptedSettings: EncryptedSettingsReadOnly, featureFlags: FeatureFlags, desktopFeatureFlags: DesktopFeatureFlags, ) : Configuration, UnencryptedSettingsReadOnly by unencryptedSettings, + EncryptedSettingsReadOnly by encryptedSettings, FeatureFlags by featureFlags, DesktopFeatureFlags by desktopFeatureFlags diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/settings/EncryptedSettings.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/settings/EncryptedSettings.kt new file mode 100644 index 0000000000000000000000000000000000000000..441e1afd87937e3238e665dd122d9f96074b678e --- /dev/null +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/settings/EncryptedSettings.kt @@ -0,0 +1,27 @@ +/* + * Briar Desktop + * Copyright (C) 2021-2022 The Briar Project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +package org.briarproject.briar.desktop.settings + +interface EncryptedSettingsReadOnly { + val showNotifications: Boolean +} + +interface EncryptedSettings : EncryptedSettingsReadOnly { + override var showNotifications: Boolean +} diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/settings/EncryptedSettingsImpl.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/settings/EncryptedSettingsImpl.kt new file mode 100644 index 0000000000000000000000000000000000000000..2645061fa19f01c0c16df44fe30f85213d162332 --- /dev/null +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/settings/EncryptedSettingsImpl.kt @@ -0,0 +1,52 @@ +/* + * Briar Desktop + * Copyright (C) 2021-2022 The Briar Project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +package org.briarproject.briar.desktop.settings + +import org.briarproject.bramble.api.lifecycle.IoExecutor +import org.briarproject.bramble.api.lifecycle.LifecycleManager +import org.briarproject.bramble.api.settings.Settings +import org.briarproject.bramble.api.settings.SettingsManager +import javax.inject.Inject + +const val SETTINGS_NAMESPACE = "desktop-ui" // NON-NLS + +const val PREF_NOTIFY = "notify" // NON-NLS + +class EncryptedSettingsImpl +@Inject internal constructor( + private val settingsManager: SettingsManager, + lifecycleManager: LifecycleManager, +) : EncryptedSettings { + + init { + lifecycleManager.registerOpenDatabaseHook { txn -> + settings = settingsManager.getSettings(txn, SETTINGS_NAMESPACE) + } + } + + private lateinit var settings: Settings + + override var showNotifications: Boolean + get() = settings.getBoolean(PREF_NOTIFY, true) + @IoExecutor + set(value) { + settings.putBoolean(PREF_NOTIFY, value) + settingsManager.mergeSettings(settings, SETTINGS_NAMESPACE) + } +} diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/settings/SettingDetails.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/settings/SettingDetails.kt index a4672d9cf77667716b85e01ba1fcbeaa1b3cdddf..46a4d3039bb4a0f65b4ae375e8724542eefb2a6a 100644 --- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/settings/SettingDetails.kt +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/settings/SettingDetails.kt @@ -31,6 +31,7 @@ import androidx.compose.foundation.layout.widthIn import androidx.compose.material.MaterialTheme import androidx.compose.material.OutlinedButton import androidx.compose.material.OutlinedExposedDropDownMenu +import androidx.compose.material.Switch import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -48,6 +49,7 @@ fun SettingDetails(viewModel: SettingsViewModel) { SettingCategory.GENERAL -> { SettingDetail(i18n("settings.general.title")) {} } + SettingCategory.DISPLAY -> { // TODO: Change this to `settings.display.title` once more categories are implemented SettingDetail(i18n("settings.title")) { @@ -97,17 +99,34 @@ fun SettingDetails(viewModel: SettingsViewModel) { Text(i18n("settings.security.password.change")) } } + + DetailItem( + label = i18n("settings.notifications.title"), + description = ( + if (viewModel.showNotifications.value) i18n("access.settings.currently_enabled") + else i18n("access.settings.currently_disabled") + ) + ". " + i18n("access.settings.click_to_toggle_notifications") + ) { + Switch( + checked = viewModel.showNotifications.value, + onCheckedChange = { viewModel.toggleShowNotifications() } + ) + } } } + SettingCategory.CONNECTIONS -> { SettingDetail(i18n("settings.connections.title")) {} } + SettingCategory.SECURITY -> { SettingDetail(i18n("settings.security.title")) {} } + SettingCategory.NOTIFICATIONS -> { SettingDetail(i18n("settings.notifications.title")) {} } + SettingCategory.ACTIONS -> { SettingDetail(i18n("settings.actions.title")) {} } diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/settings/SettingsViewModel.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/settings/SettingsViewModel.kt index 982cb5e3218f218aa6ca57ee90377b00a5eb7ee2..fd81555f638a153c623755e32210aba155301c1d 100644 --- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/settings/SettingsViewModel.kt +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/settings/SettingsViewModel.kt @@ -21,8 +21,10 @@ package org.briarproject.briar.desktop.settings import androidx.compose.runtime.mutableStateOf import org.briarproject.bramble.api.account.AccountManager import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator +import org.briarproject.bramble.api.db.TransactionManager +import org.briarproject.bramble.api.lifecycle.LifecycleManager import org.briarproject.briar.desktop.threading.BriarExecutors -import org.briarproject.briar.desktop.viewmodel.ViewModel +import org.briarproject.briar.desktop.viewmodel.DbViewModel import org.briarproject.briar.desktop.viewmodel.asState import javax.inject.Inject @@ -39,10 +41,13 @@ class SettingsViewModel @Inject constructor( private val briarExecutors: BriarExecutors, + lifecycleManager: LifecycleManager, + db: TransactionManager, private val unencryptedSettings: UnencryptedSettings, + private val encryptedSettings: EncryptedSettings, private val accountManager: AccountManager, private val passwordStrengthEstimator: PasswordStrengthEstimator, -) : ViewModel { +) : DbViewModel(briarExecutors, lifecycleManager, db) { private val _selectedSetting = mutableStateOf(SettingCategory.DISPLAY) val selectedSetting = _selectedSetting.asState() @@ -60,6 +65,9 @@ constructor( val changePasswordSubViewModel = ChangePasswordSubViewModel(accountManager, passwordStrengthEstimator) + private val _showNotifications = mutableStateOf(encryptedSettings.showNotifications) + val showNotifications = _showNotifications.asState() + fun selectSetting(selectedOption: SettingCategory) { _selectedSetting.value = selectedOption } @@ -81,4 +89,10 @@ constructor( fun dismissChangePasswordDialog() { _changePasswordDialogVisible.value = false } + + fun toggleShowNotifications() { + val newValue = !_showNotifications.value + _showNotifications.value = newValue + runOnDbThread { encryptedSettings.showNotifications = newValue } + } } diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/BriarUi.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/BriarUi.kt index 772973ce264e6a913d3ae780eb3a211f745a6329..7b8ca936ec15d1efa67d668f99c0aa39a4a7776d 100644 --- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/BriarUi.kt +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/BriarUi.kt @@ -147,7 +147,9 @@ constructor( messageCount++ if (!focusState.focused) { window.iconImage = iconBadge - notificationProvider.notifyPrivateMessages(messageCount) + if (configuration.showNotifications) { + notificationProvider.notifyPrivateMessages(messageCount) + } } } diff --git a/briar-desktop/src/main/resources/strings/BriarDesktop.properties b/briar-desktop/src/main/resources/strings/BriarDesktop.properties index c460e74194f8985c63e1c3d50cd42355e25118bb..8eeae493747783f22054504e90c4ce34addfc8c7 100644 --- a/briar-desktop/src/main/resources/strings/BriarDesktop.properties +++ b/briar-desktop/src/main/resources/strings/BriarDesktop.properties @@ -53,6 +53,10 @@ access.password.hide=Hide password access.settings.current_value=Current value access.settings.click_to_change_value=Click to change value access.settings.click_to_change_password=Click to change password +access.settings.currently_enabled=Currently enabled +access.settings.currently_disabled=Currently enabled +access.settings.click_to_toggle_notifications=Click to toggle notifications + access.return_to_previous_screen=Return to previous screen # Contacts @@ -281,6 +285,7 @@ settings.security.password.changed=Password has been changed. # Settings Notifications settings.notifications.title=Notifications +settings.notifications.show=Show Notifications # Settings Actions settings.actions.title=Actions diff --git a/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/DesktopTestModule.kt b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/DesktopTestModule.kt index 84250542eccd0512a5e1bd50ac1308f8b0ffaa65..a043f8baa051d1b17dc41c42bd8eb76fe13a0ee6 100644 --- a/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/DesktopTestModule.kt +++ b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/DesktopTestModule.kt @@ -58,6 +58,9 @@ import org.briarproject.briar.desktop.notification.StubNotificationProvider import org.briarproject.briar.desktop.notification.linux.LibnotifyNotificationProvider import org.briarproject.briar.desktop.settings.Configuration import org.briarproject.briar.desktop.settings.ConfigurationImpl +import org.briarproject.briar.desktop.settings.EncryptedSettings +import org.briarproject.briar.desktop.settings.EncryptedSettingsImpl +import org.briarproject.briar.desktop.settings.EncryptedSettingsReadOnly import org.briarproject.briar.desktop.settings.UnencryptedSettings import org.briarproject.briar.desktop.settings.UnencryptedSettingsImpl import org.briarproject.briar.desktop.settings.UnencryptedSettingsReadOnly @@ -123,6 +126,15 @@ internal class DesktopTestModule( @Singleton fun provideUnencryptedSettings(settings: UnencryptedSettingsImpl): UnencryptedSettings = settings + @Provides + @Singleton + fun provideEncryptedSettings(settings: EncryptedSettingsImpl): EncryptedSettings = settings + + @Provides + @Singleton + // provide [EncryptedSettings] singleton itself as provided above to use same object + fun provideEncryptedSettingsReadOnly(settings: EncryptedSettings): EncryptedSettingsReadOnly = settings + @Provides @Singleton @EventExecutor diff --git a/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/RunWithMultipleTemporaryAccounts.kt b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/RunWithMultipleTemporaryAccounts.kt index d02435170631eeb81ef7709d9c1090ae8ac8a85c..6b391741d7b9522af969f6bfed950e9b703f02c9 100644 --- a/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/RunWithMultipleTemporaryAccounts.kt +++ b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/RunWithMultipleTemporaryAccounts.kt @@ -19,9 +19,10 @@ package org.briarproject.briar.desktop import androidx.compose.runtime.Composable -import androidx.compose.ui.ExperimentalComposeUiApi +import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.window.ApplicationScope import androidx.compose.ui.window.application +import kotlinx.coroutines.delay import mu.KotlinLogging import org.briarproject.bramble.BrambleCoreEagerSingletons import org.briarproject.bramble.api.plugin.TorConstants.DEFAULT_CONTROL_PORT @@ -44,7 +45,6 @@ internal class RunWithMultipleTemporaryAccounts( private val apps = mutableListOf<BriarDesktopTestApp>() - @OptIn(ExperimentalComposeUiApi::class) fun run() { LogUtils.setupLogging(ALL) @@ -54,9 +54,21 @@ internal class RunWithMultipleTemporaryAccounts( apps.add(app) } - customization(apps) - application { + LaunchedEffect(Unit) { + delay(500) + + apps.forEach { + val accountManager = it.getAccountManager() + val lifecycleManager = it.getLifecycleManager() + val dbKey = accountManager.databaseKey ?: throw AssertionError() + lifecycleManager.startServices(dbKey) + lifecycleManager.waitForStartup() + } + + customization(apps) + } + for (app in apps) { start(app, this) } @@ -82,17 +94,12 @@ internal class RunWithMultipleTemporaryAccounts( BrambleCoreEagerSingletons.Helper.injectEagerSingletons(app) BriarCoreEagerSingletons.Helper.injectEagerSingletons(app) - val lifecycleManager = app.getLifecycleManager() val accountManager = app.getAccountManager() @NonNls val password = "verySecret123!" accountManager.createAccount(name, password) - val dbKey = accountManager.databaseKey ?: throw AssertionError() - lifecycleManager.startServices(dbKey) - lifecycleManager.waitForStartup() - return app } diff --git a/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/RunWithTemporaryAccount.kt b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/RunWithTemporaryAccount.kt index 1b745e495e589ec0775988e4067b0b7bba9cad19..3905d354d3d4d20dff6db27ae8b5c123624f7bb7 100644 --- a/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/RunWithTemporaryAccount.kt +++ b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/RunWithTemporaryAccount.kt @@ -18,8 +18,10 @@ package org.briarproject.briar.desktop +import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.window.application +import kotlinx.coroutines.delay import mu.KotlinLogging import org.briarproject.bramble.BrambleCoreEagerSingletons import org.briarproject.briar.BriarCoreEagerSingletons @@ -77,17 +79,21 @@ internal class RunWithTemporaryAccount( @NonNls val password = "verySecret123!" accountManager.createAccount("alice", password) - - if (login) { - val dbKey = accountManager.databaseKey ?: throw AssertionError() - lifecycleManager.startServices(dbKey) - lifecycleManager.waitForStartup() - } } - customization(app) - application { + LaunchedEffect(Unit) { + delay(500) + + if (createAccount && login) { + val dbKey = accountManager.databaseKey ?: throw AssertionError() + lifecycleManager.startServices(dbKey) + lifecycleManager.waitForStartup() + + customization(app) + } + } + app.getBriarUi().start { app.getBriarUi().stop() exitApplication()