Skip to content

Commit

Permalink
Rework bottom-sheet component
Browse files Browse the repository at this point in the history
Fixes #9848
  • Loading branch information
Ferossgp committed Feb 19, 2020
1 parent 40c1224 commit 2741fd1
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 170 deletions.
1 change: 1 addition & 0 deletions components/src/status_im/ui/components/react.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@
comp])

(def safe-area-provider (adapt-class (object/get js-dependencies/safe-area-context "SafeAreaProvider")))
(def safe-area-consumer (adapt-class (object/get js-dependencies/safe-area-context "SafeAreaConsumer")))

(defn create-main-screen-view [current-view]
(fn [props & children]
Expand Down
26 changes: 10 additions & 16 deletions src/status_im/ui/components/bottom_sheet/styles.cljs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
(ns status-im.ui.components.bottom-sheet.styles
(:require [status-im.ui.components.colors :as colors]
[status-im.utils.platform :as platform]))
(:require [status-im.ui.components.colors :as colors]))

(def border-radius 16)
(def bottom-padding (if platform/iphone-x? 34 8))
(def bottom-view-height 1000)
(def vertical-padding 8)
(def margin-top 56)

(def container
{:position :absolute
Expand All @@ -26,16 +25,16 @@
:background-color colors/black-transparent-40})

(defn content-container
[content-height bottom-value]
[window-height content-height bottom-value]
{:background-color colors/white
:border-top-left-radius border-radius
:border-top-right-radius border-radius
:height (+ content-height bottom-view-height)
:bottom (- bottom-view-height)
:align-self :stretch
:transform [{:translateY bottom-value}]
:justify-content :flex-start
:padding-bottom bottom-padding})
:height (+ content-height window-height)
:bottom (- window-height)
:transform [{:translateY bottom-value}]})

(def sheet-wrapper {:flex 1
:justify-content :flex-end})

(def content-header
{:height border-radius
Expand All @@ -48,8 +47,3 @@
:height 4
:background-color colors/gray-transparent-40
:border-radius 2})

(def bottom-view
{:background-color colors/white
:height bottom-view-height
:align-self :stretch})
198 changes: 116 additions & 82 deletions src/status_im/ui/components/bottom_sheet/view.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
[reagent.core :as reagent]
[re-frame.core :as re-frame]))

(def initial-animation-duration 300)
(def initial-animation-duration 400)
(def release-animation-duration 150)
(def cancellation-animation-duration 100)
(def swipe-opacity-range 100)
(def cancellation-height 180)
(def cancellation-coefficient 0.3)
(def min-opacity 0.05)
(def min-velocity 0.1)

Expand All @@ -32,13 +32,6 @@
:friction 6
:useNativeDriver true})])))

(defn animate-panel-open [opacity-value bottom-value]
(animate {:bottom bottom-value
:new-bottom-value 0
:opacity opacity-value
:new-opacity-value 1
:duration initial-animation-duration}))

(defn- on-move
[{:keys [height bottom-value opacity-value]}]
(fn [_ state]
Expand All @@ -48,12 +41,12 @@
(animation/set-value bottom-value dy)
(animation/set-value opacity-value opacity))
(neg? dy)
(animation/set-value bottom-value (/ dy 2))))))
(animation/set-value bottom-value dy)))))

(defn cancelled? [height dy vy]
(defn- cancelled? [height dy vy]
(or
(<= min-velocity vy)
(> cancellation-height (- height dy))))
(> (* cancellation-coefficient height) (- height dy))))

(defn- cancel
([opts] (cancel opts nil))
Expand All @@ -68,18 +61,18 @@
(when (fn? callback) (callback)))})))

(defn- on-release
[{:keys [height bottom-value opacity-value on-cancel] :as opts}]
[{:keys [height bottom-value close-sheet opacity-value]}]
(fn [_ state]
(let [{:strs [dy vy]} (js->clj state)]
(if (cancelled? height dy vy)
(cancel opts on-cancel)
(close-sheet)
(animate {:bottom bottom-value
:new-bottom-value 0
:opacity opacity-value
:new-opacity-value 1
:duration release-animation-duration})))))

(defn swipe-pan-responder [opts]
(defn- swipe-pan-responder [opts]
(.create
react/pan-responder
(clj->js
Expand All @@ -90,75 +83,116 @@
:onPanResponderRelease (on-release opts)
:onPanResponderTerminate (on-release opts)})))

