core, ui: invite member of one group to another group (#7682)

* rfc: invite member of one group to another group

* update

* update

* implement

* version

* update

* do not show error if contact was removed when joining group

---------

Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
This commit is contained in:
Evgeny
2026-10-11 09:50:42 +01:00
committed by GitHub
co-authored by Evgeny @ SimpleX Chat
parent 1053e9fb5c
commit 07c363849b
41 changed files with 1571 additions and 52 deletions
@@ -3128,6 +3128,13 @@ object ChatController {
// TODO NtfManager.shared.notifyGroupInvitation
}
}
is CR.ReceivedGroupInvitationViaGroup -> {
if (active(r.user)) {
withContext(Dispatchers.Main) {
chatModel.chatsContext.updateGroup(rhId, r.groupInfo)
}
}
}
is CR.UserAcceptedGroupSent -> {
if (!active(r.user)) return
@@ -6815,6 +6822,7 @@ sealed class CR {
@Serializable @SerialName("leftMemberUser") class LeftMemberUser(val user: UserRef, val groupInfo: GroupInfo): CR()
@Serializable @SerialName("groupMembers") class GroupMembers(val user: UserRef, val group: Group): CR()
@Serializable @SerialName("receivedGroupInvitation") class ReceivedGroupInvitation(val user: UserRef, val groupInfo: GroupInfo, val contact: Contact, val memberRole: GroupMemberRole): CR()
@Serializable @SerialName("receivedGroupInvitationViaGroup") class ReceivedGroupInvitationViaGroup(val user: UserRef, val groupInfo: GroupInfo, val viaGroupInfo: GroupInfo, val viaMember: GroupMember, val memberRole: GroupMemberRole): CR()
@Serializable @SerialName("groupDeletedUser") class GroupDeletedUser(val user: UserRef, val groupInfo: GroupInfo): CR()
@Serializable @SerialName("joinedGroupMemberConnecting") class JoinedGroupMemberConnecting(val user: UserRef, val groupInfo: GroupInfo, val hostMember: GroupMember, val member: GroupMember): CR()
@Serializable @SerialName("memberAccepted") class MemberAccepted(val user: UserRef, val groupInfo: GroupInfo, val member: GroupMember): CR()
@@ -7015,6 +7023,7 @@ sealed class CR {
is LeftMemberUser -> "leftMemberUser"
is GroupMembers -> "groupMembers"
is ReceivedGroupInvitation -> "receivedGroupInvitation"
is ReceivedGroupInvitationViaGroup -> "receivedGroupInvitationViaGroup"
is GroupDeletedUser -> "groupDeletedUser"
is JoinedGroupMemberConnecting -> "joinedGroupMemberConnecting"
is MemberAccepted -> "memberAccepted"
@@ -7206,6 +7215,7 @@ sealed class CR {
is LeftMemberUser -> withUser(user, json.encodeToString(groupInfo))
is GroupMembers -> withUser(user, json.encodeToString(group))
is ReceivedGroupInvitation -> withUser(user, "groupInfo: $groupInfo\ncontact: $contact\nmemberRole: $memberRole")
is ReceivedGroupInvitationViaGroup -> withUser(user, "groupInfo: $groupInfo\nviaGroupInfo: $viaGroupInfo\nviaMember: $viaMember\nmemberRole: $memberRole")
is GroupDeletedUser -> withUser(user, json.encodeToString(groupInfo))
is JoinedGroupMemberConnecting -> withUser(user, "groupInfo: $groupInfo\nhostMember: $hostMember\nmember: $member")
is MemberAccepted -> withUser(user, "groupInfo: $groupInfo\nmember: $member")
@@ -29,6 +29,7 @@ fun CIGroupInvitationView(
memberRole: GroupMemberRole,
showTimestamp: Boolean,
chatIncognito: Boolean = false,
groupChat: Boolean = false,
joinGroup: (Long, () -> Unit) -> Unit,
timedMessagesTTL: Int?
) {
@@ -111,6 +112,9 @@ fun CIGroupInvitationView(
val secondaryColor = MaterialTheme.colors.secondary
Divider(Modifier.fillMaxWidth().padding(top = 8.dp))
Column(Modifier.padding(top = 8.dp, bottom = 4.dp, start = 4.dp), verticalArrangement = Arrangement.spacedBy(2.dp)) {
if (groupChat) {
Text(if (sent) String.format(stringResource(MR.strings.group_invitation_for_member_only), groupInvitation.localDisplayName) else stringResource(MR.strings.group_invitation_for_you_only), fontSize = 12.sp, color = secondaryColor)
}
if (action) {
Text(groupInvitationStr(), fontSize = 13.sp, lineHeight = 18.sp)
Text(
@@ -720,11 +720,11 @@ fun ChatItemView(
DeleteItemMenu()
}
is CIContent.RcvGroupInvitation -> {
CIGroupInvitationView(cItem, c.groupInvitation, c.memberRole, joinGroup = joinGroup, chatIncognito = cInfo.incognito, showTimestamp = showTimestamp, timedMessagesTTL = cInfo.timedMessagesTTL)
CIGroupInvitationView(cItem, c.groupInvitation, c.memberRole, joinGroup = joinGroup, chatIncognito = cInfo.incognito, groupChat = cInfo is ChatInfo.Group, showTimestamp = showTimestamp, timedMessagesTTL = cInfo.timedMessagesTTL)
DeleteItemMenu()
}
is CIContent.SndGroupInvitation -> {
CIGroupInvitationView(cItem, c.groupInvitation, c.memberRole, joinGroup = joinGroup, chatIncognito = cInfo.incognito, showTimestamp = showTimestamp, timedMessagesTTL = cInfo.timedMessagesTTL)
CIGroupInvitationView(cItem, c.groupInvitation, c.memberRole, joinGroup = joinGroup, chatIncognito = cInfo.incognito, groupChat = cInfo is ChatInfo.Group, showTimestamp = showTimestamp, timedMessagesTTL = cInfo.timedMessagesTTL)
DeleteItemMenu()
}
is CIContent.RcvDirectEventContent -> {
@@ -1769,6 +1769,8 @@
<string name="you_joined_this_group">You joined this group</string>
<string name="you_rejected_group_invitation">You rejected group invitation</string>
<string name="group_invitation_expired">Group invitation expired</string>
<string name="group_invitation_for_you_only">For you only</string>
<string name="group_invitation_for_member_only">For %1$s only</string>
<!-- Direct event chat items -->
<string name="rcv_direct_event_contact_deleted">deleted contact</string>