Skip to content

Commit 67e3a78

Browse files
J-Son89ulisesmac
authored andcommitted
chore: add floating button page component (#17737)
Co-authored-by: Ulises M <[email protected]>
1 parent 98e529b commit 67e3a78

File tree

16 files changed

+370
-10
lines changed

16 files changed

+370
-10
lines changed

src/status_im/ui/screens/profile/user/views.cljs

+7
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,13 @@
131131
:accessibility-label :appearance-settings-button
132132
:chevron true
133133
:on-press #(re-frame/dispatch [:navigate-to :quo-preview])}])
134+
(when config/quo-preview-enabled?
135+
[list.item/list-item
136+
{:icon :main-icons/appearance
137+
:title "Status IM Components"
138+
:accessibility-label :status-im-common-components
139+
:chevron true
140+
:on-press #(re-frame/dispatch [:navigate-to :status-im-preview])}])
134141
[list.item/list-item
135142
{:icon :main-icons/appearance
136143
:title (i18n/label :t/appearance)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
(ns status-im2.common.floating-button-page.component-spec
2+
(:require [quo.core :as quo]
3+
[status-im2.common.floating-button-page.view :as floating-button-page]
4+
[test-helpers.component :as h]))
5+
6+
(h/describe "floating button page"
7+
(h/test "renders with a header and standard button"
8+
(h/render [floating-button-page/view
9+
{:header [quo/page-nav
10+
{:type :title-description
11+
:title "floating button page"
12+
:description "press right icon to swap button type"
13+
:text-align :left
14+
:background :blur
15+
:icon-name :i/close}]
16+
:footer [quo/button {} "continue"]}])
17+
(h/is-truthy (h/get-by-text "continue"))
18+
(h/is-truthy (h/get-by-text "floating button page")))
19+
20+
(h/test "renders with a header and a slide button"
21+
(h/render [floating-button-page/view
22+
{:header [quo/page-nav
23+
{:type :title-description
24+
:title "floating button page"
25+
:description "press right icon to swap button type"
26+
:text-align :left
27+
:background :blur
28+
:icon-name :i/close}]
29+
:footer [quo/slide-button
30+
{:track-text "We gotta slide"
31+
:track-icon :face-id}]}])
32+
(h/is-truthy (h/get-by-text "We gotta slide"))))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
(ns status-im2.common.floating-button-page.floating-container.style
2+
(:require [react-native.safe-area :as safe-area]))
3+
4+
(defn content-container
5+
[blur? keyboard-shown?]
6+
(let [margin-bottom (if keyboard-shown? 0 (safe-area/get-bottom))]
7+
(cond-> {:margin-top :auto
8+
:overflow :hidden
9+
:margin-bottom margin-bottom
10+
:padding-vertical 12
11+
:padding-horizontal 20}
12+
blur? (dissoc :padding-vertical :padding-horizontal))))
13+
14+
(def blur-inner-container
15+
{:background-color :transparent ; required, otherwise blur-view will shrink
16+
:padding-vertical 12
17+
:padding-horizontal 20})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
(ns status-im2.common.floating-button-page.floating-container.view
2+
(:require [quo.theme :as quo.theme]
3+
[react-native.blur :as blur]
4+
[react-native.core :as rn]
5+
[status-im2.common.floating-button-page.floating-container.style :as style]))
6+
7+
(defn- blur-container
8+
[child theme]
9+
[blur/view
10+
{:blur-amount 12
11+
:blur-radius 12
12+
:blur-type (quo.theme/theme-value :light :dark theme)}
13+
[rn/view {:style style/blur-inner-container}
14+
child]])
15+
16+
(defn view-internal
17+
[{:keys [theme on-layout keyboard-shown? blur?]} child]
18+
[rn/view
19+
{:style (style/content-container blur? keyboard-shown?)
20+
:on-layout on-layout}
21+
(if blur?
22+
[blur-container child theme]
23+
child)])
24+
25+
(def view (quo.theme/with-theme view-internal))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
(ns status-im2.common.floating-button-page.style)
2+
3+
(def page-container
4+
{:position :absolute
5+
:top 0
6+
:bottom 0
7+
:left 0
8+
:right 0})
9+
10+
(def keyboard-avoiding-view
11+
{:position :absolute
12+
:top 0
13+
:bottom 0
14+
:left 0
15+
:right 0})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
(ns status-im2.common.floating-button-page.view
2+
(:require
3+
[oops.core :as oops]
4+
[react-native.core :as rn]
5+
[react-native.platform :as platform]
6+
[react-native.safe-area :as safe-area]
7+
[reagent.core :as reagent]
8+
[status-im2.common.floating-button-page.floating-container.view :as floating-container]
9+
[status-im2.common.floating-button-page.style :as style]))
10+
11+
(defn- show-background
12+
[{:keys [window-height keyboard-height footer-container-height content-scroll-y
13+
content-container-height header-height keyboard-shown?]}]
14+
(let [available-space (- window-height
15+
(safe-area/get-top)
16+
header-height
17+
keyboard-height ; Already contains the bottom safe area value
18+
footer-container-height)
19+
scroll-view-height (- content-container-height content-scroll-y)
20+
overlap? (< available-space scroll-view-height)]
21+
(and keyboard-shown? overlap?)))
22+
23+
(defn- set-height-on-layout
24+
[ratom]
25+
(fn [event]
26+
(let [height (oops/oget event "nativeEvent.layout.height")]
27+
(reset! ratom height))))
28+
29+
(defn- init-keyboard-listeners
30+
[{:keys [on-did-show]}]
31+
(let [keyboard-will-show? (reagent/atom false)
32+
keyboard-did-show? (reagent/atom false)
33+
add-listener (fn [listener callback]
34+
(oops/ocall rn/keyboard "addListener" listener callback))
35+
will-show-listener (add-listener "keyboardWillShow"
36+
#(reset! keyboard-will-show? true))
37+
did-show-listener (add-listener "keyboardDidShow"
38+
(fn [e]
39+
(reset! keyboard-did-show? true)
40+
(when on-did-show (on-did-show e))))
41+
will-hide-listener (add-listener "keyboardWillHide"
42+
#(reset! keyboard-will-show? false))
43+
did-hide-listener (add-listener "keyboardDidHide"
44+
#(reset! keyboard-did-show? false))
45+
remove-listeners (fn []
46+
(doseq [listener [will-show-listener will-hide-listener
47+
did-show-listener did-hide-listener]]
48+
(oops/ocall listener "remove")))]
49+
{:keyboard-will-show? keyboard-will-show?
50+
:keyboard-did-show? keyboard-did-show?
51+
:remove-listeners remove-listeners}))
52+
53+
(defn view
54+
[{:keys [header footer]} & children]
55+
(reagent/with-let [window-height (:height (rn/get-window))
56+
footer-container-height (reagent/atom 0)
57+
header-height (reagent/atom 0)
58+
content-container-height (reagent/atom 0)
59+
content-scroll-y (reagent/atom 0)
60+
keyboard-height (reagent/atom 0)
61+
{:keys [keyboard-will-show?
62+
keyboard-did-show?
63+
remove-listeners]} (init-keyboard-listeners
64+
{:on-did-show
65+
(fn [e]
66+
(reset! keyboard-height
67+
(oops/oget e "endCoordinates.height")))})
68+
set-header-height (set-height-on-layout header-height)
69+
set-content-container-height (set-height-on-layout content-container-height)
70+
set-footer-container-height (set-height-on-layout footer-container-height)
71+
set-content-y-scroll (fn [event]
72+
(reset! content-scroll-y
73+
(oops/oget event "nativeEvent.contentOffset.y")))]
74+
(let [keyboard-shown? (if platform/ios? @keyboard-will-show? @keyboard-did-show?)
75+
show-background? (show-background {:window-height window-height
76+
:footer-container-height @footer-container-height
77+
:keyboard-height @keyboard-height
78+
:content-scroll-y @content-scroll-y
79+
:content-container-height @content-container-height
80+
:header-height @header-height
81+
:keyboard-shown? keyboard-shown?})]
82+
83+
[rn/view {:style style/page-container}
84+
[rn/view {:on-layout set-header-height}
85+
header]
86+
[rn/scroll-view
87+
{:on-scroll set-content-y-scroll
88+
:scroll-event-throttle 64
89+
:content-container-style {:flex-grow 1}}
90+
(into [rn/view {:on-layout set-content-container-height}]
91+
children)]
92+
[rn/keyboard-avoiding-view
93+
{:style style/keyboard-avoiding-view
94+
:keyboard-vertical-offset (if platform/ios? (safe-area/get-top) 0)
95+
:pointer-events :box-none}
96+
[floating-container/view
97+
{:on-layout set-footer-container-height
98+
:keyboard-shown? keyboard-shown?
99+
:blur? show-background?}
100+
footer]]])
101+
(finally
102+
(remove-listeners))))

src/status_im2/contexts/quo_preview/common.cljs

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@
66

77

88
(defn- view-internal
9-
[{:keys [theme]}]
9+
[{:keys [theme title]}]
1010
(let [logged-in? (rf/sub [:multiaccount/logged-in?])
1111
has-profiles? (boolean (rf/sub [:profile/profiles-overview]))
1212
root (if has-profiles? :profiles :intro)
1313
light? (= theme :light)]
1414
[quo/page-nav
1515
{:type :title
16-
:title "quo components preview"
16+
:title title
1717
:text-align :left
1818
:icon-name :i/close
1919
:right-side [{:icon-name (if light? :i/dark :i/light)

src/status_im2/contexts/quo_preview/main.cljs

+1-1
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,7 @@
487487
(defn- main-screen
488488
[]
489489
[:<>
490-
[common/navigation-bar]
490+
[common/navigation-bar {:title "Quo components preview"}]
491491
[rn/scroll-view {:style (style/main)}
492492
(for [category (sort screens-categories)]
493493
^{:key (first category)}

src/status_im2/contexts/quo_preview/preview.cljs

+3-3
Original file line numberDiff line numberDiff line change
@@ -317,10 +317,10 @@
317317
children)])
318318

319319
(defn- f-preview-container
320-
[{:keys [state descriptor blur? blur-dark-only?
320+
[{:keys [title state descriptor blur? blur-dark-only?
321321
component-container-style
322322
blur-container-style blur-view-props blur-height show-blur-background?]
323-
:or {blur-height 200}}
323+
:or {blur-height 200 title "quo component"}}
324324
& children]
325325
(let [theme (quo.theme/use-theme-value)]
326326
(rn/use-effect (fn []
@@ -332,7 +332,7 @@
332332
[rn/view
333333
{:style {:top (safe-area/get-top)
334334
:flex 1}}
335-
[common/navigation-bar]
335+
[common/navigation-bar {:title title}]
336336
[rn/scroll-view
337337
{:style (style/panel-basic)
338338
:shows-vertical-scroll-indicator false}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
(ns status-im2.contexts.status-im-preview.common.floating-button-page.style
2+
(:require [quo.foundations.colors :as colors]
3+
[react-native.safe-area :as safe-area]))
4+
5+
(defn container
6+
[]
7+
{:flex 1
8+
:margin-top (safe-area/get-top)})
9+
10+
(def background-image
11+
{:position :absolute
12+
:top (- (safe-area/get-top))
13+
:left 0
14+
:right 0
15+
:bottom 200})
16+
17+
(defn page-content
18+
[height]
19+
{:flex 1
20+
:height height
21+
:overflow :hidden
22+
:background-color (colors/resolve-color :army 30)})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
(ns status-im2.contexts.status-im-preview.common.floating-button-page.view
2+
(:require [quo.core :as quo]
3+
[re-frame.core :as rf]
4+
[react-native.core :as rn]
5+
[reagent.core :as reagent]
6+
[status-im2.common.floating-button-page.view :as floating-button-page]
7+
[status-im2.common.resources :as resources]
8+
[status-im2.contexts.status-im-preview.common.floating-button-page.style :as style]))
9+
10+
(defn view
11+
[]
12+
(let [content-height (reagent/atom 450)
13+
slide? (reagent/atom false)]
14+
(fn []
15+
[rn/view {:style (style/container)}
16+
(when-not @slide?
17+
[rn/image
18+
{:style style/background-image
19+
:source (resources/get-mock-image :dark-blur-bg)}])
20+
[floating-button-page/view
21+
{:header [quo/page-nav
22+
{:type :title-description
23+
:title "floating button page"
24+
:description "press right icon to swap button type"
25+
:text-align :left
26+
:right-side [{:icon-name :i/swap
27+
:on-press #(swap! slide? not)}]
28+
:background :blur
29+
:icon-name :i/close
30+
:on-press #(rf/dispatch [:navigate-back])}]
31+
:footer (if @slide?
32+
[quo/slide-button
33+
{:track-text "We gotta slide"
34+
:track-icon :face-id
35+
:container-style {:z-index 2}
36+
:customization-color :blue
37+
:on-complete #(js/alert "button slid")}
38+
"Save address"]
39+
[quo/button
40+
{:container-style {:z-index 2}
41+
:on-press #(js/alert "button pressed")}
42+
"Save address"])}
43+
[rn/view {:style (style/page-content @content-height)}
44+
[quo/text {:size :heading-1} "Page Content"]
45+
[quo/input
46+
{:auto-focus true
47+
:value ""}]
48+
[quo/button
49+
{:type :outline
50+
:on-press #(swap! content-height (fn [v] (+ v 10)))}
51+
"increase height"]
52+
[quo/button
53+
{:type :outline
54+
:on-press #(swap! content-height (fn [v] (- v 10)))}
55+
"decrease height"]]]])))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
(ns status-im2.contexts.status-im-preview.main
2+
(:refer-clojure :exclude [filter])
3+
(:require
4+
[quo.core :as quo]
5+
[react-native.core :as rn]
6+
[reagent.core :as reagent]
7+
[status-im2.contexts.quo-preview.common :as common]
8+
[status-im2.contexts.status-im-preview.common.floating-button-page.view :as floating-button-page]
9+
[status-im2.contexts.status-im-preview.style :as style]
10+
[utils.re-frame :as rf]))
11+
12+
(def screens-categories
13+
{:common [{:name :floating-button-page
14+
:component floating-button-page/view}]})
15+
16+
(defn- category-view
17+
[]
18+
(let [open? (reagent/atom false)
19+
on-press #(swap! open? not)]
20+
(fn [category]
21+
[rn/view {:style {:margin-vertical 8}}
22+
[quo/dropdown
23+
{:type :grey
24+
:state (if @open? :active :default)
25+
:on-press on-press}
26+
(name (key category))]
27+
(when @open?
28+
(for [{category-name :name} (val category)]
29+
^{:key category-name}
30+
[quo/button
31+
{:type :outline
32+
:container-style {:margin-vertical 8}
33+
:on-press #(rf/dispatch [:navigate-to category-name])}
34+
(name category-name)]))])))
35+
36+
(defn- main-screen
37+
[]
38+
[:<>
39+
[common/navigation-bar {:title "Status IM components"}]
40+
[rn/scroll-view {:style (style/main)}
41+
(for [category (sort screens-categories)]
42+
^{:key (first category)}
43+
[category-view category])]])
44+
45+
(def screens
46+
(->> screens-categories
47+
(map val)
48+
flatten
49+
(map (fn [subcategory]
50+
(update-in subcategory
51+
[:options :topBar]
52+
merge
53+
{:visible false})))))
54+
55+
(def main-screens
56+
[{:name :status-im-preview
57+
:options {:topBar {:visible false}
58+
:insets {:top? true}}
59+
:component main-screen}])

0 commit comments

Comments
 (0)