jsdw_ios/QuickLocation/Section/LockDistract/LockDistractView.swift

725 lines
23 KiB
Swift

//
// LockDistractView.swift
// QuickLocation
//
import UIKit
import RxSwift
import RxCocoa
final class LockDistractView: UIView {
var disposeBag = DisposeBag()
let lockIconNames = [
"LockDistract/lock_icon_1",
"LockDistract/lock_icon_2",
"LockDistract/lock_icon_3",
"LockDistract/lock_icon_4",
"LockDistract/lock_icon_5",
"LockDistract/lock_icon_6",
"LockDistract/lock_icon_7"
]
private(set) var selectedLockIconIndex = 0
private(set) var selectedAppIndexes: Set<Int> = []
private(set) var isLocked = false
private let copyMaxLength = 20
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = UIColor(hexStr: "#FAFAFA")
setupUI()
setupCopyLimit()
applyLockedState()
}
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
func configureMember(name: String, avatar: UIImage?) {
memberNameLab.text = name.isEmpty ? " " : name
memberAvatar.image = avatar ?? UIImage(named: "Common/default_avatar")
}
func setTodayLockCount(_ count: Int) {
todayCountLab.text = "\(count)"
}
func setGroupName(_ name: String) {
// let title = name.isEmpty ? "" : " \(name) "
// switchGroupBtn.setTitle(title, for: .normal)
let trimmedName = name.trimmingCharacters(in: .whitespacesAndNewlines)
var titleAttributes = AttributeContainer()
titleAttributes.font = .systemFont(ofSize: 12, weight: .medium)
var configuration = switchGroupBtn.configuration ?? UIButton.Configuration.plain()
configuration.attributedTitle = AttributedString(
trimmedName.isEmpty ? "当前圈子" : trimmedName,
attributes: titleAttributes
)
configuration.image = UIImage(named: "Home/group_name_icon")
configuration.imagePadding = 3
configuration.contentInsets = NSDirectionalEdgeInsets(
top: 0,
leading: 6,
bottom: 0,
trailing: 6
)
configuration.baseForegroundColor = UIColor(hexStr: "#293445")
switchGroupBtn.configuration = configuration
switchGroupBtn.titleLabel?.lineBreakMode = .byTruncatingTail
switchGroupBtn.sizeToFit()
}
func configureLocked(_ locked: Bool) {
isLocked = locked
applyLockedState()
}
private func applyLockedState() {
avatarLockView.isHidden = !isLocked
styleSectionTitle.isHidden = isLocked
styleCard.isHidden = isLocked
lockedEmptyView.isHidden = !isLocked
appCollectionView.reloadData()
tipLab.text = isLocked
? "已被锁定情况下,先解锁才能锁定哟~"
: "锁定功能只有在圈主的情况下才能使用哟~"
lockBtn.setTitle(isLocked ? "请求解锁" : "锁定", for: .normal)
}
private func setupUI() {
addSubview(scrollView)
scrollView.addSubview(contentView)
addSubview(navView)
navView.addRightButton(switchGroupBtn)
addSubview(footerBar)
footerBar.addSubview(tipRow)
footerBar.addSubview(lockBtn)
contentView.addSubview(navBgView)
contentView.addSubview(statsRow)
statsRow.addArrangedSubview(memberCard)
statsRow.addArrangedSubview(todayCard)
contentView.addSubview(appsSectionTitle)
contentView.addSubview(appsCard)
appsCard.addSubview(appsHeaderRow)
appsCard.addSubview(appCollectionView)
contentView.addSubview(bottomStack)
bottomStack.addArrangedSubview(styleSectionTitle)
bottomStack.addArrangedSubview(styleCard)
bottomStack.addArrangedSubview(lockedEmptyView)
navView.layoutChain
.edges(excludingEdge: .bottom)
.height(kNaviHeight)
footerBar.layoutChain
.edgesHorzontal()
.bottom()
lockBtn.layoutChain
.bottom(kSafeBottomMargin)
.edgesHorzontal(30)
.height(56)
tipRow.layoutChain
.centerX()
.bottomToTopOfView(lockBtn, offset: -8)
.top(10)
scrollView.layoutChain
.top()
.edgesHorzontal()
.bottomToTopOfView(footerBar)
contentView.layoutChain
.edges()
.widthToView(scrollView)
navBgView.layoutChain
.top()
.edgesHorzontal()
.heightToWidth(200.0 / 375.0)
statsRow.layoutChain
.topToBottomOfView(navBgView, offset: -48)
.edgesHorzontal(16)
.height(120)
appsSectionTitle.layoutChain
.topToBottomOfView(statsRow, offset: 22)
.left(20)
appsCard.layoutChain
.topToBottomOfView(appsSectionTitle, offset: 12)
.edgesHorzontal(16)
appsHeaderRow.layoutChain
.top(16)
.edgesHorzontal(14)
.height(28)
appCollectionView.layoutChain
.topToBottomOfView(appsHeaderRow, offset: 12)
.edgesHorzontal(8)
.height(78)
.bottom(16)
bottomStack.layoutChain
.topToBottomOfView(appsCard, offset: 22)
.edgesHorzontal(16)
.bottom(24)
styleSectionTitle.layoutChain.left(4)
lockedEmptyView.layoutChain
.centerX()
.height(180)
}
private func setupCopyLimit() {
copyTF.rx.text.orEmpty
.subscribe(onNext: { [weak self] text in
guard let self else { return }
if text.count > self.copyMaxLength {
self.copyTF.text = String(text.prefix(self.copyMaxLength))
}
let count = self.copyTF.text?.count ?? 0
self.copyCountLab.text = "\(count)/\(self.copyMaxLength)"
})
.disposed(by: disposeBag)
}
// MARK: - Views
lazy var navBgView: UIImageView = {
let iv = UIImageView()
iv.image = UIImage(named: "LockDistract/header_hero")
iv.contentMode = .scaleAspectFill
iv.clipsToBounds = true
return iv
}()
lazy var navView: BaseNavigationView = {
BaseNavigationView(title: "")
}()
lazy var footerBar: UIView = {
let view = UIView()
view.backgroundColor = UIColor(hexStr: "#FAFAFA")
return view
}()
lazy var switchGroupBtn: UIButton = {
let btn = UIButton(type: .custom)
btn.backgroundColor = .white.withAlphaComponent(0.92)
btn.setImage(UIImage(named: "Home/group_name_icon"), for: .normal)
btn.titleLabel?.font = .systemFont(ofSize: 12, weight: .medium)
btn.setTitleColor(UIColor(hexStr: "#293445"), for: .normal)
btn.cornerRadius = 8
btn.extendEdgeInsets = UIEdgeInsets(top: 20, left: 12, bottom: 12, right: 4)
return btn
}()
lazy var scrollView: UIScrollView = {
let sv = UIScrollView()
sv.contentInsetAdjustmentBehavior = .never
sv.showsVerticalScrollIndicator = false
sv.alwaysBounceVertical = true
sv.keyboardDismissMode = .onDrag
return sv
}()
lazy var contentView = UIView()
lazy var statsRow: UIStackView = {
let stack = UIStackView()
stack.axis = .horizontal
stack.spacing = 12
stack.distribution = .fillEqually
return stack
}()
lazy var memberCard: UIView = {
let view = UIView()
view.backgroundColor = .white
view.cornerRadius = 16
view.addSubview(memberPrevBtn)
view.addSubview(memberAvatar)
view.addSubview(avatarLockView)
view.addSubview(memberNextBtn)
view.addSubview(memberNameChip)
memberNameChip.addSubview(memberNameLab)
memberAvatar.layoutChain
.top(18)
.centerX()
.width(56)
.height(56)
avatarLockView.layoutChain
.topToView(memberAvatar)
.leftToView(memberAvatar)
.rightToView(memberAvatar)
.bottomToView(memberAvatar)
memberPrevBtn.layoutChain
.centerY(memberAvatar)
.rightToLeftOfView(memberAvatar, offset: -18)
.width(16)
.height(16)
memberNextBtn.layoutChain
.centerY(memberAvatar)
.leftToRightOfView(memberAvatar, offset: 18)
.width(16)
.height(16)
memberNameChip.layoutChain
.topToBottomOfView(memberAvatar, offset: 10)
.centerX()
.left(8, relation: .greaterThanOrEqual)
.right(8, relation: .greaterThanOrEqual)
.bottom(14)
memberNameLab.layoutChain
.top(6)
.bottom(6)
.left(5)
.right(5)
return view
}()
lazy var memberAvatar: UIImageView = {
let iv = UIImageView(image: UIImage(named: "Common/default_avatar"))
iv.contentMode = .scaleAspectFill
iv.clipsToBounds = true
iv.cornerRadius = 12
return iv
}()
lazy var avatarLockView: UIImageView = {
let iv = UIImageView(image: UIImage(named: "LockDistract/avatar_lock"))
iv.contentMode = .scaleAspectFill
iv.clipsToBounds = true
iv.cornerRadius = 12
iv.isHidden = true
return iv
}()
lazy var memberNameChip: UIView = {
let view = UIView()
view.backgroundColor = UIColor(hexStr: "#F2F2F2")
view.cornerRadius = 8
return view
}()
lazy var memberNameLab: UILabel = {
let lab = UILabel()
lab.text = " "
lab.font = .systemFont(ofSize: 10, weight: .bold)
lab.textColor = UIColor(hexStr: "#293445")
lab.textAlignment = .center
lab.lineBreakMode = .byTruncatingTail
return lab
}()
lazy var memberPrevBtn: UIButton = {
let btn = UIButton(type: .custom)
btn.setImage(UIImage(named: "LockDistract/member_prev"), for: .normal)
btn.extendEdgeInsets = UIEdgeInsets(top: 50, left: 30, bottom: 50, right: 18)
return btn
}()
lazy var memberNextBtn: UIButton = {
let btn = UIButton(type: .custom)
btn.setImage(UIImage(named: "LockDistract/member_next"), for: .normal)
btn.extendEdgeInsets = UIEdgeInsets(top: 50, left: 18, bottom: 50, right: 30)
return btn
}()
lazy var todayCard: UIView = {
let view = UIView()
view.backgroundColor = .white
view.cornerRadius = 16
let title = UILabel()
title.text = "今日锁定应用"
title.font = .systemFont(ofSize: 16, weight: .bold)
title.textColor = UIColor(hexStr: "#293445")
view.addSubview(title)
title.layoutChain.top(21).left(23)
view.addSubview(todayCountLab)
view.addSubview(todayUnitLab)
todayCountLab.layoutChain
.leftToView(title, offset: 4)
.bottom(10)
todayUnitLab.layoutChain
.leftToRightOfView(todayCountLab, offset: 7)
.bottomToView(todayCountLab, offset: -12)
return view
}()
lazy var todayCountLab: UILabel = {
let lab = UILabel()
lab.text = "0"
lab.font = .systemFont(ofSize: 50, weight: .heavy)
lab.textColor = UIColor(hexStr: "#00ADFE")
return lab
}()
lazy var todayUnitLab: UILabel = {
let lab = UILabel()
lab.text = ""
lab.font = .systemFont(ofSize: 16, weight: .bold)
lab.textColor = UIColor(hexStr: "#293445")
return lab
}()
lazy var appsSectionTitle: UIView = {
makeSectionTitle("锁定应用")
}()
lazy var appsCard: UIView = {
let view = UIView()
view.backgroundColor = .white
view.cornerRadius = 26
return view
}()
lazy var appsHeaderRow: UIView = {
let row = UIView()
let left = UILabel()
left.text = "选择锁定TA的app"
left.font = .systemFont(ofSize: 14, weight: .medium)
left.textColor = UIColor(hexStr: "#293445")
row.addSubview(left)
left.layoutChain.left().centerY()
row.addSubview(notFetchedView)
notFetchedView.layoutChain.right().centerY().height(28)
row.layoutChain.height(28)
return row
}()
lazy var notFetchedView: UIButton = {
let btn = UIButton(type: .custom)
btn.extendEdgeInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 4)
let warn = UIView()
warn.isUserInteractionEnabled = false
warn.backgroundColor = UIColor(hexStr: "#FA5151")
warn.cornerRadius = 5
let warnText = UILabel()
warnText.text = "!"
warnText.textColor = .white
warnText.font = .systemFont(ofSize: 8)
warnText.isUserInteractionEnabled = false
btn.addSubview(warn)
warn.addSubview(warnText)
warnText.layoutChain.centerX().centerY()
let notFetchedText = UILabel()
notFetchedText.text = "未获取"
notFetchedText.textColor = UIColor(hexStr: "#293445")
notFetchedText.font = .systemFont(ofSize: 12, weight: .medium)
notFetchedText.isUserInteractionEnabled = false
btn.addSubview(notFetchedText)
let arrow = UIImageView(image: UIImage(named: "LockDistract/arrow_right"))
arrow.isUserInteractionEnabled = false
btn.addSubview(arrow)
warn.layoutChain
.left()
.centerY()
.width(10).height(10)
notFetchedText.layoutChain
.leftToRightOfView(warn, offset: 4)
.centerY()
arrow.layoutChain
.leftToRightOfView(notFetchedText, offset: 2)
.right()
.width(10)
.heightToWidth(1)
.centerY()
return btn
}()
lazy var appCollectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.itemSize = CGSize(width: 56, height: 78)
layout.minimumLineSpacing = 12
layout.sectionInset = UIEdgeInsets(top: 0, left: 6, bottom: 0, right: 6)
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.backgroundColor = .clear
cv.showsHorizontalScrollIndicator = false
cv.register(LockDistractAppCell.self)
cv.dataSource = self
cv.delegate = self
cv.tag = 1
return cv
}()
lazy var bottomStack: UIStackView = {
let stack = UIStackView()
stack.axis = .vertical
stack.alignment = .fill
stack.spacing = 12
return stack
}()
lazy var styleSectionTitle: UIView = {
makeSectionTitle("锁定界面样式")
}()
lazy var styleCard: UIView = {
let card = UIView()
card.backgroundColor = .white
card.cornerRadius = 26
let wallLab = UILabel()
wallLab.text = "锁定图标"
wallLab.font = .systemFont(ofSize: 13, weight: .medium)
wallLab.textColor = UIColor(hexStr: "#8A94A6")
card.addSubview(wallLab)
wallLab.layoutChain.top(16).left(14)
card.addSubview(lockIconCV)
lockIconCV.layoutChain
.topToBottomOfView(wallLab, offset: 10)
.edgesHorzontal(14)
.height(74)
let copyLab = UILabel()
copyLab.text = "锁定文案"
copyLab.font = .systemFont(ofSize: 13, weight: .medium)
copyLab.textColor = UIColor(hexStr: "#8A94A6")
card.addSubview(copyLab)
copyLab.layoutChain.topToBottomOfView(lockIconCV, offset: 16).left(14)
let input = UIView()
input.backgroundColor = UIColor(hexStr: "#F5F6F8")
input.cornerRadius = 12
card.addSubview(input)
input.layoutChain
.topToBottomOfView(copyLab, offset: 10)
.edgesHorzontal(14)
.height(44)
.bottom(16)
input.addSubview(copyTF)
input.addSubview(copyCountLab)
copyCountLab.layoutChain.centerY().right(12).width(35)
copyTF.layoutChain.edgesVertical().left(12).rightToLeftOfView(copyCountLab, offset: -8)
return card
}()
lazy var lockIconCV: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.itemSize = CGSize(width: 56, height: 74)
layout.minimumLineSpacing = 10
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.backgroundColor = .clear
cv.showsHorizontalScrollIndicator = false
cv.register(LockDistractWallpaperCell.self)
cv.dataSource = self
cv.delegate = self
cv.tag = 2
return cv
}()
lazy var copyTF: UITextField = {
let tf = UITextField()
tf.font = .systemFont(ofSize: 14, weight: .medium)
tf.textColor = UIColor(hexStr: "#293445")
tf.placeholderColor(placeholder: "随便说点什么吧~",
color: UIColor(hexStr: "#999999"),
font: .systemFont(ofSize: 14, weight: .medium))
return tf
}()
lazy var copyCountLab: UILabel = {
let lab = UILabel()
lab.text = "0/20"
lab.font = .systemFont(ofSize: 14, weight: .medium)
lab.textColor = UIColor(hexStr: "#AAAAAA")
return lab
}()
lazy var lockedEmptyView: UIImageView = {
let iv = UIImageView(image: UIImage(named: "LockDistract/locked_empty"))
iv.contentMode = .scaleAspectFit
iv.isHidden = true
return iv
}()
lazy var tipLab: UILabel = {
let lab = UILabel()
lab.text = "锁定功能只有在圈主的情况下才能使用哟~"
lab.font = .systemFont(ofSize: 12, weight: .regular)
lab.textColor = UIColor(hexStr: "#00ADFE")
lab.numberOfLines = 0
return lab
}()
lazy var tipRow: UIView = {
let row = UIView()
let icon = UIImageView(image: UIImage(named: "LockDistract/info_circle"))
icon.contentMode = .scaleAspectFit
row.addSubview(icon)
row.addSubview(tipLab)
icon.layoutChain.left().centerY().width(14).height(14)
tipLab.layoutChain.leftToRightOfView(icon, offset: 6).right().top().bottom()
return row
}()
lazy var lockBtn: UIButton = {
let btn = UIButton(type: .custom)
btn.setTitle("锁定", for: .normal)
btn.setTitleColor(.white, for: .normal)
btn.titleLabel?.font = FontManager.boboBold(18)
btn.setBackgroundImage(UIImage(named: "Common/button_bg_2"), for: .normal)
btn.cornerRadius = 20
return btn
}()
private func makeSectionTitle(_ text: String) -> UIView {
let row = UIView()
let star = UIImageView(image: UIImage(named: "LockDistract/section_star"))
star.contentMode = .scaleAspectFit
let lab = UILabel()
lab.text = text
lab.font = .systemFont(ofSize: 16, weight: .bold)
lab.textColor = UIColor(hexStr: "#1F2A44")
row.addSubview(star)
row.addSubview(lab)
star.layoutChain.left().centerY().width(14).height(14)
lab.layoutChain.leftToRightOfView(star, offset: 6).right().centerY()
row.layoutChain.height(22)
return row
}
}
extension LockDistractView: UICollectionViewDataSource, UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
collectionView.tag == 1 ? 1 : lockIconNames.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView.tag == 1 {
let cell = collectionView.dequeueReusableCell(for: indexPath) as LockDistractAppCell
cell.configure(
image: UIImage(named: "LockDistract/app_unknown"),
selected: selectedAppIndexes.contains(indexPath.item),
showsCheck: false
)
return cell
}
let cell = collectionView.dequeueReusableCell(for: indexPath) as LockDistractWallpaperCell
cell.configure(
imageName: lockIconNames[indexPath.item],
isSelected: indexPath.item == selectedLockIconIndex
)
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if collectionView.tag == 1 {
guard !isLocked, indexPath.item > 0 else { return }
if selectedAppIndexes.contains(indexPath.item) {
selectedAppIndexes.remove(indexPath.item)
} else {
selectedAppIndexes.insert(indexPath.item)
}
collectionView.reloadData()
return
}
selectedLockIconIndex = indexPath.item
collectionView.reloadData()
}
}
final class LockDistractAppCell: UICollectionViewCell {
private let iconView: UIImageView = {
let iv = UIImageView()
iv.contentMode = .scaleAspectFit
iv.clipsToBounds = true
iv.cornerRadius = 12
return iv
}()
private let checkBtn: UIButton = {
let btn = UIButton(type: .custom)
btn.setImage(UIImage(named: "Common/checkbox"), for: .normal)
btn.setImage(UIImage(named: "Common/checkbox_on"), for: .selected)
btn.isUserInteractionEnabled = false
return btn
}()
override init(frame: CGRect) {
super.init(frame: frame)
contentView.addSubview(iconView)
contentView.addSubview(checkBtn)
iconView.layoutChain.top().centerX().width(48).height(48)
checkBtn.layoutChain.topToBottomOfView(iconView, offset: 6).centerX().width(16).height(16)
}
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
func configure(image: UIImage?, selected: Bool, showsCheck: Bool) {
iconView.image = image
checkBtn.isSelected = selected
checkBtn.isHidden = !showsCheck
}
}
final class LockDistractWallpaperCell: UICollectionViewCell {
private let frameView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(hexStr: "#F6F6F6")
view.cornerRadius = 14
return view
}()
private let imageView: UIImageView = {
let iv = UIImageView()
iv.contentMode = .scaleAspectFit
iv.clipsToBounds = true
return iv
}()
override init(frame: CGRect) {
super.init(frame: frame)
contentView.addSubview(frameView)
frameView.addSubview(imageView)
frameView.layoutChain.edges()
imageView.layoutChain
.centerY()
.centerX()
.width(48)
.height(48)
}
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
func configure(imageName: String, isSelected: Bool) {
imageView.image = UIImage(named: imageName)
frameView.backgroundColor = UIColor(hexStr: isSelected ? "#EAF8FF" : "#F6F6F6")
frameView.borderWidth = isSelected ? 1.5 : 0
frameView.borderColor = UIColor(hexStr: isSelected ? "#00ADFE" : "")
}
}