feat: 实现动态内容的分页加载与刷新功能

- 在FeedListFeature中新增分页相关状态管理,支持上拉加载更多和下拉刷新功能,提升用户体验。
- 在FeedListView中实现上拉加载更多的触发逻辑和加载指示器,优化动态内容展示。
This commit is contained in:
edwinQQQ
2025-07-22 17:43:24 +08:00
parent 60b3f824be
commit 4eb01bde7c
2 changed files with 77 additions and 6 deletions

View File

@@ -13,12 +13,17 @@ struct FeedListFeature {
var moments: [MomentsInfo] = []
//
var isLoaded: Bool = false
//
var currentPage: Int = 1
var hasMore: Bool = true
var isLoadingMore: Bool = false
}
enum Action: Equatable {
case onAppear
case reload
case loadMore
case loadMoreResponse(TaskResult<MomentsLatestResponse>)
case editFeedButtonTapped // add
case editFeedDismissed //
//
@@ -34,6 +39,57 @@ struct FeedListFeature {
guard !state.isLoaded else { return .none }
state.isLoaded = true
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
@@ -49,21 +105,19 @@ struct FeedListFeature {
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
return .none
case .reload:
//
return .none
case .loadMore:
//
state.hasMore = false
return .none
case .editFeedButtonTapped:
state.isEditFeedPresented = true

View File

@@ -69,12 +69,29 @@ struct FeedListView: View {
LazyVStack(spacing: 16) {
ForEach(Array(viewStore.moments.enumerated()), id: \ .element.dynamicId) { index, moment in
OptimizedDynamicCardView(moment: moment, allMoments: viewStore.moments, currentIndex: index)
//
if index == viewStore.moments.count - 1, viewStore.hasMore, !viewStore.isLoadingMore {
Color.clear
.frame(height: 1)
.onAppear {
viewStore.send(.loadMore)
}
}
}
//
if viewStore.isLoadingMore {
ProgressView()
.progressViewStyle(CircularProgressViewStyle(tint: .white))
.padding(.vertical, 8)
}
}
.padding(.horizontal, 16)
.padding(.top, 10)
.padding(.bottom, 20)
}
.refreshable {
viewStore.send(.reload)
}
}
Spacer()
}