// // AccountCollectionViewCell.swift // Tusker // // Created by Shadowfacts on 11/22/22. // Copyright © 2022 Shadowfacts. All rights reserved. // import UIKit import HTMLStreamer class AccountCollectionViewCell: UICollectionViewListCell { private lazy var hStack = UIStackView(arrangedSubviews: [ avatarImageView, vStack, ]).configure { $0.axis = .horizontal $0.spacing = 8 $0.alignment = .leading } private let avatarImageView = CachedImageView(cache: .avatars).configure { $0.layer.masksToBounds = true $0.layer.cornerCurve = .continuous NSLayoutConstraint.activate([ $0.widthAnchor.constraint(equalToConstant: 50), $0.heightAnchor.constraint(equalToConstant: 50), ]) } private lazy var vStack = UIStackView(arrangedSubviews: [ displayNameLabel, usernameLabel, noteLabel, ]).configure { $0.axis = .vertical $0.spacing = 4 $0.alignment = .leading } private let displayNameLabel = EmojiLabel().configure { $0.font = .preferredFont(forTextStyle: .body) $0.adjustsFontSizeToFitWidth = true $0.adjustsFontForContentSizeCategory = true } private let usernameLabel = UILabel().configure { $0.font = UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 15, weight: .light)) $0.textColor = .secondaryLabel $0.adjustsFontSizeToFitWidth = true $0.adjustsFontForContentSizeCategory = true } private let noteLabel = EmojiLabel().configure { $0.font = UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 15)) $0.numberOfLines = 2 } weak var delegate: (TuskerNavigationDelegate & MenuActionProvider)? var mastodonController: MastodonController! { delegate?.apiController } private var accountID: String? private var isGrayscale = false override init(frame: CGRect) { super.init(frame: .zero) hStack.translatesAutoresizingMaskIntoConstraints = false contentView.addSubview(hStack) NSLayoutConstraint.activate([ hStack.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 8), hStack.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -8), hStack.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 8), hStack.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -8), ]) NotificationCenter.default.addObserver(self, selector: #selector(preferencesChanged), name: .preferencesChanged, object: nil) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } // MARK: Accessibility override var isAccessibilityElement: Bool { get { true } set {} } override var accessibilityAttributedLabel: NSAttributedString? { get { guard let accountID, let account = mastodonController.persistentContainer.account(for: accountID) else { return nil } var str = AttributedString(account.displayNameWithoutCustomEmoji) str += ", @" str += AttributedString(account.acct) return NSAttributedString(str) } set {} } override func accessibilityActivate() -> Bool { guard let accountID else { return false } delegate?.selected(account: accountID) return true } // MARK: Configure UI func updateUI(accountID: String) { guard let account = mastodonController.persistentContainer.account(for: accountID) else { fatalError() } self.accountID = accountID avatarImageView.update(for: account.avatar) usernameLabel.text = "@\(account.acct)" updateUIForPreferences(account: account) } private func updateUIForPreferences(account: AccountMO) { avatarImageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadiusFraction * 50 isGrayscale = Preferences.shared.grayscaleImages if Preferences.shared.hideCustomEmojiInUsernames { displayNameLabel.text = account.displayNameWithoutCustomEmoji } else { displayNameLabel.text = account.displayOrUserName displayNameLabel.setEmojis(account.emojis, identifier: account.id) } var converter = TextConverter(callbacks: HTMLConverter.Callbacks.self) noteLabel.text = converter.convert(html: account.note) noteLabel.setEmojis(account.emojis, identifier: account.id) } @objc private func preferencesChanged() { if let accountID, let account = mastodonController?.persistentContainer.account(for: accountID) { updateUIForPreferences(account: account) } } }