123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656 |
- /**
- * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
- #import "NCChatMessage.h"
- #import "NCAPIController.h"
- #import "NCAppBranding.h"
- #import "NextcloudTalk-Swift.h"
- NSInteger const kChatMessageGroupTimeDifference = 30;
- NSString * const kMessageTypeComment = @"comment";
- NSString * const kMessageTypeCommentDeleted = @"comment_deleted";
- NSString * const kMessageTypeSystem = @"system";
- NSString * const kMessageTypeCommand = @"command";
- NSString * const kMessageTypeVoiceMessage = @"voice-message";
- NSString * const kSharedItemTypeAudio = @"audio";
- NSString * const kSharedItemTypeDeckcard = @"deckcard";
- NSString * const kSharedItemTypeFile = @"file";
- NSString * const kSharedItemTypeLocation = @"location";
- NSString * const kSharedItemTypeMedia = @"media";
- NSString * const kSharedItemTypeOther = @"other";
- NSString * const kSharedItemTypeVoice = @"voice";
- NSString * const kSharedItemTypePoll = @"poll";
- NSString * const kSharedItemTypeRecording = @"recording";
- @interface NCChatMessage ()
- {
- NCMessageFileParameter *_fileParameter;
- NCMessageLocationParameter *_locationParameter;
- NCDeckCardParameter *_deckCardParameter;
- NSString *_objectShareLink;
- NSMutableArray *_temporaryReactions;
- BOOL _urlDetectionDone;
- NSString *_urlDetected;
- BOOL _referenceDataDone;
- NSDictionary *_referenceData;
- }
- @end
- @implementation NCChatMessage
- + (instancetype)messageWithDictionary:(NSDictionary *)messageDict
- {
- if (!messageDict || ![messageDict isKindOfClass:[NSDictionary class]]) {
- return nil;
- }
-
- NCChatMessage *message = [[NCChatMessage alloc] init];
- message.actorId = [messageDict objectForKey:@"actorId"];
- message.actorType = [messageDict objectForKey:@"actorType"];
- message.messageId = [[messageDict objectForKey:@"id"] integerValue];
- message.message = [messageDict objectForKey:@"message"];
- message.timestamp = [[messageDict objectForKey:@"timestamp"] integerValue];
- message.token = [messageDict objectForKey:@"token"];
- message.systemMessage = [messageDict objectForKey:@"systemMessage"];
- message.isReplyable = [[messageDict objectForKey:@"isReplyable"] boolValue];
- message.referenceId = [messageDict objectForKey:@"referenceId"];
- message.messageType = [messageDict objectForKey:@"messageType"];
- message.expirationTimestamp = [[messageDict objectForKey:@"expirationTimestamp"] integerValue];
- message.isMarkdownMessage = [[messageDict objectForKey:@"markdown"] boolValue];
- message.lastEditActorId = [messageDict objectForKey:@"lastEditActorId"];
- message.lastEditActorType = [messageDict objectForKey:@"lastEditActorType"];
- message.lastEditActorDisplayName = [messageDict objectForKey:@"lastEditActorDisplayName"];
- message.lastEditTimestamp = [[messageDict objectForKey:@"lastEditTimestamp"] integerValue];
- message.isSilent = [[messageDict objectForKey:@"silent"] boolValue];
- id actorDisplayName = [messageDict objectForKey:@"actorDisplayName"];
- if (!actorDisplayName) {
- message.actorDisplayName = @"";
- } else {
- if ([actorDisplayName isKindOfClass:[NSString class]]) {
- message.actorDisplayName = actorDisplayName;
- } else {
- message.actorDisplayName = [actorDisplayName stringValue];
- }
- }
-
- id messageParameters = [messageDict objectForKey:@"messageParameters"];
- if ([messageParameters isKindOfClass:[NSDictionary class]]) {
- NSError *error;
- NSData *jsonData = [NSJSONSerialization dataWithJSONObject:messageParameters
- options:0
- error:&error];
- if (jsonData) {
- message.messageParametersJSONString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
- } else {
- NSLog(@"Error generating message parameters JSON string: %@", error);
- }
- }
-
- id reactions = [messageDict objectForKey:@"reactions"];
- if ([reactions isKindOfClass:[NSDictionary class]]) {
- NSError *error;
- NSData *jsonData = [NSJSONSerialization dataWithJSONObject:reactions
- options:0
- error:&error];
- if (jsonData) {
- message.reactionsJSONString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
- } else {
- NSLog(@"Error generating reactions JSON string: %@", error);
- }
- }
-
- id reactionsSelf = [messageDict objectForKey:@"reactionsSelf"];
- if ([reactionsSelf isKindOfClass:[NSArray class]]) {
- NSError *error;
- NSData *jsonData = [NSJSONSerialization dataWithJSONObject:reactionsSelf
- options:0
- error:&error];
- if (jsonData) {
- message.reactionsSelfJSONString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
- } else {
- NSLog(@"Error generating reactionsSelf JSON string: %@", error);
- }
- }
-
- return message;
- }
- + (instancetype)messageWithDictionary:(NSDictionary *)messageDict andAccountId:(NSString *)accountId
- {
- NCChatMessage *message = [NCChatMessage messageWithDictionary:messageDict];
- if (message) {
- message.accountId = accountId;
- message.internalId = [NSString stringWithFormat:@"%@@%@@%ld", accountId, message.token, (long)message.messageId];
- NCChatMessage *parent = [NCChatMessage messageWithDictionary:[messageDict objectForKey:@"parent"] andAccountId:accountId];
- message.parentId = parent.internalId;
- }
-
- return message;
- }
- + (void)updateChatMessage:(NCChatMessage *)managedChatMessage withChatMessage:(NCChatMessage *)chatMessage isRoomLastMessage:(BOOL)isRoomLastMessage
- {
- int previewImageHeight = 0;
- // Try to keep our locally saved previewImageHeight when updating this messages with the server message
- // This happens when updating the last message of a room for example
- if (managedChatMessage.file && chatMessage.file) {
- // Only do this, if the new message does not include a height, to prevent an infinite recursion
- if (managedChatMessage.file.previewImageHeight > 0 && chatMessage.file.previewImageHeight == 0) {
- previewImageHeight = managedChatMessage.file.previewImageHeight;
- }
- }
- managedChatMessage.actorDisplayName = chatMessage.actorDisplayName;
- managedChatMessage.actorId = chatMessage.actorId;
- managedChatMessage.actorType = chatMessage.actorType;
- managedChatMessage.message = chatMessage.message;
- managedChatMessage.messageParametersJSONString = chatMessage.messageParametersJSONString;
- managedChatMessage.timestamp = chatMessage.timestamp;
- managedChatMessage.systemMessage = chatMessage.systemMessage;
- managedChatMessage.isReplyable = chatMessage.isReplyable;
- managedChatMessage.messageType = chatMessage.messageType;
- managedChatMessage.reactionsJSONString = chatMessage.reactionsJSONString;
- managedChatMessage.expirationTimestamp = chatMessage.expirationTimestamp;
- managedChatMessage.isMarkdownMessage = chatMessage.isMarkdownMessage;
- managedChatMessage.lastEditActorId = chatMessage.lastEditActorId;
- managedChatMessage.lastEditActorType = chatMessage.lastEditActorType;
- managedChatMessage.lastEditActorDisplayName = chatMessage.lastEditActorDisplayName;
- managedChatMessage.lastEditTimestamp = chatMessage.lastEditTimestamp;
- if (!isRoomLastMessage) {
- managedChatMessage.reactionsSelfJSONString = chatMessage.reactionsSelfJSONString;
- }
-
- if (!managedChatMessage.parentId && chatMessage.parentId) {
- managedChatMessage.parentId = chatMessage.parentId;
- }
- if (previewImageHeight > 0) {
- [managedChatMessage setPreviewImageHeight:previewImageHeight];
- }
- }
- + (NSString *)primaryKey {
- return @"internalId";
- }
- - (id)copyWithZone:(NSZone *)zone
- {
- NCChatMessage *messageCopy = [[NCChatMessage alloc] init];
-
- messageCopy.internalId = [_internalId copyWithZone:zone];
- messageCopy.accountId = [_accountId copyWithZone:zone];
- messageCopy.actorDisplayName = [_actorDisplayName copyWithZone:zone];
- messageCopy.actorId = [_actorId copyWithZone:zone];
- messageCopy.actorType = [_actorType copyWithZone:zone];
- messageCopy.messageId = _messageId;
- messageCopy.message = [_message copyWithZone:zone];
- messageCopy.messageParametersJSONString = [_messageParametersJSONString copyWithZone:zone];
- messageCopy.timestamp = _timestamp;
- messageCopy.token = [_token copyWithZone:zone];
- messageCopy.systemMessage = [_systemMessage copyWithZone:zone];
- messageCopy.isReplyable = _isReplyable;
- messageCopy.parentId = [_parentId copyWithZone:zone];
- messageCopy.referenceId = [_referenceId copyWithZone:zone];
- messageCopy.messageType = [_messageType copyWithZone:zone];
- messageCopy.reactionsJSONString = [_reactionsJSONString copyWithZone:zone];
- messageCopy.reactionsSelfJSONString = [_reactionsSelfJSONString copyWithZone:zone];
- messageCopy.expirationTimestamp = _expirationTimestamp;
- messageCopy.isTemporary = _isTemporary;
- messageCopy.sendingFailed = _sendingFailed;
- messageCopy.isGroupMessage = _isGroupMessage;
- messageCopy.isDeleting = _isDeleting;
- messageCopy.isOfflineMessage = _isOfflineMessage;
- messageCopy.isSilent = _isSilent;
- messageCopy.isMarkdownMessage = _isMarkdownMessage;
- messageCopy.lastEditActorId = _lastEditActorId;
- messageCopy.lastEditActorType = _lastEditActorType;
- messageCopy.lastEditActorDisplayName = _lastEditActorDisplayName;
- messageCopy.lastEditTimestamp = _lastEditTimestamp;
- return messageCopy;
- }
- - (NCMessageParameter *)file
- {
- if (!_fileParameter) {
- for (NSDictionary *parameterDict in [[self messageParameters] allValues]) {
- NCMessageFileParameter *parameter = [[NCMessageFileParameter alloc] initWithDictionary:parameterDict];
- if (![parameter.type isEqualToString:@"file"]) {
- continue;
- }
-
- if (!_fileParameter) {
- _fileParameter = parameter;
- } else {
- // If there is more than one file in the message,
- // we don't display any preview.
- _fileParameter = nil;
- return nil;
- }
- }
- }
- return _fileParameter;
- }
- - (NCMessageLocationParameter *)geoLocation
- {
- if (!_locationParameter) {
- for (NSDictionary *parameterDict in [[self messageParameters] allValues]) {
- NCMessageLocationParameter *parameter = [[NCMessageLocationParameter alloc] initWithDictionary:parameterDict] ;
- if ([parameter.type isEqualToString:@"geo-location"]) {
- _locationParameter = parameter;
- break;
- }
- }
- }
- return _locationParameter;
- }
- - (NCDeckCardParameter *)deckCard
- {
- if (!_deckCardParameter) {
- for (NSDictionary *parameterDict in [[self messageParameters] allValues]) {
- NCDeckCardParameter *parameter = [[NCDeckCardParameter alloc] initWithDictionary:parameterDict] ;
- if ([parameter.type isEqualToString:@"deck-card"]) {
- _deckCardParameter = parameter;
- break;
- }
- }
- }
- return _deckCardParameter;
- }
- - (NSString *)objectShareLink;
- {
- if (!_objectShareLink && [self isObjectShare]) {
- _objectShareLink = [[self.messageParameters objectForKey:@"object"] objectForKey:@"link"];
- }
- return _objectShareLink;
- }
- - (NSMutableAttributedString *)parsedMessage
- {
- if (!self.message) {
- return nil;
- }
- NSString *originalMessage = self.file.contactName ? self.file.contactName : self.message;
- if (self.collapsedMessage && self.isCollapsed) {
- originalMessage = self.collapsedMessage;
- }
- NSString *parsedMessage = originalMessage;
- NSError *error = nil;
- NSRegularExpression *parameterRegex = [NSRegularExpression regularExpressionWithPattern:@"\\{([^}]+)\\}" options:NSRegularExpressionCaseInsensitive error:&error];
- NSArray *matches = [parameterRegex matchesInString:originalMessage
- options:0
- range:NSMakeRange(0, [originalMessage length])];
- // Find message parameters
- NSMutableArray *parameters = [NSMutableArray new];
- for (NSTextCheckingResult *match in matches) {
- NSString* parameter = [originalMessage substringWithRange:match.range];
- NSString *parameterKey = [[parameter stringByReplacingOccurrencesOfString:@"{" withString:@""]
- stringByReplacingOccurrencesOfString:@"}" withString:@""];
- NSDictionary *parameterDict = [[self messageParameters] objectForKey:parameterKey];
- if (self.collapsedMessage && self.isCollapsed) {
- parameterDict = [[self collapsedMessageParameters] objectForKey:parameterKey];
- }
- if (parameterDict) {
- NCMessageParameter *messageParameter = [[NCMessageParameter alloc] initWithDictionary:parameterDict] ;
- // Default replacement string is the parameter name
- NSString *replaceString = messageParameter.name;
- // Format user and call mentions
- if ([messageParameter.type isEqualToString:@"user"] || [messageParameter.type isEqualToString:@"guest"] ||
- [messageParameter.type isEqualToString:@"user-group"] || [messageParameter.type isEqualToString:@"call"]) {
- replaceString = [NSString stringWithFormat:@"@%@", [parameterDict objectForKey:@"name"]];
- }
- parsedMessage = [parsedMessage stringByReplacingOccurrencesOfString:parameter withString:replaceString];
- // Calculate parameter range
- NSRange searchRange = NSMakeRange(0,parsedMessage.length);
- if (parameters.count > 0) {
- NCMessageParameter *lastParameter = [parameters objectAtIndex:parameters.count - 1];
- NSInteger newRangeLocation = lastParameter.range.location + lastParameter.range.length;
- searchRange = NSMakeRange(newRangeLocation, parsedMessage.length - newRangeLocation);
- }
- messageParameter.range = [parsedMessage rangeOfString:replaceString options:0 range:searchRange];
- [parameters addObject:messageParameter];
- }
- }
- UIColor *defaultColor = [NCAppBranding chatForegroundColor];
- NSMutableAttributedString *attributedMessage = [[NSMutableAttributedString alloc] initWithString:parsedMessage];
- [attributedMessage addAttribute:NSForegroundColorAttributeName value:defaultColor range:NSMakeRange(0, parsedMessage.length)];
- if (self.isEmojiMessage) {
- [attributedMessage addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:36.0f] range:NSMakeRange(0, parsedMessage.length)];
- } else {
- [attributedMessage addAttribute:NSFontAttributeName value:[UIFont preferredFontForTextStyle:UIFontTextStyleBody] range:NSMakeRange(0, parsedMessage.length)];
- }
- UIColor *highlightedColor = nil;
- for (NCMessageParameter *param in parameters) {
- //Set color for mentions
- if ([param.type isEqualToString:@"user"] || [param.type isEqualToString:@"guest"] ||
- [param.type isEqualToString:@"user-group"] || [param.type isEqualToString:@"call"]) {
- if (param.shouldBeHighlighted) {
- if (!highlightedColor) {
- // Only get the elementColor if we really need it to reduce realm queries
- highlightedColor = [NCAppBranding elementColor];
- }
- [attributedMessage addAttribute:NSForegroundColorAttributeName value:highlightedColor range:param.range];
- } else {
- [attributedMessage addAttribute:NSForegroundColorAttributeName value:defaultColor range:param.range];
- }
- [attributedMessage addAttribute:NSFontAttributeName value:[UIFont preferredFontFor:UIFontTextStyleBody weight:UIFontWeightBold] range:param.range];
- }
- //Create a link if parameter contains a link
- else if (param.link) {
- // Do not create links for files. File preview images will redirect to files client or browser.
- if ([param.type isEqualToString:@"file"]) {
- [attributedMessage addAttribute:NSFontAttributeName value:[UIFont preferredFontFor:UIFontTextStyleBody weight:UIFontWeightBold] range:param.range];
- } else {
- [attributedMessage addAttribute:NSLinkAttributeName value:param.link range:param.range];
- }
- }
- }
- return attributedMessage;
- }
- - (NSMutableAttributedString *)parsedMarkdown
- {
- NSMutableAttributedString *parsedMessage = self.parsedMessage;
- if (!parsedMessage) {
- return nil;
- }
- if (!_isMarkdownMessage) {
- return parsedMessage;
- }
- return [SwiftMarkdownObjCBridge parseMarkdownWithMarkdownString:parsedMessage];
- }
- - (NSMutableAttributedString *)parsedMarkdownForChat
- {
- // In some circumstances we want/need to hide the message in the chat, but still want to show it in other parts like the conversation list
- if ([self getDeckCardUrlForReferenceProvider]) {
- return nil;
- }
- NSMutableAttributedString *parsedMessage = self.parsedMessage;
- if (!parsedMessage) {
- return nil;
- }
- if (!_isMarkdownMessage) {
- return parsedMessage;
- }
- return [SwiftMarkdownObjCBridge parseMarkdownWithMarkdownString:parsedMessage];
- }
- - (NSMutableArray *)temporaryReactions
- {
- if (!_temporaryReactions) {
- _temporaryReactions = [NSMutableArray new];
- }
- return _temporaryReactions;
- }
- - (void)mergeTemporaryReactionsWithReactions:(NSMutableArray *)reactions
- {
- for (NCChatReaction *temporaryReaction in [self temporaryReactions]) {
- if (temporaryReaction.state == NCChatReactionStateAdding) {
- [self addTemporaryReaction:temporaryReaction.reaction inReactions:reactions];
- } else if (temporaryReaction.state == NCChatReactionStateRemoving) {
- [self removeReactionTemporarily:temporaryReaction.reaction inReactions:reactions];
- }
- }
- }
- - (void)addTemporaryReaction:(NSString *)reaction inReactions:(NSMutableArray *)reactions
- {
- BOOL includedReaction = NO;
- for (NCChatReaction *currentReaction in reactions) {
- if ([currentReaction.reaction isEqualToString:reaction]) {
- currentReaction.count += 1;
- currentReaction.userReacted = YES;
- includedReaction = YES;
- }
- }
- if (!includedReaction) {
- NCChatReaction *newReaction = [[NCChatReaction alloc] init];
- newReaction.reaction = reaction;
- newReaction.count = 1;
- newReaction.userReacted = YES;
- [reactions addObject:newReaction];
- }
- }
- - (void)removeReactionTemporarily:(NSString *)reaction inReactions:(NSMutableArray *)reactions
- {
- NCChatReaction *removeReaction = nil;
- for (NCChatReaction *currentReaction in reactions) {
- if ([currentReaction.reaction isEqualToString:reaction]) {
- currentReaction.state = NCChatReactionStateRemoving;
- if (currentReaction.count > 1) {
- currentReaction.count -= 1;
- currentReaction.userReacted = NO;
- } else {
- removeReaction = currentReaction;
- }
- }
- }
- if (removeReaction) {
- [reactions removeObject:removeReaction];
- }
- }
- - (NSDictionary *)reactionsDictionary
- {
- NSDictionary *reactionsDictionary = @{};
- NSData *data = [self.reactionsJSONString dataUsingEncoding:NSUTF8StringEncoding];
- if (data) {
- NSError* error;
- NSDictionary* jsonData = [NSJSONSerialization JSONObjectWithData:data
- options:0
- error:&error];
- if (jsonData) {
- reactionsDictionary = jsonData;
- } else {
- NSLog(@"Error retrieving reactions JSON data: %@", error);
- }
- }
- return reactionsDictionary;
- }
- - (NSArray *)reactionsSelfArray
- {
- NSArray *reactionsSelfArray = @[];
- NSData *data = [self.reactionsSelfJSONString dataUsingEncoding:NSUTF8StringEncoding];
- if (data) {
- NSError* error;
- NSArray* jsonData = [NSJSONSerialization JSONObjectWithData:data
- options:0
- error:&error];
- if (jsonData) {
- reactionsSelfArray = jsonData;
- } else {
- NSLog(@"Error retrieving reactionsSelf JSON data: %@", error);
- }
- }
- return reactionsSelfArray;
- }
- - (NSMutableArray<NCChatReaction *> *)reactionsArray
- {
- NSMutableArray *reactionsArray = [NSMutableArray new];
- // Grab message reactions
- NSDictionary *reactionsDict = [self reactionsDictionary];
- for (NSString *reactionKey in reactionsDict.allKeys) {
- // We need to keep this check for users who installed v14.0 (beta 1)
- if ([reactionKey isEqualToString:@"self"]) {continue;}
- NCChatReaction *reaction = [NCChatReaction initWithReaction:reactionKey andCount:[[reactionsDict objectForKey:reactionKey] integerValue]];
- [reactionsArray addObject:reaction];
- }
- // Set flag for own reactions
- for (NSString *ownReaction in [self reactionsSelfArray]) {
- for (NCChatReaction *reaction in reactionsArray) {
- if ([reaction.reaction isEqualToString:ownReaction]) {
- reaction.userReacted = YES;
- }
- }
- }
- // Merge with temporary reactions
- [self mergeTemporaryReactionsWithReactions:reactionsArray];
- // Sort by reactions count
- NSSortDescriptor *valueDescriptor = [[NSSortDescriptor alloc] initWithKey:@"count" ascending:NO];
- NSArray *descriptors = [NSArray arrayWithObject:valueDescriptor];
- [reactionsArray sortUsingDescriptors:descriptors];
- return reactionsArray;
- }
- - (NSString *)getDeckCardUrlForReferenceProvider
- {
- // Check if the message is a shared deck card and a reference provider can be used to retrieve details
- if (self.deckCard != nil && self.deckCard.link != nil && [self.deckCard.link length] > 0) {
- if ([self isReferenceApiSupported]) {
- return _deckCardParameter.link;
- }
- }
- return nil;
- }
- - (BOOL)containsURL
- {
- if (!self.message) {
- return NO;
- }
-
- if (_urlDetectionDone) {
- return ([_urlDetected length] != 0);
- }
- if (![self isReferenceApiSupported]) {
- _urlDetectionDone = YES;
- return NO;
- }
- NSString *deckCardUrl = [self getDeckCardUrlForReferenceProvider];
- if (deckCardUrl != nil) {
- _urlDetectionDone = YES;
- _urlDetected = deckCardUrl;
- return YES;
- }
- NSDataDetector *dataDetector = [[NSDataDetector alloc] initWithTypes:NSTextCheckingTypeLink error:nil];
- NSArray *urlMatches = [dataDetector matchesInString:self.message options:0 range:NSMakeRange(0, [self.message length])];
- _urlDetectionDone = YES;
- for (NSTextCheckingResult *match in urlMatches) {
- NSURL *url = [match URL];
- NSString *scheme = [url scheme];
- // Check that the scheme is either https or http, because other schemes (like mailto) would be recognized as well
- if ([[scheme lowercaseString] isEqualToString:@"http"] || [[scheme lowercaseString] isEqualToString:@"https"]) {
- _urlDetected = [url absoluteString];
- return true;
- }
- }
- return false;
- }
- - (void)getReferenceDataWithCompletionBlock:(GetReferenceDataCompletionBlock)block
- {
- if (_referenceDataDone) {
- if (block) {
- block(self, _referenceData, _urlDetected);
- }
- } else {
- TalkAccount *account = [[NCDatabaseManager sharedInstance] talkAccountForAccountId:_accountId];
- [[NCAPIController sharedInstance] getReferenceForUrlString:_urlDetected forAccount:account withCompletionBlock:^(NSDictionary *references, NSError *error) {
- if (block) {
- block(self, references, self->_urlDetected);
- }
- self->_referenceData = references;
- self->_referenceDataDone = YES;
- }];
- }
- }
- - (void)setPreviewImageHeight:(CGFloat)height
- {
- // Since the messageParameters property is a non-mutable dictionary, we create a mutable copy
- NSMutableDictionary *messageParameterDict = [[NSMutableDictionary alloc] initWithDictionary:self.messageParameters];
- NSMutableDictionary *fileParameterDict = [[NSMutableDictionary alloc] initWithDictionary:[messageParameterDict objectForKey:@"file"]];
- if (!fileParameterDict) {
- return;
- }
- [messageParameterDict setObject:fileParameterDict forKey:@"file"];
- [fileParameterDict setObject:@(height) forKey:@"preview-image-height"];
- NSData *jsonData = [NSJSONSerialization dataWithJSONObject:messageParameterDict
- options:0
- error:nil];
- if (jsonData) {
- NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
- // Only the JSON String is stored inside of the database
- self.messageParametersJSONString = jsonString;
- // Since we previously accessed the 'file' property, it would not be created from the JSON String again
- // Manually set it for the lifetime of this message
- self.file.previewImageHeight = height;
- // Save our changes to the database
- RLMRealm *realm = [RLMRealm defaultRealm];
- void (^update)(void) = ^void(){
- NCChatMessage *managedMessage = [NCChatMessage objectsWhere:@"internalId = %@", self.internalId].firstObject;
- [NCChatMessage updateChatMessage:managedMessage withChatMessage:self isRoomLastMessage:NO];
- };
- if ([realm inWriteTransaction]) {
- update();
- } else {
- [realm transactionWithBlock:^{
- update();
- }];
- }
- }
- }
- @end
|