150 lines
6.0 KiB
Swift
150 lines
6.0 KiB
Swift
//
|
||
// SignInPhoneView.swift
|
||
// IOS_study
|
||
//
|
||
// Created by CC-star on 2025/7/10.
|
||
//
|
||
|
||
import SwiftUI
|
||
import Combine
|
||
private let totalTime = 60
|
||
|
||
struct SignInPhoneView: View {
|
||
enum FocusedField { case phoneNum, verCode }//聚焦在那个case
|
||
@Environment(SignInPhoneViewModel.self) var vm
|
||
@Environment(HUD.self) var hud
|
||
@State var showVerBtn = true
|
||
@State var timer: Publishers.Autoconnect<Timer.TimerPublisher>?//后面的 ? 表示可选类型
|
||
@State var timeRemain = totalTime//倒计时
|
||
@State var isAgree = false //是否同意协议,默认未勾选
|
||
@State var showAgreeSheet = false//确认协议弹窗
|
||
@State var showAgreeView = false//展示协议
|
||
@State var agreeType = 0//0表示用户协议,1表示隐私政策
|
||
@FocusState var focusedField: FocusedField?//光标聚焦用,设置为可选性,方便赋予nil
|
||
var enableLoginBtn: Bool { vm.phoneNum.isPhoneNum && vm.verCode.isVerCode }
|
||
|
||
var totalNumCount: Int { vm.phoneNum.count + vm.verCode.count }
|
||
|
||
var body: some View {
|
||
@Bindable var vm = vm
|
||
NavigationStack {
|
||
ScrollView {
|
||
VStack(spacing: 33) {
|
||
HStack {
|
||
NavigationLink {
|
||
SettginsView(naviPath: .constant(NavigationPath()), isLogin: false)
|
||
} label: {
|
||
Image(systemName: "gearshape")
|
||
}
|
||
Button {
|
||
focusedField = nil//不聚焦光标 -> 收起键盘
|
||
} label: {
|
||
Image(systemName: "xmark")
|
||
}
|
||
}.push(to: .trailing).font(.title3).secondary()
|
||
Text("手机号登陆").tc().font(.title).bold()
|
||
.kerning(1.2)//字间距,默认1
|
||
|
||
VStack(spacing: 14) {
|
||
HStack {
|
||
TextField("请输入手机号", text: $vm.phoneNum).tc().kerning(1.2)
|
||
.keyboardType(.numberPad)//数字键盘
|
||
.focused($focusedField, equals: .phoneNum)
|
||
if !vm.phoneNum.isEmpty {
|
||
Image(systemName: "xmark.circle.fill").font(.title2).secondary().onTapGesture { vm.phoneNum = "" }
|
||
}
|
||
}
|
||
exDivider()
|
||
|
||
HStack {
|
||
//797687
|
||
TextField("请输入验证码", text: $vm.verCode).tc().tc().kerning(1.2).keyboardType(.numberPad)
|
||
.focused($focusedField, equals: .verCode)
|
||
if vm.phoneNum.isPhoneNum || !showVerBtn {//是否为中国的手机号
|
||
if showVerBtn {
|
||
Button("获取验证码") {
|
||
timeRemain = totalTime
|
||
focusedField = .verCode//光标聚焦在case为verCode的区域
|
||
timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()//每隔一秒,在主循环,自动执行
|
||
showVerBtn = false
|
||
Task {
|
||
await getVerCode()
|
||
}
|
||
}.headline()
|
||
|
||
} else {
|
||
if let timer {
|
||
Text("重新发送(\(timeRemain)s)").headline().secondary()
|
||
//监听异步任务
|
||
.onReceive(timer) { _ in
|
||
timeRemain -= 1
|
||
if timeRemain <= 0 {
|
||
stopTimer()
|
||
showVerBtn = true
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
exDivider()
|
||
Button {
|
||
preLogin()
|
||
} label: {
|
||
if vm.isLogining {
|
||
ProgressView().appleStyleP()
|
||
} else {
|
||
Text("登录").appleStyle(disabled: !enableLoginBtn)
|
||
}
|
||
}.disabled(!enableLoginBtn || vm.isLogining)
|
||
HStack(spacing: 3) {
|
||
Button { isAgree.toggle()} label: {
|
||
Image(systemName: isAgree ? "checkmark.circle.fill" : "circle")
|
||
}.tint(isAgree ? .accent : .secondary).size16()
|
||
agreeTextView.size14()
|
||
}
|
||
}.font(.title3)
|
||
}.padding(33)
|
||
}
|
||
.scrollDismissesKeyboard(.immediately).bg()//滚动时立刻收起键盘
|
||
.fullScreenCover(isPresented: $showAgreeView, content: { AgreeView(agreeType: $agreeType) })
|
||
.sheet(isPresented: $showAgreeSheet) {//弹窗
|
||
VStack(spacing: 18) {
|
||
agreeTextView.size15()
|
||
Button {
|
||
isAgree = true//同意全部协议
|
||
showAgreeSheet = false//关闭弹窗
|
||
Task { await login() }//登录
|
||
} label: {
|
||
Text("同意并登录").font(.body).push(to: .center).padding(.vertical, 6)
|
||
}.buttonStyle(.borderedProminent)
|
||
}.padding(33)
|
||
.presentationDetents([.height(200)])//指定弹窗展示多少
|
||
// .presentationDetents([.medium, .large])//可以拖动弹窗展示多少
|
||
}
|
||
}
|
||
.onChange(of: totalNumCount) {
|
||
if totalNumCount == 17 {
|
||
preLogin()
|
||
}
|
||
|
||
|
||
}
|
||
}
|
||
|
||
var agreeTextView: some View {
|
||
HStack(spacing: 3) {
|
||
Text("我已阅读并同意").secondary()
|
||
Button("用户协议") {
|
||
agreeType = 0
|
||
showAgreeView = true
|
||
}
|
||
Text("和").secondary()
|
||
Button("隐私政策") {
|
||
agreeType = 1
|
||
showAgreeView = true
|
||
}
|
||
}
|
||
}
|
||
}
|