Skip to content

Commit

Permalink
Improve digitalCrown experience
Browse files Browse the repository at this point in the history
  • Loading branch information
fermoya committed Apr 7, 2022
1 parent bbe61ad commit b898aef
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 43 deletions.
2 changes: 2 additions & 0 deletions Sources/SwiftUIPager/Page.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ public class Page: ObservableObject {

var isInfinite = false

var lastDigitalCrownPageOffset: CGFloat = 0

/// Initializes a new instance
///
/// - Parameter page: Current page index
Expand Down
26 changes: 13 additions & 13 deletions Sources/SwiftUIPager/Pager+Buildable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,6 @@ extension Pager: Buildable {

#if !os(tvOS)

/// Sets the explicit animation to be used. Defaults to `.standard`
///
/// - Parameter value: animation to use while dragging and to page
///
/// - Warning: `spring` animations don't work well. Avoid high responses while dragging as the animation should be short
public func draggingAnimation(_ value: DraggingAnimation) -> Self {
mutating(keyPath: \.draggingAnimation, value: value)
}

/// User can only swipe forward so in one direction
///
/// - Parameter enabled: by default dragForwardOnly is disables so pages can be scrolled in both directions,
Expand Down Expand Up @@ -169,8 +160,19 @@ extension Pager: Buildable {
mutating(keyPath: \.onDraggingEnded, value: callback)
}

#else

#endif

/// Adds a callback to react when _iWatch Digital Crown_ is rotated
///
/// - Parameter callback: block to be called when dragging begins
@available(iOS, unavailable)
@available(macOS, unavailable)
@available(tvOS, unavailable)
@available(watchOS 7.0, *)
public func onDigitalCrownRotated(_ callback: ((Double) -> Void)?) -> Self {
mutating(keyPath: \.onDigitalCrownRotated, value: callback)
}

/// Sets the explicit animation to be used. Defaults to `.standard`
///
/// - Parameter value: animation to use while dragging and to page
Expand All @@ -180,8 +182,6 @@ extension Pager: Buildable {
mutating(keyPath: \.draggingAnimation, value: value)
}

#endif

/// Changes the a the alignment of the pages relative to their container
///
/// - Parameter value: alignment of the pages inside the scroll
Expand Down
15 changes: 12 additions & 3 deletions Sources/SwiftUIPager/Pager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -153,15 +153,18 @@ public struct Pager<Element, ID, PageView>: View where PageView: View, Element:
/// Callback invoked when a new page is set
var onPageChanged: ((Int) -> Void)?

/// Callback for when dragging begins
/// Callback for a dragging began event
var onDraggingBegan: (() -> Void)?

/// Callback for when dragging changes
/// Callback for a dragging changed event
var onDraggingChanged: ((Double) -> Void)?

/// Callback for when dragging ends
/// Callback for a dragging ended event
var onDraggingEnded: (() -> Void)?

/// Callback for a digital crown rotated event
var onDigitalCrownRotated: ((Double) -> Void)?

/*** State and Binding properties ***/

let pagerModel: Page
Expand Down Expand Up @@ -227,6 +230,12 @@ public struct Pager<Element, ID, PageView>: View where PageView: View, Element:
pagerContent = pagerContent.draggingAnimation(draggingAnimation)
#endif

#if os(watchOS)
if #available(watchOS 7.0, *) {
pagerContent = pagerContent.onDigitalCrownRotated(onDigitalCrownRotated)
}
#endif

pagerContent = allowsMultiplePagination ? pagerContent.multiplePagination() : pagerContent
pagerContent = isHorizontal ? pagerContent.horizontal(horizontalSwipeDirection) : pagerContent.vertical(verticalSwipeDirection)

Expand Down
26 changes: 13 additions & 13 deletions Sources/SwiftUIPager/PagerContent+Buildable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,6 @@ extension Pager.PagerContent: Buildable {

#if !os(tvOS)

/// Sets the explicit animation to be used. Defaults to `.standard`
///
/// - Parameter value: animation to use while dragging and to page
///
/// - Warning: `spring` animations don't work well. Avoid high responses while dragging as the animation should be short
func draggingAnimation(_ value: DraggingAnimation) -> Self {
mutating(keyPath: \.draggingAnimation, value: value)
}

/// User can only swipe forward so in one direction
///
/// - Parameter enabled: by default dragForwardOnly is disables so pages can be scrolled in both directions,
Expand Down Expand Up @@ -166,19 +157,28 @@ extension Pager.PagerContent: Buildable {
mutating(keyPath: \.onDraggingEnded, value: callback)
}

#else
#endif

/// Adds a callback to react when _iWatch Digital Crown_ is rotated
///
/// - Parameter callback: block to be called when dragging begins
@available(iOS, unavailable)
@available(macOS, unavailable)
@available(tvOS, unavailable)
@available(watchOS 7.0, *)
func onDigitalCrownRotated(_ callback: ((Double) -> Void)?) -> Self {
mutating(keyPath: \.onDigitalCrownRotated, value: callback)
}

/// Sets the explicit animation to be used. Defaults to `.standard`
///
/// - Parameter value: animation to use while dragging and to page
///
/// - Warning: `spring` animations don't work well. Avoid high responses while dragging as the animation should be short
public func draggingAnimation(_ value: DraggingAnimation) -> Self {
func draggingAnimation(_ value: DraggingAnimation) -> Self {
mutating(keyPath: \.draggingAnimation, value: value)
}

#endif

/// Changes the a the alignment of the pages relative to their container
///
/// - Parameter value: alignment of the pages inside the scroll
Expand Down
37 changes: 24 additions & 13 deletions Sources/SwiftUIPager/PagerContent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -131,15 +131,18 @@ extension Pager {
/// Callback invoked when a new page is set
var onPageChanged: ((Int) -> Void)?

/// Callback for when dragging begins
/// Callback for a dragging began event
var onDraggingBegan: (() -> Void)?

/// Callback for when dragging changes
/// Callback for a dragging changed event
var onDraggingChanged: ((Double) -> Void)?

/// Callback for when dragging ends
/// Callback for a dragging ended event
var onDraggingEnded: (() -> Void)?

/// Callback for a digital crown rotated event
var onDigitalCrownRotated: ((Double) -> Void)?

/*** State and Binding properties ***/

/// Page index
Expand All @@ -155,9 +158,6 @@ extension Pager {
/// Digital Crown offset
@State var digitalCrownPageOffset: CGFloat = 0

/// Digital Crown offset
@State var lastDigitalCrownPageOffset: CGFloat = 0

#endif

/// Initializes a new `Pager`.
Expand Down Expand Up @@ -246,7 +246,7 @@ extension Pager {
#endif

#if os(watchOS)
if #available(watchOSApplicationExtension 7.0, *) {
if #available(watchOS 7.0, *) {
resultView = resultView
.focusable()
.digitalCrownRotation(
Expand All @@ -257,12 +257,21 @@ extension Pager {
sensitivity: .low
)
.onChange(of: digitalCrownPageOffset) { newValue in
print(newValue)
let increment = min(1, max(-1, Int(newValue - lastDigitalCrownPageOffset)))
guard abs(increment) > 0 else { return }
lastDigitalCrownPageOffset = newValue
withAnimation {
pagerModel.update(.move(increment: increment))
let pageIncrement = min(1, max(-1, Int(newValue - pagerModel.lastDigitalCrownPageOffset)))
let offset = (newValue - pagerModel.lastDigitalCrownPageOffset) - CGFloat(pageIncrement)
onDigitalCrownRotated?(newValue * pageDistance)
let animation = self.draggingAnimation.animation ?? .default
guard abs(pageIncrement) > 0 else {
withAnimation(animation) {
pagerModel.draggingOffset = -offset * pageDistance
pagerModel.objectWillChange.send()
}
return
}
withAnimation(animation) {
pagerModel.lastDigitalCrownPageOffset = newValue - offset
pagerModel.draggingOffset = -offset
pagerModel.update(.move(increment: pageIncrement))
}
}
.eraseToAny()
Expand All @@ -284,10 +293,12 @@ extension Pager.PagerContent {
let animation = self.draggingAnimation.animation ?? .default
switch (command, isHorizontal) {
case (.left, true):
guard !dragForwardOnly else { return }
withAnimation(animation) { self.pagerModel.update(.previous) }
case (.right, true):
withAnimation(animation) { self.pagerModel.update(.next) }
case (.up, false):
guard !dragForwardOnly else { return }
withAnimation(animation) { self.pagerModel.update(.previous) }
case (.down, false):
withAnimation(animation) { self.pagerModel.update(.next) }
Expand Down
3 changes: 2 additions & 1 deletion release_description.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
### Features
- #254 New modifier `dragForwardOnly`
- #254 New modifier `dragForwardOnly`
- #265 Support for _watchOS_ `digitalCrownRotation`

0 comments on commit b898aef

Please sign in to comment.