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 b406225863b6cba88c3750adfea1aa4201ddf8ac..8256634c1bda95b34816c0a59b2a1a1f09e81b96 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 @@ -55,8 +55,11 @@ import org.briarproject.briar.desktop.attachment.media.ImageCompressorImpl import org.briarproject.briar.desktop.notification.NotificationProvider 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.UnencryptedSettings import org.briarproject.briar.desktop.settings.UnencryptedSettingsImpl +import org.briarproject.briar.desktop.settings.UnencryptedSettingsReadOnly import org.briarproject.briar.desktop.threading.BriarExecutors import org.briarproject.briar.desktop.threading.BriarExecutorsImpl import org.briarproject.briar.desktop.threading.UiExecutor @@ -109,6 +112,11 @@ internal class DesktopModule( @Singleton fun provideUnencryptedSettings(settings: UnencryptedSettingsImpl): UnencryptedSettings = settings + @Provides + @Singleton + // provide [UnencryptedSettings] singleton itself as provided above to use same object + fun provideUnencryptedSettingsReadOnly(settings: UnencryptedSettings): UnencryptedSettingsReadOnly = settings + @Provides @Singleton @EventExecutor @@ -171,6 +179,10 @@ internal class DesktopModule( override fun shouldEnableTransportSettings() = false } + @Provides + @Singleton + fun provideConfiguration(configuration: ConfigurationImpl): Configuration = configuration + @Provides @Singleton internal fun provideImageCompressor(imageCompressor: ImageCompressorImpl): ImageCompressor { diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactDropDown.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactDropDown.kt index ea43f749768fa41a83b47a2abb38e302db061dc8..77a8d96e3d66c4b470ad135465ee45dd681468fa 100644 --- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactDropDown.kt +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactDropDown.kt @@ -35,8 +35,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import org.briarproject.briar.desktop.contact.ContactDropDown.State import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n -import org.briarproject.briar.desktop.utils.getCoreFeatureFlags -import org.briarproject.briar.desktop.utils.getDesktopFeatureFlags +import org.briarproject.briar.desktop.utils.getConfiguration class ContactDropDown { enum class State { @@ -56,8 +55,7 @@ fun ContactDropDown( onChangeAlias: () -> Unit, onDeleteContact: () -> Unit, ) { - val coreFeatureFlags = getCoreFeatureFlags() - val desktopFeatureFlags = getDesktopFeatureFlags() + val configuration = getConfiguration() val close = { setState(State.CLOSED) } @@ -68,7 +66,7 @@ fun ContactDropDown( DropdownMenuItem(onClick = { close(); onMakeIntroduction() }) { Text(i18n("contacts.dropdown.introduction"), style = MaterialTheme.typography.body2) } - if (coreFeatureFlags.shouldEnableDisappearingMessages()) { + if (configuration.shouldEnableDisappearingMessages()) { DropdownMenuItem(onClick = {}) { Text(i18n("contacts.dropdown.disappearing"), style = MaterialTheme.typography.body2) } @@ -76,7 +74,7 @@ fun ContactDropDown( DropdownMenuItem(onClick = { close(); onDeleteAllMessages() }) { Text(i18n("contacts.dropdown.delete.all"), style = MaterialTheme.typography.body2) } - if (desktopFeatureFlags.shouldEnableTransportSettings()) { + if (configuration.shouldEnableTransportSettings()) { DropdownMenuItem(onClick = { setState(State.CONNECTION) }) { Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) { Text( diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/navigation/BriarSidebar.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/navigation/BriarSidebar.kt index a9c17ba486bdb89c157ad0bce81c9b44d809599c..513d76f55973edf25459214ee3bd2ff2d254ed3f 100644 --- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/navigation/BriarSidebar.kt +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/navigation/BriarSidebar.kt @@ -28,6 +28,14 @@ import androidx.compose.foundation.selection.selectableGroup import androidx.compose.material.IconButton import androidx.compose.material.MaterialTheme import androidx.compose.material.Surface +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ChromeReaderMode +import androidx.compose.material.icons.filled.Contacts +import androidx.compose.material.icons.filled.Forum +import androidx.compose.material.icons.filled.Group +import androidx.compose.material.icons.filled.Info +import androidx.compose.material.icons.filled.Settings +import androidx.compose.material.icons.filled.WifiTethering import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -38,7 +46,7 @@ import org.briarproject.briar.desktop.contact.ProfileCircle import org.briarproject.briar.desktop.theme.sidebarSurface import org.briarproject.briar.desktop.ui.UiMode import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n -import org.briarproject.briar.desktop.utils.getDesktopFeatureFlags +import org.briarproject.briar.desktop.utils.getConfiguration val SIDEBAR_WIDTH = 56.dp @@ -69,33 +77,27 @@ fun BriarSidebar( account?.let { ProfileCircle(size = 45.dp, it.id.bytes) } } val modes = buildList { - add(UiMode.CONTACTS) - val featureFlags = getDesktopFeatureFlags() - if (featureFlags.shouldEnablePrivateGroups()) add(UiMode.GROUPS) - if (featureFlags.shouldEnableForums()) add(UiMode.FORUMS) - if (featureFlags.shouldEnableBlogs()) add(UiMode.BLOGS) + add(Pair(UiMode.CONTACTS, Icons.Filled.Contacts)) + val configuration = getConfiguration() + if (configuration.shouldEnablePrivateGroups()) add(Pair(UiMode.GROUPS, Icons.Filled.Group)) + if (configuration.shouldEnableForums()) add(Pair(UiMode.FORUMS, Icons.Filled.Forum)) + if (configuration.shouldEnableBlogs()) add(Pair(UiMode.BLOGS, Icons.Filled.ChromeReaderMode)) } - modes.forEach { mode -> - BriarSidebarButton( - currentMode = uiMode, - mode = mode, - setUiMode = setUiMode, - ) + modes.forEach { (mode, icon) -> + displayButton(uiMode, mode, icon) } } Column(verticalArrangement = Arrangement.Bottom) { val modes = buildList { - val featureFlags = getDesktopFeatureFlags() - if (featureFlags.shouldEnableTransportSettings()) add(UiMode.TRANSPORTS) - add(UiMode.SETTINGS) - add(UiMode.ABOUT) - } - modes.forEach { mode -> - BriarSidebarButton( - currentMode = uiMode, - mode = mode, - setUiMode = setUiMode, + val configuration = getConfiguration() + if (configuration.shouldEnableTransportSettings()) add( + Pair(UiMode.TRANSPORTS, Icons.Filled.WifiTethering) ) + add(Pair(UiMode.SETTINGS, Icons.Filled.Settings)) + add(Pair(UiMode.ABOUT, Icons.Filled.Info)) + } + modes.forEach { (mode, icon) -> + displayButton(uiMode, mode, icon) } } } 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 new file mode 100644 index 0000000000000000000000000000000000000000..aa042a5aa487757435932848e0a9db245c9525cb --- /dev/null +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/settings/Configuration.kt @@ -0,0 +1,24 @@ +/* + * 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.FeatureFlags +import org.briarproject.briar.desktop.DesktopFeatureFlags + +interface Configuration : UnencryptedSettingsReadOnly, 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 new file mode 100644 index 0000000000000000000000000000000000000000..db7eabe9d80537dfa2efa114c5105d4aad78e913 --- /dev/null +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/settings/ConfigurationImpl.kt @@ -0,0 +1,33 @@ +/* + * 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.FeatureFlags +import org.briarproject.briar.desktop.DesktopFeatureFlags +import javax.inject.Inject + +class ConfigurationImpl +@Inject internal constructor( + unencryptedSettings: UnencryptedSettingsReadOnly, + featureFlags: FeatureFlags, + desktopFeatureFlags: DesktopFeatureFlags, +) : Configuration, + UnencryptedSettingsReadOnly by unencryptedSettings, + FeatureFlags by featureFlags, + DesktopFeatureFlags by desktopFeatureFlags diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/settings/UnencryptedSettings.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/settings/UnencryptedSettings.kt index 0f12e8d35146807953f4a420b4d46563d7351c4c..650ed7e3dbe31f63909379d3ae4c8730123f93a5 100644 --- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/settings/UnencryptedSettings.kt +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/settings/UnencryptedSettings.kt @@ -21,7 +21,14 @@ package org.briarproject.briar.desktop.settings import org.briarproject.briar.desktop.viewmodel.SingleStateEvent import java.util.Locale -interface UnencryptedSettings { +interface UnencryptedSettingsReadOnly { + val theme: UnencryptedSettings.Theme + val language: UnencryptedSettings.Language + + val invalidateScreen: SingleStateEvent<Unit> +} + +interface UnencryptedSettings : UnencryptedSettingsReadOnly { enum class Theme { AUTO, LIGHT, DARK } @@ -38,8 +45,8 @@ interface UnencryptedSettings { else Locale.forLanguageTag(name.replace('_', '-')) } - var theme: Theme - var language: Language + override var theme: Theme + override var language: Language - val invalidateScreen: SingleStateEvent<Unit> + override val invalidateScreen: SingleStateEvent<Unit> } 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 771eb54199f66ade28f329aca9a22a7cd4aff519..772973ce264e6a913d3ae780eb3a211f745a6329 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 @@ -40,20 +40,18 @@ import androidx.compose.ui.platform.PlatformLocalization import androidx.compose.ui.res.painterResource import androidx.compose.ui.window.FrameWindowScope import androidx.compose.ui.window.Window -import org.briarproject.bramble.api.FeatureFlags import org.briarproject.bramble.api.event.EventBus import org.briarproject.bramble.api.event.EventListener import org.briarproject.bramble.api.lifecycle.LifecycleManager import org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.RUNNING import org.briarproject.bramble.api.lifecycle.event.LifecycleEvent import org.briarproject.briar.api.conversation.event.ConversationMessageReceivedEvent -import org.briarproject.briar.desktop.DesktopFeatureFlags import org.briarproject.briar.desktop.conversation.ConversationMessagesReadEvent import org.briarproject.briar.desktop.expiration.ExpirationBanner import org.briarproject.briar.desktop.login.ErrorScreen import org.briarproject.briar.desktop.login.StartupScreen import org.briarproject.briar.desktop.notification.NotificationProvider -import org.briarproject.briar.desktop.settings.UnencryptedSettings +import org.briarproject.briar.desktop.settings.Configuration import org.briarproject.briar.desktop.settings.UnencryptedSettings.Theme.AUTO import org.briarproject.briar.desktop.settings.UnencryptedSettings.Theme.DARK import org.briarproject.briar.desktop.theme.BriarTheme @@ -85,8 +83,7 @@ interface BriarUi { val LocalWindowScope = staticCompositionLocalOf<FrameWindowScope?> { null } val LocalViewModelProvider = staticCompositionLocalOf<ViewModelProvider?> { null } -val LocalCoreFeatureFlags = staticCompositionLocalOf<FeatureFlags?> { null } -val LocalDesktopFeatureFlags = staticCompositionLocalOf<DesktopFeatureFlags?> { null } +val LocalConfiguration = staticCompositionLocalOf<Configuration?> { null } @Immutable @Singleton @@ -96,9 +93,7 @@ constructor( private val lifecycleManager: LifecycleManager, private val eventBus: EventBus, private val viewModelProvider: ViewModelProvider, - private val unencryptedSettings: UnencryptedSettings, - private val featureFlags: FeatureFlags, - private val desktopFeatureFlags: DesktopFeatureFlags, + private val configuration: Configuration, private val notificationProvider: NotificationProvider, ) : BriarUi { @@ -147,6 +142,7 @@ constructor( when (e) { is LifecycleEvent -> if (e.lifecycleState == RUNNING) screenState = MAIN + is ConversationMessageReceivedEvent<*> -> { messageCount++ if (!focusState.focused) { @@ -154,6 +150,7 @@ constructor( notificationProvider.notifyPrivateMessages(messageCount) } } + is ConversationMessagesReadEvent -> { messageCount -= e.count if (messageCount < 0) messageCount = 0 @@ -187,18 +184,17 @@ constructor( LocalWindowScope provides this, LocalWindowFocusState provides focusState, LocalViewModelProvider provides viewModelProvider, - LocalCoreFeatureFlags provides featureFlags, - LocalDesktopFeatureFlags provides desktopFeatureFlags, + LocalConfiguration provides configuration, LocalLocalization provides platformLocalization, ) { // invalidate whole application window in case the theme or language setting is changed - unencryptedSettings.invalidateScreen.react { + configuration.invalidateScreen.react { window.title = i18n("main.title") return@CompositionLocalProvider } - val isDarkTheme = unencryptedSettings.theme == DARK || - (unencryptedSettings.theme == AUTO && isSystemInDarkTheme()) + val isDarkTheme = configuration.theme == DARK || + (configuration.theme == AUTO && isSystemInDarkTheme()) BriarTheme(isDarkTheme) { Column(Modifier.fillMaxSize()) { ExpirationBanner { screenState = EXPIRED; stop() } diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/utils/FeatureFlagUtils.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/utils/LocalCompositionProviderUtils.kt similarity index 65% rename from briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/utils/FeatureFlagUtils.kt rename to briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/utils/LocalCompositionProviderUtils.kt index fafde86be2153b515347264fa185ddc58dc6fd66..c3dbf00efd0b7a4260c73f3ab644f8350d84dc64 100644 --- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/utils/FeatureFlagUtils.kt +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/utils/LocalCompositionProviderUtils.kt @@ -19,15 +19,9 @@ package org.briarproject.briar.desktop.utils import androidx.compose.runtime.Composable -import org.briarproject.briar.desktop.ui.LocalCoreFeatureFlags -import org.briarproject.briar.desktop.ui.LocalDesktopFeatureFlags +import org.briarproject.briar.desktop.ui.LocalConfiguration @Composable -fun getCoreFeatureFlags() = checkNotNull(LocalCoreFeatureFlags.current) { - "No FeatureFlags was provided via LocalCoreFeatureFlags" // NON-NLS -} - -@Composable -fun getDesktopFeatureFlags() = checkNotNull(LocalDesktopFeatureFlags.current) { - "No DesktopFeatureFlags was provided via LocalDesktopFeatureFlags" // NON-NLS +fun getConfiguration() = checkNotNull(LocalConfiguration.current) { + "No configuration was provided via LocalConfiguration" // NON-NLS } 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 6fb2ca9fbc30cdd8a11ff89cd067b97838e173d4..84250542eccd0512a5e1bd50ac1308f8b0ffaa65 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 @@ -56,8 +56,11 @@ import org.briarproject.briar.desktop.attachment.media.ImageCompressorImpl import org.briarproject.briar.desktop.notification.NotificationProvider 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.UnencryptedSettings import org.briarproject.briar.desktop.settings.UnencryptedSettingsImpl +import org.briarproject.briar.desktop.settings.UnencryptedSettingsReadOnly import org.briarproject.briar.desktop.testdata.DeterministicTestDataCreator import org.briarproject.briar.desktop.testdata.DeterministicTestDataCreatorImpl import org.briarproject.briar.desktop.testdata.TestAvatarCreatorImpl @@ -111,6 +114,11 @@ internal class DesktopTestModule( return DesktopDatabaseConfig(dbDir, keyDir) } + @Provides + @Singleton + // provide [UnencryptedSettings] singleton itself as provided above to use same object + fun provideUnencryptedSettingsReadOnly(settings: UnencryptedSettings): UnencryptedSettingsReadOnly = settings + @Provides @Singleton fun provideUnencryptedSettings(settings: UnencryptedSettingsImpl): UnencryptedSettings = settings @@ -177,6 +185,10 @@ internal class DesktopTestModule( override fun shouldEnableTransportSettings() = false } + @Provides + @Singleton + fun provideConfiguration(configuration: ConfigurationImpl): Configuration = configuration + @Provides @Singleton internal fun provideImageCompressor(imageCompressor: ImageCompressorImpl): ImageCompressor {