diff --git a/src/main/kotlin/org/briarproject/briar/desktop/contact/ConnectionIndicator.kt b/src/main/kotlin/org/briarproject/briar/desktop/contact/ConnectionIndicator.kt new file mode 100644 index 0000000000000000000000000000000000000000..e3c80ae5c8524445eccf7ba6f165d9049740bd9e --- /dev/null +++ b/src/main/kotlin/org/briarproject/briar/desktop/contact/ConnectionIndicator.kt @@ -0,0 +1,43 @@ +/* + * Briar Desktop + * Copyright (C) 2021-2022 The Briar Project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +package org.briarproject.briar.desktop.contact + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import org.briarproject.briar.desktop.theme.contactConnected +import org.briarproject.briar.desktop.theme.outline + +@Composable +fun ConnectionIndicator( + modifier: Modifier = Modifier.size(16.dp), + isConnected: Boolean, + notConnectedColor: Color = Color.Transparent, +) = Box( + modifier = modifier + .border(1.dp, MaterialTheme.colors.outline, CircleShape) + .background(if (isConnected) MaterialTheme.colors.contactConnected else notConnectedColor, CircleShape) +) diff --git a/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactCard.kt b/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactCard.kt index 0e98b2bb6f26449763a98af6a3e678ec59d7eb70..9622f9083beb33562650ac606f2eb618246cba63 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactCard.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactCard.kt @@ -18,8 +18,7 @@ package org.briarproject.briar.desktop.contact -import androidx.compose.foundation.Canvas -import androidx.compose.foundation.clickable +import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -30,8 +29,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.offset 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.foundation.selection.selectable import androidx.compose.material.Icon import androidx.compose.material.IconButton import androidx.compose.material.MaterialTheme @@ -41,13 +39,12 @@ import androidx.compose.material.icons.filled.Delete 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.TextOverflow.Companion.Ellipsis import androidx.compose.ui.unit.dp import org.briarproject.bramble.api.contact.ContactId import org.briarproject.bramble.api.identity.AuthorId -import org.briarproject.briar.desktop.theme.outline import org.briarproject.briar.desktop.theme.selectedCard -import org.briarproject.briar.desktop.theme.surfaceVariant import org.briarproject.briar.desktop.ui.Constants.HEADER_SIZE import org.briarproject.briar.desktop.ui.HorizontalDivider import org.briarproject.briar.desktop.ui.MessageCounter @@ -90,13 +87,16 @@ fun ContactCard( onRemovePending: () -> Unit, padding: PaddingValues = PaddingValues(0.dp), ) { - val bgColor = if (selected) MaterialTheme.colors.selectedCard else MaterialTheme.colors.surfaceVariant + val bgColor = if (selected) MaterialTheme.colors.selectedCard else Color.Transparent - Card( - modifier = Modifier.fillMaxWidth().defaultMinSize(minHeight = HEADER_SIZE).clickable(onClick = onSel), - shape = RoundedCornerShape(0.dp), - backgroundColor = bgColor, - contentColor = MaterialTheme.colors.onSurface + Column( + modifier = Modifier + .fillMaxWidth() + .defaultMinSize(minHeight = HEADER_SIZE) + .selectable(selected, onClick = onSel) + .background(bgColor) + .padding(vertical = 8.dp), + verticalArrangement = Arrangement.Center ) { when (contactItem) { is ContactItem -> { @@ -112,16 +112,15 @@ fun ContactCard( @Composable private fun RealContactRow(contactItem: ContactItem, padding: PaddingValues) { - val outlineColor = MaterialTheme.colors.outline - val briarSecondary = MaterialTheme.colors.secondary - val briarSurfaceVar = MaterialTheme.colors.surfaceVariant - - Row(horizontalArrangement = Arrangement.SpaceBetween, modifier = Modifier.padding(padding)) { + Row( + horizontalArrangement = Arrangement.SpaceBetween, + modifier = Modifier.padding(padding), + verticalAlignment = Alignment.CenterVertically + ) { Row( - modifier = Modifier.align(Alignment.CenterVertically).padding(start = 16.dp, end = 8.dp) - .weight(1f, fill = false) + modifier = Modifier.padding(horizontal = 16.dp).weight(1f) ) { - Box(modifier = Modifier.align(Alignment.CenterVertically)) { + Box { ProfileCircle(36.dp, contactItem) MessageCounter( unread = contactItem.unread, @@ -130,19 +129,11 @@ private fun RealContactRow(contactItem: ContactItem, padding: PaddingValues) { } RealContactInfo( contactItem = contactItem, - modifier = Modifier.align(Alignment.CenterVertically) ) } - Canvas( - modifier = Modifier.size(24.dp).align(Alignment.CenterVertically), - onDraw = { - val size = 16.dp - drawCircle(color = outlineColor, radius = size.toPx() / 2f) - drawCircle( - color = if (contactItem.isConnected) briarSecondary else briarSurfaceVar, - radius = (size - 2.dp).toPx() / 2f - ) - } + ConnectionIndicator( + modifier = Modifier.padding(end = 18.dp).size(16.dp), + isConnected = contactItem.isConnected ) } } @@ -151,8 +142,8 @@ private fun RealContactRow(contactItem: ContactItem, padding: PaddingValues) { private fun PendingContactRow(contactItem: PendingContactItem, onRemove: () -> Unit, padding: PaddingValues) { Row(horizontalArrangement = Arrangement.SpaceBetween) { Row( - modifier = Modifier.align(Alignment.CenterVertically).padding(start = 16.dp, end = 8.dp) - .weight(1f, fill = false) + modifier = Modifier.align(Alignment.CenterVertically).padding(horizontal = 16.dp) + .weight(1f) ) { ProfileCircle(36.dp) PendingContactInfo( diff --git a/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactList.kt b/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactList.kt index b0324ffa504334e1c6e59874df4246b2e4a0c1c4..9e0dc02552f0a038ee2a31ee4215a19fd904066d 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactList.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactList.kt @@ -32,13 +32,12 @@ 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.material.MaterialTheme -import androidx.compose.material.Scaffold +import androidx.compose.foundation.selection.selectableGroup import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import org.briarproject.briar.desktop.theme.surfaceVariant +import org.briarproject.briar.desktop.ui.BackgroundSurface import org.briarproject.briar.desktop.ui.Constants.COLUMN_WIDTH import org.briarproject.briar.desktop.ui.Constants.HEADER_SIZE @@ -54,10 +53,11 @@ fun ContactList( ) { val scrollState = rememberLazyListState() - Scaffold( + BackgroundSurface( modifier = Modifier.fillMaxHeight().width(COLUMN_WIDTH), - backgroundColor = MaterialTheme.colors.surfaceVariant, - topBar = { + overlayAlpha = 0.04f + ) { + Column { Column( modifier = Modifier.fillMaxWidth().height(HEADER_SIZE + 1.dp), ) { @@ -67,10 +67,9 @@ fun ContactList( onContactAdd = onContactAdd, ) } - }, - content = { padding -> - Box(modifier = Modifier.padding(padding).fillMaxSize()) { - LazyColumn(state = scrollState) { + + Box(modifier = Modifier.fillMaxSize()) { + LazyColumn(state = scrollState, modifier = Modifier.selectableGroup()) { items(contactList) { contactItem -> ContactCard( contactItem, @@ -87,6 +86,6 @@ fun ContactList( modifier = Modifier.align(Alignment.CenterEnd).fillMaxHeight() ) } - }, - ) + } + } } diff --git a/src/main/kotlin/org/briarproject/briar/desktop/contact/add/remote/AddContactDialog.kt b/src/main/kotlin/org/briarproject/briar/desktop/contact/add/remote/AddContactDialog.kt index c497b390ef051a91ce401ae6b567e78cfc3d5d32..c162d9bee9fd166d644642c77e0b27764cab5a57 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/contact/add/remote/AddContactDialog.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/contact/add/remote/AddContactDialog.kt @@ -95,6 +95,7 @@ import org.briarproject.briar.desktop.dialogs.DialogType.WARNING import org.briarproject.briar.desktop.theme.Orange500 import org.briarproject.briar.desktop.theme.Red500 import org.briarproject.briar.desktop.theme.surfaceVariant +import org.briarproject.briar.desktop.ui.BackgroundSurface import org.briarproject.briar.desktop.ui.Constants.DIALOG_WIDTH import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18nF @@ -203,7 +204,7 @@ fun AddContactDialog( val scaffoldState = rememberScaffoldState() val coroutineScope = rememberCoroutineScope() val aliasFocusRequester = remember { FocusRequester() } - Surface { + BackgroundSurface { Scaffold( modifier = Modifier.padding(horizontal = 24.dp).padding(top = 24.dp, bottom = 12.dp), topBar = { diff --git a/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationHeader.kt b/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationHeader.kt index a161b184b35a2ee179923fb6024bd90fbfff5fe7..ea9a365d2ee1edbbbb8620001217e220970eef3a 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationHeader.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationHeader.kt @@ -18,7 +18,6 @@ package org.briarproject.briar.desktop.conversation -import androidx.compose.foundation.Canvas import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row @@ -38,14 +37,12 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.drawscope.withTransform import androidx.compose.ui.text.style.TextOverflow.Companion.Ellipsis import androidx.compose.ui.unit.dp +import org.briarproject.briar.desktop.contact.ConnectionIndicator import org.briarproject.briar.desktop.contact.ContactDropDown import org.briarproject.briar.desktop.contact.ContactItem import org.briarproject.briar.desktop.contact.ProfileCircle -import org.briarproject.briar.desktop.theme.outline -import org.briarproject.briar.desktop.theme.surfaceVariant import org.briarproject.briar.desktop.ui.Constants.HEADER_SIZE import org.briarproject.briar.desktop.ui.HorizontalDivider import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n @@ -59,9 +56,6 @@ fun ConversationHeader( onDeleteContact: () -> Unit, ) { val (menuState, setMenuState) = remember { mutableStateOf(ContactDropDown.State.CLOSED) } - val onlineColor = - if (contactItem.isConnected) MaterialTheme.colors.secondary else MaterialTheme.colors.surfaceVariant - val outlineColor = MaterialTheme.colors.outline Box(modifier = Modifier.fillMaxWidth().height(HEADER_SIZE + 1.dp)) { Row( @@ -71,15 +65,10 @@ fun ConversationHeader( Row(modifier = Modifier.fillMaxHeight().padding(start = 8.dp).weight(1f, fill = false)) { Box(modifier = Modifier.align(Alignment.CenterVertically)) { ProfileCircle(36.dp, contactItem) - Canvas( - modifier = Modifier, - onDraw = { - val size = 10.dp.toPx() - withTransform({ translate(left = 30f, top = 30f) }) { - drawCircle(color = outlineColor, radius = (size + 2.dp.toPx()) / 2f) - drawCircle(color = onlineColor, radius = size / 2f) - } - } + ConnectionIndicator( + modifier = Modifier.align(Alignment.BottomEnd).size(12.dp), + isConnected = contactItem.isConnected, + notConnectedColor = MaterialTheme.colors.background, ) } Text( diff --git a/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationScreen.kt b/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationScreen.kt index 89abe704c9066450494cfac6b810d00a0485403a..bbfba16678038f90ae450a07f597514d1efc3885 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationScreen.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationScreen.kt @@ -45,7 +45,6 @@ import org.briarproject.bramble.api.contact.ContactId import org.briarproject.briar.desktop.contact.ContactInfoDrawer import org.briarproject.briar.desktop.contact.ContactInfoDrawerState import org.briarproject.briar.desktop.navigation.SIDEBAR_WIDTH -import org.briarproject.briar.desktop.theme.surfaceVariant import org.briarproject.briar.desktop.ui.Constants.COLUMN_WIDTH import org.briarproject.briar.desktop.ui.Loader import org.briarproject.briar.desktop.viewmodel.viewModel @@ -135,7 +134,7 @@ fun ConversationScreen( Column( modifier = Modifier.fillMaxHeight().width(COLUMN_WIDTH) .offset(maxWidth + animatedInfoDrawerOffsetX) - .background(MaterialTheme.colors.surfaceVariant) + .background(MaterialTheme.colors.background) ) { ContactInfoDrawer( contactItem, diff --git a/src/main/kotlin/org/briarproject/briar/desktop/conversation/PrivateMessageScreen.kt b/src/main/kotlin/org/briarproject/briar/desktop/conversation/PrivateMessageScreen.kt index 1b374b6dc80e2c05342d6d3c4ab8da2031b0b400..f99908b6af8392c2c1761f683bf3910cbfdb472a 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/conversation/PrivateMessageScreen.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/conversation/PrivateMessageScreen.kt @@ -48,6 +48,7 @@ import org.briarproject.briar.desktop.contact.PendingContactIdWrapper 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.BackgroundSurface import org.briarproject.briar.desktop.ui.BriarLogo import org.briarproject.briar.desktop.ui.Constants.PARAGRAPH_WIDTH import org.briarproject.briar.desktop.ui.VerticalDivider @@ -132,21 +133,23 @@ fun PendingContactSelected() = Explainer( @Composable fun Explainer(headline: String, text: String, content: @Composable () -> Unit = {}) = - Column( - modifier = Modifier.padding(16.dp).fillMaxSize(), - verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.CenterHorizontally - ) { - BriarLogo(modifier = Modifier.size(200.dp)) - Text( - text = headline, - modifier = Modifier.padding(top = 16.dp, bottom = 4.dp), - style = MaterialTheme.typography.h3 - ) - Text( - text = text, - modifier = Modifier.padding(top = 4.dp, bottom = 16.dp).widthIn(max = PARAGRAPH_WIDTH), - style = MaterialTheme.typography.body2.copy(textAlign = TextAlign.Center) - ) - content() + BackgroundSurface { + Column( + modifier = Modifier.padding(16.dp).fillMaxSize(), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + BriarLogo(modifier = Modifier.size(200.dp)) + Text( + text = headline, + modifier = Modifier.padding(top = 16.dp, bottom = 4.dp), + style = MaterialTheme.typography.h3 + ) + Text( + text = text, + modifier = Modifier.padding(top = 4.dp, bottom = 16.dp).widthIn(max = PARAGRAPH_WIDTH), + style = MaterialTheme.typography.body2.copy(textAlign = TextAlign.Center) + ) + content() + } } diff --git a/src/main/kotlin/org/briarproject/briar/desktop/introduction/ContactDrawerMakeIntro.kt b/src/main/kotlin/org/briarproject/briar/desktop/introduction/ContactDrawerMakeIntro.kt index ea12210b752777f5bb4ea3b2f8658df28a536cbe..32e55d138baa8cefa96765cf6e1b329b76552a31 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/introduction/ContactDrawerMakeIntro.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/introduction/ContactDrawerMakeIntro.kt @@ -32,7 +32,6 @@ import androidx.compose.material.Button import androidx.compose.material.Icon import androidx.compose.material.IconButton import androidx.compose.material.MaterialTheme -import androidx.compose.material.Surface import androidx.compose.material.Text import androidx.compose.material.TextField import androidx.compose.material.icons.Icons @@ -48,7 +47,7 @@ import androidx.compose.ui.unit.dp import org.briarproject.briar.desktop.contact.ContactCard import org.briarproject.briar.desktop.contact.ContactItem import org.briarproject.briar.desktop.contact.ProfileCircle -import org.briarproject.briar.desktop.theme.surfaceVariant +import org.briarproject.briar.desktop.ui.BackgroundSurface import org.briarproject.briar.desktop.ui.Constants.HEADER_SIZE import org.briarproject.briar.desktop.ui.HorizontalDivider import org.briarproject.briar.desktop.utils.InternationalizationUtils @@ -65,7 +64,7 @@ fun ContactDrawerMakeIntro( LaunchedEffect(contactItem) { viewModel.setFirstContact(contactItem) } - Surface(color = MaterialTheme.colors.surfaceVariant, contentColor = MaterialTheme.colors.onSurface) { + BackgroundSurface { Column { if (!viewModel.secondScreen.value) { Row(Modifier.fillMaxWidth().height(HEADER_SIZE)) { diff --git a/src/main/kotlin/org/briarproject/briar/desktop/login/ErrorScreen.kt b/src/main/kotlin/org/briarproject/briar/desktop/login/ErrorScreen.kt index fc3ba64c07894d6f8e0f7539909c85e2eafcbbca..16e6599113ebd6e72eee867e99a553ba477d9f80 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/login/ErrorScreen.kt +++ b/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.BackgroundSurface 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 @@ -109,37 +110,39 @@ 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 - ) +) = BackgroundSurface { + 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 + ) - Text(i18n("sorry"), style = MaterialTheme.typography.h5) - Text( - text = text, - style = MaterialTheme.typography.body1, - modifier = Modifier.widthIn(max = STARTUP_FIELDS_WIDTH) - ) - } + 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("back")) + if (onBackButton != null) { + IconButton(onClick = onBackButton) { + Icon(Icons.Filled.ArrowBack, i18n("back")) + } } - } - IconButton( - onClick = onShowAbout, - modifier = Modifier.align(Alignment.BottomStart) - ) { - Icon(Icons.Filled.Info, i18n("access.about_briar_desktop")) + IconButton( + onClick = onShowAbout, + modifier = Modifier.align(Alignment.BottomStart) + ) { + Icon(Icons.Filled.Info, i18n("access.about_briar_desktop")) + } } } diff --git a/src/main/kotlin/org/briarproject/briar/desktop/login/StartupScreen.kt b/src/main/kotlin/org/briarproject/briar/desktop/login/StartupScreen.kt index cae1225cf1456ecaa9ee97993d96c1e6c97ff304..e2ad0cbc99b573f82827fe0066b85442cfdb941f 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/login/StartupScreen.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/login/StartupScreen.kt @@ -38,6 +38,7 @@ 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.BackgroundSurface import org.briarproject.briar.desktop.ui.BriarLogo import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n import org.briarproject.briar.desktop.viewmodel.viewModel @@ -61,30 +62,32 @@ fun StartupScreenScaffold( onBackButton: () -> Unit = {}, onShowAbout: () -> Unit = {}, content: @Composable () -> Unit -) = Box { - Column( - modifier = Modifier.padding(16.dp).fillMaxSize(), - horizontalAlignment = CenterHorizontally - ) { - HeaderLine(title) - content() - } +) = BackgroundSurface { + Box { + Column( + modifier = Modifier.padding(16.dp).fillMaxSize(), + horizontalAlignment = CenterHorizontally + ) { + HeaderLine(title) + content() + } + + if (showBackButton) { + IconButton( + onClick = onBackButton, + modifier = Modifier.align(Alignment.TopStart) + ) { + Icon(Icons.Filled.ArrowBack, i18n("back")) + } + } - if (showBackButton) { IconButton( - onClick = onBackButton, - modifier = Modifier.align(Alignment.TopStart) + onClick = onShowAbout, + modifier = Modifier.align(Alignment.BottomStart) ) { - Icon(Icons.Filled.ArrowBack, i18n("back")) + Icon(Icons.Filled.Info, i18n("access.about_briar_desktop")) } } - - IconButton( - onClick = onShowAbout, - modifier = Modifier.align(Alignment.BottomStart) - ) { - Icon(Icons.Filled.Info, i18n("access.about_briar_desktop")) - } } @Composable diff --git a/src/main/kotlin/org/briarproject/briar/desktop/navigation/BriarSidebar.kt b/src/main/kotlin/org/briarproject/briar/desktop/navigation/BriarSidebar.kt index fe080e6eade164bfb2f7089b6dd4e1b83a62c82d..4a2f458135211144734b789f7f2faaac0bc4885a 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/navigation/BriarSidebar.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/navigation/BriarSidebar.kt @@ -25,10 +25,11 @@ 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.foundation.selection.selectable +import androidx.compose.foundation.selection.selectableGroup +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.Surface import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ChromeReaderMode import androidx.compose.material.icons.filled.Contacts @@ -40,17 +41,23 @@ import androidx.compose.material.icons.filled.WifiTethering import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.unit.dp import org.briarproject.bramble.api.identity.LocalAuthor import org.briarproject.briar.desktop.contact.ProfileCircle -import org.briarproject.briar.desktop.theme.sidebarSurface +import org.briarproject.briar.desktop.ui.BackgroundSurface import org.briarproject.briar.desktop.ui.UiMode import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n import org.briarproject.briar.desktop.utils.getDesktopFeatureFlags val SIDEBAR_WIDTH = 56.dp +/** + * The sidebar used in Briar Desktop as main navigation. + * It currently follows the MaterialTheme Navigation Rail compact design for all screen sizes, + * but could be adapted in future to extend to standard size (72.dp) or even a standard Navigation Drawer for large screens. + */ @Composable fun BriarSidebar( account: LocalAuthor?, @@ -67,7 +74,10 @@ fun BriarSidebar( ) } - Surface(modifier = Modifier.width(SIDEBAR_WIDTH).fillMaxHeight(), color = MaterialTheme.colors.sidebarSurface) { + BackgroundSurface( + modifier = Modifier.width(SIDEBAR_WIDTH).fillMaxHeight().selectableGroup(), + overlayAlpha = 0.08f, + ) { Column(verticalArrangement = Arrangement.Top) { // profile button Box( @@ -109,11 +119,16 @@ fun BriarSidebar( @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), - onClick = onClick + val tint = if (selected) MaterialTheme.colors.primaryVariant else MaterialTheme.colors.onBackground.copy(alpha = 0.6f) + Box( + contentAlignment = Alignment.Center, + modifier = Modifier.clip(CircleShape).selectable(selected, onClick = onClick).size(SIDEBAR_WIDTH) ) { - Icon(icon, contentDescription, tint = tint, modifier = Modifier.size(30.dp)) + Icon( + icon, + contentDescription, + tint = tint, + modifier = Modifier.size(24.dp) + ) } } diff --git a/src/main/kotlin/org/briarproject/briar/desktop/theme/Colors.kt b/src/main/kotlin/org/briarproject/briar/desktop/theme/Colors.kt index 7ff1bedee63ef77f5e8c6eddb1f5983c66cb408b..4759bf29391ff1e1a691f3fd527e219e91067bd2 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/theme/Colors.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/theme/Colors.kt @@ -20,10 +20,17 @@ package org.briarproject.briar.desktop.theme import androidx.compose.ui.graphics.Color +/** + * All the colors defined in this file are taken from the Briar Styleguide. + * See https://briar-styleguide.netlify.app/design/ + */ + val Night50 = Color(0xffebf3fa) val Night500 = Color(0xff435b77) +val Night600 = Color(0xff374b61) val Night700 = Color(0xff2e3d4f) val Night800 = Color(0xff212d3b) +val Night900 = Color(0xff15212d) val Night950 = Color(0xff0e171f) val Gray50 = Color(0xfffafafa) @@ -36,27 +43,32 @@ val Gray700 = Color(0xff707070) val Gray800 = Color(0xff4f4f4f) val Gray900 = Color(0xff2e2e2e) val Gray950 = Color(0xff1f1f1f) -val materialDarkBg = Color(0xff121212) val Red500 = Color(0xffdb3b21) -val Orange500 = Color(0xfffc9403) -// taken from Android AppCompat DayNight theme as error colors -// https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx-appcompat-release/appcompat/appcompat/src/main/res/values/colors_material.xml#102 -val DeepOrange400 = Color(0xffff7043) -val DeepOrange500 = Color(0xffff5722) +val Orange200 = Color(0xfffed69f) +val Orange500 = Color(0xfffc9403) +val Orange800 = Color(0xffa35200) +val Blue300 = Color(0xff73afea) val Blue400 = Color(0xff418cd8) -val Blue500 = Color(0xff1f78d1) // todo: unused in Android +val Blue500 = Color(0xff1f78d1) val Blue600 = Color(0xff1b69b6) val Blue800 = Color(0xff134a81) val Lime300 = Color(0xff95DE2D) +val Lime400 = Color(0xff82c91e) val Lime500 = Color(0xff74B816) +val Lime600 = Color(0xff67a60f) +val Lime800 = Color(0xff3e620c) +// taken from Android AppCompat DayNight theme as error colors +// https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx-appcompat-release/appcompat/appcompat/src/main/res/values/colors_material.xml#102 +val DeepOrange400 = Color(0xffff7043) +val DeepOrange500 = Color(0xffff5722) + +// taken from Briar Android val TextPrimaryMaterialDark = Color(0xffffffff) val TextPrimaryMaterialLight = Color(0xde000000) val TextSecondaryMaterialDark = Color(0xb3ffffff) val TextSecondaryMaterialLight = Color(0x8a000000) - -val briarError = Color(0xffb00020) diff --git a/src/main/kotlin/org/briarproject/briar/desktop/theme/Theme.kt b/src/main/kotlin/org/briarproject/briar/desktop/theme/Theme.kt index 69d6ae7d859ab7e76df8b2c0305f84686962f730..6833cebead3d9431fb76860668b447725785c45c 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/theme/Theme.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/theme/Theme.kt @@ -35,11 +35,12 @@ import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.platform.Font import androidx.compose.ui.unit.sp -val Colors.divider: Color get() = if (isLight) Gray300 else Gray800 +val Colors.divider: Color get() = if (isLight) Gray300 else Night700 val Colors.outline: Color get() = if (isLight) Gray900 else Gray200 +@Deprecated("use BackgroundSurface with a suitable overlayAlpha instead") val Colors.surfaceVariant: Color get() = if (isLight) Gray100 else Gray950 -val Colors.sidebarSurface: Color get() = if (isLight) Gray200 else Gray900 -val Colors.selectedCard: Color get() = if (isLight) Gray400 else Gray700 +val Colors.selectedCard: Color get() = if (isLight) Gray300 else Night600 +val Colors.contactConnected: Color get() = Lime500 val Colors.msgStroke: Color get() = if (isLight) Gray300 else Gray900 val Colors.msgIn: Color get() = if (isLight) Color.White else Night700 val Colors.msgOut: Color get() = if (isLight) Blue400 else Blue600 @@ -55,10 +56,10 @@ val Colors.warningForeground get() = Color.White val DarkColors = darkColors( primary = Blue500, - primaryVariant = Night500, - secondary = Lime500, - background = materialDarkBg, - surface = materialDarkBg, + primaryVariant = Blue500, + secondary = Lime400, + background = Night900, + surface = Night800, error = DeepOrange400, onPrimary = Color.White, onSecondary = Color.White, @@ -67,14 +68,14 @@ val DarkColors = darkColors( onError = Color.White, ) val LightColors = lightColors( - primary = Blue500, - primaryVariant = Night500, - secondary = Lime300, - background = Color.White, + primary = Blue800, + primaryVariant = Blue600, + secondary = Lime600, + background = Gray100, surface = Color.White, error = DeepOrange500, onPrimary = Color.White, - onSecondary = Color.Black, + onSecondary = Color.White, onBackground = Color.Black, onSurface = Color.Black, onError = Color.White, diff --git a/src/main/kotlin/org/briarproject/briar/desktop/ui/BackgroundSurface.kt b/src/main/kotlin/org/briarproject/briar/desktop/ui/BackgroundSurface.kt new file mode 100644 index 0000000000000000000000000000000000000000..01f7194b01c9fde65917b257e5d9bcf14dea4d80 --- /dev/null +++ b/src/main/kotlin/org/briarproject/briar/desktop/ui/BackgroundSurface.kt @@ -0,0 +1,51 @@ +/* + * Briar Desktop + * Copyright (C) 2021-2022 The Briar Project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +package org.briarproject.briar.desktop.ui + +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Surface +import androidx.compose.material.contentColorFor +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.RectangleShape +import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.graphics.compositeOver + +/** + * A surface that is meant to be used as background, with [MaterialTheme.colors.background] as default color. + * It will automatically match the corresponding [contentColor] if the given [color] is part of the Material theme. + * An [overlayAlpha] value bigger than zero applies a color overlay to the background color, + * that can be used to generate slightly varying colors for different parts of the UI. + */ +@Composable +fun BackgroundSurface( + modifier: Modifier = Modifier, + shape: Shape = RectangleShape, + overlayAlpha: Float = 0f, + color: Color = MaterialTheme.colors.background, + contentColor: Color = contentColorFor(color), + content: @Composable () -> Unit +) = Surface( + modifier = modifier, + shape = shape, + color = if (overlayAlpha != 0f) contentColor.copy(alpha = overlayAlpha).compositeOver(color) else color, + contentColor = contentColor, + content = content +) diff --git a/src/main/kotlin/org/briarproject/briar/desktop/ui/MessageCounter.kt b/src/main/kotlin/org/briarproject/briar/desktop/ui/MessageCounter.kt index 07f2c8d71f9b64e85901401ff4f8b77bd39f40b0..938230e75abf511cda5ff2cb7ba39d1de1aef434 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/ui/MessageCounter.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/ui/MessageCounter.kt @@ -37,19 +37,18 @@ import org.briarproject.briar.desktop.theme.outline @Composable fun MessageCounter(unread: Int, modifier: Modifier = Modifier) { - val outlineColor = MaterialTheme.colors.outline - val briarSecondary = MaterialTheme.colors.secondary if (unread > 0) { Box( modifier = modifier .height(20.dp) .widthIn(min = 20.dp, max = Dp.Infinity) - .border(1.dp, outlineColor, CircleShape) - .background(briarSecondary, CircleShape) + .border(2.dp, MaterialTheme.colors.outline, CircleShape) + .background(MaterialTheme.colors.primary, CircleShape) .padding(horizontal = 6.dp) ) { Text( modifier = Modifier.align(Alignment.Center), + color = MaterialTheme.colors.onPrimary, style = MaterialTheme.typography.overline, textAlign = TextAlign.Center, text = unread.toString(), diff --git a/src/main/kotlin/org/briarproject/briar/desktop/ui/UiPlaceholder.kt b/src/main/kotlin/org/briarproject/briar/desktop/ui/UiPlaceholder.kt index 39c7f933066370e4df01660133ed1945c40a81e6..4c984fa4de27b2fca1f8b43a88c70ab46d2dcf77 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/ui/UiPlaceholder.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/ui/UiPlaceholder.kt @@ -26,9 +26,11 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @Composable -fun UiPlaceholder() = Box( - contentAlignment = Alignment.Center, - modifier = Modifier.fillMaxSize() -) { - Text("TBD") +fun UiPlaceholder() = BackgroundSurface { + Box( + contentAlignment = Alignment.Center, + modifier = Modifier.fillMaxSize() + ) { + Text("TBD") + } } diff --git a/src/main/kotlin/org/briarproject/briar/desktop/utils/PreviewUtils.kt b/src/main/kotlin/org/briarproject/briar/desktop/utils/PreviewUtils.kt index fa5c8e52675fc6c5b5afaaa485c48a1dfabaf5ee..a376f5ae14d89657320f1ca6a83c5d53ef8786f9 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/utils/PreviewUtils.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/utils/PreviewUtils.kt @@ -52,6 +52,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.window.singleWindowApplication import org.briarproject.bramble.api.UniqueId import org.briarproject.briar.desktop.theme.BriarTheme +import org.briarproject.briar.desktop.ui.BackgroundSurface import org.briarproject.briar.desktop.ui.LocalWindowScope import kotlin.random.Random @@ -225,7 +226,7 @@ object PreviewUtils { } BriarTheme(isDarkTheme = scope.getBooleanParameter("darkTheme")) { - Box(Modifier.fillMaxSize(1f)) { + BackgroundSurface(Modifier.fillMaxSize(1f)) { Column(Modifier.padding(10.dp)) { content(scope) }