Skip to content

Commit

Permalink
Implement mention rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
nielsandriesse committed Oct 8, 2019
1 parent cbc1297 commit a1d40a5
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -676,12 +676,14 @@ - (void)configureBodyTextView
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
Expand All @@ -690,11 +692,11 @@ + (void)loadForTextDisplay:(OWSMessageTextView *)textView
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,
Expand All @@ -703,21 +705,43 @@ + (void)loadForTextDisplay:(OWSMessageTextView *)textView
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];
Expand Down
15 changes: 14 additions & 1 deletion SignalServiceKit/src/Loki/API/LokiAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ public final class LokiAPI : NSObject {
}
}

// MARK: Caching
// MARK: Message Caching
private static let receivedMessageHashValuesKey = "receivedMessageHashValuesKey"
private static let receivedMessageHashValuesCollection = "receivedMessageHashValuesCollection"

Expand Down Expand Up @@ -293,6 +293,19 @@ public final class LokiAPI : NSObject {
transaction.setObject(receivedMessageHashValues, forKey: receivedMessageHashValuesKey, inCollection: receivedMessageHashValuesCollection)
}
}

// MARK: User ID Caching
@objc static var userHexEncodedPublicKeyCache: [String:Set<String>] = [:] // Thread ID to set of user hex encoded public keys

@objc public static func cache(_ userHexEncodedPublicKey: String, for thread: String) {
if let cache = userHexEncodedPublicKeyCache[thread] {
var mutableCache = cache
mutableCache.insert(userHexEncodedPublicKey)
userHexEncodedPublicKeyCache[thread] = mutableCache
} else {
userHexEncodedPublicKeyCache[thread] = [ userHexEncodedPublicKey ]
}
}
}

// MARK: Error Handling
Expand Down
5 changes: 5 additions & 0 deletions SignalServiceKit/src/Messages/OWSMessageManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -1413,15 +1413,20 @@ - (TSIncomingMessage *_Nullable)handleReceivedEnvelope:(SSKProtoEnvelope *)envel
return nil;
}

// Loki: Cache the user hex encoded public key (for mentions)
[LKAPI cache:incomingMessage.authorId for:oldGroupThread.uniqueId];

[self finalizeIncomingMessage:incomingMessage
thread:oldGroupThread
envelope:envelope
transaction:transaction];

// Loki: Map the message ID to the message server ID if needed
if (dataMessage.publicChatInfo != nil && dataMessage.publicChatInfo.hasServerID) {
[self.primaryStorage setIDForMessageWithServerID:dataMessage.publicChatInfo.serverID to:incomingMessage.uniqueId in:transaction];
}

// Loki: Generate a link preview if needed
dispatch_async(dispatch_get_main_queue(), ^{
NSString *linkPreviewURL = [OWSLinkPreview previewURLForRawBodyText:incomingMessage.body];
if (linkPreviewURL != nil) {
Expand Down

0 comments on commit a1d40a5

Please sign in to comment.