mirror of
https://github.com/status-im/status-react.git
synced 2025-01-11 03:26:31 +00:00
[Feature] Sign in by scanning sync QR code (#15416)
This commit is contained in:
parent
2f19badc6c
commit
7d4be37111
@ -19,7 +19,7 @@
|
|||||||
"@babel/preset-typescript": "^7.17.12",
|
"@babel/preset-typescript": "^7.17.12",
|
||||||
"@react-native-async-storage/async-storage": "^1.17.9",
|
"@react-native-async-storage/async-storage": "^1.17.9",
|
||||||
"@react-native-community/audio-toolkit": "git+https://github.com/tbenr/react-native-audio-toolkit.git#refs/tags/v2.0.3-status-v6",
|
"@react-native-community/audio-toolkit": "git+https://github.com/tbenr/react-native-audio-toolkit.git#refs/tags/v2.0.3-status-v6",
|
||||||
"@react-native-community/blur": "git+https://github.com/status-im/react-native-blur#refs/tags/v4.3.1-status",
|
"@react-native-community/blur": "git+https://github.com/status-im/react-native-blur#refs/tags/v4.3.2-status",
|
||||||
"@react-native-community/cameraroll": "git+https://github.com/status-im/react-native-cameraroll.git#refs/tags/v4.0.4-status.0",
|
"@react-native-community/cameraroll": "git+https://github.com/status-im/react-native-cameraroll.git#refs/tags/v4.0.4-status.0",
|
||||||
"@react-native-community/clipboard": "^1.2.2",
|
"@react-native-community/clipboard": "^1.2.2",
|
||||||
"@react-native-community/hooks": "^2.5.1",
|
"@react-native-community/hooks": "^2.5.1",
|
||||||
|
@ -5,6 +5,10 @@
|
|||||||
[react-native.core :as rn]
|
[react-native.core :as rn]
|
||||||
[reagent.core :as reagent]))
|
[reagent.core :as reagent]))
|
||||||
|
|
||||||
|
(def themes-for-blur
|
||||||
|
{:light {:background-color colors/neutral-80-opa-5}
|
||||||
|
:dark {:background-color colors/white-opa-5}})
|
||||||
|
|
||||||
(def themes
|
(def themes
|
||||||
{:light {:background-color colors/neutral-20}
|
{:light {:background-color colors/neutral-20}
|
||||||
:dark {:background-color colors/neutral-80}})
|
:dark {:background-color colors/neutral-80}})
|
||||||
@ -12,11 +16,12 @@
|
|||||||
(defn segmented-control
|
(defn segmented-control
|
||||||
[{:keys [default-active on-change]}]
|
[{:keys [default-active on-change]}]
|
||||||
(let [active-tab-id (reagent/atom default-active)]
|
(let [active-tab-id (reagent/atom default-active)]
|
||||||
(fn [{:keys [data size]}]
|
(fn [{:keys [data size override-theme blur?]}]
|
||||||
(let [active-id @active-tab-id]
|
(let [active-id @active-tab-id]
|
||||||
[rn/view
|
[rn/view
|
||||||
{:flex-direction :row
|
{:flex-direction :row
|
||||||
:background-color (get-in themes [(theme/get-theme) :background-color])
|
:background-color (get-in (if blur? themes-for-blur themes)
|
||||||
|
[(or override-theme (theme/get-theme)) :background-color])
|
||||||
:border-radius (case size
|
:border-radius (case size
|
||||||
32 10
|
32 10
|
||||||
28 8
|
28 8
|
||||||
@ -32,6 +37,8 @@
|
|||||||
{:id id
|
{:id id
|
||||||
:segmented? true
|
:segmented? true
|
||||||
:size size
|
:size size
|
||||||
|
:override-theme override-theme
|
||||||
|
:blur? blur?
|
||||||
:active (= id active-id)
|
:active (= id active-id)
|
||||||
:on-press (fn [tab-id]
|
:on-press (fn [tab-id]
|
||||||
(reset! active-tab-id tab-id)
|
(reset! active-tab-id tab-id)
|
||||||
|
@ -79,10 +79,11 @@
|
|||||||
[notification-dot/notification-dot
|
[notification-dot/notification-dot
|
||||||
{:style style/notification-dot}])
|
{:style style/notification-dot}])
|
||||||
[rn/view
|
[rn/view
|
||||||
{:style (style/tab {:size size
|
{:style (style/tab
|
||||||
|
{:size size
|
||||||
:disabled disabled
|
:disabled disabled
|
||||||
:segmented? segmented?
|
:segmented? segmented?
|
||||||
:background-color background-color
|
:background-color (if (and segmented? (not active)) :transparent background-color)
|
||||||
:show-notification-dot? show-notification-dot?})}
|
:show-notification-dot? show-notification-dot?})}
|
||||||
(when before
|
(when before
|
||||||
[rn/view
|
[rn/view
|
||||||
|
@ -60,6 +60,7 @@
|
|||||||
quo2.components.settings.accounts.view
|
quo2.components.settings.accounts.view
|
||||||
quo2.components.settings.privacy-option
|
quo2.components.settings.privacy-option
|
||||||
quo2.components.onboarding.small-option-card.view
|
quo2.components.onboarding.small-option-card.view
|
||||||
|
quo2.components.tabs.segmented-tab
|
||||||
quo2.components.tabs.account-selector
|
quo2.components.tabs.account-selector
|
||||||
quo2.components.tabs.tabs
|
quo2.components.tabs.tabs
|
||||||
quo2.components.tags.context-tags
|
quo2.components.tags.context-tags
|
||||||
@ -91,6 +92,7 @@
|
|||||||
(def audio-tag quo2.components.tags.context-tags/audio-tag)
|
(def audio-tag quo2.components.tags.context-tags/audio-tag)
|
||||||
(def community-tag quo2.components.tags.context-tags/community-tag)
|
(def community-tag quo2.components.tags.context-tags/community-tag)
|
||||||
(def tabs quo2.components.tabs.tabs/tabs)
|
(def tabs quo2.components.tabs.tabs/tabs)
|
||||||
|
(def segmented-control quo2.components.tabs.segmented-tab/segmented-control)
|
||||||
(def account-selector quo2.components.tabs.account-selector/account-selector)
|
(def account-selector quo2.components.tabs.account-selector/account-selector)
|
||||||
(def floating-shell-button quo2.components.navigation.floating-shell-button/floating-shell-button)
|
(def floating-shell-button quo2.components.navigation.floating-shell-button/floating-shell-button)
|
||||||
(def page-nav quo2.components.navigation.page-nav/page-nav)
|
(def page-nav quo2.components.navigation.page-nav/page-nav)
|
||||||
|
5
src/react_native/camera_kit.cljs
Normal file
5
src/react_native/camera_kit.cljs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
(ns react-native.camera-kit
|
||||||
|
(:require ["react-native-camera-kit" :refer (CameraKitCamera)]
|
||||||
|
[reagent.core :as reagent]))
|
||||||
|
|
||||||
|
(def camera (reagent/adapt-react-class CameraKitCamera))
|
@ -481,6 +481,9 @@
|
|||||||
"Decides which root should be initialised depending on user and app state"
|
"Decides which root should be initialised depending on user and app state"
|
||||||
[db]
|
[db]
|
||||||
(cond
|
(cond
|
||||||
|
(get db :local-pairing/completed-pairing?)
|
||||||
|
(re-frame/dispatch [:syncing/pairing-completed])
|
||||||
|
|
||||||
(get db :onboarding-2/new-account?)
|
(get db :onboarding-2/new-account?)
|
||||||
(re-frame/dispatch [:navigate-to :enable-notifications])
|
(re-frame/dispatch [:navigate-to :enable-notifications])
|
||||||
|
|
||||||
|
@ -9,7 +9,10 @@
|
|||||||
[status-im.visibility-status-updates.core :as visibility-status-updates]
|
[status-im.visibility-status-updates.core :as visibility-status-updates]
|
||||||
[utils.re-frame :as rf]
|
[utils.re-frame :as rf]
|
||||||
[status-im2.contexts.chat.messages.link-preview.events :as link-preview]
|
[status-im2.contexts.chat.messages.link-preview.events :as link-preview]
|
||||||
[taoensso.timbre :as log]))
|
[taoensso.timbre :as log]
|
||||||
|
[status-im2.constants :as constants]
|
||||||
|
[quo2.foundations.colors :as colors]
|
||||||
|
[status-im.multiaccounts.model :as multiaccounts.model]))
|
||||||
|
|
||||||
(rf/defn status-node-started
|
(rf/defn status-node-started
|
||||||
[{db :db :as cofx} {:keys [error]}]
|
[{db :db :as cofx} {:keys [error]}]
|
||||||
@ -53,10 +56,40 @@
|
|||||||
:peer-stats peer-stats
|
:peer-stats peer-stats
|
||||||
:peers-count (count (:peers peer-stats)))}))
|
:peers-count (count (:peers peer-stats)))}))
|
||||||
|
|
||||||
(defn handle-local-pairing-signals
|
(rf/defn handle-local-pairing-signals
|
||||||
[event]
|
[{:keys [db] :as cofx} event]
|
||||||
(log/debug "local pairing signal received"
|
(log/info "local pairing signal received"
|
||||||
{:event event}))
|
{:event event})
|
||||||
|
(let [connection-success? (= (:type event)
|
||||||
|
constants/local-pairing-event-connection-success)
|
||||||
|
error-on-pairing? (contains? constants/local-pairing-event-errors (:type event))
|
||||||
|
completed-pairing? (and (= (:type event)
|
||||||
|
constants/local-pairing-event-process-success)
|
||||||
|
(= (:action event)
|
||||||
|
constants/local-pairing-action-pairing-account))
|
||||||
|
logged-in? (multiaccounts.model/logged-in? cofx)
|
||||||
|
;; since `connection-success` event is received on both sender and receiver devices
|
||||||
|
;; we check the `logged-in?` status to identify the receiver and take the user to next screen
|
||||||
|
navigate-to-syncing-devices? (and connection-success? (not logged-in?))
|
||||||
|
user-in-syncing-devices-screen? (= (:view-id db) :syncing-devices)]
|
||||||
|
(merge {:db (cond-> db
|
||||||
|
connection-success?
|
||||||
|
(assoc :local-pairing/completed-pairing? false)
|
||||||
|
|
||||||
|
error-on-pairing?
|
||||||
|
(dissoc :local-pairing/completed-pairing?)
|
||||||
|
|
||||||
|
completed-pairing?
|
||||||
|
(assoc :local-pairing/completed-pairing? true))}
|
||||||
|
(when navigate-to-syncing-devices?
|
||||||
|
{:dispatch [:navigate-to :syncing-devices]})
|
||||||
|
(when (and error-on-pairing? user-in-syncing-devices-screen?)
|
||||||
|
{:dispatch-n [[:toasts/upsert
|
||||||
|
{:icon :i/info
|
||||||
|
:icon-color colors/danger-50
|
||||||
|
:override-theme :light
|
||||||
|
:text (i18n/label :t/error-syncing-connection-failed)}]
|
||||||
|
[:navigate-back]]}))))
|
||||||
|
|
||||||
(rf/defn process
|
(rf/defn process
|
||||||
{:events [:signals/signal-received]}
|
{:events [:signals/signal-received]}
|
||||||
@ -110,5 +143,6 @@
|
|||||||
"status.updates.timedout" (visibility-status-updates/handle-visibility-status-updates
|
"status.updates.timedout" (visibility-status-updates/handle-visibility-status-updates
|
||||||
cofx
|
cofx
|
||||||
(js->clj event-js :keywordize-keys true))
|
(js->clj event-js :keywordize-keys true))
|
||||||
"localPairing" (handle-local-pairing-signals (js->clj event-js :keywordize-keys true))
|
"localPairing" (handle-local-pairing-signals cofx
|
||||||
|
(js->clj event-js :keywordize-keys true))
|
||||||
(log/debug "Event " type " not handled"))))
|
(log/debug "Event " type " not handled"))))
|
||||||
|
@ -263,6 +263,27 @@
|
|||||||
An example of a connection string is -> cs2:5vd6J6:Jfc:27xMmHKEYwzRGXcvTtuiLZFfXscMx4Mz8d9wEHUxDj4p7:EG7Z13QScfWBJNJ5cprszzDQ5fBVsYMirXo8MaQFJvpF:3 "
|
An example of a connection string is -> cs2:5vd6J6:Jfc:27xMmHKEYwzRGXcvTtuiLZFfXscMx4Mz8d9wEHUxDj4p7:EG7Z13QScfWBJNJ5cprszzDQ5fBVsYMirXo8MaQFJvpF:3 "
|
||||||
"cs")
|
"cs")
|
||||||
|
|
||||||
|
;; sender and receiver events
|
||||||
|
(def ^:const local-pairing-event-connection-success "connection-success")
|
||||||
|
(def ^:const local-pairing-event-connection-error "connection-error")
|
||||||
|
(def ^:const local-pairing-event-transfer-success "transfer-success")
|
||||||
|
(def ^:const local-pairing-event-transfer-error "transfer-error")
|
||||||
|
|
||||||
|
;; receiver events
|
||||||
|
(def ^:const local-pairing-event-received-amount "received-account")
|
||||||
|
(def ^:const local-pairing-event-process-success "process-success")
|
||||||
|
(def ^:const local-pairing-event-process-error "process-error")
|
||||||
|
|
||||||
|
(def ^:const local-pairing-event-errors
|
||||||
|
#{local-pairing-event-connection-error
|
||||||
|
local-pairing-event-transfer-error
|
||||||
|
local-pairing-event-process-error})
|
||||||
|
|
||||||
|
(def ^:const local-pairing-action-connect 1)
|
||||||
|
(def ^:const local-pairing-action-pairing-account 2)
|
||||||
|
(def ^:const local-pairing-action-sync-device 3)
|
||||||
|
(def ^:const local-pairing-action-pairing-installation 4)
|
||||||
|
|
||||||
(def ^:const serialization-key
|
(def ^:const serialization-key
|
||||||
"We pass this serialization key as a parameter to MultiformatSerializePublicKey
|
"We pass this serialization key as a parameter to MultiformatSerializePublicKey
|
||||||
function at status-go, This key determines the output base of the serialization.
|
function at status-go, This key determines the output base of the serialization.
|
||||||
|
@ -1,14 +1,92 @@
|
|||||||
(ns status-im2.contexts.onboarding.sign-in.style
|
(ns status-im2.contexts.onboarding.sign-in.style
|
||||||
(:require [quo2.foundations.colors :as colors]
|
(:require [quo2.foundations.colors :as colors]))
|
||||||
[react-native.platform :as platform]))
|
|
||||||
|
|
||||||
(def navigation-bar {:height 56})
|
(def screen-padding 20)
|
||||||
|
|
||||||
(def page-container
|
(def flex-spacer {:flex 1})
|
||||||
{:padding-top (if platform/ios? 44 0)
|
|
||||||
:position :absolute
|
(def absolute-fill
|
||||||
|
{:position :absolute
|
||||||
:top 0
|
:top 0
|
||||||
:bottom 0
|
:bottom 0
|
||||||
:left 0
|
:left 0
|
||||||
:right 0
|
:right 0})
|
||||||
:background-color colors/neutral-80-opa-80-blur})
|
|
||||||
|
(defn root-container
|
||||||
|
[padding-top]
|
||||||
|
{:flex 1
|
||||||
|
:padding-top padding-top})
|
||||||
|
|
||||||
|
(def header-container
|
||||||
|
{:flex-direction :row
|
||||||
|
:justify-content :space-between
|
||||||
|
:padding-horizontal screen-padding
|
||||||
|
:margin-vertical 12})
|
||||||
|
|
||||||
|
(def header-text
|
||||||
|
{:padding-horizontal screen-padding
|
||||||
|
:padding-top 12
|
||||||
|
:padding-bottom 8
|
||||||
|
:color colors/white})
|
||||||
|
|
||||||
|
(def header-sub-text
|
||||||
|
{:padding-horizontal screen-padding
|
||||||
|
:color colors/white})
|
||||||
|
|
||||||
|
(def tabs-container
|
||||||
|
{:padding-horizontal screen-padding
|
||||||
|
:margin-top 20})
|
||||||
|
|
||||||
|
(def scan-qr-code-container
|
||||||
|
{:margin-top 19})
|
||||||
|
|
||||||
|
(def qr-view-finder
|
||||||
|
{:margin-horizontal screen-padding
|
||||||
|
:height 1
|
||||||
|
:display :flex})
|
||||||
|
|
||||||
|
(defn viewfinder-container
|
||||||
|
[viewfinder]
|
||||||
|
{:position :absolute
|
||||||
|
:left (:x viewfinder)
|
||||||
|
:top (:y viewfinder)})
|
||||||
|
|
||||||
|
(def viewfinder-text
|
||||||
|
{:color colors/white-opa-70
|
||||||
|
:text-align :center
|
||||||
|
:padding-top 16})
|
||||||
|
|
||||||
|
(def camera-permission-container
|
||||||
|
{:height 335
|
||||||
|
:margin-horizontal screen-padding
|
||||||
|
:background-color colors/white-opa-5
|
||||||
|
:border-color colors/white-opa-10
|
||||||
|
:border-radius 12
|
||||||
|
:align-items :center
|
||||||
|
:justify-content :center})
|
||||||
|
|
||||||
|
(def enable-camera-access-header
|
||||||
|
{:color colors/white})
|
||||||
|
|
||||||
|
(def enable-camera-access-sub-text
|
||||||
|
{:color colors/white-opa-70
|
||||||
|
:margin-bottom 16})
|
||||||
|
|
||||||
|
(def enter-sync-code-container
|
||||||
|
{:margin-top 20
|
||||||
|
:justify-content :center
|
||||||
|
:align-items :center})
|
||||||
|
|
||||||
|
(defn bottom-container
|
||||||
|
[padding-bottom]
|
||||||
|
{:padding-top 12
|
||||||
|
:padding-bottom padding-bottom
|
||||||
|
:background-color colors/white-opa-5
|
||||||
|
:border-top-left-radius 20
|
||||||
|
:border-top-right-radius 20
|
||||||
|
:align-items :center
|
||||||
|
:justify-content :center})
|
||||||
|
|
||||||
|
(def bottom-text
|
||||||
|
{:color colors/white
|
||||||
|
:padding-bottom 12})
|
||||||
|
@ -1,42 +1,234 @@
|
|||||||
(ns status-im2.contexts.onboarding.sign-in.view
|
(ns status-im2.contexts.onboarding.sign-in.view
|
||||||
(:require [quo2.core :as quo]
|
(:require [clojure.string :as string]
|
||||||
|
[oops.core :as oops]
|
||||||
|
[quo2.core :as quo]
|
||||||
[quo2.foundations.colors :as colors]
|
[quo2.foundations.colors :as colors]
|
||||||
|
[react-native.blur :as blur]
|
||||||
|
[react-native.camera-kit :as camera-kit]
|
||||||
[react-native.core :as rn]
|
[react-native.core :as rn]
|
||||||
|
[react-native.hole-view :as hole-view]
|
||||||
|
[react-native.permissions :as permissions]
|
||||||
|
[react-native.platform :as platform]
|
||||||
|
[react-native.safe-area :as safe-area]
|
||||||
|
[reagent.core :as reagent]
|
||||||
|
[status-im2.common.resources :as resources]
|
||||||
|
[status-im2.constants :as constants]
|
||||||
[status-im2.contexts.onboarding.sign-in.style :as style]
|
[status-im2.contexts.onboarding.sign-in.style :as style]
|
||||||
[utils.i18n :as i18n]
|
[utils.i18n :as i18n]
|
||||||
[status-im2.contexts.onboarding.common.background.view :as background]
|
|
||||||
[utils.re-frame :as rf]))
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(defn navigation-bar
|
(defonce camera-permission-granted? (reagent/atom false))
|
||||||
[]
|
|
||||||
[rn/view {:style style/navigation-bar}
|
|
||||||
[quo/page-nav
|
|
||||||
{:align-mid? true
|
|
||||||
:mid-section {:type :text-only :main-text ""}
|
|
||||||
:left-section {:type :blur-bg
|
|
||||||
:icon :i/arrow-left
|
|
||||||
:icon-override-theme :dark
|
|
||||||
:on-press #(rf/dispatch [:navigate-back])}
|
|
||||||
:right-section-buttons [{:type :blur-bg
|
|
||||||
:icon :i/info
|
|
||||||
:icon-override-theme :dark
|
|
||||||
:on-press #(js/alert "Pending")}]}]])
|
|
||||||
|
|
||||||
(defn page
|
(defn- header
|
||||||
[]
|
[active-tab read-qr-once?]
|
||||||
[rn/view {:style style/page-container}
|
[:<>
|
||||||
[navigation-bar]
|
[rn/view {:style style/header-container}
|
||||||
[rn/view {:style {:padding-horizontal 20}}
|
[quo/button
|
||||||
|
{:icon true
|
||||||
|
:type :blur-bg
|
||||||
|
:size 32
|
||||||
|
:accessibility-label :close-sign-in-by-syncing
|
||||||
|
:override-theme :dark
|
||||||
|
:on-press #(rf/dispatch [:navigate-back])}
|
||||||
|
:i/close]
|
||||||
|
[quo/button
|
||||||
|
{:before :i/info
|
||||||
|
:type :blur-bg
|
||||||
|
:size 32
|
||||||
|
:accessibility-label :find-sync-code
|
||||||
|
:override-theme :dark
|
||||||
|
:on-press #(js/alert "Yet to be implemented")}
|
||||||
|
(i18n/label :t/find-sync-code)]]
|
||||||
[quo/text
|
[quo/text
|
||||||
{:size :heading-1
|
{:size :heading-1
|
||||||
:weight :semi-bold
|
:weight :semi-bold
|
||||||
:style {:color colors/white}} "Sign in by syncing"]
|
:style style/header-text}
|
||||||
[quo/button
|
(i18n/label :t/sign-in-by-syncing)]
|
||||||
{:on-press #(rf/dispatch [:navigate-to :syncing-devices])
|
[quo/text
|
||||||
:style {}} (i18n/label :t/continue)]]])
|
{:size :paragraph-1
|
||||||
|
:weight :regular
|
||||||
|
:style style/header-sub-text}
|
||||||
|
(i18n/label :t/synchronise-your-data-across-your-devices)]
|
||||||
|
[rn/view {:style style/tabs-container}
|
||||||
|
[quo/segmented-control
|
||||||
|
{:size 32
|
||||||
|
:override-theme :dark
|
||||||
|
:blur? true
|
||||||
|
:default-active @active-tab
|
||||||
|
:data [{:id 1 :label (i18n/label :t/scan-sync-qr-code)}
|
||||||
|
{:id 2 :label (i18n/label :t/enter-sync-code)}]
|
||||||
|
:on-change (fn [id]
|
||||||
|
(reset! active-tab id)
|
||||||
|
(reset! read-qr-once? false))}]]])
|
||||||
|
|
||||||
(defn sign-in
|
(defn- camera-permission-view
|
||||||
|
[request-camera-permission]
|
||||||
|
[rn/view {:style style/camera-permission-container}
|
||||||
|
[quo/text
|
||||||
|
{:size :paragraph-1
|
||||||
|
:weight :medium
|
||||||
|
:style style/enable-camera-access-header}
|
||||||
|
(i18n/label :t/enable-access-to-camera)]
|
||||||
|
[quo/text
|
||||||
|
{:size :paragraph-2
|
||||||
|
:weight :regular
|
||||||
|
:style style/enable-camera-access-sub-text}
|
||||||
|
(i18n/label :t/to-scan-a-qr-enable-your-camera)]
|
||||||
|
[quo/button
|
||||||
|
{:before :i/camera
|
||||||
|
:type :primary
|
||||||
|
:size 32
|
||||||
|
:accessibility-label :request-camera-permission
|
||||||
|
:override-theme :dark
|
||||||
|
:on-press request-camera-permission}
|
||||||
|
(i18n/label :t/enable-camera)]])
|
||||||
|
|
||||||
|
(defn- qr-scan-hole-area
|
||||||
|
[qr-view-finder]
|
||||||
|
[rn/view
|
||||||
|
{:style style/qr-view-finder
|
||||||
|
:on-layout (fn [event]
|
||||||
|
(let [layout (js->clj (oops/oget event "nativeEvent.layout")
|
||||||
|
:keywordize-keys
|
||||||
|
true)
|
||||||
|
view-finder (assoc layout :height (:width layout))]
|
||||||
|
(reset! qr-view-finder view-finder)))}])
|
||||||
|
|
||||||
|
(defn- border
|
||||||
|
[border1 border2 corner]
|
||||||
|
[rn/view
|
||||||
|
(assoc {:border-color colors/white :width 80 :height 80} border1 2 border2 2 corner 16)])
|
||||||
|
|
||||||
|
(defn- viewfinder
|
||||||
|
[qr-view-finder]
|
||||||
|
(let [size (:width qr-view-finder)]
|
||||||
|
[rn/view {:style (style/viewfinder-container qr-view-finder)}
|
||||||
|
[rn/view {:width size :height size :justify-content :space-between}
|
||||||
|
[rn/view {:flex-direction :row :justify-content :space-between}
|
||||||
|
[border :border-top-width :border-left-width :border-top-left-radius]
|
||||||
|
[border :border-top-width :border-right-width :border-top-right-radius]]
|
||||||
|
[rn/view {:flex-direction :row :justify-content :space-between}
|
||||||
|
[border :border-bottom-width :border-left-width :border-bottom-left-radius]
|
||||||
|
[border :border-bottom-width :border-right-width :border-bottom-right-radius]]]
|
||||||
|
[quo/text
|
||||||
|
{:size :paragraph-2
|
||||||
|
:weight :regular
|
||||||
|
:style style/viewfinder-text}
|
||||||
|
(i18n/label :t/ensure-qr-code-is-in-focus-to-scan)]]))
|
||||||
|
|
||||||
|
(defn- scan-qr-code-tab
|
||||||
|
[qr-view-finder request-camera-permission]
|
||||||
|
[:<>
|
||||||
|
[rn/view {:style style/scan-qr-code-container}]
|
||||||
|
(when (empty? @qr-view-finder)
|
||||||
|
[qr-scan-hole-area qr-view-finder])
|
||||||
|
(if (and @camera-permission-granted? (boolean (not-empty @qr-view-finder)))
|
||||||
|
[viewfinder @qr-view-finder]
|
||||||
|
[camera-permission-view request-camera-permission])])
|
||||||
|
|
||||||
|
(defn- enter-sync-code-tab
|
||||||
[]
|
[]
|
||||||
[rn/view {:style {:flex 1}}
|
[rn/view {:style style/enter-sync-code-container}
|
||||||
[background/view true]
|
[quo/text
|
||||||
[page]])
|
{:size :paragraph-1
|
||||||
|
:weight :medium
|
||||||
|
:style {:color colors/white}}
|
||||||
|
"Yet to be implemented"]])
|
||||||
|
|
||||||
|
(defn- bottom-view
|
||||||
|
[insets]
|
||||||
|
[rn/touchable-without-feedback
|
||||||
|
{:on-press #(js/alert "Yet to be implemented")}
|
||||||
|
[rn/view
|
||||||
|
{:style (style/bottom-container (:bottom insets))}
|
||||||
|
[quo/text
|
||||||
|
{:size :paragraph-2
|
||||||
|
:weight :regular
|
||||||
|
:style style/bottom-text}
|
||||||
|
(i18n/label :t/i-dont-have-status-on-another-device)]]])
|
||||||
|
|
||||||
|
(defn- check-qr-code-data
|
||||||
|
[event]
|
||||||
|
(let [connection-string (string/trim (oops/oget event "nativeEvent.codeStringValue"))
|
||||||
|
valid-connection-string? (string/starts-with?
|
||||||
|
connection-string
|
||||||
|
constants/local-pairing-connection-string-identifier)]
|
||||||
|
(if valid-connection-string?
|
||||||
|
(rf/dispatch [:syncing/input-connection-string-for-bootstrapping connection-string])
|
||||||
|
(rf/dispatch [:toasts/upsert
|
||||||
|
{:icon :i/info
|
||||||
|
:icon-color colors/danger-50
|
||||||
|
:override-theme :light
|
||||||
|
:text (i18n/label :t/error-this-is-not-a-sync-qr-code)}]))))
|
||||||
|
|
||||||
|
(defn view
|
||||||
|
[]
|
||||||
|
(let [active-tab (reagent/atom 1)
|
||||||
|
qr-view-finder (reagent/atom {})
|
||||||
|
{:keys [height width]} (rf/sub [:dimensions/window])
|
||||||
|
request-camera-permission (fn []
|
||||||
|
(rf/dispatch
|
||||||
|
[:request-permissions
|
||||||
|
{:permissions [:camera]
|
||||||
|
:on-allowed #(reset! camera-permission-granted? true)
|
||||||
|
:on-denied #(rf/dispatch
|
||||||
|
[:toasts/upsert
|
||||||
|
{:icon :i/info
|
||||||
|
:icon-color colors/danger-50
|
||||||
|
: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}]
|
||||||
|
[rn/image
|
||||||
|
{:style (merge style/absolute-fill {:height height :width width})
|
||||||
|
:source (resources/get-image :intro-4)}])
|
||||||
|
(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]]))]))
|
||||||
|
@ -3,9 +3,7 @@
|
|||||||
[quo2.foundations.colors :as colors]
|
[quo2.foundations.colors :as colors]
|
||||||
[react-native.core :as rn]
|
[react-native.core :as rn]
|
||||||
[status-im2.contexts.onboarding.syncing.syncing-devices.style :as style]
|
[status-im2.contexts.onboarding.syncing.syncing-devices.style :as style]
|
||||||
[utils.i18n :as i18n]
|
[status-im2.contexts.onboarding.common.background.view :as background]))
|
||||||
[status-im2.contexts.onboarding.common.background.view :as background]
|
|
||||||
[utils.re-frame :as rf]))
|
|
||||||
|
|
||||||
|
|
||||||
(defn navigation-bar
|
(defn navigation-bar
|
||||||
@ -14,10 +12,6 @@
|
|||||||
[quo/page-nav
|
[quo/page-nav
|
||||||
{:align-mid? true
|
{:align-mid? true
|
||||||
:mid-section {:type :text-only :main-text ""}
|
:mid-section {:type :text-only :main-text ""}
|
||||||
:left-section {:type :blur-bg
|
|
||||||
:icon :i/arrow-left
|
|
||||||
:icon-override-theme :dark
|
|
||||||
:on-press #(rf/dispatch [:navigate-back])}
|
|
||||||
:right-section-buttons [{:type :blur-bg
|
:right-section-buttons [{:type :blur-bg
|
||||||
:icon :i/info
|
:icon :i/info
|
||||||
:icon-override-theme :dark
|
:icon-override-theme :dark
|
||||||
@ -39,10 +33,7 @@
|
|||||||
[quo/text
|
[quo/text
|
||||||
{:size :heading-2
|
{:size :heading-2
|
||||||
:weight :semi-bold
|
:weight :semi-bold
|
||||||
:style {:color colors/white}} "will show sync failed if unsuccessful"]
|
:style {:color colors/white}} "will show sync failed if unsuccessful"]]])
|
||||||
[quo/button
|
|
||||||
{:on-press #(rf/dispatch [:navigate-to :enable-notifications])
|
|
||||||
:style {}} (i18n/label :t/continue)]]])
|
|
||||||
|
|
||||||
(defn syncing-devices
|
(defn syncing-devices
|
||||||
[]
|
[]
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
(ns status-im2.contexts.quo-preview.tabs.segmented-tab
|
(ns status-im2.contexts.quo-preview.tabs.segmented-tab
|
||||||
(:require [quo2.components.tabs.segmented-tab :as quo2]
|
(:require [quo2.components.tabs.segmented-tab :as quo2]
|
||||||
[quo2.foundations.colors :as colors]
|
[quo2.foundations.colors :as colors]
|
||||||
|
[quo2.theme :as theme]
|
||||||
[react-native.core :as rn]
|
[react-native.core :as rn]
|
||||||
[reagent.core :as reagent]
|
[reagent.core :as reagent]
|
||||||
[status-im2.contexts.quo-preview.preview :as preview]))
|
[status-im2.contexts.quo-preview.preview :as preview]))
|
||||||
@ -12,17 +13,26 @@
|
|||||||
:options [{:key 28
|
:options [{:key 28
|
||||||
:value "28"}
|
:value "28"}
|
||||||
{:key 20
|
{:key 20
|
||||||
:value "20"}]}])
|
:value "20"}]}
|
||||||
|
{:label "Blur?"
|
||||||
|
:key :blur?
|
||||||
|
:type :boolean}])
|
||||||
|
|
||||||
(defn cool-preview
|
(defn cool-preview
|
||||||
[]
|
[]
|
||||||
(let [state (reagent/atom {:size 32})]
|
(let [state (reagent/atom {:size 32
|
||||||
|
:blur? false})]
|
||||||
(fn []
|
(fn []
|
||||||
[rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!}
|
[rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!}
|
||||||
[rn/view {:padding-bottom 150}
|
[rn/view {:padding-bottom 150}
|
||||||
[rn/view {:flex 1}
|
[rn/view {:flex 1}
|
||||||
[preview/customizer state descriptor]]
|
[preview/customizer state descriptor]]
|
||||||
[rn/view {:padding-vertical 60}
|
[preview/blur-view
|
||||||
|
{:show-blur-background? (:blur? @state)
|
||||||
|
:height 200
|
||||||
|
:style {:width "100%"}
|
||||||
|
:blur-view-props {:blur-type (theme/get-theme)}}
|
||||||
|
[:<>
|
||||||
[quo2/segmented-control
|
[quo2/segmented-control
|
||||||
(merge @state
|
(merge @state
|
||||||
{:default-active 1
|
{:default-active 1
|
||||||
@ -30,14 +40,14 @@
|
|||||||
{:id 2 :label "Tab 2"}
|
{:id 2 :label "Tab 2"}
|
||||||
{:id 3 :label "Tab 3"}
|
{:id 3 :label "Tab 3"}
|
||||||
{:id 4 :label "Tab 4"}]
|
{:id 4 :label "Tab 4"}]
|
||||||
:on-change #(println "Active tab" %)})]]
|
:on-change #(println "Active tab" %)})]
|
||||||
[rn/view {:padding-vertical 60}
|
[rn/view {:style {:padding-top 24}}
|
||||||
[quo2/segmented-control
|
[quo2/segmented-control
|
||||||
(merge @state
|
(merge @state
|
||||||
{:default-active 1
|
{:default-active 1
|
||||||
:data [{:id 1 :label "Tab 1"}
|
:data [{:id 1 :label "Tab 1"}
|
||||||
{:id 2 :label "Tab 2"}]
|
{:id 2 :label "Tab 2"}]
|
||||||
:on-change #(println "Active tab" %)})]]]])))
|
:on-change #(println "Active tab" %)})]]]]]])))
|
||||||
|
|
||||||
(defn preview-segmented
|
(defn preview-segmented
|
||||||
[]
|
[]
|
||||||
|
@ -10,6 +10,13 @@
|
|||||||
[status-im.data-store.settings :as data-store.settings]
|
[status-im.data-store.settings :as data-store.settings]
|
||||||
[status-im.utils.platform :as utils.platform]))
|
[status-im.utils.platform :as utils.platform]))
|
||||||
|
|
||||||
|
(rf/defn local-pairing-completed
|
||||||
|
{:events [:syncing/pairing-completed]}
|
||||||
|
[{:keys [db] :as cofx}]
|
||||||
|
(rf/merge cofx
|
||||||
|
{:db (dissoc db :local-pairing/completed-pairing?)
|
||||||
|
:dispatch [:init-root :enable-notifications]}))
|
||||||
|
|
||||||
(defn- get-default-node-config
|
(defn- get-default-node-config
|
||||||
[installation-id]
|
[installation-id]
|
||||||
(let [db {:networks/current-network config/default-network
|
(let [db {:networks/current-network config/default-network
|
||||||
@ -24,7 +31,7 @@
|
|||||||
(rf/defn initiate-local-pairing-with-connection-string
|
(rf/defn initiate-local-pairing-with-connection-string
|
||||||
{:events [:syncing/input-connection-string-for-bootstrapping]
|
{:events [:syncing/input-connection-string-for-bootstrapping]
|
||||||
:interceptors [(re-frame/inject-cofx :random-guid-generator)]}
|
:interceptors [(re-frame/inject-cofx :random-guid-generator)]}
|
||||||
[{:keys [random-guid-generator db]} {connection-string :data}]
|
[{:keys [random-guid-generator db]} connection-string]
|
||||||
(let [installation-id (random-guid-generator)
|
(let [installation-id (random-guid-generator)
|
||||||
default-node-config (get-default-node-config installation-id)
|
default-node-config (get-default-node-config installation-id)
|
||||||
default-node-config-string (.stringify js/JSON (clj->js default-node-config))
|
default-node-config-string (.stringify js/JSON (clj->js default-node-config))
|
||||||
|
@ -160,6 +160,14 @@
|
|||||||
{:stack {:id :profiles
|
{:stack {:id :profiles
|
||||||
:children [{:component {:name :profiles
|
:children [{:component {:name :profiles
|
||||||
:id :profiles
|
:id :profiles
|
||||||
|
:options (merge
|
||||||
|
(status-bar-options)
|
||||||
|
{:topBar {:visible false}})}}]}}}
|
||||||
|
:enable-notifications
|
||||||
|
{:root
|
||||||
|
{:stack {:id :enable-notifications
|
||||||
|
:children [{:component {:name :enable-notifications
|
||||||
|
:id :enable-notifications
|
||||||
:options (merge
|
:options (merge
|
||||||
(status-bar-options)
|
(status-bar-options)
|
||||||
{:topBar {:visible false}})}}]}}}}))
|
{:topBar {:visible false}})}}]}}}}))
|
||||||
|
@ -184,11 +184,13 @@
|
|||||||
:component enable-notifications/enable-notifications}
|
:component enable-notifications/enable-notifications}
|
||||||
|
|
||||||
{:name :sign-in
|
{:name :sign-in
|
||||||
:options {:statusBar {:style :light}
|
:options {:statusBar {:style :light
|
||||||
|
:backgroundColor :transparent
|
||||||
|
:translucent true}
|
||||||
:topBar {:visible false}
|
:topBar {:visible false}
|
||||||
:navigationBar {:backgroundColor colors/black}}
|
:navigationBar {:backgroundColor colors/black}}
|
||||||
:insets {:top false}
|
:insets {:top false}
|
||||||
:component sign-in/sign-in}
|
:component sign-in/view}
|
||||||
|
|
||||||
{:name :syncing-devices
|
{:name :syncing-devices
|
||||||
:options {:statusBar {:style :light}
|
:options {:statusBar {:style :light}
|
||||||
|
@ -2020,5 +2020,19 @@
|
|||||||
"remove-profile-message": "Remove profile from this device",
|
"remove-profile-message": "Remove profile from this device",
|
||||||
"remove-profile-confirm-message": "All profile data will removed from device.",
|
"remove-profile-confirm-message": "All profile data will removed from device.",
|
||||||
"create-new-profile": "Create new profile",
|
"create-new-profile": "Create new profile",
|
||||||
"add-existing-status-profile": "Add existing Status profile"
|
"add-existing-status-profile": "Add existing Status profile",
|
||||||
|
"find-sync-code": "Find sync code",
|
||||||
|
"sign-in-by-syncing": "Sign in by syncing",
|
||||||
|
"synchronise-your-data-across-your-devices": "Synchronise your data across your devices",
|
||||||
|
"scan-sync-qr-code": "Scan QR code",
|
||||||
|
"enter-sync-code": "Enter sync code",
|
||||||
|
"enable-access-to-camera": "Enable access to camera",
|
||||||
|
"to-scan-a-qr-enable-your-camera": "To scan a QR, enable your camera",
|
||||||
|
"enable-camera": "Enable camera",
|
||||||
|
"ensure-qr-code-in-focus-to-scan": "Ensure that the QR code is in focus to scan",
|
||||||
|
"i-dont-have-status-on-another-device": "I don’t have Status on another device",
|
||||||
|
"ensure-qr-code-is-in-focus-to-scan":"Ensure that the QR code is in focus to scan",
|
||||||
|
"error-this-is-not-a-sync-qr-code": "Oops! This is not a sync QR code",
|
||||||
|
"error-syncing-connection-failed": "Oops! Connection failed. Try again",
|
||||||
|
"camera-permission-denied": "Permission denied"
|
||||||
}
|
}
|
||||||
|
@ -1786,9 +1786,9 @@
|
|||||||
eventemitter3 "^1.2.0"
|
eventemitter3 "^1.2.0"
|
||||||
lodash "^4.17.15"
|
lodash "^4.17.15"
|
||||||
|
|
||||||
"@react-native-community/blur@git+https://github.com/status-im/react-native-blur#refs/tags/v4.3.1-status":
|
"@react-native-community/blur@git+https://github.com/status-im/react-native-blur#refs/tags/v4.3.2-status":
|
||||||
version "4.3.0"
|
version "4.3.2"
|
||||||
resolved "git+https://github.com/status-im/react-native-blur#7317898ee7c824d2d5501aec72a509baced2b253"
|
resolved "git+https://github.com/status-im/react-native-blur#722940e19c7ac8f90d3fccc5e9d34e0fd2342d51"
|
||||||
|
|
||||||
"@react-native-community/cameraroll@git+https://github.com/status-im/react-native-cameraroll.git#refs/tags/v4.0.4-status.0":
|
"@react-native-community/cameraroll@git+https://github.com/status-im/react-native-cameraroll.git#refs/tags/v4.0.4-status.0":
|
||||||
version "4.0.4"
|
version "4.0.4"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user