0

I implemented this custom countdown DatePicker that I found on stack overflow here's the link but it has a bug where if I change the picker from something different then 1 minute the first time I start the timer it'll still set the timer to one minute, but if I change it after that first time it works fine.

import SwiftUI

struct DurationPicker: UIViewRepresentable {
    @Binding var duration: Double

    func makeUIView(context: Context) -> UIDatePicker {
        let datePicker = UIDatePicker()
        datePicker.datePickerMode = .countDownTimer
        datePicker.addTarget(context.coordinator, action: #selector(Coordinator.updateDuration), for: .valueChanged)
        return datePicker
    }

    func updateUIView(_ datePicker: UIDatePicker, context: Context) {
        datePicker.countDownDuration = duration
        
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    class Coordinator: NSObject {
        let parent: DurationPicker

        init(_ parent: DurationPicker) {
            self.parent = parent
        }

        @objc func updateDuration(datePicker: UIDatePicker) {
            parent.duration = datePicker.countDownDuration
        }
    }
}

struct ContentView: View {
    
    @State var duration = 60.0
    @State var timeRemaining = 60.0
    @State private var isActive = false
    var timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
    
    
    var body: some View {
        VStack {
            Text("\(timeRemaining)")
                .bold()
                .font(.largeTitle)
            DurationPicker(duration: $duration)
            HStack {
                Button("Cancel") {
                    isActive = false
                }
                .padding()
                Button("Start") {
                    self.timeRemaining = duration
                    isActive = true
                }
                .padding()
            }
        }
        .onReceive(timer) { time in
            guard self.isActive else { return }
            
            if self.timeRemaining > 0 {
                self.timeRemaining -= 1
            }
        }
        .onReceive(NotificationCenter.default.publisher(for: UIApplication.willResignActiveNotification)) { _ in
            self.isActive = false
        }
        .onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in
            self.isActive = true
        }

    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

I'm not quite sure what to set meditateTime as, I thought @State would automatically change it if it did change so I'm not quite sure what's going on.

1 Answers1

0

Seems like the bug is in SwiftUI itself, here's my workaround

import SwiftUI

struct CountDownPicker: View {
    
    var hours = Array(0...23)
    var min = Array(0...59)
    
    @Binding var selectedHours: Int
    @Binding var selectedMins: Int
    
    var body: some View {
        GeometryReader { geometry in
            HStack {
                Picker(selection: $selectedHours, label: Text("hrs")) {
                    ForEach(0..<self.hours.count) {
                        Text("\(self.hours[$0]) hrs")
                            .bold()
                    }
                }
                .frame(maxWidth: geometry.size.width / 2)
                .clipped()
                .pickerStyle(.wheel)
                
                Picker(selection: self.$selectedMins, label: Text("mins")) {
                    ForEach(0..<self.min.count) {
                        Text("\(self.min[$0]) mins")
                            .bold()
                    }
                }
                .frame(maxWidth: geometry.size.width / 2)
                .clipped()
                .pickerStyle(.wheel)
            }
        }
        .offset(y: -100)
        .padding()
        .frame(width: .infinity, height: 140, alignment: .center)
        
    }
}

I'm open to any suggestions