// // ProfileHeaderMovedOverlayView.swift // Tusker // // Created by Shadowfacts on 2/23/23. // Copyright © 2023 Shadowfacts. All rights reserved. // import UIKit class ProfileHeaderMovedOverlayView: UIView { private var movedToID: String! weak var delegate: TuskerNavigationDelegate? var collapse: (() -> Void)? private var avatarImageView: CachedImageView! private var displayNameLabel: EmojiLabel! private var usernameLabel: UILabel! private(set) var collapseButton: UIButton! init() { super.init(frame: .zero) let blur = UIBlurEffect(style: .systemUltraThinMaterial) let blurView = UIVisualEffectView(effect: blur) blurView.translatesAutoresizingMaskIntoConstraints = false addSubview(blurView) let vibrancy = UIVibrancyEffect(blurEffect: blur, style: .label) let vibrancyView = UIVisualEffectView(effect: vibrancy) vibrancyView.translatesAutoresizingMaskIntoConstraints = false blurView.contentView.addSubview(vibrancyView) let label = UILabel() label.text = "This account has moved to" label.font = .preferredFont(forTextStyle: .title3).withTraits(.traitBold) label.adjustsFontForContentSizeCategory = true label.textColor = .label avatarImageView = CachedImageView(cache: .avatars) avatarImageView.layer.masksToBounds = true avatarImageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadiusFraction * 50 avatarImageView.addInteraction(UIPointerInteraction(delegate: self)) avatarImageView.isUserInteractionEnabled = true displayNameLabel = EmojiLabel() displayNameLabel.adjustsFontForContentSizeCategory = true displayNameLabel.font = UIFont(descriptor: .preferredFontDescriptor(withTextStyle: .body).addingAttributes([ .traits: [ UIFontDescriptor.TraitKey.weight: UIFont.Weight.semibold.rawValue, ] ]), size: 0) usernameLabel = UILabel() usernameLabel.adjustsFontForContentSizeCategory = true usernameLabel.font = .preferredFont(forTextStyle: .body) usernameLabel.textColor = .secondaryLabel let nameVStack = UIStackView(arrangedSubviews: [ displayNameLabel, usernameLabel, ]) nameVStack.axis = .vertical nameVStack.alignment = .leading nameVStack.spacing = 4 let accountHStack = UIStackView(arrangedSubviews: [ avatarImageView, nameVStack, ]) accountHStack.axis = .horizontal accountHStack.alignment = .top accountHStack.spacing = 4 accountHStack.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(accountTapped))) let stack = UIStackView(arrangedSubviews: [ label, accountHStack, ]) stack.axis = .vertical stack.alignment = .center stack.spacing = 8 stack.translatesAutoresizingMaskIntoConstraints = false vibrancyView.contentView.addSubview(stack) var config = UIButton.Configuration.plain() config.image = UIImage(systemName: "chevron.up") collapseButton = UIButton(configuration: config, primaryAction: UIAction(handler: { [unowned self] _ in self.collapse?() })) collapseButton.accessibilityLabel = "Shrink banner" collapseButton.isPointerInteractionEnabled = true collapseButton.translatesAutoresizingMaskIntoConstraints = false addSubview(collapseButton) NSLayoutConstraint.activate([ blurView.leadingAnchor.constraint(equalTo: leadingAnchor), blurView.trailingAnchor.constraint(equalTo: trailingAnchor), blurView.topAnchor.constraint(equalTo: topAnchor), blurView.bottomAnchor.constraint(equalTo: bottomAnchor), vibrancyView.leadingAnchor.constraint(equalTo: blurView.contentView.leadingAnchor), vibrancyView.trailingAnchor.constraint(equalTo: blurView.contentView.trailingAnchor), vibrancyView.topAnchor.constraint(equalTo: blurView.contentView.topAnchor), vibrancyView.bottomAnchor.constraint(equalTo: blurView.contentView.bottomAnchor), stack.centerXAnchor.constraint(equalTo: vibrancyView.contentView.readableContentGuide.centerXAnchor), stack.centerYAnchor.constraint(equalTo: vibrancyView.contentView.centerYAnchor), stack.leadingAnchor.constraint(greaterThanOrEqualTo: vibrancyView.contentView.readableContentGuide.leadingAnchor), stack.trailingAnchor.constraint(lessThanOrEqualTo: vibrancyView.contentView.readableContentGuide.trailingAnchor), stack.topAnchor.constraint(greaterThanOrEqualTo: vibrancyView.contentView.topAnchor), stack.bottomAnchor.constraint(lessThanOrEqualTo: vibrancyView.contentView.bottomAnchor), avatarImageView.widthAnchor.constraint(equalToConstant: 50), avatarImageView.heightAnchor.constraint(equalToConstant: 50), bottomAnchor.constraint(equalToSystemSpacingBelow: collapseButton.bottomAnchor, multiplier: 1), collapseButton.centerXAnchor.constraint(equalTo: centerXAnchor), ]) NotificationCenter.default.addObserver(self, selector: #selector(preferencesChanged), name: .preferencesChanged, object: nil) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } @objc private func preferencesChanged() { avatarImageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadiusFraction * 50 } func updateUI(movedTo: AccountMO) { movedToID = movedTo.id avatarImageView.update(for: movedTo.avatar) displayNameLabel.text = movedTo.displayOrUserName displayNameLabel.setEmojis(movedTo.emojis, identifier: movedTo.id) usernameLabel.text = "@\(movedTo.acct)" } @objc private func accountTapped() { delegate?.selected(account: movedToID) } } extension ProfileHeaderMovedOverlayView: UIPointerInteractionDelegate { func pointerInteraction(_ interaction: UIPointerInteraction, regionFor request: UIPointerRegionRequest, defaultRegion: UIPointerRegion) -> UIPointerRegion? { return defaultRegion } func pointerInteraction(_ interaction: UIPointerInteraction, styleFor region: UIPointerRegion) -> UIPointerStyle? { let preview = UITargetedPreview(view: interaction.view!) return UIPointerStyle(effect: .lift(preview)) } }