Files
e-party-iOS/yana/Views/AppSettingView.swift
edwinQQQ 3ec1b1302f feat: 更新iOS和Podfile的部署目标以支持新版本
- 将iOS平台版本更新至17,确保与最新的开发环境兼容。
- 更新Podfile中的iOS部署目标至17.0,确保依赖项与新版本兼容。
- 修改Podfile.lock以反映新的依赖项版本,确保项目一致性。
- 在多个视图中重构代码,优化状态管理和视图逻辑,提升用户体验。
2025-07-29 15:59:09 +08:00

358 lines
14 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// AppSettingView.swift
// yana
//
// Created by Edwin on 2024/11/20.
//
import SwiftUI
import ComposableArchitecture
import PhotosUI
struct AppSettingView: View {
let store: StoreOf<AppSettingFeature>
// letpickerStore
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)
}
}