So I read that it's not possible to get an array of pages from the API (like; 1...50 or so), you have to do it individually. But I'm lazy so I'mm trying to work around it. Here is the api call
func fetchMovies(from endpoint: MovieListEndpoint, page: Int, completion: @escaping (Result<MovieResponse, MovieError>) -> ()) {
guard let url = URL(string: "\(baseAPIURL)/movie/\(endpoint.rawValue)?api_key=\(apiKey)&page=\(page)") else {
completion(.failure(.invalidEndpoint))
return
}
self.loadURLAndDecode(url: url) { [weak self] (result: Result<MovieResponse, MovieError>) in
switch result {
case .success(let movieResponse):
self?.movies.append(contentsOf: movieResponse.results)
// Increment the current page for the next fetch
self?.currentPage += 1
completion(.success(movieResponse))
case .failure(let error):
completion(.failure(error))
}
}
}
Here is the loading code
class MovieListState: ObservableObject {
@Published var movies: [Movie] = []
@Published var isLoading: Bool = false
@Published var error: MovieError?
private let movieService: MovieService
private var currentPage: Int = 1
init(movieService: MovieService = MovieStore.shared) {
self.movieService = movieService
}
func fetchNextPage(with endpoint: MovieListEndpoint) {
guard !isLoading else { return }
currentPage += 1
loadMovies(with: endpoint, page: currentPage)
}
func loadMovies(with endpoint: MovieListEndpoint, page: Int) {
isLoading = true
movieService.fetchMovies(from: endpoint, page: page) { [weak self] result in
guard let self = self else { return }
self.isLoading = false
switch result {
case .success(let response):
self.movies.append(contentsOf: response.results)
case .failure(let error):
self.error = error
}
}
}
}
and lastly the view code
struct MovieFullListView: View {
@ObservedObject private var movieListState: MovieListState
let title: String
let endpoint: MovieListEndpoint
@State var selection = 0
@State private var isScrolledToEnd = false
var items: [GridItem] = [GridItem(.flexible(), spacing: 20), GridItem(.flexible(), spacing: 20)]
init(title: String, endpoint: MovieListEndpoint) {
self.title = title
self.endpoint = endpoint
self.movieListState = MovieListState()
}
var body: some View {
VStack(alignment: .leading, spacing: 16) {
Text(title)
.font(.title)
.fontWeight(.bold)
.padding(.horizontal)
ScrollView(.vertical, showsIndicators: false) {
LazyVGrid(columns: items, spacing: 30) {
ForEach(movieListState.movies) { movie in
VStack {
NavigationLink(destination: MovieDetailView(movieId: movie.id)) {
MoviePosterCard(movie: movie)
.aspectRatio(contentMode: .fit)
}
.buttonStyle(.plain)
HStack {
Spacer()
Button(action: {
// Action code here
}) {
VStack {
if selection == 0 {
Image("Watched")
.resizable()
.frame(width: 28, height: 28)
} else {
Image("watch")
.resizable()
.frame(width: 28, height: 28)
}
}
}
Spacer()
Button(action: {
// Action code here
}) {
VStack {
if selection == 1 {
Image("Saved")
.resizable()
.frame(width: 25, height: 25)
} else {
Image("Save")
.resizable()
.frame(width: 25, height: 25)
}
}
}
Spacer()
}
.padding(.bottom, 6)
}
.background(Color.gray.opacity(0.1))
.cornerRadius(10)
}
}
Button(action: {
movieListState.fetchNextPage(with: endpoint)
}) {
Text("Load More")
.font(.headline)
.foregroundColor(.blue)
.padding()
.background(Color.gray.opacity(0.1))
.cornerRadius(10)
}
.padding()
}
}
.onAppear {
movieListState.loadMovies(with: endpoint, page: 1)
}
}
}
The problem is it doesn't fetch a new api call when I press the load more button. Any idea how to fix this?