New message deletion feature

This commit is contained in:
Benoit Martins 2025-11-20 16:48:38 +01:00
parent 07dbf407b0
commit 0daba4fe03
14 changed files with 272 additions and 86 deletions

View file

@ -474,9 +474,9 @@
"message_copied_to_clipboard_toast" = "Zpráva zkopírována do schránky"; "message_copied_to_clipboard_toast" = "Zpráva zkopírována do schránky";
"message_delivery_info_read_title" = "Přečteno"; "message_delivery_info_read_title" = "Přečteno";
"message_delivery_info_received_title" = "Přijato"; "message_delivery_info_received_title" = "Přijato";
"message_meeting_invitation_cancelled_notification" = "📅 Schůzka byla zrušena"; "message_meeting_invitation_cancelled_notification" = "Schůzka byla zrušena";
"message_meeting_invitation_notification" = "📅 Jste pozváni na schůzku"; "message_meeting_invitation_notification" = "Jste pozváni na schůzku";
"message_meeting_invitation_updated_notification" = "📅 Schůzka byla aktualizována"; "message_meeting_invitation_updated_notification" = "Schůzka byla aktualizována";
"message_reactions_info_all_title" = "Reakce"; "message_reactions_info_all_title" = "Reakce";
"network_reachable_again" = "Síť je znovu dostupná"; "network_reachable_again" = "Síť je znovu dostupná";
"menu_block_number" = "Blokovat číslo"; "menu_block_number" = "Blokovat číslo";

View file

@ -467,9 +467,9 @@
"message_delivery_info_read_title" = "Gelesen"; "message_delivery_info_read_title" = "Gelesen";
"message_delivery_info_received_title" = "Empfangen"; "message_delivery_info_received_title" = "Empfangen";
"message_delivery_info_sent_title" = "Gesendet"; "message_delivery_info_sent_title" = "Gesendet";
"message_meeting_invitation_cancelled_notification" = "📅 Die Besprechung wurde abgesagt"; "message_meeting_invitation_cancelled_notification" = "Die Besprechung wurde abgesagt";
"message_meeting_invitation_notification" = "📅 Sie sind zu einer Besprechung eingeladen"; "message_meeting_invitation_notification" = "Sie sind zu einer Besprechung eingeladen";
"message_meeting_invitation_updated_notification" = "📅 Besprechung wurde aktualisiert"; "message_meeting_invitation_updated_notification" = "Besprechung wurde aktualisiert";
"message_reactions_info_all_title" = "Reaktionen"; "message_reactions_info_all_title" = "Reaktionen";
"network_reachable_again" = "Netzwerk ist nun wieder erreichbar"; "network_reachable_again" = "Netzwerk ist nun wieder erreichbar";
"None" = "Kein"; "None" = "Kein";

View file

@ -206,6 +206,11 @@
"conversation_dialog_subject_hint" = "Conversation subject"; "conversation_dialog_subject_hint" = "Conversation subject";
"conversation_editing_message_title" = "Message being edited"; "conversation_editing_message_title" = "Message being edited";
"conversation_message_edited_label" = "Edited"; "conversation_message_edited_label" = "Edited";
"conversation_dialog_delete_chat_message_title" = "Delete this message?";
"conversation_dialog_delete_locally_label" = "For me";
"conversation_dialog_delete_for_everyone_label" = "For everyone";
"conversation_message_content_deleted_label" = "This message has been deleted";
"conversation_message_content_deleted_by_us_label" = "You have deleted this message";
"conversation_end_to_end_encrypted_bottom_sheet_link" = "https://linphone.org/en/features/#security"; "conversation_end_to_end_encrypted_bottom_sheet_link" = "https://linphone.org/en/features/#security";
"conversation_end_to_end_encrypted_event_title" = "End-to-end encrypted conversation"; "conversation_end_to_end_encrypted_event_title" = "End-to-end encrypted conversation";
"conversation_end_to_end_encrypted_event_subtitle" = "Messages in this conversation are e2e encrypted. Only your correspondent can decrypt them."; "conversation_end_to_end_encrypted_event_subtitle" = "Messages in this conversation are e2e encrypted. Only your correspondent can decrypt them.";
@ -407,9 +412,9 @@
"message_delivery_info_received_title" = "Received"; "message_delivery_info_received_title" = "Received";
"message_delivery_info_sent_title" = "Sent"; "message_delivery_info_sent_title" = "Sent";
"message_forwarded_label" = "Forwarded"; "message_forwarded_label" = "Forwarded";
"message_meeting_invitation_cancelled_notification" = "📅 Meeting has been cancelled"; "message_meeting_invitation_cancelled_notification" = "Meeting has been cancelled";
"message_meeting_invitation_notification" = "📅 You are invited to a meeting"; "message_meeting_invitation_notification" = "You are invited to a meeting";
"message_meeting_invitation_updated_notification" = "📅 Meeting has been updated"; "message_meeting_invitation_updated_notification" = "Meeting has been updated";
"message_reaction_click_to_remove_label" = "Click to remove"; "message_reaction_click_to_remove_label" = "Click to remove";
"message_reactions_info_all_title" = "Reactions"; "message_reactions_info_all_title" = "Reactions";
"network_not_reachable" = "You aren't connected to internet"; "network_not_reachable" = "You aren't connected to internet";

View file

