How to add round tip on trim circle in SwiftUI

I want make progress bar (circle) with big round tip, that will follow to progress. Can you please suggest me, Is there any standard way to do it? Or it requires additional circle and some calculation to understand position?

struct Loader: View {
    
    var percent: CGFloat = 0
    var colors: [Color] = [
        Color(red: 0.949, green: 0.9098, blue: 0.8706),
        Color(red: 0.9569, green: 0.5882, blue: 0.2196)
    ]
     
    var body: some View {
        ZStack{
            Circle()
                .fill(Color.white)
                .frame(width: 300, height: 300, alignment: .center)
                .overlay(
                    Circle()
                        .trim(from: 0, to: percent * 0.01)
                        .stroke(style: StrokeStyle(lineWidth: 22, lineCap: .butt, lineJoin: .miter, miterLimit: 10))
                        .fill(AngularGradient(gradient: .init(colors: colors), center: .center, startAngle: .zero, endAngle: .init(degrees: 360)))
                        .rotationEffect(.degrees(-90))
                ).animation(.spring(response: 1.0, dampingFraction: 1.0, blendDuration: 1.0))
            
            Text(String(format: "%.1f", percent) + " %").font(.system(size: 20)).fontWeight(.heavy)
        }
    }
}

What i want to make:

enter image description here

What i have done already:

enter image description here


Here's potential solution. I added an overlay on top of the Loader, I made it's height the full size of the big Circle, and then simply rotated the overlay with the completion. This way they animate at the same time.

import SwiftUI

struct CircleView: View {
    
    @State var percent: CGFloat = 0
    
    var body: some View {
        Loader(percent: $percent)
            .onAppear {
                DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
                    withAnimation(Animation.linear(duration: 1.0)) {
                        percent = 20
                    }
                }
                DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
                    withAnimation(Animation.linear(duration: 2.0)) {
                        percent = 55
                    }
                }
                DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
                    withAnimation(Animation.linear(duration: 4.0)) {
                        percent = 100
                    }
                }
            }
    }
}

struct CircleView_Previews: PreviewProvider {
    static var previews: some View {
        CircleView()
    }
}


struct Loader: View {
    
    @Binding var percent: CGFloat
    var colors: [Color] = [
        Color(red: 0.949, green: 0.9098, blue: 0.8706),
        Color(red: 0.9569, green: 0.5882, blue: 0.2196)
    ]
    
    let circleHeight: CGFloat = 300
     
    var body: some View {
        let pinHeight = circleHeight * 0.1
        let completion = percent * 0.01
        Circle()
            .trim(from: 0, to: completion)
            .stroke(style: StrokeStyle(lineWidth: 22, lineCap: .butt, lineJoin: .miter, miterLimit: 10))
            .fill(AngularGradient(gradient: .init(colors: colors), center: .center, startAngle: .zero, endAngle: .init(degrees: 360)))
            .rotationEffect(.degrees(-90))
            .frame(width: circleHeight, height: circleHeight)
            .overlay(
                Text(String(format: "%.1f", percent) + " %").font(.system(size: 20)).fontWeight(.heavy)
                    .animation(nil)
            )
            .overlay(
                Circle()
                    .frame(width: pinHeight, height: pinHeight)
                    .offset(y: -pinHeight / 2)
                    .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
                    .rotationEffect(Angle(degrees: 360 * Double(completion)))
            )
    }
}