Add Share Extension for importing recipes via URL

Adds a Share Extension so users can share URLs from Safari (or any app)
to open the main app with the ImportURLSheet pre-filled. Uses a custom
URL scheme (nextcloud-cookbook://) as the bridge between the extension
and the main app.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-15 10:17:22 +01:00
parent 151e69ff28
commit ce2a814e5a
10 changed files with 547 additions and 26 deletions

View File

@@ -3,10 +3,11 @@
archiveVersion = 1; archiveVersion = 1;
classes = { classes = {
}; };
objectVersion = 56; objectVersion = 70;
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
A1B2C3D52F0A000100000001 /* AppearanceMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3D42F0A000100000001 /* AppearanceMode.swift */; };
A70171822AA8E71900064C43 /* Nextcloud_Cookbook_iOS_ClientApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = A70171812AA8E71900064C43 /* Nextcloud_Cookbook_iOS_ClientApp.swift */; }; A70171822AA8E71900064C43 /* Nextcloud_Cookbook_iOS_ClientApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = A70171812AA8E71900064C43 /* Nextcloud_Cookbook_iOS_ClientApp.swift */; };
A70171842AA8E71900064C43 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A70171832AA8E71900064C43 /* MainView.swift */; }; A70171842AA8E71900064C43 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A70171832AA8E71900064C43 /* MainView.swift */; };
A70171862AA8E71F00064C43 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A70171852AA8E71F00064C43 /* Assets.xcassets */; }; A70171862AA8E71F00064C43 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A70171852AA8E71F00064C43 /* Assets.xcassets */; };
@@ -20,10 +21,6 @@
A70171BE2AB4987900064C43 /* RecipeListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A70171BD2AB4987900064C43 /* RecipeListView.swift */; }; A70171BE2AB4987900064C43 /* RecipeListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A70171BD2AB4987900064C43 /* RecipeListView.swift */; };
A70171C02AB498A900064C43 /* RecipeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A70171BF2AB498A900064C43 /* RecipeView.swift */; }; A70171C02AB498A900064C43 /* RecipeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A70171BF2AB498A900064C43 /* RecipeView.swift */; };
A70171C22AB498C600064C43 /* RecipeCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A70171C12AB498C600064C43 /* RecipeCardView.swift */; }; A70171C22AB498C600064C43 /* RecipeCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A70171C12AB498C600064C43 /* RecipeCardView.swift */; };
B1C0DE022CF0000100000001 /* CategoryCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1C0DE012CF0000100000001 /* CategoryCardView.swift */; };
B1C0DE042CF0000200000002 /* RecentRecipesSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1C0DE032CF0000200000002 /* RecentRecipesSection.swift */; };
B1C0DE062CF0000300000003 /* AllRecipesCategoryCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1C0DE052CF0000300000003 /* AllRecipesCategoryCardView.swift */; };
B1C0DE082CF0000400000004 /* AllRecipesListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1C0DE072CF0000400000004 /* AllRecipesListView.swift */; };
A70171C42AB4A31200064C43 /* DataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = A70171C32AB4A31200064C43 /* DataStore.swift */; }; A70171C42AB4A31200064C43 /* DataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = A70171C32AB4A31200064C43 /* DataStore.swift */; };
A70171C62AB4C43A00064C43 /* DataModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = A70171C52AB4C43A00064C43 /* DataModels.swift */; }; A70171C62AB4C43A00064C43 /* DataModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = A70171C52AB4C43A00064C43 /* DataModels.swift */; };
A70171CB2AB4CD1700064C43 /* UserSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = A70171CA2AB4CD1700064C43 /* UserSettings.swift */; }; A70171CB2AB4CD1700064C43 /* UserSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = A70171CA2AB4CD1700064C43 /* UserSettings.swift */; };
@@ -41,7 +38,6 @@
A79AA8ED2B063AD5007D25F2 /* NextcloudApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = A79AA8EC2B063AD5007D25F2 /* NextcloudApi.swift */; }; A79AA8ED2B063AD5007D25F2 /* NextcloudApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = A79AA8EC2B063AD5007D25F2 /* NextcloudApi.swift */; };
A7AEAE642AD5521400135378 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = A7AEAE632AD5521400135378 /* Localizable.xcstrings */; }; A7AEAE642AD5521400135378 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = A7AEAE632AD5521400135378 /* Localizable.xcstrings */; };
A7CD3FD22B2C546A00D764AD /* CollapsibleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7CD3FD12B2C546A00D764AD /* CollapsibleView.swift */; }; A7CD3FD22B2C546A00D764AD /* CollapsibleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7CD3FD12B2C546A00D764AD /* CollapsibleView.swift */; };
DFCB4E9FD4E0884AF217E5C5 /* LiquidGlassModifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04B6ECAD063AEE501543FC76 /* LiquidGlassModifiers.swift */; };
A7F3F8E82ACBFC760076C227 /* RecipeKeywordSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7F3F8E72ACBFC760076C227 /* RecipeKeywordSection.swift */; }; A7F3F8E82ACBFC760076C227 /* RecipeKeywordSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7F3F8E72ACBFC760076C227 /* RecipeKeywordSection.swift */; };
A7FB0D7A2B25C66600A3469E /* OnboardingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7FB0D792B25C66600A3469E /* OnboardingView.swift */; }; A7FB0D7A2B25C66600A3469E /* OnboardingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7FB0D792B25C66600A3469E /* OnboardingView.swift */; };
A7FB0D7C2B25C68500A3469E /* TokenLoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7FB0D7B2B25C68500A3469E /* TokenLoginView.swift */; }; A7FB0D7C2B25C68500A3469E /* TokenLoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7FB0D7B2B25C68500A3469E /* TokenLoginView.swift */; };
@@ -65,16 +61,20 @@
A9CA6CEF2B4C086100F78AB5 /* RecipeExporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9CA6CEE2B4C086100F78AB5 /* RecipeExporter.swift */; }; A9CA6CEF2B4C086100F78AB5 /* RecipeExporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9CA6CEE2B4C086100F78AB5 /* RecipeExporter.swift */; };
A9CA6CF62B4C63F200F78AB5 /* TPPDF in Frameworks */ = {isa = PBXBuildFile; productRef = A9CA6CF52B4C63F200F78AB5 /* TPPDF */; }; A9CA6CF62B4C63F200F78AB5 /* TPPDF in Frameworks */ = {isa = PBXBuildFile; productRef = A9CA6CF52B4C63F200F78AB5 /* TPPDF */; };
A9D89AB02B4FE97800F49D92 /* TimerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D89AAF2B4FE97800F49D92 /* TimerView.swift */; }; A9D89AB02B4FE97800F49D92 /* TimerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D89AAF2B4FE97800F49D92 /* TimerView.swift */; };
A9D8F9052B99F3E5009BACAE /* RecipeImportSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D8F9042B99F3E4009BACAE /* RecipeImportSection.swift */; };
C1F0AB022D0B000100000001 /* ImportURLSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F0AB012D0B000100000001 /* ImportURLSheet.swift */; };
A9E78A2B2BE7799F00206866 /* JsonAny.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E78A2A2BE7799F00206866 /* JsonAny.swift */; }; A9E78A2B2BE7799F00206866 /* JsonAny.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E78A2A2BE7799F00206866 /* JsonAny.swift */; };
A9FA2AB62B5079B200A43702 /* alarm_sound_0.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = A9FA2AB52B5079B200A43702 /* alarm_sound_0.mp3 */; }; A9FA2AB62B5079B200A43702 /* alarm_sound_0.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = A9FA2AB52B5079B200A43702 /* alarm_sound_0.mp3 */; };
A1B2C3D52F0A000100000001 /* AppearanceMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3D42F0A000100000001 /* AppearanceMode.swift */; }; B1C0DE022CF0000100000001 /* CategoryCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1C0DE012CF0000100000001 /* CategoryCardView.swift */; };
B1C0DE042CF0000200000002 /* RecentRecipesSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1C0DE032CF0000200000002 /* RecentRecipesSection.swift */; };
B1C0DE062CF0000300000003 /* AllRecipesCategoryCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1C0DE052CF0000300000003 /* AllRecipesCategoryCardView.swift */; };
B1C0DE082CF0000400000004 /* AllRecipesListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1C0DE072CF0000400000004 /* AllRecipesListView.swift */; };
C1F0AB022D0B000100000001 /* ImportURLSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F0AB012D0B000100000001 /* ImportURLSheet.swift */; };
D1A0CE012D0A000100000001 /* GroceryListMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1A0CE002D0A000100000001 /* GroceryListMode.swift */; }; D1A0CE012D0A000100000001 /* GroceryListMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1A0CE002D0A000100000001 /* GroceryListMode.swift */; };
D1A0CE032D0A000200000002 /* RemindersGroceryStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1A0CE022D0A000200000002 /* RemindersGroceryStore.swift */; }; D1A0CE032D0A000200000002 /* RemindersGroceryStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1A0CE022D0A000200000002 /* RemindersGroceryStore.swift */; };
D1A0CE052D0A000300000003 /* GroceryListManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1A0CE042D0A000300000003 /* GroceryListManager.swift */; }; D1A0CE052D0A000300000003 /* GroceryListManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1A0CE042D0A000300000003 /* GroceryListManager.swift */; };
DFCB4E9FD4E0884AF217E5C5 /* LiquidGlassModifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04B6ECAD063AEE501543FC76 /* LiquidGlassModifiers.swift */; };
E1B0CF072D0B000400000004 /* GroceryStateModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B0CF062D0B000400000004 /* GroceryStateModels.swift */; }; E1B0CF072D0B000400000004 /* GroceryStateModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B0CF062D0B000400000004 /* GroceryStateModels.swift */; };
E1B0CF092D0B000500000005 /* GroceryStateSyncManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B0CF082D0B000500000005 /* GroceryStateSyncManager.swift */; }; E1B0CF092D0B000500000005 /* GroceryStateSyncManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B0CF082D0B000500000005 /* GroceryStateSyncManager.swift */; };
E498A7A42F41C35500D7D7A4 /* ShareExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = E498A79A2F41C35500D7D7A4 /* ShareExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
F1A0DE022E0C000100000001 /* MealPlanModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1A0DE012E0C000100000001 /* MealPlanModels.swift */; }; F1A0DE022E0C000100000001 /* MealPlanModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1A0DE012E0C000100000001 /* MealPlanModels.swift */; };
F1A0DE042E0C000200000002 /* MealPlanManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1A0DE032E0C000200000002 /* MealPlanManager.swift */; }; F1A0DE042E0C000200000002 /* MealPlanManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1A0DE032E0C000200000002 /* MealPlanManager.swift */; };
F1A0DE062E0C000300000003 /* MealPlanSyncManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1A0DE052E0C000300000003 /* MealPlanSyncManager.swift */; }; F1A0DE062E0C000300000003 /* MealPlanSyncManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1A0DE052E0C000300000003 /* MealPlanSyncManager.swift */; };
@@ -99,9 +99,32 @@
remoteGlobalIDString = A701717D2AA8E71900064C43; remoteGlobalIDString = A701717D2AA8E71900064C43;
remoteInfo = "Nextcloud Cookbook iOS Client"; remoteInfo = "Nextcloud Cookbook iOS Client";
}; };
E498A7A22F41C35500D7D7A4 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = A70171762AA8E71900064C43 /* Project object */;
proxyType = 1;
remoteGlobalIDString = E498A7992F41C35500D7D7A4;
remoteInfo = ShareExtension;
};
/* End PBXContainerItemProxy section */ /* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
E498A7A52F41C35500D7D7A4 /* Embed Foundation Extensions */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 13;
files = (
E498A7A42F41C35500D7D7A4 /* ShareExtension.appex in Embed Foundation Extensions */,
);
name = "Embed Foundation Extensions";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
04B6ECAD063AEE501543FC76 /* LiquidGlassModifiers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiquidGlassModifiers.swift; sourceTree = "<group>"; };
A1B2C3D42F0A000100000001 /* AppearanceMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearanceMode.swift; sourceTree = "<group>"; };
A701717E2AA8E71900064C43 /* Nextcloud Cookbook iOS Client.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Nextcloud Cookbook iOS Client.app"; sourceTree = BUILT_PRODUCTS_DIR; }; A701717E2AA8E71900064C43 /* Nextcloud Cookbook iOS Client.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Nextcloud Cookbook iOS Client.app"; sourceTree = BUILT_PRODUCTS_DIR; };
A70171812AA8E71900064C43 /* Nextcloud_Cookbook_iOS_ClientApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Nextcloud_Cookbook_iOS_ClientApp.swift; sourceTree = "<group>"; }; A70171812AA8E71900064C43 /* Nextcloud_Cookbook_iOS_ClientApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Nextcloud_Cookbook_iOS_ClientApp.swift; sourceTree = "<group>"; };
A70171832AA8E71900064C43 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = "<group>"; }; A70171832AA8E71900064C43 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = "<group>"; };
@@ -119,10 +142,6 @@
A70171BD2AB4987900064C43 /* RecipeListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeListView.swift; sourceTree = "<group>"; }; A70171BD2AB4987900064C43 /* RecipeListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeListView.swift; sourceTree = "<group>"; };
A70171BF2AB498A900064C43 /* RecipeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeView.swift; sourceTree = "<group>"; }; A70171BF2AB498A900064C43 /* RecipeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeView.swift; sourceTree = "<group>"; };
A70171C12AB498C600064C43 /* RecipeCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeCardView.swift; sourceTree = "<group>"; }; A70171C12AB498C600064C43 /* RecipeCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeCardView.swift; sourceTree = "<group>"; };
B1C0DE012CF0000100000001 /* CategoryCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryCardView.swift; sourceTree = "<group>"; };
B1C0DE032CF0000200000002 /* RecentRecipesSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecentRecipesSection.swift; sourceTree = "<group>"; };
B1C0DE052CF0000300000003 /* AllRecipesCategoryCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllRecipesCategoryCardView.swift; sourceTree = "<group>"; };
B1C0DE072CF0000400000004 /* AllRecipesListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllRecipesListView.swift; sourceTree = "<group>"; };
A70171C32AB4A31200064C43 /* DataStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataStore.swift; sourceTree = "<group>"; }; A70171C32AB4A31200064C43 /* DataStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataStore.swift; sourceTree = "<group>"; };
A70171C52AB4C43A00064C43 /* DataModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataModels.swift; sourceTree = "<group>"; }; A70171C52AB4C43A00064C43 /* DataModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataModels.swift; sourceTree = "<group>"; };
A70171CA2AB4CD1700064C43 /* UserSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSettings.swift; sourceTree = "<group>"; }; A70171CA2AB4CD1700064C43 /* UserSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSettings.swift; sourceTree = "<group>"; };
@@ -140,7 +159,6 @@
A79AA8EC2B063AD5007D25F2 /* NextcloudApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextcloudApi.swift; sourceTree = "<group>"; }; A79AA8EC2B063AD5007D25F2 /* NextcloudApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextcloudApi.swift; sourceTree = "<group>"; };
A7AEAE632AD5521400135378 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = "<group>"; }; A7AEAE632AD5521400135378 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = "<group>"; };
A7CD3FD12B2C546A00D764AD /* CollapsibleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsibleView.swift; sourceTree = "<group>"; }; A7CD3FD12B2C546A00D764AD /* CollapsibleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsibleView.swift; sourceTree = "<group>"; };
04B6ECAD063AEE501543FC76 /* LiquidGlassModifiers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiquidGlassModifiers.swift; sourceTree = "<group>"; };
A7F3F8E72ACBFC760076C227 /* RecipeKeywordSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeKeywordSection.swift; sourceTree = "<group>"; }; A7F3F8E72ACBFC760076C227 /* RecipeKeywordSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeKeywordSection.swift; sourceTree = "<group>"; };
A7FB0D792B25C66600A3469E /* OnboardingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingView.swift; sourceTree = "<group>"; }; A7FB0D792B25C66600A3469E /* OnboardingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingView.swift; sourceTree = "<group>"; };
A7FB0D7B2B25C68500A3469E /* TokenLoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenLoginView.swift; sourceTree = "<group>"; }; A7FB0D7B2B25C68500A3469E /* TokenLoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenLoginView.swift; sourceTree = "<group>"; };
@@ -164,16 +182,20 @@
A9CA6CEE2B4C086100F78AB5 /* RecipeExporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeExporter.swift; sourceTree = "<group>"; }; A9CA6CEE2B4C086100F78AB5 /* RecipeExporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeExporter.swift; sourceTree = "<group>"; };
A9D89AAF2B4FE97800F49D92 /* TimerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimerView.swift; sourceTree = "<group>"; }; A9D89AAF2B4FE97800F49D92 /* TimerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimerView.swift; sourceTree = "<group>"; };
A9D8F9042B99F3E4009BACAE /* RecipeImportSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeImportSection.swift; sourceTree = "<group>"; }; A9D8F9042B99F3E4009BACAE /* RecipeImportSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeImportSection.swift; sourceTree = "<group>"; };
C1F0AB012D0B000100000001 /* ImportURLSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportURLSheet.swift; sourceTree = "<group>"; };
A9DA25D42B82096B0061FC2B /* Nextcloud-Cookbook-iOS-Client-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "Nextcloud-Cookbook-iOS-Client-Info.plist"; sourceTree = SOURCE_ROOT; }; A9DA25D42B82096B0061FC2B /* Nextcloud-Cookbook-iOS-Client-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "Nextcloud-Cookbook-iOS-Client-Info.plist"; sourceTree = SOURCE_ROOT; };
A9E78A2A2BE7799F00206866 /* JsonAny.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JsonAny.swift; sourceTree = "<group>"; }; A9E78A2A2BE7799F00206866 /* JsonAny.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JsonAny.swift; sourceTree = "<group>"; };
A9FA2AB52B5079B200A43702 /* alarm_sound_0.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = alarm_sound_0.mp3; sourceTree = "<group>"; }; A9FA2AB52B5079B200A43702 /* alarm_sound_0.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = alarm_sound_0.mp3; sourceTree = "<group>"; };
A1B2C3D42F0A000100000001 /* AppearanceMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearanceMode.swift; sourceTree = "<group>"; }; B1C0DE012CF0000100000001 /* CategoryCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryCardView.swift; sourceTree = "<group>"; };
B1C0DE032CF0000200000002 /* RecentRecipesSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecentRecipesSection.swift; sourceTree = "<group>"; };
B1C0DE052CF0000300000003 /* AllRecipesCategoryCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllRecipesCategoryCardView.swift; sourceTree = "<group>"; };
B1C0DE072CF0000400000004 /* AllRecipesListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllRecipesListView.swift; sourceTree = "<group>"; };
C1F0AB012D0B000100000001 /* ImportURLSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportURLSheet.swift; sourceTree = "<group>"; };
D1A0CE002D0A000100000001 /* GroceryListMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroceryListMode.swift; sourceTree = "<group>"; }; D1A0CE002D0A000100000001 /* GroceryListMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroceryListMode.swift; sourceTree = "<group>"; };
D1A0CE022D0A000200000002 /* RemindersGroceryStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemindersGroceryStore.swift; sourceTree = "<group>"; }; D1A0CE022D0A000200000002 /* RemindersGroceryStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemindersGroceryStore.swift; sourceTree = "<group>"; };
D1A0CE042D0A000300000003 /* GroceryListManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroceryListManager.swift; sourceTree = "<group>"; }; D1A0CE042D0A000300000003 /* GroceryListManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroceryListManager.swift; sourceTree = "<group>"; };
E1B0CF062D0B000400000004 /* GroceryStateModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroceryStateModels.swift; sourceTree = "<group>"; }; E1B0CF062D0B000400000004 /* GroceryStateModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroceryStateModels.swift; sourceTree = "<group>"; };
E1B0CF082D0B000500000005 /* GroceryStateSyncManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroceryStateSyncManager.swift; sourceTree = "<group>"; }; E1B0CF082D0B000500000005 /* GroceryStateSyncManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroceryStateSyncManager.swift; sourceTree = "<group>"; };
E498A79A2F41C35500D7D7A4 /* ShareExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = ShareExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
F1A0DE012E0C000100000001 /* MealPlanModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MealPlanModels.swift; sourceTree = "<group>"; }; F1A0DE012E0C000100000001 /* MealPlanModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MealPlanModels.swift; sourceTree = "<group>"; };
F1A0DE032E0C000200000002 /* MealPlanManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MealPlanManager.swift; sourceTree = "<group>"; }; F1A0DE032E0C000200000002 /* MealPlanManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MealPlanManager.swift; sourceTree = "<group>"; };
F1A0DE052E0C000300000003 /* MealPlanSyncManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MealPlanSyncManager.swift; sourceTree = "<group>"; }; F1A0DE052E0C000300000003 /* MealPlanSyncManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MealPlanSyncManager.swift; sourceTree = "<group>"; };
@@ -183,6 +205,20 @@
G1A0CE022F0B000200000002 /* CategoryReorderSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryReorderSheet.swift; sourceTree = "<group>"; }; G1A0CE022F0B000200000002 /* CategoryReorderSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryReorderSheet.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
E498A7A82F41C35500D7D7A4 /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
Info.plist,
);
target = E498A7992F41C35500D7D7A4 /* ShareExtension */;
};
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
/* Begin PBXFileSystemSynchronizedRootGroup section */
E498A79B2F41C35500D7D7A4 /* ShareExtension */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (E498A7A82F41C35500D7D7A4 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = ShareExtension; sourceTree = "<group>"; };
/* End PBXFileSystemSynchronizedRootGroup section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
A701717B2AA8E71900064C43 /* Frameworks */ = { A701717B2AA8E71900064C43 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
@@ -206,6 +242,13 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
E498A7972F41C35500D7D7A4 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */ /* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */ /* Begin PBXGroup section */
@@ -217,6 +260,7 @@
A70171802AA8E71900064C43 /* Nextcloud Cookbook iOS Client */, A70171802AA8E71900064C43 /* Nextcloud Cookbook iOS Client */,
A70171922AA8E72000064C43 /* Nextcloud Cookbook iOS ClientTests */, A70171922AA8E72000064C43 /* Nextcloud Cookbook iOS ClientTests */,
A701719C2AA8E72000064C43 /* Nextcloud Cookbook iOS ClientUITests */, A701719C2AA8E72000064C43 /* Nextcloud Cookbook iOS ClientUITests */,
E498A79B2F41C35500D7D7A4 /* ShareExtension */,
A701717F2AA8E71900064C43 /* Products */, A701717F2AA8E71900064C43 /* Products */,
); );
sourceTree = "<group>"; sourceTree = "<group>";
@@ -227,6 +271,7 @@
A701717E2AA8E71900064C43 /* Nextcloud Cookbook iOS Client.app */, A701717E2AA8E71900064C43 /* Nextcloud Cookbook iOS Client.app */,
A701718F2AA8E72000064C43 /* Nextcloud Cookbook iOS ClientTests.xctest */, A701718F2AA8E72000064C43 /* Nextcloud Cookbook iOS ClientTests.xctest */,
A70171992AA8E72000064C43 /* Nextcloud Cookbook iOS ClientUITests.xctest */, A70171992AA8E72000064C43 /* Nextcloud Cookbook iOS ClientUITests.xctest */,
E498A79A2F41C35500D7D7A4 /* ShareExtension.appex */,
); );
name = Products; name = Products;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -480,10 +525,12 @@
A701717A2AA8E71900064C43 /* Sources */, A701717A2AA8E71900064C43 /* Sources */,
A701717B2AA8E71900064C43 /* Frameworks */, A701717B2AA8E71900064C43 /* Frameworks */,
A701717C2AA8E71900064C43 /* Resources */, A701717C2AA8E71900064C43 /* Resources */,
E498A7A52F41C35500D7D7A4 /* Embed Foundation Extensions */,
); );
buildRules = ( buildRules = (
); );
dependencies = ( dependencies = (
E498A7A32F41C35500D7D7A4 /* PBXTargetDependency */,
); );
name = "Nextcloud Cookbook iOS Client"; name = "Nextcloud Cookbook iOS Client";
packageProductDependencies = ( packageProductDependencies = (
@@ -529,6 +576,28 @@
productReference = A70171992AA8E72000064C43 /* Nextcloud Cookbook iOS ClientUITests.xctest */; productReference = A70171992AA8E72000064C43 /* Nextcloud Cookbook iOS ClientUITests.xctest */;
productType = "com.apple.product-type.bundle.ui-testing"; productType = "com.apple.product-type.bundle.ui-testing";
}; };
E498A7992F41C35500D7D7A4 /* ShareExtension */ = {
isa = PBXNativeTarget;
buildConfigurationList = E498A7A92F41C35500D7D7A4 /* Build configuration list for PBXNativeTarget "ShareExtension" */;
buildPhases = (
E498A7962F41C35500D7D7A4 /* Sources */,
E498A7972F41C35500D7D7A4 /* Frameworks */,
E498A7982F41C35500D7D7A4 /* Resources */,
);
buildRules = (
);
dependencies = (
);
fileSystemSynchronizedGroups = (
E498A79B2F41C35500D7D7A4 /* ShareExtension */,
);
name = ShareExtension;
packageProductDependencies = (
);
productName = ShareExtension;
productReference = E498A79A2F41C35500D7D7A4 /* ShareExtension.appex */;
productType = "com.apple.product-type.app-extension";
};
/* End PBXNativeTarget section */ /* End PBXNativeTarget section */
/* Begin PBXProject section */ /* Begin PBXProject section */
@@ -536,7 +605,7 @@
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
BuildIndependentTargetsInParallel = 1; BuildIndependentTargetsInParallel = 1;
LastSwiftUpdateCheck = 1430; LastSwiftUpdateCheck = 2620;
LastUpgradeCheck = 1500; LastUpgradeCheck = 1500;
TargetAttributes = { TargetAttributes = {
A701717D2AA8E71900064C43 = { A701717D2AA8E71900064C43 = {
@@ -550,6 +619,10 @@
CreatedOnToolsVersion = 14.3; CreatedOnToolsVersion = 14.3;
TestTargetID = A701717D2AA8E71900064C43; TestTargetID = A701717D2AA8E71900064C43;
}; };
E498A7992F41C35500D7D7A4 = {
CreatedOnToolsVersion = 26.2;
LastSwiftMigration = 2620;
};
}; };
}; };
buildConfigurationList = A70171792AA8E71900064C43 /* Build configuration list for PBXProject "Nextcloud Cookbook iOS Client" */; buildConfigurationList = A70171792AA8E71900064C43 /* Build configuration list for PBXProject "Nextcloud Cookbook iOS Client" */;
@@ -574,6 +647,7 @@
A701717D2AA8E71900064C43 /* Nextcloud Cookbook iOS Client */, A701717D2AA8E71900064C43 /* Nextcloud Cookbook iOS Client */,
A701718E2AA8E72000064C43 /* Nextcloud Cookbook iOS ClientTests */, A701718E2AA8E72000064C43 /* Nextcloud Cookbook iOS ClientTests */,
A70171982AA8E72000064C43 /* Nextcloud Cookbook iOS ClientUITests */, A70171982AA8E72000064C43 /* Nextcloud Cookbook iOS ClientUITests */,
E498A7992F41C35500D7D7A4 /* ShareExtension */,
); );
}; };
/* End PBXProject section */ /* End PBXProject section */
@@ -604,6 +678,13 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
E498A7982F41C35500D7D7A4 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */ /* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */
@@ -698,6 +779,13 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
E498A7962F41C35500D7D7A4 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */ /* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */ /* Begin PBXTargetDependency section */
@@ -711,6 +799,11 @@
target = A701717D2AA8E71900064C43 /* Nextcloud Cookbook iOS Client */; target = A701717D2AA8E71900064C43 /* Nextcloud Cookbook iOS Client */;
targetProxy = A701719A2AA8E72000064C43 /* PBXContainerItemProxy */; targetProxy = A701719A2AA8E72000064C43 /* PBXContainerItemProxy */;
}; };
E498A7A32F41C35500D7D7A4 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = E498A7992F41C35500D7D7A4 /* ShareExtension */;
targetProxy = E498A7A22F41C35500D7D7A4 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */ /* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */ /* Begin XCBuildConfiguration section */
@@ -920,7 +1013,6 @@
A70171A72AA8E72000064C43 /* Debug */ = { A70171A72AA8E72000064C43 /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
BUNDLE_LOADER = "$(TEST_HOST)"; BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
@@ -944,7 +1036,6 @@
A70171A82AA8E72000064C43 /* Release */ = { A70171A82AA8E72000064C43 /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
BUNDLE_LOADER = "$(TEST_HOST)"; BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
@@ -968,7 +1059,6 @@
A70171AA2AA8E72000064C43 /* Debug */ = { A70171AA2AA8E72000064C43 /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEAD_CODE_STRIPPING = YES; DEAD_CODE_STRIPPING = YES;
@@ -991,7 +1081,6 @@
A70171AB2AA8E72000064C43 /* Release */ = { A70171AB2AA8E72000064C43 /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEAD_CODE_STRIPPING = YES; DEAD_CODE_STRIPPING = YES;
@@ -1011,6 +1100,79 @@
}; };
name = Release; name = Release;
}; };
E498A7A62F41C35500D7D7A4 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = EF2ABA36D9;
GCC_C_LANGUAGE_STANDARD = gnu17;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = ShareExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = ShareExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 26.2;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = "VincentMeilinger.Nextcloud-Cookbook-iOS-Client.ShareExtension";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
STRING_CATALOG_GENERATE_SYMBOLS = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
SWIFT_APPROACHABLE_CONCURRENCY = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OBJC_BRIDGING_HEADER = "";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
E498A7A72F41C35500D7D7A4 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = EF2ABA36D9;
GCC_C_LANGUAGE_STANDARD = gnu17;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = ShareExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = ShareExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 26.2;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = "VincentMeilinger.Nextcloud-Cookbook-iOS-Client.ShareExtension";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
STRING_CATALOG_GENERATE_SYMBOLS = YES;
SWIFT_APPROACHABLE_CONCURRENCY = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OBJC_BRIDGING_HEADER = "";
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
/* End XCBuildConfiguration section */ /* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */ /* Begin XCConfigurationList section */
@@ -1050,6 +1212,15 @@
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release; defaultConfigurationName = Release;
}; };
E498A7A92F41C35500D7D7A4 /* Build configuration list for PBXNativeTarget "ShareExtension" */ = {
isa = XCConfigurationList;
buildConfigurations = (
E498A7A62F41C35500D7D7A4 /* Debug */,
E498A7A72F41C35500D7D7A4 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */ /* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */ /* Begin XCRemoteSwiftPackageReference section */

View File

@@ -0,0 +1,102 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "2620"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "A701717D2AA8E71900064C43"
BuildableName = "Nextcloud Cookbook iOS Client.app"
BlueprintName = "Nextcloud Cookbook iOS Client"
ReferencedContainer = "container:Nextcloud Cookbook iOS Client.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
<Testables>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "A701718E2AA8E72000064C43"
BuildableName = "Nextcloud Cookbook iOS ClientTests.xctest"
BlueprintName = "Nextcloud Cookbook iOS ClientTests"
ReferencedContainer = "container:Nextcloud Cookbook iOS Client.xcodeproj">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "A70171982AA8E72000064C43"
BuildableName = "Nextcloud Cookbook iOS ClientUITests.xctest"
BlueprintName = "Nextcloud Cookbook iOS ClientUITests"
ReferencedContainer = "container:Nextcloud Cookbook iOS Client.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "A701717D2AA8E71900064C43"
BuildableName = "Nextcloud Cookbook iOS Client.app"
BlueprintName = "Nextcloud Cookbook iOS Client"
ReferencedContainer = "container:Nextcloud Cookbook iOS Client.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "A701717D2AA8E71900064C43"
BuildableName = "Nextcloud Cookbook iOS Client.app"
BlueprintName = "Nextcloud Cookbook iOS Client"
ReferencedContainer = "container:Nextcloud Cookbook iOS Client.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -0,0 +1,97 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "2620"
wasCreatedForAppExtension = "YES"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "E498A7992F41C35500D7D7A4"
BuildableName = "ShareExtension.appex"
BlueprintName = "ShareExtension"
ReferencedContainer = "container:Nextcloud Cookbook iOS Client.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "A701717D2AA8E71900064C43"
BuildableName = "Nextcloud Cookbook iOS Client.app"
BlueprintName = "Nextcloud Cookbook iOS Client"
ReferencedContainer = "container:Nextcloud Cookbook iOS Client.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = ""
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
launchStyle = "0"
askForAppToLaunch = "Yes"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES"
launchAutomaticallySubstyle = "2">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "A701717D2AA8E71900064C43"
BuildableName = "Nextcloud Cookbook iOS Client.app"
BlueprintName = "Nextcloud Cookbook iOS Client"
ReferencedContainer = "container:Nextcloud Cookbook iOS Client.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES"
askForAppToLaunch = "Yes"
launchAutomaticallySubstyle = "2">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "A701717D2AA8E71900064C43"
BuildableName = "Nextcloud Cookbook iOS Client.app"
BlueprintName = "Nextcloud Cookbook iOS Client"
ReferencedContainer = "container:Nextcloud Cookbook iOS Client.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -15,6 +15,8 @@ struct Nextcloud_Cookbook_iOS_ClientApp: App {
@AppStorage("language") var language = Locale.current.language.languageCode?.identifier ?? "en" @AppStorage("language") var language = Locale.current.language.languageCode?.identifier ?? "en"
@AppStorage("appearanceMode") var appearanceMode = AppearanceMode.system.rawValue @AppStorage("appearanceMode") var appearanceMode = AppearanceMode.system.rawValue
@State private var pendingImportURL: String?
var colorScheme: ColorScheme? { var colorScheme: ColorScheme? {
switch appearanceMode { switch appearanceMode {
case AppearanceMode.light.rawValue: return .light case AppearanceMode.light.rawValue: return .light
@@ -29,7 +31,7 @@ struct Nextcloud_Cookbook_iOS_ClientApp: App {
if onboarding { if onboarding {
OnboardingView() OnboardingView()
} else { } else {
MainView() MainView(pendingImportURL: $pendingImportURL)
} }
} }
.preferredColorScheme(colorScheme) .preferredColorScheme(colorScheme)
@@ -39,6 +41,16 @@ struct Nextcloud_Cookbook_iOS_ClientApp: App {
.init(identifier: language == .init(identifier: language ==
SupportedLanguage.DEVICE.rawValue ? (Locale.current.language.languageCode?.identifier ?? "en") : language) SupportedLanguage.DEVICE.rawValue ? (Locale.current.language.languageCode?.identifier ?? "en") : language)
) )
.onOpenURL { url in
guard !onboarding else { return }
guard url.scheme == "nextcloud-cookbook",
url.host == "import",
let components = URLComponents(url: url, resolvingAgainstBaseURL: false),
let recipeURL = components.queryItems?.first(where: { $0.name == "url" })?.value,
!recipeURL.isEmpty
else { return }
pendingImportURL = recipeURL
}
} }
} }
} }

