Modernize networking layer and fix category navigation and recipe list bugs

Network layer:
- Replace static CookbookApi protocol with instance-based CookbookApiProtocol
  using async/throws instead of tuple returns
- Refactor ApiRequest to use URLComponents for proper URL encoding, replace
  print statements with OSLog, and return typed NetworkError cases
- Add structured NetworkError variants (httpError, connectionError, etc.)
- Remove global cookbookApi constant in favor of injected dependency on AppState
- Delete unused RecipeEditViewModel, RecipeScraper, and Scraper playground

Data & model fixes:
- Add custom Decodable for RecipeDetail with safe fallbacks for malformed JSON
- Make Category Hashable/Equatable use only `name` so NavigationSplitView
  selection survives category refreshes with updated recipe_count
- Return server-assigned ID from uploadRecipe so new recipes get their ID
  before the post-upload refresh block executes

View updates:
- Refresh both old and new category recipe lists after upload when category
  changes, mapping empty recipeCategory to "*" for uncategorized recipes
- Raise deployment target to iOS 18, adopt new SwiftUI API conventions
- Clean up alerts, onboarding views, and settings

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-15 00:47:28 +01:00
parent 527acd2967
commit 7c824b492e
31 changed files with 534 additions and 1103 deletions

View File

@@ -94,33 +94,6 @@ enum RecipeAlert: UserAlert {
}
enum RecipeImportAlert: UserAlert {
case BAD_URL,
CHECK_CONNECTION,
WEBSITE_NOT_SUPPORTED
var localizedDescription: LocalizedStringKey {
switch self {
case .BAD_URL: return "Please check the entered URL."
case .CHECK_CONNECTION: return "Unable to load website content. Please check your internet connection."
case .WEBSITE_NOT_SUPPORTED: return "This website might not be currently supported. If this appears incorrect, you can use the support options in the app settings to raise awareness about this issue."
}
}
var localizedTitle: LocalizedStringKey {
switch self {
case .BAD_URL: return "Bad URL"
case .CHECK_CONNECTION: return "Connection error"
case .WEBSITE_NOT_SUPPORTED: return "Parsing error"
}
}
var alertButtons: [AlertButton] {
return [.OK]
}
}
enum RequestAlert: UserAlert {
case REQUEST_DELAYED,
REQUEST_DROPPED,