// // FastSwitchingAccountView.swift // Tusker // // Created by Shadowfacts on 11/4/20. // Copyright © 2020 Shadowfacts. All rights reserved. // import UIKit import UserAccounts import WebURL class FastSwitchingAccountView: UIView { private lazy var selectedColor = UIColor { [unowned self] (traits) in var hue: CGFloat = 0 var saturation: CGFloat = 0 var brightness: CGFloat = 0 var alpha: CGFloat = 0 self.tintColor.resolvedColor(with: traits).getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha) brightness = min(1, brightness + 0.4) saturation = max(0, saturation - 0.3) return UIColor(hue: hue, saturation: saturation, brightness: brightness, alpha: alpha) } private lazy var currentColor = UIColor { [unowned self] (traits) in var hue: CGFloat = 0 var saturation: CGFloat = 0 var brightness: CGFloat = 0 var alpha: CGFloat = 0 self.tintColor.resolvedColor(with: traits).getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha) brightness = min(1, brightness + 0.3) saturation = max(0, saturation - 0.2) return UIColor(hue: hue, saturation: saturation, brightness: brightness, alpha: alpha) } var isSelected = false { didSet { updateLabelColors() } } var isCurrent = false { didSet { updateLabelColors() } } private let orientation: FastAccountSwitcherViewController.ItemOrientation private let usernameLabel = UILabel() private let instanceLabel = UILabel() private let avatarImageView = UIImageView() private var avatarRequest: ImageCache.Request? init(account: UserAccountInfo, orientation: FastAccountSwitcherViewController.ItemOrientation) { self.orientation = orientation super.init(frame: .zero) commonInit() setupAccount(account: account) } init(orientation: FastAccountSwitcherViewController.ItemOrientation) { self.orientation = orientation super.init(frame: .zero) commonInit() setupPlaceholder() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } private func commonInit() { usernameLabel.textColor = .white usernameLabel.font = UIFont(descriptor: .preferredFontDescriptor(withTextStyle: .headline), size: 0) instanceLabel.textColor = .white instanceLabel.font = UIFont(descriptor: .preferredFontDescriptor(withTextStyle: .subheadline), size: 0) let stackView = UIStackView(arrangedSubviews: [ usernameLabel, instanceLabel ]) stackView.translatesAutoresizingMaskIntoConstraints = false stackView.axis = .vertical addSubview(stackView) avatarImageView.translatesAutoresizingMaskIntoConstraints = false avatarImageView.layer.masksToBounds = true avatarImageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadiusFraction * 40 avatarImageView.layer.cornerCurve = .continuous avatarImageView.image = UIImage(systemName: Preferences.shared.avatarStyle == .circle ? "person.crop.circle" : "person.crop.square") // todo: this should really be fit, but somehow the image view ends up being 37pt tall? avatarImageView.contentMode = .scaleAspectFill addSubview(avatarImageView) NSLayoutConstraint.activate([ avatarImageView.topAnchor.constraint(equalTo: topAnchor, constant: 8), avatarImageView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8), avatarImageView.widthAnchor.constraint(equalToConstant: 40), avatarImageView.heightAnchor.constraint(equalTo: avatarImageView.widthAnchor), stackView.centerYAnchor.constraint(equalTo: avatarImageView.centerYAnchor), ]) switch orientation { case .iconsLeading: stackView.alignment = .leading NSLayoutConstraint.activate([ avatarImageView.leadingAnchor.constraint(equalTo: leadingAnchor), stackView.leadingAnchor.constraint(equalTo: avatarImageView.trailingAnchor, constant: 8), stackView.trailingAnchor.constraint(equalTo: trailingAnchor), ]) case .iconsTrailing: stackView.alignment = .trailing NSLayoutConstraint.activate([ avatarImageView.trailingAnchor.constraint(equalTo: trailingAnchor), stackView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8), stackView.trailingAnchor.constraint(equalTo: avatarImageView.leadingAnchor, constant: -8), ]) } updateLabelColors() isAccessibilityElement = true } private func setupAccount(account: UserAccountInfo) { usernameLabel.text = account.username if let domain = WebURL.Domain(account.instanceURL.host!) { instanceLabel.text = domain.render(.uncheckedUnicodeString) } else { instanceLabel.text = account.instanceURL.host! } let controller = MastodonController.getForAccount(account) controller.getOwnAccount { [weak self] (result) in guard let self = self, case let .success(account) = result, let avatar = account.avatar else { return } self.avatarRequest = ImageCache.avatars.get(avatar) { [weak self] (_, image) in guard let self = self, let image = image else { return } DispatchQueue.main.async { self.avatarImageView.image = image } } } accessibilityLabel = "\(account.username!)@\(instanceLabel.text!)" } private func setupPlaceholder() { usernameLabel.text = "Add Account" instanceLabel.isHidden = true avatarImageView.image = UIImage(systemName: "plus") accessibilityLabel = "Add Account" } private func updateLabelColors() { let color: UIColor if isSelected { color = selectedColor } else if isCurrent { color = currentColor } else { color = .white } usernameLabel.textColor = color instanceLabel.textColor = color avatarImageView.tintColor = color } }