Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ///////////////////////////////
- //------------ ContentView.swift -----------
- import SwiftUI
- struct ContentView: View {
- let data: [MealSection] = Bundle.main.decode("meals.json")
- @State private var searchText = ""
- @State private var showCancelButton: Bool = false
- var body: some View {
- NavigationView {
- VStack {
- HStack {
- HStack {
- Image(systemName: "magnifyingglass")
- TextField("search", text: $searchText, onEditingChanged: { isEditing in
- self.showCancelButton = true
- }, onCommit: {
- print("onCommit")
- }).foregroundColor(.primary)
- Button(action: {
- self.searchText = ""
- }) {
- Image(systemName: "xmark.circle.fill").opacity(searchText == "" ? 0 : 1)
- }
- }
- .padding(EdgeInsets(top: 8, leading: 6, bottom: 8, trailing: 6))
- .foregroundColor(.secondary)
- .background(Color(.secondarySystemBackground))
- .cornerRadius(10.0)
- if showCancelButton {
- Button("Cancel") {
- UIApplication.shared.endEditing(true) // this must be placed before the other commands here
- self.searchText = ""
- self.showCancelButton = false
- }
- .foregroundColor(Color(.systemBlue))
- }
- }
- .padding(.horizontal)
- .navigationBarHidden(showCancelButton) // .animation(.default) //
- List {
- ForEach(data) { daytimeMeals in
- Section(header: Text("\(daytimeMeals.daytime)"), content: {
- mealRow(meals: daytimeMeals.meals, searchText: self.searchText)
- })
- }
- }.navigationBarTitle("Meals", displayMode: .large)
- }
- }
- }
- }
- struct ContentView_Previews: PreviewProvider {
- static var previews: some View {
- Group {
- ContentView()
- .environment(\.colorScheme, .light)
- ContentView()
- .environment(\.colorScheme, .dark)
- }
- }
- }
- // Cell prototype
- struct mealRow: View {
- let meals: [Meal]
- let searchText: String
- var body: some View {
- ForEach(meals.filter {
- $0.name.hasPrefix(self.searchText) || self.searchText == ""
- }) { meal in
- HStack {
- Image(meal.image).resizable().aspectRatio(contentMode: .fill).frame(width: 90, height: 90).clipShape(Circle())
- VStack(alignment: .leading) {
- Text("\(meal.name)").font(.headline)
- Text("Only \(meal.calories) calories").foregroundColor(.red).bold()
- Text("\(meal.description)").italic()
- }
- }
- }
- }
- }
- extension UIApplication {
- func endEditing(_ force: Bool) {
- self.windows
- .filter{$0.isKeyWindow}
- .first?
- .endEditing(force)
- }
- }
- struct ResignKeyboardOnDragGesture: ViewModifier {
- var gesture = DragGesture().onChanged{_ in
- UIApplication.shared.endEditing(true)
- }
- func body(content: Content) -> some View {
- content.gesture(gesture)
- }
- }
- extension View {
- func resignKeyboardOnDragGesture() -> some View {
- return modifier(ResignKeyboardOnDragGesture())
- }
- }
- //-------------- Bundle-Decodable.swift ---------------
- // Extension for the Bundle class to parse JSON files
- import Foundation
- extension Bundle {
- // Using Generics so the function will suit not only to MealSection Objects
- func decode<T: Codable>(_ file: String) -> T {
- guard let url = self.url(forResource: file, withExtension: nil) else {
- fatalError("Failed to locate \(file) in bundle.")
- }
- guard let data = try? Data(contentsOf: url) else {
- fatalError("Failed to load \(file) from bundle.")
- }
- let decoder = JSONDecoder()
- // Another cool code that I found for parsing dates and make them look great!
- /*
- let formatter = DateFormatter()
- formatter.dateFormat = "y-MM-dd"
- decoder.dateDecodingStrategy = .formatted(formatter) // This turns dates to more sensible format. The appropriate text field should be defined as follows:
- var formattedDate: String {
- if let myDate = dateFromJSON {
- let formatter.dateStyle = .long
- return formatter.string(from: dateFromJSON)
- } else {
- return "N/A"
- }
- }
- // Then when ever I want to show the date in this format I call: Text(MyObject.formattedDate)
- */
- guard let loaded = try? decoder.decode(T.self, from: data) else {
- fatalError("Failed to decode \(file) from bundle.")
- }
- return loaded
- }
- }
- //-------------- Meals.swift -----------------
- import Foundation
- struct MealSection: Codable, Identifiable {
- var id: Int
- var daytime: String
- var meals: [Meal]
- }
- struct Meal: Codable, Equatable, Identifiable {
- var id: Int
- var name: String
- var calories: Int
- var image: String
- var description: String
- }
- // -------------- meals.json ---------------------
- [
- {
- "id" : 1,
- "daytime" : "breakfast",
- "meals" : [
- {
- "id" : 11,
- "name" : "Omlet",
- "calories" : 200,
- "image" : "omletImage",
- "description" : "A 2 eggs omlet with onion, salmon, and a peace of bread"
- },
- {
- "id" : 12,
- "name" : "Toast",
- "calories" : 350,
- "image" : "toastImage",
- "description" : "2 Toasts with a yellow cheese, tomato souce, and mushrooms"
- },
- {
- "id" : 13,
- "name" : "Muzesli",
- "calories" : 260,
- "image" : "muesliImage",
- "description" : "Yogurt 4% fat with granola and cranbarries and strawbarries"
- }
- ]
- },
- {
- "id" : 2,
- "daytime" : "lunch",
- "meals" : [
- {
- "id" : 21,
- "name" : "Steak",
- "calories" : 510,
- "image" : "steakImage",
- "description" : "200 grams of entrecote steak with mashed potatoes"
- },
- {
- "id" : 22,
- "name" : "Schnitzel",
- "calories" : 480,
- "image" : "schnitzelImage",
- "description" : "A true Wiener Schnitzel is a breaded cutlet of veal served with a lemon wedge to add some extra zing"
- },
- {
- "id" : 23,
- "name" : "Ceaser Salad",
- "calories" : 530,
- "image" : "caesarSaladImage",
- "description" : "A large salad with homemade Caesar dressing, fresh croutons, and shavings of parmigiano reggiano"
- }
- ]
- },
- {
- "id" : 3,
- "daytime" : "dinner",
- "meals" : [
- {
- "id" : 31,
- "name" : "Alfredo Pasta",
- "calories" : 660,
- "image" : "alfredoPastaImage",
- "description" : "A rich and creamy pumpkin alfredo pasta is made with canned pumpkin puree and a dash of nutmeg"
- },
- {
- "id" : 32,
- "name" : "Pizza",
- "calories" : 240,
- "image" : "pizzaImage",
- "description" : "Pizza Margherita from Tony's Pizza Napoletana"
- },
- {
- "id" : 33,
- "name" : "Salad",
- "calories" : 320,
- "image" : "saladImage",
- "description" : "Greek salad with fresh vegetables, feta cheese and black olives"
- }
- ]
- },
- {
- "id" : 4,
- "daytime" : "night",
- "meals" : [
- {
- "id" : 41,
- "name" : "Cheese Cake",
- "calories" : 27,
- "image" : "cheeseCakeImage",
- "description" : "Cheesecake with Blackberries slice on the plate"
- },
- {
- "id" : 42,
- "name" : "Pancake",
- "calories" : 410,
- "image" : "pancakeImage",
- "description" : "Good Old Fashioned Pancakes"
- },
- {
- "id" : 43,
- "name" : "Cream Brolle",
- "calories" : 561,
- "image" : "creamBrolleImage",
- "description" : "a very nice dessert to serve when entertaining. Delicious served over mangos sprinkled with rum, or strawberries with Grand Marnier or Cointreau"
- }
- ]
- }
- ]
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement