From 7b1a25d0efee29705c959dcfeffb1bb5241e03f0 Mon Sep 17 00:00:00 2001 From: SessionHero01 <180888785+SessionHero01@users.noreply.github.com> Date: Thu, 30 Jan 2025 11:25:27 +1100 Subject: [PATCH] [SES-2960] - Control messages for leaving groups (#898) * Removed the "overridenSnippet" facility * Add missing control messages --- .../securesms/database/Storage.kt | 10 ++ .../database/model/MessageRecord.java | 14 +- .../database/model/ThreadRecord.java | 11 +- .../securesms/groups/GroupManagerV2Impl.kt | 120 ++++++++++-------- .../securesms/home/ConversationView.kt | 20 ++- .../securesms/home/HomeActivity.kt | 21 +-- .../securesms/home/HomeAdapter.kt | 17 +-- .../securesms/home/HomeDiffUtil.kt | 5 - .../securesms/home/HomeViewModel.kt | 43 +------ .../libsession/database/StorageProtocol.kt | 1 + .../utilities/UpdateMessageBuilder.kt | 7 +- .../messaging/utilities/UpdateMessageData.kt | 6 +- 12 files changed, 116 insertions(+), 159 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt index 29ee66f2da..239c840398 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt @@ -1056,6 +1056,16 @@ open class Storage @Inject constructor( return insertUpdateControlMessage(updateData, sentTimestamp, senderPublicKey, closedGroup) } + override fun insertGroupInfoErrorQuit(closedGroup: AccountId): Long? { + val sentTimestamp = clock.currentTimeMills() + val senderPublicKey = getUserPublicKey() ?: return null + val groupName = configFactory.withGroupConfigs(closedGroup) { it.groupInfo.getName() } + ?: configFactory.getGroup(closedGroup)?.name + val updateData = UpdateMessageData.buildGroupLeaveUpdate(UpdateMessageData.Kind.GroupErrorQuit(groupName.orEmpty())) + + return insertUpdateControlMessage(updateData, sentTimestamp, senderPublicKey, closedGroup) + } + override fun updateGroupInfoChange(messageId: Long, newType: UpdateMessageData.Kind) { val mmsDB = mmsDatabase val newMessage = UpdateMessageData.buildGroupLeaveUpdate(newType) diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java index e4ada0b9c4..a27da20ee4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java @@ -19,6 +19,7 @@ package org.thoughtcrime.securesms.database.model; import android.content.Context; import android.text.Spannable; import android.text.SpannableString; +import android.text.style.ForegroundColorSpan; import android.text.style.RelativeSizeSpan; import android.text.style.StyleSpan; import androidx.annotation.NonNull; @@ -33,9 +34,12 @@ import org.session.libsession.messaging.utilities.UpdateMessageBuilder; import org.session.libsession.messaging.utilities.UpdateMessageData; import org.session.libsession.utilities.IdentityKeyMismatch; import org.session.libsession.utilities.NetworkFailure; +import org.session.libsession.utilities.ThemeUtil; import org.session.libsession.utilities.recipients.Recipient; import org.thoughtcrime.securesms.dependencies.DatabaseComponent; +import network.loki.messenger.R; + /** * The base class for message record models that are displayed in * conversations, as opposed to models that are displayed in a thread list. @@ -137,7 +141,7 @@ public abstract class MessageRecord extends DisplayRecord { return ""; } - return new SpannableString(UpdateMessageBuilder.buildGroupUpdateMessage( + SpannableString text = new SpannableString(UpdateMessageBuilder.buildGroupUpdateMessage( context, updateMessageData, MessagingModuleConfiguration.getShared().getConfigFactory(), @@ -145,6 +149,14 @@ public abstract class MessageRecord extends DisplayRecord { getTimestamp(), getExpireStarted()) ); + + if (updateMessageData.isGroupErrorQuitKind()) { + text.setSpan(new ForegroundColorSpan(ThemeUtil.getThemedColor(context, R.attr.danger)), 0, text.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE); + } else if (updateMessageData.isGroupLeavingKind()) { + text.setSpan(new ForegroundColorSpan(ThemeUtil.getThemedColor(context, android.R.attr.textColorTertiary)), 0, text.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE); + } + + return text; } else if (isExpirationTimerUpdate()) { int seconds = (int) (getExpiresIn() / 1000); boolean isGroup = DatabaseComponent.get(context).threadDatabase().getRecipientForThreadId(getThreadId()).isGroupOrCommunityRecipient(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/ThreadRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/ThreadRecord.java index f08812324a..59c47e297c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/ThreadRecord.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/ThreadRecord.java @@ -125,7 +125,16 @@ public class ThreadRecord extends DisplayRecord { return ""; } else if (isGroupUpdateMessage()) { - return lastMessage.getDisplayBody(context).toString(); + CharSequence body = lastMessage.getDisplayBody(context); + UpdateMessageData updatedMessage = lastMessage.getGroupUpdateMessage(); + + // For group leaving and error quit messages, we will leave the message as formatted + if (updatedMessage != null && (updatedMessage.isGroupLeavingKind() || updatedMessage.isGroupErrorQuitKind())) { + return body; + } + + // Otherwise we'll need to remove all the formatting and just display the text + return body.toString(); } else if (isOpenGroupInvitation()) { return context.getString(R.string.communityInvitation); } else if (MmsSmsColumns.Types.isLegacyType(type)) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupManagerV2Impl.kt b/app/src/main/java/org/thoughtcrime/securesms/groups/GroupManagerV2Impl.kt index b4dd9fbddf..08f6363fa7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupManagerV2Impl.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/GroupManagerV2Impl.kt @@ -426,72 +426,80 @@ class GroupManagerV2Impl @Inject constructor( withContext(SupervisorJob()) { val group = configFactory.getGroup(groupId) - if (group?.destroyed != true) { - // Only send the left/left notification group message when we are not kicked and we are not the only admin (only admin has a special treatment) - val weAreTheOnlyAdmin = configFactory.withGroupConfigs(groupId) { config -> - val allMembers = config.groupMembers.all() - allMembers.count { it.admin } == 1 && - allMembers.first { it.admin } - .accountIdString() == storage.getUserPublicKey() - } - - if (group != null && !group.kicked && !weAreTheOnlyAdmin) { - val destination = Destination.ClosedGroup(groupId.hexString) - val sendMessageTasks = mutableListOf>() - - // Always send a "XXX left" message to the group if we can - sendMessageTasks += async { - MessageSender.send( - GroupUpdated( - GroupUpdateMessage.newBuilder() - .setMemberLeftNotificationMessage(DataMessage.GroupUpdateMemberLeftNotificationMessage.getDefaultInstance()) - .build() - ), - destination, - isSyncMessage = false - ).await() + storage.insertGroupInfoLeaving(groupId) + + try { + if (group?.destroyed != true) { + // Only send the left/left notification group message when we are not kicked and we are not the only admin (only admin has a special treatment) + val weAreTheOnlyAdmin = configFactory.withGroupConfigs(groupId) { config -> + val allMembers = config.groupMembers.all() + allMembers.count { it.admin } == 1 && + allMembers.first { it.admin } + .accountIdString() == storage.getUserPublicKey() } + if (group != null && !group.kicked && !weAreTheOnlyAdmin) { + val destination = Destination.ClosedGroup(groupId.hexString) + val sendMessageTasks = mutableListOf>() + + // Always send a "XXX left" message to the group if we can + sendMessageTasks += async { + MessageSender.send( + GroupUpdated( + GroupUpdateMessage.newBuilder() + .setMemberLeftNotificationMessage(DataMessage.GroupUpdateMemberLeftNotificationMessage.getDefaultInstance()) + .build() + ), + destination, + isSyncMessage = false + ).await() + } - // If we are not the only admin, send a left message for other admin to handle the member removal - sendMessageTasks += async { - MessageSender.send( - GroupUpdated( - GroupUpdateMessage.newBuilder() - .setMemberLeftMessage(DataMessage.GroupUpdateMemberLeftMessage.getDefaultInstance()) - .build() - ), - destination, - isSyncMessage = false - ).await() - } - sendMessageTasks.awaitAll() - } + // If we are not the only admin, send a left message for other admin to handle the member removal + sendMessageTasks += async { + MessageSender.send( + GroupUpdated( + GroupUpdateMessage.newBuilder() + .setMemberLeftMessage(DataMessage.GroupUpdateMemberLeftMessage.getDefaultInstance()) + .build() + ), + destination, + isSyncMessage = false + ).await() + } - // If we are the only admin, leaving this group will destroy the group - if (weAreTheOnlyAdmin) { - configFactory.withMutableGroupConfigs(groupId) { configs -> - configs.groupInfo.destroyGroup() + sendMessageTasks.awaitAll() } - // Must wait until the config is pushed, otherwise if we go through the rest - // of the code it will destroy the conversation, destroying the necessary configs - // along the way, we won't be able to push the "destroyed" state anymore. - configFactory.waitUntilGroupConfigsPushed(groupId) - } - } + // If we are the only admin, leaving this group will destroy the group + if (weAreTheOnlyAdmin) { + configFactory.withMutableGroupConfigs(groupId) { configs -> + configs.groupInfo.destroyGroup() + } - pollerFactory.pollerFor(groupId)?.stop() + // Must wait until the config is pushed, otherwise if we go through the rest + // of the code it will destroy the conversation, destroying the necessary configs + // along the way, we won't be able to push the "destroyed" state anymore. + configFactory.waitUntilGroupConfigsPushed(groupId) + } + } - // Delete conversation and group configs - storage.getThreadId(Address.fromSerialized(groupId.hexString)) - ?.let(storage::deleteConversation) - configFactory.removeGroup(groupId) - lokiAPIDatabase.clearLastMessageHashes(groupId.hexString) - lokiAPIDatabase.clearReceivedMessageHashValues(groupId.hexString) + pollerFactory.pollerFor(groupId)?.stop() + + // Delete conversation and group configs + storage.getThreadId(Address.fromSerialized(groupId.hexString)) + ?.let(storage::deleteConversation) + configFactory.removeGroup(groupId) + lokiAPIDatabase.clearLastMessageHashes(groupId.hexString) + lokiAPIDatabase.clearReceivedMessageHashValues(groupId.hexString) + } catch (e: Exception) { + storage.insertGroupInfoErrorQuit(groupId) + throw e + } } - } } + } + } override suspend fun promoteMember( group: AccountId, diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/ConversationView.kt b/app/src/main/java/org/thoughtcrime/securesms/home/ConversationView.kt index 248ff1e4f2..875ea31092 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/home/ConversationView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/home/ConversationView.kt @@ -48,7 +48,7 @@ class ConversationView : LinearLayout { // endregion // region Updating - fun bind(thread: ThreadRecord, isTyping: Boolean, overriddenSnippet: CharSequence?) { + fun bind(thread: ThreadRecord, isTyping: Boolean) { this.thread = thread if (thread.isPinned) { binding.conversationViewDisplayNameTextView.setCompoundDrawablesRelativeWithIntrinsicBounds( @@ -102,18 +102,14 @@ class ConversationView : LinearLayout { } binding.muteIndicatorImageView.setImageResource(drawableRes) - if (overriddenSnippet != null) { - binding.snippetTextView.text = overriddenSnippet - } else { - binding.snippetTextView.text = highlightMentions( - text = thread.getDisplayBody(context), - formatOnly = true, // no styling here, only text formatting - threadID = thread.threadId, - context = context - ) - } + binding.snippetTextView.text = highlightMentions( + text = thread.getDisplayBody(context), + formatOnly = true, // no styling here, only text formatting + threadID = thread.threadId, + context = context + ) - binding.snippetTextView.typeface = if (unreadCount > 0 && !thread.isRead && overriddenSnippet == null) Typeface.DEFAULT_BOLD else Typeface.DEFAULT + binding.snippetTextView.typeface = if (unreadCount > 0 && !thread.isRead) Typeface.DEFAULT_BOLD else Typeface.DEFAULT binding.snippetTextView.visibility = if (isTyping) View.GONE else View.VISIBLE if (isTyping) { binding.typingIndicatorView.root.startAnimation() diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/HomeActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/home/HomeActivity.kt index 5ecf9495f7..e3aaa86e4f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/home/HomeActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/home/HomeActivity.kt @@ -582,7 +582,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity(), val recipient = thread.recipient if (recipient.isGroupV2Recipient) { - val statusChannel = ConversationMenuHelper.leaveGroup( + ConversationMenuHelper.leaveGroup( context = this, thread = recipient, threadID = threadID, @@ -591,25 +591,6 @@ class HomeActivity : PassphraseRequiredActionBarActivity(), groupManager = groupManagerV2, ) - if (statusChannel != null) { - lifecycleScope.launch { - statusChannel.consumeEach { status -> - when (status) { - ConversationMenuHelper.GroupLeavingStatus.Leaving -> { - homeViewModel.onLeavingGroupStarted(threadID) - } - - ConversationMenuHelper.GroupLeavingStatus.Left -> { - homeViewModel.onLeavingGroupFinished(threadID, isError = false) - } - ConversationMenuHelper.GroupLeavingStatus.Error -> { - homeViewModel.onLeavingGroupFinished(threadID, isError = true) - } - } - } - } - } - return } diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/HomeAdapter.kt b/app/src/main/java/org/thoughtcrime/securesms/home/HomeAdapter.kt index 55856a5e33..1e64fc3f4f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/home/HomeAdapter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/home/HomeAdapter.kt @@ -2,18 +2,14 @@ package org.thoughtcrime.securesms.home import android.annotation.SuppressLint import android.content.Context -import android.text.SpannableStringBuilder -import android.text.style.ForegroundColorSpan import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.DiffUtil -import androidx.recyclerview.widget.ListUpdateCallback import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView.NO_ID import com.bumptech.glide.RequestManager import network.loki.messenger.R import network.loki.messenger.databinding.ViewMessageRequestBannerBinding -import org.session.libsession.utilities.getColorFromAttr import org.thoughtcrime.securesms.dependencies.ConfigFactory class HomeAdapter( @@ -80,18 +76,7 @@ class HomeAdapter( is ConversationViewHolder -> { val item = data.items[position] as HomeViewModel.Item.Thread - val overrideText = item.overriddenSnippet?.let { msg -> - SpannableStringBuilder(msg.text).apply { - setSpan( - ForegroundColorSpan(holder.view.context.getColorFromAttr(msg.colorAttr)), - 0, - msg.text.length, - SpannableStringBuilder.SPAN_INCLUSIVE_EXCLUSIVE - ) - } - } - - holder.view.bind(item.thread, item.isTyping, overrideText) + holder.view.bind(item.thread, item.isTyping) } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/HomeDiffUtil.kt b/app/src/main/java/org/thoughtcrime/securesms/home/HomeDiffUtil.kt index a923709efd..d77eb5b19e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/home/HomeDiffUtil.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/home/HomeDiffUtil.kt @@ -62,11 +62,6 @@ class HomeDiffUtil( // once when the initial recipient data is loaded if (isSameItem) { isSameItem = (oldItem.initialRecipientHash == newItem.initialRecipientHash) } - // Check if we would have different "overridden" message summary - if (isSameItem) { - isSameItem = (old.overriddenSnippet == new.overriddenSnippet) - } - // Note: Two instances of 'SpannableString' may not equate even though their content matches if (isSameItem) { isSameItem = (oldItem.getDisplayBody(context).toString() == newItem.getDisplayBody(context).toString()) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/HomeViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/home/HomeViewModel.kt index d34c1b3097..5891d10f2a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/home/HomeViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/home/HomeViewModel.kt @@ -6,14 +6,12 @@ import androidx.annotation.AttrRes import androidx.lifecycle.ViewModel import androidx.lifecycle.asFlow import androidx.lifecycle.viewModelScope -import com.squareup.phrase.Phrase import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine @@ -26,10 +24,7 @@ import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn -import kotlinx.coroutines.flow.update -import network.loki.messenger.R import network.loki.messenger.libsession_util.ConfigBase.Companion.PRIORITY_HIDDEN -import org.session.libsession.utilities.StringSubstitutionConstants.GROUP_NAME_KEY import org.session.libsession.utilities.TextSecurePreferences import org.thoughtcrime.securesms.database.DatabaseContentProviders import org.thoughtcrime.securesms.database.ThreadDatabase @@ -45,7 +40,6 @@ class HomeViewModel @Inject constructor( private val threadDb: ThreadDatabase, private val contentResolver: ContentResolver, private val prefs: TextSecurePreferences, - @ApplicationContextQualifier private val context: Context, private val typingStatusRepository: TypingStatusRepository, private val configFactory: ConfigFactory ) : ViewModel() { @@ -55,8 +49,6 @@ class HomeViewModel @Inject constructor( onBufferOverflow = BufferOverflow.DROP_OLDEST ) - private val overrideMessageSnippets = MutableStateFlow(emptyMap()) - /** * A [StateFlow] that emits the list of threads and the typing status of each thread. * @@ -66,10 +58,9 @@ class HomeViewModel @Inject constructor( val data: StateFlow = combine( observeConversationList(), observeTypingStatus(), - overrideMessageSnippets, messageRequests(), hasHiddenNoteToSelf() - ) { threads, typingStatus, overrideMessageSnippets, messageRequests, hideNoteToSelf -> + ) { threads, typingStatus, messageRequests, hideNoteToSelf -> Data( items = buildList { messageRequests?.let { add(it) } @@ -83,7 +74,6 @@ class HomeViewModel @Inject constructor( Item.Thread( thread = thread, isTyping = typingStatus.contains(thread.threadId), - overriddenSnippet = overrideMessageSnippets[thread.threadId] ) } } @@ -148,7 +138,6 @@ class HomeViewModel @Inject constructor( data class Thread( val thread: ThreadRecord, val isTyping: Boolean, - val overriddenSnippet: MessageSnippetOverride? ) : Item data class MessageRequests(val count: Int) : Item @@ -159,36 +148,6 @@ class HomeViewModel @Inject constructor( hidden: Boolean, ) = if (count > 0 && !hidden) Item.MessageRequests(count) else null - fun onLeavingGroupStarted(threadId: Long) { - val message = MessageSnippetOverride( - text = context.getString(R.string.leaving), - colorAttr = android.R.attr.textColorTertiary - ) - - overrideMessageSnippets.update { it + (threadId to message) } - } - - fun onLeavingGroupFinished(threadId: Long, isError: Boolean) { - if (isError) { - val errorMessage = MessageSnippetOverride( - text = Phrase.from(context, R.string.groupLeaveErrorFailed) - .put(GROUP_NAME_KEY, - data.value?.items - ?.asSequence() - ?.filterIsInstance() - ?.find { it.thread.threadId == threadId } - ?.thread?.recipient?.name - ?: context.getString(R.string.unknown) - ) - .format(), - colorAttr = R.attr.danger - ) - - overrideMessageSnippets.update { it + (threadId to errorMessage) } - } else { - overrideMessageSnippets.update { it - threadId } - } - } fun hideNoteToSelf() { prefs.setHasHiddenNoteToSelf(true) diff --git a/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt b/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt index d0ba0d7b1f..cdb6b439e6 100644 --- a/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt +++ b/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt @@ -169,6 +169,7 @@ interface StorageProtocol { fun getClosedGroupDisplayInfo(groupAccountId: String): GroupDisplayInfo? fun insertGroupInfoChange(message: GroupUpdated, closedGroup: AccountId): Long? fun insertGroupInfoLeaving(closedGroup: AccountId): Long? + fun insertGroupInfoErrorQuit(closedGroup: AccountId): Long? fun insertGroupInviteControlMessage( sentTimestamp: Long, senderPublicKey: String, diff --git a/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt b/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt index fbcca8fa24..b1d1937233 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt @@ -11,14 +11,11 @@ import org.session.libsession.messaging.calls.CallMessageType.CALL_MISSED import org.session.libsession.messaging.calls.CallMessageType.CALL_OUTGOING import org.session.libsession.messaging.contacts.Contact import org.session.libsession.messaging.sending_receiving.data_extraction.DataExtractionNotificationInfoMessage -import org.session.libsession.utilities.Address import org.session.libsession.messaging.sending_receiving.data_extraction.DataExtractionNotificationInfoMessage.Kind.MEDIA_SAVED import org.session.libsession.messaging.sending_receiving.data_extraction.DataExtractionNotificationInfoMessage.Kind.SCREENSHOT -import org.session.libsession.snode.SnodeAPI import org.session.libsession.utilities.ConfigFactoryProtocol import org.session.libsession.utilities.ExpirationUtil import org.session.libsession.utilities.getExpirationTypeDisplayValue -import org.session.libsession.utilities.recipients.Recipient import org.session.libsession.utilities.truncateIdForDisplay import org.session.libsignal.utilities.Log import org.session.libsession.utilities.StringSubstitutionConstants.COUNT_KEY @@ -311,7 +308,9 @@ object UpdateMessageBuilder { } } is UpdateMessageData.Kind.GroupErrorQuit -> { - return context.getString(R.string.groupLeaveErrorFailed) + return Phrase.from(context, R.string.groupLeaveErrorFailed) + .put(GROUP_NAME_KEY, updateData.groupName) + .format() } } } diff --git a/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageData.kt b/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageData.kt index 4181b2e28d..311767da93 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageData.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageData.kt @@ -63,7 +63,9 @@ class UpdateMessageData () { constructor(): this("", "") } data object GroupLeaving: Kind() - data object GroupErrorQuit: Kind() + data class GroupErrorQuit(val groupName: String): Kind() { + constructor(): this("") + } class GroupInvitation( val groupAccountId: String, val invitingAdminId: String, @@ -101,7 +103,7 @@ class UpdateMessageData () { SignalServiceGroup.Type.MEMBER_REMOVED -> UpdateMessageData(Kind.GroupMemberRemoved(members, name)) SignalServiceGroup.Type.QUIT -> UpdateMessageData(Kind.GroupMemberLeft(members, name)) SignalServiceGroup.Type.LEAVING -> UpdateMessageData(Kind.GroupLeaving) - SignalServiceGroup.Type.ERROR_QUIT -> UpdateMessageData(Kind.GroupErrorQuit) + SignalServiceGroup.Type.ERROR_QUIT -> UpdateMessageData(Kind.GroupErrorQuit(groupName = name)) SignalServiceGroup.Type.UNKNOWN, SignalServiceGroup.Type.UPDATE, SignalServiceGroup.Type.DELIVER,