Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,8 @@ import UIKit

struct CircularProgressPreview: View {
@State private var model = Self.initialModel
@State private var currentValue: CGFloat = Self.initialValue

private let circularProgress = UKCircularProgress(
initialValue: Self.initialValue,
model: Self.initialModel
)
private let circularProgress = UKCircularProgress(model: Self.initialModel)

private let timer = Timer
.publish(every: 0.5, on: .main, in: .common)
Expand All @@ -21,18 +17,14 @@ struct CircularProgressPreview: View {
self.circularProgress
.preview
.onAppear {
self.circularProgress.currentValue = Self.initialValue
self.circularProgress.model = Self.initialModel
}
.onChange(of: model) { newModel in
self.circularProgress.model = newModel
}
.onChange(of: self.currentValue) { newValue in
self.circularProgress.currentValue = newValue
}
}
PreviewWrapper(title: "SwiftUI") {
SUCircularProgress(currentValue: self.currentValue, model: self.model)
SUCircularProgress(model: self.model)
}
Form {
ComponentColorPicker(selection: self.$model.color)
Expand All @@ -54,28 +46,25 @@ struct CircularProgressPreview: View {
SizePicker(selection: self.$model.size)
}
.onReceive(self.timer) { _ in
if self.currentValue < self.model.maxValue {
if self.model.currentValue < self.model.maxValue {
let step = (self.model.maxValue - self.model.minValue) / 100
self.currentValue = min(
self.model.currentValue = min(
self.model.maxValue,
self.currentValue + CGFloat(Int.random(in: 1...20)) * step
self.model.currentValue + CGFloat(Int.random(in: 1...20)) * step
)
} else {
self.currentValue = self.model.minValue
self.model.currentValue = self.model.minValue
}
self.model.label = "\(Int(self.currentValue))%"
self.model.label = "\(Int(self.model.currentValue))%"
}
}
}

// MARK: - Helpers

private static var initialValue: Double {
return 0.0
}

private static var initialModel = CircularProgressVM {
$0.label = "0%"
$0.currentValue = 0.0
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@ import UIKit

struct ProgressBarPreview: View {
@State private var model = Self.initialModel
@State private var currentValue: CGFloat = Self.initialValue

private let progressBar = UKProgressBar(initialValue: Self.initialValue, model: Self.initialModel)


private let progressBar = UKProgressBar(model: Self.initialModel)

private let timer = Timer
.publish(every: 0.5, on: .main, in: .common)
.autoconnect()
Expand All @@ -18,15 +17,14 @@ struct ProgressBarPreview: View {
self.progressBar
.preview
.onAppear {
self.progressBar.currentValue = self.currentValue
self.progressBar.model = Self.initialModel
}
.onChange(of: self.model) { newValue in
self.progressBar.model = newValue
}
}
PreviewWrapper(title: "SwiftUI") {
SUProgressBar(currentValue: self.currentValue, model: self.model)
SUProgressBar(model: self.model)
}
Form {
ComponentColorPicker(selection: self.$model.color)
Expand All @@ -42,25 +40,20 @@ struct ProgressBarPreview: View {
}
}
.onReceive(self.timer) { _ in
if self.currentValue < self.model.maxValue {
if self.model.currentValue < self.model.maxValue {
let step = (self.model.maxValue - self.model.minValue) / 100
self.currentValue = min(
self.model.currentValue = min(
self.model.maxValue,
self.currentValue + CGFloat(Int.random(in: 1...20)) * step
self.model.currentValue + CGFloat(Int.random(in: 1...20)) * step
)
} else {
self.currentValue = self.model.minValue
self.model.currentValue = self.model.minValue
}

self.progressBar.currentValue = self.currentValue
}
}

// MARK: - Helpers

private static var initialValue: Double {
return 0.0
}
private static var initialModel: ProgressBarVM {
return .init()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ public struct CircularProgressVM: ComponentVM {
/// Defaults to `.accent`.
public var color: ComponentColor = .accent

/// The current value of the circular progress.
///
/// Defaults to `0`.
public var currentValue: CGFloat = 0

/// The font used for the circular progress label text.
public var font: UniversalFont?

Expand Down Expand Up @@ -103,6 +108,13 @@ extension CircularProgressVM {
}

extension CircularProgressVM {
var progress: CGFloat {
let range = self.maxValue - self.minValue
guard range > 0 else { return 0 }
let normalized = (self.currentValue - self.minValue) / range
return max(0, min(1, normalized))
}

func progress(for currentValue: CGFloat) -> CGFloat {
let range = self.maxValue - self.minValue
guard range > 0 else { return 0 }
Expand All @@ -123,6 +135,7 @@ extension CircularProgressVM {
func shouldRecalculateProgress(_ oldModel: Self) -> Bool {
return self.minValue != oldModel.minValue
|| self.maxValue != oldModel.maxValue
|| self.currentValue != oldModel.currentValue
}
func shouldUpdateShape(_ oldModel: Self) -> Bool {
return self.shape != oldModel.shape
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ public struct SUCircularProgress: View {
public var model: CircularProgressVM

/// The current progress value.
public var currentValue: CGFloat
public var currentValue: CGFloat?

private var progress: CGFloat {
self.model.progress(for: self.currentValue)
self.currentValue.map { self.model.progress(for: $0) } ?? self.model.progress
}

// MARK: - Initializer
Expand All @@ -20,6 +20,7 @@ public struct SUCircularProgress: View {
/// - Parameters:
/// - currentValue: Current progress.
/// - model: A model that defines the appearance properties.
@available(*, deprecated, message: "Set `currentValue` in the model instead.")
public init(
currentValue: CGFloat = 0,
model: CircularProgressVM = .init()
Expand All @@ -28,6 +29,13 @@ public struct SUCircularProgress: View {
self.model = model
}

/// Initializer.
/// - Parameters:
/// - model: A model that defines the appearance properties.
public init(model: CircularProgressVM) {
self.model = model
}

// MARK: - Body

public var body: some View {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,16 @@ open class UKCircularProgress: UIView, UKComponent {
}

/// The current progress value.
public var currentValue: CGFloat {
public var currentValue: CGFloat? {
didSet {
self.updateProgress()
}
}

private var progress: CGFloat {
self.currentValue.map { self.model.progress(for: $0) } ?? self.model.progress
}

// MARK: - Subviews

/// The shape layer responsible for rendering the background.
Expand All @@ -42,6 +46,7 @@ open class UKCircularProgress: UIView, UKComponent {
/// - Parameters:
/// - initialValue: The initial progress value. Defaults to `0`.
/// - model: The model that defines the appearance properties.
@available(*, deprecated, message: "Set `currentValue` in the model instead.")
public init(
initialValue: CGFloat = 0,
model: CircularProgressVM = .init()
Expand All @@ -55,6 +60,18 @@ open class UKCircularProgress: UIView, UKComponent {
self.layout()
}

/// Initializer.
/// - Parameters:
/// - model: The model that defines the appearance properties.
public init(model: CircularProgressVM) {
self.model = model
super.init(frame: .zero)

self.setup()
self.style()
self.layout()
}

public required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
Expand All @@ -72,7 +89,7 @@ open class UKCircularProgress: UIView, UKComponent {
}
}

self.progressLayer.strokeEnd = self.model.progress(for: self.currentValue)
self.progressLayer.strokeEnd = self.progress
self.label.text = self.model.label
}

Expand Down Expand Up @@ -132,7 +149,7 @@ open class UKCircularProgress: UIView, UKComponent {
CATransaction.begin()
CATransaction.setAnimationDuration(self.model.animationDuration)
CATransaction.setAnimationTimingFunction(CAMediaTimingFunction(name: .linear))
self.progressLayer.strokeEnd = self.model.progress(for: self.currentValue)
self.progressLayer.strokeEnd = self.progress
CATransaction.commit()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,29 @@ public struct ProgressBarVM: ComponentVM {
/// Defaults to `.accent`.
public var color: ComponentColor = .accent

/// The visual style of the progress bar component.
///
/// Defaults to `.striped`.
public var style: Style = .striped

/// The size of the progress bar.
/// The corner radius of the progress bar.
///
/// Defaults to `.medium`.
public var size: ComponentSize = .medium
public var cornerRadius: ComponentRadius = .medium

/// The minimum value of the progress bar.
public var minValue: CGFloat = 0
/// The current value of the progress bar.
public var currentValue: CGFloat = 0

/// The maximum value of the progress bar.
public var maxValue: CGFloat = 100

/// The corner radius of the progress bar.
/// The minimum value of the progress bar.
public var minValue: CGFloat = 0

/// The size of the progress bar.
///
/// Defaults to `.medium`.
public var cornerRadius: ComponentRadius = .medium
public var size: ComponentSize = .medium

/// The visual style of the progress bar component.
///
/// Defaults to `.striped`.
public var style: Style = .striped

/// Initializes a new instance of `ProgressBarVM` with default values.
public init() {}
Expand Down Expand Up @@ -139,6 +142,13 @@ extension ProgressBarVM {
}

extension ProgressBarVM {
var progress: CGFloat {
let range = self.maxValue - self.minValue
guard range > 0 else { return 0 }
let normalized = (self.currentValue - self.minValue) / range
return max(0, min(1, normalized))
}

func progress(for currentValue: CGFloat) -> CGFloat {
let range = self.maxValue - self.minValue
guard range > 0 else { return 0 }
Expand Down
14 changes: 11 additions & 3 deletions Sources/ComponentsKit/Components/ProgressBar/SUProgressBar.swift
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import SwiftUI

/// A SwiftUI component that displays a progress bar.
/// A SwiftUI component that visually represents the progress of a task or process using a horizontal bar.
public struct SUProgressBar: View {
// MARK: - Properties

/// A model that defines the appearance properties.
public var model: ProgressBarVM
/// The current progress value.
public var currentValue: CGFloat
public var currentValue: CGFloat?

private var progress: CGFloat {
self.model.progress(for: self.currentValue)
self.currentValue.map { self.model.progress(for: $0) } ?? self.model.progress
}

// MARK: - Initializer
Expand All @@ -19,6 +19,7 @@ public struct SUProgressBar: View {
/// - Parameters:
/// - currentValue: The current progress value.
/// - model: A model that defines the appearance properties.
@available(*, deprecated, message: "Set `currentValue` in the model instead.")
public init(
currentValue: CGFloat,
model: ProgressBarVM = .init()
Expand All @@ -27,6 +28,13 @@ public struct SUProgressBar: View {
self.model = model
}

/// Initializer.
/// - Parameters:
/// - model: A model that defines the appearance properties.
public init(model: ProgressBarVM) {
self.model = model
}

// MARK: - Body

public var body: some View {
Expand Down
Loading