diff --git a/README.md b/README.md index a0d7ee0..de2b801 100644 --- a/README.md +++ b/README.md @@ -4,5 +4,4 @@ This is demo app for displaying a list of recipes. Main View | Detailed View :-------------------------:|:-------------------------: -| - +| diff --git a/RecipeList.xcodeproj/project.pbxproj b/RecipeList.xcodeproj/project.pbxproj index 6b6c813..d4cbd71 100644 --- a/RecipeList.xcodeproj/project.pbxproj +++ b/RecipeList.xcodeproj/project.pbxproj @@ -11,11 +11,12 @@ 1B01F6AF29C74C92002E8674 /* RecipeListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B01F6AE29C74C92002E8674 /* RecipeListView.swift */; }; 1B01F6B129C74C93002E8674 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1B01F6B029C74C93002E8674 /* Assets.xcassets */; }; 1B01F6B429C74C93002E8674 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1B01F6B329C74C93002E8674 /* Preview Assets.xcassets */; }; - 1B01F6C029C74D88002E8674 /* recipes.json in Resources */ = {isa = PBXBuildFile; fileRef = 1B01F6BF29C74D88002E8674 /* recipes.json */; }; 1B01F6C229C74E0A002E8674 /* Recipe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B01F6C129C74E0A002E8674 /* Recipe.swift */; }; 1B01F6C429C74F25002E8674 /* RecipeModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B01F6C329C74F25002E8674 /* RecipeModel.swift */; }; 1B01F6C629C75066002E8674 /* DataService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B01F6C529C75066002E8674 /* DataService.swift */; }; 1B01F6C929C76E12002E8674 /* RecipeDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B01F6C829C76E12002E8674 /* RecipeDetailView.swift */; }; + 1B01F71329C85CB1002E8674 /* RecipeTabView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B01F71229C85CB1002E8674 /* RecipeTabView.swift */; }; + 1B01F74A29C88BA4002E8674 /* recipes.json in Resources */ = {isa = PBXBuildFile; fileRef = 1B01F74929C88BA4002E8674 /* recipes.json */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -24,11 +25,12 @@ 1B01F6AE29C74C92002E8674 /* RecipeListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeListView.swift; sourceTree = ""; }; 1B01F6B029C74C93002E8674 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 1B01F6B329C74C93002E8674 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; - 1B01F6BF29C74D88002E8674 /* recipes.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = recipes.json; sourceTree = ""; }; 1B01F6C129C74E0A002E8674 /* Recipe.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Recipe.swift; sourceTree = ""; }; 1B01F6C329C74F25002E8674 /* RecipeModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeModel.swift; sourceTree = ""; }; 1B01F6C529C75066002E8674 /* DataService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataService.swift; sourceTree = ""; }; 1B01F6C829C76E12002E8674 /* RecipeDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeDetailView.swift; sourceTree = ""; }; + 1B01F71229C85CB1002E8674 /* RecipeTabView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeTabView.swift; sourceTree = ""; }; + 1B01F74929C88BA4002E8674 /* recipes.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = recipes.json; path = ../../../../../../Downloads/recipes.json; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -86,6 +88,7 @@ children = ( 1B01F6AE29C74C92002E8674 /* RecipeListView.swift */, 1B01F6C829C76E12002E8674 /* RecipeDetailView.swift */, + 1B01F71229C85CB1002E8674 /* RecipeTabView.swift */, ); path = Views; sourceTree = ""; @@ -101,7 +104,7 @@ 1B01F6BC29C74CD0002E8674 /* Data */ = { isa = PBXGroup; children = ( - 1B01F6BF29C74D88002E8674 /* recipes.json */, + 1B01F74929C88BA4002E8674 /* recipes.json */, ); path = Data; sourceTree = ""; @@ -181,8 +184,8 @@ buildActionMask = 2147483647; files = ( 1B01F6B429C74C93002E8674 /* Preview Assets.xcassets in Resources */, - 1B01F6C029C74D88002E8674 /* recipes.json in Resources */, 1B01F6B129C74C93002E8674 /* Assets.xcassets in Resources */, + 1B01F74A29C88BA4002E8674 /* recipes.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -199,6 +202,7 @@ 1B01F6AF29C74C92002E8674 /* RecipeListView.swift in Sources */, 1B01F6AD29C74C92002E8674 /* RecipeListApp.swift in Sources */, 1B01F6C629C75066002E8674 /* DataService.swift in Sources */, + 1B01F71329C85CB1002E8674 /* RecipeTabView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/RecipeList/Data/recipes.json b/RecipeList/Data/recipes.json deleted file mode 100644 index a664d09..0000000 --- a/RecipeList/Data/recipes.json +++ /dev/null @@ -1,177 +0,0 @@ -[ - { - "name": "Eggplant Parmesan", - "featured": false, - "image" : "eggplant parmesan", - "description": "Baked eggplant with bread crumbs and lots of cheese. Delicious!", - "prepTime": "25 minutes", - "cookTime": "35 minutes", - "totalTime": "1 hour", - "servings": 10, - "ingredients": [ - "3 Eggplant, peeled and thinly sliced", - "3 Large eggs", - "4 cups Italian seasoned bread crumbs", - "6 cups Spaghetti sauce", - "2 cups Mozarella cheese, shredded", - "1/2 cup Parmesan cheese, grated", - "1/2 teaspoon Dried basil" - ], - "directions": [ - "Preheat oven to 350 degrees F (175 degrees C).", - "Dip eggplant slices in egg, then in bread crumbs. Place in a single layer on a baking sheet. Bake in preheated oven for 5 minutes on each side.", - "In a 9x13 inch baking dish spread spaghetti sauce to cover the bottom. Place a layer of eggplant slices in the sauce. Sprinkle with mozzarella and Parmesan cheeses. Repeat with remaining ingredients, ending with the cheeses. Sprinkle basil on top.", - "Bake in preheated oven for 35 minutes, or until golden brown." - ] - }, - { - "name": "Lasagna", - "featured": false, - "image" : "lasagna", - "description": "Layers of goodness in this cheesy delight.", - "prepTime": "30 minutes", - "cookTime": "2 hours 30 minutes", - "totalTime": "3 hours", - "servings": 12, - "highlights": [ - "Cheesy", - "Oven meal" - ], - "ingredients": [ - "1 pound Italian Sausage", - "3/4 pound Ground beef", - "1/2 cup Diced onion", - "2 cloves Garlic", - "28 ounce Crushed tomatoes", - "12 ounce Tomato paste", - "13 ounce Tomato sauce", - "2 cups Water", - "2 tablespoon White sugar", - "2/3 tablespoon Dried basil leaves", - "1/2 teaspoon Fennel seeds", - "1 teaspoon Italian seasoning", - "2 teaspoon Salt", - "1/4 teaspoon Black pepper", - "4 tablespoon Fresh parsley, chopped", - "12 Lasagna noodles", - "16 ounce Ricotta cheese", - "1 Egg", - "3/4 pound Mozarella cheese", - "3/4 cup Parmesan cheese" - ], - "directions": [ - "In a Dutch oven, cook sausage, ground beef, onion, and garlic over medium heat until well browned. Stir in crushed tomatoes, tomato paste, tomato sauce, and water. Season with sugar, basil, fennel seeds, Italian seasoning, 1 teaspoon salt, pepper, and 2 tablespoons parsley. Simmer, covered, for about 1 1/2 hours, stirring occasionally.", - "Bring a large pot of lightly salted water to a boil. Cook lasagna noodles in boiling water for 8 to 10 minutes. Drain noodles, and rinse with cold water. In a mixing bowl, combine ricotta cheese with egg, remaining parsley, and 1/2 teaspoon salt.", - "Preheat oven to 375 degrees F (190 degrees C).", - "To assemble, spread 1 1/2 cups of meat sauce in the bottom of a 9x13 inch baking dish. Arrange 6 noodles lengthwise over meat sauce. Spread with one half of the ricotta cheese mixture. Top with a third of mozzarella cheese slices. Spoon 1 1/2 cups meat sauce over mozzarella, and sprinkle with 1/4 cup Parmesan cheese. Repeat layers, and top with remaining mozzarella and Parmesan cheese. Cover with foil: to prevent sticking, either spray foil with cooking spray, or make sure the foil does not touch the cheese.", - "Bake in preheated oven for 25 minutes. Remove foil, and bake an additional 25 minutes. Cool for 15 minutes before serving." - ] - }, - { - "name": "Pad Thai", - "featured": true, - "image" : "pad thai", - "description": "A delicious noodle dish!", - "prepTime": "15 minutes", - "cookTime": "15 minutes", - "totalTime": "30 minutes", - "servings": 4, - "highlights": [ - "Spicy", - "Fast", - "Make it your own" - ], - "ingredients": [ - "8 ounce Flat rice noodles", - "3 tablespoon Fish sauce", - "1/4 cup Fresh lime juice", - "1 tablespoon White sugar", - "2 tablespoon Oyster sauce", - "1 1/2 tablespoon Asian chile pepper sauce", - "1/4 cup Chicken stock", - "1/4 cup Vegetable oil", - "1 tablespoon Chopped garlic", - "8 ounce Medium shrimp", - "8 ounce Boneless, skinless chicken breast, cubed", - "2 Large eggs, beaten", - "3 cup Bean sprouts", - "6 Green onions, chopped", - "2 tablespoon Unsalted, roasted peanuts, chopped", - "1/4 cup Fresh cilantro, chopped", - "8 Lime wedges" - ], - "directions": [ - "Fill a large bowl with hot tap water and place the noodles in it to soak for 20 minutes.", - "In a small bowl, stir together the fish sauce, lime juice, sugar, oyster sauce, 2 teaspoons of the chile sauce and chicken stock. Set aside.", - "Heat a wok or large skillet over high heat and add vegetable oil. When the oil is hot, stir in garlic and cook for about 10 seconds. Add shrimp and chicken; cook, stirring constantly until shrimp is opaque and chicken is cooked through, 5 to 7 minutes.", - "Move everything in the wok out to the sides and pour the eggs in the center. Cook and stir the eggs until firm. Add the noodles to the wok and pour in the sauce. Cook, stirring constantly, until the noodles are tender. Add a bit more water if needed to finish cooking the noodles. Stir in 3 cups of bean sprouts and green onions. Remove from the heat and garnish with chopped peanuts. Taste for seasoning, adjusting the spice or lime juice if needed.", - "Serve garnished with fresh cilantro and remaining bean sprouts and lime wedges on the side." - ] - }, - { - "name": "Monterey Chicken", - "featured": true, - "image" : "monterey chicken", - "description": "Classic Monterey Chicken, worth the time!", - "prepTime": "45 minutes", - "cookTime": "15 minutes", - "totalTime": "1 hour", - "servings": 4, - "highlights": [ - "Melt in your mouth", - "Gluten free" - ], - "ingredients": [ - "4 half Skinless, boneless chicken breast", - "1 cup Teriyaki marinade sauce", - "1/2 pound Bacon", - "2 tablespoon Butter", - "1 Onion, cut into long slices", - "8 ounce Fresh mushrooms, coarsely chopped", - "4 slice Mozarella cheese" - ], - "directions": [ - "To Marinate: Place chicken in a nonporous glass dish or bowl. Pour marinade over chicken and toss to coat. Cover and refrigerate to marinate for 1 to 2 hours.", - "Preheat oven to 350 degrees F (175 degrees C).", - "Place chicken in a 9x13 inch baking dish and bake preheated oven for 20 to 30 minutes, or until cooked through and juices run clear. Meanwhile, place bacon in a large, deep skillet. Cook over medium high heat until evenly brown. Drain and set aside.", - "In same skillet, melt butter over medium high heat. Saute onion, bell pepper and mushrooms for about 3 to 5 minutes. Add remaining 1/3 cup of marinade and simmer until soft. Drain and set onion mixture aside.", - "Top baked chicken with bacon strips. Add onion mixture and top each breast with a slice of cheese. Bake for another 10 to 15 minutes, or until cheese is melted and bubbly." - ] - }, - { - "name": "Twice-baked potatoes", - "featured": false, - "image" : "baked potato", - "description": "A fantastic starchy side.", - "prepTime": "30 minutes", - "cookTime": "1 hour 30 minutes", - "totalTime": "2 hours", - "servings": 4, - "highlights": [ - "Comfort food", - "Filling" - ], - "ingredients": [ - "4 Russet potatoes", - "2 teaspoon Vegetable oil", - "3 tablespoon Butter", - "1 tablespoon Green onion, minced", - "Salt and pepper to taste", - "1 pinch Cayenne pepper", - "2 cups Cheddar cheese, shredded", - "1/2 cup Heavy cream", - "1 Egg yolk", - "1 tablespoon Butter, melted", - "1 teaspoon Paprika" - ], - "directions": [ - "Preheat oven to 400 degrees F (200 degrees C). Line a baking sheet with aluminum foil.", - "Rub potatoes with vegetable oil and place on the prepared baking sheet.", - "Bake in the preheated oven until a paring knife easily inserts into the center of a potato, about 1 hour. Set aside to cool until easy to handle, about 10 minutes.", - "Cut 1/3 off each potato lengthwise. Scoop flesh from each potato to within about 1/8-inch of the skins. Transfer flesh to a bowl.", - "Combine potato flesh with butter and green onion; stir until butter is melted evenly into potato. Add salt, black pepper, cayenne pepper, and cheese; stir until cheese is melted. Pour cream and egg yolk into potato mixture; mix to combine. Season with salt to taste.", - "Place small piece of potato skin inside the bottom of each larger potato shell. Fill each potato with an equal amount of cheese mixture. Gently press the surface of the filling with a fork to create texture. Brush tops with melted butter and sprinkle with paprika.", - "Bake stuffed potatoes until golden brown on top, 20 to 30 minutes." - ] - } -] diff --git a/RecipeList/Models/Recipe.swift b/RecipeList/Models/Recipe.swift index 45b11fe..bb956ae 100644 --- a/RecipeList/Models/Recipe.swift +++ b/RecipeList/Models/Recipe.swift @@ -18,6 +18,16 @@ class Recipe: Identifiable, Decodable { var prepTime:String var cookTime:String var servings:Int - var ingredients:[String] + var ingredients:[Ingredients] var directions:[String] + var highlights:[String] +} + +class Ingredients: Identifiable, Decodable { + + var id:UUID? = UUID() + var name:String + var num:Int? + var denom:Int? + var unit:String? } diff --git a/RecipeList/RecipeListApp.swift b/RecipeList/RecipeListApp.swift index 510ff4c..3a6f16a 100644 --- a/RecipeList/RecipeListApp.swift +++ b/RecipeList/RecipeListApp.swift @@ -11,7 +11,7 @@ import SwiftUI struct RecipeListApp: App { var body: some Scene { WindowGroup { - RecipeListView() + RecipeTabView() } } } diff --git a/RecipeList/Services/DataService.swift b/RecipeList/Services/DataService.swift index f373fbc..bc94271 100644 --- a/RecipeList/Services/DataService.swift +++ b/RecipeList/Services/DataService.swift @@ -30,6 +30,10 @@ class DataService { for r in recipeData { r.id = UUID() + + for i in r.ingredients { + i.id = UUID() + } } return recipeData } diff --git a/RecipeList/Views/RecipeDetailView.swift b/RecipeList/Views/RecipeDetailView.swift index 78e9c2a..5cb334b 100644 --- a/RecipeList/Views/RecipeDetailView.swift +++ b/RecipeList/Views/RecipeDetailView.swift @@ -21,9 +21,9 @@ struct RecipeDetailView: View { // MARK: Ingredients VStack(alignment: .leading){ Text("Ingredients").font(.headline).padding([.bottom, .top], 5) - ForEach (recipe.ingredients, id: \.self) { + ForEach (recipe.ingredients) { item in - Text("* " + item) + Text("* " + item.name) } } .padding(.horizontal) diff --git a/RecipeList/Views/RecipeTabView.swift b/RecipeList/Views/RecipeTabView.swift new file mode 100644 index 0000000..2a3c303 --- /dev/null +++ b/RecipeList/Views/RecipeTabView.swift @@ -0,0 +1,47 @@ +// +// RecipeTabView.swift +// RecipeList +// +// Created by Nick Jüttner on 20.03.23. +// + +import SwiftUI + +struct RecipeTabView: View { + + @ObservedObject var model = RecipeModel() + + var body: some View { + VStack { + HStack{ + Spacer() + Button(action: { print("Hello") } ) { + Image(systemName: "plus.circle.fill") + Text("Add Recipe") + } + Spacer() + } + TabView { + Text("Featured View").tabItem { + VStack { + Image(systemName: "star.fill") + Text("Featured") + } + } + RecipeListView() + .tabItem { + VStack { + Image(systemName: "list.bullet") + Text("List") + } + }.badge(model.recipes.count) + } + } + } +} + +struct RecipeTabView_Previews: PreviewProvider { + static var previews: some View { + RecipeTabView() + } +} diff --git a/screenshots/demo.png b/screenshots/demo.png new file mode 100644 index 0000000..9ade0a4 Binary files /dev/null and b/screenshots/demo.png differ