diff --git a/yana/Views/AppSettingView.swift b/yana/Views/AppSettingView.swift index f3662a6..585b669 100644 --- a/yana/Views/AppSettingView.swift +++ b/yana/Views/AppSettingView.swift @@ -11,44 +11,51 @@ import PhotosUI struct AppSettingView: View { let store: StoreOf - @State private var showPhotoPicker = false + // 直接let声明pickerStore + let pickerStore = Store( + initialState: ImagePickerWithPreviewReducer.State(inner: ImagePickerWithPreviewState(selectionMode: .single)), + reducer: { ImagePickerWithPreviewReducer() } + ) + @State private var showImagePicker = false @State private var showNicknameAlert = false @State private var nicknameInput = "" - @State private var selectedPhotoItem: PhotosPickerItem? - + var body: some View { -// WithPerceptionTracking { - WithViewStore(store, observe: { $0 }) { viewStore in - WithPerceptionTracking{ - mainContent(viewStore: viewStore) - .navigationBarHidden(true) - .photosPicker( - isPresented: $showPhotoPicker, - selection: $selectedPhotoItem, - matching: .images, - photoLibrary: .shared() - ) - .onChange(of: selectedPhotoItem) { item in - handlePhotoSelection(item: item, viewStore: viewStore) - selectedPhotoItem = nil - } - .alert("修改昵称", isPresented: $showNicknameAlert) { - nicknameAlertContent(viewStore: viewStore) - } message: { - Text("昵称最长15个字符") - } - .sheet(isPresented: userAgreementBinding(viewStore: viewStore)) { - WebView(url: URL(string: "https://www.yana.com/user-agreement")!) - } - .sheet(isPresented: privacyPolicyBinding(viewStore: viewStore)) { - WebView(url: URL(string: "https://www.yana.com/privacy-policy")!) + WithViewStore(store, observe: { $0 }) { viewStore in + ZStack { + mainContent(viewStore: viewStore) + if showImagePicker { + WithPerceptionTracking{ + ImagePickerWithPreviewView(store: pickerStore) { images in + if let image = images.first, let data = image.jpegData(compressionQuality: 0.8) { + viewStore.send(.avatarSelected(data)) + } + showImagePicker = false } + .zIndex(10) + } } - } -// } + .navigationBarHidden(true) + .alert("修改昵称", isPresented: $showNicknameAlert) { + nicknameAlertContent(viewStore: viewStore) + } message: { + Text("昵称最长15个字符") + } + .sheet(isPresented: userAgreementBinding(viewStore: viewStore)) { + WebView(url: URL(string: "https://www.yana.com/user-agreement")!) + } + .sheet(isPresented: privacyPolicyBinding(viewStore: viewStore)) { + WebView(url: URL(string: "https://www.yana.com/privacy-policy")!) + } + .onChange(of: showImagePicker) { newValue in + if newValue { + pickerStore.send(.inner(.showActionSheet(true))) + } + } + } } - + // MARK: - 主要内容 private func mainContent(viewStore: ViewStoreOf) -> some View { ZStack { @@ -56,98 +63,38 @@ struct AppSettingView: View { VStack(spacing: 0) { topBar ScrollView { - VStack(spacing: 32) { - // 头像区域 - avatarSection(viewStore: viewStore) - - // 昵称设置项 - nicknameSection(viewStore: viewStore) - - // 设置项区域 - settingsSection(viewStore: viewStore) - - // 退出登录按钮 - logoutButton(viewStore: viewStore) + WithPerceptionTracking { + VStack(spacing: 32) { + // 头像区域 + avatarSection(viewStore: viewStore) + // 昵称设置项 + nicknameSection(viewStore: viewStore) + // 设置项区域 + settingsSection(viewStore: viewStore) + // 退出登录按钮 + logoutButton(viewStore: viewStore) + } } } } } } - - // MARK: - 照片选择处理 - private func handlePhotoSelection(item: PhotosPickerItem?, viewStore: ViewStoreOf) { - if let item = item { - loadAndProcessImage(item: item) { data in - if let data = data { - viewStore.send(.avatarSelected(data)) - } - } - } - } - - // MARK: - 昵称Alert内容 - @ViewBuilder - private func nicknameAlertContent(viewStore: ViewStoreOf) -> some View { - TextField("请输入昵称", text: $nicknameInput) - .onChange(of: nicknameInput) { newValue in - if newValue.count > 15 { - nicknameInput = String(newValue.prefix(15)) - } - } - Button("确定") { - let trimmed = nicknameInput.trimmingCharacters(in: .whitespacesAndNewlines) - if !trimmed.isEmpty && trimmed != viewStore.nickname { - viewStore.send(.nicknameEditConfirmed(trimmed)) - } - } - Button("取消", role: .cancel) {} - } - - // MARK: - 顶部栏 - private var topBar: some View { - HStack { - WithViewStore(store, observe: { $0 }) { viewStore in - Button(action: { - viewStore.send(.dismissTapped) - }) { - Image(systemName: "chevron.left") - .foregroundColor(.white) - .font(.system(size: 20, weight: .medium)) - } - } - - Spacer() - - Text(NSLocalizedString("appSetting.title", comment: "Settings")) - .font(.system(size: 18, weight: .semibold)) - .foregroundColor(.white) - - Spacer() - - // 占位符,保持标题居中 - Color.clear - .frame(width: 20, height: 20) - } - .padding(.horizontal, 20) - .padding(.top, 8) - .padding(.bottom, 16) - } - + // MARK: - 头像区域 private func avatarSection(viewStore: ViewStoreOf) -> some View { ZStack(alignment: .bottomTrailing) { avatarImageView(viewStore: viewStore) .onTapGesture { - showPhotoPicker = true + showImagePicker = true } cameraButton .onTapGesture { - showPhotoPicker = true + showImagePicker = true } } .padding(.top, 24) } - + // MARK: - 头像图片视图 @ViewBuilder private func avatarImageView(viewStore: ViewStoreOf) -> some View { @@ -159,7 +106,7 @@ struct AppSettingView: View { defaultAvatarView } } - + // MARK: - 加载状态头像 private var loadingAvatarView: some View { Circle() @@ -171,7 +118,7 @@ struct AppSettingView: View { .scaleEffect(1.2) ) } - + // MARK: - 网络头像 private func networkAvatarView(url: URL) -> some View { CachedAsyncImage(url: url.absoluteString) { image in @@ -184,7 +131,7 @@ struct AppSettingView: View { .frame(width: 120, height: 120) .clipShape(Circle()) } - + // MARK: - 默认头像 private var defaultAvatarView: some View { Circle() @@ -196,7 +143,7 @@ struct AppSettingView: View { .foregroundColor(.white) ) } - + // MARK: - 相机按钮 private var cameraButton: some View { Button(action: {}) { @@ -208,7 +155,7 @@ struct AppSettingView: View { } .offset(x: 8, y: 8) } - + // MARK: - 昵称设置项 private func nicknameSection(viewStore: ViewStoreOf) -> some View { VStack(spacing: 0) { @@ -227,12 +174,12 @@ struct AppSettingView: View { nicknameInput = viewStore.nickname showNicknameAlert = true } - + Divider().background(Color.gray.opacity(0.3)) .padding(.horizontal, 32) } } - + // MARK: - 设置项区域 private func settingsSection(viewStore: ViewStoreOf) -> some View { VStack(spacing: 0) { @@ -245,7 +192,7 @@ struct AppSettingView: View { .background(Color.clear) .padding(.horizontal, 0) } - + // MARK: - 个人信息权限行 private func personalInfoPermissionsRow(viewStore: ViewStoreOf) -> some View { settingRow( @@ -253,7 +200,7 @@ struct AppSettingView: View { action: { viewStore.send(.personalInfoPermissionsTapped) } ) } - + // MARK: - 帮助行 private func helpRow(viewStore: ViewStoreOf) -> some View { settingRow( @@ -261,7 +208,7 @@ struct AppSettingView: View { action: { viewStore.send(.helpTapped) } ) } - + // MARK: - 清除缓存行 private func clearCacheRow(viewStore: ViewStoreOf) -> some View { settingRow( @@ -269,7 +216,7 @@ struct AppSettingView: View { action: { viewStore.send(.clearCacheTapped) } ) } - + // MARK: - 检查更新行 private func checkUpdatesRow(viewStore: ViewStoreOf) -> some View { settingRow( @@ -277,7 +224,7 @@ struct AppSettingView: View { action: { viewStore.send(.checkUpdatesTapped) } ) } - + // MARK: - 关于我们行 private func aboutUsRow(viewStore: ViewStoreOf) -> some View { settingRow( @@ -285,7 +232,7 @@ struct AppSettingView: View { action: { viewStore.send(.aboutUsTapped) } ) } - + // MARK: - 设置项行 private func settingRow(title: String, action: @escaping () -> Void) -> some View { VStack(spacing: 0) { @@ -301,12 +248,12 @@ struct AppSettingView: View { .onTapGesture { action() } - + Divider().background(Color.gray.opacity(0.3)) .padding(.horizontal, 32) } } - + // MARK: - 退出登录按钮 private func logoutButton(viewStore: ViewStoreOf) -> some View { Button(action: { @@ -323,7 +270,7 @@ struct AppSettingView: View { } .padding(.bottom, 32) } - + // MARK: - 用户协议绑定 private func userAgreementBinding(viewStore: ViewStoreOf) -> Binding { viewStore.binding( @@ -331,7 +278,7 @@ struct AppSettingView: View { send: AppSettingFeature.Action.userAgreementDismissed ) } - + // MARK: - 隐私政策绑定 private func privacyPolicyBinding(viewStore: ViewStoreOf) -> Binding { viewStore.binding( @@ -339,7 +286,55 @@ struct AppSettingView: View { send: AppSettingFeature.Action.privacyPolicyDismissed ) } - + + // MARK: - 昵称Alert内容 + @ViewBuilder + private func nicknameAlertContent(viewStore: ViewStoreOf) -> some View { + TextField("请输入昵称", text: $nicknameInput) + .onChange(of: nicknameInput) { newValue in + if newValue.count > 15 { + nicknameInput = String(newValue.prefix(15)) + } + } + Button("确定") { + let trimmed = nicknameInput.trimmingCharacters(in: .whitespacesAndNewlines) + if !trimmed.isEmpty && trimmed != viewStore.nickname { + viewStore.send(.nicknameEditConfirmed(trimmed)) + } + } + Button("取消", role: .cancel) {} + } + + // MARK: - 顶部栏 + private var topBar: some View { + HStack { + WithViewStore(store, observe: { $0 }) { viewStore in + Button(action: { + viewStore.send(.dismissTapped) + }) { + Image(systemName: "chevron.left") + .foregroundColor(.white) + .font(.system(size: 20, weight: .medium)) + } + } + + Spacer() + + Text(NSLocalizedString("appSetting.title", comment: "Settings")) + .font(.system(size: 18, weight: .semibold)) + .foregroundColor(.white) + + Spacer() + + // 占位符,保持标题居中 + Color.clear + .frame(width: 20, height: 20) + } + .padding(.horizontal, 20) + .padding(.top, 8) + .padding(.bottom, 16) + } + // MARK: - 图片处理 private func loadAndProcessImage(item: PhotosPickerItem, completion: @escaping (Data?) -> Void) { item.loadTransferable(type: Data.self) { result in