[#7871] Handle multiple opened screens with qr code readers

This commit is contained in:
Roman Volosovskyi 2019-05-01 20:24:36 +03:00
parent 49fbf21f8d
commit 148d43fdab
No known key found for this signature in database
GPG Key ID: 0238A4B5ECEE70DE
11 changed files with 75 additions and 61 deletions

View File

@ -34,7 +34,7 @@
(= permission constants/dapp-permission-qr-code)
(fx/merge (assoc-in cofx [:db :browser/options :yielding-control?] true)
(qr-scanner/scan-qr-code {:modal? false}
(qr-scanner/scan-qr-code {}
{:handler :browser.bridge.callback/qr-code-scanned
:cancel-handler :browser.bridge.callback/qr-code-canceled
:data {:dapp-name dapp-name

View File

@ -55,8 +55,7 @@
(handlers/register-handler-fx
:extensions/camera-qr-code
(fn [{:keys [db] :as cofx} [_ _ {:keys [on-success on-failure]}]]
(qr-scanner/scan-qr-code cofx {:modal? false
:deny-handler :extensions/camera-denied}
(qr-scanner/scan-qr-code cofx {:deny-handler :extensions/camera-denied}
{:handler :extensions/camera-qr-code-scanned
:cancel-handler :extensions/camera-cancel
:data {:on-success on-success

View File

@ -5,11 +5,12 @@
[status-im.utils.fx :as fx]))
(fx/defn scan-qr-code
[{:keys [db]} {:keys [modal? deny-handler] :as identifier} qr-codes]
{:db (assoc db :qr-codes qr-codes)
[{:keys [db]} {:keys [deny-handler] :as identifier} qr-codes]
{:db (assoc-in db [:qr-codes identifier] qr-codes)
:request-permissions-fx {:permissions [:camera]
:on-allowed #(re-frame/dispatch [(if modal? :navigate-to-modal :navigate-to)
:qr-scanner {:current-qr-context identifier}])
:on-allowed #(re-frame/dispatch
[:navigate-to :qr-scanner
{:current-qr-context identifier}])
:on-denied (if (nil? deny-handler)
(fn []
(utils/set-timeout
@ -23,7 +24,7 @@
(merge {:db (-> db
(update :qr-codes dissoc context)
(dissoc :current-qr-context))}
(when-let [qr-codes (:qr-codes db)]
(when-let [qr-codes (get-in db [:qr-codes context])]
{:dispatch [(:handler qr-codes) context data (dissoc qr-codes :handler)]})))
(fx/defn set-qr-code-cancel
@ -31,6 +32,6 @@
(merge {:db (-> db
(update :qr-codes dissoc context)
(dissoc :current-qr-context))}
(when-let [qr-codes (:qr-codes db)]
(when-let [qr-codes (get-in db [:qr-codes context])]
(when-let [handler (:cancel-handler qr-codes)]
{:dispatch [handler context qr-codes]}))))

View File

@ -53,7 +53,7 @@
{:db (if (= view-id go-to-view-id)
db
(push-view db go-to-view-id))
::navigate-to go-to-view-id}))
::navigate-to [go-to-view-id screen-params]}))
(fx/defn navigate-reset
[{:keys [db]} {:keys [index actions] :as config}]
@ -76,9 +76,9 @@
(re-frame/reg-fx
::navigate-to
(fn [view-id]
(log/debug :navigate-to view-id)
(navigation/navigate-to (name view-id))))
(fn [[view-id params]]
(log/debug :navigate-to view-id params)
(navigation/navigate-to (name view-id) params)))
(re-frame/reg-fx
::navigate-back

View File

@ -23,20 +23,25 @@
(defn on-barcode-read [identifier data]
(re-frame/dispatch [:qr-scanner.callback/scan-qr-code-success identifier (camera/get-qr-code-data data)]))
(defview qr-scanner []
(letsubs [{identifier :current-qr-context} [:get-screen-params]
camera-initialized? (reagent/atom false)
;; identifier is passed via navigation params instead of subs in order to ensure
;; that two separate instances of `qr-scanner` screen can work simultaneously
(defview qr-scanner [{identifier :current-qr-context} screen-focused?]
(letsubs [camera-initialized? (reagent/atom false)
barcode-read? (reagent/atom false)]
[react/view styles/barcode-scanner-container
[qr-scanner-toolbar (or (:toolbar-title identifier) (i18n/label :t/scan-qr)) identifier]
[camera/camera {:onBarCodeRead #(if (:multiple? identifier)
(on-barcode-read identifier %)
(when-not @barcode-read?
(do (reset! barcode-read? true)
(on-barcode-read identifier %))))
:ref #(reset! camera-initialized? true)
:captureAudio false
:style styles/barcode-scanner}]
;; camera component should be hidden if screen is not shown
;; otherwise another screen with camera from a different stack
;; will not work properly
(when @screen-focused?
[camera/camera {:onBarCodeRead #(if (:multiple? identifier)
(on-barcode-read identifier %)
(when-not @barcode-read?
(do (reset! barcode-read? true)
(on-barcode-read identifier %))))
:ref #(reset! camera-initialized? true)
:captureAudio false
:style styles/barcode-scanner}])
[react/view styles/rectangle-container
[react/view styles/rectangle
[react/image {:source {:uri :corner_left_top}

View File

@ -21,10 +21,11 @@
(defonce view-id (reagent.core/atom nil))
(defn navigation-events [current-view-id modal?]
(defn navigation-events [current-view-id modal? screen-focused?]
[:> navigation/navigation-events
{:on-will-focus
(fn []
(reset! screen-focused? true)
(when (not= @view-id current-view-id)
(reset! view-id current-view-id))
(log/debug :on-will-focus current-view-id)
@ -34,13 +35,18 @@
:on-did-focus
(fn []
(when-not modal?
(status-bar/set-status-bar current-view-id)))}])
(status-bar/set-status-bar current-view-id)))
:on-will-blur
(fn [] (reset! screen-focused? false))}])
(defn wrap
"Wraps screen with main view and adds navigation-events component"
[view-id component]
(fn []
(let [main-view (react/create-main-screen-view view-id)]
(fn [args]
(let [main-view (react/create-main-screen-view view-id)
;; params passed to :navigate-to
params (get-in args [:navigation :state :params])
screen-focused? (reagent.core/atom true)]
(if platform/ios?
[main-view (assoc common-styles/flex
:margin-bottom
@ -64,38 +70,40 @@
:else
tabs.styles/minimized-tabs-height))
[component]
[navigation-events view-id false]]
[component params screen-focused?]
[navigation-events view-id false screen-focused?]]
[main-view common-styles/flex
[component]
[navigation-events view-id false]]))))
[component params screen-focused?]
[navigation-events view-id false screen-focused?]]))))
(defn wrap-modal [modal-view component]
"Wraps modal screen with necessary styling and adds :on-request-close handler
on Android"
(fn []
(if platform/android?
[react/view common-styles/modal
[react/modal
{:transparent true
:animation-type :slide
:on-request-close (fn []
(cond
(#{:wallet-send-transaction-modal
:wallet-sign-message-modal}
modal-view)
(re-frame/dispatch
[:wallet/discard-transaction-navigate-back])
(fn [args]
(let [params (get-in args [:navigation :state :params])
active? (reagent.core/atom true)]
(if platform/android?
[react/view common-styles/modal
[react/modal
{:transparent true
:animation-type :slide
:on-request-close (fn []
(cond
(#{:wallet-send-transaction-modal
:wallet-sign-message-modal}
modal-view)
(re-frame/dispatch
[:wallet/discard-transaction-navigate-back])
:else
(re-frame/dispatch [:navigate-back])))}
:else
(re-frame/dispatch [:navigate-back])))}
[react/main-screen-modal-view modal-view
[component params active?]]
[navigation-events modal-view true active?]]]
[react/main-screen-modal-view modal-view
[component]]
[navigation-events modal-view true]]]
[react/main-screen-modal-view modal-view
[component]
[navigation-events modal-view true]])))
[component params active?]
[navigation-events modal-view true active?]]))))
(defn prepare-config [config]
(-> config

View File

@ -82,7 +82,7 @@
platform/android?
(not js/goog.DEBUG)
(not (contains? #{:intro :login :progress} @view-id)))
(navigation/navigate-to @view-id)))
(navigation/navigate-to @view-id nil)))
;; see https://reactnavigation.org/docs/en/state-persistence.html#development-mode
:persistenceKey (when js/goog.DEBUG rand-label)}]
[bottom-sheet]]))})))

