I have a movie listing view with basic listing functionality, Once pagination reaches to the last page I want to show an alert for that I am using reachedLastPage
property.
The viewModel.state
is an enum, the case movies has associated value in which there is moreRemaining
property which tells if there are more pages or not.
Once the moreRemaining
property becomes false I want to make reachedLastPage
to true so that I can show an alert.
How can I achieve this in best way?
import SwiftUI
import SwiftUIRefresh
struct MovieListingView<T>: View where T: BaseMoviesListViewModel {
@ObservedObject var viewModel: T
@State var title: String
@State var reachedLastPage: Bool = false
var body: some View {
NavigationView {
ZStack {
switch viewModel.state {
case .loading:
LoadingView(title: "Loading Movies...")
.onAppear {
fetchMovies()
}
case .error(let error):
ErrorView(message: error.localizedDescription, buttonTitle: "Retry") {
fetchMovies()
}
case .noData:
Text("No data")
.multilineTextAlignment(.center)
.font(.system(size: 20))
case .movies(let data):
List {
ForEach(data.movies) { movie in
NavigationLink(destination: LazyView(MovieDetailView(viewModel: MovieDetailViewModel(id: movie.id)))) {
MovieViewRow(movie: movie)
.onAppear {
if movie == data.movies.last && data.moreRemaining {
DispatchQueue.main.asyncAfter(deadline: .now() 1) {
fetchMovies()
}
}
}
}
if movie == data.movies.last && data.moreRemaining {
HStack {
Spacer()
ActivityIndicator(isAnimating: .constant(data.moreRemaining))
Spacer()
}
}
}
}.pullToRefresh(isShowing: .constant(data.isRefreshing)) {
print("Refresheeeee")
DispatchQueue.main.asyncAfter(deadline: .now() 1) {
refreshMovies()
}
}
}
}
.navigationViewStyle(.stack)
.navigationBarTitle("\(title)", displayMode: .inline)
.alert(isPresented: $reachedLastPage) {
Alert(title: Text("You have reached to the end of the list."))
}
}
}
private func fetchMovies() {
viewModel.trigger(.fetchMovies(false))
}
private func refreshMovies() {
viewModel.trigger(.fetchMovies(true))
}
}
CodePudding user response:
you could try this approach, using .onReceive(...)
. Add this to your
ZStack
or NavigationView
:
.onReceive(Just(viewModel.moreRemaining)) { val in
reachedLastPage = !val
}
Also add: import Combine
CodePudding user response:
(Ignoring "the best way" part, 'cause it's opinion-based,) one way to achieve that is to make your view model an observable object (which likely already is), adding the publisher of reachedLastPage
there, and observe it directly from the view. Something like this:
final class ContentViewModel: ObservableObject {
@Published var reachedLastPage = false
init() {
// Just an example of changing the value.
DispatchQueue.main.asyncAfter(deadline: .now() .seconds(1)) { self.reachedLastPage = true }
}
}
struct ContentView: View {
var body: some View {
Text("Hello World")
.alert(isPresented: $viewModel.reachedLastPage) {
Alert(title: Text("Alert is triggered"))
}
}
@ObservedObject private var viewModel: ContentViewModel
init(viewModel: ContentViewModel) {
self.viewModel = viewModel
}
}
Once reachedLastPage
takes the true
value, the alert will be presented.