mirror of
https://github.com/status-im/status-react.git
synced 2025-01-11 03:26:31 +00:00
Implement Swipe navigation for floating screen (#16390)
This commit is contained in:
parent
6b0a51720e
commit
b5a96a254a
@ -1,4 +1,4 @@
|
|||||||
import { useDerivedValue, withTiming, withSequence, withDelay, Easing } from 'react-native-reanimated';
|
import { useDerivedValue, withTiming, withSequence, withDelay, Easing, runOnJS } from 'react-native-reanimated';
|
||||||
import * as constants from './constants';
|
import * as constants from './constants';
|
||||||
|
|
||||||
// Derived Values
|
// Derived Values
|
||||||
@ -106,3 +106,43 @@ export function screenBorderRadius(screenState) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function screenGestureOnUpdate(screenLeft) {
|
||||||
|
return function (event) {
|
||||||
|
'worklet';
|
||||||
|
const absoluteX = event.absoluteX;
|
||||||
|
if (absoluteX !== null) {
|
||||||
|
screenLeft.value = event.absoluteX;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function screenGestureOnEnd(data) {
|
||||||
|
return function (event) {
|
||||||
|
'worklet';
|
||||||
|
|
||||||
|
const { screenLeft, screenState, screenWidth, leftVelocity, rightVelocity, screenClosedCallback } = data;
|
||||||
|
const absoluteX = event.absoluteX ?? 0;
|
||||||
|
const velocityX = event.velocityX ?? 0;
|
||||||
|
const closeScreen = velocityX > rightVelocity || (velocityX > leftVelocity && absoluteX >= screenWidth / 2);
|
||||||
|
|
||||||
|
// Velocity (points/sec) = Distance/time
|
||||||
|
var animationVelocity = (screenWidth * 1000) / constants.SHELL_ANIMATION_TIME;
|
||||||
|
|
||||||
|
if (Math.abs(velocityX) > animationVelocity) {
|
||||||
|
animationVelocity = velocityX; // Faster fling
|
||||||
|
}
|
||||||
|
|
||||||
|
const newDistance = closeScreen ? screenWidth - absoluteX : absoluteX;
|
||||||
|
const animationTime = (newDistance * 1000) / animationVelocity;
|
||||||
|
|
||||||
|
screenLeft.value = withTiming(closeScreen ? screenWidth : 0, {
|
||||||
|
duration: animationTime,
|
||||||
|
easing: Easing.bezier(0, 0, 0.58, 1),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (closeScreen) {
|
||||||
|
runOnJS(screenClosedCallback)(animationTime);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@ -37,6 +37,10 @@
|
|||||||
|
|
||||||
(defn min-distance [gesture dist] (.minDistance ^js gesture dist))
|
(defn min-distance [gesture dist] (.minDistance ^js gesture dist))
|
||||||
|
|
||||||
|
(defn fail-offset-x [gesture offset] (.failOffsetX ^js gesture offset))
|
||||||
|
|
||||||
|
(defn hit-slop [gesture settings] (.hitSlop ^js gesture settings))
|
||||||
|
|
||||||
(defn number-of-taps [gesture count] (.numberOfTaps ^js gesture count))
|
(defn number-of-taps [gesture count] (.numberOfTaps ^js gesture count))
|
||||||
|
|
||||||
(defn enabled [gesture enabled?] (.enabled ^js gesture enabled?))
|
(defn enabled [gesture enabled?] (.enabled ^js gesture enabled?))
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
(ns status-im2.contexts.shell.jump-to.components.floating-screens.view
|
(ns status-im2.contexts.shell.jump-to.components.floating-screens.view
|
||||||
(:require [utils.re-frame :as rf]
|
(:require [utils.re-frame :as rf]
|
||||||
[react-native.core :as rn]
|
[react-native.core :as rn]
|
||||||
|
[react-native.gesture :as gesture]
|
||||||
[react-native.reanimated :as reanimated]
|
[react-native.reanimated :as reanimated]
|
||||||
|
[status-im2.contexts.chat.messages.view :as chat]
|
||||||
[status-im2.contexts.shell.jump-to.state :as state]
|
[status-im2.contexts.shell.jump-to.state :as state]
|
||||||
[status-im2.contexts.shell.jump-to.utils :as utils]
|
[status-im2.contexts.shell.jump-to.utils :as utils]
|
||||||
[status-im2.contexts.chat.messages.view :as chat]
|
|
||||||
[status-im2.contexts.shell.jump-to.animation :as animation]
|
[status-im2.contexts.shell.jump-to.animation :as animation]
|
||||||
|
[status-im2.contexts.shell.jump-to.gesture :as shell.gesture]
|
||||||
[status-im2.contexts.shell.jump-to.constants :as shell.constants]
|
[status-im2.contexts.shell.jump-to.constants :as shell.constants]
|
||||||
[status-im2.contexts.shell.jump-to.components.floating-screens.style :as style]
|
[status-im2.contexts.communities.overview.view :as communities.overview]
|
||||||
[status-im2.contexts.communities.overview.view :as communities.overview]))
|
[status-im2.contexts.shell.jump-to.components.floating-screens.style :as style]))
|
||||||
|
|
||||||
(def screens-map
|
(def screens-map
|
||||||
{shell.constants/community-screen communities.overview/overview
|
{shell.constants/community-screen communities.overview/overview
|
||||||
@ -23,10 +25,12 @@
|
|||||||
[animation id])
|
[animation id])
|
||||||
[reanimated/view
|
[reanimated/view
|
||||||
{:style (style/screen (get @state/shared-values-atom screen-id))}
|
{:style (style/screen (get @state/shared-values-atom screen-id))}
|
||||||
[rn/view
|
[gesture/gesture-detector
|
||||||
{:style (style/screen-container (utils/dimensions))
|
{:gesture (shell.gesture/floating-screen-gesture screen-id)}
|
||||||
:key id}
|
[rn/view
|
||||||
[(get screens-map screen-id) id]]])
|
{:style (style/screen-container (utils/dimensions))
|
||||||
|
:key id}
|
||||||
|
[(get screens-map screen-id) id]]]])
|
||||||
|
|
||||||
;; Currently chat screen and events both depends on current-chat-id, once we remove
|
;; Currently chat screen and events both depends on current-chat-id, once we remove
|
||||||
;; use of current-chat-id from view then we can keep last chat loaded, for fast navigation
|
;; use of current-chat-id from view then we can keep last chat loaded, for fast navigation
|
||||||
|
@ -61,3 +61,8 @@
|
|||||||
(def ^:const open-screen-with-shell-animation 3)
|
(def ^:const open-screen-with-shell-animation 3)
|
||||||
(def ^:const close-screen-without-animation 4)
|
(def ^:const close-screen-without-animation 4)
|
||||||
(def ^:const open-screen-without-animation 5)
|
(def ^:const open-screen-without-animation 5)
|
||||||
|
|
||||||
|
;; Floating Screen gesture
|
||||||
|
(def ^:const gesture-width 20)
|
||||||
|
(def ^:const gesture-fling-right-velocity 2000)
|
||||||
|
(def ^:const gesture-fling-left-velocity -1000)
|
||||||
|
43
src/status_im2/contexts/shell/jump_to/gesture.cljs
Normal file
43
src/status_im2/contexts/shell/jump_to/gesture.cljs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
(ns status-im2.contexts.shell.jump-to.gesture
|
||||||
|
(:require [utils.re-frame :as rf]
|
||||||
|
[react-native.gesture :as gesture]
|
||||||
|
[react-native.reanimated :as reanimated]
|
||||||
|
[utils.worklets.shell :as worklets.shell]
|
||||||
|
[status-im2.contexts.shell.jump-to.utils :as utils]
|
||||||
|
[status-im2.contexts.shell.jump-to.state :as state]
|
||||||
|
[status-im2.contexts.shell.jump-to.constants :as constants]))
|
||||||
|
|
||||||
|
(defn screen-closed-callback
|
||||||
|
[screen-id]
|
||||||
|
(fn [animation-time]
|
||||||
|
(js/setTimeout
|
||||||
|
(fn []
|
||||||
|
(reanimated/set-shared-value
|
||||||
|
(get-in @state/shared-values-atom [screen-id :screen-state])
|
||||||
|
constants/close-screen-without-animation)
|
||||||
|
(reset! state/floating-screens-state
|
||||||
|
(assoc @state/floating-screens-state
|
||||||
|
screen-id
|
||||||
|
constants/close-screen-without-animation))
|
||||||
|
(rf/dispatch [:shell/floating-screen-closed screen-id]))
|
||||||
|
(or animation-time constants/shell-animation-time))))
|
||||||
|
|
||||||
|
(defn floating-screen-gesture
|
||||||
|
[screen-id]
|
||||||
|
(let [{:keys [screen-left screen-state]} (get @state/shared-values-atom screen-id)
|
||||||
|
{:keys [width]} (utils/dimensions)]
|
||||||
|
(-> (gesture/gesture-pan)
|
||||||
|
(gesture/min-distance 0)
|
||||||
|
(gesture/max-pointers 1)
|
||||||
|
(gesture/fail-offset-x -1)
|
||||||
|
(gesture/hit-slop (clj->js {:left 0 :width constants/gesture-width}))
|
||||||
|
(gesture/on-update (worklets.shell/floating-screen-gesture-on-update screen-left))
|
||||||
|
(gesture/on-end
|
||||||
|
(worklets.shell/floating-screen-gesture-on-end
|
||||||
|
{:screen-left screen-left
|
||||||
|
:screen-state screen-state
|
||||||
|
:screen-width width
|
||||||
|
:left-velocity constants/gesture-fling-left-velocity
|
||||||
|
:right-velocity constants/gesture-fling-right-velocity
|
||||||
|
:screen-closed-callback (screen-closed-callback screen-id)})))))
|
||||||
|
|
@ -1,4 +1,6 @@
|
|||||||
(ns utils.worklets.shell)
|
(ns utils.worklets.shell
|
||||||
|
(:require [utils.collection]
|
||||||
|
[camel-snake-kebab.core :as csk]))
|
||||||
|
|
||||||
(def bottom-tabs-worklets (js/require "../src/js/worklets/shell/bottom_tabs.js"))
|
(def bottom-tabs-worklets (js/require "../src/js/worklets/shell/bottom_tabs.js"))
|
||||||
(def home-stack-worklets (js/require "../src/js/worklets/shell/home_stack.js"))
|
(def home-stack-worklets (js/require "../src/js/worklets/shell/home_stack.js"))
|
||||||
@ -87,3 +89,13 @@
|
|||||||
(defn floating-screen-z-index
|
(defn floating-screen-z-index
|
||||||
[screen-state]
|
[screen-state]
|
||||||
(.screenZIndex ^js floating-screen-worklets screen-state))
|
(.screenZIndex ^js floating-screen-worklets screen-state))
|
||||||
|
|
||||||
|
(defn floating-screen-gesture-on-update
|
||||||
|
[screen-left]
|
||||||
|
(.screenGestureOnUpdate ^js floating-screen-worklets screen-left))
|
||||||
|
|
||||||
|
(defn floating-screen-gesture-on-end
|
||||||
|
[data]
|
||||||
|
(.screenGestureOnEnd
|
||||||
|
^js floating-screen-worklets
|
||||||
|
(clj->js (utils.collection/map-keys csk/->camelCaseString data))))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user