session-ios/Session/Utilities/MentionUtilities.swift
Morgan Pretty 3c07a2d044 Added linting for the localized strings, updated the quote & mention behaviour for the current user
Added a script and build step to error if we have localised a string in code bug don't have an entry in the localisable files
Added the logic and UI to replace the current users public key (or blinded key) with 'You' in mentions and quotes
Cleaned up some duplicate & missing localised strings
Fixed a bug where new closed groups weren't getting setup locally correctly
Updated the id truncating behaviour to always truncate from the middle
2022-07-15 18:15:28 +10:00

108 lines
4.5 KiB
Swift

// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import Foundation
import GRDB
import SessionUIKit
import SessionMessagingKit
public enum MentionUtilities {
public static func highlightMentions(
in string: String,
threadVariant: SessionThread.Variant,
currentUserPublicKey: String,
currentUserBlindedPublicKey: String?
) -> String {
return highlightMentions(
in: string,
threadVariant: threadVariant,
currentUserPublicKey: currentUserPublicKey,
currentUserBlindedPublicKey: currentUserBlindedPublicKey,
isOutgoingMessage: false,
attributes: [:]
).string // isOutgoingMessage and attributes are irrelevant
}
public static func highlightMentions(
in string: String,
threadVariant: SessionThread.Variant,
currentUserPublicKey: String?,
currentUserBlindedPublicKey: String?,
isOutgoingMessage: Bool,
attributes: [NSAttributedString.Key: Any]
) -> NSAttributedString {
guard
let regex: NSRegularExpression = try? NSRegularExpression(pattern: "@[0-9a-fA-F]{66}", options: [])
else {
return NSAttributedString(string: string)
}
var string = string
var lastMatchEnd: Int = 0
var mentions: [(range: NSRange, isCurrentUser: Bool)] = []
let currentUserPublicKeys: Set<String> = [
currentUserPublicKey,
currentUserBlindedPublicKey
]
.compactMap { $0 }
.asSet()
while let match: NSTextCheckingResult = regex.firstMatch(
in: string,
options: .withoutAnchoringBounds,
range: NSRange(location: lastMatchEnd, length: string.utf16.count - lastMatchEnd)
) {
guard let range: Range = Range(match.range, in: string) else { break }
let publicKey: String = String(string[range].dropFirst()) // Drop the @
let isCurrentUser: Bool = currentUserPublicKeys.contains(publicKey)
guard let targetString: String = {
guard !isCurrentUser else { return "MEDIA_GALLERY_SENDER_NAME_YOU".localized() }
guard let displayName: String = Profile.displayNameNoFallback(id: publicKey, threadVariant: threadVariant) else {
lastMatchEnd = (match.range.location + match.range.length)
return nil
}
return displayName
}()
else { continue }
string = string.replacingCharacters(in: range, with: "@\(targetString)")
lastMatchEnd = (match.range.location + targetString.utf16.count)
mentions.append((
// + 1 to include the @
range: NSRange(location: match.range.location, length: targetString.utf16.count + 1),
isCurrentUser: isCurrentUser
))
}
let sizeDiff: CGFloat = (Values.smallFontSize / Values.mediumFontSize)
let result: NSMutableAttributedString = NSMutableAttributedString(string: string, attributes: attributes)
mentions.forEach { mention in
result.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: Values.smallFontSize), range: mention.range)
if mention.isCurrentUser {
// Note: The designs don't match with the dynamic sizing so these values need to be calculated
// to maintain a "rounded rect" effect rather than a "pill" effect
result.addAttribute(.currentUserMentionBackgroundCornerRadius, value: (8 * sizeDiff), range: mention.range)
result.addAttribute(.currentUserMentionBackgroundPadding, value: (3 * sizeDiff), range: mention.range)
result.addAttribute(.currentUserMentionBackgroundColor, value: Colors.accent, range: mention.range)
result.addAttribute(.foregroundColor, value: UIColor.black, range: mention.range)
}
else {
let color: UIColor = {
switch (isLightMode, isOutgoingMessage) {
case (_, true): return .black
case (true, false): return .black
case (false, false): return Colors.accent
}
}()
result.addAttribute(.foregroundColor, value: color, range: mention.range)
}
}
return result
}
}