fix (fn[]) usage in hiccup (#15713)

This commit is contained in:
flexsurfer 2023-04-25 15:13:14 +02:00 committed by GitHub
parent 2fe4956f4d
commit cd69d0423a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
75 changed files with 2145 additions and 2420 deletions

View File

@ -256,8 +256,6 @@ PODS:
- React-Core
- react-native-randombytes (3.6.1):
- React-Core
- react-native-safe-area-context (2.0.0):
- React
- react-native-shake (3.4.0):
- React
- react-native-slider (3.0.0):
@ -412,6 +410,8 @@ PODS:
- Yoga
- RNShare (7.0.1):
- React-Core
- RNStaticSafeAreaInsets (2.2.0):
- React-Core
- RNSVG (9.13.6):
- React
- SDWebImage (5.11.1):
@ -468,7 +468,6 @@ DEPENDENCIES:
- "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
- react-native-orientation-locker (from `../node_modules/react-native-orientation-locker`)
- react-native-randombytes (from `../node_modules/react-native-randombytes`)
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
- react-native-shake (from `../node_modules/react-native-shake`)
- "react-native-slider (from `../node_modules/@react-native-community/slider`)"
- react-native-status (from `../modules/react-native-status`)
@ -503,6 +502,7 @@ DEPENDENCIES:
- RNReactNativeHapticFeedback (from `../node_modules/react-native-haptic-feedback`)
- RNReanimated (from `../node_modules/react-native-reanimated`)
- RNShare (from `../node_modules/react-native-share`)
- RNStaticSafeAreaInsets (from `../node_modules/react-native-static-safe-area-insets`)
- RNSVG (from `../node_modules/react-native-svg`)
- secp256k1 (from `https://github.com/status-im/secp256k1.swift.git`)
- SQLCipher (~> 3.0)
@ -589,8 +589,6 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-orientation-locker"
react-native-randombytes:
:path: "../node_modules/react-native-randombytes"
react-native-safe-area-context:
:path: "../node_modules/react-native-safe-area-context"
react-native-shake:
:path: "../node_modules/react-native-shake"
react-native-slider:
@ -659,6 +657,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-reanimated"
RNShare:
:path: "../node_modules/react-native-share"
RNStaticSafeAreaInsets:
:path: "../node_modules/react-native-static-safe-area-insets"
RNSVG:
:path: "../node_modules/react-native-svg"
secp256k1:
@ -682,11 +682,11 @@ SPEC CHECKSUMS:
boost: a7c83b31436843459a1961bfd74b96033dc77234
BVLinearGradient: e3aad03778a456d77928f594a649e96995f1c872
CryptoSwift: c4f2debceb38bf44c80659afe009f71e23e4a082
DoubleConversion: 831926d9b8bf8166fd87886c4abab286c2422662
DoubleConversion: cde416483dac037923206447da6e1454df403714
FBLazyVector: d2db9d00883282819d03bbd401b2ad4360d47580
FBReactNativeSpec: 94da4d84ba3b1acf459103320882daa481a2b62d
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
glog: 9e3310013355e9221591364060e841c28041dfe3
glog: 997518ea2aa2d8cd5df9797b641b758d52ecf2bc
HMSegmentedControl: 34c1f54d822d8308e7b24f5d901ec674dfa31352
Keycard: ac6df4d91525c3c82635ac24d4ddd9a80aca5fc8
libwebp: f62cb61d0a484ba548448a4bd52aabf150ff6eef
@ -716,7 +716,6 @@ SPEC CHECKSUMS:
react-native-netinfo: ddaca8bbb9e6e914b1a23787ccb879bc642931c9
react-native-orientation-locker: 851f6510d8046ea2f14aa169b1e01fcd309a94ba
react-native-randombytes: 421f1c7d48c0af8dbcd471b0324393ebf8fe7846
react-native-safe-area-context: 60f654e00b6cc416573f6d5dbfce3839958eb57a
react-native-shake: de052eaa3eadc4a326b8ddd7ac80c06e8d84528c
react-native-slider: 12bd76d3d568c9c5500825db54123d44b48e4ad4
react-native-status: 21f75d492fd311dc111303da38a7a2b23a8a8466
@ -751,6 +750,7 @@ SPEC CHECKSUMS:
RNReactNativeHapticFeedback: 2566b468cc8d0e7bb2f84b23adc0f4614594d071
RNReanimated: 3ad6ec4e147462206be9d1c925df10b6ea850b0e
RNShare: 2dc2fcac3f7321cfd6b60a23ed4bf4d549f86f5f
RNStaticSafeAreaInsets: 055ddbf5e476321720457cdaeec0ff2ba40ec1b8
RNSVG: 8ba35cbeb385a52fd960fd28db9d7d18b4c2974f
SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d
SDWebImageWebPCoder: 908b83b6adda48effe7667cd2b7f78c897e5111d
@ -763,4 +763,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: c29de3b14e3275299c51aa95520622f09d084bcb
COCOAPODS: 1.12.0
COCOAPODS: 1.12.1

View File

@ -63,9 +63,9 @@
"react-native-randombytes": "^3.6.1",
"react-native-reanimated": "2.3.3",
"react-native-redash": "^16.0.11",
"react-native-safe-area-context": "^2.0.0",
"react-native-shake": "^3.3.1",
"react-native-share": "^7.0.1",
"react-native-static-safe-area-insets": "^2.2.0",
"react-native-status-keycard": "git+https://github.com/status-im/react-native-status-keycard.git#refs/tags/v2.5.39",
"react-native-svg": "^9.8.4",
"react-native-touch-id": "^4.4.1",

View File

@ -155,10 +155,7 @@ globalThis.__STATUS_MOBILE_JS_IDENTITY_PROXY__ = new Proxy({}, {get() { return (
(def net-info #js {})
(def touchid #js {})
(def react-native-image-viewing #js {:default {}})
(def safe-area-context
(clj->js {:SafeAreaProvider {:_reactNativeIphoneXHelper {:getStatusBarHeight (fn [])}}
:SafeAreaInsetsContext {:Consumer (fn [])}
:SafeAreaView {}}))
(def react-native-static-safe-area-insets #js {:default {}})
(def back-handler
#js
@ -367,7 +364,7 @@ globalThis.__STATUS_MOBILE_JS_IDENTITY_PROXY__ = new Proxy({}, {get() { return (
"react-native-background-timer" background-timer
"react-native-image-crop-picker" image-crop-picker
"react-native-gesture-handler" react-native-gesture-handler
"react-native-safe-area-context" safe-area-context
"react-native-static-safe-area-insets" react-native-static-safe-area-insets
"react-native-config" config
"react-native-iphone-x-helper" (clj->js {:getStatusBarHeight (fn [])
:getBottomSpace (fn [])})

View File

@ -2,10 +2,10 @@
(:require [oops.core :refer [oget]]
[quo.animated :as animated]
[quo.components.header :as header]
[quo.components.safe-area :as safe-area]
[quo.design-system.colors :as colors]
[quo.platform :as platform]
[reagent.core :as reagent]))
[reagent.core :as reagent]
[react-native.safe-area :as safe-area]))
(defn header-wrapper-style
[{:keys [value offset]}]
@ -95,11 +95,9 @@
(defn header
[{:keys [use-insets] :as props} & children]
(if use-insets
[safe-area/consumer
(fn [insets]
[header-container
(-> props
(dissoc :use-insets)
(assoc :insets insets))
children])]
[header-container
(-> props
(dissoc :use-insets)
(assoc :insets (safe-area/get-insets)))
children]
[header-container props children]))

View File

@ -2,13 +2,13 @@
(:require [cljs-bean.core :as bean]
[quo.animated :as animated]
[quo.components.bottom-sheet.style :as styles]
[quo.components.safe-area :as safe-area]
[quo.design-system.colors :as colors]
[quo.gesture-handler :as gesture-handler]
[quo.platform :as platform]
[quo.react :as react]
[quo.react-native :as rn]
[reagent.core :as reagent]))
[reagent.core :as reagent]
[react-native.safe-area :as safe-area]))
(def opacity-coeff 0.8)
(def close-duration 150)
@ -43,7 +43,7 @@
(rn/use-keyboard)
keyboard-height-android-delta
(if (and platform/android? keyboard-shown) (+ keyboard-height 20) 0)
safe-area (safe-area/use-safe-area)
safe-area (safe-area/get-insets)
window-height (- window-height
(if platform/android?
(+ 50 keyboard-height-android-delta) ;; TODO : remove 50 when

View File

@ -1,23 +0,0 @@
(ns quo.components.safe-area
(:require ["react-native-safe-area-context" :as safe-area-context :refer
(SafeAreaView SafeAreaProvider SafeAreaInsetsContext useSafeAreaInsets)]
[reagent.core :as reagent]))
(def provider (reagent/adapt-react-class SafeAreaProvider))
(def ^:private consumer-raw (reagent/adapt-react-class (.-Consumer ^js SafeAreaInsetsContext)))
(def view (reagent/adapt-react-class SafeAreaView))
(defn consumer
[component]
[consumer-raw
(fn [insets]
(reagent/as-element
[component (js->clj insets :keywordize-keys true)]))])
(defn use-safe-area
[]
(let [insets (useSafeAreaInsets)]
{:top (.-top ^js insets)
:bottom (.-bottom ^js insets)
:left (.-left ^js insets)
:right (.-right ^js insets)}))

View File

@ -8,7 +8,6 @@
[quo.components.list.header :as list-header]
[quo.components.list.index :as list-index]
[quo.components.list.item :as list-item]
[quo.components.safe-area :as safe-area]
[quo.components.separator :as separator]
[quo.components.text :as text]
[quo.components.text-input :as text-input]
@ -29,8 +28,5 @@
(def switch controls/switch)
(def radio controls/radio)
(def checkbox controls/checkbox)
(def safe-area-provider safe-area/provider)
(def safe-area-consumer safe-area/consumer)
(def safe-area-view safe-area/view)
(def separator separator/separator)
(def get-color colors/get-color)

View File

@ -30,7 +30,7 @@
(reanimated/set-shared-value scroll-y current-y)))
(defn header
[{:keys [theme-color display-picture-comp cover-uri title-comp]} top-inset scroll-y]
[{:keys [theme-color f-display-picture-comp cover-uri title-comp]} top-inset scroll-y]
(let [input-range [0 (* threshold 0.33)]
picture-scale-down 0.4
size-animation (interpolate scroll-y input-range [80 (* 80 picture-scale-down)])
@ -48,50 +48,49 @@
[reanimated/view {:style (style/header-bottom-part border-animation)}
[title-comp]]
[reanimated/view {:style (style/entity-picture size-animation)}
[display-picture-comp image-animation]]]))
[:f> f-display-picture-comp image-animation]]]))
(defn- f-animated-header-list
[{:keys [header-comp main-comp back-button-on-press] :as params}]
(let [window-height (:height (rn/get-window))
{:keys [top bottom]} (safe-area/get-insets)
;; view height calculation is different because window height is different on iOS and Android:
view-height (if platform/ios?
(- window-height bottom)
(+ window-height top))
initial-y (if platform/ios? (- top) 0)
scroll-y (reanimated/use-shared-value initial-y)
opacity-animation (interpolate scroll-y
[(* threshold 0.33) (* threshold 0.66)]
[0 1])
translate-animation (interpolate scroll-y [(* threshold 0.66) threshold] [100 56])
title-opacity-animation (interpolate scroll-y [(* threshold 0.66) threshold] [0 1])]
[rn/view {:style (style/container-view view-height)}
[rn/touchable-opacity
{:active-opacity 1
:on-press back-button-on-press
:style (style/button-container {:left 20})}
[quo/icon :i/arrow-left {:size 20 :color (colors/theme-colors colors/black colors/white)}]]
[rn/touchable-opacity
{:active-opacity 1
:style (style/button-container {:right 20})}
[quo/icon :i/options {:size 20 :color (colors/theme-colors colors/black colors/white)}]]
[reanimated/blur-view
{:blurAmount 32
:blurType :light
:overlayColor (if platform/ios? colors/white-opa-70 :transparent)
:style (style/blur-view opacity-animation)}
[reanimated/view {:style (style/header-comp translate-animation title-opacity-animation)}
[header-comp]]]
[reanimated/flat-list
{:data [nil]
:render-fn main-comp
:key-fn str
:header (reagent/as-element (header params top scroll-y))
;; TODO: https://github.com/status-im/status-mobile/issues/14924
:scroll-event-throttle 8
:on-scroll (fn [event] (scroll-handler event initial-y scroll-y))}]]))
(defn animated-header-list
[{:keys [header-comp main-comp back-button-on-press] :as parameters}]
[safe-area/consumer
(fn [insets]
(let [window-height (:height (rn/get-window))
status-bar-height (rn/status-bar-height)
bottom-inset (:bottom insets)
;; view height calculation is different because window height is different on iOS and Android:
view-height (if platform/ios?
(- window-height bottom-inset)
(+ window-height status-bar-height))
initial-y (if platform/ios? (- (:top insets)) 0)]
[:f>
(fn []
(let [scroll-y (reanimated/use-shared-value initial-y)
opacity-animation (interpolate scroll-y
[(* threshold 0.33) (* threshold 0.66)]
[0 1])
translate-animation (interpolate scroll-y [(* threshold 0.66) threshold] [100 56])
title-opacity-animation (interpolate scroll-y [(* threshold 0.66) threshold] [0 1])]
[rn/view {:style (style/container-view view-height)}
[rn/touchable-opacity
{:active-opacity 1
:on-press back-button-on-press
:style (style/button-container {:left 20})}
[quo/icon :i/arrow-left {:size 20 :color (colors/theme-colors colors/black colors/white)}]]
[rn/touchable-opacity
{:active-opacity 1
:style (style/button-container {:right 20})}
[quo/icon :i/options {:size 20 :color (colors/theme-colors colors/black colors/white)}]]
[reanimated/blur-view
{:blurAmount 32
:blurType :light
:overlayColor (if platform/ios? colors/white-opa-70 :transparent)
:style (style/blur-view opacity-animation)}
[reanimated/view {:style (style/header-comp translate-animation title-opacity-animation)}
[header-comp]]]
[reanimated/flat-list
{:data [nil]
:render-fn main-comp
:key-fn str
:header (reagent/as-element (header parameters (:top insets) scroll-y))
;; TODO: https://github.com/status-im/status-mobile/issues/14924
:scroll-event-throttle 8
:on-scroll (fn [event] (scroll-handler event initial-y scroll-y))}]]))]))])
[params]
[:f> f-animated-header-list params])

View File

@ -65,10 +65,10 @@
18 ;; ~ 9 is char width, 18 is width used in Figma.
(* 9 max-line-digits font-scale))))
(defn- native-renderer
(defn- f-native-renderer
[{:keys [rows max-lines on-copy-press]
:or {max-lines ##Inf}}]
(let [font-scale (:font-scale (rn/use-window-dimensions))
(let [font-scale (:font-scale (rn/get-window))
total-rows (count rows)
number-rows-to-show (min (count rows) max-lines)
line-number-width (calc-line-number-width font-scale number-rows-to-show)
@ -100,7 +100,7 @@
{:language language
:renderer (fn [^js/Object props]
(reagent/as-element
[:f> native-renderer
[:f> f-native-renderer
{:rows (-> props .-rows bean/->clj)
:on-copy-press #(when on-copy-press (on-copy-press children))
:max-lines max-lines}]))

View File

@ -43,7 +43,7 @@
(colors/alpha color 0.6))
(defn dropdown-comp
[{:keys [icon open? dd-height size disabled? dd-color use-border? border-color]}]
[{:keys [icon dd-height size disabled? dd-color use-border? border-color]}]
(let [dark? (colors/dark?)
{:keys [width height width-with-icon padding font icon-size]} (size sizes)
{:keys [padding-with-icon padding-with-no-icon]} padding
@ -51,74 +51,75 @@
spacing (case size
:big 4
:medium 2
:small 2)]
[rn/touchable-opacity
(cond->
{:on-press (fn []
(if (swap! open? not)
(apply-anim dd-height 120)
(apply-anim dd-height 0)))
:style (cond->
(merge
(if icon
padding-with-icon
padding-with-no-icon)
{:width (if icon
width-with-icon
width)
:height height
:border-radius (case size
:big 12
:medium 10
:small 8)
:flex-direction :row
:align-items :center
:background-color (if @open?
dd-color
(color-by-10 dd-color))})
use-border? (assoc :border-width 1
:border-color (if @open?
border-color
(color-by-10 border-color))))}
disabled? (assoc-in [:style :opacity] 0.3)
disabled? (assoc :disabled true))
(when icon
[icons/icon icon
{:no-color true
:size 20
:container-style {:margin-right spacing
:margin-top 1
:width icon-size
:height icon-size}}])
[text/text
{:size font-size
:weight :medium
:font :font-medium
:color :main} "Dropdown"]
[icons/icon
(if @open?
(if dark?
:main-icons/pullup-dark
:main-icons/pullup)
(if dark?
:main-icons/dropdown-dark
:main-icons/dropdown))
{:size 20
:no-color true
:container-style {:width (+ icon-size 3)
:border-radius 20
:margin-left (if (= :small size)
2
4)
:margin-top 1
:height (+ icon-size 4)}}]]))
:small 2)
open? (reagent/atom false)]
(fn []
[rn/touchable-opacity
(cond->
{:on-press (fn []
(if (swap! open? not)
(apply-anim dd-height 120)
(apply-anim dd-height 0)))
:style (cond->
(merge
(if icon
padding-with-icon
padding-with-no-icon)
{:width (if icon
width-with-icon
width)
:height height
:border-radius (case size
:big 12
:medium 10
:small 8)
:flex-direction :row
:align-items :center
:background-color (if @open?
dd-color
(color-by-10 dd-color))})
use-border? (assoc :border-width 1
:border-color (if @open?
border-color
(color-by-10 border-color))))}
disabled? (assoc-in [:style :opacity] 0.3)
disabled? (assoc :disabled true))
(when icon
[icons/icon icon
{:no-color true
:size 20
:container-style {:margin-right spacing
:margin-top 1
:width icon-size
:height icon-size}}])
[text/text
{:size font-size
:weight :medium
:font :font-medium
:color :main} "Dropdown"]
[icons/icon
(if @open?
(if dark?
:main-icons/pullup-dark
:main-icons/pullup)
(if dark?
:main-icons/dropdown-dark
:main-icons/dropdown))
{:size 20
:no-color true
:container-style {:width (+ icon-size 3)
:border-radius 20
:margin-left (if (= :small size)
2
4)
:margin-top 1
:height (+ icon-size 4)}}]])))
(defn items-comp
[{:keys [items on-select]}]
(let [items-count (count items)]
[rn/scroll-view
{:style {:height "100%"}
:horizontal false
{:horizontal false
:nestedScrollEnabled true}
(doall
(map-indexed (fn [index item]
@ -136,29 +137,29 @@
[text/text {:style {:text-align :center}} item]])
items))]))
(defn dropdown
(defn- f-dropdown
[{:keys [items icon text default-item on-select size disabled? border-color use-border? dd-color]}]
[:f>
(fn []
(let [open? (reagent/atom false)
dd-height (reanimated/use-shared-value 0)]
[rn/view {:style {:flex-grow 1}}
[dropdown-comp
{:items items
:icon icon
:disabled? disabled?
:size size
:dd-color dd-color
:text text
:border-color (colors/custom-color-by-theme border-color 50 60)
:use-border? use-border?
:default-item default-item
:open? open?
:dd-height dd-height}]
[reanimated/view
{:style (reanimated/apply-animations-to-style
{:height dd-height}
{:height dd-height})}
[items-comp
{:items items
:on-select on-select}]]]))])
(let [dd-height (reanimated/use-shared-value 0)]
[rn/view {:style {:flex-grow 1}}
[dropdown-comp
{:items items
:icon icon
:disabled? disabled?
:size size
:dd-color dd-color
:text text
:border-color (colors/custom-color-by-theme border-color 50 60)
:use-border? use-border?
:default-item default-item
:dd-height dd-height}]
[reanimated/view
{:style (reanimated/apply-animations-to-style
{:height dd-height}
{})}
[items-comp
{:items items
:on-select on-select}]]]))
(defn dropdown
[params]
[:f> f-dropdown params])

View File

@ -50,7 +50,7 @@
(- (oops/oget e "nativeEvent.layout.width")
(* 2 horizontal-spacing))))
(defn- view-component
(defn- f-view
[]
(let [preview-width (reagent/atom 0)
flat-list-ref (atom nil)]
@ -83,4 +83,4 @@
(defn view
[props]
[:f> view-component props])
[:f> f-view props])

View File

@ -20,61 +20,59 @@
:message 144}])
;; Standlone message skeleton
(defn message-skeleton
(defn- f-message-skeleton
[]
[:f>
(fn []
(let [color (colors/theme-colors colors/neutral-5 colors/neutral-70)
loading-color (colors/theme-colors colors/neutral-10 colors/neutral-60)
content-width (rand-nth message-content-width)
author-width (content-width :author)
message-width (content-width :message)
{window-width :width} (rn/use-window-dimensions)
translate-x (reanimated/use-shared-value (- window-width))
animated-gradient-style (reanimated/apply-animations-to-style
{:transform [{:translateX translate-x}]}
{:width window-width
:height "100%"})]
(reanimated/animate-shared-value-with-repeat translate-x window-width 1000 :linear (- 1) false)
[masked-view/masked-view
{:style {:height message-skeleton-height}
:maskElement (reagent/as-element
[rn/view
{:style {:height message-skeleton-height
:flex-direction :row
:padding-vertical 11
:background-color :transparent
:padding-left 21}}
[rn/view
{:style {:height avatar-skeleton-size
:width avatar-skeleton-size
:border-radius (/ avatar-skeleton-size 2)
:background-color color
:overflow :hidden}}]
[rn/view
{:style {:padding-left 8
:background-color :transparent}}
[rn/view
{:style {:height 8
:width author-width
:border-radius 6
:background-color color
:margin-bottom 8
:overflow :hidden}}]
[rn/view
{:style {:height 16
:width message-width
:border-radius 6
:overflow :hidden
:background-color color}}]]])}
[rn/view
{:style {:flex 1
:background-color color}}
[reanimated/linear-gradient
{:colors [color color loading-color color color]
:start {:x 0 :y 0}
:end {:x 1 :y 0}
:style animated-gradient-style}]]]))])
(let [color (colors/theme-colors colors/neutral-5 colors/neutral-70)
loading-color (colors/theme-colors colors/neutral-10 colors/neutral-60)
content-width (rand-nth message-content-width)
author-width (content-width :author)
message-width (content-width :message)
{window-width :width} (rn/get-window)
translate-x (reanimated/use-shared-value (- window-width))
animated-gradient-style (reanimated/apply-animations-to-style
{:transform [{:translateX translate-x}]}
{:width window-width
:height "100%"})]
(reanimated/animate-shared-value-with-repeat translate-x window-width 1000 :linear (- 1) false)
[masked-view/masked-view
{:style {:height message-skeleton-height}
:maskElement (reagent/as-element
[rn/view
{:style {:height message-skeleton-height
:flex-direction :row
:padding-vertical 11
:background-color :transparent
:padding-left 21}}
[rn/view
{:style {:height avatar-skeleton-size
:width avatar-skeleton-size
:border-radius (/ avatar-skeleton-size 2)
:background-color color
:overflow :hidden}}]
[rn/view
{:style {:padding-left 8
:background-color :transparent}}
[rn/view
{:style {:height 8
:width author-width
:border-radius 6
:background-color color
:margin-bottom 8
:overflow :hidden}}]
[rn/view
{:style {:height 16
:width message-width
:border-radius 6
:overflow :hidden
:background-color color}}]]])}
[rn/view
{:style {:flex 1
:background-color color}}
[reanimated/linear-gradient
{:colors [color color loading-color color color]
:start {:x 0 :y 0}
:end {:x 1 :y 0}
:style animated-gradient-style}]]]))
(defn skeleton
[parent-height]
@ -84,5 +82,6 @@
colors/white
colors/neutral-90)
:flex 1}}
(for [n (range number-of-skeletons)]
[message-skeleton {:key n}])]))
(doall
(for [n (range number-of-skeletons)]
[:f> f-message-skeleton {:key n}]))]))

