Reputation: 55
I've made a Circular countdowntimer, it works, but is have a little issue.
Instead of going from a orange circle and countdown to .. a grey circle, is always a little portion of orange in the circle, and when the estimated delivery time is achieved , is all grey, as expected.
This is how it stays : Picture 1
This is how I'm expecting to be : Picture 2
I'll Show the code bellow and I will explain the important things.
This is WaitingOrderView.
struct WaitingOrderView: View {
@State private var timer: AnyCancellable?
@EnvironmentObject var syncViewModel : SyncViewModel
var body: some View {
ZStack {
if syncViewModel._order.id == 0 && syncViewModel._order.status == 0 {
CartView()
}
else if syncViewModel._order.status == syncViewModel.statusList.first(where: { status in
status.key == StatusKey.accepted.rawValue
})?.id
{
OrderConfirmedView()
}
}
.onAppear() {
startFetchStatus()
}
}
func startFetchStatus() {
timer = Timer.publish(every: 20, on: .main, in: .common)
.autoconnect()
.sink { _ in
syncViewModel.fetchOrder(id: syncViewModel._order.id)
}
}
}
The function startFetchStatus() gets the data from the backend every 20 seconds, and it looks like this, for example: Fetch response
This is the CircularTimer View :
let timer = Timer
.publish(every: 1, on: .main, in: .common)
.autoconnect()
@available(iOS 15, *)
struct CircularTimer: View {
var orderDate : Date
var orderDeliveryDate : Date
@State var onTick: CGFloat = 1
let date = Date()
var body: some View {
VStack(spacing : 0){
Image("clock_button")
ZStack{
Circle()
.fill(Color.clear)
.frame(width: 250, height: 250)
.overlay(
Circle().stroke(Color.gray.opacity(22/100), lineWidth: 5)
)
Circle()
.fill(Color.clear)
.frame(width: 250, height: 250)
.overlay(
Circle().trim(from:0, to: onTick)
.stroke(
style: StrokeStyle(
lineWidth: 5,
lineCap: .round ,
lineJoin:.round
)
)
.foregroundColor(
( completed() ? Color.orange: Color.orange)
).animation(
.easeInOut(duration: 0.2)
)
)
.rotationEffect(Angle(degrees: 270.0))
Image("indicator_ellipse")
.resizable()
.frame(width: 230, height: 230)
}
}.onReceive(timer) { time in
progress(time: Int(time.timeIntervalSince1970))
}
}
func completed() -> Bool {
return onTick == 1
}
func progress(time: Int) {
let minutesOrderDeliveryDate = Int(orderDeliveryDate.timeIntervalSince1970)
let minutesOrderDate = Int(orderDate.timeIntervalSince1970)
let minutesCurrentDate = time
let totalMinutes = minutesOrderDeliveryDate - minutesOrderDate
let remainingMinutes = minutesOrderDeliveryDate - minutesCurrentDate
onTick = CGFloat(remainingMinutes) / CGFloat(totalMinutes) * 0.01
print(onTick)
}
func dateFormatTime(date : String) -> Date {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
dateFormatter.timeZone = .current
return dateFormatter.date(from: date) ?? Date.now
}
}
This is OrderConfirmedView :
struct OrderConfirmedVieww: View {
@EnvironmentObject var syncViewModel : SyncViewModel
@State var nowDate: Date = Date()
var body: some View {
VStack {
Spacer()
Text(Texts.orderConfirmedText1)
.font(.title)
.fontWeight(.semibold)
.foregroundColor(.colorGrayDark)
.multilineTextAlignment(.center)
.lineLimit(3)
.padding(40)
CircularTimer(orderDate: dateFormatTime(date: syncViewModel._order.date ?? ""), orderDeliveryDate: dateFormatTime(date: syncViewModel._order.deliveryDate ?? ""))
.padding()
// Spacer()
Text(Texts.orderOraLivrareText)
.font(.headline)
.fontWeight(.thin)
.padding(.bottom)
Text(dateFormatTime(date: syncViewModel._order.deliveryDate ?? ""), style: .time)
.font(.title2)
.fontWeight(.bold)
Spacer()
Spacer()
Button {
} label: {
Text(Texts.orderButtonText)
.font(.headline)
.foregroundColor(.white)
.frame(height: 55)
.frame(maxWidth: .infinity)
.background(Color.onboardingColor)
.cornerRadius(20)
}
.padding()
}
}
func dateFormatTime(date : String) -> Date {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
dateFormatter.timeZone = .current
return dateFormatter.date(from: date) ?? Date.now
}
}
Upvotes: 2
Views: 214
Reputation: 55
Fixed the issue. I just needed to delete * 0.01 from
onTick = CGFloat(remainingMinutes) / CGFloat(totalMinutes) * 0.01
Thanks everyone for all the replies. !
Upvotes: 1