View File

@@ -20,6 +20,8 @@ struct MainView: View {
@State private var selectedTab: Tab = .recipes @State private var selectedTab: Tab = .recipes
@Binding var pendingImportURL: String?
enum Tab { enum Tab {
case recipes, search, mealPlan, groceryList case recipes, search, mealPlan, groceryList
} }
@@ -106,5 +108,19 @@ struct MainView: View {
} }
recipeViewModel.presentLoadingIndicator = false recipeViewModel.presentLoadingIndicator = false
} }
.onChange(of: pendingImportURL) { _, newURL in
guard let url = newURL, !url.isEmpty else { return }
selectedTab = .recipes
recipeViewModel.pendingImportURL = url
// Dismiss any currently open import sheet before re-presenting
if recipeViewModel.showImportURLSheet {
recipeViewModel.showImportURLSheet = false
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
recipeViewModel.showImportURLSheet = true
}
} else {
recipeViewModel.showImportURLSheet = true
}
}
} }
} }

View File

@@ -10,6 +10,7 @@ struct ImportURLSheet: View {
@Environment(\.dismiss) private var dismiss @Environment(\.dismiss) private var dismiss
var onImport: (RecipeDetail) -> Void var onImport: (RecipeDetail) -> Void
var initialURL: String = ""
@State private var url: String = "" @State private var url: String = ""
@State private var isLoading: Bool = false @State private var isLoading: Bool = false
@@ -62,6 +63,11 @@ struct ImportURLSheet: View {
} message: { } message: {
Text(alertMessage) Text(alertMessage)
} }
.onAppear {
if !initialURL.isEmpty {
url = initialURL
}
}
} }
} }

