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:
@@ -26,13 +26,10 @@
|
||||
A70171CD2AB501B100064C43 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A70171CC2AB501B100064C43 /* SettingsView.swift */; };
|
||||
A703226A2ABAF49800D7C4ED /* JSONCoderExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A70322692ABAF49800D7C4ED /* JSONCoderExtension.swift */; };
|
||||
A703226F2ABB1DD700D7C4ED /* ColorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A703226E2ABB1DD700D7C4ED /* ColorExtension.swift */; };
|
||||
A74D33BE2AF82AAE00D06555 /* SwiftSoup in Frameworks */ = {isa = PBXBuildFile; productRef = A74D33BD2AF82AAE00D06555 /* SwiftSoup */; };
|
||||
A74D33C32AFCD1C300D06555 /* RecipeScraper.swift in Sources */ = {isa = PBXBuildFile; fileRef = A74D33C22AFCD1C300D06555 /* RecipeScraper.swift */; };
|
||||
A76B8A6F2ADFFA8800096CEC /* SupportedLanguage.swift in Sources */ = {isa = PBXBuildFile; fileRef = A76B8A6E2ADFFA8800096CEC /* SupportedLanguage.swift */; };
|
||||
A76B8A712AE002AE00096CEC /* Alerts.swift in Sources */ = {isa = PBXBuildFile; fileRef = A76B8A702AE002AE00096CEC /* Alerts.swift */; };
|
||||
A787B0782B2B1E6400C2DF1B /* DateExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A787B0772B2B1E6400C2DF1B /* DateExtension.swift */; };
|
||||
A79AA8E02AFF80E3007D25F2 /* DurationComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = A79AA8DF2AFF80E3007D25F2 /* DurationComponents.swift */; };
|
||||
A79AA8E22AFF8C14007D25F2 /* RecipeEditViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A79AA8E12AFF8C14007D25F2 /* RecipeEditViewModel.swift */; };
|
||||
A79AA8E42B02A962007D25F2 /* CookbookApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = A79AA8E32B02A961007D25F2 /* CookbookApi.swift */; };
|
||||
A79AA8E62B02C3CB007D25F2 /* LoggerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A79AA8E52B02C3CB007D25F2 /* LoggerExtension.swift */; };
|
||||
A79AA8E92B062DD1007D25F2 /* CookbookApiV1.swift in Sources */ = {isa = PBXBuildFile; fileRef = A79AA8E82B062DD1007D25F2 /* CookbookApiV1.swift */; };
|
||||
@@ -110,12 +107,10 @@
|
||||
A70171CC2AB501B100064C43 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
|
||||
A70322692ABAF49800D7C4ED /* JSONCoderExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONCoderExtension.swift; sourceTree = "<group>"; };
|
||||
A703226E2ABB1DD700D7C4ED /* ColorExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorExtension.swift; sourceTree = "<group>"; };
|
||||
A74D33C22AFCD1C300D06555 /* RecipeScraper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeScraper.swift; sourceTree = "<group>"; };
|
||||
A76B8A6E2ADFFA8800096CEC /* SupportedLanguage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupportedLanguage.swift; sourceTree = "<group>"; };
|
||||
A76B8A702AE002AE00096CEC /* Alerts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Alerts.swift; sourceTree = "<group>"; };
|
||||
A787B0772B2B1E6400C2DF1B /* DateExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateExtension.swift; sourceTree = "<group>"; };
|
||||
A79AA8DF2AFF80E3007D25F2 /* DurationComponents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DurationComponents.swift; sourceTree = "<group>"; };
|
||||
A79AA8E12AFF8C14007D25F2 /* RecipeEditViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeEditViewModel.swift; sourceTree = "<group>"; };
|
||||
A79AA8E32B02A961007D25F2 /* CookbookApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CookbookApi.swift; sourceTree = "<group>"; };
|
||||
A79AA8E52B02C3CB007D25F2 /* LoggerExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoggerExtension.swift; sourceTree = "<group>"; };
|
||||
A79AA8E82B062DD1007D25F2 /* CookbookApiV1.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CookbookApiV1.swift; sourceTree = "<group>"; };
|
||||
@@ -157,7 +152,6 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
A74D33BE2AF82AAE00D06555 /* SwiftSoup in Frameworks */,
|
||||
A9CA6CF62B4C63F200F78AB5 /* TPPDF in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -263,7 +257,6 @@
|
||||
A70171B72AB2445700064C43 /* Models */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A79AA8E12AFF8C14007D25F2 /* RecipeEditViewModel.swift */,
|
||||
);
|
||||
path = Models;
|
||||
sourceTree = "<group>";
|
||||
@@ -314,7 +307,6 @@
|
||||
A781E75F2AF8228100452F6F /* RecipeImport */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A74D33C22AFCD1C300D06555 /* RecipeScraper.swift */,
|
||||
);
|
||||
path = RecipeImport;
|
||||
sourceTree = "<group>";
|
||||
@@ -441,7 +433,6 @@
|
||||
);
|
||||
name = "Nextcloud Cookbook iOS Client";
|
||||
packageProductDependencies = (
|
||||
A74D33BD2AF82AAE00D06555 /* SwiftSoup */,
|
||||
A9CA6CF52B4C63F200F78AB5 /* TPPDF */,
|
||||
);
|
||||
productName = "Nextcloud Cookbook iOS Client";
|
||||
@@ -520,7 +511,6 @@
|
||||
);
|
||||
mainGroup = A70171752AA8E71900064C43;
|
||||
packageReferences = (
|
||||
A74D33BC2AF82AAE00D06555 /* XCRemoteSwiftPackageReference "SwiftSoup" */,
|
||||
A9CA6CF42B4C63F200F78AB5 /* XCRemoteSwiftPackageReference "TPPDF" */,
|
||||
);
|
||||
productRefGroup = A701717F2AA8E71900064C43 /* Products */;
|
||||
@@ -575,7 +565,7 @@
|
||||
A9805BED2BAAC70E003B7231 /* NumberFormatter.swift in Sources */,
|
||||
A9D89AB02B4FE97800F49D92 /* TimerView.swift in Sources */,
|
||||
A9BBB38C2B8D3B0C002DA7FF /* ParallaxHeaderView.swift in Sources */,
|
||||
A79AA8E22AFF8C14007D25F2 /* RecipeEditViewModel.swift in Sources */,
|
||||
A79AA8E02AFF80E3007D25F2 /* DurationComponents.swift in Sources */,
|
||||
A97506152B920DF200E86029 /* RecipeGenericViews.swift in Sources */,
|
||||
A7FB0D7C2B25C68500A3469E /* TokenLoginView.swift in Sources */,
|
||||
A977D0E22B60034E009783A9 /* GroceryListTabView.swift in Sources */,
|
||||
@@ -613,7 +603,6 @@
|
||||
A79AA8ED2B063AD5007D25F2 /* NextcloudApi.swift in Sources */,
|
||||
A97506132B920D9F00E86029 /* RecipeDurationSection.swift in Sources */,
|
||||
A70171822AA8E71900064C43 /* Nextcloud_Cookbook_iOS_ClientApp.swift in Sources */,
|
||||
A74D33C32AFCD1C300D06555 /* RecipeScraper.swift in Sources */,
|
||||
A70171AD2AA8EF4700064C43 /* AppState.swift in Sources */,
|
||||
A76B8A6F2ADFFA8800096CEC /* SupportedLanguage.swift in Sources */,
|
||||
A977D0E02B600318009783A9 /* RecipeTabView.swift in Sources */,
|
||||
@@ -993,14 +982,6 @@
|
||||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCRemoteSwiftPackageReference section */
|
||||
A74D33BC2AF82AAE00D06555 /* XCRemoteSwiftPackageReference "SwiftSoup" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/scinfu/SwiftSoup.git";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 2.6.1;
|
||||
};
|
||||
};
|
||||
A9CA6CF42B4C63F200F78AB5 /* XCRemoteSwiftPackageReference "TPPDF" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/techprimate/TPPDF.git";
|
||||
@@ -1012,11 +993,6 @@
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
A74D33BD2AF82AAE00D06555 /* SwiftSoup */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = A74D33BC2AF82AAE00D06555 /* XCRemoteSwiftPackageReference "SwiftSoup" */;
|
||||
productName = SwiftSoup;
|
||||
};
|
||||
A9CA6CF52B4C63F200F78AB5 /* TPPDF */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = A9CA6CF42B4C63F200F78AB5 /* XCRemoteSwiftPackageReference "TPPDF" */;
|
||||
|
||||
Reference in New Issue
Block a user