ChangePasswordModalView.swift 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. import SwiftUI
  2. /// Modal Sheet allowing logged-in users to change their password.
  3. struct ChangePasswordModalView: View {
  4. @Environment(\.dismiss) private var dismiss
  5. @ObservedObject var authManager: AuthManager = .shared
  6. @State private var oldPasswordInput: String = ""
  7. @State private var newPasswordInput: String = ""
  8. @State private var confirmPasswordInput: String = ""
  9. @State private var errorMessage: String?
  10. @State private var successToast: String?
  11. var body: some View {
  12. ZStack {
  13. Color.spaceBlack.ignoresSafeArea()
  14. VStack(spacing: 20) {
  15. // Header
  16. HStack {
  17. Text("修改密码")
  18. .font(.system(size: 18, weight: .bold))
  19. .foregroundStyle(Color.primary)
  20. Spacer()
  21. Button {
  22. dismiss()
  23. } label: {
  24. Image(systemName: "xmark.circle.fill")
  25. .font(.system(size: 22))
  26. .foregroundStyle(Color.secondary.opacity(0.6))
  27. }
  28. }
  29. .padding(.horizontal, 20)
  30. .padding(.top, 20)
  31. VStack(spacing: 14) {
  32. passwordField(label: "当前原密码", text: $oldPasswordInput, placeholder: "请输入当前账号原密码")
  33. passwordField(label: "新密码", text: $newPasswordInput, placeholder: "请输入新密码 (不少于 6 位)")
  34. passwordField(label: "确认新密码", text: $confirmPasswordInput, placeholder: "请再次输入新密码")
  35. if let error = errorMessage {
  36. Text(error)
  37. .font(.system(size: 12))
  38. .foregroundStyle(Color.recordingRed)
  39. .frame(maxWidth: .infinity, alignment: .leading)
  40. }
  41. if let toast = successToast {
  42. Text(toast)
  43. .font(.system(size: 12))
  44. .foregroundStyle(Color.green)
  45. .frame(maxWidth: .infinity, alignment: .leading)
  46. }
  47. }
  48. .padding(.horizontal, 20)
  49. .padding(.top, 10)
  50. Spacer()
  51. Button {
  52. handleChangePassword()
  53. } label: {
  54. if authManager.isProcessing {
  55. ProgressView()
  56. .tint(Color.spaceBlack)
  57. } else {
  58. Text("确认修改密码")
  59. .font(.system(size: 15, weight: .semibold))
  60. .foregroundStyle(Color.spaceBlack)
  61. }
  62. }
  63. .frame(maxWidth: .infinity)
  64. .padding(.vertical, 14)
  65. .background(Color.primary)
  66. .cornerRadius(8)
  67. .padding(.horizontal, 20)
  68. .padding(.bottom, 24)
  69. .disabled(authManager.isProcessing)
  70. }
  71. }
  72. }
  73. private func passwordField(label: String, text: Binding<String>, placeholder: String) -> some View {
  74. VStack(alignment: .leading, spacing: 6) {
  75. Text(label)
  76. .font(.system(size: 12))
  77. .foregroundStyle(Color.secondary)
  78. HStack(spacing: 12) {
  79. Image(systemName: "lock")
  80. .font(.system(size: 14))
  81. .foregroundStyle(Color.secondary)
  82. .frame(width: 20)
  83. SecureField(placeholder, text: text)
  84. .font(.system(size: 14))
  85. }
  86. .padding(.horizontal, 14)
  87. .padding(.vertical, 12)
  88. .background(Color.cardBackground.opacity(0.3))
  89. .businessBorder(cornerRadius: 8)
  90. }
  91. }
  92. private func handleChangePassword() {
  93. errorMessage = nil
  94. successToast = nil
  95. guard !oldPasswordInput.isEmpty else {
  96. errorMessage = "请输入原密码"
  97. return
  98. }
  99. guard newPasswordInput.count >= 6 else {
  100. errorMessage = "新密码长度不能少于 6 位"
  101. return
  102. }
  103. guard newPasswordInput == confirmPasswordInput else {
  104. errorMessage = "两次输入的无缝新密码不一致"
  105. return
  106. }
  107. authManager.changePassword(oldPassword: oldPasswordInput, newPassword: newPasswordInput) { success, err in
  108. if success {
  109. successToast = "密码修改成功!请记牢新密码"
  110. DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
  111. dismiss()
  112. }
  113. } else {
  114. errorMessage = err ?? "原密码错误或修改失败"
  115. }
  116. }
  117. }
  118. }