Files
e-party-iOS/yana/Views/AppSettingView.swift
edwinQQQ 71c40e465d feat: 更新AppSettingFeature以增强用户设置功能
- 重构AppSettingFeature,采用@Reducer和@ObservableState以优化状态管理。
- 新增用户信息加载逻辑,支持从服务器获取用户信息并更新界面。
- 更新AppSettingView,整合头像、昵称及其他设置项的展示,提升用户体验。
- 增加多语言支持,更新Localizable.strings文件以适应新的设置项。
2025-07-24 11:24:04 +08:00

259 lines
8.9 KiB
Swift

import SwiftUI
import ComposableArchitecture
struct AppSettingView: View {
let store: StoreOf<AppSettingFeature>
var body: some View {
WithViewStore(self.store, observe: { $0 }) { viewStore in
ZStack {
Color(red: 22/255, green: 17/255, blue: 44/255).ignoresSafeArea()
// VStack(spacing: 0) {
//
VStack(spacing: 0) {
//
avatarSection(viewStore: viewStore)
//
nicknameSection(viewStore: viewStore)
//
settingsSection(viewStore: viewStore)
Spacer()
//
logoutButton(viewStore: viewStore)
}
// }
}
.navigationTitle(NSLocalizedString("appSetting.title", comment: "Edit"))
.navigationBarTitleDisplayMode(.inline)
.toolbarBackground(.hidden, for: .navigationBar)
.toolbarColorScheme(.dark, for: .navigationBar)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button(action: {}) {
Image(systemName: "chevron.left")
.font(.system(size: 24, weight: .medium))
.foregroundColor(.white)
}
}
}
.onAppear {
viewStore.send(.onAppear)
}
.webView(
isPresented: userAgreementBinding(viewStore: viewStore),
url: APIConfiguration.webURL(for: .userAgreement)
)
.webView(
isPresented: privacyPolicyBinding(viewStore: viewStore),
url: APIConfiguration.webURL(for: .privacyPolicy)
)
}
}
// MARK: -
private func avatarSection(viewStore: ViewStoreOf<AppSettingFeature>) -> some View {
ZStack(alignment: .bottomTrailing) {
avatarImageView(viewStore: viewStore)
cameraButton
}
.padding(.top, 24)
}
// MARK: -
@ViewBuilder
private func avatarImageView(viewStore: ViewStoreOf<AppSettingFeature>) -> some View {
if viewStore.isLoadingUserInfo {
loadingAvatarView
} else if let avatarURLString = viewStore.avatarURL, !avatarURLString.isEmpty, let avatarURL = URL(string: avatarURLString) {
networkAvatarView(url: avatarURL)
} else {
defaultAvatarView
}
}
// MARK: -
private var loadingAvatarView: some View {
Circle()
.fill(Color.gray.opacity(0.3))
.frame(width: 120, height: 120)
.overlay(
ProgressView()
.progressViewStyle(CircularProgressViewStyle(tint: .white))
.scaleEffect(1.2)
)
}
// MARK: -
private func networkAvatarView(url: URL) -> some View {
CachedAsyncImage(url: url.absoluteString) { image in
image
.resizable()
.aspectRatio(contentMode: .fill)
} placeholder: {
defaultAvatarView
}
.frame(width: 120, height: 120)
.clipShape(Circle())
}
// MARK: -
private var defaultAvatarView: some View {
Circle()
.fill(Color.gray.opacity(0.3))
.frame(width: 120, height: 120)
.overlay(
Image(systemName: "person.fill")
.font(.system(size: 40))
.foregroundColor(.white)
)
}
// MARK: -
private var cameraButton: some View {
Button(action: {}) {
ZStack {
Circle().fill(Color.purple).frame(width: 36, height: 36)
Image(systemName: "camera.fill")
.foregroundColor(.white)
}
}
.offset(x: 8, y: 8)
}
// MARK: -
private func nicknameSection(viewStore: ViewStoreOf<AppSettingFeature>) -> some View {
VStack(spacing: 0) {
HStack {
Text(NSLocalizedString("appSetting.nickname", comment: "Nickname"))
.foregroundColor(.white)
Spacer()
Text(viewStore.nickname)
.foregroundColor(.gray)
Image(systemName: "chevron.right")
.foregroundColor(.gray)
}
.padding(.horizontal, 32)
.padding(.vertical, 18)
.onTapGesture {
viewStore.send(.editNicknameTapped)
}
Divider().background(Color.gray.opacity(0.3))
.padding(.horizontal, 32)
}
}
// MARK: -
private func settingsSection(viewStore: ViewStoreOf<AppSettingFeature>) -> some View {
VStack(spacing: 0) {
personalInfoPermissionsRow(viewStore: viewStore)
helpRow(viewStore: viewStore)
clearCacheRow(viewStore: viewStore)
checkUpdatesRow(viewStore: viewStore)
aboutUsRow(viewStore: viewStore)
}
.background(Color.clear)
.padding(.horizontal, 0)
}
// MARK: -
private func personalInfoPermissionsRow(viewStore: ViewStoreOf<AppSettingFeature>) -> some View {
settingRow(
title: NSLocalizedString("appSetting.personalInfoPermissions", comment: "Personal Information and Permissions"),
action: { viewStore.send(.personalInfoPermissionsTapped) }
)
}
// MARK: -
private func helpRow(viewStore: ViewStoreOf<AppSettingFeature>) -> some View {
settingRow(
title: NSLocalizedString("appSetting.help", comment: "Help"),
action: { viewStore.send(.helpTapped) }
)
}
// MARK: -
private func clearCacheRow(viewStore: ViewStoreOf<AppSettingFeature>) -> some View {
settingRow(
title: NSLocalizedString("appSetting.clearCache", comment: "Clear Cache"),
action: { viewStore.send(.clearCacheTapped) }
)
}
// MARK: -
private func checkUpdatesRow(viewStore: ViewStoreOf<AppSettingFeature>) -> some View {
settingRow(
title: NSLocalizedString("appSetting.checkUpdates", comment: "Check for Updates"),
action: { viewStore.send(.checkUpdatesTapped) }
)
}
// MARK: -
private func aboutUsRow(viewStore: ViewStoreOf<AppSettingFeature>) -> some View {
settingRow(
title: NSLocalizedString("appSetting.aboutUs", comment: "About Us"),
action: { viewStore.send(.aboutUsTapped) }
)
}
// MARK: -
private func settingRow(title: String, action: @escaping () -> Void) -> some View {
VStack(spacing: 0) {
HStack {
Text(title)
.foregroundColor(.white)
Spacer()
Image(systemName: "chevron.right")
.foregroundColor(.gray)
}
.padding(.horizontal, 32)
.padding(.vertical, 18)
.onTapGesture {
action()
}
Divider().background(Color.gray.opacity(0.3))
.padding(.horizontal, 32)
}
}
// MARK: - 退
private func logoutButton(viewStore: ViewStoreOf<AppSettingFeature>) -> some View {
Button(action: {
viewStore.send(.logoutTapped)
}) {
Text(NSLocalizedString("appSetting.logoutAccount", comment: "Log out of account"))
.font(.system(size: 18, weight: .semibold))
.foregroundColor(.white)
.frame(maxWidth: .infinity)
.padding(.vertical, 18)
.background(Color.white.opacity(0.08))
.cornerRadius(28)
.padding(.horizontal, 32)
}
.padding(.bottom, 32)
}
// MARK: -
private func userAgreementBinding(viewStore: ViewStoreOf<AppSettingFeature>) -> Binding<Bool> {
viewStore.binding(
get: \.showUserAgreement,
send: AppSettingFeature.Action.userAgreementDismissed
)
}
// MARK: -
private func privacyPolicyBinding(viewStore: ViewStoreOf<AppSettingFeature>) -> Binding<Bool> {
viewStore.binding(
get: \.showPrivacyPolicy,
send: AppSettingFeature.Action.privacyPolicyDismissed
)
}
}