Onboarding screens (#17165)

* Broken back navigation on "Create profile" screen #17155
Onboarding screens layout is broken
#17152
Onboarding Flow - Layout issues in enable biometrics screen
#17151
Onboarding navigation issues
#17129
This commit is contained in:
flexsurfer 2023-09-05 13:19:15 +02:00 committed by GitHub
parent 7ca17e537e
commit a1babada69
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 95 additions and 150 deletions

View File

@ -2,14 +2,10 @@
(defn container
[container-style]
(merge
{:flex 1
:margin-horizontal 20}
container-style))
(assoc container-style :margin-horizontal 20))
(def title-container
{:flex 1
:flex-direction :row
{:flex-direction :row
:align-items :center})
(def avatar-container

View File

@ -34,8 +34,7 @@
(defn f-video
[{:keys [layers disable-parallax? offset stretch container-style enable-looping?]
:or {offset 50
stretch 0}}]
:or {offset 50 stretch 0}}]
[rn/view
{:style (style/outer-container container-style)}
(map-indexed (fn [idx layer]

View File

@ -0,0 +1,18 @@
(ns status-im2.contexts.onboarding.common.overlay.events
(:require [utils.re-frame :as rf]
[status-im2.contexts.onboarding.common.overlay.view :as overlay]
[status-im2.contexts.profile.profiles.view :as profiles]
[re-frame.core :as re-frame]))
(re-frame/reg-fx
:onboarding/overlay-dismiss-fx
(fn []
(when-let [blur-dismiss-fn @overlay/blur-dismiss-fn-atom]
(blur-dismiss-fn))
(when-let [pop-animation-fn @profiles/pop-animation-fn-atom]
(pop-animation-fn))))
(rf/defn overlay-dismiss
{:events [:onboarding/overlay-dismiss]}
[_]
{:onboarding/overlay-dismiss-fx nil})

View File

@ -35,19 +35,23 @@
0
(/ constants/onboarding-modal-animation-duration 2)
(/ constants/onboarding-modal-animation-duration 2))
(js/clearInterval @timer-interval)
(reset! timer-interval
(js/setInterval
(fn []
(if (> @blur-amount 0)
(swap! blur-amount - 1)
(swap! blur-amount dec)
(js/clearInterval @timer-interval)))
(/ constants/onboarding-modal-animation-duration
max-blur-amount
2))))
;; we had to register it here, because of hotreload, overwise on hotreload it will be reseted
(defonce blur-amount (reagent/atom 0))
(defn f-view
[blur-amount]
(let [opacity (reanimated/use-shared-value 0)
[]
(let [opacity (reanimated/use-shared-value (if (zero? @blur-amount) 0 1))
blur-show-fn #(blur-show opacity blur-amount)
blur-dismiss-fn #(blur-dismiss opacity blur-amount)]
(rn/use-effect
@ -69,5 +73,4 @@
(defn view
[]
(let [blur-amount (reagent/atom 0)]
[:f> f-view blur-amount]))
[:f> f-view])

View File

@ -136,7 +136,7 @@
{:margin-top navigation-bar-top
:background :blur
:icon-name :i/arrow-left
:on-press #(rf/dispatch [:navigate-back])}]
:on-press #(rf/dispatch [:navigate-back-within-stack :new-to-status])}]
[rn/scroll-view
{:on-layout (fn [event]
(let [height (oops/oget event "nativeEvent.layout.height")]

View File

@ -6,7 +6,7 @@
[insets]
{:flex 1
:justify-content :space-between
:padding-top (:top insets)})
:padding-top (+ (:top insets) 56)})
(defn page-illustration
[width]

View File

@ -43,31 +43,23 @@
(defn enable-biometrics-parallax
[]
(let [stretch (if rn/small-screen? 25 40)]
[:<>
[parallax/video
{:layers (:biometrics resources/parallax-video)
:stretch stretch}]
[rn/view
[quo/page-nav {:background :blur}]
[page-title]]]))
[parallax/video
{:layers (:biometrics resources/parallax-video)
:stretch stretch}]))
(defn enable-biometrics-simple
[]
(let [width (:width (rn/get-window))]
[:<>
[rn/view {:flex 1}
[quo/page-nav {:background :blur}]
[page-title]
[rn/view {:style {:flex 1}}
[rn/image
{:resize-mode :contain
:style (style/page-illustration width)
:source (resources/get-image :biometrics)}]]]]))
[rn/image
{:resize-mode :contain
:style (style/page-illustration width)
:source (resources/get-image :biometrics)}]))
(defn enable-biometrics
[]
(let [insets (safe-area/get-insets)]
[rn/view {:style (style/page-container insets)}
[page-title]
(if whitelist/whitelisted?
[enable-biometrics-parallax]
[enable-biometrics-simple])

View File

@ -52,7 +52,7 @@
[quo/page-nav
{:background :blur
:icon-name :i/arrow-left
:on-press #(rf/dispatch [:navigate-back-within-stack :identifiers])}]
:on-press #(rf/dispatch [:navigate-back-within-stack :new-to-status])}]
[page-title]
[rn/view {:style style/page-illustration}
[quo/text

View File

@ -26,8 +26,8 @@
:animated-heading (i18n/label :t/sign-in-by-syncing)
:accessibility-label :already-use-status-button}
:bottom-card {:on-press (fn []
(when @overlay/blur-show-fn-atom
(@overlay/blur-show-fn-atom))
(when-let [blur-show-fn @overlay/blur-show-fn-atom]
(blur-show-fn))
(rf/dispatch [:open-modal :new-to-status]))
:heading (i18n/label :t/new-to-status)
:accessibility-label :new-to-status-button}}

View File

@ -8,17 +8,8 @@
[status-im2.contexts.onboarding.new-to-status.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]
[status-im2.contexts.onboarding.common.overlay.view :as overlay]
[status-im2.contexts.profile.profiles.view :as profiles]
[status-im2.config :as config]))
(defn navigate-back
[]
(when @overlay/blur-dismiss-fn-atom
(@overlay/blur-dismiss-fn-atom))
(when @profiles/pop-animation-fn-atom
(@profiles/pop-animation-fn-atom))
(rf/dispatch [:dismiss-modal :new-to-status]))
[status-im2.config :as config]
re-frame.db))
(defn sign-in-options
[]
@ -107,7 +98,9 @@
:type :no-title
:background :blur
:icon-name :i/arrow-left
:on-press navigate-back
:on-press #(do
(rf/dispatch [:onboarding/overlay-dismiss])
(rf/dispatch [:navigate-back]))
:right-side [{:icon-name :i/info
:on-press #(rf/dispatch [:show-bottom-sheet
{:content getting-started-doc

View File

@ -3,11 +3,6 @@
[status-im2.contexts.onboarding.common.background.view :as background]
[status-im2.contexts.syncing.scan-sync-code.view :as scan-sync-code]))
(defn navigate-back
[]
(when @scan-sync-code/navigate-back-fn
(@scan-sync-code/navigate-back-fn)))
(defn view
[]
[scan-sync-code/view

View File

@ -20,10 +20,13 @@
(defonce push-animation-fn-atom (atom nil))
(defonce pop-animation-fn-atom (atom nil))
;; we need this for hotreload, overwise on hotreload translate-x will be reseted
(defonce translate-x-atom (atom 0))
(defn push-animation
[translate-x]
(let [window-width (:width (rn/get-window))]
(reset! translate-x-atom (- window-width))
(reanimated/animate-shared-value-with-delay translate-x
(- window-width)
constants/onboarding-modal-animation-duration
@ -32,6 +35,7 @@
(defn pop-animation
[translate-x]
(reset! translate-x-atom 0)
(reanimated/animate-shared-value-with-delay translate-x
0
constants/onboarding-modal-animation-duration
@ -126,7 +130,7 @@
(defn- f-profiles-section
[{:keys [set-hide-profiles]}]
(let [profiles (vals (rf/sub [:profile/profiles-overview]))
translate-x (reanimated/use-shared-value 0)]
translate-x (reanimated/use-shared-value @translate-x-atom)]
(rn/use-effect (fn []
(reset! push-animation-fn-atom #(push-animation translate-x))
(reset! pop-animation-fn-atom #(pop-animation translate-x))
@ -305,10 +309,12 @@
:container-style {:margin-bottom (+ (safe-area/get-bottom) 12)}}
(i18n/label :t/log-in)]]))
;; we had to register it here, because of hotreload, overwise on hotreload it will be reseted
(defonce show-profiles? (reagent/atom false))
(defn view
[]
(let [show-profiles? (reagent/atom false)
set-show-profiles #(reset! show-profiles? true)
(let [set-show-profiles #(reset! show-profiles? true)
set-hide-profiles #(reset! show-profiles? false)]
(fn []
[:<>

View File

@ -17,7 +17,6 @@
[status-im2.contexts.syncing.scan-sync-code.animation :as animation]
[status-im2.contexts.syncing.scan-sync-code.style :as style]
[status-im2.contexts.syncing.utils :as sync-utils]
[status-im2.navigation.util :as navigation.util]
[utils.debounce :as debounce]
[utils.i18n :as i18n]
[utils.re-frame :as rf]
@ -28,7 +27,6 @@
(defonce camera-permission-granted? (reagent/atom false))
(defonce dismiss-animations (atom nil))
(defonce navigate-back-fn (atom nil))
(defn perform-preflight-check
"Performing the check for the first time
@ -290,6 +288,7 @@
(defn f-view
[_]
(let [insets (safe-area/get-insets)
qr-code-succeed? (reagent/atom false)
active-tab (reagent/atom 1)
qr-view-finder (reagent/atom {})
render-camera? (reagent/atom false)
@ -298,8 +297,7 @@
set-rescan-timeout (fn []
(reset! scan-code? false)
(js/setTimeout #(reset! scan-code? true) 3000))]
(fn [{:keys [title show-bottom-view? background animated? qr-code-succeed?
set-qr-code-succeeded]}]
(fn [{:keys [title show-bottom-view? background animated?]}]
(let [torch-mode (if @torch? :on :off)
flashlight-icon (if @torch? :i/flashlight-on :i/flashlight-off)
scan-qr-code-tab? (= @active-tab 1)
@ -309,7 +307,7 @@
(boolean (not-empty @qr-view-finder)))
camera-ready-to-scan? (and (or (not animated?) @render-camera?)
show-camera?
(not qr-code-succeed?))
(not @qr-code-succeed?))
title-opacity (reanimated/use-shared-value (if animated? 0 1))
subtitle-opacity (reanimated/use-shared-value (if animated? 0 1))
content-opacity (reanimated/use-shared-value (if animated? 0 1))
@ -322,10 +320,16 @@
:content-opacity content-opacity
:subtitle-opacity subtitle-opacity
:title-opacity title-opacity})]
(rn/use-effect
#(set-listener-torch-off-on-app-inactive torch?))
(when animated?
(rn/use-effect
(fn []
(rn/hw-back-add-listener reset-animations-fn)
#(rn/hw-back-remove-listener reset-animations-fn))
[])
(animation/animate-subtitle subtitle-opacity)
(animation/animate-title title-opacity)
(animation/animate-bottom bottom-view-translate-y))
@ -337,8 +341,7 @@
(js/setTimeout #(reset! render-camera? true)
(+ constants/onboarding-modal-animation-duration
constants/onboarding-modal-animation-delay
300))
(reset! navigate-back-fn reset-animations-fn))
300)))
(when-not @camera-permission-granted?
(permissions/permission-granted? :camera
#(reset! camera-permission-granted? %)
@ -350,7 +353,7 @@
{:torch-mode torch-mode
:qr-view-finder @qr-view-finder
:scan-code? @scan-code?
:set-qr-code-succeeded set-qr-code-succeeded
:set-qr-code-succeeded #(reset! qr-code-succeed? true)
:set-rescan-timeout set-rescan-timeout}])
[rn/view {:style (style/root-container (:top insets))}
[:f> header
@ -389,14 +392,5 @@
flashlight-icon])]]))))
(defn view
[{:keys [screen-name] :as _props}]
(let [qr-code-succeed? (reagent/atom false)]
(navigation.util/create-class-and-bind
screen-name
{:component-did-appear (fn set-qr-code-failed [_this]
(reset! qr-code-succeed? false))}
(fn [props]
(let [new-pops (assoc props
:qr-code-succeed? @qr-code-succeed?
:set-qr-code-succeeded #(reset! qr-code-succeed? true))]
[:f> f-view new-pops])))))
[props]
[:f> f-view props])

View File

@ -14,6 +14,7 @@
status-im2.contexts.profile.events
status-im2.contexts.shell.share.events
status-im2.contexts.syncing.events
status-im2.contexts.onboarding.common.overlay.events
[status-im2.db :as db]
[utils.re-frame :as rf]))

View File

@ -48,8 +48,12 @@
(navigation/reg-component-did-appear-listener
(fn [view-id]
(when (get views/screens view-id)
(set-view-id view-id)
;;NOTE when back from the background on Android, this event happens for all screens, but we need
;;only for active one
(when (and @state/curr-modal (= @state/curr-modal view-id))
(set-view-id view-id))
(when-not @state/curr-modal
(set-view-id view-id)
(reset! state/pushed-screen-id view-id)))))
(defn dissmissModal
@ -167,18 +171,11 @@
(navigation/reg-button-pressed-listener
(fn [id]
(cond
(= "dismiss-modal" id)
(if (= "dismiss-modal" id)
(do
(when-let [event (get-in views/screens [(last @state/modals) :on-dissmiss])]
(re-frame/dispatch event))
(dissmissModal))
(= "RNN.hardwareBackButton" id)
(when-let [handler (get-in views/screens
[(or (last @state/modals) @state/pushed-screen-id)
:hardware-back-button-handler])]
(handler))
:else
(when-let [handler (get-in views/screens [(keyword id) :right-handler])]
(handler)))))

View File

@ -118,25 +118,24 @@
;; Onboarding
{:name :intro
:options {:theme :dark}
:on-focus [:onboarding/overlay-dismiss]
:component intro/view}
{:name :profiles
:options {:theme :dark
:layout options/onboarding-layout}
:on-focus [:onboarding/overlay-dismiss]
:component profiles/view}
{:name :new-to-status
:options {:theme :dark
:layout options/onboarding-transparent-layout
:animations (merge
transitions/new-to-status-modal-animations
transitions/push-animations-for-transparent-background)
:popGesture false
:modalPresentationStyle :overCurrentContext
:hardwareBackButton {:dismissModalOnPress false
:popStackOnPress false}}
:hardware-back-button-handler new-to-status/navigate-back
:component new-to-status/new-to-status}
{:name :new-to-status
:options {:theme :dark
:layout options/onboarding-transparent-layout
:animations (merge
transitions/new-to-status-modal-animations
transitions/push-animations-for-transparent-background)
:popGesture false
:modalPresentationStyle :overCurrentContext}
:component new-to-status/new-to-status}
{:name :create-profile
:options {:theme :dark
@ -181,10 +180,7 @@
:layout options/onboarding-transparent-layout
:animations (merge transitions/new-to-status-modal-animations
transitions/push-animations-for-transparent-background)
:modalPresentationStyle :overCurrentContext
:popGesture false
:hardwareBackButton {:dismissModalOnPress false
:popStackOnPress false}}
:modalPresentationStyle :overCurrentContext}
:component enable-notifications/enable-notifications}
{:name :identifiers
@ -200,16 +196,13 @@
:options options/dark-screen
:component scan-sync-code-page/view}
{:name :sign-in-intro
:options {:layout options/onboarding-transparent-layout
:animations (merge
transitions/sign-in-modal-animations
transitions/push-animations-for-transparent-background)
:modalPresentationStyle :overCurrentContext
:hardwareBackButton {:dismissModalOnPress false
:popStackOnPress false}}
:hardware-back-button-handler sign-in/navigate-back
:component sign-in/animated-view}
{:name :sign-in-intro
:options {:layout options/onboarding-transparent-layout
:animations (merge
transitions/sign-in-modal-animations
transitions/push-animations-for-transparent-background)
:modalPresentationStyle :overCurrentContext}
:component sign-in/animated-view}
{:name :sign-in
:options {:theme :dark

View File

@ -1,42 +0,0 @@
(ns status-im2.navigation.util
(:require [react-native.navigation :as navigation]
[reagent.core :as reagent]))
(defn create-class-and-bind
"Creates a React class that allows the use of life-cycle methods added by
react-native-navigation:
- componentWillAppear
- componentDidAppear
- componentDidDisappear
Receives:
- `component-id` - The component-id to subscribe registered in navigation
- `react-methods` - A map of React methods (kebab-case) -> function handler
- `reagent-render` - A regular reagent function that returns hiccup.
Example:
(defn view
[props & children]
;; Bindings executed when component is created
(let [qr-code-succeed? (reagent/atom false)]
(create-class-and-bind
\"sign-in-intro\" ; navigation component-id of the screen to subscribe
{:component-did-appear (fn [this]
;; Executed when component appeared to the screen
)
:component-will-appear (fn [this]
;; Executed when component will be shown to the screen
)
:component-did-disappear (fn [this]
;; Executed when component disappeared from the screen
)}
(fn [props & children] ; Must be the same signature as this `view` function
;; Regular component call, e.g.:
[rn/view {:style {:padding-top 10}}
[:f> my-f-component-call (assoc props :on-press identity)]
children]))))
"
[component-id react-methods reagent-render]
(reagent/create-class
(assoc react-methods
:display-name (str component-id "-view")
:component-did-mount #(navigation/bind-component % component-id)
:reagent-render reagent-render)))