Files
suixinkan_uikit/suixinkan/UI/Login/AccountSelectionViewController.swift

340 lines
12 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// AccountSelectionViewController.swift
// suixinkan
//
import SnapKit
import UIKit
private typealias AccountSelectionSection = Int
private typealias AccountSelectionItem = String
/// /
final class AccountSelectionViewController: UIViewController, UITableViewDelegate {
private let payload: AccountSelectionPayload
private var isLoading: Bool
private let onCancel: () -> Void
private let onConfirm: (AccountSwitchAccount) -> Void
private var selectedAccountId: String?
private let tableView = UITableView(frame: .zero, style: .plain)
private var tableDataSource: UITableViewDiffableDataSource<AccountSelectionSection, AccountSelectionItem>!
private let confirmButton = UIButton(type: .system)
private let bottomBar = UIView()
init(
payload: AccountSelectionPayload,
isLoading: Bool,
onCancel: @escaping () -> Void,
onConfirm: @escaping (AccountSwitchAccount) -> Void
) {
self.payload = payload
self.isLoading = isLoading
self.onCancel = onCancel
self.onConfirm = onConfirm
super.init(nibName: nil, bundle: nil)
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
title = "选择账号"
view.backgroundColor = UIColor(hex: 0xF5F7FB)
navigationItem.leftBarButtonItem = UIBarButtonItem(
title: "取消",
style: .plain,
target: self,
action: #selector(cancelTapped)
)
isModalInPresentation = isLoading
selectedAccountId = payload.accounts.first?.id
configureTableView()
configureTableDataSource()
configureBottomBar()
}
/// Loading
func updateLoading(_ loading: Bool) {
isLoading = loading
isModalInPresentation = loading
confirmButton.isEnabled = canConfirm
confirmButton.backgroundColor = canConfirm ? AppColor.primary : AppColor.buttonDisabled
}
private var selectedAccount: AccountSwitchAccount? {
payload.accounts.first { $0.id == selectedAccountId }
}
private var canConfirm: Bool {
selectedAccount != nil && !isLoading
}
private func configureTableDataSource() {
tableDataSource = UITableViewDiffableDataSource<AccountSelectionSection, AccountSelectionItem>(
tableView: tableView
) { [weak self] tableView, indexPath, item in
guard let self,
let cell = tableView.dequeueReusableCell(
withIdentifier: AccountSelectionCell.reuseIdentifier,
for: indexPath
) as? AccountSelectionCell,
let account = self.payload.accounts.first(where: { $0.id == item }) else {
return UITableViewCell()
}
cell.configure(account: account, selected: account.id == self.selectedAccountId)
return cell
}
applyTableSnapshot(animated: false)
}
private func buildTableSnapshot() -> NSDiffableDataSourceSnapshot<AccountSelectionSection, AccountSelectionItem> {
var snapshot = NSDiffableDataSourceSnapshot<AccountSelectionSection, AccountSelectionItem>()
snapshot.appendSections([0])
snapshot.appendItems(payload.accounts.map(\.id), toSection: 0)
return snapshot
}
private func applyTableSnapshot(animated: Bool = true, reconfigure: Bool = false) {
var snapshot = buildTableSnapshot()
if reconfigure, !snapshot.itemIdentifiers.isEmpty {
snapshot.reconfigureItems(snapshot.itemIdentifiers)
}
tableDataSource.apply(snapshot, animatingDifferences: animated)
}
private func configureTableView() {
tableView.backgroundColor = .clear
tableView.separatorStyle = .none
tableView.contentInset = UIEdgeInsets(top: 10, left: 0, bottom: 10, right: 0)
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 92
tableView.delegate = self
tableView.register(AccountSelectionCell.self, forCellReuseIdentifier: AccountSelectionCell.reuseIdentifier)
view.addSubview(tableView)
tableView.snp.makeConstraints { make in
make.top.leading.trailing.equalToSuperview()
make.bottom.equalTo(view.safeAreaLayoutGuide).inset(90)
}
}
private func configureBottomBar() {
bottomBar.backgroundColor = .white
let divider = UIView()
divider.backgroundColor = UIColor.separator
confirmButton.setTitle("进入系统", for: .normal)
confirmButton.titleLabel?.font = .systemFont(ofSize: 16, weight: .semibold)
confirmButton.setTitleColor(.white, for: .normal)
confirmButton.layer.cornerRadius = 8
confirmButton.addTarget(self, action: #selector(confirmTapped), for: .touchUpInside)
updateLoading(isLoading)
view.addSubview(bottomBar)
bottomBar.addSubview(divider)
bottomBar.addSubview(confirmButton)
bottomBar.snp.makeConstraints { make in
make.leading.trailing.bottom.equalToSuperview()
}
divider.snp.makeConstraints { make in
make.top.leading.trailing.equalToSuperview()
make.height.equalTo(0.5)
}
confirmButton.snp.makeConstraints { make in
make.top.equalTo(divider.snp.bottom).offset(12)
make.leading.trailing.equalToSuperview().inset(16)
make.bottom.equalTo(view.safeAreaLayoutGuide).inset(14)
make.height.equalTo(50)
}
}
@objc private func cancelTapped() {
onCancel()
dismiss(animated: true)
}
@objc private func confirmTapped() {
guard let selectedAccount else { return }
onConfirm(selectedAccount)
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
guard let item = tableDataSource.itemIdentifier(for: indexPath) else { return }
selectedAccountId = item
applyTableSnapshot(animated: false, reconfigure: true)
confirmButton.isEnabled = canConfirm
confirmButton.backgroundColor = canConfirm ? AppColor.primary : AppColor.buttonDisabled
}
}
/// Cell
private final class AccountSelectionCell: UITableViewCell {
static let reuseIdentifier = "AccountSelectionCell"
private let card = UIView()
private let avatarView = UIImageView()
private let avatarPlaceholderLabel = UILabel()
private let titleLabel = UILabel()
private let subtitleLabel = UILabel()
private let nameLabel = UILabel()
private let typeTag = UILabel()
private let currentTag = UILabel()
private let checkmark = UIImageView()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
selectionStyle = .none
backgroundColor = .clear
contentView.backgroundColor = .clear
card.backgroundColor = .white
card.layer.cornerRadius = 10
card.layer.masksToBounds = true
avatarView.clipsToBounds = true
avatarView.layer.cornerRadius = 25
avatarView.contentMode = .scaleAspectFill
avatarPlaceholderLabel.font = .systemFont(ofSize: 14, weight: .semibold)
avatarPlaceholderLabel.textAlignment = .center
titleLabel.font = .systemFont(ofSize: 16, weight: .semibold)
titleLabel.textColor = AppColor.text333
subtitleLabel.font = .systemFont(ofSize: 13)
subtitleLabel.textColor = AppColor.text666
nameLabel.font = .systemFont(ofSize: 12)
nameLabel.textColor = UIColor(hex: 0x9AA1AA)
typeTag.font = .systemFont(ofSize: 11, weight: .semibold)
typeTag.textAlignment = .center
typeTag.layer.cornerRadius = 4
typeTag.clipsToBounds = true
typeTag.setContentCompressionResistancePriority(.required, for: .horizontal)
currentTag.font = .systemFont(ofSize: 11, weight: .semibold)
currentTag.textAlignment = .center
currentTag.text = "当前"
currentTag.textColor = AppColor.primary
currentTag.backgroundColor = AppColor.secondaryButtonBackground
currentTag.layer.cornerRadius = 4
currentTag.clipsToBounds = true
currentTag.isHidden = true
checkmark.contentMode = .scaleAspectFit
contentView.addSubview(card)
card.addSubview(avatarView)
avatarView.addSubview(avatarPlaceholderLabel)
card.addSubview(titleLabel)
card.addSubview(subtitleLabel)
card.addSubview(nameLabel)
card.addSubview(typeTag)
card.addSubview(currentTag)
card.addSubview(checkmark)
card.snp.makeConstraints { make in
make.edges.equalToSuperview().inset(UIEdgeInsets(top: 6, left: 16, bottom: 6, right: 16))
}
avatarView.snp.makeConstraints { make in
make.leading.equalToSuperview().inset(16)
make.centerY.equalToSuperview()
make.width.height.equalTo(50)
}
avatarPlaceholderLabel.snp.makeConstraints { make in
make.center.equalToSuperview()
}
titleLabel.snp.makeConstraints { make in
make.top.equalToSuperview().inset(16)
make.leading.equalTo(avatarView.snp.trailing).offset(12)
make.trailing.lessThanOrEqualTo(typeTag.snp.leading).offset(-8)
}
currentTag.snp.makeConstraints { make in
make.leading.equalTo(titleLabel.snp.trailing).offset(6)
make.trailing.lessThanOrEqualTo(typeTag.snp.leading).offset(-8)
make.centerY.equalTo(titleLabel)
make.height.equalTo(18)
}
subtitleLabel.snp.makeConstraints { make in
make.top.equalTo(titleLabel.snp.bottom).offset(4)
make.leading.equalTo(titleLabel)
make.trailing.equalTo(checkmark.snp.leading).offset(-8)
}
nameLabel.snp.makeConstraints { make in
make.top.equalTo(subtitleLabel.snp.bottom).offset(4)
make.leading.equalTo(titleLabel)
make.bottom.equalToSuperview().inset(16)
}
typeTag.snp.makeConstraints { make in
make.trailing.equalTo(checkmark.snp.leading).offset(-8)
make.top.equalTo(titleLabel)
make.height.equalTo(18)
}
checkmark.snp.makeConstraints { make in
make.trailing.equalToSuperview().inset(16)
make.centerY.equalToSuperview()
make.width.height.equalTo(22)
}
}
required init?(coder: NSCoder) {
nil
}
func configure(account: AccountSwitchAccount, selected: Bool) {
titleLabel.text = account.title.isEmpty ? account.accountTypeLabel : account.title
subtitleLabel.text = account.subtitle
subtitleLabel.isHidden = account.subtitle.isEmpty
nameLabel.text = account.realName
nameLabel.isHidden = account.realName.isEmpty
currentTag.isHidden = !account.isCurrent
let avatarPlaceholderColor: UIColor
let avatarTextColor: UIColor
if account.isStoreUser {
avatarPlaceholderColor = UIColor(hex: 0xE8F8F1)
avatarTextColor = UIColor(hex: 0x0F9F6E)
avatarPlaceholderLabel.text = ""
typeTag.text = " 门店 "
typeTag.textColor = UIColor(hex: 0x0F9F6E)
typeTag.backgroundColor = UIColor(hex: 0xE8F8F1)
} else {
avatarPlaceholderColor = UIColor(hex: 0xF3ECFF)
avatarTextColor = UIColor(hex: 0x7C3AED)
avatarPlaceholderLabel.text = ""
typeTag.text = " 景区 "
typeTag.textColor = UIColor(hex: 0x7C3AED)
typeTag.backgroundColor = UIColor(hex: 0xF3ECFF)
}
avatarPlaceholderLabel.textColor = avatarTextColor
avatarPlaceholderLabel.isHidden = !account.avatar.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
avatarView.loadRemoteImage(urlString: account.avatar, placeholderColor: avatarPlaceholderColor)
let symbolName = selected ? "checkmark.circle.fill" : "circle"
checkmark.image = UIImage(systemName: symbolName)
checkmark.tintColor = selected ? AppColor.primary : UIColor(hex: 0xB6BECA)
card.layer.borderWidth = selected ? 1.4 : 1
card.layer.borderColor = (selected ? AppColor.primary : UIColor(hex: 0xE6ECF4)).cgColor
}
}