2021-04-01 14:54:57 +02:00
|
|
|
//
|
|
|
|
// SearchRecommendAccountsCollectionViewCell.swift
|
|
|
|
// Mastodon
|
|
|
|
//
|
|
|
|
// Created by sxiaojian on 2021/4/1.
|
|
|
|
//
|
|
|
|
|
2021-04-09 13:39:35 +02:00
|
|
|
import Combine
|
|
|
|
import CoreDataStack
|
2021-04-01 14:54:57 +02:00
|
|
|
import Foundation
|
|
|
|
import MastodonSDK
|
2021-04-02 06:10:12 +02:00
|
|
|
import UIKit
|
2021-06-29 13:27:40 +02:00
|
|
|
import ActiveLabel
|
2021-04-01 14:54:57 +02:00
|
|
|
|
2021-04-09 13:39:35 +02:00
|
|
|
protocol SearchRecommendAccountsCollectionViewCellDelegate: NSObject {
|
|
|
|
func followButtonDidPressed(clickedUser: MastodonUser)
|
2021-04-09 07:59:33 +02:00
|
|
|
|
2021-04-09 13:39:35 +02:00
|
|
|
func configFollowButton(with mastodonUser: MastodonUser, followButton: HighlightDimmableButton)
|
|
|
|
}
|
|
|
|
|
|
|
|
class SearchRecommendAccountsCollectionViewCell: UICollectionViewCell {
|
2021-04-09 07:59:33 +02:00
|
|
|
var disposeBag = Set<AnyCancellable>()
|
|
|
|
|
2021-04-09 13:39:35 +02:00
|
|
|
weak var delegate: SearchRecommendAccountsCollectionViewCellDelegate?
|
|
|
|
|
2021-04-01 14:54:57 +02:00
|
|
|
let avatarImageView: UIImageView = {
|
|
|
|
let imageView = UIImageView()
|
2021-04-08 07:30:32 +02:00
|
|
|
imageView.layer.cornerRadius = 8.4
|
2021-04-01 14:54:57 +02:00
|
|
|
imageView.clipsToBounds = true
|
|
|
|
return imageView
|
|
|
|
}()
|
|
|
|
|
|
|
|
let headerImageView: UIImageView = {
|
|
|
|
let imageView = UIImageView()
|
2021-04-08 07:30:32 +02:00
|
|
|
imageView.contentMode = .scaleAspectFill
|
|
|
|
imageView.layer.cornerRadius = 10
|
2021-04-13 07:06:35 +02:00
|
|
|
imageView.layer.cornerCurve = .continuous
|
2021-04-01 14:54:57 +02:00
|
|
|
imageView.clipsToBounds = true
|
2021-04-08 07:30:32 +02:00
|
|
|
imageView.layer.borderWidth = 2
|
|
|
|
imageView.layer.borderColor = Asset.Colors.Border.searchCard.color.cgColor
|
2021-04-01 14:54:57 +02:00
|
|
|
return imageView
|
|
|
|
}()
|
|
|
|
|
2021-04-08 07:30:32 +02:00
|
|
|
let visualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .regular))
|
|
|
|
|
2021-06-29 13:27:40 +02:00
|
|
|
let displayNameLabel: ActiveLabel = {
|
|
|
|
let label = ActiveLabel(style: .statusName)
|
2021-04-01 14:54:57 +02:00
|
|
|
label.textColor = .white
|
2021-04-08 08:19:59 +02:00
|
|
|
label.textAlignment = .center
|
2021-04-01 14:54:57 +02:00
|
|
|
label.font = .systemFont(ofSize: 18, weight: .semibold)
|
|
|
|
label.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
return label
|
|
|
|
}()
|
|
|
|
|
|
|
|
let acctLabel: UILabel = {
|
|
|
|
let label = UILabel()
|
|
|
|
label.textColor = .white
|
|
|
|
label.font = .preferredFont(forTextStyle: .body)
|
2021-04-08 08:17:57 +02:00
|
|
|
label.textAlignment = .center
|
2021-04-01 14:54:57 +02:00
|
|
|
label.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
return label
|
|
|
|
}()
|
|
|
|
|
2021-04-09 13:39:35 +02:00
|
|
|
let followButton: HighlightDimmableButton = {
|
|
|
|
let button = HighlightDimmableButton(type: .custom)
|
2021-04-19 11:00:51 +02:00
|
|
|
button.setInsets(forContentPadding: UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16), imageTitlePadding: 0)
|
2021-04-01 14:54:57 +02:00
|
|
|
button.setTitleColor(.white, for: .normal)
|
|
|
|
button.setTitle(L10n.Scene.Search.Recommend.Accounts.follow, for: .normal)
|
|
|
|
button.titleLabel?.font = .systemFont(ofSize: 14, weight: .semibold)
|
|
|
|
button.layer.cornerRadius = 12
|
2021-04-13 07:06:35 +02:00
|
|
|
button.layer.cornerCurve = .continuous
|
2021-04-08 07:30:32 +02:00
|
|
|
button.layer.borderWidth = 2
|
2021-04-01 14:54:57 +02:00
|
|
|
button.layer.borderColor = UIColor.white.cgColor
|
|
|
|
return button
|
|
|
|
}()
|
|
|
|
|
|
|
|
override func prepareForReuse() {
|
|
|
|
super.prepareForReuse()
|
|
|
|
headerImageView.af.cancelImageRequest()
|
|
|
|
avatarImageView.af.cancelImageRequest()
|
2021-04-08 07:30:32 +02:00
|
|
|
visualEffectView.removeFromSuperview()
|
2021-04-09 14:04:12 +02:00
|
|
|
disposeBag.removeAll()
|
2021-04-01 14:54:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
override init(frame: CGRect) {
|
|
|
|
super.init(frame: .zero)
|
|
|
|
configure()
|
|
|
|
}
|
|
|
|
|
|
|
|
required init?(coder: NSCoder) {
|
|
|
|
super.init(coder: coder)
|
|
|
|
configure()
|
|
|
|
}
|
2021-06-22 11:30:42 +02:00
|
|
|
|
|
|
|
override var isHighlighted: Bool {
|
|
|
|
didSet {
|
|
|
|
contentView.alpha = isHighlighted ? 0.8 : 1.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-01 14:54:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
extension SearchRecommendAccountsCollectionViewCell {
|
2021-04-08 07:30:32 +02:00
|
|
|
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
|
|
|
super.traitCollectionDidChange(previousTraitCollection)
|
|
|
|
headerImageView.layer.borderColor = Asset.Colors.Border.searchCard.color.cgColor
|
|
|
|
applyShadow(color: Asset.Colors.Shadow.searchCard.color, alpha: 0.1, x: 0, y: 3, blur: 12, spread: 0)
|
|
|
|
}
|
2021-04-21 11:58:56 +02:00
|
|
|
|
2021-04-01 14:54:57 +02:00
|
|
|
private func configure() {
|
2021-04-07 08:44:58 +02:00
|
|
|
headerImageView.backgroundColor = Asset.Colors.brandBlue.color
|
2021-04-08 07:30:32 +02:00
|
|
|
layer.cornerRadius = 10
|
2021-04-13 07:06:35 +02:00
|
|
|
layer.cornerCurve = .continuous
|
2021-04-08 07:30:32 +02:00
|
|
|
clipsToBounds = false
|
|
|
|
applyShadow(color: Asset.Colors.Shadow.searchCard.color, alpha: 0.1, x: 0, y: 3, blur: 12, spread: 0)
|
2021-04-01 14:54:57 +02:00
|
|
|
|
2021-04-19 05:41:50 +02:00
|
|
|
headerImageView.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
contentView.addSubview(headerImageView)
|
|
|
|
NSLayoutConstraint.activate([
|
|
|
|
headerImageView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 16),
|
|
|
|
headerImageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
|
|
|
|
headerImageView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
|
|
|
|
headerImageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
|
2021-04-01 14:54:57 +02:00
|
|
|
])
|
|
|
|
|
2021-04-19 05:41:50 +02:00
|
|
|
let containerStackView = UIStackView()
|
|
|
|
containerStackView.axis = .vertical
|
|
|
|
containerStackView.distribution = .fill
|
|
|
|
containerStackView.alignment = .center
|
|
|
|
containerStackView.spacing = 6
|
|
|
|
containerStackView.layoutMargins = UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16)
|
|
|
|
containerStackView.isLayoutMarginsRelativeArrangement = true
|
|
|
|
containerStackView.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
|
|
|
|
contentView.addSubview(containerStackView)
|
|
|
|
NSLayoutConstraint.activate([
|
|
|
|
containerStackView.topAnchor.constraint(equalTo: contentView.topAnchor),
|
|
|
|
containerStackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
|
|
|
|
containerStackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
|
2021-04-01 14:54:57 +02:00
|
|
|
])
|
|
|
|
|
2021-04-19 05:41:50 +02:00
|
|
|
avatarImageView.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
contentView.addSubview(avatarImageView)
|
|
|
|
NSLayoutConstraint.activate([
|
|
|
|
avatarImageView.widthAnchor.constraint(equalToConstant: 88),
|
|
|
|
avatarImageView.heightAnchor.constraint(equalToConstant: 88)
|
2021-04-01 14:54:57 +02:00
|
|
|
])
|
2021-04-19 05:41:50 +02:00
|
|
|
containerStackView.addArrangedSubview(avatarImageView)
|
|
|
|
containerStackView.setCustomSpacing(20, after: avatarImageView)
|
|
|
|
displayNameLabel.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
containerStackView.addArrangedSubview(displayNameLabel)
|
|
|
|
containerStackView.setCustomSpacing(0, after: displayNameLabel)
|
|
|
|
|
|
|
|
acctLabel.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
containerStackView.addArrangedSubview(acctLabel)
|
|
|
|
containerStackView.setCustomSpacing(7, after: acctLabel)
|
2021-04-01 14:54:57 +02:00
|
|
|
|
2021-04-19 05:41:50 +02:00
|
|
|
followButton.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
containerStackView.addArrangedSubview(followButton)
|
|
|
|
NSLayoutConstraint.activate([
|
2021-04-19 11:00:51 +02:00
|
|
|
followButton.widthAnchor.constraint(greaterThanOrEqualToConstant: 76),
|
|
|
|
followButton.heightAnchor.constraint(greaterThanOrEqualToConstant: 24)
|
2021-04-01 14:54:57 +02:00
|
|
|
])
|
2021-04-19 05:41:50 +02:00
|
|
|
containerStackView.addArrangedSubview(followButton)
|
2021-04-01 14:54:57 +02:00
|
|
|
}
|
|
|
|
|
2021-04-09 07:59:33 +02:00
|
|
|
func config(with mastodonUser: MastodonUser) {
|
2021-06-29 13:27:40 +02:00
|
|
|
displayNameLabel.configure(content: mastodonUser.displayNameWithFallback, emojiDict: mastodonUser.emojiDict)
|
2021-04-19 05:41:50 +02:00
|
|
|
acctLabel.text = "@" + mastodonUser.acct
|
2021-04-01 14:54:57 +02:00
|
|
|
avatarImageView.af.setImage(
|
2021-04-09 07:59:33 +02:00
|
|
|
withURL: URL(string: mastodonUser.avatar)!,
|
2021-04-01 14:54:57 +02:00
|
|
|
placeholderImage: UIImage.placeholder(color: .systemFill),
|
|
|
|
imageTransition: .crossDissolve(0.2)
|
|
|
|
)
|
|
|
|
headerImageView.af.setImage(
|
2021-04-09 07:59:33 +02:00
|
|
|
withURL: URL(string: mastodonUser.header)!,
|
2021-04-01 14:54:57 +02:00
|
|
|
placeholderImage: UIImage.placeholder(color: .systemFill),
|
2021-04-09 13:39:35 +02:00
|
|
|
imageTransition: .crossDissolve(0.2)
|
|
|
|
) { [weak self] _ in
|
2021-04-08 07:30:32 +02:00
|
|
|
guard let self = self else { return }
|
|
|
|
self.headerImageView.addSubview(self.visualEffectView)
|
2021-04-19 05:41:50 +02:00
|
|
|
self.visualEffectView.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
NSLayoutConstraint.activate([
|
|
|
|
self.visualEffectView.topAnchor.constraint(equalTo: self.headerImageView.topAnchor),
|
|
|
|
self.visualEffectView.leadingAnchor.constraint(equalTo: self.headerImageView.leadingAnchor),
|
|
|
|
self.visualEffectView.trailingAnchor.constraint(equalTo: self.headerImageView.trailingAnchor),
|
|
|
|
self.visualEffectView.bottomAnchor.constraint(equalTo: self.headerImageView.bottomAnchor)
|
|
|
|
])
|
2021-04-08 07:30:32 +02:00
|
|
|
}
|
2021-04-09 13:39:35 +02:00
|
|
|
delegate?.configFollowButton(with: mastodonUser, followButton: followButton)
|
|
|
|
followButton.publisher(for: .touchUpInside)
|
|
|
|
.sink { [weak self] _ in
|
|
|
|
self?.followButtonDidPressed(mastodonUser: mastodonUser)
|
2021-04-09 07:59:33 +02:00
|
|
|
}
|
|
|
|
.store(in: &disposeBag)
|
|
|
|
}
|
|
|
|
|
2021-04-09 13:39:35 +02:00
|
|
|
func followButtonDidPressed(mastodonUser: MastodonUser) {
|
|
|
|
delegate?.followButtonDidPressed(clickedUser: mastodonUser)
|
2021-04-09 07:59:33 +02:00
|
|
|
}
|
2021-04-01 14:54:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#if canImport(SwiftUI) && DEBUG
|
|
|
|
import SwiftUI
|
|
|
|
|
|
|
|
struct SearchRecommendAccountsCollectionViewCell_Previews: PreviewProvider {
|
|
|
|
static var controls: some View {
|
|
|
|
Group {
|
2021-04-02 06:10:12 +02:00
|
|
|
UIViewPreview {
|
2021-04-01 14:54:57 +02:00
|
|
|
let cell = SearchRecommendAccountsCollectionViewCell()
|
|
|
|
cell.avatarImageView.backgroundColor = .white
|
|
|
|
cell.headerImageView.backgroundColor = .red
|
|
|
|
cell.displayNameLabel.text = "sunxiaojian"
|
|
|
|
cell.acctLabel.text = "sunxiaojian@mastodon.online"
|
|
|
|
return cell
|
|
|
|
}
|
|
|
|
.previewLayout(.fixed(width: 257, height: 202))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static var previews: some View {
|
|
|
|
Group {
|
|
|
|
controls.colorScheme(.light)
|
|
|
|
controls.colorScheme(.dark)
|
|
|
|
}
|
|
|
|
.background(Color.gray)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|