import SwiftUI import PhotosUI import UIKit // MARK: - Setting Page struct SettingPage: View { @StateObject private var viewModel = SettingViewModel() let onBack: () -> Void let onLogout: () -> Void var body: some View { GeometryReader { geometry in ZStack { // 背景颜色 Color(hex: 0x0C0527) .ignoresSafeArea(.all) VStack(spacing: 0) { // 顶部导航栏 HStack { Button(action: { viewModel.onBackTapped() }) { Image(systemName: "chevron.left") .font(.system(size: 24, weight: .medium)) .foregroundColor(.white) .frame(width: 44, height: 44) } Spacer() Text(LocalizedString("appSetting.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: 0) { // 头像设置区域 avatarSection() .padding(.top, 20) // 个人信息设置区域 personalInfoSection() .padding(.top, 30) // 其他设置区域 otherSettingsSection() .padding(.top, 20) Spacer(minLength: 40) // 退出登录按钮 logoutSection() .padding(.bottom, 40) } .padding(.horizontal, 20) } } } } .navigationBarHidden(true) .onAppear { viewModel.onBack = onBack viewModel.onLogout = onLogout viewModel.onAppear() } // 图片源选择 ActionSheet .confirmationDialog( "请选择图片来源", isPresented: $viewModel.showImageSourceActionSheet, titleVisibility: .visible ) { Button(LocalizedString("app_settings.take_photo", comment: "拍照")) { viewModel.selectImageSource(.camera) } Button(LocalizedString("app_settings.select_from_album", comment: "从相册选择")) { viewModel.selectImageSource(.photoLibrary) } Button(LocalizedString("common.cancel", comment: "取消"), role: .cancel) { } } // 相机选择器 .sheet(isPresented: $viewModel.showCamera) { CameraPicker { image in guard let image = image else { return } viewModel.onCameraImagePicked(image) } } // 相册选择器 .photosPicker( isPresented: $viewModel.showPhotoPicker, selection: $viewModel.selectedPhotoItems, maxSelectionCount: 1, matching: .images ) // 昵称编辑弹窗 .alert(LocalizedString("appSetting.nickname", comment: "编辑昵称"), isPresented: $viewModel.isEditingNickname) { TextField(LocalizedString("appSetting.nickname", comment: "请输入昵称"), text: $viewModel.nicknameInput) .onChange(of: viewModel.nicknameInput) { _, newValue in viewModel.onNicknameInputChanged(newValue) } Button(LocalizedString("common.cancel", comment: "取消")) { viewModel.isEditingNickname = false } Button(LocalizedString("common.confirm", comment: "确认")) { viewModel.onNicknameEditConfirmed() } } message: { Text(LocalizedString("appSetting.nickname", comment: "请输入新的昵称")) } // 登出确认弹窗 .alert(LocalizedString("appSetting.logoutConfirmation.title", comment: "确认退出"), isPresented: $viewModel.showLogoutConfirmation) { Button(LocalizedString("common.cancel", comment: "取消"), role: .cancel) { viewModel.showLogoutConfirmation = false } Button(LocalizedString("appSetting.logoutConfirmation.confirm", comment: "确认退出"), role: .destructive) { viewModel.onLogoutConfirmed() viewModel.showLogoutConfirmation = false } } message: { Text(LocalizedString("appSetting.logoutConfirmation.message", comment: "确定要退出当前账户吗?")) } // 关于我们弹窗 .alert(LocalizedString("appSetting.aboutUs.title", comment: "关于我们"), isPresented: $viewModel.showAboutUs) { Button(LocalizedString("common.ok", comment: "确定")) { viewModel.showAboutUs = false } } message: { VStack(alignment: .leading, spacing: 8) { Text(LocalizedString("feedList.title", comment: "享受您的生活时光")) .font(.headline) Text(LocalizedString("feedList.slogan", comment: "疾病如同残酷的统治者,\n而时间是我们最宝贵的财富。\n我们活着的每一刻,都是对不可避免命运的胜利。")) .font(.body) } } // WebView 导航 .webView( isPresented: $viewModel.showPrivacyPolicy, url: APIConfiguration.webURL(for: .privacyPolicy) ) .onChange(of: viewModel.showPrivacyPolicy) { _, isPresented in if !isPresented { viewModel.onPrivacyPolicyDismissed() } } .webView( isPresented: $viewModel.showUserAgreement, url: APIConfiguration.webURL(for: .userAgreement) ) .onChange(of: viewModel.showUserAgreement) { _, isPresented in if !isPresented { viewModel.onUserAgreementDismissed() } } .webView( isPresented: $viewModel.showDeactivateAccount, url: APIConfiguration.webURL(for: .deactivateAccount) ) .onChange(of: viewModel.showDeactivateAccount) { _, isPresented in if !isPresented { viewModel.onDeactivateAccountDismissed() } } } // MARK: - 头像设置区域 @ViewBuilder private func avatarSection() -> some View { VStack(spacing: 16) { // 头像 Button(action: { viewModel.onAvatarTapped() }) { ZStack { AsyncImage(url: URL(string: viewModel.userInfo?.avatar ?? "")) { image in image .resizable() .aspectRatio(contentMode: .fill) } placeholder: { Image(systemName: "person.circle.fill") .resizable() .aspectRatio(contentMode: .fill) .foregroundColor(.gray) } .frame(width: 120, height: 120) .clipShape(Circle()) // 相机图标覆盖 VStack { Spacer() HStack { Spacer() Circle() .fill(Color.purple) .frame(width: 32, height: 32) .overlay( Image(systemName: "camera") .font(.system(size: 16, weight: .medium)) .foregroundColor(.white) ) } } .frame(width: 120, height: 120) } } .disabled(viewModel.isUploadingAvatar || viewModel.isUpdatingUser) // 上传状态提示 if viewModel.isUploadingAvatar { Text("正在上传头像...") .font(.system(size: 14)) .foregroundColor(.white.opacity(0.8)) } if let error = viewModel.avatarUploadError { Text(error) .font(.system(size: 14)) .foregroundColor(.red) } } } // MARK: - 个人信息设置区域 @ViewBuilder private func personalInfoSection() -> some View { VStack(spacing: 0) { // 昵称设置 SettingRow( title: LocalizedString("appSetting.nickname", comment: "昵称"), subtitle: viewModel.userInfo?.nick ?? LocalizedString("app_settings.not_set", comment: "未设置"), action: { viewModel.onNicknameTapped() } ) .disabled(viewModel.isUpdatingUser) // 更新状态提示 if viewModel.isUpdatingUser { HStack { ProgressView() .progressViewStyle(CircularProgressViewStyle(tint: .white)) .scaleEffect(0.8) Text("正在更新...") .font(.system(size: 14)) .foregroundColor(.white.opacity(0.8)) } .padding(.top, 8) } if let error = viewModel.updateUserError { Text(error) .font(.system(size: 14)) .foregroundColor(.red) .padding(.top, 8) } } } // MARK: - 其他设置区域 @ViewBuilder private func otherSettingsSection() -> some View { VStack(spacing: 0) { SettingRow( title: LocalizedString("appSetting.personalInfoPermissions", comment: "个人信息与权限"), subtitle: "", action: { viewModel.onPersonalInfoPermissionsTapped() } ) Divider() .background(Color.white.opacity(0.2)) .padding(.leading, 16) SettingRow( title: LocalizedString("appSetting.help", comment: "帮助"), subtitle: "", action: { viewModel.onHelpTapped() } ) Divider() .background(Color.white.opacity(0.2)) .padding(.leading, 16) SettingRow( title: LocalizedString("appSetting.clearCache", comment: "清除缓存"), subtitle: "", action: { viewModel.onClearCacheTapped() } ) Divider() .background(Color.white.opacity(0.2)) .padding(.leading, 16) SettingRow( title: LocalizedString("appSetting.checkUpdates", comment: "检查更新"), subtitle: "", action: { viewModel.onCheckUpdatesTapped() } ) Divider() .background(Color.white.opacity(0.2)) .padding(.leading, 16) SettingRow( title: LocalizedString("appSetting.deactivateAccount", comment: "注销账号"), subtitle: "", action: { viewModel.onDeactivateAccountTapped() } ) Divider() .background(Color.white.opacity(0.2)) .padding(.leading, 16) SettingRow( title: LocalizedString("appSetting.aboutUs", comment: "关于我们"), subtitle: "", action: { viewModel.onAboutUsTapped() } ) } } // MARK: - 退出登录区域 @ViewBuilder private func logoutSection() -> some View { VStack(spacing: 12) { // 退出登录按钮 Button(action: { viewModel.onLogoutTapped() }) { Text(LocalizedString("appSetting.logoutAccount", comment: "退出账户")) .font(.system(size: 16, weight: .medium)) .foregroundColor(.white) .frame(maxWidth: .infinity) .padding(.vertical, 16) .background(Color.red.opacity(0.8)) .cornerRadius(12) } } } } //#Preview { // SettingPage( // onBack: {}, // onLogout: {} // ) //}