From 0f286032f6ebe59f6ddb14b56c14aecb76034c97 Mon Sep 17 00:00:00 2001 From: Torsten Grote <t@grobox.de> Date: Tue, 20 Sep 2022 18:38:41 -0300 Subject: [PATCH] Address review feedback for initial forum prototype --- .../briar/desktop/contact/ContactList.kt | 8 ++++- .../briar/desktop/forums/AddForumDialog.kt | 7 ++--- .../forums/{ForumsItem.kt => ForumItem.kt} | 31 ++++++++++++++++++- .../{ForumsScreen.kt => ForumScreen.kt} | 10 +++--- .../{ForumsViewModel.kt => ForumViewModel.kt} | 23 +++++++------- .../forums/{GroupsCard.kt => GroupCard.kt} | 23 +++++++++----- .../briar/desktop/forums/GroupCircle.kt | 13 ++++---- .../desktop/forums/GroupConversationScreen.kt | 10 +++--- .../desktop/forums/GroupInputComposable.kt | 2 +- .../{ForumsList.kt => GroupListComposable.kt} | 14 ++++++--- .../briar/desktop/forums/ThreadItem.kt | 23 +++----------- .../briar/desktop/threading/BriarExecutors.kt | 5 +++ .../desktop/threading/BriarExecutorsImpl.kt | 15 +++++++++ .../briar/desktop/ui/MainScreen.kt | 4 +-- .../{contact => ui}/SearchTextField.kt | 6 ++-- .../briar/desktop/viewmodel/DbViewModel.kt | 25 +++++---------- .../desktop/viewmodel/ViewModelModule.kt | 6 ++-- .../resources/strings/BriarDesktop.properties | 5 ++- 18 files changed, 140 insertions(+), 90 deletions(-) rename briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/{ForumsItem.kt => ForumItem.kt} (55%) rename briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/{ForumsScreen.kt => ForumScreen.kt} (94%) rename briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/{ForumsViewModel.kt => ForumViewModel.kt} (91%) rename briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/{GroupsCard.kt => GroupCard.kt} (86%) rename briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/{ForumsList.kt => GroupListComposable.kt} (88%) rename briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/{contact => ui}/SearchTextField.kt (93%) diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactList.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactList.kt index be304ce31c..c2b33acd9b 100644 --- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactList.kt +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactList.kt @@ -44,6 +44,7 @@ import androidx.compose.ui.unit.dp import org.briarproject.briar.desktop.theme.surfaceVariant import org.briarproject.briar.desktop.ui.Constants.COLUMN_WIDTH import org.briarproject.briar.desktop.ui.Constants.HEADER_SIZE +import org.briarproject.briar.desktop.ui.SearchTextField import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n @Composable @@ -70,6 +71,7 @@ fun ContactList( placeholder = i18n("contacts.search.title"), icon = Icons.Filled.PersonAdd, searchValue = filterBy, + addButtonDescription = i18n("access.contacts.add"), onValueChange = setFilterBy, onAddButtonClicked = onContactAdd, ) @@ -89,7 +91,11 @@ fun ContactList( contactItem, onSel = { selectContact(contactItem) }, selected = isSelected(contactItem), - onRemovePending = { if (contactItem is PendingContactItem) removePendingContact(contactItem) }, + onRemovePending = { + if (contactItem is PendingContactItem) { + removePendingContact(contactItem) + } + }, ) } } 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 26511da0f9..c0f6e74bc5 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 @@ -52,10 +52,10 @@ import androidx.compose.ui.window.rememberDialogState import org.briarproject.briar.api.forum.ForumConstants.MAX_FORUM_NAME_LENGTH import org.briarproject.briar.desktop.utils.AccessibilityUtils.description import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n -import org.briarproject.briar.desktop.utils.PreviewUtils +import org.briarproject.briar.desktop.utils.PreviewUtils.preview import java.awt.Dimension -fun main() = PreviewUtils.preview { +fun main() = preview { val visible = mutableStateOf(true) AddForumDialog(visible, {}, { visible.value = false }) } @@ -66,13 +66,13 @@ fun AddForumDialog( onCreate: (String) -> Unit, onCancelButtonClicked: () -> Unit, ) { + if (!visible.value) return Dialog( title = i18n("forum.add.title"), onCloseRequest = onCancelButtonClicked, state = rememberDialogState( position = WindowPosition(Alignment.Center), ), - visible = visible.value, ) { window.minimumSize = Dimension(360, 180) val scaffoldState = rememberScaffoldState() @@ -101,7 +101,6 @@ fun AddForumDialog( okButtonEnabled = isValidForumName(name.value), onOkButtonClicked = { onCreate(name.value) - name.value = "" }, onCancelButtonClicked = onCancelButtonClicked, ) diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumsItem.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumItem.kt similarity index 55% rename from briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumsItem.kt rename to briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumItem.kt index a8765ab1cd..b3b4820f94 100644 --- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumsItem.kt +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumItem.kt @@ -18,9 +18,16 @@ 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 @@ -28,9 +35,10 @@ interface GroupItem { val msgCount: Int val unread: Int val timestamp: Long + val description: AnnotatedString } -data class ForumsItem( +data class ForumItem( val forum: Forum, override val msgCount: Int, override val unread: Int, @@ -46,4 +54,25 @@ data class ForumsItem( 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 + } + + override fun hashCode(): Int { + return forum.hashCode() + } } diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumsScreen.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumScreen.kt similarity index 94% rename from briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumsScreen.kt rename to briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumScreen.kt index 1b4cca977d..55b598364c 100644 --- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumsScreen.kt +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumScreen.kt @@ -36,8 +36,8 @@ import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n import org.briarproject.briar.desktop.viewmodel.viewModel @Composable -fun ForumsScreen( - viewModel: ForumsViewModel = viewModel(), +fun ForumScreen( + viewModel: ForumViewModel = viewModel(), ) { val addDialogVisible = remember { mutableStateOf(false) } AddForumDialog( @@ -49,12 +49,12 @@ fun ForumsScreen( onCancelButtonClicked = { addDialogVisible.value = false } ) - if (viewModel.groupList.value.isEmpty()) { + if (viewModel.forumList.value.isEmpty()) { NoForumsYet { addDialogVisible.value = true } } else { Row(modifier = Modifier.fillMaxWidth()) { - ForumsList( - list = viewModel.groupList, + GroupListComposable( + list = viewModel.forumList, isSelected = viewModel::isSelected, filterBy = viewModel.filterBy, onFilterSet = viewModel::setFilterBy, diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumsViewModel.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumViewModel.kt similarity index 91% rename from briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumsViewModel.kt rename to briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumViewModel.kt index 8755aa850d..7b70e4b40c 100644 --- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumsViewModel.kt +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumViewModel.kt @@ -18,7 +18,6 @@ package org.briarproject.briar.desktop.forums -import androidx.compose.runtime.State import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf @@ -57,7 +56,7 @@ class Loaded( val posts: MutableList<ThreadItem> get() = messageTree.depthFirstOrder() } -class ForumsViewModel @Inject constructor( +class ForumViewModel @Inject constructor( private val forumManager: ForumManager, private val identityManager: IdentityManager, private val clock: Clock, @@ -68,22 +67,22 @@ class ForumsViewModel @Inject constructor( eventBus: EventBus, ) : EventListenerDbViewModel(briarExecutors, lifecycleManager, db, eventBus) { - private val _fullGroupList = mutableStateListOf<ForumsItem>() - val groupList = derivedStateOf { + private val _fullForumList = mutableStateListOf<ForumItem>() + val forumList = derivedStateOf { val filter = _filterBy.value - _fullGroupList.filter { item -> + _fullForumList.filter { item -> item.name.contains(filter, ignoreCase = true) }.sortedByDescending { it.timestamp } } private val _selectedGroupItem = mutableStateOf<GroupItem?>(null) - val selectedGroupItem: State<GroupItem?> = _selectedGroupItem + val selectedGroupItem = _selectedGroupItem.asState() private val _filterBy = mutableStateOf("") val filterBy = _filterBy.asState() private val _posts = mutableStateOf<PostsState>(Loading) - val posts: State<PostsState> = _posts + val posts = _posts.asState() override fun onInit() { super.onInit() @@ -108,13 +107,13 @@ class ForumsViewModel @Inject constructor( private fun loadGroups() { runOnDbThreadWithTransaction(true) { txn -> val list = forumManager.getForums(txn).map { forums -> - ForumsItem( - forums, - forumManager.getGroupCount(txn, forums.id), + ForumItem( + forum = forums, + groupCount = forumManager.getGroupCount(txn, forums.id), ) } txn.attach { - _fullGroupList.clearAndAddAll(list) + _fullForumList.clearAndAddAll(list) } } } @@ -174,6 +173,6 @@ class ForumsViewModel @Inject constructor( } fun deleteGroup(groupItem: GroupItem) { - forumManager.removeForum((groupItem as ForumsItem).forum) + forumManager.removeForum((groupItem as ForumItem).forum) } } diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/GroupsCard.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/GroupCard.kt similarity index 86% rename from briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/GroupsCard.kt rename to briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/GroupCard.kt index 68f3a255c0..7ef6bb884b 100644 --- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/GroupsCard.kt +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/GroupCard.kt @@ -18,13 +18,13 @@ package org.briarproject.briar.desktop.forums -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement.SpaceBetween 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.padding +import androidx.compose.foundation.selection.selectable import androidx.compose.foundation.selection.selectableGroup import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Card @@ -35,8 +35,11 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment.Companion.CenterVertically import androidx.compose.ui.Alignment.Companion.Start import androidx.compose.ui.Modifier +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 @@ -44,13 +47,14 @@ import org.briarproject.briar.desktop.theme.surfaceVariant import org.briarproject.briar.desktop.ui.Constants.HEADER_SIZE import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18nP -import org.briarproject.briar.desktop.utils.PreviewUtils +import org.briarproject.briar.desktop.utils.PreviewUtils.preview import org.briarproject.briar.desktop.utils.TimeUtils.getFormattedTimestamp +import org.briarproject.briar.desktop.utils.buildBlankAnnotatedString @Suppress("HardCodedStringLiteral") -fun main() = PreviewUtils.preview { +fun main() = preview { Column(Modifier.selectableGroup()) { - GroupsCard( + GroupCard( item = object : GroupItem { override val id: GroupId = GroupId(getRandomId()) override val name: String = @@ -58,6 +62,7 @@ fun main() = PreviewUtils.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, @@ -66,7 +71,7 @@ fun main() = PreviewUtils.preview { } @Composable -fun GroupsCard( +fun GroupCard( item: GroupItem, onGroupItemSelected: (GroupItem) -> Unit, selected: Boolean, @@ -75,7 +80,7 @@ fun GroupsCard( modifier = Modifier .fillMaxWidth() .defaultMinSize(minHeight = HEADER_SIZE) - .clickable(onClick = { onGroupItemSelected(item) }) + .selectable(selected, onClick = { onGroupItemSelected(item) }, role = Role.Button) .semantics { contentDescription = if (selected) i18n("access.list.selected.yes") @@ -90,7 +95,11 @@ fun GroupsCard( contentColor = MaterialTheme.colors.onSurface, ) { Row( - modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp), + modifier = Modifier + .padding(horizontal = 8.dp, vertical = 4.dp) + .semantics { + text = item.description + }, ) { GroupCircle(item, modifier = Modifier.align(Alignment.Top).padding(vertical = 12.dp)) Column( 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 76874e0a7b..c3b244d259 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 @@ -39,6 +39,7 @@ 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) { @@ -54,7 +55,7 @@ fun GroupCircle(item: GroupItem, showMessageCount: Boolean = true, modifier: Mod .background(item.id.getBackgroundColor()), ) { Text( - text = item.name.substring(0..0).uppercase(), + text = item.name.substring(0..0).uppercase(locale), color = Color.White, style = MaterialTheme.typography.body1.copy( fontSize = 24.sp, @@ -75,12 +76,12 @@ fun GroupCircle(item: GroupItem, showMessageCount: Boolean = true, modifier: Mod fun GroupId.getBackgroundColor(): Color { return Color( - red = getByte(bytes, 0) * 3 / 4 + 96, - green = getByte(bytes, 1) * 3 / 4 + 96, - blue = getByte(bytes, 2) * 3 / 4 + 96, + red = bytes.getByte(0) * 3 / 4 + 96, + green = bytes.getByte(1) * 3 / 4 + 96, + blue = bytes.getByte(2) * 3 / 4 + 96, ) } -private fun getByte(bytes: ByteArray, index: Int): Byte { - return bytes[index % bytes.size] +private fun ByteArray.getByte(index: Int): Byte { + return this[index % size] } 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 679d8a76f7..600b8fbd17 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 @@ -60,7 +60,7 @@ import org.briarproject.briar.desktop.viewmodel.viewModel @Composable fun GroupConversationScreen( groupItem: GroupItem, - viewModel: ForumsViewModel = viewModel(), + viewModel: ForumViewModel = viewModel(), ) { val selectedPost = remember { mutableStateOf<MessageId?>(null) } Scaffold( @@ -87,7 +87,7 @@ private fun GroupConversationHeader( groupItem: GroupItem, onGroupDelete: () -> Unit, ) { - val deleteGroupDialogState = remember { mutableStateOf(false) } + val deleteGroupDialogVisible = remember { mutableStateOf(false) } val menuState = remember { mutableStateOf(CLOSED) } val close = { menuState.value = CLOSED } Box(modifier = Modifier.fillMaxWidth().height(HEADER_SIZE + 1.dp)) { @@ -130,7 +130,7 @@ private fun GroupConversationHeader( DropdownMenuItem( onClick = { close() - deleteGroupDialogState.value = true + deleteGroupDialogVisible.value = true } ) { Text( @@ -143,9 +143,9 @@ private fun GroupConversationHeader( } HorizontalDivider(modifier = Modifier.align(BottomCenter)) } - if (deleteGroupDialogState.value) { + if (deleteGroupDialogVisible.value) { DeleteForumDialog( - close = { deleteGroupDialogState.value = false }, + close = { deleteGroupDialogVisible.value = false }, onDelete = onGroupDelete, ) } diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/GroupInputComposable.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/GroupInputComposable.kt index 152c39e77b..1b1b7120e9 100644 --- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/GroupInputComposable.kt +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/GroupInputComposable.kt @@ -73,7 +73,7 @@ fun GroupInputComposable( text = if (selectedPost.value == null) { i18n("forum.message.hint") } else { - i18n("forum.message.replay.hint") + i18n("forum.message.reply.hint") }, style = MaterialTheme.typography.body1, ) diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumsList.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/GroupListComposable.kt similarity index 88% rename from briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumsList.kt rename to briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/GroupListComposable.kt index e90dd40aea..7ced0abe86 100644 --- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumsList.kt +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/GroupListComposable.kt @@ -39,17 +39,19 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.State 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.unit.dp import org.briarproject.bramble.api.sync.GroupId -import org.briarproject.briar.desktop.contact.SearchTextField import org.briarproject.briar.desktop.theme.surfaceVariant import org.briarproject.briar.desktop.ui.Constants import org.briarproject.briar.desktop.ui.Constants.COLUMN_WIDTH import org.briarproject.briar.desktop.ui.HorizontalDivider +import org.briarproject.briar.desktop.ui.SearchTextField import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n @Composable -fun ForumsList( +fun GroupListComposable( list: State<List<GroupItem>>, isSelected: (GroupId) -> Boolean, filterBy: State<String>, @@ -70,6 +72,7 @@ fun ForumsList( placeholder = i18n("forum.search.title"), icon = Icons.Filled.AddComment, searchValue = filterBy.value, + addButtonDescription = i18n("forum.add.title"), onValueChange = onFilterSet, onAddButtonClicked = onAddButtonClicked, ) @@ -77,10 +80,13 @@ fun ForumsList( Box(modifier = Modifier.fillMaxSize()) { LazyColumn( state = scrollState, - modifier = Modifier.selectableGroup() + modifier = Modifier + .semantics { + contentDescription = i18n("access.forums.list") + }.selectableGroup() ) { items(list.value) { item -> - GroupsCard( + GroupCard( item = item, onGroupItemSelected = onGroupItemSelected, selected = isSelected(item.id) 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 bd1dc746ed..ee751e90dd 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 @@ -55,21 +55,10 @@ abstract class ThreadItem( private var level: Int = UNDEFINED var isHighlighted = false - fun getLevel(): Int { - return level - } - - override fun getId(): MessageId { - return messageId - } - - override fun getParentId(): MessageId? { - return parentId - } - - override fun getTimestamp(): Long { - return timestamp - } + override fun getId(): MessageId = messageId + override fun getParentId(): MessageId? = parentId + override fun getTimestamp(): Long = timestamp + fun getLevel(): Int = level /** * Returns the author's name, with an alias if one exists. @@ -81,9 +70,7 @@ abstract class ThreadItem( this.level = level } - override fun hashCode(): Int { - return messageId.hashCode() - } + override fun hashCode(): Int = messageId.hashCode() override fun equals(other: Any?): Boolean { return other is ThreadItem && messageId == other.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 545c12cd79..e18685288a 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,6 +30,11 @@ interface BriarExecutors { @DatabaseExecutor task: (Transaction) -> Unit, ) + suspend fun <T> runOnDbThread( + readOnly: Boolean, + @DatabaseExecutor task: (Transaction) -> T, + ): T + fun onUiThread(@UiExecutor task: () -> Unit) fun onIoThread(@IoExecutor task: () -> Unit) 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 f002b48e0a..0700aa2092 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 @@ -20,6 +20,7 @@ package org.briarproject.briar.desktop.threading import mu.KotlinLogging import org.briarproject.bramble.api.db.DatabaseExecutor +import org.briarproject.bramble.api.db.DbCallable import org.briarproject.bramble.api.db.Transaction import org.briarproject.bramble.api.db.TransactionManager import org.briarproject.bramble.api.lifecycle.IoExecutor @@ -27,6 +28,8 @@ import org.briarproject.bramble.api.lifecycle.LifecycleManager import org.briarproject.briar.desktop.utils.KLoggerUtils.w import java.util.concurrent.Executor import javax.inject.Inject +import kotlin.coroutines.resume +import kotlin.coroutines.suspendCoroutine class BriarExecutorsImpl @Inject @@ -75,6 +78,18 @@ constructor( } } + override suspend fun <T> runOnDbThread( + readOnly: Boolean, + @DatabaseExecutor task: (Transaction) -> T + ) = suspendCoroutine<T> { cont -> + // The coroutine suspends until the DatabaseExecutor has finished the task + // and ended the transaction. It then resumes with the returned value. + onDbThread { + val t = db.transactionWithResult(readOnly, DbCallable { txn -> task(txn) }) + cont.resume(t) + } + } + override fun onUiThread(@UiExecutor task: () -> Unit) = uiExecutor.execute(task) override fun onIoThread(@IoExecutor task: () -> Unit) = ioExecutor.execute(task) 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 43245ff456..0e2dfd36d7 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 @@ -21,7 +21,7 @@ package org.briarproject.briar.desktop.ui import androidx.compose.foundation.layout.Row import androidx.compose.runtime.Composable import org.briarproject.briar.desktop.conversation.PrivateMessageScreen -import org.briarproject.briar.desktop.forums.ForumsScreen +import org.briarproject.briar.desktop.forums.ForumScreen import org.briarproject.briar.desktop.navigation.BriarSidebar import org.briarproject.briar.desktop.navigation.SidebarViewModel import org.briarproject.briar.desktop.privategroups.PrivateGroupScreen @@ -45,7 +45,7 @@ fun MainScreen(viewModel: SidebarViewModel = viewModel()) { when (viewModel.uiMode.value) { UiMode.CONTACTS -> PrivateMessageScreen() UiMode.GROUPS -> PrivateGroupScreen() - UiMode.FORUMS -> ForumsScreen() + UiMode.FORUMS -> ForumScreen() UiMode.SETTINGS -> SettingsScreen() UiMode.ABOUT -> AboutScreen() else -> UiPlaceholder() 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/ui/SearchTextField.kt similarity index 93% rename from briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/SearchTextField.kt rename to briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/SearchTextField.kt index 6d3e564dfb..b61a0466ab 100644 --- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/SearchTextField.kt +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/SearchTextField.kt @@ -16,7 +16,7 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ -package org.briarproject.briar.desktop.contact +package org.briarproject.briar.desktop.ui import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding @@ -32,7 +32,6 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.unit.dp -import org.briarproject.briar.desktop.ui.ColoredIconButton import org.briarproject.briar.desktop.utils.AccessibilityUtils.description import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n @@ -41,6 +40,7 @@ fun SearchTextField( placeholder: String, icon: ImageVector, searchValue: String, + addButtonDescription: String, onValueChange: (String) -> Unit, onAddButtonClicked: () -> Unit, ) { @@ -61,7 +61,7 @@ fun SearchTextField( ColoredIconButton( icon = icon, iconSize = 20.dp, - contentDescription = i18n("access.contacts.add"), + contentDescription = addButtonDescription, onClick = onAddButtonClicked, modifier = Modifier.padding(end = 8.dp) ) 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 b82cb09a2f..8547165856 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 @@ -18,26 +18,18 @@ package org.briarproject.briar.desktop.viewmodel -import mu.KotlinLogging import org.briarproject.bramble.api.db.DatabaseExecutor -import org.briarproject.bramble.api.db.DbCallable import org.briarproject.bramble.api.db.Transaction import org.briarproject.bramble.api.db.TransactionManager import org.briarproject.bramble.api.lifecycle.LifecycleManager import org.briarproject.briar.desktop.threading.BriarExecutors -import kotlin.coroutines.resume -import kotlin.coroutines.suspendCoroutine abstract class DbViewModel( private val briarExecutors: BriarExecutors, private val lifecycleManager: LifecycleManager, - private val db: TransactionManager + private val db: TransactionManager, ) : ViewModel { - companion object { - private val LOG = KotlinLogging.logger {} - } - /** * Waits for the DB to open and runs the given [task] on the [DatabaseExecutor]. * To avoid inconsistent state between the database and the UI @@ -54,16 +46,15 @@ abstract class DbViewModel( */ protected fun runOnDbThreadWithTransaction( readOnly: Boolean, - task: (Transaction) -> Unit + task: (Transaction) -> Unit, ) = briarExecutors.onDbThreadWithTransaction(readOnly, task) + /** + * Waits for the DB to open and runs the given [task] on the [DatabaseExecutor], + * returning its result. + */ protected suspend fun <T> runOnDbThread( readOnly: Boolean, - task: (Transaction) -> T - ) = suspendCoroutine<T> { cont -> - briarExecutors.onDbThread { - val t = db.transactionWithResult(readOnly, DbCallable { txn -> task(txn) }) - cont.resume(t) - } - } + @DatabaseExecutor task: (Transaction) -> T, + ): T = briarExecutors.runOnDbThread(readOnly, task) } diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/viewmodel/ViewModelModule.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/viewmodel/ViewModelModule.kt index 9f29948d41..bcb4353996 100644 --- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/viewmodel/ViewModelModule.kt +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/viewmodel/ViewModelModule.kt @@ -25,7 +25,7 @@ import dagger.multibindings.IntoMap import org.briarproject.briar.desktop.contact.ContactListViewModel import org.briarproject.briar.desktop.contact.add.remote.AddContactViewModel import org.briarproject.briar.desktop.conversation.ConversationViewModel -import org.briarproject.briar.desktop.forums.ForumsViewModel +import org.briarproject.briar.desktop.forums.ForumViewModel import org.briarproject.briar.desktop.introduction.IntroductionViewModel import org.briarproject.briar.desktop.login.StartupViewModel import org.briarproject.briar.desktop.navigation.SidebarViewModel @@ -76,8 +76,8 @@ abstract class ViewModelModule { @Binds @IntoMap - @ViewModelKey(ForumsViewModel::class) - abstract fun bindForumsViewModel(forumsViewModel: ForumsViewModel): ViewModel + @ViewModelKey(ForumViewModel::class) + abstract fun bindForumsViewModel(forumViewModel: ForumViewModel): ViewModel @Binds @IntoMap diff --git a/briar-desktop/src/main/resources/strings/BriarDesktop.properties b/briar-desktop/src/main/resources/strings/BriarDesktop.properties index 28a7b003cd..0ccafe4e80 100644 --- a/briar-desktop/src/main/resources/strings/BriarDesktop.properties +++ b/briar-desktop/src/main/resources/strings/BriarDesktop.properties @@ -60,6 +60,9 @@ access.settings.click_to_toggle_notifications=Click to toggle notifications access.return_to_previous_screen=Return to previous screen 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} # Contacts contacts.none_selected.title=No contact selected @@ -115,7 +118,7 @@ forum.delete.dialog.title=Confirm Leaving Forum forum.delete.dialog.message=Are you sure that you want to leave this forum?\n\nAny contacts you\'ve shared this forum with might stop receiving updates. forum.delete.dialog.button=Leave forum.message.hint=New Post -forum.message.replay.hint=New Reply +forum.message.reply.hint=New Reply group.card.no_posts=No posts group.card.posts={0, plural, one {{0} post} other {{0} posts}} -- GitLab