View File

@ -10,64 +10,62 @@
(defn author
[{:keys [primary-name secondary-name short-chat-key time-str contact? verified? untrustworthy?]}]
[:f>
(fn []
[rn/view {:style style/container}
[rn/view {:style style/container}
[:<>
[text/text
{:weight :semi-bold
:size :paragraph-2
:number-of-lines 1
:style {:color (colors/theme-colors colors/neutral-100 colors/white)}}
primary-name]
(when (not (string/blank? secondary-name))
[:<>
[text/text
{:weight :semi-bold
{:size :paragraph-2
:number-of-lines 1
:style style/middle-dot-nickname}
middle-dot]
[text/text
{:weight :medium
:size :paragraph-2
:number-of-lines 1
:style {:color (colors/theme-colors colors/neutral-100 colors/white)}}
primary-name]
(when (not (string/blank? secondary-name))
[:<>
[text/text
{:size :paragraph-2
:number-of-lines 1
:style style/middle-dot-nickname}
middle-dot]
[text/text
{:weight :medium
:size :paragraph-2
:number-of-lines 1
:style {:color (colors/theme-colors colors/neutral-60 colors/neutral-40)}}
secondary-name]])]
(when contact?
[icons/icon :main-icons2/contact
{:size 12
:no-color true
:container-style style/icon-container}])
(cond
verified?
[icons/icon :main-icons2/verified
{:size 12
:no-color true
:container-style style/icon-container}]
untrustworthy?
[icons/icon :main-icons2/untrustworthy
{:size 12
:no-color true
:container-style style/icon-container}])
(when (and (not verified?) short-chat-key)
[text/text
{:monospace true
:size :paragraph-2
:number-of-lines 1
:style style/chat-key-text}
short-chat-key])
(when (and (not verified?) time-str)
[text/text
{:monospace true
:size :paragraph-2
:number-of-lines 1
:style style/middle-dot-chat-key}
middle-dot])
(when time-str
[text/text
{:monospace true
:size :paragraph-2
:accessibility-label :message-timestamp
:number-of-lines 1
:style (style/time-text verified?)}
time-str])])])
:style {:color (colors/theme-colors colors/neutral-60 colors/neutral-40)}}
secondary-name]])]
(when contact?
[icons/icon :main-icons2/contact
{:size 12
:no-color true
:container-style style/icon-container}])
(cond
verified?
[icons/icon :main-icons2/verified
{:size 12
:no-color true
:container-style style/icon-container}]
untrustworthy?
[icons/icon :main-icons2/untrustworthy
{:size 12
:no-color true
:container-style style/icon-container}])
(when (and (not verified?) short-chat-key)
[text/text
{:monospace true
:size :paragraph-2
:number-of-lines 1
:style style/chat-key-text}
short-chat-key])
(when (and (not verified?) time-str)
[text/text
{:monospace true
:size :paragraph-2
:number-of-lines 1
:style style/middle-dot-chat-key}
middle-dot])
(when time-str
[text/text
{:monospace true
:size :paragraph-2
:accessibility-label :message-timestamp
:number-of-lines 1
:style (style/time-text verified?)}
time-str])])

View File

@ -172,31 +172,33 @@
:style {:color (get-color :time)}}
(utils/truncate-str (:info content) 24)])]]]])
(defn system-message
(defn- f-system-message
[{:keys [type style non-pressable? animate-landing? labels on-long-press] :as message}]
[:f>
(fn []
(let [sv-color (reanimated/use-shared-value
(get-color :bg (if animate-landing? :landed :default) type))]
(when animate-landing?
(reanimated/animate-shared-value-with-delay
sv-color
(get-color :bg :default type)
0
:linear
1000))
[reanimated/touchable-opacity
{:on-press #(when-not non-pressable?
(reanimated/set-shared-value sv-color (get-color :bg :pressed type)))
:on-long-press on-long-press
:style (reanimated/apply-animations-to-style
{:background-color sv-color}
(merge
{:flex-direction :row
:flex 1
:border-radius 16
:padding-vertical 9
:padding-horizontal 11
:background-color sv-color}
style))}
[sm-render message labels]]))])
(let [sv-color (reanimated/use-shared-value
(get-color :bg (if animate-landing? :landed :default) type))]
(when animate-landing?
(reanimated/animate-shared-value-with-delay
sv-color
(get-color :bg :default type)
0
:linear
1000))
[reanimated/touchable-opacity
{:on-press #(when-not non-pressable?
(reanimated/set-shared-value sv-color (get-color :bg :pressed type)))
:on-long-press on-long-press
:style (reanimated/apply-animations-to-style
{:background-color sv-color}
(merge
{:flex-direction :row
:flex 1
:border-radius 16
:padding-vertical 9
:padding-horizontal 11
:background-color sv-color}
style))}
[sm-render message labels]]))
(defn system-message
[message]
[:f> f-system-message message])

View File

@ -16,7 +16,7 @@
pass-through? colors/white-opa-5
:else colors/neutral-70)))
(defn bottom-nav-tab
(defn- f-bottom-nav-tab
"[bottom-nav-tab opts]
opts
{:icon :i/communities
@ -29,66 +29,68 @@
"
[{:keys [icon new-notifications? notification-indicator counter-label
on-press pass-through? icon-color-anim accessibility-label test-ID]}]
[:f>
(fn []
(let [icon-animated-style (reanimated/apply-animations-to-style
{:tint-color icon-color-anim}
{:width 24
:height 24
:margin-left 33
:margin-top 8})
background-color (reanimated/use-shared-value "transparent")
background-animated-style (reanimated/apply-animations-to-style
{:background-color background-color}
{:width 90
:height 40
:border-radius 10})]
[rn/touchable-without-feedback
{:test-ID test-ID
:on-press on-press
:on-press-in #(toggle-background-color background-color false pass-through?)
:on-press-out #(toggle-background-color background-color true pass-through?)
:accessibility-label accessibility-label}
[reanimated/view {:style background-animated-style}
;; In android animations are not working for the animated components which are nested by
;; hole-view,
;; Interestingly this only happens when hole view and blur view are used together
;; Similar behavior is also seen while removing holes, and to fix that we used key and
;; force-rendered view
;; But we need animations faster for tab clicks, so we can't rely on reagent atoms,
;; so for now only using hole view for the ios tab icon notification boundary
(if platform/ios?
[hole-view/hole-view
{:key new-notifications? ;; Key is required to force removal of holes
:holes (cond
(not new-notifications?) ;; No new notifications, remove holes
[]
(let [icon-animated-style (reanimated/apply-animations-to-style
{:tint-color icon-color-anim}
{:width 24
:height 24
:margin-left 33
:margin-top 8})
background-color (reanimated/use-shared-value "transparent")
background-animated-style (reanimated/apply-animations-to-style
{:background-color background-color}
{:width 90
:height 40
:border-radius 10})]
[rn/touchable-without-feedback
{:test-ID test-ID
:on-press on-press
:on-press-in #(toggle-background-color background-color false pass-through?)
:on-press-out #(toggle-background-color background-color true pass-through?)
:accessibility-label accessibility-label}
[reanimated/view {:style background-animated-style}
;; In android animations are not working for the animated components which are nested by
;; hole-view,
;; Interestingly this only happens when hole view and blur view are used together
;; Similar behavior is also seen while removing holes, and to fix that we used key and
;; force-rendered view
;; But we need animations faster for tab clicks, so we can't rely on reagent atoms,
;; so for now only using hole view for the ios tab icon notification boundary
(if platform/ios?
[hole-view/hole-view
{:key new-notifications? ;; Key is required to force removal of holes
:holes (cond
(not new-notifications?) ;; No new notifications, remove holes
[]
(= notification-indicator :unread-dot)
[{:x 50 :y 5 :width 10 :height 10 :borderRadius 5}]
(= notification-indicator :unread-dot)
[{:x 50 :y 5 :width 10 :height 10 :borderRadius 5}]
:else
[{:x 47 :y 1 :width 18 :height 18 :borderRadius 7}])}
[reanimated/image
{:style icon-animated-style
:source (icons/icon-source (keyword (str icon 24)))}]]
[reanimated/image
{:style icon-animated-style
:source (icons/icon-source (keyword (str icon 24)))}])
(when new-notifications?
(if (= notification-indicator :counter)
[counter/counter
{:override-text-color colors/white
:override-bg-color colors/primary-50
:style {:position :absolute
:left 48
:top 2}}
counter-label]
[rn/view
{:style {:width 8
:height 8
:border-radius 4
:top 6
:left 51
:position :absolute
:background-color colors/primary-50}}]))]]))])
:else
[{:x 47 :y 1 :width 18 :height 18 :borderRadius 7}])}
[reanimated/image
{:style icon-animated-style
:source (icons/icon-source (keyword (str icon 24)))}]]
[reanimated/image
{:style icon-animated-style
:source (icons/icon-source (keyword (str icon 24)))}])
(when new-notifications?
(if (= notification-indicator :counter)
[counter/counter
{:override-text-color colors/white
:override-bg-color colors/primary-50
:style {:position :absolute
:left 48
:top 2}}
counter-label]
[rn/view
{:style {:width 8
:height 8
:border-radius 4
:top 6
:left 51
:position :absolute
:background-color colors/primary-50}}]))]]))
(defn bottom-nav-tab
[opts]
[:f> f-bottom-nav-tab opts])

View File

@ -14,40 +14,42 @@
:style style
:customization-color customization-color}]))
(defn- f-floating-shell-button
[dynamic-buttons style opacity-anim]
(let [original-style (merge {:flex-direction :row
:margin-horizontal 12
:pointer-events :box-none}
style)
animated-style (reanimated/apply-animations-to-style
(if opacity-anim
{:opacity opacity-anim}
{})
original-style)]
[reanimated/view {:style animated-style}
;; Left Section
[rn/view {:style {:flex 1}}
[dynamic-button-view :search dynamic-buttons
{:position :absolute
:right 8}]]
;; Mid Section (jump-to)
[dynamic-button-view :jump-to dynamic-buttons nil]
;; Right Section
[rn/view {:style {:flex 1}}
[rn/view
{:style {:position :absolute
:flex-direction :row
:right 0}}
[dynamic-button-view :mention dynamic-buttons {:margin-left 8}]
[dynamic-button-view :notification-down dynamic-buttons {:margin-left 8}]
[dynamic-button-view :notification-up dynamic-buttons {:margin-left 8}]
[dynamic-button-view :scroll-to-bottom dynamic-buttons {:margin-left 8}]]]]))
(defn floating-shell-button
"[floating-shell-button dynamic-buttons style opacity-anim pointer-anim]
dynamic-buttons {:button-type {:on-press on-press :count count}}
style override style
opacity-anim reanimated value (optional)"
([dynamic-button style]
(floating-shell-button dynamic-button style nil))
([dynamic-buttons style]
[:f> f-floating-shell-button dynamic-buttons style nil])
([dynamic-buttons style opacity-anim]
[:f>
(fn []
(let [original-style (merge {:flex-direction :row
:margin-horizontal 12
:pointer-events :box-none}
style)
animated-style (reanimated/apply-animations-to-style
(if opacity-anim
{:opacity opacity-anim}
{})
original-style)]
[reanimated/view {:style animated-style}
;; Left Section
[rn/view {:style {:flex 1}}
[dynamic-button-view :search dynamic-buttons
{:position :absolute
:right 8}]]
;; Mid Section (jump-to)
[dynamic-button-view :jump-to dynamic-buttons nil]
;; Right Section
[rn/view {:style {:flex 1}}
[rn/view
{:style {:position :absolute
:flex-direction :row
:right 0}}
[dynamic-button-view :mention dynamic-buttons {:margin-left 8}]
[dynamic-button-view :notification-down dynamic-buttons {:margin-left 8}]
[dynamic-button-view :notification-up dynamic-buttons {:margin-left 8}]
[dynamic-button-view :scroll-to-bottom dynamic-buttons {:margin-left 8}]]]]))]))
[:f> f-floating-shell-button dynamic-buttons style opacity-anim]))

View File

