iOS/Sources/Shared/DesignSystem/Components/HAProgressView.swift

87 lines
2.6 KiB
Swift

import SwiftUI
final class HAProgressViewModel: ObservableObject {
@Published var isAnimating = false
@Published var trimEnd: CGFloat = 0.1
}
public struct HAProgressView: View {
public enum Style {
case small
case medium
case large
case extraLarge
var size: CGSize {
switch self {
case .small:
return CGSize(width: 24, height: 24)
case .medium:
return CGSize(width: 28, height: 28)
case .large:
return CGSize(width: 48, height: 48)
case .extraLarge:
return CGSize(width: 68, height: 68)
}
}
var lineWidth: CGFloat {
4
}
}
public enum ColorType {
/// When display in light background
case `default`
/// When displayed on accented background such as haPrimary
case light
}
@StateObject private var viewModel = HAProgressViewModel()
let style: Style
let colorType: ColorType
public init(style: Style = .medium, colorType: ColorType = .default) {
self.style = style
self.colorType = colorType
}
public var body: some View {
ZStack {
Circle()
.stroke(
colorType == .default ? Color.track : Color.white,
style: StrokeStyle(lineWidth: style.lineWidth)
)
.frame(width: style.size.width, height: style.size.height)
Circle()
.trim(from: 0, to: viewModel.trimEnd)
.stroke(
Color.haPrimary.opacity(colorType == .default ? 1 : 0.5),
style: StrokeStyle(lineWidth: style.lineWidth, lineCap: .round)
)
.frame(width: style.size.width, height: style.size.height)
.rotationEffect(Angle(degrees: viewModel.isAnimating ? 360 : 0))
.animation(
Animation.linear(duration: 1).repeatForever(autoreverses: false),
value: viewModel.isAnimating
)
.onAppear {
viewModel.isAnimating = true
withAnimation(.easeInOut(duration: 1.75).repeatForever(autoreverses: true)) {
viewModel.trimEnd = 0.7
}
}
}
}
}
#Preview {
HStack(spacing: DesignSystem.Spaces.two) {
HAProgressView(style: .small)
HAProgressView(style: .medium)
HAProgressView(style: .large)
HAProgressView(style: .extraLarge)
}
}