import Foundation import ComposableArchitecture @Reducer struct FeedListFeature { @Dependency(\.apiService) var apiService struct State: Equatable { var isFirstLoad: Bool = true var feeds: [Feed] = [] // 预留 feed 内容 var isLoading: Bool = false var error: String? = nil var isEditFeedPresented: Bool = false // 新增:控制 EditFeedView 弹窗 // 新增:动态内容 var moments: [MomentsInfo] = [] // 新增:只加载一次标志 var isLoaded: Bool = false // 分页相关 var currentPage: Int = 1 var hasMore: Bool = true var isLoadingMore: Bool = false // 新增:DetailView相关状态 var showDetail: Bool = false var selectedMoment: MomentsInfo? // 新增:点赞相关状态 var likeLoadingDynamicIds: Set = [] } enum Action: Equatable { case onAppear case reload case loadMore case loadMoreResponse(TaskResult) case editFeedButtonTapped // 新增:点击 add 按钮 case editFeedDismissed // 新增:关闭编辑页 case testButtonTapped // 新增:点击测试按钮 // 新增:动态内容相关 case fetchFeeds case fetchFeedsResponse(TaskResult) // 新增:DetailView相关Action case showDetail(MomentsInfo) case detailDismissed // 新增:点赞相关Action case likeDynamic(Int, Int, Int, Int) // dynamicId, uid, likedUid, worldId case likeResponse(TaskResult) // 预留后续 Action } func reduce(into state: inout State, action: Action) -> Effect { switch action { case .onAppear: guard state.isFirstLoad else { return .none } state.isFirstLoad = false return .send(.fetchFeeds) case .reload: // 下拉刷新,重置状态并请求第一页 state.isLoading = true state.error = nil state.currentPage = 1 state.hasMore = true state.isLoaded = true return .run { [apiService] send in await send(.fetchFeedsResponse(TaskResult { let request = LatestDynamicsRequest(dynamicId: "", pageSize: 20, types: [.text, .picture]) return try await apiService.request(request) })) } case .loadMore: // 上拉加载更多 guard state.hasMore, !state.isLoadingMore, !state.isLoading else { return .none } state.isLoadingMore = true let lastDynamicId: String = { if let last = state.moments.last { return String(last.dynamicId) } else { return "" } }() return .run { [apiService] send in await send(.loadMoreResponse(TaskResult { let request = LatestDynamicsRequest(dynamicId: lastDynamicId, pageSize: 20, types: [.text, .picture]) return try await apiService.request(request) })) } case let .loadMoreResponse(.success(response)): state.isLoadingMore = false if let list = response.data?.dynamicList { if list.isEmpty { state.hasMore = false } else { state.moments.append(contentsOf: list) state.currentPage += 1 state.hasMore = (list.count >= 20) } state.error = nil } else { state.hasMore = false state.error = response.message } return .none case let .loadMoreResponse(.failure(error)): state.isLoadingMore = false state.hasMore = false state.error = error.localizedDescription return .none case .fetchFeeds: state.isLoading = true state.error = nil // 发起 API 请求 return .run { [apiService] send in await send(.fetchFeedsResponse(TaskResult { let request = LatestDynamicsRequest(dynamicId: "", pageSize: 20, types: [.text, .picture]) return try await apiService.request(request) })) } case let .fetchFeedsResponse(.success(response)): state.isLoading = false if let list = response.data?.dynamicList { state.moments = list state.error = nil state.currentPage = 1 state.hasMore = (list.count >= 20) } else { state.moments = [] state.error = response.message state.hasMore = false } return .none case let .fetchFeedsResponse(.failure(error)): state.isLoading = false state.moments = [] state.error = error.localizedDescription state.hasMore = false return .none case .editFeedButtonTapped: state.isEditFeedPresented = true return .none case .editFeedDismissed: state.isEditFeedPresented = false return .none case .testButtonTapped: debugInfoSync("[LOG] FeedListFeature testButtonTapped") return .none case let .showDetail(moment): state.selectedMoment = moment state.showDetail = true return .none case .detailDismissed: state.showDetail = false state.selectedMoment = nil return .none case let .likeDynamic(dynamicId, uid, likedUid, worldId): // 找到对应的动态并更新点赞状态 guard let index = state.moments.firstIndex(where: { $0.dynamicId == dynamicId }) else { return .none } // 添加loading状态 state.likeLoadingDynamicIds.insert(dynamicId) // 获取当前点赞状态 let currentMoment = state.moments[index] let status = currentMoment.isLike ? 0 : 1 // 0: 取消点赞, 1: 点赞 let request = LikeDynamicRequest( dynamicId: dynamicId, uid: uid, status: status, likedUid: likedUid, worldId: worldId ) return .run { [apiService] send in let result = await TaskResult { try await apiService.request(request) } await send(.likeResponse(result)) } case let .likeResponse(.success(response)): // 移除loading状态 if let data = response.data, let success = data.success, success { // 找到对应的动态并更新点赞状态 // 注意:这里我们需要从loading状态中找到对应的dynamicId let loadingDynamicIds = state.likeLoadingDynamicIds for dynamicId in loadingDynamicIds { if let index = state.moments.firstIndex(where: { $0.dynamicId == dynamicId }) { let currentMoment = state.moments[index] let newLikeState = !currentMoment.isLike let newLikeCount = data.likeCount ?? currentMoment.likeCount // 创建更新后的动态对象 let updatedMoment = MomentsInfo( dynamicId: currentMoment.dynamicId, uid: currentMoment.uid, nick: currentMoment.nick, avatar: currentMoment.avatar, type: currentMoment.type, content: currentMoment.content, likeCount: newLikeCount, isLike: newLikeState, commentCount: currentMoment.commentCount, publishTime: currentMoment.publishTime, worldId: currentMoment.worldId, status: currentMoment.status, playCount: currentMoment.playCount, dynamicResList: currentMoment.dynamicResList, gender: currentMoment.gender, squareTop: currentMoment.squareTop, topicTop: currentMoment.topicTop, newUser: currentMoment.newUser, defUser: currentMoment.defUser, scene: currentMoment.scene, userVipInfoVO: currentMoment.userVipInfoVO, headwearPic: currentMoment.headwearPic, headwearEffect: currentMoment.headwearEffect, headwearType: currentMoment.headwearType, headwearName: currentMoment.headwearName, headwearId: currentMoment.headwearId, experLevelPic: currentMoment.experLevelPic, charmLevelPic: currentMoment.charmLevelPic, isCustomWord: currentMoment.isCustomWord, labelList: currentMoment.labelList ) state.moments[index] = updatedMoment break // 找到并更新后退出循环 } } } // 移除所有loading状态 state.likeLoadingDynamicIds.removeAll() return .none case let .likeResponse(.failure(error)): // 移除loading状态 state.likeLoadingDynamicIds.removeAll() return .none } } } // Feed 数据模型占位,后续可替换为真实模型 enum Feed: Equatable, Identifiable { case placeholder(id: UUID = UUID()) var id: UUID { switch self { case .placeholder(let id): return id } } }