WWDC22 SALE: Save 50% on all my Swift books and bundles! >>

Day 28 BetterSleep - Challenge improvements

Forums > 100 Days of SwiftUI

Hi, this is my first post and I first wanted to thank Paul and everyone for creating and maintaining such a wonderful community! (Also, please let me know if I'm breaking any code of conduct or any kind of improvements on how I formatted my question)

I was tackling Day 28's challenge problems. And, here's what I've successfully done so far,

UI Changes

  1. Replaced VStack with Sections.

  2. Got rid of the Toolbar and Alert - replaced it with a "Calculate" button inside form, where clicking on "Calculate" will display sleep time as a text value (sleepTimeDisplay).

Added methods

  1. Added a resetForm function, which is called when the user clicks on "Reset". It wipes all user inputs and restores default values.

  2. Added a resetSleepTimeDisplay function, which resets sleepTimeDisplay. In my code, I called it whenever there's a change in user input, to encourage users to click on "calculate" with every new input.

Room for Improvements?

I think that's all the features I wanted to build for this project, and it's working as intended. But I do think there are many improvements that can be made in the code. I am definitely not too happy about how I used three individual onChange() to call resetSleepTimeDisplay for every section. I did read up on how to pass multiple parameters on onChange, but I couldn't successfully write the code. It would be really helpful to find a way to call resetSleepTimeDisplay with just one line of code, instead of calling it with onChange for every section! Thank you!

struct ContentView: View {
    @State private var sleepAmount = 8.0
    @State private var coffeeAmount = 0
    @State private var wakeUp = defaultWakeTime

    @State private var sleepTimeDisplay = ""

    static var defaultWakeTime: Date {
        var components = DateComponents()
        components.hour = 7
        components.minute = 0
        return Calendar.current.date(from: components) ?? Date.now
    }

    var body: some View {
        NavigationView {
            Form {
                Section {
                    Picker("How much coffee did you drink", selection: $coffeeAmount) {
                        ForEach(1..<6) {number in
                            Text(number == 1 ? "1 cup" : "\(number) cups")
                        }
                    }
                    .pickerStyle(.segmented)
                } header: {
                    Text("How much coffee did you drink?")
                        .font(.subheadline)
                }
                .onChange(of: coffeeAmount) {newValue in
                    resetSleepTimeDisplay()
                }

                Section {
                    Stepper("\(sleepAmount.formatted()) hours", value: $sleepAmount, in: 0...24, step: 0.5) {_ in
                    }
                } header: {
                    Text("How much sleep do you want?")
                        .font(.subheadline)
                }
                .onChange(of: sleepAmount) {newValue in
                    resetSleepTimeDisplay()
                }

                Section {
                    HStack {
                        Text("I'll wake up at")
                        DatePicker("Please enter a time", selection: $wakeUp, displayedComponents: .hourAndMinute)
                            .labelsHidden()
                        .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .trailing)
                    }

                } header: {
                    Text("When do you want to wake up?")
                        .font(.subheadline)
                }
                .onChange(of: wakeUp) {newValue in
                    resetSleepTimeDisplay()
                }

                Button("Calculate", action: calculateBedtime)

                Text(sleepTimeDisplay == "" ? "Tap Calculate to get your new bedtime." : "Your ideal bedtime is \(sleepTimeDisplay)")

                Button("Reset") {
                    resetForm()
                    resetSleepTimeDisplay()
                }
            }
            .navigationTitle("BetterRest")
        }
    }

    func calculateBedtime() {
        do {
            let config = MLModelConfiguration()
            let model = try SleepCalculator(configuration: config)

            let sleepTimeComponent = Calendar.current.dateComponents([.hour, .minute], from: wakeUp)

            let hour = (sleepTimeComponent.hour ?? 0) * 3600 // in seconds
            let minute = sleepTimeComponent.minute ?? 0 * 60 // in seconds

            let prediction = try model.prediction(wake: Double(hour + minute), estimatedSleep: sleepAmount, coffee: Double(coffeeAmount))

            let sleepTime = wakeUp - prediction.actualSleep

            sleepTimeDisplay = "\(sleepTime.formatted(date: .omitted, time: .shortened))"

        } catch {
            sleepTimeDisplay = "Sorry, there was an error calculating your bedtime."
        }

    }

    func resetForm() {
        sleepAmount = 8
        coffeeAmount = 0
        wakeUp = ContentView.defaultWakeTime
    }

    func resetSleepTimeDisplay() {
        sleepTimeDisplay = ""
    }
}

   

Save 50% in my Black Friday sale.

SAVE 50% To celebrate WWDC22, all our books and bundles are half price, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

Save 50% on all our books and bundles!

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.