| 
						
						
							
								
							
						
						
					 | 
				
			
			 | 
			 | 
			
				@ -676,12 +676,14 @@ NS_ASSUME_NONNULL_BEGIN
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        TSOutgoingMessage *outgoingMessage = (TSOutgoingMessage *)self.viewItem.interaction;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        shouldIgnoreEvents = outgoingMessage.messageState != TSOutgoingMessageStateSent;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    NSString *threadID = self.viewItem.interaction.uniqueThreadId;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    [self.class loadForTextDisplay:self.bodyTextView
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                   displayableText:self.displayableBodyText
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                        searchText:self.delegate.lastSearchedText
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                         textColor:self.bodyTextColor
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                              font:self.textMessageFont
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                shouldIgnoreEvents:shouldIgnoreEvents];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                shouldIgnoreEvents:shouldIgnoreEvents
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                          threadID:threadID];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				+ (void)loadForTextDisplay:(OWSMessageTextView *)textView
 | 
			
		
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
			
			 | 
			 | 
			
				@ -690,11 +692,11 @@ NS_ASSUME_NONNULL_BEGIN
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                 textColor:(UIColor *)textColor
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                      font:(UIFont *)font
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        shouldIgnoreEvents:(BOOL)shouldIgnoreEvents
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                  threadID:(NSString *)threadID
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    textView.hidden = NO;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    textView.textColor = textColor;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // Honor dynamic type in the message bodies.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    textView.font = font;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    textView.linkTextAttributes = @{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        NSForegroundColorAttributeName : textColor,
 | 
			
		
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
			
			 | 
			 | 
			
				@ -703,21 +705,43 @@ NS_ASSUME_NONNULL_BEGIN
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    textView.shouldIgnoreEvents = shouldIgnoreEvents;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    NSString *text = displayableText.displayText;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc]
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        initWithString:text
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            attributes:@{ NSFontAttributeName : font, NSForegroundColorAttributeName : textColor }];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    NSError *error1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    NSRegularExpression *regex1 = [[NSRegularExpression alloc] initWithPattern:@"@\\w*" options:0 error:&error1];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    OWSAssertDebug(error1 == nil);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    NSSet<NSString *> *knownUserIDs = LKAPI.userHexEncodedPublicKeyCache[threadID];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    NSMutableSet<NSValue *> *mentions = [NSMutableSet new];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    NSTextCheckingResult *match = [regex1 firstMatchInString:text options:NSMatchingWithoutAnchoringBounds range:NSMakeRange(0, text.length)];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (match != nil) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        while (YES) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            NSString *userID = [[text substringWithRange:match.range] stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:@""];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            NSUInteger matchEnd;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            if ([knownUserIDs containsObject:userID]) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                NSString *userDisplayName = [Environment.shared.contactsManager attributedContactOrProfileNameForPhoneIdentifier:userID primaryFont:font secondaryFont:font].string;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                text = [text stringByReplacingCharactersInRange:match.range withString:[NSString stringWithFormat:@"@%@", userDisplayName]];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                [mentions addObject:[NSValue valueWithRange:NSMakeRange(match.range.location, userDisplayName.length + 1)]];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                matchEnd = match.range.location + userDisplayName.length;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            } else {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                matchEnd = match.range.location + match.range.length;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            match = [regex1 firstMatchInString:text options:NSMatchingWithoutAnchoringBounds range:NSMakeRange(matchEnd, text.length - matchEnd)];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            if (match == nil) { break; }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:text attributes:@{ NSFontAttributeName : font, NSForegroundColorAttributeName : textColor }];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    for (NSValue *mention in mentions) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        NSRange range = mention.rangeValue;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        [attributedText addAttribute:NSBackgroundColorAttributeName value:UIColor.lokiDarkGray range:range];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        [attributedText addAttribute:NSForegroundColorAttributeName value:UIColor.ows_whiteColor range:range];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (searchText.length >= ConversationSearchController.kMinimumSearchTextLength) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        NSString *searchableText = [FullTextSearchFinder normalizeWithText:searchText];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        NSError *error;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        NSRegularExpression *regex =
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            [[NSRegularExpression alloc] initWithPattern:[NSRegularExpression escapedPatternForString:searchableText]
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                                                 options:NSRegularExpressionCaseInsensitive
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                                                   error:&error];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        OWSAssertDebug(error == nil);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        NSError *error2;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        NSRegularExpression *regex2 = [[NSRegularExpression alloc] initWithPattern:[NSRegularExpression escapedPatternForString:searchableText] options:NSRegularExpressionCaseInsensitive error:&error2];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        OWSAssertDebug(error2 == nil);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        for (NSTextCheckingResult *match in
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            [regex matchesInString:text options:NSMatchingWithoutAnchoringBounds range:NSMakeRange(0, text.length)]) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            [regex2 matchesInString:text options:NSMatchingWithoutAnchoringBounds range:NSMakeRange(0, text.length)]) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            OWSAssertDebug(match.range.length >= ConversationSearchController.kMinimumSearchTextLength);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            [attributedText addAttribute:NSBackgroundColorAttributeName value:UIColor.yellowColor range:match.range];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            [attributedText addAttribute:NSForegroundColorAttributeName value:UIColor.ows_blackColor range:match.range];
 | 
			
		
		
	
	
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
				
			
			 | 
			 | 
			
				
 
 |