mirror of
https://github.com/metabolist/metatext.git
synced 2024-11-22 08:10:59 +00:00
Notifications tab
This commit is contained in:
parent
00605ff212
commit
79b1c531f0
7 changed files with 266 additions and 106 deletions
|
@ -17,6 +17,7 @@
|
|||
D036AA02254B6101009094DF /* NotificationListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D036AA01254B6101009094DF /* NotificationListCell.swift */; };
|
||||
D036AA07254B6118009094DF /* NotificationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D036AA06254B6118009094DF /* NotificationView.swift */; };
|
||||
D036AA0C254B612B009094DF /* NotificationContentConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D036AA0B254B612B009094DF /* NotificationContentConfiguration.swift */; };
|
||||
D036AA17254CA824009094DF /* StatusBodyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D036AA16254CA823009094DF /* StatusBodyView.swift */; };
|
||||
D03B1B2A253818F3008F964B /* MediaPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B1B29253818F3008F964B /* MediaPreferencesView.swift */; };
|
||||
D04226FD2546AC0B000980A3 /* StartupAndSyncingPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04226FC2546AC0B000980A3 /* StartupAndSyncingPreferencesView.swift */; };
|
||||
D0625E59250F092900502611 /* StatusListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0625E58250F092900502611 /* StatusListCell.swift */; };
|
||||
|
@ -124,6 +125,7 @@
|
|||
D036AA01254B6101009094DF /* NotificationListCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationListCell.swift; sourceTree = "<group>"; };
|
||||
D036AA06254B6118009094DF /* NotificationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationView.swift; sourceTree = "<group>"; };
|
||||
D036AA0B254B612B009094DF /* NotificationContentConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationContentConfiguration.swift; sourceTree = "<group>"; };
|
||||
D036AA16254CA823009094DF /* StatusBodyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusBodyView.swift; sourceTree = "<group>"; };
|
||||
D03B1B29253818F3008F964B /* MediaPreferencesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaPreferencesView.swift; sourceTree = "<group>"; };
|
||||
D04226FC2546AC0B000980A3 /* StartupAndSyncingPreferencesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartupAndSyncingPreferencesView.swift; sourceTree = "<group>"; };
|
||||
D047FA8C24C3E21200AF17C5 /* Metatext.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Metatext.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
|
@ -278,6 +280,7 @@
|
|||
D01F41E224F8889700D55A2D /* StatusAttachmentsView.swift */,
|
||||
D0BEB1F224F8EE8C001B0F04 /* StatusAttachmentView.swift */,
|
||||
D0625E5C250F0B5C00502611 /* StatusContentConfiguration.swift */,
|
||||
D036AA16254CA823009094DF /* StatusBodyView.swift */,
|
||||
D0625E58250F092900502611 /* StatusListCell.swift */,
|
||||
D00CB2EC2533ACC00080096B /* StatusView.swift */,
|
||||
);
|
||||
|
@ -645,6 +648,7 @@
|
|||
D0BEB1FF24F9E5BB001B0F04 /* ListsView.swift in Sources */,
|
||||
D0C7D49724F7616A001EBDBB /* IdentitiesView.swift in Sources */,
|
||||
D01EF22425182B1F00650C6B /* AccountHeaderView.swift in Sources */,
|
||||
D036AA17254CA824009094DF /* StatusBodyView.swift in Sources */,
|
||||
D0EA59482522B8B600804347 /* ViewConstants.swift in Sources */,
|
||||
D04226FD2546AC0B000980A3 /* StartupAndSyncingPreferencesView.swift in Sources */,
|
||||
D036AA0C254B612B009094DF /* NotificationContentConfiguration.swift in Sources */,
|
||||
|
|
|
@ -391,7 +391,7 @@ private extension TableViewController {
|
|||
view.isDescendant(of: visibleView),
|
||||
let superview = view.superview,
|
||||
let attachmentsViewClosestToCenter = tableView.visibleCells
|
||||
.compactMap({ ($0.contentView as? StatusView)?.attachmentsView })
|
||||
.compactMap({ ($0.contentView as? StatusView)?.bodyView.attachmentsView })
|
||||
.filter(\.shouldAutoplay)
|
||||
.min(by: {
|
||||
abs(superview.convert($0.frame, from: $0.superview).midY - view.frame.midY)
|
||||
|
|
|
@ -165,6 +165,7 @@ extension CollectionItemsViewModel: CollectionViewModel {
|
|||
}
|
||||
}
|
||||
|
||||
// swiftlint:disable:next function_body_length
|
||||
public func viewModel(indexPath: IndexPath) -> CollectionItemViewModel {
|
||||
let item = items.value[indexPath.section][indexPath.item]
|
||||
let cachedViewModel = viewModelCache[item]?.viewModel
|
||||
|
|
|
@ -7,6 +7,7 @@ import ServiceLayer
|
|||
|
||||
public final class NotificationViewModel: CollectionItemViewModel, ObservableObject {
|
||||
public let accountViewModel: AccountViewModel
|
||||
public let statusViewModel: StatusViewModel?
|
||||
public let events: AnyPublisher<AnyPublisher<CollectionItemEvent, Error>, Never>
|
||||
|
||||
private let notificationService: NotificationService
|
||||
|
@ -20,6 +21,15 @@ public final class NotificationViewModel: CollectionItemViewModel, ObservableObj
|
|||
accountService: notificationService.navigationService.accountService(
|
||||
account: notificationService.notification.account),
|
||||
identification: identification)
|
||||
|
||||
if let status = notificationService.notification.status {
|
||||
statusViewModel = StatusViewModel(
|
||||
statusService: notificationService.navigationService.statusService(status: status),
|
||||
identification: identification)
|
||||
} else {
|
||||
statusViewModel = nil
|
||||
}
|
||||
|
||||
self.events = eventsSubject.eraseToAnyPublisher()
|
||||
}
|
||||
}
|
||||
|
@ -28,4 +38,14 @@ public extension NotificationViewModel {
|
|||
var type: MastodonNotification.NotificationType {
|
||||
notificationService.notification.type
|
||||
}
|
||||
|
||||
func accountSelected() {
|
||||
eventsSubject.send(
|
||||
Just(.navigation(
|
||||
.profile(
|
||||
notificationService.navigationService.profileService(
|
||||
account: notificationService.notification.account))))
|
||||
.setFailureType(to: Error.self)
|
||||
.eraseToAnyPublisher())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
// Copyright © 2020 Metabolist. All rights reserved.
|
||||
|
||||
import Kingfisher
|
||||
import Mastodon
|
||||
import UIKit
|
||||
|
||||
class NotificationView: UIView {
|
||||
final class NotificationView: UIView {
|
||||
private let iconImageView = UIImageView()
|
||||
private let avatarImageView = AnimatedImageView()
|
||||
private let avatarButton = UIButton()
|
||||
private let typeLabel = UILabel()
|
||||
private let displayNameLabel = UILabel()
|
||||
private let accountLabel = UILabel()
|
||||
private let statusBodyView = StatusBodyView()
|
||||
private var notificationConfiguration: NotificationContentConfiguration
|
||||
|
||||
init(configuration: NotificationContentConfiguration) {
|
||||
|
@ -37,31 +43,89 @@ extension NotificationView: UIContentView {
|
|||
}
|
||||
|
||||
private extension NotificationView {
|
||||
// swiftlint:disable function_body_length
|
||||
func initialSetup() {
|
||||
let stackView = UIStackView()
|
||||
let containerStackView = UIStackView()
|
||||
let sideStackView = UIStackView()
|
||||
let mainStackView = UIStackView()
|
||||
|
||||
addSubview(stackView)
|
||||
stackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
stackView.spacing = .compactSpacing
|
||||
addSubview(containerStackView)
|
||||
containerStackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
containerStackView.spacing = .defaultSpacing
|
||||
|
||||
stackView.addArrangedSubview(iconImageView)
|
||||
sideStackView.axis = .vertical
|
||||
sideStackView.alignment = .trailing
|
||||
sideStackView.spacing = .compactSpacing
|
||||
sideStackView.addArrangedSubview(iconImageView)
|
||||
sideStackView.addArrangedSubview(avatarImageView)
|
||||
sideStackView.addArrangedSubview(UIView())
|
||||
containerStackView.addArrangedSubview(sideStackView)
|
||||
|
||||
mainStackView.axis = .vertical
|
||||
mainStackView.spacing = .compactSpacing
|
||||
mainStackView.addArrangedSubview(typeLabel)
|
||||
mainStackView.addSubview(UIView())
|
||||
mainStackView.addArrangedSubview(statusBodyView)
|
||||
mainStackView.addArrangedSubview(displayNameLabel)
|
||||
mainStackView.addArrangedSubview(accountLabel)
|
||||
containerStackView.addArrangedSubview(mainStackView)
|
||||
|
||||
iconImageView.contentMode = .scaleAspectFit
|
||||
iconImageView.setContentHuggingPriority(.required, for: .horizontal)
|
||||
|
||||
stackView.addArrangedSubview(typeLabel)
|
||||
typeLabel.font = .preferredFont(forTextStyle: .body)
|
||||
avatarImageView.layer.cornerRadius = .avatarDimension / 2
|
||||
avatarImageView.clipsToBounds = true
|
||||
|
||||
let avatarHeightConstraint = avatarImageView.heightAnchor.constraint(equalToConstant: .avatarDimension)
|
||||
|
||||
avatarHeightConstraint.priority = .justBelowMax
|
||||
|
||||
avatarButton.translatesAutoresizingMaskIntoConstraints = false
|
||||
avatarImageView.addSubview(avatarButton)
|
||||
avatarImageView.isUserInteractionEnabled = true
|
||||
avatarButton.setBackgroundImage(.highlightedButtonBackground, for: .highlighted)
|
||||
|
||||
avatarButton.addAction(
|
||||
UIAction { [weak self] _ in self?.notificationConfiguration.viewModel.accountSelected() },
|
||||
for: .touchUpInside)
|
||||
|
||||
typeLabel.font = .preferredFont(forTextStyle: .headline)
|
||||
typeLabel.adjustsFontForContentSizeCategory = true
|
||||
typeLabel.numberOfLines = 0
|
||||
|
||||
statusBodyView.alpha = 0.5
|
||||
statusBodyView.isUserInteractionEnabled = false
|
||||
|
||||
displayNameLabel.font = .preferredFont(forTextStyle: .headline)
|
||||
displayNameLabel.adjustsFontForContentSizeCategory = true
|
||||
displayNameLabel.numberOfLines = 0
|
||||
|
||||
accountLabel.font = .preferredFont(forTextStyle: .subheadline)
|
||||
accountLabel.adjustsFontForContentSizeCategory = true
|
||||
accountLabel.textColor = .secondaryLabel
|
||||
accountLabel.numberOfLines = 0
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
stackView.leadingAnchor.constraint(equalTo: readableContentGuide.leadingAnchor),
|
||||
stackView.topAnchor.constraint(equalTo: readableContentGuide.topAnchor),
|
||||
stackView.trailingAnchor.constraint(equalTo: readableContentGuide.trailingAnchor),
|
||||
stackView.bottomAnchor.constraint(equalTo: readableContentGuide.bottomAnchor)
|
||||
containerStackView.leadingAnchor.constraint(equalTo: readableContentGuide.leadingAnchor),
|
||||
containerStackView.topAnchor.constraint(equalTo: readableContentGuide.topAnchor),
|
||||
containerStackView.trailingAnchor.constraint(equalTo: readableContentGuide.trailingAnchor),
|
||||
containerStackView.bottomAnchor.constraint(equalTo: readableContentGuide.bottomAnchor),
|
||||
avatarImageView.widthAnchor.constraint(equalToConstant: .avatarDimension),
|
||||
avatarHeightConstraint,
|
||||
sideStackView.widthAnchor.constraint(equalToConstant: .avatarDimension),
|
||||
iconImageView.centerYAnchor.constraint(equalTo: typeLabel.centerYAnchor),
|
||||
avatarButton.leadingAnchor.constraint(equalTo: avatarImageView.leadingAnchor),
|
||||
avatarButton.topAnchor.constraint(equalTo: avatarImageView.topAnchor),
|
||||
avatarButton.bottomAnchor.constraint(equalTo: avatarImageView.bottomAnchor),
|
||||
avatarButton.trailingAnchor.constraint(equalTo: avatarImageView.trailingAnchor)
|
||||
])
|
||||
}
|
||||
|
||||
func applyNotificationConfiguration() {
|
||||
let viewModel = notificationConfiguration.viewModel
|
||||
|
||||
avatarImageView.kf.setImage(with: viewModel.accountViewModel.avatarURL())
|
||||
|
||||
switch viewModel.type {
|
||||
case .follow:
|
||||
typeLabel.attributedText = "notifications.followed-you".localizedBolding(
|
||||
|
@ -96,10 +160,28 @@ private extension NotificationView {
|
|||
iconImageView.tintColor = nil
|
||||
}
|
||||
|
||||
if viewModel.statusViewModel == nil {
|
||||
let mutableDisplayName = NSMutableAttributedString(string: viewModel.accountViewModel.displayName)
|
||||
|
||||
mutableDisplayName.insert(emoji: viewModel.accountViewModel.emoji, view: displayNameLabel)
|
||||
mutableDisplayName.resizeAttachments(toLineHeight: displayNameLabel.font.lineHeight)
|
||||
displayNameLabel.attributedText = mutableDisplayName
|
||||
accountLabel.text = viewModel.accountViewModel.accountName
|
||||
statusBodyView.isHidden = true
|
||||
displayNameLabel.isHidden = false
|
||||
accountLabel.isHidden = false
|
||||
} else {
|
||||
statusBodyView.viewModel = viewModel.statusViewModel
|
||||
statusBodyView.isHidden = false
|
||||
displayNameLabel.isHidden = true
|
||||
accountLabel.isHidden = true
|
||||
}
|
||||
|
||||
iconImageView.image = UIImage(
|
||||
systemName: viewModel.type.systemImageName,
|
||||
withConfiguration: UIImage.SymbolConfiguration(scale: .medium))
|
||||
}
|
||||
// swiftlint:enable function_body_length
|
||||
}
|
||||
|
||||
extension MastodonNotification.NotificationType {
|
||||
|
|
138
Views/Status/StatusBodyView.swift
Normal file
138
Views/Status/StatusBodyView.swift
Normal file
|
@ -0,0 +1,138 @@
|
|||
// Copyright © 2020 Metabolist. All rights reserved.
|
||||
|
||||
import UIKit
|
||||
import ViewModels
|
||||
|
||||
final class StatusBodyView: UIView {
|
||||
let spoilerTextLabel = UILabel()
|
||||
let toggleShowContentButton = UIButton(type: .system)
|
||||
let contentTextView = TouchFallthroughTextView()
|
||||
let attachmentsView = StatusAttachmentsView()
|
||||
let pollView = PollView()
|
||||
let cardView = CardView()
|
||||
|
||||
var viewModel: StatusViewModel? {
|
||||
didSet {
|
||||
guard let viewModel = viewModel else { return }
|
||||
|
||||
let isContextParent = viewModel.configuration.isContextParent
|
||||
let mutableContent = NSMutableAttributedString(attributedString: viewModel.content)
|
||||
let mutableSpoilerText = NSMutableAttributedString(string: viewModel.spoilerText)
|
||||
let contentFont = UIFont.preferredFont(forTextStyle: isContextParent ? .title3 : .callout)
|
||||
let contentRange = NSRange(location: 0, length: mutableContent.length)
|
||||
|
||||
contentTextView.shouldFallthrough = !isContextParent
|
||||
|
||||
mutableContent.removeAttribute(.font, range: contentRange)
|
||||
mutableContent.addAttributes(
|
||||
[.font: contentFont, .foregroundColor: UIColor.label],
|
||||
range: contentRange)
|
||||
mutableContent.insert(emoji: viewModel.contentEmoji, view: contentTextView)
|
||||
mutableContent.resizeAttachments(toLineHeight: contentFont.lineHeight)
|
||||
contentTextView.attributedText = mutableContent
|
||||
contentTextView.isHidden = contentTextView.text == ""
|
||||
|
||||
mutableSpoilerText.insert(emoji: viewModel.contentEmoji, view: spoilerTextLabel)
|
||||
mutableSpoilerText.resizeAttachments(toLineHeight: spoilerTextLabel.font.lineHeight)
|
||||
spoilerTextLabel.font = contentFont
|
||||
spoilerTextLabel.attributedText = mutableSpoilerText
|
||||
spoilerTextLabel.isHidden = spoilerTextLabel.text == ""
|
||||
toggleShowContentButton.setTitle(
|
||||
viewModel.shouldShowContent
|
||||
? NSLocalizedString("status.show-less", comment: "")
|
||||
: NSLocalizedString("status.show-more", comment: ""),
|
||||
for: .normal)
|
||||
toggleShowContentButton.isHidden = viewModel.spoilerText == ""
|
||||
|
||||
contentTextView.isHidden = !viewModel.shouldShowContent
|
||||
|
||||
attachmentsView.isHidden = viewModel.attachmentViewModels.count == 0
|
||||
attachmentsView.viewModel = viewModel
|
||||
|
||||
pollView.isHidden = viewModel.pollOptions.count == 0
|
||||
pollView.viewModel = viewModel
|
||||
|
||||
cardView.viewModel = viewModel.cardViewModel
|
||||
cardView.isHidden = viewModel.cardViewModel == nil
|
||||
}
|
||||
}
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
initialSetup()
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
}
|
||||
|
||||
extension StatusBodyView: UITextViewDelegate {
|
||||
func textView(
|
||||
_ textView: UITextView,
|
||||
shouldInteractWith URL: URL,
|
||||
in characterRange: NSRange,
|
||||
interaction: UITextItemInteraction) -> Bool {
|
||||
switch interaction {
|
||||
case .invokeDefaultAction:
|
||||
viewModel?.urlSelected(URL)
|
||||
return false
|
||||
case .preview: return false
|
||||
case .presentActions: return false
|
||||
@unknown default: return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension StatusBodyView {
|
||||
func initialSetup() {
|
||||
let stackView = UIStackView()
|
||||
|
||||
addSubview(stackView)
|
||||
stackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
stackView.axis = .vertical
|
||||
stackView.spacing = .compactSpacing
|
||||
|
||||
spoilerTextLabel.numberOfLines = 0
|
||||
spoilerTextLabel.adjustsFontForContentSizeCategory = true
|
||||
stackView.addArrangedSubview(spoilerTextLabel)
|
||||
|
||||
toggleShowContentButton.titleLabel?.font = .preferredFont(forTextStyle: .headline)
|
||||
toggleShowContentButton.titleLabel?.adjustsFontForContentSizeCategory = true
|
||||
toggleShowContentButton.addAction(
|
||||
UIAction { [weak self] _ in self?.viewModel?.toggleShowContent() },
|
||||
for: .touchUpInside)
|
||||
stackView.addArrangedSubview(toggleShowContentButton)
|
||||
|
||||
contentTextView.adjustsFontForContentSizeCategory = true
|
||||
contentTextView.isScrollEnabled = false
|
||||
contentTextView.backgroundColor = .clear
|
||||
contentTextView.delegate = self
|
||||
stackView.addArrangedSubview(contentTextView)
|
||||
|
||||
stackView.addArrangedSubview(attachmentsView)
|
||||
|
||||
stackView.addArrangedSubview(pollView)
|
||||
|
||||
cardView.button.addAction(
|
||||
UIAction { [weak self] _ in
|
||||
guard
|
||||
let viewModel = self?.viewModel,
|
||||
let url = viewModel.cardViewModel?.url
|
||||
else { return }
|
||||
|
||||
viewModel.urlSelected(url)
|
||||
},
|
||||
for: .touchUpInside)
|
||||
stackView.addArrangedSubview(cardView)
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
stackView.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||
stackView.topAnchor.constraint(equalTo: topAnchor),
|
||||
stackView.trailingAnchor.constraint(equalTo: trailingAnchor),
|
||||
stackView.bottomAnchor.constraint(equalTo: bottomAnchor)
|
||||
])
|
||||
}
|
||||
}
|
|
@ -12,12 +12,7 @@ final class StatusView: UIView {
|
|||
let displayNameLabel = UILabel()
|
||||
let accountLabel = UILabel()
|
||||
let timeLabel = UILabel()
|
||||
let spoilerTextLabel = UILabel()
|
||||
let toggleShowContentButton = UIButton(type: .system)
|
||||
let contentTextView = TouchFallthroughTextView()
|
||||
let attachmentsView = StatusAttachmentsView()
|
||||
let pollView = PollView()
|
||||
let cardView = CardView()
|
||||
let bodyView = StatusBodyView()
|
||||
let contextParentTimeLabel = UILabel()
|
||||
let timeApplicationDividerLabel = UILabel()
|
||||
let applicationButton = UIButton(type: .system)
|
||||
|
@ -145,38 +140,7 @@ private extension StatusView {
|
|||
nameAccountContainerStackView.addArrangedSubview(nameAccountTimeStackView)
|
||||
mainStackView.addArrangedSubview(nameAccountContainerStackView)
|
||||
|
||||
spoilerTextLabel.numberOfLines = 0
|
||||
spoilerTextLabel.adjustsFontForContentSizeCategory = true
|
||||
mainStackView.addArrangedSubview(spoilerTextLabel)
|
||||
|
||||
toggleShowContentButton.titleLabel?.font = .preferredFont(forTextStyle: .headline)
|
||||
toggleShowContentButton.titleLabel?.adjustsFontForContentSizeCategory = true
|
||||
toggleShowContentButton.addAction(
|
||||
UIAction { [weak self] _ in self?.statusConfiguration.viewModel.toggleShowContent() },
|
||||
for: .touchUpInside)
|
||||
mainStackView.addArrangedSubview(toggleShowContentButton)
|
||||
|
||||
contentTextView.adjustsFontForContentSizeCategory = true
|
||||
contentTextView.isScrollEnabled = false
|
||||
contentTextView.backgroundColor = .clear
|
||||
contentTextView.delegate = self
|
||||
mainStackView.addArrangedSubview(contentTextView)
|
||||
|
||||
mainStackView.addArrangedSubview(attachmentsView)
|
||||
|
||||
mainStackView.addArrangedSubview(pollView)
|
||||
|
||||
cardView.button.addAction(
|
||||
UIAction { [weak self] _ in
|
||||
guard
|
||||
let viewModel = self?.statusConfiguration.viewModel,
|
||||
let url = viewModel.cardViewModel?.url
|
||||
else { return }
|
||||
|
||||
viewModel.urlSelected(url)
|
||||
},
|
||||
for: .touchUpInside)
|
||||
mainStackView.addArrangedSubview(cardView)
|
||||
mainStackView.addArrangedSubview(bodyView)
|
||||
|
||||
contextParentTimeLabel.font = .preferredFont(forTextStyle: .footnote)
|
||||
contextParentTimeLabel.adjustsFontForContentSizeCategory = true
|
||||
|
@ -296,15 +260,10 @@ private extension StatusView {
|
|||
func applyStatusConfiguration() {
|
||||
let viewModel = statusConfiguration.viewModel
|
||||
let isContextParent = viewModel.configuration.isContextParent
|
||||
let mutableContent = NSMutableAttributedString(attributedString: viewModel.content)
|
||||
let mutableDisplayName = NSMutableAttributedString(string: viewModel.displayName)
|
||||
let mutableSpoilerText = NSMutableAttributedString(string: viewModel.spoilerText)
|
||||
let contentFont = UIFont.preferredFont(forTextStyle: isContextParent ? .title3 : .callout)
|
||||
let contentRange = NSRange(location: 0, length: mutableContent.length)
|
||||
|
||||
avatarImageView.kf.setImage(with: viewModel.avatarURL)
|
||||
|
||||
contentTextView.shouldFallthrough = !isContextParent
|
||||
sideStackView.isHidden = isContextParent
|
||||
avatarImageView.removeFromSuperview()
|
||||
|
||||
|
@ -326,25 +285,11 @@ private extension StatusView {
|
|||
inReplyToView.isHidden = !viewModel.configuration.isReplyInContext
|
||||
hasReplyFollowingView.isHidden = !viewModel.configuration.hasReplyFollowing
|
||||
|
||||
if
|
||||
viewModel.isReblog {
|
||||
let metaText = String.localizedStringWithFormat(
|
||||
NSLocalizedString("status.reblogged-by", comment: ""),
|
||||
viewModel.rebloggedByDisplayName)
|
||||
let mutableInfoText = NSMutableAttributedString(string: metaText)
|
||||
|
||||
let range = (mutableInfoText.string as NSString).range(of: viewModel.rebloggedByDisplayName)
|
||||
|
||||
if range.location != NSNotFound,
|
||||
let boldFontDescriptor = infoLabel.font.fontDescriptor.withSymbolicTraits([.traitBold]) {
|
||||
let boldFont = UIFont(descriptor: boldFontDescriptor, size: infoLabel.font.pointSize)
|
||||
|
||||
mutableInfoText.setAttributes([NSAttributedString.Key.font: boldFont], range: range)
|
||||
}
|
||||
|
||||
mutableInfoText.insert(emoji: viewModel.rebloggedByDisplayNameEmoji, view: infoLabel)
|
||||
mutableInfoText.resizeAttachments(toLineHeight: infoLabel.font.lineHeight)
|
||||
infoLabel.attributedText = mutableInfoText
|
||||
if viewModel.isReblog {
|
||||
infoLabel.attributedText = "status.reblogged-by".localizedBolding(
|
||||
displayName: viewModel.rebloggedByDisplayName,
|
||||
emoji: viewModel.rebloggedByDisplayNameEmoji,
|
||||
label: infoLabel)
|
||||
infoIcon.image = UIImage(
|
||||
systemName: "arrow.2.squarepath",
|
||||
withConfiguration: UIImage.SymbolConfiguration(scale: .small))
|
||||
|
@ -362,33 +307,10 @@ private extension StatusView {
|
|||
infoIcon.isHidden = true
|
||||
}
|
||||
|
||||
mutableContent.removeAttribute(.font, range: contentRange)
|
||||
mutableContent.addAttributes(
|
||||
[.font: contentFont, .foregroundColor: UIColor.label],
|
||||
range: contentRange)
|
||||
mutableContent.insert(emoji: viewModel.contentEmoji, view: contentTextView)
|
||||
mutableContent.resizeAttachments(toLineHeight: contentFont.lineHeight)
|
||||
contentTextView.attributedText = mutableContent
|
||||
contentTextView.isHidden = contentTextView.text == ""
|
||||
|
||||
mutableDisplayName.insert(emoji: viewModel.displayNameEmoji, view: displayNameLabel)
|
||||
mutableDisplayName.resizeAttachments(toLineHeight: displayNameLabel.font.lineHeight)
|
||||
displayNameLabel.attributedText = mutableDisplayName
|
||||
|
||||
mutableSpoilerText.insert(emoji: viewModel.contentEmoji, view: spoilerTextLabel)
|
||||
mutableSpoilerText.resizeAttachments(toLineHeight: spoilerTextLabel.font.lineHeight)
|
||||
spoilerTextLabel.font = contentFont
|
||||
spoilerTextLabel.attributedText = mutableSpoilerText
|
||||
spoilerTextLabel.isHidden = spoilerTextLabel.text == ""
|
||||
toggleShowContentButton.setTitle(
|
||||
viewModel.shouldShowContent
|
||||
? NSLocalizedString("status.show-less", comment: "")
|
||||
: NSLocalizedString("status.show-more", comment: ""),
|
||||
for: .normal)
|
||||
toggleShowContentButton.isHidden = viewModel.spoilerText == ""
|
||||
|
||||
contentTextView.isHidden = !viewModel.shouldShowContent
|
||||
|
||||
nameAccountTimeStackView.axis = isContextParent ? .vertical : .horizontal
|
||||
nameAccountTimeStackView.alignment = isContextParent ? .leading : .fill
|
||||
nameAccountTimeStackView.spacing = isContextParent ? 0 : .compactSpacing
|
||||
|
@ -407,14 +329,7 @@ private extension StatusView {
|
|||
timeLabel.text = viewModel.time
|
||||
timeLabel.isHidden = isContextParent
|
||||
|
||||
attachmentsView.isHidden = viewModel.attachmentViewModels.count == 0
|
||||
attachmentsView.viewModel = viewModel
|
||||
|
||||
pollView.isHidden = viewModel.pollOptions.count == 0
|
||||
pollView.viewModel = viewModel
|
||||
|
||||
cardView.viewModel = viewModel.cardViewModel
|
||||
cardView.isHidden = viewModel.cardViewModel == nil
|
||||
bodyView.viewModel = viewModel
|
||||
|
||||
contextParentTimeLabel.text = viewModel.contextParentTime
|
||||
timeApplicationDividerLabel.isHidden = viewModel.applicationName == nil
|
||||
|
|
Loading…
Reference in a new issue