UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

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 = ""
    }
}

1      

Hacking with Swift is sponsored by Essential Developer

SPONSORED Join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer! Hurry up because it'll be available only until April 28th.

Click to save your free spot now

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

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

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.