Files
Nextcloud-Cookbook-iOS/Nextcloud Cookbook iOS Client/Network/NetworkError.swift
Hendrik Hogertz 7c824b492e 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>
2026-02-15 00:47:28 +01:00

52 lines
1.6 KiB
Swift

//
// CustomError.swift
// Nextcloud Cookbook iOS Client
//
// Created by Vincent Meilinger on 13.09.23.
//
import Foundation
public enum NetworkError: Error, LocalizedError {
case missingUrl
case encodingFailed(detail: String? = nil)
case decodingFailed(detail: String? = nil)
case httpError(statusCode: Int, body: String? = nil)
case connectionError(underlying: Error? = nil)
case invalidRequest
case unknownError(detail: String? = nil)
public var errorDescription: String? {
switch self {
case .missingUrl:
return "Missing URL."
case .encodingFailed(let detail):
return "Parameter encoding failed." + (detail.map { " \($0)" } ?? "")
case .decodingFailed(let detail):
return "Data decoding failed." + (detail.map { " \($0)" } ?? "")
case .httpError(let statusCode, let body):
return "HTTP error \(statusCode)." + (body.map { " \($0)" } ?? "")
case .connectionError(let underlying):
return "Connection error." + (underlying.map { " \($0.localizedDescription)" } ?? "")
case .invalidRequest:
return "Invalid request."
case .unknownError(let detail):
return "Unknown error." + (detail.map { " \($0)" } ?? "")
}
}
var isClientError: Bool {
if case .httpError(let statusCode, _) = self {
return (400...499).contains(statusCode)
}
return false
}
var isServerError: Bool {
if case .httpError(let statusCode, _) = self {
return (500...599).contains(statusCode)
}
return false
}
}