From 6c3ac9bc5d69ffc042b009ba0ec58e1af6973dd0 Mon Sep 17 00:00:00 2001 From: 0x330a <92654767+0x330a@users.noreply.github.com> Date: Thu, 2 Nov 2023 17:34:52 +1100 Subject: [PATCH] feat: update group creation composables and let contact parcelize --- .../securesms/groups/CreateGroupFragment.kt | 21 ++++++++---- .../securesms/groups/CreateGroupViewModel.kt | 32 ++++++++++++++++--- .../securesms/groups/compose/CreateGroup.kt | 28 ++++++++-------- .../groups/compose/SelectContacts.kt | 11 +++++-- .../libsession/messaging/contacts/Contact.kt | 3 ++ 5 files changed, 69 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/CreateGroupFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/groups/CreateGroupFragment.kt index 8ca393d08..9206d8147 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/CreateGroupFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/CreateGroupFragment.kt @@ -7,15 +7,14 @@ import android.view.ViewGroup import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.platform.ComposeView -import androidx.compose.ui.platform.LocalContext import androidx.fragment.app.Fragment import androidx.hilt.navigation.compose.hiltViewModel import com.ramcosta.composedestinations.DestinationsNavHost import com.ramcosta.composedestinations.annotation.Destination import com.ramcosta.composedestinations.navigation.DestinationsNavigator import com.ramcosta.composedestinations.navigation.dependency +import com.ramcosta.composedestinations.result.NavResult import com.ramcosta.composedestinations.result.ResultBackNavigator import com.ramcosta.composedestinations.result.ResultRecipient import dagger.hilt.android.AndroidEntryPoint @@ -25,6 +24,7 @@ import org.thoughtcrime.securesms.conversation.start.NewConversationDelegate import org.thoughtcrime.securesms.groups.compose.CreateGroup import org.thoughtcrime.securesms.groups.compose.CreateGroupNavGraph import org.thoughtcrime.securesms.groups.compose.SelectContacts +import org.thoughtcrime.securesms.groups.compose.StateUpdate import org.thoughtcrime.securesms.groups.compose.ViewState import org.thoughtcrime.securesms.groups.destinations.SelectContactScreenDestination import org.thoughtcrime.securesms.ui.AppTheme @@ -64,11 +64,19 @@ fun CreateGroupScreen( getDelegate: () -> NewConversationDelegate ) { val viewState by viewModel.viewState.observeAsState(ViewState.DEFAULT) - val lifecycleScope = rememberCoroutineScope() - val context = LocalContext.current + + resultSelectContact.onNavResult { navResult -> + when (navResult) { + is NavResult.Value -> { + viewModel.updateState(StateUpdate.AddContact(navResult.value)) + } + is NavResult.Canceled -> { /* do nothing */ } + } + } CreateGroup( viewState, + viewModel::updateState, onClose = { getDelegate().onDialogClosePressed() }, @@ -90,11 +98,12 @@ fun SelectContactScreen( val viewState by viewModel.viewState.observeAsState(ViewState.DEFAULT) val currentMembers = viewState.members - val contacts by viewModel.contacts.observeAsState(initial = emptyList()) + val contacts by viewModel.contacts.observeAsState(initial = emptySet()) SelectContacts( contacts - currentMembers, onBack = { resultNavigator.navigateBack() }, - onClose = { getDelegate().onDialogClosePressed() } + onClose = { getDelegate().onDialogClosePressed() }, + onContactsSelected = {} ) } \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/CreateGroupViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/groups/CreateGroupViewModel.kt index abc174ca1..405addda1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/CreateGroupViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/CreateGroupViewModel.kt @@ -8,6 +8,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel import network.loki.messenger.R import org.session.libsession.utilities.recipients.Recipient import org.thoughtcrime.securesms.database.Storage +import org.thoughtcrime.securesms.groups.compose.StateUpdate import org.thoughtcrime.securesms.groups.compose.ViewState import javax.inject.Inject @@ -16,10 +17,30 @@ class CreateGroupViewModel @Inject constructor( private val storage: Storage, ) : ViewModel() { - private val _viewState = MutableLiveData(ViewState.DEFAULT) - val viewState: LiveData = _viewState + private fun create() { + tryCreateGroup() + } - val contacts = liveData { emit(storage.getAllContacts()) } + private inline fun MutableLiveData.update(body: T.() -> T) { + this.postValue(body(this.value!!)) + } + + private val _viewState = MutableLiveData(ViewState.DEFAULT.copy()) + + val viewState: LiveData = _viewState + + fun updateState(stateUpdate: StateUpdate) { + when (stateUpdate) { + is StateUpdate.AddContact -> _viewState.update { copy(members = members + stateUpdate.value) } + is StateUpdate.Description -> _viewState.update { copy(description = stateUpdate.value) } + is StateUpdate.Name -> _viewState.update { copy(name = stateUpdate.value) } + is StateUpdate.RemoveContact -> _viewState.update { copy(members = members - stateUpdate.value) } + StateUpdate.Create -> { tryCreateGroup() } + } + } + + val contacts + get() = liveData { emit(storage.getAllContacts()) } fun tryCreateGroup(): Recipient? { @@ -46,7 +67,10 @@ class CreateGroupViewModel @Inject constructor( if (members.size <= 1) { _viewState.postValue( - currentState.copy(isLoading = false, error = R.string.activity_create_closed_group_not_enough_group_members_error) + currentState.copy( + isLoading = false, + error = R.string.activity_create_closed_group_not_enough_group_members_error + ) ) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/compose/CreateGroup.kt b/app/src/main/java/org/thoughtcrime/securesms/groups/compose/CreateGroup.kt index 171e29133..93bc0ce62 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/compose/CreateGroup.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/compose/CreateGroup.kt @@ -32,7 +32,6 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import network.loki.messenger.R import org.session.libsession.messaging.contacts.Contact -import org.thoughtcrime.securesms.groups.compose.ViewState.StateUpdate import org.thoughtcrime.securesms.ui.CellWithPaddingAndMargin import org.thoughtcrime.securesms.ui.Divider import org.thoughtcrime.securesms.ui.EditableAvatar @@ -49,6 +48,7 @@ data class CreateGroupState ( @Composable fun CreateGroup( viewState: ViewState, + updateState: (StateUpdate) -> Unit, onSelectContact: () -> Unit, onBack: () -> Unit, onClose: () -> Unit, @@ -80,7 +80,7 @@ fun CreateGroup( val nameDescription = stringResource(id = R.string.AccessibilityId_closed_group_edit_group_name) OutlinedTextField( value = viewState.name, - onValueChange = { viewState.updateState(StateUpdate.Name(it)) }, + onValueChange = { updateState(StateUpdate.Name(it)) }, modifier = Modifier .fillMaxWidth() .align(Alignment.CenterHorizontally) @@ -93,7 +93,7 @@ fun CreateGroup( val descriptionDescription = stringResource(id = R.string.AccessibilityId_closed_group_edit_group_description) OutlinedTextField( value = viewState.description, - onValueChange = { viewState.updateState(StateUpdate.Description(it)) }, + onValueChange = { updateState(StateUpdate.Description(it)) }, modifier = Modifier .fillMaxWidth() .align(Alignment.CenterHorizontally) @@ -150,13 +150,13 @@ fun CreateGroup( } // Group list memberList(contacts = viewState.members, modifier = Modifier.padding(vertical = 8.dp, horizontal = 24.dp)) { deletedContact -> - viewState.updateState(StateUpdate.RemoveContact(deletedContact)) + updateState(StateUpdate.RemoveContact(deletedContact)) } } // Create button val createDescription = stringResource(id = R.string.AccessibilityId_create_closed_group_create_button) OutlinedButton( - onClick = { viewState.create() }, + onClick = { updateState(StateUpdate.Create) }, enabled = viewState.canCreate, modifier = Modifier .align(Alignment.CenterHorizontally) @@ -203,6 +203,7 @@ fun ClosedGroupPreview( viewState = ViewState.DEFAULT.copy( // override any preview parameters ), + updateState = {}, onSelectContact = {}, onBack = {}, onClose = {}, @@ -216,22 +217,21 @@ data class ViewState( val name: String = "", val description: String = "", val members: List = emptyList(), - val updateState: (StateUpdate)->Unit, - val create: ()->Unit, ) { val canCreate get() = name.isNotEmpty() && members.isNotEmpty() companion object { - val DEFAULT = ViewState(false, null, updateState = {}, create = {}) + val DEFAULT = ViewState(false, null) } - sealed class StateUpdate { - data class Name(val value: String): StateUpdate() - data class Description(val value: String): StateUpdate() - data class RemoveContact(val value: Contact): StateUpdate() - data class AddContact(val value: Contact): StateUpdate() - } +} +sealed class StateUpdate { + data object Create: StateUpdate() + data class Name(val value: String): StateUpdate() + data class Description(val value: String): StateUpdate() + data class RemoveContact(val value: Contact): StateUpdate() + data class AddContact(val value: Contact): StateUpdate() } \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/compose/SelectContacts.kt b/app/src/main/java/org/thoughtcrime/securesms/groups/compose/SelectContacts.kt index 904a024b2..3e407124f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/compose/SelectContacts.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/compose/SelectContacts.kt @@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.groups.compose import androidx.compose.foundation.layout.Column import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -16,21 +17,23 @@ import org.thoughtcrime.securesms.ui.SearchBar @Composable fun SelectContacts( - contactListState: List, + contactListState: Set, onBack: ()->Unit, onClose: ()->Unit, + onContactsSelected: (List) -> Unit, ) { var queryFilter by remember { mutableStateOf("") } // May introduce more advanced filters - val filtered = if (queryFilter.isEmpty()) contactListState + val filtered = if (queryFilter.isEmpty()) contactListState.toList() else { contactListState .filter { contact -> contact.getSearchName() .contains(queryFilter) } + .toList() } Column { @@ -45,6 +48,10 @@ fun SelectContacts( // Search Bar SearchBar(queryFilter, onValueChanged = { value -> queryFilter = value }) } + + items(filtered) { contact -> + + } } } diff --git a/libsession/src/main/java/org/session/libsession/messaging/contacts/Contact.kt b/libsession/src/main/java/org/session/libsession/messaging/contacts/Contact.kt index c7981fa9f..6bb71f9e5 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/contacts/Contact.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/contacts/Contact.kt @@ -32,6 +32,9 @@ class Contact( */ var nickname: String? = null, ): Parcelable { + + constructor(id: String): this(sessionID = id) + /** * The name to display in the UI. For local use only. */