import Foundation import ComposableArchitecture @Reducer struct FeedFeature { @ObservableState struct State: Equatable { var moments: [MomentsInfo] = [] var isLoading = false var isRefreshing = false var hasMoreData = true var error: String? var nextDynamicId: Int = 0 // CreateFeedView 相关状态 var createFeedState = CreateFeedFeature.State() } enum Action: Equatable { case onAppear case refresh case loadLatestMoments case loadMoreMoments case momentsResponse(TaskResult) case clearError case retryLoad // CreateFeedView 相关 Action case createFeedCompleted case createFeedDismissed // CreateFeedFeature 的 action case createFeed(CreateFeedFeature.Action) } @Dependency(\.apiService) var apiService var body: some ReducerOf { Scope(state: \.createFeedState, action: \.createFeed) { CreateFeedFeature() } Reduce { state, action in switch action { case .onAppear: guard state.moments.isEmpty && !state.isLoading else { return .none } return .send(.loadLatestMoments) case .refresh: guard !state.isRefreshing else { return .none } state.isRefreshing = true state.error = nil let request = LatestDynamicsRequest(dynamicId: "", pageSize: 20, types: [.text, .picture]) return .run { send in await send(.momentsResponse(TaskResult { try await apiService.request(request) })) } case .loadLatestMoments: guard !state.isLoading else { return .none } state.isLoading = true state.error = nil let request = LatestDynamicsRequest(dynamicId: "", pageSize: 20, types: [.text, .picture]) return .run { send in await send(.momentsResponse(TaskResult { try await apiService.request(request) })) } case .loadMoreMoments: guard !state.isLoading && state.hasMoreData else { return .none } state.isLoading = true state.error = nil let request = LatestDynamicsRequest(dynamicId: state.nextDynamicId == 0 ? "" : String(state.nextDynamicId), pageSize: 20, types: [.text, .picture]) return .run { send in await send(.momentsResponse(TaskResult { try await apiService.request(request) })) } case let .momentsResponse(.success(response)): state.isLoading = false state.isRefreshing = false guard response.code == 200, let data = response.data else { let errorMsg = response.message.isEmpty ? "获取动态失败" : response.message state.error = errorMsg return .none } let isRefresh = state.nextDynamicId == 0 || state.isRefreshing if isRefresh { state.moments = data.dynamicList } else { state.moments.append(contentsOf: data.dynamicList) } state.nextDynamicId = data.nextDynamicId state.hasMoreData = !data.dynamicList.isEmpty return .none case let .momentsResponse(.failure(error)): state.isLoading = false state.isRefreshing = false state.error = error.localizedDescription return .none case .clearError: state.error = nil return .none case .retryLoad: if state.moments.isEmpty { return .send(.loadLatestMoments) } else { return .send(.loadMoreMoments) } case .createFeedCompleted: return .send(.refresh) case .createFeedDismissed: return .none case .createFeed(.dismissView): return .send(.createFeedDismissed) case .createFeed: return .none } } } }