diff --git a/Monal/Classes/ActiveChatsViewController.m b/Monal/Classes/ActiveChatsViewController.m index 202eae8949..2a2f139601 100755 --- a/Monal/Classes/ActiveChatsViewController.m +++ b/Monal/Classes/ActiveChatsViewController.m @@ -333,6 +333,7 @@ -(void) viewDidLoad [nc addObserver:self selector:@selector(handleRefreshDisplayNotification:) name:kMonalMessageFiletransferUpdateNotice object:nil]; [nc addObserver:self selector:@selector(refreshContact:) name:kMonalContactRefresh object:nil]; [nc addObserver:self selector:@selector(handleNewMessage:) name:kMonalNewMessageNotice object:nil]; + [nc addObserver:self selector:@selector(handleNewMessage:) name:kMonalUpdatedMessageNotice object:nil]; [nc addObserver:self selector:@selector(handleNewMessage:) name:kMonalDeletedMessageNotice object:nil]; [nc addObserver:self selector:@selector(messageSent:) name:kMLMessageSentToContact object:nil]; [nc addObserver:self selector:@selector(handleDeviceRotation) name:UIDeviceOrientationDidChangeNotification object:nil]; diff --git a/Monal/Classes/BlockedUsers.swift b/Monal/Classes/BlockedUsers.swift index e05da1a6a3..de632eb008 100644 --- a/Monal/Classes/BlockedUsers.swift +++ b/Monal/Classes/BlockedUsers.swift @@ -51,7 +51,7 @@ struct BlockedUsers: View { showBlockingUnsupportedPlaceholder = blockingUnsupported reloadBlocksFromDB() } - .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("kMonalAccountDiscoDone")).receive(on: RunLoop.main)) { notification in + .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name(kMonalAccountDiscoDone)).receive(on: RunLoop.main)) { notification in guard let notificationAccountID = notification.userInfo?["accountID"] as? NSNumber, notificationAccountID.intValue == xmppAccount.accountID.intValue else { return @@ -62,7 +62,7 @@ struct BlockedUsers: View { reloadBlocksFromDB() hideLoadingOverlay(overlay) } - .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("kMonalBlockListRefresh")).receive(on: RunLoop.main)) { notification in + .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name(kMonalBlockListRefresh)).receive(on: RunLoop.main)) { notification in guard let notificationAccountID = notification.userInfo?["accountID"] as? NSNumber, notificationAccountID.intValue == xmppAccount.accountID.intValue else { return diff --git a/Monal/Classes/ChannelMemberList.swift b/Monal/Classes/ChannelMemberList.swift index 3229edbf2e..1e2362b4be 100644 --- a/Monal/Classes/ChannelMemberList.swift +++ b/Monal/Classes/ChannelMemberList.swift @@ -59,7 +59,7 @@ struct ChannelMemberList: View { .onAppear { updateParticipantList() } - .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("kMonalMucParticipantsAndMembersUpdated")).receive(on: RunLoop.main)) { notification in + .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name(kMonalMucParticipantsAndMembersUpdated)).receive(on: RunLoop.main)) { notification in if let xmppAccount = notification.object as? xmpp, let contact = notification.userInfo?["contact"] as? MLContact { DDLogVerbose("Got muc participants/members update from account \(xmppAccount)...") if contact == channel { diff --git a/Monal/Classes/ChatView.swift b/Monal/Classes/ChatView.swift index 951e1c331f..667b0aa3c9 100644 --- a/Monal/Classes/ChatView.swift +++ b/Monal/Classes/ChatView.swift @@ -200,7 +200,9 @@ struct ChatView: View { guard let newMLMessage = MLXMPPManager.sharedInstance().sendMessageAndAddToHistory(message: draft.text, havingType: kMessageTypeText, toContact: self.contact.obj, isEncrypted: self.contact.isEncrypted, uploadInfo: nil) else { return } - messages.append(ChatViewMessage(newMLMessage)) + messages.append(ChatViewMessage(ObservableKVOWrapper(newMLMessage))) + } messageBuilder: { message, viewModel, positionInUserGroup, positionInMessagesSection, positionInCommentsGroup, showContextMenuClosure, messageActionClosure, showAttachmentClosure in + MessageView(message: (message as! ChatViewMessage).message, viewModel: viewModel, positionInUserGroup: positionInUserGroup, positionInMessagesSection: positionInMessagesSection) } .showNetworkConnectionProblem(false) // .enableLoadMore(pageSize: 3) { message in @@ -350,7 +352,7 @@ struct ChatView: View { if messages.isEmpty { let dbMessages = DataLayer.sharedInstance().messages(forContact:contact.contactJid, forAccount:contact.accountID) as! [MLMessage] for msg in dbMessages { - messages.append(ChatViewMessage(msg)) + messages.append(ChatViewMessage(ObservableKVOWrapper(msg))) } } ChatViewHelpers.refreshCounter(for: self.contact.obj) @@ -386,7 +388,7 @@ struct ChatView: View { MLNotificationManager.sharedInstance().currentContact = nil } } - .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("kMonalOmemoFetchingStateUpdate")).receive(on: RunLoop.main)) { notification in + .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name(kMonalOmemoFetchingStateUpdate)).receive(on: RunLoop.main)) { notification in if let xmppAccount = notification.object as? xmpp, let notificationJid = notification.userInfo?["jid"] as? String { if xmppAccount.accountID == contact.accountID && notificationJid == contact.contactJid { DDLogDebug("Got omemo fetching update: \(contact) --> \(String(describing:notification.userInfo))") @@ -398,7 +400,7 @@ struct ChatView: View { } } } - .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("kMonalNewMessageNotice")).receive(on: RunLoop.main)) { notification in + .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name(kMonalNewMessageNotice)).receive(on: RunLoop.main)) { notification in DDLogVerbose("chat view got new message notice \(String(describing:notification.userInfo))") guard let message = notification.userInfo?["message"] as? MLMessage else { @@ -408,23 +410,24 @@ struct ChatView: View { if message.isEqual(to: self.contact.obj) { // Do not insert based on delay timestamp because that // would make it possible to fake history entries. - messages.append(ChatViewMessage(message)) + messages.append(ChatViewMessage(ObservableKVOWrapper(message))) } ChatViewHelpers.refreshCounter(for: self.contact.obj) } - .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("kMonalRefresh")).receive(on: RunLoop.main)) { notification in + .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name(kMonalRefresh)).receive(on: RunLoop.main)) { notification in ChatViewHelpers.refreshCounter(for: self.contact.obj) } } } class ChatViewMessage: ExyteChat.Message { - @Published public var message: MLMessage - - init(_ message: MLMessage) { + let message: ObservableKVOWrapper + + init(_ message: ObservableKVOWrapper) { self.message = message + let messageText = message.retracted ? NSLocalizedString("This message got retracted", comment: "") : message.messageText let user = ExyteChat.User(id: message.senderID, name: message.contactDisplayName, avatarURL: nil, isCurrentUser: !message.inbound) - super.init(id: message.id, user: user, createdAt: message.timestamp, text: message.messageText) + super.init(id: message.id, user: user, createdAt: message.timestamp, text: messageText) } } @@ -481,3 +484,32 @@ public extension ExyteChat.MessageView { // } } }*/ +struct MessageView: View { + @StateObject var message: ObservableKVOWrapper + @ObservedObject var viewModel: ExyteChat.ChatViewModel + let positionInUserGroup: PositionInUserGroup + let positionInMessagesSection: PositionInMessagesSection + init(message: ObservableKVOWrapper, viewModel: ChatViewModel, positionInUserGroup: PositionInUserGroup, positionInMessagesSection: PositionInMessagesSection) { + _message = StateObject(wrappedValue: message) + self.viewModel = viewModel + self.positionInUserGroup = positionInUserGroup + self.positionInMessagesSection = positionInMessagesSection + } + var body: some View { + ExyteChat.MessageView( + viewModel: viewModel, + message: ChatViewMessage(message), + positionInUserGroup: positionInUserGroup, + positionInMessagesSection: positionInMessagesSection, + chatType: .conversation, + avatarSize: 32, + tapAvatarClosure: nil, + messageStyler: AttributedString.init, + shouldShowLinkPreview: { _ in true }, + isDisplayingMessageMenu: false, + showMessageTimeView: true, + messageLinkPreviewLimit: 8, + font: UIFontMetrics.default.scaledFont(for: UIFont.systemFont(ofSize: 15)) + ) + } +} diff --git a/Monal/Classes/ContactDetails.swift b/Monal/Classes/ContactDetails.swift index 795b686305..330dad1d47 100644 --- a/Monal/Classes/ContactDetails.swift +++ b/Monal/Classes/ContactDetails.swift @@ -676,7 +676,7 @@ struct ContactDetails: View { .onAppear { self.updateRoleAndAffiliation() } - .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("kMonalMucParticipantsAndMembersUpdated")).receive(on: RunLoop.main)) { notification in + .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name(kMonalMucParticipantsAndMembersUpdated)).receive(on: RunLoop.main)) { notification in if let xmppAccount = notification.object as? xmpp, let notificationContact = notification.userInfo?["contact"] as? MLContact { DDLogVerbose("Got muc participants/members update from account \(xmppAccount)...") if notificationContact == contact { diff --git a/Monal/Classes/ContactRequestsMenu.swift b/Monal/Classes/ContactRequestsMenu.swift index a362e35eb7..fdf0f4a0c7 100644 --- a/Monal/Classes/ContactRequestsMenu.swift +++ b/Monal/Classes/ContactRequestsMenu.swift @@ -112,10 +112,10 @@ struct ContactRequestsMenu: View { } } } - .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("kMonalContactRefresh")).receive(on: RunLoop.main)) { notification in + .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name(kMonalContactRefresh)).receive(on: RunLoop.main)) { notification in updateRequests() } - .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("kMonalContactRemoved")).receive(on: RunLoop.main)) { notification in + .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name(kMonalContactRemoved)).receive(on: RunLoop.main)) { notification in updateRequests() } .onAppear { diff --git a/Monal/Classes/ContactResources.swift b/Monal/Classes/ContactResources.swift index 5b51d44d20..d67f672f45 100644 --- a/Monal/Classes/ContactResources.swift +++ b/Monal/Classes/ContactResources.swift @@ -88,7 +88,7 @@ struct ContactResources: View { } } } - .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("kMonalXmppUserSoftWareVersionRefresh")).receive(on: RunLoop.main)) { notification in + .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name(kMonalXmppUserSoftWareVersionRefresh)).receive(on: RunLoop.main)) { notification in if let xmppAccount = notification.object as? xmpp, let softwareInfo = notification.userInfo?["versionInfo"] as? MLContactSoftwareVersionInfo { DDLogVerbose("Got software version info from account \(xmppAccount)...") if softwareInfo.fromJid == contact.obj.contactJid && xmppAccount.accountID == contact.obj.accountID { @@ -99,7 +99,7 @@ struct ContactResources: View { } } } - .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("kMonalNewPresenceNotice")).receive(on: RunLoop.main)) { notification in + .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name(kMonalNewPresenceNotice)).receive(on: RunLoop.main)) { notification in if let xmppAccount = notification.object as? xmpp, let jid = notification.userInfo?["jid"] as? String, let resource = notification.userInfo?["resource"] as? String, let available = notification.userInfo?["available"] as? NSNumber { DDLogVerbose("Got presence update from account \(xmppAccount)...") if jid == contact.obj.contactJid && xmppAccount.accountID == contact.obj.accountID { @@ -118,7 +118,7 @@ struct ContactResources: View { } } } - .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("kMonalLastInteractionUpdatedNotice")).receive(on: RunLoop.main)) { notification in + .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name(kMonalLastInteractionUpdatedNotice)).receive(on: RunLoop.main)) { notification in if let xmppAccount = notification.object as? xmpp, let jid = notification.userInfo?["jid"] as? String, let resource = notification.userInfo?["resource"] as? String, notification.userInfo?["lastInteraction"] as? NSDate != nil { DDLogVerbose("Got lastInteraction update from account \(xmppAccount)...") if jid == contact.obj.contactJid && xmppAccount.accountID == contact.obj.accountID { diff --git a/Monal/Classes/ContactsView.swift b/Monal/Classes/ContactsView.swift index 7480e516d1..cdac614f0b 100644 --- a/Monal/Classes/ContactsView.swift +++ b/Monal/Classes/ContactsView.swift @@ -200,10 +200,10 @@ class Contacts: ObservableObject { self.contacts = Set(DataLayer.sharedInstance().contactList()) self.requestCount = DataLayer.sharedInstance().allContactRequests().count subscriptions = [ - NotificationCenter.default.publisher(for: NSNotification.Name("kMonalContactRefresh")) + NotificationCenter.default.publisher(for: NSNotification.Name(kMonalContactRefresh)) .receive(on: DispatchQueue.main) .sink() { _ in self.refreshContacts() }, - NotificationCenter.default.publisher(for: NSNotification.Name("kMonalContactRemoved")) + NotificationCenter.default.publisher(for: NSNotification.Name(kMonalContactRemoved)) .receive(on: DispatchQueue.main) .sink() { _ in self.refreshContacts() }, ] diff --git a/Monal/Classes/DataLayer.h b/Monal/Classes/DataLayer.h index a368c66189..5abf208cb1 100644 --- a/Monal/Classes/DataLayer.h +++ b/Monal/Classes/DataLayer.h @@ -179,7 +179,6 @@ extern NSString* const kMessageTypeFiletransfer; returns messages with the provided local id number */ -(NSArray*) messagesForHistoryIDs:(NSArray*) historyIDs; --(MLMessage* _Nullable) messageForHistoryID:(NSNumber* _Nullable) historyID; -(NSNumber*) getSmallestHistoryId; -(NSNumber*) getBiggestHistoryId; diff --git a/Monal/Classes/DataLayer.m b/Monal/Classes/DataLayer.m index 25bd6034ba..064c1e1f87 100644 --- a/Monal/Classes/DataLayer.m +++ b/Monal/Classes/DataLayer.m @@ -283,7 +283,7 @@ -(BOOL) removeAccount:(NSNumber*) accountID // delete transfered files from local device NSArray* messageHistoryIDs = [self.db executeScalarReader:@"SELECT message_history_id FROM message_history WHERE messageType=? AND account_id=?;" andArguments:@[kMessageTypeFiletransfer, accountID]]; for(NSNumber* historyId in messageHistoryIDs) - [MLFiletransfer deleteFileForMessage:[self messageForHistoryID:historyId]]; + [MLFiletransfer deleteFileForMessage:[MLMessage createMessageFromHistoryID:historyId]]; // delete account and all entries with the same account_id (CASCADE DELETE) BOOL accountDeleted = [self.db executeNonQuery:@"DELETE FROM account WHERE account_id=?;" andArguments:@[accountID]]; @@ -1243,16 +1243,6 @@ -(NSString*) getMucTypeOfRoom:(NSString*) room andAccount:(NSNumber*) accountID }]; } --(MLMessage*) messageForHistoryID:(NSNumber*) historyID -{ - if(historyID == nil) - return nil; - NSArray* result = [self messagesForHistoryIDs:@[historyID]]; - if(![result count]) - return nil; - return result[0]; -} - -(NSNumber*) getSmallestHistoryId { return [self.db idReadTransaction:^{ @@ -1475,7 +1465,7 @@ -(void) clearMessages:(NSNumber*) accountID [self.db executeNonQuery:@"PRAGMA secure_delete=on;"]; NSArray* messageHistoryIDs = [self.db executeScalarReader:@"SELECT message_history_id FROM message_history WHERE messageType=? AND account_id=?;" andArguments:@[kMessageTypeFiletransfer, accountID]]; for(NSNumber* historyId in messageHistoryIDs) - [MLFiletransfer deleteFileForMessage:[self messageForHistoryID:historyId]]; + [MLFiletransfer deleteFileForMessage:[MLMessage createMessageFromHistoryID:historyId]]; [self.db executeNonQuery:@"DELETE FROM message_history WHERE account_id=?;" andArguments:@[accountID]]; [self.db executeNonQuery:@"DELETE FROM activechats WHERE account_id=?;" andArguments:@[accountID]]; @@ -1489,7 +1479,7 @@ -(void) clearMessagesWithBuddy:(NSString*) buddy onAccount:(NSNumber*) accountID [self.db executeNonQuery:@"PRAGMA secure_delete=on;"]; NSArray* messageHistoryIDs = [self.db executeScalarReader:@"SELECT message_history_id FROM message_history WHERE messageType=? AND account_id=? AND buddy_name=?;" andArguments:@[kMessageTypeFiletransfer, accountID, buddy]]; for(NSNumber* historyId in messageHistoryIDs) - [MLFiletransfer deleteFileForMessage:[self messageForHistoryID:historyId]]; + [MLFiletransfer deleteFileForMessage:[MLMessage createMessageFromHistoryID:historyId]]; [self.db executeNonQuery:@"DELETE FROM message_history WHERE account_id=? AND buddy_name=?;" andArguments:@[accountID, buddy]]; //better UX without deleting the active chat @@ -1510,7 +1500,7 @@ -(NSNumber*) autoDeleteMessagesAfterInterval:(NSTimeInterval) interval //if they are filetransfers and delete those files NSArray* messageHistoryIDs = [self.db executeScalarReader:@"SELECT message_history_id FROM message_history WHERE (inbound=0 OR unread=0) AND timestamp busyWaitCounter=%d, waitTime=%f", queue.name, busyWaitCounter, waitTime); } -+(id) getObjcDefinedValue:(MLDefinedIdentifier) identifier -{ - switch(identifier) - { - case MLDefinedIdentifier_kAppGroup: return kAppGroup; break; - case MLDefinedIdentifier_kMonalOpenURL: return kMonalOpenURL; break; - case MLDefinedIdentifier_kBackgroundProcessingTask: return kBackgroundProcessingTask; break; - case MLDefinedIdentifier_kBackgroundRefreshingTask: return kBackgroundRefreshingTask; break; - case MLDefinedIdentifier_kMonalKeychainName: return kMonalKeychainName; break; - case MLDefinedIdentifier_kMucTypeGroup: return kMucTypeGroup; break; - case MLDefinedIdentifier_kMucRoleModerator: return kMucRoleModerator; break; - case MLDefinedIdentifier_kMucRoleNone: return kMucRoleNone; break; - case MLDefinedIdentifier_kMucRoleParticipant: return kMucRoleParticipant; break; - case MLDefinedIdentifier_kMucRoleVisitor: return kMucRoleVisitor; break; - case MLDefinedIdentifier_kMucAffiliationOwner: return kMucAffiliationOwner; break; - case MLDefinedIdentifier_kMucAffiliationAdmin: return kMucAffiliationAdmin; break; - case MLDefinedIdentifier_kMucAffiliationMember: return kMucAffiliationMember; break; - case MLDefinedIdentifier_kMucAffiliationOutcast: return kMucAffiliationOutcast; break; - case MLDefinedIdentifier_kMucAffiliationNone: return kMucAffiliationNone; break; - case MLDefinedIdentifier_kMucActionShowProfile: return kMucActionShowProfile; break; - case MLDefinedIdentifier_kMucActionReinvite: return kMucActionReinvite; break; - case MLDefinedIdentifier_kMucTypeChannel: return kMucTypeChannel; break; - case MLDefinedIdentifier_SHORT_PING: return @(SHORT_PING); break; - case MLDefinedIdentifier_LONG_PING: return @(LONG_PING); break; - case MLDefinedIdentifier_MUC_PING: return @(MUC_PING); break; - case MLDefinedIdentifier_BGFETCH_DEFAULT_INTERVAL: return @(BGFETCH_DEFAULT_INTERVAL); break; - default: - unreachable(@"unknown MLDefinedIdentifier!"); - } -} - +(NSRunLoop*) getExtraRunloopWithIdentifier:(MLRunLoopIdentifier) identifier { static NSMutableDictionary* runloops = nil; diff --git a/Monal/Classes/MLConstants.h b/Monal/Classes/MLConstants.h index ab595530b0..0cb27be8ae 100644 --- a/Monal/Classes/MLConstants.h +++ b/Monal/Classes/MLConstants.h @@ -151,6 +151,7 @@ static inline NSString* _Nonnull LocalizationNotNeeded(NSString* _Nonnull s) #define kMonalFrozen @"kMonalFrozen" #define kMonalUnfrozen @"kMonalUnfrozen" #define kMonalNewMessageNotice @"kMonalNewMessageNotice" +#define kMonalUpdatedMessageNotice @"kMonalUpdatedMessageNotice" #define kMonalMucSubjectChanged @"kMonalMucSubjectChanged" #define kMonalDeletedMessageNotice @"kMonalDeletedMessageNotice" #define kMonalDisplayedMessagesNotice @"kMonalDisplayedMessagesNotice" diff --git a/Monal/Classes/MLContact.m b/Monal/Classes/MLContact.m index b382ba925d..ab35a8895e 100644 --- a/Monal/Classes/MLContact.m +++ b/Monal/Classes/MLContact.m @@ -274,6 +274,7 @@ -(instancetype) init [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleContactRefresh:) name:kMonalContactRemoved object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleMucSubjectChange:) name:kMonalMucSubjectChanged object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateUnreadCount) name:kMonalNewMessageNotice object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateUnreadCount) name:kMonalUpdatedMessageNotice object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateUnreadCount) name:kMonalDeletedMessageNotice object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateUnreadCount) name:kMLMessageSentToContact object:nil]; return self; diff --git a/Monal/Classes/MLFiletransfer.m b/Monal/Classes/MLFiletransfer.m index d2d5e428a0..95a86a41aa 100644 --- a/Monal/Classes/MLFiletransfer.m +++ b/Monal/Classes/MLFiletransfer.m @@ -54,7 +54,7 @@ +(BOOL) isIdle +(void) checkMimeTypeAndSizeForHistoryID:(NSNumber*) historyId { NSString* url; - MLMessage* msg = [[DataLayer sharedInstance] messageForHistoryID:historyId]; + MLMessage* msg = [MLMessage createMessageFromHistoryID:historyId]; if(!msg) { DDLogError(@"historyId %@ does not yield an MLMessage object, aborting", historyId); @@ -116,12 +116,14 @@ +(void) checkMimeTypeAndSizeForHistoryID:(NSNumber*) historyId //update db with content type and size [[DataLayer sharedInstance] setMessageHistoryId:historyId filetransferMimeType:mimeType filetransferSize:contentLength]; - //send out update notification (and update used MLMessage object directly instead of reloading it from db after updating the db) - msg.filetransferMimeType = mimeType; - msg.filetransferSize = contentLength; + //send out update notification xmpp* account = [[MLXMPPManager sharedInstance] getEnabledAccountForID:msg.accountID]; if(account != nil) //don't send out update notices for already deleted accounts - [[MLNotificationQueue currentQueue] postNotificationName:kMonalMessageFiletransferUpdateNotice object:account userInfo:@{@"message": msg}]; + [[MLNotificationQueue currentQueue] postNotificationName:kMonalMessageFiletransferUpdateNotice object:account userInfo:@{ + @"message": msg, + @"mimeType": mimeType, + @"filetransferSize": contentLength + }]; else return; //abort here without autodownloading if account was already deleted @@ -155,7 +157,7 @@ +(void) downloadFileForHistoryID:(NSNumber*) historyId +(void) downloadFileForHistoryID:(NSNumber*) historyId andForceDownload:(BOOL) forceDownload { - MLMessage* msg = [[DataLayer sharedInstance] messageForHistoryID:historyId]; + MLMessage* msg = [MLMessage createMessageFromHistoryID:historyId]; if(!msg) { DDLogError(@"historyId %@ does not yield an MLMessage object, aborting", historyId); @@ -274,21 +276,22 @@ +(void) downloadFileForHistoryID:(NSNumber*) historyId andForceDownload:(BOOL) f [HelperTools configureFileProtectionFor:cacheFile]; } - //update MLMessage object with mime type and size - NSNumber* filetransferSize = @([[_fileManager attributesOfItemAtPath:cacheFile error:nil] fileSize]); - msg.filetransferMimeType = mimeType; - msg.filetransferSize = filetransferSize; - //hardlink cache file if possible [self hardlinkFileForMessage:msg]; + NSNumber* filetransferSize = @([[_fileManager attributesOfItemAtPath:cacheFile error:nil] fileSize]); DDLogDebug(@"Updating db and sending out kMonalMessageFiletransferUpdateNotice"); //update db with content type and size [[DataLayer sharedInstance] setMessageHistoryId:historyId filetransferMimeType:mimeType filetransferSize:filetransferSize]; - //send out update notification (using our directly update MLMessage object instead of reloading it from db after updating the db) + //send out update notification xmpp* account = [[MLXMPPManager sharedInstance] getEnabledAccountForID:msg.accountID]; if(account != nil) //don't send out update notices for already deleted accounts - [[MLNotificationQueue currentQueue] postNotificationName:kMonalMessageFiletransferUpdateNotice object:account userInfo:@{@"message": msg}]; + [[MLNotificationQueue currentQueue] postNotificationName:kMonalMessageFiletransferUpdateNotice object:account userInfo:@{ + @"message": msg, + @"mimeType": mimeType, + @"filetransferSize": filetransferSize + }]; + else [_fileManager removeItemAtPath:cacheFile error:nil]; diff --git a/Monal/Classes/MLIQProcessor.m b/Monal/Classes/MLIQProcessor.m index 61d4d0b447..7b0d2b89d5 100644 --- a/Monal/Classes/MLIQProcessor.m +++ b/Monal/Classes/MLIQProcessor.m @@ -184,7 +184,7 @@ +(void) processErrorIq:(XMPPIQ*) iqNode forAccount:(xmpp*) account { //latestMessage can be nil, thus [latestMessage timestamp] will return nil and setMAMQueryAfterTimestamp:nil //will query the whole archive since dawn of time - MLMessage* latestMessage = [[DataLayer sharedInstance] messageForHistoryID:[[DataLayer sharedInstance] getBiggestHistoryId]]; + MLMessage* latestMessage = [MLMessage createMessageFromHistoryID:[[DataLayer sharedInstance] getBiggestHistoryId]]; DDLogInfo(@"Querying COMPLETE muc mam:2 archive at %@ after timestamp %@ for catchup", account.connectionProperties.identity.jid, [latestMessage timestamp]); XMPPIQ* mamQuery = [[XMPPIQ alloc] initWithType:kiqSetType]; [mamQuery setMAMQueryAfterTimestamp:[latestMessage timestamp]]; @@ -783,7 +783,6 @@ +(BOOL) processRosterWithAccount:(xmpp*) account andIqNode:(XMPPIQ*) iqNode $$ $$class_handler(handleModerationResponse, $$ID(xmpp*, account), $$ID(XMPPIQ*, iqNode), $$ID(MLMessage*, msg)) - [msg updateWithMessage:[[DataLayer sharedInstance] messageForHistoryID:msg.messageDBId]]; //make sure our msg is up to date if([iqNode check:@"/"]) { DDLogError(@"Moderating message %@ returned an error: %@", msg, [iqNode findFirst:@"error"]); diff --git a/Monal/Classes/MLMessage.h b/Monal/Classes/MLMessage.h index 49ccde79fe..95bb9c8c52 100644 --- a/Monal/Classes/MLMessage.h +++ b/Monal/Classes/MLMessage.h @@ -17,6 +17,7 @@ NS_ASSUME_NONNULL_BEGIN */ @interface MLMessage : NSObject ++(MLMessage* _Nullable) createMessageFromHistoryID:(NSNumber* _Nullable) historyID; +(BOOL) supportsSecureCoding; @property (readonly) NSString* id; //for Identifiable protocol @@ -125,7 +126,6 @@ The of the message in the DB , should be int */ +(MLMessage*) messageFromDictionary:(NSDictionary*) dic; --(void) updateWithMessage:(MLMessage*) msg; @property (nonatomic, readonly) MLContact* contact; -(BOOL) isEqualToContact:(MLContact*) contact; diff --git a/Monal/Classes/MLMessage.m b/Monal/Classes/MLMessage.m index dabd9b7ada..389a8c77f4 100644 --- a/Monal/Classes/MLMessage.m +++ b/Monal/Classes/MLMessage.m @@ -9,52 +9,97 @@ #import #import #import +#import #import +#import "XMPPMessage.h" + +static NSMutableDictionary* _singletonCache; @implementation MLMessage { MLContact* _contact; } ++(void) initialize +{ + _singletonCache = [NSMutableDictionary new]; +} + ++(MLMessage*) createMessageFromHistoryID:(NSNumber*) historyID +{ + if(historyID == nil) + return nil; + NSArray* result = [[DataLayer sharedInstance] messagesForHistoryIDs:@[historyID]]; + if(![result count]) + return nil; + return result[0]; +} + +(MLMessage*) messageFromDictionary:(NSDictionary*) dic { - MLMessage* message = [MLMessage new]; - message.accountID = [dic objectForKey:@"account_id"]; - - message.buddyName = [dic objectForKey:@"buddy_name"]; - message.inbound = [(NSNumber*)[dic objectForKey:@"inbound"] boolValue]; - message.actualFrom = [dic objectForKey:@"af"]; - message.messageText = [dic objectForKey:@"message"]; - message.isMuc = [(NSNumber*)[dic objectForKey:@"Muc"] boolValue]; - - message.messageId = [dic objectForKey:@"messageid"]; - message.stanzaId = [dic objectForKey:@"stanzaid"]; - message.messageDBId = [dic objectForKey:@"message_history_id"]; - message.timestamp = [dic objectForKey:@"thetime"]; - message.messageType = [dic objectForKey:@"messageType"]; - message.mucType = [dic objectForKey:@"muc_type"]; - message.participantJid = [dic objectForKey:@"participant_jid"]; - - message.hasBeenDisplayed = [(NSNumber*)[dic objectForKey:@"displayed"] boolValue]; - message.hasBeenReceived = [(NSNumber*)[dic objectForKey:@"received"] boolValue]; - message.hasBeenSent = [(NSNumber*)[dic objectForKey:@"sent"] boolValue]; - message.encrypted = [(NSNumber*)[dic objectForKey:@"encrypted"] boolValue]; - - message.unread = [(NSNumber*)[dic objectForKey:@"unread"] boolValue]; - message.displayMarkerWanted = [(NSNumber*)[dic objectForKey:@"displayMarkerWanted"] boolValue]; - - message.previewText = [dic objectForKey:@"previewText"]; - message.previewImage = [NSURL URLWithString:[dic objectForKey:@"previewImage"]]; - - message.errorType = [dic objectForKey:@"errorType"]; - message.errorReason = [dic objectForKey:@"errorReason"]; - - message.filetransferMimeType = [dic objectForKey:@"filetransferMimeType"]; - message.filetransferSize = [dic objectForKey:@"filetransferSize"]; - - message.retracted = [(NSNumber*)[dic objectForKey:@"retracted"] boolValue]; - - return message; + // Draft messages don't have a historyID and shouldn't be cached + if ([[dic objectForKey:@"messageType"] isEqualToString:kMessageTypeMessageDraft]) + { + MLMessage* message = [MLMessage new]; + // Fill only the properties useful for a draft message + // The timestamp is used when rendering MLContactCell, among other things + message.messageText = [dic objectForKey:@"message"]; + message.messageType = [dic objectForKey:@"messageType"]; + message.timestamp = [dic objectForKey:@"thetime"]; + return message; + } + + NSNumber* cacheKey = [dic objectForKey:@"message_history_id"]; + MLAssert(cacheKey != nil, @"A non-draft message can't have a nil historyID!"); + @synchronized(_singletonCache) { + if(_singletonCache[cacheKey] != nil) + { + MLMessage* obj = ((WeakContainer*)_singletonCache[cacheKey]).obj; + if(obj != nil) + return obj; + else + [_singletonCache removeObjectForKey:cacheKey]; + } + + MLMessage* message = [MLMessage new]; + message.accountID = [dic objectForKey:@"account_id"]; + + message.buddyName = [dic objectForKey:@"buddy_name"]; + message.inbound = [(NSNumber*)[dic objectForKey:@"inbound"] boolValue]; + message.actualFrom = [dic objectForKey:@"af"]; + message.messageText = [dic objectForKey:@"message"]; + message.isMuc = [(NSNumber*)[dic objectForKey:@"Muc"] boolValue]; + + message.messageId = [dic objectForKey:@"messageid"]; + message.stanzaId = [dic objectForKey:@"stanzaid"]; + message.messageDBId = [dic objectForKey:@"message_history_id"]; + message.timestamp = [dic objectForKey:@"thetime"]; + message.messageType = [dic objectForKey:@"messageType"]; + message.mucType = [dic objectForKey:@"muc_type"]; + message.participantJid = [dic objectForKey:@"participant_jid"]; + + message.hasBeenDisplayed = [(NSNumber*)[dic objectForKey:@"displayed"] boolValue]; + message.hasBeenReceived = [(NSNumber*)[dic objectForKey:@"received"] boolValue]; + message.hasBeenSent = [(NSNumber*)[dic objectForKey:@"sent"] boolValue]; + message.encrypted = [(NSNumber*)[dic objectForKey:@"encrypted"] boolValue]; + + message.unread = [(NSNumber*)[dic objectForKey:@"unread"] boolValue]; + message.displayMarkerWanted = [(NSNumber*)[dic objectForKey:@"displayMarkerWanted"] boolValue]; + + message.previewText = [dic objectForKey:@"previewText"]; + message.previewImage = [NSURL URLWithString:[dic objectForKey:@"previewImage"]]; + + message.errorType = [dic objectForKey:@"errorType"]; + message.errorReason = [dic objectForKey:@"errorReason"]; + + message.filetransferMimeType = [dic objectForKey:@"filetransferMimeType"]; + message.filetransferSize = [dic objectForKey:@"filetransferSize"]; + + message.retracted = [(NSNumber*)[dic objectForKey:@"retracted"] boolValue]; + + _singletonCache[cacheKey] = [[WeakContainer alloc] initWithObj:message]; + return message; + } } +(BOOL) supportsSecureCoding @@ -124,34 +169,134 @@ -(instancetype) initWithCoder:(NSCoder*) coder return self; } --(void) updateWithMessage:(MLMessage*) msg -{ - self.accountID = msg.accountID; - self.buddyName = msg.buddyName; - self.inbound = msg.inbound; - self.actualFrom = msg.actualFrom; - self.messageText = msg.messageText; - self.isMuc = msg.isMuc; - self.messageId = msg.messageId; - self.stanzaId = msg.stanzaId; - self.messageDBId = msg.messageDBId; - self.timestamp = msg.timestamp; - self.messageType = msg.messageType; - self.mucType = msg.mucType; - self.participantJid = msg.participantJid; - self.hasBeenDisplayed = msg.hasBeenDisplayed; - self.hasBeenReceived = msg.hasBeenReceived; - self.hasBeenSent = msg.hasBeenSent; - self.encrypted = msg.encrypted; - self.unread = msg.unread; - self.displayMarkerWanted = msg.displayMarkerWanted; - self.previewText = msg.previewText; - self.previewImage = msg.previewImage; - self.errorType = msg.errorType; - self.errorReason = msg.errorReason; - self.filetransferMimeType = msg.filetransferMimeType; - self.filetransferSize = msg.filetransferSize; - self.retracted = msg.retracted; +-(instancetype) init +{ + self = [super init]; + //watch for all sorts of changes and update our singleton dynamically + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleMessageUpdate:) name:kMonalUpdatedMessageNotice object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleMessageDeletion:) name:kMonalDeletedMessageNotice object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleFiletransferUpdate:) name:kMonalMessageFiletransferUpdateNotice object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleMessageSent:) name:kMonalSentMessageNotice object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleMessageReceived:) name:kMonalMessageReceivedNotice object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleMessageDisplayed:) name:kMonalMessageDisplayedNotice object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleMessageError:) name:kMonalMessageErrorNotice object:nil]; + return self; +} + +-(void) dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +-(void) handleMessageUpdate:(NSNotification*) notification +{ + NSDictionary* data = notification.userInfo; + MLMessage* message = data[@"message"]; + MLAssert(message != nil, @"Notification without message"); + if(self.messageDBId.integerValue != message.messageDBId.integerValue) + return; //ignore updates of other messages + NSNumber* LMCReplaced = data[@"LMCReplaced"]; + MLAssert(LMCReplaced != nil, @"Message update notification without LMCReplaced object"); + if(LMCReplaced.boolValue) + { + // Message correction + NSString* correctedText = data[@"correctedText"]; + MLAssert(correctedText != nil, @"Message correction notification without the corrected text"); + self.messageText = correctedText; + } + else + { + // MUC reflection + NSString* stanzaId = data[@"stanzaId"]; + MLAssert(stanzaId != nil, @"MUC reflection notification without the new stanzaId"); + self.stanzaId = stanzaId; + } +} + +// Handle message retraction and moderation +-(void) handleMessageDeletion:(NSNotification*) notification +{ + NSDictionary* data = notification.userInfo; + MLMessage* message = data[@"message"]; + MLAssert(message != nil, @"Notification without message"); + if(self.messageDBId.integerValue != message.messageDBId.integerValue) + return; //ignore deletions of other messages + + self.messageText = @""; + self.messageType = kMessageTypeText; + self.filetransferMimeType = @""; + self.filetransferSize = @0; + self.retracted = YES; +} + +-(void) handleFiletransferUpdate:(NSNotification*) notification +{ + NSDictionary* data = notification.userInfo; + MLMessage* message = data[@"message"]; + MLAssert(message != nil, @"Notification without message"); + if(self.messageDBId.integerValue != message.messageDBId.integerValue) + return; //ignore filetransfer updates of other messages + + NSString* mimeType = data[@"mimeType"]; + NSNumber* filetransferSize = data[@"filetransferSize"]; + MLAssert(mimeType != nil && filetransferSize != nil, @"Notification without mimeType and/or filetransferSize"); + self.filetransferMimeType = mimeType; + self.filetransferSize = filetransferSize; +} + +-(void) handleMessageSent:(NSNotification*) notification +{ + NSDictionary* data = notification.userInfo; + XMPPMessage* messageNode = data[@"message"]; + MLAssert(messageNode != nil, @"Notification without message node"); + if([messageNode.id isEqualToString:self.messageId]) + self.hasBeenSent = YES; +} + +-(void) handleMessageReceived:(NSNotification*) notification +{ + NSDictionary* data = notification.userInfo; + NSString* messageId = data[kMessageId]; + NSString* jid = data[@"jid"]; + MLAssert(messageId != nil && jid != nil, @"Notification without jid and/or messageId"); + if([messageId isEqualToString:self.messageId] && [jid isEqualToString:self.buddyName]) + { + self.hasBeenSent = YES; + self.hasBeenReceived = YES; + } +} + +-(void) handleMessageDisplayed:(NSNotification*) notification +{ + NSDictionary* data = notification.userInfo; + MLMessage* message = data[@"message"]; + MLAssert(message != nil, @"Notification without message"); + if(self.messageDBId.integerValue != message.messageDBId.integerValue) + return; //ignore displayed notices of other messages + + self.hasBeenSent = YES; + self.hasBeenReceived = YES; + self.hasBeenDisplayed = YES; +} + +-(void) handleMessageError:(NSNotification*) notification +{ + NSDictionary* data = notification.userInfo; + NSString* jid = data[@"jid"]; + NSString* messageId = data[kMessageId]; + NSString* errorType = data[@"errorType"]; + NSString* errorReason = data[@"errorReason"]; + MLAssert(jid != nil && messageId != nil && errorType != nil && errorReason != nil, @"Notification is missing data"); + + if([messageId isEqualToString:self.messageId] && [jid isEqualToString:self.buddyName]) + { + //we don't want to show errors if the message has been received at least once + if(!self.hasBeenReceived) + { + self.errorType = errorType; + self.errorReason = errorReason; + } + } } -(NSString*) contactDisplayName diff --git a/Monal/Classes/MLMessageProcessor.m b/Monal/Classes/MLMessageProcessor.m index c9410bb043..bb18bb0f51 100644 --- a/Monal/Classes/MLMessageProcessor.m +++ b/Monal/Classes/MLMessageProcessor.m @@ -483,7 +483,7 @@ +(MLMessage* _Nullable) processMessage:(XMPPMessage*) messageNode andOuterMessag //update ui DDLogInfo(@"Sending out kMonalDeletedMessageNotice notification for historyId %@", historyIdToRetract); [[MLNotificationQueue currentQueue] postNotificationName:kMonalDeletedMessageNotice object:account userInfo:@{ - @"message": [[[DataLayer sharedInstance] messagesForHistoryIDs:@[historyIdToRetract]] firstObject], + @"message": [MLMessage createMessageFromHistoryID:historyIdToRetract], @"contact": possiblyUnknownContact, }]; @@ -532,7 +532,7 @@ +(MLMessage* _Nullable) processMessage:(XMPPMessage*) messageNode andOuterMessag //update ui DDLogInfo(@"Sending out kMonalDeletedMessageNotice notification for historyId %@", historyIdToRetract); [[MLNotificationQueue currentQueue] postNotificationName:kMonalDeletedMessageNotice object:account userInfo:@{ - @"message": [[[DataLayer sharedInstance] messagesForHistoryIDs:@[historyIdToRetract]] firstObject], + @"message": [MLMessage createMessageFromHistoryID:historyIdToRetract], @"historyId": historyIdToRetract, @"contact": possiblyUnknownContact, }]; @@ -642,7 +642,7 @@ +(MLMessage* _Nullable) processMessage:(XMPPMessage*) messageNode andOuterMessag ]; } - message = [[DataLayer sharedInstance] messageForHistoryID:historyId]; + message = [MLMessage createMessageFromHistoryID:historyId]; if(message != nil && historyId != nil) //check historyId to make static analyzer happy { //send receive markers if requested, but DON'T do so for MLhistory messages (and don't do so for channel type mucs) @@ -698,13 +698,26 @@ +(MLMessage* _Nullable) processMessage:(XMPPMessage*) messageNode andOuterMessag [[DataLayer sharedInstance] addActiveBuddies:buddyName forAccount:account.accountID]; - DDLogInfo(@"Sending out kMonalNewMessageNotice notification for historyId %@", historyId); - [[MLNotificationQueue currentQueue] postNotificationName:kMonalNewMessageNotice object:account userInfo:@{ - @"message": message, - @"showAlert": @(showAlert), - @"contact": possiblyUnknownContact, - @"LMCReplaced": @(LMCReplaced), - }]; + if (LMCReplaced) + { + DDLogInfo(@"Sending out kMonalUpdatedMessageNotice notification for historyId %@", historyId); + [[MLNotificationQueue currentQueue] postNotificationName:kMonalUpdatedMessageNotice object:account userInfo:@{ + @"message": message, + @"showAlert": @(showAlert), + @"contact": possiblyUnknownContact, + @"LMCReplaced": @YES, + @"correctedText": body, + }]; + } + else + { + DDLogInfo(@"Sending out kMonalNewMessageNotice notification for historyId %@", historyId); + [[MLNotificationQueue currentQueue] postNotificationName:kMonalNewMessageNotice object:account userInfo:@{ + @"message": message, + @"showAlert": @(showAlert), + @"contact": possiblyUnknownContact, + }]; + } //try to automatically determine content type of filetransfers if(messageType == kMessageTypeFiletransfer && [[HelperTools defaultsDB] boolForKey:@"AutodownloadFiletransfers"]) @@ -719,13 +732,15 @@ +(MLMessage* _Nullable) processMessage:(XMPPMessage*) messageNode andOuterMessag NSNumber* historyId = [[DataLayer sharedInstance] hasMessageForStanzaId:stanzaid orMessageID:messageId withInboundDir:inbound occupantId:occupantId andJid:buddyName onAccount:account.accountID]; if(historyId != nil) { - message = [[DataLayer sharedInstance] messageForHistoryID:historyId]; + message = [MLMessage createMessageFromHistoryID:historyId]; DDLogDebug(@"Managed to update stanzaid of message (or stanzaid already known): %@", message); - DDLogInfo(@"Sending out kMonalNewMessageNotice notification for historyId %@", historyId); - [[MLNotificationQueue currentQueue] postNotificationName:kMonalNewMessageNotice object:account userInfo:@{ + DDLogInfo(@"Sending out kMonalUpdatedMessageNotice notification for historyId %@", historyId); + [[MLNotificationQueue currentQueue] postNotificationName:kMonalUpdatedMessageNotice object:account userInfo:@{ @"message": message, @"showAlert": @(NO), @"contact": possiblyUnknownContact, + @"LMCReplaced": @NO, + @"stanzaId": stanzaid, }]; } } diff --git a/Monal/Classes/MLNotificationManager.m b/Monal/Classes/MLNotificationManager.m index 50bf9a95f6..db12c050a6 100644 --- a/Monal/Classes/MLNotificationManager.m +++ b/Monal/Classes/MLNotificationManager.m @@ -50,6 +50,7 @@ -(id) init { self = [super init]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleNewMessage:) name:kMonalNewMessageNotice object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleNewMessage:) name:kMonalUpdatedMessageNotice object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleFiletransferUpdate:) name:kMonalMessageFiletransferUpdateNotice object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleDeletedMessage:) name:kMonalDeletedMessageNotice object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleDisplayedMessages:) name:kMonalDisplayedMessagesNotice object:nil]; @@ -613,7 +614,7 @@ -(void) showModernNotificationForMessage:(MLMessage*) message withSound:(BOOL) s -(void) donateInteractionForOutgoingDBId:(NSNumber*) messageDBId { - MLMessage* message = [[DataLayer sharedInstance] messageForHistoryID:messageDBId]; + MLMessage* message = [MLMessage createMessageFromHistoryID:messageDBId]; INSendMessageIntent* intent = [self makeIntentForMessage:message usingText:@"dummyText" andAudioAttachment:nil direction:INInteractionDirectionOutgoing]; INInteraction* interaction = [[INInteraction alloc] initWithIntent:intent response:nil]; interaction.direction = INInteractionDirectionOutgoing; diff --git a/Monal/Classes/MLOMEMO.m b/Monal/Classes/MLOMEMO.m index 7f4840ac16..5c77484297 100644 --- a/Monal/Classes/MLOMEMO.m +++ b/Monal/Classes/MLOMEMO.m @@ -444,7 +444,7 @@ -(void) postOMEMOMessageForUser:(NSString*) jid withMessage:(NSString*) omemoMes NSString* newMessageID = [[NSUUID UUID] UUIDString]; NSNumber* historyId = [[DataLayer sharedInstance] addMessageHistoryTo:jid forAccount:self.account.accountID withMessage:omemoMessage actuallyFrom:jid withId:newMessageID encrypted:NO messageType:kMessageTypeStatus mimeType:nil size:nil]; - MLMessage* message = [[DataLayer sharedInstance] messageForHistoryID:historyId]; + MLMessage* message = [MLMessage createMessageFromHistoryID:historyId]; MLContact* contact = [MLContact createContactFromJid:jid andAccountID:self.account.accountID]; [[MLNotificationQueue currentQueue] postNotificationName:kMonalNewMessageNotice object:self.account userInfo:@{ @"message": message, diff --git a/Monal/Classes/MLXMPPManager.m b/Monal/Classes/MLXMPPManager.m index 19b217eb7d..75e96d63ac 100644 --- a/Monal/Classes/MLXMPPManager.m +++ b/Monal/Classes/MLXMPPManager.m @@ -711,7 +711,7 @@ -(MLMessage*) sendMessageAndAddToHistory:(NSString*) message havingType:(NSStrin DDLogVerbose(@"Message added to history with id %ld", (long)[messageDBId intValue]); // MLMessage object that will be returned by the method - MLMessage* newMLMessage = [[DataLayer sharedInstance] messageForHistoryID:messageDBId]; + MLMessage* newMLMessage = [MLMessage createMessageFromHistoryID:messageDBId]; if (!newMLMessage) { DDLogError(@"Could not find message for history ID %@!", messageDBId); diff --git a/Monal/Classes/MemberList.swift b/Monal/Classes/MemberList.swift index c7f6a62ba2..e8a4d89a69 100644 --- a/Monal/Classes/MemberList.swift +++ b/Monal/Classes/MemberList.swift @@ -340,7 +340,7 @@ struct MemberList: View { .onAppear { updateMemberlist() } - .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("kMonalMucParticipantsAndMembersUpdated")).receive(on: RunLoop.main)) { notification in + .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name(kMonalMucParticipantsAndMembersUpdated)).receive(on: RunLoop.main)) { notification in if let xmppAccount = notification.object as? xmpp, let contact = notification.userInfo?["contact"] as? MLContact { DDLogVerbose("Got muc participants/members update from account \(xmppAccount)...") //only trigger update if we are either in a group type muc or have admin/owner priviledges diff --git a/Monal/Classes/OmemoKeysView.swift b/Monal/Classes/OmemoKeysView.swift index 7b457a8e9b..741bb9b150 100644 --- a/Monal/Classes/OmemoKeysView.swift +++ b/Monal/Classes/OmemoKeysView.swift @@ -453,10 +453,10 @@ class OmemoKeysForChat: ObservableObject { self.viewContact = viewContact self.contacts = OmemoKeysForChat.knownDevices(viewContact: self.viewContact) subscriptions = [ - NotificationCenter.default.publisher(for: NSNotification.Name("kMonalOmemoStateUpdated")) + NotificationCenter.default.publisher(for: NSNotification.Name(kMonalOmemoStateUpdated)) .receive(on: DispatchQueue.main) .sink() { _ in self.updateContactDevices() }, - NotificationCenter.default.publisher(for: NSNotification.Name("kMonalMucParticipantsAndMembersUpdated")) + NotificationCenter.default.publisher(for: NSNotification.Name(kMonalMucParticipantsAndMembersUpdated)) .receive(on: DispatchQueue.main) .sink() { _ in self.updateContactDevices() }, ] diff --git a/Monal/Classes/PasswordMigration.swift b/Monal/Classes/PasswordMigration.swift index 0986a66ca4..cde5856853 100644 --- a/Monal/Classes/PasswordMigration.swift +++ b/Monal/Classes/PasswordMigration.swift @@ -116,7 +116,7 @@ struct PasswordMigration: View { DataLayer.sharedInstance().updateAccoun(with:dic) } } - NotificationCenter.default.post(name:Notification.Name("kMonalRefresh"), object:nil); + NotificationCenter.default.post(name:Notification.Name(kMonalRefresh), object:nil); self.delegate.dismiss() }, label: { Text("Done") diff --git a/Monal/Classes/Quicksy_RegisterAccount.swift b/Monal/Classes/Quicksy_RegisterAccount.swift index 9e84c6c77c..97043a8674 100644 --- a/Monal/Classes/Quicksy_RegisterAccount.swift +++ b/Monal/Classes/Quicksy_RegisterAccount.swift @@ -447,7 +447,7 @@ struct Quicksy_RegisterAccount: View { }) .padding() .addLoadingOverlay(overlay) - .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("kXMPPError")).receive(on: RunLoop.main)) { notification in + .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name(kXMPPError)).receive(on: RunLoop.main)) { notification in if(self.errorObserverEnabled == false) { return } @@ -463,7 +463,7 @@ struct Quicksy_RegisterAccount: View { } } } - .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("kMLResourceBoundNotice")).receive(on: RunLoop.main)) { notification in + .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name(kMLResourceBoundNotice)).receive(on: RunLoop.main)) { notification in if let xmppAccount = notification.object as? xmpp, let newAccountID : NSNumber = self.newAccountID { if(xmppAccount.accountID.intValue == newAccountID.intValue) { DispatchQueue.main.async { @@ -474,7 +474,7 @@ struct Quicksy_RegisterAccount: View { } } } - .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("kMonalUpdateBundleFetchStatus")).receive(on: RunLoop.main)) { notification in + .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name(kMonalUpdateBundleFetchStatus)).receive(on: RunLoop.main)) { notification in if let notificationAccountID = notification.userInfo?["accountID"] as? NSNumber, let completed = notification.userInfo?["completed"] as? NSNumber, let all = notification.userInfo?["all"] as? NSNumber, let newAccountID : NSNumber = self.newAccountID { if(notificationAccountID.intValue == newAccountID.intValue) { isLoadingOmemoBundles = true @@ -486,7 +486,7 @@ struct Quicksy_RegisterAccount: View { } } } - .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("kMonalFinishedOmemoBundleFetch")).receive(on: RunLoop.main)) { notification in + .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name(kMonalFinishedOmemoBundleFetch)).receive(on: RunLoop.main)) { notification in if let notificationAccountID = notification.userInfo?["accountID"] as? NSNumber, let newAccountID : NSNumber = self.newAccountID { if(notificationAccountID.intValue == newAccountID.intValue && isLoadingOmemoBundles) { DispatchQueue.main.async { @@ -496,7 +496,7 @@ struct Quicksy_RegisterAccount: View { } } } - .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("kMonalFinishedCatchup")).receive(on: RunLoop.main)) { notification in + .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name(kMonalFinishedCatchup)).receive(on: RunLoop.main)) { notification in if let xmppAccount = notification.object as? xmpp, let newAccountID : NSNumber = self.newAccountID { if(xmppAccount.accountID.intValue == newAccountID.intValue && !isLoadingOmemoBundles) { DispatchQueue.main.async { diff --git a/Monal/Classes/RegisterAccount.swift b/Monal/Classes/RegisterAccount.swift index d90e161a75..b963e0c09b 100644 --- a/Monal/Classes/RegisterAccount.swift +++ b/Monal/Classes/RegisterAccount.swift @@ -452,7 +452,7 @@ struct RegisterAccount: View { } .addLoadingOverlay(overlay) .navigationBarTitle(Text("Register"), displayMode:.large) - .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("kXMPPError")).receive(on: RunLoop.main)) { notification in + .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name(kXMPPError)).receive(on: RunLoop.main)) { notification in DDLogDebug("Got xmpp error") if(self.errorObserverEnabled == false) { return @@ -473,7 +473,7 @@ struct RegisterAccount: View { } } } - .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("kMLResourceBoundNotice")).receive(on: RunLoop.main)) { notification in + .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name(kMLResourceBoundNotice)).receive(on: RunLoop.main)) { notification in if(self.registerComplete == true) { return } diff --git a/Monal/Classes/SwiftHelpers.swift b/Monal/Classes/SwiftHelpers.swift index 739902f63f..929160de26 100644 --- a/Monal/Classes/SwiftHelpers.swift +++ b/Monal/Classes/SwiftHelpers.swift @@ -18,33 +18,6 @@ import Combine import SwiftUI import SVGView -//import some defines in MLConstants.h into swift -let kAppGroup = HelperTools.getObjcDefinedValue(.kAppGroup) -let kMonalOpenURL = HelperTools.getObjcDefinedValue(.kMonalOpenURL) -let kBackgroundProcessingTask = HelperTools.getObjcDefinedValue(.kBackgroundProcessingTask) -let kBackgroundRefreshingTask = HelperTools.getObjcDefinedValue(.kBackgroundRefreshingTask) -let kMonalKeychainName = HelperTools.getObjcDefinedValue(.kMonalKeychainName) -let kMucTypeGroup = HelperTools.getObjcDefinedValue(.kMucTypeGroup) -let kMucTypeChannel = HelperTools.getObjcDefinedValue(.kMucTypeChannel) - -let kMucRoleModerator = HelperTools.getObjcDefinedValue(.kMucRoleModerator) -let kMucRoleNone = HelperTools.getObjcDefinedValue(.kMucRoleNone) -let kMucRoleParticipant = HelperTools.getObjcDefinedValue(.kMucRoleParticipant) -let kMucRoleVisitor = HelperTools.getObjcDefinedValue(.kMucRoleVisitor) - -let kMucAffiliationOwner = HelperTools.getObjcDefinedValue(.kMucAffiliationOwner) -let kMucAffiliationAdmin = HelperTools.getObjcDefinedValue(.kMucAffiliationAdmin) -let kMucAffiliationMember = HelperTools.getObjcDefinedValue(.kMucAffiliationMember) -let kMucAffiliationOutcast = HelperTools.getObjcDefinedValue(.kMucAffiliationOutcast) -let kMucAffiliationNone = HelperTools.getObjcDefinedValue(.kMucAffiliationNone) -let kMucActionShowProfile = HelperTools.getObjcDefinedValue(.kMucActionShowProfile) -let kMucActionReinvite = HelperTools.getObjcDefinedValue(.kMucActionReinvite) - -let SHORT_PING = HelperTools.getObjcDefinedValue(.SHORT_PING) -let LONG_PING = HelperTools.getObjcDefinedValue(.LONG_PING) -let MUC_PING = HelperTools.getObjcDefinedValue(.MUC_PING) -let BGFETCH_DEFAULT_INTERVAL = HelperTools.getObjcDefinedValue(.BGFETCH_DEFAULT_INTERVAL) - public typealias monal_timer_block_t = @convention(block) (MLDelayableTimer?) -> Void; public typealias monal_void_block_t = @convention(block) () -> Void; public typealias monal_id_block_t = @convention(block) (AnyObject?) -> Void; diff --git a/Monal/Classes/WelcomeLogIn.swift b/Monal/Classes/WelcomeLogIn.swift index a77f6a5743..c98edba744 100644 --- a/Monal/Classes/WelcomeLogIn.swift +++ b/Monal/Classes/WelcomeLogIn.swift @@ -339,7 +339,7 @@ struct WelcomeLogIn: View { .navigationTitle(advancedMode ? Text("Add Account (advanced)") : Text("Welcome")) .navigationBarTitleDisplayMode(advancedMode ? .inline : .large) .onDisappear {UITableView.appearance().tableHeaderView = nil} //why that?? - .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("kXMPPError")).receive(on: RunLoop.main)) { notification in + .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name(kXMPPError)).receive(on: RunLoop.main)) { notification in if(self.errorObserverEnabled == false) { return } @@ -355,7 +355,7 @@ struct WelcomeLogIn: View { } } } - .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("kMLResourceBoundNotice")).receive(on: RunLoop.main)) { notification in + .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name(kMLResourceBoundNotice)).receive(on: RunLoop.main)) { notification in if let xmppAccount = notification.object as? xmpp, let newAccountID : NSNumber = self.newAccountID { if(xmppAccount.accountID.intValue == newAccountID.intValue) { DispatchQueue.main.async { @@ -366,7 +366,7 @@ struct WelcomeLogIn: View { } } } - .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("kMonalUpdateBundleFetchStatus")).receive(on: RunLoop.main)) { notification in + .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name(kMonalUpdateBundleFetchStatus)).receive(on: RunLoop.main)) { notification in if let notificationAccountID = notification.userInfo?["accountID"] as? NSNumber, let completed = notification.userInfo?["completed"] as? NSNumber, let all = notification.userInfo?["all"] as? NSNumber, let newAccountID : NSNumber = self.newAccountID { if(notificationAccountID.intValue == newAccountID.intValue) { isLoadingOmemoBundles = true @@ -378,7 +378,7 @@ struct WelcomeLogIn: View { } } } - .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("kMonalFinishedOmemoBundleFetch")).receive(on: RunLoop.main)) { notification in + .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name(kMonalFinishedOmemoBundleFetch)).receive(on: RunLoop.main)) { notification in if let notificationAccountID = notification.userInfo?["accountID"] as? NSNumber, let newAccountID : NSNumber = self.newAccountID { if(notificationAccountID.intValue == newAccountID.intValue && isLoadingOmemoBundles) { DispatchQueue.main.async { @@ -388,7 +388,7 @@ struct WelcomeLogIn: View { } } } - .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("kMonalFinishedCatchup")).receive(on: RunLoop.main)) { notification in + .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name(kMonalFinishedCatchup)).receive(on: RunLoop.main)) { notification in if let xmppAccount = notification.object as? xmpp, let newAccountID : NSNumber = self.newAccountID { if(xmppAccount.accountID.intValue == newAccountID.intValue && !isLoadingOmemoBundles) { DispatchQueue.main.async { diff --git a/Monal/Classes/chatViewController.m b/Monal/Classes/chatViewController.m index e10cbf8c30..6e629f33f5 100644 --- a/Monal/Classes/chatViewController.m +++ b/Monal/Classes/chatViewController.m @@ -777,6 +777,7 @@ -(void) viewWillAppear:(BOOL)animated NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; [nc addObserver:self selector:@selector(handleNewMessage:) name:kMonalNewMessageNotice object:nil]; + [nc addObserver:self selector:@selector(handleNewMessage:) name:kMonalUpdatedMessageNotice object:nil]; [nc addObserver:self selector:@selector(handleDeletedMessage:) name:kMonalDeletedMessageNotice object:nil]; [nc addObserver:self selector:@selector(handleSentMessage:) name:kMonalSentMessageNotice object:nil]; [nc addObserver:self selector:@selector(handleMessageError:) name:kMonalMessageErrorNotice object:nil]; @@ -1628,13 +1629,12 @@ -(MLMessage* _Nullable) addMessageto:(NSString *)to withMessage:(nonnull NSStrin if(messageDBId != nil) { DDLogVerbose(@"added message"); - NSArray* msgList = [[DataLayer sharedInstance] messagesForHistoryIDs:@[messageDBId]]; - if(![msgList count]) + MLMessage* messageObj = [MLMessage createMessageFromHistoryID:messageDBId]; + if(!messageObj) { DDLogError(@"Could not find msg for history ID %@!", messageDBId); return nil; } - MLMessage* messageObj = msgList[0]; [self tempfreezeAutoloading]; @@ -1698,9 +1698,6 @@ -(void) handleNewMessage:(NSNotification *)notification MLMessage* msgInList = [self.messageList objectAtIndex:(msgIdx - 1)]; if([msgInList.messageDBId intValue] == [message.messageDBId intValue]) { - //update message in our list - [msgInList updateWithMessage:message]; - //update table entry NSIndexPath* indexPath = [NSIndexPath indexPathForRow:(msgIdx - 1) inSection:messagesSection]; dispatch_async(dispatch_get_main_queue(), ^{ @@ -1755,9 +1752,6 @@ -(void) handleDeletedMessage:(NSNotification*) notification MLMessage* msgInList = [self.messageList objectAtIndex:(msgIdx - 1)]; if([msgInList.messageDBId intValue] == [msg.messageDBId intValue]) { - //update message in our list - [msgInList updateWithMessage:msg]; - //update table entry NSIndexPath* indexPath = [NSIndexPath indexPathForRow:(msgIdx - 1) inSection:messagesSection]; dispatch_async(dispatch_get_main_queue(), ^{ @@ -1779,33 +1773,6 @@ -(void) updateMsgState:(NSString *) messageId withEvent:(size_t) event withOptDi MLMessage* msg = [self.messageList objectAtIndex:(msgIdx - 1)]; if([msg.messageId isEqualToString:messageId]) { - // Set correct flags - if(event == msgSent) { - DDLogVerbose(@"got msgSent event for messageid: %@", messageId); - msg.hasBeenSent = YES; - } else if(event == msgRecevied) { - DDLogVerbose(@"got msgRecevied event for messageid: %@", messageId); - msg.hasBeenSent = YES; - msg.hasBeenReceived = YES; - } else if(event == msgDisplayed) { - DDLogVerbose(@"got msgDisplayed event for messageid: %@", messageId); - msg.hasBeenSent = YES; - msg.hasBeenReceived = YES; - msg.hasBeenDisplayed = YES; - } else if(event == msgErrorAfterSent) { - DDLogVerbose(@"got msgErrorAfterSent event for messageid: %@", messageId); - //we don't want to show errors if the message has been received at least once - if(!msg.hasBeenReceived) - { - msg.errorType = [dic objectForKey:@"errorType"]; - msg.errorReason = [dic objectForKey:@"errorReason"]; - - //ping muc to self-heal cases where we aren't joined anymore without noticing it - if(self.contact.isMuc) - [self.xmppAccount.mucProcessor ping:self.contact.contactJid]; - } - } - indexPath = [NSIndexPath indexPathForRow:(msgIdx - 1) inSection:messagesSection]; //update table entry @@ -1862,9 +1829,6 @@ -(void) handleFiletransferMessageUpdate:(NSNotification*) notification MLMessage* msgInList = [self.messageList objectAtIndex:(msgIdx - 1)]; if([msgInList.messageDBId intValue] == [msg.messageDBId intValue]) { - //update message in our list (this will copy filetransferMimeType and filetransferSize fields) - [msgInList updateWithMessage:msg]; - //update table entry indexPath = [NSIndexPath indexPathForRow:(msgIdx - 1) inSection:messagesSection]; dispatch_async(dispatch_get_main_queue(), ^{ @@ -1981,13 +1945,12 @@ -(NSString*) formattedTimeStampWithSource:(NSDate *) sourceDate -(void) retry:(id) sender { NSInteger msgHistoryID = ((UIButton*) sender).tag; - NSArray* msgArray = [[DataLayer sharedInstance] messagesForHistoryIDs:@[[NSNumber numberWithInteger:msgHistoryID]]]; - if(![msgArray count]) + MLMessage* msg = [MLMessage createMessageFromHistoryID:@(msgHistoryID)]; + if(!msg) { DDLogError(@"Called retry for non existing message with history id %ld", (long)msgHistoryID); return; } - MLMessage* msg = msgArray[0]; DDLogDebug(@"Called retry for message with history id %ld: %@", (long)msgHistoryID, msg); UIAlertController* alert = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Retry sending message?", @"") message:[NSString stringWithFormat:NSLocalizedString(@"This message failed to send (%@): %@", @""), msg.errorType, msg.errorReason] preferredStyle:UIAlertControllerStyleActionSheet]; @@ -2512,15 +2475,10 @@ -(UISwipeActionsConfiguration*) tableView:(UITableView*) tableView trailingSwipe { [self.xmppAccount retractMessage:message]; [[DataLayer sharedInstance] retractMessageHistory:message.messageDBId]; - [message updateWithMessage:[[[DataLayer sharedInstance] messagesForHistoryIDs:@[message.messageDBId]] firstObject]]; - - //update table entry - [self->_messageTable beginUpdates]; - [self->_messageTable reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; - [self->_messageTable endUpdates]; - - //update active chats if necessary - [[MLNotificationQueue currentQueue] postNotificationName:kMonalContactRefresh object:self.xmppAccount userInfo:@{@"contact": self.contact}]; + [[MLNotificationQueue currentQueue] postNotificationName:kMonalDeletedMessageNotice object:self.xmppAccount userInfo:@{ + @"message": message, + @"contact": self.contact + }]; } else { diff --git a/Monal/Monal.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Monal/Monal.xcworkspace/xcshareddata/swiftpm/Package.resolved index b49ff1c024..23484658b9 100644 --- a/Monal/Monal.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Monal/Monal.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -6,8 +6,8 @@ "repositoryURL": "https://github.com/exyte/ActivityIndicatorView", "state": { "branch": null, - "revision": "9970fd0bb7a05dad0b6566ae1f56937716686b24", - "version": "1.1.1" + "revision": "36140867802ae4a1d2b11490bcbbefe058001d14", + "version": "1.2.1" } }, { @@ -15,8 +15,8 @@ "repositoryURL": "https://github.com/cocoalumberjack/cocoalumberjack", "state": { "branch": null, - "revision": "4b8714a7fb84d42393314ce897127b3939885ec3", - "version": "3.8.5" + "revision": "a9ed4b6f9bdedce7d77046f43adfb8ce1fd54114", + "version": "3.9.0" } }, { @@ -24,35 +24,26 @@ "repositoryURL": "https://github.com/monal-im/ExyteChat", "state": { "branch": "main", - "revision": "b52d2cb406add00fdc482930122d0a64bb833469", + "revision": "120f7d960e67d36f7f411a03cca9ad5344c26021", "version": null } }, - { - "package": "FloatingButton", - "repositoryURL": "https://github.com/exyte/FloatingButton", - "state": { - "branch": null, - "revision": "cf77c2f124df1423d90a9a1985e9b9ccfa4b9b3e", - "version": "1.3.0" - } - }, { "package": "FrameUp", "repositoryURL": "https://github.com/ryanlintott/FrameUp", "state": { "branch": null, - "revision": "3b46ddcfc02a85ed060bb0c9e7ab14a7f90f415a", - "version": "0.9.7" + "revision": "0fccfdc93a01c8555cec86bf2c64caee30c23704", + "version": "0.9.11" } }, { "package": "ExyteMediaPicker", - "repositoryURL": "https://github.com/exyte/MediaPicker.git", + "repositoryURL": "https://github.com/monal-im/MediaPicker.git", "state": { - "branch": null, - "revision": "88769b1b69c2b5e5fa5b65522c08bc7b667a6cb8", - "version": "2.2.3" + "branch": "main", + "revision": "81ec10c7f9cd32d296fdc42c376c0f252925c719", + "version": null } }, { @@ -69,8 +60,8 @@ "repositoryURL": "https://github.com/apple/swift-collections.git", "state": { "branch": null, - "revision": "671108c96644956dddcd89dd59c203dcdb36cec7", - "version": "1.1.4" + "revision": "8c0c0a8b49e080e54e5e328cc552821ff07cd341", + "version": "1.2.1" } }, { @@ -78,17 +69,8 @@ "repositoryURL": "https://github.com/apple/swift-log", "state": { "branch": null, - "revision": "96a2f8a0fa41e9e09af4585e2724c4e825410b91", - "version": "1.6.2" - } - }, - { - "package": "swiftui-introspect", - "repositoryURL": "https://github.com/siteline/swiftui-introspect", - "state": { - "branch": null, - "revision": "807f73ce09a9b9723f12385e592b4e0aaebd3336", - "version": "1.3.0" + "revision": "ce592ae52f982c847a4efc0dd881cc9eb32d29f2", + "version": "1.6.4" } }, { @@ -114,7 +96,7 @@ "repositoryURL": "https://github.com/Stasel/WebRTC", "state": { "branch": "latest", - "revision": "b85669f32ffb3f48ce3a8f18ad828c6f559a8a0c", + "revision": "820d216010b6bb5695139852ec6740edd6f790ff", "version": null } }