Files
e-party-iOS/yana/Views/LoginView.swift
edwinQQQ b35b6e1ce1 feat: 移除CreateFeedView-Analysis文档并新增用户协议组件以增强用户体验
- 删除CreateFeedView-Analysis.md文档以简化项目结构。
- 新增UserAgreementComponent以处理用户协议的显示和交互。
- 更新多个视图中的onChange逻辑以兼容iOS 17的新API用法,确保代码一致性和可维护性。
- 在Localizable.strings中新增用户协议相关的本地化文本,提升多语言支持。
2025-08-01 14:34:53 +08:00

201 lines
6.6 KiB
Swift

import SwiftUI
import ComposableArchitecture
import Perception
struct LoginView: View {
let store: StoreOf<LoginFeature>
let onLoginSuccess: () -> Void
// 使@StateUI
@State private var showIDLogin: Bool = false
@State private var showEmailLogin: Bool = false
@State private var showLanguageSettings: Bool = false
@State private var showUserAgreement: Bool = false
@State private var showPrivacyPolicy: Bool = false
@State private var isAgreementAccepted: Bool = true //
@State private var showAgreementAlert: Bool = false
var body: some View {
NavigationStack {
GeometryReader { geometry in
ZStack {
backgroundView
VStack(spacing: 0) {
Image("top")
.resizable()
.aspectRatio(375/400, contentMode: .fit)
.frame(maxWidth: .infinity)
HStack {
Text(LocalizedString("login.app_title", comment: ""))
.font(FontManager.adaptedFont(.bayonRegular, designSize: 56, for: geometry.size.width))
.foregroundColor(.white)
.padding(.leading, 20)
Spacer()
}
.padding(.bottom, 20) // top
Spacer()
bottomSection
}
// -
languageSettingsButton
.position(x: geometry.size.width - 40, y: 60)
APILoadingEffectView()
}
}
.ignoresSafeArea()
.navigationBarHidden(true)
.navigationDestination(isPresented: $showIDLogin) {
IDLoginView(
store: store.scope(
state: \.idLoginState,
action: \.idLogin
),
onBack: {
showIDLogin = false
},
showIDLogin: $showIDLogin
)
.navigationBarHidden(true)
}
.navigationDestination(isPresented: $showEmailLogin) {
EMailLoginView(
store: store.scope(
state: \.emailLoginState,
action: \.emailLogin
),
onBack: {
showEmailLogin = false
},
showEmailLogin: $showEmailLogin
)
.navigationBarHidden(true)
}
.sheet(isPresented: $showLanguageSettings) {
LanguageSettingsView(isPresented: $showLanguageSettings)
}
.webView(
isPresented: $showUserAgreement,
url: APIConfiguration.webURL(for: .userAgreement)
)
.webView(
isPresented: $showPrivacyPolicy,
url: APIConfiguration.webURL(for: .privacyPolicy)
)
.alert(LocalizedString("login.agreement_alert_title", comment: ""), isPresented: $showAgreementAlert) {
Button(LocalizedString("login.agreement_alert_confirm", comment: "")) { }
} message: {
Text(LocalizedString("login.agreement_alert_message", comment: ""))
}
.onChange(of: store.isAnyLoginCompleted) { _, isAnyLoginCompleted in
if isAnyLoginCompleted {
onLoginSuccess()
}
}
.onChange(of: showIDLogin) { _, showIDLogin in
if showIDLogin == false && store.isAnyLoginCompleted {
onLoginSuccess()
}
}
.onChange(of: showEmailLogin) { _, showEmailLogin in
if showEmailLogin == false && store.isAnyLoginCompleted {
onLoginSuccess()
}
}
}
}
// MARK: -
private var backgroundView: some View {
Image("bg")
.resizable()
.aspectRatio(contentMode: .fill)
.ignoresSafeArea(.all)
}
private var bottomSection: some View {
VStack(spacing: 20) {
loginButtons
userAgreementComponent
}
.padding(.horizontal, 28)
.padding(.bottom, 48)
}
private var loginButtons: some View {
VStack(spacing: 20) {
LoginButton(
iconName: "person.circle",
iconColor: .blue,
title: LocalizedString("login.id_login", comment: ""),
action: {
if isAgreementAccepted {
showIDLogin = true
} else {
showAgreementAlert = true
}
}
)
LoginButton(
iconName: "envelope",
iconColor: .green,
title: LocalizedString("login.email_login", comment: ""),
action: {
if isAgreementAccepted {
showEmailLogin = true
} else {
showAgreementAlert = true
}
}
)
}
}
private var languageSettingsButton: some View {
Button(action: {
showLanguageSettings = true
}) {
Image(systemName: "globe")
.font(.system(size: 20))
.foregroundColor(.white.opacity(0.8))
}
}
private var userAgreementComponent: some View {
UserAgreementComponent(
isAgreed: $isAgreementAccepted,
onAgreementTap: {
Task { @MainActor in
showUserAgreement = true
}
},
onPolicyTap: {
Task { @MainActor in
showPrivacyPolicy = true
}
}
)
.frame(height: 40)
.padding(.horizontal, -20)
}
}
//#Preview {
// LoginView(
// store: Store(
// initialState: LoginFeature.State()
// ) {
// LoginFeature()
// },
// onLoginSuccess: {}
// )
//}