jsdw_ios/QuickLocation/Section/Home/SOS/SOSView.swift

330 lines
11 KiB
Swift
Raw Permalink 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.

//
// SOSView.swift
// QuickLocation
//
// Created by on 2026/6/18.
//
import UIKit
import RxSwift
import RxCocoa
import RxGesture
import Lottie
import SwiftyUserDefaults
class SOSView: UIView {
var disposeBag = DisposeBag()
var sosPracticeView: SOSPracticeView = SOSPracticeView()
var didSendSOS: ((Bool) -> Void)?
var countDownFinish: Bool = false
private func setupRx() {
backBtn.rx.tap.subscribe(onNext: { _ in
AppRouter.shared.popOrDismiss()
}).disposed(by: disposeBag)
exclamationLottieView.rx.tapGesture.subscribe(onNext: { _ in
UIView.animate(withDuration: 0.3, delay: 0, options: [.curveEaseInOut], animations: {
self.countDownView.alpha = 1
}, completion: { _ in
self.countDownLottieView.play { completed in
guard completed else { return }
if let path = Bundle.main.path(forResource: "red-exclamation", ofType: "json") {
self.countDownLottieView.animation = LottieAnimation.filepath(path)
self.countDownLottieView.loopMode = .loop
self.countDownLottieView.play()
self.countDownTipsLab.text = "已将你的SOS和位置发送到你的圈子和紧急联系人。\n\n您的 SOS 将发送给5个人"
self.countDownFinish = true
if let didSendSOS = self.didSendSOS {
didSendSOS(true)
}
}
}
})
}).disposed(by: disposeBag)
sliderIcon.rx.panGesture()
.subscribe(onNext: { [weak self] gesture in
guard let self = self else { return }
let translation = gesture.translation(in: self.sliderView)
let maxX = self.sliderView.bounds.width - self.sliderIcon.frame.width
switch gesture.state {
case .began, .changed:
var newX = self.sliderIcon.frame.minX + translation.x
newX = max(0, min(maxX, newX))
self.sliderIcon.frame.origin.x = newX
gesture.setTranslation(.zero, in: self.sliderView)
case .ended:
if self.sliderIcon.frame.minX >= maxX - 5 {
if countDownFinish {
if let didSendSOS = self.didSendSOS {
didSendSOS(false)
}
}
else {
self.countDownView.alpha = 0
self.countDownLottieView.stop()
}
}
UIView.animate(withDuration: 0.3) {
self.sliderIcon.frame.origin.x = 3
}
default:
break
}
})
.disposed(by: disposeBag)
}
private func setupUI() {
addSubview(exclamationLottieView)
addSubview(messageLab)
addSubview(tipsLab)
addSubview(bottomTipsLab)
addSubview(addContactView)
addSubview(sosPracticeView)
addSubview(countDownView)
addSubview(navBgView)
addSubview(navBarView)
navBarView.addSubview(navTitleLabel)
navBarView.addSubview(backBtn)
navBgView.layoutChain
.edges(excludingEdge: .bottom)
.heightToWidth(160/375)
navBarView.layoutChain
.edges(excludingEdge: .bottom)
.height(kNaviHeight)
navTitleLabel.layoutChain
.top(kStatusBarHeight + 12)
.centerY(backBtn)
.centerX()
backBtn.layoutChain
.centerY(navTitleLabel)
.left(15)
.width(24)
.height(24)
sosPracticeView.layoutChain
.topToBottomOfView(navBarView)
.edges(excludingEdge: .top)
exclamationLottieView.layoutChain
.topToBottomOfView(navBarView, offset: 40)
.edgesHorzontal(28)
.heightToWidth(1)
messageLab.layoutChain
.topToBottomOfView(exclamationLottieView, offset: 19)
.centerX()
tipsLab.layoutChain
.topToBottomOfView(messageLab, offset: 10)
.edgesHorzontal(23)
addContactView.layoutChain
.topToBottomOfView(tipsLab, offset: 30)
.centerX()
countDownView.layoutChain
.topToBottomOfView(navBarView)
.edges(excludingEdge: .top)
bottomTipsLab.layoutChain
.centerX()
.bottom(kSafeBottomMargin + 40)
}
lazy var navBgView: UIImageView = {
let iv = UIImageView()
iv.image = UIImage(named: "Common/navBar_bg_2")
iv.contentMode = .scaleAspectFill
return iv
}()
lazy var navBarView: UIView = {
let view = UIView()
view.backgroundColor = .clear
return view
}()
lazy var navTitleLabel: UILabel = {
let label = UILabel()
label.text = "SOS"
label.font = .systemFont(ofSize: 18, weight: .medium)
label.textColor = ThemeManager.shared.color.titleAuxColor
label.textAlignment = .center
return label
}()
lazy var backBtn: UIButton = {
let btn = UIButton(type: .custom)
btn.setImage(UIImage(named: "Common/back"), for: .normal)
btn.extendEdgeInsets = UIEdgeInsets(top: 54, left: 15, bottom: 100, right: 100)
return btn
}()
lazy var exclamationLottieView: LottieAnimationView = {
let view = LottieAnimationView(name: "yellow-exclamation")
view.loopMode = .loop
return view
}()
lazy var messageLab: UILabel = {
let label = UILabel()
label.text = "当您感到紧张或不安全时,请按住此按钮。"
label.font = .systemFont(ofSize: 16, weight: .medium)
label.textColor = UIColor(hexStr: "#333333")
return label
}()
lazy var tipsLab: UILabel = {
let label = UILabel()
label.text = "提示若你在气泡当中时发送SOS将会自动从气泡中弹出。"
label.font = .systemFont(ofSize: 14, weight: .regular)
label.textColor = UIColor(hexStr: "#999999")
label.numberOfLines = 0
return label
}()
lazy var addContactView: UIView = {
let view = UIView()
view.backgroundColor = .clear
let icon = UIImageView(image: UIImage(named: "SOS/add"))
view.addSubview(icon)
icon.layoutChain
.left()
.edgesVertical()
.height(30)
.width(30)
let label = UILabel()
label.text = "添加紧急联系人"
label.font = .systemFont(ofSize: 14, weight: .medium)
view.addSubview(label)
label.layoutChain
.leftToRightOfView(icon, offset: 10)
.right()
.centerY()
return view
}()
//
lazy var countDownView: UIView = {
let view = UIView()
view.backgroundColor = .white
view.alpha = 0
view.addSubview(countDownLottieView)
countDownLottieView.layoutChain
.top(40)
.edgesHorzontal(27)
.heightToWidth(1)
let titleLab = UILabel()
titleLab.text = "滑动取消"
titleLab.font = .systemFont(ofSize: 26, weight: .semibold)
view.addSubview(titleLab)
titleLab.layoutChain
.topToBottomOfView(countDownLottieView, offset: 15)
.centerX()
view.addSubview(countDownTipsLab)
countDownTipsLab.layoutChain
.topToBottomOfView(titleLab, offset: 8)
.edgesHorzontal(38)
view.addSubview(sliderView)
sliderView.layoutChain
.edgesHorzontal(30)
.bottom(kSafeBottomMargin + 30)
.height(50)
return view
}()
lazy var countDownLottieView: LottieAnimationView = {
let view = LottieAnimationView(name: "10-second-timer")
view.loopMode = .playOnce
return view
}()
lazy var countDownTipsLab: UILabel = {
let tipsLab = UILabel()
tipsLab.text = "10秒后会将你的SOS和位置发送到你的圈子和紧急联系人。"
tipsLab.font = .systemFont(ofSize: 16, weight: .medium)
tipsLab.textAlignment = .center
tipsLab.numberOfLines = 0
return tipsLab
}()
lazy var sliderView: UIView = {
let view = UIView()
view.backgroundColor = .clear
view.cornerRadius = 25
let imgView = UIImageView(image: UIImage(named: "Common/button_bg_2"))
imgView.contentMode = .scaleAspectFill
view.addSubview(imgView)
imgView.layoutChain.edges()
let label = UILabel()
label.text = "滑动以取消SOS"
label.textColor = .white
label.font = .systemFont(ofSize: 16, weight: .medium)
view.addSubview(label)
label.layoutChain.centerX().centerY()
view.addSubview(sliderIcon)
return view
}()
lazy var sliderIcon: UIImageView = {
let view = UIImageView(frame: CGRectMake(3, 2, 46, 46))
view.image = UIImage(named: "SOS/slider")
view.isUserInteractionEnabled = true
return view
}()
lazy var bottomTipsLab: UILabel = {
let label = UILabel()
label.textColor = UIColor(hexStr: "#333333")
let text = "轻点感叹号发送SOS"
let attr = NSMutableAttributedString(string: text)
attr.addAttribute(.font, value: UIFont.systemFont(ofSize: 20, weight: .semibold), range: NSRange(location: 0, length: text.count))
attr.addAttribute(.foregroundColor, value: UIColor(hexStr: "#FF383C"), range: NSRange(location: "轻点感叹号发送".count, length: "SOS".count))
label.attributedText = attr
return label
}()
override init(frame: CGRect) {
super.init(frame: .zero)
backgroundColor = .white
setupUI()
setupRx()
exclamationLottieView.play()
let isHidden = Defaults[\.sosIsPracticeList].first(where: { $0 == AppContextManager.shared.userId }) != nil
sosPracticeView.isHidden = isHidden
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}