165 lines
5.8 KiB
Swift
165 lines
5.8 KiB
Swift
//
|
||
// AppRestrictCell.swift
|
||
// QuickLocation
|
||
//
|
||
|
||
import FamilyControls
|
||
import UIKit
|
||
import ManagedSettings
|
||
|
||
@available(iOS 16.0, *)
|
||
final class AppRestrictCell: UITableViewCell {
|
||
static let reuseId = "AppRestrictCell"
|
||
|
||
private enum Metric {
|
||
static let appIcon: CGFloat = 40
|
||
static let linkIcon: CGFloat = 28
|
||
static let actionWidth: CGFloat = 48
|
||
static let actionHeight: CGFloat = 56
|
||
/// divider 右侧:8 + 48 + 8 + 48 + 12
|
||
static let actionAreaWidth: CGFloat = 124
|
||
}
|
||
|
||
var onPair: (() -> Void)?
|
||
var onDelete: (() -> Void)?
|
||
|
||
private let systemIconHost = UIView()
|
||
private let linkIconView = UIImageView()
|
||
private let catalogIconView = UIImageView()
|
||
private let placeholderView = UIView()
|
||
private let placeholderLab = UILabel()
|
||
|
||
private let divider = UIView()
|
||
private let pairBtn = UIButton(type: .custom)
|
||
private let deleteBtn = UIButton(type: .custom)
|
||
|
||
private var systemTokenHost: ApplicationTokenIconHostingView?
|
||
|
||
override init(style: CellStyle, reuseIdentifier: String?) {
|
||
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||
selectionStyle = .none
|
||
backgroundColor = .clear
|
||
contentView.backgroundColor = .clear
|
||
setup()
|
||
}
|
||
|
||
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
|
||
|
||
private func setup() {
|
||
contentView.addSubview(systemIconHost)
|
||
contentView.addSubview(linkIconView)
|
||
contentView.addSubview(catalogIconView)
|
||
contentView.addSubview(placeholderView)
|
||
contentView.addSubview(divider)
|
||
contentView.addSubview(pairBtn)
|
||
contentView.addSubview(deleteBtn)
|
||
|
||
systemIconHost.clipsToBounds = true
|
||
systemIconHost.layer.cornerRadius = 10
|
||
systemIconHost.layoutChain
|
||
.left(16)
|
||
.centerY()
|
||
.width(Metric.appIcon)
|
||
.height(Metric.appIcon)
|
||
|
||
linkIconView.contentMode = .scaleAspectFit
|
||
linkIconView.layoutChain
|
||
.leftToRightOfView(systemIconHost, offset: 12)
|
||
.centerY()
|
||
.width(Metric.linkIcon)
|
||
.height(Metric.linkIcon)
|
||
|
||
catalogIconView.contentMode = .scaleAspectFill
|
||
catalogIconView.layer.cornerRadius = 10
|
||
catalogIconView.clipsToBounds = true
|
||
catalogIconView.layoutChain
|
||
.leftToRightOfView(linkIconView, offset: 12)
|
||
.centerY()
|
||
.width(Metric.appIcon)
|
||
.height(Metric.appIcon)
|
||
|
||
placeholderView.backgroundColor = UIColor(hexStr: "#F3F4F6")
|
||
placeholderView.layer.cornerRadius = Metric.appIcon / 2
|
||
placeholderView.layer.borderWidth = 1
|
||
placeholderView.layer.borderColor = UIColor(hexStr: "#E5E7EB").cgColor
|
||
placeholderView.layoutChain
|
||
.leftToRightOfView(linkIconView, offset: 12)
|
||
.centerY()
|
||
.width(Metric.appIcon)
|
||
.height(Metric.appIcon)
|
||
placeholderView.addSubview(placeholderLab)
|
||
placeholderLab.text = "?"
|
||
placeholderLab.font = .systemFont(ofSize: 18, weight: .bold)
|
||
placeholderLab.textColor = UIColor(hexStr: "#9CA3AF")
|
||
placeholderLab.textAlignment = .center
|
||
placeholderLab.layoutChain.center()
|
||
|
||
divider.backgroundColor = UIColor(hexStr: "#F0F0F0")
|
||
divider.layoutChain
|
||
.right(Metric.actionAreaWidth)
|
||
.width(1)
|
||
.top(12)
|
||
.bottom(12)
|
||
|
||
configureActionButton(pairBtn, imageName: "AppRestrict/pair_action_link", title: "配对", color: UIColor(hexStr: "#00ADFE"))
|
||
configureActionButton(deleteBtn, imageName: "AppRestrict/pair_action_delete", title: "删除", color: UIColor(hexStr: "#FF2323"))
|
||
pairBtn.addTarget(self, action: #selector(tapPair), for: .touchUpInside)
|
||
deleteBtn.addTarget(self, action: #selector(tapDelete), for: .touchUpInside)
|
||
|
||
pairBtn.layoutChain
|
||
.leftToRightOfView(divider, offset: 8)
|
||
.centerY()
|
||
.width(Metric.actionWidth)
|
||
.height(Metric.actionHeight)
|
||
|
||
deleteBtn.layoutChain
|
||
.leftToRightOfView(pairBtn, offset: 8)
|
||
.centerY()
|
||
.width(Metric.actionWidth)
|
||
.height(Metric.actionHeight)
|
||
}
|
||
|
||
override func layoutSubviews() {
|
||
super.layoutSubviews()
|
||
pairBtn.setImageEdge(.top, spacing: 4)
|
||
deleteBtn.setImageEdge(.top, spacing: 4)
|
||
}
|
||
|
||
private func configureActionButton(_ button: UIButton, imageName: String, title: String, color: UIColor) {
|
||
button.setImage(UIImage(named: imageName)?.withRenderingMode(.alwaysOriginal), for: .normal)
|
||
button.setTitle(title, for: .normal)
|
||
button.setTitleColor(color, for: .normal)
|
||
button.titleLabel?.font = .systemFont(ofSize: 12, weight: .medium)
|
||
button.titleLabel?.textAlignment = .center
|
||
button.titleLabel?.lineBreakMode = .byClipping
|
||
}
|
||
|
||
func configure(token: ApplicationToken, catalog: AppCatalogItem?) {
|
||
systemTokenHost?.subviews.forEach { $0.removeFromSuperview() }
|
||
let host = ApplicationTokenIconHostingView(token: token)
|
||
systemIconHost.addSubview(host)
|
||
host.layoutChain.edges()
|
||
systemTokenHost = host
|
||
|
||
let isPaired = catalog != nil
|
||
linkIconView.image = UIImage(named: isPaired ? "AppRestrict/pair_link_active" : "AppRestrict/pair_link_inactive")?
|
||
.withRenderingMode(.alwaysOriginal)
|
||
|
||
catalogIconView.isHidden = !isPaired
|
||
placeholderView.isHidden = isPaired
|
||
if let catalog {
|
||
AppCatalogStore.setIcon(for: catalogIconView, item: catalog, cornerRadius: 10)
|
||
} else {
|
||
catalogIconView.image = nil
|
||
}
|
||
}
|
||
|
||
@objc private func tapPair() {
|
||
onPair?()
|
||
}
|
||
|
||
@objc private func tapDelete() {
|
||
onDelete?()
|
||
}
|
||
}
|