diff --git a/yana/Features/HomeFeature.swift b/yana/Features/HomeFeature.swift index d99246e..8485bb7 100644 --- a/yana/Features/HomeFeature.swift +++ b/yana/Features/HomeFeature.swift @@ -11,8 +11,6 @@ struct HomeFeature: Reducer { var userInfo: UserInfo? var accountModel: AccountModel? var error: String? - var isSettingPresented = false - var settingState = SettingFeature.State() var feedState = FeedFeature.State() var meDynamic = MeDynamicFeature.State(uid: 0) var isLoggedOut = false @@ -28,8 +26,6 @@ struct HomeFeature: Reducer { case accountModelLoaded(AccountModel?) case logoutTapped case logout - case settingDismissed - case setting(SettingFeature.Action) case feed(FeedFeature.Action) case meDynamic(MeDynamicFeature.Action) case logoutCompleted @@ -38,9 +34,6 @@ struct HomeFeature: Reducer { } var body: some ReducerOf { - Scope(state: \.settingState, action: \.setting) { - SettingFeature() - } Scope(state: \.feedState, action: \.feed) { FeedFeature() } @@ -83,10 +76,9 @@ struct HomeFeature: Reducer { case .logoutCompleted: state.isLoggedOut = true return .none - case .settingDismissed: - state.isSettingPresented = false + case .feed: return .none - case .setting: + case .meDynamic: return .none case .showCreateFeed: state.route = .createFeed @@ -94,10 +86,6 @@ struct HomeFeature: Reducer { case .createFeedDismissed: state.route = nil return .none - case .feed: - return .none - case .meDynamic: - return .none } } } diff --git a/yana/Features/MainFeature.swift b/yana/Features/MainFeature.swift index b5ef4fe..54ae296 100644 --- a/yana/Features/MainFeature.swift +++ b/yana/Features/MainFeature.swift @@ -14,7 +14,6 @@ struct MainFeature: Reducer { var accountModel: AccountModel? = nil // 新增:导航路径和设置页面 State var navigationPath: [Destination] = [] - var settingState: SettingFeature.State? = nil var appSettingState: AppSettingFeature.State? = nil // 新增:登出标志 var isLoggedOut: Bool = false @@ -22,7 +21,6 @@ struct MainFeature: Reducer { // 新增:导航目标 enum Destination: Hashable, Equatable { - case setting case test case appSetting } @@ -36,8 +34,6 @@ struct MainFeature: Reducer { case accountModelLoaded(AccountModel?) // 新增:导航相关 case navigationPathChanged([Destination]) - case settingButtonTapped - case settingAction(SettingFeature.Action) case testButtonTapped case appSettingButtonTapped case appSettingAction(AppSettingFeature.Action) @@ -84,20 +80,11 @@ struct MainFeature: Reducer { return .none case .navigationPathChanged(let newPath): // pop 回来时清空 settingState - if !newPath.contains(.setting) { - state.settingState = nil - } if !newPath.contains(.appSetting) { state.appSettingState = nil } state.navigationPath = newPath return .none - case .settingButtonTapped: - state.settingState = SettingFeature.State() - state.navigationPath.append(.setting) - return .none - case .settingAction: - return .none case .testButtonTapped: state.navigationPath.append(.test) return .none @@ -117,9 +104,6 @@ struct MainFeature: Reducer { } } // 设置页作用域 - .ifLet(\ .settingState, action: \.settingAction) { - SettingFeature() - } .ifLet(\ .appSettingState, action: \.appSettingAction) { AppSettingFeature() } diff --git a/yana/Features/SettingFeature.swift b/yana/Features/SettingFeature.swift deleted file mode 100644 index 8ff2468..0000000 --- a/yana/Features/SettingFeature.swift +++ /dev/null @@ -1,102 +0,0 @@ -import Foundation -import ComposableArchitecture - -@Reducer -struct SettingFeature { - @ObservableState - struct State: Equatable { - var userInfo: UserInfo? - var accountModel: AccountModel? - var isLoading = false - var error: String? - var isRefreshingUserInfo = false // 新增:用户信息刷新状态 - } - - enum Action: Equatable { - case onAppear - case loadUserInfo - case userInfoLoaded(UserInfo?) - case loadAccountModel - case accountModelLoaded(AccountModel?) - case refreshUserInfo // 新增:刷新用户信息 - case refreshUserInfoResponse(TaskResult) // 新增:刷新用户信息响应 - case logoutTapped - case logout - case dismissTapped - } - - @Dependency(\.apiService) var apiService // 新增:API服务依赖 - - var body: some ReducerOf { - Reduce { state, action in - switch action { - case .onAppear: - return .concatenate( - .send(.loadUserInfo), - .send(.loadAccountModel) - ) - - case .loadUserInfo: - return .run { send in - let userInfo = await UserInfoManager.getUserInfo() - await send(.userInfoLoaded(userInfo)) - } - - case let .userInfoLoaded(userInfo): - state.userInfo = userInfo - return .none - - case .loadAccountModel: - return .run { send in - let accountModel = await UserInfoManager.getAccountModel() - await send(.accountModelLoaded(accountModel)) - } - - case let .accountModelLoaded(accountModel): - state.accountModel = accountModel - return .none - - case .refreshUserInfo: // 新增:刷新用户信息 - return .none -// state.isRefreshingUserInfo = true -// state.error = nil -// return .run { send in -// let userInfo = await UserInfoManager.refreshCurrentUserInfo(apiService: apiService) -// await send(.refreshUserInfoResponse(.success(userInfo))) -// } - - case let .refreshUserInfoResponse(.success(userInfo)): // 新增:处理刷新响应 - state.isRefreshingUserInfo = false - if let userInfo = userInfo { - state.userInfo = userInfo - state.error = nil - } else { - state.error = "刷新用户信息失败" - } - return .none - - case let .refreshUserInfoResponse(.failure(error)): // 新增:处理刷新错误 - state.isRefreshingUserInfo = false - state.error = error.localizedDescription - return .none - - case .logoutTapped: - return .send(.logout) - - case .logout: - state.isLoading = true - return .run { _ in - await UserInfoManager.clearAllAuthenticationData() - } - - case .dismissTapped: - return .none - } - } - } -} - -// 移除:未使用的通知名称定义 -// extension Notification.Name { -// static let settingsDismiss = Notification.Name("settingsDismiss") -// } diff --git a/yana/Views/HomeView.swift b/yana/Views/HomeView.swift index 9c07c4f..f3ab5d4 100644 --- a/yana/Views/HomeView.swift +++ b/yana/Views/HomeView.swift @@ -58,12 +58,6 @@ struct HomeView: View { .onAppear { store.send(.onAppear) } - .sheet(isPresented: Binding( - get: { store.withState(\.isSettingPresented) }, - set: { _ in store.send(.settingDismissed) } - )) { - SettingView(store: store.scope(state: \.settingState, action: \.setting)) - } .navigationDestination(isPresented: Binding( get: { store.withState(\.route) == .createFeed }, set: { isPresented in diff --git a/yana/Views/MainView.swift b/yana/Views/MainView.swift index 169e770..a1513f1 100644 --- a/yana/Views/MainView.swift +++ b/yana/Views/MainView.swift @@ -48,21 +48,6 @@ struct InternalMainView: View { .isHidden(viewStore.selectedTab != .other) } .frame(maxWidth: .infinity, maxHeight: .infinity) - // 测试按钮 - VStack { - Spacer() - HStack { - Spacer() - Button("Test Push") { - viewStore.send(.testButtonTapped) - } - .padding() - .background(Color.red) - .foregroundColor(.white) - .cornerRadius(8) - .padding() - } - } // 底部导航栏 VStack { Spacer() @@ -76,18 +61,6 @@ struct InternalMainView: View { } .navigationDestination(for: MainFeature.Destination.self) { destination in switch destination { - case .setting: - IfLetStore( - self.store.scope( - state: \.settingState, - action: MainFeature.Action.settingAction - ), - then: { settingStore in - WithPerceptionTracking { - SettingView(store: settingStore) - } - } - ) case .test: TestPushView() case .appSetting: diff --git a/yana/Views/SettingView.swift b/yana/Views/SettingView.swift deleted file mode 100644 index e0746a4..0000000 --- a/yana/Views/SettingView.swift +++ /dev/null @@ -1,332 +0,0 @@ -import SwiftUI -import ComposableArchitecture - -struct SettingView: View { - let store: StoreOf - @ObservedObject private var localizationManager = LocalizationManager.shared - - var body: some View { - NavigationStack { - WithPerceptionTracking { - GeometryReader { geometry in - ZStack { - // 背景图片 - 使用"bg"图片,全屏显示 - Image("bg") - .resizable() - .aspectRatio(contentMode: .fill) - .ignoresSafeArea(.all) - - VStack(spacing: 0) { - // Navigation Bar - HStack { - // 返回按钮 - Button(action: { - store.send(.dismissTapped) - }) { - Image(systemName: "chevron.left") - .font(.title2) - .foregroundColor(.white) - } - .padding(.leading, 16) - - Spacer() - - // 标题 - Text(NSLocalizedString("setting.title", comment: "Settings")) - .font(.custom("PingFang SC-Semibold", size: 16)) - .foregroundColor(.white) - - Spacer() - - // 占位符,保持标题居中 - Color.clear - .frame(width: 44, height: 44) - } - .padding(.top, 8) - .padding(.horizontal) - - // 内容区域 - ScrollView { - VStack(spacing: 24) { - UserInfoCardView(userInfo: store.userInfo, accountModel: store.accountModel, isRefreshing: store.isRefreshingUserInfo, onRefresh: { - store.send(.refreshUserInfo) - }) -// .padding() - .padding(.top, 32) - - SettingOptionsView( - onLanguageTapped: { - // TODO: 实现语言设置 - }, - onAboutTapped: { - // TODO: 实现关于页面 - } - ) - - Spacer(minLength: 50) - - LogoutButtonView { - store.send(.logoutTapped) - } - .padding(.bottom, 50) - } - } - } - } - } - .onAppear { - store.send(.onAppear) - } - } - } - } -} - -// MARK: - User Info Card View -struct UserInfoCardView: View { - let userInfo: UserInfo? - let accountModel: AccountModel? - let isRefreshing: Bool // 新增:刷新状态 - let onRefresh: () -> Void // 新增:刷新回调 - - var body: some View { - VStack(spacing: 16) { - // 头像区域 - Image(systemName: "person.circle.fill") - .font(.system(size: 60)) - .foregroundColor(.white.opacity(0.8)) - - // 用户信息 - VStack(spacing: 8) { - if let userInfo = userInfo, let userName = userInfo.username { - Text(userName) - .font(.title2.weight(.semibold)) - .foregroundColor(.white) - } else { - Text(NSLocalizedString("setting.user", comment: "User")) - .font(.title2.weight(.semibold)) - .foregroundColor(.white) - } - - // 显示用户ID - if let userInfo = userInfo, let userId = userInfo.userId { - Text("ID: \(userId)") - .font(.caption) - .foregroundColor(.white.opacity(0.8)) - } else if let accountModel = accountModel, let uid = accountModel.uid { - Text("UID: \(uid)") - .font(.caption) - .foregroundColor(.white.opacity(0.8)) - } - } - - // 新增:刷新按钮 - Button(action: onRefresh) { - HStack(spacing: 4) { - if isRefreshing { - ProgressView() - .scaleEffect(0.8) - .progressViewStyle(CircularProgressViewStyle(tint: .white)) - } else { - Image(systemName: "arrow.clockwise") - .font(.caption) - } - Text(isRefreshing ? "刷新中..." : "刷新") - .font(.caption) - } - .foregroundColor(.white) - .padding(.horizontal, 12) - .padding(.vertical, 6) - .background(Color.white.opacity(0.2)) - .cornerRadius(12) - } - .disabled(isRefreshing) - } - .padding(.vertical, 24) - .padding(.horizontal, 20) - .background(Color.black.opacity(0.3)) - .cornerRadius(16) - .padding(.horizontal, 24) - } -} - -// MARK: - Setting Options View -// Add this new view for testing COS upload -struct TestCOSUploadView: View { - @State private var imageURL: String = "https://img.toto.im/mw600/66b3de17ly1i3mpcw0k7yj20hs0md0tf.jpg.webp" - @State private var uploadResult: String = "" - @State private var isUploading: Bool = false - @Dependency(\.apiService) private var apiService - - var body: some View { - VStack(spacing: 20) { - TextField("Enter image URL", text: $imageURL) - .textFieldStyle(RoundedBorderTextFieldStyle()) - .padding() - - Button(action: { - Task { - await uploadImageFromURL() - } - }) { - Text(isUploading ? "Uploading..." : "Upload to COS") - .padding() - .background(Color.blue) - .foregroundColor(.white) - .cornerRadius(8) - } - .disabled(isUploading || imageURL.isEmpty) - - Text(uploadResult) - .multilineTextAlignment(.center) - .padding() - } - .navigationTitle("Test COS Upload") - } - - private func uploadImageFromURL() async { - guard let url = URL(string: imageURL) else { - uploadResult = "Invalid URL" - return - } - isUploading = true - uploadResult = "" - do { - let (data, _) = try await URLSession.shared.data(from: url) - if let cloudURL = await COSManager.shared.uploadImage(data, apiService: apiService) { - uploadResult = "Upload successful! Cloud URL: \(cloudURL)" - } else { - uploadResult = "Upload failed" - } - } catch { - uploadResult = "Download failed: \(error.localizedDescription)" - } - isUploading = false - } -} - -// Modify SettingOptionsView to add the test row -struct SettingOptionsView: View { - let onLanguageTapped: () -> Void - let onAboutTapped: () -> Void - - var body: some View { - VStack(spacing: 12) { - SettingRowView( - icon: "globe", - title: NSLocalizedString("setting.language", comment: "Language Settings"), - action: onLanguageTapped - ) - - SettingRowView( - icon: "info.circle", - title: NSLocalizedString("setting.about", comment: "About Us"), - action: onAboutTapped - ) - - #if DEBUG - NavigationLink(destination: TestCOSUploadView()) { - HStack { - Image(systemName: "cloud.upload") - .foregroundColor(.white.opacity(0.8)) - .frame(width: 24) - - Text("Test COS Upload") - .foregroundColor(.white) - - Spacer() - - Image(systemName: "chevron.right") - .foregroundColor(.white.opacity(0.6)) - .font(.caption) - } - .padding(.horizontal, 20) - .padding(.vertical, 16) - .background(Color.black.opacity(0.2)) - .cornerRadius(12) - } - #endif - - HStack { - Image(systemName: "app.badge") - .foregroundColor(.white.opacity(0.8)) - .frame(width: 24) - - Text(NSLocalizedString("setting.version", comment: "Version Info")) - .foregroundColor(.white) - - Spacer() - - Text("1.0.0") - .foregroundColor(.white.opacity(0.6)) - .font(.caption) - } - .padding(.horizontal, 20) - .padding(.vertical, 16) - .background(Color.black.opacity(0.2)) - .cornerRadius(12) - } - .padding(.horizontal, 24) - } -} - -// MARK: - Logout Button View -struct LogoutButtonView: View { - let action: () -> Void - - var body: some View { - Button(action: action) { - HStack { - Image(systemName: "arrow.right.square") - Text(NSLocalizedString("setting.logout", comment: "Logout")) - } - .font(.body.weight(.medium)) - .foregroundColor(.white) - .frame(maxWidth: .infinity) - .padding(.vertical, 16) - .background(Color.red.opacity(0.7)) - .cornerRadius(12) - } - .padding(.horizontal, 24) - } -} - -// MARK: - Setting Row View -struct SettingRowView: View { - let icon: String - let title: String - let action: () -> Void - - var body: some View { - Button(action: action) { - HStack { - Image(systemName: icon) - .foregroundColor(.white.opacity(0.8)) - .frame(width: 24) - - Text(title) - .foregroundColor(.white) - - Spacer() - - Image(systemName: "chevron.right") - .foregroundColor(.white.opacity(0.6)) - .font(.caption) - } - .padding(.horizontal, 20) - .padding(.vertical, 16) - .background(Color.black.opacity(0.2)) - .cornerRadius(12) - } - } -} - -//#Preview { -// SettingView( -// store: Store( -// initialState: SettingFeature.State() -// ) { -// SettingFeature() -// } -// ) -//}