feat: update group creation composables and let contact parcelize
This commit is contained in:
parent
fabe2d44da
commit
6c3ac9bc5d
|
@ -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 = {}
|
||||
)
|
||||
}
|
|
@ -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> = _viewState
|
||||
private fun create() {
|
||||
tryCreateGroup()
|
||||
}
|
||||
|
||||
val contacts = liveData { emit(storage.getAllContacts()) }
|
||||
private inline fun <reified T> MutableLiveData<T>.update(body: T.() -> T) {
|
||||
this.postValue(body(this.value!!))
|
||||
}
|
||||
|
||||
private val _viewState = MutableLiveData(ViewState.DEFAULT.copy())
|
||||
|
||||
val viewState: LiveData<ViewState> = _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
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -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<Contact> = 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()
|
||||
}
|
|
@ -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<Contact>,
|
||||
contactListState: Set<Contact>,
|
||||
onBack: ()->Unit,
|
||||
onClose: ()->Unit,
|
||||
onContactsSelected: (List<Contact>) -> 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 ->
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue