From 5ca7b7dbe7c5aad26281771b25d3a16922c4d5d2 Mon Sep 17 00:00:00 2001 From: Mikhail Date: Wed, 2 Apr 2025 12:33:45 +0200 Subject: [PATCH 1/6] remove stroked style; add arc shape in the circular progress --- .../CircularProgressPreview.swift | 9 +- .../Models/CircularProgressShape.swift | 9 ++ .../Models/CircularProgressStyle.swift | 9 -- .../Models/CircularProgressVM.swift | 126 +++++------------- .../CircularProgress/SUCircularProgress.swift | 85 +++--------- .../CircularProgress/UKCircularProgress.swift | 70 ++-------- 6 files changed, 79 insertions(+), 229 deletions(-) create mode 100644 Sources/ComponentsKit/Components/CircularProgress/Models/CircularProgressShape.swift delete mode 100644 Sources/ComponentsKit/Components/CircularProgress/Models/CircularProgressStyle.swift diff --git a/Examples/DemosApp/DemosApp/ComponentsPreview/PreviewPages/CircularProgressPreview.swift b/Examples/DemosApp/DemosApp/ComponentsPreview/PreviewPages/CircularProgressPreview.swift index 40c9edee..39734ec7 100644 --- a/Examples/DemosApp/DemosApp/ComponentsPreview/PreviewPages/CircularProgressPreview.swift +++ b/Examples/DemosApp/DemosApp/ComponentsPreview/PreviewPages/CircularProgressPreview.swift @@ -7,6 +7,7 @@ struct CircularProgressPreview: View { @State private var currentValue: CGFloat = Self.initialValue private let circularProgress = UKCircularProgress( + initialValue: Self.initialValue, model: Self.initialModel ) @@ -43,9 +44,9 @@ struct CircularProgressPreview: View { Text("8").tag(Optional.some(8)) } SizePicker(selection: self.$model.size) - Picker("Style", selection: self.$model.style) { - Text("Light").tag(CircularProgressVM.Style.light) - Text("Striped").tag(CircularProgressVM.Style.striped) + Picker("Shape", selection: self.$model.shape) { + Text("Circle").tag(CircularProgressVM.Shape.circle) + Text("Arc").tag(CircularProgressVM.Shape.arc) } } .onReceive(self.timer) { _ in @@ -71,7 +72,7 @@ struct CircularProgressPreview: View { private static var initialModel = CircularProgressVM { $0.label = "0%" - $0.style = .light + $0.shape = .arc } } diff --git a/Sources/ComponentsKit/Components/CircularProgress/Models/CircularProgressShape.swift b/Sources/ComponentsKit/Components/CircularProgress/Models/CircularProgressShape.swift new file mode 100644 index 00000000..586e7872 --- /dev/null +++ b/Sources/ComponentsKit/Components/CircularProgress/Models/CircularProgressShape.swift @@ -0,0 +1,9 @@ +import Foundation + +extension CircularProgressVM { + /// Defines the shapes for the circular progress component. + public enum Shape { + case circle + case arc + } +} diff --git a/Sources/ComponentsKit/Components/CircularProgress/Models/CircularProgressStyle.swift b/Sources/ComponentsKit/Components/CircularProgress/Models/CircularProgressStyle.swift deleted file mode 100644 index 3c0588d7..00000000 --- a/Sources/ComponentsKit/Components/CircularProgress/Models/CircularProgressStyle.swift +++ /dev/null @@ -1,9 +0,0 @@ -import Foundation - -extension CircularProgressVM { - public enum Style { - /// Defines the visual styles for the circular progress component. - case light - case striped - } -} diff --git a/Sources/ComponentsKit/Components/CircularProgress/Models/CircularProgressVM.swift b/Sources/ComponentsKit/Components/CircularProgress/Models/CircularProgressVM.swift index a032d056..e145e5e5 100644 --- a/Sources/ComponentsKit/Components/CircularProgress/Models/CircularProgressVM.swift +++ b/Sources/ComponentsKit/Components/CircularProgress/Models/CircularProgressVM.swift @@ -7,34 +7,34 @@ public struct CircularProgressVM: ComponentVM { /// Defaults to `.accent`. public var color: ComponentColor = .accent - /// The style of the circular progress indicator. - /// - /// Defaults to `.light`. - public var style: Style = .light + /// The font used for the circular progress label text. + public var font: UniversalFont? - /// The size of the circular progress. - /// - /// Defaults to `.medium`. - public var size: ComponentSize = .medium + /// An optional label to display inside the circular progress. + public var label: String? - /// The minimum value of the circular progress. - /// - /// Defaults to `0`. - public var minValue: CGFloat = 0 + /// The width of the circular progress stroke. + public var lineWidth: CGFloat? /// The maximum value of the circular progress. /// /// Defaults to `100`. public var maxValue: CGFloat = 100 - /// The width of the circular progress stroke. - public var lineWidth: CGFloat? + /// The minimum value of the circular progress. + /// + /// Defaults to `0`. + public var minValue: CGFloat = 0 - /// An optional label to display inside the circular progress. - public var label: String? + /// The shape of the circular progress indicator. + /// + /// Defaults to `.circle`. + public var shape: Shape = .circle - /// The font used for the circular progress label text. - public var font: UniversalFont? + /// The size of the circular progress. + /// + /// Defaults to `.medium`. + public var size: ComponentSize = .medium /// Initializes a new instance of `CircularProgressVM` with default values. public init() {} @@ -68,6 +68,22 @@ extension CircularProgressVM { y: self.preferredSize.height / 2 ) } + var startAngle: CGFloat { + switch self.shape { + case .circle: + return -0.5 * .pi + case .arc: + return 0.75 * .pi + } + } + var endAngle: CGFloat { + switch self.shape { + case .circle: + return 1.5 * .pi + case .arc: + return 2.25 * .pi + } + } var titleFont: UniversalFont { if let font { return font @@ -81,44 +97,6 @@ extension CircularProgressVM { return .lgCaption } } - var stripeWidth: CGFloat { - return 0.5 - } - private func stripesCGPath(in rect: CGRect) -> CGMutablePath { - let stripeSpacing: CGFloat = 3 - let stripeAngle: Angle = .degrees(135) - - let path = CGMutablePath() - let step = stripeWidth + stripeSpacing - let radians = stripeAngle.radians - - let dx: CGFloat = rect.height * tan(radians) - for x in stride(from: 0, through: rect.width + rect.height, by: step) { - let topLeft = CGPoint(x: x, y: 0) - let bottomRight = CGPoint(x: x + dx, y: rect.height) - - path.move(to: topLeft) - path.addLine(to: bottomRight) - path.closeSubpath() - } - return path - } -} - -extension CircularProgressVM { - func gap(for normalized: CGFloat) -> CGFloat { - return normalized > 0 ? 0.05 : 0 - } - - func stripedArcStart(for normalized: CGFloat) -> CGFloat { - let gapValue = self.gap(for: normalized) - return max(0, min(1, normalized + gapValue)) - } - - func stripedArcEnd(for normalized: CGFloat) -> CGFloat { - let gapValue = self.gap(for: normalized) - return 1 - gapValue - } } extension CircularProgressVM { @@ -133,33 +111,6 @@ extension CircularProgressVM { // MARK: - UIKit Helpers extension CircularProgressVM { - var isStripesLayerHidden: Bool { - switch self.style { - case .light: - return true - case .striped: - return false - } - } - var isBackgroundLayerHidden: Bool { - switch self.style { - case .light: - return false - case .striped: - return true - } - } - func stripesBezierPath(in rect: CGRect) -> UIBezierPath { - let center = CGPoint(x: rect.midX, y: rect.midY) - let path = UIBezierPath(cgPath: self.stripesCGPath(in: rect)) - var transform = CGAffineTransform.identity - transform = transform - .translatedBy(x: center.x, y: center.y) - .rotated(by: -CGFloat.pi / 2) - .translatedBy(x: -center.x, y: -center.y) - path.apply(transform) - return path - } func shouldInvalidateIntrinsicContentSize(_ oldModel: Self) -> Bool { return self.preferredSize != oldModel.preferredSize } @@ -170,12 +121,7 @@ extension CircularProgressVM { return self.minValue != oldModel.minValue || self.maxValue != oldModel.maxValue } -} - -// MARK: - SwiftUI Helpers - -extension CircularProgressVM { - func stripesPath(in rect: CGRect) -> Path { - Path(self.stripesCGPath(in: rect)) + func shouldUpdateShape(_ oldModel: Self) -> Bool { + return self.shape != oldModel.shape } } diff --git a/Sources/ComponentsKit/Components/CircularProgress/SUCircularProgress.swift b/Sources/ComponentsKit/Components/CircularProgress/SUCircularProgress.swift index 0ba970ac..02597c4f 100644 --- a/Sources/ComponentsKit/Components/CircularProgress/SUCircularProgress.swift +++ b/Sources/ComponentsKit/Components/CircularProgress/SUCircularProgress.swift @@ -33,14 +33,22 @@ public struct SUCircularProgress: View { public var body: some View { ZStack { // Background part - Group { - switch self.model.style { - case .light: - self.lightBackground - case .striped: - self.stripedBackground - } + Path { path in + path.addArc( + center: self.model.center, + radius: self.model.radius, + startAngle: .radians(self.model.startAngle), + endAngle: .radians(self.model.endAngle), + clockwise: false + ) } + .stroke( + self.model.color.background.color, + style: StrokeStyle( + lineWidth: self.model.circularLineWidth, + lineCap: .round + ) + ) .frame( width: self.model.preferredSize.width, height: self.model.preferredSize.height @@ -51,8 +59,8 @@ public struct SUCircularProgress: View { path.addArc( center: self.model.center, radius: self.model.radius, - startAngle: .radians(0), - endAngle: .radians(2 * .pi), + startAngle: .radians(self.model.startAngle), + endAngle: .radians(self.model.endAngle), clockwise: false ) } @@ -64,7 +72,6 @@ public struct SUCircularProgress: View { lineCap: .round ) ) - .rotationEffect(.degrees(-90)) .frame( width: self.model.preferredSize.width, height: self.model.preferredSize.height @@ -82,62 +89,4 @@ public struct SUCircularProgress: View { value: self.progress ) } - - // MARK: - Subviews - - var lightBackground: some View { - Path { path in - path.addArc( - center: self.model.center, - radius: self.model.radius, - startAngle: .radians(0), - endAngle: .radians(2 * .pi), - clockwise: false - ) - } - .stroke( - self.model.color.background.color, - lineWidth: self.model.circularLineWidth - ) - } - - var stripedBackground: some View { - StripesShapeCircularProgress(model: self.model) - .stroke( - self.model.color.main.color, - style: StrokeStyle(lineWidth: self.model.stripeWidth) - ) - .mask { - Path { maskPath in - maskPath.addArc( - center: self.model.center, - radius: self.model.radius, - startAngle: .radians(0), - endAngle: .radians(2 * .pi), - clockwise: false - ) - } - .trim( - from: self.model.stripedArcStart(for: self.progress), - to: self.model.stripedArcEnd(for: self.progress) - ) - .stroke( - style: StrokeStyle( - lineWidth: self.model.circularLineWidth, - lineCap: .round - ) - ) - } - .rotationEffect(.degrees(-90)) - } -} - -// MARK: - Helpers - -struct StripesShapeCircularProgress: Shape, @unchecked Sendable { - var model: CircularProgressVM - - func path(in rect: CGRect) -> Path { - self.model.stripesPath(in: rect) - } } diff --git a/Sources/ComponentsKit/Components/CircularProgress/UKCircularProgress.swift b/Sources/ComponentsKit/Components/CircularProgress/UKCircularProgress.swift index e910e623..3edec8c0 100644 --- a/Sources/ComponentsKit/Components/CircularProgress/UKCircularProgress.swift +++ b/Sources/ComponentsKit/Components/CircularProgress/UKCircularProgress.swift @@ -21,18 +21,12 @@ open class UKCircularProgress: UIView, UKComponent { // MARK: - Subviews - /// The shape layer responsible for rendering the background of the circular progress indicator in a light style. + /// The shape layer responsible for rendering the background of the circular progress indicator. public let backgroundLayer = CAShapeLayer() /// The shape layer responsible for rendering the progress arc of the circular progress indicator. public let progressLayer = CAShapeLayer() - /// The shape layer responsible for rendering the striped effect in the circular progress indicator. - public let stripesLayer = CAShapeLayer() - - /// The shape layer that acts as a mask for `stripesLayer`, ensuring it has the intended shape. - public let stripesMaskLayer = CAShapeLayer() - /// The label used to display text inside the circular progress indicator. public let label = UILabel() @@ -69,24 +63,16 @@ open class UKCircularProgress: UIView, UKComponent { private func setup() { self.layer.addSublayer(self.backgroundLayer) - self.layer.addSublayer(self.stripesLayer) self.layer.addSublayer(self.progressLayer) self.addSubview(self.label) - self.stripesLayer.mask = self.stripesMaskLayer - if #available(iOS 17.0, *) { self.registerForTraitChanges([UITraitUserInterfaceStyle.self]) { (view: Self, _: UITraitCollection) in view.handleTraitChanges() } } - let progress = self.model.progress(for: self.currentValue) - self.progressLayer.strokeEnd = progress - if !self.model.isStripesLayerHidden { - self.stripesMaskLayer.strokeStart = self.model.stripedArcStart(for: progress) - self.stripesMaskLayer.strokeEnd = self.model.stripedArcEnd(for: progress) - } + self.progressLayer.strokeEnd = self.model.progress(for: self.currentValue) self.label.text = self.model.label } @@ -96,8 +82,6 @@ open class UKCircularProgress: UIView, UKComponent { Self.Style.backgroundLayer(self.backgroundLayer, model: self.model) Self.Style.progressLayer(self.progressLayer, model: self.model) Self.Style.label(self.label, model: self.model) - Self.Style.stripesLayer(self.stripesLayer, model: self.model) - Self.Style.stripesMaskLayer(self.stripesMaskLayer, model: self.model) } // MARK: - Update @@ -105,7 +89,6 @@ open class UKCircularProgress: UIView, UKComponent { public func update(_ oldModel: CircularProgressVM) { guard self.model != oldModel else { return } self.style() - self.updateShapePaths() if self.model.shouldUpdateText(oldModel) { UIView.transition( @@ -121,6 +104,9 @@ open class UKCircularProgress: UIView, UKComponent { if self.model.shouldRecalculateProgress(oldModel) { self.updateProgress() } + if self.model.shouldUpdateShape(oldModel) { + self.updateShapePaths() + } if self.model.shouldInvalidateIntrinsicContentSize(oldModel) { self.invalidateIntrinsicContentSize() } @@ -128,31 +114,25 @@ open class UKCircularProgress: UIView, UKComponent { private func updateShapePaths() { let center = CGPoint(x: self.bounds.midX, y: self.bounds.midY) + let minSide = min(self.bounds.width, self.bounds.height) + let radius = (minSide - self.model.circularLineWidth) / 2 let circlePath = UIBezierPath( arcCenter: center, - radius: self.model.radius, - startAngle: -CGFloat.pi / 2, - endAngle: -CGFloat.pi / 2 + 2 * .pi, + radius: radius, + startAngle: self.model.startAngle, + endAngle: self.model.endAngle, clockwise: true ) self.backgroundLayer.path = circlePath.cgPath self.progressLayer.path = circlePath.cgPath - self.stripesMaskLayer.path = circlePath.cgPath - self.stripesLayer.path = self.model.stripesBezierPath(in: self.bounds).cgPath } private func updateProgress() { - let progress = self.model.progress(for: self.currentValue) - CATransaction.begin() CATransaction.setAnimationDuration(self.model.animationDuration) CATransaction.setAnimationTimingFunction(CAMediaTimingFunction(name: .linear)) - self.progressLayer.strokeEnd = progress - if !self.model.isStripesLayerHidden { - self.stripesMaskLayer.strokeStart = self.model.stripedArcStart(for: progress) - self.stripesMaskLayer.strokeEnd = self.model.stripedArcEnd(for: progress) - } + self.progressLayer.strokeEnd = self.model.progress(for: self.currentValue) CATransaction.commit() } @@ -167,8 +147,6 @@ open class UKCircularProgress: UIView, UKComponent { self.backgroundLayer.frame = self.bounds self.progressLayer.frame = self.bounds - self.stripesLayer.frame = self.bounds - self.stripesMaskLayer.frame = self.bounds self.updateShapePaths() } @@ -191,8 +169,6 @@ open class UKCircularProgress: UIView, UKComponent { private func handleTraitChanges() { Self.Style.backgroundLayer(self.backgroundLayer, model: self.model) Self.Style.progressLayer(self.progressLayer, model: self.model) - Self.Style.stripesLayer(self.stripesLayer, model: self.model) - Self.Style.stripesMaskLayer(self.stripesMaskLayer, model: self.model) } } @@ -205,10 +181,9 @@ extension UKCircularProgress { model: CircularProgressVM ) { layer.fillColor = UIColor.clear.cgColor - layer.strokeColor = model.color.background.uiColor.cgColor + layer.strokeColor = model.color.background.cgColor layer.lineCap = .round layer.lineWidth = model.circularLineWidth - layer.isHidden = model.isBackgroundLayerHidden } static func progressLayer( @@ -226,29 +201,8 @@ extension UKCircularProgress { model: CircularProgressVM ) { label.textAlignment = .center - label.adjustsFontSizeToFitWidth = true - label.minimumScaleFactor = 0.5 label.font = model.titleFont.uiFont label.textColor = model.color.main.uiColor } - - static func stripesLayer( - _ layer: CAShapeLayer, - model: CircularProgressVM - ) { - layer.isHidden = model.isStripesLayerHidden - layer.strokeColor = model.color.main.uiColor.cgColor - layer.lineWidth = model.stripeWidth - } - - static func stripesMaskLayer( - _ layer: CAShapeLayer, - model: CircularProgressVM - ) { - layer.fillColor = UIColor.clear.cgColor - layer.strokeColor = model.color.background.uiColor.cgColor - layer.lineCap = .round - layer.lineWidth = model.circularLineWidth - } } } From f1f5144f4b1746b1bab3cd32de5edcd06c09087a Mon Sep 17 00:00:00 2001 From: Mikhail Date: Wed, 2 Apr 2025 12:45:55 +0200 Subject: [PATCH 2/6] add `lineCap` param to circular progress --- .../CircularProgressPreview.swift | 7 ++- .../Models/CircularProgressLineCap.swift | 44 +++++++++++++++++++ .../Models/CircularProgressShape.swift | 2 + .../Models/CircularProgressVM.swift | 3 ++ .../CircularProgress/SUCircularProgress.swift | 4 +- .../CircularProgress/UKCircularProgress.swift | 4 +- 6 files changed, 59 insertions(+), 5 deletions(-) create mode 100644 Sources/ComponentsKit/Components/CircularProgress/Models/CircularProgressLineCap.swift diff --git a/Examples/DemosApp/DemosApp/ComponentsPreview/PreviewPages/CircularProgressPreview.swift b/Examples/DemosApp/DemosApp/ComponentsPreview/PreviewPages/CircularProgressPreview.swift index 39734ec7..8acbcf61 100644 --- a/Examples/DemosApp/DemosApp/ComponentsPreview/PreviewPages/CircularProgressPreview.swift +++ b/Examples/DemosApp/DemosApp/ComponentsPreview/PreviewPages/CircularProgressPreview.swift @@ -37,17 +37,22 @@ struct CircularProgressPreview: View { Form { ComponentColorPicker(selection: self.$model.color) CaptionFontPicker(selection: self.$model.font) + Picker("Line Cap", selection: self.$model.lineCap) { + Text("Butt").tag(CircularProgressVM.LineCap.butt) + Text("Rounded").tag(CircularProgressVM.LineCap.rounded) + Text("Square").tag(CircularProgressVM.LineCap.square) + } Picker("Line Width", selection: self.$model.lineWidth) { Text("Default").tag(Optional.none) Text("2").tag(Optional.some(2)) Text("4").tag(Optional.some(4)) Text("8").tag(Optional.some(8)) } - SizePicker(selection: self.$model.size) Picker("Shape", selection: self.$model.shape) { Text("Circle").tag(CircularProgressVM.Shape.circle) Text("Arc").tag(CircularProgressVM.Shape.arc) } + SizePicker(selection: self.$model.size) } .onReceive(self.timer) { _ in if self.currentValue < self.model.maxValue { diff --git a/Sources/ComponentsKit/Components/CircularProgress/Models/CircularProgressLineCap.swift b/Sources/ComponentsKit/Components/CircularProgress/Models/CircularProgressLineCap.swift new file mode 100644 index 00000000..078c49a7 --- /dev/null +++ b/Sources/ComponentsKit/Components/CircularProgress/Models/CircularProgressLineCap.swift @@ -0,0 +1,44 @@ +import SwiftUI +import UIKit + +extension CircularProgressVM { + /// Defines the style of line endings. + public enum LineCap { + /// The line ends exactly at the endpoint with a flat edge. + case butt + /// The line ends with a semicircular arc that extends beyond the endpoint, creating a rounded appearance. + case rounded + /// The line ends with a square cap that extends beyond the endpoint by half the line width, similar to `butt` but with a protruding end. + case square + } +} + +// MARK: - UIKit Helpers + +extension CircularProgressVM.LineCap { + var shapeLayerLineCap: CAShapeLayerLineCap { + switch self { + case .butt: + return .butt + case .rounded: + return .round + case .square: + return .square + } + } +} + +// MARK: - SwiftUI Helpers + +extension CircularProgressVM.LineCap { + var cgLineCap: CGLineCap { + switch self { + case .butt: + return .butt + case .rounded: + return .round + case .square: + return .square + } + } +} diff --git a/Sources/ComponentsKit/Components/CircularProgress/Models/CircularProgressShape.swift b/Sources/ComponentsKit/Components/CircularProgress/Models/CircularProgressShape.swift index 586e7872..7c4e4e1c 100644 --- a/Sources/ComponentsKit/Components/CircularProgress/Models/CircularProgressShape.swift +++ b/Sources/ComponentsKit/Components/CircularProgress/Models/CircularProgressShape.swift @@ -3,7 +3,9 @@ import Foundation extension CircularProgressVM { /// Defines the shapes for the circular progress component. public enum Shape { + /// Renders a complete circle to represent the progress. case circle + /// Renders only a portion of the circle (an arc) to represent progress. case arc } } diff --git a/Sources/ComponentsKit/Components/CircularProgress/Models/CircularProgressVM.swift b/Sources/ComponentsKit/Components/CircularProgress/Models/CircularProgressVM.swift index e145e5e5..768c487e 100644 --- a/Sources/ComponentsKit/Components/CircularProgress/Models/CircularProgressVM.swift +++ b/Sources/ComponentsKit/Components/CircularProgress/Models/CircularProgressVM.swift @@ -13,6 +13,9 @@ public struct CircularProgressVM: ComponentVM { /// An optional label to display inside the circular progress. public var label: String? + /// The style of line endings. + public var lineCap: LineCap = .rounded + /// The width of the circular progress stroke. public var lineWidth: CGFloat? diff --git a/Sources/ComponentsKit/Components/CircularProgress/SUCircularProgress.swift b/Sources/ComponentsKit/Components/CircularProgress/SUCircularProgress.swift index 02597c4f..f4f258ec 100644 --- a/Sources/ComponentsKit/Components/CircularProgress/SUCircularProgress.swift +++ b/Sources/ComponentsKit/Components/CircularProgress/SUCircularProgress.swift @@ -46,7 +46,7 @@ public struct SUCircularProgress: View { self.model.color.background.color, style: StrokeStyle( lineWidth: self.model.circularLineWidth, - lineCap: .round + lineCap: self.model.lineCap.cgLineCap ) ) .frame( @@ -69,7 +69,7 @@ public struct SUCircularProgress: View { self.model.color.main.color, style: StrokeStyle( lineWidth: self.model.circularLineWidth, - lineCap: .round + lineCap: self.model.lineCap.cgLineCap ) ) .frame( diff --git a/Sources/ComponentsKit/Components/CircularProgress/UKCircularProgress.swift b/Sources/ComponentsKit/Components/CircularProgress/UKCircularProgress.swift index 3edec8c0..8e82a701 100644 --- a/Sources/ComponentsKit/Components/CircularProgress/UKCircularProgress.swift +++ b/Sources/ComponentsKit/Components/CircularProgress/UKCircularProgress.swift @@ -182,7 +182,7 @@ extension UKCircularProgress { ) { layer.fillColor = UIColor.clear.cgColor layer.strokeColor = model.color.background.cgColor - layer.lineCap = .round + layer.lineCap = model.lineCap.shapeLayerLineCap layer.lineWidth = model.circularLineWidth } @@ -192,7 +192,7 @@ extension UKCircularProgress { ) { layer.fillColor = UIColor.clear.cgColor layer.strokeColor = model.color.main.uiColor.cgColor - layer.lineCap = .round + layer.lineCap = model.lineCap.shapeLayerLineCap layer.lineWidth = model.circularLineWidth } From 8d4a46df68919cec299c6111e5a33c6feae9873c Mon Sep 17 00:00:00 2001 From: Mikhail Date: Wed, 2 Apr 2025 12:48:02 +0200 Subject: [PATCH 3/6] update initial model for circular progress in the demos --- .../ComponentsPreview/PreviewPages/CircularProgressPreview.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Examples/DemosApp/DemosApp/ComponentsPreview/PreviewPages/CircularProgressPreview.swift b/Examples/DemosApp/DemosApp/ComponentsPreview/PreviewPages/CircularProgressPreview.swift index 8acbcf61..059273f1 100644 --- a/Examples/DemosApp/DemosApp/ComponentsPreview/PreviewPages/CircularProgressPreview.swift +++ b/Examples/DemosApp/DemosApp/ComponentsPreview/PreviewPages/CircularProgressPreview.swift @@ -77,7 +77,6 @@ struct CircularProgressPreview: View { private static var initialModel = CircularProgressVM { $0.label = "0%" - $0.shape = .arc } } From 57bb363aa0475c9135145a8bc89f2514679c80a8 Mon Sep 17 00:00:00 2001 From: Mikhail Date: Wed, 2 Apr 2025 12:57:49 +0200 Subject: [PATCH 4/6] improve docs --- .../Components/CircularProgress/SUCircularProgress.swift | 2 +- .../Components/CircularProgress/UKCircularProgress.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/ComponentsKit/Components/CircularProgress/SUCircularProgress.swift b/Sources/ComponentsKit/Components/CircularProgress/SUCircularProgress.swift index f4f258ec..993c4dee 100644 --- a/Sources/ComponentsKit/Components/CircularProgress/SUCircularProgress.swift +++ b/Sources/ComponentsKit/Components/CircularProgress/SUCircularProgress.swift @@ -1,6 +1,6 @@ import SwiftUI -/// A SwiftUI component that displays a circular progress. +/// A SwiftUI component that displays the progress of a task or operation in a circular form. public struct SUCircularProgress: View { // MARK: - Properties diff --git a/Sources/ComponentsKit/Components/CircularProgress/UKCircularProgress.swift b/Sources/ComponentsKit/Components/CircularProgress/UKCircularProgress.swift index 8e82a701..0aeb8858 100644 --- a/Sources/ComponentsKit/Components/CircularProgress/UKCircularProgress.swift +++ b/Sources/ComponentsKit/Components/CircularProgress/UKCircularProgress.swift @@ -1,7 +1,7 @@ import AutoLayout import UIKit -/// A UIKit component that displays a circular progress indicator. +/// A UIKit component that displays the progress of a task or operation in a circular form. open class UKCircularProgress: UIView, UKComponent { // MARK: - Properties From 9f550313ea8c32aa6824fdaf2df564a0d4ad5d0a Mon Sep 17 00:00:00 2001 From: Mikhail Date: Wed, 2 Apr 2025 13:14:54 +0200 Subject: [PATCH 5/6] improve docs for `UKCircularProgress` --- .../Components/CircularProgress/UKCircularProgress.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/ComponentsKit/Components/CircularProgress/UKCircularProgress.swift b/Sources/ComponentsKit/Components/CircularProgress/UKCircularProgress.swift index 0aeb8858..e68f5001 100644 --- a/Sources/ComponentsKit/Components/CircularProgress/UKCircularProgress.swift +++ b/Sources/ComponentsKit/Components/CircularProgress/UKCircularProgress.swift @@ -21,13 +21,13 @@ open class UKCircularProgress: UIView, UKComponent { // MARK: - Subviews - /// The shape layer responsible for rendering the background of the circular progress indicator. + /// The shape layer responsible for rendering the background. public let backgroundLayer = CAShapeLayer() - /// The shape layer responsible for rendering the progress arc of the circular progress indicator. + /// The shape layer responsible for rendering the progress arc. public let progressLayer = CAShapeLayer() - /// The label used to display text inside the circular progress indicator. + /// The label used to display text. public let label = UILabel() // MARK: - UIView Properties From 01e29b3e9f0d9604eb89b31efa1e6590240b51e0 Mon Sep 17 00:00:00 2001 From: Mikhail Date: Wed, 2 Apr 2025 14:40:07 +0200 Subject: [PATCH 6/6] remove `butt` line cap --- .../PreviewPages/CircularProgressPreview.swift | 1 - .../Models/CircularProgressLineCap.swift | 12 +++--------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/Examples/DemosApp/DemosApp/ComponentsPreview/PreviewPages/CircularProgressPreview.swift b/Examples/DemosApp/DemosApp/ComponentsPreview/PreviewPages/CircularProgressPreview.swift index 059273f1..436dcb68 100644 --- a/Examples/DemosApp/DemosApp/ComponentsPreview/PreviewPages/CircularProgressPreview.swift +++ b/Examples/DemosApp/DemosApp/ComponentsPreview/PreviewPages/CircularProgressPreview.swift @@ -38,7 +38,6 @@ struct CircularProgressPreview: View { ComponentColorPicker(selection: self.$model.color) CaptionFontPicker(selection: self.$model.font) Picker("Line Cap", selection: self.$model.lineCap) { - Text("Butt").tag(CircularProgressVM.LineCap.butt) Text("Rounded").tag(CircularProgressVM.LineCap.rounded) Text("Square").tag(CircularProgressVM.LineCap.square) } diff --git a/Sources/ComponentsKit/Components/CircularProgress/Models/CircularProgressLineCap.swift b/Sources/ComponentsKit/Components/CircularProgress/Models/CircularProgressLineCap.swift index 078c49a7..72a86b8c 100644 --- a/Sources/ComponentsKit/Components/CircularProgress/Models/CircularProgressLineCap.swift +++ b/Sources/ComponentsKit/Components/CircularProgress/Models/CircularProgressLineCap.swift @@ -4,11 +4,9 @@ import UIKit extension CircularProgressVM { /// Defines the style of line endings. public enum LineCap { - /// The line ends exactly at the endpoint with a flat edge. - case butt /// The line ends with a semicircular arc that extends beyond the endpoint, creating a rounded appearance. case rounded - /// The line ends with a square cap that extends beyond the endpoint by half the line width, similar to `butt` but with a protruding end. + /// The line ends exactly at the endpoint with a flat edge. case square } } @@ -18,12 +16,10 @@ extension CircularProgressVM { extension CircularProgressVM.LineCap { var shapeLayerLineCap: CAShapeLayerLineCap { switch self { - case .butt: - return .butt case .rounded: return .round case .square: - return .square + return .butt } } } @@ -33,12 +29,10 @@ extension CircularProgressVM.LineCap { extension CircularProgressVM.LineCap { var cgLineCap: CGLineCap { switch self { - case .butt: - return .butt case .rounded: return .round case .square: - return .square + return .butt } } }