I want to display a countdown timer, which will take the current hour, minute, second, then count down to 00:00:00. Currently I have the current date displayed, But it's adding up.
My expectation: It will count down and when it gets back to 00:00:00 it will stop.
Below is all my code
struct TimerView: View {
@State var timeRemaining = 24*60*60
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
var body: some View {
HStack(spacing: 12) {
timerStringView(timer: "\(hourString(timer: timeRemaining))")
timerStringView(timer: "\(minutesString(timer: timeRemaining))")
timerStringView(timer: "\(secondsString(timer: timeRemaining))")
}
.frame(width: 300, height: 34)
.background(Color.gray)
.onReceive(timer) { _ in
if timeRemaining > 0 {
timeRemaining -= 1
} else {
timer.upstream.connect().cancel()
}
}
}
func timerStringView(timer: String) -> some View {
Text(timer)
.font(.system(size: 18, weight: .bold))
.foregroundColor(.black)
.background(Color.white)
.cornerRadius(6)
}
func hourString(timer: Int) -> String {
let date = Date()
let calendar = Calendar.current
let hours = calendar.component(.hour, from: date)
return String(format: "%02i", hours)
}
func minutesString(timer: Int) -> String {
let date = Date()
let calendar = Calendar.current
let minutes = calendar.component(.minute, from: date)
return String(format: "%02i", minutes)
}
func secondsString(timer: Int) -> String {
let date = Date()
let calendar = Calendar.current
let second = calendar.component(.second, from: date)
return String(format: "%02i", second)
}
}
Using on appear get the hours minutes and seconds all added up into seconds to set the @State. Note: taking the hours and multiplying by 3600 was bugging out, so I used an extra variable to fix it on my machine.
struct ContentView: View {
@State var timeRemaining:Int = 0
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
var body: some View {
HStack(spacing: 12) {
timerStringView(timer: "\(hourString(timer: timeRemaining))")
timerStringView(timer: "\(minutesString(timer: timeRemaining))")
timerStringView(timer: "\(secondsString(timer: timeRemaining))")
}
.frame(width: 300, height: 34)
.background(Color.gray)
.onReceive(timer) { _ in
if timeRemaining > 0 {
timeRemaining -= 1
} else {
timer.upstream.connect().cancel()
}
}
// Get the time
.onAppear() {
setTimer()
}
}
func timerStringView(timer: String) -> some View {
Text(timer)
.font(.system(size: 18, weight: .bold))
.foregroundColor(.black)
.background(Color.white)
.cornerRadius(6)
}
func hourString(timer: Int) -> String {
let date = Date()
let calendar = Calendar.current
let hours = calendar.component(.hour, from: date)
return String(format: "%02i", hours)
}
func minutesString(timer: Int) -> String {
let date = Date()
let calendar = Calendar.current
let minutes = calendar.component(.minute, from: date)
return String(format: "%02i", minutes)
}
func secondsString(timer: Int) -> String {
let date = Date()
let calendar = Calendar.current
let second = calendar.component(.second, from: date)
return String(format: "%02i", second)
}
func setTimer() {
let date = Date()
let calendar = Calendar.current
let hours = calendar.component(.hour, from: date)
let hourSeconds = hours * 3600
let minuteSeconds = calendar.component(.minute, from: date) * 60
let seconds = calendar.component(.second, from: date)
timeRemaining = hourSeconds
timeRemaining += minuteSeconds
timeRemaining += seconds
}
}