diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/AddForumDialog.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/AddForumDialog.kt index d078c9026591778db9208c8c5b2f342de8a63f29..529e80f028af236e5efd9cd133c19a7693c075ac 100644 --- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/AddForumDialog.kt +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/AddForumDialog.kt @@ -20,6 +20,7 @@ package org.briarproject.briar.desktop.forums import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.text.KeyboardOptions @@ -39,7 +40,6 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment -import androidx.compose.ui.Alignment.Companion.CenterEnd import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester @@ -148,21 +148,20 @@ fun OkCancelBottomBar( onOkButtonClicked: () -> Unit, onCancelButtonClicked: () -> Unit, ) { - Box(Modifier.fillMaxWidth()) { - Row(Modifier.align(CenterEnd)) { - TextButton( - onClick = onCancelButtonClicked, - colors = ButtonDefaults.textButtonColors(contentColor = MaterialTheme.colors.error) - ) { - Text(i18n("cancel")) - } - Button( - onClick = onOkButtonClicked, - enabled = okButtonEnabled, - modifier = Modifier.padding(start = 8.dp) - ) { - Text(okButtonLabel) - } + Row(Modifier.fillMaxWidth()) { + Spacer(Modifier.weight(1f)) + TextButton( + onClick = onCancelButtonClicked, + colors = ButtonDefaults.textButtonColors(contentColor = MaterialTheme.colors.error) + ) { + Text(i18n("cancel")) + } + Button( + onClick = onOkButtonClicked, + enabled = okButtonEnabled, + modifier = Modifier.padding(start = 8.dp) + ) { + Text(okButtonLabel) } } } diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumItem.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumItem.kt index b3b4820f949ae91d285faed21e3ef3141f2a169d..83a8b4e19795f6e1fd46a2f41ec28d66c00546e4 100644 --- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumItem.kt +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumItem.kt @@ -18,16 +18,9 @@ package org.briarproject.briar.desktop.forums -import androidx.compose.ui.text.AnnotatedString import org.briarproject.bramble.api.sync.GroupId import org.briarproject.briar.api.client.MessageTracker import org.briarproject.briar.api.forum.Forum -import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n -import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18nF -import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18nP -import org.briarproject.briar.desktop.utils.TimeUtils.getFormattedTimestamp -import org.briarproject.briar.desktop.utils.appendCommaSeparated -import org.briarproject.briar.desktop.utils.buildBlankAnnotatedString interface GroupItem { val id: GroupId @@ -35,7 +28,6 @@ interface GroupItem { val msgCount: Int val unread: Int val timestamp: Long - val description: AnnotatedString } data class ForumItem( @@ -55,19 +47,6 @@ data class ForumItem( override val id: GroupId get() = forum.id override val name: String get() = forum.name - override val description: AnnotatedString - get() = buildBlankAnnotatedString { - append(name) - if (unread > 0) appendCommaSeparated(i18nP("access.forums.unread_count", unread)) - if (msgCount == 0) appendCommaSeparated(i18n("group.card.no_posts")) - else appendCommaSeparated( - i18nF( - "access.forums.last_message_timestamp", - getFormattedTimestamp(timestamp) - ) - ) - } - override fun equals(other: Any?): Boolean { return other is ForumItem && other.id == id } diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumViewModel.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumViewModel.kt index 7b70e4b40c4a64615b31a1f09b7815d7ea352a82..cb766dfa208f97579271f1ddaf59a84eea44293f 100644 --- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumViewModel.kt +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumViewModel.kt @@ -31,12 +31,14 @@ import org.briarproject.bramble.api.db.TransactionManager import org.briarproject.bramble.api.event.Event import org.briarproject.bramble.api.event.EventBus import org.briarproject.bramble.api.identity.IdentityManager +import org.briarproject.bramble.api.identity.LocalAuthor import org.briarproject.bramble.api.lifecycle.LifecycleManager import org.briarproject.bramble.api.sync.GroupId import org.briarproject.bramble.api.sync.MessageId import org.briarproject.bramble.api.sync.event.GroupAddedEvent import org.briarproject.bramble.api.sync.event.GroupRemovedEvent import org.briarproject.bramble.api.system.Clock +import org.briarproject.briar.api.client.MessageTracker.GroupCount import org.briarproject.briar.api.forum.ForumManager import org.briarproject.briar.client.MessageTreeImpl import org.briarproject.briar.desktop.threading.BriarExecutors @@ -144,17 +146,17 @@ class ForumViewModel @Inject constructor( @OptIn(DelicateCoroutinesApi::class) fun createPost(groupItem: GroupItem, text: String, parentId: MessageId?) = GlobalScope.launch { - val author = runOnDbThread(false) { txn -> + val author = runOnDbThreadWithTransaction<LocalAuthor>(false) { txn -> identityManager.getLocalAuthor(txn) } - val count = runOnDbThread(false) { txn -> + val count = runOnDbThreadWithTransaction<GroupCount>(false) { txn -> forumManager.getGroupCount(txn, groupItem.id) } val timestamp = max(count.latestMsgTime + 1, clock.currentTimeMillis()) val post = withContext(cryptoDispatcher) { forumManager.createLocalPost(groupItem.id, text, timestamp, parentId, author) } - runOnDbThread(false) { txn -> + runOnDbThreadWithTransaction(false) { txn -> val header = forumManager.addLocalPost(txn, post) txn.attach { val item = ForumPostItem(header, text) diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/GroupCard.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/GroupCard.kt index 7ef6bb884bcbe7ccd2ac242956a2f7a0d24dc0b0..33ec050a50efe6fca248cd3161d28bf761f00f56 100644 --- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/GroupCard.kt +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/GroupCard.kt @@ -19,10 +19,12 @@ package org.briarproject.briar.desktop.forums import androidx.compose.foundation.layout.Arrangement.SpaceBetween +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.defaultMinSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.selection.selectable import androidx.compose.foundation.selection.selectableGroup @@ -39,16 +41,18 @@ import androidx.compose.ui.semantics.Role 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.unit.dp import org.briarproject.bramble.api.sync.GroupId 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.NumberBadge +import org.briarproject.briar.desktop.utils.InternationalizationUtils import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18nP import org.briarproject.briar.desktop.utils.PreviewUtils.preview import org.briarproject.briar.desktop.utils.TimeUtils.getFormattedTimestamp +import org.briarproject.briar.desktop.utils.appendCommaSeparated import org.briarproject.briar.desktop.utils.buildBlankAnnotatedString @Suppress("HardCodedStringLiteral") @@ -62,7 +66,6 @@ fun main() = preview { override val msgCount: Int = 42 override val unread: Int = 23 override val timestamp: Long = System.currentTimeMillis() - override val description: AnnotatedString = buildBlankAnnotatedString { } }, onGroupItemSelected = {}, selected = false, @@ -94,14 +97,23 @@ fun GroupCard( }, contentColor = MaterialTheme.colors.onSurface, ) { + val itemDescription = getItemDescription(item) Row( modifier = Modifier .padding(horizontal = 8.dp, vertical = 4.dp) .semantics { - text = item.description + text = itemDescription }, ) { - GroupCircle(item, modifier = Modifier.align(Alignment.Top).padding(vertical = 12.dp)) + Box( + modifier = Modifier.align(Alignment.Top).padding(vertical = 12.dp), + ) { + GroupCircle(item) + NumberBadge( + num = item.unread, + modifier = Modifier.align(Alignment.TopEnd).offset(8.dp, (-6).dp) + ) + } Column( verticalArrangement = SpaceBetween, modifier = Modifier.align(CenterVertically).padding(start = 16.dp) @@ -134,3 +146,16 @@ fun GroupCard( } } } + +@Composable +private fun getItemDescription(item: GroupItem) = buildBlankAnnotatedString { + append(item.name) + if (item.unread > 0) appendCommaSeparated(i18nP("access.forums.unread_count", item.unread)) + if (item.msgCount == 0) appendCommaSeparated(i18n("group.card.no_posts")) + else appendCommaSeparated( + InternationalizationUtils.i18nF( + "access.forums.last_post_timestamp", + getFormattedTimestamp(item.timestamp) + ) + ) +} diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/GroupCircle.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/GroupCircle.kt index c3b244d2598b87e7ad8f6a216c11f4448a404934..1a41ac1f4dd732c1a4cabde33c2943d0de611b6e 100644 --- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/GroupCircle.kt +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/GroupCircle.kt @@ -21,14 +21,12 @@ package org.briarproject.briar.desktop.forums import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment.Companion.Center -import androidx.compose.ui.Alignment.Companion.TopEnd import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.geometry.Offset @@ -38,38 +36,29 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import org.briarproject.bramble.api.sync.GroupId import org.briarproject.briar.desktop.theme.outline -import org.briarproject.briar.desktop.ui.NumberBadge import org.briarproject.briar.desktop.utils.InternationalizationUtils.locale @Composable -fun GroupCircle(item: GroupItem, showMessageCount: Boolean = true, modifier: Modifier = Modifier) { +fun GroupCircle(item: GroupItem, modifier: Modifier = Modifier) { Box( + contentAlignment = Center, modifier = modifier + .size(36.dp) + .clip(CircleShape) + .border(1.dp, MaterialTheme.colors.outline, CircleShape) + .background(item.id.getBackgroundColor()), ) { - Box( - contentAlignment = Center, - modifier = Modifier - .size(36.dp) - .clip(CircleShape) - .border(1.dp, MaterialTheme.colors.outline, CircleShape) - .background(item.id.getBackgroundColor()), - ) { - Text( - text = item.name.substring(0..0).uppercase(locale), - color = Color.White, - style = MaterialTheme.typography.body1.copy( - fontSize = 24.sp, - shadow = Shadow( - color = Color.Black.copy(alpha = 0.4f), - offset = Offset(4f, 4f), - blurRadius = 8f - ) + Text( + text = item.name.substring(0..0).uppercase(locale), + color = Color.White, + style = MaterialTheme.typography.body1.copy( + fontSize = 24.sp, + shadow = Shadow( + color = Color.Black.copy(alpha = 0.4f), + offset = Offset(4f, 4f), + blurRadius = 8f ) ) - } - if (showMessageCount) NumberBadge( - num = item.unread, - modifier = Modifier.align(TopEnd).offset(8.dp, (-6).dp) ) } } diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/GroupConversationScreen.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/GroupConversationScreen.kt index 600b8fbd17cb4d12172027e2edbb4e0ee33e1ce3..6540ceec2f0998784cc40f562a68a5620379fcd9 100644 --- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/GroupConversationScreen.kt +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/GroupConversationScreen.kt @@ -103,7 +103,6 @@ private fun GroupConversationHeader( ) { GroupCircle( item = groupItem, - showMessageCount = false, modifier = Modifier.align(CenterVertically), ) Text( diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ThreadItem.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ThreadItem.kt index ee751e90dd109bf6c4b54e350e227bce82a7a046..a751f18fbd566521e3bf639ab027539adf4b32bb 100644 --- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ThreadItem.kt +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ThreadItem.kt @@ -37,6 +37,8 @@ class ForumPostItem(h: ForumPostHeader, text: String?) : ThreadItem( isRead = h.isRead ) +// TODO the mutable state here might need to be made immutable later +// and copy on data classes used to trigger recompositions when items update @NotThreadSafe abstract class ThreadItem( private val messageId: MessageId, diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/threading/BriarExecutors.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/threading/BriarExecutors.kt index e18685288a955c709acdd84e74bd37d5ec2c67b2..d1affd5700904b60e0c2a6bb9e6768400ab3f50d 100644 --- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/threading/BriarExecutors.kt +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/threading/BriarExecutors.kt @@ -30,7 +30,7 @@ interface BriarExecutors { @DatabaseExecutor task: (Transaction) -> Unit, ) - suspend fun <T> runOnDbThread( + suspend fun <T> runOnDbThreadWithTransaction( readOnly: Boolean, @DatabaseExecutor task: (Transaction) -> T, ): T diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/threading/BriarExecutorsImpl.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/threading/BriarExecutorsImpl.kt index 0700aa2092aefa6bd9f67e23ca8818b28ee197a6..28f36dbf3182386c2fbd8adbbca3dfaf9e1a8339 100644 --- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/threading/BriarExecutorsImpl.kt +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/threading/BriarExecutorsImpl.kt @@ -78,7 +78,7 @@ constructor( } } - override suspend fun <T> runOnDbThread( + override suspend fun <T> runOnDbThreadWithTransaction( readOnly: Boolean, @DatabaseExecutor task: (Transaction) -> T ) = suspendCoroutine<T> { cont -> diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/viewmodel/DbViewModel.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/viewmodel/DbViewModel.kt index 8547165856fb888d493aec9fd1cd1524b39d764c..e3b97b9c3178eee70b8657db20de4559d8a4e907 100644 --- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/viewmodel/DbViewModel.kt +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/viewmodel/DbViewModel.kt @@ -53,8 +53,8 @@ abstract class DbViewModel( * Waits for the DB to open and runs the given [task] on the [DatabaseExecutor], * returning its result. */ - protected suspend fun <T> runOnDbThread( + protected suspend fun <T> runOnDbThreadWithTransaction( readOnly: Boolean, @DatabaseExecutor task: (Transaction) -> T, - ): T = briarExecutors.runOnDbThread(readOnly, task) + ): T = briarExecutors.runOnDbThreadWithTransaction(readOnly, task) } diff --git a/briar-desktop/src/main/resources/strings/BriarDesktop.properties b/briar-desktop/src/main/resources/strings/BriarDesktop.properties index 0ccafe4e803b7f07a32ba9acceb40809e9f65661..13b4b15c13c7620499288eb5b4aa5ab30e25ba52 100644 --- a/briar-desktop/src/main/resources/strings/BriarDesktop.properties +++ b/briar-desktop/src/main/resources/strings/BriarDesktop.properties @@ -62,7 +62,7 @@ access.menu=Show menu access.forums.add=Add forum access.forums.list=forum list access.forums.unread_count={0, plural, one {one unread posts} other {{0} unread posts}} -access.forums.last_message_timestamp=last message: {0} +access.forums.last_post_timestamp=last post: {0} # Contacts contacts.none_selected.title=No contact selected