Recipe decoding fixes

This commit is contained in:
VincentMeilinger
2024-05-05 10:33:33 +02:00
parent 6ae9926c41
commit b66ef63b6a
8 changed files with 98 additions and 18 deletions

View File

@@ -135,11 +135,15 @@ import UIKit
guard UserSettings.shared.storeRecipes else { return }
guard let recipes = self.recipes[category] else { return }
for recipe in recipes {
if needsUpdate(category: category, lastModified: recipe.dateModified) {
print("\(recipe.name) needs an update. (last modified: \(recipe.dateModified)")
await updateRecipeDetail(id: recipe.recipe_id, withThumb: UserSettings.shared.storeThumb, withImage: UserSettings.shared.storeImages)
if let dateModified = recipe.dateModified {
if needsUpdate(category: category, lastModified: dateModified) {
print("\(recipe.name) needs an update. (last modified: \(recipe.dateModified)")
await updateRecipeDetail(id: recipe.recipe_id, withThumb: UserSettings.shared.storeThumb, withImage: UserSettings.shared.storeImages)
} else {
print("\(recipe.name) is up to date.")
}
} else {
print("\(recipe.name) is up to date.")
await updateRecipeDetail(id: recipe.recipe_id, withThumb: UserSettings.shared.storeThumb, withImage: UserSettings.shared.storeImages)
}
}
}

View File

@@ -55,12 +55,12 @@ class ObservableRecipeDetail: ObservableObject {
id = recipeDetail.id
name = recipeDetail.name
keywords = recipeDetail.keywords.isEmpty ? [] : recipeDetail.keywords.components(separatedBy: ",")
imageUrl = recipeDetail.imageUrl
imageUrl = recipeDetail.imageUrl ?? ""
prepTime = DurationComponents.fromPTString(recipeDetail.prepTime ?? "")
cookTime = DurationComponents.fromPTString(recipeDetail.cookTime ?? "")
totalTime = DurationComponents.fromPTString(recipeDetail.totalTime ?? "")
description = recipeDetail.description
url = recipeDetail.url
url = recipeDetail.url ?? ""
recipeYield = recipeDetail.recipeYield == 0 ? 1 : recipeDetail.recipeYield // Recipe yield should not be zero
recipeCategory = recipeDetail.recipeCategory
tool = recipeDetail.tool

View File

@@ -12,10 +12,10 @@ import SwiftUI
struct Recipe: Codable {
let name: String
let keywords: String?
let dateCreated: String
let dateModified: String
let imageUrl: String
let imagePlaceholderUrl: String
let dateCreated: String?
let dateModified: String?
let imageUrl: String?
let imagePlaceholderUrl: String?
let recipe_id: Int
// Properties excluded from Codable
@@ -35,15 +35,15 @@ extension Recipe: Identifiable, Hashable {
struct RecipeDetail: Codable {
var name: String
var keywords: String
var dateCreated: String
var dateModified: String
var imageUrl: String
var dateCreated: String?
var dateModified: String?
var imageUrl: String?
var id: String
var prepTime: String?
var cookTime: String?
var totalTime: String?
var description: String
var url: String
var url: String?
var recipeYield: Int
var recipeCategory: String
var tool: [String]
@@ -90,6 +90,33 @@ struct RecipeDetail: Codable {
recipeInstructions = []
nutrition = [:]
}
// Custom decoder to handle value type ambiguity
private enum CodingKeys: String, CodingKey {
case name, keywords, dateCreated, dateModified, imageUrl, id, prepTime, cookTime, totalTime, description, url, recipeYield, recipeCategory, tool, recipeIngredient, recipeInstructions, nutrition
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
name = try container.decode(String.self, forKey: .name)
keywords = try container.decode(String.self, forKey: .keywords)
dateCreated = try container.decodeIfPresent(String.self, forKey: .dateCreated)
dateModified = try container.decodeIfPresent(String.self, forKey: .dateModified)
imageUrl = try container.decodeIfPresent(String.self, forKey: .imageUrl)
id = try container.decode(String.self, forKey: .id)
prepTime = try container.decodeIfPresent(String.self, forKey: .prepTime)
cookTime = try container.decodeIfPresent(String.self, forKey: .cookTime)
totalTime = try container.decodeIfPresent(String.self, forKey: .totalTime)
description = try container.decode(String.self, forKey: .description)
url = try container.decode(String.self, forKey: .url)
recipeYield = try container.decode(Int.self, forKey: .recipeYield)
recipeCategory = try container.decode(String.self, forKey: .recipeCategory)
tool = try container.decode([String].self, forKey: .tool)
recipeIngredient = try container.decode([String].self, forKey: .recipeIngredient)
recipeInstructions = try container.decode([String].self, forKey: .recipeInstructions)
nutrition = try container.decode(Dictionary<String, JSONAny>.self, forKey: .nutrition).mapValues { String(describing: $0.value) }
}
}

View File

@@ -0,0 +1,35 @@
//
// JsonAny.swift
// Nextcloud Cookbook iOS Client
//
// Created by Vincent Meilinger on 05.05.24.
//
import Foundation
struct JSONAny: Codable {
let value: Any
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let intVal = try? container.decode(Int.self) {
value = intVal
} else if let stringVal = try? container.decode(String.self) {
value = stringVal
} else {
throw DecodingError.typeMismatch(JSONAny.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Unsupported type for JSONAny"))
}
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
switch value {
case let intValue as Int:
try container.encode(intValue)
case let stringValue as String:
try container.encode(stringValue)
default:
throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: encoder.codingPath, debugDescription: "Unsupported type for JSONAny"))
}
}
}

View File

@@ -131,8 +131,12 @@ struct MoreInformationSection: View {
var body: some View {
CollapsibleView(titleColor: .secondary, isCollapsed: !UserSettings.shared.expandInfoSection) {
VStack(alignment: .leading) {
Text("Created: \(Date.convertISOStringToLocalString(isoDateString: viewModel.recipeDetail.dateCreated) ?? "")")
Text("Last modified: \(Date.convertISOStringToLocalString(isoDateString: viewModel.recipeDetail.dateModified) ?? "")")
if let dateCreated = viewModel.recipeDetail.dateCreated {
Text("Created: \(Date.convertISOStringToLocalString(isoDateString: dateCreated) ?? "")")
}
if let dateModified = viewModel.recipeDetail.dateModified {
Text("Last modified: \(Date.convertISOStringToLocalString(isoDateString: dateModified) ?? "")")
}
if viewModel.observableRecipeDetail.url != "", let url = URL(string: viewModel.observableRecipeDetail.url) {
HStack(alignment: .top) {
Text("URL:")