@ -206,6 +206,11 @@
"conversation_dialog_subject_hint" = "Nom de la conversation"; "conversation_dialog_subject_hint" = "Nom de la conversation";
"conversation_editing_message_title" = "Modification du message"; "conversation_editing_message_title" = "Modification du message";
"conversation_message_edited_label" = "Modifié"; "conversation_message_edited_label" = "Modifié";
"conversation_dialog_delete_chat_message_title" = "Supprimer le message ?";
"conversation_dialog_delete_locally_label" = "Pour moi";
"conversation_dialog_delete_for_everyone_label" = "Pour tout le monde";
"conversation_message_content_deleted_label" = "*Le message a été supprimé*";
"conversation_message_content_deleted_by_us_label" = "*Vous avez supprimé le message*";
"conversation_end_to_end_encrypted_bottom_sheet_link" = "https://linphone.org/en/features/#security"; "conversation_end_to_end_encrypted_bottom_sheet_link" = "https://linphone.org/en/features/#security";
"conversation_end_to_end_encrypted_event_title" = "Conversation chiffrée de bout en bout"; "conversation_end_to_end_encrypted_event_title" = "Conversation chiffrée de bout en bout";
"conversation_end_to_end_encrypted_event_subtitle" = "Les messages de cette conversation sont chiffrés de bout en bout. Seul votre correspondant peut les déchiffrer."; "conversation_end_to_end_encrypted_event_subtitle" = "Les messages de cette conversation sont chiffrés de bout en bout. Seul votre correspondant peut les déchiffrer.";
@ -407,9 +412,9 @@
"message_delivery_info_received_title" = "Reçu"; "message_delivery_info_received_title" = "Reçu";
"message_delivery_info_sent_title" = "Envoyé"; "message_delivery_info_sent_title" = "Envoyé";
"message_forwarded_label" = "Transféré"; "message_forwarded_label" = "Transféré";
"message_meeting_invitation_cancelled_notification" = "📅 Réunion annulée"; "message_meeting_invitation_cancelled_notification" = "Réunion annulée";
"message_meeting_invitation_notification" = "📅 Invitation à une réunion"; "message_meeting_invitation_notification" = "Invitation à une réunion";
"message_meeting_invitation_updated_notification" = "📅 Réunion mise à jour"; "message_meeting_invitation_updated_notification" = "Réunion mise à jour";
"message_reaction_click_to_remove_label" = "Cliquez pour supprimer"; "message_reaction_click_to_remove_label" = "Cliquez pour supprimer";
"message_reactions_info_all_title" = "Réactions"; "message_reactions_info_all_title" = "Réactions";
"network_not_reachable" = "Vous nêtes pas connecté à internet"; "network_not_reachable" = "Vous nêtes pas connecté à internet";

View file

@ -456,9 +456,9 @@
"message_delivery_info_read_title" = "Читати"; "message_delivery_info_read_title" = "Читати";
"message_delivery_info_received_title" = "Отримано"; "message_delivery_info_received_title" = "Отримано";
"message_delivery_info_sent_title" = "Відправлено"; "message_delivery_info_sent_title" = "Відправлено";
"message_meeting_invitation_cancelled_notification" = "📅 Нараду скасовано"; "message_meeting_invitation_cancelled_notification" = "Нараду скасовано";
"message_meeting_invitation_notification" = "📅 Вас запрошено на нараду"; "message_meeting_invitation_notification" = "Вас запрошено на нараду";
"message_meeting_invitation_updated_notification" = "📅 Нараду оновлено"; "message_meeting_invitation_updated_notification" = "Нараду оновлено";
"message_reactions_info_all_title" = "Реакції"; "message_reactions_info_all_title" = "Реакції";
"network_reachable_again" = "Мережа знову доступна"; "network_reachable_again" = "Мережа знову доступна";
"None" = "Жоден"; "None" = "Жоден";

View file

