forked from shadowfacts/Tusker
Show custom emoji in display names on Compose screen
This commit is contained in:
parent
3da7aacb35
commit
dd8a196630
|
@ -227,6 +227,7 @@
|
||||||
D6B053AB23BD2F1400A066FA /* AssetCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B053A923BD2F1400A066FA /* AssetCollectionViewCell.swift */; };
|
D6B053AB23BD2F1400A066FA /* AssetCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B053A923BD2F1400A066FA /* AssetCollectionViewCell.swift */; };
|
||||||
D6B053AC23BD2F1400A066FA /* AssetCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D6B053AA23BD2F1400A066FA /* AssetCollectionViewCell.xib */; };
|
D6B053AC23BD2F1400A066FA /* AssetCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D6B053AA23BD2F1400A066FA /* AssetCollectionViewCell.xib */; };
|
||||||
D6B053AE23BD322B00A066FA /* AssetPickerSheetContainerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B053AD23BD322B00A066FA /* AssetPickerSheetContainerViewController.swift */; };
|
D6B053AE23BD322B00A066FA /* AssetPickerSheetContainerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B053AD23BD322B00A066FA /* AssetPickerSheetContainerViewController.swift */; };
|
||||||
|
D6B4A4FF2506B81A000C81C1 /* AccountDisplayNameLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B4A4FE2506B81A000C81C1 /* AccountDisplayNameLabel.swift */; };
|
||||||
D6B8DB342182A59300424AF7 /* UIAlertController+Visibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B8DB332182A59300424AF7 /* UIAlertController+Visibility.swift */; };
|
D6B8DB342182A59300424AF7 /* UIAlertController+Visibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B8DB332182A59300424AF7 /* UIAlertController+Visibility.swift */; };
|
||||||
D6BC874521961F73006163F1 /* Gifu.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D6BC874421961F73006163F1 /* Gifu.framework */; };
|
D6BC874521961F73006163F1 /* Gifu.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D6BC874421961F73006163F1 /* Gifu.framework */; };
|
||||||
D6BC874621961F73006163F1 /* Gifu.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D6BC874421961F73006163F1 /* Gifu.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
D6BC874621961F73006163F1 /* Gifu.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D6BC874421961F73006163F1 /* Gifu.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||||
|
@ -547,6 +548,7 @@
|
||||||
D6B053A923BD2F1400A066FA /* AssetCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetCollectionViewCell.swift; sourceTree = "<group>"; };
|
D6B053A923BD2F1400A066FA /* AssetCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetCollectionViewCell.swift; sourceTree = "<group>"; };
|
||||||
D6B053AA23BD2F1400A066FA /* AssetCollectionViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AssetCollectionViewCell.xib; sourceTree = "<group>"; };
|
D6B053AA23BD2F1400A066FA /* AssetCollectionViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AssetCollectionViewCell.xib; sourceTree = "<group>"; };
|
||||||
D6B053AD23BD322B00A066FA /* AssetPickerSheetContainerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetPickerSheetContainerViewController.swift; sourceTree = "<group>"; };
|
D6B053AD23BD322B00A066FA /* AssetPickerSheetContainerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetPickerSheetContainerViewController.swift; sourceTree = "<group>"; };
|
||||||
|
D6B4A4FE2506B81A000C81C1 /* AccountDisplayNameLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountDisplayNameLabel.swift; sourceTree = "<group>"; };
|
||||||
D6B8DB332182A59300424AF7 /* UIAlertController+Visibility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIAlertController+Visibility.swift"; sourceTree = "<group>"; };
|
D6B8DB332182A59300424AF7 /* UIAlertController+Visibility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIAlertController+Visibility.swift"; sourceTree = "<group>"; };
|
||||||
D6BC874421961F73006163F1 /* Gifu.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Gifu.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
D6BC874421961F73006163F1 /* Gifu.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Gifu.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
D6BC8747219738E1006163F1 /* EnhancedTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnhancedTableViewController.swift; sourceTree = "<group>"; };
|
D6BC8747219738E1006163F1 /* EnhancedTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnhancedTableViewController.swift; sourceTree = "<group>"; };
|
||||||
|
@ -1251,6 +1253,7 @@
|
||||||
D6403CC124A6B72D00E81C55 /* VisualEffectImageButton.swift */,
|
D6403CC124A6B72D00E81C55 /* VisualEffectImageButton.swift */,
|
||||||
D6C99FC624FACFAB005C74D3 /* ActivityIndicatorView.swift */,
|
D6C99FC624FACFAB005C74D3 /* ActivityIndicatorView.swift */,
|
||||||
D686BBE224FBF8110068E6AA /* WrappedProgressView.swift */,
|
D686BBE224FBF8110068E6AA /* WrappedProgressView.swift */,
|
||||||
|
D6B4A4FE2506B81A000C81C1 /* AccountDisplayNameLabel.swift */,
|
||||||
D67C57A721E2649B00C3118B /* Account Detail */,
|
D67C57A721E2649B00C3118B /* Account Detail */,
|
||||||
D67C57B021E28F9400C3118B /* Compose Status Reply */,
|
D67C57B021E28F9400C3118B /* Compose Status Reply */,
|
||||||
D626494023C122C800612E6E /* Asset Picker */,
|
D626494023C122C800612E6E /* Asset Picker */,
|
||||||
|
@ -1794,6 +1797,7 @@
|
||||||
D646C956213B365700269FB5 /* LargeImageExpandAnimationController.swift in Sources */,
|
D646C956213B365700269FB5 /* LargeImageExpandAnimationController.swift in Sources */,
|
||||||
D667E5F82135C3040057A976 /* Mastodon+Equatable.swift in Sources */,
|
D667E5F82135C3040057A976 /* Mastodon+Equatable.swift in Sources */,
|
||||||
D681E4D5246E2BC30053414F /* UnmuteConversationActivity.swift in Sources */,
|
D681E4D5246E2BC30053414F /* UnmuteConversationActivity.swift in Sources */,
|
||||||
|
D6B4A4FF2506B81A000C81C1 /* AccountDisplayNameLabel.swift in Sources */,
|
||||||
D67C57B421E2910700C3118B /* ComposeStatusReplyView.swift in Sources */,
|
D67C57B421E2910700C3118B /* ComposeStatusReplyView.swift in Sources */,
|
||||||
D6B053A623BD2D0C00A066FA /* AssetCollectionViewController.swift in Sources */,
|
D6B053A623BD2D0C00A066FA /* AssetCollectionViewController.swift in Sources */,
|
||||||
D62275A024F1677200B82A16 /* ComposeHostingController.swift in Sources */,
|
D62275A024F1677200B82A16 /* ComposeHostingController.swift in Sources */,
|
||||||
|
|
|
@ -20,8 +20,7 @@ struct ComposeCurrentAccount: View {
|
||||||
HStack(alignment: .top) {
|
HStack(alignment: .top) {
|
||||||
ComposeAvatarImageView(url: account.avatar)
|
ComposeAvatarImageView(url: account.avatar)
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
Text(verbatim: account.displayName)
|
AccountDisplayNameLabel(account: mastodonController.persistentContainer.account(for: account.id)!, fontSize: 20)
|
||||||
.font(.system(size: 20, weight: .semibold))
|
|
||||||
.lineLimit(1)
|
.lineLimit(1)
|
||||||
|
|
||||||
Text(verbatim: "@\(account.acct)")
|
Text(verbatim: "@\(account.acct)")
|
||||||
|
|
|
@ -23,8 +23,7 @@ struct ComposeReplyView: View {
|
||||||
|
|
||||||
VStack(alignment: .leading, spacing: 0) {
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
HStack {
|
HStack {
|
||||||
Text(verbatim: status.account.displayName)
|
AccountDisplayNameLabel(account: status.account, fontSize: 17)
|
||||||
.font(.system(size: 17, weight: .semibold))
|
|
||||||
.lineLimit(1)
|
.lineLimit(1)
|
||||||
.layoutPriority(1)
|
.layoutPriority(1)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,109 @@
|
||||||
|
//
|
||||||
|
// AccountDisplayNameLabel.swift
|
||||||
|
// Tusker
|
||||||
|
//
|
||||||
|
// Created by Shadowfacts on 9/7/20.
|
||||||
|
// Copyright © 2020 Shadowfacts. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
private let emojiRegex = try! NSRegularExpression(pattern: ":(\\w+):", options: [])
|
||||||
|
|
||||||
|
struct AccountDisplayNameLabel: View {
|
||||||
|
let account: AccountMO
|
||||||
|
let fontSize: Int
|
||||||
|
@State var text: Text
|
||||||
|
@State var emojiRequests = [ImageCache.Request]()
|
||||||
|
|
||||||
|
init(account: AccountMO, fontSize: Int) {
|
||||||
|
self.account = account
|
||||||
|
self.fontSize = fontSize
|
||||||
|
self._text = State(initialValue: Text(verbatim: account.displayName))
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
if #available(iOS 14.0, *) {
|
||||||
|
text
|
||||||
|
.font(.system(size: CGFloat(fontSize), weight: .semibold))
|
||||||
|
.onAppear(perform: self.loadEmojis)
|
||||||
|
} else {
|
||||||
|
text
|
||||||
|
.font(.system(size: CGFloat(fontSize), weight: .semibold))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// embedding Image inside Text is only available on iOS 14
|
||||||
|
@available(iOS 14.0, *)
|
||||||
|
private func loadEmojis() {
|
||||||
|
let fullRange = NSRange(account.displayName.startIndex..., in: account.displayName)
|
||||||
|
let matches = emojiRegex.matches(in: account.displayName, options: [], range: fullRange)
|
||||||
|
guard !matches.isEmpty else { return }
|
||||||
|
|
||||||
|
let emojiImages = CachedDictionary<Image>(name: "AcccountDisplayNameLabel Emoji Images")
|
||||||
|
|
||||||
|
let group = DispatchGroup()
|
||||||
|
|
||||||
|
for emoji in account.emojis {
|
||||||
|
guard matches.contains(where: { (match) in
|
||||||
|
let matchShortcode = (account.displayName as NSString).substring(with: match.range(at: 1))
|
||||||
|
return emoji.shortcode == matchShortcode
|
||||||
|
}) else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
group.enter()
|
||||||
|
let request = ImageCache.emojis.get(emoji.url) { (data) in
|
||||||
|
defer { group.leave() }
|
||||||
|
guard let data = data, let image = UIImage(data: data) else { return }
|
||||||
|
|
||||||
|
let size = CGSize(width: fontSize, height: fontSize)
|
||||||
|
let renderer = UIGraphicsImageRenderer(size: size)
|
||||||
|
let resized = renderer.image { (ctx) in
|
||||||
|
image.draw(in: CGRect(origin: .zero, size: size))
|
||||||
|
}
|
||||||
|
|
||||||
|
emojiImages[emoji.shortcode] = Image(uiImage: resized)
|
||||||
|
}
|
||||||
|
if let request = request {
|
||||||
|
emojiRequests.append(request)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
group.notify(queue: .main) {
|
||||||
|
var text: Text?
|
||||||
|
|
||||||
|
var endIndex = account.displayName.utf16.count
|
||||||
|
|
||||||
|
// iterate backwards as to not alter the indices of earlier matches
|
||||||
|
for match in matches.reversed() {
|
||||||
|
let shortcode = (account.displayName as NSString).substring(with: match.range(at: 1))
|
||||||
|
guard let image = emojiImages[shortcode] else { continue }
|
||||||
|
|
||||||
|
let afterCurrentMatch = (account.displayName as NSString).substring(with: NSRange(location: match.range.upperBound, length: endIndex - match.range.upperBound))
|
||||||
|
|
||||||
|
if let subsequent = text {
|
||||||
|
text = Text(image) + Text(verbatim: afterCurrentMatch) + subsequent
|
||||||
|
} else {
|
||||||
|
text = Text(image) + Text(verbatim: afterCurrentMatch)
|
||||||
|
}
|
||||||
|
|
||||||
|
endIndex = match.range.lowerBound
|
||||||
|
}
|
||||||
|
|
||||||
|
let beforeLastMatch = (account.displayName as NSString).substring(to: endIndex)
|
||||||
|
|
||||||
|
if let text = text {
|
||||||
|
self.text = Text(verbatim: beforeLastMatch) + text
|
||||||
|
} else {
|
||||||
|
self.text = Text(verbatim: beforeLastMatch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//struct AccountDisplayNameLabel_Previews: PreviewProvider {
|
||||||
|
// static var previews: some View {
|
||||||
|
// AccountDisplayNameLabel()
|
||||||
|
// }
|
||||||
|
//}
|
Loading…
Reference in New Issue