I create a pagination display screen utilizing TMDb api in SwiftUI for GridView :
var physique: some View {
ZStack {
ScrollView {
LazyVGrid(columns: [GridItem(.adaptive(minimum: Constants.gridItemSize))]) {
ForEach(viewModel.motion pictures, id: .self.id) { film in
MovieColumn(film: film).onAppear {
if film == viewModel.motion pictures.final, viewModel.hasMoreData {
Job {
await viewModel.loadMoreData()
}
}
}
}
}
if(!viewModel.motion pictures.isEmpty) {
Spacer()
loadingOrErrorView
}
}
if(viewModel.motion pictures.isEmpty) {
loadingOrErrorView
}
}.process {
await viewModel.loadMoreData()
}
}
@ViewBuilder
non-public var loadingOrErrorView: some View {
change viewModel.viewState {
case .loading:
ProgressView()
case .failure(let error):
errorView(error: error)
case .idle:
EmptyView()
}
}
non-public func errorView(error: Error) -> some View {
VStack {
Textual content(error.localizedDescription)
.foregroundColor(.purple)
.multilineTextAlignment(.middle)
.padding()
Button(motion: {
Job {
await viewModel.loadMoreData()
}
}) {
Textual content("Retry")
.padding()
.background(Colour.blue)
.foregroundColor(.white)
.cornerRadius(8)
}
}
}
And right here is my ViewModel :
@Observable
class PaginationViewModel {
var motion pictures: [Movie] = []
var hasMoreData = true
var viewState: ViewState = .idle
@ObservationIgnored
non-public var currentPage = 1
@ObservationIgnored
non-public let networkService: NetworkService
init(networkService: NetworkService) {
self.networkService = networkService
}
@MainActor
func loadMoreData() async {
guard viewState != .loading && hasMoreData else { return }
self.viewState = .loading
do {
let request = TMDbRequest(path: .motion pictures, web page: currentPage)
let newItems: TMDbWrapper = strive await networkService.carry out(request: request)
self.motion pictures.append(contentsOf: newItems.motion pictures)
self.currentPage += 1
self.hasMoreData = newItems.motion pictures.rely == Constants.PAGE_SIZE
self.viewState = .idle
} catch {
self.viewState = .failure(error: error)
}
}
non-public struct Constants {
static let PAGE_SIZE = 20
}
}
enum ViewState: Equatable {
case idle
case loading
case failure(error: Error)
static func == (lhs: ViewState, rhs: ViewState) -> Bool {
change (lhs, rhs) {
case (.idle, .idle): return true
case (.loading, .loading): return true
case (.failure(error: _), .failure(error: _)): return true
default: return false
}
}
}
As you see I’ve applied loading and error view logic in two completely different place. One for preliminary state and one for loading subsequent web page. Is there any resolution to enhance this logic whereas utilizing GridView? I additionally marvel if in case you have a extra optimize resolution for Pagination in SwiftUI?
Supply code : https://github.com/alirezaeiii/Pagination-Task/tree/major