Skip to content
Snippets Groups Projects
Verified Commit c9dc349f authored by Mikolai Gütschow's avatar Mikolai Gütschow
Browse files

move add contact functionality to view model

parent dc26e76e
No related branches found
No related tags found
1 merge request!33Finish view model for contact list
......@@ -15,35 +15,16 @@ import androidx.compose.material.Text
import androidx.compose.material.TextButton
import androidx.compose.material.TextField
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.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import org.briarproject.bramble.api.FormatException
import org.briarproject.bramble.api.contact.ContactManager
import org.briarproject.bramble.api.db.ContactExistsException
import org.briarproject.bramble.api.db.PendingContactExistsException
import org.briarproject.bramble.api.identity.AuthorConstants
import org.briarproject.bramble.util.StringUtils
import org.briarproject.briar.desktop.ui.CTM
import java.security.GeneralSecurityException
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun AddContactDialog(isVisible: Boolean, setDialogVisibility: (Boolean) -> Unit) {
if (!isVisible) {
return
}
var contactAlias by remember { mutableStateOf("") }
var contactLink by remember { mutableStateOf("") }
val contactManager = CTM.current
val ownLink = CTM.current.handshakeLink
fun AddContactDialog(viewModel: ContactsViewModel) {
AlertDialog(
onDismissRequest = { setDialogVisibility(false) },
onDismissRequest = viewModel::closeAddContactDialog,
text = {
Column(modifier = Modifier.fillMaxWidth()) {
Row(Modifier.fillMaxWidth().padding(vertical = 16.dp)) {
......@@ -58,14 +39,22 @@ fun AddContactDialog(isVisible: Boolean, setDialogVisibility: (Boolean) -> Unit)
"Contact's Link",
Modifier.width(128.dp).align(Alignment.CenterVertically),
)
TextField(contactLink, onValueChange = { contactLink = it }, modifier = Modifier.fillMaxWidth())
TextField(
viewModel.addContactLink.value,
viewModel::setAddContactLink,
modifier = Modifier.fillMaxWidth()
)
}
Row(horizontalArrangement = Arrangement.SpaceBetween, modifier = Modifier.fillMaxWidth()) {
Text(
"Contact's Name",
Modifier.width(128.dp).align(Alignment.CenterVertically),
)
TextField(contactAlias, onValueChange = { contactAlias = it }, modifier = Modifier.fillMaxWidth())
TextField(
viewModel.addContactAlias.value,
viewModel::setAddContactAlias,
modifier = Modifier.fillMaxWidth()
)
}
Row(horizontalArrangement = Arrangement.SpaceBetween, modifier = Modifier.fillMaxWidth()) {
Text(
......@@ -73,7 +62,7 @@ fun AddContactDialog(isVisible: Boolean, setDialogVisibility: (Boolean) -> Unit)
modifier = Modifier.width(128.dp).align(Alignment.CenterVertically),
)
TextField(
ownLink,
viewModel.addContactOwnLink,
onValueChange = {},
modifier = Modifier.fillMaxWidth()
)
......@@ -81,23 +70,13 @@ fun AddContactDialog(isVisible: Boolean, setDialogVisibility: (Boolean) -> Unit)
}
},
confirmButton = {
Button(
onClick = {
if (ownLink.equals(contactLink)) {
println("Please enter contact's link, not your own")
setDialogVisibility(false)
return@Button
}
addPendingContact(contactManager, contactAlias, contactLink)
setDialogVisibility(false)
},
) {
Button(onClick = viewModel::onSubmitAddContactDialog) {
Text("Add")
}
},
dismissButton = {
TextButton(
onClick = { setDialogVisibility(false) }
onClick = viewModel::closeAddContactDialog
) {
Text("Cancel", color = MaterialTheme.colors.onSurface)
}
......@@ -105,38 +84,3 @@ fun AddContactDialog(isVisible: Boolean, setDialogVisibility: (Boolean) -> Unit)
modifier = Modifier.size(600.dp, 300.dp),
)
}
private fun addPendingContact(contactManager: ContactManager, alias: String, link: String) {
if (aliasIsInvalid(alias)) {
println("Alias is invalid")
return
}
try {
contactManager.addPendingContact(link, alias)
} catch (e: FormatException) {
println("Link is invalid")
println(e.stackTrace)
} catch (e: GeneralSecurityException) {
println("Public key is invalid")
println(e.stackTrace)
}
/*
TODO: Warn user that the following two errors might be an attack
Use `e.pendingContact.id.bytes` and `e.pendingContact.alias` to implement the following logic:
https://code.briarproject.org/briar/briar-gtk/-/merge_requests/97
*/
catch (e: ContactExistsException) {
println("Contact already exists")
println(e.stackTrace)
} catch (e: PendingContactExistsException) {
println("Pending Contact already exists")
println(e.stackTrace)
}
}
private fun aliasIsInvalid(alias: String): Boolean {
val aliasUtf8 = StringUtils.toUtf8(alias)
return aliasUtf8.isEmpty() || aliasUtf8.size > AuthorConstants.MAX_AUTHOR_NAME_LENGTH
}
......@@ -18,9 +18,9 @@ import org.briarproject.briar.desktop.ui.Constants.HEADER_SIZE
@Composable
fun ContactList(
contacts: ContactsViewModel,
onContactAdd: () -> Unit,
viewModel: ContactsViewModel,
) {
if (viewModel.addContactDialogVisible.value) AddContactDialog(viewModel)
Scaffold(
modifier = Modifier.fillMaxHeight().width(CONTACTLIST_WIDTH),
backgroundColor = MaterialTheme.colors.surfaceVariant,
......@@ -29,16 +29,16 @@ fun ContactList(
modifier = Modifier.fillMaxWidth().height(HEADER_SIZE + 1.dp),
) {
SearchTextField(
contacts.filterBy.value,
onValueChange = contacts::setFilterBy,
onContactAdd
viewModel.filterBy.value,
onValueChange = viewModel::setFilterBy,
onContactAdd = viewModel::openAddContactDialog
)
}
},
content = {
LazyColumn {
itemsIndexed(contacts.contactList) { index, contact ->
ContactCard(contact, { contacts.selectContact(index) }, contacts.isSelected(index), true)
itemsIndexed(viewModel.contactList) { index, contact ->
ContactCard(contact, { viewModel.selectContact(index) }, viewModel.isSelected(index), true)
}
}
},
......
......@@ -3,8 +3,14 @@ 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.FormatException
import org.briarproject.bramble.api.contact.Contact
import org.briarproject.bramble.api.contact.ContactManager
import org.briarproject.bramble.api.db.ContactExistsException
import org.briarproject.bramble.api.db.PendingContactExistsException
import org.briarproject.bramble.api.identity.AuthorConstants
import org.briarproject.bramble.util.StringUtils
import java.security.GeneralSecurityException
import java.util.logging.Logger
import javax.inject.Inject
......@@ -24,10 +30,19 @@ constructor(
private var _selectedContactIndex = -1;
private val _selectedContact = mutableStateOf<Contact?>(null)
private val _addContactDialogVisible = mutableStateOf(false)
private val _addContactAlias = mutableStateOf("")
private val _addContactLink = mutableStateOf("")
val contactList: List<Contact> = _filteredContactList
val filterBy: State<String> = _filterBy
val selectedContact: State<Contact?> = _selectedContact
val addContactDialogVisible: State<Boolean> = _addContactDialogVisible
val addContactAlias: State<String> = _addContactAlias
val addContactLink: State<String> = _addContactLink
val addContactOwnLink = contactManager.handshakeLink
internal fun loadContacts() {
_contactList.apply {
clear()
......@@ -57,4 +72,67 @@ constructor(
_filterBy.value = filter
updateFilteredList()
}
fun openAddContactDialog() {
_addContactDialogVisible.value = true
}
fun closeAddContactDialog() {
_addContactDialogVisible.value = false
}
fun setAddContactAlias(alias: String) {
_addContactAlias.value = alias
}
fun setAddContactLink(link: String) {
_addContactLink.value = link
}
fun onSubmitAddContactDialog() {
val link = _addContactLink.value
val alias = _addContactAlias.value
addPendingContact(link, alias)
closeAddContactDialog()
}
private fun addPendingContact(link: String, alias: String) {
if (addContactOwnLink.equals(link)) {
println("Please enter contact's link, not your own")
return
}
if (aliasIsInvalid(alias)) {
println("Alias is invalid")
return
}
try {
contactManager.addPendingContact(link, alias)
} catch (e: FormatException) {
println("Link is invalid")
println(e.stackTrace)
} catch (e: GeneralSecurityException) {
println("Public key is invalid")
println(e.stackTrace)
}
/*
TODO: Warn user that the following two errors might be an attack
Use `e.pendingContact.id.bytes` and `e.pendingContact.alias` to implement the following logic:
https://code.briarproject.org/briar/briar-gtk/-/merge_requests/97
*/
catch (e: ContactExistsException) {
println("Contact already exists")
println(e.stackTrace)
} catch (e: PendingContactExistsException) {
println("Pending Contact already exists")
println(e.stackTrace)
}
}
private fun aliasIsInvalid(alias: String): Boolean {
val aliasUtf8 = StringUtils.toUtf8(alias)
return aliasUtf8.isEmpty() || aliasUtf8.size > AuthorConstants.MAX_AUTHOR_NAME_LENGTH
}
}
......@@ -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.briar.desktop.contact.AddContactDialog
import org.briarproject.briar.desktop.contact.ContactInfoDrawerState.MakeIntro
import org.briarproject.briar.desktop.contact.ContactList
import org.briarproject.briar.desktop.contact.ContactsViewModel
......@@ -18,13 +17,11 @@ import org.briarproject.briar.desktop.ui.VerticalDivider
fun PrivateMessageView(
contacts: ContactsViewModel,
) {
val (isDialogVisible, setDialogVisibility) = remember { mutableStateOf(false) }
val (dropdownExpanded, setExpanded) = remember { mutableStateOf(false) }
val (infoDrawer, setInfoDrawer) = remember { mutableStateOf(false) }
val (contactDrawerState, setDrawerState) = remember { mutableStateOf(MakeIntro) }
AddContactDialog(isDialogVisible, setDialogVisibility)
Row(modifier = Modifier.fillMaxWidth()) {
ContactList(contacts) { setDialogVisibility(true) }
ContactList(contacts)
VerticalDivider()
Column(modifier = Modifier.weight(1f).fillMaxHeight()) {
contacts.selectedContact.value?.let { selectedContact ->
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment