Download function for all recipes or recipes in a certain category

This commit is contained in:
Vicnet
2023-09-19 09:39:08 +02:00
parent 5fdfed9413
commit 4350cad1e0
6 changed files with 99 additions and 9 deletions

View File

@@ -9,6 +9,9 @@ import Foundation
import SwiftUI import SwiftUI
class DataStore { class DataStore {
let fileManager = FileManager.default
private static func fileURL(appending: String) throws -> URL { private static func fileURL(appending: String) throws -> URL {
try FileManager.default.url( try FileManager.default.url(
for: .documentDirectory, for: .documentDirectory,
@@ -53,16 +56,24 @@ class DataStore {
} }
} }
func recipeDetailExists(recipeId: Int) -> Bool {
let filePath = "recipe\(recipeId).data"
guard let folderPath = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first?.path() else { return false }
let exists = fileManager.fileExists(atPath: folderPath + filePath)
print("Path: ", folderPath + filePath)
print("Recipe detail with id \(recipeId)", exists ? "exists" : "does not exist")
return exists
}
func clearAll() -> Bool { func clearAll() -> Bool {
print("Attempting to delete all data ...") print("Attempting to delete all data ...")
let fm = FileManager.default guard let folderPath = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first?.path() else { return false }
guard let folderPath = fm.urls(for: .documentDirectory, in: .userDomainMask).first?.path() else { return false }
print("Folder path: ", folderPath) print("Folder path: ", folderPath)
do { do {
let filePaths = try fm.contentsOfDirectory(atPath: folderPath) let filePaths = try fileManager.contentsOfDirectory(atPath: folderPath)
for filePath in filePaths { for filePath in filePaths {
print("File path: ", filePath) print("File path: ", filePath)
try fm.removeItem(atPath: folderPath + filePath) try fileManager.removeItem(atPath: folderPath + filePath)
} }
} catch { } catch {
print("Could not delete documents folder contents: \(error)") print("Could not delete documents folder contents: \(error)")

View File

@@ -69,6 +69,30 @@ import UIKit
return RecipeDetail.error() return RecipeDetail.error()
} }
func downloadAllRecipes() async {
for category in categories {
await loadRecipeList(categoryName: category.name, needsUpdate: true)
guard let recipeList = recipes[category.name] else { continue }
for recipe in recipeList {
let _ = await loadRecipeDetail(recipeId: recipe.recipe_id, needsUpdate: true)
let _ = await loadImage(recipeId: recipe.recipe_id, full: false)
}
}
}
/// Check if recipeDetail is stored locally, either in cache or on disk
/// - Parameters
/// - recipeId: The id of a recipe.
/// - Returns: True if the recipeDetail is stored, otherwise false
func recipeDetailExists(recipeId: Int) -> Bool {
if recipeDetails[recipeId] != nil {
return true
} else if (dataStore.recipeDetailExists(recipeId: recipeId)) {
return true
}
return false
}
/// Try to load the recipe image from cache. If not found, try to load from store or the server. /// Try to load the recipe image from cache. If not found, try to load from store or the server.
/// - Parameters /// - Parameters
@@ -156,7 +180,7 @@ extension MainViewModel {
let (data, error): (D?, Error?) = await networkController.sendDataRequest(request) let (data, error): (D?, Error?) = await networkController.sendDataRequest(request)
print(error as Any) print(error as Any)
if let data = data { if let data = data {
try await dataStore.save(data: data, toPath: localPath) await dataStore.save(data: data, toPath: localPath)
} }
return data return data
} }

View File

@@ -26,7 +26,7 @@ struct CategoryCardView: View {
Text(category.name) Text(category.name)
.font(.headline) .font(.headline)
) )
.frame(maxHeight: 30) .frame(maxHeight: 25)
} }
) )
.clipShape(RoundedRectangle(cornerRadius: 10)) .clipShape(RoundedRectangle(cornerRadius: 10))

View File

@@ -13,13 +13,14 @@ import SwiftUI
struct RecipeBookView: View { struct RecipeBookView: View {
@State var categoryName: String @State var categoryName: String
@ObservedObject var viewModel: MainViewModel @ObservedObject var viewModel: MainViewModel
var body: some View { var body: some View {
ScrollView(showsIndicators: false) { ScrollView(showsIndicators: false) {
LazyVStack { LazyVStack {
if let recipes = viewModel.recipes[categoryName] { if let recipes = viewModel.recipes[categoryName] {
ForEach(recipes, id: \.recipe_id) { recipe in ForEach(recipes, id: \.recipe_id) { recipe in
NavigationLink(destination: RecipeDetailView(viewModel: viewModel, recipe: recipe)) { NavigationLink(destination: RecipeDetailView(viewModel: viewModel, recipe: recipe)) {
RecipeCardView(viewModel: viewModel, recipe: recipe) RecipeCardView(viewModel: viewModel, recipe: recipe, isDownloaded: viewModel.recipeDetailExists(recipeId: recipe.recipe_id))
} }
.buttonStyle(.plain) .buttonStyle(.plain)
} }
@@ -27,6 +28,22 @@ struct RecipeBookView: View {
} }
} }
.navigationTitle(categoryName) .navigationTitle(categoryName)
.toolbar {
Menu {
Button {
print("Downloading all recipes in category \(categoryName) ...")
downloadRecipes()
} label: {
HStack {
Text("Download recipes")
Image(systemName: "icloud.and.arrow.down")
}
}
} label: {
Image(systemName: "ellipsis.circle")
}
}
.task { .task {
await viewModel.loadRecipeList(categoryName: categoryName) await viewModel.loadRecipeList(categoryName: categoryName)
} }
@@ -34,4 +51,18 @@ struct RecipeBookView: View {
await viewModel.loadRecipeList(categoryName: categoryName, needsUpdate: true) await viewModel.loadRecipeList(categoryName: categoryName, needsUpdate: true)
} }
} }
func downloadRecipes() {
if let recipes = viewModel.recipes[categoryName] {
let dispatchQueue = DispatchQueue(label: "RecipeDownload", qos: .background)
dispatchQueue.async {
for recipe in recipes {
Task {
let _ = await viewModel.loadRecipeDetail(recipeId: recipe.recipe_id)
let _ = await viewModel.loadImage(recipeId: recipe.recipe_id, full: true)
}
}
}
}
}
} }

View File

@@ -12,7 +12,7 @@ struct MainView: View {
@StateObject var userSettings: UserSettings @StateObject var userSettings: UserSettings
var columns: [GridItem] = [GridItem(.adaptive(minimum: 150), spacing: 0)] var columns: [GridItem] = [GridItem(.adaptive(minimum: 150), spacing: 0)]
var body: some View { var body: some View {
NavigationStack { NavigationView {
ScrollView(.vertical, showsIndicators: false) { ScrollView(.vertical, showsIndicators: false) {
LazyVGrid(columns: columns, spacing: 0) { LazyVGrid(columns: columns, spacing: 0) {
ForEach(viewModel.categories, id: \.name) { category in ForEach(viewModel.categories, id: \.name) { category in
@@ -30,8 +30,24 @@ struct MainView: View {
} }
.navigationTitle("CookBook") .navigationTitle("CookBook")
.toolbar { .toolbar {
Menu {
Button {
print("Downloading all recipes ...")
Task {
await viewModel.downloadAllRecipes()
}
} label: {
HStack {
Text("Download all recipes")
Image(systemName: "icloud.and.arrow.down")
}
}
} label: {
Image(systemName: "ellipsis.circle")
}
NavigationLink( destination: SettingsView(userSettings: userSettings, viewModel: viewModel)) { NavigationLink( destination: SettingsView(userSettings: userSettings, viewModel: viewModel)) {
Image(systemName: "gear") Image(systemName: "gearshape")
} }
} }
} }

View File

@@ -12,6 +12,8 @@ struct RecipeCardView: View {
@State var viewModel: MainViewModel @State var viewModel: MainViewModel
@State var recipe: Recipe @State var recipe: Recipe
@State var recipeThumb: UIImage? @State var recipeThumb: UIImage?
@State var isDownloaded: Bool
var body: some View { var body: some View {
HStack { HStack {
Image(uiImage: recipeThumb ?? UIImage(named: "CookBook")!) Image(uiImage: recipeThumb ?? UIImage(named: "CookBook")!)
@@ -23,6 +25,12 @@ struct RecipeCardView: View {
.font(.headline) .font(.headline)
Spacer() Spacer()
VStack {
Image(systemName: isDownloaded ? "checkmark.icloud" : "icloud.and.arrow.down")
.foregroundColor(.secondary)
.padding()
Spacer()
}
} }
.background(.ultraThickMaterial) .background(.ultraThickMaterial)
.clipShape(RoundedRectangle(cornerRadius: 10)) .clipShape(RoundedRectangle(cornerRadius: 10))