diff --git a/briar-desktop/src/main/kotlin/androidx/compose/material/IconButtonExt.kt b/briar-desktop/src/main/kotlin/androidx/compose/material/IconButtonExt.kt
new file mode 100644
index 0000000000000000000000000000000000000000..d6619e0d021a881cbe8b6ad6c9a498cb694d8b53
--- /dev/null
+++ b/briar-desktop/src/main/kotlin/androidx/compose/material/IconButtonExt.kt
@@ -0,0 +1,97 @@
+/*
+ * 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 .
+ */
+
+package androidx.compose.material
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.TooltipArea
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.shadow
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+
+/**
+ * IconButton is a clickable icon, used to represent actions. An IconButton has an overall minimum
+ * touch target size of 48 x 48dp, to meet accessibility guidelines.
+ * This version of [IconButton] enables tooltips on Desktop Devices and internally uses an [Icon] to show [icon].
+ *
+ * @param icon [ImageVector] to draw as icon inside this IconButton
+ * @param contentDescription text used by accessibility services and the tooltip
+ * to describe the action invoked by this IconButton.
+ * @param onClick the lambda to be invoked when this icon is pressed
+ * @param modifier optional [Modifier] for this IconButton
+ * @param iconTint tint to be applied to [icon]. See [Icon] for more information.
+ * @param enabled whether or not this IconButton will handle input events and appear enabled for
+ * semantics purposes
+ * @param interactionSource the [MutableInteractionSource] representing the stream of
+ * [Interaction]s for this IconButton. You can create and pass in your own remembered
+ * [MutableInteractionSource] if you want to observe [Interaction]s and customize the
+ * appearance / behavior of this IconButton in different [Interaction]s.
+ * @param extraContent content that is added after the [icon]. This is mainly used for showing [DropdownMenu]s.
+ */
+@OptIn(ExperimentalFoundationApi::class)
+@Composable
+fun IconButton(
+ icon: ImageVector,
+ contentDescription: String,
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+ iconSize: Dp = 24.dp,
+ iconTint: Color = LocalContentColor.current.copy(alpha = LocalContentAlpha.current),
+ enabled: Boolean = true,
+ interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+ extraContent: (@Composable () -> Unit)? = null
+) = TooltipArea(
+ tooltip = {
+ Surface(
+ modifier = Modifier.shadow(4.dp),
+ shape = RoundedCornerShape(4.dp),
+ ) {
+ Text(
+ text = contentDescription,
+ modifier = Modifier.padding(4.dp)
+ )
+ }
+ },
+ // taken from https://ux.stackexchange.com/questions/358/how-long-should-the-delay-be-before-a-tooltip-pops-up
+ delayMillis = 500,
+ modifier = modifier
+) {
+ IconButton(
+ onClick = onClick,
+ enabled = enabled,
+ interactionSource = interactionSource
+ ) {
+ Icon(
+ icon,
+ contentDescription,
+ Modifier.size(iconSize),
+ iconTint
+ )
+ extraContent?.invoke()
+ }
+}
diff --git a/briar-desktop/src/main/kotlin/androidx/compose/material/OutlinedTextFieldExt.kt b/briar-desktop/src/main/kotlin/androidx/compose/material/OutlinedTextFieldExt.kt
index d2defb118f2a555ff0f74e30b06fb92be6f03e3f..bdcf40982561e41f354744b73443bb4ed069292e 100644
--- a/briar-desktop/src/main/kotlin/androidx/compose/material/OutlinedTextFieldExt.kt
+++ b/briar-desktop/src/main/kotlin/androidx/compose/material/OutlinedTextFieldExt.kt
@@ -228,20 +228,8 @@ fun OutlinedPasswordTextField(
private fun ShowHidePasswordIcon(
isVisible: Boolean,
toggleIsVisible: () -> Unit,
-) {
- IconButton(
- onClick = toggleIsVisible
- ) {
- if (isVisible) {
- Icon(
- imageVector = Icons.Filled.VisibilityOff,
- contentDescription = i18n("access.password.show"),
- )
- } else {
- Icon(
- imageVector = Icons.Filled.Visibility,
- contentDescription = i18n("access.password.hide"),
- )
- }
- }
-}
+) = IconButton(
+ icon = if (isVisible) Icons.Filled.VisibilityOff else Icons.Filled.Visibility,
+ contentDescription = if (isVisible) i18n("access.password.hide") else i18n("access.password.show"),
+ onClick = toggleIsVisible
+)
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactCard.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactCard.kt
index 0e98b2bb6f26449763a98af6a3e678ec59d7eb70..73772d5611d06d8060fb4e34eaf4e093439e7cb3 100644
--- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactCard.kt
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactCard.kt
@@ -32,7 +32,6 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Card
-import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
@@ -161,11 +160,11 @@ private fun PendingContactRow(contactItem: PendingContactItem, onRemove: () -> U
)
}
IconButton(
+ icon = Icons.Filled.Delete,
+ contentDescription = i18n("access.contacts.pending.remove"),
onClick = onRemove,
modifier = Modifier.padding(end = 4.dp).align(Alignment.CenterVertically)
- ) {
- Icon(Icons.Filled.Delete, i18n("access.contacts.pending.remove"))
- }
+ )
}
}
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/SearchTextField.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/SearchTextField.kt
index fa7db6ab6e46d5e49c41236cd4462320dee3d9f9..1d32ffc4ca6c1039454f5bac0b17d6dc908e83d8 100644
--- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/SearchTextField.kt
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/SearchTextField.kt
@@ -20,7 +20,6 @@ package org.briarproject.briar.desktop.contact
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Icon
import androidx.compose.material.LocalTextStyle
@@ -53,15 +52,12 @@ fun SearchTextField(searchValue: String, onValueChange: (String) -> Unit, onCont
},
trailingIcon = {
ColoredIconButton(
+ icon = Icons.Filled.PersonAdd,
+ iconSize = 20.dp,
+ contentDescription = i18n("access.contacts.add"),
onClick = onContactAdd,
modifier = Modifier.padding(end = 8.dp)
- ) {
- Icon(
- Icons.Filled.PersonAdd,
- i18n("access.contacts.add"),
- modifier = Modifier.size(20.dp)
- )
- }
+ )
},
modifier = Modifier.fillMaxSize()
)
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/add/remote/AddContactDialog.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/add/remote/AddContactDialog.kt
index c497b390ef051a91ce401ae6b567e78cfc3d5d32..aab5f86a7dc9555cfee3de2c04009555f84caadd 100644
--- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/add/remote/AddContactDialog.kt
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/add/remote/AddContactDialog.kt
@@ -362,7 +362,7 @@ fun OwnLink(
}
}
-@OptIn(ExperimentalFoundationApi::class, ExperimentalComposeUiApi::class)
+@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun ContactLink(
remoteHandshakeLink: String,
@@ -394,55 +394,32 @@ fun ContactLink(
letterSpacing = (-0.5).sp,
),
trailingIcon = {
- TooltipArea(
- tooltip = {
- Surface(
- modifier = Modifier.shadow(4.dp),
- shape = RoundedCornerShape(4.dp),
- ) {
- Text(
- text = i18n("contact.add.remote.paste_tooltip"),
- modifier = Modifier.padding(8.dp),
- color = MaterialTheme.colors.onSurface,
- )
+ IconButton(
+ icon = Icons.Filled.ContentPaste,
+ iconTint = MaterialTheme.colors.onSurface,
+ contentDescription = i18n("contact.add.remote.paste_tooltip"),
+ onClick = {
+ val clipboardText = clipboardManager.getText().toString()
+ if (clipboardText.isNotEmpty()) {
+ setRemoteHandshakeLink(clipboardManager.getText().toString())
+ coroutineScope.launch {
+ scaffoldState.snackbarHostState.showSnackbar(
+ message = i18n("contact.add.remote.link_pasted_snackbar"),
+ duration = SnackbarDuration.Short,
+ )
+ }
+ aliasFocusRequester.requestFocus()
+ } else {
+ coroutineScope.launch {
+ scaffoldState.snackbarHostState.showSnackbar(
+ message = i18n("contact.add.remote.paste_error_snackbar"),
+ duration = SnackbarDuration.Short,
+ )
+ }
}
},
- modifier = Modifier.padding(start = 30.dp),
- delayMillis = 200,
- tooltipPlacement = TooltipPlacement.ComponentRect(
- alignment = Alignment.BottomCenter,
- )
- ) {
- IconButton(
- {
- val clipboardText = clipboardManager.getText().toString()
- if (clipboardText.isNotEmpty()) {
- setRemoteHandshakeLink(clipboardManager.getText().toString())
- coroutineScope.launch {
- scaffoldState.snackbarHostState.showSnackbar(
- message = i18n("contact.add.remote.link_pasted_snackbar"),
- duration = SnackbarDuration.Short,
- )
- }
- aliasFocusRequester.requestFocus()
- } else {
- coroutineScope.launch {
- scaffoldState.snackbarHostState.showSnackbar(
- message = i18n("contact.add.remote.paste_error_snackbar"),
- duration = SnackbarDuration.Short,
- )
- }
- }
- },
- Modifier.pointerHoverIcon(PointerIconDefaults.Default)
- ) {
- Icon(
- Icons.Filled.ContentPaste,
- "contact.add.remote.paste_tooltip",
- tint = MaterialTheme.colors.onSurface
- )
- }
- }
+ modifier = Modifier.pointerHoverIcon(PointerIconDefaults.Default)
+ )
}
)
}
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationHeader.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationHeader.kt
index a161b184b35a2ee179923fb6024bd90fbfff5fe7..eb6d737b942254902cd17f1688fdb8c45d2ae0ff 100644
--- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationHeader.kt
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationHeader.kt
@@ -26,8 +26,6 @@ import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
-import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
@@ -92,10 +90,11 @@ fun ConversationHeader(
)
}
IconButton(
+ icon = Icons.Filled.MoreVert,
+ contentDescription = i18n("access.contact.menu"),
onClick = { setMenuState(ContactDropDown.State.MAIN) },
modifier = Modifier.align(Alignment.CenterVertically).padding(end = 16.dp)
) {
- Icon(Icons.Filled.MoreVert, i18n("access.contact.menu"), modifier = Modifier.size(24.dp))
ContactDropDown(
menuState,
setMenuState,
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationInput.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationInput.kt
index ca555805176a263cca0b087ff4ee40e8be49f182..1787696cd4793c265fb8b2d21a18b104907d6969 100644
--- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationInput.kt
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationInput.kt
@@ -27,7 +27,6 @@ import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.AlertDialog
import androidx.compose.material.ExperimentalMaterialApi
-import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
@@ -115,6 +114,8 @@ fun ConversationInput(
leadingIcon = {
val windowScope = LocalWindowScope.current!!
ColoredIconButton(
+ icon = if (image == null) Icons.Filled.Add else Icons.Filled.Close,
+ contentDescription = if (image == null) i18n("access.attachment_add") else i18n("access.attachment_remove"),
onClick = {
if (image == null) {
pickImageUsingDialog(windowScope.window, updateImage)
@@ -122,27 +123,17 @@ fun ConversationInput(
updateImage(null)
}
},
- Modifier.padding(4.dp),
- ) {
- if (image == null) {
- Icon(Icons.Filled.Add, i18n("access.attachment_add"), Modifier.size(24.dp))
- } else {
- Icon(Icons.Filled.Close, i18n("access.attachment_remove"), Modifier.size(24.dp))
- }
- }
+ modifier = Modifier.padding(4.dp),
+ )
},
trailingIcon = {
IconButton(
+ icon = Icons.Filled.Send,
+ iconTint = MaterialTheme.colors.sendButton,
+ contentDescription = i18n("access.message.send"),
onClick = onSend,
modifier = Modifier.padding(4.dp).size(32.dp).pointerHoverIcon(PointerIconDefaults.Default),
- ) {
- Icon(
- Icons.Filled.Send,
- i18n("access.message.send"),
- tint = MaterialTheme.colors.sendButton,
- modifier = Modifier.size(24.dp)
- )
- }
+ )
}
)
}
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/conversation/PrivateMessageScreen.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/conversation/PrivateMessageScreen.kt
index 1b374b6dc80e2c05342d6d3c4ab8da2031b0b400..67511a08d261cf4248df9a67f210356554ce04b8 100644
--- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/conversation/PrivateMessageScreen.kt
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/conversation/PrivateMessageScreen.kt
@@ -18,7 +18,6 @@
package org.briarproject.briar.desktop.conversation
-import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
@@ -28,9 +27,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.widthIn
-import androidx.compose.foundation.shape.CircleShape
-import androidx.compose.material.Icon
-import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
@@ -38,7 +34,6 @@ import androidx.compose.material.icons.filled.PersonAdd
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import org.briarproject.briar.desktop.contact.ConfirmRemovePendingContactDialog
@@ -49,6 +44,7 @@ import org.briarproject.briar.desktop.contact.RealContactIdWrapper
import org.briarproject.briar.desktop.contact.add.remote.AddContactDialog
import org.briarproject.briar.desktop.contact.add.remote.AddContactViewModel
import org.briarproject.briar.desktop.ui.BriarLogo
+import org.briarproject.briar.desktop.ui.ColoredIconButton
import org.briarproject.briar.desktop.ui.Constants.PARAGRAPH_WIDTH
import org.briarproject.briar.desktop.ui.VerticalDivider
import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n
@@ -104,18 +100,12 @@ fun NoContactsYet(onContactAdd: () -> Unit) = Explainer(
headline = i18n("welcome.title"),
text = i18n("welcome.text"),
) {
- IconButton(
+ ColoredIconButton(
+ icon = Icons.Filled.PersonAdd,
+ iconSize = 20.dp,
+ contentDescription = i18n("access.contacts.add"),
onClick = onContactAdd,
- modifier = Modifier.padding(end = 10.dp).size(32.dp)
- .background(MaterialTheme.colors.primary, CircleShape)
- ) {
- Icon(
- Icons.Filled.PersonAdd,
- i18n("access.contacts.add"),
- tint = Color.White,
- modifier = Modifier.size(20.dp)
- )
- }
+ )
}
@Composable
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/expiration/ExpirationBanner.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/expiration/ExpirationBanner.kt
index a2b206d18a77939f1bc1702b0ce5bb42b95355cf..78a179ea7829394a66f4b71d8c8bcb6ab7f99d69 100644
--- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/expiration/ExpirationBanner.kt
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/expiration/ExpirationBanner.kt
@@ -108,8 +108,11 @@ fun ExpirationBanner(
style = MaterialTheme.typography.body2,
modifier = Modifier.weight(1f, true).padding(vertical = 12.dp)
)
- IconButton(hide, modifier = Modifier.padding(vertical = 4.dp)) {
- Icon(Icons.Filled.Close, i18n("hide"), Modifier.size(24.dp))
- }
+ IconButton(
+ icon = Icons.Filled.Close,
+ contentDescription = i18n("hide"),
+ onClick = hide,
+ modifier = Modifier.padding(vertical = 4.dp)
+ )
}
}
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/introduction/ContactDrawerMakeIntro.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/introduction/ContactDrawerMakeIntro.kt
index ea12210b752777f5bb4ea3b2f8658df28a536cbe..54b0b9ce8b2d99867dd01acd788e8b5b60aa5568 100644
--- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/introduction/ContactDrawerMakeIntro.kt
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/introduction/ContactDrawerMakeIntro.kt
@@ -70,11 +70,11 @@ fun ContactDrawerMakeIntro(
if (!viewModel.secondScreen.value) {
Row(Modifier.fillMaxWidth().height(HEADER_SIZE)) {
IconButton(
+ icon = Icons.Filled.Close,
+ contentDescription = i18n("access.introduction.close"),
onClick = { closeInfoDrawer(false) },
- Modifier.padding(start = 24.dp).size(24.dp).align(Alignment.CenterVertically)
- ) {
- Icon(Icons.Filled.Close, i18n("access.introduction.close"))
- }
+ modifier = Modifier.padding(start = 24.dp).size(24.dp).align(Alignment.CenterVertically)
+ )
Text(
text = i18nF("introduction.title_first", contactItem.displayName),
modifier = Modifier.align(Alignment.CenterVertically).padding(start = 16.dp),
@@ -97,11 +97,11 @@ fun ContactDrawerMakeIntro(
} else {
Row(Modifier.fillMaxWidth().height(HEADER_SIZE)) {
IconButton(
+ icon = Icons.Filled.ArrowBack,
+ contentDescription = i18n("access.introduction.back.contact"),
onClick = viewModel::backToFirstScreen,
- Modifier.padding(start = 24.dp).size(24.dp).align(Alignment.CenterVertically)
- ) {
- Icon(Icons.Filled.ArrowBack, i18n("access.introduction.back.contact"))
- }
+ modifier = Modifier.padding(start = 24.dp).size(24.dp).align(Alignment.CenterVertically)
+ )
Text(
text = i18n("introduction.title_second"),
modifier = Modifier.align(Alignment.CenterVertically).padding(start = 16.dp),
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/login/AboutSubViewModel.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/login/AboutSubViewModel.kt
new file mode 100644
index 0000000000000000000000000000000000000000..63e2bfc697bef2bae09448b4218dc340af0e4df6
--- /dev/null
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/login/AboutSubViewModel.kt
@@ -0,0 +1,23 @@
+/*
+ * 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 .
+ */
+
+package org.briarproject.briar.desktop.login
+
+class AboutSubViewModel(
+ val onBackButton: () -> Unit,
+) : StartupViewModel.SubViewModel
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/login/ErrorScreen.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/login/ErrorScreen.kt
index adf541b9120046b5674a6e68756611baab2b4c4d..3439a6694acf72a99d72702c1226e39bcd4f1d31 100644
--- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/login/ErrorScreen.kt
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/login/ErrorScreen.kt
@@ -53,6 +53,7 @@ import org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.DB_ER
import org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.SERVICE_ERROR
import org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.SUCCESS
import org.briarproject.briar.desktop.theme.Red500
+import org.briarproject.briar.desktop.ui.AboutScreen
import org.briarproject.briar.desktop.ui.Constants.STARTUP_FIELDS_WIDTH
import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n
import org.briarproject.briar.desktop.utils.PreviewUtils.preview
@@ -72,19 +73,17 @@ fun main() = preview {
}
}
- ErrorScreen(error, {}) {}
+ ErrorScreen(error) {}
}
@Composable
fun ErrorScreen(
- onShowAbout: () -> Unit,
viewHolder: ErrorSubViewModel
-) = ErrorScreen(viewHolder.error, onShowAbout, viewHolder.onBackButton)
+) = ErrorScreen(viewHolder.error, viewHolder.onBackButton)
@Composable
fun ErrorScreen(
error: ErrorSubViewModel.Error,
- onShowAbout: () -> Unit,
onBackButton: (() -> Unit)?,
) {
val text = when (error) {
@@ -101,45 +100,52 @@ fun ErrorScreen(
}
}
- ErrorScreen(text, onShowAbout, onBackButton)
+ ErrorScreen(text, onBackButton)
}
@Composable
fun ErrorScreen(
text: String,
- onShowAbout: () -> Unit,
onBackButton: (() -> Unit)? = null,
) = Box {
- Column(
- modifier = Modifier.fillMaxSize().padding(32.dp),
- horizontalAlignment = CenterHorizontally,
- verticalArrangement = spacedBy(32.dp)
- ) {
- Icon(
- imageVector = Icons.Filled.Error,
- contentDescription = i18n("error"),
- modifier = Modifier.size(128.dp),
- tint = Red500
- )
+ var showAbout by remember { mutableStateOf(false) }
- Text(i18n("sorry"), style = MaterialTheme.typography.h5)
- Text(
- text = text,
- style = MaterialTheme.typography.body1,
- modifier = Modifier.widthIn(max = STARTUP_FIELDS_WIDTH)
- )
- }
+ if (showAbout) {
+ AboutScreen { showAbout = false }
+ } else {
+ Column(
+ modifier = Modifier.fillMaxSize().padding(32.dp),
+ horizontalAlignment = CenterHorizontally,
+ verticalArrangement = spacedBy(32.dp)
+ ) {
+ Icon(
+ imageVector = Icons.Filled.Error,
+ contentDescription = i18n("error"),
+ modifier = Modifier.size(128.dp),
+ tint = Red500
+ )
- if (onBackButton != null) {
- IconButton(onClick = onBackButton) {
- Icon(Icons.Filled.ArrowBack, i18n("access.return_to_previous_screen"))
+ Text(i18n("sorry"), style = MaterialTheme.typography.h5)
+ Text(
+ text = text,
+ style = MaterialTheme.typography.body1,
+ modifier = Modifier.widthIn(max = STARTUP_FIELDS_WIDTH)
+ )
}
- }
- IconButton(
- onClick = onShowAbout,
- modifier = Modifier.align(Alignment.BottomStart)
- ) {
- Icon(Icons.Filled.Info, i18n("access.about_briar_desktop"))
+ if (onBackButton != null) {
+ IconButton(
+ icon = Icons.Filled.ArrowBack,
+ contentDescription = i18n("access.return_to_previous_screen"),
+ onClick = onBackButton
+ )
+ }
+
+ IconButton(
+ icon = Icons.Filled.Info,
+ contentDescription = i18n("access.mode.about"),
+ onClick = { showAbout = true },
+ modifier = Modifier.align(Alignment.BottomStart)
+ )
}
}
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/login/StartupScreen.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/login/StartupScreen.kt
index e03d14f2835de651b5392cd962f0a0248c59261f..122df268c848f34ab482997d1204da1b15139b16 100644
--- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/login/StartupScreen.kt
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/login/StartupScreen.kt
@@ -25,7 +25,6 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
-import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
@@ -38,19 +37,20 @@ import androidx.compose.ui.Alignment.Companion.CenterHorizontally
import androidx.compose.ui.Alignment.Companion.CenterVertically
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
+import org.briarproject.briar.desktop.ui.AboutScreen
import org.briarproject.briar.desktop.ui.BriarLogo
import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n
import org.briarproject.briar.desktop.viewmodel.viewModel
@Composable
fun StartupScreen(
- onShowAbout: () -> Unit,
viewModel: StartupViewModel = viewModel(),
) {
when (val holder = viewModel.currentSubViewModel.value) {
- is LoginSubViewModel -> LoginScreen(onShowAbout, holder)
- is RegistrationSubViewModel -> RegistrationScreen(onShowAbout, holder)
- is ErrorSubViewModel -> ErrorScreen(onShowAbout, holder)
+ is LoginSubViewModel -> LoginScreen(viewModel::showAbout, holder)
+ is RegistrationSubViewModel -> RegistrationScreen(viewModel::showAbout, holder)
+ is ErrorSubViewModel -> ErrorScreen(holder)
+ is AboutSubViewModel -> AboutScreen(holder.onBackButton)
}
}
@@ -72,19 +72,19 @@ fun StartupScreenScaffold(
if (showBackButton) {
IconButton(
+ icon = Icons.Filled.ArrowBack,
+ contentDescription = i18n("access.return_to_previous_screen"),
onClick = onBackButton,
modifier = Modifier.align(Alignment.TopStart)
- ) {
- Icon(Icons.Filled.ArrowBack, i18n("access.return_to_previous_screen"))
- }
+ )
}
IconButton(
+ icon = Icons.Filled.Info,
+ contentDescription = i18n("access.mode.about"),
onClick = onShowAbout,
modifier = Modifier.align(Alignment.BottomStart)
- ) {
- Icon(Icons.Filled.Info, i18n("access.about_briar_desktop"))
- }
+ )
}
@Composable
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/login/StartupViewModel.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/login/StartupViewModel.kt
index 21af167213a438998facd91090c13c9611617ad6..a51ba875fe9fb08d3097be14f36f8b11c970a438 100644
--- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/login/StartupViewModel.kt
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/login/StartupViewModel.kt
@@ -90,6 +90,13 @@ constructor(
_currentSubViewModel.value = makeError(error)
}
+ private fun makeAbout(previous: SubViewModel) =
+ AboutSubViewModel { _currentSubViewModel.value = previous }
+
+ fun showAbout() {
+ _currentSubViewModel.value = makeAbout(_currentSubViewModel.value)
+ }
+
override fun eventOccurred(e: Event) {
if (e is LifecycleEvent) _currentSubViewModel.value.lifecycleStateChanged(e.lifecycleState)
}
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 fe080e6eade164bfb2f7089b6dd4e1b83a62c82d..6d5bdd8b69b382c798525b3140778c56909ee140 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
@@ -23,20 +23,10 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
-import androidx.compose.material.Icon
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
@@ -56,17 +46,7 @@ fun BriarSidebar(
account: LocalAuthor?,
uiMode: UiMode,
setUiMode: (UiMode) -> Unit,
- showAbout: () -> Unit,
) {
- val displayButton = @Composable { selectedMode: UiMode, mode: UiMode, icon: ImageVector ->
- BriarSidebarButton(
- selectedMode == mode,
- { setUiMode(mode) },
- icon,
- mode.toString()
- )
- }
-
Surface(modifier = Modifier.width(SIDEBAR_WIDTH).fillMaxHeight(), color = MaterialTheme.colors.sidebarSurface) {
Column(verticalArrangement = Arrangement.Top) {
// profile button
@@ -75,45 +55,65 @@ fun BriarSidebar(
) {
account?.let { ProfileCircle(size = 45.dp, it.id.bytes) }
}
- val items = buildList {
- add(Pair(UiMode.CONTACTS, Icons.Filled.Contacts))
+ val modes = buildList {
+ add(UiMode.CONTACTS)
val featureFlags = getDesktopFeatureFlags()
- if (featureFlags.shouldEnablePrivateGroups()) add(Pair(UiMode.GROUPS, Icons.Filled.Group))
- if (featureFlags.shouldEnableForums()) add(Pair(UiMode.FORUMS, Icons.Filled.Forum))
- if (featureFlags.shouldEnableBlogs()) add(Pair(UiMode.BLOGS, Icons.Filled.ChromeReaderMode))
+ if (featureFlags.shouldEnablePrivateGroups()) add(UiMode.GROUPS)
+ if (featureFlags.shouldEnableForums()) add(UiMode.FORUMS)
+ if (featureFlags.shouldEnableBlogs()) add(UiMode.BLOGS)
}
- for ((mode, icon) in items) {
- displayButton(uiMode, mode, icon)
+ modes.forEach { mode ->
+ BriarSidebarButton(
+ currentMode = uiMode,
+ mode = mode,
+ setUiMode = setUiMode,
+ )
}
}
Column(verticalArrangement = Arrangement.Bottom) {
- val items = buildList {
+ val modes = buildList {
val featureFlags = getDesktopFeatureFlags()
- if (featureFlags.shouldEnableTransportSettings()) add(
- Pair(UiMode.TRANSPORTS, Icons.Filled.WifiTethering)
- )
- add(Pair(UiMode.SETTINGS, Icons.Filled.Settings))
+ if (featureFlags.shouldEnableTransportSettings()) add(UiMode.TRANSPORTS)
+ add(UiMode.SETTINGS)
+ add(UiMode.ABOUT)
}
- for ((mode, icon) in items) {
- displayButton(uiMode, mode, icon)
+ modes.forEach { mode ->
+ BriarSidebarButton(
+ currentMode = uiMode,
+ mode = mode,
+ setUiMode = setUiMode,
+ )
}
- BriarSidebarButton(
- selected = false,
- onClick = showAbout,
- icon = Icons.Filled.Info,
- contentDescription = i18n("access.about_briar_desktop")
- )
}
}
}
@Composable
-fun BriarSidebarButton(selected: Boolean, onClick: () -> Unit, icon: ImageVector, contentDescription: String?) {
+fun BriarSidebarButton(
+ mode: UiMode,
+ currentMode: UiMode,
+ setUiMode: (UiMode) -> Unit,
+) = BriarSidebarButton(
+ currentMode == mode,
+ { setUiMode(mode) },
+ mode.icon,
+ i18n(mode.contentDescriptionKey)
+)
+
+@Composable
+fun BriarSidebarButton(
+ selected: Boolean,
+ onClick: () -> Unit,
+ icon: ImageVector,
+ contentDescription: String,
+) {
val tint = if (selected) MaterialTheme.colors.primary else MaterialTheme.colors.onSurface
IconButton(
+ icon = icon,
+ iconSize = 30.dp,
+ iconTint = tint,
+ contentDescription = contentDescription,
+ onClick = onClick,
modifier = Modifier.padding(vertical = 4.dp, horizontal = 12.dp),
- onClick = onClick
- ) {
- Icon(icon, contentDescription, tint = tint, modifier = Modifier.size(30.dp))
- }
+ )
}
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/AboutDialog.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/AboutDialog.kt
deleted file mode 100644
index 5899d87ba3aa427a1a87305c6608aeff4239f598..0000000000000000000000000000000000000000
--- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/AboutDialog.kt
+++ /dev/null
@@ -1,128 +0,0 @@
-package org.briarproject.briar.desktop.ui
-
-import androidx.compose.foundation.VerticalScrollbar
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.IntrinsicSize
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.fillMaxHeight
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.requiredSize
-import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.foundation.lazy.items
-import androidx.compose.foundation.lazy.rememberLazyListState
-import androidx.compose.foundation.rememberScrollbarAdapter
-import androidx.compose.foundation.text.selection.SelectionContainer
-import androidx.compose.material.MaterialTheme
-import androidx.compose.material.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.text.style.TextOverflow
-import androidx.compose.ui.unit.dp
-import org.briarproject.briar.desktop.BuildData
-import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n
-import org.briarproject.briar.desktop.utils.PreviewUtils.preview
-import java.time.Instant
-import java.time.ZoneId
-import java.time.format.DateTimeFormatter
-
-@Suppress("HardCodedStringLiteral")
-fun main() = preview(
- "visible" to true,
-) {
- if (getBooleanParameter("visible")) {
- AboutDialog(
- onClose = { setBooleanParameter("visible", false) },
- )
- }
-}
-
-@Composable
-fun AboutDialog(
- onClose: () -> Unit,
-) {
- // sizes of the two columns
- val colSizes = listOf(0.3f, 0.7f)
-
- // format date
- val buildTime = Instant.ofEpochMilli(BuildData.GIT_TIME).atZone(ZoneId.systemDefault()).toLocalDateTime()
-
- // rows displayed in table
- val lines = buildList> {
- add(i18n("about.copyright") to "The Briar Project") // NON-NLS
- add(i18n("about.license") to "GNU Affero General Public License v3") // NON-NLS
- add(i18n("about.version") to BuildData.VERSION)
- add(i18n("about.version.core") to BuildData.CORE_VERSION)
- if (BuildData.GIT_BRANCH != null) add("Git branch" to BuildData.GIT_BRANCH) // NON-NLS
- if (BuildData.GIT_TAG != null) add("Git tag" to BuildData.GIT_TAG) // NON-NLS
- if (BuildData.GIT_BRANCH == null && BuildData.GIT_TAG == null) add("Git branch/tag" to "None detected") // NON-NLS
- add("Git hash" to BuildData.GIT_HASH) // NON-NLS
- add("Commit time" to DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(buildTime)) // NON-NLS
- add(i18n("about.website") to "https://briarproject.org")
- add(i18n("about.contact") to "desktop@briarproject.org") // NON-NLS
- }
-
- BriarDialog(onClose = onClose) {
- val box = this
- Column(
- modifier = Modifier.requiredSize(
- box.maxWidth.times(0.8f), box.maxHeight.times(0.8f)
- ).padding(16.dp)
- ) {
- Row(
- modifier = Modifier.padding(bottom = 8.dp).fillMaxWidth(),
- verticalAlignment = Alignment.CenterVertically,
- horizontalArrangement = Arrangement.Center
- ) {
- BriarLogo(modifier = Modifier.height(48.dp))
- Text(
- i18n("main.title"),
- style = MaterialTheme.typography.h4,
- modifier = Modifier.padding(start = 16.dp),
- overflow = TextOverflow.Ellipsis,
- maxLines = 1,
- )
- }
- val scrollState = rememberLazyListState()
- Box {
- LazyColumn(state = scrollState) {
- item {
- HorizontalDivider()
- }
- items(lines) { (key, value) ->
- // this is required for Divider between Boxes to have appropriate size
- Row(Modifier.fillMaxWidth().height(IntrinsicSize.Min)) {
- Box(modifier = Modifier.weight(colSizes[0]).fillMaxHeight()) {
- Text(
- text = key,
- modifier = Modifier.padding(horizontal = 8.dp)
- .padding(vertical = 8.dp).padding(end = 8.dp)
- .align(Alignment.CenterStart)
- )
- }
- VerticalDivider()
- Box(modifier = Modifier.weight(colSizes[1]).fillMaxHeight()) {
- SelectionContainer {
- Text(
- text = value,
- modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp)
- .padding(start = 8.dp)
- )
- }
- }
- }
- HorizontalDivider()
- }
- }
- VerticalScrollbar(
- adapter = rememberScrollbarAdapter(scrollState),
- modifier = Modifier.align(Alignment.CenterEnd).fillMaxHeight()
- )
- }
- }
- }
-}
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/AboutScreen.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/AboutScreen.kt
new file mode 100644
index 0000000000000000000000000000000000000000..113e670133c4ae1eca9ce4c02268036a0eb31184
--- /dev/null
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/AboutScreen.kt
@@ -0,0 +1,182 @@
+package org.briarproject.briar.desktop.ui
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.VerticalScrollbar
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.IntrinsicSize
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.items
+import androidx.compose.foundation.lazy.rememberLazyListState
+import androidx.compose.foundation.rememberScrollbarAdapter
+import androidx.compose.foundation.text.selection.SelectionContainer
+import androidx.compose.material.IconButton
+import androidx.compose.material.MaterialTheme
+import androidx.compose.material.Text
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.ArrowBack
+import androidx.compose.material.icons.filled.ContentCopy
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalClipboardManager
+import androidx.compose.ui.semantics.contentDescription
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.semantics.text
+import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.text.buildAnnotatedString
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.dp
+import org.briarproject.briar.desktop.BuildData
+import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n
+import org.briarproject.briar.desktop.utils.PreviewUtils.preview
+import java.time.Instant
+import java.time.ZoneId
+import java.time.format.DateTimeFormatter
+
+@Suppress("HardCodedStringLiteral")
+fun main() = preview(
+ "visible" to true,
+) {
+ if (getBooleanParameter("visible")) {
+ AboutScreen(
+ onBackButton = { setBooleanParameter("visible", false) },
+ )
+ }
+}
+
+@Composable
+fun AboutScreen(
+ onBackButton: () -> Unit,
+) = Box {
+ AboutScreen()
+
+ IconButton(
+ icon = Icons.Filled.ArrowBack,
+ contentDescription = i18n("access.return_to_previous_screen"),
+ onClick = onBackButton,
+ modifier = Modifier.align(Alignment.TopStart)
+ )
+}
+
+@OptIn(ExperimentalFoundationApi::class)
+@Composable
+fun AboutScreen(modifier: Modifier = Modifier.padding(16.dp)) {
+ // format date
+ val buildTime = Instant.ofEpochMilli(BuildData.GIT_TIME).atZone(ZoneId.systemDefault()).toLocalDateTime()
+
+ // rows displayed in table
+ val lines = buildList {
+ add(Entry(i18n("about.copyright"), "The Briar Project")) // NON-NLS
+ add(Entry(i18n("about.license"), "GNU Affero General Public License v3")) // NON-NLS
+ add(Entry(i18n("about.version"), BuildData.VERSION))
+ add(Entry(i18n("about.version.core"), BuildData.CORE_VERSION))
+ if (BuildData.GIT_BRANCH != null) add(Entry("Git branch", BuildData.GIT_BRANCH)) // NON-NLS
+ if (BuildData.GIT_TAG != null) add(Entry("Git tag", BuildData.GIT_TAG)) // NON-NLS
+ if (BuildData.GIT_BRANCH == null && BuildData.GIT_TAG == null)
+ add(Entry("Git branch/tag", "None detected")) // NON-NLS
+ add(Entry("Git hash", BuildData.GIT_HASH)) // NON-NLS
+ add(Entry("Commit time", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(buildTime))) // NON-NLS
+ add(Entry(i18n("about.website"), "https://briarproject.org", true))
+ add(Entry(i18n("about.contact"), "desktop@briarproject.org", true)) // NON-NLS
+ }
+
+ Column(modifier) {
+ Row(
+ modifier = Modifier.padding(bottom = 16.dp).fillMaxWidth(),
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.Center
+ ) {
+ BriarLogo(modifier = Modifier.height(48.dp))
+ Text(
+ i18n("main.title"),
+ style = MaterialTheme.typography.h4,
+ modifier = Modifier.padding(start = 16.dp),
+ overflow = TextOverflow.Ellipsis,
+ maxLines = 1,
+ )
+ }
+ val scrollState = rememberLazyListState()
+ Box {
+ LazyColumn(
+ modifier = Modifier.semantics {
+ contentDescription = i18n("access.about.list")
+ },
+ state = scrollState
+ ) {
+ item {
+ HorizontalDivider()
+ }
+ items(lines) {
+ AboutEntry(it)
+ HorizontalDivider()
+ }
+ }
+ VerticalScrollbar(
+ adapter = rememberScrollbarAdapter(scrollState),
+ modifier = Modifier.align(Alignment.CenterEnd).fillMaxHeight()
+ )
+ }
+ }
+}
+
+private data class Entry(
+ val label: String,
+ val value: String,
+ val showCopy: Boolean = false
+)
+
+// sizes of the two columns
+private val colSizes = listOf(0.3f, 0.7f)
+
+@Composable
+private fun AboutEntry(entry: Entry) =
+ Row(
+ Modifier
+ .fillMaxWidth()
+ // this is required for Divider between Boxes to have appropriate size
+ .height(IntrinsicSize.Min)
+ .semantics(mergeDescendants = true) {
+ // manual text setting can be removed if Compose issue resolved
+ // https://github.com/JetBrains/compose-jb/issues/2111
+ text = buildAnnotatedString { append("${entry.label}: ${entry.value}") }
+ }
+ ) {
+ Box(modifier = Modifier.weight(colSizes[0]).fillMaxHeight()) {
+ Text(
+ text = entry.label,
+ modifier = Modifier.padding(8.dp).align(Alignment.CenterStart)
+ )
+ }
+ VerticalDivider()
+ Box(modifier = Modifier.weight(colSizes[1]).fillMaxHeight()) {
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ SelectionContainer {
+ Text(
+ text = entry.value,
+ modifier = Modifier.padding(8.dp)
+ )
+ }
+ if (entry.showCopy) {
+ val clipboardManager = LocalClipboardManager.current
+ IconButton(
+ icon = Icons.Filled.ContentCopy,
+ contentDescription = i18n("copy"),
+ onClick = {
+ clipboardManager.setText(AnnotatedString(entry.value))
+ }
+ )
+ }
+ }
+ }
+ }
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/BriarDialog.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/BriarDialog.kt
deleted file mode 100644
index f2929d55169c2b67b606b308889c0fe11333c7ae..0000000000000000000000000000000000000000
--- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/BriarDialog.kt
+++ /dev/null
@@ -1,46 +0,0 @@
-package org.briarproject.briar.desktop.ui
-
-import androidx.compose.foundation.ExperimentalFoundationApi
-import androidx.compose.foundation.background
-import androidx.compose.foundation.clickable
-import androidx.compose.foundation.interaction.MutableInteractionSource
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.BoxWithConstraints
-import androidx.compose.foundation.layout.BoxWithConstraintsScope
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.requiredSize
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material.ExperimentalMaterialApi
-import androidx.compose.material.MaterialTheme
-import androidx.compose.material.Surface
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.remember
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.unit.dp
-
-@OptIn(ExperimentalMaterialApi::class, ExperimentalFoundationApi::class)
-@Composable
-fun BriarDialog(
- onClose: () -> Unit,
- content: @Composable BoxWithConstraintsScope.() -> Unit,
-) {
- BoxWithConstraints(Modifier.fillMaxSize()) {
- // This adds a scrim that dims the background to make the dialog stand out visually
- Box(
- modifier = Modifier.requiredSize(maxWidth, maxHeight)
- .background(MaterialTheme.colors.onSurface.copy(alpha = 0.32f))
- .clickable(
- // prevent visual indication
- interactionSource = remember { MutableInteractionSource() },
- indication = null
- ) {
- onClose()
- }
- )
-
- Surface(modifier = Modifier.align(Alignment.Center), shape = RoundedCornerShape(8.dp)) {
- content()
- }
- }
-}
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 5f0f7eb729953b588418a07a4fb99e12f73a1162..cb7000b2706d0cba532ce6b6f6bfc57007a3fbc1 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
@@ -178,21 +178,17 @@ constructor(
return@CompositionLocalProvider
}
- var showAbout by remember { mutableStateOf(false) }
val isDarkTheme = unencryptedSettings.theme == DARK ||
(unencryptedSettings.theme == AUTO && isSystemInDarkTheme())
BriarTheme(isDarkTheme) {
Column(Modifier.fillMaxSize()) {
ExpirationBanner { screenState = EXPIRED; stop() }
when (screenState) {
- STARTUP -> StartupScreen(onShowAbout = { showAbout = true })
- MAIN -> MainScreen(onShowAbout = { showAbout = true })
- EXPIRED -> ErrorScreen(i18n("startup.failed.expired"), onShowAbout = { showAbout = true })
+ STARTUP -> StartupScreen()
+ MAIN -> MainScreen()
+ EXPIRED -> ErrorScreen(i18n("startup.failed.expired"))
}
}
- if (showAbout) {
- AboutDialog(onClose = { showAbout = false })
- }
}
}
}
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/ColoredIconButton.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/ColoredIconButton.kt
index f47501cf9c84e8ce7630c07d24e78c2d6ee000d4..870c8ce0a492e9718afc8d43704568d8f814ab36 100644
--- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/ColoredIconButton.kt
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/ColoredIconButton.kt
@@ -33,8 +33,10 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.input.pointer.PointerIconDefaults
import androidx.compose.ui.input.pointer.pointerHoverIcon
+import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
@OptIn(ExperimentalComposeUiApi::class)
@@ -62,3 +64,29 @@ fun ColoredIconButton(
content = content
)
}
+
+@OptIn(ExperimentalComposeUiApi::class)
+@Composable
+fun ColoredIconButton(
+ icon: ImageVector,
+ contentDescription: String,
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+ iconSize: Dp = 24.dp,
+ color: Color = MaterialTheme.colors.primary,
+ contentColor: Color = contentColorFor(color),
+ enabled: Boolean = true,
+ interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
+) = IconButton(
+ icon = icon,
+ contentDescription = contentDescription,
+ onClick = onClick,
+ modifier = modifier
+ .pointerHoverIcon(PointerIconDefaults.Default)
+ .background(color, CircleShape)
+ .then(Modifier.size(32.dp)),
+ iconSize = iconSize,
+ iconTint = contentColor,
+ enabled = enabled,
+ interactionSource = interactionSource
+)
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 48581bd3217a070476f52c40e78ea669ffd9e7f6..582ab6ab4c499692feef548752b464a2c88243c5 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
@@ -33,22 +33,19 @@ import org.briarproject.briar.desktop.viewmodel.viewModel
* Multiplatform, stateless, composable are found in briarCompose (possible briar-compose project in the future)
*/
@Composable
-fun MainScreen(
- viewModel: SidebarViewModel = viewModel(),
- onShowAbout: () -> Unit,
-) {
+fun MainScreen(viewModel: SidebarViewModel = viewModel()) {
Row {
BriarSidebar(
viewModel.account.value,
viewModel.uiMode.value,
viewModel::setUiMode,
- showAbout = onShowAbout,
)
VerticalDivider()
when (viewModel.uiMode.value) {
UiMode.CONTACTS -> PrivateMessageScreen()
UiMode.GROUPS -> PrivateGroupScreen()
UiMode.SETTINGS -> SettingsScreen()
+ UiMode.ABOUT -> AboutScreen()
else -> UiPlaceholder()
}
}
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/UiMode.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/UiMode.kt
index 414966fb5347f4c1a2e83300f586fa244bb450f4..10a464edbea9cfb4230f02a92d64dd51079dc791 100644
--- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/UiMode.kt
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/UiMode.kt
@@ -18,11 +18,22 @@
package org.briarproject.briar.desktop.ui
-enum class UiMode {
- CONTACTS,
- GROUPS,
- FORUMS,
- BLOGS,
- TRANSPORTS,
- SETTINGS,
+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.ui.graphics.vector.ImageVector
+
+enum class UiMode(val icon: ImageVector, val contentDescriptionKey: String) {
+ CONTACTS(Icons.Filled.Contacts, "access.mode.contacts"),
+ GROUPS(Icons.Filled.Group, "access.mode.groups"),
+ FORUMS(Icons.Filled.Forum, "access.mode.forums"),
+ BLOGS(Icons.Filled.ChromeReaderMode, "access.mode.blogs"),
+ TRANSPORTS(Icons.Filled.WifiTethering, "access.mode.transports"),
+ SETTINGS(Icons.Filled.Settings, "access.mode.settings"),
+ ABOUT(Icons.Filled.Info, "access.mode.about"),
}
diff --git a/briar-desktop/src/main/resources/strings/BriarDesktop.properties b/briar-desktop/src/main/resources/strings/BriarDesktop.properties
index f95ee998a6a978c1eed4c6eb8572f75db7707144..d4f2c7da2a33bce5ca73011fe0e9e1d2ce4d070d 100644
--- a/briar-desktop/src/main/resources/strings/BriarDesktop.properties
+++ b/briar-desktop/src/main/resources/strings/BriarDesktop.properties
@@ -14,7 +14,14 @@ access.message.send=Send message
access.message.sent=Message sent
access.logo=Briar logo
access.swap=Icon showing errors between two contacts
-access.about_briar_desktop=About Briar Desktop
+access.mode.contacts=Contacts
+access.mode.groups=Private Groups
+access.mode.forums=Forums
+access.mode.blogs=Blogs
+access.mode.transports=Transport Settings
+access.mode.settings=Settings
+access.mode.about=About Briar Desktop
+access.about.list=Information about your version of Briar Desktop, the Briar Project in general and how to get in touch
access.password.show=Show password
access.password.hide=Hide password
access.settings.current_value=Current value