From dcea75ad904a054316b7577bf3e66da29a89682e Mon Sep 17 00:00:00 2001 From: ialokim Date: Wed, 15 Jun 2022 18:22:55 +0200 Subject: [PATCH 1/6] drop dialog imitation for AboutScreen due to poor accessibility in MainScreen --- .../briar/desktop/login/ErrorScreen.kt | 2 +- .../briar/desktop/login/StartupScreen.kt | 2 +- .../briar/desktop/navigation/BriarSidebar.kt | 79 ++++++------- .../briar/desktop/ui/AboutDialog.kt | 107 ++++++++++-------- .../briar/desktop/ui/MainScreen.kt | 2 +- .../briarproject/briar/desktop/ui/UiMode.kt | 25 ++-- .../resources/strings/BriarDesktop.properties | 8 +- 7 files changed, 125 insertions(+), 100 deletions(-) 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 adf541b9..09c36ab1 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 @@ -140,6 +140,6 @@ fun ErrorScreen( onClick = onShowAbout, modifier = Modifier.align(Alignment.BottomStart) ) { - Icon(Icons.Filled.Info, i18n("access.about_briar_desktop")) + Icon(Icons.Filled.Info, i18n("access.mode.about")) } } 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 e03d14f2..089cf830 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 @@ -83,7 +83,7 @@ fun StartupScreenScaffold( onClick = onShowAbout, modifier = Modifier.align(Alignment.BottomStart) ) { - Icon(Icons.Filled.Info, i18n("access.about_briar_desktop")) + Icon(Icons.Filled.Info, i18n("access.mode.about")) } } 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 fe080e6e..418a6a33 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 @@ -29,14 +29,6 @@ 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 +48,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,40 +57,59 @@ 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( modifier = Modifier.padding(vertical = 4.dp, horizontal = 12.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 index 5899d87b..252d749c 100644 --- 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 @@ -45,6 +45,20 @@ fun main() = preview( fun AboutDialog( onClose: () -> Unit, ) { + BriarDialog(onClose = onClose) { + val box = this + Column( + modifier = Modifier.requiredSize( + box.maxWidth.times(0.8f), box.maxHeight.times(0.8f) + ).padding(16.dp) + ) { + AboutScreen() + } + } +} + +@Composable +fun AboutScreen() { // sizes of the two columns val colSizes = listOf(0.3f, 0.7f) @@ -52,7 +66,7 @@ fun AboutDialog( val buildTime = Instant.ofEpochMilli(BuildData.GIT_TIME).atZone(ZoneId.systemDefault()).toLocalDateTime() // rows displayed in table - val lines = buildList> { + 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) @@ -66,63 +80,56 @@ fun AboutDialog( 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) + Column { + Row( + modifier = Modifier.padding(bottom = 8.dp).fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center ) { - 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()) { + 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 = key, - modifier = Modifier.padding(horizontal = 8.dp) - .padding(vertical = 8.dp).padding(end = 8.dp) - .align(Alignment.CenterStart) + text = value, + modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp) + .padding(start = 8.dp) ) } - VerticalDivider() - Box(modifier = Modifier.weight(colSizes[1]).fillMaxHeight()) { - SelectionContainer { - Text( - text = value, - modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp) - .padding(start = 8.dp) - ) - } - } } - HorizontalDivider() } + HorizontalDivider() } - VerticalScrollbar( - adapter = rememberScrollbarAdapter(scrollState), - modifier = Modifier.align(Alignment.CenterEnd).fillMaxHeight() - ) } + VerticalScrollbar( + adapter = rememberScrollbarAdapter(scrollState), + modifier = Modifier.align(Alignment.CenterEnd).fillMaxHeight() + ) } } } 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 48581bd3..196a5748 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 @@ -42,13 +42,13 @@ fun MainScreen( 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 414966fb..10a464ed 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 f95ee998..39f09d11 100644 --- a/briar-desktop/src/main/resources/strings/BriarDesktop.properties +++ b/briar-desktop/src/main/resources/strings/BriarDesktop.properties @@ -14,7 +14,13 @@ 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.password.show=Show password access.password.hide=Hide password access.settings.current_value=Current value -- GitLab From b5dfec3014abe05f1cd9686f9015013924a6c0e0 Mon Sep 17 00:00:00 2001 From: ialokim Date: Wed, 15 Jun 2022 18:52:43 +0200 Subject: [PATCH 2/6] drop dialog imitation for AboutScreen due to poor accessibility in StartupScreen and ErrorScreen --- .../briar/desktop/login/AboutSubViewModel.kt | 23 ++++++ .../briar/desktop/login/ErrorScreen.kt | 70 ++++++++++--------- .../briar/desktop/login/StartupScreen.kt | 18 +++-- .../briar/desktop/login/StartupViewModel.kt | 7 ++ .../briar/desktop/navigation/BriarSidebar.kt | 1 - .../ui/{AboutDialog.kt => AboutScreen.kt} | 35 +++++----- .../briar/desktop/ui/BriarDialog.kt | 46 ------------ .../briarproject/briar/desktop/ui/BriarUi.kt | 10 +-- .../briar/desktop/ui/MainScreen.kt | 5 +- 9 files changed, 103 insertions(+), 112 deletions(-) create mode 100644 briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/login/AboutSubViewModel.kt rename briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/{AboutDialog.kt => AboutScreen.kt} (89%) delete mode 100644 briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/BriarDialog.kt 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 00000000..63e2bfc6 --- /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 09c36ab1..498043f9 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,50 @@ 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) + ) + } + + if (onBackButton != null) { + IconButton(onClick = onBackButton) { + Icon(Icons.Filled.ArrowBack, i18n("access.return_to_previous_screen")) + } } - } - IconButton( - onClick = onShowAbout, - modifier = Modifier.align(Alignment.BottomStart) - ) { - Icon(Icons.Filled.Info, i18n("access.mode.about")) + IconButton( + onClick = { showAbout = true }, + modifier = Modifier.align(Alignment.BottomStart) + ) { + Icon(Icons.Filled.Info, i18n("access.mode.about")) + } } } 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 089cf830..5e5c17b8 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 @@ -38,19 +38,29 @@ 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 -> Box { + AboutScreen(Modifier.padding(16.dp)) + + IconButton( + onClick = holder.onBackButton, + modifier = Modifier.align(Alignment.TopStart) + ) { + Icon(Icons.Filled.ArrowBack, i18n("back")) + } + } } } 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 21af1672..a51ba875 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 418a6a33..93416d2d 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 @@ -102,7 +102,6 @@ fun BriarSidebarButton( i18n(mode.contentDescriptionKey) ) - @Composable fun BriarSidebarButton( selected: Boolean, 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/AboutScreen.kt similarity index 89% rename from briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/AboutDialog.kt rename to briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/AboutScreen.kt index 252d749c..7d4867d9 100644 --- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/AboutDialog.kt +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/AboutScreen.kt @@ -10,14 +10,17 @@ 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.Icon +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.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -35,30 +38,28 @@ fun main() = preview( "visible" to true, ) { if (getBooleanParameter("visible")) { - AboutDialog( - onClose = { setBooleanParameter("visible", false) }, + AboutScreen( + onBackButton = { setBooleanParameter("visible", false) }, ) } } @Composable -fun AboutDialog( - onClose: () -> Unit, -) { - BriarDialog(onClose = onClose) { - val box = this - Column( - modifier = Modifier.requiredSize( - box.maxWidth.times(0.8f), box.maxHeight.times(0.8f) - ).padding(16.dp) - ) { - AboutScreen() - } +fun AboutScreen( + onBackButton: () -> Unit, +) = Box { + AboutScreen(Modifier.padding(16.dp)) + + IconButton( + onClick = onBackButton, + modifier = Modifier.align(Alignment.TopStart) + ) { + Icon(Icons.Filled.ArrowBack, i18n("back")) } } @Composable -fun AboutScreen() { +fun AboutScreen(modifier: Modifier = Modifier) { // sizes of the two columns val colSizes = listOf(0.3f, 0.7f) @@ -80,7 +81,7 @@ fun AboutScreen() { add(i18n("about.contact") to "desktop@briarproject.org") // NON-NLS } - Column { + Column(modifier) { Row( modifier = Modifier.padding(bottom = 8.dp).fillMaxWidth(), verticalAlignment = Alignment.CenterVertically, 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 f2929d55..00000000 --- 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 5f0f7eb7..cb7000b2 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/MainScreen.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/MainScreen.kt index 196a5748..582ab6ab 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,10 +33,7 @@ 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, -- GitLab From 9b9e4b38718e9d0cf3107eace871f53e17b67e9b Mon Sep 17 00:00:00 2001 From: ialokim Date: Tue, 21 Jun 2022 14:08:22 +0200 Subject: [PATCH 3/6] better screen reader support for about table --- .../briar/desktop/login/StartupScreen.kt | 11 +----- .../briar/desktop/ui/AboutScreen.kt | 39 +++++++++++++------ .../resources/strings/BriarDesktop.properties | 1 + 3 files changed, 29 insertions(+), 22 deletions(-) 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 5e5c17b8..fb697f35 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 @@ -51,16 +51,7 @@ fun StartupScreen( is LoginSubViewModel -> LoginScreen(viewModel::showAbout, holder) is RegistrationSubViewModel -> RegistrationScreen(viewModel::showAbout, holder) is ErrorSubViewModel -> ErrorScreen(holder) - is AboutSubViewModel -> Box { - AboutScreen(Modifier.padding(16.dp)) - - IconButton( - onClick = holder.onBackButton, - modifier = Modifier.align(Alignment.TopStart) - ) { - Icon(Icons.Filled.ArrowBack, i18n("back")) - } - } + is AboutSubViewModel -> AboutScreen(holder.onBackButton) } } 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 index 7d4867d9..8fc87997 100644 --- 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 @@ -24,6 +24,10 @@ import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.semantics.contentDescription +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.semantics.text +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 @@ -48,18 +52,18 @@ fun main() = preview( fun AboutScreen( onBackButton: () -> Unit, ) = Box { - AboutScreen(Modifier.padding(16.dp)) + AboutScreen() IconButton( onClick = onBackButton, modifier = Modifier.align(Alignment.TopStart) ) { - Icon(Icons.Filled.ArrowBack, i18n("back")) + Icon(Icons.Filled.ArrowBack, i18n("access.return_to_previous_screen")) } } @Composable -fun AboutScreen(modifier: Modifier = Modifier) { +fun AboutScreen(modifier: Modifier = Modifier.padding(16.dp)) { // sizes of the two columns val colSizes = listOf(0.3f, 0.7f) @@ -83,7 +87,7 @@ fun AboutScreen(modifier: Modifier = Modifier) { Column(modifier) { Row( - modifier = Modifier.padding(bottom = 8.dp).fillMaxWidth(), + modifier = Modifier.padding(bottom = 16.dp).fillMaxWidth(), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.Center ) { @@ -98,19 +102,31 @@ fun AboutScreen(modifier: Modifier = Modifier) { } val scrollState = rememberLazyListState() Box { - LazyColumn(state = scrollState) { + LazyColumn( + modifier = Modifier.semantics { + contentDescription = i18n("access.about.list") + }, + 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)) { + 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("$key: $value") } + } + ) { 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) + modifier = Modifier.padding(8.dp) ) } VerticalDivider() @@ -118,8 +134,7 @@ fun AboutScreen(modifier: Modifier = Modifier) { SelectionContainer { Text( text = value, - modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp) - .padding(start = 8.dp) + modifier = Modifier.padding(8.dp) ) } } diff --git a/briar-desktop/src/main/resources/strings/BriarDesktop.properties b/briar-desktop/src/main/resources/strings/BriarDesktop.properties index 39f09d11..d4f2c7da 100644 --- a/briar-desktop/src/main/resources/strings/BriarDesktop.properties +++ b/briar-desktop/src/main/resources/strings/BriarDesktop.properties @@ -21,6 +21,7 @@ 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 -- GitLab From 5aa38c0f22743c0ac98bb9f213cf6135d317e17f Mon Sep 17 00:00:00 2001 From: ialokim Date: Wed, 17 Aug 2022 09:36:04 +0200 Subject: [PATCH 4/6] show tooltips per default on all IconButtons --- .../compose/material/IconButtonExt.kt | 97 +++++++++++++++++++ .../compose/material/OutlinedTextFieldExt.kt | 22 +---- .../briar/desktop/contact/ContactCard.kt | 7 +- .../briar/desktop/contact/SearchTextField.kt | 12 +-- .../contact/add/remote/AddContactDialog.kt | 73 +++++--------- .../conversation/ConversationHeader.kt | 5 +- .../desktop/conversation/ConversationInput.kt | 25 ++--- .../conversation/PrivateMessageScreen.kt | 22 ++--- .../desktop/expiration/ExpirationBanner.kt | 9 +- .../introduction/ContactDrawerMakeIntro.kt | 16 +-- .../briar/desktop/login/ErrorScreen.kt | 14 +-- .../briar/desktop/login/StartupScreen.kt | 13 ++- .../briar/desktop/navigation/BriarSidebar.kt | 14 +-- .../briar/desktop/ui/AboutScreen.kt | 7 +- .../briar/desktop/ui/ColoredIconButton.kt | 28 ++++++ 15 files changed, 216 insertions(+), 148 deletions(-) create mode 100644 briar-desktop/src/main/kotlin/androidx/compose/material/IconButtonExt.kt 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 00000000..d6619e0d --- /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 d2defb11..bdcf4098 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 0e98b2bb..73772d56 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 fa7db6ab..1d32ffc4 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 c497b390..aab5f86a 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 a161b184..eb6d737b 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 ca555805..1787696c 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 1b374b6d..67511a08 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 a2b206d1..78a179ea 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 ea12210b..54b0b9ce 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/ErrorScreen.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/login/ErrorScreen.kt index 498043f9..3439a669 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 @@ -134,16 +134,18 @@ fun ErrorScreen( } if (onBackButton != null) { - IconButton(onClick = onBackButton) { - Icon(Icons.Filled.ArrowBack, i18n("access.return_to_previous_screen")) - } + 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) - ) { - Icon(Icons.Filled.Info, i18n("access.mode.about")) - } + ) } } 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 fb697f35..122df268 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 @@ -73,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.mode.about")) - } + ) } @Composable 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 93416d2d..6d5bdd8b 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,9 +23,7 @@ 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 @@ -107,13 +105,15 @@ fun BriarSidebarButton( selected: Boolean, onClick: () -> Unit, icon: ImageVector, - contentDescription: String?, + 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/AboutScreen.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/AboutScreen.kt index 8fc87997..1e0d73c5 100644 --- 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 @@ -15,7 +15,6 @@ 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.Icon import androidx.compose.material.IconButton import androidx.compose.material.MaterialTheme import androidx.compose.material.Text @@ -55,11 +54,11 @@ fun AboutScreen( AboutScreen() 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")) - } + ) } @Composable 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 f47501cf..870c8ce0 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 +) -- GitLab From 9fc1bab93fe1f163137480468457913db4f5e72d Mon Sep 17 00:00:00 2001 From: ialokim Date: Wed, 22 Jun 2022 16:54:21 +0200 Subject: [PATCH 5/6] add copy buttons to website and email links --- .../briar/desktop/ui/AboutScreen.kt | 68 +++++++++++++------ 1 file changed, 48 insertions(+), 20 deletions(-) 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 index 1e0d73c5..2699ee58 100644 --- 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 @@ -1,5 +1,6 @@ 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 @@ -20,12 +21,15 @@ 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 @@ -61,6 +65,7 @@ fun AboutScreen( ) } +@OptIn(ExperimentalFoundationApi::class) @Composable fun AboutScreen(modifier: Modifier = Modifier.padding(16.dp)) { // sizes of the two columns @@ -69,19 +74,26 @@ fun AboutScreen(modifier: Modifier = Modifier.padding(16.dp)) { // format date val buildTime = Instant.ofEpochMilli(BuildData.GIT_TIME).atZone(ZoneId.systemDefault()).toLocalDateTime() + data class Entry( + val label: String, + val value: String, + val showCopy: Boolean = false + ) + // 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 + 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) { @@ -110,7 +122,7 @@ fun AboutScreen(modifier: Modifier = Modifier.padding(16.dp)) { item { HorizontalDivider() } - items(lines) { (key, value) -> + items(lines) { (label, value, showCopy) -> Row( Modifier .fillMaxWidth() @@ -119,22 +131,38 @@ fun AboutScreen(modifier: Modifier = Modifier.padding(16.dp)) { .semantics(mergeDescendants = true) { // manual text setting can be removed if Compose issue resolved // https://github.com/JetBrains/compose-jb/issues/2111 - text = buildAnnotatedString { append("$key: $value") } + text = buildAnnotatedString { append("$label: $value") } } ) { Box(modifier = Modifier.weight(colSizes[0]).fillMaxHeight()) { Text( - text = key, - modifier = Modifier.padding(8.dp) + text = label, + modifier = Modifier.padding(8.dp).align(Alignment.CenterStart) ) } VerticalDivider() Box(modifier = Modifier.weight(colSizes[1]).fillMaxHeight()) { - SelectionContainer { - Text( - text = value, - modifier = Modifier.padding(8.dp) - ) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + SelectionContainer { + Text( + text = value, + modifier = Modifier.padding(8.dp) + ) + } + if (showCopy) { + val clipboardManager = LocalClipboardManager.current + IconButton( + icon = Icons.Filled.ContentCopy, + contentDescription = i18n("copy"), + onClick = { + clipboardManager.setText(AnnotatedString(value)) + } + ) + } } } } -- GitLab From c34f85f1cd2f1d9f923cdca8be0b8465d07e67ee Mon Sep 17 00:00:00 2001 From: ialokim Date: Wed, 17 Aug 2022 09:52:38 +0200 Subject: [PATCH 6/6] tame the AboutScreen beast --- .../briar/desktop/ui/AboutScreen.kt | 110 +++++++++--------- 1 file changed, 57 insertions(+), 53 deletions(-) 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 index 2699ee58..113e6701 100644 --- 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 @@ -68,18 +68,9 @@ fun AboutScreen( @OptIn(ExperimentalFoundationApi::class) @Composable fun AboutScreen(modifier: Modifier = Modifier.padding(16.dp)) { - // 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() - data class Entry( - val label: String, - val value: String, - val showCopy: Boolean = false - ) - // rows displayed in table val lines = buildList { add(Entry(i18n("about.copyright"), "The Briar Project")) // NON-NLS @@ -122,50 +113,8 @@ fun AboutScreen(modifier: Modifier = Modifier.padding(16.dp)) { item { HorizontalDivider() } - items(lines) { (label, value, showCopy) -> - 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("$label: $value") } - } - ) { - Box(modifier = Modifier.weight(colSizes[0]).fillMaxHeight()) { - Text( - text = 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 = value, - modifier = Modifier.padding(8.dp) - ) - } - if (showCopy) { - val clipboardManager = LocalClipboardManager.current - IconButton( - icon = Icons.Filled.ContentCopy, - contentDescription = i18n("copy"), - onClick = { - clipboardManager.setText(AnnotatedString(value)) - } - ) - } - } - } - } + items(lines) { + AboutEntry(it) HorizontalDivider() } } @@ -176,3 +125,58 @@ fun AboutScreen(modifier: Modifier = Modifier.padding(16.dp)) { } } } + +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)) + } + ) + } + } + } + } -- GitLab