@ -10,7 +10,7 @@
[quo2.components.profile.profile-card.style :as style]
[quo2.components.avatars.user-avatar.view :as user-avatar]))
(defn- profile-card-component
(defn- f-profile-card-component
[{:keys [keycard-account? profile-picture name hash
customization-color emoji-hash on-options-press
show-emoji-hash? show-options-button? show-user-hash?
@ -25,7 +25,7 @@
last-item? false
card-style {:padding-horizontal 20
:flex 1}}}]
(let [{:keys [width]} (rn/use-window-dimensions)
(let [{:keys [width]} (rn/get-window)
padding-bottom (cond
login-card? 38
show-emoji-hash? 12
@ -104,4 +104,4 @@
(defn profile-card
[props]
[:f> profile-card-component props])
[:f> f-profile-card-component props])

View File

@ -6,85 +6,83 @@
[react-native.core :refer [use-effect]]
[quo2.components.record-audio.record-audio.helpers :as helpers]))
(defn delete-button
(defn f-delete-button
[recording? ready-to-delete? reviewing-audio? force-show-controls?]
[:f>
(fn []
(let [opacity (reanimated/use-shared-value (if force-show-controls? 1 0))
translate-x (reanimated/use-shared-value (if force-show-controls? 35 20))
scale (reanimated/use-shared-value (if force-show-controls? 0.75 1))
connector-opacity (reanimated/use-shared-value 0)
connector-width (reanimated/use-shared-value 24)
connector-height (reanimated/use-shared-value 12)
border-radius-first-half (reanimated/use-shared-value 8)
border-radius-second-half (reanimated/use-shared-value 8)
start-x-animation (fn []
(helpers/animate-linear-with-delay translate-x 12 50 133.33)
(helpers/animate-easing-with-delay connector-opacity 1 0 93.33)
(helpers/animate-easing-with-delay connector-width 56 83.33 80)
(helpers/animate-easing-with-delay connector-height 56 83.33 80)
(helpers/animate-easing-with-delay border-radius-first-half
28
83.33
80)
(helpers/animate-easing-with-delay border-radius-second-half
28
83.33
80))
reset-x-animation (fn []
(helpers/animate-linear translate-x 0 100)
(helpers/set-value connector-opacity 0)
(helpers/set-value connector-width 24)
(helpers/set-value connector-height 12)
(helpers/set-value border-radius-first-half 8)
(helpers/set-value border-radius-second-half 16))
fade-in-animation (fn []
(helpers/animate-linear translate-x 0 200)
(helpers/animate-linear opacity 1 200))
fade-out-animation (fn []
(helpers/animate-linear
translate-x
(if @reviewing-audio? 35 20)
200)
(if @reviewing-audio?
(helpers/animate-linear scale 0.75 200)
(helpers/animate-linear opacity 0 200))
(helpers/set-value connector-opacity 0)
(helpers/set-value connector-width 24)
(helpers/set-value connector-height 12)
(helpers/set-value border-radius-first-half 8)
(helpers/set-value border-radius-second-half 16))
fade-out-reset-animation (fn []
(helpers/animate-linear opacity 0 200)
(helpers/animate-linear-with-delay translate-x 20 0 200)
(helpers/animate-linear-with-delay scale 1 0 200))]
(use-effect (fn []
(if @recording?
(fade-in-animation)
(fade-out-animation)))
[@recording?])
(use-effect (fn []
(when-not @reviewing-audio?
(fade-out-reset-animation)))
[@reviewing-audio?])
(use-effect (fn []
(cond
@ready-to-delete?
(start-x-animation)
@recording?
(reset-x-animation)))
[@ready-to-delete?])
[:<>
[reanimated/view {:style (style/delete-button-container opacity)}
[reanimated/view
{:style (style/delete-button-connector connector-opacity
connector-width
connector-height
border-radius-first-half
border-radius-second-half)}]]
[reanimated/view
{:style (style/delete-button scale translate-x opacity)
:pointer-events :none}
[icons/icon :i/delete
{:color colors/white
:size 20}]]]))])
(let [opacity (reanimated/use-shared-value (if force-show-controls? 1 0))
translate-x (reanimated/use-shared-value (if force-show-controls? 35 20))
scale (reanimated/use-shared-value (if force-show-controls? 0.75 1))
connector-opacity (reanimated/use-shared-value 0)
connector-width (reanimated/use-shared-value 24)
connector-height (reanimated/use-shared-value 12)
border-radius-first-half (reanimated/use-shared-value 8)
border-radius-second-half (reanimated/use-shared-value 8)
start-x-animation (fn []
(helpers/animate-linear-with-delay translate-x 12 50 133.33)
(helpers/animate-easing-with-delay connector-opacity 1 0 93.33)
(helpers/animate-easing-with-delay connector-width 56 83.33 80)
(helpers/animate-easing-with-delay connector-height 56 83.33 80)
(helpers/animate-easing-with-delay border-radius-first-half
28
83.33
80)
(helpers/animate-easing-with-delay border-radius-second-half
28
83.33
80))
reset-x-animation (fn []
(helpers/animate-linear translate-x 0 100)
(helpers/set-value connector-opacity 0)
(helpers/set-value connector-width 24)
(helpers/set-value connector-height 12)
(helpers/set-value border-radius-first-half 8)
(helpers/set-value border-radius-second-half 16))
fade-in-animation (fn []
(helpers/animate-linear translate-x 0 200)
(helpers/animate-linear opacity 1 200))
fade-out-animation (fn []
(helpers/animate-linear
translate-x
(if @reviewing-audio? 35 20)
200)
(if @reviewing-audio?
(helpers/animate-linear scale 0.75 200)
(helpers/animate-linear opacity 0 200))
(helpers/set-value connector-opacity 0)
(helpers/set-value connector-width 24)
(helpers/set-value connector-height 12)
(helpers/set-value border-radius-first-half 8)
(helpers/set-value border-radius-second-half 16))
fade-out-reset-animation (fn []
(helpers/animate-linear opacity 0 200)
(helpers/animate-linear-with-delay translate-x 20 0 200)
(helpers/animate-linear-with-delay scale 1 0 200))]
(use-effect (fn []
(if @recording?
(fade-in-animation)
(fade-out-animation)))
[@recording?])
(use-effect (fn []
(when-not @reviewing-audio?
(fade-out-reset-animation)))
[@reviewing-audio?])
(use-effect (fn []
(cond
@ready-to-delete?
(start-x-animation)
@recording?
(reset-x-animation)))
[@ready-to-delete?])
[:<>
[reanimated/view {:style (style/delete-button-container opacity)}
[reanimated/view
{:style (style/delete-button-connector connector-opacity
connector-width
connector-height
border-radius-first-half
border-radius-second-half)}]]
[reanimated/view
{:style (style/delete-button scale translate-x opacity)
:pointer-events :none}
[icons/icon :i/delete
{:color colors/white
:size 20}]]]))

View File

@ -6,76 +6,74 @@
[react-native.core :refer [use-effect]]
[quo2.components.record-audio.record-audio.helpers :as helpers]))
(defn lock-button
(defn f-lock-button
[recording? ready-to-lock? locked?]
[:f>
(fn []
(let [translate-x-y (reanimated/use-shared-value 20)
opacity (reanimated/use-shared-value 0)
connector-opacity (reanimated/use-shared-value 0)
width (reanimated/use-shared-value 24)
height (reanimated/use-shared-value 12)
border-radius-first-half (reanimated/use-shared-value 8)
border-radius-second-half (reanimated/use-shared-value 8)
start-x-y-animation (fn []
(helpers/animate-linear-with-delay translate-x-y 8 50 116.66)
(helpers/animate-easing-with-delay connector-opacity 1 0 80)
(helpers/animate-easing-with-delay width 56 83.33 63.33)
(helpers/animate-easing-with-delay height 56 83.33 63.33)
(helpers/animate-easing-with-delay border-radius-first-half
28
83.33
63.33)
(helpers/animate-easing-with-delay border-radius-second-half
28
83.33
63.33))
reset-x-y-animation (fn []
(helpers/animate-linear translate-x-y 0 100)
(helpers/set-value connector-opacity 0)
(helpers/set-value width 24)
(helpers/set-value height 12)
(helpers/set-value border-radius-first-half 8)
(helpers/set-value border-radius-second-half 16))
fade-in-animation (fn []
(helpers/animate-linear translate-x-y 0 220)
(helpers/animate-linear opacity 1 220))
fade-out-animation (fn []
(helpers/animate-linear translate-x-y 20 200)
(helpers/animate-linear opacity 0 200)
(helpers/set-value connector-opacity 0)
(helpers/set-value width 24)
(helpers/set-value height 12)
(helpers/set-value border-radius-first-half 8)
(helpers/set-value border-radius-second-half 16))]
(use-effect (fn []
(if @recording?
(fade-in-animation)
(fade-out-animation)))
[@recording?])
(use-effect (fn []
(cond
@ready-to-lock?
(start-x-y-animation)
(and @recording? (not @locked?))
(reset-x-y-animation)))
[@ready-to-lock?])
(use-effect (fn []
(if @locked?
(fade-out-animation)
(reset-x-y-animation)))
[@locked?])
[:<>
[reanimated/view {:style (style/lock-button-container opacity)}
[reanimated/view
{:style (style/lock-button-connector connector-opacity
width
height
border-radius-first-half
border-radius-second-half)}]]
[reanimated/view
{:style (style/lock-button translate-x-y opacity)
:pointer-events :none}
[icons/icon (if @ready-to-lock? :i/locked :i/unlocked)
{:color (colors/theme-colors colors/black colors/white)
:size 20}]]]))])
(let [translate-x-y (reanimated/use-shared-value 20)
opacity (reanimated/use-shared-value 0)
connector-opacity (reanimated/use-shared-value 0)
width (reanimated/use-shared-value 24)
height (reanimated/use-shared-value 12)
border-radius-first-half (reanimated/use-shared-value 8)
border-radius-second-half (reanimated/use-shared-value 8)
start-x-y-animation (fn []
(helpers/animate-linear-with-delay translate-x-y 8 50 116.66)
(helpers/animate-easing-with-delay connector-opacity 1 0 80)
(helpers/animate-easing-with-delay width 56 83.33 63.33)
(helpers/animate-easing-with-delay height 56 83.33 63.33)
(helpers/animate-easing-with-delay border-radius-first-half
28
83.33
63.33)
(helpers/animate-easing-with-delay border-radius-second-half
28
83.33
63.33))
reset-x-y-animation (fn []
(helpers/animate-linear translate-x-y 0 100)
(helpers/set-value connector-opacity 0)
(helpers/set-value width 24)
(helpers/set-value height 12)
(helpers/set-value border-radius-first-half 8)
(helpers/set-value border-radius-second-half 16))
fade-in-animation (fn []
(helpers/animate-linear translate-x-y 0 220)
(helpers/animate-linear opacity 1 220))
fade-out-animation (fn []
(helpers/animate-linear translate-x-y 20 200)
(helpers/animate-linear opacity 0 200)
(helpers/set-value connector-opacity 0)
(helpers/set-value width 24)
(helpers/set-value height 12)
(helpers/set-value border-radius-first-half 8)
(helpers/set-value border-radius-second-half 16))]
(use-effect (fn []
(if @recording?
(fade-in-animation)
(fade-out-animation)))
[@recording?])
(use-effect (fn []
(cond
@ready-to-lock?
(start-x-y-animation)
(and @recording? (not @locked?))
(reset-x-y-animation)))
[@ready-to-lock?])
(use-effect (fn []
(if @locked?
(fade-out-animation)
(reset-x-y-animation)))
[@locked?])
[:<>
[reanimated/view {:style (style/lock-button-container opacity)}
[reanimated/view
{:style (style/lock-button-connector connector-opacity
width
height
border-radius-first-half
border-radius-second-half)}]]
[reanimated/view
{:style (style/lock-button translate-x-y opacity)
:pointer-events :none}
[icons/icon (if @ready-to-lock? :i/locked :i/unlocked)
{:color (colors/theme-colors colors/black colors/white)
:size 20}]]]))

View File

@ -7,22 +7,20 @@
[quo2.components.buttons.button :as button]
[quo2.components.record-audio.record-audio.helpers :as helpers]))
(defn record-button
(defn f-record-button
[recording? reviewing-audio?]
[:f>
(fn []
(let [opacity (reanimated/use-shared-value 1)
show-animation #(helpers/set-value opacity 1)
hide-animation #(helpers/set-value opacity 0)]
(use-effect (fn []
(if (or @recording? @reviewing-audio?)
(hide-animation)
(show-animation)))
[@recording? @reviewing-audio?])
[reanimated/view {:style (style/record-button-container opacity)}
[button/button
{:type :outline
:size 32
:width 32
:accessibility-label :mic-button}
[icons/icon :i/audio {:color (colors/theme-colors colors/neutral-50 colors/neutral-40)}]]]))])
(let [opacity (reanimated/use-shared-value 1)
show-animation #(helpers/set-value opacity 1)
hide-animation #(helpers/set-value opacity 0)]
(use-effect (fn []
(if (or @recording? @reviewing-audio?)
(hide-animation)
(show-animation)))
[@recording? @reviewing-audio?])
[reanimated/view {:style (style/record-button-container opacity)}
[button/button
{:type :outline
:size 32
:width 32
:accessibility-label :mic-button}
[icons/icon :i/audio {:color (colors/theme-colors colors/neutral-50 colors/neutral-40)}]]]))

View File

@ -27,177 +27,175 @@
(reagent/as-element
[reanimated/view {:style (style/animated-circle scale opacity color)}]))))))
(defn record-button-big
(defn f-record-button-big
[recording? ready-to-send? ready-to-lock? ready-to-delete? record-button-is-animating?
record-button-at-initial-position? locked? reviewing-audio? recording-timer recording-length-ms
clear-timeout touch-active? recorder-ref reload-recorder-fn idle? on-send on-cancel]
[:f>
(fn []
(let [scale (reanimated/use-shared-value 1)
opacity (reanimated/use-shared-value 0)
opacity-from (if @ready-to-lock? opacity-from-lock opacity-from-default)
animations (map
(fn [index]
(let [ring-scale (worklets.record-audio/ring-scale scale
(* scale-padding
index))]
{:scale ring-scale
:opacity (reanimated/interpolate ring-scale
[1 scale-to-each]
[opacity-from 0])}))
(range 0 5))
rings-color (cond
@ready-to-lock? (colors/theme-colors colors/neutral-80-opa-5-opaque
colors/neutral-80)
@ready-to-delete? colors/danger-50
:else colors/primary-50)
translate-y (reanimated/use-shared-value 0)
translate-x (reanimated/use-shared-value 0)
button-color colors/primary-50
icon-color (if (and (not (colors/dark?)) @ready-to-lock?) colors/black colors/white)
icon-opacity (reanimated/use-shared-value 1)
red-overlay-opacity (reanimated/use-shared-value 0)
gray-overlay-opacity (reanimated/use-shared-value 0)
complete-animation
(fn []
(cond
(and @ready-to-lock? (not @record-button-is-animating?))
(do
(reset! locked? true)
(reset! ready-to-lock? false))
(and (not @locked?) (not @reviewing-audio?))
(audio/stop-recording
@recorder-ref
(fn []
(let [scale (reanimated/use-shared-value 1)
opacity (reanimated/use-shared-value 0)
opacity-from (if @ready-to-lock? opacity-from-lock opacity-from-default)
animations (map
(fn [index]
(let [ring-scale (worklets.record-audio/ring-scale scale
(* scale-padding
index))]
{:scale ring-scale
:opacity (reanimated/interpolate ring-scale
[1 scale-to-each]
[opacity-from 0])}))
(range 0 5))
rings-color (cond
@ready-to-lock? (colors/theme-colors colors/neutral-80-opa-5-opaque
colors/neutral-80)
@ready-to-delete? colors/danger-50
:else colors/primary-50)
translate-y (reanimated/use-shared-value 0)
translate-x (reanimated/use-shared-value 0)
button-color colors/primary-50
icon-color (if (and (not (colors/dark?)) @ready-to-lock?) colors/black colors/white)
icon-opacity (reanimated/use-shared-value 1)
red-overlay-opacity (reanimated/use-shared-value 0)
gray-overlay-opacity (reanimated/use-shared-value 0)
complete-animation
(fn []
(cond
(and @ready-to-lock? (not @record-button-is-animating?))
(do
(reset! locked? true)
(reset! ready-to-lock? false))
(and (not @locked?) (not @reviewing-audio?))
(audio/stop-recording
@recorder-ref
(fn []
(cond
@ready-to-send?
(when on-send
(on-send {:file-path (audio/get-recorder-file-path @recorder-ref)
:duration @recording-length-ms}))
@ready-to-delete?
(when on-cancel
(on-cancel)))
(reload-recorder-fn)
(reset! recording? false)
(reset! ready-to-send? false)
(reset! ready-to-delete? false)
(reset! ready-to-lock? false)
(reset! idle? true)
(js/setTimeout #(reset! idle? false) 1000)
(js/clearInterval @recording-timer)
(reset! recording-length-ms 0)
(log/debug "[record-audio] stop recording - success"))
#(log/error "[record-audio] stop recording - error: " %))))
start-animation (fn []
(helpers/set-value opacity 1)
(helpers/animate-linear scale 2.6 signal-anim-duration)
;; TODO: Research if we can implement this with withSequence method
;; from Reanimated 2
;; GitHub issue [#14561]:
;; https://github.com/status-im/status-mobile/issues/14561
(reset! clear-timeout
(js/setTimeout
(fn []
(helpers/set-value scale scale-to-each)
(helpers/animate-linear-with-delay-loop scale
scale-to-total
signal-anim-duration-2
0))
signal-anim-duration)))
stop-animation (fn []
(helpers/set-value opacity 0)
(reanimated/cancel-animation scale)
(helpers/set-value scale 1)
(when @clear-timeout (js/clearTimeout @clear-timeout)))
start-y-animation (fn []
(reset! record-button-at-initial-position? false)
(reset! record-button-is-animating? true)
(helpers/animate-easing translate-y -64 250)
(helpers/animate-linear-with-delay icon-opacity 0 33.33 76.66)
(js/setTimeout (fn []
(reset! record-button-is-animating? false)
(when-not @touch-active? (complete-animation)))
250))
reset-y-animation (fn []
(helpers/animate-easing translate-y 0 300)
(helpers/animate-linear icon-opacity 1 500)
(js/setTimeout (fn []
(reset! record-button-at-initial-position? true))
500))
start-x-animation (fn []
(reset! record-button-at-initial-position? false)
(reset! record-button-is-animating? true)
(helpers/animate-easing translate-x -64 250)
(helpers/animate-linear-with-delay icon-opacity 0 33.33 76.66)
(helpers/animate-linear red-overlay-opacity 1 33.33)
(js/setTimeout (fn []
(reset! record-button-is-animating? false)
(when-not @touch-active? (complete-animation)))
250))
reset-x-animation (fn []
(helpers/animate-easing translate-x 0 300)
(helpers/animate-linear icon-opacity 1 500)
(helpers/animate-linear red-overlay-opacity 0 100)
(js/setTimeout (fn []
(reset! record-button-at-initial-position? true))
500))
start-x-y-animation (fn []
(reset! record-button-at-initial-position? false)
(reset! record-button-is-animating? true)
(helpers/animate-easing translate-y -44 200)
(helpers/animate-easing translate-x -44 200)
(helpers/animate-linear-with-delay icon-opacity 0 33.33 33.33)
(helpers/animate-linear gray-overlay-opacity 1 33.33)
(js/setTimeout (fn []
(reset! record-button-is-animating? false)
(when-not @touch-active? (complete-animation)))
200))
reset-x-y-animation (fn []
(helpers/animate-easing translate-y 0 300)
(helpers/animate-easing translate-x 0 300)
(helpers/animate-linear icon-opacity 1 500)
(helpers/animate-linear gray-overlay-opacity 0 800)
(js/setTimeout (fn []
(reset! record-button-at-initial-position? true))
800))]
(use-effect (fn []
(cond
@ready-to-send?
(when on-send
(on-send {:file-path (audio/get-recorder-file-path @recorder-ref)
:duration @recording-length-ms}))
@ready-to-delete?
(when on-cancel
(on-cancel)))
(reload-recorder-fn)
(reset! recording? false)
(reset! ready-to-send? false)
(reset! ready-to-delete? false)
(reset! ready-to-lock? false)
(reset! idle? true)
(js/setTimeout #(reset! idle? false) 1000)
(js/clearInterval @recording-timer)
(reset! recording-length-ms 0)
(log/debug "[record-audio] stop recording - success"))
#(log/error "[record-audio] stop recording - error: " %))))
start-animation (fn []
(helpers/set-value opacity 1)
(helpers/animate-linear scale 2.6 signal-anim-duration)
;; TODO: Research if we can implement this with withSequence method
;; from Reanimated 2
;; GitHub issue [#14561]:
;; https://github.com/status-im/status-mobile/issues/14561
(reset! clear-timeout
(js/setTimeout
(fn []
(helpers/set-value scale scale-to-each)
(helpers/animate-linear-with-delay-loop scale
scale-to-total
signal-anim-duration-2
0))
signal-anim-duration)))
stop-animation (fn []
(helpers/set-value opacity 0)
(reanimated/cancel-animation scale)
(helpers/set-value scale 1)
(when @clear-timeout (js/clearTimeout @clear-timeout)))
start-y-animation (fn []
(reset! record-button-at-initial-position? false)
(reset! record-button-is-animating? true)
(helpers/animate-easing translate-y -64 250)
(helpers/animate-linear-with-delay icon-opacity 0 33.33 76.66)
(js/setTimeout (fn []
(reset! record-button-is-animating? false)
(when-not @touch-active? (complete-animation)))
250))
reset-y-animation (fn []
(helpers/animate-easing translate-y 0 300)
(helpers/animate-linear icon-opacity 1 500)
(js/setTimeout (fn []
(reset! record-button-at-initial-position? true))
500))
start-x-animation (fn []
(reset! record-button-at-initial-position? false)
(reset! record-button-is-animating? true)
(helpers/animate-easing translate-x -64 250)
(helpers/animate-linear-with-delay icon-opacity 0 33.33 76.66)
(helpers/animate-linear red-overlay-opacity 1 33.33)
(js/setTimeout (fn []
(reset! record-button-is-animating? false)
(when-not @touch-active? (complete-animation)))
250))
reset-x-animation (fn []
(helpers/animate-easing translate-x 0 300)
(helpers/animate-linear icon-opacity 1 500)
(helpers/animate-linear red-overlay-opacity 0 100)
(js/setTimeout (fn []
(reset! record-button-at-initial-position? true))
500))
start-x-y-animation (fn []
(reset! record-button-at-initial-position? false)
(reset! record-button-is-animating? true)
(helpers/animate-easing translate-y -44 200)
(helpers/animate-easing translate-x -44 200)
(helpers/animate-linear-with-delay icon-opacity 0 33.33 33.33)
(helpers/animate-linear gray-overlay-opacity 1 33.33)
(js/setTimeout (fn []
(reset! record-button-is-animating? false)
(when-not @touch-active? (complete-animation)))
200))
reset-x-y-animation (fn []
(helpers/animate-easing translate-y 0 300)
(helpers/animate-easing translate-x 0 300)
(helpers/animate-linear icon-opacity 1 500)
(helpers/animate-linear gray-overlay-opacity 0 800)
(js/setTimeout (fn []
(reset! record-button-at-initial-position? true))
800))]
(use-effect (fn []
(cond
@recording?
(start-animation)
(not @ready-to-lock?)
(stop-animation)))
[@recording?])
(use-effect (fn []
(if @ready-to-lock?
(start-x-y-animation)
(reset-x-y-animation)))
[@ready-to-lock?])
(use-effect (fn []
(if @ready-to-send?
(start-y-animation)
(reset-y-animation)))
[@ready-to-send?])
(use-effect (fn []
(if @ready-to-delete?
(start-x-animation)
(reset-x-animation)))
[@ready-to-delete?])
[reanimated/view
{:style (style/record-button-big-container translate-x translate-y opacity)
:pointer-events :none}
[:<>
(map-indexed
(fn [id animation]
^{:key id}
[animated-ring
{:scale (:scale animation)
:opacity (:opacity animation)
:color rings-color}])
animations)]
[rn/view {:style (style/record-button-big-body button-color)}
[reanimated/view {:style (style/record-button-big-red-overlay red-overlay-opacity)}]
[reanimated/view {:style (style/record-button-big-gray-overlay gray-overlay-opacity)}]
[reanimated/view {:style (style/record-button-big-icon-container icon-opacity)}
(if @locked?
[rn/view {:style style/stop-icon}]
[icons/icon :i/audio {:color icon-color}])]]]))])
@recording?
(start-animation)
(not @ready-to-lock?)
(stop-animation)))
[@recording?])
(use-effect (fn []
(if @ready-to-lock?
(start-x-y-animation)
(reset-x-y-animation)))
[@ready-to-lock?])
(use-effect (fn []
(if @ready-to-send?
(start-y-animation)
(reset-y-animation)))
[@ready-to-send?])
(use-effect (fn []
(if @ready-to-delete?
(start-x-animation)
(reset-x-animation)))
[@ready-to-delete?])
[reanimated/view
{:style (style/record-button-big-container translate-x translate-y opacity)
:pointer-events :none}
[:<>
(map-indexed
(fn [id animation]
^{:key id}
[animated-ring
{:scale (:scale animation)
:opacity (:opacity animation)
:color rings-color}])
animations)]
[rn/view {:style (style/record-button-big-body button-color)}
[reanimated/view {:style (style/record-button-big-red-overlay red-overlay-opacity)}]
[reanimated/view {:style (style/record-button-big-gray-overlay gray-overlay-opacity)}]
[reanimated/view {:style (style/record-button-big-icon-container icon-opacity)}
(if @locked?
[rn/view {:style style/stop-icon}]
[icons/icon :i/audio {:color icon-color}])]]]))

View File

@ -6,88 +6,86 @@
[react-native.core :refer [use-effect]]
[quo2.components.record-audio.record-audio.helpers :as helpers]))
(defn send-button
(defn f-send-button
[recording? ready-to-send? reviewing-audio? force-show-controls?]
[:f>
(fn []
(let [opacity (reanimated/use-shared-value (if force-show-controls? 1 0))
translate-y (reanimated/use-shared-value (if force-show-controls? 76 20))
connector-opacity (reanimated/use-shared-value 0)
width (reanimated/use-shared-value 12)
height (reanimated/use-shared-value 24)
border-radius-first-half (reanimated/use-shared-value 16)
border-radius-second-half (reanimated/use-shared-value 8)
start-y-animation (fn []
(helpers/animate-linear-with-delay translate-y 12 50 133.33)
(helpers/animate-easing-with-delay connector-opacity 1 0 93.33)
(helpers/animate-easing-with-delay width 56 83.33 80)
(helpers/animate-easing-with-delay height 56 83.33 80)
(helpers/animate-easing-with-delay border-radius-first-half
28
83.33
80)
(helpers/animate-easing-with-delay border-radius-second-half
28
83.33
80))
reset-y-animation (fn []
(helpers/animate-linear translate-y 0 100)
(helpers/set-value connector-opacity 0)
(helpers/set-value width 12)
(helpers/set-value height 24)
(helpers/set-value border-radius-first-half 16)
(helpers/set-value border-radius-second-half 8))
fade-in-animation (fn []
(helpers/animate-linear translate-y 0 200)
(helpers/animate-linear opacity 1 200))
fade-out-animation (fn []
(when-not force-show-controls?
(helpers/animate-linear
translate-y
(if @reviewing-audio? 76 20)
200))
(when-not @reviewing-audio?
(helpers/animate-linear opacity 0 200))
(helpers/set-value connector-opacity 0)
(helpers/set-value width 24)
(helpers/set-value height 12)
(helpers/set-value border-radius-first-half 8)
(helpers/set-value border-radius-second-half 16))
fade-out-reset-animation (fn []
(helpers/animate-linear opacity 0 200)
(helpers/animate-linear-with-delay translate-y 20 0 200)
(helpers/set-value connector-opacity 0)
(helpers/set-value width 24)
(helpers/set-value height 12)
(helpers/set-value border-radius-first-half 8)
(helpers/set-value border-radius-second-half 16))]
(use-effect (fn []
(if @recording?
(fade-in-animation)
(fade-out-animation)))
[@recording?])
(use-effect (fn []
(when-not @reviewing-audio?
(fade-out-reset-animation)))
[@reviewing-audio?])
(use-effect (fn []
(cond
@ready-to-send?
(start-y-animation)
@recording? (reset-y-animation)))
[@ready-to-send?])
[:<>
[reanimated/view {:style (style/send-button-container opacity)}
[reanimated/view
{:style (style/send-button-connector connector-opacity
width
height
border-radius-first-half
border-radius-second-half)}]]
[reanimated/view
{:style (style/send-button translate-y opacity)
:pointer-events :none}
[icons/icon :i/arrow-up
{:color colors/white
:size 20
:container-style style/send-icon-container}]]]))])
(let [opacity (reanimated/use-shared-value (if force-show-controls? 1 0))
translate-y (reanimated/use-shared-value (if force-show-controls? 76 20))
connector-opacity (reanimated/use-shared-value 0)
width (reanimated/use-shared-value 12)
height (reanimated/use-shared-value 24)
border-radius-first-half (reanimated/use-shared-value 16)
border-radius-second-half (reanimated/use-shared-value 8)
start-y-animation (fn []
(helpers/animate-linear-with-delay translate-y 12 50 133.33)
(helpers/animate-easing-with-delay connector-opacity 1 0 93.33)
(helpers/animate-easing-with-delay width 56 83.33 80)
(helpers/animate-easing-with-delay height 56 83.33 80)
(helpers/animate-easing-with-delay border-radius-first-half
28
83.33
80)
(helpers/animate-easing-with-delay border-radius-second-half
28
83.33
80))
reset-y-animation (fn []
(helpers/animate-linear translate-y 0 100)
(helpers/set-value connector-opacity 0)
(helpers/set-value width 12)
(helpers/set-value height 24)
(helpers/set-value border-radius-first-half 16)
(helpers/set-value border-radius-second-half 8))
fade-in-animation (fn []
(helpers/animate-linear translate-y 0 200)
(helpers/animate-linear opacity 1 200))
fade-out-animation (fn []
(when-not force-show-controls?
(helpers/animate-linear
translate-y
(if @reviewing-audio? 76 20)
200))
(when-not @reviewing-audio?
(helpers/animate-linear opacity 0 200))
(helpers/set-value connector-opacity 0)
(helpers/set-value width 24)
(helpers/set-value height 12)
(helpers/set-value border-radius-first-half 8)
(helpers/set-value border-radius-second-half 16))
fade-out-reset-animation (fn []
(helpers/animate-linear opacity 0 200)
(helpers/animate-linear-with-delay translate-y 20 0 200)
(helpers/set-value connector-opacity 0)
(helpers/set-value width 24)
(helpers/set-value height 12)
(helpers/set-value border-radius-first-half 8)
(helpers/set-value border-radius-second-half 16))]
(use-effect (fn []
(if @recording?
(fade-in-animation)
(fade-out-animation)))
[@recording?])
(use-effect (fn []
(when-not @reviewing-audio?
(fade-out-reset-animation)))
[@reviewing-audio?])
(use-effect (fn []
(cond
@ready-to-send?
(start-y-animation)
@recording? (reset-y-animation)))
[@ready-to-send?])
[:<>
[reanimated/view {:style (style/send-button-container opacity)}
[reanimated/view
{:style (style/send-button-connector connector-opacity
width
height
border-radius-first-half
border-radius-second-half)}]]
[reanimated/view
{:style (style/send-button translate-y opacity)
:pointer-events :none}
[icons/icon :i/arrow-up
{:color colors/white
:size 20
:container-style style/send-icon-container}]]]))

View File

@ -86,71 +86,68 @@
(or ignore-min-y? (>= location-y y))
(or ignore-max-y? (<= location-y max-y))))))
(defn- recording-bar
(defn- f-recording-bar
[recording-length-ms ready-to-delete?]
[:f>
(fn []
(let [fill-percentage (/ (* recording-length-ms 100) max-audio-duration-ms)]
[rn/view {:style (style/recording-bar-container)}
[rn/view {:style (style/recording-bar fill-percentage ready-to-delete?)}]]))])
(let [fill-percentage (/ (* recording-length-ms 100) max-audio-duration-ms)]
[rn/view {:style (style/recording-bar-container)}
[rn/view {:style (style/recording-bar fill-percentage ready-to-delete?)}]]))
(defn- time-counter
(defn- f-time-counter
[recording? recording-length-ms ready-to-delete? reviewing-audio? audio-current-time-ms]
[:f>
(fn []
(let [s (quot (if recording? recording-length-ms audio-current-time-ms) 1000)
time-str (gstring/format "%02d:%02d" (quot s 60) (mod s 60))]
[rn/view {:style (style/timer-container reviewing-audio?)}
(when-not reviewing-audio?
[rn/view {:style (style/timer-circle)}])
[text/text
(merge
{:size :label
:weight :semi-bold}
(when ready-to-delete?
{:style (style/timer-text)}))
time-str]]))])
(let [s (quot (if recording? recording-length-ms audio-current-time-ms) 1000)
time-str (gstring/format "%02d:%02d" (quot s 60) (mod s 60))]
[rn/view {:style (style/timer-container reviewing-audio?)}
(when-not reviewing-audio?
[rn/view {:style (style/timer-circle)}])
[text/text
(merge
{:size :label
:weight :semi-bold}
(when ready-to-delete?
{:style (style/timer-text)}))
time-str]]))
(defn- play-button
(defn- f-play-button
[playing-audio? player-ref playing-timer audio-current-time-ms seeking-audio?]
[:f>
(fn []
(let [on-play (fn []
(reset! playing-audio? true)
(reset! playing-timer
(js/setInterval
(fn []
(let [current-time (audio/get-player-current-time @player-ref)
player-state (audio/get-state @player-ref)
playing? (= player-state audio/PLAYING)]
(when (and playing? (not @seeking-audio?) (> current-time 0))
(reset! audio-current-time-ms current-time))))
100)))
on-pause (fn []
(reset! playing-audio? false)
(when @playing-timer
(js/clearInterval @playing-timer)
(reset! playing-timer nil))
(log/debug "[record-audio] toggle play / pause - success"))
on-press (fn []
(audio/toggle-playpause-player
@player-ref
on-play
on-pause
#(log/error "[record-audio] toggle play / pause - error: " %)))]
[rn/touchable-opacity
{:style (style/play-button)
:on-press on-press}
[icons/icon
(if @playing-audio? :i/pause :i/play)
{:color (colors/theme-colors colors/neutral-100 colors/white)}]]))])
(let [on-play (fn []
(reset! playing-audio? true)
(reset! playing-timer
(js/setInterval
(fn []
(let [current-time (audio/get-player-current-time @player-ref)
player-state (audio/get-state @player-ref)
playing? (= player-state audio/PLAYING)]
(when (and playing? (not @seeking-audio?) (> current-time 0))
(reset! audio-current-time-ms current-time))))
100)))
on-pause (fn []
(reset! playing-audio? false)
(when @playing-timer
(js/clearInterval @playing-timer)
(reset! playing-timer nil))
(log/debug "[record-audio] toggle play / pause - success"))
on-press (fn []
(audio/toggle-playpause-player
@player-ref
on-play
on-pause
#(log/error "[record-audio] toggle play / pause - error: " %)))]
[rn/touchable-opacity
{:style (style/play-button)
:on-press on-press}
[icons/icon
(if @playing-audio? :i/pause :i/play)
{:color (colors/theme-colors colors/neutral-100 colors/white)}]]))
(defn view
(defn record-audio
[{:keys [on-init on-start-recording on-send on-cancel on-reviewing-audio
record-audio-permission-granted
on-request-record-audio-permission on-check-audio-permissions
audio-file]}]
[:f>
;; TODO we need to refactor this, and use :f> with defined function, currenly state is reseted each
;; time parent component
;; is re-rendered
(fn []
(let [recording? (reagent/atom false)
locked? (reagent/atom false)
@ -524,16 +521,17 @@
:pointer-events :box-none}
(when @reviewing-audio?
[:<>
[play-button playing-audio? player-ref playing-timer audio-current-time-ms seeking-audio?]
[soundtrack/soundtrack
[:f> f-play-button playing-audio? player-ref playing-timer audio-current-time-ms
seeking-audio?]
[:f> soundtrack/f-soundtrack
{:audio-current-time-ms audio-current-time-ms
:player-ref player-ref
:seeking-audio? seeking-audio?}]])
(when (or @recording? @reviewing-audio?)
[time-counter @recording? @recording-length-ms @ready-to-delete? @reviewing-audio?
[:f> f-time-counter @recording? @recording-length-ms @ready-to-delete? @reviewing-audio?
@audio-current-time-ms])
(when @recording?
[recording-bar @recording-length-ms @ready-to-delete?])
[:f> f-recording-bar @recording-length-ms @ready-to-delete?])
[rn/view
{:test-ID "record-audio"
:style style/button-container
@ -545,11 +543,12 @@
:on-start-should-set-responder on-start-should-set-responder
:on-responder-move on-responder-move
:on-responder-release on-responder-release}
[delete-button/delete-button recording? ready-to-delete? reviewing-audio?
[:f> delete-button/f-delete-button recording? ready-to-delete? reviewing-audio?
@force-show-controls?]
[lock-button/lock-button recording? ready-to-lock? locked?]
[send-button/send-button recording? ready-to-send? reviewing-audio? @force-show-controls?]
[record-button-big/record-button-big
[:f> lock-button/f-lock-button recording? ready-to-lock? locked?]
[:f> send-button/f-send-button recording? ready-to-send? reviewing-audio?
@force-show-controls?]
[:f> record-button-big/f-record-button-big
recording?
ready-to-send?
ready-to-lock?
@ -567,6 +566,4 @@
idle?
on-send
on-cancel]
[record-button/record-button recording? reviewing-audio?]]])))])
(def record-audio view)
[:f> record-button/f-record-button recording? reviewing-audio?]]])))])

View File

@ -18,7 +18,7 @@
(with-redefs [audio/get-player-duration (fn [] 2000)]
(let [player-ref (reagent/atom {})
audio-current-time-ms (reagent/atom 0)]
(h/render [soundtrack/soundtrack
(h/render [:f> soundtrack/f-soundtrack
{:player-ref player-ref
:audio-current-time-ms audio-current-time-ms}])
(-> (h/expect (h/get-by-test-id "soundtrack"))
@ -29,7 +29,7 @@
(let [seeking-audio? (reagent/atom false)
player-ref (reagent/atom {})
audio-current-time-ms (reagent/atom 0)]
(h/render [soundtrack/soundtrack
(h/render [:f> soundtrack/f-soundtrack
{:seeking-audio? seeking-audio?
:player-ref player-ref
:audio-current-time-ms audio-current-time-ms}])
@ -45,7 +45,7 @@
(let [seeking-audio? (reagent/atom false)
player-ref (reagent/atom {})
audio-current-time-ms (reagent/atom 0)]
(h/render [soundtrack/soundtrack
(h/render [:f> soundtrack/f-soundtrack
{:seeking-audio? seeking-audio?
:player-ref player-ref
:audio-current-time-ms audio-current-time-ms}])
@ -67,7 +67,7 @@
(let [seeking-audio? (reagent/atom false)
player-ref (reagent/atom {})
audio-current-time-ms (reagent/atom 0)]
(h/render [soundtrack/soundtrack
(h/render [:f> soundtrack/f-soundtrack
{:seeking-audio? seeking-audio?
:player-ref player-ref
:audio-current-time-ms audio-current-time-ms}])

View File

@ -9,30 +9,28 @@
(def ^:private thumb-light (js/require "../resources/images/icons2/12x12/thumb-light.png"))
(def ^:private thumb-dark (js/require "../resources/images/icons2/12x12/thumb-dark.png"))
(defn soundtrack
(defn f-soundtrack
[{:keys [audio-current-time-ms player-ref seeking-audio?]}]
[:f>
(fn []
(let [audio-duration-ms (audio/get-player-duration @player-ref)]
[:<>
[slider/slider
{:test-ID "soundtrack"
:style (style/player-slider-container)
:minimum-value 0
:maximum-value audio-duration-ms
:value @audio-current-time-ms
:on-sliding-start #(reset! seeking-audio? true)
:on-sliding-complete (fn [seek-time]
(reset! seeking-audio? false)
(audio/seek-player
@player-ref
seek-time
#(log/debug "[record-audio] on seek - seek time: " seek-time)
#(log/error "[record-audio] on seek - error: " %)))
:on-value-change #(when @seeking-audio?
(reset! audio-current-time-ms %))
:thumb-image (if (colors/dark?) thumb-dark thumb-light)
:minimum-track-tint-color (colors/theme-colors colors/primary-50 colors/primary-60)
:maximum-track-tint-color (colors/theme-colors
(if platform/ios? colors/neutral-20 colors/neutral-40)
(if platform/ios? colors/neutral-80 colors/neutral-60))}]]))])
(let [audio-duration-ms (audio/get-player-duration @player-ref)]
[:<>
[slider/slider
{:test-ID "soundtrack"
:style (style/player-slider-container)
:minimum-value 0
:maximum-value audio-duration-ms
:value @audio-current-time-ms
:on-sliding-start #(reset! seeking-audio? true)
:on-sliding-complete (fn [seek-time]
(reset! seeking-audio? false)
(audio/seek-player
@player-ref
seek-time
#(log/debug "[record-audio] on seek - seek time: " seek-time)
#(log/error "[record-audio] on seek - error: " %)))
:on-value-change #(when @seeking-audio?
(reset! audio-current-time-ms %))
:thumb-image (if (colors/dark?) thumb-dark thumb-light)
:minimum-track-tint-color (colors/theme-colors colors/primary-50 colors/primary-60)
:maximum-track-tint-color (colors/theme-colors
(if platform/ios? colors/neutral-20 colors/neutral-40)
(if platform/ios? colors/neutral-80 colors/neutral-60))}]]))

View File

@ -37,14 +37,6 @@
(def dismiss-keyboard! #(.dismiss keyboard))
(defn use-window-dimensions
[]
(let [window ^js (react-native/useWindowDimensions)]
{:font-scale (.-fontScale window)
:height (.-height window)
:scale (.-scale window)
:width (.-width window)}))
(defn hide-splash-screen
[]
(.hide ^js (-> react-native .-NativeModules .-SplashScreen)))
@ -63,17 +55,15 @@
[handler]
(.addChangeListener appearance handler))
(defn get-window
[]
(js->clj (.get (.-Dimensions ^js react-native) "window") :keywordize-keys true))
(def get-window
(memoize
(fn []
(js->clj (.get (.-Dimensions ^js react-native) "window") :keywordize-keys true))))
(def status-bar (.-StatusBar ^js react-native))
(def style-sheet (.-StyleSheet ^js react-native))
(defn status-bar-height
[]
(.-currentHeight ^js status-bar))
(def get-screen
(memoize
(fn []
(js->clj (.get (.-Dimensions ^js react-native) "screen") :keywordize-keys true))))
(defn hw-back-add-listener
[callback]

View File

@ -1,23 +1,30 @@
(ns react-native.safe-area
(:require ["react-native-safe-area-context" :as safe-area-context :refer
(SafeAreaProvider SafeAreaInsetsContext useSafeAreaInsets)]
[reagent.core :as reagent]))
(:require ["react-native-static-safe-area-insets" :default StaticSafeAreaInsets]
[oops.core :as oops]
[react-native.platform :as platform]
[react-native.navigation :as navigation]))
(def ^:private consumer-raw (reagent/adapt-react-class (.-Consumer ^js SafeAreaInsetsContext)))
(def provider (reagent/adapt-react-class SafeAreaProvider))
(defn consumer
[component]
[consumer-raw
(fn [^js insets]
(reagent/as-element
[component (js->clj insets :keywordize-keys true)]))])
(defn use-safe-area
(defn- get-static-top
[]
(let [insets ^js (useSafeAreaInsets)]
{:top (.-top insets)
:bottom (.-bottom insets)
:left (.-left insets)
:right (.-right insets)}))
(oops/oget StaticSafeAreaInsets "safeAreaInsetsTop"))
(defn- get-static-bottom
[]
(oops/oget StaticSafeAreaInsets "safeAreaInsetsBottom"))
(defn get-top
[]
(if platform/ios?
(get-static-top)
(navigation/status-bar-height)))
(defn get-bottom
[]
(if platform/ios?
(get-static-bottom)
0))
(defn get-insets
[]
{:top (get-top)
:bottom (get-bottom)})

View File

@ -115,126 +115,125 @@
(re-frame/dispatch [:bottom-sheet/hide-old-navigation-overlay])
(reset-atoms))
animation-delay))]
[safe-area/consumer
(fn [insets]
[:f>
(fn []
(let [{height :height
window-width :width}
(rn/use-window-dimensions)
window-height (if selected-item (- height 72) height)
{:keys [keyboard-shown]} (hooks/use-keyboard)
bg-height-expanded (- window-height (:top insets))
bg-height (max (min @content-height bg-height-expanded) 109)
bottom-sheet-dy (reanimated/use-shared-value 0)
pan-y (reanimated/use-shared-value 0)
translate-y (worklets.bottom-sheet/use-translate-y window-height bottom-sheet-dy pan-y)
bg-opacity
(worklets.bottom-sheet/use-background-opacity translate-y bg-height window-height 0.7)
on-content-layout (fn [evt]
(let [height (oget evt "nativeEvent" "layout" "height")]
(reset! content-height height)))
on-expanded (fn []
(reanimated/set-shared-value bottom-sheet-dy bg-height-expanded)
(reanimated/set-shared-value pan-y 0))
on-collapsed (fn []
(reanimated/set-shared-value bottom-sheet-dy bg-height)
(reanimated/set-shared-value pan-y 0))
bottom-sheet-gesture (get-bottom-sheet-gesture
pan-y
translate-y
bg-height
bg-height-expanded
window-height
keyboard-shown
disable-drag?
expandable?
show-bottom-sheet?
expanded?
close-bottom-sheet
gesture-running?)
handle-comp [gesture/gesture-detector {:gesture bottom-sheet-gesture}
[handle-comp window-width override-theme]]]
[:f>
(fn []
(let [{height :height
window-width :width}
(rn/get-window)
window-height (if selected-item (- height 72) height)
{:keys [keyboard-shown]} (hooks/use-keyboard)
insets (safe-area/get-insets)
bg-height-expanded (- window-height (:top insets))
bg-height (max (min @content-height bg-height-expanded) 109)
bottom-sheet-dy (reanimated/use-shared-value 0)
pan-y (reanimated/use-shared-value 0)
translate-y (worklets.bottom-sheet/use-translate-y window-height bottom-sheet-dy pan-y)
bg-opacity
(worklets.bottom-sheet/use-background-opacity translate-y bg-height window-height 0.7)
on-content-layout (fn [evt]
(let [height (oget evt "nativeEvent" "layout" "height")]
(reset! content-height height)))
on-expanded (fn []
(reanimated/set-shared-value bottom-sheet-dy bg-height-expanded)
(reanimated/set-shared-value pan-y 0))
on-collapsed (fn []
(reanimated/set-shared-value bottom-sheet-dy bg-height)
(reanimated/set-shared-value pan-y 0))
bottom-sheet-gesture (get-bottom-sheet-gesture
pan-y
translate-y
bg-height
bg-height-expanded
window-height
keyboard-shown
disable-drag?
expandable?
show-bottom-sheet?
expanded?
close-bottom-sheet
gesture-running?)
handle-comp [gesture/gesture-detector {:gesture bottom-sheet-gesture}
[handle-comp window-width override-theme]]]
(react/effect! #(do
(cond
(and
(nil? @show-bottom-sheet?)
visible?
(some? @content-height)
(> @content-height 0))
(reset! show-bottom-sheet? true)
(react/effect! #(do
(cond
(and
(nil? @show-bottom-sheet?)
visible?
(some? @content-height)
(> @content-height 0))
(reset! show-bottom-sheet? true)
(and @show-bottom-sheet? (not visible?))
(close-bottom-sheet)))
[@show-bottom-sheet? @content-height visible?])
(react/effect! #(do
(when @show-bottom-sheet?
(cond
keyboard-shown
(do
(reset! keyboard-was-shown? true)
(reset! expanded? true))
(and @keyboard-was-shown? (not keyboard-shown))
(reset! expanded? false))))
[@show-bottom-sheet? @keyboard-was-shown? keyboard-shown])
(react/effect! #(do
(when-not @gesture-running?
(cond
@show-bottom-sheet?
(if @expanded?
(do
(reanimated/set-shared-value
bottom-sheet-dy
(with-animation (+ bg-height-expanded (.-value pan-y))))
;; Workaround for
;; https://github.com/software-mansion/react-native-reanimated/issues/1758#issue-817145741
;; withTiming/withSpring callback not working
;; on-expanded should be called as a callback of
;; with-animation instead, once this issue has been resolved
(timer/set-timeout on-expanded animation-delay))
(do
(reanimated/set-shared-value
bottom-sheet-dy
(with-animation (+ bg-height (.-value pan-y))))
;; Workaround for
;; https://github.com/software-mansion/react-native-reanimated/issues/1758#issue-817145741
;; withTiming/withSpring callback not working
;; on-collapsed should be called as a callback of
;; with-animation instead, once this issue has been resolved
(timer/set-timeout on-collapsed animation-delay)))
(and @show-bottom-sheet? (not visible?))
(close-bottom-sheet)))
[@show-bottom-sheet? @content-height visible?])
(react/effect! #(do
(when @show-bottom-sheet?
(cond
keyboard-shown
(do
(reset! keyboard-was-shown? true)
(reset! expanded? true))
(and @keyboard-was-shown? (not keyboard-shown))
(reset! expanded? false))))
[@show-bottom-sheet? @keyboard-was-shown? keyboard-shown])
(react/effect! #(do
(when-not @gesture-running?
(cond
@show-bottom-sheet?
(if @expanded?
(do
(reanimated/set-shared-value
bottom-sheet-dy
(with-animation (+ bg-height-expanded (.-value pan-y))))
;; Workaround for
;; https://github.com/software-mansion/react-native-reanimated/issues/1758#issue-817145741
;; withTiming/withSpring callback not working
;; on-expanded should be called as a callback of
;; with-animation instead, once this issue has been resolved
(timer/set-timeout on-expanded animation-delay))
(do
(reanimated/set-shared-value
bottom-sheet-dy
(with-animation (+ bg-height (.-value pan-y))))
;; Workaround for
;; https://github.com/software-mansion/react-native-reanimated/issues/1758#issue-817145741
;; withTiming/withSpring callback not working
;; on-collapsed should be called as a callback of
;; with-animation instead, once this issue has been resolved
(timer/set-timeout on-collapsed animation-delay)))
(= @show-bottom-sheet? false)
(reanimated/set-shared-value bottom-sheet-dy (with-animation 0)))))
[@show-bottom-sheet? @expanded? @gesture-running?])
(= @show-bottom-sheet? false)
(reanimated/set-shared-value bottom-sheet-dy (with-animation 0)))))
[@show-bottom-sheet? @expanded? @gesture-running?])
[:<>
[rn/touchable-without-feedback {:on-press (when backdrop-dismiss? close-bottom-sheet)}
[reanimated/view
{:style (reanimated/apply-animations-to-style
{:opacity bg-opacity}
styles/backdrop)}]]
(cond->> [reanimated/view
{:style (reanimated/apply-animations-to-style
{:transform [{:translateY translate-y}]}
{:width window-width
:height window-height})}
[rn/view {:style styles/container}
(when selected-item
[rn/view {:style (styles/selected-background override-theme)}
[selected-item]])
[rn/view {:style (styles/background override-theme)}
[rn/keyboard-avoiding-view
{:behaviour (if platform/ios? :padding :height)
:style {:flex 1}}
[rn/view
{:style (styles/content-style insets bottom-safe-area-spacing?)
:on-layout (when-not (and
(some? @content-height)
(> @content-height 0))
on-content-layout)}
children]]
(when show-handle?
handle-comp)]]]
(not show-handle?)
(conj [gesture/gesture-detector {:gesture bottom-sheet-gesture}]))]))])]))
[:<>
[rn/touchable-without-feedback {:on-press (when backdrop-dismiss? close-bottom-sheet)}
[reanimated/view
{:style (reanimated/apply-animations-to-style
{:opacity bg-opacity}
styles/backdrop)}]]
(cond->> [reanimated/view
{:style (reanimated/apply-animations-to-style
{:transform [{:translateY translate-y}]}
{:width window-width
:height window-height})}
[rn/view {:style styles/container}
(when selected-item
[rn/view {:style (styles/selected-background override-theme)}
[selected-item]])
[rn/view {:style (styles/background override-theme)}
[rn/keyboard-avoiding-view
{:behaviour (if platform/ios? :padding :height)
:style {:flex 1}}
[rn/view
{:style (styles/content-style insets bottom-safe-area-spacing?)
:on-layout (when-not (and
(some? @content-height)
(> @content-height 0))
on-content-layout)}
children]]
(when show-handle?
handle-comp)]]]
(not show-handle?)
(conj [gesture/gesture-detector {:gesture bottom-sheet-gesture}]))]))]))

View File

@ -1,6 +1,5 @@
(ns status-im.ui.components.keyboard-avoid-presentation
(:require [oops.core :refer [oget]]
[reagent.core :as reagent]
(:require [reagent.core :as reagent]
[status-im.ui.components.react :as react]))
(defn keyboard-avoiding-view
@ -8,16 +7,11 @@
(let [this (reagent/current-component)
props (reagent/props this)
children (reagent/children this)]
[react/safe-area-consumer
(fn [insets]
(let [vertical-offset (+ (oget insets "top")
;; 20 is the margin-top for presentation modal
20)]
(reagent/as-element
(into [react/keyboard-avoiding-view
(update props
:keyboardVerticalOffset
+
vertical-offset
(if (:ignore-offset props) 44 0))]
children))))]))
(reagent/as-element
(into [react/keyboard-avoiding-view
(update props
:keyboardVerticalOffset
+
20
(if (:ignore-offset props) 44 0))]
children))))

View File

@ -8,8 +8,6 @@
["react-native-image-crop-picker" :default image-picker]
["react-native-linear-gradient" :default LinearGradient]
["react-native-navigation" :refer (Navigation)]
["react-native-safe-area-context" :as safe-area-context :refer
(SafeAreaProvider SafeAreaInsetsContext)]
[quo.design-system.colors :as colors]
[reagent.core :as reagent]
[utils.i18n :as i18n]
@ -308,9 +306,6 @@
[activity-indicator {:animating true}]])
comp)))
(def safe-area-provider (reagent/adapt-react-class SafeAreaProvider))
(def safe-area-consumer (reagent/adapt-react-class (.-Consumer ^js SafeAreaInsetsContext)))
(defn hw-back-add-listener
[callback]
(.addEventListener BackHandler "hardwareBackPress" callback))

