diff --git a/Nextcloud Cookbook iOS Client.xcodeproj/project.pbxproj b/Nextcloud Cookbook iOS Client.xcodeproj/project.pbxproj index 0d85e80..4f76e6e 100644 --- a/Nextcloud Cookbook iOS Client.xcodeproj/project.pbxproj +++ b/Nextcloud Cookbook iOS Client.xcodeproj/project.pbxproj @@ -65,6 +65,7 @@ A9CA6CEF2B4C086100F78AB5 /* RecipeExporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9CA6CEE2B4C086100F78AB5 /* RecipeExporter.swift */; }; A9CA6CF62B4C63F200F78AB5 /* TPPDF in Frameworks */ = {isa = PBXBuildFile; productRef = A9CA6CF52B4C63F200F78AB5 /* TPPDF */; }; A9D89AB02B4FE97800F49D92 /* TimerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D89AAF2B4FE97800F49D92 /* TimerView.swift */; }; + A9D8F9052B99F3E5009BACAE /* RecipeImportSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D8F9042B99F3E4009BACAE /* RecipeImportSection.swift */; }; A9FA2AB62B5079B200A43702 /* alarm_sound_0.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = A9FA2AB52B5079B200A43702 /* alarm_sound_0.mp3 */; }; /* End PBXBuildFile section */ @@ -145,6 +146,7 @@ A9BBB38F2B91BE31002DA7FF /* ObservableRecipeDetail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObservableRecipeDetail.swift; sourceTree = ""; }; A9CA6CEE2B4C086100F78AB5 /* RecipeExporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeExporter.swift; sourceTree = ""; }; A9D89AAF2B4FE97800F49D92 /* TimerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimerView.swift; sourceTree = ""; }; + A9D8F9042B99F3E4009BACAE /* RecipeImportSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeImportSection.swift; sourceTree = ""; }; A9DA25D42B82096B0061FC2B /* Nextcloud-Cookbook-iOS-Client-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "Nextcloud-Cookbook-iOS-Client-Info.plist"; sourceTree = SOURCE_ROOT; }; A9FA2AB52B5079B200A43702 /* alarm_sound_0.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = alarm_sound_0.mp3; sourceTree = ""; }; /* End PBXFileReference section */ @@ -356,6 +358,7 @@ A7F3F8E72ACBFC760076C227 /* RecipeKeywordSection.swift */, A97506142B920DF200E86029 /* RecipeGenericViews.swift */, A97506202B92104700E86029 /* RecipeMetadataSection.swift */, + A9D8F9042B99F3E4009BACAE /* RecipeImportSection.swift */, ); path = RecipeViewSections; sourceTree = ""; @@ -573,6 +576,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + A9D8F9052B99F3E5009BACAE /* RecipeImportSection.swift in Sources */, A9BBB38E2B8E44B3002DA7FF /* BottomClipper.swift in Sources */, A97506192B920EC200E86029 /* RecipeIngredientSection.swift in Sources */, A97B4D352B80B82A00EC1A88 /* ShareView.swift in Sources */, diff --git a/Nextcloud Cookbook iOS Client.xcodeproj/project.xcworkspace/xcuserdata/vincie.xcuserdatad/UserInterfaceState.xcuserstate b/Nextcloud Cookbook iOS Client.xcodeproj/project.xcworkspace/xcuserdata/vincie.xcuserdatad/UserInterfaceState.xcuserstate index 05fabb5..8e75c4d 100644 Binary files a/Nextcloud Cookbook iOS Client.xcodeproj/project.xcworkspace/xcuserdata/vincie.xcuserdatad/UserInterfaceState.xcuserstate and b/Nextcloud Cookbook iOS Client.xcodeproj/project.xcworkspace/xcuserdata/vincie.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/Nextcloud Cookbook iOS Client/Assets.xcassets/ncgradientdarkblue.colorset/Contents.json b/Nextcloud Cookbook iOS Client/Assets.xcassets/ncgradientdarkblue.colorset/Contents.json new file mode 100644 index 0000000..f31fd0e --- /dev/null +++ b/Nextcloud Cookbook iOS Client/Assets.xcassets/ncgradientdarkblue.colorset/Contents.json @@ -0,0 +1,56 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x29", + "green" : "0x1B", + "red" : "0x00" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "light" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xFF", + "green" : "0xE2", + "red" : "0xAD" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x29", + "green" : "0x1B", + "red" : "0x00" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Nextcloud Cookbook iOS Client/Assets.xcassets/ncgradientlightblue.colorset/Contents.json b/Nextcloud Cookbook iOS Client/Assets.xcassets/ncgradientlightblue.colorset/Contents.json new file mode 100644 index 0000000..416f3ca --- /dev/null +++ b/Nextcloud Cookbook iOS Client/Assets.xcassets/ncgradientlightblue.colorset/Contents.json @@ -0,0 +1,56 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x52", + "green" : "0x35", + "red" : "0x00" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "light" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xFF", + "green" : "0xF8", + "red" : "0xEB" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x52", + "green" : "0x35", + "red" : "0x00" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Nextcloud Cookbook iOS Client/Data/ObservableRecipeDetail.swift b/Nextcloud Cookbook iOS Client/Data/ObservableRecipeDetail.swift index 18cc166..999d904 100644 --- a/Nextcloud Cookbook iOS Client/Data/ObservableRecipeDetail.swift +++ b/Nextcloud Cookbook iOS Client/Data/ObservableRecipeDetail.swift @@ -82,6 +82,13 @@ class ObservableRecipeDetail: ObservableObject { nutrition: self.nutrition ) } + + func ingredients(for servings: Int) -> [String] { + for ingredient in recipeIngredient { + // TODO: Parse ingredient strings, adjust them for yield + } + return [] + } } diff --git a/Nextcloud Cookbook iOS Client/Extensions/ColorExtension.swift b/Nextcloud Cookbook iOS Client/Extensions/ColorExtension.swift index 66136e6..439e045 100644 --- a/Nextcloud Cookbook iOS Client/Extensions/ColorExtension.swift +++ b/Nextcloud Cookbook iOS Client/Extensions/ColorExtension.swift @@ -21,4 +21,10 @@ extension Color { public static var background: Color { return Color(UIColor.systemBackground) } + public static var ncGradientDark: Color { + return Color("ncgradientdarkblue") + } + public static var ncGradientLight: Color { + return Color("ncgradientlightblue") + } } diff --git a/Nextcloud Cookbook iOS Client/Localizable.xcstrings b/Nextcloud Cookbook iOS Client/Localizable.xcstrings index db55e15..9c834ce 100644 --- a/Nextcloud Cookbook iOS Client/Localizable.xcstrings +++ b/Nextcloud Cookbook iOS Client/Localizable.xcstrings @@ -114,11 +114,29 @@ }, "%@: %@" : { "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@: %2$@" + } + }, "en" : { "stringUnit" : { "state" : "new", "value" : "%1$@: %2$@" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@: %2$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@: %2$@" + } } } }, @@ -168,11 +186,29 @@ }, "%lld h %lld min" : { "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$lld h %2$lld min" + } + }, "en" : { "stringUnit" : { "state" : "new", "value" : "%1$lld h %2$lld min" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$lld h %2$lld min" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$lld h %2$lld min" + } } } }, @@ -226,8 +262,27 @@ } } }, - "%lld serving(s)" : { - + "%lld Serving(s)" : { + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld Portion(en)" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld Porción(es)" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld Portion(s)" + } + } + } }, "%lld." : { "extractionState" : "stale", @@ -431,14 +486,33 @@ } }, "Add cooking steps for fellow chefs to follow." : { - + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hier ist Platz für eine Rezeptanleitung." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Todavía no hay pasos de cocina." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Il n'y a pas encore d'étapes de cuisson." + } + } + } }, "Add groceries to this list by either using the button next to an ingredient list in a recipe, or by swiping right on individual ingredients of a recipe." : { "localizations" : { "de" : { "stringUnit" : { "state" : "translated", - "value" : "Wenn du alle Zutaten eines Rezepts auf einmal hinzufügen möchtest, klicke einfach auf den „Einkaufsliste“-Button, den du neben der Zutatenliste des Rezepts findest. Möchtest du nur einzelne Zutaten hinzufügen, wische die gewünschte Zutat in der Liste des Rezepts einfach nach rechts." + "value" : "Für das Hinzufügen aller Zutaten eines Rezepts kann der „Einkaufsliste“-Button neben der Zutatenliste eines Rezepts benutzt werden. Sollen nur einzelne Zutaten hinzugefügt werden, kann die gewünschte Zutat in der Liste des Rezepts nach rechts gewischt werden." } }, "es" : { @@ -589,7 +663,27 @@ } }, "Calories" : { - "comment" : "Calories" + "comment" : "Calories", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kalorien" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Calorías" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Calories" + } + } + } }, "Cancel" : { "localizations" : { @@ -614,7 +708,27 @@ } }, "Carbohydrate content" : { - "comment" : "Carbohydrate content" + "comment" : "Carbohydrate content", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kohlenhydratgehalt" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Carbohidratos" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Glucides" + } + } + } }, "Category" : { "localizations" : { @@ -662,10 +776,49 @@ } }, "Cholesterol content" : { - "comment" : "Cholesterol content" + "comment" : "Cholesterol content", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cholesteringehalt" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Colesterol" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cholestérol" + } + } + } }, "Choose" : { - + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Auswählen" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Elija" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Choisissez" + } + } + } }, "Configure what is stored on your device." : { "localizations" : { @@ -821,29 +974,6 @@ } } }, - "Cooking duration:" : { - "extractionState" : "stale", - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "Kochen:" - } - }, - "es" : { - "stringUnit" : { - "state" : "translated", - "value" : "Duración de cocción:" - } - }, - "fr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Temps de cuisson:" - } - } - } - }, "Cooking time" : { "localizations" : { "de" : { @@ -982,7 +1112,7 @@ "de" : { "stringUnit" : { "state" : "translated", - "value" : "Rezept Löschen" + "value" : "Rezept löschen" } }, "es" : { @@ -1000,7 +1130,26 @@ } }, "Delete Recipe" : { - + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rezept löschen" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Eliminar receta" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Supprimer la recette" + } + } + } }, "Delete recipe?" : { "localizations" : { @@ -1075,6 +1224,18 @@ "state" : "translated", "value" : "Fertig" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hecho" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Terminer" + } } } }, @@ -1300,10 +1461,50 @@ } }, "Fat content" : { - "comment" : "Fat content" + "comment" : "Fat content", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fett" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Grasas" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lipides" + } + } + } }, "Fiber content" : { - "comment" : "Fiber content" + "comment" : "Fiber content", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ballaststoffgehalt" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fibra dietética" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fibres alimentaires" + } + } + } }, "General" : { "localizations" : { @@ -1372,7 +1573,26 @@ } }, "Hours" : { - + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Stunden" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Horas" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Heures" + } + } + } }, "If 'Same as Device' is selected and your device language is not supported yet, this option will default to english." : { "localizations" : { @@ -1423,7 +1643,7 @@ "de" : { "stringUnit" : { "state" : "translated", - "value" : "Möchtest du einen Beitrag zu diesem Projekt leisten oder einfach nur einen Blick in den Quellcode werfen? Wir freuen uns über jedes Interesse und laden dich ein, das GitHub-Repository unserer Anwendung zu besuchen." + "value" : "Wir freuen uns über jedes Interesse und laden Nutzer ein, das GitHub-Repository dieser Anwendung zu besuchen, um einen Beitrag zu diesem Projekt zu leisten oder einfach nur einen Blick in den Quellcode zu werfen. " } }, "es" : { @@ -1462,29 +1682,6 @@ } } }, - "Image MIME Error" : { - "extractionState" : "stale", - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "MIME fehler" - } - }, - "es" : { - "stringUnit" : { - "state" : "translated", - "value" : "" - } - }, - "fr" : { - "stringUnit" : { - "state" : "translated", - "value" : "" - } - } - } - }, "Import" : { "localizations" : { "de" : { @@ -1529,37 +1726,27 @@ } } }, - "Import recipe from a website" : { - "extractionState" : "stale", + "Ingredient" : { "localizations" : { "de" : { "stringUnit" : { "state" : "translated", - "value" : "Rezept von einer Website importieren (Experimentell)" - } - }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Import recipe from a website (Experimental)" + "value" : "Zutat" } }, "es" : { "stringUnit" : { "state" : "translated", - "value" : "Importar receta desde un sitio web (Experimental)" + "value" : "Ingrediente" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "Importer une recette depuis un site web (Expérimental)" + "value" : "Ingrédient" } } } - }, - "Ingredient" : { - }, "Ingredients" : { "localizations" : { @@ -1628,7 +1815,26 @@ } }, "Instruction" : { - + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Anleitung" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Instrucción" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Instruction" + } + } + } }, "Instructions" : { "localizations" : { @@ -1763,7 +1969,26 @@ } }, "List your tools here. 🍴" : { - + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Küchenutensilien können hier notiert werden. 🍴" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enumera tus utensilios de cocina aquí. 🍴" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Listez vos ustensiles de cuisine ici. 🍴" + } + } + } }, "Log out" : { "localizations" : { @@ -1876,7 +2101,26 @@ } }, "Minutes" : { - + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Minuten" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Minutos" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Minutes" + } + } + } }, "Missing Name" : { "extractionState" : "stale", @@ -2014,7 +2258,26 @@ } }, "New Recipe" : { - + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Neues Rezept" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nueva receta" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nouvelle recette" + } + } + } }, "Nextcloud Login" : { "localizations" : { @@ -2307,7 +2570,7 @@ "de" : { "stringUnit" : { "state" : "translated", - "value" : "Bitte überprüfe die Anmeldedaten oder die Internetverbindung." + "value" : "Bitte die Anmeldedaten und die Internetverbindung überprüfen." } }, "es" : { @@ -2392,7 +2655,27 @@ } }, "Protein content" : { - "comment" : "Protein content" + "comment" : "Protein content", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Proteingehalt" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Proteínas" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Protéines" + } + } + } }, "Recipe" : { "localizations" : { @@ -2417,7 +2700,26 @@ } }, "Recipe Name" : { - + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rezept-Titel" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Título de la receta" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Titre de la recette" + } + } + } }, "Recipes" : { "localizations" : { @@ -2486,7 +2788,27 @@ } }, "Saturated fat content" : { - "comment" : "Saturated fat content" + "comment" : "Saturated fat content", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Gesättigte Fettsäuren" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Grasas saturadas" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Graisses saturées" + } + } + } }, "Search" : { "localizations" : { @@ -2577,7 +2899,26 @@ } }, "Select Keywords" : { - + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Schlagwörter auswählen" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Seleccione palabras clave" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sélectionnez les mots-clés" + } + } + } }, "Selected keywords:" : { "localizations" : { @@ -2602,10 +2943,49 @@ } }, "Serving size" : { - "comment" : "Serving size" + "comment" : "Serving size", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Portionen" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Porciones" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Portions" + } + } + } }, "Servings" : { - + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Portionen" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Porciones" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Portions" + } + } + } }, "Servings:" : { "extractionState" : "stale", @@ -2720,7 +3100,26 @@ } }, "Share Recipe" : { - + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Teilen" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Compartir receta" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Partager la recette" + } + } + } }, "Show help" : { "localizations" : { @@ -2745,10 +3144,49 @@ } }, "Sodium content" : { - "comment" : "Sodium content" + "comment" : "Sodium content", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Natriumgehalt" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sodio" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sodium" + } + } + } }, "Start by adding your first ingredient! 🥬" : { - + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hier fehlen Zutaten! 🥬" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "¡Empieza por añadir tu primer ingrediente! 🥬" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Commencez par ajouter votre premier ingrédient ! 🥬" + } + } + } }, "Store recipe images locally" : { "localizations" : { @@ -2817,7 +3255,27 @@ } }, "Sugar content" : { - "comment" : "Sugar content" + "comment" : "Sugar content", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zuckergehalt" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Azúcares" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sucres" + } + } + } }, "Support" : { "localizations" : { @@ -3002,7 +3460,7 @@ "de" : { "stringUnit" : { "state" : "translated", - "value" : "Diese Anwendung ist ein Open-Source-Projekt. Bei bestehendem Interesse neue Funktionen vorzuschlagen oder beizutragen, oder wenn Probleme auftreten, nutze den Kontakt-Link oder besuche das GitHub-Repository in den App-Einstellungen." + "value" : "Diese Anwendung ist ein Open-Source-Projekt. Bei bestehendem Interesse neue Funktionen vorzuschlagen oder beizutragen, oder wenn Probleme auftreten, den Kontakt-Link nutzen oder das GitHub-Repository in den App-Einstellungen besuchen." } }, "es" : { @@ -3065,7 +3523,26 @@ } }, "Tool" : { - + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Küchenutensilie" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Utensilio de cocina" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ustensile de cuisine" + } + } + } }, "Tools" : { "localizations" : { @@ -3157,7 +3634,27 @@ } }, "Trans fat content" : { - "comment" : "Trans fat content" + "comment" : "Trans fat content", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Transfettgehalt" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Grasas trans" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Graisses trans" + } + } + } }, "Unable to complete action." : { "localizations" : { @@ -3208,7 +3705,7 @@ "de" : { "stringUnit" : { "state" : "translated", - "value" : "Der Inhalt der Website konnte nicht geladen werden. Bitte überprüfe die Internetverbindung." + "value" : "Der Inhalt der Website konnte nicht geladen werden. Bitte die Internetverbindung überprüfen." } }, "es" : { @@ -3230,7 +3727,7 @@ "de" : { "stringUnit" : { "state" : "translated", - "value" : "Es ist nicht möglich, das Rezept hochzuladen. Bitte überprüfe die Internetverbindung." + "value" : "Es ist nicht möglich, das Rezept hochzuladen. Bitte die Internetverbindung überprüfen." } }, "es" : { @@ -3248,7 +3745,27 @@ } }, "Unsaturated fat content" : { - "comment" : "Unsaturated fat content" + "comment" : "Unsaturated fat content", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ungesättigte Fettsäuren" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Grasas insaturadas" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Graisses insaturées" + } + } + } }, "Upload" : { "extractionState" : "stale", @@ -3274,10 +3791,48 @@ } }, "Upload Changes" : { - + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Speichern" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cargar" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Télécharger" + } + } + } }, "Upload Recipe" : { - + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Speichern" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cargar" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Télécharger" + } + } + } }, "URL (e.g. example.com/recipe)" : { "localizations" : { @@ -3330,6 +3885,18 @@ "state" : "translated", "value" : "Nutzername: %@" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nombre de usuario: %@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nom d'utilisateur: %@" + } } } }, diff --git a/Nextcloud Cookbook iOS Client/Network/CookbookApi/CookbookApiV1.swift b/Nextcloud Cookbook iOS Client/Network/CookbookApi/CookbookApiV1.swift index cbe6b59..facab74 100644 --- a/Nextcloud Cookbook iOS Client/Network/CookbookApi/CookbookApiV1.swift +++ b/Nextcloud Cookbook iOS Client/Network/CookbookApi/CookbookApiV1.swift @@ -49,6 +49,7 @@ class CookbookApiV1: CookbookApi { let (data, error) = await request.send() guard let data = data else { return (nil, error) } + print("\n\nRECIPE: ", String(data: data, encoding: .utf8)) return (JSONDecoder.safeDecode(data), nil) } diff --git a/Nextcloud Cookbook iOS Client/Views/Recipes/RecipeListView.swift b/Nextcloud Cookbook iOS Client/Views/Recipes/RecipeListView.swift index b9ebd5c..56480fd 100644 --- a/Nextcloud Cookbook iOS Client/Views/Recipes/RecipeListView.swift +++ b/Nextcloud Cookbook iOS Client/Views/Recipes/RecipeListView.swift @@ -12,6 +12,7 @@ import SwiftUI struct RecipeListView: View { @EnvironmentObject var appState: AppState + @EnvironmentObject var groceryList: GroceryList @State var categoryName: String @State var searchText: String = "" @Binding var showEditView: Bool @@ -37,6 +38,8 @@ struct RecipeListView: View { } .navigationDestination(for: Recipe.self) { recipe in RecipeView(isPresented: .constant(true), viewModel: RecipeView.ViewModel(recipe: recipe)) + .environmentObject(appState) + .environmentObject(groceryList) } .navigationTitle(categoryName == "*" ? String(localized: "Other") : categoryName) .toolbar { diff --git a/Nextcloud Cookbook iOS Client/Views/Recipes/RecipeView.swift b/Nextcloud Cookbook iOS Client/Views/Recipes/RecipeView.swift index b914a8d..a1d9190 100644 --- a/Nextcloud Cookbook iOS Client/Views/Recipes/RecipeView.swift +++ b/Nextcloud Cookbook iOS Client/Views/Recipes/RecipeView.swift @@ -13,7 +13,12 @@ struct RecipeView: View { @EnvironmentObject var appState: AppState @Binding var isPresented: Bool @StateObject var viewModel: ViewModel - @State var imageHeight: CGFloat = 350 + var imageHeight: CGFloat { + if let image = viewModel.recipeImage { + return image.size.height < 350 ? image.size.height : 350 + } + return 200 + } private enum CoordinateSpaces { case scrollView @@ -37,7 +42,7 @@ struct RecipeView: View { .frame(height: 400) .foregroundStyle( LinearGradient( - gradient: Gradient(colors: [.nextcloudBlue, .nextcloudDarkBlue]), + gradient: Gradient(colors: [.ncGradientDark, .ncGradientLight]), startPoint: .topLeading, endPoint: .bottomTrailing ) @@ -107,6 +112,7 @@ struct RecipeView: View { .coordinateSpace(name: CoordinateSpaces.scrollView) .ignoresSafeArea(.container, edges: .top) .navigationBarTitleDisplayMode(.inline) + .toolbar(.visible, for: .navigationBar) //.toolbarTitleDisplayMode(.inline) .navigationTitle(viewModel.showTitle ? viewModel.recipe.name : "") .toolbar { @@ -170,9 +176,7 @@ struct RecipeView: View { size: .FULL, fetchMode: UserSettings.shared.storeImages ? .preferLocal : .onlyServer ) - if let image = viewModel.recipeImage { - imageHeight = image.size.height < 350 ? image.size.height : 350 - } + } else { // Prepare view for a new recipe viewModel.setupView(recipeDetail: RecipeDetail()) @@ -278,6 +282,7 @@ struct RecipeView: View { } + extension RecipeView { func importRecipe(from url: String) async -> UserAlert? { let (scrapedRecipe, error) = await appState.importRecipe(url: url) @@ -300,8 +305,6 @@ extension RecipeView { } return nil } - - } @@ -446,42 +449,3 @@ struct RecipeViewToolBar: ToolbarContent { } -// MARK: - Recipe Import Section - -fileprivate struct RecipeImportSection: View { - @ObservedObject var viewModel: RecipeView.ViewModel - var importRecipe: (String) async -> UserAlert? - - var body: some View { - VStack(alignment: .leading) { - SecondaryLabel(text: "Import Recipe") - - Text(LocalizedStringKey("Paste the url of a recipe you would like to import in the above, and we will try to fill in the fields for you. This feature does not work with every website. If your favourite website is not supported, feel free to reach out for help. You can find the contact details in the app settings.")) - .font(.caption) - .foregroundStyle(.secondary) - - - TextField(LocalizedStringKey("URL (e.g. example.com/recipe)"), text: $viewModel.importUrl) - .textFieldStyle(.roundedBorder) - .padding(.top, 5) - Button { - Task { - if let res = await importRecipe(viewModel.importUrl) { - viewModel.presentAlert( - RecipeAlert.CUSTOM( - title: res.localizedTitle, - description: res.localizedDescription - ) - ) - } - } - } label: { - Text(LocalizedStringKey("Import")) - } - .buttonStyle(.bordered) - } - .padding() - .background(RoundedRectangle(cornerRadius: 20).foregroundStyle(Color.white.opacity(0.1))) - .padding() - } -} diff --git a/Nextcloud Cookbook iOS Client/Views/Recipes/RecipeViewSections/RecipeImportSection.swift b/Nextcloud Cookbook iOS Client/Views/Recipes/RecipeViewSections/RecipeImportSection.swift new file mode 100644 index 0000000..c853aed --- /dev/null +++ b/Nextcloud Cookbook iOS Client/Views/Recipes/RecipeViewSections/RecipeImportSection.swift @@ -0,0 +1,52 @@ +// +// RecipeImportSection.swift +// Nextcloud Cookbook iOS Client +// +// Created by Vincent Meilinger on 07.03.24. +// + +import Foundation +import SwiftUI + + +// MARK: - RecipeView Import Section + +struct RecipeImportSection: View { + @ObservedObject var viewModel: RecipeView.ViewModel + var importRecipe: (String) async -> UserAlert? + + var body: some View { + VStack(alignment: .leading) { + SecondaryLabel(text: "Import Recipe") + + Text(LocalizedStringKey("Paste the url of a recipe you would like to import in the above, and we will try to fill in the fields for you. This feature does not work with every website. If your favourite website is not supported, feel free to reach out for help. You can find the contact details in the app settings.")) + .font(.caption) + .foregroundStyle(.secondary) + + + TextField(LocalizedStringKey("URL (e.g. example.com/recipe)"), text: $viewModel.importUrl) + .textFieldStyle(.roundedBorder) + .padding(.top, 5) + Button { + Task { + if let res = await importRecipe(viewModel.importUrl) { + viewModel.presentAlert( + RecipeAlert.CUSTOM( + title: res.localizedTitle, + description: res.localizedDescription + ) + ) + } + } + } label: { + Text(LocalizedStringKey("Import")) + } + .buttonStyle(.bordered) + } + .padding() + .background(RoundedRectangle(cornerRadius: 20).foregroundStyle(Color.white.opacity(0.1))) + .padding(5) + .padding(.top, 5) + } +} + diff --git a/Nextcloud Cookbook iOS Client/Views/Recipes/RecipeViewSections/RecipeIngredientSection.swift b/Nextcloud Cookbook iOS Client/Views/Recipes/RecipeViewSections/RecipeIngredientSection.swift index 81aa350..8364395 100644 --- a/Nextcloud Cookbook iOS Client/Views/Recipes/RecipeViewSections/RecipeIngredientSection.swift +++ b/Nextcloud Cookbook iOS Client/Views/Recipes/RecipeViewSections/RecipeIngredientSection.swift @@ -43,7 +43,7 @@ struct RecipeIngredientSection: View { } else { Image(systemName: "heart.text.square") } - } + }.disabled(viewModel.editMode) } ForEach(0..: View where Collection.Element == Item { + @Binding var isPresented: Bool @Binding var value: Item @State var items: Collection + var title: LocalizedStringKey var titleKey: LocalizedStringKey = "" var body: some View { - HStack { - Picker(selection: $value, label: Text(titleKey)) { - ForEach(Array(items), id: \.self) { item in - Text(item.description).tag(item) + VStack { + HStack { + SecondaryLabel(text: title) + Spacer() + Button { + isPresented = false + } label: { + Text("Done") } } - .pickerStyle(WheelPickerStyle()) - .frame(width: 150, height: 150) - .clipped() + Spacer() + HStack { + Picker(selection: $value, label: Text(titleKey)) { + ForEach(Array(items), id: \.self) { item in + Text(item.description).tag(item) + } + } + .pickerStyle(WheelPickerStyle()) + .frame(width: 150, height: 150) + .clipped() + } + Spacer() } .padding() } diff --git a/Nextcloud Cookbook iOS Client/Views/Recipes/ShareView.swift b/Nextcloud Cookbook iOS Client/Views/Recipes/ShareView.swift index 655f69b..86cecec 100644 --- a/Nextcloud Cookbook iOS Client/Views/Recipes/ShareView.swift +++ b/Nextcloud Cookbook iOS Client/Views/Recipes/ShareView.swift @@ -18,37 +18,47 @@ struct ShareView: View { @State var sharedURL: URL? = nil var body: some View { - VStack(alignment: .leading) { - if let url = sharedURL { - ShareLink(item: url, subject: Text("PDF Document")) { - Image(systemName: "doc") - Text("Share as PDF") + NavigationStack { + VStack(alignment: .leading) { + if let url = sharedURL { + ShareLink(item: url, subject: Text("PDF Document")) { + Image(systemName: "doc") + Text("Share as PDF") + } + .foregroundStyle(.primary) + .bold() + .padding() + } + + ShareLink(item: exporter.createText(recipe: recipeDetail), subject: Text("Recipe")) { + Image(systemName: "ellipsis.message") + Text("Share as text") } .foregroundStyle(.primary) .bold() .padding() + + /*ShareLink(item: exporter.createJson(recipe: recipeDetail), subject: Text("Recipe")) { + Image(systemName: "doc.badge.gearshape") + Text("Share as JSON") + } + .foregroundStyle(.primary) + .bold() + .padding() + */ } - - ShareLink(item: exporter.createText(recipe: recipeDetail), subject: Text("Recipe")) { - Image(systemName: "ellipsis.message") - Text("Share as text") + .toolbar { + ToolbarItem(placement: .topBarTrailing) { + Button("Done") { + presentShareSheet = false + } + } } - .foregroundStyle(.primary) - .bold() - .padding() - - /*ShareLink(item: exporter.createJson(recipe: recipeDetail), subject: Text("Recipe")) { - Image(systemName: "doc.badge.gearshape") - Text("Share as JSON") - } - .foregroundStyle(.primary) - .bold() - .padding() - */ } .task { self.sharedURL = exporter.createPDF(recipe: recipeDetail, image: recipeImage) } + } } diff --git a/Nextcloud Cookbook iOS Client/Views/Tabs/RecipeTabView.swift b/Nextcloud Cookbook iOS Client/Views/Tabs/RecipeTabView.swift index 1b20290..56d65d4 100644 --- a/Nextcloud Cookbook iOS Client/Views/Tabs/RecipeTabView.swift +++ b/Nextcloud Cookbook iOS Client/Views/Tabs/RecipeTabView.swift @@ -10,6 +10,8 @@ import SwiftUI struct RecipeTabView: View { + @EnvironmentObject var appState: AppState + @EnvironmentObject var groceryList: GroceryList @EnvironmentObject var viewModel: RecipeTabView.ViewModel @EnvironmentObject var mainViewModel: AppState @@ -49,9 +51,12 @@ struct RecipeTabView: View { } .navigationDestination(isPresented: $viewModel.presentSettingsView) { SettingsView() + .environmentObject(appState) } .navigationDestination(isPresented: $viewModel.presentEditView) { RecipeView(isPresented: $viewModel.presentEditView, viewModel: RecipeView.ViewModel()) + .environmentObject(appState) + .environmentObject(groceryList) } } detail: { NavigationStack { @@ -62,6 +67,7 @@ struct RecipeTabView: View { ) .id(category.id) // Workaround: This is needed to update the detail view when the selection changes } + } } .tint(.nextcloudBlue)