405 lines
12 KiB
Swift
405 lines
12 KiB
Swift
//
|
||
// MineView.swift
|
||
// QuickLocation
|
||
//
|
||
// Created based on Lanhu design: 我的·版本6 / 照片墙改版
|
||
//
|
||
|
||
import UIKit
|
||
import RxSwift
|
||
import RxCocoa
|
||
|
||
final class MineView: UIView {
|
||
|
||
var disposeBag = DisposeBag()
|
||
|
||
private let vipCardHeight: CGFloat = 90
|
||
private let settingsRowHeight: CGFloat = 52
|
||
private let quickItemTitles = ["权限检测", "数据安全", "状态设置", "隐私设置"]
|
||
|
||
var onQuickTap: ((String) -> Void)?
|
||
|
||
func setupData(_ model: UserConfigModel) {
|
||
guard AppContextManager.shared.systemConfig?.isIntercept == false else {
|
||
maskBgView.isHidden = false
|
||
return
|
||
}
|
||
maskBgView.isHidden = true
|
||
guard model.vip > 1 else {
|
||
vipTitleLab.text = "开通会员"
|
||
vipContentLab.text = "会员尊享10+VIP特权"
|
||
vipActivateButton.isHidden = false
|
||
vipActivateButton.setTitle("立即开通", for: .normal)
|
||
return
|
||
}
|
||
vipTitleLab.text = model.vip_name
|
||
vipContentLab.text = model.vip == 3 ? "会员终身有效"
|
||
: "会员到期:\(self.getDateInterval2String(date: model.vip_expire_time, dateFormat: "yyyy.MM.dd"))"
|
||
vipActivateButton.setTitle("点击续费", for: .normal)
|
||
vipActivateButton.isHidden = model.vip == 3
|
||
}
|
||
|
||
// MARK: - Components
|
||
|
||
private lazy var scrollView: UIScrollView = {
|
||
let sv = UIScrollView()
|
||
sv.backgroundColor = UIColor(hexStr: "#FAFAFA")
|
||
sv.showsVerticalScrollIndicator = false
|
||
// sv.alwaysBounceVertical = true
|
||
return sv
|
||
}()
|
||
|
||
private lazy var contentView: UIView = {
|
||
let v = UIView()
|
||
v.backgroundColor = .clear
|
||
return v
|
||
}()
|
||
|
||
private lazy var headerBgView: UIView = {
|
||
let v = UIView()
|
||
v.backgroundColor = .clear
|
||
return v
|
||
}()
|
||
|
||
lazy var photoWall: MinePhotoWallView = {
|
||
MinePhotoWallView()
|
||
}()
|
||
|
||
lazy var vipCardView: UIView = {
|
||
let view = UIView()
|
||
view.layer.cornerRadius = 16
|
||
view.clipsToBounds = true
|
||
return view
|
||
}()
|
||
|
||
lazy var vipCardBgImageView: UIImageView = {
|
||
let iv = UIImageView()
|
||
iv.image = UIImage(named: "Mine/vip_card")
|
||
iv.contentMode = .scaleToFill
|
||
return iv
|
||
}()
|
||
|
||
lazy var maskBgView: UIImageView = {
|
||
let iv = UIImageView()
|
||
iv.image = UIImage(named: "Mine/mask_bg")
|
||
iv.contentMode = .scaleToFill
|
||
iv.isHidden = true
|
||
return iv
|
||
}()
|
||
|
||
lazy var vipTitleLab: UILabel = {
|
||
let label = UILabel()
|
||
label.font = FontManager.boboBold(18)
|
||
label.textColor = .white
|
||
label.text = " "
|
||
return label
|
||
}()
|
||
|
||
lazy var vipContentLab: UILabel = {
|
||
let label = UILabel()
|
||
label.font = .systemFont(ofSize: 12, weight: .medium)
|
||
label.textColor = .white
|
||
label.text = " "
|
||
return label
|
||
}()
|
||
|
||
lazy var vipActivateButton: UIButton = {
|
||
let btn = UIButton(type: .custom)
|
||
btn.backgroundColor = UIColor(hexStr: "#C0FF54")
|
||
btn.setTitle("立即开通", for: .normal)
|
||
btn.setTitleColor(UIColor(hexStr: "#00343B"), for: .normal)
|
||
btn.titleLabel?.font = FontManager.boboBold(14)
|
||
btn.cornerRadius = 9
|
||
btn.isHidden = true
|
||
return btn
|
||
}()
|
||
|
||
private lazy var quickCardView: UIView = {
|
||
let v = UIView()
|
||
v.backgroundColor = .white
|
||
v.cornerRadius = 20
|
||
return v
|
||
}()
|
||
|
||
private lazy var quickStack: UIStackView = {
|
||
let stack = UIStackView()
|
||
stack.axis = .horizontal
|
||
stack.distribution = .fillEqually
|
||
stack.alignment = .center
|
||
return stack
|
||
}()
|
||
|
||
private lazy var settingsCardView: UIView = {
|
||
let view = UIView()
|
||
view.backgroundColor = .white
|
||
view.layer.cornerRadius = 12
|
||
view.layer.shadowColor = UIColor(red: 0.898, green: 0.898, blue: 0.898, alpha: 0.3).cgColor
|
||
view.layer.shadowOffset = .zero
|
||
view.layer.shadowRadius = 4
|
||
view.layer.shadowOpacity = 1
|
||
return view
|
||
}()
|
||
|
||
lazy var settingsTableView: UITableView = {
|
||
let tv = UITableView(frame: .zero, style: .plain)
|
||
tv.backgroundColor = .clear
|
||
tv.isScrollEnabled = false
|
||
tv.separatorStyle = .none
|
||
tv.register(MineMenuCell.self)
|
||
tv.rowHeight = settingsRowHeight
|
||
tv.estimatedRowHeight = settingsRowHeight
|
||
return tv
|
||
}()
|
||
|
||
private var settingsCardHeightConstraint: NSLayoutConstraint?
|
||
private var contentSizeObservation: NSKeyValueObservation?
|
||
|
||
// 兼容旧绑定(已迁到 photoWall)
|
||
lazy var avatarImageView: UIImageView = UIImageView()
|
||
lazy var nameLabel: UILabel = UILabel()
|
||
lazy var idLabel: UILabel = UILabel()
|
||
lazy var editButton: UIButton = UIButton(type: .custom)
|
||
lazy var copyButton: UIButton = UIButton(type: .custom)
|
||
|
||
override init(frame: CGRect) {
|
||
super.init(frame: frame)
|
||
setupUI()
|
||
setupLayout()
|
||
setupQuickActions()
|
||
}
|
||
|
||
required init?(coder: NSCoder) {
|
||
fatalError("init(coder:) has not been implemented")
|
||
}
|
||
|
||
private func setupUI() {
|
||
backgroundColor = UIColor(hexStr: "#FAFAFA")
|
||
|
||
addSubview(scrollView)
|
||
scrollView.addSubview(contentView)
|
||
contentView.addSubview(headerBgView)
|
||
|
||
// 照片墙固定顶部,不随列表滚动
|
||
addSubview(photoWall)
|
||
|
||
contentView.addSubview(vipCardView)
|
||
vipCardView.addSubview(vipCardBgImageView)
|
||
vipCardView.addSubview(vipActivateButton)
|
||
vipCardView.addSubview(vipTitleLab)
|
||
vipCardView.addSubview(vipContentLab)
|
||
vipCardView.addSubview(maskBgView)
|
||
|
||
contentView.addSubview(quickCardView)
|
||
quickCardView.addSubview(quickStack)
|
||
|
||
contentView.addSubview(settingsCardView)
|
||
settingsCardView.addSubview(settingsTableView)
|
||
}
|
||
|
||
private func setupLayout() {
|
||
photoWall.layoutChain
|
||
.top(40)
|
||
.edgesHorzontal()
|
||
|
||
scrollView.layoutChain
|
||
.topToBottomOfView(photoWall)
|
||
.edgesHorzontal()
|
||
.bottom()
|
||
|
||
contentView.layoutChain
|
||
.edges()
|
||
.widthToView(scrollView)
|
||
|
||
vipCardView.layoutChain
|
||
.top(12)
|
||
.left(16).right(16)
|
||
.height(vipCardHeight)
|
||
|
||
vipCardBgImageView.layoutChain.edges()
|
||
|
||
vipTitleLab.layoutChain
|
||
.top(22)
|
||
.left(77)
|
||
|
||
vipContentLab.layoutChain
|
||
.topToBottomOfView(vipTitleLab, offset: 6)
|
||
.leftToView(vipTitleLab)
|
||
|
||
vipActivateButton.layoutChain
|
||
.right(19).centerY()
|
||
.width(70).height(28)
|
||
|
||
maskBgView.layoutChain.edges()
|
||
|
||
quickCardView.layoutChain
|
||
.topToBottomOfView(vipCardView, offset: 20)
|
||
.left(16).right(16)
|
||
.height(90)
|
||
|
||
quickStack.layoutChain
|
||
.edges(all: 8)
|
||
|
||
settingsCardView.layoutChain
|
||
.topToBottomOfView(quickCardView, offset: 16)
|
||
.left(16).right(16)
|
||
.bottom(20)
|
||
|
||
settingsCardHeightConstraint = settingsCardView.heightAnchor.constraint(equalToConstant: 208)
|
||
settingsCardHeightConstraint?.isActive = true
|
||
|
||
settingsTableView.layoutChain.edges()
|
||
|
||
contentSizeObservation = settingsTableView.observe(\.contentSize, options: [.new, .initial]) { [weak self] _, _ in
|
||
self?.refreshTableViewHeight()
|
||
}
|
||
}
|
||
|
||
private func setupQuickActions() {
|
||
let icons = [
|
||
"Mine/quick_permission",
|
||
"Mine/quick_data_security",
|
||
"Mine/quick_status",
|
||
"Mine/quick_privacy"
|
||
]
|
||
for (i, title) in quickItemTitles.enumerated() {
|
||
let item = makeQuickItem(icon: icons[i], title: title)
|
||
item.tag = i
|
||
item.rx.tapGesture
|
||
.subscribe(onNext: { [weak self] _ in
|
||
self?.onQuickTap?(title)
|
||
})
|
||
.disposed(by: disposeBag)
|
||
quickStack.addArrangedSubview(item)
|
||
}
|
||
}
|
||
|
||
private func makeQuickItem(icon: String, title: String) -> UIView {
|
||
let wrap = UIView()
|
||
wrap.isUserInteractionEnabled = true
|
||
let view = UIView()
|
||
view.backgroundColor = UIColor(hexStr: "#F3F5F8")
|
||
view.cornerRadius = 16
|
||
|
||
let iv = UIImageView(image: UIImage(named: icon))
|
||
iv.contentMode = .scaleAspectFill
|
||
view.addSubview(iv)
|
||
|
||
let lab = UILabel()
|
||
lab.text = title
|
||
lab.font = .systemFont(ofSize: 12, weight: .medium)
|
||
lab.textColor = UIColor(hexStr: "#293445")
|
||
lab.textAlignment = .center
|
||
wrap.addSubview(view)
|
||
wrap.addSubview(lab)
|
||
view.layoutChain
|
||
.top(8)
|
||
.centerX()
|
||
.width(40)
|
||
.height(40)
|
||
iv.layoutChain
|
||
.centerY()
|
||
.centerX()
|
||
.width(24)
|
||
.height(24)
|
||
lab.layoutChain
|
||
.topToBottomOfView(view, offset: 6)
|
||
.edgesHorzontal(2)
|
||
.bottom(4)
|
||
return wrap
|
||
}
|
||
|
||
override func layoutSubviews() {
|
||
super.layoutSubviews()
|
||
// 顶部淡色渐变氛围
|
||
setGradientLayer(
|
||
frame: CGRect(x: 0, y: 0, width: bounds.width, height: min(280, bounds.height * 0.35)),
|
||
startPoint: CGPoint(x: 0.5, y: 0),
|
||
endPoint: CGPoint(x: 0.5, y: 1),
|
||
colors: [UIColor(hexStr: "#D8F4FF"), UIColor(hexStr: "#FAFAFA")],
|
||
locations: [0, 1]
|
||
)
|
||
refreshTableViewHeight()
|
||
}
|
||
|
||
func refreshTableViewHeight() {
|
||
let contentHeight = settingsTableView.contentSize.height
|
||
guard contentHeight > 0 else { return }
|
||
settingsCardHeightConstraint?.constant = contentHeight
|
||
settingsTableView.isScrollEnabled = false
|
||
}
|
||
}
|
||
|
||
// MARK: - MineMenuCell
|
||
final class MineMenuCell: UITableViewCell {
|
||
|
||
func configure(_ model: MineMenuItem) {
|
||
iconImageView.image = UIImage(named: model.icon)
|
||
titleLabel.text = model.title
|
||
}
|
||
|
||
private func setupSubviews() {
|
||
contentView.addSubview(iconImageView)
|
||
contentView.addSubview(titleLabel)
|
||
contentView.addSubview(arrowImageView)
|
||
contentView.addSubview(dividerLine)
|
||
|
||
iconImageView.layoutChain
|
||
.left(14).centerY()
|
||
.size(CGSize(width: 24, height: 24))
|
||
|
||
titleLabel.layoutChain
|
||
.leftToRightOfView(iconImageView, offset: 8)
|
||
.centerY()
|
||
|
||
arrowImageView.layoutChain
|
||
.right(14).centerY()
|
||
.size(CGSize(width: 18, height: 18))
|
||
|
||
dividerLine.layoutChain
|
||
.left(14).right().bottom()
|
||
.height(0.5)
|
||
}
|
||
|
||
var showDivider: Bool = true {
|
||
didSet { dividerLine.isHidden = !showDivider }
|
||
}
|
||
|
||
private let iconImageView: UIImageView = {
|
||
let iv = UIImageView()
|
||
iv.contentMode = .scaleAspectFit
|
||
return iv
|
||
}()
|
||
|
||
private let titleLabel: UILabel = {
|
||
let label = UILabel()
|
||
label.font = UIFont(name: "PingFangSC-Medium", size: 14)
|
||
?? UIFont.systemFont(ofSize: 14, weight: .medium)
|
||
label.textColor = UIColor(hexStr: "#1A1A1A")
|
||
return label
|
||
}()
|
||
|
||
private let arrowImageView: UIImageView = {
|
||
let iv = UIImageView()
|
||
iv.contentMode = .scaleAspectFit
|
||
iv.image = UIImage(named: "Mine/arrow_right")
|
||
return iv
|
||
}()
|
||
|
||
private let dividerLine: UIView = {
|
||
let view = UIView()
|
||
view.backgroundColor = UIColor(hexStr: "#EDEDED")
|
||
return view
|
||
}()
|
||
|
||
override init(style: CellStyle, reuseIdentifier: String?) {
|
||
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||
backgroundColor = .clear
|
||
selectionStyle = .none
|
||
setupSubviews()
|
||
}
|
||
|
||
required init?(coder: NSCoder) {
|
||
fatalError("init(coder:) has not been implemented")
|
||
}
|
||
}
|