
- 将iOS平台版本更新至17,确保与最新的开发环境兼容。 - 更新Podfile中的iOS部署目标至17.0,确保依赖项与新版本兼容。 - 修改Podfile.lock以反映新的依赖项版本,确保项目一致性。 - 在多个视图中重构代码,优化状态管理和视图逻辑,提升用户体验。
358 lines
14 KiB
Swift
358 lines
14 KiB
Swift
//
|
||
// AppSettingView.swift
|
||
// yana
|
||
//
|
||
// Created by Edwin on 2024/11/20.
|
||
//
|
||
|
||
import SwiftUI
|
||
import ComposableArchitecture
|
||
import PhotosUI
|
||
|
||
struct AppSettingView: View {
|
||
let store: StoreOf<AppSettingFeature>
|
||
// 直接let声明pickerStore
|
||
let pickerStore = Store(
|
||
initialState: ImagePickerWithPreviewReducer.State(inner: ImagePickerWithPreviewState(selectionMode: .single)),
|
||
reducer: { ImagePickerWithPreviewReducer() }
|
||
)
|
||
@State private var showNicknameAlert = false
|
||
@State private var nicknameInput = ""
|
||
@State private var showImagePickerSheet = false
|
||
@State private var showActionSheet = false
|
||
@State private var showPhotoPicker = false
|
||
@State private var showCamera = false
|
||
@State private var selectedPhotoItems: [PhotosPickerItem] = []
|
||
@State private var selectedImages: [UIImage] = []
|
||
@State private var cameraImage: UIImage? = nil
|
||
@State private var previewIndex: Int = 0
|
||
@State private var showPreview = false
|
||
@State private var isLoading = false
|
||
@State private var errorMessage: String? = nil
|
||
|
||
var body: some View {
|
||
WithPerceptionTracking {
|
||
mainView()
|
||
}
|
||
}
|
||
|
||
@ViewBuilder
|
||
private func mainView() -> some View {
|
||
WithPerceptionTracking {
|
||
GeometryReader { geometry in
|
||
ZStack {
|
||
// 背景图片
|
||
Image("bg")
|
||
.resizable()
|
||
.aspectRatio(contentMode: .fill)
|
||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||
.clipped()
|
||
.ignoresSafeArea(.all)
|
||
|
||
VStack(spacing: 0) {
|
||
// 顶部导航栏
|
||
HStack {
|
||
Button(action: {
|
||
store.send(.dismissTapped)
|
||
}) {
|
||
Image(systemName: "chevron.left")
|
||
.font(.system(size: 24, weight: .medium))
|
||
.foregroundColor(.white)
|
||
.frame(width: 44, height: 44)
|
||
}
|
||
|
||
Spacer()
|
||
|
||
Text(LocalizedString("app_settings.title", comment: "设置"))
|
||
.font(.system(size: 18, weight: .medium))
|
||
.foregroundColor(.white)
|
||
|
||
Spacer()
|
||
|
||
// 占位,保持标题居中
|
||
Color.clear
|
||
.frame(width: 44, height: 44)
|
||
}
|
||
.padding(.horizontal, 16)
|
||
.padding(.top, 8)
|
||
|
||
// 主要内容区域
|
||
ScrollView {
|
||
VStack(spacing: 20) {
|
||
// 头像设置区域
|
||
avatarSection()
|
||
|
||
// 个人信息设置区域
|
||
personalInfoSection()
|
||
|
||
// 其他设置区域
|
||
otherSettingsSection()
|
||
|
||
// 退出登录按钮
|
||
logoutSection()
|
||
}
|
||
.padding(.horizontal, 20)
|
||
.padding(.top, 20)
|
||
.padding(.bottom, 40)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
.navigationBarHidden(true)
|
||
// 头像选择器
|
||
.sheet(isPresented: $showImagePickerSheet) {
|
||
ImagePickerWithPreviewView(
|
||
store: pickerStore,
|
||
onUpload: { images in
|
||
if let firstImage = images.first,
|
||
let imageData = firstImage.jpegData(compressionQuality: 0.8) {
|
||
store.send(AppSettingFeature.Action.avatarSelected(imageData))
|
||
}
|
||
showImagePickerSheet = false
|
||
},
|
||
onCancel: {
|
||
showImagePickerSheet = false
|
||
}
|
||
)
|
||
}
|
||
// 相机拍照
|
||
.sheet(isPresented: $showCamera) {
|
||
ImagePickerWithPreviewView(
|
||
store: pickerStore,
|
||
onUpload: { images in
|
||
if let firstImage = images.first,
|
||
let imageData = firstImage.jpegData(compressionQuality: 0.8) {
|
||
store.send(AppSettingFeature.Action.avatarSelected(imageData))
|
||
}
|
||
showCamera = false
|
||
},
|
||
onCancel: {
|
||
showCamera = false
|
||
}
|
||
)
|
||
}
|
||
// 昵称编辑弹窗
|
||
.alert(LocalizedString("app_settings.edit_nickname", comment: "编辑昵称"), isPresented: $showNicknameAlert) {
|
||
TextField(LocalizedString("app_settings.nickname_placeholder", comment: "请输入昵称"), text: $nicknameInput)
|
||
Button(LocalizedString("app_settings.cancel", comment: "取消")) {
|
||
showNicknameAlert = false
|
||
nicknameInput = ""
|
||
}
|
||
Button(LocalizedString("app_settings.confirm", comment: "确认")) {
|
||
let trimmed = nicknameInput.trimmingCharacters(in: .whitespacesAndNewlines)
|
||
if !trimmed.isEmpty {
|
||
store.send(.nicknameEditConfirmed(trimmed))
|
||
}
|
||
showNicknameAlert = false
|
||
nicknameInput = ""
|
||
}
|
||
} message: {
|
||
Text(LocalizedString("app_settings.nickname_tip", comment: "请输入新的昵称"))
|
||
}
|
||
}
|
||
}
|
||
|
||
// MARK: - 头像设置区域
|
||
@ViewBuilder
|
||
private func avatarSection() -> some View {
|
||
WithPerceptionTracking {
|
||
VStack(spacing: 16) {
|
||
// 头像
|
||
Button(action: {
|
||
showImagePickerSheet = true
|
||
}) {
|
||
AsyncImage(url: URL(string: store.userInfo?.avatar ?? "")) { image in
|
||
image
|
||
.resizable()
|
||
.aspectRatio(contentMode: .fill)
|
||
} placeholder: {
|
||
Image(systemName: "person.circle.fill")
|
||
.resizable()
|
||
.aspectRatio(contentMode: .fill)
|
||
.foregroundColor(.gray)
|
||
}
|
||
.frame(width: 80, height: 80)
|
||
.clipShape(Circle())
|
||
.overlay(
|
||
Circle()
|
||
.stroke(Color.white.opacity(0.3), lineWidth: 2)
|
||
)
|
||
}
|
||
|
||
Text(LocalizedString("app_settings.tap_to_change_avatar", comment: "点击更换头像"))
|
||
.font(.system(size: 14))
|
||
.foregroundColor(.white.opacity(0.7))
|
||
}
|
||
.padding(.vertical, 20)
|
||
.frame(maxWidth: .infinity)
|
||
.background(Color.white.opacity(0.1))
|
||
.cornerRadius(12)
|
||
}
|
||
}
|
||
|
||
// MARK: - 个人信息设置区域
|
||
@ViewBuilder
|
||
private func personalInfoSection() -> some View {
|
||
WithPerceptionTracking {
|
||
VStack(spacing: 0) {
|
||
// 昵称设置
|
||
SettingRow(
|
||
icon: "person",
|
||
title: LocalizedString("app_settings.nickname", comment: "昵称"),
|
||
subtitle: store.userInfo?.nick ?? LocalizedString("app_settings.not_set", comment: "未设置"),
|
||
action: {
|
||
nicknameInput = store.userInfo?.nick ?? ""
|
||
showNicknameAlert = true
|
||
}
|
||
)
|
||
|
||
Divider()
|
||
.background(Color.white.opacity(0.2))
|
||
.padding(.leading, 50)
|
||
|
||
// 用户ID
|
||
SettingRow(
|
||
icon: "number",
|
||
title: LocalizedString("app_settings.user_id", comment: "用户ID"),
|
||
subtitle: "\(store.userInfo?.uid ?? 0)",
|
||
action: nil
|
||
)
|
||
}
|
||
.background(Color.white.opacity(0.1))
|
||
.cornerRadius(12)
|
||
}
|
||
}
|
||
|
||
// MARK: - 其他设置区域
|
||
@ViewBuilder
|
||
private func otherSettingsSection() -> some View {
|
||
WithPerceptionTracking {
|
||
VStack(spacing: 0) {
|
||
SettingRow(
|
||
icon: "hand.raised",
|
||
title: LocalizedString("app_settings.personal_info_permissions", comment: "个人信息权限"),
|
||
subtitle: LocalizedString("app_settings.manage_permissions", comment: "管理权限"),
|
||
action: { store.send(.personalInfoPermissionsTapped) }
|
||
)
|
||
|
||
Divider()
|
||
.background(Color.white.opacity(0.2))
|
||
.padding(.leading, 50)
|
||
|
||
SettingRow(
|
||
icon: "questionmark.circle",
|
||
title: LocalizedString("app_settings.help", comment: "帮助"),
|
||
subtitle: LocalizedString("app_settings.get_help", comment: "获取帮助"),
|
||
action: { store.send(.helpTapped) }
|
||
)
|
||
|
||
Divider()
|
||
.background(Color.white.opacity(0.2))
|
||
.padding(.leading, 50)
|
||
|
||
SettingRow(
|
||
icon: "trash",
|
||
title: LocalizedString("app_settings.clear_cache", comment: "清除缓存"),
|
||
subtitle: LocalizedString("app_settings.free_up_space", comment: "释放空间"),
|
||
action: { store.send(.clearCacheTapped) }
|
||
)
|
||
|
||
Divider()
|
||
.background(Color.white.opacity(0.2))
|
||
.padding(.leading, 50)
|
||
|
||
SettingRow(
|
||
icon: "arrow.clockwise",
|
||
title: LocalizedString("app_settings.check_updates", comment: "检查更新"),
|
||
subtitle: LocalizedString("app_settings.latest_version", comment: "最新版本"),
|
||
action: { store.send(.checkUpdatesTapped) }
|
||
)
|
||
|
||
Divider()
|
||
.background(Color.white.opacity(0.2))
|
||
.padding(.leading, 50)
|
||
|
||
SettingRow(
|
||
icon: "person.crop.circle.badge.minus",
|
||
title: LocalizedString("app_settings.deactivate_account", comment: "注销账号"),
|
||
subtitle: LocalizedString("app_settings.permanent_deletion", comment: "永久删除"),
|
||
action: { store.send(.deactivateAccountTapped) }
|
||
)
|
||
|
||
Divider()
|
||
.background(Color.white.opacity(0.2))
|
||
.padding(.leading, 50)
|
||
|
||
SettingRow(
|
||
icon: "info.circle",
|
||
title: LocalizedString("app_settings.about_us", comment: "关于我们"),
|
||
subtitle: LocalizedString("app_settings.app_info", comment: "应用信息"),
|
||
action: { store.send(.aboutUsTapped) }
|
||
)
|
||
}
|
||
.background(Color.white.opacity(0.1))
|
||
.cornerRadius(12)
|
||
}
|
||
}
|
||
|
||
// MARK: - 退出登录区域
|
||
@ViewBuilder
|
||
private func logoutSection() -> some View {
|
||
WithPerceptionTracking {
|
||
Button(action: {
|
||
store.send(.logoutTapped)
|
||
}) {
|
||
Text(LocalizedString("app_settings.logout", comment: "退出登录"))
|
||
.font(.system(size: 16, weight: .medium))
|
||
.foregroundColor(.white)
|
||
.frame(maxWidth: .infinity)
|
||
.padding(.vertical, 16)
|
||
.background(Color.red.opacity(0.8))
|
||
.cornerRadius(12)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// MARK: - 设置行组件
|
||
struct SettingRow: View {
|
||
let icon: String
|
||
let title: String
|
||
let subtitle: String
|
||
let action: (() -> Void)?
|
||
|
||
var body: some View {
|
||
Button(action: {
|
||
action?()
|
||
}) {
|
||
HStack(spacing: 16) {
|
||
Image(systemName: icon)
|
||
.font(.system(size: 18))
|
||
.foregroundColor(.white)
|
||
.frame(width: 24)
|
||
|
||
VStack(alignment: .leading, spacing: 4) {
|
||
Text(title)
|
||
.font(.system(size: 16))
|
||
.foregroundColor(.white)
|
||
|
||
Text(subtitle)
|
||
.font(.system(size: 14))
|
||
.foregroundColor(.white.opacity(0.7))
|
||
}
|
||
|
||
Spacer()
|
||
|
||
if action != nil {
|
||
Image(systemName: "chevron.right")
|
||
.font(.system(size: 14))
|
||
.foregroundColor(.white.opacity(0.5))
|
||
}
|
||
}
|
||
.padding(.horizontal, 16)
|
||
.padding(.vertical, 12)
|
||
}
|
||
.disabled(action == nil)
|
||
}
|
||
}
|