
- 重构AppSettingFeature,采用@Reducer和@ObservableState以优化状态管理。 - 新增用户信息加载逻辑,支持从服务器获取用户信息并更新界面。 - 更新AppSettingView,整合头像、昵称及其他设置项的展示,提升用户体验。 - 增加多语言支持,更新Localizable.strings文件以适应新的设置项。
259 lines
8.9 KiB
Swift
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
|
|
)
|
|
}
|
|
}
|