Skip to content

Commit

Permalink
Fixes RTL support (#5)
Browse files Browse the repository at this point in the history
closes #4 
---------

Co-authored-by: Bjørn Inge Berg <bjorninge-git@bjorninge.no>
Co-authored-by: Miká Kruschel <20423069+mikakruschel@users.noreply.github.com>
  • Loading branch information
3 people authored Dec 29, 2023
1 parent 82e9076 commit 5eacebb
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 4 deletions.
23 changes: 19 additions & 4 deletions Sources/SlideButton/SlideButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ public struct SlideButton<Label: View>: View {
@GestureState private var offset: CGFloat
@State private var swipeState: SwipeState = .start

@Environment(\.layoutDirection) private var layoutDirection

// When layoutdirection is RTL, the indicatorshape will be right aligned
// instead of left aligned and values need to be negated
private var layoutDirectionMultiplier: Double {
self.layoutDirection == .rightToLeft ? -1 : 1
}

/// Initializes a slide button with the given title, styling options, and action.
///
/// Use this initializer to create a new instance of `SlideButton` with the given title, styling, and callback. The `styling` parameter allows you to customize the appearance of the slide button, such as changing the size and color of the indicator, the alignment of the title text, and whether the text fades or hides behind the indicator. The `action` parameter is executed when the user successfully swipes the indicator.
Expand Down Expand Up @@ -110,6 +118,7 @@ public struct SlideButton<Label: View>: View {
.foregroundColor(.white)
.font(.system(size: max(0.4 * styling.indicatorSize, 0.5 * styling.indicatorSize - 2 * styling.indicatorSpacing), weight: .semibold))
.opacity(swipeState == .end ? 0 : 1)
.rotationEffect(Angle(degrees: styling.indicatorRotatesForRTL && self.layoutDirection == .rightToLeft ? 180 : 0))
}
})
.offset(x: calculatedOffset)
Expand All @@ -127,23 +136,29 @@ public struct SlideButton<Label: View>: View {
#endif
}
}
state = clampValue(value: value.translation.width, min: styling.indicatorSpacing, max: reading.size.width - styling.indicatorSize + styling.indicatorSpacing)

let val = value.translation.width * layoutDirectionMultiplier

state = clampValue(value: val, min: styling.indicatorSpacing, max: reading.size.width - styling.indicatorSize + styling.indicatorSpacing)
}
.onEnded { value in
guard swipeState == .swiping else { return }
swipeState = .end

if value.predictedEndTranslation.width > reading.size.width
|| value.translation.width > reading.size.width - styling.indicatorSize - 2 * styling.indicatorSpacing {
let predictedVal = value.predictedEndTranslation.width * layoutDirectionMultiplier
let val = value.translation.width * layoutDirectionMultiplier

if predictedVal > reading.size.width
|| val > reading.size.width - styling.indicatorSize - 2 * styling.indicatorSpacing {
Task {
#if os(iOS)
UIImpactFeedbackGenerator(style: .light).impactOccurred()
#endif

await callback()

swipeState = .start
}

} else {
swipeState = .start
#if os(iOS)
Expand Down
6 changes: 6 additions & 0 deletions Sources/SlideButton/SlideButtonStyling.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ public struct SlideButtonStyling {
/// - indicatorSize: The size of the indicator. Default is `60`.
/// - indicatorSpacing: The spacing between the indicator and the border / button title. Default is `5`.
/// - indicatorColor: The color of the indicator. Default is `.accentColor`.
/// - indicatorShape: The shape type of the indicator. Default is `.circular`.
/// - indicatorRotatesForRTL: Whether to rotate the indicator for right-to-left layout or not. Default is `true`.
/// - indicatorBrightness: The brightness of the indicator if enabled. Default is `0.0`.
/// - backgroundColor: The color of the background. Default is `nil`, which sets the background color to a 30% opacity version of the indicator color.
/// - textColor: The color of the title text. Default is `.secondary`.
/// - indicatorSystemName: The system name of the icon used for the indicator. Default is `"chevron.right"`.
Expand All @@ -25,6 +28,7 @@ public struct SlideButtonStyling {
indicatorSpacing: CGFloat = 5,
indicatorColor: Color = .accentColor,
indicatorShape: ShapeType = .circular,
indicatorRotatesForRTL: Bool = true,
indicatorBrightness: Double = 0.0,
backgroundColor: Color? = nil,
textColor: Color = .secondary,
Expand All @@ -39,6 +43,7 @@ public struct SlideButtonStyling {
self.indicatorSpacing = indicatorSpacing
self.indicatorShape = indicatorShape
self.indicatorBrightness = indicatorBrightness
self.indicatorRotatesForRTL = indicatorRotatesForRTL

self.indicatorColor = indicatorColor
self.backgroundColor = backgroundColor ?? indicatorColor.opacity(0.3)
Expand All @@ -55,6 +60,7 @@ public struct SlideButtonStyling {
var indicatorSize: CGFloat
var indicatorSpacing: CGFloat
var indicatorShape: ShapeType
var indicatorRotatesForRTL: Bool
var indicatorBrightness: Double

var indicatorColor: Color
Expand Down

0 comments on commit 5eacebb

Please sign in to comment.