Skip to content
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

Cleanup states #45

Merged
merged 1 commit into from
Aug 3, 2021
Merged
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
105 changes: 55 additions & 50 deletions Rideau/RideauInternalView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -114,20 +114,24 @@ final class RideauInternalView : RideauTouchThroughView {
private var oldValueSet: CachedValueSet?

private let scrollController: ScrollController = .init()

// To tracking pan gesture
private var lastOffset: CGPoint!
private var shouldKillDecelerate: Bool = false
private var initialLocation: ResolvedConfiguration.Location?
private var hasReachedMostTop: Bool = false
private var initialShowsVerticalScrollIndicator: Bool = false

private struct TrackingState {
// To tracking pan gesture
var lastOffset: CGPoint!
var shouldKillDecelerate: Bool = false
var initialLocation: ResolvedConfiguration.Location?
var hasReachedMostTop: Bool = false
var initialShowsVerticalScrollIndicator: Bool = false
var beganPoint: CGPoint = .zero
var _isPanGestureTracking = false
}

private var trackingState: TrackingState = .init()

private var hasTakenAlongsideAnimators: Bool = false

private let panGesture = RideauViewDragGestureRecognizer()

private var beganPoint: CGPoint = .zero
private var _isPanGestureTracking = false

// MARK: - Initializers

init(
Expand Down Expand Up @@ -424,14 +428,15 @@ final class RideauInternalView : RideauTouchThroughView {
case .began:

throttlingGesture_preparation: do {
_isPanGestureTracking = false
beganPoint = gesture.location(in: gesture.view?.window)
trackingState._isPanGestureTracking = false
trackingState.beganPoint = gesture.location(in: gesture.view?.window)
}

initialLocation = currentLocation
shouldKillDecelerate = false
trackingState.initialLocation = currentLocation
trackingState.shouldKillDecelerate = false
trackingState.hasReachedMostTop = false

isInteracting = true
hasReachedMostTop = false

containerDraggingAnimator?.pauseAnimation()
containerDraggingAnimator?.stopAnimation(true)
Expand All @@ -443,98 +448,98 @@ final class RideauInternalView : RideauTouchThroughView {
if let scrollView = targetScrollView {
scrollController.startTracking(scrollView: scrollView)
scrollController.lockScrolling()
lastOffset = scrollView.contentOffset
initialShowsVerticalScrollIndicator = scrollView.showsVerticalScrollIndicator
trackingState.lastOffset = scrollView.contentOffset
trackingState.initialShowsVerticalScrollIndicator = scrollView.showsVerticalScrollIndicator
}

fallthrough
case .changed:

throttlingGesture_run: do {
let locationInWindow = gesture.location(in: gesture.view?.window)
if _isPanGestureTracking == false, abs(beganPoint.y - locationInWindow.y) < 15 {
if trackingState._isPanGestureTracking == false, abs(trackingState.beganPoint.y - locationInWindow.y) < 15 {
return
} else {
_isPanGestureTracking = true
trackingState._isPanGestureTracking = true
}
}

let isCurrentReachedMostTop = isReachedMostTop(location: currentLocation)

hasReachedMostTop = hasReachedMostTop ? hasReachedMostTop : isCurrentReachedMostTop
trackingState.hasReachedMostTop = trackingState.hasReachedMostTop ? trackingState.hasReachedMostTop : isCurrentReachedMostTop

var skipsDragging = false

if let scrollView = targetScrollView {

let isInitialReachedMostTop = isReachedMostTop(location: initialLocation!)
let isInitialReachedMostTop = isReachedMostTop(location: trackingState.initialLocation!)

let isScrollingDown = gesture.velocity(in: gesture.view).y > 0
let isScrollViewOnTop = scrollView.contentOffset.y <= -_getActualContentInset(from: scrollView).top

skipsDragging = !isScrollViewOnTop

assert(lastOffset != nil)
assert(trackingState.lastOffset != nil)

if isScrollingDown {

switch (isScrollViewOnTop, isInitialReachedMostTop, isCurrentReachedMostTop, hasReachedMostTop) {
switch (isScrollViewOnTop, isInitialReachedMostTop, isCurrentReachedMostTop, trackingState.hasReachedMostTop) {
case (false, false, false, true):
scrollController.unlockScrolling()
shouldKillDecelerate = true
lastOffset = scrollView.contentOffset
trackingState.shouldKillDecelerate = true
trackingState.lastOffset = scrollView.contentOffset
return
case (false, false, false, false):
scrollController.unlockScrolling()
shouldKillDecelerate = true
scrollView.contentOffset = lastOffset!
trackingState.shouldKillDecelerate = true
scrollView.contentOffset = trackingState.lastOffset!
skipsDragging = false
case (true, true, false, _):
shouldKillDecelerate = true
trackingState.shouldKillDecelerate = true
scrollController.lockScrolling()
lastOffset = scrollView.contentOffset
trackingState.lastOffset = scrollView.contentOffset
case (false, true, true, _):
scrollController.unlockScrolling()
shouldKillDecelerate = false
lastOffset = scrollView.contentOffset
trackingState.shouldKillDecelerate = false
trackingState.lastOffset = scrollView.contentOffset
return
case (false, true, false, _):
scrollController.unlockScrolling()
shouldKillDecelerate = true
lastOffset = scrollView.contentOffset
trackingState.shouldKillDecelerate = true
trackingState.lastOffset = scrollView.contentOffset
return
case (true, false, false, _):
shouldKillDecelerate = true
trackingState.shouldKillDecelerate = true
scrollController.lockScrolling()
lastOffset = scrollView.contentOffset
trackingState.lastOffset = scrollView.contentOffset
case (false, false, true, _):
scrollController.unlockScrolling()
shouldKillDecelerate = false
lastOffset = scrollView.contentOffset
trackingState.shouldKillDecelerate = false
trackingState.lastOffset = scrollView.contentOffset
return
default:
scrollController.unlockScrolling()
shouldKillDecelerate = false
lastOffset = scrollView.contentOffset
trackingState.shouldKillDecelerate = false
trackingState.lastOffset = scrollView.contentOffset
break
}

} else {

if isCurrentReachedMostTop {
shouldKillDecelerate = false
lastOffset = scrollView.contentOffset
trackingState.shouldKillDecelerate = false
trackingState.lastOffset = scrollView.contentOffset
scrollController.unlockScrolling()
} else {
skipsDragging = false
scrollView.contentOffset = lastOffset!
scrollView.contentOffset = trackingState.lastOffset!
scrollController.lockScrolling()
shouldKillDecelerate = true
trackingState.shouldKillDecelerate = true
}
}

if initialShowsVerticalScrollIndicator {
scrollView.showsVerticalScrollIndicator = !shouldKillDecelerate
if trackingState.initialShowsVerticalScrollIndicator {
scrollView.showsVerticalScrollIndicator = !trackingState.shouldKillDecelerate
}

}
Expand Down Expand Up @@ -603,25 +608,25 @@ final class RideauInternalView : RideauTouchThroughView {
}

if let scrollView = targetScrollView {
lastOffset = scrollView.contentOffset
trackingState.lastOffset = scrollView.contentOffset
}

case .ended, .cancelled, .failed:

scrollController.endTracking()

if let scrollView = targetScrollView, shouldKillDecelerate {
if let scrollView = targetScrollView, trackingState.shouldKillDecelerate {
// To perform task next event loop.
DispatchQueue.main.async {
DispatchQueue.main.async { [self] in

var targetOffset = self.lastOffset!
var targetOffset = trackingState.lastOffset!
let insetTop = _getActualContentInset(from: scrollView).top
if targetOffset.y < -insetTop {
// Workaround: sometimes, scrolling-lock may be failed. ContentOffset has a little bit negative offset.
targetOffset.y = -insetTop
}
scrollView.setContentOffset(targetOffset, animated: false)
scrollView.showsVerticalScrollIndicator = self.initialShowsVerticalScrollIndicator
scrollView.showsVerticalScrollIndicator = trackingState.initialShowsVerticalScrollIndicator
}
}

Expand Down