View File

@@ -255,10 +255,15 @@ struct RecipeTabView: View {
} }
} }
} }
.sheet(isPresented: $viewModel.showImportURLSheet) { .sheet(isPresented: $viewModel.showImportURLSheet, onDismiss: {
ImportURLSheet { recipeDetail in viewModel.pendingImportURL = nil
viewModel.navigateToImportedRecipe(recipeDetail: recipeDetail) }) {
} ImportURLSheet(
onImport: { recipeDetail in
viewModel.navigateToImportedRecipe(recipeDetail: recipeDetail)
},
initialURL: viewModel.pendingImportURL ?? ""
)
.environmentObject(appState) .environmentObject(appState)
} }
.sheet(isPresented: $showManualReorderSheet) { .sheet(isPresented: $showManualReorderSheet) {
@@ -303,6 +308,7 @@ struct RecipeTabView: View {
@Published var showImportURLSheet: Bool = false @Published var showImportURLSheet: Bool = false
@Published var importedRecipeDetail: RecipeDetail? = nil @Published var importedRecipeDetail: RecipeDetail? = nil
@Published var pendingImportURL: String? = nil
func navigateToSettings() { func navigateToSettings() {
sidebarPath.append(SidebarDestination.settings) sidebarPath.append(SidebarDestination.settings)

View File

@@ -2,6 +2,17 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>com.vincentmeilinger.nextcloud-cookbook</string>
<key>CFBundleURLSchemes</key>
<array>
<string>nextcloud-cookbook</string>
</array>
</dict>
</array>
<key>NSRemindersFullAccessUsageDescription</key> <key>NSRemindersFullAccessUsageDescription</key>
<string>This app uses Reminders to save your grocery list items.</string> <string>This app uses Reminders to save your grocery list items.</string>
</dict> </dict>

21
ShareExtension/Info.plist Normal file
View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>NSExtensionActivationRule</key>
<dict>
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
<integer>1</integer>
</dict>
</dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.share-services</string>
<key>NSExtensionPrincipalClass</key>
<string>$(PRODUCT_MODULE_NAME).ShareViewController</string>
</dict>
</dict>
</plist>

View File

@@ -0,0 +1,79 @@
//
// ShareViewController.swift
// ShareExtension
//
// Created by Hendrik Hogertz on 15.02.26.
//
import UIKit
import UniformTypeIdentifiers
class ShareViewController: UIViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
handleSharedItems()
}
private func handleSharedItems() {
guard let extensionItems = extensionContext?.inputItems as? [NSExtensionItem] else {
completeRequest()
return
}
for item in extensionItems {
guard let attachments = item.attachments else { continue }
for provider in attachments {
if provider.hasItemConformingToTypeIdentifier(UTType.url.identifier) {
provider.loadItem(forTypeIdentifier: UTType.url.identifier) { [weak self] item, _ in
if let url = item as? URL {
self?.openMainApp(with: url.absoluteString)
} else {
self?.completeRequest()
}
}
return
} else if provider.hasItemConformingToTypeIdentifier(UTType.plainText.identifier) {
provider.loadItem(forTypeIdentifier: UTType.plainText.identifier) { [weak self] item, _ in
if let text = item as? String, let url = URL(string: text), url.scheme?.hasPrefix("http") == true {
self?.openMainApp(with: url.absoluteString)
} else {
self?.completeRequest()
}
}
return
}
}
}
completeRequest()
}
private func openMainApp(with urlString: String) {
guard let encoded = urlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
let appURL = URL(string: "nextcloud-cookbook://import?url=\(encoded)")
else {
completeRequest()
return
}
// Use the responder chain to open the URL
var responder: UIResponder? = self
while let r = responder {
if let application = r as? UIApplication {
application.open(appURL, options: [:], completionHandler: nil)
break
}
responder = r.next
}
// Give the system a moment to process the URL before dismissing
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { [weak self] in
self?.completeRequest()
}
}
private func completeRequest() {
extensionContext?.completeRequest(returningItems: nil)
}
}