(defn pan-handlers [pan-responder]
(defn- pan-handlers [pan-responder]
(js->clj (.-panHandlers pan-responder)))

(defn- bottom-sheet-view
[{:keys [opacity-value bottom-value]}]
(reagent.core/create-class
{:component-did-mount
(fn []
(react/dismiss-keyboard!)
(animate-panel-open opacity-value bottom-value))
:reagent-render
(fn [{:keys [opacity-value bottom-value height
content on-cancel disable-drag?]
:or {on-cancel #(re-frame/dispatch [:bottom-sheet/hide])}
:as opts}]
[react/keyboard-avoiding-view {:style styles/container}
[react/touchable-highlight
{:on-press #(cancel opts on-cancel)
:style styles/container}
(defn- on-open [{:keys [bottom-value internal opacity-value]}]
(when-not @internal
(react/dismiss-keyboard!)
(reset! internal true)
(animate {:bottom bottom-value
:new-bottom-value 0
:opacity opacity-value
:new-opacity-value 1
:duration initial-animation-duration})))

(defn- on-close
[{:keys [bottom-value opacity-value on-cancel internal height]}]
(when @internal
(animate {:bottom bottom-value
:new-bottom-value height
:opacity opacity-value
:new-opacity-value 0
:duration cancellation-animation-duration
:callback (fn []
(when (fn? on-cancel)
(animation/set-value bottom-value height)
(animation/set-value opacity-value 0)
(reset! internal false)
(on-cancel)))})))

(defn bottom-sheet-view [{:keys [window-height]}]
(let [opacity-value (animation/create-value 0)
bottom-value (animation/create-value window-height)
content-height (reagent/atom window-height)
internal-visible (reagent/atom false)
external-visible (reagent/atom false)]
(fn [{:keys [content on-cancel disable-drag? show-handle? show?
backdrop-dismiss? safe-area window-height]
:or {show-handle? true
backdrop-dismiss? true
on-cancel #(re-frame/dispatch [:bottom-sheet/hide])}}]
(let [height (+ @content-height
styles/border-radius)
max-height (- window-height
(:top safe-area)
styles/margin-top)
sheet-height (min max-height height)
close-sheet (fn []
(on-close {:opacity-value opacity-value
:bottom-value bottom-value
:height height
:internal internal-visible
:on-cancel on-cancel}))]
(when-not (= @external-visible show?)
(reset! external-visible show?)
(cond
(true? show?)
(on-open {:bottom-value bottom-value
:opacity-value opacity-value
:internal internal-visible
:height height})

[react/animated-view (styles/shadow opacity-value)]]
[react/animated-view (merge
{:style (styles/content-container height bottom-value)}
(when-not disable-drag?
(pan-handlers (swipe-pan-responder opts))))
[react/view {:style styles/content-header}
[react/view styles/handle]]
[react/view {:style {:flex 1
:height height}}
[content]]
[react/view {:style styles/bottom-view}]]])}))
(false? show?)
(close-sheet)))
(when @internal-visible
[react/view {:style styles/container}
[react/touchable-highlight (merge {:style styles/container}
(when backdrop-dismiss?
{:on-press #(close-sheet)}))
[react/animated-view {:style (styles/shadow opacity-value)}]]

(defn bottom-sheet
[{:keys [show? content-height on-cancel]}]
(let [show-sheet? (reagent/atom show?)
total-content-height (+ content-height styles/border-radius
styles/bottom-padding)
bottom-value (animation/create-value total-content-height)
opacity-value (animation/create-value 0)
opts {:height total-content-height
:bottom-value bottom-value
:opacity-value opacity-value
:show-sheet? show-sheet?
:on-cancel on-cancel}]
(reagent.core/create-class
{:component-will-update
(fn [this [_ new-args]]
(let [old-args (second (.-argv (.-props this)))
old-show? (:show? old-args)
new-show? (:show? new-args)
old-height (:content-height old-args)
new-height (:content-height new-args)
total-content-height (+ new-height
styles/border-radius
styles/bottom-padding)
opts' (assoc opts :height total-content-height)]
(when (and new-show? (not= old-height new-height))
(animation/set-value bottom-value new-height))
(cond (and (not old-show?) new-show?)
(reset! show-sheet? true)
[react/keyboard-avoiding-view {:pointer-events "box-none"
:behaviour "position"
:style styles/sheet-wrapper}
[react/animated-view (merge
{:pointer-events "box-none"
:style (styles/content-container window-height sheet-height bottom-value)}
(when-not (or disable-drag?
(= max-height sheet-height))
(pan-handlers
(swipe-pan-responder {:bottom-value bottom-value
:opacity-value opacity-value
:height height
:close-sheet #(close-sheet)}))))
[react/view (merge {:style styles/content-header}
(when-not disable-drag?
(pan-handlers
(swipe-pan-responder {:bottom-value bottom-value
:opacity-value opacity-value
:height height
:close-sheet #(close-sheet)}))))
(when show-handle?
[react/view styles/handle])]
[react/animated-view {:style {:height sheet-height}}
;; NOTE: For a better UX on onScrollBeginDrag we can start dragging the sheet.
[react/scroll-view {:bounces false
:scroll-enabled true
:style {:flex 1}}
[react/view {:style {:padding-top styles/vertical-padding
:padding-bottom (+ styles/vertical-padding
(:bottom safe-area))}
:on-layout #(->> %
.-nativeEvent
.-layout
.-height
(reset! content-height))}
[content]]]]]]])))))

(and old-show? (false? new-show?) (true? @show-sheet?))
(cancel opts'))))
:reagent-render
(fn [{:keys [content content-height]}]
(let [total-content-height (+ content-height
styles/border-radius
styles/bottom-padding)]
(when @show-sheet?
[bottom-sheet-view (assoc opts
:content content
:height total-content-height)])))})))
(defn bottom-sheet [props]
[react/safe-area-consumer
(fn [insets]
(reagent/as-element
[bottom-sheet-view (assoc props
:window-height @(re-frame/subscribe [:dimensions/window-height])
:safe-area (js->clj insets :keywordize-keys true))]))])
60 changes: 29 additions & 31 deletions src/status_im/ui/screens/home/sheet/views.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -15,36 +15,34 @@
(re-frame/dispatch event))

(defn add-new-view []
[react/view {:flex 1 :flex-direction :row}
[react/view {:flex 1}
[list-item/list-item
{:theme :action
:title :t/start-new-chat
:accessibility-label :start-1-1-chat-button
:icon :main-icons/one-on-one-chat
:on-press #(hide-sheet-and-dispatch [:navigate-to :new-chat])}]
(when config/group-chat-enabled?
[list-item/list-item
{:theme :action
:title :t/start-group-chat
:accessibility-label :start-group-chat-button
:icon :main-icons/group-chat
:on-press #(hide-sheet-and-dispatch [:contact.ui/start-group-chat-pressed])}])
[list-item/list-item
{:theme :action
:title :t/new-public-group-chat
:accessibility-label :join-public-chat-button
:icon :main-icons/public-chat
:on-press #(hide-sheet-and-dispatch [:navigate-to :new-public-chat])}]
[list-item/list-item
{:theme :action
:title :t/invite-friends
:accessibility-label :chats-menu-invite-friends-button
:icon :main-icons/share
:on-press #(do
(re-frame/dispatch [:bottom-sheet/hide-sheet])
(list-selection/open-share {:message (i18n/label :t/get-status-at)}))}]]])
[react/view
[list-item/list-item
{:theme :action
:title :t/start-new-chat
:accessibility-label :start-1-1-chat-button
:icon :main-icons/one-on-one-chat
:on-press #(hide-sheet-and-dispatch [:navigate-to :new-chat])}]
(when config/group-chat-enabled?
[list-item/list-item
{:theme :action
:title :t/start-group-chat
:accessibility-label :start-group-chat-button
:icon :main-icons/group-chat
:on-press #(hide-sheet-and-dispatch [:contact.ui/start-group-chat-pressed])}])
[list-item/list-item
{:theme :action
:title :t/new-public-group-chat
:accessibility-label :join-public-chat-button
:icon :main-icons/public-chat
:on-press #(hide-sheet-and-dispatch [:navigate-to :new-public-chat])}]
[list-item/list-item
{:theme :action
:title :t/invite-friends
:accessibility-label :chats-menu-invite-friends-button
:icon :main-icons/share
:on-press #(do
(re-frame/dispatch [:bottom-sheet/hide-sheet])
(list-selection/open-share {:message (i18n/label :t/get-status-at)}))}]])

(def add-new
{:content add-new-view
:content-height (if config/group-chat-enabled? 256 192)})
{:content add-new-view})
Loading

0 comments on commit 2741fd1

Please sign in to comment.