feat: add inviting members to group scaffolding, need to wire up the storage to create job and modify group state
This commit is contained in:
parent
9275a2b0ec
commit
cc24542af3
|
@ -1274,6 +1274,12 @@ open class Storage(
|
|||
}
|
||||
}
|
||||
|
||||
override fun inviteClosedGroupMembers(groupSessionId: String, invitees: List<String>) {
|
||||
// don't try to process invitee acceptance if we aren't admin
|
||||
if (configFactory.userGroups?.getClosedGroup(groupSessionId)?.hasAdminKey() != true) return
|
||||
val infoConfig = configFactory
|
||||
}
|
||||
|
||||
override fun setServerCapabilities(server: String, capabilities: List<String>) {
|
||||
return DatabaseComponent.get(context).lokiAPIDatabase().setServerCapabilities(server, capabilities)
|
||||
}
|
||||
|
|
|
@ -57,10 +57,6 @@ class CreateGroupViewModel @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
storage.getAllContacts().forEach { contact ->
|
||||
members.add(contact)
|
||||
}
|
||||
|
||||
if (members.size <= 1) {
|
||||
_viewState.postValue(
|
||||
currentState.copy(
|
||||
|
|
|
@ -41,12 +41,6 @@ import org.thoughtcrime.securesms.ui.NavigationBar
|
|||
import org.thoughtcrime.securesms.ui.PreviewTheme
|
||||
|
||||
|
||||
data class CreateGroupState (
|
||||
var groupName: String,
|
||||
var groupDescription: String,
|
||||
val members: MutableSet<Contact>
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun CreateGroup(
|
||||
viewState: ViewState,
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package org.thoughtcrime.securesms.groups.compose
|
||||
|
||||
import android.content.Context
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
|
@ -22,6 +24,7 @@ import androidx.compose.runtime.remember
|
|||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment.Companion.CenterVertically
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
|
@ -35,12 +38,19 @@ import app.cash.molecule.RecompositionMode.Immediate
|
|||
import app.cash.molecule.launchMolecule
|
||||
import com.ramcosta.composedestinations.annotation.Destination
|
||||
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||
import com.ramcosta.composedestinations.result.NavResult
|
||||
import com.ramcosta.composedestinations.result.ResultBackNavigator
|
||||
import com.ramcosta.composedestinations.result.ResultRecipient
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import network.loki.messenger.R
|
||||
import network.loki.messenger.libsession_util.util.GroupMember
|
||||
import org.session.libsession.database.StorageProtocol
|
||||
import org.session.libsession.messaging.contacts.Contact
|
||||
import org.session.libsession.messaging.jobs.InviteContactsJob
|
||||
import org.session.libsession.messaging.jobs.JobQueue
|
||||
import org.thoughtcrime.securesms.groups.ContactList
|
||||
import org.thoughtcrime.securesms.groups.destinations.EditClosedGroupInviteScreenDestination
|
||||
import org.thoughtcrime.securesms.ui.CellWithPaddingAndMargin
|
||||
import org.thoughtcrime.securesms.ui.NavigationBar
|
||||
|
@ -51,13 +61,21 @@ import org.thoughtcrime.securesms.ui.PreviewTheme
|
|||
@Destination
|
||||
fun EditClosedGroupScreen(
|
||||
navigator: DestinationsNavigator,
|
||||
resultSelectContact: ResultRecipient<EditClosedGroupInviteScreenDestination, ContactList>,
|
||||
viewModel: EditGroupViewModel,
|
||||
onFinish: () -> Unit
|
||||
) {
|
||||
val group by viewModel.viewState.collectAsState()
|
||||
val context = LocalContext.current
|
||||
val viewState = group.viewState
|
||||
val eventSink = group.eventSink
|
||||
|
||||
resultSelectContact.onNavResult { navResult ->
|
||||
if (navResult is NavResult.Value) {
|
||||
eventSink(EditGroupEvent.InviteContacts(context, navResult.value))
|
||||
}
|
||||
}
|
||||
|
||||
EditGroupView(
|
||||
onBack = {
|
||||
onFinish()
|
||||
|
@ -65,7 +83,7 @@ fun EditClosedGroupScreen(
|
|||
onInvite = {
|
||||
navigator.navigate(EditClosedGroupInviteScreenDestination)
|
||||
},
|
||||
viewState = viewState as EditGroupViewState.Group
|
||||
viewState = viewState
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -73,16 +91,31 @@ fun EditClosedGroupScreen(
|
|||
@Composable
|
||||
@Destination
|
||||
fun EditClosedGroupInviteScreen(
|
||||
navigator: DestinationsNavigator,
|
||||
resultNavigator: ResultBackNavigator<ContactList>,
|
||||
viewModel: EditGroupInviteViewModel,
|
||||
) {
|
||||
|
||||
val state by viewModel.viewState.collectAsState()
|
||||
val viewState = state.viewState
|
||||
val currentMemberSessionIds = viewState.currentMembers.map { it.memberSessionId }
|
||||
val eventSink = state.eventSink
|
||||
|
||||
SelectContacts(
|
||||
viewState.allContacts
|
||||
.filterNot { it.sessionID in currentMemberSessionIds }
|
||||
.toSet(),
|
||||
onBack = { resultNavigator.navigateBack() },
|
||||
onContactsSelected = {
|
||||
resultNavigator.navigateBack(ContactList(it))
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
class EditGroupViewModel @AssistedInject constructor(
|
||||
@Assisted private val groupSessionId: String,
|
||||
private val storage: StorageProtocol): ViewModel() {
|
||||
private val storage: StorageProtocol,
|
||||
): ViewModel() {
|
||||
|
||||
val viewState = viewModelScope.launchMolecule(Immediate) {
|
||||
|
||||
|
@ -113,14 +146,32 @@ class EditGroupViewModel @AssistedInject constructor(
|
|||
val description = closedGroup.description
|
||||
|
||||
EditGroupState(
|
||||
EditGroupViewState.Group(
|
||||
EditGroupViewState(
|
||||
groupName = name,
|
||||
groupDescription = description,
|
||||
memberStateList = closedGroupMembers,
|
||||
admin = closedGroup.isUserAdmin
|
||||
)
|
||||
) { event ->
|
||||
|
||||
when (event) {
|
||||
is EditGroupEvent.InviteContacts -> {
|
||||
val sessionIds = event.contacts
|
||||
val invite = InviteContactsJob(
|
||||
groupSessionId,
|
||||
sessionIds.contacts.map(Contact::sessionID).toTypedArray()
|
||||
)
|
||||
storage.inviteClosedGroupMembers(
|
||||
groupSessionId,
|
||||
sessionIds.contacts.map(Contact::sessionID)
|
||||
)
|
||||
JobQueue.shared.add(invite)
|
||||
Toast.makeText(
|
||||
event.context,
|
||||
"Inviting ${event.contacts.contacts.size}",
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,6 +187,33 @@ class EditGroupInviteViewModel @AssistedInject constructor(
|
|||
private val storage: StorageProtocol
|
||||
): ViewModel() {
|
||||
|
||||
val viewState = viewModelScope.launchMolecule(Immediate) {
|
||||
|
||||
val currentUserId = rememberSaveable {
|
||||
storage.getUserPublicKey()!!
|
||||
}
|
||||
|
||||
val contacts = remember {
|
||||
storage.getAllContacts()
|
||||
}
|
||||
|
||||
val closedGroupMembers = remember {
|
||||
storage.getMembers(groupSessionId).map { member ->
|
||||
MemberViewModel(
|
||||
memberName = member.name,
|
||||
memberSessionId = member.sessionId,
|
||||
currentUser = member.sessionId == currentUserId,
|
||||
memberState = memberStateOf(member)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
EditGroupInviteState(
|
||||
EditGroupInviteViewState(closedGroupMembers, contacts)
|
||||
) { event ->
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
|
@ -148,7 +226,7 @@ class EditGroupInviteViewModel @AssistedInject constructor(
|
|||
fun EditGroupView(
|
||||
onBack: ()->Unit,
|
||||
onInvite: ()->Unit,
|
||||
viewState: EditGroupViewState.Group,
|
||||
viewState: EditGroupViewState,
|
||||
) {
|
||||
val scaffoldState = rememberScaffoldState()
|
||||
|
||||
|
@ -238,7 +316,12 @@ fun EditGroupView(
|
|||
|
||||
data class EditGroupState(
|
||||
val viewState: EditGroupViewState,
|
||||
val eventSink: (Unit)->Unit
|
||||
val eventSink: (EditGroupEvent) -> Unit
|
||||
)
|
||||
|
||||
data class EditGroupInviteState(
|
||||
val viewState: EditGroupInviteViewState,
|
||||
val eventSink: (Unit) -> Unit
|
||||
)
|
||||
|
||||
data class MemberViewModel(
|
||||
|
@ -268,15 +351,23 @@ fun memberStateOf(member: GroupMember): MemberState = when {
|
|||
else -> MemberState.Member
|
||||
}
|
||||
|
||||
sealed class EditGroupViewState {
|
||||
data class Group(
|
||||
val groupName: String,
|
||||
val groupDescription: String?,
|
||||
val memberStateList: List<MemberViewModel>,
|
||||
val admin: Boolean
|
||||
): EditGroupViewState()
|
||||
data class EditGroupViewState(
|
||||
val groupName: String,
|
||||
val groupDescription: String?,
|
||||
val memberStateList: List<MemberViewModel>,
|
||||
val admin: Boolean
|
||||
)
|
||||
|
||||
sealed class EditGroupEvent {
|
||||
data class InviteContacts(val context: Context,
|
||||
val contacts: ContactList): EditGroupEvent()
|
||||
}
|
||||
|
||||
data class EditGroupInviteViewState(
|
||||
val currentMembers: List<MemberViewModel>,
|
||||
val allContacts: Set<Contact>
|
||||
)
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun PreviewList() {
|
||||
|
@ -288,7 +379,7 @@ fun PreviewList() {
|
|||
false
|
||||
)
|
||||
|
||||
val viewState = EditGroupViewState.Group(
|
||||
val viewState = EditGroupViewState(
|
||||
"Preview",
|
||||
"This is a preview description",
|
||||
listOf(oneMember),
|
||||
|
|
|
@ -1,12 +1,18 @@
|
|||
package org.thoughtcrime.securesms.groups.compose
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.defaultMinSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material.ButtonDefaults
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.OutlinedButton
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
|
@ -16,22 +22,29 @@ import androidx.compose.runtime.remember
|
|||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Brush.Companion.verticalGradient
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import network.loki.messenger.R
|
||||
import org.session.libsession.messaging.contacts.Contact
|
||||
import org.thoughtcrime.securesms.home.search.getSearchName
|
||||
import org.thoughtcrime.securesms.ui.CloseIcon
|
||||
import org.thoughtcrime.securesms.ui.NavigationBar
|
||||
import org.thoughtcrime.securesms.ui.PreviewTheme
|
||||
import org.thoughtcrime.securesms.ui.SearchBar
|
||||
import org.thoughtcrime.securesms.ui.ThemeResPreviewParameterProvider
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun SelectContacts(
|
||||
contactListState: Set<Contact>,
|
||||
onBack: ()->Unit,
|
||||
onClose: ()->Unit,
|
||||
onClose: (()->Unit)? = null,
|
||||
onContactsSelected: (Set<Contact>) -> Unit,
|
||||
@StringRes okButtonResId: Int = R.string.ok
|
||||
) {
|
||||
|
||||
var queryFilter by remember { mutableStateOf("") }
|
||||
|
@ -55,7 +68,11 @@ fun SelectContacts(
|
|||
NavigationBar(
|
||||
title = stringResource(id = R.string.activity_create_closed_group_select_contacts),
|
||||
onBack = onBack,
|
||||
actionElement = { CloseIcon(onClose) }
|
||||
actionElement = {
|
||||
if (onClose != null) {
|
||||
CloseIcon(onClose)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
LazyColumn(modifier = Modifier.weight(1f)) {
|
||||
|
@ -70,15 +87,43 @@ fun SelectContacts(
|
|||
onListUpdated = { selected = it },
|
||||
)
|
||||
}
|
||||
Box(contentAlignment = Alignment.Center, modifier = Modifier.fillMaxWidth()) {
|
||||
Box(
|
||||
contentAlignment = Alignment.Center,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
.background(
|
||||
verticalGradient(
|
||||
0f to Color.Transparent,
|
||||
0.2f to MaterialTheme.colors.primaryVariant,
|
||||
)
|
||||
)
|
||||
) {
|
||||
OutlinedButton(
|
||||
onClick = { onContactsSelected(selected) },
|
||||
modifier = Modifier.padding(horizontal = 12.dp, vertical = 4.dp).defaultMinSize(minWidth = 128.dp),
|
||||
border = BorderStroke(1.dp, MaterialTheme.colors.onPrimary),
|
||||
shape = CircleShape,
|
||||
modifier = Modifier.padding(horizontal = 12.dp, vertical = 4.dp)) {
|
||||
Text(stringResource(id = R.string.ok))
|
||||
colors = ButtonDefaults.outlinedButtonColors(
|
||||
backgroundColor = Color.Transparent,
|
||||
contentColor = MaterialTheme.colors.onPrimary,
|
||||
)
|
||||
) {
|
||||
Text(
|
||||
stringResource(id = okButtonResId)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun previewSelectContacts(
|
||||
@PreviewParameter(ThemeResPreviewParameterProvider::class) themeRes: Int
|
||||
) {
|
||||
val empty = emptySet<Contact>()
|
||||
PreviewTheme(themeResId = themeRes) {
|
||||
SelectContacts(contactListState = empty, onBack = { /*TODO*/ }, onContactsSelected = {})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -165,6 +165,7 @@ interface StorageProtocol {
|
|||
fun setGroupInviteCompleteIfNeeded(approved: Boolean, invitee: String, closedGroup: SessionId)
|
||||
fun getLibSessionClosedGroup(groupSessionId: String): GroupInfo.ClosedGroupInfo?
|
||||
fun getClosedGroupDisplayInfo(groupSessionId: String): GroupDisplayInfo?
|
||||
fun inviteClosedGroupMembers(groupSessionId: String, invitees: List<String>)
|
||||
|
||||
// Groups
|
||||
fun getAllGroups(includeInactive: Boolean): List<GroupRecord>
|
||||
|
|
Loading…
Reference in New Issue