-
Notifications
You must be signed in to change notification settings - Fork 10
SUProgressBar #43
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
SUProgressBar #43
Changes from 3 commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
b47ec3d
SUProgressBar and ProgressBarVM
VislovIvan ac97dea
Documentation
VislovIvan 04c3980
swiftlint fix
VislovIvan 1070027
.self added
VislovIvan b2ac453
code style fix
VislovIvan 4504026
ProgressBarPreview step fix
VislovIvan fd77126
padding fix
VislovIvan dd1158d
var fraction fix
VislovIvan 0ff5aea
stripes fix
VislovIvan 9b65fae
unused properties removed
VislovIvan 3cec343
added innerCornerRadius
VislovIvan 1f5ecd1
some minor fix
VislovIvan 4d508f6
automatic progress in preview
VislovIvan f21599a
fix contentPaddings
VislovIvan b6470ff
code style fix
VislovIvan 8a36501
fix self
VislovIvan a88172e
.onReceive code style fix
VislovIvan 40d1a5f
swiftlint fix
VislovIvan 4e8055d
minor code improvements
mikhailChelbaev c08d790
merge with dev
mikhailChelbaev File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
36 changes: 36 additions & 0 deletions
36
Examples/DemosApp/DemosApp/ComponentsPreview/PreviewPages/ProgressBarPreview.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| import ComponentsKit | ||
| import SwiftUI | ||
| import UIKit | ||
|
|
||
| struct ProgressBarPreview: View { | ||
| @State private var model = ProgressBarVM() | ||
| @State private var currentValue: CGFloat = 50 | ||
|
|
||
| var body: some View { | ||
| VStack { | ||
| PreviewWrapper(title: "SwiftUI") { | ||
| SUProgressBar(currentValue: $currentValue, model: model) | ||
| } | ||
| Form { | ||
| ComponentColorPicker(selection: self.$model.color) | ||
| Picker("Current Value", selection: $currentValue) { | ||
| Text("0").tag(CGFloat(0)) | ||
| Text("25").tag(CGFloat(25)) | ||
| Text("50").tag(CGFloat(50)) | ||
| Text("75").tag(CGFloat(75)) | ||
| Text("100").tag(CGFloat(100)) | ||
| } | ||
| SizePicker(selection: self.$model.size) | ||
| Picker("Style", selection: $model.style) { | ||
| Text("Light").tag(ProgressBarVM.ProgressBarStyle.light) | ||
| Text("Filled").tag(ProgressBarVM.ProgressBarStyle.filled) | ||
| Text("Striped").tag(ProgressBarVM.ProgressBarStyle.striped) | ||
| } | ||
VislovIvan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| #Preview { | ||
| ProgressBarPreview() | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10 changes: 10 additions & 0 deletions
10
Sources/ComponentsKit/ProgressBar/Models/ProgressBarStyle.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| import Foundation | ||
|
|
||
| extension ProgressBarVM { | ||
| /// Defines the visual styles for the progress bar component. | ||
| public enum ProgressBarStyle { | ||
VislovIvan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| case light | ||
| case filled | ||
| case striped | ||
| } | ||
| } | ||
140 changes: 140 additions & 0 deletions
140
Sources/ComponentsKit/ProgressBar/Models/ProgressBarVM.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,140 @@ | ||
| import SwiftUI | ||
|
|
||
| /// A model that defines the appearance properties for a a progress bar component. | ||
| public struct ProgressBarVM: ComponentVM { | ||
| /// The color of the progress bar.. | ||
| /// | ||
| /// Defaults to `.primary`. | ||
| public var color: ComponentColor = .primary | ||
VislovIvan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| /// The visual style of the progress bar component. | ||
| /// | ||
| /// Defaults to `.light`. | ||
| public var style: ProgressBarStyle = .striped | ||
VislovIvan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| /// The size of the progress bar. | ||
| /// | ||
| /// Defaults to `.medium`. | ||
| public var size: ComponentSize = .large | ||
VislovIvan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| /// The minimum value of the progress bar. | ||
| public var minValue: CGFloat = 0 | ||
|
|
||
| /// The maximum value of the progress bar. | ||
| public var maxValue: CGFloat = 100 | ||
|
|
||
| /// The corner radius of the progress bar. | ||
| /// | ||
| /// Defaults to `.medium`. | ||
| public var cornerRadius: ComponentRadius = .medium | ||
|
|
||
| /// The width of the stripes in the `.striped` progress bar style. | ||
| public var stripeWidth: CGFloat = 2 | ||
|
|
||
| /// The spacing between the stripes in the `.striped` progress bar style. | ||
| public var stripeSpacing: CGFloat = 4 | ||
|
|
||
| /// The angle of the stripes in the `.striped` progress bar style.. | ||
| public var stripeAngle: Angle = .degrees(135) | ||
VislovIvan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| /// Initializes a new instance of `ProgressBarVM` with default values. | ||
| public init() {} | ||
| } | ||
|
|
||
| // MARK: - Shared Helpers | ||
|
|
||
| extension ProgressBarVM { | ||
VislovIvan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| var barHeight: CGFloat { | ||
| switch style { | ||
| case .light: | ||
| switch size { | ||
| case .small: | ||
| return 4 | ||
| case .medium: | ||
| return 8 | ||
| case .large: | ||
| return 16 | ||
| } | ||
| case .filled, .striped: | ||
| switch size { | ||
| case .small: | ||
| return 10 | ||
| case .medium: | ||
| return 25 | ||
| case .large: | ||
| return 45 | ||
| } | ||
| } | ||
| } | ||
VislovIvan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| var computedCornerRadius: CGFloat { | ||
| switch style { | ||
| case .light: | ||
| return barHeight / 2 | ||
| case .filled, .striped: | ||
| switch size { | ||
| case .small, .medium: | ||
| return barHeight / 2 | ||
| case .large: | ||
| return barHeight / 2.5 | ||
| } | ||
| } | ||
VislovIvan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
VislovIvan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| var backgroundColor: UniversalColor { | ||
| switch style { | ||
| case .light: | ||
| return self.color.main.withOpacity(0.15) | ||
VislovIvan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| case .filled, .striped: | ||
| return self.color.main | ||
| } | ||
| } | ||
|
|
||
| var barColor: UniversalColor { | ||
| switch style { | ||
| case .light: | ||
| return self.color.main | ||
| case .filled, .striped: | ||
| return self.color.contrast | ||
| } | ||
| } | ||
|
|
||
| func shouldUpdateLayout(_ oldModel: Self) -> Bool { | ||
| return self.size != oldModel.size | ||
| } | ||
|
|
||
| public func stripesPath(in rect: CGRect) -> Path { | ||
| var path = Path() | ||
| let step = stripeWidth + stripeSpacing | ||
| let radians = stripeAngle.radians | ||
| let dx = rect.height * tan(radians) | ||
|
|
||
| for x in stride(from: dx - step, through: rect.width + step, by: step) { | ||
| let topLeft = CGPoint(x: x, y: 0) | ||
| let topRight = CGPoint(x: x + stripeWidth, y: 0) | ||
| let bottomLeft = CGPoint(x: x + dx, y: rect.height) | ||
| let bottomRight = CGPoint(x: x + stripeWidth + dx, y: rect.height) | ||
|
|
||
| path.move(to: topLeft) | ||
| path.addLine(to: topRight) | ||
| path.addLine(to: bottomRight) | ||
| path.addLine(to: bottomLeft) | ||
| path.closeSubpath() | ||
| } | ||
|
|
||
| return path | ||
| } | ||
|
|
||
| public func stripesBezierPath(in rect: CGRect) -> UIBezierPath { | ||
| let swiftUIPath = stripesPath(in: rect) | ||
| return UIBezierPath(cgPath: swiftUIPath.cgPath) | ||
| } | ||
VislovIvan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| // MARK: - Validation | ||
|
|
||
| extension ProgressBarVM { | ||
| public func isValid() -> Bool { | ||
| return minValue < maxValue | ||
| } | ||
VislovIvan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| import SwiftUI | ||
|
|
||
| /// A SwiftUI component that displays a progress bar. | ||
| public struct SUProgressBar: View { | ||
| // MARK: - Properties | ||
|
|
||
| /// A model that defines the appearance properties. | ||
| public var model: ProgressBarVM | ||
|
|
||
| @Binding private var currentValue: CGFloat | ||
|
|
||
| // MARK: - Initializer | ||
|
|
||
| /// Initializer. | ||
| /// - Parameters: | ||
| /// - currentValue: A binding to the current value. | ||
| /// - model: A model that defines the appearance properties. | ||
| public init( | ||
| currentValue: Binding<CGFloat>, | ||
| model: ProgressBarVM | ||
VislovIvan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| ) { | ||
| self._currentValue = currentValue | ||
| self.model = model | ||
| } | ||
|
|
||
| // MARK: - Body | ||
|
|
||
| public var body: some View { | ||
| GeometryReader { geometry in | ||
| switch model.style { | ||
| case .light: | ||
| HStack(spacing: 4) { | ||
| Rectangle() | ||
| .foregroundColor(model.barColor.color) | ||
| .frame(width: geometry.size.width * fraction, height: model.barHeight) | ||
| .cornerRadius(model.computedCornerRadius) | ||
| Rectangle() | ||
| .foregroundColor(model.backgroundColor.color) | ||
| .frame(width: geometry.size.width * (1 - fraction), height: model.barHeight) | ||
| .cornerRadius(model.computedCornerRadius) | ||
| .scaleEffect(fraction == 0 ? 0 : 1, anchor: .leading) | ||
VislovIvan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
| .animation(.spring, value: fraction) | ||
|
|
||
| case .filled: | ||
| ZStack(alignment: .leading) { | ||
| RoundedRectangle(cornerRadius: model.computedCornerRadius) | ||
| .foregroundColor(model.color.main.color) | ||
VislovIvan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| .frame(width: geometry.size.width, height: model.barHeight) | ||
|
|
||
| RoundedRectangle(cornerRadius: model.computedCornerRadius) | ||
| .foregroundColor((model.color.contrast ?? .foreground).color) | ||
| .frame(width: (geometry.size.width - 6) * fraction, height: model.barHeight - 6) | ||
| .padding(3) | ||
| .scaleEffect(fraction == 0 ? 0 : 1, anchor: .leading) | ||
VislovIvan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
| .animation(.spring, value: fraction) | ||
|
|
||
| case .striped: | ||
| ZStack(alignment: .leading) { | ||
| RoundedRectangle(cornerRadius: model.computedCornerRadius) | ||
| .foregroundColor(model.color.main.color) | ||
| .frame(width: geometry.size.width, height: model.barHeight) | ||
|
|
||
| RoundedRectangle(cornerRadius: model.computedCornerRadius) | ||
VislovIvan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| .foregroundColor(model.color.contrast.color) | ||
| .frame(width: (geometry.size.width - 6) * fraction, height: model.barHeight - 6) | ||
| .padding(3) | ||
VislovIvan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| .scaleEffect(fraction == 0 ? 0 : 1, anchor: .leading) | ||
VislovIvan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| StripesShape(model: model) | ||
| .foregroundColor(model.color.main.color) | ||
| .scaleEffect(1.2) | ||
| .cornerRadius(model.computedCornerRadius) | ||
| .clipped() | ||
| } | ||
| .animation(.spring, value: fraction) | ||
| } | ||
| } | ||
| .frame(height: model.barHeight) | ||
VislovIvan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| // MARK: - Properties | ||
|
|
||
| private var fraction: CGFloat { | ||
| let range = model.maxValue - model.minValue | ||
| guard range != 0 else { return 0 } | ||
| let fraction = (currentValue - model.minValue) / range | ||
| return max(0, min(1, fraction)) | ||
| } | ||
VislovIvan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| struct StripesShape: Shape { | ||
| var model: ProgressBarVM | ||
|
|
||
| func path(in rect: CGRect) -> Path { | ||
| model.stripesPath(in: rect) | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.