Compare commits

...

3 Commits

Author SHA1 Message Date
Shadowfacts 8319935a3d BaseEmojiLabel improvements
Avoid rechecking disk/memory caches when fetching

Use UIImage thumbnail API, rather than UIGraphicsImageRenderer, and make
thumbnail off main thread when possible
2023-05-14 15:19:00 -04:00
Shadowfacts 91ef386a41 Fix reblogger label getting updated twice for every cell 2023-05-14 14:58:46 -04:00
Shadowfacts c8eec17180 Fix custom emoji in display name being replaced multiple times unnecessarily 2023-05-14 14:41:36 -04:00
23 changed files with 211 additions and 168 deletions

View File

@ -246,7 +246,7 @@
D6B17255254F88B800128392 /* OppositeCollapseKeywordsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B17254254F88B800128392 /* OppositeCollapseKeywordsView.swift */; }; D6B17255254F88B800128392 /* OppositeCollapseKeywordsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B17254254F88B800128392 /* OppositeCollapseKeywordsView.swift */; };
D6B22A0F2560D52D004D82EF /* TabbedPageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B22A0E2560D52D004D82EF /* TabbedPageViewController.swift */; }; D6B22A0F2560D52D004D82EF /* TabbedPageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B22A0E2560D52D004D82EF /* TabbedPageViewController.swift */; };
D6B30E09254BAF63009CAEE5 /* ImageGrayscalifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B30E08254BAF63009CAEE5 /* ImageGrayscalifier.swift */; }; D6B30E09254BAF63009CAEE5 /* ImageGrayscalifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B30E08254BAF63009CAEE5 /* ImageGrayscalifier.swift */; };
D6B4A4FF2506B81A000C81C1 /* AccountDisplayNameLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B4A4FE2506B81A000C81C1 /* AccountDisplayNameLabel.swift */; }; D6B4A4FF2506B81A000C81C1 /* AccountDisplayNameView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B4A4FE2506B81A000C81C1 /* AccountDisplayNameView.swift */; };
D6B81F3C2560365300F6E31D /* RefreshableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B81F3B2560365300F6E31D /* RefreshableViewController.swift */; }; D6B81F3C2560365300F6E31D /* RefreshableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B81F3B2560365300F6E31D /* RefreshableViewController.swift */; };
D6B81F442560390300F6E31D /* MenuController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B81F432560390300F6E31D /* MenuController.swift */; }; D6B81F442560390300F6E31D /* MenuController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B81F432560390300F6E31D /* MenuController.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 */; };
@ -302,6 +302,7 @@
D6D79F2D2A0D61B400AB2315 /* StatusEditContentTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D79F2C2A0D61B400AB2315 /* StatusEditContentTextView.swift */; }; D6D79F2D2A0D61B400AB2315 /* StatusEditContentTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D79F2C2A0D61B400AB2315 /* StatusEditContentTextView.swift */; };
D6D79F2F2A0D6A7F00AB2315 /* StatusEditPollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D79F2E2A0D6A7F00AB2315 /* StatusEditPollView.swift */; }; D6D79F2F2A0D6A7F00AB2315 /* StatusEditPollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D79F2E2A0D6A7F00AB2315 /* StatusEditPollView.swift */; };
D6D79F532A0FFE3200AB2315 /* ToggleableButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D79F522A0FFE3200AB2315 /* ToggleableButton.swift */; }; D6D79F532A0FFE3200AB2315 /* ToggleableButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D79F522A0FFE3200AB2315 /* ToggleableButton.swift */; };
D6D79F572A1160B800AB2315 /* AccountDisplayNameLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D79F562A1160B800AB2315 /* AccountDisplayNameLabel.swift */; };
D6D94955298963A900C59229 /* Colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D94954298963A900C59229 /* Colors.swift */; }; D6D94955298963A900C59229 /* Colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D94954298963A900C59229 /* Colors.swift */; };
D6D9498D298CBB4000C59229 /* TrendingStatusCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D9498C298CBB4000C59229 /* TrendingStatusCollectionViewCell.swift */; }; D6D9498D298CBB4000C59229 /* TrendingStatusCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D9498C298CBB4000C59229 /* TrendingStatusCollectionViewCell.swift */; };
D6D9498F298EB79400C59229 /* CopyableLable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D9498E298EB79400C59229 /* CopyableLable.swift */; }; D6D9498F298EB79400C59229 /* CopyableLable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D9498E298EB79400C59229 /* CopyableLable.swift */; };
@ -638,7 +639,7 @@
D6B17254254F88B800128392 /* OppositeCollapseKeywordsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OppositeCollapseKeywordsView.swift; sourceTree = "<group>"; }; D6B17254254F88B800128392 /* OppositeCollapseKeywordsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OppositeCollapseKeywordsView.swift; sourceTree = "<group>"; };
D6B22A0E2560D52D004D82EF /* TabbedPageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabbedPageViewController.swift; sourceTree = "<group>"; }; D6B22A0E2560D52D004D82EF /* TabbedPageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabbedPageViewController.swift; sourceTree = "<group>"; };
D6B30E08254BAF63009CAEE5 /* ImageGrayscalifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageGrayscalifier.swift; sourceTree = "<group>"; }; D6B30E08254BAF63009CAEE5 /* ImageGrayscalifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageGrayscalifier.swift; sourceTree = "<group>"; };
D6B4A4FE2506B81A000C81C1 /* AccountDisplayNameLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountDisplayNameLabel.swift; sourceTree = "<group>"; }; D6B4A4FE2506B81A000C81C1 /* AccountDisplayNameView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountDisplayNameView.swift; sourceTree = "<group>"; };
D6B81F3B2560365300F6E31D /* RefreshableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RefreshableViewController.swift; sourceTree = "<group>"; }; D6B81F3B2560365300F6E31D /* RefreshableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RefreshableViewController.swift; sourceTree = "<group>"; };
D6B81F432560390300F6E31D /* MenuController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuController.swift; sourceTree = "<group>"; }; D6B81F432560390300F6E31D /* MenuController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuController.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>"; };
@ -702,6 +703,7 @@
D6D79F2C2A0D61B400AB2315 /* StatusEditContentTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusEditContentTextView.swift; sourceTree = "<group>"; }; D6D79F2C2A0D61B400AB2315 /* StatusEditContentTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusEditContentTextView.swift; sourceTree = "<group>"; };
D6D79F2E2A0D6A7F00AB2315 /* StatusEditPollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusEditPollView.swift; sourceTree = "<group>"; }; D6D79F2E2A0D6A7F00AB2315 /* StatusEditPollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusEditPollView.swift; sourceTree = "<group>"; };
D6D79F522A0FFE3200AB2315 /* ToggleableButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToggleableButton.swift; sourceTree = "<group>"; }; D6D79F522A0FFE3200AB2315 /* ToggleableButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToggleableButton.swift; sourceTree = "<group>"; };
D6D79F562A1160B800AB2315 /* AccountDisplayNameLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountDisplayNameLabel.swift; sourceTree = "<group>"; };
D6D94954298963A900C59229 /* Colors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Colors.swift; sourceTree = "<group>"; }; D6D94954298963A900C59229 /* Colors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Colors.swift; sourceTree = "<group>"; };
D6D9498C298CBB4000C59229 /* TrendingStatusCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrendingStatusCollectionViewCell.swift; sourceTree = "<group>"; }; D6D9498C298CBB4000C59229 /* TrendingStatusCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrendingStatusCollectionViewCell.swift; sourceTree = "<group>"; };
D6D9498E298EB79400C59229 /* CopyableLable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CopyableLable.swift; sourceTree = "<group>"; }; D6D9498E298EB79400C59229 /* CopyableLable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CopyableLable.swift; sourceTree = "<group>"; };
@ -1351,7 +1353,7 @@
D6BED1722126661300F02DA0 /* Views */ = { D6BED1722126661300F02DA0 /* Views */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
D6B4A4FE2506B81A000C81C1 /* AccountDisplayNameLabel.swift */, D6B4A4FE2506B81A000C81C1 /* AccountDisplayNameView.swift */,
D68E6F5E253C9B2D001A1B4C /* BaseEmojiLabel.swift */, D68E6F5E253C9B2D001A1B4C /* BaseEmojiLabel.swift */,
D6ADB6EF28ED1F25009924AB /* CachedImageView.swift */, D6ADB6EF28ED1F25009924AB /* CachedImageView.swift */,
D6895DC328D65342006341DA /* ConfirmReblogStatusPreviewView.swift */, D6895DC328D65342006341DA /* ConfirmReblogStatusPreviewView.swift */,
@ -1386,6 +1388,7 @@
D641C78B213DD92F004B4513 /* Profile Header */, D641C78B213DD92F004B4513 /* Profile Header */,
D641C78A213DD926004B4513 /* Status */, D641C78A213DD926004B4513 /* Status */,
D64AAE8F26C80DB600FC57FB /* Toast */, D64AAE8F26C80DB600FC57FB /* Toast */,
D6D79F562A1160B800AB2315 /* AccountDisplayNameLabel.swift */,
); );
path = Views; path = Views;
sourceTree = "<group>"; sourceTree = "<group>";
@ -2013,7 +2016,7 @@
D646C956213B365700269FB5 /* LargeImageExpandAnimationController.swift in Sources */, D646C956213B365700269FB5 /* LargeImageExpandAnimationController.swift in Sources */,
D646DCD22A06F2510059ECEB /* NotificationsCollectionViewController.swift in Sources */, D646DCD22A06F2510059ECEB /* NotificationsCollectionViewController.swift in Sources */,
D667E5F82135C3040057A976 /* Mastodon+Equatable.swift in Sources */, D667E5F82135C3040057A976 /* Mastodon+Equatable.swift in Sources */,
D6B4A4FF2506B81A000C81C1 /* AccountDisplayNameLabel.swift in Sources */, D6B4A4FF2506B81A000C81C1 /* AccountDisplayNameView.swift in Sources */,
D63D8DF42850FE7A008D95E1 /* ViewTags.swift in Sources */, D63D8DF42850FE7A008D95E1 /* ViewTags.swift in Sources */,
D61DC84B28F4FD2000B82C6E /* ProfileHeaderCollectionViewCell.swift in Sources */, D61DC84B28F4FD2000B82C6E /* ProfileHeaderCollectionViewCell.swift in Sources */,
D61A45E828DF477D002BE511 /* LoadingCollectionViewCell.swift in Sources */, D61A45E828DF477D002BE511 /* LoadingCollectionViewCell.swift in Sources */,
@ -2109,6 +2112,7 @@
D663626C21361C6700C9CBA2 /* Account+Preferences.swift in Sources */, D663626C21361C6700C9CBA2 /* Account+Preferences.swift in Sources */,
D67895C0246870DE00D4CD9E /* LocalAccountAvatarView.swift in Sources */, D67895C0246870DE00D4CD9E /* LocalAccountAvatarView.swift in Sources */,
D6ADB6E828E8C878009924AB /* PublicTimelineDescriptionCollectionViewCell.swift in Sources */, D6ADB6E828E8C878009924AB /* PublicTimelineDescriptionCollectionViewCell.swift in Sources */,
D6D79F572A1160B800AB2315 /* AccountDisplayNameLabel.swift in Sources */,
D646DCAC2A06C8840059ECEB /* ProfileFieldValueView.swift in Sources */, D646DCAC2A06C8840059ECEB /* ProfileFieldValueView.swift in Sources */,
D6F4D79429ECB0AF00351B87 /* UIBackgroundConfiguration+AppColors.swift in Sources */, D6F4D79429ECB0AF00351B87 /* UIBackgroundConfiguration+AppColors.swift in Sources */,
D6333B372137838300CE884A /* AttributedString+Helpers.swift in Sources */, D6333B372137838300CE884A /* AttributedString+Helpers.swift in Sources */,

