Use eventLogId instead of eventLog to prevent crashes on background/foreground transitions

This commit is contained in:
Benoit Martins 2024-10-15 16:25:20 +02:00
parent 54f1c2a27d
commit d3ca95b46f
3 changed files with 173 additions and 155 deletions

View file

@ -25,17 +25,19 @@ class EventModel: ObservableObject {
@Published var icon: Image?
var eventLog: EventLog
var eventLogId: String
var eventLogType: EventLog.Kind
init(eventLog: EventLog) {
self.eventLog = eventLog
self.eventLogId = eventLog.chatMessage != nil ? eventLog.chatMessage!.messageId : String(eventLog.notifyId)
self.eventLogType = eventLog.type
self.text = ""
self.icon = nil
setupEventData()
setupEventData(eventLog: eventLog)
}
private func setupEventData() {
private func setupEventData(eventLog: EventLog) {
let address = eventLog.participantAddress ?? eventLog.peerAddress
if address != nil {
ContactsManager.shared.getFriendWithAddressInCoreQueue(address: address) { friendResult in
@ -49,7 +51,7 @@ class EventModel: ObservableObject {
let textValue: String
let iconValue: Image?
switch self.eventLog.type {
switch eventLog.type {
case .ConferenceCreated:
textValue = NSLocalizedString("conversation_event_conference_created", comment: "")
case .ConferenceTerminated:
@ -59,7 +61,7 @@ class EventModel: ObservableObject {
case .ConferenceParticipantRemoved:
textValue = String(format: NSLocalizedString("conversation_event_participant_removed", comment: ""), address != nil ? name : "<?>")
case .ConferenceSubjectChanged:
textValue = String(format: NSLocalizedString("conversation_event_subject_changed", comment: ""), self.eventLog.subject ?? "")
textValue = String(format: NSLocalizedString("conversation_event_subject_changed", comment: ""), eventLog.subject ?? "")
case .ConferenceParticipantSetAdmin:
textValue = String(format: NSLocalizedString("conversation_event_admin_set", comment: ""), address != nil ? name : "<?>")
case .ConferenceParticipantUnsetAdmin:
@ -74,13 +76,13 @@ class EventModel: ObservableObject {
textValue = NSLocalizedString("conversation_event_ephemeral_messages_disabled", comment: "")
case .ConferenceEphemeralMessageLifetimeChanged:
textValue = String(format: NSLocalizedString("conversation_event_ephemeral_messages_lifetime_changed", comment: ""),
self.formatEphemeralExpiration(duration: Int64(self.eventLog.ephemeralMessageLifetime)).lowercased())
self.formatEphemeralExpiration(duration: Int64(eventLog.ephemeralMessageLifetime)).lowercased())
default:
textValue = String(self.eventLog.type.rawValue)
textValue = String(eventLog.type.rawValue)
}
// Icon assignment
switch self.eventLog.type {
switch eventLog.type {
case .ConferenceEphemeralMessageEnabled, .ConferenceEphemeralMessageDisabled, .ConferenceEphemeralMessageLifetimeChanged:
iconValue = Image("clock-countdown")
case .ConferenceTerminated:

View file

@ -280,7 +280,8 @@ class ConversationForwardMessageViewModel: ObservableObject {
func forwardMessage() {
CoreContext.shared.doOnCoreQueue { _ in
if self.displayedConversation != nil && self.selectedMessage != nil {
if let messageToForward = self.selectedMessage!.eventModel.eventLog.chatMessage {
let chatMessageToDisplay = self.displayedConversation!.chatRoom.findEventLog(messageId: self.selectedMessage!.eventModel.eventLogId)?.chatMessage
if let messageToForward = chatMessageToDisplay {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
do {
let forwardedMessage = try self.displayedConversation!.chatRoom.createForwardMessage(message: messageToForward)

View file

@ -152,7 +152,11 @@ class ConversationViewModel: ObservableObject {
let ephemeralExpireTimeTmp = message.ephemeralExpireTime
if !self.conversationMessagesSection.isEmpty && !self.conversationMessagesSection[0].rows.isEmpty {
if let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLog.chatMessage?.messageId == message.messageId}) {
if let indexMessageEventLogId = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLogId.isEmpty && $0.eventModel.eventLog.chatMessage != nil ? $0.eventModel.eventLog.chatMessage!.messageId == message.messageId : false}) {
self.conversationMessagesSection[0].rows[indexMessageEventLogId].eventModel.eventLogId = message.messageId
}
if let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLogId == message.messageId}) {
if indexMessage < self.conversationMessagesSection[0].rows.count {
if self.conversationMessagesSection[0].rows[indexMessage].message.status != statusTmp {
DispatchQueue.main.async {
@ -188,7 +192,11 @@ class ConversationViewModel: ObservableObject {
statusTmp = .sending
}
let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLog.chatMessage?.messageId == message.messageId})
if let indexMessageEventLogId = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLogId.isEmpty && $0.eventModel.eventLog.chatMessage != nil ? $0.eventModel.eventLog.chatMessage!.messageId == message.messageId : false}) {
self.conversationMessagesSection[0].rows[indexMessageEventLogId].eventModel.eventLogId = message.messageId
}
let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLogId == message.messageId})
DispatchQueue.main.async {
if indexMessage != nil { // self.objectWillChange.send()
@ -196,7 +204,7 @@ class ConversationViewModel: ObservableObject {
}
}
}, onNewMessageReaction: { (message: ChatMessage, _: ChatMessageReaction) in
let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLog.chatMessage?.messageId == message.messageId})
let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLogId == message.messageId})
var reactionsTmp: [String] = []
message.reactions.forEach({ chatMessageReaction in
reactionsTmp.append(chatMessageReaction.body)
@ -209,7 +217,7 @@ class ConversationViewModel: ObservableObject {
}
}
}, onReactionRemoved: { (message: ChatMessage, _: Address) in
let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLog.chatMessage?.messageId == message.messageId})
let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLogId == message.messageId})
var reactionsTmp: [String] = []
message.reactions.forEach({ chatMessageReaction in
reactionsTmp.append(chatMessageReaction.body)
@ -222,7 +230,7 @@ class ConversationViewModel: ObservableObject {
}
}
}, onEphemeralMessageTimerStarted: { (message: ChatMessage) in
let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLog.chatMessage?.messageId == message.messageId})
let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLogId == message.messageId})
let ephemeralExpireTimeTmp = message.ephemeralExpireTime
DispatchQueue.main.async {
@ -982,7 +990,7 @@ class ConversationViewModel: ObservableObject {
)
)
if self.conversationMessagesSection[0].rows.first?.eventModel.eventLog.chatMessage?.messageId != eventLog.chatMessage?.messageId {
if self.conversationMessagesSection[0].rows.first?.eventModel.eventLogId != eventLog.chatMessage?.messageId {
self.addChatMessageDelegate(message: eventLog.chatMessage!)
DispatchQueue.main.async {
@ -1054,7 +1062,7 @@ class ConversationViewModel: ObservableObject {
func scrollToMessage(message: Message) {
coreContext.doOnCoreQueue { _ in
if message.replyMessage != nil {
if let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLog.chatMessage?.messageId == message.replyMessage!.id}) {
if let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLogId == message.replyMessage!.id}) {
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "onScrollToIndex"), object: nil, userInfo: ["index": indexMessage, "animated": true])
} else {
if self.conversationMessagesSection[0].rows.last != nil {
@ -1339,128 +1347,130 @@ class ConversationViewModel: ObservableObject {
}
func sendMessage(audioRecorder: AudioRecorder? = nil) {
coreContext.doOnCoreQueue { _ in
do {
var message: ChatMessage?
if self.messageToReply != nil {
let chatMessageToReply = self.messageToReply!.eventModel.eventLog.chatMessage
if chatMessageToReply != nil {
message = try self.displayedConversation!.chatRoom.createReplyMessage(message: chatMessageToReply!)
if self.displayedConversation != nil {
coreContext.doOnCoreQueue { _ in
do {
var message: ChatMessage?
if self.messageToReply != nil {
let chatMessageToReply = self.displayedConversation!.chatRoom.findEventLog(messageId: self.messageToReply!.eventModel.eventLogId)?.chatMessage
if chatMessageToReply != nil {
message = try self.displayedConversation!.chatRoom.createReplyMessage(message: chatMessageToReply!)
}
} else {
message = try self.displayedConversation!.chatRoom.createEmptyMessage()
}
self.messageToReply = nil
} else {
message = try self.displayedConversation!.chatRoom.createEmptyMessage()
}
let toSend = self.messageText.trimmingCharacters(in: .whitespacesAndNewlines)
if !toSend.isEmpty {
if message != nil {
message!.addUtf8TextContent(text: toSend)
}
}
if audioRecorder != nil {
do {
audioRecorder!.stopVoiceRecorder()
let content = try audioRecorder!.linphoneAudioRecorder.createContent()
Log.info(
"[ConversationViewModel] Voice recording content created, file name is \(content.name ?? "") and duration is \(content.fileDuration)"
)
let toSend = self.messageText.trimmingCharacters(in: .whitespacesAndNewlines)
if !toSend.isEmpty {
if message != nil {
message!.addContent(content: content)
message!.addUtf8TextContent(text: toSend)
}
}
} else {
self.mediasToSend.forEach { attachment in
if audioRecorder != nil {
do {
let content = try Factory.Instance.createContent()
switch attachment.type {
case .image:
content.type = "image"
/*
case .audio:
content.type = "audio"
*/
case .video:
content.type = "video"
/*
case .pdf:
content.type = "application"
case .plainText:
content.type = "text"
*/
default:
content.type = "file"
}
// content.subtype = attachment.type == .plainText ? "plain" : FileUtils.getExtensionFromFileName(attachment.fileName)
content.subtype = attachment.full.pathExtension
content.name = attachment.full.lastPathComponent
audioRecorder!.stopVoiceRecorder()
let content = try audioRecorder!.linphoneAudioRecorder.createContent()
Log.info(
"[ConversationViewModel] Voice recording content created, file name is \(content.name ?? "") and duration is \(content.fileDuration)"
)
if message != nil {
let path = FileManager.default.temporaryDirectory.appendingPathComponent((attachment.full.lastPathComponent.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) ?? ""))
let newPath = URL(string: FileUtil.sharedContainerUrl().appendingPathComponent("Library/Images").absoluteString
+ (attachment.full.lastPathComponent.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) ?? ""))
/*
let data = try Data(contentsOf: path)
let decodedData: () = try data.write(to: path)
*/
do {
if FileManager.default.fileExists(atPath: newPath!.path) {
try FileManager.default.removeItem(atPath: newPath!.path)
}
try FileManager.default.moveItem(atPath: path.path, toPath: newPath!.path)
let filePathTmp = newPath?.absoluteString
content.filePath = String(filePathTmp!.dropFirst(7))
message!.addFileContent(content: content)
} catch {
Log.error(error.localizedDescription)
}
message!.addContent(content: content)
}
}
} else {
self.mediasToSend.forEach { attachment in
do {
let content = try Factory.Instance.createContent()
switch attachment.type {
case .image:
content.type = "image"
/*
case .audio:
content.type = "audio"
*/
case .video:
content.type = "video"
/*
case .pdf:
content.type = "application"
case .plainText:
content.type = "text"
*/
default:
content.type = "file"
}
// content.subtype = attachment.type == .plainText ? "plain" : FileUtils.getExtensionFromFileName(attachment.fileName)
content.subtype = attachment.full.pathExtension
content.name = attachment.full.lastPathComponent
if message != nil {
let path = FileManager.default.temporaryDirectory.appendingPathComponent((attachment.full.lastPathComponent.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) ?? ""))
let newPath = URL(string: FileUtil.sharedContainerUrl().appendingPathComponent("Library/Images").absoluteString
+ (attachment.full.lastPathComponent.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) ?? ""))
/*
let data = try Data(contentsOf: path)
let decodedData: () = try data.write(to: path)
*/
do {
if FileManager.default.fileExists(atPath: newPath!.path) {
try FileManager.default.removeItem(atPath: newPath!.path)
}
try FileManager.default.moveItem(atPath: path.path, toPath: newPath!.path)
let filePathTmp = newPath?.absoluteString
content.filePath = String(filePathTmp!.dropFirst(7))
message!.addFileContent(content: content)
} catch {
Log.error(error.localizedDescription)
}
}
} catch {
}
} catch {
}
}
}
if message != nil && !message!.contents.isEmpty {
Log.info("[ConversationViewModel] Sending message")
message!.send()
}
Log.info("[ConversationViewModel] Message sent, re-setting defaults")
DispatchQueue.main.async {
withAnimation {
self.mediasToSend.removeAll()
if message != nil && !message!.contents.isEmpty {
Log.info("[ConversationViewModel] Sending message")
message!.send()
}
self.messageText = ""
Log.info("[ConversationViewModel] Message sent, re-setting defaults")
DispatchQueue.main.async {
self.messageToReply = nil
withAnimation {
self.mediasToSend.removeAll()
}
self.messageText = ""
}
/*
isReplying.postValue(false)
isFileAttachmentsListOpen.postValue(false)
isParticipantsListOpen.postValue(false)
isEmojiPickerOpen.postValue(false)
if (::voiceMessageRecorder.isInitialized) {
stopVoiceRecorder()
}
isVoiceRecording.postValue(false)
// Warning: do not delete files
val attachmentsList = arrayListOf<FileModel>()
attachments.postValue(attachmentsList)
chatMessageToReplyTo = null
*/
} catch {
}
/*
isReplying.postValue(false)
isFileAttachmentsListOpen.postValue(false)
isParticipantsListOpen.postValue(false)
isEmojiPickerOpen.postValue(false)
if (::voiceMessageRecorder.isInitialized) {
stopVoiceRecorder()
}
isVoiceRecording.postValue(false)
// Warning: do not delete files
val attachmentsList = arrayListOf<FileModel>()
attachments.postValue(attachmentsList)
chatMessageToReplyTo = null
*/
} catch {
}
}
}
@ -1597,26 +1607,28 @@ class ConversationViewModel: ObservableObject {
}
func removeReaction() {
coreContext.doOnCoreQueue { _ in
if self.selectedMessageToDisplayDetails != nil {
Log.info("[ConversationViewModel] Remove reaction to message with ID \(self.selectedMessageToDisplayDetails!.message.id)")
let messageToSendReaction = self.selectedMessageToDisplayDetails!.eventModel.eventLog.chatMessage
if messageToSendReaction != nil {
do {
let reaction = try messageToSendReaction!.createReaction(utf8Reaction: "")
reaction.send()
let indexMessageSelected = self.conversationMessagesSection[0].rows.firstIndex(of: self.selectedMessageToDisplayDetails!)
DispatchQueue.main.async {
if indexMessageSelected != nil {
self.conversationMessagesSection[0].rows[indexMessageSelected!].message.ownReaction = ""
if self.displayedConversation != nil {
coreContext.doOnCoreQueue { _ in
if self.selectedMessageToDisplayDetails != nil {
Log.info("[ConversationViewModel] Remove reaction to message with ID \(self.selectedMessageToDisplayDetails!.message.id)")
let messageToSendReaction = self.displayedConversation!.chatRoom.findEventLog(messageId: self.selectedMessageToDisplayDetails!.eventModel.eventLogId)?.chatMessage
if messageToSendReaction != nil {
do {
let reaction = try messageToSendReaction!.createReaction(utf8Reaction: "")
reaction.send()
let indexMessageSelected = self.conversationMessagesSection[0].rows.firstIndex(of: self.selectedMessageToDisplayDetails!)
DispatchQueue.main.async {
if indexMessageSelected != nil {
self.conversationMessagesSection[0].rows[indexMessageSelected!].message.ownReaction = ""
}
self.selectedMessageToDisplayDetails = nil
self.isShowSelectedMessageToDisplayDetails = false
}
self.selectedMessageToDisplayDetails = nil
self.isShowSelectedMessageToDisplayDetails = false
} catch {
Log.info("[ConversationViewModel] Error: Can't remove reaction to message with ID \(self.selectedMessageToDisplayDetails!.message.id)")
}
} catch {
Log.info("[ConversationViewModel] Error: Can't remove reaction to message with ID \(self.selectedMessageToDisplayDetails!.message.id)")
}
}
}
@ -1627,7 +1639,7 @@ class ConversationViewModel: ObservableObject {
coreContext.doOnCoreQueue { _ in
if self.selectedMessage != nil {
Log.info("[ConversationViewModel] Sending reaction \(emoji) to message with ID \(self.selectedMessage!.message.id)")
let messageToSendReaction = self.selectedMessage!.eventModel.eventLog.chatMessage
let messageToSendReaction = self.displayedConversation!.chatRoom.findEventLog(messageId: self.selectedMessage!.eventModel.eventLogId)?.chatMessage
if messageToSendReaction != nil {
do {
let reaction = try messageToSendReaction!.createReaction(utf8Reaction: messageToSendReaction?.ownReaction?.body == emoji ? "" : emoji)
@ -1651,9 +1663,10 @@ class ConversationViewModel: ObservableObject {
func resend() {
coreContext.doOnCoreQueue { _ in
if self.selectedMessage != nil && self.selectedMessage!.eventModel.eventLog.chatMessage != nil {
Log.info("[ConversationViewModel] Re-sending message with ID \(self.selectedMessage!.eventModel.eventLog.chatMessage!)")
self.selectedMessage!.eventModel.eventLog.chatMessage!.send()
let chatMessageToResend = self.displayedConversation!.chatRoom.findEventLog(messageId: self.selectedMessage!.eventModel.eventLogId)?.chatMessage
if self.selectedMessage != nil && chatMessageToResend != nil {
Log.info("[ConversationViewModel] Re-sending message with ID \(chatMessageToResend!)")
chatMessageToResend!.send()
}
}
}
@ -1661,9 +1674,10 @@ class ConversationViewModel: ObservableObject {
func prepareBottomSheetForDeliveryStatus() {
self.sheetCategories.removeAll()
coreContext.doOnCoreQueue { _ in
if self.selectedMessageToDisplayDetails != nil && self.selectedMessageToDisplayDetails!.eventModel.eventLog.chatMessage != nil {
let chatMessageToDisplay = self.displayedConversation!.chatRoom.findEventLog(messageId: self.selectedMessageToDisplayDetails!.eventModel.eventLogId)?.chatMessage
if self.selectedMessageToDisplayDetails != nil && chatMessageToDisplay != nil {
let participantsImdnDisplayed = self.selectedMessageToDisplayDetails!.eventModel.eventLog.chatMessage!.getParticipantsByImdnState(state: .Displayed)
let participantsImdnDisplayed = chatMessageToDisplay!.getParticipantsByImdnState(state: .Displayed)
var participantListDisplayed: [InnerSheetCategory] = []
participantsImdnDisplayed.forEach({ participantImdn in
if participantImdn.participant != nil && participantImdn.participant!.address != nil {
@ -1674,7 +1688,7 @@ class ConversationViewModel: ObservableObject {
}
})
let participantsImdnDeliveredToUser = self.selectedMessageToDisplayDetails!.eventModel.eventLog.chatMessage!.getParticipantsByImdnState(state: .DeliveredToUser)
let participantsImdnDeliveredToUser = chatMessageToDisplay!.getParticipantsByImdnState(state: .DeliveredToUser)
var participantListDeliveredToUser: [InnerSheetCategory] = []
participantsImdnDeliveredToUser.forEach({ participantImdn in
if participantImdn.participant != nil && participantImdn.participant!.address != nil {
@ -1685,7 +1699,7 @@ class ConversationViewModel: ObservableObject {
}
})
let participantsImdnDelivered = self.selectedMessageToDisplayDetails!.eventModel.eventLog.chatMessage!.getParticipantsByImdnState(state: .Delivered)
let participantsImdnDelivered = chatMessageToDisplay!.getParticipantsByImdnState(state: .Delivered)
var participantListDelivered: [InnerSheetCategory] = []
participantsImdnDelivered.forEach({ participantImdn in
if participantImdn.participant != nil && participantImdn.participant!.address != nil {
@ -1696,7 +1710,7 @@ class ConversationViewModel: ObservableObject {
}
})
let participantsImdnNotDelivered = self.selectedMessageToDisplayDetails!.eventModel.eventLog.chatMessage!.getParticipantsByImdnState(state: .NotDelivered)
let participantsImdnNotDelivered = chatMessageToDisplay!.getParticipantsByImdnState(state: .NotDelivered)
var participantListNotDelivered: [InnerSheetCategory] = []
participantsImdnNotDelivered.forEach({ participantImdn in
if participantImdn.participant != nil && participantImdn.participant!.address != nil {
@ -1722,7 +1736,8 @@ class ConversationViewModel: ObservableObject {
func prepareBottomSheetForReactions() {
self.sheetCategories.removeAll()
coreContext.doOnCoreQueue { core in
if self.selectedMessageToDisplayDetails != nil && self.selectedMessageToDisplayDetails!.eventModel.eventLog.chatMessage != nil {
let chatMessageToDisplay = self.displayedConversation!.chatRoom.findEventLog(messageId: self.selectedMessageToDisplayDetails!.eventModel.eventLogId)?.chatMessage
if self.selectedMessageToDisplayDetails != nil && chatMessageToDisplay != nil {
let dispatchGroup = DispatchGroup()
var sheetCategoriesTmp: [SheetCategory] = []
@ -1730,7 +1745,7 @@ class ConversationViewModel: ObservableObject {
var participantList: [[InnerSheetCategory]] = [[]]
var reactionList: [String] = []
self.selectedMessageToDisplayDetails!.eventModel.eventLog.chatMessage!.reactions.forEach { chatMessageReaction in
chatMessageToDisplay!.reactions.forEach { chatMessageReaction in
if chatMessageReaction.fromAddress != nil {
dispatchGroup.enter()
ContactAvatarModel.getAvatarModelFromAddress(address: chatMessageReaction.fromAddress!) { avatarResult in