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 7910e6e892d6943f9f2d777aedee30d570be6955..4ef92218c627af94da70721184480b06a74325cf 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 @@ -18,8 +18,11 @@ package org.briarproject.briar.desktop.navigation +import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background +import androidx.compose.foundation.border import androidx.compose.foundation.layout.Arrangement.Absolute.spacedBy +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxHeight @@ -29,6 +32,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.selection.selectableGroup +import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.Badge import androidx.compose.material.BadgedBox import androidx.compose.material.Icon @@ -38,15 +42,22 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Error import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment +import androidx.compose.ui.Alignment.Companion.BottomEnd import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.unit.dp -import org.briarproject.bramble.api.identity.LocalAuthor +import org.briarproject.bramble.api.identity.Author +import org.briarproject.bramble.api.plugin.Plugin import org.briarproject.briar.desktop.contact.ProfileCircle import org.briarproject.briar.desktop.navigation.SidebarButtonState.None import org.briarproject.briar.desktop.navigation.SidebarButtonState.UnreadMessages import org.briarproject.briar.desktop.navigation.SidebarButtonState.Warning +import org.briarproject.briar.desktop.theme.Lime500 +import org.briarproject.briar.desktop.theme.Orange500 +import org.briarproject.briar.desktop.theme.outline import org.briarproject.briar.desktop.theme.sidebarSurface +import org.briarproject.briar.desktop.ui.Tooltip import org.briarproject.briar.desktop.ui.UiMode import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n import org.briarproject.briar.desktop.utils.getConfiguration @@ -55,10 +66,11 @@ val SIDEBAR_WIDTH = 56.dp @Composable fun BriarSidebar( - account: LocalAuthor?, + account: Author?, uiMode: UiMode, setUiMode: (UiMode) -> Unit, messageCount: SidebarViewModel.MessageCount, + torPluginState: Plugin.State, hasMailboxProblem: Boolean, ) { @Composable @@ -83,7 +95,7 @@ fun BriarSidebar( horizontalAlignment = Alignment.CenterHorizontally, ) { // profile button - account?.let { ProfileCircle(size = 45.dp, it.id.bytes) } + SideBarAvatar(account, torPluginState) Spacer(Modifier.height(4.dp)) @@ -108,6 +120,36 @@ fun BriarSidebar( } } +@Composable +@OptIn(ExperimentalFoundationApi::class) +private fun SideBarAvatar(account: Author?, torPluginState: Plugin.State) = Box { + ProfileCircle(size = 45.dp, account?.id?.bytes ?: ByteArray(0)) + Tooltip( + text = torPluginState.getString(), + modifier = Modifier.align(BottomEnd), + ) { + Box( + modifier = Modifier + .size(16.dp) + .border(1.dp, MaterialTheme.colors.outline, CircleShape) + .background(torPluginState.getIconColor(), CircleShape) + ) + } +} + +@Composable +private fun Plugin.State.getIconColor(): Color { + return if (this == Plugin.State.ACTIVE) Lime500 + else if (this == Plugin.State.ENABLING) Orange500 + else MaterialTheme.colors.sidebarSurface +} + +private fun Plugin.State.getString(): String { + return if (this == Plugin.State.ACTIVE) i18n("transports.tor.active") + else if (this == Plugin.State.ENABLING) i18n("transports.tor.enabling") + else i18n("transports.tor.inactive") +} + sealed class SidebarButtonState { object None : SidebarButtonState() class UnreadMessages(val messageCount: Int) : SidebarButtonState() diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/navigation/SidebarViewModel.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/navigation/SidebarViewModel.kt index d8f6441bf6268d367fe10dc77738e281671c297e..d9daf76bea903da35b64fcb0f673e3679fe36b61 100644 --- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/navigation/SidebarViewModel.kt +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/navigation/SidebarViewModel.kt @@ -22,9 +22,14 @@ import androidx.compose.runtime.mutableStateOf import org.briarproject.bramble.api.event.Event import org.briarproject.bramble.api.event.EventBus import org.briarproject.bramble.api.event.EventListener +import org.briarproject.bramble.api.identity.Author import org.briarproject.bramble.api.identity.IdentityManager -import org.briarproject.bramble.api.identity.LocalAuthor import org.briarproject.bramble.api.mailbox.event.MailboxProblemEvent +import org.briarproject.bramble.api.plugin.Plugin +import org.briarproject.bramble.api.plugin.PluginManager +import org.briarproject.bramble.api.plugin.TorConstants +import org.briarproject.bramble.api.plugin.TransportId +import org.briarproject.bramble.api.plugin.event.TransportStateEvent import org.briarproject.briar.desktop.threading.UiExecutor import org.briarproject.briar.desktop.ui.MessageCounter import org.briarproject.briar.desktop.ui.MessageCounterData @@ -43,10 +48,14 @@ class SidebarViewModel constructor( private val identityManager: IdentityManager, private val messageCounter: MessageCounter, + private val pluginManager: PluginManager, private val eventBus: EventBus, ) : EventListener, ViewModel() { private var listensToEventBus = false + private val _torPluginState = mutableStateOf(getTransportState(TorConstants.ID)) + val torPluginState = _torPluginState.asState() + override fun onInit() { super.onInit() if (!listensToEventBus) { @@ -64,6 +73,7 @@ constructor( override fun eventOccurred(e: Event) { if (e is MailboxProblemEvent) _mailboxProblem.value = true + else if (e is TransportStateEvent && e.transportId == TorConstants.ID) _torPluginState.value = e.state } private fun onMessageCounterUpdated(data: MessageCounterData) { @@ -77,7 +87,7 @@ constructor( } private val _uiMode = mutableStateOf(UiMode.CONTACTS) - private val _account = mutableStateOf<LocalAuthor?>(null) + private val _account = mutableStateOf<Author?>(null) private val _mailboxProblem = mutableStateOf(false) private val _messageCount = mutableStateOf(MessageCount()) @@ -99,6 +109,11 @@ constructor( _account.value = identityManager.localAuthor } + private fun getTransportState(id: TransportId): Plugin.State { + val plugin = pluginManager.getPlugin(id) + return if (plugin == null) Plugin.State.STARTING_STOPPING else plugin.state + } + data class MessageCount( val privateMessages: Int = 0, val forumPosts: Int = 0, diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/MainScreen.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/MainScreen.kt index 549f6b401c4403278b79e2ec668b8589aeffe3f2..4581a8b47468168fb0410dd1cc315d47ceecded0 100644 --- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/MainScreen.kt +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/MainScreen.kt @@ -54,11 +54,12 @@ fun MainScreen(viewModel: SidebarViewModel = viewModel()) { CompositionLocalProvider(LocalInfoDrawerHandler provides drawerHandler) { Row { BriarSidebar( - viewModel.account.value, - viewModel.uiMode.value, - viewModel::setUiMode, - viewModel.messageCount.value, - viewModel.mailboxProblem.value, + account = viewModel.account.value, + uiMode = viewModel.uiMode.value, + setUiMode = viewModel::setUiMode, + messageCount = viewModel.messageCount.value, + torPluginState = viewModel.torPluginState.value, + hasMailboxProblem = viewModel.mailboxProblem.value, ) VerticalDivider() when (viewModel.uiMode.value) { diff --git a/briar-desktop/src/main/resources/strings/BriarDesktop.properties b/briar-desktop/src/main/resources/strings/BriarDesktop.properties index a20067d11ad39f4b787426b24ce7e63cd07a2407..586d68d73fa3c6fda01c0a637be177b13ade2245 100644 --- a/briar-desktop/src/main/resources/strings/BriarDesktop.properties +++ b/briar-desktop/src/main/resources/strings/BriarDesktop.properties @@ -322,6 +322,11 @@ main.help.tor.port.control=Tor Control Port welcome.title=Welcome to Briar welcome.text=You don't have any contacts yet. Tap the + icon to add a contact: +# Transports +transports.tor.active=Briar is connected to the Internet +transports.tor.inactive=Briar can\'t connect to the Internet +transports.tor.enabling=Briar is connecting to the Internet + # About about.category.general=General about.category.dependencies=Dependencies