@ -60,6 +60,7 @@ struct ContentView: View {
@State var isShowDismissPopup = false @State var isShowDismissPopup = false
@State var isShowSendCancelMeetingNotificationPopup = false @State var isShowSendCancelMeetingNotificationPopup = false
@State var isShowStartCallGroupPopup = false @State var isShowStartCallGroupPopup = false
@State var isShowDeleteMessagePopup = false
@State var isShowSipAddressesPopup = false @State var isShowSipAddressesPopup = false
@State var isShowSipAddressesPopupType = 0 // 0 to call, 1 to message, 2 to video call @State var isShowSipAddressesPopupType = 0 // 0 to call, 1 to message, 2 to video call
@State var isShowConversationFragment = false @State var isShowConversationFragment = false
@ -987,6 +988,7 @@ struct ContentView: View {
ConversationFragment( ConversationFragment(
isShowConversationFragment: $isShowConversationFragment, isShowConversationFragment: $isShowConversationFragment,
isShowStartCallGroupPopup: $isShowStartCallGroupPopup, isShowStartCallGroupPopup: $isShowStartCallGroupPopup,
isShowDeleteMessagePopup: $isShowDeleteMessagePopup,
isShowEditContactFragment: $isShowEditContactFragment, isShowEditContactFragment: $isShowEditContactFragment,
isShowEditContactFragmentAddress: $isShowEditContactFragmentAddress, isShowEditContactFragmentAddress: $isShowEditContactFragmentAddress,
isShowScheduleMeetingFragment: $isShowScheduleMeetingFragment, isShowScheduleMeetingFragment: $isShowScheduleMeetingFragment,
@ -1354,31 +1356,30 @@ struct ContentView: View {
} }
} }
/* if isShowDeleteMessagePopup {
if isShowStartCallGroupPopup {
PopupView( PopupView(
isShowPopup: $isShowStartCallGroupPopup, isShowPopup: $isShowDeleteMessagePopup,
title: Text("conversation_info_confirm_start_group_call_dialog_title"), title: Text("conversation_dialog_delete_chat_message_title"),
content: Text("conversation_info_confirm_start_group_call_dialog_message"), content: nil,
titleFirstButton: Text("dialog_cancel"), titleFirstButton: Text("conversation_dialog_delete_for_everyone_label"),
actionFirstButton: { self.isShowStartCallGroupPopup.toggle() }, actionFirstButton: {
titleSecondButton: Text("dialog_confirm"), NotificationCenter.default.post(name: NSNotification.Name("DeleteMessageForEveryone"), object: nil)
self.isShowDeleteMessagePopup.toggle()
},
titleSecondButton: Text("conversation_dialog_delete_locally_label"),
actionSecondButton: { actionSecondButton: {
if sharedMainViewModel.displayedConversation != nil { NotificationCenter.default.post(name: NSNotification.Name("DeleteMessageForMe"), object: nil)
sharedMainViewModel.displayedConversation!.createGroupCall() self.isShowDeleteMessagePopup.toggle()
}
self.isShowStartCallGroupPopup.toggle()
}, },
titleThirdButton: Text("dialog_cancel"), titleThirdButton: Text("dialog_cancel"),
actionThirdButton: { self.isShowStartCallGroupPopup.toggle() } actionThirdButton: { self.isShowDeleteMessagePopup.toggle() }
) )
.background(.black.opacity(0.65)) .background(.black.opacity(0.65))
.zIndex(3) .zIndex(3)
.onTapGesture { .onTapGesture {
self.isShowStartCallGroupPopup.toggle() self.isShowDeleteMessagePopup.toggle()
} }
} }
*/
if isShowConversationInfoPopup { if isShowConversationInfoPopup {
PopupViewWithTextField( PopupViewWithTextField(

View file

@ -52,7 +52,7 @@ struct ChatBubbleView: View {
HStack { HStack {
if eventLogMessage.eventModel.eventLogType == .ConferenceChatMessage { if eventLogMessage.eventModel.eventLogType == .ConferenceChatMessage {
VStack { VStack {
if !eventLogMessage.message.text.isEmpty || !eventLogMessage.message.attachments.isEmpty || eventLogMessage.message.isIcalendar { if !eventLogMessage.message.text.isEmpty || !eventLogMessage.message.attachments.isEmpty || eventLogMessage.message.isIcalendar || eventLogMessage.message.isRetracted {
HStack(alignment: .top, content: { HStack(alignment: .top, content: {
if eventLogMessage.message.isOutgoing { if eventLogMessage.message.isOutgoing {
Spacer() Spacer()
@ -137,6 +137,12 @@ struct ChatBubbleView: View {
.foregroundStyle(Color.grayMain2c700) .foregroundStyle(Color.grayMain2c700)
.default_text_style(styleSize: 14) .default_text_style(styleSize: 14)
.lineLimit(/*@START_MENU_TOKEN@*/2/*@END_MENU_TOKEN@*/) .lineLimit(/*@START_MENU_TOKEN@*/2/*@END_MENU_TOKEN@*/)
} else if eventLogMessage.message.replyMessage!.isRetracted {
Text(eventLogMessage.message.replyMessage!.isOutgoing ? "conversation_message_content_deleted_by_us_label" : "conversation_message_content_deleted_label")
.italic()
.foregroundStyle(Color.grayMain2c500)
.font(.system(size: 14))
.lineLimit(1)
} }
} }
.padding(.all, 15) .padding(.all, 15)
@ -174,6 +180,12 @@ struct ChatBubbleView: View {
if !eventLogMessage.message.text.isEmpty { if !eventLogMessage.message.text.isEmpty {
DynamicLinkText(text: eventLogMessage.message.text) DynamicLinkText(text: eventLogMessage.message.text)
} else if eventLogMessage.message.isRetracted {
Text(eventLogMessage.message.isOutgoing ? "conversation_message_content_deleted_by_us_label" : "conversation_message_content_deleted_label")
.italic()
.foregroundStyle(Color.grayMain2c500)
.font(.system(size: 14))
.lineLimit(1)
} }
if eventLogMessage.message.isIcalendar && eventLogMessage.message.messageConferenceInfo != nil { if eventLogMessage.message.isIcalendar && eventLogMessage.message.messageConferenceInfo != nil {

View file

@ -64,6 +64,7 @@ struct ConversationFragment: View {
@Binding var isShowConversationFragment: Bool @Binding var isShowConversationFragment: Bool
@Binding var isShowStartCallGroupPopup: Bool @Binding var isShowStartCallGroupPopup: Bool
@Binding var isShowDeleteMessagePopup: Bool
@State private var selectedCategoryIndex = 0 @State private var selectedCategoryIndex = 0
@ -1194,6 +1195,7 @@ struct ConversationFragment: View {
Divider() Divider()
} }
if !conversationViewModel.selectedMessage!.message.isRetracted {
Button { Button {
let indexMessage = conversationViewModel.conversationMessagesSection[0].rows.firstIndex(where: {$0.message.id == conversationViewModel.selectedMessage!.message.id}) let indexMessage = conversationViewModel.conversationMessagesSection[0].rows.firstIndex(where: {$0.message.id == conversationViewModel.selectedMessage!.message.id})
conversationViewModel.selectedMessage = nil conversationViewModel.selectedMessage = nil
@ -1215,6 +1217,7 @@ struct ConversationFragment: View {
} }
Divider() Divider()
}
if !conversationViewModel.selectedMessage!.message.text.isEmpty { if !conversationViewModel.selectedMessage!.message.text.isEmpty {
Button { Button {
@ -1243,6 +1246,7 @@ struct ConversationFragment: View {
Divider() Divider()
} }
if !conversationViewModel.selectedMessage!.message.isRetracted {
Button { Button {
withAnimation { withAnimation {
isShowConversationForwardMessageFragment = true isShowConversationForwardMessageFragment = true
@ -1261,9 +1265,16 @@ struct ConversationFragment: View {
} }
Divider() Divider()
}
Button { Button {
if conversationViewModel.selectedMessage!.message.isOutgoing
&& !(SharedMainViewModel.shared.displayedConversation?.isReadOnly ?? cachedConversation!.isReadOnly)
&& conversationViewModel.selectedMessage!.message.isRetractable && !conversationViewModel.selectedMessage!.message.isRetracted {
isShowDeleteMessagePopup = true
} else {
conversationViewModel.deleteMessage() conversationViewModel.deleteMessage()
}
} label: { } label: {
HStack { HStack {
Text("menu_delete_selected_item") Text("menu_delete_selected_item")
@ -1316,6 +1327,10 @@ struct ConversationFragment: View {
if conversationViewModel.selectedMessage != nil { if conversationViewModel.selectedMessage != nil {
conversationViewModel.selectedMessage = nil conversationViewModel.selectedMessage = nil
} }
}.onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("DeleteMessageForMe"))) { _ in
conversationViewModel.deleteMessage()
}.onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("DeleteMessageForEveryone"))) { _ in
conversationViewModel.deleteMessageForEveryone()
} }
} }

View file

@ -105,6 +105,17 @@ struct ConversationRow: View {
.frame(maxWidth: .infinity, alignment: .leading) .frame(maxWidth: .infinity, alignment: .leading)
.lineLimit(1) .lineLimit(1)
if conversation.lastMessageInItalic {
Text(conversation.lastMessageText)
.italic()
.if(conversation.unreadMessagesCount > 0) { view in
view.bold()
}
.foregroundStyle(Color.grayMain2c400)
.font(.system(size: 14))
.frame(maxWidth: .infinity, alignment: .leading)
.lineLimit(1)
} else {
Text(conversation.lastMessageText) Text(conversation.lastMessageText)
.foregroundStyle(Color.grayMain2c400) .foregroundStyle(Color.grayMain2c400)
.if(conversation.unreadMessagesCount > 0) { view in .if(conversation.unreadMessagesCount > 0) { view in
@ -113,6 +124,7 @@ struct ConversationRow: View {
.default_text_style(styleSize: 14) .default_text_style(styleSize: 14)
.frame(maxWidth: .infinity, alignment: .leading) .frame(maxWidth: .infinity, alignment: .leading)
.lineLimit(1) .lineLimit(1)
}
Spacer() Spacer()
} }

View file

@ -551,6 +551,12 @@ struct UIList: UIViewRepresentable {
} }
func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let eventLogMessage = parent.conversationViewModel.conversationMessagesSection[0].rows[indexPath.row]
guard !eventLogMessage.message.isRetracted && eventLogMessage.eventModel.eventLogType == .ConferenceChatMessage else {
return nil
}
let archiveAction = UIContextualAction(style: .normal, title: "") { _, _, completionHandler in let archiveAction = UIContextualAction(style: .normal, title: "") { _, _, completionHandler in
self.parent.conversationViewModel.replyToMessage(index: indexPath.row, isMessageTextFocused: Binding( self.parent.conversationViewModel.replyToMessage(index: indexPath.row, isMessageTextFocused: Binding(
get: { self.parent.isMessageTextFocused }, get: { self.parent.isMessageTextFocused },

View file

@ -49,6 +49,7 @@ class ConversationModel: ObservableObject, Identifiable {
@Published var lastMessageText: String @Published var lastMessageText: String
@Published var lastMessageIsOutgoing: Bool @Published var lastMessageIsOutgoing: Bool
@Published var lastMessageState: Int @Published var lastMessageState: Int
@Published var lastMessageInItalic: Bool
@Published var unreadMessagesCount: Int @Published var unreadMessagesCount: Int
@Published var avatarModel: ContactAvatarModel @Published var avatarModel: ContactAvatarModel
@ -144,6 +145,8 @@ class ConversationModel: ObservableObject, Identifiable {
self.lastMessageState = 0 self.lastMessageState = 0
self.lastMessageInItalic = false
self.unreadMessagesCount = chatRoom.unreadMessagesCount self.unreadMessagesCount = chatRoom.unreadMessagesCount
getContentTextMessage(chatRoom: chatRoom) getContentTextMessage(chatRoom: chatRoom)
@ -297,6 +300,8 @@ class ConversationModel: ObservableObject, Identifiable {
var lastMessageTextTmp = (fromAddressFriend ?? "") var lastMessageTextTmp = (fromAddressFriend ?? "")
+ (lastMessage!.contents.first(where: {$0.isText == true})?.utf8Text ?? (lastMessage!.contents.first(where: {$0.isFile == true || $0.isFileTransfer == true})?.name ?? "")) + (lastMessage!.contents.first(where: {$0.isText == true})?.utf8Text ?? (lastMessage!.contents.first(where: {$0.isFile == true || $0.isFileTransfer == true})?.name ?? ""))
var lastMessageInItalicTmp = false
if lastMessage!.contents.first != nil && lastMessage!.contents.first!.isIcalendar == true { if lastMessage!.contents.first != nil && lastMessage!.contents.first!.isIcalendar == true {
if let conferenceInfo = try? Factory.Instance.createConferenceInfoFromIcalendarContent(content: lastMessage!.contents.first!) { if let conferenceInfo = try? Factory.Instance.createConferenceInfoFromIcalendarContent(content: lastMessage!.contents.first!) {
if conferenceInfo.uri != nil { if conferenceInfo.uri != nil {
@ -308,10 +313,18 @@ class ConversationModel: ObservableObject, Identifiable {
} else if conferenceInfo.state == .Cancelled { } else if conferenceInfo.state == .Cancelled {
lastMessageTextTmp = String(localized: "message_meeting_invitation_cancelled_notification") lastMessageTextTmp = String(localized: "message_meeting_invitation_cancelled_notification")
} }
lastMessageInItalicTmp = true
} }
} }
} }
if lastMessage!.isRetracted {
lastMessageTextTmp += lastMessage!.isOutgoing ? String(localized: "conversation_message_content_deleted_by_us_label") : String(localized: "conversation_message_content_deleted_label")
lastMessageInItalicTmp = true
}
let lastMessageIsOutgoingTmp = lastMessage?.isOutgoing ?? false let lastMessageIsOutgoingTmp = lastMessage?.isOutgoing ?? false
let lastUpdateTimeTmp = lastMessage?.time ?? chatRoom.lastUpdateTime let lastUpdateTimeTmp = lastMessage?.time ?? chatRoom.lastUpdateTime
@ -326,6 +339,8 @@ class ConversationModel: ObservableObject, Identifiable {
self.lastUpdateTime = lastUpdateTimeTmp self.lastUpdateTime = lastUpdateTimeTmp
self.lastMessageState = lastMessageStateTmp self.lastMessageState = lastMessageStateTmp
self.lastMessageInItalic = lastMessageInItalicTmp
} }
getUnreadMessagesCount() getUnreadMessagesCount()

View file

@ -69,7 +69,9 @@ public struct Message: Identifiable, Hashable {
public var createdAt: Date public var createdAt: Date
public var isOutgoing: Bool public var isOutgoing: Bool
public var isEditable: Bool public var isEditable: Bool
public var isRetractable: Bool
public var isEdited: Bool public var isEdited: Bool
public var isRetracted: Bool
public var dateReceived: time_t public var dateReceived: time_t
public var address: String public var address: String
@ -97,7 +99,9 @@ public struct Message: Identifiable, Hashable {
createdAt: Date = Date(), createdAt: Date = Date(),
isOutgoing: Bool, isOutgoing: Bool,
isEditable: Bool, isEditable: Bool,
isRetractable: Bool,
isEdited: Bool, isEdited: Bool,
isRetracted: Bool,
dateReceived: time_t, dateReceived: time_t,
address: String, address: String,
isFirstMessage: Bool = false, isFirstMessage: Bool = false,
@ -121,7 +125,9 @@ public struct Message: Identifiable, Hashable {
self.createdAt = createdAt self.createdAt = createdAt
self.isOutgoing = isOutgoing self.isOutgoing = isOutgoing
self.isEditable = isEditable self.isEditable = isEditable
self.isRetractable = isRetractable
self.isEdited = isEdited self.isEdited = isEdited
self.isRetracted = isRetracted
self.dateReceived = dateReceived self.dateReceived = dateReceived
self.isFirstMessage = isFirstMessage self.isFirstMessage = isFirstMessage
self.address = address self.address = address
@ -170,7 +176,9 @@ public struct Message: Identifiable, Hashable {
createdAt: draft.createdAt, createdAt: draft.createdAt,
isOutgoing: draft.isOutgoing, isOutgoing: draft.isOutgoing,
isEditable: draft.isEditable, isEditable: draft.isEditable,
isRetractable: draft.isRetractable,
isEdited: draft.isEdited, isEdited: draft.isEdited,
isRetracted: draft.isRetracted,
dateReceived: draft.dateReceived, dateReceived: draft.dateReceived,
address: draft.address, address: draft.address,
isFirstMessage: draft.isFirstMessage, isFirstMessage: draft.isFirstMessage,
@ -192,7 +200,7 @@ extension Message {
extension Message: Equatable { extension Message: Equatable {
public static func == (lhs: Message, rhs: Message) -> Bool { public static func == (lhs: Message, rhs: Message) -> Bool {
lhs.id == rhs.id && lhs.status == rhs.status && lhs.isEdited == rhs.isEdited && lhs.isFirstMessage == rhs.isFirstMessage && lhs.text == rhs.text && lhs.attachments == rhs.attachments && lhs.replyMessage?.text == rhs.replyMessage?.text && lhs.ownReaction == rhs.ownReaction && lhs.reactions == rhs.reactions && lhs.ephemeralExpireTime == rhs.ephemeralExpireTime lhs.id == rhs.id && lhs.status == rhs.status && lhs.isEdited == rhs.isEdited && lhs.isRetracted == rhs.isRetracted && lhs.isFirstMessage == rhs.isFirstMessage && lhs.text == rhs.text && lhs.attachments == rhs.attachments && lhs.replyMessage?.text == rhs.replyMessage?.text && lhs.replyMessage?.isRetracted == rhs.replyMessage?.isRetracted && lhs.ownReaction == rhs.ownReaction && lhs.reactions == rhs.reactions && lhs.ephemeralExpireTime == rhs.ephemeralExpireTime
} }
} }
@ -220,7 +228,9 @@ public struct ReplyMessage: Codable, Identifiable, Hashable {
public var text: String public var text: String
public var isOutgoing: Bool public var isOutgoing: Bool
public var isEditable: Bool public var isEditable: Bool
public var isRetractable: Bool
public var isEdited: Bool public var isEdited: Bool
public var isRetracted: Bool
public var dateReceived: time_t public var dateReceived: time_t
public var attachmentsNames: String public var attachmentsNames: String
public var attachments: [Attachment] public var attachments: [Attachment]
@ -232,7 +242,9 @@ public struct ReplyMessage: Codable, Identifiable, Hashable {
text: String = "", text: String = "",
isOutgoing: Bool, isOutgoing: Bool,
isEditable: Bool, isEditable: Bool,
isRetractable: Bool,
isEdited: Bool, isEdited: Bool,
isRetracted: Bool,
dateReceived: time_t, dateReceived: time_t,
attachmentsNames: String = "", attachmentsNames: String = "",
attachments: [Attachment] = [], attachments: [Attachment] = [],
@ -244,7 +256,9 @@ public struct ReplyMessage: Codable, Identifiable, Hashable {
self.text = text self.text = text
self.isOutgoing = isOutgoing self.isOutgoing = isOutgoing
self.isEditable = isEditable self.isEditable = isEditable
self.isRetractable = isRetractable
self.isEdited = isEdited self.isEdited = isEdited
self.isRetracted = isRetracted
self.dateReceived = dateReceived self.dateReceived = dateReceived
self.attachmentsNames = attachmentsNames self.attachmentsNames = attachmentsNames
self.attachments = attachments self.attachments = attachments
@ -252,14 +266,14 @@ public struct ReplyMessage: Codable, Identifiable, Hashable {
} }
func toMessage() -> Message { func toMessage() -> Message {
Message(id: id, isOutgoing: isOutgoing, isEditable: isEditable, isEdited: isEdited, dateReceived: dateReceived, address: address, isFirstMessage: isFirstMessage, text: text, attachments: attachments, recording: recording) Message(id: id, isOutgoing: isOutgoing, isEditable: isEditable, isRetractable: isRetractable, isEdited: isEdited, isRetracted: isRetracted, dateReceived: dateReceived, address: address, isFirstMessage: isFirstMessage, text: text, attachments: attachments, recording: recording)
} }
} }
public extension Message { public extension Message {
func toReplyMessage() -> ReplyMessage { func toReplyMessage() -> ReplyMessage {
ReplyMessage(id: id, address: address, isFirstMessage: isFirstMessage, text: text, isOutgoing: isOutgoing, isEditable: isEditable, isEdited: isEdited, dateReceived: dateReceived, attachments: attachments, recording: recording) ReplyMessage(id: id, address: address, isFirstMessage: isFirstMessage, text: text, isOutgoing: isOutgoing, isEditable: isEditable, isRetractable: isRetractable, isEdited: isEdited, isRetracted: isRetracted, dateReceived: dateReceived, attachments: attachments, recording: recording)
} }
} }
@ -267,7 +281,9 @@ public struct DraftMessage {
public var id: String? public var id: String?
public let isOutgoing: Bool public let isOutgoing: Bool
public let isEditable: Bool public let isEditable: Bool
public let isRetractable: Bool
public let isEdited: Bool public let isEdited: Bool
public let isRetracted: Bool
public var dateReceived: time_t public var dateReceived: time_t
public let address: String public let address: String
public let isFirstMessage: Bool public let isFirstMessage: Bool
@ -282,7 +298,9 @@ public struct DraftMessage {
public init(id: String? = nil, public init(id: String? = nil,
isOutgoing: Bool, isOutgoing: Bool,
isEditable: Bool, isEditable: Bool,
isRetractable: Bool,
isEdited: Bool, isEdited: Bool,
isRetracted: Bool,
dateReceived: time_t, dateReceived: time_t,
address: String, address: String,
isFirstMessage: Bool, isFirstMessage: Bool,
@ -297,7 +315,9 @@ public struct DraftMessage {
self.id = id self.id = id
self.isOutgoing = isOutgoing self.isOutgoing = isOutgoing
self.isEditable = isEditable self.isEditable = isEditable
self.isRetractable = isRetractable
self.isEdited = isEdited self.isEdited = isEdited
self.isRetracted = isRetracted
self.dateReceived = dateReceived self.dateReceived = dateReceived
self.address = address self.address = address
self.isFirstMessage = isFirstMessage self.isFirstMessage = isFirstMessage

View file

@ -175,6 +175,10 @@ class ConversationViewModel: ObservableObject {
}, onMessageContentEdited: {(chatRoom: ChatRoom, message: ChatMessage) in }, onMessageContentEdited: {(chatRoom: ChatRoom, message: ChatMessage) in
let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLogId == message.messageId}) let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLogId == message.messageId})
if let displayedConversation = self.sharedMainViewModel.displayedConversation {
displayedConversation.getContentTextMessage(chatRoom: displayedConversation.chatRoom)
}
var attachmentNameList: String = "" var attachmentNameList: String = ""
var attachmentList: [Attachment] = [] var attachmentList: [Attachment] = []
var contentText = "" var contentText = ""
@ -290,7 +294,28 @@ class ConversationViewModel: ObservableObject {
} }
} }
}, onMessageRetracted: {(chatRoom: ChatRoom, message: ChatMessage) in }, onMessageRetracted: {(chatRoom: ChatRoom, message: ChatMessage) in
// TODO let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLogId == message.messageId})
let indexReplyMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.message.replyMessage?.id == message.messageId})
if let displayedConversation = self.sharedMainViewModel.displayedConversation {
displayedConversation.getContentTextMessage(chatRoom: displayedConversation.chatRoom)
}
DispatchQueue.main.async {
if indexMessage != nil {
self.conversationMessagesSection[0].rows[indexMessage!].message.text = ""
self.conversationMessagesSection[0].rows[indexMessage!].message.isRetracted = true
self.conversationMessagesSection[0].rows[indexMessage!].message.attachments = []
self.conversationMessagesSection[0].rows[indexMessage!].message.attachmentsNames = ""
}
if indexReplyMessage != nil {
self.conversationMessagesSection[0].rows[indexReplyMessage!].message.replyMessage?.text = ""
self.conversationMessagesSection[0].rows[indexReplyMessage!].message.replyMessage?.isRetracted = true
self.conversationMessagesSection[0].rows[indexReplyMessage!].message.replyMessage?.attachments = []
self.conversationMessagesSection[0].rows[indexReplyMessage!].message.replyMessage?.attachmentsNames = ""
}
}
}) })
self.chatRoomDelegateHolder = ChatRoomDelegateHolder(chatroom: chatRoom, delegate: chatRoomDelegate) self.chatRoomDelegateHolder = ChatRoomDelegateHolder(chatroom: chatRoom, delegate: chatRoomDelegate)
@ -666,7 +691,9 @@ class ConversationViewModel: ObservableObject {
status: nil, status: nil,
isOutgoing: false, isOutgoing: false,
isEditable: false, isEditable: false,
isRetractable: false,
isEdited: false, isEdited: false,
isRetracted: false,
dateReceived: 0, dateReceived: 0,
address: "", address: "",
isFirstMessage: false, isFirstMessage: false,
@ -827,6 +854,8 @@ class ConversationViewModel: ObservableObject {
let contentReplyText = chatMessage.replyMessage?.utf8Text ?? "" let contentReplyText = chatMessage.replyMessage?.utf8Text ?? ""
let isReplyRetracted = chatMessage.replyMessage?.isRetracted ?? false
var attachmentNameReplyList: String = "" var attachmentNameReplyList: String = ""
chatMessage.replyMessage?.contents.forEach { content in chatMessage.replyMessage?.contents.forEach { content in
@ -844,9 +873,11 @@ class ConversationViewModel: ObservableObject {
address: addressReplyCleaned?.asStringUriOnly() ?? "", address: addressReplyCleaned?.asStringUriOnly() ?? "",
isFirstMessage: false, isFirstMessage: false,
text: contentReplyText, text: contentReplyText,
isOutgoing: false, isOutgoing: chatMessage.replyMessage!.isOutgoing,
isEditable: false, isEditable: false,
isRetractable: false,
isEdited: false, isEdited: false,
isRetracted: isReplyRetracted,
dateReceived: 0, dateReceived: 0,
attachmentsNames: attachmentNameReplyList, attachmentsNames: attachmentNameReplyList,
attachments: [] attachments: []
@ -861,7 +892,9 @@ class ConversationViewModel: ObservableObject {
status: statusTmp, status: statusTmp,
isOutgoing: chatMessage.isOutgoing, isOutgoing: chatMessage.isOutgoing,
isEditable: chatMessage.isOutgoing ? chatMessage.isEditable : false, isEditable: chatMessage.isOutgoing ? chatMessage.isEditable : false,
isRetractable: chatMessage.isOutgoing ? chatMessage.isRetractable : false,
isEdited: chatMessage.isEdited, isEdited: chatMessage.isEdited,
isRetracted: chatMessage.isRetracted,
dateReceived: chatMessage.time, dateReceived: chatMessage.time,
address: addressCleaned?.asStringUriOnly() ?? "", address: addressCleaned?.asStringUriOnly() ?? "",
isFirstMessage: isFirstMessageTmp, isFirstMessage: isFirstMessageTmp,
@ -916,7 +949,9 @@ class ConversationViewModel: ObservableObject {
status: nil, status: nil,
isOutgoing: false, isOutgoing: false,
isEditable: false, isEditable: false,
isRetractable: false,
isEdited: false, isEdited: false,
isRetracted: false,
dateReceived: 0, dateReceived: 0,
address: "", address: "",
isFirstMessage: false, isFirstMessage: false,
@ -1076,6 +1111,8 @@ class ConversationViewModel: ObservableObject {
let contentReplyText = chatMessage.replyMessage?.utf8Text ?? "" let contentReplyText = chatMessage.replyMessage?.utf8Text ?? ""
let isReplyRetracted = chatMessage.replyMessage?.isRetracted ?? false
var attachmentNameReplyList: String = "" var attachmentNameReplyList: String = ""
chatMessage.replyMessage?.contents.forEach { content in chatMessage.replyMessage?.contents.forEach { content in
@ -1093,9 +1130,11 @@ class ConversationViewModel: ObservableObject {
address: addressReplyCleaned?.asStringUriOnly() ?? "", address: addressReplyCleaned?.asStringUriOnly() ?? "",
isFirstMessage: false, isFirstMessage: false,
text: contentReplyText, text: contentReplyText,
isOutgoing: false, isOutgoing: chatMessage.replyMessage!.isOutgoing,
isEditable: false, isEditable: false,
isRetractable: false,
isEdited: false, isEdited: false,
isRetracted: isReplyRetracted,
dateReceived: 0, dateReceived: 0,
attachmentsNames: attachmentNameReplyList, attachmentsNames: attachmentNameReplyList,
attachments: [] attachments: []
@ -1110,7 +1149,9 @@ class ConversationViewModel: ObservableObject {
status: statusTmp, status: statusTmp,
isOutgoing: chatMessage.isOutgoing, isOutgoing: chatMessage.isOutgoing,
isEditable: chatMessage.isOutgoing ? chatMessage.isEditable : false, isEditable: chatMessage.isOutgoing ? chatMessage.isEditable : false,
isRetractable: chatMessage.isOutgoing ? chatMessage.isRetractable : false,
isEdited: chatMessage.isEdited, isEdited: chatMessage.isEdited,
isRetracted: chatMessage.isRetracted,
dateReceived: chatMessage.time, dateReceived: chatMessage.time,
address: addressCleaned?.asStringUriOnly() ?? "", address: addressCleaned?.asStringUriOnly() ?? "",
isFirstMessage: isFirstMessageTmp, isFirstMessage: isFirstMessageTmp,
@ -1182,7 +1223,9 @@ class ConversationViewModel: ObservableObject {
status: nil, status: nil,
isOutgoing: false, isOutgoing: false,
isEditable: false, isEditable: false,
isRetractable: false,
isEdited: false, isEdited: false,
isRetracted: false,
dateReceived: 0, dateReceived: 0,
address: "", address: "",
isFirstMessage: false, isFirstMessage: false,
@ -1356,6 +1399,8 @@ class ConversationViewModel: ObservableObject {
let contentReplyText = chatMessage.replyMessage?.utf8Text ?? "" let contentReplyText = chatMessage.replyMessage?.utf8Text ?? ""
let isReplyRetracted = chatMessage.replyMessage?.isRetracted ?? false
var attachmentNameReplyList: String = "" var attachmentNameReplyList: String = ""
chatMessage.replyMessage?.contents.forEach { content in chatMessage.replyMessage?.contents.forEach { content in
@ -1373,9 +1418,11 @@ class ConversationViewModel: ObservableObject {
address: addressReplyCleaned != nil ? addressReplyCleaned!.asStringUriOnly() : "", address: addressReplyCleaned != nil ? addressReplyCleaned!.asStringUriOnly() : "",
isFirstMessage: false, isFirstMessage: false,
text: contentReplyText, text: contentReplyText,
isOutgoing: false, isOutgoing: chatMessage.replyMessage!.isOutgoing,
isEditable: false, isEditable: false,
isRetractable: false,
isEdited: false, isEdited: false,
isRetracted: isReplyRetracted,
dateReceived: 0, dateReceived: 0,
attachmentsNames: attachmentNameReplyList, attachmentsNames: attachmentNameReplyList,
attachments: [] attachments: []
@ -1391,7 +1438,9 @@ class ConversationViewModel: ObservableObject {
status: statusTmp, status: statusTmp,
isOutgoing: chatMessage.isOutgoing, isOutgoing: chatMessage.isOutgoing,
isEditable: chatMessage.isOutgoing ? chatMessage.isEditable : false, isEditable: chatMessage.isOutgoing ? chatMessage.isEditable : false,
isRetractable: chatMessage.isOutgoing ? chatMessage.isRetractable : false,
isEdited: chatMessage.isEdited, isEdited: chatMessage.isEdited,
isRetracted: chatMessage.isRetracted,
dateReceived: chatMessage.time, dateReceived: chatMessage.time,
address: addressCleaned != nil ? addressCleaned!.asStringUriOnly() : "", address: addressCleaned != nil ? addressCleaned!.asStringUriOnly() : "",
isFirstMessage: isFirstMessageTmp, isFirstMessage: isFirstMessageTmp,
@ -1592,6 +1641,8 @@ class ConversationViewModel: ObservableObject {
let contentReplyText = chatMessage.replyMessage?.utf8Text ?? "" let contentReplyText = chatMessage.replyMessage?.utf8Text ?? ""
let isReplyRetracted = chatMessage.replyMessage?.isRetracted ?? false
var attachmentNameReplyList: String = "" var attachmentNameReplyList: String = ""
chatMessage.replyMessage?.contents.forEach { content in chatMessage.replyMessage?.contents.forEach { content in
@ -1609,9 +1660,11 @@ class ConversationViewModel: ObservableObject {
address: addressReplyCleaned != nil ? addressReplyCleaned!.asStringUriOnly() : "", address: addressReplyCleaned != nil ? addressReplyCleaned!.asStringUriOnly() : "",
isFirstMessage: false, isFirstMessage: false,
text: contentReplyText, text: contentReplyText,
isOutgoing: false, isOutgoing: chatMessage.replyMessage!.isOutgoing,
isEditable: false, isEditable: false,
isRetractable: false,
isEdited: false, isEdited: false,
isRetracted: isReplyRetracted,
dateReceived: 0, dateReceived: 0,
attachmentsNames: attachmentNameReplyList, attachmentsNames: attachmentNameReplyList,
attachments: [] attachments: []
@ -1627,7 +1680,9 @@ class ConversationViewModel: ObservableObject {
status: statusTmp, status: statusTmp,
isOutgoing: chatMessage.isOutgoing, isOutgoing: chatMessage.isOutgoing,
isEditable: chatMessage.isOutgoing ? chatMessage.isEditable : false, isEditable: chatMessage.isOutgoing ? chatMessage.isEditable : false,
isRetractable: chatMessage.isOutgoing ? chatMessage.isRetractable : false,
isEdited: chatMessage.isEdited, isEdited: chatMessage.isEdited,
isRetracted: chatMessage.isRetracted,
dateReceived: chatMessage.time, dateReceived: chatMessage.time,
address: addressCleaned != nil ? addressCleaned!.asStringUriOnly() : "", address: addressCleaned != nil ? addressCleaned!.asStringUriOnly() : "",
isFirstMessage: isFirstMessageTmp, isFirstMessage: isFirstMessageTmp,
@ -1670,7 +1725,9 @@ class ConversationViewModel: ObservableObject {
status: nil, status: nil,
isOutgoing: false, isOutgoing: false,
isEditable: false, isEditable: false,
isRetractable: false,
isEdited: false, isEdited: false,
isRetracted: false,
dateReceived: 0, dateReceived: 0,
address: "", address: "",
isFirstMessage: false, isFirstMessage: false,
@ -1783,7 +1840,9 @@ class ConversationViewModel: ObservableObject {
status: nil, status: nil,
isOutgoing: false, isOutgoing: false,
isEditable: false, isEditable: false,
isRetractable: false,
isEdited: false, isEdited: false,
isRetracted: false,
dateReceived: 0, dateReceived: 0,
address: "", address: "",
isFirstMessage: false, isFirstMessage: false,
@ -1943,6 +2002,8 @@ class ConversationViewModel: ObservableObject {
let contentReplyText = chatMessage.replyMessage?.utf8Text ?? "" let contentReplyText = chatMessage.replyMessage?.utf8Text ?? ""
let isReplyRetracted = chatMessage.replyMessage?.isRetracted ?? false
var attachmentNameReplyList: String = "" var attachmentNameReplyList: String = ""
chatMessage.replyMessage?.contents.forEach { content in chatMessage.replyMessage?.contents.forEach { content in
@ -1960,9 +2021,11 @@ class ConversationViewModel: ObservableObject {
address: addressReplyCleaned?.asStringUriOnly() ?? "", address: addressReplyCleaned?.asStringUriOnly() ?? "",
isFirstMessage: false, isFirstMessage: false,
text: contentReplyText, text: contentReplyText,
isOutgoing: false, isOutgoing: chatMessage.replyMessage!.isOutgoing,
isEditable: false, isEditable: false,
isRetractable: false,
isEdited: false, isEdited: false,
isRetracted: isReplyRetracted,
dateReceived: 0, dateReceived: 0,
attachmentsNames: attachmentNameReplyList, attachmentsNames: attachmentNameReplyList,
attachments: [] attachments: []
@ -1977,7 +2040,9 @@ class ConversationViewModel: ObservableObject {
status: statusTmp, status: statusTmp,
isOutgoing: chatMessage.isOutgoing, isOutgoing: chatMessage.isOutgoing,
isEditable: chatMessage.isOutgoing ? chatMessage.isEditable : false, isEditable: chatMessage.isOutgoing ? chatMessage.isEditable : false,
isRetractable: chatMessage.isOutgoing ? chatMessage.isRetractable : false,
isEdited: chatMessage.isEdited, isEdited: chatMessage.isEdited,
isRetracted: chatMessage.isRetracted,
dateReceived: chatMessage.time, dateReceived: chatMessage.time,
address: addressCleaned?.asStringUriOnly() ?? "", address: addressCleaned?.asStringUriOnly() ?? "",
isFirstMessage: isFirstMessageTmp, isFirstMessage: isFirstMessageTmp,
@ -2845,12 +2910,34 @@ class ConversationViewModel: ObservableObject {
if let displayedConversation = self.sharedMainViewModel.displayedConversation, if let displayedConversation = self.sharedMainViewModel.displayedConversation,
let selectedMessage = self.selectedMessage, let selectedMessage = self.selectedMessage,
let chatMessage = selectedMessage.eventModel.eventLog.chatMessage { let chatMessage = selectedMessage.eventModel.eventLog.chatMessage {
let indexReplyMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.message.replyMessage?.id == chatMessage.messageId})
displayedConversation.chatRoom.deleteMessage(message: chatMessage) displayedConversation.chatRoom.deleteMessage(message: chatMessage)
displayedConversation.getContentTextMessage(chatRoom: displayedConversation.chatRoom)
DispatchQueue.main.async { DispatchQueue.main.async {
if let sectionIndex = self.conversationMessagesSection.firstIndex(where: { $0.chatRoomID == displayedConversation.id }), if let sectionIndex = self.conversationMessagesSection.firstIndex(where: { $0.chatRoomID == displayedConversation.id }),
let rowIndex = self.conversationMessagesSection[sectionIndex].rows.firstIndex(of: selectedMessage) { let rowIndex = self.conversationMessagesSection[sectionIndex].rows.firstIndex(of: selectedMessage) {
self.conversationMessagesSection[sectionIndex].rows.remove(at: rowIndex) self.conversationMessagesSection[sectionIndex].rows.remove(at: rowIndex)
if indexReplyMessage != nil {
self.conversationMessagesSection[0].rows[indexReplyMessage!].message.replyMessage = nil
} }
}
self.selectedMessage = nil
}
}
}
}
func deleteMessageForEveryone(){
coreContext.doOnCoreQueue { _ in
if let displayedConversation = self.sharedMainViewModel.displayedConversation,
let selectedMessage = self.selectedMessage,
let chatMessage = selectedMessage.eventModel.eventLog.chatMessage {
displayedConversation.chatRoom.retractMessage(message: chatMessage)
DispatchQueue.main.async {
self.selectedMessage = nil self.selectedMessage = nil
} }
} }

View file

@ -89,7 +89,11 @@ class ConversationsListViewModel: ObservableObject {
fromAddressFriend = nil fromAddressFriend = nil
} }
let lastMessageTextTmp = (fromAddressFriend ?? "") + (lastMessage.contents.first(where: { $0.isText })?.utf8Text ?? (lastMessage.contents.first(where: { $0.isFile || $0.isFileTransfer })?.name ?? "")) var lastMessageTextTmp = (fromAddressFriend ?? "") + (lastMessage.contents.first(where: { $0.isText })?.utf8Text ?? (lastMessage.contents.first(where: { $0.isFile || $0.isFileTransfer })?.name ?? ""))
if lastMessage.isRetracted {
lastMessageTextTmp += lastMessage.isOutgoing ? String(localized: "conversation_message_content_deleted_by_us_label") : String(localized: "conversation_message_content_deleted_label")
}
if let index = self.conversationsList.firstIndex(where: { $0.chatRoom === conversationModel.chatRoom }) { if let index = self.conversationsList.firstIndex(where: { $0.chatRoom === conversationModel.chatRoom }) {
DispatchQueue.main.async { DispatchQueue.main.async {
@ -148,7 +152,11 @@ class ConversationsListViewModel: ObservableObject {
fromAddressFriend = nil fromAddressFriend = nil
} }
let lastMessageTextTmp = (fromAddressFriend ?? "") + (lastMessage.contents.first(where: { $0.isText })?.utf8Text ?? (lastMessage.contents.first(where: { $0.isFile || $0.isFileTransfer })?.name ?? "")) var lastMessageTextTmp = (fromAddressFriend ?? "") + (lastMessage.contents.first(where: { $0.isText })?.utf8Text ?? (lastMessage.contents.first(where: { $0.isFile || $0.isFileTransfer })?.name ?? ""))
if lastMessage.isRetracted {
lastMessageTextTmp += lastMessage.isOutgoing ? String(localized: "conversation_message_content_deleted_by_us_label") : String(localized: "conversation_message_content_deleted_label")
}
if let index = self.conversationsList.firstIndex(where: { $0.chatRoom === conversationModel.chatRoom }) { if let index = self.conversationsList.firstIndex(where: { $0.chatRoom === conversationModel.chatRoom }) {
DispatchQueue.main.async { DispatchQueue.main.async {