View File

@ -37,6 +37,11 @@ class ImageCache {
completion?(entry.data, entry.image) completion?(entry.data, entry.image)
return nil return nil
} else { } else {
return getFromSource(url, completion: completion)
}
}
func getFromSource(_ url: URL, completion: ((Data?, UIImage?) -> Void)?) -> Request? {
return Task.detached(priority: .userInitiated) { return Task.detached(priority: .userInitiated) {
let result = await self.fetch(url: url) let result = await self.fetch(url: url)
switch result { switch result {
@ -49,7 +54,6 @@ class ImageCache {
} }
} }
} }
}
func get(_ url: URL, loadOriginal: Bool = false) async -> (Data?, UIImage?) { func get(_ url: URL, loadOriginal: Bool = false) async -> (Data?, UIImage?) {
if !ImageCache.disableCaching, if !ImageCache.disableCaching,

View File

@ -10,6 +10,7 @@ import UIKit
extension NSTextAttachment { extension NSTextAttachment {
// Based on https://github.com/ReticentJohn/Amaroq/blob/7c5b7088eb9fd1611dcb0f47d43bf8df093e142c/DireFloof/InlineImageHelpers.m // Based on https://github.com/ReticentJohn/Amaroq/blob/7c5b7088eb9fd1611dcb0f47d43bf8df093e142c/DireFloof/InlineImageHelpers.m
@available(iOS, deprecated: 15.0)
convenience init(emojiImage image: UIImage, in font: UIFont, with textColor: UIColor = .label) { convenience init(emojiImage image: UIImage, in font: UIFont, with textColor: UIColor = .label) {
let adjustedCapHeight = font.capHeight - 1 let adjustedCapHeight = font.capHeight - 1
var imageSizeMatchingFontSize = CGSize(width: image.size.width * (adjustedCapHeight / image.size.height), height: adjustedCapHeight) var imageSizeMatchingFontSize = CGSize(width: image.size.width * (adjustedCapHeight / image.size.height), height: adjustedCapHeight)

View File

@ -41,7 +41,7 @@ class ComposeHostingController: UIHostingController<ComposeHostingController.Vie
fetchAvatar: { @MainActor in await ImageCache.avatars.get($0).1 }, fetchAvatar: { @MainActor in await ImageCache.avatars.get($0).1 },
fetchAttachment: { @MainActor in await ImageCache.attachments.get($0).1 }, fetchAttachment: { @MainActor in await ImageCache.attachments.get($0).1 },
fetchStatus: { mastodonController.persistentContainer.status(for: $0) }, fetchStatus: { mastodonController.persistentContainer.status(for: $0) },
displayNameLabel: { AnyView(AccountDisplayNameLabel(account: $0, textStyle: $1, emojiSize: $2)) }, displayNameLabel: { AnyView(AccountDisplayNameView(account: $0, textStyle: $1, emojiSize: $2)) },
replyContentView: { AnyView(ComposeReplyContentView(status: $0, mastodonController: mastodonController, heightChanged: $1)) }, replyContentView: { AnyView(ComposeReplyContentView(status: $0, mastodonController: mastodonController, heightChanged: $1)) },
emojiImageView: { AnyView(CustomEmojiImageView(emoji: $0)) } emojiImageView: { AnyView(CustomEmojiImageView(emoji: $0)) }
) )

View File

@ -15,7 +15,7 @@ class FeaturedProfileCollectionViewCell: UICollectionViewCell {
@IBOutlet weak var headerImageView: UIImageView! @IBOutlet weak var headerImageView: UIImageView!
@IBOutlet weak var avatarContainerView: UIView! @IBOutlet weak var avatarContainerView: UIView!
@IBOutlet weak var avatarImageView: UIImageView! @IBOutlet weak var avatarImageView: UIImageView!
@IBOutlet weak var displayNameLabel: EmojiLabel! @IBOutlet weak var displayNameLabel: AccountDisplayNameLabel!
@IBOutlet weak var noteTextView: StatusContentTextView! @IBOutlet weak var noteTextView: StatusContentTextView!
var account: Account? var account: Account?

View File

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/> <device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies> <dependencies>
<deployment identifier="iOS"/> <deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21678"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/> <capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/> <capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
@ -47,7 +47,7 @@
<constraint firstItem="4wd-wq-Sh2" firstAttribute="centerX" secondItem="RQe-uE-TEv" secondAttribute="centerX" id="bRk-uJ-JGg"/> <constraint firstItem="4wd-wq-Sh2" firstAttribute="centerX" secondItem="RQe-uE-TEv" secondAttribute="centerX" id="bRk-uJ-JGg"/>
</constraints> </constraints>
</view> </view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Display name" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" minimumFontSize="10" adjustsLetterSpacingToFitWidth="YES" translatesAutoresizingMaskIntoConstraints="NO" id="voW-Is-1b2" customClass="EmojiLabel" customModule="Tusker" customModuleProvider="target"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Display name" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" minimumFontSize="10" adjustsLetterSpacingToFitWidth="YES" translatesAutoresizingMaskIntoConstraints="NO" id="voW-Is-1b2" customClass="AccountDisplayNameLabel" customModule="Tusker" customModuleProvider="target">
<rect key="frame" x="76" y="72" width="316" height="24"/> <rect key="frame" x="76" y="72" width="316" height="24"/>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="20"/> <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="20"/>
<nil key="textColor"/> <nil key="textColor"/>

View File

@ -21,7 +21,7 @@ class SuggestedProfileCardCollectionViewCell: UICollectionViewCell {
@IBOutlet weak var headerImageView: CachedImageView! @IBOutlet weak var headerImageView: CachedImageView!
@IBOutlet weak var avatarContainerView: UIView! @IBOutlet weak var avatarContainerView: UIView!
@IBOutlet weak var avatarImageView: CachedImageView! @IBOutlet weak var avatarImageView: CachedImageView!
@IBOutlet weak var displayNameLabel: EmojiLabel! @IBOutlet weak var displayNameLabel: AccountDisplayNameLabel!
@IBOutlet weak var usernameLabel: UILabel! @IBOutlet weak var usernameLabel: UILabel!
@IBOutlet weak var noteTextView: StatusContentTextView! @IBOutlet weak var noteTextView: StatusContentTextView!
@IBOutlet weak var suggestionSourceButton: UIButton! @IBOutlet weak var suggestionSourceButton: UIButton!

View File

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_12" orientation="portrait" appearance="light"/> <device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies> <dependencies>
<deployment identifier="iOS"/> <deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21678"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/> <capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="collection view cell content view" minToolsVersion="11.0"/> <capability name="collection view cell content view" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
@ -44,7 +44,7 @@
<constraint firstAttribute="width" constant="90" id="wav-YT-e4Y"/> <constraint firstAttribute="width" constant="90" id="wav-YT-e4Y"/>
</constraints> </constraints>
</view> </view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Display name" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsLetterSpacingToFitWidth="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="XCk-sZ-ujT" customClass="EmojiLabel" customModule="Tusker" customModuleProvider="target"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Display name" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsLetterSpacingToFitWidth="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="XCk-sZ-ujT" customClass="AccountDisplayNameLabel" customModule="Tusker" customModuleProvider="target">
<rect key="frame" x="106" y="100" width="333" height="29"/> <rect key="frame" x="106" y="100" width="333" height="29"/>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="24"/> <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="24"/>
<nil key="textColor"/> <nil key="textColor"/>

View File

@ -65,7 +65,7 @@ struct MuteAccountView: View {
) )
VStack(alignment: .leading) { VStack(alignment: .leading) {
AccountDisplayNameLabel(account: account, textStyle: .headline, emojiSize: 17) AccountDisplayNameView(account: account, textStyle: .headline, emojiSize: 17)
Text("@\(account.acct)") Text("@\(account.acct)")
.fontWeight(.light) .fontWeight(.light)
.foregroundColor(.secondary) .foregroundColor(.secondary)

View File

@ -55,7 +55,7 @@ struct ReportView: View {
) )
VStack(alignment: .leading) { VStack(alignment: .leading) {
AccountDisplayNameLabel(account: account, textStyle: .headline, emojiSize: 17) AccountDisplayNameView(account: account, textStyle: .headline, emojiSize: 17)
Text("@\(account.acct)") Text("@\(account.acct)")
.fontWeight(.light) .fontWeight(.light)
.foregroundColor(.secondary) .foregroundColor(.secondary)

View File

@ -15,7 +15,7 @@ class AccountTableViewCell: UITableViewCell {
var mastodonController: MastodonController! { delegate?.apiController } var mastodonController: MastodonController! { delegate?.apiController }
@IBOutlet weak var avatarImageView: UIImageView! @IBOutlet weak var avatarImageView: UIImageView!
@IBOutlet weak var displayNameLabel: EmojiLabel! @IBOutlet weak var displayNameLabel: AccountDisplayNameLabel!
@IBOutlet weak var usernameLabel: UILabel! @IBOutlet weak var usernameLabel: UILabel!
@IBOutlet weak var noteLabel: EmojiLabel! @IBOutlet weak var noteLabel: EmojiLabel!

View File

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/> <device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies> <dependencies>
<deployment identifier="iOS"/> <deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21678"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/> <capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/> <capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
@ -28,7 +28,7 @@
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="Iif-9m-vM5"> <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="Iif-9m-vM5">
<rect key="frame" x="74" y="11" width="230" height="78"/> <rect key="frame" x="74" y="11" width="230" height="78"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Display Name" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Fhc-bZ-lkB" customClass="EmojiLabel" customModule="Tusker" customModuleProvider="target"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Display Name" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Fhc-bZ-lkB" customClass="AccountDisplayNameLabel" customModule="Tusker" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="230" height="20.5"/> <rect key="frame" x="0.0" y="0.0" width="230" height="20.5"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/> <fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<nil key="textColor"/> <nil key="textColor"/>

View File

@ -12,7 +12,7 @@ import Pachyderm
class LargeAccountDetailView: UIView { class LargeAccountDetailView: UIView {
var avatarImageView = UIImageView() var avatarImageView = UIImageView()
var displayNameLabel = EmojiLabel() var displayNameLabel = AccountDisplayNameLabel()
var usernameLabel = UILabel() var usernameLabel = UILabel()
var avatarRequest: ImageCache.Request? var avatarRequest: ImageCache.Request?

View File

@ -2,106 +2,31 @@
// AccountDisplayNameLabel.swift // AccountDisplayNameLabel.swift
// Tusker // Tusker
// //
// Created by Shadowfacts on 9/7/20. // Created by Shadowfacts on 5/14/23.
// Copyright © 2020 Shadowfacts. All rights reserved. // Copyright © 2023 Shadowfacts. All rights reserved.
// //
import SwiftUI import UIKit
import Pachyderm import Pachyderm
import WebURLFoundationExtras
private let emojiRegex = try! NSRegularExpression(pattern: ":(\\w+):", options: []) class AccountDisplayNameLabel: EmojiLabel {
struct AccountDisplayNameLabel: View { private var accountID: String?
let account: any AccountProtocol // store the display name, so that if it changes the label updates w/o changing the id
let textStyle: Font.TextStyle private var accountDisplayName: String?
@ScaledMetric var emojiSize: CGFloat
@State var text: Text
@State var emojiRequests = [ImageCache.Request]()
init(account: any AccountProtocol, textStyle: Font.TextStyle, emojiSize: CGFloat) { func updateForAccountDisplayName(account: some AccountProtocol) {
self.account = account guard accountID != account.id || accountDisplayName != account.displayName || Preferences.shared.hideCustomEmojiInUsernames == hasEmojis else {
self.textStyle = textStyle return
self._emojiSize = ScaledMetric(wrappedValue: emojiSize, relativeTo: textStyle)
let name = account.displayName.isEmpty ? account.username : account.displayName
self._text = State(initialValue: Text(verbatim: name))
} }
accountID = account.id
var body: some View { accountDisplayName = account.displayName
text self.text = accountDisplayName
.font(.system(textStyle).weight(.semibold)) if Preferences.shared.hideCustomEmojiInUsernames {
.onAppear(perform: self.loadEmojis) self.removeEmojis()
}
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 = MultiThreadDictionary<String, Image>()
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(URL(emoji.url)!) { (_, image) in
defer { group.leave() }
guard let image = image else { return }
let size = CGSize(width: emojiSize, height: emojiSize)
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 { } else {
text = Text(image) + Text(verbatim: afterCurrentMatch) self.setEmojis(account.emojis, identifier: account.id)
}
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()
// }
//}

View File

@ -0,0 +1,107 @@
//
// AccountDisplayNameView.swift
// Tusker
//
// Created by Shadowfacts on 9/7/20.
// Copyright © 2020 Shadowfacts. All rights reserved.
//
import SwiftUI
import Pachyderm
import WebURLFoundationExtras
private let emojiRegex = try! NSRegularExpression(pattern: ":(\\w+):", options: [])
struct AccountDisplayNameView: View {
let account: any AccountProtocol
let textStyle: Font.TextStyle
@ScaledMetric var emojiSize: CGFloat
@State var text: Text
@State var emojiRequests = [ImageCache.Request]()
init(account: any AccountProtocol, textStyle: Font.TextStyle, emojiSize: CGFloat) {
self.account = account
self.textStyle = textStyle
self._emojiSize = ScaledMetric(wrappedValue: emojiSize, relativeTo: textStyle)
let name = account.displayName.isEmpty ? account.username : account.displayName
self._text = State(initialValue: Text(verbatim: name))
}
var body: some View {
text
.font(.system(textStyle).weight(.semibold))
.onAppear(perform: self.loadEmojis)
}
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 = MultiThreadDictionary<String, Image>()
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(URL(emoji.url)!) { (_, image) in
defer { group.leave() }
guard let image = image else { return }
let size = CGSize(width: emojiSize, height: emojiSize)
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 {
// AccountDisplayNameView()
// }
//}

View File

@ -40,6 +40,16 @@ extension BaseEmojiLabel {
return return
} }
// Based on https://github.com/ReticentJohn/Amaroq/blob/7c5b7088eb9fd1611dcb0f47d43bf8df093e142c/DireFloof/InlineImageHelpers.m
let adjustedCapHeight = emojiFont.capHeight - 1
func emojiImageSize(_ image: UIImage) -> CGSize {
var imageSizeMatchingFontSize = CGSize(width: image.size.width * (adjustedCapHeight / image.size.height), height: adjustedCapHeight)
var scale: CGFloat = 1.4
scale *= UIScreen.main.scale
imageSizeMatchingFontSize = CGSize(width: imageSizeMatchingFontSize.width * scale, height: imageSizeMatchingFontSize.height * scale)
return imageSizeMatchingFontSize
}
let emojiImages = MultiThreadDictionary<String, UIImage>() let emojiImages = MultiThreadDictionary<String, UIImage>()
var foundEmojis = false var foundEmojis = false
@ -57,22 +67,36 @@ extension BaseEmojiLabel {
foundEmojis = true foundEmojis = true
if let image = ImageCache.emojis.get(URL(emoji.url)!)?.image { if let image = ImageCache.emojis.get(URL(emoji.url)!)?.image {
// if the image is cached, add it immediately // if the image is cached, add it immediately.
emojiImages[emoji.shortcode] = image // we generate the thumbnail on the main thread, because it's usually fast enough
// and the delay caused by doing it asynchronously looks works.
// todo: consider caching these somewhere? the cache needs to take into account both the url and the font size, which may vary across labels, so can't just use ImageCache
if let thumbnail = image.preparingThumbnail(of: emojiImageSize(image)),
let cgImage = thumbnail.cgImage {
// the thumbnail API takes a pixel size and returns an image with scale 1, but we want the actual screen scale, so convert
// see FB12187798
emojiImages[emoji.shortcode] = UIImage(cgImage: cgImage, scale: UIScreen.main.scale, orientation: .up)
}
} else { } else {
// otherwise, perform the network request // otherwise, perform the network request
group.enter() group.enter()
// todo: ImageCache.emojis.get here will re-check the memory and disk caches, there should be another method to force-refetch let request = ImageCache.emojis.getFromSource(URL(emoji.url)!) { (_, image) in
let request = ImageCache.emojis.get(URL(emoji.url)!) { (_, image) in guard let image else {
guard let image = image, group.leave()
let transformedImage = ImageGrayscalifier.convertIfNecessary(url: URL(emoji.url)!, image: image) else { return
}
image.prepareThumbnail(of: emojiImageSize(image)) { thumbnail in
guard let thumbnail = thumbnail?.cgImage,
case let rescaled = UIImage(cgImage: thumbnail, scale: UIScreen.main.scale, orientation: .up),
let transformedImage = ImageGrayscalifier.convertIfNecessary(url: URL(emoji.url)!, image: rescaled) else {
group.leave() group.leave()
return return
} }
emojiImages[emoji.shortcode] = transformedImage emojiImages[emoji.shortcode] = transformedImage
group.leave() group.leave()
} }
}
if let request = request { if let request = request {
emojiRequests.append(request) emojiRequests.append(request)
} }
@ -91,10 +115,8 @@ extension BaseEmojiLabel {
// even though the closures is invoked on the same thread that withLock is called, so it's unclear why it needs to be @Sendable (FB11494878) // even though the closures is invoked on the same thread that withLock is called, so it's unclear why it needs to be @Sendable (FB11494878)
// so, just ignore the warnings // so, just ignore the warnings
let emojiAttachments = emojiImages.withLock { let emojiAttachments = emojiImages.withLock {
let emojiFont = self.emojiFont
let emojiTextColor = self.emojiTextColor
return $0.mapValues { image in return $0.mapValues { image in
NSTextAttachment(emojiImage: image, in: emojiFont, with: emojiTextColor) NSTextAttachment(image: image)
} }
} }
let placeholder = usePlaceholders ? NSTextAttachment(emojiPlaceholderIn: self.emojiFont) : nil let placeholder = usePlaceholders ? NSTextAttachment(emojiPlaceholderIn: self.emojiFont) : nil

View File

@ -52,7 +52,7 @@ class ConfirmReblogStatusPreviewView: UIView {
vStack.setContentHuggingPriority(.defaultLow, for: .horizontal) vStack.setContentHuggingPriority(.defaultLow, for: .horizontal)
hStack.addArrangedSubview(vStack) hStack.addArrangedSubview(vStack)
let displayNameLabel = EmojiLabel() let displayNameLabel = AccountDisplayNameLabel()
displayNameLabel.font = UIFont(descriptor: .preferredFontDescriptor(withTextStyle: .caption1).addingAttributes([.traits: [UIFontDescriptor.TraitKey.weight: UIFont.Weight.semibold]]), size: 0) displayNameLabel.font = UIFont(descriptor: .preferredFontDescriptor(withTextStyle: .caption1).addingAttributes([.traits: [UIFontDescriptor.TraitKey.weight: UIFont.Weight.semibold]]), size: 0)
displayNameLabel.adjustsFontSizeToFitWidth = true displayNameLabel.adjustsFontSizeToFitWidth = true
displayNameLabel.adjustsFontForContentSizeCategory = true displayNameLabel.adjustsFontForContentSizeCategory = true

View File

@ -38,24 +38,3 @@ class EmojiLabel: UILabel, BaseEmojiLabel {
} }
} }
extension EmojiLabel {
func updateForAccountDisplayName(account: Account) {
if Preferences.shared.hideCustomEmojiInUsernames {
self.text = account.displayName
self.removeEmojis()
} else {
self.text = account.displayName
self.setEmojis(account.emojis, identifier: account.id)
}
}
func updateForAccountDisplayName(account: AccountMO) {
if Preferences.shared.hideCustomEmojiInUsernames {
self.text = account.displayNameWithoutCustomEmoji
self.removeEmojis()
} else {
self.text = account.displayOrUserName
self.setEmojis(account.emojis, identifier: account.id)
}
}
}

View File

@ -28,7 +28,7 @@ class ProfileHeaderView: UIView {
@IBOutlet weak var avatarImageView: UIImageView! @IBOutlet weak var avatarImageView: UIImageView!
@IBOutlet weak var moreButton: ProfileHeaderButton! @IBOutlet weak var moreButton: ProfileHeaderButton!
@IBOutlet weak var followButton: ProfileHeaderButton! @IBOutlet weak var followButton: ProfileHeaderButton!
@IBOutlet weak var displayNameLabel: EmojiLabel! @IBOutlet weak var displayNameLabel: AccountDisplayNameLabel!
@IBOutlet weak var usernameLabel: UILabel! @IBOutlet weak var usernameLabel: UILabel!
@IBOutlet weak var lockImageView: UIImageView! @IBOutlet weak var lockImageView: UIImageView!
@IBOutlet weak var vStack: UIStackView! @IBOutlet weak var vStack: UIStackView!

View File

@ -39,7 +39,7 @@
<constraint firstItem="TkY-oK-if4" firstAttribute="centerX" secondItem="wT9-2J-uSY" secondAttribute="centerX" id="ozz-sa-gSc"/> <constraint firstItem="TkY-oK-if4" firstAttribute="centerX" secondItem="wT9-2J-uSY" secondAttribute="centerX" id="ozz-sa-gSc"/>
</constraints> </constraints>
</view> </view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" text="Display name" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="10" adjustsLetterSpacingToFitWidth="YES" translatesAutoresizingMaskIntoConstraints="NO" id="vcl-Gl-kXl" customClass="EmojiLabel" customModule="Tusker" customModuleProvider="target"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" text="Display name" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="10" adjustsLetterSpacingToFitWidth="YES" translatesAutoresizingMaskIntoConstraints="NO" id="vcl-Gl-kXl" customClass="AccountDisplayNameLabel" customModule="Tusker" customModuleProvider="target">
<rect key="frame" x="144" y="206" width="254" height="29"/> <rect key="frame" x="144" y="206" width="254" height="29"/>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="24"/> <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="24"/>
<nil key="textColor"/> <nil key="textColor"/>

View File

@ -39,7 +39,7 @@ class ConversationMainStatusCollectionViewCell: UICollectionViewListCell, Status
$0.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(accountPressed))) $0.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(accountPressed)))
} }
let displayNameLabel = EmojiLabel().configure { let displayNameLabel = AccountDisplayNameLabel().configure {
$0.font = UIFontMetrics(forTextStyle: .title1).scaledFont(for: .systemFont(ofSize: 24, weight: .semibold)) $0.font = UIFontMetrics(forTextStyle: .title1).scaledFont(for: .systemFont(ofSize: 24, weight: .semibold))
$0.adjustsFontForContentSizeCategory = true $0.adjustsFontForContentSizeCategory = true
} }

View File

@ -20,7 +20,7 @@ protocol StatusCollectionViewCellDelegate: AnyObject, TuskerNavigationDelegate,
protocol StatusCollectionViewCell: UICollectionViewCell, AttachmentViewDelegate { protocol StatusCollectionViewCell: UICollectionViewCell, AttachmentViewDelegate {
// MARK: Subviews // MARK: Subviews
var avatarImageView: CachedImageView { get } var avatarImageView: CachedImageView { get }
var displayNameLabel: EmojiLabel { get } var displayNameLabel: AccountDisplayNameLabel { get }
var usernameLabel: UILabel { get } var usernameLabel: UILabel { get }
var contentWarningLabel: EmojiLabel { get } var contentWarningLabel: EmojiLabel { get }
var collapseButton: StatusCollapseButton { get } var collapseButton: StatusCollapseButton { get }

View File

@ -114,7 +114,7 @@ class TimelineStatusCollectionViewCell: UICollectionViewListCell, StatusCollecti
$0.spacing = 4 $0.spacing = 4
} }
let displayNameLabel = EmojiLabel().configure { let displayNameLabel = AccountDisplayNameLabel().configure {
$0.font = UIFont(descriptor: .preferredFontDescriptor(withTextStyle: .body).addingAttributes([ $0.font = UIFont(descriptor: .preferredFontDescriptor(withTextStyle: .body).addingAttributes([
.traits: [ .traits: [
UIFontDescriptor.TraitKey.weight: UIFont.Weight.semibold.rawValue, UIFontDescriptor.TraitKey.weight: UIFont.Weight.semibold.rawValue,
@ -619,10 +619,6 @@ class TimelineStatusCollectionViewCell: UICollectionViewListCell, StatusCollecti
metaIndicatorsView.updateUI(status: status) metaIndicatorsView.updateUI(status: status)
timelineReasonIcon.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadiusFraction * Self.timelineReasonIconSize timelineReasonIcon.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadiusFraction * Self.timelineReasonIconSize
if let rebloggerID,
let reblogger = mastodonController.persistentContainer.account(for: rebloggerID) {
updateRebloggerLabel(reblogger: reblogger)
}
} }
func updateStatusState(status: StatusMO) { func updateStatusState(status: StatusMO) {
@ -703,6 +699,11 @@ class TimelineStatusCollectionViewCell: UICollectionViewListCell, StatusCollecti
updateUIForPreferences(status: status) updateUIForPreferences(status: status)
if let rebloggerID,
let reblogger = mastodonController.persistentContainer.account(for: rebloggerID) {
updateRebloggerLabel(reblogger: reblogger)
}
if isGrayscale != Preferences.shared.grayscaleImages { if isGrayscale != Preferences.shared.grayscaleImages {
updateGrayscaleableUI(status: status) updateGrayscaleableUI(status: status)
} }