feat: 更新iOS和Podfile的部署目标以支持新版本

- 将iOS平台版本更新至17,确保与最新的开发环境兼容。
- 更新Podfile中的iOS部署目标至17.0,确保依赖项与新版本兼容。
- 修改Podfile.lock以反映新的依赖项版本,确保项目一致性。
- 在多个视图中重构代码,优化状态管理和视图逻辑,提升用户体验。
This commit is contained in:
edwinQQQ
2025-07-29 15:59:09 +08:00
parent 567b1f3fd9
commit 3ec1b1302f
12 changed files with 1053 additions and 1131 deletions

View File

@@ -5,37 +5,41 @@ import Combine
struct EMailLoginView: View {
let store: StoreOf<EMailLoginFeature>
let onBack: () -> Void
@Binding var showEmailLogin: Bool
@Binding var showEmailLogin: Bool //
// 使@StateUI
@State private var email: String = ""
@State private var verificationCode: String = ""
@State private var codeCountdown: Int = 0
@State private var timerCancellable: AnyCancellable?
@FocusState private var focusedField: Field?
//
@State private var timerCancellable: AnyCancellable?
//
private var isLoginButtonEnabled: Bool {
return !store.isLoading && !email.isEmpty && !verificationCode.isEmpty
}
private var getCodeButtonText: String {
if codeCountdown > 0 {
return "\(codeCountdown)s"
} else {
return LocalizedString("email_login.get_code", comment: "")
}
}
private var isCodeButtonEnabled: Bool {
return !store.isCodeLoading && codeCountdown == 0 && !email.isEmpty
}
enum Field {
case email
case verificationCode
}
private var isLoginButtonEnabled: Bool {
return !store.isLoading && !email.isEmpty && !verificationCode.isEmpty
}
private var getCodeButtonText: String {
if store.isCodeLoading {
return ""
} else if codeCountdown > 0 {
return "\(codeCountdown)S"
} else {
return LocalizedString("email_login.get_code", comment: "")
}
}
private var isCodeButtonEnabled: Bool {
return !store.isCodeLoading && codeCountdown == 0
}
var body: some View {
WithViewStore(store, observe: { $0.loginStep }) { viewStore in
WithPerceptionTracking {
LoginContentView(
store: store,
onBack: onBack,
@@ -47,7 +51,7 @@ struct EMailLoginView: View {
getCodeButtonText: getCodeButtonText,
isCodeButtonEnabled: isCodeButtonEnabled
)
.onChange(of: viewStore.state) { newStep in
.onChange(of: store.loginStep) { newStep in
debugInfoSync("🔄 EMailLoginView: loginStep 变化为 \(newStep)")
if newStep == .completed {
debugInfoSync("✅ EMailLoginView: 登录成功,准备关闭自身")
@@ -151,115 +155,112 @@ private struct LoginContentView: View {
.font(.system(size: 28, weight: .medium))
.foregroundColor(.white)
.padding(.bottom, 80)
VStack(spacing: 24) {
ZStack {
RoundedRectangle(cornerRadius: 25)
.fill(Color.white.opacity(0.1))
.overlay(
RoundedRectangle(cornerRadius: 25)
.stroke(Color.white.opacity(0.3), lineWidth: 1)
)
.frame(height: 56)
VStack(spacing: 20) {
//
VStack(alignment: .leading, spacing: 8) {
HStack {
Image("email icon")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 20, height: 20)
Text(LocalizedString("email_login.email", comment: ""))
.font(.system(size: 16))
.foregroundColor(.white)
}
TextField("", text: $email)
.placeholder(when: email.isEmpty) {
Text(NSLocalizedString("placeholder.enter_email", comment: ""))
.foregroundColor(.white.opacity(0.6))
}
.foregroundColor(.white)
.textFieldStyle(PlainTextFieldStyle())
.font(.system(size: 16))
.padding(.horizontal, 24)
.keyboardType(.emailAddress)
.foregroundColor(.white)
.padding(.horizontal, 16)
.padding(.vertical, 12)
.background(Color.white.opacity(0.1))
.cornerRadius(8)
.focused($focusedField, equals: .email)
.keyboardType(.emailAddress)
.autocapitalization(.none)
}
ZStack {
RoundedRectangle(cornerRadius: 25)
.fill(Color.white.opacity(0.1))
.overlay(
RoundedRectangle(cornerRadius: 25)
.stroke(Color.white.opacity(0.3), lineWidth: 1)
)
.frame(height: 56)
//
VStack(alignment: .leading, spacing: 8) {
HStack {
Image("id icon")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 20, height: 20)
Text(LocalizedString("email_login.verification_code", comment: ""))
.font(.system(size: 16))
.foregroundColor(.white)
}
HStack {
TextField("", text: $verificationCode)
.placeholder(when: verificationCode.isEmpty) {
Text(NSLocalizedString("placeholder.enter_code", comment: ""))
.foregroundColor(.white.opacity(0.6))
}
.foregroundColor(.white)
.textFieldStyle(PlainTextFieldStyle())
.font(.system(size: 16))
.keyboardType(.numberPad)
.foregroundColor(.white)
.padding(.horizontal, 16)
.padding(.vertical, 12)
.background(Color.white.opacity(0.1))
.cornerRadius(8)
.focused($focusedField, equals: .verificationCode)
.keyboardType(.numberPad)
Button(action: {
store.send(.getVerificationCodeTapped)
store.send(.getVerificationCodeButtonTapped)
}) {
ZStack {
if store.isCodeLoading {
ProgressView()
.progressViewStyle(CircularProgressViewStyle(tint: .white))
.scaleEffect(0.7)
} else {
Text(getCodeButtonText)
.font(.system(size: 14, weight: .medium))
.foregroundColor(.white)
}
}
.frame(width: 60, height: 36)
.background(
RoundedRectangle(cornerRadius: 18)
.fill(Color.white.opacity(isCodeButtonEnabled && !email.isEmpty ? 0.2 : 0.1))
)
Text(getCodeButtonText)
.font(.system(size: 14, weight: .medium))
.foregroundColor(.white)
.padding(.horizontal, 16)
.padding(.vertical, 12)
.background(isCodeButtonEnabled ? Color.blue : Color.gray)
.cornerRadius(8)
}
.disabled(!isCodeButtonEnabled || email.isEmpty || store.isCodeLoading)
.disabled(!isCodeButtonEnabled)
}
.padding(.horizontal, 24)
}
}
.padding(.horizontal, 32)
Spacer().frame(height: 60)
Button(action: {
store.send(.loginButtonTapped(email: email, verificationCode: verificationCode))
}) {
ZStack {
LinearGradient(
colors: [
Color(red: 0.85, green: 0.37, blue: 1.0),
Color(red: 0.54, green: 0.31, blue: 1.0)
],
startPoint: .leading,
endPoint: .trailing
)
.clipShape(RoundedRectangle(cornerRadius: 28))
HStack {
if store.isLoading {
ProgressView()
.progressViewStyle(CircularProgressViewStyle(tint: .white))
.scaleEffect(0.8)
}
Text(store.isLoading ? LocalizedString("email_login.logging_in", comment: "") : LocalizedString("email_login.login_button", comment: ""))
.font(.system(size: 18, weight: .semibold))
//
Button(action: {
store.send(.loginButtonTapped)
}) {
if store.isLoading {
ProgressView()
.progressViewStyle(CircularProgressViewStyle(tint: .white))
.scaleEffect(1.2)
} else {
Text(LocalizedString("email_login.login", comment: ""))
.font(.system(size: 16, weight: .medium))
.foregroundColor(.white)
}
}
.frame(height: 56)
.frame(maxWidth: .infinity)
.padding(.vertical, 16)
.background(isLoginButtonEnabled ? Color.blue : Color.gray)
.cornerRadius(8)
.disabled(!isLoginButtonEnabled)
.padding(.top, 20)
//
if let errorMessage = store.errorMessage {
Text(errorMessage)
.font(.system(size: 14))
.foregroundColor(.red)
.padding(.top, 16)
.padding(.horizontal, 32)
}
Spacer()
}
.disabled(store.isLoading || email.isEmpty || verificationCode.isEmpty)
.opacity(isLoginButtonEnabled ? 1.0 : 0.5)
.padding(.horizontal, 32)
if let errorMessage = store.errorMessage {
Text(errorMessage)
.font(.system(size: 14))
.foregroundColor(.red)
.padding(.top, 16)
.padding(.horizontal, 32)
}
Spacer()
// API Loading
APILoadingEffectView()
}
// API Loading
APILoadingEffectView()
}
}
}
.navigationBarHidden(true)
}
}