Skip to content

Commit e4b3556

Browse files
committed
Tapbacks sheet: slide down on drag instead of shrinking
Below the resting stop the sheet no longer shrinks under damping — it slides down 1:1 with the finger so the dismiss threshold matches what the user sees. A hard downward flick dismisses from either stop; release mid-slide continues from the current position. Co-authored-by: D3C0Y <decoder-dev@users.noreply.github.com>
1 parent b31b699 commit e4b3556

1 file changed

Lines changed: 26 additions & 15 deletions

File tree

‎submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift‎

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -565,21 +565,27 @@ public final class ReactionContextNode: ASDisplayNode, ASScrollViewDelegate {
565565
)
566566
}
567567

568-
/// The height to lay the sheet out at: the stop it is resting at, moved by however far the
569-
/// grabber drag has taken it. Past either stop the drag is damped, so the sheet stays under the
570-
/// finger without growing off-screen or collapsing to nothing before the release decides.
571-
private func tapbacksPickerHeight(size: CGSize, insets: UIEdgeInsets) -> CGFloat {
568+
/// Where to lay the sheet out: the stop it is resting at, moved by however far the grabber drag
569+
/// has taken it.
570+
///
571+
/// Between the two stops the drag changes the sheet's height, so more of the grid comes into
572+
/// view as it rises; above the top stop that is damped hard, since there is nowhere left to go.
573+
/// Below the resting stop the sheet stops shrinking and slides down the screen instead, one to
574+
/// one with the finger — a sheet on its way out should look like it is leaving, and shrinking
575+
/// it there would drop grid rows a few at a time instead.
576+
private func tapbacksPickerGeometry(size: CGSize, insets: UIEdgeInsets) -> (height: CGFloat, bottomOverscroll: CGFloat) {
572577
let collapsed = self.tapbacksPickerCollapsedHeight(size: size, bottomInset: insets.bottom)
573578
let expanded = self.tapbacksPickerExpandedHeight(size: size, insets: insets)
574579
let resting = self.tapbacksPickerIsExpanded ? expanded : collapsed
575580
// Dragging up is a negative translation and has to make the sheet taller.
576-
var height = resting - self.tapbacksPickerDragOffset
577-
if height > expanded {
578-
height = expanded + (height - expanded) * 0.15
579-
} else if height < collapsed {
580-
height = collapsed - (collapsed - height) * 0.25
581+
let rawHeight = resting - self.tapbacksPickerDragOffset
582+
if rawHeight > expanded {
583+
return (expanded + (rawHeight - expanded) * 0.15, 0.0)
584+
} else if rawHeight < collapsed {
585+
return (collapsed, collapsed - rawHeight)
586+
} else {
587+
return (rawHeight, 0.0)
581588
}
582-
return max(EmojiStatusSelectionComponent.bottomDockHeaderHeight + insets.bottom, height)
583589
}
584590

585591
/// Drags the Tapbacks sheet between its two stops. Only the 44pt header drags — the recognizer
@@ -626,9 +632,11 @@ public final class ReactionContextNode: ASDisplayNode, ASScrollViewDelegate {
626632
shouldExpand = abs(currentHeight - expanded) < abs(currentHeight - collapsed)
627633
}
628634

629-
// Pulled down off the collapsed stop: the sheet is on its way out, which is what this
630-
// gesture does to every other sheet in the app.
631-
if !wasExpanded, !shouldExpand, (currentHeight < collapsed - 40.0) || (velocity > Self.tapbacksPickerDismissVelocity) {
635+
// Thrown down hard from either stop, or dragged well below the resting one: the sheet
636+
// closes back to the reaction pill, the same thing its close button does. Distance only
637+
// counts from the resting stop — from the top stop a slow drag down has a stop of its
638+
// own to land on first.
639+
if !shouldExpand, (velocity > Self.tapbacksPickerDismissVelocity) || (!wasExpanded && currentHeight < collapsed - 40.0) {
632640
self.collapse()
633641
return
634642
}
@@ -1885,7 +1893,10 @@ public final class ReactionContextNode: ASDisplayNode, ASScrollViewDelegate {
18851893
}
18861894

18871895
let pickerContainerWidth = tapbacksBottomPickerActive ? size.width : actualBackgroundFrame.width
1888-
let pickerContainerHeight = tapbacksBottomPickerActive ? self.tapbacksPickerHeight(size: size, insets: insets) : self.emojiContentHeight
1896+
let pickerGeometry: (height: CGFloat, bottomOverscroll: CGFloat) = tapbacksBottomPickerActive
1897+
? self.tapbacksPickerGeometry(size: size, insets: insets)
1898+
: (height: self.emojiContentHeight, bottomOverscroll: 0.0)
1899+
let pickerContainerHeight = pickerGeometry.height
18891900

18901901
var pickerDockStyle: EmojiStatusSelectionComponent.BottomDockStyle?
18911902
var pickerDismiss: (() -> Void)?
@@ -2034,7 +2045,7 @@ public final class ReactionContextNode: ASDisplayNode, ASScrollViewDelegate {
20342045
let componentFrame: CGRect
20352046
if tapbacksBottomPickerActive {
20362047
componentFrame = CGRect(
2037-
origin: CGPoint(x: 0.0, y: size.height - pickerContainerHeight),
2048+
origin: CGPoint(x: 0.0, y: size.height - pickerContainerHeight + pickerGeometry.bottomOverscroll),
20382049
size: CGSize(width: pickerContainerWidth, height: pickerContainerHeight)
20392050
)
20402051
} else {

0 commit comments

Comments
 (0)