View File

@ -1,7 +1,8 @@
(ns status-im.ui.components.topbar
(:require [re-frame.core :as re-frame]
[quo.core :as quo]
[quo2.foundations.colors :as quo2.colors]))
[quo2.foundations.colors :as quo2.colors]
[react-native.safe-area :as safe-area]))
(def default-button-width 48)
@ -32,18 +33,16 @@
(let [navigation (if (= navigation :none)
nil
[(default-navigation modal? navigation)])]
[quo/safe-area-consumer
(fn [insets]
[quo/header
(merge {:left-accessories navigation
:title-component content
:insets (when use-insets insets)
:left-width (when navigation
default-button-width)
:border-bottom border-bottom?}
props
(when (seq right-accessories)
{:right-accessories right-accessories})
(when new-ui?
{:background (quo2.colors/theme-colors quo2.colors/neutral-5
quo2.colors/neutral-95)}))])]))
[quo/header
(merge {:left-accessories navigation
:title-component content
:insets (when use-insets (safe-area/get-insets))
:left-width (when navigation
default-button-width)
:border-bottom border-bottom?}
props
(when (seq right-accessories)
{:right-accessories right-accessories})
(when new-ui?
{:background (quo2.colors/theme-colors quo2.colors/neutral-5
quo2.colors/neutral-95)}))]))

View File

@ -9,11 +9,9 @@
(defn browser-stack
[]
(let [screen-id (rf/sub [:browser/screen-id])]
[safe-area/consumer
(fn [{:keys [top]}]
[rn/view {:padding-top top :flex 1}
(case screen-id
:empty-tab [empty-tab/empty-tab]
:browser [browser/browser]
:browser-tabs [tabs/tabs]
[empty-tab/empty-tab])])]))
[rn/view {:padding-top (safe-area/get-top) :flex 1}
(case screen-id
:empty-tab [empty-tab/empty-tab]
:browser [browser/browser]
:browser-tabs [tabs/tabs]
[empty-tab/empty-tab])]))

View File

@ -1,14 +1,14 @@
(ns status-im.ui.screens.chat.components.accessory
(:require [cljs-bean.core :as bean]
[quo.animated :as animated]
[quo.components.safe-area :refer [use-safe-area]]
[quo.design-system.colors :as colors]
[quo.platform :as platform]
[quo.react :as react]
[quo.react-native :as rn]
[reagent.core :as reagent]
[status-im.ui.components.tabbar.core :as tabbar]
[status-im.ui.screens.chat.components.hooks :refer [use-keyboard-dimension]]))
[status-im.ui.screens.chat.components.hooks :refer [use-keyboard-dimension]]
[react-native.safe-area :as safe-area]))
(def duration 250)
@ -51,7 +51,7 @@
keyboard-max-height :max-height
keyboard-end-position :end-position}
(use-keyboard-dimension)
{:keys [bottom]} (use-safe-area)
bottom (safe-area/get-bottom)
{on-layout :on-layout
bar-height :height}
(rn/use-layout)
@ -121,7 +121,7 @@
children :children}
(bean/bean props)
{keyboard-max-height :max-height} (use-keyboard-dimension)
{:keys [bottom]} (use-safe-area)
bottom (safe-area/get-bottom)
{on-layout :on-layout
bar-height :height}
(rn/use-layout)

View File

