You are on page 1of 3

x

import SwiftUI
struct HorizontalProgressBar: View {
var currentMileStone : Int
@State var totalMileStones : Int
var milestoneTitle : String
var isAttentionNeeded : Bool
var mileStoneSubtitle : String = ""
let currentMileStoneSize : CGFloat = 26
let normalMilestoneSize : CGFloat = 16
let milestoneStrokewidth : CGFloat = 2
var maxHeightValue : CGFloat = 0.0
var body: some View {
GeometryReader { geo in
VStack (spacing: 5) {
let progressWidth : CGFloat = geo.size.width
let milestoneSpacing = calculateMileStoneSpacing(totalSteps: totalMileStones,
progressWidth: progressWidth)
let titleTextSpacing = calculateTextSpacing(Spacing: milestoneSpacing, isSubtitle:
false)
let subTitleTextSpacing = calculateTextSpacing(Spacing: milestoneSpacing,
isSubtitle: true)
let textAlignment = calculateAlignment(current: currentMileStone, Total:
totalMileStones)
HStack( spacing : titleTextSpacing){
ForEach(0 ..< totalMileStones) { index in
ZStack{
if (index == currentMileStone && isAttentionNeeded ){
Image("attention")
.accessibilityIdentifier("attention_image")
.frame(width: currentMileStoneSize-milestoneStrokewidth, height:
currentMileStoneSize-milestoneStrokewidth)
}
}
}
}
.frame(minWidth:progressWidth + normalMilestoneSize , alignment:textAlignment)
ZStack{
HStack(spacing: 0) {
ForEach(0 ..< totalMileStones-1) { index in
Rectangle()
.foregroundColor(index <= currentMileStone-1 ? .tealInteractiveColor :
.secondaryInteractiveColor)
}
}
.frame(width: progressWidth , height: 3 )
HStack(spacing : milestoneSpacing){
ForEach(0 ..< totalMileStones) { index in
Circle()
.stroke(Color.secondaryInteractiveColor, lineWidth: index <= currentMileStone ? 0
: milestoneStrokewidth)
.background(Circle().fill(index <= currentMileStone ? Color.tealInteractiveColor :
.mainBackgroundColor))
.frame(width: index == currentMileStone ? currentMileStoneSize :
normalMilestoneSize,
height: index == currentMileStone ? currentMileStoneSize : normalMilestoneSize)
.overlay( Image ("check").hidden(index == currentMileStone && currentMileStone ==
(totalMileStones-1) ? false : true).frame(width: 11, height: 8.8))
.overlay(Image (systemName: "circle.fill").hidden(index == currentMileStone
&& currentMileStone != (totalMileStones-1) ? false : true) )
.foregroundColor(.mainBackgroundColor)
}
}
}
VStack (spacing: 0){
HStack(spacing:titleTextSpacing){
ForEach(0 ..< totalMileStones) { index in
Text (index == currentMileStone ? "\(milestoneTitle)" : "")
.font(AppFont.Roboto_Medium.of(size: 12))
.fixedSize()
}
}
.frame(maxWidth:progressWidth + normalMilestoneSize , alignment: textAlignment)
HStack(spacing : subTitleTextSpacing){
ForEach(0 ..< totalMileStones) { index in
Text( index == currentMileStone && isAttentionNeeded ? "\(mileStoneSubtitle)" :
"")
.font(AppFont.Roboto_Medium.of(size: 12))
.foregroundColor(.secondaryTextColor)
.frame(maxWidth: (totalMileStones - currentMileStone) == 1 || currentMileStone ==
0 ? progressWidth
: milestoneSpacing * 3 , minHeight : normalMilestoneSize , maxHeight:
normalMilestoneSize * 3,alignment:.top)
.fixedSize(horizontal: true, vertical: false)
.multilineTextAlignment(.center)
.accessibilityIdentifier(mileStoneSubtitle + "_text")
}
}
.frame(maxWidth:progressWidth + normalMilestoneSize , alignment: textAlignment)
}
.frame(maxWidth:progressWidth + normalMilestoneSize)
}
.frame(maxWidth:geo.size.width,maxHeight: geo.size.height)
}
.frame(maxHeight: maxHeightValue)
.padding()
}
mutating func getMaxHeight(geo : GeometryProxy){
self.maxHeightValue = geo.size.height
}
func calculateMileStoneSpacing (totalSteps : Int , progressWidth : CGFloat) ->
CGFloat {
let spacing = progressWidth / (CGFloat(totalSteps)-1)
return (spacing-normalMilestoneSize-milestoneStrokewidth)
}
func calculateTextSpacing(Spacing : CGFloat, isSubtitle : Bool) -> CGFloat {
let titleTextSpacing = Spacing + ( (totalMileStones - currentMileStone) == 1 ||
currentMileStone == 0 ? 0 : normalMilestoneSize)
let subTitleTextSpacing = Spacing + normalMilestoneSize
return (isSubtitle ? subTitleTextSpacing : titleTextSpacing)
}
func calculateAlignment (current: Int , Total: Int) -> Alignment {
if (current == 0 && Total == 1){
return Alignment.center
}
else if (current == 0){
return Alignment.leading
}
else if (current == Total-1){
return Alignment.trailing
}
return Alignment.center
}
struct HorizontalProgressBar_Previews: PreviewProvider {
static var previews: some View {
*if #available(iOS 15.0, ) {
HorizontalProgressBar(currentMileStone: 0, totalMileStones:6, milestoneTitle:
"Something here", isAttentionNeeded: true)
.previewInterfaceOrientation(.portrait)
.previewDevice("iPhone 13 Pro Max")
} else {
// Fallback on earlier versions
}
}
}
}

You might also like