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 e66b88535187b55b52547fe3f5332b820e7bf145..f380fea9d45859e40d2dd81c93e54759590e4aff 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactCard.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactCard.kt @@ -31,7 +31,6 @@ import org.briarproject.briar.desktop.utils.TimeUtils.getFormattedTimestamp @Composable fun ContactCard( contact: Contact, - selContact: Contact, onSel: (Contact) -> Unit, selected: Boolean, drawNotifications: Boolean diff --git a/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactDrawerMakeIntro.kt b/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactDrawerMakeIntro.kt index f8885da16c092b851415d2af2303b01d05c1f36c..d0fc82fb2e26734d115c5ea87701893974ce0057 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactDrawerMakeIntro.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactDrawerMakeIntro.kt @@ -57,7 +57,7 @@ fun ContactDrawerMakeIntro(contact: Contact, contacts: List<Contact>, setInfoDra Column(Modifier.verticalScroll(rememberScrollState())) { for (c in contacts) { if (c.id != contact.id) { - ContactCard(c, contact, { onCancelSel(c); introNextPg = true }, false, false) + ContactCard(c, { onCancelSel(c); introNextPg = true }, false, false) } } } 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 ef1d1a5a112f1c8f3f7e048df4c300557fea29e7..42edcbf1a70fcb48875265490f5a92655992a354 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactList.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactList.kt @@ -5,41 +5,22 @@ import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.width -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.material.MaterialTheme import androidx.compose.material.Scaffold import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import org.briarproject.bramble.api.contact.Contact import org.briarproject.briar.desktop.theme.surfaceVariant import org.briarproject.briar.desktop.ui.Constants.CONTACTLIST_WIDTH import org.briarproject.briar.desktop.ui.Constants.HEADER_SIZE @Composable fun ContactList( - contact: Contact, - contacts: List<Contact>, - onContactSelect: (Contact) -> Unit, - onContactAdd: (Boolean) -> Unit + contacts: ContactsViewModel, + onContactAdd: () -> Unit, ) { - var searchValue by remember { mutableStateOf("") } - val filteredContacts = if (searchValue.isEmpty()) { - ArrayList(contacts) - } else { - val resultList = ArrayList<Contact>() - for (c in contacts) { - if (c.author.name.lowercase().contains(searchValue.lowercase())) { - resultList.add(c) - } - } - resultList - } Scaffold( modifier = Modifier.fillMaxHeight().width(CONTACTLIST_WIDTH), backgroundColor = MaterialTheme.colors.surfaceVariant, @@ -47,13 +28,17 @@ fun ContactList( Column( modifier = Modifier.fillMaxWidth().height(HEADER_SIZE + 1.dp), ) { - SearchTextField(searchValue, onValueChange = { searchValue = it }, onContactAdd) + SearchTextField( + contacts.filterBy.value, + onValueChange = contacts::setFilterBy, + onContactAdd + ) } }, content = { - Column(Modifier.verticalScroll(rememberScrollState())) { - for (c in filteredContacts) { - ContactCard(c, contact, onContactSelect, contact.id == c.id, true) + LazyColumn { + itemsIndexed(contacts.contactList) { index, contact -> + ContactCard(contact, { contacts.selectContact(index) }, contacts.isSelected(index), true) } } }, diff --git a/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactsViewModel.kt b/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactsViewModel.kt index 9e51de185321c436107891c7c371c911423967ed..9bc56f9778384b0006acbb55c087eb4194bf8141 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactsViewModel.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactsViewModel.kt @@ -1,6 +1,8 @@ package org.briarproject.briar.desktop.contact +import androidx.compose.runtime.State import androidx.compose.runtime.mutableStateListOf +import androidx.compose.runtime.mutableStateOf import org.briarproject.bramble.api.contact.Contact import org.briarproject.bramble.api.contact.ContactManager import java.util.logging.Logger @@ -16,17 +18,43 @@ constructor( private val LOG = Logger.getLogger(ContactsViewModel::class.java.name) } - internal val contacts = mutableStateListOf<Contact>() + private val _contactList = mutableListOf<Contact>() + private val _filteredContactList = mutableStateListOf<Contact>() + private val _filterBy = mutableStateOf("") + private var _selectedContactIndex = -1; + private val _selectedContact = mutableStateOf<Contact?>(null) + + val contactList: List<Contact> = _filteredContactList + val filterBy: State<String> = _filterBy + val selectedContact: State<Contact?> = _selectedContact internal fun loadContacts() { - val contacts = contactManager.contacts - for (contact in contacts) { - LOG.info("loaded contact: ${contact.author.name} (${contact.alias})") - this.contacts.add(contact) + _contactList.apply { + clear() + addAll(contactManager.contacts) + } + updateFilteredList() + } + + fun selectContact(index: Int) { + _selectedContactIndex = index + _selectedContact.value = _filteredContactList[index] + } + + fun isSelected(index: Int) = _selectedContactIndex == index + + private fun updateFilteredList() { + _filteredContactList.apply { + clear() + addAll(_contactList.filter { + // todo: also filter on alias? + it.author.name.lowercase().contains(_filterBy.value) + }) } } - fun getFirst(): Contact? { - return if (contacts.isEmpty()) null else contacts[0] + fun setFilterBy(filter: String) { + _filterBy.value = filter + updateFilteredList() } } diff --git a/src/main/kotlin/org/briarproject/briar/desktop/contact/SearchTextField.kt b/src/main/kotlin/org/briarproject/briar/desktop/contact/SearchTextField.kt index 29542dd7d07d47a172f63a06202775b3e9314a1b..61d13a2f4cd48fa352f4cc2b36cd6909b483624a 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/contact/SearchTextField.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/contact/SearchTextField.kt @@ -22,7 +22,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @Composable -fun SearchTextField(searchValue: String, onValueChange: (String) -> Unit, onContactAdd: (Boolean) -> Unit) { +fun SearchTextField(searchValue: String, onValueChange: (String) -> Unit, onContactAdd: () -> Unit) { TextField( value = searchValue, onValueChange = onValueChange, @@ -36,7 +36,7 @@ fun SearchTextField(searchValue: String, onValueChange: (String) -> Unit, onCont }, trailingIcon = { IconButton( - onClick = { onContactAdd(true) }, + onClick = onContactAdd, modifier = Modifier.padding(end = 10.dp).size(32.dp) .background(MaterialTheme.colors.primary, CircleShape) ) { diff --git a/src/main/kotlin/org/briarproject/briar/desktop/conversation/PrivateMessageView.kt b/src/main/kotlin/org/briarproject/briar/desktop/conversation/PrivateMessageView.kt index 929c3f076221676d3cdc5bf951174be5a5da055a..74b89783592ba6dec3e65c948e174c05d59ab001 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/conversation/PrivateMessageView.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/conversation/PrivateMessageView.kt @@ -8,7 +8,6 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier -import org.briarproject.bramble.api.contact.Contact import org.briarproject.briar.desktop.contact.AddContactDialog import org.briarproject.briar.desktop.contact.ContactInfoDrawerState.MakeIntro import org.briarproject.briar.desktop.contact.ContactList @@ -17,9 +16,7 @@ import org.briarproject.briar.desktop.ui.VerticalDivider @Composable fun PrivateMessageView( - contact: Contact, contacts: ContactsViewModel, - onContactSelect: (Contact) -> Unit ) { val (isDialogVisible, setDialogVisibility) = remember { mutableStateOf(false) } val (dropdownExpanded, setExpanded) = remember { mutableStateOf(false) } @@ -27,18 +24,20 @@ fun PrivateMessageView( val (contactDrawerState, setDrawerState) = remember { mutableStateOf(MakeIntro) } AddContactDialog(isDialogVisible, setDialogVisibility) Row(modifier = Modifier.fillMaxWidth()) { - ContactList(contact, contacts.contacts, onContactSelect, setDialogVisibility) + ContactList(contacts) { setDialogVisibility(true) } VerticalDivider() Column(modifier = Modifier.weight(1f).fillMaxHeight()) { - Conversation( - contact, - contacts.contacts, - dropdownExpanded, - setExpanded, - infoDrawer, - setInfoDrawer, - contactDrawerState - ) + contacts.selectedContact.value?.let { selectedContact -> + Conversation( + selectedContact, + contacts.contactList, + dropdownExpanded, + setExpanded, + infoDrawer, + setInfoDrawer, + contactDrawerState + ) + } } } } diff --git a/src/main/kotlin/org/briarproject/briar/desktop/ui/MainScreen.kt b/src/main/kotlin/org/briarproject/briar/desktop/ui/MainScreen.kt index 9a27637bbebd2921e4f4149938f851db1476ecd6..f0ac067ca8ecfd22423f4a39adae4385944c85c1 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/ui/MainScreen.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/ui/MainScreen.kt @@ -28,19 +28,12 @@ fun MainScreen( ) { // current selected mode, changed using the sidebar buttons val (uiMode, setUiMode) = remember { mutableStateOf(UiMode.CONTACTS) } - // TODO Figure out how to handle accounts with 0 contacts - // current selected contact - val (contact, setContact) = remember { mutableStateOf(contactsViewModel.getFirst()) } // Other global state that we need to track should go here also Row { BriarSidebar(uiMode, setUiMode) VerticalDivider() when (uiMode) { - UiMode.CONTACTS -> if (contact != null) PrivateMessageView( - contact, - contactsViewModel, - setContact - ) + UiMode.CONTACTS -> PrivateMessageView(contactsViewModel) UiMode.SETTINGS -> PlaceHolderSettingsView(isDark, setDark) else -> Surface(modifier = Modifier.fillMaxSize().background(MaterialTheme.colors.background)) { Text("TBD")