@ -1,8 +1,8 @@
(ns status-im.ui.screens.chat.components.hooks
(:require [quo.components.safe-area :refer [use-safe-area]]
[quo.platform :as platform]
(:require [quo.platform :as platform]
[quo.react :as react]
[quo.react-native :refer [use-window-dimensions] :as rn]))
[quo.react-native :refer [use-window-dimensions] :as rn]
[react-native.safe-area :as safe-area]))
(def ^:private keyboard-change-event (if platform/android? "keyboardDidShow" "keyboardWillChangeFrame"))
@ -12,7 +12,7 @@
(defn use-keyboard-dimension
[]
(let [{:keys [height]} (use-window-dimensions)
{:keys [bottom]} (use-safe-area)
bottom (safe-area/get-bottom)
keyboard-listener (atom nil)
keyboard (react/state
{:height 0

View File

@ -1,6 +1,5 @@
(ns status-im.ui.screens.chat.image.preview.views
(:require ["react-native-image-viewing" :default image-viewing]
[quo.components.safe-area :as safe-area]
[quo.design-system.colors :as colors]
[quo.platform :as platform]
[re-frame.core :as re-frame]
@ -9,7 +8,8 @@
[status-im.ui.components.icons.icons :as icons]
[status-im.ui.components.react :as react]
[status-im.utils.share :as share]
[taoensso.timbre :as log]))
[taoensso.timbre :as log]
[react-native.safe-area :as safe-area]))
(defn share
[path]
@ -53,29 +53,27 @@
(defn header
[{:keys [on-close] :as props}]
[safe-area/consumer
(fn [insets]
[react/view
{:style {:padding-horizontal 15
:padding-top (+ (safe-area/get-bottom) 50)}}
[react/view {:style {:justify-content :center}}
[react/touchable-opacity
{:on-press on-close
:style {:padding-vertical 11
:border-radius 44}
:accessibility-label :close-button}
[react/view
{:style {:padding-horizontal 15
:padding-top (+ (:bottom insets) 50)}}
[react/view {:style {:justify-content :center}}
[react/touchable-opacity
{:on-press on-close
:style {:padding-vertical 11
:border-radius 44}
:accessibility-label :close-button}
[react/view
{:style {:background-color colors/black-transparent-86
:border-radius 20
:width 40
:height 40
:justify-content :center
:align-items :center}}
[icons/icon :main-icons/close
{:container-style {:width 24
:height 24}
:color colors/white-persist}]]]
[header-options props]]])])
{:style {:background-color colors/black-transparent-86
:border-radius 20
:width 40
:height 40
:justify-content :center
:align-items :center}}
[icons/icon :main-icons/close
{:container-style {:width 24
:height 24}
:color colors/white-persist}]]]
[header-options props]]])
(defn preview-image
[{{:keys [content] :as message} :message

View File

@ -299,39 +299,36 @@
(defn accounts-overview
[]
(let [mnemonic @(re-frame/subscribe [:mnemonic])
;mainnet? @(re-frame/subscribe [:mainnet?])
selected-account-atom (reagent/atom nil)]
(fn []
[safe-area/consumer
(fn [{:keys [top]}]
[react/view
{:style {:flex 1
:padding-top top
:background-color (quo2.colors/theme-colors quo2.colors/neutral-5
quo2.colors/neutral-95)}}
[react/view {:padding-horizontal 20}
[react/view {:flex-direction :row :height 56 :align-items :center :justify-content :flex-end}
[quo2.button/button
{:icon true
:size 32
:type :grey
:accessibility-label :accounts-qr-code
:on-press #(re-frame/dispatch
[::qr-scanner/scan-code
{:handler :wallet.send/qr-scanner-result}])}
:i/placeholder]
[react/view {:width 12}]
[quo2.button/button
{:icon true
:size 32
:type :grey
:on-press #(re-frame/dispatch [:bottom-sheet/show-sheet-old
{:content (sheets/accounts-options mnemonic)}])
:accessibility-label :accounts-more-options}
:i/placeholder]]
[total-value]
[accounts selected-account-atom]]
[account.views/account-new @selected-account-atom]])])))
[react/view
{:style {:flex 1
:padding-top (safe-area/get-top)
:background-color (quo2.colors/theme-colors quo2.colors/neutral-5
quo2.colors/neutral-95)}}
[react/view {:padding-horizontal 20}
[react/view {:flex-direction :row :height 56 :align-items :center :justify-content :flex-end}
[quo2.button/button
{:icon true
:size 32
:type :grey
:accessibility-label :accounts-qr-code
:on-press #(re-frame/dispatch
[::qr-scanner/scan-code
{:handler :wallet.send/qr-scanner-result}])}
:i/placeholder]
[react/view {:width 12}]
[quo2.button/button
{:icon true
:size 32
:type :grey
:on-press #(re-frame/dispatch [:bottom-sheet/show-sheet-old
{:content (sheets/accounts-options mnemonic)}])
:accessibility-label :accounts-more-options}
:i/placeholder]]
[total-value]
[accounts selected-account-atom]]
[account.views/account-new @selected-account-atom]])))
(defn accounts-overview-old
[]

View File

@ -60,62 +60,60 @@
(defn contact-selection-list
[{:keys [scroll-enabled on-scroll]}]
[:f>
(fn []
(let [contacts (rf/sub [:contacts/sorted-and-grouped-by-first-letter])
selected-contacts-count (rf/sub [:selected-contacts-count])
selected-contacts (rf/sub [:group/selected-contacts])
one-contact-selected? (= selected-contacts-count 1)
contacts-selected? (pos? selected-contacts-count)
{:keys [primary-name public-key]} (when one-contact-selected?
(rf/sub [:contacts/contact-by-identity
(first selected-contacts)]))
no-contacts? (empty? contacts)]
[:<>
[quo2/button
{:type :grey
:icon true
:on-press #(rf/dispatch [:navigate-back])
:style style/contact-selection-close
:override-background-color (quo2.colors/theme-colors quo2.colors/neutral-10
quo2.colors/neutral-90)}
:i/close]
[rn/view style/contact-selection-heading
[quo2/text
{:weight :semi-bold
:size :heading-1
:style {:color (quo2.colors/theme-colors quo2.colors/neutral-100 quo2.colors/white)}}
(i18n/label :t/new-chat)]
(when-not no-contacts?
[quo2/text
{:size :paragraph-2
:weight :regular
:style {:color (quo2.colors/theme-colors quo2.colors/neutral-40 quo2.colors/neutral-50)}}
(i18n/label :t/selected-count-from-max
{:selected selected-contacts-count
:max constants/max-group-chat-participants})])]
[rn/view
{:style {:flex 1}}
(if no-contacts?
[no-contacts-view]
[gesture/section-list
{:key-fn :title
:sticky-section-headers-enabled false
:sections (rf/sub [:contacts/filtered-active-sections])
:render-section-header-fn contact-list/contacts-section-header
:content-container-style {:padding-bottom 70}
:render-fn contact-item-render
:scroll-enabled @scroll-enabled
:on-scroll on-scroll}])]
(when contacts-selected?
[button/button
{:type :primary
:style style/chat-button
:accessibility-label :next-button
:on-press (fn []
(if one-contact-selected?
(rf/dispatch [:chat.ui/start-chat public-key])
(rf/dispatch [:navigate-to :new-group])))}
(if one-contact-selected?
(i18n/label :t/chat-with {:selected-user primary-name})
(i18n/label :t/setup-group-chat))])]))])
(let [contacts (rf/sub [:contacts/sorted-and-grouped-by-first-letter])
selected-contacts-count (rf/sub [:selected-contacts-count])
selected-contacts (rf/sub [:group/selected-contacts])
one-contact-selected? (= selected-contacts-count 1)
contacts-selected? (pos? selected-contacts-count)
{:keys [primary-name public-key]} (when one-contact-selected?
(rf/sub [:contacts/contact-by-identity
(first selected-contacts)]))
no-contacts? (empty? contacts)]
[:<>
[quo2/button
{:type :grey
:icon true
:on-press #(rf/dispatch [:navigate-back])
:style style/contact-selection-close
:override-background-color (quo2.colors/theme-colors quo2.colors/neutral-10
quo2.colors/neutral-90)}
:i/close]
[rn/view style/contact-selection-heading
[quo2/text
{:weight :semi-bold
:size :heading-1
:style {:color (quo2.colors/theme-colors quo2.colors/neutral-100 quo2.colors/white)}}
(i18n/label :t/new-chat)]
(when-not no-contacts?
[quo2/text
{:size :paragraph-2
:weight :regular
:style {:color (quo2.colors/theme-colors quo2.colors/neutral-40 quo2.colors/neutral-50)}}
(i18n/label :t/selected-count-from-max
{:selected selected-contacts-count
:max constants/max-group-chat-participants})])]
[rn/view
{:style {:flex 1}}
(if no-contacts?
[no-contacts-view]
[gesture/section-list
{:key-fn :title
:sticky-section-headers-enabled false
:sections (rf/sub [:contacts/filtered-active-sections])
:render-section-header-fn contact-list/contacts-section-header
:content-container-style {:padding-bottom 70}
:render-fn contact-item-render
:scroll-enabled @scroll-enabled
:on-scroll on-scroll}])]
(when contacts-selected?
[button/button
{:type :primary
:style style/chat-button
:accessibility-label :next-button
:on-press (fn []
(if one-contact-selected?
(rf/dispatch [:chat.ui/start-chat public-key])
(rf/dispatch [:navigate-to :new-group])))}
(if one-contact-selected?
(i18n/label :t/chat-with {:selected-user primary-name})
(i18n/label :t/setup-group-chat))])]))

View File

@ -1,61 +0,0 @@
(ns status-im.ui2.screens.chat.pin-limit-popover.view
(:require [utils.i18n :as i18n]
[quo.react :as react]
[quo2.core :as quo]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[react-native.reanimated :as reanimated]
[status-im.ui2.screens.chat.pin-limit-popover.style :as style]
[utils.re-frame :as rf]))
;; TODO (flexsurfer) this should be an in-app notification component in quo2
;; https://github.com/status-im/status-mobile/issues/14527
(defn pin-limit-popover
[chat-id]
[:f>
(fn []
(let [width (rf/sub [:dimensions/window-width])
show-pin-limit-modal? (rf/sub [:chats/pin-modal chat-id])
opacity-animation (reanimated/use-shared-value 0)
z-index-animation (reanimated/use-shared-value -1)]
(react/effect!
#(do
(reanimated/set-shared-value opacity-animation
(reanimated/with-timing (if show-pin-limit-modal? 1 0)))
(reanimated/set-shared-value z-index-animation
(reanimated/with-timing (if show-pin-limit-modal? 10 -1)))))
(when show-pin-limit-modal?
[reanimated/view
{:style (reanimated/apply-animations-to-style
{:opacity opacity-animation
:z-index z-index-animation}
(style/pin-popover width))
:accessibility-label :pin-limit-popover}
[rn/view {:style (style/pin-alert-container)}
[rn/view {:style style/pin-alert-circle}
[rn/text {:style {:color colors/danger-50}} "!"]]]
[rn/view {:style {:margin-left 8}}
[quo/text {:weight :semi-bold :color (colors/theme-colors colors/white colors/neutral-100)}
(i18n/label :t/cannot-pin-title)]
[quo/text {:size :paragraph-2 :color (colors/theme-colors colors/white colors/neutral-100)}
(i18n/label :t/cannot-pin-desc)]
[rn/touchable-opacity
{:accessibility-label :view-pinned-messages
:active-opacity 1
:on-press (fn []
(rf/dispatch [:pin-message/hide-pin-limit-modal chat-id])
(rf/dispatch [:pin-message/show-pins-bottom-sheet chat-id])
(rf/dispatch [:dismiss-keyboard]))
:style style/view-pinned-messages}
[quo/text {:size :paragraph-2 :weight :medium :color colors/white}
(i18n/label :t/view-pinned-messages)]]]
[rn/touchable-opacity
{:accessibility-label :close-pin-limit-popover
:active-opacity 1
:on-press #(rf/dispatch [:pin-message/hide-pin-limit-modal chat-id])
:style {:position :absolute
:top 16
:right 16}}
[quo/icon :i/close
{:color (colors/theme-colors colors/white colors/neutral-100)
:size 12}]]])))])

View File

@ -50,7 +50,7 @@
(defn view
[{:keys [hide? insets]} {:keys [content override-theme selected-item]}]
(let [{window-height :height} (rn/use-window-dimensions)
(let [{window-height :height} (rn/get-window)
bg-opacity (reanimated/use-shared-value 0)
translate-y (reanimated/use-shared-value window-height)
sheet-gesture (get-sheet-gesture translate-y bg-opacity window-height)]

View File

@ -2,7 +2,6 @@
(:require
[react-native.gesture :as gesture]
[react-native.hooks :as hooks]
[react-native.navigation :as navigation]
[react-native.platform :as platform]
[react-native.reanimated :as reanimated]
[oops.core :as oops]
@ -46,37 +45,35 @@
(let [y (oops/oget e "nativeEvent.contentOffset.y")]
(reset! curr-scroll y)))
(defn view
(defn f-view
[content skip-background?]
[:f>
(let [scroll-enabled (reagent/atom true)
curr-scroll (atom 0)]
(fn []
(let [sb-height (navigation/status-bar-height)
insets (safe-area/use-safe-area)
padding-top (Math/max sb-height (:top insets))
padding-top (if platform/ios? padding-top (+ padding-top 10))
opacity (reanimated/use-shared-value 0)
translate-y (reanimated/use-shared-value 0)
close (fn []
(reanimated/set-shared-value opacity (reanimated/with-timing-duration 0 100))
(rf/dispatch [:navigate-back]))]
(rn/use-effect
(fn []
(reanimated/animate-delay opacity 1 (if platform/ios? 300 100))))
(hooks/use-back-handler close)
[rn/view
{:style {:flex 1
:padding-top padding-top}}
(when-not skip-background?
[reanimated/view {:style (style/background opacity)}])
[gesture/gesture-detector
{:gesture (drag-gesture translate-y opacity scroll-enabled curr-scroll)}
[reanimated/view {:style (style/main-view translate-y)}
[rn/view {:style style/handle-container}
[rn/view {:style (style/handle)}]]
[content
{:insets insets
:close close
:scroll-enabled scroll-enabled
:on-scroll #(on-scroll % curr-scroll)}]]]])))])
(let [scroll-enabled (reagent/atom true)
curr-scroll (atom 0)]
(fn []
(let [insets (safe-area/get-insets)
padding-top (:top insets)
padding-top (if platform/ios? padding-top (+ padding-top 10))
opacity (reanimated/use-shared-value 0)
translate-y (reanimated/use-shared-value 0)
close (fn []
(reanimated/set-shared-value opacity (reanimated/with-timing-duration 0 100))
(rf/dispatch [:navigate-back]))]
(rn/use-effect
(fn []
(reanimated/animate-delay opacity 1 (if platform/ios? 300 100))))
(hooks/use-back-handler close)
[rn/view
{:style {:flex 1
:padding-top padding-top}}
(when-not skip-background?
[reanimated/view {:style (style/background opacity)}])
[gesture/gesture-detector
{:gesture (drag-gesture translate-y opacity scroll-enabled curr-scroll)}
[reanimated/view {:style (style/main-view translate-y)}
[rn/view {:style style/handle-container}
[rn/view {:style (style/handle)}]]
[content
{:insets insets
:close close
:scroll-enabled scroll-enabled
:on-scroll #(on-scroll % curr-scroll)}]]]]))))

View File

@ -24,7 +24,7 @@
(max minimum)
(min maximum)))
(defn scroll-page-header
(defn f-scroll-page-header
[scroll-height height name page-nav logo sticky-header top-nav title-colum navigate-back?]
(let [input-range (if platform/ios? [-47 10] [0 10])
output-range (if platform/ios? [-208 0] [-208 -45])
@ -88,7 +88,7 @@
sticky-header]]))
(defn display-picture
(defn f-display-picture
[scroll-height cover]
(let [input-range (if platform/ios? [-67 10] [0 150])
y (reanimated/use-shared-value scroll-height)
@ -115,7 +115,7 @@
sticky-header
children]
[:<>
[:f> scroll-page-header @scroll-height height name page-nav-right-section-buttons
[:f> f-scroll-page-header @scroll-height height name page-nav-right-section-buttons
logo sticky-header top-nav title-colum navigate-back?]
[rn/scroll-view
{:content-container-style (style/scroll-view-container
@ -144,5 +144,5 @@
:border-radius (diff-with-max-min @scroll-height 16 0)
:background-color background-color}
(when cover-image
[:f> display-picture @scroll-height logo])
[:f> f-display-picture @scroll-height logo])
children])]])))

View File

@ -1,100 +0,0 @@
(ns status-im2.common.sticky-scroll-view.view
(:require [react-native.reanimated :as reanimated]
[react-native.core :as rn]
[react-native.platform :as platform]
[utils.worklets.scroll-view :as worklets.scroll-view]
[quo2.foundations.colors :as colors]))
(defn sticky-item
[{:keys [height translation-y background-color]} content]
[:f>
(fn []
[rn/view (merge {:height height} (when platform/ios? {:z-index 1}))
[reanimated/view
{:style (reanimated/apply-animations-to-style
{:transform [{:translateY translation-y}]}
{:position :absolute
:z-index (when platform/android? 1)
:top 0
:left 0
:right 0
:height height
:background-color background-color})}
content]])])
(defn scroll-view
[{:keys [ref scroll-y blur]} & content]
[:f>
(fn []
(let [scroll-handler (worklets.scroll-view/use-animated-scroll-handler scroll-y)
opacity (when blur
(reanimated/interpolate scroll-y
[0 (:delta blur)]
[0 1]
{:extrapolateLeft "clamp"
:extrapolateRight "extend"}))]
(into [reanimated/scroll-view
{:ref ref
:scroll-event-throttle 1
:shows-vertical-scroll-indicator false
:contentInsetAdjustmentBehavior :never
:on-scroll scroll-handler}]
(concat
(when blur
;bug on Android
;https://github.com/Kureev/react-native-blur/issues/520}
[[reanimated/view
{:style (reanimated/apply-animations-to-style
{:transform [{:translateY scroll-y}]
:opacity opacity}
{:overflow (if platform/ios? :visible :hidden)
:position :absolute
:z-index 1
:top 0
:height (:height blur)
:right 0
:left 0})}
[reanimated/blur-view
{:blur-amount 10
:blur-type (if (colors/dark?) :dark :xlight)
:style {:position :absolute
:top 0
:height (:height blur)
:right 0
:left 0}}]]])
content))))])
(defn flat-list
[{:keys [scroll-y blur header render-fn data]}]
[:f>
(fn []
(let [scroll-handler (worklets.scroll-view/use-animated-scroll-handler scroll-y)
opacity (when blur
(reanimated/interpolate scroll-y
[0 (:delta blur)]
[0 1]
{:extrapolateLeft "clamp"
:extrapolateRight "extend"}))]
[reanimated/flat-list
{:scroll-event-throttle 1
:shows-vertical-scroll-indicator false
:contentInsetAdjustmentBehavior :never
:data data
:render-fn render-fn
:header (if blur
[:<>
[reanimated/blur-view
{:blur-amount 10
:blur-type :xlight
:style (reanimated/apply-animations-to-style
{:transform [{:translateY scroll-y}]
:opacity opacity}
{:z-index 1
:position :absolute
:top 0
:height (:height blur)
:right 0
:left 0})}]
header]
header)
:on-scroll scroll-handler}]))])

View File

@ -33,66 +33,64 @@
[quo/notification toast-opts]
[quo/toast toast-opts])))
(defn container
(defn f-container
[id]
(let [dismissed-locally? (reagent/atom false)
close! #(rf/dispatch [:toasts/close id])
timer (reagent/atom nil)
clear-timer #(utils.utils/clear-timeout @timer)]
(fn []
[:f>
(fn []
(let [duration (or (rf/sub [:toasts/toast-cursor id :duration]) 3000)
on-dismissed (or (rf/sub [:toasts/toast-cursor id :on-dismissed]) identity)
create-timer (fn []
(reset! timer (utils.utils/set-timeout close! duration)))
translate-y (reanimated/use-shared-value 0)
pan
(->
(gesture/gesture-pan)
;; remove timer on pan start
(gesture/on-start clear-timer)
(gesture/on-update
(fn [^js evt]
(let [evt-translation-y (.-translationY evt)]
(cond
;; reset translate y on pan down
(> evt-translation-y 100)
(reanimated/animate-shared-value-with-spring translate-y
0
{:mass 1
:damping 20
:stiffness 300})
;; dismiss on pan up
(< evt-translation-y -30)
(do (reanimated/animate-shared-value-with-spring
translate-y
-500
{:mass 1 :damping 20 :stiffness 300})
(reset! dismissed-locally? true)
(close!))
:else
(reanimated/set-shared-value translate-y
evt-translation-y)))))
(gesture/on-end (fn [_]
(when-not @dismissed-locally?
(reanimated/set-shared-value translate-y 0)
(create-timer)))))]
;; create auto dismiss timer, clear timer when unmount or duration changed
(rn/use-effect (fn [] (create-timer) clear-timer) [duration])
(rn/use-unmount #(on-dismissed id))
[gesture/gesture-detector {:gesture pan}
[reanimated/view
{;; TODO: this will enable layout animation at runtime and causing flicker on android
;; we need to resolve this and re-enable layout animation
;; issue at https://github.com/status-im/status-mobile/issues/14752
;; :entering slide-in-up-animation
;; :exiting slide-out-up-animation
;; :layout reanimated/linear-transition
:style (reanimated/apply-animations-to-style
{:transform [{:translateY translate-y}]}
style/each-toast-container)}
[toast id]]]))])))
(let [duration (or (rf/sub [:toasts/toast-cursor id :duration]) 3000)
on-dismissed (or (rf/sub [:toasts/toast-cursor id :on-dismissed]) identity)
create-timer (fn []
(reset! timer (utils.utils/set-timeout close! duration)))
translate-y (reanimated/use-shared-value 0)
pan
(->
(gesture/gesture-pan)
;; remove timer on pan start
(gesture/on-start clear-timer)
(gesture/on-update
(fn [^js evt]
(let [evt-translation-y (.-translationY evt)]
(cond
;; reset translate y on pan down
(> evt-translation-y 100)
(reanimated/animate-shared-value-with-spring translate-y
0
{:mass 1
:damping 20
:stiffness 300})
;; dismiss on pan up
(< evt-translation-y -30)
(do (reanimated/animate-shared-value-with-spring
translate-y
-500
{:mass 1 :damping 20 :stiffness 300})
(reset! dismissed-locally? true)
(close!))
:else
(reanimated/set-shared-value translate-y
evt-translation-y)))))
(gesture/on-end (fn [_]
(when-not @dismissed-locally?
(reanimated/set-shared-value translate-y 0)
(create-timer)))))]
;; create auto dismiss timer, clear timer when unmount or duration changed
(rn/use-effect (fn [] (create-timer) clear-timer) [duration])
(rn/use-unmount #(on-dismissed id))
[gesture/gesture-detector {:gesture pan}
[reanimated/view
{;; TODO: this will enable layout animation at runtime and causing flicker on android
;; we need to resolve this and re-enable layout animation
;; issue at https://github.com/status-im/status-mobile/issues/14752
;; :entering slide-in-up-animation
;; :exiting slide-out-up-animation
;; :layout reanimated/linear-transition
:style (reanimated/apply-animations-to-style
{:transform [{:translateY translate-y}]}
style/each-toast-container)}
[toast id]]]))))
(defn toasts
[]
@ -101,4 +99,4 @@
[rn/view
{:style style/outmost-transparent-container}]
(doall
(map (fn [id] ^{:key id} [container id]) toasts-ordered))]))
(map (fn [id] ^{:key id} [:f> f-container id]) toasts-ordered))]))

View File

@ -102,32 +102,31 @@
[]
(fn []
(let [pending-contact-requests (rf/sub [:activity-center/pending-contact-requests])
selected-tab (or (rf/sub [:messages-home/selected-tab]) :tab/recent)]
[safe-area/consumer
(fn [{:keys [top]}]
[:<>
(if (= selected-tab :tab/contacts)
[contacts pending-contact-requests top]
[chats selected-tab top])
[rn/view
{:style (style/blur-container top)}
[blur/view
{:blur-amount (if platform/ios? 20 10)
:blur-type (if (colors/dark?) :dark (if platform/ios? :light :xlight))
:style style/blur}]
[common.home/top-nav]
[common.home/title-column
{:label (i18n/label :t/messages)
:handler #(rf/dispatch [:show-bottom-sheet
{:content home.sheet/new-chat-bottom-sheet}])
:accessibility-label :new-chat-button}]
[quo/discover-card
{:title (i18n/label :t/invite-friends-to-status)
:description (i18n/label :t/share-invite-link)}]
[quo/tabs
{:style style/tabs
:size 32
:on-change (fn [tab]
(rf/dispatch [:messages-home/select-tab tab]))
:default-active selected-tab
:data (get-tabs-data (pos? (count pending-contact-requests)))}]]])])))
selected-tab (or (rf/sub [:messages-home/selected-tab]) :tab/recent)
top (safe-area/get-top)]
[:<>
(if (= selected-tab :tab/contacts)
[contacts pending-contact-requests top]
[chats selected-tab top])
[rn/view
{:style (style/blur-container top)}
[blur/view
{:blur-amount (if platform/ios? 20 10)
:blur-type (if (colors/dark?) :dark (if platform/ios? :light :xlight))
:style style/blur}]
[common.home/top-nav]
[common.home/title-column
{:label (i18n/label :t/messages)
:handler #(rf/dispatch [:show-bottom-sheet
{:content home.sheet/new-chat-bottom-sheet}])
:accessibility-label :new-chat-button}]
[quo/discover-card
{:title (i18n/label :t/invite-friends-to-status)
:description (i18n/label :t/share-invite-link)}]
[quo/tabs
{:style style/tabs
:size 32
:on-change (fn [tab]
(rf/dispatch [:messages-home/select-tab tab]))
:default-active selected-tab
:data (get-tabs-data (pos? (count pending-contact-requests)))}]]])))

View File

@ -25,47 +25,43 @@
render-data (rf/sub [:chats/current-chat-message-list-view-context :in-pinned-view])
current-chat (rf/sub [:chat-by-id chat-id])
{:keys [community-id]} current-chat
community (rf/sub [:communities/community community-id])]
[safe-area/consumer
(fn [insets]
[:f>
(fn []
(let [bottom-inset (:bottom insets)]
[gesture/scroll-view
{:accessibility-label :pinned-messages-menu}
[:<>
[quo/text
{:size :heading-1
:weight :semi-bold
:style style/heading}
(i18n/label :t/pinned-messages)]
(when community
[rn/view {:style (style/heading-container)}
[rn/text {:style (style/heading-text)} (:name community)]
[quo/icon
:i/chevron-right
{:color (colors/theme-colors colors/neutral-60 colors/neutral-30)
:size 12}]
[rn/text
{:style (style/chat-name-text)}
(str "# " (:chat-name current-chat))]])]
(if (pos? (count pinned-messages))
[rn/flat-list
{:data pinned-messages
:render-data render-data
:render-fn message-render-fn
:footer [rn/view {:style (style/list-footer bottom-inset)}]
:key-fn list-key-fn
:separator quo/separator}]
[rn/view {:style (style/no-pinned-messages-container bottom-inset)}
[rn/view {:style style/no-pinned-messages-icon}
[quo/icon :i/placeholder]]
[quo/text
{:weight :semi-bold
:style style/no-pinned-messages-text}
(i18n/label :t/no-pinned-messages)]
[quo/text {:size :paragraph-2}
(i18n/label
(if community
:t/no-pinned-messages-community-desc
:t/no-pinned-messages-desc))]])]))])]))
community (rf/sub [:communities/community community-id])
bottom-inset (safe-area/get-bottom)]
[gesture/scroll-view
{:accessibility-label :pinned-messages-menu}
[:<>
[quo/text
{:size :heading-1
:weight :semi-bold
:style style/heading}
(i18n/label :t/pinned-messages)]
(when community
[rn/view {:style (style/heading-container)}
[rn/text {:style (style/heading-text)} (:name community)]
[quo/icon
:i/chevron-right
{:color (colors/theme-colors colors/neutral-60 colors/neutral-30)
:size 12}]
[rn/text
{:style (style/chat-name-text)}
(str "# " (:chat-name current-chat))]])]
(if (pos? (count pinned-messages))
[rn/flat-list
{:data pinned-messages
:render-data render-data
:render-fn message-render-fn
:footer [rn/view {:style (style/list-footer bottom-inset)}]
:key-fn list-key-fn
:separator quo/separator}]
[rn/view {:style (style/no-pinned-messages-container bottom-inset)}
[rn/view {:style style/no-pinned-messages-icon}
[quo/icon :i/placeholder]]
[quo/text
{:weight :semi-bold
:style style/no-pinned-messages-text}
(i18n/label :t/no-pinned-messages)]
[quo/text {:size :paragraph-2}
(i18n/label
(if community
:t/no-pinned-messages-community-desc
:t/no-pinned-messages-desc))]])]))

