Skip to content

Commit cdd8ed6

Browse files
[CM 1206] Add additional shapes (#4)
* [UPDATE]rebase conflict * [UPDATE] typo corrected * [UPDATE] removed extra files [UPDATE] added shapes without stroke, test case updated * [UPDATE] added scaled rounded rect * [UPDATE] white space around operator, removed border scaling * [UPDATE] removed foreground from images and added text color
1 parent c26cc76 commit cdd8ed6

File tree

4 files changed

+165
-9
lines changed

4 files changed

+165
-9
lines changed

Sources/YStepper/SwiftUI/Views/Stepper.swift

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import YMatterType
1313
public struct Stepper {
1414
@Environment(\.sizeCategory) var sizeCategory
1515
let buttonSize: CGSize = CGSize(width: 44, height: 44)
16+
@ScaledMetric var scale = 1.0
1617
@ObservedObject private var appearanceObserver = Stepper.AppearanceObserver()
1718
@ObservedObject private var valueObserver = Stepper.ValueObserver()
1819

@@ -96,16 +97,15 @@ extension Stepper: View {
9697
}
9798
.frame(width: (2 * buttonSize.width) + getStringSize(sizeCategory).width)
9899
.background(
99-
Capsule()
100-
.strokeBorder(Color(appearance.borderColor), lineWidth: appearance.borderWidth)
101-
.background(Capsule().foregroundColor(Color(appearance.backgroundColor)))
100+
getShape()
101+
.background(getShapeWithoutStroke().foregroundColor(Color(appearance.backgroundColor)))
102102
)
103103
}
104104

105105
@ViewBuilder
106106
func getIncrementButton() -> some View {
107107
Button { buttonAction(buttonType: .increment) } label: {
108-
getIncrementImage().renderingMode(.template).foregroundColor(Color(appearance.textStyle.textColor))
108+
getIncrementImage().renderingMode(.template)
109109
}
110110
.frame(width: buttonSize.width, height: buttonSize.height)
111111
.accessibilityLabel(StepperControl.Strings.incrementA11yButton.localized)
@@ -114,9 +114,7 @@ extension Stepper: View {
114114
@ViewBuilder
115115
func getDecrementButton() -> some View {
116116
Button { buttonAction(buttonType: .decrement) } label: {
117-
getImageForDecrementButton()?.renderingMode(.template).foregroundColor(
118-
Color(appearance.textStyle.textColor)
119-
)
117+
getImageForDecrementButton()?.renderingMode(.template)
120118
}
121119
.frame(width: buttonSize.width, height: buttonSize.height)
122120
.accessibilityLabel(getAccessibilityText())
@@ -129,10 +127,63 @@ extension Stepper: View {
129127
) { label in
130128
label.textAlignment = .center
131129
label.numberOfLines = 1
130+
label.textColor = appearance.textStyle.textColor
132131
}
133132
.frame(width: getStringSize(sizeCategory).width)
134133
.accessibilityLabel(getAccessibilityLabelText())
135134
}
135+
136+
@ViewBuilder
137+
func getShape() -> some View {
138+
switch appearance.shape {
139+
case .none:
140+
EmptyView()
141+
case .rectangle:
142+
Rectangle().strokeBorder(Color(appearance.borderColor), lineWidth: appearance.borderWidth)
143+
case .roundRect(cornerRadius: let cornerRadius):
144+
RoundedRectangle(
145+
cornerSize: CGSize(
146+
width: cornerRadius,
147+
height: cornerRadius
148+
)
149+
).strokeBorder(Color(appearance.borderColor), lineWidth: appearance.borderWidth)
150+
case .scaledRoundRect(cornerRadius: let cornerRadius):
151+
RoundedRectangle(
152+
cornerSize: CGSize(
153+
width: cornerRadius * scale,
154+
height: cornerRadius * scale
155+
)
156+
).strokeBorder(Color(appearance.borderColor), lineWidth: appearance.borderWidth)
157+
case .capsule:
158+
Capsule().strokeBorder(Color(appearance.borderColor), lineWidth: appearance.borderWidth)
159+
}
160+
}
161+
162+
@ViewBuilder
163+
func getShapeWithoutStroke() -> some View {
164+
switch appearance.shape {
165+
case .none:
166+
EmptyView()
167+
case .rectangle:
168+
Rectangle()
169+
case .roundRect(cornerRadius: let cornerRadius):
170+
RoundedRectangle(
171+
cornerSize: CGSize(
172+
width: cornerRadius,
173+
height: cornerRadius
174+
)
175+
)
176+
case .scaledRoundRect(cornerRadius: let cornerRadius):
177+
RoundedRectangle(
178+
cornerSize: CGSize(
179+
width: cornerRadius * scale,
180+
height: cornerRadius * scale
181+
)
182+
)
183+
case .capsule:
184+
Capsule()
185+
}
186+
}
136187
}
137188

138189
extension Stepper {

Sources/YStepper/UIKit/StepperControl+Appearance.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ extension StepperControl {
2626
public var incrementImage: UIImage
2727
/// Decrement button image
2828
public var decrementImage: UIImage
29+
/// Stepper's shape
30+
public var shape: Shape
2931
/// Whether to show delete button or not.
3032
var hasDeleteButton: Bool { deleteImage != nil }
3133

@@ -40,6 +42,8 @@ extension StepperControl {
4042
/// - deleteImage: Delete button image. Default is `Appearance.defaultDeleteImage`
4143
/// - incrementImage: Increment button image. Default is `Appearance.defaultIncrementImage`
4244
/// - decrementImage: Decrement button image. Default is `Appearance.defaultDecrementImage`
45+
/// - shape: Stepper's shape. Default is `.capsule`
46+
4347
public init(
4448
textStyle: (textColor: UIColor, typography: Typography) = (.label, .systemLabel),
4549
foregroundColor: UIColor = .label,
@@ -48,7 +52,8 @@ extension StepperControl {
4852
borderWidth: CGFloat = 1.0,
4953
deleteImage: UIImage? = Appearance.defaultDeleteImage,
5054
incrementImage: UIImage = Appearance.defaultIncrementImage,
51-
decrementImage: UIImage = Appearance.defaultDecrementImage
55+
decrementImage: UIImage = Appearance.defaultDecrementImage,
56+
shape: Shape = .capsule
5257
) {
5358
self.textStyle = textStyle
5459
self.backgroundColor = backgroundColor
@@ -57,6 +62,7 @@ extension StepperControl {
5762
self.deleteImage = deleteImage
5863
self.incrementImage = incrementImage
5964
self.decrementImage = decrementImage
65+
self.shape = shape
6066
}
6167
}
6268
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//
2+
// YStepper+Shapes.swift
3+
// YStepper
4+
//
5+
// Created by Sahil Saini on 15/03/23.
6+
// Copyright © 2023 Y Media Labs. All rights reserved.
7+
//
8+
9+
import UIKit
10+
11+
extension StepperControl.Appearance {
12+
/// Stepper's shape.
13+
public enum Shape: Equatable {
14+
/// None
15+
case none
16+
/// Rectangle.
17+
case rectangle
18+
/// Rounded rectangle.
19+
case roundRect(cornerRadius: CGFloat)
20+
/// Rounded rectangle that scales with Dynamic Type.
21+
case scaledRoundRect(cornerRadius: CGFloat)
22+
/// Capsule.
23+
case capsule
24+
}
25+
}

Tests/YStepperTests/Views/StepperTests.swift

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,13 +145,87 @@ final class StepperTests: XCTestCase {
145145
XCTAssertEqual(sut.value, sut.minimumValue)
146146
}
147147

148-
func testBackgroundNotNill() {
148+
func testBackgroundNotNil() {
149149
let sut = makeSUT()
150150
let button = sut.getDecrementButton()
151151

152152
XCTAssertNotNil(button)
153153
}
154154

155+
func testShapesNotNil() {
156+
var expectedAppearance = StepperControl.Appearance(shape: .rectangle)
157+
var sut = makeSUT(appearance: expectedAppearance)
158+
let rectShape = sut.getShape()
159+
160+
XCTAssertEqual(sut.appearance.shape, expectedAppearance.shape)
161+
XCTAssertNotNil(rectShape)
162+
163+
expectedAppearance = StepperControl.Appearance(shape: .roundRect(cornerRadius: 10))
164+
sut.appearance = expectedAppearance
165+
let roundedRectShape = sut.getShape()
166+
167+
XCTAssertEqual(sut.appearance.shape, expectedAppearance.shape)
168+
XCTAssertNotNil(roundedRectShape)
169+
170+
expectedAppearance = StepperControl.Appearance(shape: .scaledRoundRect(cornerRadius: 10))
171+
sut.appearance = expectedAppearance
172+
let scaledRoundRect = sut.getShape()
173+
174+
XCTAssertEqual(sut.appearance.shape, expectedAppearance.shape)
175+
XCTAssertNotNil(scaledRoundRect)
176+
177+
expectedAppearance = StepperControl.Appearance(shape: .capsule)
178+
sut.appearance = expectedAppearance
179+
let capsuleShape = sut.getShape()
180+
181+
XCTAssertEqual(sut.appearance.shape, expectedAppearance.shape)
182+
XCTAssertNotNil(capsuleShape)
183+
184+
expectedAppearance = StepperControl.Appearance(shape: .none)
185+
sut.appearance = expectedAppearance
186+
let emptyView = sut.getShape()
187+
188+
XCTAssertEqual(sut.appearance.shape, expectedAppearance.shape)
189+
XCTAssertNotNil(emptyView)
190+
}
191+
192+
func testShapesWithoutStrokeNotNil() {
193+
var expectedAppearance = StepperControl.Appearance(shape: .rectangle)
194+
var sut = makeSUT(appearance: expectedAppearance)
195+
let rectShape = sut.getShapeWithoutStroke()
196+
197+
XCTAssertEqual(sut.appearance.shape, expectedAppearance.shape)
198+
XCTAssertNotNil(rectShape)
199+
200+
expectedAppearance = StepperControl.Appearance(shape: .roundRect(cornerRadius: 10))
201+
sut.appearance = expectedAppearance
202+
let roundedRectShape = sut.getShapeWithoutStroke()
203+
204+
XCTAssertEqual(sut.appearance.shape, expectedAppearance.shape)
205+
XCTAssertNotNil(roundedRectShape)
206+
207+
expectedAppearance = StepperControl.Appearance(shape: .scaledRoundRect(cornerRadius: 10))
208+
sut.appearance = expectedAppearance
209+
let scaledRoundRect = sut.getShapeWithoutStroke()
210+
211+
XCTAssertEqual(sut.appearance.shape, expectedAppearance.shape)
212+
XCTAssertNotNil(scaledRoundRect)
213+
214+
expectedAppearance = StepperControl.Appearance(shape: .capsule)
215+
sut.appearance = expectedAppearance
216+
let capsuleShape = sut.getShapeWithoutStroke()
217+
218+
XCTAssertEqual(sut.appearance.shape, expectedAppearance.shape)
219+
XCTAssertNotNil(capsuleShape)
220+
221+
expectedAppearance = StepperControl.Appearance(shape: .none)
222+
sut.appearance = expectedAppearance
223+
let emptyView = sut.getShapeWithoutStroke()
224+
225+
XCTAssertEqual(sut.appearance.shape, expectedAppearance.shape)
226+
XCTAssertNotNil(emptyView)
227+
}
228+
155229
func testPreviewNotNil() {
156230
XCTAssertNotNil(Stepper_Previews.previews)
157231
}

0 commit comments

Comments
 (0)