View File

@ -19,13 +19,14 @@
(defn can-be-called? []
@navigator-ref)
(defn navigate-to [route]
(defn navigate-to [route params]
(when (can-be-called?)
(.dispatch
@navigator-ref
(.navigate
navigation-actions
#js {:routeName (name route)}))))
#js {:routeName (name route)
:params (clj->js params)}))))
(defn- navigate [params]
(when (can-be-called?)

View File

@ -5,7 +5,7 @@
(defn has-navigated-to-browser? [result]
(and (= (get result :status-im.ui.screens.navigation/navigate-to)
:browser)
[:browser nil])
(= (get-in result [:db :view-id])
:browser)))

View File

@ -145,7 +145,7 @@
:error true}}
(-> actual :db :mailserver.edit/mailserver))))
(testing "it navigates to edit-mailserver view"
(is (= :edit-mailserver
(is (= [:edit-mailserver nil]
(:status-im.ui.screens.navigation/navigate-to actual))))))
(testing "when an id is given"
(testing "when the mailserver is in the list"
@ -159,7 +159,7 @@
:error false}}
(-> actual :db :mailserver.edit/mailserver))))
(testing "it navigates to edit-mailserver view"
(is (= :edit-mailserver
(is (= [:edit-mailserver nil]
(:status-im.ui.screens.navigation/navigate-to actual))))))
(testing "when the mailserver is not in the list"
(let [actual (mailserver/edit cofx "not-existing")]
@ -172,7 +172,7 @@
:error true}}
(-> actual :db :mailserver.edit/mailserver))))
(testing "it navigates to edit-mailserver view"
(is (= :edit-mailserver
(is (= [:edit-mailserver nil]
(:status-im.ui.screens.navigation/navigate-to actual)))))))))
(deftest connected-mailserver

View File

@ -50,7 +50,7 @@
(testing "Request notifications permissions."
(is (contains? efx :notifications/request-notifications-permissions)))
(testing "Navigate to :home."
(is (= :home (efx :status-im.ui.screens.navigation/navigate-to))))
(is (= [:home nil] (efx :status-im.ui.screens.navigation/navigate-to))))
(testing "Account selected."
(is (contains? new-db :account/account)))
(testing "Chats initialized."