
- 在AppSettingFeature中新增登出确认和关于我们弹窗的状态和Action。 - 更新AppSettingView以支持登出确认和关于我们弹窗的逻辑。 - 替换多个视图中的NSLocalizedString为LocalizedString,提升本地化一致性。 - 在Localizable.strings中新增相关本地化文本,确保多语言支持。
199 lines
6.2 KiB
Swift
199 lines
6.2 KiB
Swift
import SwiftUI
|
|
import ComposableArchitecture
|
|
import Perception
|
|
|
|
// PreferenceKey 用于传递图片高度
|
|
struct ImageHeightPreferenceKey: PreferenceKey {
|
|
static let defaultValue: CGFloat = 0
|
|
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
|
|
value = max(value, nextValue())
|
|
}
|
|
}
|
|
|
|
struct LoginView: View {
|
|
let store: StoreOf<LoginFeature>
|
|
let onLoginSuccess: () -> Void
|
|
|
|
// 使用本地@State管理UI状态
|
|
@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
|
|
|
|
var body: some View {
|
|
NavigationStack {
|
|
GeometryReader { geometry in
|
|
ZStack {
|
|
backgroundView
|
|
mainContentView(geometry: geometry)
|
|
APILoadingEffectView()
|
|
}
|
|
}
|
|
.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)
|
|
)
|
|
.onChange(of: store.isAnyLoginCompleted) {
|
|
if store.isAnyLoginCompleted {
|
|
onLoginSuccess()
|
|
}
|
|
}
|
|
.onChange(of: showIDLogin) {
|
|
if showIDLogin == false && store.isAnyLoginCompleted {
|
|
onLoginSuccess()
|
|
}
|
|
}
|
|
.onChange(of: showEmailLogin) {
|
|
if showEmailLogin == false && store.isAnyLoginCompleted {
|
|
onLoginSuccess()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - 子视图
|
|
|
|
private var backgroundView: some View {
|
|
Image("bg")
|
|
.resizable()
|
|
.aspectRatio(contentMode: .fill)
|
|
.ignoresSafeArea(.all)
|
|
}
|
|
|
|
private func mainContentView(geometry: GeometryProxy) -> some View {
|
|
VStack(spacing: 0) {
|
|
topSection(geometry: geometry)
|
|
bottomSection
|
|
}
|
|
}
|
|
|
|
private func topSection(geometry: GeometryProxy) -> some View {
|
|
ZStack {
|
|
Image("top")
|
|
.resizable()
|
|
.aspectRatio(contentMode: .fit)
|
|
.frame(maxWidth: .infinity)
|
|
.padding(.top, -100)
|
|
.background(
|
|
GeometryReader { topImageGeometry in
|
|
Color.clear.preference(key: ImageHeightPreferenceKey.self, value: topImageGeometry.size.height)
|
|
}
|
|
)
|
|
|
|
HStack {
|
|
Text(LocalizedString("login.app_title", comment: ""))
|
|
.font(FontManager.adaptedFont(.bayonRegular, designSize: 56, for: geometry.size.width))
|
|
.foregroundColor(.white)
|
|
.padding(.leading, 20)
|
|
Spacer()
|
|
}
|
|
.padding(.top, 100) // 简化计算逻辑
|
|
}
|
|
}
|
|
|
|
private var bottomSection: some View {
|
|
VStack(spacing: 20) {
|
|
loginButtons
|
|
bottomButtons
|
|
}
|
|
.padding(.horizontal, 28)
|
|
.padding(.bottom, 140)
|
|
}
|
|
|
|
private var loginButtons: some View {
|
|
VStack(spacing: 20) {
|
|
LoginButton(
|
|
iconName: "person.circle",
|
|
iconColor: .blue,
|
|
title: LocalizedString("login.id_login", comment: ""),
|
|
action: {
|
|
showIDLogin = true
|
|
}
|
|
)
|
|
|
|
LoginButton(
|
|
iconName: "envelope",
|
|
iconColor: .green,
|
|
title: LocalizedString("login.email_login", comment: ""),
|
|
action: {
|
|
showEmailLogin = true
|
|
}
|
|
)
|
|
}
|
|
}
|
|
|
|
private var bottomButtons: some View {
|
|
HStack(spacing: 20) {
|
|
Button(action: {
|
|
showLanguageSettings = true
|
|
}) {
|
|
Text(LocalizedString("setting.language", comment: ""))
|
|
.font(.system(size: 14))
|
|
.foregroundColor(.white.opacity(0.8))
|
|
}
|
|
|
|
Button(action: {
|
|
showUserAgreement = true
|
|
}) {
|
|
Text(LocalizedString("login.agreement", comment: ""))
|
|
.font(.system(size: 14))
|
|
.foregroundColor(.white.opacity(0.8))
|
|
}
|
|
|
|
Button(action: {
|
|
showPrivacyPolicy = true
|
|
}) {
|
|
Text(LocalizedString("login.policy", comment: ""))
|
|
.font(.system(size: 14))
|
|
.foregroundColor(.white.opacity(0.8))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//#Preview {
|
|
// LoginView(
|
|
// store: Store(
|
|
// initialState: LoginFeature.State()
|
|
// ) {
|
|
// LoginFeature()
|
|
// },
|
|
// onLoginSuccess: {}
|
|
// )
|
|
//}
|