Skip to content

Commit

Permalink
chore: add floating button page component (#17737)
Browse files Browse the repository at this point in the history
Co-authored-by: Ulises M <ulises.ssb@hotmail.com>
  • Loading branch information
2 people authored and yevh-berdnyk committed Dec 8, 2023
1 parent 98e529b commit 67e3a78
Show file tree
Hide file tree
Showing 16 changed files with 370 additions and 10 deletions.
7 changes: 7 additions & 0 deletions src/status_im/ui/screens/profile/user/views.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,13 @@
:accessibility-label :appearance-settings-button
:chevron true
:on-press #(re-frame/dispatch [:navigate-to :quo-preview])}])
(when config/quo-preview-enabled?
[list.item/list-item
{:icon :main-icons/appearance
:title "Status IM Components"
:accessibility-label :status-im-common-components
:chevron true
:on-press #(re-frame/dispatch [:navigate-to :status-im-preview])}])
[list.item/list-item
{:icon :main-icons/appearance
:title (i18n/label :t/appearance)
Expand Down
32 changes: 32 additions & 0 deletions src/status_im2/common/floating_button_page/component_spec.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
(ns status-im2.common.floating-button-page.component-spec
(:require [quo.core :as quo]
[status-im2.common.floating-button-page.view :as floating-button-page]
[test-helpers.component :as h]))

(h/describe "floating button page"
(h/test "renders with a header and standard button"
(h/render [floating-button-page/view
{:header [quo/page-nav
{:type :title-description
:title "floating button page"
:description "press right icon to swap button type"
:text-align :left
:background :blur
:icon-name :i/close}]
:footer [quo/button {} "continue"]}])
(h/is-truthy (h/get-by-text "continue"))
(h/is-truthy (h/get-by-text "floating button page")))

(h/test "renders with a header and a slide button"
(h/render [floating-button-page/view
{:header [quo/page-nav
{:type :title-description
:title "floating button page"
:description "press right icon to swap button type"
:text-align :left
:background :blur
:icon-name :i/close}]
:footer [quo/slide-button
{:track-text "We gotta slide"
:track-icon :face-id}]}])
(h/is-truthy (h/get-by-text "We gotta slide"))))
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
(ns status-im2.common.floating-button-page.floating-container.style
(:require [react-native.safe-area :as safe-area]))

(defn content-container
[blur? keyboard-shown?]
(let [margin-bottom (if keyboard-shown? 0 (safe-area/get-bottom))]
(cond-> {:margin-top :auto
:overflow :hidden
:margin-bottom margin-bottom
:padding-vertical 12
:padding-horizontal 20}
blur? (dissoc :padding-vertical :padding-horizontal))))

(def blur-inner-container
{:background-color :transparent ; required, otherwise blur-view will shrink
:padding-vertical 12
:padding-horizontal 20})
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
(ns status-im2.common.floating-button-page.floating-container.view
(:require [quo.theme :as quo.theme]
[react-native.blur :as blur]
[react-native.core :as rn]
[status-im2.common.floating-button-page.floating-container.style :as style]))

(defn- blur-container
[child theme]
[blur/view
{:blur-amount 12
:blur-radius 12
:blur-type (quo.theme/theme-value :light :dark theme)}
[rn/view {:style style/blur-inner-container}
child]])

(defn view-internal
[{:keys [theme on-layout keyboard-shown? blur?]} child]
[rn/view
{:style (style/content-container blur? keyboard-shown?)
:on-layout on-layout}
(if blur?
[blur-container child theme]
child)])

(def view (quo.theme/with-theme view-internal))
15 changes: 15 additions & 0 deletions src/status_im2/common/floating_button_page/style.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
(ns status-im2.common.floating-button-page.style)

(def page-container
{:position :absolute
:top 0
:bottom 0
:left 0
:right 0})

(def keyboard-avoiding-view
{:position :absolute
:top 0
:bottom 0
:left 0
:right 0})
102 changes: 102 additions & 0 deletions src/status_im2/common/floating_button_page/view.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
(ns status-im2.common.floating-button-page.view
(:require
[oops.core :as oops]
[react-native.core :as rn]
[react-native.platform :as platform]
[react-native.safe-area :as safe-area]
[reagent.core :as reagent]
[status-im2.common.floating-button-page.floating-container.view :as floating-container]
[status-im2.common.floating-button-page.style :as style]))

(defn- show-background
[{:keys [window-height keyboard-height footer-container-height content-scroll-y
content-container-height header-height keyboard-shown?]}]
(let [available-space (- window-height
(safe-area/get-top)
header-height
keyboard-height ; Already contains the bottom safe area value
footer-container-height)
scroll-view-height (- content-container-height content-scroll-y)
overlap? (< available-space scroll-view-height)]
(and keyboard-shown? overlap?)))

(defn- set-height-on-layout
[ratom]
(fn [event]
(let [height (oops/oget event "nativeEvent.layout.height")]
(reset! ratom height))))

(defn- init-keyboard-listeners
[{:keys [on-did-show]}]
(let [keyboard-will-show? (reagent/atom false)
keyboard-did-show? (reagent/atom false)
add-listener (fn [listener callback]
(oops/ocall rn/keyboard "addListener" listener callback))
will-show-listener (add-listener "keyboardWillShow"
#(reset! keyboard-will-show? true))
did-show-listener (add-listener "keyboardDidShow"
(fn [e]
(reset! keyboard-did-show? true)
(when on-did-show (on-did-show e))))
will-hide-listener (add-listener "keyboardWillHide"
#(reset! keyboard-will-show? false))
did-hide-listener (add-listener "keyboardDidHide"
#(reset! keyboard-did-show? false))
remove-listeners (fn []
(doseq [listener [will-show-listener will-hide-listener
did-show-listener did-hide-listener]]
(oops/ocall listener "remove")))]
{:keyboard-will-show? keyboard-will-show?
:keyboard-did-show? keyboard-did-show?
:remove-listeners remove-listeners}))

(defn view
[{:keys [header footer]} & children]
(reagent/with-let [window-height (:height (rn/get-window))
footer-container-height (reagent/atom 0)
header-height (reagent/atom 0)
content-container-height (reagent/atom 0)
content-scroll-y (reagent/atom 0)
keyboard-height (reagent/atom 0)
{:keys [keyboard-will-show?
keyboard-did-show?
remove-listeners]} (init-keyboard-listeners
{:on-did-show
(fn [e]
(reset! keyboard-height
(oops/oget e "endCoordinates.height")))})
set-header-height (set-height-on-layout header-height)
set-content-container-height (set-height-on-layout content-container-height)
set-footer-container-height (set-height-on-layout footer-container-height)
set-content-y-scroll (fn [event]
(reset! content-scroll-y
(oops/oget event "nativeEvent.contentOffset.y")))]
(let [keyboard-shown? (if platform/ios? @keyboard-will-show? @keyboard-did-show?)
show-background? (show-background {:window-height window-height
:footer-container-height @footer-container-height
:keyboard-height @keyboard-height
:content-scroll-y @content-scroll-y
:content-container-height @content-container-height
:header-height @header-height
:keyboard-shown? keyboard-shown?})]

[rn/view {:style style/page-container}
[rn/view {:on-layout set-header-height}
header]
[rn/scroll-view
{:on-scroll set-content-y-scroll
:scroll-event-throttle 64
:content-container-style {:flex-grow 1}}
(into [rn/view {:on-layout set-content-container-height}]
children)]
[rn/keyboard-avoiding-view
{:style style/keyboard-avoiding-view
:keyboard-vertical-offset (if platform/ios? (safe-area/get-top) 0)
:pointer-events :box-none}
[floating-container/view
{:on-layout set-footer-container-height
:keyboard-shown? keyboard-shown?
:blur? show-background?}
footer]]])
(finally
(remove-listeners))))
4 changes: 2 additions & 2 deletions src/status_im2/contexts/quo_preview/common.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@


(defn- view-internal
[{:keys [theme]}]
[{:keys [theme title]}]
(let [logged-in? (rf/sub [:multiaccount/logged-in?])
has-profiles? (boolean (rf/sub [:profile/profiles-overview]))
root (if has-profiles? :profiles :intro)
light? (= theme :light)]
[quo/page-nav
{:type :title
:title "quo components preview"
:title title
:text-align :left
:icon-name :i/close
:right-side [{:icon-name (if light? :i/dark :i/light)
Expand Down
2 changes: 1 addition & 1 deletion src/status_im2/contexts/quo_preview/main.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@
(defn- main-screen
[]
[:<>
[common/navigation-bar]
[common/navigation-bar {:title "Quo components preview"}]
[rn/scroll-view {:style (style/main)}
(for [category (sort screens-categories)]
^{:key (first category)}
Expand Down
6 changes: 3 additions & 3 deletions src/status_im2/contexts/quo_preview/preview.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -317,10 +317,10 @@
children)])

(defn- f-preview-container
[{:keys [state descriptor blur? blur-dark-only?
[{:keys [title state descriptor blur? blur-dark-only?
component-container-style
blur-container-style blur-view-props blur-height show-blur-background?]
:or {blur-height 200}}
:or {blur-height 200 title "quo component"}}
& children]
(let [theme (quo.theme/use-theme-value)]
(rn/use-effect (fn []
Expand All @@ -332,7 +332,7 @@
[rn/view
{:style {:top (safe-area/get-top)
:flex 1}}
[common/navigation-bar]
[common/navigation-bar {:title title}]
[rn/scroll-view
{:style (style/panel-basic)
:shows-vertical-scroll-indicator false}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
(ns status-im2.contexts.status-im-preview.common.floating-button-page.style
(:require [quo.foundations.colors :as colors]
[react-native.safe-area :as safe-area]))

(defn container
[]
{:flex 1
:margin-top (safe-area/get-top)})

(def background-image
{:position :absolute
:top (- (safe-area/get-top))
:left 0
:right 0
:bottom 200})

(defn page-content
[height]
{:flex 1
:height height
:overflow :hidden
:background-color (colors/resolve-color :army 30)})
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
(ns status-im2.contexts.status-im-preview.common.floating-button-page.view
(:require [quo.core :as quo]
[re-frame.core :as rf]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im2.common.floating-button-page.view :as floating-button-page]
[status-im2.common.resources :as resources]
[status-im2.contexts.status-im-preview.common.floating-button-page.style :as style]))

(defn view
[]
(let [content-height (reagent/atom 450)
slide? (reagent/atom false)]
(fn []
[rn/view {:style (style/container)}
(when-not @slide?
[rn/image
{:style style/background-image
:source (resources/get-mock-image :dark-blur-bg)}])
[floating-button-page/view
{:header [quo/page-nav
{:type :title-description
:title "floating button page"
:description "press right icon to swap button type"
:text-align :left
:right-side [{:icon-name :i/swap
:on-press #(swap! slide? not)}]
:background :blur
:icon-name :i/close
:on-press #(rf/dispatch [:navigate-back])}]
:footer (if @slide?
[quo/slide-button
{:track-text "We gotta slide"
:track-icon :face-id
:container-style {:z-index 2}
:customization-color :blue
:on-complete #(js/alert "button slid")}
"Save address"]
[quo/button
{:container-style {:z-index 2}
:on-press #(js/alert "button pressed")}
"Save address"])}
[rn/view {:style (style/page-content @content-height)}
[quo/text {:size :heading-1} "Page Content"]
[quo/input
{:auto-focus true
:value ""}]
[quo/button
{:type :outline
:on-press #(swap! content-height (fn [v] (+ v 10)))}
"increase height"]
[quo/button
{:type :outline
:on-press #(swap! content-height (fn [v] (- v 10)))}
"decrease height"]]]])))
59 changes: 59 additions & 0 deletions src/status_im2/contexts/status_im_preview/main.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
(ns status-im2.contexts.status-im-preview.main
(:refer-clojure :exclude [filter])
(:require
[quo.core :as quo]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im2.contexts.quo-preview.common :as common]
[status-im2.contexts.status-im-preview.common.floating-button-page.view :as floating-button-page]
[status-im2.contexts.status-im-preview.style :as style]
[utils.re-frame :as rf]))

(def screens-categories
{:common [{:name :floating-button-page
:component floating-button-page/view}]})

(defn- category-view
[]
(let [open? (reagent/atom false)
on-press #(swap! open? not)]
(fn [category]
[rn/view {:style {:margin-vertical 8}}
[quo/dropdown
{:type :grey
:state (if @open? :active :default)
:on-press on-press}
(name (key category))]
(when @open?
(for [{category-name :name} (val category)]
^{:key category-name}
[quo/button
{:type :outline
:container-style {:margin-vertical 8}
:on-press #(rf/dispatch [:navigate-to category-name])}
(name category-name)]))])))

(defn- main-screen
[]
[:<>
[common/navigation-bar {:title "Status IM components"}]
[rn/scroll-view {:style (style/main)}
(for [category (sort screens-categories)]
^{:key (first category)}
[category-view category])]])

(def screens
(->> screens-categories
(map val)
flatten
(map (fn [subcategory]
(update-in subcategory
[:options :topBar]
merge
{:visible false})))))

(def main-screens
[{:name :status-im-preview
:options {:topBar {:visible false}
:insets {:top? true}}
:component main-screen}])
Loading

0 comments on commit 67e3a78

Please sign in to comment.