I’ve a ProductListScreen, which shows all merchandise. I need to make it possible for a consumer can not carry out a number of concurrent calls to the loadProducts. At the moment, I’m utilizing the next code and it really works. However I’m searching for higher choices and possibly even transferring the logic of process cancellation contained in the Retailer.
struct ProductListScreen: View {
let class: Class
@Atmosphere(Retailer.self) personal var retailer
@Atmosphere(.dismiss) personal var dismiss
@State personal var showAddProductScreen: Bool = false
@State personal var isLoading: Bool = false
personal func loadProducts() async {
guard !isLoading else { return }
isLoading = true
defer { isLoading = false }
do {
attempt await retailer.loadProductsBy(categoryId: class.id)
} catch {
// present error in toast message
print("Didn't load: (error.localizedDescription)")
}
}
var physique: some View {
ZStack {
if retailer.merchandise.isEmpty {
ContentUnavailableView("No merchandise obtainable", systemImage: "shippingbox")
} else {
Checklist(retailer.merchandise) { product in
NavigationLink {
ProductDetailScreen(product: product)
} label: {
ProductCellView(product: product)
}
}.refreshable(motion: {
await loadProducts()
})
}
}.overlay(alignment: .heart, content material: {
if isLoading {
ProgressView("Loading...")
}
})
.process {
await loadProducts()
}
Right here is my implementation of Retailer.
@MainActor
@Observable
class Retailer {
var classes: [Category] = []
var merchandise: [Product] = []
let httpClient: HTTPClient
init(httpClient: HTTPClient) {
self.httpClient = httpClient
}
func loadProductsBy(categoryId: Int) async throws {
let useful resource = Useful resource(endpoint: .productsByCategory(categoryId), modelType: [Product].self)
merchandise = attempt await httpClient.load(useful resource)
}