People here in the forums have been so helpful, I thought I would ask another question. I am designing an App where I need a timer to be persistent. I wanted to show the user seconds, days, weeks, months, etc, since the start date.
I have the timer running off of the view. Trying to figure out how to make the time persistent. Right now... the timer runs well. Every time the App is started, it starts at 0 sec, and starts counting away. I was wanting the App to remember what time it was, and add to it. So that if it was 1 minute ago when the App was closed. When the App is re-opened it basically adds 1 minute to the counter and keeps going, I have used AppData and UserDefaults for other things in this App, but I could not quite see how to do this here. I was thinking I would have to save to defaults a value inside of the "Timer" service, but there might be a better way. Thanks for taking a look...
This is my separate file that is the "Timer" Service
import Foundation
import SwiftUI
import UIKit
class TimerService: NSObject, ObservableObject {
@Published var timeremaining: String = ""
private var timer: Timer!
let formatPicker: [String] = ["Seconds","Minutes","Hours","Days", "Weeks", "Months"]
let calendar = Calendar.current
let setdate: Date = Calendar.current.date(byAdding: .second, value:0, to: Date()) ?? Date ()
private func updateTimeRemaining() {
let remaining = Calendar.current.dateComponents([.year, .month, .weekOfYear, .hour, .minute, .second], from: setdate, to: Date())
let year = remaining.year ?? 0
let month = remaining.month ?? 0
let week = remaining.weekOfYear ?? 0
let day = remaining.day ?? 0
let hour = remaining.hour ?? 0
let minute = remaining.minute ?? 0
let second = remaining.second ?? 0
timeremaining = "Whisky has been aging for \(year) Years \(month) Months \(week) Weeks \(day) Days \(hour) Hours \(minute) Minutes \(second) Seconds"
}
override init() {
super.init()
timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
self.updateTimeRemaining()
}
}
}
This is my main view where the timer will be located:
import SwiftUI
import UIKit
import Foundation
struct ContentView: View {
@EnvironmentObject var bluetoothService: BluetoothService
@EnvironmentObject var timerService: TimerService
@Binding var whiskyname: String
@Binding var barrelabv: String
@Binding var imageSelected: UIImage
@Binding var weightlownum: Float32
@Binding var weighthinum: Float32
@Binding var screenDisable: Bool
@AppStorage("pourabv") var pourabv: String = "ABV"
@State var TempValue: String = ""
@State var link = UIImage()
@State var timeinterval = Date()
@State var percentFilled: Float = 0
@State var timeFormat: String = "Days"
@State var timeremaining: String = ""
var body: some View {
NavigationStack{
NavigationLink {
SetupView()
} label: {
}
VStack{
Text(self.whiskyname)
.frame(width: 300, height:1)
.font(.system(size: 24))
}
VStack{
Image(uiImage: imageSelected)
.resizable()
.font(.system(size: 40))
.aspectRatio(contentMode: .fill)
.frame(width:245, height:245)
.font(.system(size: 24))
.background(Color.blue.opacity(0.4))
.cornerRadius(15)
.padding(.vertical, 10)
}
VStack(alignment: .leading){
HStack{
if bluetoothService.Connected == true{
let link = Image(systemName: "link.circle.fill").foregroundColor(.blue)
link
Text("Bluetooth Connected")
.font(.footnote)
} else {
let link = Image(systemName: "link.circle.fill").foregroundColor(.red)
link
Text("Bluetooth Disconnected")
.font(.footnote)
}
}
HStack{
TextField("", text: $pourabv)
.padding(20)
.font(.system(size: 30))
.frame(width: 110, height:35)
.font(.system(size: 24))
.background(Color.blue.opacity(0.4))
.cornerRadius(15)
Text("% Pour ABV")
.font(.system(size: 30))
.frame(width: 200, height:35)
.font(.system(size: 24))
.cornerRadius(15)
}
HStack{
Text("\(bluetoothService.TempValue, specifier: "%.1f")°")
.font(.system(size: 30))
.frame(width: 110, height:35)
.font(.system(size: 24))
.background(Color.blue.opacity(0.4))
.cornerRadius(15)
Text("Temperature F")
.font(.system(size: 30))
.frame(width: 200, height:35)
.font(.system(size: 24))
.cornerRadius(15)
}
HStack{
Text("\(bluetoothService.HumidValue, specifier: "%.1f") %")
.font(.system(size: 30))
.frame(width: 110, height:35)
.font(.system(size: 24))
.background(Color.blue.opacity(0.4))
.cornerRadius(15)
Text("Humidity")
.font(.system(size: 30))
.frame(width: 200, height:35)
.font(.system(size: 24))
.cornerRadius(15)
}
HStack{
let percent = (100 / (weighthinum - weightlownum)) * (bluetoothService.WeightValue - weightlownum)
Text("\(percent, specifier: "%.1f") %")
.font(.system(size: 30))
.frame(width: 110, height:35)
.font(.system(size: 24))
.background(Color.blue.opacity(0.4))
.cornerRadius(15)
Text("Barrel Filled")
.font(.system(size: 30))
.frame(width: 200, height:35)
.font(.system(size: 24))
.cornerRadius(15)
}
HStack{
let myString = (barrelabv)
let floatbarrelabv = (myString as NSString).floatValue
let myString2 = (pourabv)
let floatpourabv = (myString2 as NSString).floatValue
let glasses = (((((1.8 * floatbarrelabv * (100 / (weighthinum - weightlownum)) * (bluetoothService.WeightValue - weightlownum))) / floatpourabv) * 3785.41) / 40) / 100
Image("whisky glass")
.resizable()
.frame(width: 50, height:50)
Text("\(glasses, specifier: "%.0f")")
.font(.system(size: 30))
.padding(20)
.frame(width: 105, height:35)
.font(.system(size: 24))
.background(Color.blue.opacity(0.4))
.cornerRadius(15)
Text("Glasses remaining")
.font(.system(size: 25))
.frame(width: 200, height:35)
.font(.system(size: 24))
.cornerRadius(15)
}
HStack{
let myString = (barrelabv)
let floatbarrelabv = (myString as NSString).floatValue
let myString2 = (pourabv)
let floatpourabv = (myString2 as NSString).floatValue
let bottles = (((((1.8 * floatbarrelabv * (100 / (weighthinum - weightlownum)) * (bluetoothService.WeightValue - weightlownum))) / floatpourabv) * 3785.41) / 750) / 100
Image("bottle")
.resizable()
.frame(width: 50, height:50)
Text("\(bottles, specifier: "%.1f")")
.font(.system(size: 30))
.padding(20)
.frame(width: 105, height:35)
.font(.system(size: 24))
.background(Color.blue.opacity(0.4))
.cornerRadius(15)
Text("Bottles remaining")
.font(.system(size: 25))
.frame(width: 200, height:40)
.font(.system(size: 24))
.cornerRadius(15)
}
Text(timerService.timeremaining)
} //Main VStack ends here
Spacer()
} //Navigation Stack
} // body view
} // Content View
struct ContentView_Previews: PreviewProvider {
@State static var whiskyname: String = ""
@State static var barrelabv: String = ""
@State static var weighthinum: Float32 = 0
@State static var weightlownum: Float32 = 0
@State static var imageSelected = UIImage()
@State static var screenDisable: Bool = false
@State var link = UIImage()
@State static var bottles: Float32 = 0
static var previews: some View{
ContentView(whiskyname: $whiskyname, barrelabv: $barrelabv, imageSelected: $imageSelected, weightlownum: $weightlownum, weighthinum: $weighthinum, screenDisable: $screenDisable)
.environmentObject(BluetoothService())
.environmentObject(TimerService())
}
}
Currently I am just displaying the time with the following line in the code above.
Text(timerService.timeremaining)