Skip to content

[CM-1252] Add layout to set edge insets #6

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 3 commits into from
Mar 20, 2023
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
14 changes: 6 additions & 8 deletions Sources/YStepper/SwiftUI/Views/Stepper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import YMatterType
/// A SwiftUI stepper control.
public struct Stepper {
@Environment(\.sizeCategory) var sizeCategory
let buttonSize: CGSize = CGSize(width: 44, height: 44)

@ScaledMetric var scale = 1.0
@ObservedObject private var appearanceObserver = Stepper.AppearanceObserver()
@ObservedObject private var valueObserver = Stepper.ValueObserver()
Expand Down Expand Up @@ -90,12 +90,12 @@ public struct Stepper {
extension Stepper: View {
/// :nodoc:
public var body: some View {
HStack(spacing: 0) {
HStack(spacing: appearance.layout.gap) {
getDecrementButton()
getTextView()
getIncrementButton()
}
.frame(width: (2 * buttonSize.width) + getStringSize(sizeCategory).width)
.padding(EdgeInsets(appearance.layout.contentInset))
.background(
getShape()
.background(getShapeWithoutStroke().foregroundColor(Color(appearance.backgroundColor)))
Expand All @@ -107,7 +107,6 @@ extension Stepper: View {
Button { buttonAction(buttonType: .increment) } label: {
getIncrementImage().renderingMode(.template)
}
.frame(width: buttonSize.width, height: buttonSize.height)
.accessibilityLabel(StepperControl.Strings.incrementA11yButton.localized)
}

Expand All @@ -116,7 +115,6 @@ extension Stepper: View {
Button { buttonAction(buttonType: .decrement) } label: {
getImageForDecrementButton()?.renderingMode(.template)
}
.frame(width: buttonSize.width, height: buttonSize.height)
.accessibilityLabel(getAccessibilityText())
}

Expand All @@ -135,7 +133,7 @@ extension Stepper: View {

@ViewBuilder
func getShape() -> some View {
switch appearance.shape {
switch appearance.layout.shape {
case .none:
EmptyView()
case .rectangle:
Expand All @@ -161,7 +159,7 @@ extension Stepper: View {

@ViewBuilder
func getShapeWithoutStroke() -> some View {
switch appearance.shape {
switch appearance.layout.shape {
case .none:
EmptyView()
case .rectangle:
Expand Down Expand Up @@ -276,7 +274,7 @@ extension Stepper {

private extension Stepper {
func onMinimumValueChange(newValue: Double) {
if minimumValue < maximumValue {
if newValue < maximumValue {
valueObserver.minimumValue = newValue
if value < minimumValue {
valueObserver.value = minimumValue
Expand Down
41 changes: 41 additions & 0 deletions Sources/YStepper/UIKit/StepperControl+Appearance+Layout.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// StepperControl+Appearance+Layout.swift
// YStepper
//
// Created by Sahil Saini on 20/03/23.
// Copyright © 2023 Y Media Labs. All rights reserved.
//

import UIKit

extension StepperControl.Appearance {
/// A collection of layout properties for the `StepperControl`
public struct Layout: Equatable {
/// The content inset from edges. Stepper "content" consists of the two buttons and the text label between them.
/// Default is `{8, 16, 8, 16}`.
public var contentInset: NSDirectionalEdgeInsets
/// The horizontal spacing between the stepper buttons and label. Default is `8.0`
public var gap: CGFloat
/// Stepper's shape
public var shape: Shape

/// Default stepper control layout.
public static let `default` = Layout()

/// Initializes a `Layout`.
/// - Parameters:
/// - contentInset: content inset from edges
/// - gap: horizontal spacing between icons and label
/// - shape: Stepper's shape. Default is `.capsule`
public init(
contentInset: NSDirectionalEdgeInsets =
NSDirectionalEdgeInsets(topAndBottom: 8, leadingAndTrailing: 16),
gap: CGFloat = 8,
shape: Shape = .capsule
) {
self.contentInset = contentInset
self.gap = gap
self.shape = shape
}
}
}
12 changes: 6 additions & 6 deletions Sources/YStepper/UIKit/StepperControl+Appearance.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ extension StepperControl {
public var incrementImage: UIImage
/// Decrement button image
public var decrementImage: UIImage
/// Stepper's shape
public var shape: Shape
/// Whether to show delete button or not.
/// Stepper's layout properties such as spacing between views. Default is `.default`
public var layout: Layout
/// Whether to show delete button or not
var hasDeleteButton: Bool { deleteImage != nil }

/// Initializer for appearance
Expand All @@ -42,7 +42,7 @@ extension StepperControl {
/// - deleteImage: Delete button image. Default is `Appearance.defaultDeleteImage`
/// - incrementImage: Increment button image. Default is `Appearance.defaultIncrementImage`
/// - decrementImage: Decrement button image. Default is `Appearance.defaultDecrementImage`
/// - shape: Stepper's shape. Default is `.capsule`
/// - layout: Stepper's layout properties like spacing between views

public init(
textStyle: (textColor: UIColor, typography: Typography) = (.label, .systemLabel),
Expand All @@ -53,7 +53,7 @@ extension StepperControl {
deleteImage: UIImage? = Appearance.defaultDeleteImage,
incrementImage: UIImage = Appearance.defaultIncrementImage,
decrementImage: UIImage = Appearance.defaultDecrementImage,
shape: Shape = .capsule
layout: Layout = .default
) {
self.textStyle = textStyle
self.backgroundColor = backgroundColor
Expand All @@ -62,7 +62,7 @@ extension StepperControl {
self.deleteImage = deleteImage
self.incrementImage = incrementImage
self.decrementImage = decrementImage
self.shape = shape
self.layout = layout
}
}
}
Expand Down
48 changes: 28 additions & 20 deletions Tests/YStepperTests/Views/StepperTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -153,76 +153,84 @@ final class StepperTests: XCTestCase {
}

func testShapesNotNil() {
var expectedAppearance = StepperControl.Appearance(shape: .rectangle)
var expectedAppearance = StepperControl.Appearance(layout: StepperControl.Appearance.Layout(shape: .rectangle))
var sut = makeSUT(appearance: expectedAppearance)
let rectShape = sut.getShape()

XCTAssertEqual(sut.appearance.shape, expectedAppearance.shape)
XCTAssertEqual(sut.appearance.layout.shape, expectedAppearance.layout.shape)
XCTAssertNotNil(rectShape)

expectedAppearance = StepperControl.Appearance(shape: .roundRect(cornerRadius: 10))
expectedAppearance = StepperControl.Appearance(
layout: StepperControl.Appearance.Layout(shape: .roundRect(cornerRadius: 10))
)
sut.appearance = expectedAppearance
let roundedRectShape = sut.getShape()

XCTAssertEqual(sut.appearance.shape, expectedAppearance.shape)
XCTAssertEqual(sut.appearance.layout.shape, expectedAppearance.layout.shape)
XCTAssertNotNil(roundedRectShape)

expectedAppearance = StepperControl.Appearance(shape: .scaledRoundRect(cornerRadius: 10))
expectedAppearance = StepperControl.Appearance(
layout: StepperControl.Appearance.Layout(shape: .scaledRoundRect(cornerRadius: 10))
)
sut.appearance = expectedAppearance
let scaledRoundRect = sut.getShape()

XCTAssertEqual(sut.appearance.shape, expectedAppearance.shape)
XCTAssertEqual(sut.appearance.layout.shape, expectedAppearance.layout.shape)
XCTAssertNotNil(scaledRoundRect)

expectedAppearance = StepperControl.Appearance(shape: .capsule)
expectedAppearance = StepperControl.Appearance(layout: StepperControl.Appearance.Layout(shape: .capsule))
sut.appearance = expectedAppearance
let capsuleShape = sut.getShape()

XCTAssertEqual(sut.appearance.shape, expectedAppearance.shape)
XCTAssertEqual(sut.appearance.layout.shape, expectedAppearance.layout.shape)
XCTAssertNotNil(capsuleShape)

expectedAppearance = StepperControl.Appearance(shape: .none)
expectedAppearance = StepperControl.Appearance(layout: StepperControl.Appearance.Layout(shape: .none))
sut.appearance = expectedAppearance
let emptyView = sut.getShape()

XCTAssertEqual(sut.appearance.shape, expectedAppearance.shape)
XCTAssertEqual(sut.appearance.layout.shape, expectedAppearance.layout.shape)
XCTAssertNotNil(emptyView)
}

func testShapesWithoutStrokeNotNil() {
var expectedAppearance = StepperControl.Appearance(shape: .rectangle)
var expectedAppearance = StepperControl.Appearance(layout: StepperControl.Appearance.Layout(shape: .rectangle))
var sut = makeSUT(appearance: expectedAppearance)
let rectShape = sut.getShapeWithoutStroke()

XCTAssertEqual(sut.appearance.shape, expectedAppearance.shape)
XCTAssertEqual(sut.appearance.layout.shape, expectedAppearance.layout.shape)
XCTAssertNotNil(rectShape)

expectedAppearance = StepperControl.Appearance(shape: .roundRect(cornerRadius: 10))
expectedAppearance = StepperControl.Appearance(
layout: StepperControl.Appearance.Layout(shape: .roundRect(cornerRadius: 10))
)
sut.appearance = expectedAppearance
let roundedRectShape = sut.getShapeWithoutStroke()

XCTAssertEqual(sut.appearance.shape, expectedAppearance.shape)
XCTAssertEqual(sut.appearance.layout.shape, expectedAppearance.layout.shape)
XCTAssertNotNil(roundedRectShape)

expectedAppearance = StepperControl.Appearance(shape: .scaledRoundRect(cornerRadius: 10))
expectedAppearance = StepperControl.Appearance(
layout: StepperControl.Appearance.Layout(shape: .scaledRoundRect(cornerRadius: 10))
)
sut.appearance = expectedAppearance
let scaledRoundRect = sut.getShapeWithoutStroke()

XCTAssertEqual(sut.appearance.shape, expectedAppearance.shape)
XCTAssertEqual(sut.appearance.layout.shape, expectedAppearance.layout.shape)
XCTAssertNotNil(scaledRoundRect)

expectedAppearance = StepperControl.Appearance(shape: .capsule)
expectedAppearance = StepperControl.Appearance(layout: StepperControl.Appearance.Layout(shape: .capsule))
sut.appearance = expectedAppearance
let capsuleShape = sut.getShapeWithoutStroke()

XCTAssertEqual(sut.appearance.shape, expectedAppearance.shape)
XCTAssertEqual(sut.appearance.layout.shape, expectedAppearance.layout.shape)
XCTAssertNotNil(capsuleShape)

expectedAppearance = StepperControl.Appearance(shape: .none)
expectedAppearance = StepperControl.Appearance(layout: StepperControl.Appearance.Layout(shape: .none))
sut.appearance = expectedAppearance
let emptyView = sut.getShapeWithoutStroke()

XCTAssertEqual(sut.appearance.shape, expectedAppearance.shape)
XCTAssertEqual(sut.appearance.layout.shape, expectedAppearance.layout.shape)
XCTAssertNotNil(emptyView)
}

Expand Down