View File

@ -9,29 +9,27 @@
[contact-list-item/contact-list-item
{:on-press #(rf/dispatch [:chat.ui/select-mention text-input-ref user])} user])
(defn mentions
(defn f-mentions
[{:keys [refs suggestions max-y]} bottom-inset]
[:f>
(fn []
(let [translate-y (reanimated/use-shared-value 0)]
(rn/use-effect
(fn []
(reanimated/set-shared-value translate-y
(reanimated/with-timing (if (seq suggestions) 0 200)))))
[reanimated/view
{:style (reanimated/apply-animations-to-style
{:transform [{:translateY translate-y}]}
{:bottom (or bottom-inset 0)
:position :absolute
:left 0
:right 0
:z-index 5
:elevation 5
:max-height (/ max-y 2)})}
[rn/flat-list
{:keyboard-should-persist-taps :always
:data (vals suggestions)
:key-fn :key
:render-fn mention-item
:render-data (:text-input-ref refs)
:accessibility-label :mentions-list}]]))])
(let [translate-y (reanimated/use-shared-value 0)]
(rn/use-effect
(fn []
(reanimated/set-shared-value translate-y
(reanimated/with-timing (if (seq suggestions) 0 200)))))
[reanimated/view
{:style (reanimated/apply-animations-to-style
{:transform [{:translateY translate-y}]}
{:bottom (or bottom-inset 0)
:position :absolute
:left 0
:right 0
:z-index 5
:elevation 5
:max-height (/ max-y 2)})}
[rn/flat-list
{:keyboard-should-persist-taps :always
:data (vals suggestions)
:key-fn :key
:render-fn mention-item
:render-data (:text-input-ref refs)
:accessibility-label :mentions-list}]]))

View File

@ -153,7 +153,7 @@
;; `keyboard-hiding?` flag
;; 4) we store input content height in `input/input-text-content-heights` atom , we need it when chat
;; screen is reopened
(defn composer
(defn f-composer
[_ _]
(let [text-input-ref (rn/create-ref)
send-ref (rn/create-ref)
@ -162,82 +162,80 @@
:text-input-ref text-input-ref
:record-ref record-ref}]
(fn [chat-id insets]
[:f>
(fn []
(let [reply (rf/sub [:chats/reply-message])
edit (rf/sub [:chats/edit-message])
suggestions (rf/sub [:chat/mention-suggestions])
images (rf/sub [:chats/sending-image])
(let [reply (rf/sub [:chats/reply-message])
edit (rf/sub [:chats/edit-message])
suggestions (rf/sub [:chat/mention-suggestions])
images (rf/sub [:chats/sending-image])
bottom-inset (max 20 (:bottom insets))
{window-height :height} (rn/use-window-dimensions)
{:keys [keyboard-shown keyboard-height]} (hooks/use-keyboard)
translate-y (reanimated/use-shared-value 0)
bg-opacity (reanimated/use-shared-value 0)
bg-bottom (reanimated/use-shared-value (- window-height))
bottom-inset (max 20 (:bottom insets))
{window-height :height} (rn/get-window)
{:keys [keyboard-shown keyboard-height]} (hooks/use-keyboard)
translate-y (reanimated/use-shared-value 0)
bg-opacity (reanimated/use-shared-value 0)
bg-bottom (reanimated/use-shared-value (- window-height))
suggestions? (and (seq suggestions)
keyboard-shown
(not @keyboard-hiding?))
suggestions? (and (seq suggestions)
keyboard-shown
(not @keyboard-hiding?))
max-y (- window-height
(- (if (> keyboard-height 0)
keyboard-height
360)
bottom-inset)
46)
max-y (- window-height
(- (if (> keyboard-height 0)
keyboard-height
360)
bottom-inset)
46)
min-y (+ 108
bottom-inset
(if suggestions?
(min (/ max-y 2)
(+ 16
(* 46 (dec (count suggestions)))))
(+ 0
(when (and
(or edit reply)
(not @input/recording-audio?))
38)
(when (seq images) 80))))
min-y (+ 108
bottom-inset
(if suggestions?
(min (/ max-y 2)
(+ 16
(* 46 (dec (count suggestions)))))
(+ 0
(when (and
(or edit reply)
(not @input/recording-audio?))
38)
(when (seq images) 80))))
parent-height (reanimated/use-shared-value min-y)
max-parent-height (Math/abs (- max-y 110 bottom-inset))
parent-height (reanimated/use-shared-value min-y)
max-parent-height (Math/abs (- max-y 110 bottom-inset))
params
(prepare-params
[refs window-height translate-y bg-opacity bg-bottom min-y max-y parent-height
max-parent-height chat-id suggestions reply edit images keyboard-shown])
params
(prepare-params
[refs window-height translate-y bg-opacity bg-bottom min-y max-y parent-height
max-parent-height chat-id suggestions reply edit images keyboard-shown])
input-content-change (get-input-content-change params)
bottom-sheet-gesture (get-bottom-sheet-gesture params)]
(effect! params)
[reanimated/view
{:style (reanimated/apply-animations-to-style
{:height parent-height}
{})}
;;;;input
[gesture/gesture-detector {:gesture bottom-sheet-gesture}
[reanimated/view
{:style (reanimated/apply-animations-to-style
{:transform [{:translateY translate-y}]}
(style/input-bottom-sheet window-height))}
[rn/view {:style (style/bottom-sheet-handle)}]
[edit/edit-message-auto-focus-wrapper text-input-ref edit #(clean-and-minimize params)]
[reply/reply-message-auto-focus-wrapper text-input-ref reply]
[rn/view
{:style {:height (- max-y (- min-y 38))}}
[input/text-input
{:chat-id chat-id
:on-content-size-change input-content-change
:sending-image (seq images)
:refs refs}]]]]
(if suggestions?
[mentions/mentions (select-keys params [:refs :suggestions :max-y]) bottom-inset]
[controls/view send-ref record-ref params bottom-inset chat-id images
edit #(clean-and-minimize params)])
;;;;black background
[reanimated/view
{:style (reanimated/apply-animations-to-style
{:opacity bg-opacity
:transform [{:translateY bg-bottom}]}
(style/bottom-sheet-background window-height))}]]))])))
input-content-change (get-input-content-change params)
bottom-sheet-gesture (get-bottom-sheet-gesture params)]
(effect! params)
[reanimated/view
{:style (reanimated/apply-animations-to-style
{:height parent-height}
{})}
;;;;input
[gesture/gesture-detector {:gesture bottom-sheet-gesture}
[reanimated/view
{:style (reanimated/apply-animations-to-style
{:transform [{:translateY translate-y}]}
(style/input-bottom-sheet window-height))}
[rn/view {:style (style/bottom-sheet-handle)}]
[edit/edit-message-auto-focus-wrapper text-input-ref edit #(clean-and-minimize params)]
[reply/reply-message-auto-focus-wrapper text-input-ref reply]
[rn/view
{:style {:height (- max-y (- min-y 38))}}
[input/text-input
{:chat-id chat-id
:on-content-size-change input-content-change
:sending-image (seq images)
:refs refs}]]]]
(if suggestions?
[:f> mentions/f-mentions (select-keys params [:refs :suggestions :max-y]) bottom-inset]
[controls/view send-ref record-ref params bottom-inset chat-id images
edit #(clean-and-minimize params)])
;;;;black background
[reanimated/view
{:style (reanimated/apply-animations-to-style
{:opacity bg-opacity
:transform [{:translateY bg-bottom}]}
(style/bottom-sheet-background window-height))}]]))))

View File

@ -20,61 +20,59 @@
(defn album-message
[{:keys [albumize?] :as message} context on-long-press]
[:f>
(fn []
(let [insets (safe-area/use-safe-area)
shared-element-id (rf/sub [:shared-element-id])
first-image (first (:album message))
album-style (if (> (:image-width first-image) (:image-height first-image))
:landscape
:portrait)
images-count (count (:album message))
;; album images are always square, except when we have 3 images, then they must be rectangular
;; (portrait or landscape)
portrait? (and (= images-count rectangular-style-count) (= album-style :portrait))
text (:text (:content first-image))]
(if (and albumize? (> images-count 1))
[:<>
(when (not= text "placeholder")
[rn/view {:style {:margin-bottom 10}} [text/text-content first-image context]])
[rn/view
{:style (style/album-container portrait?)}
(map-indexed
(fn [index item]
(let [images-size-key (if (< images-count constants/max-album-photos)
images-count
:default)
size (get-in constants/album-image-sizes [images-size-key index])
dimensions (if (not= images-count rectangular-style-count)
{:width size :height size}
(find-size size album-style))]
[rn/touchable-opacity
{:key (:message-id item)
:active-opacity 1
:on-long-press #(on-long-press message context)
:on-press #(rf/dispatch [:chat.ui/navigate-to-lightbox
(:message-id item)
{:messages (:album message)
:index index
:insets insets}])}
[fast-image/fast-image
{:style (style/image dimensions index portrait? images-count)
:source {:uri (:image (:content item))}
:native-ID (when (and (= shared-element-id (:message-id item))
(< index constants/max-album-photos))
:shared-element)}]
(when (and (> images-count constants/max-album-photos)
(= index (- constants/max-album-photos 1)))
[rn/view
{:style style/overlay}
[quo/text
{:weight :bold
:size :heading-2
:style {:color colors/white}}
(str "+" (- images-count (dec constants/max-album-photos)))]])]))
(:album message))]]
[:<>
(map-indexed
(fn [index item]
[image/image-message index item context #(on-long-press message context)])
(:album message))])))])
(let [insets (safe-area/get-insets)
shared-element-id (rf/sub [:shared-element-id])
first-image (first (:album message))
album-style (if (> (:image-width first-image) (:image-height first-image))
:landscape
:portrait)
images-count (count (:album message))
;; album images are always square, except when we have 3 images, then they must be rectangular
;; (portrait or landscape)
portrait? (and (= images-count rectangular-style-count) (= album-style :portrait))
text (:text (:content first-image))]
(if (and albumize? (> images-count 1))
[:<>
(when (not= text "placeholder")
[rn/view {:style {:margin-bottom 10}} [text/text-content first-image context]])
[rn/view
{:style (style/album-container portrait?)}
(map-indexed
(fn [index item]
(let [images-size-key (if (< images-count constants/max-album-photos)
images-count
:default)
size (get-in constants/album-image-sizes [images-size-key index])
dimensions (if (not= images-count rectangular-style-count)
{:width size :height size}
(find-size size album-style))]
[rn/touchable-opacity
{:key (:message-id item)
:active-opacity 1
:on-long-press #(on-long-press message context)
:on-press #(rf/dispatch [:chat.ui/navigate-to-lightbox
(:message-id item)
{:messages (:album message)
:index index
:insets insets}])}
[fast-image/fast-image
{:style (style/image dimensions index portrait? images-count)
:source {:uri (:image (:content item))}
:native-ID (when (and (= shared-element-id (:message-id item))
(< index constants/max-album-photos))
:shared-element)}]
(when (and (> images-count constants/max-album-photos)
(= index (- constants/max-album-photos 1)))
[rn/view
{:style style/overlay}
[quo/text
{:weight :bold
:size :heading-2
:style {:color colors/white}}
(str "+" (- images-count (dec constants/max-album-photos)))]])]))
(:album message))]]
[:<>
(map-indexed
(fn [index item]
[image/image-message index item context #(on-long-press message context)])
(:album message))])))

View File

@ -15,26 +15,24 @@
(defn image-message
[index {:keys [content image-width image-height message-id] :as message} context on-long-press]
[:f>
(fn []
(let [insets (safe-area/use-safe-area)
dimensions (calculate-dimensions (or image-width 1000) (or image-height 1000))
text (:text content)]
(fn []
(let [shared-element-id (rf/sub [:shared-element-id])]
[rn/touchable-opacity
{:active-opacity 1
:key message-id
:style {:margin-top (when (pos? index) 10)}
:on-long-press on-long-press
:on-press #(rf/dispatch [:chat.ui/navigate-to-lightbox
message-id
{:messages [message]
:index 0
:insets insets}])}
(when (and (not= text "placeholder") (= index 0))
[rn/view {:style {:margin-bottom 10}} [text/text-content message context]])
[fast-image/fast-image
{:source {:uri (:image content)}
:style (merge dimensions {:border-radius 12})
:native-ID (when (= shared-element-id message-id) :shared-element)}]]))))])
(let [insets (safe-area/get-insets)
dimensions (calculate-dimensions (or image-width 1000) (or image-height 1000))
text (:text content)]
(fn []
(let [shared-element-id (rf/sub [:shared-element-id])]
[rn/touchable-opacity
{:active-opacity 1
:key message-id
:style {:margin-top (when (pos? index) 10)}
:on-long-press on-long-press
:on-press #(rf/dispatch [:chat.ui/navigate-to-lightbox
message-id
{:messages [message]
:index 0
:insets insets}])}
(when (and (not= text "placeholder") (= index 0))
[rn/view {:style {:margin-bottom 10}} [text/text-content message context]])
[fast-image/fast-image
{:source {:uri (:image content)}
:style (merge dimensions {:border-radius 12})
:native-ID (when (= shared-element-id message-id) :shared-element)}]]))))

View File

@ -68,18 +68,17 @@
[]
(let [;;NOTE: we want to react only on these fields, do not use full chat map here
{:keys [chat-id contact-request-state group-chat able-to-send-message?] :as chat}
(rf/sub [:chats/current-chat-chat-view])]
[safe-area/consumer
(fn [insets]
[rn/keyboard-avoiding-view
{:style {:position :relative :flex 1}
:keyboardVerticalOffset (- (:bottom insets))}
[page-nav]
[pin.banner/banner chat-id]
[messages.list/messages-list chat insets]
(if-not able-to-send-message?
[contact-requests.bottom-drawer/view chat-id contact-request-state group-chat]
[composer/composer chat-id insets])])]))
(rf/sub [:chats/current-chat-chat-view])
insets (safe-area/get-insets)]
[rn/keyboard-avoiding-view
{:style {:position :relative :flex 1}
:keyboardVerticalOffset (- (:bottom insets))}
[page-nav]
[pin.banner/banner chat-id]
[messages.list/messages-list chat insets]
(if-not able-to-send-message?
[contact-requests.bottom-drawer/view chat-id contact-request-state group-chat]
[:f> composer/f-composer chat-id insets])]))
(defn chat
[]

View File

@ -51,26 +51,22 @@
(str (:title item) index))
(defn album-selector
[{:keys [scroll-enabled on-scroll]}]
[:f>
(fn []
(let [albums (rf/sub [:camera-roll/albums])
selected-album (or (rf/sub [:camera-roll/selected-album]) (i18n/label :t/recent))]
(rn/use-effect-once
(fn []
(rf/dispatch [:chat.ui/camera-roll-get-albums])
js/undefined))
[rn/view {:style {:padding-top 20}}
[album-title false]
[gesture/section-list
{:data albums
:render-fn album
:render-data selected-album
:sections albums
:sticky-section-headers-enabled false
:render-section-header-fn section-header
:style {:margin-top 12}
:content-container-style {:padding-bottom 40}
:key-fn key-fn
:scroll-enabled @scroll-enabled
:on-scroll on-scroll}]]))])
[{:keys [on-scroll]}]
(rf/dispatch [:chat.ui/camera-roll-get-albums])
(fn [{:keys [scroll-enabled]}]
(let [albums (rf/sub [:camera-roll/albums])
selected-album (or (rf/sub [:camera-roll/selected-album]) (i18n/label :t/recent))]
[rn/view {:style {:padding-top 20}}
[album-title false]
[gesture/section-list
{:data albums
:render-fn album
:render-data selected-album
:sections albums
:sticky-section-headers-enabled false
:render-section-header-fn section-header
:style {:margin-top 12}
:content-container-style {:padding-bottom 40}
:key-fn key-fn
:scroll-enabled @scroll-enabled
:on-scroll on-scroll}]])))

View File

@ -40,35 +40,34 @@
selected-items (case @selected-tab
:joined joined
:pending pending
:opened opened)]
[safe-area/consumer
(fn [{:keys [top]}]
[:<>
[rn/flat-list
{:key-fn :id
:content-inset-adjustment-behavior :never
:header [rn/view {:height (+ 245 top)}]
:render-fn item-render
:data selected-items}]
[rn/view
{:style (style/blur-container top)}
[blur/view
{:blur-amount (if platform/ios? 20 10)
:blur-type (if (colors/dark?) :dark (if platform/ios? :light :xlight))
:style style/blur}]
[common.home/top-nav]
[common.home/title-column
{:label (i18n/label :t/communities)
:handler #(rf/dispatch [:bottom-sheet/show-sheet-old :add-new {}])
:accessibility-label :new-chat-button}]
[quo/discover-card
{:on-press #(rf/dispatch [:navigate-to :discover-communities])
:title (i18n/label :t/discover)
:description (i18n/label :t/whats-trending)
:accessibility-label :communities-home-discover-card}]
[quo/tabs
{:size 32
:style style/tabs
:on-change #(reset! selected-tab %)
:default-active @selected-tab
:data tabs-data}]]])]))))
:opened opened)
top (safe-area/get-top)]
[:<>
[rn/flat-list
{:key-fn :id
:content-inset-adjustment-behavior :never
:header [rn/view {:height (+ 245 top)}]
:render-fn item-render
:data selected-items}]
[rn/view
{:style (style/blur-container top)}
[blur/view
{:blur-amount (if platform/ios? 20 10)
:blur-type (if (colors/dark?) :dark (if platform/ios? :light :xlight))
:style style/blur}]
[common.home/top-nav]
[common.home/title-column
{:label (i18n/label :t/communities)
:handler #(rf/dispatch [:bottom-sheet/show-sheet-old :add-new {}])
:accessibility-label :new-chat-button}]
[quo/discover-card
{:on-press #(rf/dispatch [:navigate-to :discover-communities])
:title (i18n/label :t/discover)
:description (i18n/label :t/whats-trending)
:accessibility-label :communities-home-discover-card}]
[quo/tabs
{:size 32
:style style/tabs
:on-change #(reset! selected-tab %)
:default-active @selected-tab
:data tabs-data}]]]))))

View File

