606 lines
18 KiB
Swift
606 lines
18 KiB
Swift
//
|
||
// LockDistractView.swift
|
||
// QuickLocation
|
||
//
|
||
|
||
import UIKit
|
||
import RxSwift
|
||
import RxCocoa
|
||
|
||
final class LockDistractView: UIView {
|
||
|
||
var disposeBag = DisposeBag()
|
||
|
||
let wallpaperNames = [
|
||
"LockDistract/wallpaper_1",
|
||
"LockDistract/wallpaper_2",
|
||
"LockDistract/wallpaper_3"
|
||
]
|
||
|
||
private(set) var selectedWallpaperIndex = 0
|
||
private let copyMaxLength = 20
|
||
|
||
// MARK: - Init
|
||
|
||
override init(frame: CGRect) {
|
||
super.init(frame: frame)
|
||
backgroundColor = UIColor(hexStr: "#FAFAFA")
|
||
setupUI()
|
||
setupCopyLimit()
|
||
}
|
||
|
||
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
|
||
|
||
// MARK: - Public
|
||
|
||
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)"
|
||
}
|
||
|
||
// MARK: - UI
|
||
|
||
private func setupUI() {
|
||
addSubview(navBgView)
|
||
addSubview(navView)
|
||
navView.addRightButton(switchGroupBtn)
|
||
addSubview(scrollView)
|
||
scrollView.addSubview(contentView)
|
||
addSubview(lockBtn)
|
||
|
||
contentView.addSubview(titleLab)
|
||
contentView.addSubview(subtitleLab)
|
||
contentView.addSubview(heroPlaceholder)
|
||
contentView.addSubview(statsRow)
|
||
statsRow.addArrangedSubview(memberCard)
|
||
statsRow.addArrangedSubview(todayCard)
|
||
contentView.addSubview(appsSectionTitle)
|
||
contentView.addSubview(appsCard)
|
||
appsCard.addSubview(appsHeaderRow)
|
||
appsCard.addSubview(unknownAppIcon)
|
||
contentView.addSubview(styleSectionTitle)
|
||
contentView.addSubview(styleCard)
|
||
addSubview(tipRow)
|
||
|
||
navBgView.layoutChain
|
||
.edges(excludingEdge: .bottom)
|
||
.heightToWidth(160/375)
|
||
|
||
navView.layoutChain
|
||
.edges(excludingEdge: .bottom)
|
||
.height(kNaviHeight)
|
||
|
||
lockBtn.layoutChain
|
||
.bottom(kSafeBottomMargin + 0)
|
||
.edgesHorzontal(30)
|
||
.height(56)
|
||
|
||
scrollView.layoutChain
|
||
.topToBottomOfView(navView)
|
||
.edgesHorzontal()
|
||
.bottomToTopOfView(tipRow, offset: -12)
|
||
|
||
contentView.layoutChain
|
||
.edges()
|
||
.widthToView(scrollView)
|
||
|
||
titleLab.layoutChain
|
||
.top(8)
|
||
.left(20)
|
||
|
||
subtitleLab.layoutChain
|
||
.topToBottomOfView(titleLab, offset: 6)
|
||
.left(20)
|
||
.right(140)
|
||
|
||
heroPlaceholder.layoutChain
|
||
.top(0)
|
||
.right(16)
|
||
.width(120)
|
||
.height(100)
|
||
|
||
statsRow.layoutChain
|
||
.topToBottomOfView(subtitleLab, offset: 20)
|
||
.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)
|
||
|
||
unknownAppIcon.layoutChain
|
||
.topToBottomOfView(appsHeaderRow, offset: 14)
|
||
.left(14)
|
||
.width(56)
|
||
.height(56)
|
||
.bottom(16)
|
||
|
||
styleSectionTitle.layoutChain
|
||
.topToBottomOfView(appsCard, offset: 22)
|
||
.left(20)
|
||
|
||
styleCard.layoutChain
|
||
.topToBottomOfView(styleSectionTitle, offset: 12)
|
||
.edgesHorzontal(16)
|
||
.bottom(20)
|
||
|
||
tipRow.layoutChain
|
||
.centerX()
|
||
.bottomToTopOfView(lockBtn, offset: -6)
|
||
}
|
||
|
||
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: "Common/navBar_bg_2")
|
||
iv.contentMode = .scaleAspectFill
|
||
return iv
|
||
}()
|
||
|
||
lazy var navView: BaseNavigationView = {
|
||
BaseNavigationView(title: "")
|
||
}()
|
||
|
||
lazy var switchGroupBtn: UIButton = {
|
||
let btn = UIButton(type: .custom)
|
||
btn.backgroundColor = .white.withAlphaComponent(0.9)
|
||
btn.setTitle(" 切换圈子 ", 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.showsVerticalScrollIndicator = false
|
||
sv.alwaysBounceVertical = true
|
||
sv.keyboardDismissMode = .onDrag
|
||
return sv
|
||
}()
|
||
|
||
lazy var contentView = UIView()
|
||
|
||
lazy var titleLab: UILabel = {
|
||
let lab = UILabel()
|
||
lab.text = "锁住分心"
|
||
lab.font = FontManager.boboBold(30)
|
||
lab.textColor = UIColor(hexStr: "#293445")
|
||
return lab
|
||
}()
|
||
|
||
lazy var subtitleLab: UILabel = {
|
||
let lab = UILabel()
|
||
lab.text = "减少干扰,只专注重要的事"
|
||
lab.font = .systemFont(ofSize: 13, weight: .medium)
|
||
lab.textColor = UIColor(hexStr: "#8A94A6")
|
||
lab.numberOfLines = 2
|
||
return lab
|
||
}()
|
||
|
||
lazy var heroPlaceholder: UIView = {
|
||
let view = UIView()
|
||
view.backgroundColor = .clear
|
||
return view
|
||
}()
|
||
|
||
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(memberNextBtn)
|
||
view.addSubview(memberNameChip)
|
||
memberNameChip.addSubview(memberNameLab)
|
||
|
||
memberAvatar.layoutChain
|
||
.top(18)
|
||
.centerX()
|
||
.width(56)
|
||
.height(56)
|
||
|
||
memberPrevBtn.layoutChain
|
||
.centerY(memberAvatar)
|
||
.left(8)
|
||
.width(28)
|
||
.height(28)
|
||
|
||
memberNextBtn.layoutChain
|
||
.centerY(memberAvatar)
|
||
.right(8)
|
||
.width(28)
|
||
.height(28)
|
||
|
||
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 = 16
|
||
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: .system)
|
||
btn.setImage(UIImage(systemName: "chevron.left"), for: .normal)
|
||
btn.tintColor = UIColor(hexStr: "#9CA3AF")
|
||
return btn
|
||
}()
|
||
|
||
lazy var memberNextBtn: UIButton = {
|
||
let btn = UIButton(type: .system)
|
||
btn.setImage(UIImage(systemName: "chevron.right"), for: .normal)
|
||
btn.tintColor = UIColor(hexStr: "#9CA3AF")
|
||
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: UIView = {
|
||
let view = UIView()
|
||
|
||
let warn = UIView()
|
||
warn.backgroundColor = UIColor(hexStr: "#FA5151")
|
||
warn.cornerRadius = 5
|
||
let warnText = UILabel()
|
||
warnText.text = "!"
|
||
warnText.textColor = .white
|
||
warnText.font = .systemFont(ofSize: 8)
|
||
|
||
view.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)
|
||
view.addSubview(notFetchedText)
|
||
|
||
let arrow = UIImageView(image: UIImage(named: "LockDistract/arrow_right"))
|
||
|
||
view.addSubview(arrow)
|
||
view.addSubview(notFetchedText)
|
||
|
||
arrow.layoutChain
|
||
.right(14)
|
||
.width(10)
|
||
.heightToWidth(1)
|
||
.centerY()
|
||
|
||
notFetchedText.layoutChain
|
||
.rightToLeftOfView(arrow)
|
||
.centerY()
|
||
|
||
warn.layoutChain
|
||
.rightToLeftOfView(notFetchedText, offset: -4)
|
||
.centerY()
|
||
.width(10).height(10)
|
||
|
||
return view
|
||
}()
|
||
|
||
lazy var unknownAppIcon: UIImageView = {
|
||
let iv = UIImageView(image: UIImage(named: "LockDistract/app_unknown"))
|
||
iv.contentMode = .scaleAspectFit
|
||
return iv
|
||
}()
|
||
|
||
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(wallpaperCV)
|
||
wallpaperCV.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(wallpaperCV, 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 wallpaperCV: UICollectionView = {
|
||
let layout = UICollectionViewFlowLayout()
|
||
layout.scrollDirection = .horizontal
|
||
layout.itemSize = CGSize(width: 50, height: 74)
|
||
layout.minimumLineSpacing = 12
|
||
layout.minimumInteritemSpacing = 0
|
||
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
|
||
cv.backgroundColor = .clear
|
||
cv.showsHorizontalScrollIndicator = false
|
||
cv.register(LockDistractWallpaperCell.self)
|
||
cv.dataSource = self
|
||
cv.delegate = self
|
||
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 tipRow: UIView = {
|
||
let row = UIView()
|
||
let icon = UIImageView(image: UIImage(systemName: "info.circle.fill"))
|
||
icon.tintColor = UIColor(hexStr: "#16B3FF")
|
||
let lab = UILabel()
|
||
lab.text = "锁定功能只有在圈主的情况下才能使用哟~"
|
||
lab.font = .systemFont(ofSize: 12, weight: .regular)
|
||
lab.textColor = UIColor(hexStr: "#00ADFE")
|
||
lab.numberOfLines = 0
|
||
row.addSubview(icon)
|
||
row.addSubview(lab)
|
||
icon.layoutChain.left().top(1).width(14).height(14)
|
||
lab.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"))
|
||
// 切图目前带黑底,先用 SF Symbol 保证白底可读;资源补透明图后可改回 LockDistract/section_star
|
||
// let config = UIImage.SymbolConfiguration(pointSize: 12, weight: .bold)
|
||
// star.image = UIImage(systemName: "sparkle", withConfiguration: config)
|
||
// star.tintColor = UIColor(hexStr: "#16B3FF")
|
||
// 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 {
|
||
wallpaperNames.count
|
||
}
|
||
|
||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||
let cell = collectionView.dequeueReusableCell(for: indexPath) as LockDistractWallpaperCell
|
||
cell.configure(imageName: wallpaperNames[indexPath.item],
|
||
isSelected: indexPath.item == selectedWallpaperIndex)
|
||
return cell
|
||
}
|
||
|
||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||
selectedWallpaperIndex = indexPath.item
|
||
collectionView.reloadData()
|
||
}
|
||
}
|
||
|
||
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 = .scaleAspectFill
|
||
iv.clipsToBounds = true
|
||
iv.cornerRadius = 10
|
||
return iv
|
||
}()
|
||
|
||
override init(frame: CGRect) {
|
||
super.init(frame: frame)
|
||
contentView.addSubview(frameView)
|
||
frameView.addSubview(imageView)
|
||
frameView.layoutChain.edges()
|
||
imageView.layoutChain
|
||
.centerY()
|
||
.centerX()
|
||
.width(40)
|
||
.height(40)
|
||
}
|
||
|
||
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 : 0
|
||
frameView.borderColor = UIColor(hexStr: isSelected ? "#00ADFE" : "")
|
||
}
|
||
}
|