修改这册流程
This commit is contained in:
parent
883f9d7f64
commit
c9c507974e
@ -17,14 +17,14 @@ class AppContext {
|
|||||||
|
|
||||||
// 当前的场景
|
// 当前的场景
|
||||||
enum AppScene {
|
enum AppScene {
|
||||||
case login
|
case login(username: String?)
|
||||||
case logined
|
case logined
|
||||||
case register
|
case register
|
||||||
case resetPassword
|
case resetPassword
|
||||||
}
|
}
|
||||||
|
|
||||||
// 当前app所处的场景
|
// 当前app所处的场景
|
||||||
var appScene: AppScene = .login
|
var appScene: AppScene = .login(username: nil)
|
||||||
|
|
||||||
init(noticePort: Int) {
|
init(noticePort: Int) {
|
||||||
self.noticePort = noticePort
|
self.noticePort = noticePort
|
||||||
|
|||||||
@ -12,6 +12,8 @@ struct LoginView: View {
|
|||||||
@Environment(UserContext.self) var userContext: UserContext
|
@Environment(UserContext.self) var userContext: UserContext
|
||||||
@State private var authMethod: AuthMethod = .account
|
@State private var authMethod: AuthMethod = .account
|
||||||
|
|
||||||
|
var username: String?
|
||||||
|
|
||||||
enum AuthMethod: String, CaseIterable {
|
enum AuthMethod: String, CaseIterable {
|
||||||
case account = "账户登录"
|
case account = "账户登录"
|
||||||
case token = "密钥认证"
|
case token = "密钥认证"
|
||||||
@ -54,7 +56,7 @@ struct LoginView: View {
|
|||||||
LoginTokenView()
|
LoginTokenView()
|
||||||
.transition(.move(edge: .trailing).combined(with: .opacity))
|
.transition(.move(edge: .trailing).combined(with: .opacity))
|
||||||
} else {
|
} else {
|
||||||
LoginAccountView()
|
LoginAccountView(username: self.username ?? "")
|
||||||
.transition(.move(edge: .leading).combined(with: .opacity))
|
.transition(.move(edge: .leading).combined(with: .opacity))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -88,8 +90,8 @@ struct LoginAccountView: View {
|
|||||||
@Environment(UserContext.self) var userContext: UserContext
|
@Environment(UserContext.self) var userContext: UserContext
|
||||||
@Environment(AppContext.self) var appContext: AppContext
|
@Environment(AppContext.self) var appContext: AppContext
|
||||||
|
|
||||||
@State private var username = ""
|
@State var username: String = ""
|
||||||
@State private var password = ""
|
@State private var password: String = ""
|
||||||
@State private var isLoading = false
|
@State private var isLoading = false
|
||||||
|
|
||||||
// 错误提示
|
// 错误提示
|
||||||
|
|||||||
@ -12,10 +12,10 @@ import SwiftUI
|
|||||||
@Observable
|
@Observable
|
||||||
class RegisterModel {
|
class RegisterModel {
|
||||||
|
|
||||||
enum Stage {
|
enum Stage: Equatable {
|
||||||
case requestVerifyCode(username: String?)
|
case requestVerifyCode
|
||||||
case submitVerifyCode(username: String, sessionId: Int)
|
case submitVerifyCode
|
||||||
case setPassword(sessionId: Int)
|
case setPassword
|
||||||
case success
|
case success
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,7 +28,11 @@ class RegisterModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var stage: Stage = .requestVerifyCode(username: nil)
|
// 保存临时变量
|
||||||
|
var username: String = ""
|
||||||
|
var sessionId: Int = 0
|
||||||
|
|
||||||
|
var stage: Stage = .requestVerifyCode
|
||||||
var transitionEdge: Edge = .trailing // 默认从右进入
|
var transitionEdge: Edge = .trailing // 默认从右进入
|
||||||
|
|
||||||
private let baseParams: [String: Any] = [
|
private let baseParams: [String: Any] = [
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import Observation
|
|||||||
// MARK: - 注册根视图
|
// MARK: - 注册根视图
|
||||||
struct RegisterRootView: View {
|
struct RegisterRootView: View {
|
||||||
@State private var registerModel = RegisterModel()
|
@State private var registerModel = RegisterModel()
|
||||||
|
@Environment(AppContext.self) private var appContext: AppContext
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
@ -19,12 +20,12 @@ struct RegisterRootView: View {
|
|||||||
|
|
||||||
Group {
|
Group {
|
||||||
switch registerModel.stage {
|
switch registerModel.stage {
|
||||||
case .requestVerifyCode(let username):
|
case .requestVerifyCode:
|
||||||
RegisterRequestVerifyCodeView(username: username ?? "")
|
RegisterRequestVerifyCodeView()
|
||||||
case .submitVerifyCode(let username, let sessionId):
|
case .submitVerifyCode:
|
||||||
RegisterSubmitVerifyCodeView(username: username, sessionId: sessionId)
|
RegisterSubmitVerifyCodeView()
|
||||||
case .setPassword(let sessionId):
|
case .setPassword:
|
||||||
RegisterSetPasswordView(sessionId: sessionId)
|
RegisterSetPasswordView()
|
||||||
case .success:
|
case .success:
|
||||||
RegisterSuccessView()
|
RegisterSuccessView()
|
||||||
}
|
}
|
||||||
@ -35,6 +36,34 @@ struct RegisterRootView: View {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
.environment(registerModel)
|
.environment(registerModel)
|
||||||
|
// --- 核心改动:使用 overlay ---
|
||||||
|
.overlay(alignment: .topLeading) {
|
||||||
|
// 仅在非成功页面显示返回按钮
|
||||||
|
switch registerModel.stage {
|
||||||
|
case .success:
|
||||||
|
EmptyView()
|
||||||
|
default:
|
||||||
|
Button(action: {
|
||||||
|
// 执行返回逻辑,例如重置到登录
|
||||||
|
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
||||||
|
self.appContext.appScene = .login(username: nil)
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
HStack {
|
||||||
|
Image(systemName: "chevron.left")
|
||||||
|
.font(.system(size: 16, weight: .semibold))
|
||||||
|
.padding(5)
|
||||||
|
|
||||||
|
Text("首页")
|
||||||
|
.font(.system(size: 16, weight: .regular))
|
||||||
|
}
|
||||||
|
.contentShape(Rectangle()) // 扩大点击热区
|
||||||
|
}
|
||||||
|
.buttonStyle(.plain)
|
||||||
|
.padding([.top, .leading], 16) // 控制距离窗口边缘的边距
|
||||||
|
.transition(.opacity) // 按钮出现的动画
|
||||||
|
}
|
||||||
|
}
|
||||||
.frame(width: 500, height: 400)
|
.frame(width: 500, height: 400)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -74,8 +103,7 @@ struct PunchTextField: View {
|
|||||||
|
|
||||||
// MARK: - 第一步:获取验证码
|
// MARK: - 第一步:获取验证码
|
||||||
struct RegisterRequestVerifyCodeView: View {
|
struct RegisterRequestVerifyCodeView: View {
|
||||||
@Environment(RegisterModel.self) var registerModel
|
@Environment(RegisterModel.self) var registerModel: RegisterModel
|
||||||
@State var username: String = ""
|
|
||||||
@State private var isProcessing = false
|
@State private var isProcessing = false
|
||||||
|
|
||||||
// 错误提示
|
// 错误提示
|
||||||
@ -83,16 +111,18 @@ struct RegisterRequestVerifyCodeView: View {
|
|||||||
@State private var errorMessage: String = ""
|
@State private var errorMessage: String = ""
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
@Bindable var model = registerModel
|
||||||
|
|
||||||
VStack(spacing: 24) {
|
VStack(spacing: 24) {
|
||||||
headerSection(title: "创建个人网络", subtitle: "输入邮箱开始注册")
|
headerSection(title: "创建个人网络", subtitle: "输入邮箱开始注册")
|
||||||
|
|
||||||
VStack(spacing: 16) {
|
VStack(spacing: 16) {
|
||||||
PunchTextField(icon: "person.crop.circle", placeholder: "邮箱", text: $username)
|
PunchTextField(icon: "person.crop.circle", placeholder: "邮箱", text: $model.username)
|
||||||
}
|
}
|
||||||
.frame(width: 280)
|
.frame(width: 280)
|
||||||
|
|
||||||
Button(action: {
|
Button(action: {
|
||||||
self.requestVerifyCode()
|
self.requestVerifyCode(username: model.username)
|
||||||
}) {
|
}) {
|
||||||
Text("获取验证码")
|
Text("获取验证码")
|
||||||
.fontWeight(.medium)
|
.fontWeight(.medium)
|
||||||
@ -101,7 +131,7 @@ struct RegisterRequestVerifyCodeView: View {
|
|||||||
.buttonStyle(.borderedProminent)
|
.buttonStyle(.borderedProminent)
|
||||||
.controlSize(.large)
|
.controlSize(.large)
|
||||||
.frame(width: 280)
|
.frame(width: 280)
|
||||||
.disabled(!SDLUtil.isValidIdentifyContact(username) || isProcessing)
|
.disabled(!SDLUtil.isValidIdentifyContact(model.username) || isProcessing)
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
@ -111,7 +141,7 @@ struct RegisterRequestVerifyCodeView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func requestVerifyCode() {
|
private func requestVerifyCode(username: String) {
|
||||||
self.isProcessing = true
|
self.isProcessing = true
|
||||||
Task { @MainActor in
|
Task { @MainActor in
|
||||||
if username.isEmpty {
|
if username.isEmpty {
|
||||||
@ -126,7 +156,10 @@ struct RegisterRequestVerifyCodeView: View {
|
|||||||
do {
|
do {
|
||||||
let registerSession = try await self.registerModel.requestVerifyCode(username: username)
|
let registerSession = try await self.registerModel.requestVerifyCode(username: username)
|
||||||
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
||||||
self.registerModel.stage = .submitVerifyCode(username: username, sessionId: registerSession.sessionId)
|
self.registerModel.stage = .submitVerifyCode
|
||||||
|
self.registerModel.username = username
|
||||||
|
self.registerModel.sessionId = registerSession.sessionId
|
||||||
|
|
||||||
self.registerModel.transitionEdge = .trailing
|
self.registerModel.transitionEdge = .trailing
|
||||||
}
|
}
|
||||||
} catch let err as SDLAPIError {
|
} catch let err as SDLAPIError {
|
||||||
@ -148,10 +181,7 @@ struct RegisterRequestVerifyCodeView: View {
|
|||||||
|
|
||||||
// MARK: - 第二步:验证
|
// MARK: - 第二步:验证
|
||||||
struct RegisterSubmitVerifyCodeView: View {
|
struct RegisterSubmitVerifyCodeView: View {
|
||||||
@Environment(RegisterModel.self) var registerModel
|
@Environment(RegisterModel.self) var registerModel: RegisterModel
|
||||||
|
|
||||||
let username: String
|
|
||||||
let sessionId: Int
|
|
||||||
|
|
||||||
@State private var code: String = ""
|
@State private var code: String = ""
|
||||||
@State private var isProcessing = false
|
@State private var isProcessing = false
|
||||||
@ -172,13 +202,15 @@ struct RegisterSubmitVerifyCodeView: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(spacing: 24) {
|
VStack(spacing: 24) {
|
||||||
headerSection(title: "身份验证", subtitle: "验证码已发送至 \(username)")
|
headerSection(title: "身份验证", subtitle: "验证码已发送至 \(registerModel.username)")
|
||||||
|
|
||||||
VStack(alignment: .trailing, spacing: 16) {
|
VStack(alignment: .trailing, spacing: 16) {
|
||||||
PunchTextField(icon: "envelope.badge", placeholder: "输入 6 位验证码", text: $code)
|
PunchTextField(icon: "envelope.badge", placeholder: "输入 6 位验证码", text: $code)
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
self.resendVerifyCodeAction()
|
Task { @MainActor in
|
||||||
|
await self.resendVerifyCodeAction(username: registerModel.username)
|
||||||
|
}
|
||||||
} label: {
|
} label: {
|
||||||
if isEnabled {
|
if isEnabled {
|
||||||
Text("没有收到?重新获取")
|
Text("没有收到?重新获取")
|
||||||
@ -194,7 +226,9 @@ struct RegisterSubmitVerifyCodeView: View {
|
|||||||
|
|
||||||
VStack(spacing: 12) {
|
VStack(spacing: 12) {
|
||||||
Button(action: {
|
Button(action: {
|
||||||
self.submitVerifyCode()
|
Task { @MainActor in
|
||||||
|
await self.submitVerifyCode(sessionId: registerModel.sessionId)
|
||||||
|
}
|
||||||
}) {
|
}) {
|
||||||
Text("验证并设置密码")
|
Text("验证并设置密码")
|
||||||
.fontWeight(.medium)
|
.fontWeight(.medium)
|
||||||
@ -206,7 +240,8 @@ struct RegisterSubmitVerifyCodeView: View {
|
|||||||
|
|
||||||
Button("返回上一步") {
|
Button("返回上一步") {
|
||||||
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
||||||
self.registerModel.stage = .requestVerifyCode(username: self.username)
|
self.registerModel.stage = .requestVerifyCode
|
||||||
|
|
||||||
self.registerModel.transitionEdge = .leading
|
self.registerModel.transitionEdge = .leading
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -227,8 +262,7 @@ struct RegisterSubmitVerifyCodeView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 重新发送验证码
|
// 重新发送验证码
|
||||||
private func resendVerifyCodeAction() {
|
private func resendVerifyCodeAction(username: String) async {
|
||||||
Task {
|
|
||||||
do {
|
do {
|
||||||
let result = try await self.registerModel.requestVerifyCode(username: username)
|
let result = try await self.registerModel.requestVerifyCode(username: username)
|
||||||
print("send verify code result: \(result)")
|
print("send verify code result: \(result)")
|
||||||
@ -238,7 +272,6 @@ struct RegisterSubmitVerifyCodeView: View {
|
|||||||
// 重新计时
|
// 重新计时
|
||||||
await self.startCountdown()
|
await self.startCountdown()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// 重新倒计时
|
// 重新倒计时
|
||||||
private func startCountdown() async {
|
private func startCountdown() async {
|
||||||
@ -252,13 +285,15 @@ struct RegisterSubmitVerifyCodeView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 提交验证码
|
// 提交验证码
|
||||||
private func submitVerifyCode() {
|
private func submitVerifyCode(sessionId: Int) async {
|
||||||
self.isProcessing = true
|
self.isProcessing = true
|
||||||
Task { @MainActor in
|
defer {
|
||||||
|
self.isProcessing = false
|
||||||
|
}
|
||||||
do {
|
do {
|
||||||
_ = try await self.registerModel.submitVerifyCode(sessionId: sessionId, verifyCode: self.code)
|
_ = try await self.registerModel.submitVerifyCode(sessionId: sessionId, verifyCode: self.code)
|
||||||
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
||||||
self.registerModel.stage = .setPassword(sessionId: sessionId)
|
self.registerModel.stage = .setPassword
|
||||||
self.registerModel.transitionEdge = .trailing
|
self.registerModel.transitionEdge = .trailing
|
||||||
}
|
}
|
||||||
} catch let err as SDLAPIError {
|
} catch let err as SDLAPIError {
|
||||||
@ -268,16 +303,13 @@ struct RegisterSubmitVerifyCodeView: View {
|
|||||||
self.showAlert = true
|
self.showAlert = true
|
||||||
self.errorMessage = err.localizedDescription
|
self.errorMessage = err.localizedDescription
|
||||||
}
|
}
|
||||||
|
|
||||||
self.isProcessing = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - 第三步:设置密码
|
// MARK: - 第三步:设置密码
|
||||||
struct RegisterSetPasswordView: View {
|
struct RegisterSetPasswordView: View {
|
||||||
@Environment(RegisterModel.self) var registerModel
|
@Environment(RegisterModel.self) var registerModel: RegisterModel
|
||||||
let sessionId: Int
|
|
||||||
@State private var password = ""
|
@State private var password = ""
|
||||||
@State private var confirm = ""
|
@State private var confirm = ""
|
||||||
@State private var isProcessing = false
|
@State private var isProcessing = false
|
||||||
@ -318,7 +350,9 @@ struct RegisterSetPasswordView: View {
|
|||||||
.frame(width: 280)
|
.frame(width: 280)
|
||||||
|
|
||||||
Button(action: {
|
Button(action: {
|
||||||
self.handleRegister()
|
Task { @MainActor in
|
||||||
|
await self.handleRegister(sessionId: registerModel.sessionId)
|
||||||
|
}
|
||||||
}) {
|
}) {
|
||||||
if isProcessing {
|
if isProcessing {
|
||||||
ProgressView()
|
ProgressView()
|
||||||
@ -342,9 +376,11 @@ struct RegisterSetPasswordView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func handleRegister() {
|
private func handleRegister(sessionId: Int) async {
|
||||||
self.isProcessing = true
|
self.isProcessing = true
|
||||||
Task { @MainActor in
|
defer {
|
||||||
|
self.isProcessing = false
|
||||||
|
}
|
||||||
do {
|
do {
|
||||||
_ = try await self.registerModel.register(sessionId: sessionId, password: self.password)
|
_ = try await self.registerModel.register(sessionId: sessionId, password: self.password)
|
||||||
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
||||||
@ -358,15 +394,14 @@ struct RegisterSetPasswordView: View {
|
|||||||
self.showAlert = true
|
self.showAlert = true
|
||||||
self.errorMessage = "注册失败,重稍后重试"
|
self.errorMessage = "注册失败,重稍后重试"
|
||||||
}
|
}
|
||||||
self.isProcessing = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: 第四步 注册成功
|
// MARK: 第四步 注册成功
|
||||||
struct RegisterSuccessView: View {
|
struct RegisterSuccessView: View {
|
||||||
@Environment(\.dismiss) private var dismiss // 获取关闭窗口的能力
|
@Environment(AppContext.self) private var appContext: AppContext
|
||||||
|
@Environment(RegisterModel.self) private var registerModel: RegisterModel
|
||||||
|
|
||||||
// MARK: - 动画状态
|
// MARK: - 动画状态
|
||||||
@State private var animateIcon: Bool = false // 用于呼吸灯效果
|
@State private var animateIcon: Bool = false // 用于呼吸灯效果
|
||||||
@ -410,7 +445,9 @@ struct RegisterSuccessView: View {
|
|||||||
|
|
||||||
Button(action: {
|
Button(action: {
|
||||||
// 关闭当前注册窗口
|
// 关闭当前注册窗口
|
||||||
dismiss()
|
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
||||||
|
self.appContext.appScene = .login(username: registerModel.username)
|
||||||
|
}
|
||||||
}) {
|
}) {
|
||||||
Text("立即开始使用")
|
Text("立即开始使用")
|
||||||
.fontWeight(.bold)
|
.fontWeight(.bold)
|
||||||
|
|||||||
@ -12,7 +12,7 @@ import SwiftUI
|
|||||||
@Observable
|
@Observable
|
||||||
class ResetPasswordModel {
|
class ResetPasswordModel {
|
||||||
|
|
||||||
enum Stage {
|
enum Stage: Equatable {
|
||||||
case requestVerifyCode(username: String?)
|
case requestVerifyCode(username: String?)
|
||||||
case submitVerifyCode(username: String, sessionId: Int)
|
case submitVerifyCode(username: String, sessionId: Int)
|
||||||
case resetPassword(username: String, sessionId: Int)
|
case resetPassword(username: String, sessionId: Int)
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import Observation
|
|||||||
// MARK: - 1. 根视图
|
// MARK: - 1. 根视图
|
||||||
struct ResetPasswordRootView: View {
|
struct ResetPasswordRootView: View {
|
||||||
@State private var resetPasswordModel = ResetPasswordModel()
|
@State private var resetPasswordModel = ResetPasswordModel()
|
||||||
|
@Environment(AppContext.self) private var appContext: AppContext
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
@ -35,6 +36,30 @@ struct ResetPasswordRootView: View {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
.environment(resetPasswordModel)
|
.environment(resetPasswordModel)
|
||||||
|
.overlay(alignment: .topLeading) {
|
||||||
|
// 仅在非成功页面显示返回按钮
|
||||||
|
if resetPasswordModel.stage != .success {
|
||||||
|
Button(action: {
|
||||||
|
// 执行返回逻辑,例如重置到登录
|
||||||
|
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
||||||
|
self.appContext.appScene = .login(username: nil)
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
HStack {
|
||||||
|
Image(systemName: "chevron.left")
|
||||||
|
.font(.system(size: 16, weight: .semibold))
|
||||||
|
.padding(5)
|
||||||
|
|
||||||
|
Text("首页")
|
||||||
|
.font(.system(size: 16, weight: .regular))
|
||||||
|
}
|
||||||
|
.contentShape(Rectangle()) // 扩大点击热区
|
||||||
|
}
|
||||||
|
.buttonStyle(.plain)
|
||||||
|
.padding([.top, .leading], 16) // 控制距离窗口边缘的边距
|
||||||
|
.transition(.opacity) // 按钮出现的动画
|
||||||
|
}
|
||||||
|
}
|
||||||
.frame(width: 500, height: 400)
|
.frame(width: 500, height: 400)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,7 +18,7 @@ struct RootView: View {
|
|||||||
// 主要界面
|
// 主要界面
|
||||||
Group {
|
Group {
|
||||||
switch appContext.appScene {
|
switch appContext.appScene {
|
||||||
case .login:
|
case .login(username: let username):
|
||||||
LoginView()
|
LoginView()
|
||||||
case .logined:
|
case .logined:
|
||||||
NetworkView()
|
NetworkView()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user