diff --git a/src/js/worklets/onboarding_carousel.js b/src/js/worklets/onboarding_carousel.js index b0fea3f05c..5da5ce8a9e 100644 --- a/src/js/worklets/onboarding_carousel.js +++ b/src/js/worklets/onboarding_carousel.js @@ -1,6 +1,8 @@ import { useDerivedValue, withTiming, Easing } from 'react-native-reanimated'; const slideAnimationDuration = 300; +const totalPages = 4; +const pageSize = 100 / totalPages; const easeOut = { duration: slideAnimationDuration, @@ -15,29 +17,15 @@ export function dynamicProgressBarWidth(staticProgressBarWidth, progress) { }); } -export function carouselLeftPosition(windowWidth, progress) { +export function carouselLeftPosition(windowWidth, progress, isDragging, dragAmount) { return useDerivedValue(function () { 'worklet'; const progressValue = progress.value; - switch (true) { - case progressValue < 25: - return 0; - case progressValue === 25: - return withTiming(-windowWidth, easeOut); - case progressValue < 50: - return -windowWidth; - case progressValue === 50: - return withTiming(-2 * windowWidth, easeOut); - case progressValue < 75: - return -2 * windowWidth; - case progressValue === 75: - return withTiming(-3 * windowWidth, easeOut); - case progressValue < 100: - return -3 * windowWidth; - case progressValue === 100: - return withTiming(-4 * windowWidth, easeOut); - default: - return 0; - } + const dragAmountValue = dragAmount.value; + + const baseOffset = (Math.floor(progressValue / pageSize) % totalPages) * windowWidth; + const adjustedOffset = baseOffset === 0 && dragAmountValue > 0 ? baseOffset : -baseOffset + dragAmountValue; + + return isDragging.value ? withTiming(adjustedOffset, easeOut) : withTiming(-baseOffset, easeOut); }); } diff --git a/src/react_native/gesture.cljs b/src/react_native/gesture.cljs index 2fa1efd847..d86a841ba1 100644 --- a/src/react_native/gesture.cljs +++ b/src/react_native/gesture.cljs @@ -19,6 +19,8 @@ (defn gesture-pan [] (.Pan ^js Gesture)) +(defn gesture-long-press [] (.LongPress ^js Gesture)) + (defn gesture-pinch [] (.Pinch ^js Gesture)) (defn on-begin [gesture handler] (.onBegin ^js gesture handler)) diff --git a/src/status_im2/contexts/onboarding/common/background/view.cljs b/src/status_im2/contexts/onboarding/common/background/view.cljs index fe33f78e58..1d59acb0ff 100644 --- a/src/status_im2/contexts/onboarding/common/background/view.cljs +++ b/src/status_im2/contexts/onboarding/common/background/view.cljs @@ -32,6 +32,8 @@ (defonce progress (atom nil)) (defonce paused? (atom nil)) +(defonce is-dragging? (atom nil)) +(defonce drag-amount (atom nil)) (defn store-screen-height [evt] @@ -60,7 +62,7 @@ animate? (not dark-overlay?) window-width (rf/sub [:dimensions/window-width])] (when animate? - (carousel.animation/use-initialize-animation progress paused? animate?)) + (carousel.animation/use-initialize-animation progress paused? animate? is-dragging? drag-amount)) (rn/use-effect (fn [] @@ -78,6 +80,8 @@ :progress progress :paused? paused? :header-text header-text + :is-dragging? is-dragging? + :drag-amount drag-amount :header-background true :gesture :swipeable :background [background-image (* 4 window-width)]}] diff --git a/src/status_im2/contexts/onboarding/common/carousel/animation.cljs b/src/status_im2/contexts/onboarding/common/carousel/animation.cljs index 1ce2530625..2f4cc2ed45 100644 --- a/src/status_im2/contexts/onboarding/common/carousel/animation.cljs +++ b/src/status_im2/contexts/onboarding/common/carousel/animation.cljs @@ -40,7 +40,7 @@ (if (zero? value) (slide-animation value 0) (slide-animation value))) (defn animate-progress - [progress paused next-progress] + [progress paused? next-progress] (let [q (quot next-progress 25)] (reanimated/set-shared-value progress @@ -53,7 +53,7 @@ (animate-progress-value (animation-value q 4)) (animate-progress-value (calculate-remainder next-progress drag-limit))) -1) - paused)))) + paused?)))) (defn get-next-progress [progress] @@ -74,37 +74,74 @@ (* progress-threshold))))) (defn use-initialize-animation - [progress paused animate?] + [progress paused? animate? is-dragging? drag-amount] (reset! progress (reanimated/use-shared-value 0)) - (reset! paused (reanimated/use-shared-value false)) + (reset! paused? (reanimated/use-shared-value false)) + (reset! is-dragging? (reanimated/use-shared-value false)) + (reset! drag-amount (reanimated/use-shared-value 0)) (rn/use-effect (fn [] - (animate-progress @progress @paused 0)) + (animate-progress @progress @paused? 0)) [animate?])) (defn cleanup-animation - [progress paused] + [progress paused?] (fn [] (reanimated/cancel-animation @progress) - (reanimated/cancel-animation @paused))) + (reanimated/cancel-animation @paused?))) (defn update-progress - [progress paused new-progress] + [progress paused? new-progress] (reanimated/set-shared-value @progress new-progress) - (animate-progress @progress @paused new-progress)) + (animate-progress @progress @paused? new-progress)) + +(defn handle-drag + [event paused? is-dragging? drag-amount] + (let [translation-x (oops/oget event "translationX")] + (reanimated/set-shared-value @paused? true) + (reanimated/set-shared-value @is-dragging? true) + (reanimated/set-shared-value @drag-amount translation-x))) (defn drag-gesture - [progress paused] + [progress paused? is-dragging? drag-amount] (-> (gesture/gesture-pan) (gesture/max-pointers 1) + (gesture/on-start + (fn [event] + (handle-drag event paused? is-dragging? drag-amount))) + (gesture/on-update + (fn [event] + (handle-drag event paused? is-dragging? drag-amount))) + (gesture/on-end + (fn [] + (reanimated/set-shared-value @is-dragging? false) + (reanimated/set-shared-value @paused? false))) (gesture/on-finalize (fn [event] (let [next? (< (oops/oget event "translationX") (- drag-limit)) previous? (> (oops/oget event "translationX") drag-limit)] (when next? - (update-progress progress paused (get-next-progress progress))) + (update-progress progress paused? (get-next-progress progress))) (when previous? - (update-progress progress paused (get-previous-progress progress)))))))) + (update-progress progress paused? (get-previous-progress progress)))))))) + +(defn long-press-gesture + [paused?] + (-> + (gesture/gesture-long-press) + (gesture/enabled true) + (gesture/on-start + (fn [] + (reanimated/set-shared-value @paused? true))) + (gesture/on-finalize + (fn [] + (reanimated/set-shared-value @paused? false))))) + +(defn composed-gestures + [progress paused? is-dragging? drag-amount] + (let [long-press (long-press-gesture paused?) + drag (drag-gesture progress paused? is-dragging? drag-amount)] + (gesture/simultaneous long-press drag))) (defn tap-gesture [progress paused] @@ -112,9 +149,12 @@ (gesture/on-end #(update-progress progress paused (get-next-progress progress))))) (defn carousel-left-position - [window-width animate? progress] + [window-width animate? progress is-dragging? drag-amount] (if animate? - (worklets.onboarding-carousel/carousel-left-position window-width @progress) + (worklets.onboarding-carousel/carousel-left-position window-width + @progress + @is-dragging? + @drag-amount) (-> (or (reanimated/get-shared-value @progress) 0) (quot -25) (* window-width)))) diff --git a/src/status_im2/contexts/onboarding/common/carousel/view.cljs b/src/status_im2/contexts/onboarding/common/carousel/view.cljs index b2bb049143..894a6b860c 100644 --- a/src/status_im2/contexts/onboarding/common/carousel/view.cljs +++ b/src/status_im2/contexts/onboarding/common/carousel/view.cljs @@ -50,16 +50,19 @@ :progress-bar-width progress-bar-width}]])) (defn f-view - [{:keys [animate? progress paused? header-text background header-background gesture]}] - (let [window-width (rf/sub [:dimensions/window-width]) - status-bar-height (:status-bar-height @navigation/constants) + [{:keys [animate? progress paused? header-text background header-background gesture is-dragging? + drag-amount]}] + (let [window-width (rf/sub [:dimensions/window-width]) + status-bar-height (:status-bar-height @navigation/constants) progress-bar-width (- window-width 40) - carousel-left (animation/carousel-left-position window-width animate? progress) - container-view (if animate? reanimated/view rn/view) - identified-gesture (case gesture - :swipeable (animation/drag-gesture progress paused?) - :tappable (animation/tap-gesture progress paused?) - nil)] + carousel-left + (animation/carousel-left-position window-width animate? progress is-dragging? drag-amount) + container-view (if animate? reanimated/view rn/view) + identified-gesture + (case gesture + :swipeable (animation/composed-gestures progress paused? is-dragging? drag-amount) + :tappable (animation/tap-gesture progress paused?) + nil)] [:<> [gesture/gesture-detector {:gesture identified-gesture} [container-view {:style (style/carousel-container carousel-left animate?)} diff --git a/src/status_im2/contexts/onboarding/identifiers/view.cljs b/src/status_im2/contexts/onboarding/identifiers/view.cljs index 1bf6821a10..5c69176b9e 100644 --- a/src/status_im2/contexts/onboarding/identifiers/view.cljs +++ b/src/status_im2/contexts/onboarding/identifiers/view.cljs @@ -25,12 +25,14 @@ [] (let [progress (atom nil) paused? (atom nil) + is-dragging? (atom nil) + drag-amount (atom nil) {:keys [emoji-hash display-name compressed-key public-key]} (rf/sub [:multiaccount]) {:keys [color]} (rf/sub [:onboarding-2/profile]) photo-path (rf/sub [:chats/photo-path public-key]) emoji-string (string/join emoji-hash)] - (carousel.animation/use-initialize-animation progress paused? true) + (carousel.animation/use-initialize-animation progress paused? true is-dragging? drag-amount) (rn/use-effect (fn [] (carousel.animation/cleanup-animation progress paused?)) @@ -39,11 +41,13 @@ [background/view true] [rn/view {:style style/page-container} [carousel/view - {:animate? true - :progress progress - :paused? paused? - :gesture :tappable - :header-text header-text}] + {:animate? true + :progress progress + :paused? paused? + :gesture :tappable + :is-dragging? is-dragging? + :drag-amount drag-amount + :header-text header-text}] [rn/view {:style style/content-container} [profile-card/profile-card {:profile-picture photo-path diff --git a/src/utils/worklets/onboarding_carousel.cljs b/src/utils/worklets/onboarding_carousel.cljs index bfce096c7f..dea06f8345 100644 --- a/src/utils/worklets/onboarding_carousel.cljs +++ b/src/utils/worklets/onboarding_carousel.cljs @@ -7,5 +7,5 @@ (.dynamicProgressBarWidth ^js worklets static-progress-bar-width progress)) (defn carousel-left-position - [window-width progress] - (.carouselLeftPosition ^js worklets window-width progress)) + [window-width progress is-dragging? drag-amount] + (.carouselLeftPosition ^js worklets window-width progress is-dragging? drag-amount))