diff --git a/MVMCoreUI/Atomic/Atoms/Views/CircularProgressBar.swift b/MVMCoreUI/Atomic/Atoms/Views/CircularProgressBar.swift index df5fe946..011359c8 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/CircularProgressBar.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/CircularProgressBar.swift @@ -15,6 +15,10 @@ import UIKit return model as? CircularProgressBarModel } + var viewWidth: CGFloat { + graphModel?.diameter ?? CGFloat(84) + } + private var progressLayer = CAShapeLayer() private var tracklayer = CAShapeLayer() private var labelLayer = CATextLayer() @@ -25,18 +29,16 @@ import UIKit } } - var setTrackColor: UIColor = UIColor.white { + var setTrackColor: UIColor = UIColor.lightGray { didSet { tracklayer.strokeColor = setTrackColor.cgColor } } - /** - A path that consists of straight and curved line segments that you can render in your custom views. - Meaning our CAShapeLayer will now be drawn on the screen with the path we have specified here - */ + + // A path with which CAShapeLayer will be drawn on the screen private var viewCGPath: CGPath? { - let width = graphModel?.diameter ?? 84 + let width = viewWidth let height = width return UIBezierPath(arcCenter: CGPoint(x: width / 2.0, y: height / 2.0), @@ -45,9 +47,51 @@ import UIKit endAngle: CGFloat(1.5 * Double.pi), clockwise: true).cgPath } +// MARK: setup + override open func setupView() { + super.setupView() + heightConstraint = heightAnchor.constraint(equalToConstant: 0) + heightConstraint?.isActive = true + widthAnchor.constraint(equalTo: heightAnchor).isActive = true + } + + override open func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { + + super.set(with: model, delegateObject, additionalData) + guard let model = model as? CircularProgressBarModel else { return } + + // set background color + if let backgroundColor = model.backgroundColor { + self.backgroundColor = backgroundColor.uiColor + } else { + self.backgroundColor = UIColor.clear + } + + configureProgressViewToBeCircular() + + // set progress color + if let color = model.color { + setProgressColor = color.uiColor + } else { + setProgressColor = UIColor.red + } + + // set track color + if let trackColor = model.trackColor { + setTrackColor = trackColor.uiColor + } else { + setProgressColor = UIColor.lightGray + } + + // show circular progress view with animation. + showProgressWithAnimation(duration: 0.5, value: Float(graphModel?.percent ?? 0) / 100) + + // show progress percentage label. + showProgressPercentage() + } + private func configureProgressViewToBeCircular() { - let lineWidth = graphModel?.lineWidth ?? 2.0 - self.backgroundColor = UIColor.clear + let lineWidth = graphModel?.lineWidth ?? 5.0 self.drawShape(using: tracklayer, lineWidth: lineWidth) self.drawShape(using: progressLayer, lineWidth: lineWidth) @@ -60,7 +104,8 @@ import UIKit self.layer.addSublayer(shape) } - func setProgressWithAnimation(duration: TimeInterval, value: Float) { + // value range is [0,1] + private func showProgressWithAnimation(duration: TimeInterval, value: Float) { let animation = CABasicAnimation(keyPath: "strokeEnd") animation.duration = duration @@ -71,47 +116,26 @@ import UIKit progressLayer.add(animation, forKey: "animateCircle") } - func drawLabel() { + private func showProgressPercentage() { let percent = graphModel?.percent ?? 0 let percentLen = percent > 9 ? 2 : 1 + + // configure attributed string for progress percentage. let attributedString = NSMutableAttributedString(string: String(percent) + "%") + // percent value attributedString.setAttributes([NSAttributedString.Key.font: MFStyler.fontBoldTitleLarge()], range: NSMakeRange(0, percentLen)) + // % symbol attributedString.setAttributes([NSAttributedString.Key.font: MFStyler.fontBoldBodyLarge()], range: NSMakeRange(percentLen, 1)) - // Text layer - let width = graphModel?.diameter ?? 84 + // show progress percentage in a text layer + let width = viewWidth let height = width labelLayer.string = attributedString labelLayer.frame = CGRectMake((width - CGFloat(percentLen * 20))/2, (height - 30)/2, 60, 30) self.layer.addSublayer(labelLayer) } -// MARK: setup - open override func setupView() { - super.setupView() - heightConstraint = heightAnchor.constraint(equalToConstant: 0) - heightConstraint?.isActive = true - widthAnchor.constraint(equalTo: heightAnchor).isActive = true - } - - override open func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { - super.set(with: model, delegateObject, additionalData) - guard let model = model as? CircularProgressBarModel else { return } - - configureProgressViewToBeCircular() - - if let color = model.color { - setProgressColor = color.uiColor - } - - if let backgroundColor = model.backgroundColor { - setTrackColor = backgroundColor.uiColor - } - - setProgressWithAnimation(duration: 0.5, value: Float(graphModel?.percent ?? 0) / 100) - drawLabel() - } //MARK: MVMCoreUIViewConstrainingProtocol public func needsToBeConstrained() -> Bool { diff --git a/MVMCoreUI/Atomic/Atoms/Views/CircularProgressBarModel.swift b/MVMCoreUI/Atomic/Atoms/Views/CircularProgressBarModel.swift index 3a865b62..6c58be43 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/CircularProgressBarModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/CircularProgressBarModel.swift @@ -22,9 +22,10 @@ public class CircularProgressBarModel: MoleculeModelProtocol { public var diameter: CGFloat = 84 public var lineWidth: CGFloat = 5 public var color: Color? - public var backgroundColor: Color? + public var trackColor: Color? public var percent: Int? - + public var backgroundColor: Color? = Color(uiColor: UIColor.clear) + public init() { updateSize() } @@ -35,8 +36,9 @@ public class CircularProgressBarModel: MoleculeModelProtocol { case diameter case lineWidth case color - case backgroundColor + case trackColor case percent + case backgroundColor case moleculeName } @@ -58,8 +60,10 @@ public class CircularProgressBarModel: MoleculeModelProtocol { } color = try typeContainer.decodeIfPresent(Color.self, forKey: .color) - backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) + trackColor = try typeContainer.decodeIfPresent(Color.self, forKey: .trackColor) percent = try typeContainer.decodeIfPresent(Int.self, forKey: .percent) + + backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) } public func encode(to encoder: Encoder) throws { @@ -69,9 +73,10 @@ public class CircularProgressBarModel: MoleculeModelProtocol { try container.encode(size, forKey: .size) try container.encode(diameter, forKey: .diameter) try container.encode(lineWidth, forKey: .lineWidth) - try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) + try container.encodeIfPresent(trackColor, forKey: .trackColor) try container.encodeIfPresent(color, forKey: .color) try container.encodeIfPresent(percent, forKey: .percent) + try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) } func getCGColorsFromArray(_ colorArray: [String]) -> [Color] {