Show reblogger's avatar on reblogged posts

This commit is contained in:
Shadowfacts 2023-04-17 11:19:37 -04:00
parent 2224dbebb8
commit 436159bd46
2 changed files with 26 additions and 5 deletions

View File

@ -16,6 +16,12 @@ class CachedImageView: UIImageView {
private var fetchTask: Task<Void, Error>? private var fetchTask: Task<Void, Error>?
private var blurHashTask: DispatchWorkItem? private var blurHashTask: DispatchWorkItem?
override var image: UIImage? {
didSet {
fetchTask?.cancel()
}
}
init(cache: ImageCache) { init(cache: ImageCache) {
self.cache = cache self.cache = cache
super.init(frame: .zero) super.init(frame: .zero)
@ -31,10 +37,10 @@ class CachedImageView: UIImageView {
NotificationCenter.default.addObserver(self, selector: #selector(preferencesChanged), name: .preferencesChanged, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(preferencesChanged), name: .preferencesChanged, object: nil)
} }
func update(for url: URL?, blurhash: String? = nil) { func update(for url: URL?, blurhash: String? = nil, placeholder: UIImage? = nil) {
if url != self.url || (url != nil && self.image == nil) { if url != self.url || (url != nil && self.image == nil) {
self.url = url self.url = url
self.image = nil super.image = placeholder
updateBlurhash(blurhash, for: url) updateBlurhash(blurhash, for: url)
updateImage() updateImage()
} }
@ -82,7 +88,7 @@ class CachedImageView: UIImageView {
return return
} }
try Task.checkCancellation() try Task.checkCancellation()
self.image = transformedImage super.image = transformedImage
self.isGrayscale = Preferences.shared.grayscaleImages self.isGrayscale = Preferences.shared.grayscaleImages
self.blurHashTask?.cancel() self.blurHashTask?.cancel()
} }

View File

@ -20,6 +20,8 @@ class TimelineStatusCollectionViewCell: UICollectionViewListCell, StatusCollecti
static let monospaceFont = UIFontMetrics.default.scaledFont(for: .monospacedSystemFont(ofSize: 16, weight: .regular)) static let monospaceFont = UIFontMetrics.default.scaledFont(for: .monospacedSystemFont(ofSize: 16, weight: .regular))
static let contentParagraphStyle = HTMLConverter.defaultParagraphStyle static let contentParagraphStyle = HTMLConverter.defaultParagraphStyle
private static let timelineReasonIconSize: CGFloat = 25
// MARK: Subviews // MARK: Subviews
private lazy var timelineReasonLabel = EmojiLabel().configure { private lazy var timelineReasonLabel = EmojiLabel().configure {
@ -27,8 +29,16 @@ class TimelineStatusCollectionViewCell: UICollectionViewListCell, StatusCollecti
$0.font = .preferredFont(forTextStyle: .body) $0.font = .preferredFont(forTextStyle: .body)
$0.adjustsFontForContentSizeCategory = true $0.adjustsFontForContentSizeCategory = true
} }
private let timelineReasonIcon = UIImageView(image: reblogIcon).configure { private let timelineReasonIcon = CachedImageView(cache: .avatars).configure {
$0.image = reblogIcon
$0.contentMode = .scaleAspectFit
$0.layer.masksToBounds = true
$0.tintColor = .secondaryLabel $0.tintColor = .secondaryLabel
NSLayoutConstraint.activate([
// this needs to be lessThanOrEqualTo not just equalTo b/c otherwise intermediate layouts are broken
$0.heightAnchor.constraint(lessThanOrEqualToConstant: TimelineStatusCollectionViewCell.timelineReasonIconSize),
$0.widthAnchor.constraint(equalTo: $0.heightAnchor),
])
} }
private lazy var timelineReasonHStack = UIStackView(arrangedSubviews: [ private lazy var timelineReasonHStack = UIStackView(arrangedSubviews: [
timelineReasonIcon, timelineReasonIcon,
@ -304,6 +314,9 @@ class TimelineStatusCollectionViewCell: UICollectionViewListCell, StatusCollecti
mainContainerTopToReblogLabelConstraint = mainContainer.topAnchor.constraint(equalTo: timelineReasonHStack.bottomAnchor, constant: 4) mainContainerTopToReblogLabelConstraint = mainContainer.topAnchor.constraint(equalTo: timelineReasonHStack.bottomAnchor, constant: 4)
mainContainerTopToSelfConstraint = mainContainer.topAnchor.constraint(equalTo: statusContainer.topAnchor, constant: 8) mainContainerTopToSelfConstraint = mainContainer.topAnchor.constraint(equalTo: statusContainer.topAnchor, constant: 8)
// when flipping between topToReblog and topToSelf constraints, the framework sometimes thinks both of them should be active simultaneously
// even though the code never does that; so let this one get broken temporarily
mainContainerTopToSelfConstraint.priority = .init(999)
mainContainerBottomToActionsConstraint = mainContainer.bottomAnchor.constraint(equalTo: actionsContainer.topAnchor, constant: -4) mainContainerBottomToActionsConstraint = mainContainer.bottomAnchor.constraint(equalTo: actionsContainer.topAnchor, constant: -4)
mainContainerBottomToSelfConstraint = mainContainer.bottomAnchor.constraint(equalTo: statusContainer.bottomAnchor, constant: -6) mainContainerBottomToSelfConstraint = mainContainer.bottomAnchor.constraint(equalTo: statusContainer.bottomAnchor, constant: -6)
@ -546,7 +559,6 @@ class TimelineStatusCollectionViewCell: UICollectionViewListCell, StatusCollecti
rebloggerID = status.account.id rebloggerID = status.account.id
hideTimelineReason = false hideTimelineReason = false
timelineReasonIcon.image = reblogIcon
updateRebloggerLabel(reblogger: status.account) updateRebloggerLabel(reblogger: status.account)
status = rebloggedStatus status = rebloggedStatus
} else { } else {
@ -604,6 +616,7 @@ class TimelineStatusCollectionViewCell: UICollectionViewListCell, StatusCollecti
} }
metaIndicatorsView.updateUI(status: status) metaIndicatorsView.updateUI(status: status)
timelineReasonIcon.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadiusFraction * Self.timelineReasonIconSize
if let rebloggerID, if let rebloggerID,
let reblogger = mastodonController.persistentContainer.account(for: rebloggerID) { let reblogger = mastodonController.persistentContainer.account(for: rebloggerID) {
updateRebloggerLabel(reblogger: reblogger) updateRebloggerLabel(reblogger: reblogger)
@ -650,6 +663,8 @@ class TimelineStatusCollectionViewCell: UICollectionViewListCell, StatusCollecti
} }
private func updateRebloggerLabel(reblogger: AccountMO) { private func updateRebloggerLabel(reblogger: AccountMO) {
timelineReasonIcon.update(for: reblogger.avatar, placeholder: reblogIcon)
if Preferences.shared.hideCustomEmojiInUsernames { if Preferences.shared.hideCustomEmojiInUsernames {
timelineReasonLabel.text = "\(reblogger.displayNameWithoutCustomEmoji) reblogged" timelineReasonLabel.text = "\(reblogger.displayNameWithoutCustomEmoji) reblogged"
timelineReasonLabel.removeEmojis() timelineReasonLabel.removeEmojis()