Advertisement
eranseg

List From JSON

Jun 13th, 2020
579
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Swift 9.41 KB | None | 0 0
  1. ///////////////////////////////
  2. //------------ ContentView.swift -----------
  3.  
  4. import SwiftUI
  5.  
  6. struct ContentView: View {
  7.    
  8.     let data: [MealSection] = Bundle.main.decode("meals.json")
  9.     @State private var searchText = ""
  10.     @State private var showCancelButton: Bool = false
  11.    
  12.     var body: some View {
  13.         NavigationView {
  14.             VStack {
  15.                 HStack {
  16.                     HStack {
  17.                         Image(systemName: "magnifyingglass")
  18.  
  19.                         TextField("search", text: $searchText, onEditingChanged: { isEditing in
  20.                             self.showCancelButton = true
  21.                         }, onCommit: {
  22.                             print("onCommit")
  23.                         }).foregroundColor(.primary)
  24.  
  25.                         Button(action: {
  26.                             self.searchText = ""
  27.                         }) {
  28.                             Image(systemName: "xmark.circle.fill").opacity(searchText == "" ? 0 : 1)
  29.                         }
  30.                     }
  31.                     .padding(EdgeInsets(top: 8, leading: 6, bottom: 8, trailing: 6))
  32.                     .foregroundColor(.secondary)
  33.                     .background(Color(.secondarySystemBackground))
  34.                     .cornerRadius(10.0)
  35.  
  36.                     if showCancelButton  {
  37.                         Button("Cancel") {
  38.                                 UIApplication.shared.endEditing(true) // this must be placed before the other commands here
  39.                                 self.searchText = ""
  40.                                 self.showCancelButton = false
  41.                         }
  42.                         .foregroundColor(Color(.systemBlue))
  43.                     }
  44.                 }
  45.                 .padding(.horizontal)
  46.                 .navigationBarHidden(showCancelButton) // .animation(.default) //
  47.                
  48.                 List {
  49.                     ForEach(data) { daytimeMeals in
  50.                         Section(header: Text("\(daytimeMeals.daytime)"), content: {
  51.                             mealRow(meals: daytimeMeals.meals, searchText: self.searchText)
  52.                         })
  53.                     }
  54.                 }.navigationBarTitle("Meals", displayMode: .large)
  55.             }
  56.            
  57.         }
  58.     }
  59. }
  60.  
  61. struct ContentView_Previews: PreviewProvider {
  62.     static var previews: some View {
  63.         Group {
  64.            ContentView()
  65.               .environment(\.colorScheme, .light)
  66.  
  67.            ContentView()
  68.               .environment(\.colorScheme, .dark)
  69.         }
  70.     }
  71. }
  72.  
  73. // Cell prototype
  74. struct mealRow: View {
  75.     let meals: [Meal]
  76.     let searchText: String
  77.     var body: some View {
  78.         ForEach(meals.filter {
  79.             $0.name.hasPrefix(self.searchText) || self.searchText == ""
  80.         }) { meal in
  81.             HStack {
  82.                 Image(meal.image).resizable().aspectRatio(contentMode: .fill).frame(width: 90, height: 90).clipShape(Circle())
  83.                 VStack(alignment: .leading) {
  84.                     Text("\(meal.name)").font(.headline)
  85.                     Text("Only \(meal.calories) calories").foregroundColor(.red).bold()
  86.                     Text("\(meal.description)").italic()
  87.                 }
  88.             }
  89.         }
  90.     }
  91. }
  92.  
  93. extension UIApplication {
  94.     func endEditing(_ force: Bool) {
  95.         self.windows
  96.             .filter{$0.isKeyWindow}
  97.             .first?
  98.             .endEditing(force)
  99.     }
  100. }
  101.  
  102. struct ResignKeyboardOnDragGesture: ViewModifier {
  103.     var gesture = DragGesture().onChanged{_ in
  104.         UIApplication.shared.endEditing(true)
  105.     }
  106.     func body(content: Content) -> some View {
  107.         content.gesture(gesture)
  108.     }
  109. }
  110.  
  111. extension View {
  112.     func resignKeyboardOnDragGesture() -> some View {
  113.         return modifier(ResignKeyboardOnDragGesture())
  114.     }
  115. }
  116.  
  117. //-------------- Bundle-Decodable.swift ---------------
  118.  
  119. // Extension for the Bundle class to parse JSON files
  120.  
  121. import Foundation
  122.  
  123. extension Bundle {
  124.  
  125. // Using Generics so the function will suit not only to MealSection Objects
  126.     func decode<T: Codable>(_ file: String) -> T {
  127.         guard let url = self.url(forResource: file, withExtension: nil) else {
  128.             fatalError("Failed to locate \(file) in bundle.")
  129.         }
  130.        
  131.        
  132.         guard let data = try? Data(contentsOf: url) else {
  133.             fatalError("Failed to load \(file) from bundle.")
  134.         }
  135.         let decoder = JSONDecoder()
  136.  
  137. // Another cool code that I found for parsing dates and make them look great!
  138. /*
  139.         let formatter = DateFormatter()
  140.         formatter.dateFormat = "y-MM-dd"
  141.         decoder.dateDecodingStrategy = .formatted(formatter) // This turns dates to more sensible format. The appropriate text field should be defined as follows:
  142.        
  143.          var formattedDate: String {
  144.             if let myDate = dateFromJSON {
  145.                 let formatter.dateStyle = .long
  146.                 return formatter.string(from: dateFromJSON)
  147.             } else {
  148.                 return "N/A"
  149.             }
  150.          }
  151.          // Then when ever I want to show the date in this format I call: Text(MyObject.formattedDate)
  152.          */
  153.        
  154.         guard let loaded = try? decoder.decode(T.self, from: data) else {
  155.             fatalError("Failed to decode \(file) from bundle.")
  156.         }
  157.         return loaded
  158.     }
  159. }
  160.  
  161. //-------------- Meals.swift -----------------
  162.  
  163. import Foundation
  164.  
  165. struct MealSection: Codable, Identifiable {
  166.     var id: Int
  167.     var daytime: String
  168.     var meals: [Meal]
  169. }
  170.  
  171. struct Meal: Codable, Equatable, Identifiable {
  172.     var id: Int
  173.     var name: String
  174.     var calories: Int
  175.     var image: String
  176.     var description: String
  177. }
  178.  
  179. // -------------- meals.json ---------------------
  180.  
  181. [
  182.     {
  183.         "id" : 1,
  184.         "daytime" : "breakfast",
  185.         "meals" : [
  186.             {
  187.                 "id" : 11,
  188.                 "name" : "Omlet",
  189.                 "calories" : 200,
  190.                 "image" : "omletImage",
  191.                 "description" : "A 2 eggs omlet with onion, salmon, and a peace of bread"
  192.             },
  193.             {
  194.                 "id" : 12,
  195.                 "name" : "Toast",
  196.                 "calories" : 350,
  197.                 "image" : "toastImage",
  198.                 "description" : "2 Toasts with a yellow cheese, tomato souce, and mushrooms"
  199.             },
  200.             {
  201.                 "id" : 13,
  202.                 "name" : "Muzesli",
  203.                 "calories" : 260,
  204.                 "image" : "muesliImage",
  205.                 "description" : "Yogurt 4% fat with granola and cranbarries and strawbarries"
  206.             }
  207.         ]
  208.     },
  209.     {
  210.         "id" : 2,
  211.         "daytime" : "lunch",
  212.         "meals" : [
  213.             {
  214.                 "id" : 21,
  215.                 "name" : "Steak",
  216.                 "calories" : 510,
  217.                 "image" : "steakImage",
  218.                 "description" : "200 grams of entrecote steak with mashed potatoes"
  219.             },
  220.             {
  221.                 "id" : 22,
  222.                 "name" : "Schnitzel",
  223.                 "calories" : 480,
  224.                 "image" : "schnitzelImage",
  225.                 "description" : "A true Wiener Schnitzel is a breaded cutlet of veal served with a lemon wedge to add some extra zing"
  226.             },
  227.             {
  228.                 "id" : 23,
  229.                 "name" : "Ceaser Salad",
  230.                 "calories" : 530,
  231.                 "image" : "caesarSaladImage",
  232.                 "description" : "A large salad with homemade Caesar dressing, fresh croutons, and shavings of parmigiano reggiano"
  233.             }
  234.         ]
  235.     },
  236.     {
  237.         "id" : 3,
  238.         "daytime" : "dinner",
  239.         "meals" : [
  240.             {
  241.                 "id" : 31,
  242.                 "name" : "Alfredo Pasta",
  243.                 "calories" : 660,
  244.                 "image" : "alfredoPastaImage",
  245.                 "description" : "A rich and creamy pumpkin alfredo pasta is made with canned pumpkin puree and a dash of nutmeg"
  246.             },
  247.             {
  248.                 "id" : 32,
  249.                 "name" : "Pizza",
  250.                 "calories" : 240,
  251.                 "image" : "pizzaImage",
  252.                 "description" : "Pizza Margherita from Tony's Pizza Napoletana"
  253.             },
  254.             {
  255.                 "id" : 33,
  256.                 "name" : "Salad",
  257.                 "calories" : 320,
  258.                 "image" : "saladImage",
  259.                 "description" : "Greek salad with fresh vegetables, feta cheese and black olives"
  260.             }
  261.         ]
  262.     },
  263.     {
  264.         "id" : 4,
  265.         "daytime" : "night",
  266.         "meals" : [
  267.             {
  268.                 "id" : 41,
  269.                 "name" : "Cheese Cake",
  270.                 "calories" : 27,
  271.                 "image" : "cheeseCakeImage",
  272.                 "description" : "Cheesecake with Blackberries slice on the plate"
  273.             },
  274.             {
  275.                 "id" : 42,
  276.                 "name" : "Pancake",
  277.                 "calories" : 410,
  278.                 "image" : "pancakeImage",
  279.                 "description" : "Good Old Fashioned Pancakes"
  280.             },
  281.             {
  282.                 "id" : 43,
  283.                 "name" : "Cream Brolle",
  284.                 "calories" : 561,
  285.                 "image" : "creamBrolleImage",
  286.                 "description" : "a very nice dessert to serve when entertaining. Delicious served over mangos sprinkled with rum, or strawberries with Grand Marnier or Cointreau"
  287.             }
  288.         ]
  289.     }
  290. ]
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement