Combining Day Entry Views for a Week Overview

The day entry view needs the maximum duration to provide the correct scaling to its rectangle. Before we can show the day entry views for the last seven days, though, we need to calculate the maximum duration of these entries. Open LocationProvider and add the following property:

 var​ max: ​TimeInterval​ = 1

To calculate the maximum, replace the dayEntries property declaration with the following code:

 @Published​ ​var​ dayEntries: [​DayEntry​] = [] {
 didSet​ {
  max = dayEntries.​reduce​(1.0, { result, nextDayEntry ​in
 Swift​.​max​(result, nextDayEntry.duration)
  })
  }
 }

This looks more complicated than it is. We use the reduce method defined on Collection, which uses an initial value (in our case, 1.0) and iterates over all elements in the collection. For each element the closure gets executed. The first parameter of the closure is the result of the last iteration, and the second parameter is the current element in the collection.

In the closure we call the global function Swift.max(_:_:). The word Swift tells the compiler that we mean the global max(_:_:) function. We need this here because we have a property with the same name, so the compiler could get confused otherwise.

The reduce method iterates over the day entries array and finds the maximum duration. If the day entries array is empty, it returns 1.0. We choose 1.0 instead of 0.0 as the minimum value here because we’ll divide by this value in the next step, and dividing by zero is not allowed.

Now we can add the day entries to the main user interface. Open ContentView and add the highlighted lines to the body contents:

 var​ body: some ​View​ {
 VStack​ {
 Text​(​"Into The Wild"​)
 Button​(​"Set Home"​) {
 self​.locationProvider.​setHome​()
  }
»HStack​(alignment: .bottom, spacing: 2) {
»ForEach​(​self​.locationProvider.dayEntries, id: ​​.​self​) { value ​in
»DayEntryView​(duration: value.duration,
» max: ​self​.locationProvider.max,
» weekday: value.weekday)
» }
» }
» .​padding​()
  }
» .​background​(​Color​(​UIColor​.systemBackground))
 }

In this code we iterate over all day entries, create day entry views from them, and put those into an HStack. This works only because we made DayEntry conform to Hashable. In addition, we set the background color of the main VStack to Color(UIColor.systemBackground)) to make the app work in both light and dark mode.

The preview in ContentView doesn’t work right now. To make it work again, replace the ContentView_Previews struct with the following code:

 struct​ ​ContentView_Previews​: ​PreviewProvider​ {
 
 static​ ​var​ locationProvider: ​LocationProvider​ = {
 let​ locationProvider = ​LocationProvider​()
  locationProvider.dayEntries = [
 DayEntry​(duration: 20640, weekday: ​"Monday"​),
 DayEntry​(duration: 2580, weekday: ​"Tuesday"​ ),
 DayEntry​(duration: 12000, weekday: ​"Wednesday"​),
 DayEntry​(duration: 1200, weekday: ​"Thursday"​),
 DayEntry​(duration: 2220, weekday: ​"Friday"​),
 DayEntry​(duration: 19920, weekday: ​"Saturday"​),
 DayEntry​(duration: 18000, weekday: ​"Sunday"​),
  ]
 return​ locationProvider
  }()
 
 static​ ​var​ previews: some ​View​ {
 Group​ {
 ContentView​()
  .​environmentObject​(locationProvider)
 ContentView​()
  .​environmentObject​(locationProvider)
  .​environment​(​​.colorScheme, .dark)
  }
  }
 }

First we define a location provider for the preview and fill it with seven day entries. We add a group with two previews, one for light mode (the default) and one for dark mode. Then we set the location provider as an environment object for the content view preview. Unfortunately, this still isn’t enough to make the preview work. We also have to set the environment in the setup of the app.

Open SceneDelegate and add the highlighted line in scene(_:willConnectTo:options:):

 func​ ​scene​(_ scene: ​UIScene​,
  willConnectTo session: ​UISceneSession​,
  options connectionOptions: ​UIScene​.​ConnectionOptions​) {
 
 let​ contentView = ​ContentView​()
» .​environmentObject​(​LocationProvider​())
 
 if​ ​let​ windowScene = scene ​as?​ ​UIWindowScene​ {
 let​ window = ​UIWindow​(windowScene: windowScene)
  window.rootViewController = ​UIHostingController​(rootView: contentView)
 self​.window = window
  window.​makeKeyAndVisible​()
 #if DEBUG
  trigger = ​LogTrigger​(in: window)
 #endif
  }
 }

With this code we set the environment of the content view. Go back to ContentView and click the Resume button. If you see a Try Again button rather than Resume, click it instead.

The canvas should show the user interface with the outside times. If there’s an error in the code, try to fix it according to what Xcode tells you about the error. If you still can’t get the code to work, delete the lines with errors until it works and then repeat this section to add the code again.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.223.125.219