@ -5,19 +5,21 @@
[status-im2.contexts.onboarding.common.background.style :as style]
[status-im2.contexts.onboarding.common.carousel.animation :as carousel.animation]))
(defn f-view
[dark-overlay?]
(let [animate? (not dark-overlay?)]
(when animate? (carousel.animation/initialize-animation))
[rn/view
{:style style/background-container}
[:f> carousel/f-view animate?]
(when dark-overlay?
[blur/view
{:style style/background-blur-overlay
:blur-amount 30
:blur-radius 25
:blur-type :transparent
:overlay-color :transparent}])]))
(defn view
[dark-overlay?]
[:f>
(fn []
(let [animate? (not dark-overlay?)]
(when animate? (carousel.animation/initialize-animation))
[rn/view
{:style style/background-container}
[carousel/view animate?]
(when dark-overlay?
[blur/view
{:style style/background-blur-overlay
:blur-amount 30
:blur-radius 25
:blur-type :transparent
:overlay-color :transparent}])]))])
[:f> f-view dark-overlay?])

View File

@ -53,46 +53,41 @@
[rn/view {:style (style/progress-bar-item static? false)}]
[rn/view {:style (style/progress-bar-item static? true)}]])
(defn dynamic-progress-bar
(defn f-dynamic-progress-bar
[progress-bar-width animate?]
[:f>
(fn []
(let [width (animation/dynamic-progress-bar-width progress-bar-width animate?)
container-view (if animate? reanimated/view rn/view)]
[container-view {:style (style/dynamic-progress-bar width animate?)}
[progress-bar
{:static? false
:progress-bar-width progress-bar-width}]]))])
(let [width (animation/dynamic-progress-bar-width progress-bar-width animate?)
container-view (if animate? reanimated/view rn/view)]
[container-view {:style (style/dynamic-progress-bar width animate?)}
[progress-bar
{:static? false
:progress-bar-width progress-bar-width}]]))
(defn view
(defn f-view
[animate?]
[:f>
(fn []
(let [window-width (rf/sub [:dimensions/window-width])
view-id (rf/sub [:view-id])
status-bar-height (:status-bar-height @navigation/constants)
progress-bar-width (- window-width 40)
carousel-left (animation/carousel-left-position window-width animate?)
container-view (if animate? reanimated/view rn/view)]
(when animate?
(rn/use-effect
(fn []
(reanimated/set-shared-value @animation/paused (not= view-id :intro)))
[view-id]))
[:<>
[container-view {:style (style/carousel-container carousel-left animate?)}
(for [index (range 2)]
^{:key index}
[content-view
{:window-width window-width
:status-bar-height status-bar-height
:index index}])]
[rn/view
{:style (style/progress-bar-container
progress-bar-width
status-bar-height)}
[progress-bar
{:static? true
:progress-bar-width progress-bar-width}]
[dynamic-progress-bar progress-bar-width animate?]]]))])
(let [window-width (rf/sub [:dimensions/window-width])
view-id (rf/sub [:view-id])
status-bar-height (:status-bar-height @navigation/constants)
progress-bar-width (- window-width 40)
carousel-left (animation/carousel-left-position window-width animate?)
container-view (if animate? reanimated/view rn/view)]
(when animate?
(rn/use-effect
(fn []
(reanimated/set-shared-value @animation/paused (not= view-id :intro)))
[view-id]))
[:<>
[container-view {:style (style/carousel-container carousel-left animate?)}
(for [index (range 2)]
^{:key index}
[content-view
{:window-width window-width
:status-bar-height status-bar-height
:index index}])]
[rn/view
{:style (style/progress-bar-container
progress-bar-width
status-bar-height)}
[progress-bar
{:static? true
:progress-bar-width progress-bar-width}]
[:f> f-dynamic-progress-bar progress-bar-width animate?]]]))

View File

@ -186,21 +186,20 @@
(defn create-password
[]
[:f>
(let [scroll-view-ref (atom nil)
scroll-to-end-fn #(js/setTimeout ^js/Function (.-scrollToEnd @scroll-view-ref) 250)]
(fn []
(let [{:keys [top]} (safe-area/use-safe-area)]
[:<>
[background/view true]
[rn/scroll-view
{:ref #(reset! scroll-view-ref %)
:style style/overlay
:content-container-style style/content-style}
[navigation-bar/navigation-bar
{:top top
:right-section-buttons [{:type :blur-bg
:icon :i/info
:icon-override-theme :dark
:on-press #(js/alert "Info pressed")}]}]
[password-form {:scroll-to-end-fn scroll-to-end-fn}]]])))])
(let [scroll-view-ref (atom nil)
scroll-to-end-fn #(js/setTimeout ^js/Function (.-scrollToEnd @scroll-view-ref) 250)]
(fn []
(let [{:keys [top]} (safe-area/get-insets)]
[:<>
[background/view true]
[rn/scroll-view
{:ref #(reset! scroll-view-ref %)
:style style/overlay
:content-container-style style/content-style}
[navigation-bar/navigation-bar
{:top top
:right-section-buttons [{:type :blur-bg
:icon :i/info
:icon-override-theme :dark
:on-press #(js/alert "Info pressed")}]}]
[password-form {:scroll-to-end-fn scroll-to-end-fn}]]]))))

View File

@ -55,107 +55,103 @@
[rn/view {:style style/view-button-container}
children]))
(defn page
(defn- f-page
[{:keys [onboarding-profile-data navigation-bar-top]}]
[:f>
(fn []
(let [{:keys [image-path display-name color]} onboarding-profile-data
full-name (reagent/atom display-name)
keyboard-shown? (reagent/atom false)
validation-msg (reagent/atom (validation-message @full-name))
on-change-text (fn [s]
(reset! validation-msg (validation-message s))
(reset! full-name (string/trim s)))
custom-color (reagent/atom (or color c/profile-default-color))
profile-pic (reagent/atom image-path)
on-change-profile-pic #(reset! profile-pic %)
on-change #(reset! custom-color %)]
(fn []
(rn/use-effect
(let [will-show-listener (oops/ocall rn/keyboard
"addListener"
"keyboardWillShow"
#(swap! keyboard-shown? (fn [] true)))
will-hide-listener (oops/ocall rn/keyboard
"addListener"
"keyboardWillHide"
#(swap! keyboard-shown? (fn [] false)))]
(fn []
(fn []
(oops/ocall will-show-listener "remove")
(oops/ocall will-hide-listener "remove"))))
[])
[rn/view {:style style/page-container}
[navigation-bar/navigation-bar {:top navigation-bar-top}]
[rn/scroll-view
{:keyboard-should-persist-taps :always
:content-container-style {:flex-grow 1}}
[rn/view {:style style/page-container}
[rn/view
{:style style/content-container}
[quo/text
{:size :heading-1
:weight :semi-bold
:style style/title} (i18n/label :t/create-profile)]
[rn/view
{:style style/input-container}
[rn/view
{:style style/profile-input-container}
[quo/profile-input
{:customization-color @custom-color
:placeholder (i18n/label :t/your-name)
:on-press (fn []
(rf/dispatch [:dismiss-keyboard])
(rf/dispatch
[:show-bottom-sheet
{:override-theme :dark
:content
(fn []
[method-menu/view on-change-profile-pic])}]))
:image-picker-props {:profile-picture @profile-pic
:full-name @full-name}
:title-input-props {:default-value @full-name
:max-length c/profile-name-max-length
:on-change-text on-change-text}}]]
(when @validation-msg
[quo/info-message
{:type :error
:size :default
:icon :i/info
:style style/info-message}
@validation-msg])
[quo/text
{:size :paragraph-2
:style style/color-title}
(i18n/label :t/accent-colour)]
[quo/color-picker
{:blur? true
:default-selected? :blue
:selected @custom-color
:on-change on-change}]]]]]
[rn/keyboard-avoiding-view {}
[button-container @keyboard-shown?
[quo/button
{:accessibility-label :submit-create-profile-button
:type :primary
:override-background-color (colors/custom-color @custom-color 60)
:on-press (fn []
(rf/dispatch [:onboarding-2/profile-data-set
{:image-path @profile-pic
:display-name @full-name
:color @custom-color}]))
:style style/continue-button
:disabled (or (not (seq @full-name)) @validation-msg)}
(i18n/label :t/continue)]]]])))])
(let [{:keys [image-path display-name color]} onboarding-profile-data
full-name (reagent/atom display-name)
keyboard-shown? (reagent/atom false)
validation-msg (reagent/atom (validation-message @full-name))
on-change-text (fn [s]
(reset! validation-msg (validation-message s))
(reset! full-name (string/trim s)))
custom-color (reagent/atom (or color c/profile-default-color))
profile-pic (reagent/atom image-path)
on-change-profile-pic #(reset! profile-pic %)
on-change #(reset! custom-color %)]
(fn []
(rn/use-effect
(let [will-show-listener (oops/ocall rn/keyboard
"addListener"
"keyboardWillShow"
#(swap! keyboard-shown? (fn [] true)))
will-hide-listener (oops/ocall rn/keyboard
"addListener"
"keyboardWillHide"
#(swap! keyboard-shown? (fn [] false)))]
(fn []
(fn []
(oops/ocall will-show-listener "remove")
(oops/ocall will-hide-listener "remove"))))
[])
[rn/view {:style style/page-container}
[navigation-bar/navigation-bar {:top navigation-bar-top}]
[rn/scroll-view
{:keyboard-should-persist-taps :always
:content-container-style {:flex-grow 1}}
[rn/view {:style style/page-container}
[rn/view
{:style style/content-container}
[quo/text
{:size :heading-1
:weight :semi-bold
:style style/title} (i18n/label :t/create-profile)]
[rn/view
{:style style/input-container}
[rn/view
{:style style/profile-input-container}
[quo/profile-input
{:customization-color @custom-color
:placeholder (i18n/label :t/your-name)
:on-press (fn []
(rf/dispatch [:dismiss-keyboard])
(rf/dispatch
[:show-bottom-sheet
{:override-theme :dark
:content
(fn []
[method-menu/view on-change-profile-pic])}]))
:image-picker-props {:profile-picture @profile-pic
:full-name @full-name}
:title-input-props {:default-value @full-name
:max-length c/profile-name-max-length
:on-change-text on-change-text}}]]
(when @validation-msg
[quo/info-message
{:type :error
:size :default
:icon :i/info
:style style/info-message}
@validation-msg])
[quo/text
{:size :paragraph-2
:style style/color-title}
(i18n/label :t/accent-colour)]
[quo/color-picker
{:blur? true
:default-selected? :blue
:selected @custom-color
:on-change on-change}]]]]]
[rn/keyboard-avoiding-view {}
[button-container @keyboard-shown?
[quo/button
{:accessibility-label :submit-create-profile-button
:type :primary
:override-background-color (colors/custom-color @custom-color 60)
:on-press (fn []
(rf/dispatch [:onboarding-2/profile-data-set
{:image-path @profile-pic
:display-name @full-name
:color @custom-color}]))
:style style/continue-button
:disabled (or (not (seq @full-name)) @validation-msg)}
(i18n/label :t/continue)]]]])))
(defn create-profile
[]
[:f>
(fn []
(let [{:keys [top]} (safe-area/use-safe-area)
onboarding-profile-data (rf/sub [:onboarding-2/profile])]
[:<>
[background/view true]
[page
{:navigation-bar-top top
:onboarding-profile-data onboarding-profile-data}]]))])
(let [{:keys [top]} (safe-area/get-insets)
onboarding-profile-data (rf/sub [:onboarding-2/profile])]
[:<>
[background/view true]
[:f> f-page
{:navigation-bar-top top
:onboarding-profile-data onboarding-profile-data}]]))

View File

@ -38,13 +38,11 @@
(defn enable-biometrics
[]
[:f>
(fn []
(let [insets (safe-area/use-safe-area)]
[rn/view {:style (style/page-container insets)}
[navigation-bar/navigation-bar {:disable-back-button? true}]
[page-title]
[rn/view {:style style/page-illustration}
[quo/text
"Illustration here"]]
[enable-biometrics-buttons {:insets insets}]]))])
(let [insets (safe-area/get-insets)]
[rn/view {:style (style/page-container insets)}
[navigation-bar/navigation-bar {:disable-back-button? true}]
[page-title]
[rn/view {:style style/page-illustration}
[quo/text
"Illustration here"]]
[enable-biometrics-buttons {:insets insets}]]))

View File

@ -46,14 +46,12 @@
(defn enable-notifications
[]
[:f>
(fn []
(let [insets (safe-area/use-safe-area)]
[rn/view {:style (style/page-container insets)}
[background/view true]
[navigation-bar/navigation-bar {:disable-back-button? true}]
[page-title]
[rn/view {:style style/page-illustration}
[quo/text
"Illustration here"]]
[enable-notification-buttons {:insets insets}]]))])
(let [insets (safe-area/get-insets)]
[rn/view {:style (style/page-container insets)}
[background/view true]
[navigation-bar/navigation-bar {:disable-back-button? true}]
[page-title]
[rn/view {:style style/page-illustration}
[quo/text
"Illustration here"]]
[enable-notification-buttons {:insets insets}]]))

View File

@ -65,9 +65,7 @@
(defn enter-seed-phrase
[]
[:f>
(fn []
(let [{:keys [top]} (safe-area/use-safe-area)]
[rn/view {:style {:flex 1}}
[background/view true]
[page {:navigation-bar-top top}]]))])
(let [{:keys [top]} (safe-area/get-insets)]
[rn/view {:style {:flex 1}}
[background/view true]
[page {:navigation-bar-top top}]]))

View File

@ -21,9 +21,7 @@
(defn generating-keys
[]
[:f>
(fn []
(let [{:keys [top]} (safe-area/use-safe-area)]
[rn/view {:style {:flex 1}}
[background/view true]
[page {:navigation-bar-top top}]]))])
(let [{:keys [top]} (safe-area/get-insets)]
[rn/view {:style {:flex 1}}
[background/view true]
[page {:navigation-bar-top top}]]))

View File

@ -56,16 +56,14 @@
(defn new-to-status
[]
[:f>
(fn []
(let [{:keys [top]} (safe-area/use-safe-area)]
[:<>
[background/view true]
[rn/view {:style style/content-container}
[navigation-bar/navigation-bar
{:top top
:right-section-buttons [{:type :blur-bg
:icon :i/info
:icon-override-theme :dark
:on-press #(js/alert "Info pressed")}]}]
[sign-in-options]]]))])
(let [{:keys [top]} (safe-area/get-insets)]
[:<>
[background/view true]
[rn/view {:style style/content-container}
[navigation-bar/navigation-bar
{:top top
:right-section-buttons [{:type :blur-bg
:icon :i/info
:icon-override-theme :dark
:on-press #(js/alert "Info pressed")}]}]
[sign-in-options]]]))

View File

@ -86,19 +86,18 @@
(defn- qr-scan-hole-area
[qr-view-finder]
(let [status-bar-height (rn/status-bar-height)]
[rn/view
{:style style/qr-view-finder
:on-layout (fn [event]
(let [layout (transforms/js->clj (oops/oget event "nativeEvent.layout"))
width (:width layout)
y (if platform/android?
(+ status-bar-height (:y layout))
(:y layout))
view-finder (-> layout
(assoc :height width)
(assoc :y y))]
(reset! qr-view-finder view-finder)))}]))
[rn/view
{:style style/qr-view-finder
:on-layout (fn [event]
(let [layout (transforms/js->clj (oops/oget event "nativeEvent.layout"))
width (:width layout)
y (if platform/android?
(+ (safe-area/get-top) (:y layout))
(:y layout))
view-finder (-> layout
(assoc :height width)
(assoc :y y))]
(reset! qr-view-finder view-finder)))}])
(defn- border
@ -168,9 +167,12 @@
:override-theme :light
:text (i18n/label :t/error-this-is-not-a-sync-qr-code)}]))))
(defn view
(defn f-view
[]
(let [active-tab (reagent/atom 1)
(let [camera-ref (atom nil)
read-qr-once? (atom false)
insets (safe-area/get-insets)
active-tab (reagent/atom 1)
qr-view-finder (reagent/atom {})
{:keys [height width]} (rf/sub [:dimensions/window])
request-camera-permission (fn []
@ -185,55 +187,55 @@
:override-theme :light
:text (i18n/label
:t/camera-permission-denied)}])}]))]
[:f>
(fn []
(let [insets (safe-area/use-safe-area)
camera-ref (atom nil)
read-qr-once? (atom false)
holes (merge @qr-view-finder {:borderRadius 16})
scan-qr-code-tab? (= @active-tab 1)
show-camera? (and scan-qr-code-tab? @camera-permission-granted?)
show-holes? (and show-camera?
(boolean (not-empty @qr-view-finder)))
on-read-code (fn [data]
(when-not @read-qr-once?
(reset! read-qr-once? true)
(js/setTimeout (fn []
(reset! read-qr-once? false))
3000)
(check-qr-code-data data)))
hole-view-wrapper (if show-camera?
[hole-view/hole-view
{:style style/absolute-fill
:holes (if show-holes?
[holes]
[])}]
[:<>])]
(rn/use-effect
(fn []
(when-not @camera-permission-granted?
(permissions/permission-granted? :camera
#(reset! camera-permission-granted? %)
#(reset! camera-permission-granted? false)))))
[rn/view {:style (style/root-container (:top insets))}
(if show-camera?
[camera-kit/camera
{:ref #(reset! camera-ref %)
:style (merge style/absolute-fill {:height height :width width})
:camera-options {:zoomMode :off}
:scan-barcode true
:on-read-code on-read-code}]
[background/view true])
(conj hole-view-wrapper
[blur/view
{:style style/absolute-fill
:overlay-color colors/neutral-80-opa-80
:blur-type :dark
:blur-amount (if platform/ios? 15 5)}])
[header active-tab read-qr-once?]
(case @active-tab
1 [scan-qr-code-tab qr-view-finder request-camera-permission]
2 [enter-sync-code-tab]
nil)
[rn/view {:style style/flex-spacer}]
[bottom-view insets]]))]))
(fn []
(let [holes (merge @qr-view-finder {:borderRadius 16})
scan-qr-code-tab? (= @active-tab 1)
show-camera? (and scan-qr-code-tab? @camera-permission-granted?)
show-holes? (and show-camera?
(boolean (not-empty @qr-view-finder)))
on-read-code (fn [data]
(when-not @read-qr-once?
(reset! read-qr-once? true)
(js/setTimeout (fn []
(reset! read-qr-once? false))
3000)
(check-qr-code-data data)))
hole-view-wrapper (if show-camera?
[hole-view/hole-view
{:style style/absolute-fill
:holes (if show-holes?
[holes]
[])}]
[:<>])]
(rn/use-effect
(fn []
(when-not @camera-permission-granted?
(permissions/permission-granted? :camera
#(reset! camera-permission-granted? %)
#(reset! camera-permission-granted? false)))))
[rn/view {:style (style/root-container (:top insets))}
(if show-camera?
[camera-kit/camera
{:ref #(reset! camera-ref %)
:style (merge style/absolute-fill {:height height :width width})
:camera-options {:zoomMode :off}
:scan-barcode true
:on-read-code on-read-code}]
[background/view true])
(conj hole-view-wrapper
[blur/view
{:style style/absolute-fill
:overlay-color colors/neutral-80-opa-80
:blur-type :dark
:blur-amount (if platform/ios? 15 5)}])
[header active-tab read-qr-once?]
(case @active-tab
1 [scan-qr-code-tab qr-view-finder request-camera-permission]
2 [enter-sync-code-tab]
nil)
[rn/view {:style style/flex-spacer}]
[bottom-view insets]]))))
(defn view
[]
[:f> f-view])

View File

@ -32,9 +32,6 @@
(defn syncing-devices
[]
(fn []
[safe-area/consumer
(fn [{:keys [top]}]
[rn/view {:style {:flex 1}}
[background/view true]
[page {:navigation-bar-top top}]])]))
[rn/view {:style {:flex 1}}
[background/view true]
[page {:navigation-bar-top (safe-area/get-top)}]])

View File

@ -35,20 +35,19 @@
(defn view
[]
(let [profile-color (:color (rf/sub [:onboarding-2/profile]))]
[safe-area/consumer
(fn [insets]
[rn/view {:style (style/page-container insets)}
[background/view true]
[navigation-bar :enable-notifications]
[page-title]
[rn/view {:style style/page-illustration}
[quo/text
"Illustration here"]]
[rn/view {:style (style/buttons insets)}
[quo/button
{:on-press #(rf/dispatch [:init-root :shell-stack])
:type :primary
:accessibility-label :welcome-button
:override-background-color (colors/custom-color profile-color 60)}
(i18n/label :t/start-using-status)]]])]))
(let [profile-color (:color (rf/sub [:onboarding-2/profile]))
insets (safe-area/get-insets)]
[rn/view {:style (style/page-container insets)}
[background/view true]
[navigation-bar :enable-notifications]
[page-title]
[rn/view {:style style/page-illustration}
[quo/text
"Illustration here"]]
[rn/view {:style (style/buttons insets)}
[quo/button
{:on-press #(rf/dispatch [:init-root :shell-stack])
:type :primary
:accessibility-label :welcome-button
:override-background-color (colors/custom-color profile-color 60)}
(i18n/label :t/start-using-status)]]]))

View File

@ -34,20 +34,16 @@
[quo/text {:size :paragraph-2}
"Some random description • Developer • Designer • Olympic gold winner • President • Super Hero"]]}])
(defn display-picture-comp
(defn f-display-picture-comp
[animation]
[:f>
(fn []
[reanimated/fast-image
{:style (reanimated/apply-animations-to-style
{:width animation
:height animation}
{:border-radius 72})
:source
{:uri
"https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg"}}])])
[reanimated/fast-image
{:style (reanimated/apply-animations-to-style
{:width animation
:height animation}
{:border-radius 72})
:source
{:uri
"https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg"}}])
(defn header-comp
[]
@ -78,7 +74,7 @@
{:theme-color theme-color
:cover-uri
"https://hips.hearstapps.com/hmg-prod.s3.amazonaws.com/images/kitten-playing-with-toy-mouse-royalty-free-image-590055188-1542816918.jpg?crop=1.00xw:0.758xh;0,0.132xh&resize=480:*"
:display-picture-comp display-picture-comp
:f-display-picture-comp f-display-picture-comp
:header-comp header-comp
:title-comp title-comp
:main-comp main-comp

View File

@ -45,6 +45,16 @@
pass-through? colors/white-opa-40
:else colors/neutral-50))
(defn- f-bottom-tab
[state selected? pass-through?]
(let [icon-color-anim (reanimated/use-shared-value colors/white)]
(reanimated/set-shared-value
icon-color-anim
(get-icon-color selected? pass-through?))
[quo2/bottom-nav-tab
(merge state {:icon-color-anim icon-color-anim})
(:value state)]))
(defn cool-preview
[]
(let [state (reagent/atom {:icon :i/communities
@ -54,21 +64,14 @@
:preview-label-color colors/white})
selected? (reagent/cursor state [:selected?])
pass-through? (reagent/cursor state [:pass-through?])]
[:f>
(fn []
(let [icon-color-anim (reanimated/use-shared-value colors/white)]
(reanimated/set-shared-value
icon-color-anim
(get-icon-color @selected? @pass-through?))
[rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!}
[rn/view {:padding-bottom 150}
[preview/customizer state descriptor]
[rn/view
{:padding-vertical 60
:align-items :center}
[quo2/bottom-nav-tab
(merge @state {:icon-color-anim icon-color-anim})
(:value @state)]]]]))]))
(fn []
[rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!}
[rn/view {:padding-bottom 150}
[preview/customizer state descriptor]
[rn/view
{:padding-vertical 60
:align-items :center}
[:f> f-bottom-tab @state @selected? @pass-through?]]]])))
(defn preview-bottom-nav-tab
[]

View File

@ -43,20 +43,23 @@
(= scroll-type :scroll-to-bottom)
(assoc :scroll-to-bottom {:on-press #()})))
(defn- f-shell-button
[state]
[quo2/floating-shell-button (mock-data state)
nil (reanimated/use-shared-value 1)])
(defn cool-preview
[]
(let [state (reagent/atom {:show-jump-to? true
:scroll-type :notification-down})]
[:f>
(fn []
[rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!}
[rn/view {:padding-bottom 150}
[preview/customizer state descriptor]
[rn/view
{:padding-vertical 60
:align-items :center}
[quo2/floating-shell-button (mock-data @state)
nil (reanimated/use-shared-value 1)]]]])]))
(fn []
[rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!}
[rn/view {:padding-bottom 150}
[preview/customizer state descriptor]
[rn/view
{:padding-vertical 60
:align-items :center}
[:f> f-shell-button @state]]]])))
(defn preview-floating-shell-button
[]

View File

@ -29,30 +29,32 @@
:on-press #(animation/bottom-tab-on-press stack-id)
:accessibility-label (str (name stack-id) "-tab"))])
(defn- f-bottom-tabs
[]
(let [notifications-data (rf/sub [:shell/bottom-tabs-notifications-data])
pass-through? (rf/sub [:shell/shell-pass-through?])
shared-values @animation/shared-values-atom
original-style (style/bottom-tabs-container pass-through?)
animated-style (reanimated/apply-animations-to-style
{:height (:bottom-tabs-height shared-values)}
original-style)
messages-double-tap-gesture (-> (gesture/gesture-tap)
(gesture/number-of-taps 2)
(gesture/on-start
(fn [_event]
(rf/dispatch [:messages-home/select-tab :tab/recent]))))]
(animation/load-stack @animation/selected-stack-id)
(reanimated/set-shared-value (:pass-through? shared-values) pass-through?)
[reanimated/view {:style animated-style}
(when pass-through?
[blur/view (blur-overlay-params style/bottom-tabs-blur-overlay)])
[rn/view {:style (style/bottom-tabs)}
[bottom-tab :i/communities :communities-stack shared-values notifications-data]
[gesture/gesture-detector {:gesture messages-double-tap-gesture}
[bottom-tab :i/messages :chats-stack shared-values notifications-data]]
[bottom-tab :i/wallet :wallet-stack shared-values notifications-data]
[bottom-tab :i/browser :browser-stack shared-values notifications-data]]]))
(defn bottom-tabs
[]
[:f>
(fn []
(let [notifications-data (rf/sub [:shell/bottom-tabs-notifications-data])
pass-through? (rf/sub [:shell/shell-pass-through?])
shared-values @animation/shared-values-atom
original-style (style/bottom-tabs-container pass-through?)
animated-style (reanimated/apply-animations-to-style
{:height (:bottom-tabs-height shared-values)}
original-style)
messages-double-tap-gesture (-> (gesture/gesture-tap)
(gesture/number-of-taps 2)
(gesture/on-start
(fn [_event]
(rf/dispatch [:messages-home/select-tab :tab/recent]))))]
(animation/load-stack @animation/selected-stack-id)
(reanimated/set-shared-value (:pass-through? shared-values) pass-through?)
[reanimated/view {:style animated-style}
(when pass-through?
[blur/view (blur-overlay-params style/bottom-tabs-blur-overlay)])
[rn/view {:style (style/bottom-tabs)}
[bottom-tab :i/communities :communities-stack shared-values notifications-data]
[gesture/gesture-detector {:gesture messages-double-tap-gesture}
[bottom-tab :i/messages :chats-stack shared-values notifications-data]]
[bottom-tab :i/wallet :wallet-stack shared-values notifications-data]
[bottom-tab :i/browser :browser-stack shared-values notifications-data]]]))])
[:f> f-bottom-tabs])

View File

@ -1,7 +1,7 @@
(ns status-im2.contexts.shell.constants
(:require [react-native.core :as rn]
[react-native.platform :as platform]
[utils.re-frame :as rf]))
(:require [react-native.platform :as platform]
[utils.re-frame :as rf]
[react-native.safe-area :as safe-area]))
(def shell-animation-time 200)
@ -15,7 +15,7 @@
(defn status-bar-offset
[]
(if platform/android? (rn/status-bar-height) 0))
(if platform/android? (safe-area/get-top) 0))
;; status bar height is not included in : the dimensions/window for devices with a notch
;; https://github.com/facebook/react-native/issues/23693#issuecomment-662860819

View File

@ -16,44 +16,41 @@
:browser-stack @animation/load-browser-stack?
:wallet-stack @animation/load-wallet-stack?))
(defn stack-view
(defn- f-stack-view
[stack-id shared-values]
(when (load-stack? stack-id)
[:f>
(fn []
[reanimated/view
{:style (reanimated/apply-animations-to-style
{:opacity (get shared-values
(get shell.constants/stacks-opacity-keywords stack-id))
:pointer-events (get shared-values
(get shell.constants/stacks-pointer-keywords stack-id))}
{:position :absolute
:top 0
:bottom 0
:left 0
:right 0
:accessibility-label stack-id})}
(case stack-id
:communities-stack [communities/home]
:chats-stack [chat/home]
:wallet-stack [wallet.accounts/accounts-overview]
:browser-stack [browser.stack/browser-stack])])]))
;; TODO lazy loading doesn't work with functional components with hoocks (when (load-stack? stack-id))
;; Error: Rendered more hooks than during the previous render.
[reanimated/view
{:style (reanimated/apply-animations-to-style
{:opacity (get shared-values
(get shell.constants/stacks-opacity-keywords stack-id))
:pointer-events (get shared-values
(get shell.constants/stacks-pointer-keywords stack-id))}
{:position :absolute
:top 0
:bottom 0
:left 0
:right 0
:accessibility-label stack-id})}
(case stack-id
:communities-stack [communities/home]
:chats-stack [chat/home]
:wallet-stack [wallet.accounts/accounts-overview]
:browser-stack [browser.stack/browser-stack])])
(defn home-stack
(defn f-home-stack
[]
[:f>
(fn []
(let [shared-values @animation/shared-values-atom
home-stack-original-style (styles/home-stack @animation/screen-height)
home-stack-animated-style (reanimated/apply-animations-to-style
{:top (:home-stack-top shared-values)
:left (:home-stack-left shared-values)
:opacity (:home-stack-opacity shared-values)
:pointer-events (:home-stack-pointer shared-values)
:transform [{:scale (:home-stack-scale shared-values)}]}
home-stack-original-style)]
[reanimated/view {:style home-stack-animated-style}
[stack-view :communities-stack shared-values]
[stack-view :chats-stack shared-values]
[stack-view :browser-stack shared-values]
[stack-view :wallet-stack shared-values]]))])
(let [shared-values @animation/shared-values-atom
home-stack-original-style (styles/home-stack @animation/screen-height)
home-stack-animated-style (reanimated/apply-animations-to-style
{:top (:home-stack-top shared-values)
:left (:home-stack-left shared-values)
:opacity (:home-stack-opacity shared-values)
:pointer-events (:home-stack-pointer shared-values)
:transform [{:scale (:home-stack-scale shared-values)}]}
home-stack-original-style)]
[reanimated/view {:style home-stack-animated-style}
[:f> f-stack-view :communities-stack shared-values]
[:f> f-stack-view :chats-stack shared-values]
[:f> f-stack-view :browser-stack shared-values]
[:f> f-stack-view :wallet-stack shared-values]]))

View File

@ -23,7 +23,7 @@
{:colors [colors/neutral-100-opa-0 colors/neutral-100-opa-100]
:start {:x 0 :y 0}
:end {:x 0 :y 1}
:style (style/placeholder-container (rn/status-bar-height))}
:style (style/placeholder-container (safe-area/get-top))}
[rn/image
{:source nil ;; TODO(parvesh) - add placeholder image
:style style/placeholder-image}]
@ -44,7 +44,7 @@
[quo/text
{:size :heading-1
:weight :semi-bold
:style (style/jump-to-text (rn/status-bar-height))}
:style (style/jump-to-text (safe-area/get-top))}
(i18n/label :t/jump-to)])
(defn render-card
@ -96,22 +96,21 @@
[]
(let [switcher-cards (rf/sub [:shell/sorted-switcher-cards])
width (rf/sub [:dimensions/window-width])
top (safe-area/get-top)
shell-margin (/ (- width 320) 3)] ;; 320 - two cards width
[safe-area/consumer
(fn [insets]
[rn/view
{:style {:top 0
:left 0
:right 0
:bottom -1
:position :absolute
:background-color colors/neutral-100}}
[jump-to-list switcher-cards shell-margin]
[top-nav-blur-overlay (:top insets)]
[common.home/top-nav
{:type :shell
:style {:margin-top (:top insets)
:z-index 2}}]])]))
[rn/view
{:style {:top 0
:left 0
:right 0
:bottom -1
:position :absolute
:background-color colors/neutral-100}}
[jump-to-list switcher-cards shell-margin]
[top-nav-blur-overlay top]
[common.home/top-nav
{:type :shell
:style {:margin-top top
:z-index 2}}]]))
(defn on-layout
[evt]
@ -133,21 +132,23 @@
(reset! animation/screen-height height)
(async-storage/set-item! :screen-height height))))
(defn f-shell-stack
[]
(let [shared-values (animation/calculate-shared-values)]
[rn/view
{:style {:flex 1}
:on-layout on-layout}
[shell]
[bottom-tabs/bottom-tabs]
[:f> home-stack/f-home-stack]
[quo/floating-shell-button
{:jump-to {:on-press #(animation/close-home-stack true)
:label (i18n/label :t/jump-to)}}
{:position :absolute
:bottom (+ (shell.constants/bottom-tabs-container-height) 7)} ;; bottom offset is 12 = 7 +
;; 5(padding on button)
(:home-stack-opacity shared-values)]]))
(defn shell-stack
[]
[:f>
(fn []
(let [shared-values (animation/calculate-shared-values)]
[rn/view
{:style {:flex 1}
:on-layout on-layout}
[shell]
[bottom-tabs/bottom-tabs]
[home-stack/home-stack]
[quo/floating-shell-button
{:jump-to {:on-press #(animation/close-home-stack true)
:label (i18n/label :t/jump-to)}}
{:position :absolute
:bottom (+ (shell.constants/bottom-tabs-container-height) 7)} ;; bottom offset is 12 = 7 +
;; 5(padding on button)
(:home-stack-opacity shared-values)]]))])
[:f> f-shell-stack])

View File

@ -42,6 +42,10 @@
connection-string
constants/local-pairing-connection-string-identifier)))
(defn f-use-interval
[clock cleanup-clock delay]
(hooks/use-interval clock cleanup-clock delay))
(defn view
[]
(let [valid-for-ms (reagent/atom code-valid-for-ms)
@ -67,82 +71,78 @@
(reset! code nil)
(reset! timestamp nil)
(reset! valid-for-ms code-valid-for-ms))]
[:f>
(fn []
(hooks/use-interval clock
cleanup-clock
@delay)
[safe-area/consumer
(fn [{:keys [top]}]
[rn/view {:style (style/container-main top)}
[rn/scroll-view {}
[navigation-bar]
[rn/view {:style style/page-container}
[rn/view {:style style/title-container}
(fn []
[:f> f-use-interval clock cleanup-clock @delay]
[rn/view {:style (style/container-main (safe-area/get-top))}
[rn/scroll-view {}
[navigation-bar]
[rn/view {:style style/page-container}
[rn/view {:style style/title-container}
[quo/text
{:size :heading-1
:weight :semi-bold
:style {:color colors/white}}
(i18n/label :t/setup-syncing)]]
[rn/view {:style (style/qr-container (valid-cs? @code))}
(if (valid-cs? @code)
[qr-code-viewer/qr-code-view 331 @code]
[quo/qr-code
{:source (resources/get-image :qr-code)
:height 220
:width "100%"}])
(when-not (valid-cs? @code)
[quo/button
{:on-press (fn []
;TODO https://github.com/status-im/status-mobile/issues/15570
;remove old bottom sheet when Authentication process design is created.
(rf/dispatch [:bottom-sheet/hide-old])
(rf/dispatch [:bottom-sheet/show-sheet-old
{:content (fn []
[enter-password/sheet set-code])}]))
:size 40
:style style/generate-button
:before :i/reveal} (i18n/label :t/reveal-sync-code)])
(when (valid-cs? @code)
[rn/view
{:style style/valid-cs-container}
[rn/view
{:style style/sub-text-container}
[quo/text
{:size :heading-1
:weight :semi-bold
:style {:color colors/white}}
(i18n/label :t/setup-syncing)]]
[rn/view {:style (style/qr-container (valid-cs? @code))}
(if (valid-cs? @code)
[qr-code-viewer/qr-code-view 331 @code]
[quo/qr-code
{:source (resources/get-image :qr-code)
:height 220
:width "100%"}])
(when-not (valid-cs? @code)
[quo/button
{:on-press (fn []
;TODO https://github.com/status-im/status-mobile/issues/15570
;remove old bottom sheet when Authentication process design is created.
(rf/dispatch [:bottom-sheet/hide-old])
(rf/dispatch [:bottom-sheet/show-sheet-old
{:content (fn []
[enter-password/sheet set-code])}]))
:size 40
:style style/generate-button
:before :i/reveal} (i18n/label :t/reveal-sync-code)])
(when (valid-cs? @code)
[rn/view
{:style style/valid-cs-container}
[rn/view
{:style style/sub-text-container}
[quo/text
{:size :paragraph-2
:style {:color colors/white-opa-40}}
(i18n/label :t/sync-code)]
[quo/text
{:size :paragraph-2
:style {:color (if (< @valid-for-ms one-min-ms)
colors/danger-60
colors/white-opa-40)}}
(i18n/label :t/valid-for-time {:valid-for (datetime/ms-to-duration @valid-for-ms)})]]
[quo/input
{:default-value @code
:type :password
:override-theme :dark
:default-shown? true
:editable false}]
[quo/button
{:on-press (fn []
(clipboard/set-string @code)
(rf/dispatch [:toasts/upsert
{:icon :correct
:icon-color colors/success-50
:text (i18n/label
:t/sharing-copied-to-clipboard)}]))
:override-theme :dark
:type :grey
:style {:margin-top 12}
:before :i/copy}
(i18n/label :t/copy-qr)]])]]
[rn/view {:style style/sync-code}
[quo/divider-label
{:label (i18n/label :t/have-a-sync-code?)
:increase-padding-top? true}]
[quo/action-drawer
[[{:icon :i/scan
:override-theme :dark
:on-press #(js/alert "to be implemented")
:label (i18n/label :t/Scan-or-enter-sync-code)}]]]]]])])]))
{:size :paragraph-2
:style {:color colors/white-opa-40}}
(i18n/label :t/sync-code)]
[quo/text
{:size :paragraph-2
:style {:color (if (< @valid-for-ms one-min-ms)
colors/danger-60
colors/white-opa-40)}}
(i18n/label :t/valid-for-time {:valid-for (datetime/ms-to-duration @valid-for-ms)})]]
[quo/input
{:default-value @code
:type :password
:override-theme :dark
:default-shown? true
:editable false}]
[quo/button
{:on-press (fn []
(clipboard/set-string @code)
(rf/dispatch [:toasts/upsert
{:icon :correct
:icon-color colors/success-50
:text (i18n/label
:t/sharing-copied-to-clipboard)}]))
:override-theme :dark
:type :grey
:style {:margin-top 12}
:before :i/copy}
(i18n/label :t/copy-qr)]])]]
[rn/view {:style style/sync-code}
[quo/divider-label
{:label (i18n/label :t/have-a-sync-code?)
:increase-padding-top? true}]
[quo/action-drawer
[[{:icon :i/scan
:override-theme :dark
:on-press #(js/alert "to be implemented")
:label (i18n/label :t/Scan-or-enter-sync-code)}]]]]]])))

View File

@ -40,55 +40,52 @@
:z-index 999999999999999999}]))
(defn wrapped-screen-style
[{:keys [top? bottom?]} insets background-color]
[{:keys [top? bottom?]} background-color]
(merge
{:flex 1
:background-color (or background-color (colors/theme-colors colors/white colors/neutral-100))}
(when bottom?
{:padding-bottom (:bottom insets)})
{:padding-bottom (safe-area/get-bottom)})
(when top?
{:padding-top (:top insets)})))
{:padding-top (safe-area/get-top)})))
(defn screen
[key]
(reagent.core/reactify-component
(fn []
(let [{:keys [component options]}
(get (if js/goog.DEBUG (get-screens) screens) (keyword key)) ;; needed for hot reload
{:keys [insets sheet?]} options
background-color (or (get-in options [:layout :backgroundColor])
(when sheet? :transparent))]
(let [{:keys [component options]}
(get (if js/goog.DEBUG (get-screens) screens) (keyword key)) ;; needed for hot reload
{:keys [insets sheet?]} options
background-color (or (get-in options [:layout :backgroundColor])
(when sheet? :transparent))]
(reagent.core/reactify-component
(fn []
^{:key (str "root" key @reloader/cnt)}
[safe-area/provider
[safe-area/consumer
(fn [safe-insets]
[rn/view
{:style (wrapped-screen-style insets safe-insets background-color)}
[inactive]
(if sheet?
[bottom-sheet-screen/view component]
[component])])]
[:<>
[rn/view
{:style (wrapped-screen-style insets background-color)}
[inactive]
(if sheet?
[:f> bottom-sheet-screen/f-view component]
[component])]
(when js/goog.DEBUG
[reloader/reload-view])]))))
(def bottom-sheet
(reagent/reactify-component
(fn []
^{:key (str "sheet" @reloader/cnt)}
[safe-area/provider
[inactive]
[safe-area/consumer
(fn [insets]
(let [{:keys [sheets hide?]} (rf/sub [:bottom-sheet])
sheet (last sheets)]
[rn/keyboard-avoiding-view
{:style {:position :relative :flex 1}
:keyboard-vertical-offset (- (max 20 (:bottom insets)))}
(when sheet
[:f>
bottom-sheet/view
{:insets insets :hide? hide?}
sheet])]))]])))
(let [{:keys [sheets hide?]} (rf/sub [:bottom-sheet])
sheet (last sheets)
insets (safe-area/get-insets)]
^{:key (str "sheet" @reloader/cnt)}
[:<>
[inactive]
[rn/keyboard-avoiding-view
{:style {:position :relative :flex 1}
:keyboard-vertical-offset (- (max 20 (:bottom insets)))}
(when sheet
[:f>
bottom-sheet/view
{:insets insets :hide? hide?}
sheet])]]))))
(def toasts (reagent/reactify-component toasts/toasts))
@ -97,7 +94,7 @@
(reagent/reactify-component
(fn []
^{:key (str "popover" @reloader/cnt)}
[safe-area/provider
[:<>
[inactive]
[popover/popover]
(when js/goog.DEBUG
@ -107,7 +104,7 @@
(reagent/reactify-component
(fn []
^{:key (str "visibility-status-popover" @reloader/cnt)}
[safe-area/provider
[rn/view
[inactive]
[visibility-status-views/visibility-status-popover]
(when js/goog.DEBUG
@ -117,7 +114,7 @@
(reagent/reactify-component
(fn []
^{:key (str "sheet-old" @reloader/cnt)}
[safe-area/provider
[:<>
[inactive]
[bottom-sheets-old/bottom-sheet]])))
@ -125,7 +122,7 @@
(reagent/reactify-component
(fn []
^{:key (str "signing-sheet" @reloader/cnt)}
[safe-area/provider
[:<>
[inactive]
[signing/signing]
(when js/goog.DEBUG
@ -135,7 +132,7 @@
(reagent/reactify-component
(fn []
^{:key (str "select-acc-sheet" @reloader/cnt)}
[safe-area/provider
[:<>
[inactive]
[wallet.send.views/select-account]
(when js/goog.DEBUG
@ -145,7 +142,7 @@
(reagent/reactify-component
(fn []
^{:key (str "wallet-connect-sheet" @reloader/cnt)}
[safe-area/provider
[:<>
[inactive]
[wallet-connect/wallet-connect-proposal-sheet]
(when js/goog.DEBUG
@ -155,7 +152,7 @@
(reagent/reactify-component
(fn []
^{:key (str "wallet-connect-success-sheet" @reloader/cnt)}
[safe-area/provider
[:<>
[inactive]
[wallet-connect/wallet-connect-success-sheet-view]
(when js/goog.DEBUG
@ -165,7 +162,7 @@
(reagent/reactify-component
(fn []
^{:key (str "wallet-connect-app-management-sheet" @reloader/cnt)}
[safe-area/provider
[:<>
[inactive]
[wallet-connect/wallet-connect-app-management-sheet-view]
(when js/goog.DEBUG

View File

@ -12,7 +12,7 @@ module.exports = {
},
testTimeout: 60000,
transformIgnorePatterns: [
'/node_modules/(?!(@react-native|react-native-haptic-feedback|react-native-redash|react-native-image-crop-picker|@react-native-community|react-native-linear-gradient|react-native-background-timer|react-native|rn-emoji-keyboard|react-native-languages|react-native-shake|react-native-reanimated|react-native-redash|react-native-permissions|@react-native-community/blur)/).*/',
'/node_modules/(?!(@react-native|react-native-haptic-feedback|react-native-redash|react-native-image-crop-picker|@react-native-community|react-native-linear-gradient|react-native-background-timer|react-native|rn-emoji-keyboard|react-native-languages|react-native-shake|react-native-reanimated|react-native-redash|react-native-permissions|@react-native-community/blur|react-native-static-safe-area-insets)/).*/',
],
globals: {
__TEST__: true,

View File

@ -8835,11 +8835,6 @@ react-native-redash@^16.0.11:
normalize-svg-path "^1.0.1"
parse-svg-path "^0.1.2"
react-native-safe-area-context@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/react-native-safe-area-context/-/react-native-safe-area-context-2.0.0.tgz#7ef48e5a83a1e2f7fe9d5321493822b6765fd1ab"
integrity sha512-5VtCI3Nluzm7QfTcB/3j4YeWqt25QO1u5KTA1jEg1ckJzV19qCZFyHIpCCkS5+VEX+2JEHfdczhCdwE5sPgyEw==
react-native-safe-modules@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/react-native-safe-modules/-/react-native-safe-modules-1.0.3.tgz#f5f29bb9d09d17581193843d4173ad3054f74890"
@ -8867,6 +8862,11 @@ react-native-share@^7.0.1:
resolved "https://registry.yarnpkg.com/react-native-share/-/react-native-share-7.0.1.tgz#1deef27afcd8275222ba0efeac337e7cea99bc4b"
integrity sha512-hq7nOirgih/zIF9UU9FuYKZ3NGvasu2c/eJesvyPKYiykTtgQZM+mvDwFk/ogEsGwRtTPJBtj8/6IyIFcGa7lw==
react-native-static-safe-area-insets@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/react-native-static-safe-area-insets/-/react-native-static-safe-area-insets-2.2.0.tgz#dd86b6a38f43964fac8df8c0e6bc8e062527786c"
integrity sha512-TLTW2e2kRK3COSK8gMZzwp4wHguFCtcO18itDLn5av/xQblXt9ylu84o+qD9aKJCBfvtNzGOvqqTKqC5GJRZ/g==
"react-native-status-keycard@git+https://github.com/status-im/react-native-status-keycard.git#refs/tags/v2.5.39":
version "2.5.39"
resolved "git+https://github.com/status-im/react-native-status-keycard.git#93dd64754e676172310e6ea7187cc49f2dc013c6"