Files
e-party-iOS/yana/Features/FeedFeature.swift
edwinQQQ 4bbb4f8434 feat: 添加CreateFeed功能及相关视图组件
- 新增CreateFeedView和CreateFeedFeature,支持用户发布图文动态。
- 在FeedView中集成CreateFeedView,允许用户通过加号按钮访问发布界面。
- 实现图片选择和文本输入功能,支持最多9张图片的上传。
- 添加发布API请求模型,处理动态发布逻辑。
- 更新FeedFeature以管理CreateFeedView的显示状态,确保用户体验流畅。
- 完善UI结构分析与执行计划文档,明确开发步骤和技术要点。
2025-07-16 15:53:32 +08:00

159 lines
6.0 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import Foundation
import ComposableArchitecture
@Reducer
struct FeedFeature {
@ObservableState
struct State: Equatable {
var moments: [MomentsInfo] = []
var isLoading = false
var hasMoreData = true
var error: String?
var nextDynamicId: Int = 0
//
var isInitialized = false
// CreateFeedView
var isShowingCreateFeed = false
}
enum Action: Equatable {
case onAppear
case loadLatestMoments
case loadMoreMoments
case momentsResponse(TaskResult<MomentsLatestResponse>)
case clearError
case retryLoad
// CreateFeedView Action
case showCreateFeed
case dismissCreateFeed
case createFeedCompleted
}
@Dependency(\.apiService) var apiService
var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case .onAppear:
//
guard !state.isInitialized else { return .none }
state.isInitialized = true
return .send(.loadLatestMoments)
case .loadLatestMoments:
//
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
//
debugInfo("📱 FeedFeature: API 响应成功")
debugInfo("📱 FeedFeature: response.code = \(response.code)")
debugInfo("📱 FeedFeature: response.message = \(response.message)")
debugInfo("📱 FeedFeature: response.data = \(response.data != nil ? "有数据" : "无数据")")
//
guard response.code == 200, let data = response.data else {
let errorMsg = response.message.isEmpty ? "获取动态失败" : response.message
state.error = errorMsg
debugError("❌ FeedFeature: API 响应失败 - code: \(response.code), message: \(errorMsg)")
return .none
}
//
debugInfo("📱 FeedFeature: data.dynamicList.count = \(data.dynamicList.count)")
debugInfo("📱 FeedFeature: data.nextDynamicId = \(data.nextDynamicId)")
//
let isRefresh = state.nextDynamicId == 0
debugInfo("📱 FeedFeature: isRefresh = \(isRefresh)")
if isRefresh {
//
state.moments = data.dynamicList
debugInfo(" FeedFeature: 刷新数据moments.count = \(state.moments.count)")
} else {
//
let oldCount = state.moments.count
state.moments.append(contentsOf: data.dynamicList)
debugInfo(" FeedFeature: 加载更多moments.count: \(oldCount) -> \(state.moments.count)")
}
//
state.nextDynamicId = data.nextDynamicId
state.hasMoreData = !data.dynamicList.isEmpty
debugInfo("📱 FeedFeature: 更新完成 - nextDynamicId: \(state.nextDynamicId), hasMoreData: \(state.hasMoreData)")
return .none
case let .momentsResponse(.failure(error)):
state.isLoading = false
state.error = error.localizedDescription
debugError("❌ FeedFeature: API 请求失败 - \(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 .showCreateFeed:
state.isShowingCreateFeed = true
return .none
case .dismissCreateFeed:
state.isShowingCreateFeed = false
return .none
case .createFeedCompleted:
state.isShowingCreateFeed = false
//
return .send(.loadLatestMoments)
}
}
}
}