Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0aede3510d |
@@ -1,7 +1,6 @@
|
|||||||
{:lint-as {status-im.utils.views/defview clojure.core/defn
|
{:lint-as {status-im.utils.views/defview clojure.core/defn
|
||||||
status-im.utils.views/letsubs clojure.core/let
|
status-im.utils.views/letsubs clojure.core/let
|
||||||
reagent.core/with-let clojure.core/let
|
reagent.core/with-let clojure.core/let
|
||||||
status-im.utils.fx/defn clj-kondo.lint-as/def-catch-all
|
|
||||||
utils.re-frame/defn clj-kondo.lint-as/def-catch-all
|
utils.re-frame/defn clj-kondo.lint-as/def-catch-all
|
||||||
quo.react/with-deps-check clojure.core/fn
|
quo.react/with-deps-check clojure.core/fn
|
||||||
quo.previews.preview/list-comp clojure.core/for
|
quo.previews.preview/list-comp clojure.core/for
|
||||||
@@ -12,7 +11,7 @@
|
|||||||
:linters {:consistent-alias {:level :error
|
:linters {:consistent-alias {:level :error
|
||||||
:aliases {clojure.string string
|
:aliases {clojure.string string
|
||||||
taoensso.timbre log}}
|
taoensso.timbre log}}
|
||||||
:invalid-arity {:skip-args [status-im.utils.fx/defn utils.re-frame/defn]}
|
:invalid-arity {:skip-args [utils.re-frame/defn]}
|
||||||
;; TODO remove number when this is fixed
|
;; TODO remove number when this is fixed
|
||||||
;; https://github.com/borkdude/clj-kondo/issues/867
|
;; https://github.com/borkdude/clj-kondo/issues/867
|
||||||
:unresolved-symbol {:exclude [PersistentPriorityMap.EMPTY
|
:unresolved-symbol {:exclude [PersistentPriorityMap.EMPTY
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
(ns status-im.add-new.core
|
(ns status-im.add-new.core
|
||||||
(:require [clojure.string :as string]
|
(:require [clojure.string :as string]
|
||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
|
[status-im.add-new.db :as db]
|
||||||
|
[status-im.chat.models :as chat]
|
||||||
|
[status-im.contact.core :as contact]
|
||||||
[status-im.ethereum.core :as ethereum]
|
[status-im.ethereum.core :as ethereum]
|
||||||
[status-im.ethereum.ens :as ens]
|
[status-im.ethereum.ens :as ens]
|
||||||
[status-im.add-new.db :as db]
|
[status-im.ethereum.stateofus :as stateofus]
|
||||||
|
[status-im.i18n.i18n :as i18n]
|
||||||
|
[status-im.router.core :as router]
|
||||||
|
[status-im.utils.db :as utils.db]
|
||||||
[status-im.utils.random :as random]
|
[status-im.utils.random :as random]
|
||||||
[status-im.utils.utils :as utils]
|
[status-im.utils.utils :as utils]
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[status-im.chat.models :as chat]
|
|
||||||
[status-im.i18n.i18n :as i18n]
|
|
||||||
[status-im.contact.core :as contact]
|
|
||||||
[status-im.router.core :as router]
|
|
||||||
[status-im2.navigation.events :as navigation]
|
[status-im2.navigation.events :as navigation]
|
||||||
[status-im.ethereum.stateofus :as stateofus]
|
[utils.re-frame :as rf]))
|
||||||
[status-im.utils.db :as utils.db]))
|
|
||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
:resolve-public-key
|
:resolve-public-key
|
||||||
@@ -24,19 +24,19 @@
|
|||||||
;;NOTE we want to handle only last resolve
|
;;NOTE we want to handle only last resolve
|
||||||
(def resolve-last-id (atom nil))
|
(def resolve-last-id (atom nil))
|
||||||
|
|
||||||
(fx/defn new-chat-set-new-identity
|
(rf/defn new-chat-set-new-identity
|
||||||
{:events [:new-chat/set-new-identity]}
|
{:events [:new-chat/set-new-identity]}
|
||||||
[{db :db} new-identity-raw new-ens-name id]
|
[{db :db} new-identity-raw new-ens-name id]
|
||||||
(let [ens-error (and (= new-identity-raw "0x") (not (string/blank? new-ens-name)))]
|
(let [ens-error (and (= new-identity-raw "0x") (not (string/blank? new-ens-name)))]
|
||||||
(when (or (not id) (= id @resolve-last-id))
|
(when (or (not id) (= id @resolve-last-id))
|
||||||
(if ens-error
|
(if ens-error
|
||||||
{:db (assoc-in db [:contacts/new-identity :state] :error)}
|
{:db (assoc-in db [:contacts/new-identity :state] :error)}
|
||||||
(let [new-identity (utils/safe-trim new-identity-raw)
|
(let [new-identity (utils/safe-trim new-identity-raw)
|
||||||
is-public-key? (and (string? new-identity)
|
is-public-key? (and (string? new-identity)
|
||||||
(utils.db/valid-public-key? new-identity))
|
(utils.db/valid-public-key? new-identity))
|
||||||
is-ens? (and (not is-public-key?)
|
is-ens? (and (not is-public-key?)
|
||||||
(ens/valid-eth-name-prefix? new-identity))
|
(ens/valid-eth-name-prefix? new-identity))
|
||||||
error (db/validate-pub-key db new-identity)]
|
error (db/validate-pub-key db new-identity)]
|
||||||
(reset! resolve-last-id nil)
|
(reset! resolve-last-id nil)
|
||||||
(merge {:db (assoc db
|
(merge {:db (assoc db
|
||||||
:contacts/new-identity
|
:contacts/new-identity
|
||||||
@@ -61,25 +61,27 @@
|
|||||||
new-identity
|
new-identity
|
||||||
@resolve-last-id])}})))))))
|
@resolve-last-id])}})))))))
|
||||||
|
|
||||||
(fx/defn clear-new-identity
|
(rf/defn clear-new-identity
|
||||||
{:events [::clear-new-identity ::new-chat-focus]}
|
{:events [::clear-new-identity ::new-chat-focus]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
{:db (dissoc db :contacts/new-identity)})
|
{:db (dissoc db :contacts/new-identity)})
|
||||||
|
|
||||||
(fx/defn qr-code-handled
|
(rf/defn qr-code-handled
|
||||||
{:events [::qr-code-handled]}
|
{:events [::qr-code-handled]}
|
||||||
[{:keys [db] :as cofx} {:keys [type public-key chat-id data ens-name]} {:keys [new-contact? nickname] :as opts}]
|
[{:keys [db] :as cofx} {:keys [type public-key chat-id data ens-name]}
|
||||||
(let [public-key? (and (string? data)
|
{:keys [new-contact? nickname] :as opts}]
|
||||||
(string/starts-with? data "0x"))
|
(let [public-key? (and (string? data)
|
||||||
chat-key (cond
|
(string/starts-with? data "0x"))
|
||||||
(= type :private-chat) chat-id
|
chat-key (cond
|
||||||
(= type :contact) public-key
|
(= type :private-chat) chat-id
|
||||||
(and (= type :undefined)
|
(= type :contact) public-key
|
||||||
public-key?) data)
|
(and (= type :undefined)
|
||||||
|
public-key?)
|
||||||
|
data)
|
||||||
validation-result (db/validate-pub-key db chat-key)]
|
validation-result (db/validate-pub-key db chat-key)]
|
||||||
(if-not validation-result
|
(if-not validation-result
|
||||||
(if new-contact?
|
(if new-contact?
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(contact/add-contact chat-key nickname ens-name)
|
(contact/add-contact chat-key nickname ens-name)
|
||||||
(navigation/navigate-to-cofx :contacts-list {}))
|
(navigation/navigate-to-cofx :contacts-list {}))
|
||||||
(chat/start-chat cofx chat-key ens-name))
|
(chat/start-chat cofx chat-key ens-name))
|
||||||
@@ -91,7 +93,7 @@
|
|||||||
(i18n/label :t/can-not-add-yourself))
|
(i18n/label :t/can-not-add-yourself))
|
||||||
:on-dismiss #(re-frame/dispatch [:pop-to-root-tab :chat-stack])}})))
|
:on-dismiss #(re-frame/dispatch [:pop-to-root-tab :chat-stack])}})))
|
||||||
|
|
||||||
(fx/defn qr-code-scanned
|
(rf/defn qr-code-scanned
|
||||||
{:events [:contact/qr-code-scanned]}
|
{:events [:contact/qr-code-scanned]}
|
||||||
[{:keys [db]} data opts]
|
[{:keys [db]} data opts]
|
||||||
{::router/handle-uri {:chain (ethereum/chain-keyword db)
|
{::router/handle-uri {:chain (ethereum/chain-keyword db)
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
(ns status-im.backup.core
|
(ns status-im.backup.core
|
||||||
(:require [re-frame.core :as re-frame]
|
(:require [re-frame.core :as re-frame]
|
||||||
[taoensso.timbre :as log]
|
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
[status-im.utils.fx :as fx]))
|
[taoensso.timbre :as log]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(fx/defn handle-backup-failed
|
(rf/defn handle-backup-failed
|
||||||
{:events [::backup-failed]}
|
{:events [::backup-failed]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
{:db (dissoc db :backup/performing-backup)})
|
{:db (dissoc db :backup/performing-backup)})
|
||||||
|
|
||||||
(fx/defn handle-backup-perfomed
|
(rf/defn handle-backup-perfomed
|
||||||
{:events [::backup-performed]}
|
{:events [::backup-performed]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
{:db (dissoc db :backup/performing-backup)})
|
{:db (dissoc db :backup/performing-backup)})
|
||||||
|
|
||||||
(fx/defn handle-perform-backup-pressed
|
(rf/defn handle-perform-backup-pressed
|
||||||
{:events [:multiaccounts.ui/perform-backup-pressed]}
|
{:events [:multiaccounts.ui/perform-backup-pressed]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
{:db (assoc db :backup/performing-backup true)
|
{:db (assoc db :backup/performing-backup true)
|
||||||
::json-rpc/call [{:method "wakuext_backupData"
|
::json-rpc/call [{:method "wakuext_backupData"
|
||||||
:params []
|
:params []
|
||||||
:on-error #(do
|
:on-error #(do
|
||||||
|
|||||||
@@ -4,24 +4,27 @@
|
|||||||
[status-im.i18n.i18n :as i18n]
|
[status-im.i18n.i18n :as i18n]
|
||||||
[status-im.multiaccounts.update.core :as multiaccounts.update]
|
[status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||||
[status-im2.navigation.events :as navigation]
|
[status-im2.navigation.events :as navigation]
|
||||||
[status-im.utils.fx :as fx]))
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(def address-regex #"enode://[a-zA-Z0-9]+:?(.*)\@\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b:(\d{1,5})")
|
(def address-regex #"enode://[a-zA-Z0-9]+:?(.*)\@\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b:(\d{1,5})")
|
||||||
|
|
||||||
(defn valid-address? [address]
|
(defn valid-address?
|
||||||
|
[address]
|
||||||
(re-matches address-regex address))
|
(re-matches address-regex address))
|
||||||
|
|
||||||
(defn- build [id bootnode-name address chain]
|
(defn- build
|
||||||
|
[id bootnode-name address chain]
|
||||||
{:address address
|
{:address address
|
||||||
:chain chain
|
:chain chain
|
||||||
:id (string/replace id "-" "")
|
:id (string/replace id "-" "")
|
||||||
:name bootnode-name})
|
:name bootnode-name})
|
||||||
|
|
||||||
(fx/defn fetch [cofx id]
|
(rf/defn fetch
|
||||||
|
[cofx id]
|
||||||
(let [network (get-in cofx [:db :networks/current-network])]
|
(let [network (get-in cofx [:db :networks/current-network])]
|
||||||
(get-in cofx [:db :multiaccount :custom-bootnodes network id])))
|
(get-in cofx [:db :multiaccount :custom-bootnodes network id])))
|
||||||
|
|
||||||
(fx/defn set-input
|
(rf/defn set-input
|
||||||
{:events [:bootnodes.ui/input-changed]}
|
{:events [:bootnodes.ui/input-changed]}
|
||||||
[{:keys [db]} input-key value]
|
[{:keys [db]} input-key value]
|
||||||
{:db (update
|
{:db (update
|
||||||
@@ -35,16 +38,17 @@
|
|||||||
:name (string/blank? value)
|
:name (string/blank? value)
|
||||||
:url (not (valid-address? value)))})})
|
:url (not (valid-address? value)))})})
|
||||||
|
|
||||||
(fx/defn edit
|
(rf/defn edit
|
||||||
{:events [:bootnodes.ui/add-bootnode-pressed]}
|
{:events [:bootnodes.ui/add-bootnode-pressed]}
|
||||||
[{:keys [db] :as cofx} id]
|
[{:keys [db] :as cofx} id]
|
||||||
(let [{:keys [id
|
(let [{:keys [id
|
||||||
address
|
address
|
||||||
name]} (fetch cofx id)
|
name]}
|
||||||
fxs (fx/merge cofx
|
(fetch cofx id)
|
||||||
(set-input :id id)
|
fxs (rf/merge cofx
|
||||||
(set-input :url (str address))
|
(set-input :id id)
|
||||||
(set-input :name (str name)))]
|
(set-input :url (str address))
|
||||||
|
(set-input :name (str name)))]
|
||||||
(assoc fxs :dispatch [:navigate-to :edit-bootnode])))
|
(assoc fxs :dispatch [:navigate-to :edit-bootnode])))
|
||||||
|
|
||||||
(defn custom-bootnodes-in-use?
|
(defn custom-bootnodes-in-use?
|
||||||
@@ -52,68 +56,75 @@
|
|||||||
(let [network (:networks/current-network db)]
|
(let [network (:networks/current-network db)]
|
||||||
(get-in db [:multiaccount :custom-bootnodes-enabled? network])))
|
(get-in db [:multiaccount :custom-bootnodes-enabled? network])))
|
||||||
|
|
||||||
(fx/defn delete [{{:keys [multiaccount] :as db} :db :as cofx} id]
|
(rf/defn delete
|
||||||
(let [network (:networks/current-network db)
|
[{{:keys [multiaccount] :as db} :db :as cofx} id]
|
||||||
|
(let [network (:networks/current-network db)
|
||||||
new-multiaccount (update-in multiaccount [:custom-bootnodes network] dissoc id)]
|
new-multiaccount (update-in multiaccount [:custom-bootnodes network] dissoc id)]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc db :multiaccount new-multiaccount)}
|
{:db (assoc db :multiaccount new-multiaccount)}
|
||||||
(multiaccounts.update/multiaccount-update
|
(multiaccounts.update/multiaccount-update
|
||||||
:custom-bootnodes (:custom-bootnodes new-multiaccount)
|
:custom-bootnodes
|
||||||
|
(:custom-bootnodes new-multiaccount)
|
||||||
{:success-event (when (custom-bootnodes-in-use? cofx)
|
{:success-event (when (custom-bootnodes-in-use? cofx)
|
||||||
[:multiaccounts.update.callback/save-settings-success])}))))
|
[:multiaccounts.update.callback/save-settings-success])}))))
|
||||||
|
|
||||||
(fx/defn upsert
|
(rf/defn upsert
|
||||||
{:events [:bootnodes.ui/save-pressed]
|
{:events [:bootnodes.ui/save-pressed]
|
||||||
:interceptors [(re-frame/inject-cofx :random-id-generator)]}
|
:interceptors [(re-frame/inject-cofx :random-id-generator)]}
|
||||||
[{{:bootnodes/keys [manage] :keys [multiaccount] :as db} :db
|
[{{:bootnodes/keys [manage] :keys [multiaccount] :as db} :db
|
||||||
random-id-generator :random-id-generator :as cofx}]
|
random-id-generator :random-id-generator
|
||||||
|
:as cofx}]
|
||||||
(let [{:keys [name id url]} manage
|
(let [{:keys [name id url]} manage
|
||||||
network (:networks/current-network db)
|
network (:networks/current-network db)
|
||||||
bootnode (build
|
bootnode (build
|
||||||
(or (:value id) (random-id-generator))
|
(or (:value id) (random-id-generator))
|
||||||
(:value name)
|
(:value name)
|
||||||
(:value url)
|
(:value url)
|
||||||
network)
|
network)
|
||||||
new-bootnodes (assoc-in
|
new-bootnodes (assoc-in
|
||||||
(:custom-bootnodes multiaccount)
|
(:custom-bootnodes multiaccount)
|
||||||
[network (:id bootnode)]
|
[network (:id bootnode)]
|
||||||
bootnode)]
|
bootnode)]
|
||||||
|
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (dissoc db :bootnodes/manage)
|
{:db (dissoc db :bootnodes/manage)
|
||||||
:dispatch [:navigate-back]}
|
:dispatch [:navigate-back]}
|
||||||
(multiaccounts.update/multiaccount-update
|
(multiaccounts.update/multiaccount-update
|
||||||
:custom-bootnodes new-bootnodes
|
:custom-bootnodes
|
||||||
|
new-bootnodes
|
||||||
{:success-event (when (custom-bootnodes-in-use? cofx)
|
{:success-event (when (custom-bootnodes-in-use? cofx)
|
||||||
[:multiaccounts.update.callback/save-settings-success])}))))
|
[:multiaccounts.update.callback/save-settings-success])}))))
|
||||||
|
|
||||||
(fx/defn toggle-custom-bootnodes
|
(rf/defn toggle-custom-bootnodes
|
||||||
{:events [:bootnodes.ui/custom-bootnodes-switch-toggled]}
|
{:events [:bootnodes.ui/custom-bootnodes-switch-toggled]}
|
||||||
[{:keys [db] :as cofx} value]
|
[{:keys [db] :as cofx} value]
|
||||||
(let [current-network (:networks/current-network db)
|
(let [current-network (:networks/current-network db)
|
||||||
bootnodes-settings (get-in db [:multiaccount :custom-bootnodes-enabled?])]
|
bootnodes-settings (get-in db [:multiaccount :custom-bootnodes-enabled?])]
|
||||||
(multiaccounts.update/multiaccount-update
|
(multiaccounts.update/multiaccount-update
|
||||||
cofx
|
cofx
|
||||||
:custom-bootnodes-enabled? (assoc bootnodes-settings current-network value)
|
:custom-bootnodes-enabled?
|
||||||
|
(assoc bootnodes-settings current-network value)
|
||||||
{:success-event [:multiaccounts.update.callback/save-settings-success]})))
|
{:success-event [:multiaccounts.update.callback/save-settings-success]})))
|
||||||
|
|
||||||
(fx/defn set-bootnodes-from-qr
|
(rf/defn set-bootnodes-from-qr
|
||||||
{:events [:bootnodes.callback/qr-code-scanned]}
|
{:events [:bootnodes.callback/qr-code-scanned]}
|
||||||
[cofx url]
|
[cofx url]
|
||||||
(assoc (set-input cofx :url (string/trim url))
|
(assoc (set-input cofx :url (string/trim url))
|
||||||
:dispatch [:navigate-back]))
|
:dispatch
|
||||||
|
[:navigate-back]))
|
||||||
|
|
||||||
(fx/defn show-delete-bootnode-confirmation
|
(rf/defn show-delete-bootnode-confirmation
|
||||||
{:events [:bootnodes.ui/delete-pressed]}
|
{:events [:bootnodes.ui/delete-pressed]}
|
||||||
[_ bootnode-id]
|
[_ bootnode-id]
|
||||||
{:ui/show-confirmation {:title (i18n/label :t/delete-bootnode-title)
|
{:ui/show-confirmation {:title (i18n/label :t/delete-bootnode-title)
|
||||||
:content (i18n/label :t/delete-bootnode-are-you-sure)
|
:content (i18n/label :t/delete-bootnode-are-you-sure)
|
||||||
:confirm-button-text (i18n/label :t/delete-bootnode)
|
:confirm-button-text (i18n/label :t/delete-bootnode)
|
||||||
:on-accept #(re-frame/dispatch [:bootnodes.ui/delete-confirmed bootnode-id])}})
|
:on-accept #(re-frame/dispatch [:bootnodes.ui/delete-confirmed
|
||||||
|
bootnode-id])}})
|
||||||
|
|
||||||
(fx/defn delete-bootnode
|
(rf/defn delete-bootnode
|
||||||
{:events [:bootnodes.ui/delete-confirmed]}
|
{:events [:bootnodes.ui/delete-confirmed]}
|
||||||
[cofx bootnode-id]
|
[cofx bootnode-id]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(delete bootnode-id)
|
(delete bootnode-id)
|
||||||
(navigation/navigate-back)))
|
(navigation/navigate-back)))
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
(ns status-im.bottom-sheet.core
|
(ns status-im.bottom-sheet.core
|
||||||
(:require [status-im.utils.fx :as fx]))
|
(:require [utils.re-frame :as rf]))
|
||||||
|
|
||||||
(fx/defn show-bottom-sheet
|
(rf/defn show-bottom-sheet
|
||||||
[{:keys [db]} {:keys [view options]}]
|
[{:keys [db]} {:keys [view options]}]
|
||||||
{:show-bottom-sheet nil
|
{:show-bottom-sheet nil
|
||||||
:db (assoc db
|
:db (assoc db
|
||||||
:bottom-sheet/show? true
|
:bottom-sheet/show? true
|
||||||
:bottom-sheet/view view
|
:bottom-sheet/view view
|
||||||
:bottom-sheet/options options)})
|
:bottom-sheet/options options)})
|
||||||
|
|
||||||
(fx/defn show-bottom-sheet-event
|
(rf/defn show-bottom-sheet-event
|
||||||
{:events [:bottom-sheet/show-sheet]}
|
{:events [:bottom-sheet/show-sheet]}
|
||||||
[cofx view options]
|
[cofx view options]
|
||||||
(show-bottom-sheet
|
(show-bottom-sheet
|
||||||
@@ -17,8 +17,8 @@
|
|||||||
{:view view
|
{:view view
|
||||||
:options options}))
|
:options options}))
|
||||||
|
|
||||||
(fx/defn hide-bottom-sheet
|
(rf/defn hide-bottom-sheet
|
||||||
{:events [:bottom-sheet/hide]}
|
{:events [:bottom-sheet/hide]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
{:hide-bottom-sheet nil
|
{:hide-bottom-sheet nil
|
||||||
:db (assoc db :bottom-sheet/show? false)})
|
:db (assoc db :bottom-sheet/show? false)})
|
||||||
|
|||||||
+195
-152
@@ -1,62 +1,65 @@
|
|||||||
(ns status-im.browser.core
|
(ns status-im.browser.core
|
||||||
(:require [clojure.string :as string]
|
(:require ["eth-phishing-detect" :as eth-phishing-detect]
|
||||||
|
[clojure.string :as string]
|
||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
|
[status-im.bottom-sheet.core :as bottom-sheet]
|
||||||
|
[status-im.browser.eip3085 :as eip3085]
|
||||||
|
[status-im.browser.eip3326 :as eip3326]
|
||||||
[status-im.browser.permissions :as browser.permissions]
|
[status-im.browser.permissions :as browser.permissions]
|
||||||
|
[status-im.browser.webview-ref :as webview-ref]
|
||||||
[status-im.constants :as constants]
|
[status-im.constants :as constants]
|
||||||
[status-im.ethereum.core :as ethereum]
|
[status-im.ethereum.core :as ethereum]
|
||||||
[status-im.ethereum.ens :as ens]
|
[status-im.ethereum.ens :as ens]
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
[status-im.i18n.i18n :as i18n]
|
[status-im.i18n.i18n :as i18n]
|
||||||
|
[status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||||
[status-im.native-module.core :as status]
|
[status-im.native-module.core :as status]
|
||||||
|
[status-im.signing.core :as signing]
|
||||||
[status-im.ui.components.list-selection :as list-selection]
|
[status-im.ui.components.list-selection :as list-selection]
|
||||||
[status-im2.navigation.events :as navigation]
|
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[status-im.utils.http :as http]
|
[status-im.utils.http :as http]
|
||||||
[status-im.utils.platform :as platform]
|
[status-im.utils.platform :as platform]
|
||||||
[status-im.utils.random :as random]
|
[status-im.utils.random :as random]
|
||||||
[status-im.utils.types :as types]
|
[status-im.utils.types :as types]
|
||||||
[status-im.utils.universal-links.utils :as links]
|
[status-im.utils.universal-links.utils :as links]
|
||||||
|
[status-im2.navigation.events :as navigation]
|
||||||
[taoensso.timbre :as log]
|
[taoensso.timbre :as log]
|
||||||
[status-im.signing.core :as signing]
|
|
||||||
[status-im.multiaccounts.update.core :as multiaccounts.update]
|
|
||||||
[status-im.bottom-sheet.core :as bottom-sheet]
|
|
||||||
[status-im.browser.webview-ref :as webview-ref]
|
|
||||||
["eth-phishing-detect" :as eth-phishing-detect]
|
|
||||||
[utils.debounce :as debounce]
|
[utils.debounce :as debounce]
|
||||||
[status-im.browser.eip3085 :as eip3085]
|
[utils.re-frame :as rf]))
|
||||||
[status-im.browser.eip3326 :as eip3326]))
|
|
||||||
|
|
||||||
(fx/defn update-browser-option
|
(rf/defn update-browser-option
|
||||||
[{:keys [db]} option-key option-value]
|
[{:keys [db]} option-key option-value]
|
||||||
{:db (assoc-in db [:browser/options option-key] option-value)})
|
{:db (assoc-in db [:browser/options option-key] option-value)})
|
||||||
|
|
||||||
(fx/defn update-browser-options
|
(rf/defn update-browser-options
|
||||||
[{:keys [db]} options]
|
[{:keys [db]} options]
|
||||||
{:db (update db :browser/options merge options)})
|
{:db (update db :browser/options merge options)})
|
||||||
|
|
||||||
(defn get-current-browser [db]
|
(defn get-current-browser
|
||||||
|
[db]
|
||||||
(get-in db [:browser/browsers (get-in db [:browser/options :browser-id])]))
|
(get-in db [:browser/browsers (get-in db [:browser/options :browser-id])]))
|
||||||
|
|
||||||
(defn get-current-url [{:keys [history history-index]
|
(defn get-current-url
|
||||||
:or {history-index 0}}]
|
[{:keys [history history-index]
|
||||||
|
:or {history-index 0}}]
|
||||||
(when history
|
(when history
|
||||||
(nth history history-index)))
|
(nth history history-index)))
|
||||||
|
|
||||||
(defn secure? [{:keys [error? dapp?]} {:keys [url]}]
|
(defn secure?
|
||||||
|
[{:keys [error? dapp?]} {:keys [url]}]
|
||||||
(or dapp?
|
(or dapp?
|
||||||
(and (not error?)
|
(and (not error?)
|
||||||
(when url
|
(when url
|
||||||
(string/starts-with? url "https://")))))
|
(string/starts-with? url "https://")))))
|
||||||
|
|
||||||
(fx/defn remove-browser
|
(rf/defn remove-browser
|
||||||
{:events [:browser.ui/remove-browser-pressed]}
|
{:events [:browser.ui/remove-browser-pressed]}
|
||||||
[{:keys [db]} browser-id]
|
[{:keys [db]} browser-id]
|
||||||
{:db (update-in db [:browser/browsers] dissoc browser-id)
|
{:db (update-in db [:browser/browsers] dissoc browser-id)
|
||||||
::json-rpc/call [{:method "wakuext_deleteBrowser"
|
::json-rpc/call [{:method "wakuext_deleteBrowser"
|
||||||
:params [browser-id]
|
:params [browser-id]
|
||||||
:on-success #()}]})
|
:on-success #()}]})
|
||||||
|
|
||||||
(fx/defn clear-all-browsers
|
(rf/defn clear-all-browsers
|
||||||
{:events [:browser.ui/clear-all-browsers-pressed]}
|
{:events [:browser.ui/clear-all-browsers-pressed]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
{:db (dissoc db :browser/browsers)
|
{:db (dissoc db :browser/browsers)
|
||||||
@@ -65,106 +68,116 @@
|
|||||||
:params [browser-id]
|
:params [browser-id]
|
||||||
:on-success #()})})
|
:on-success #()})})
|
||||||
|
|
||||||
(defn update-dapp-name [{:keys [name] :as browser}]
|
(defn update-dapp-name
|
||||||
|
[{:keys [name] :as browser}]
|
||||||
(assoc browser :dapp? false :name (or name (i18n/label :t/browser))))
|
(assoc browser :dapp? false :name (or name (i18n/label :t/browser))))
|
||||||
|
|
||||||
(defn check-if-phishing-url [{:keys [history history-index] :as browser}]
|
(defn check-if-phishing-url
|
||||||
|
[{:keys [history history-index] :as browser}]
|
||||||
(let [history-host (http/url-host (try (nth history history-index) (catch js/Error _)))]
|
(let [history-host (http/url-host (try (nth history history-index) (catch js/Error _)))]
|
||||||
(cond-> browser history-host (assoc :unsafe? (eth-phishing-detect history-host)))))
|
(cond-> browser history-host (assoc :unsafe? (eth-phishing-detect history-host)))))
|
||||||
|
|
||||||
(defn resolve-ens-contenthash-callback [url]
|
(defn resolve-ens-contenthash-callback
|
||||||
|
[url]
|
||||||
(if (not (string/blank? url))
|
(if (not (string/blank? url))
|
||||||
(re-frame/dispatch [:browser.callback/resolve-ens-multihash-success url])
|
(re-frame/dispatch [:browser.callback/resolve-ens-multihash-success url])
|
||||||
(re-frame/dispatch [:browser.callback/resolve-ens-multihash-error])))
|
(re-frame/dispatch [:browser.callback/resolve-ens-multihash-error])))
|
||||||
|
|
||||||
(fx/defn resolve-url
|
(rf/defn resolve-url
|
||||||
[{:keys [db]} {:keys [error? resolved-url]}]
|
[{:keys [db]} {:keys [error? resolved-url]}]
|
||||||
(when (not error?)
|
(when (not error?)
|
||||||
(let [current-url (get-current-url (get-current-browser db))
|
(let [current-url (get-current-url (get-current-browser db))
|
||||||
host (http/url-host current-url)]
|
host (http/url-host current-url)]
|
||||||
(if (and (not resolved-url) (ens/is-valid-eth-name? host))
|
(if (and (not resolved-url) (ens/is-valid-eth-name? host))
|
||||||
{:db (update db :browser/options assoc :resolving? true)
|
{:db (update db :browser/options assoc :resolving? true)
|
||||||
:browser/resolve-ens-contenthash {:chain-id (ethereum/chain-id db)
|
:browser/resolve-ens-contenthash {:chain-id (ethereum/chain-id db)
|
||||||
:ens-name host
|
:ens-name host
|
||||||
:cb resolve-ens-contenthash-callback}}
|
:cb resolve-ens-contenthash-callback}}
|
||||||
{:db (update db :browser/options assoc :url (or resolved-url current-url) :resolving? false)}))))
|
{:db (update db :browser/options assoc :url (or resolved-url current-url) :resolving? false)}))))
|
||||||
|
|
||||||
(fx/defn update-browser
|
(rf/defn update-browser
|
||||||
[{:keys [db]}
|
[{:keys [db]}
|
||||||
{:keys [browser-id] :as browser}]
|
{:keys [browser-id] :as browser}]
|
||||||
(let [updated-browser (-> browser
|
(let [updated-browser (-> browser
|
||||||
(update-dapp-name)
|
(update-dapp-name)
|
||||||
(check-if-phishing-url))]
|
(check-if-phishing-url))]
|
||||||
{:db (update-in db
|
{:db (update-in db
|
||||||
[:browser/browsers browser-id]
|
[:browser/browsers browser-id]
|
||||||
merge updated-browser)
|
merge
|
||||||
::json-rpc/call [{:method "wakuext_addBrowser"
|
updated-browser)
|
||||||
:params [(select-keys updated-browser [:browser-id :timestamp :name :dapp? :history :history-index])]
|
::json-rpc/call [{:method "wakuext_addBrowser"
|
||||||
|
:params [(select-keys updated-browser
|
||||||
|
[:browser-id :timestamp :name :dapp? :history
|
||||||
|
:history-index])]
|
||||||
:on-success #()}]}))
|
:on-success #()}]}))
|
||||||
|
|
||||||
(fx/defn store-bookmark
|
(rf/defn store-bookmark
|
||||||
{:events [:browser/store-bookmark]}
|
{:events [:browser/store-bookmark]}
|
||||||
[{:keys [db]}
|
[{:keys [db]}
|
||||||
{:keys [url] :as bookmark}]
|
{:keys [url] :as bookmark}]
|
||||||
{:db (assoc-in db [:bookmarks/bookmarks url] bookmark)
|
{:db (assoc-in db [:bookmarks/bookmarks url] bookmark)
|
||||||
::json-rpc/call [{:method "wakuext_addBookmark"
|
::json-rpc/call [{:method "wakuext_addBookmark"
|
||||||
:params [bookmark]
|
:params [bookmark]
|
||||||
:on-success #()}]})
|
:on-success #()}]})
|
||||||
|
|
||||||
(fx/defn update-bookmark
|
(rf/defn update-bookmark
|
||||||
{:events [:browser/update-bookmark]}
|
{:events [:browser/update-bookmark]}
|
||||||
[{:keys [db] :as cofx}
|
[{:keys [db] :as cofx}
|
||||||
{:keys [url] :as bookmark}]
|
{:keys [url] :as bookmark}]
|
||||||
(let [old-bookmark (get-in db [:bookmarks/bookmarks url])
|
(let [old-bookmark (get-in db [:bookmarks/bookmarks url])
|
||||||
new-bookmark (merge old-bookmark bookmark)]
|
new-bookmark (merge old-bookmark bookmark)]
|
||||||
(fx/merge cofx {:db (assoc-in db [:bookmarks/bookmarks url] new-bookmark)
|
(rf/merge cofx
|
||||||
::json-rpc/call [{:method "wakuext_updateBookmark"
|
{:db (assoc-in db [:bookmarks/bookmarks url] new-bookmark)
|
||||||
:params [url bookmark]
|
::json-rpc/call [{:method "wakuext_updateBookmark"
|
||||||
:on-success #()}]})))
|
:params [url bookmark]
|
||||||
|
:on-success #()}]})))
|
||||||
|
|
||||||
(fx/defn delete-bookmark
|
(rf/defn delete-bookmark
|
||||||
{:events [:browser/delete-bookmark]}
|
{:events [:browser/delete-bookmark]}
|
||||||
[{:keys [db] :as cofx}
|
[{:keys [db] :as cofx}
|
||||||
url]
|
url]
|
||||||
(let [old-bookmark (get-in db [:bookmarks/bookmarks url])
|
(let [old-bookmark (get-in db [:bookmarks/bookmarks url])
|
||||||
removed-bookmark (merge old-bookmark {:removed true})]
|
removed-bookmark (merge old-bookmark {:removed true})]
|
||||||
(fx/merge cofx {:db (update db :bookmarks/bookmarks dissoc url)
|
(rf/merge cofx
|
||||||
::json-rpc/call [{:method "wakuext_removeBookmark"
|
{:db (update db :bookmarks/bookmarks dissoc url)
|
||||||
:params [url]
|
::json-rpc/call [{:method "wakuext_removeBookmark"
|
||||||
:on-success #()}]})))
|
:params [url]
|
||||||
|
:on-success #()}]})))
|
||||||
|
|
||||||
(defn can-go-back? [{:keys [history-index]}]
|
(defn can-go-back?
|
||||||
|
[{:keys [history-index]}]
|
||||||
(pos? history-index))
|
(pos? history-index))
|
||||||
|
|
||||||
(fx/defn navigate-to-previous-page
|
(rf/defn navigate-to-previous-page
|
||||||
{:events [:browser.ui/previous-page-button-pressed]}
|
{:events [:browser.ui/previous-page-button-pressed]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(let [{:keys [history-index] :as browser} (get-current-browser (:db cofx))]
|
(let [{:keys [history-index] :as browser} (get-current-browser (:db cofx))]
|
||||||
(when (can-go-back? browser)
|
(when (can-go-back? browser)
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(update-browser (assoc browser :history-index (dec history-index)))
|
(update-browser (assoc browser :history-index (dec history-index)))
|
||||||
(resolve-url nil)))))
|
(resolve-url nil)))))
|
||||||
|
|
||||||
(fx/defn ignore-unsafe
|
(rf/defn ignore-unsafe
|
||||||
{:events [:browser/ignore-unsafe]}
|
{:events [:browser/ignore-unsafe]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(let [browser (get-current-browser (:db cofx))
|
(let [browser (get-current-browser (:db cofx))
|
||||||
host (http/url-host (get-current-url browser))]
|
host (http/url-host (get-current-url browser))]
|
||||||
(update-browser cofx (assoc browser :ignore-unsafe host))))
|
(update-browser cofx (assoc browser :ignore-unsafe host))))
|
||||||
|
|
||||||
(defn can-go-forward? [{:keys [history-index history]}]
|
(defn can-go-forward?
|
||||||
|
[{:keys [history-index history]}]
|
||||||
(< history-index (dec (count history))))
|
(< history-index (dec (count history))))
|
||||||
|
|
||||||
(fx/defn navigate-to-next-page
|
(rf/defn navigate-to-next-page
|
||||||
{:events [:browser.ui/next-page-button-pressed]}
|
{:events [:browser.ui/next-page-button-pressed]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(let [{:keys [history-index] :as browser} (get-current-browser (:db cofx))]
|
(let [{:keys [history-index] :as browser} (get-current-browser (:db cofx))]
|
||||||
(when (can-go-forward? browser)
|
(when (can-go-forward? browser)
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(update-browser (assoc browser :history-index (inc history-index)))
|
(update-browser (assoc browser :history-index (inc history-index)))
|
||||||
(resolve-url nil)))))
|
(resolve-url nil)))))
|
||||||
|
|
||||||
(fx/defn update-browser-history
|
(rf/defn update-browser-history
|
||||||
[cofx browser url]
|
[cofx browser url]
|
||||||
(let [history-index (:history-index browser)
|
(let [history-index (:history-index browser)
|
||||||
history (:history browser)]
|
history (:history browser)]
|
||||||
@@ -173,73 +186,81 @@
|
|||||||
new-index (dec (count new-history))]
|
new-index (dec (count new-history))]
|
||||||
(update-browser cofx
|
(update-browser cofx
|
||||||
(assoc browser
|
(assoc browser
|
||||||
:history new-history
|
:history new-history
|
||||||
:history-index new-index))))))
|
:history-index new-index))))))
|
||||||
|
|
||||||
(fx/defn resolve-ens-multihash-success
|
(rf/defn resolve-ens-multihash-success
|
||||||
{:events [:browser.callback/resolve-ens-multihash-success]}
|
{:events [:browser.callback/resolve-ens-multihash-success]}
|
||||||
[{:keys [db] :as cofx} url]
|
[{:keys [db] :as cofx} url]
|
||||||
(let [current-url (get-current-url (get-current-browser db))
|
(let [current-url (get-current-url (get-current-browser db))
|
||||||
host (http/url-host current-url)
|
host (http/url-host current-url)
|
||||||
path (subs current-url (+ (.indexOf ^js current-url host) (count host)))
|
path (subs current-url (+ (.indexOf ^js current-url host) (count host)))
|
||||||
gateway url]
|
gateway url]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (-> (update db :browser/options
|
{:db (-> (update db
|
||||||
|
:browser/options
|
||||||
assoc
|
assoc
|
||||||
:url (str gateway path)
|
:url (str gateway path)
|
||||||
:resolving? false)
|
:resolving? false)
|
||||||
(assoc-in [:browser/options :resolved-ens host] gateway))})))
|
(assoc-in [:browser/options :resolved-ens host] gateway))})))
|
||||||
|
|
||||||
(fx/defn resolve-ens-multihash-error
|
(rf/defn resolve-ens-multihash-error
|
||||||
{:events [:browser.callback/resolve-ens-multihash-error]}
|
{:events [:browser.callback/resolve-ens-multihash-error]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(update-browser-options cofx {:url (get-current-url (get-current-browser db))
|
(update-browser-options cofx
|
||||||
:resolving? false
|
{:url (get-current-url (get-current-browser db))
|
||||||
:error? true}))
|
:resolving? false
|
||||||
|
:error? true}))
|
||||||
|
|
||||||
(fx/defn handle-browser-error
|
(rf/defn handle-browser-error
|
||||||
{:events [:browser/error-occured]}
|
{:events [:browser/error-occured]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(update-browser-option :error? true)
|
(update-browser-option :error? true)
|
||||||
(update-browser-option :loading? false)))
|
(update-browser-option :loading? false)))
|
||||||
|
|
||||||
(fx/defn handle-pdf
|
(rf/defn handle-pdf
|
||||||
[_ url]
|
[_ url]
|
||||||
(when (and platform/android? (string/ends-with? url ".pdf"))
|
(when (and platform/android? (string/ends-with? url ".pdf"))
|
||||||
{:browser/show-web-browser-selection url}))
|
{:browser/show-web-browser-selection url}))
|
||||||
|
|
||||||
(fx/defn handle-message-link
|
(rf/defn handle-message-link
|
||||||
{:events [:browser.ui/message-link-pressed]}
|
{:events [:browser.ui/message-link-pressed]}
|
||||||
[_ link]
|
[_ link]
|
||||||
(if (links/universal-link? link)
|
(if (links/universal-link? link)
|
||||||
{:dispatch [:universal-links/handle-url link]}
|
{:dispatch [:universal-links/handle-url link]}
|
||||||
{:browser/show-browser-selection link}))
|
{:browser/show-browser-selection link}))
|
||||||
|
|
||||||
(fx/defn update-browser-on-nav-change
|
(rf/defn update-browser-on-nav-change
|
||||||
[cofx url error?]
|
[cofx url error?]
|
||||||
(let [browser (get-current-browser (:db cofx))
|
(let [browser (get-current-browser (:db cofx))
|
||||||
options (get-in cofx [:db :browser/options])
|
options (get-in cofx [:db :browser/options])
|
||||||
current-url (:url options)]
|
current-url (:url options)]
|
||||||
(when (and browser (not (string/blank? url)) (not= "about:blank" url) (not= current-url url) (not= (str current-url "/") url))
|
(when (and browser
|
||||||
|
(not (string/blank? url))
|
||||||
|
(not= "about:blank" url)
|
||||||
|
(not= current-url url)
|
||||||
|
(not= (str current-url "/") url))
|
||||||
(let [resolved-ens (first (filter (fn [v]
|
(let [resolved-ens (first (filter (fn [v]
|
||||||
(not= (.indexOf ^js url (second v)) -1))
|
(not= (.indexOf ^js url (second v)) -1))
|
||||||
(:resolved-ens options)))
|
(:resolved-ens options)))
|
||||||
resolved-url (if resolved-ens
|
resolved-url (if resolved-ens
|
||||||
(http/normalize-url (string/replace url (second resolved-ens) (first resolved-ens)))
|
(http/normalize-url (string/replace url
|
||||||
|
(second resolved-ens)
|
||||||
|
(first resolved-ens)))
|
||||||
url)]
|
url)]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(update-browser-history browser resolved-url)
|
(update-browser-history browser resolved-url)
|
||||||
(handle-pdf url)
|
(handle-pdf url)
|
||||||
(resolve-url {:error? error? :resolved-url (when resolved-ens url)}))))))
|
(resolve-url {:error? error? :resolved-url (when resolved-ens url)}))))))
|
||||||
|
|
||||||
(fx/defn update-browser-name
|
(rf/defn update-browser-name
|
||||||
[cofx title]
|
[cofx title]
|
||||||
(let [browser (get-current-browser (:db cofx))]
|
(let [browser (get-current-browser (:db cofx))]
|
||||||
(when (and browser (not (:dapp? browser)) title (not (string/blank? title)))
|
(when (and browser (not (:dapp? browser)) title (not (string/blank? title)))
|
||||||
(update-browser cofx (assoc browser :name title)))))
|
(update-browser cofx (assoc browser :name title)))))
|
||||||
|
|
||||||
(fx/defn navigation-state-changed
|
(rf/defn navigation-state-changed
|
||||||
{:events [:browser/navigation-state-changed]}
|
{:events [:browser/navigation-state-changed]}
|
||||||
[cofx event error?]
|
[cofx event error?]
|
||||||
(let [{:strs [url loading title]} (js->clj event)
|
(let [{:strs [url loading title]} (js->clj event)
|
||||||
@@ -247,59 +268,61 @@
|
|||||||
(if (links/universal-link? url)
|
(if (links/universal-link? url)
|
||||||
(when-not (and deep-link? platform/ios?) ;; ios webview handles this
|
(when-not (and deep-link? platform/ios?) ;; ios webview handles this
|
||||||
{:dispatch [:universal-links/handle-url url]})
|
{:dispatch [:universal-links/handle-url url]})
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(update-browser-option :loading? loading)
|
(update-browser-option :loading? loading)
|
||||||
(update-browser-name title)
|
(update-browser-name title)
|
||||||
(update-browser-on-nav-change url error?)))))
|
(update-browser-on-nav-change url error?)))))
|
||||||
|
|
||||||
(fx/defn open-url-in-current-browser
|
(rf/defn open-url-in-current-browser
|
||||||
"Opens a url in the current browser, which mean no new entry is added to the home page
|
"Opens a url in the current browser, which mean no new entry is added to the home page
|
||||||
and history of the current browser is updated so that the user can navigate back to the
|
and history of the current browser is updated so that the user can navigate back to the
|
||||||
origin url"
|
origin url"
|
||||||
{:events [:browser.ui/url-submitted]}
|
{:events [:browser.ui/url-submitted]}
|
||||||
[cofx url]
|
[cofx url]
|
||||||
(let [browser (get-current-browser (:db cofx))
|
(let [browser (get-current-browser (:db cofx))
|
||||||
normalized-url (http/normalize-and-decode-url url)]
|
normalized-url (http/normalize-and-decode-url url)]
|
||||||
(if (links/universal-link? normalized-url)
|
(if (links/universal-link? normalized-url)
|
||||||
{:dispatch [:universal-links/handle-url normalized-url]}
|
{:dispatch [:universal-links/handle-url normalized-url]}
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(update-browser-option :url-editing? false)
|
(update-browser-option :url-editing? false)
|
||||||
(update-browser-history browser normalized-url)
|
(update-browser-history browser normalized-url)
|
||||||
(resolve-url nil)))))
|
(resolve-url nil)))))
|
||||||
|
|
||||||
(fx/defn open-url
|
(rf/defn open-url
|
||||||
"Opens a url in the browser. If a host can be extracted from the url and
|
"Opens a url in the browser. If a host can be extracted from the url and
|
||||||
there is already a browser for this host, this browser is reused
|
there is already a browser for this host, this browser is reused
|
||||||
If the browser is reused, the history is flushed"
|
If the browser is reused, the history is flushed"
|
||||||
{:events [:browser.ui/open-url]}
|
{:events [:browser.ui/open-url]}
|
||||||
[{:keys [db] :as cofx} url]
|
[{:keys [db] :as cofx} url]
|
||||||
(let [normalized-url (http/normalize-and-decode-url url)
|
(let [normalized-url (http/normalize-and-decode-url url)
|
||||||
browser {:browser-id (random/id)
|
browser {:browser-id (random/id)
|
||||||
:history-index 0
|
:history-index 0
|
||||||
:history [normalized-url]}]
|
:history [normalized-url]}]
|
||||||
(if (links/universal-link? normalized-url)
|
(if (links/universal-link? normalized-url)
|
||||||
{:dispatch [:universal-links/handle-url normalized-url]}
|
{:dispatch [:universal-links/handle-url normalized-url]}
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc db :browser/options
|
{:db (assoc db
|
||||||
|
:browser/options
|
||||||
{:browser-id (:browser-id browser)})}
|
{:browser-id (:browser-id browser)})}
|
||||||
(navigation/change-tab :browser)
|
(navigation/change-tab :browser)
|
||||||
(navigation/set-stack-root :browser-stack :browser)
|
(navigation/set-stack-root :browser-stack :browser)
|
||||||
(update-browser browser)
|
(update-browser browser)
|
||||||
(resolve-url nil)))))
|
(resolve-url nil)))))
|
||||||
|
|
||||||
(fx/defn open-existing-browser
|
(rf/defn open-existing-browser
|
||||||
"Opens an existing browser with it's history"
|
"Opens an existing browser with it's history"
|
||||||
{:events [:browser.ui/browser-item-selected]}
|
{:events [:browser.ui/browser-item-selected]}
|
||||||
[{:keys [db] :as cofx} browser-id]
|
[{:keys [db] :as cofx} browser-id]
|
||||||
(let [browser (get-in db [:browser/browsers browser-id])]
|
(let [browser (get-in db [:browser/browsers browser-id])]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc db :browser/options
|
{:db (assoc db
|
||||||
|
:browser/options
|
||||||
{:browser-id browser-id})}
|
{:browser-id browser-id})}
|
||||||
(update-browser browser)
|
(update-browser browser)
|
||||||
(navigation/set-stack-root :browser-stack :browser)
|
(navigation/set-stack-root :browser-stack :browser)
|
||||||
(resolve-url nil))))
|
(resolve-url nil))))
|
||||||
|
|
||||||
(fx/defn web3-error-callback
|
(rf/defn web3-error-callback
|
||||||
{:events [:browser.dapp/transaction-on-error]}
|
{:events [:browser.dapp/transaction-on-error]}
|
||||||
[_ message-id message]
|
[_ message-id message]
|
||||||
{:browser/send-to-bridge
|
{:browser/send-to-bridge
|
||||||
@@ -307,7 +330,7 @@
|
|||||||
:messageId message-id
|
:messageId message-id
|
||||||
:error message}})
|
:error message}})
|
||||||
|
|
||||||
(fx/defn dapp-complete-transaction
|
(rf/defn dapp-complete-transaction
|
||||||
{:events [:browser.dapp/transaction-on-result]}
|
{:events [:browser.dapp/transaction-on-result]}
|
||||||
[_ message-id id result]
|
[_ message-id id result]
|
||||||
;;TODO check and test id
|
;;TODO check and test id
|
||||||
@@ -336,21 +359,24 @@
|
|||||||
(ethereum/address? second-param)
|
(ethereum/address? second-param)
|
||||||
[second-param (if typed? first-param (normalize-message first-param))]))))
|
[second-param (if typed? first-param (normalize-message first-param))]))))
|
||||||
|
|
||||||
(fx/defn send-to-bridge
|
(rf/defn send-to-bridge
|
||||||
{:events [:browser.callback/call-rpc]}
|
{:events [:browser.callback/call-rpc]}
|
||||||
[_ message]
|
[_ message]
|
||||||
{:browser/send-to-bridge message})
|
{:browser/send-to-bridge message})
|
||||||
|
|
||||||
(defn web3-sign-message? [method]
|
(defn web3-sign-message?
|
||||||
|
[method]
|
||||||
(#{constants/web3-sign-typed-data constants/web3-sign-typed-data-v3 constants/web3-sign-typed-data-v4
|
(#{constants/web3-sign-typed-data constants/web3-sign-typed-data-v3 constants/web3-sign-typed-data-v4
|
||||||
constants/web3-personal-sign
|
constants/web3-personal-sign
|
||||||
constants/web3-eth-sign constants/web3-keycard-sign-typed-data} method))
|
constants/web3-eth-sign constants/web3-keycard-sign-typed-data}
|
||||||
|
method))
|
||||||
|
|
||||||
(fx/defn web3-send-async
|
(rf/defn web3-send-async
|
||||||
[cofx dapp-name {:keys [method params id] :as payload} message-id]
|
[cofx dapp-name {:keys [method params id] :as payload} message-id]
|
||||||
(let [message? (web3-sign-message? method)
|
(let [message? (web3-sign-message? method)
|
||||||
dapps-address (get-in cofx [:db :multiaccount :dapps-address])
|
dapps-address (get-in cofx [:db :multiaccount :dapps-address])
|
||||||
typed? (and (not= constants/web3-personal-sign method) (not= constants/web3-eth-sign method))]
|
typed? (and (not= constants/web3-personal-sign method)
|
||||||
|
(not= constants/web3-eth-sign method))]
|
||||||
(if (or message? (= constants/web3-send-transaction method))
|
(if (or message? (= constants/web3-send-transaction method))
|
||||||
(let [[address data] (cond (and (= method constants/web3-keycard-sign-typed-data)
|
(let [[address data] (cond (and (= method constants/web3-keycard-sign-typed-data)
|
||||||
(not (vector? params)))
|
(not (vector? params)))
|
||||||
@@ -359,34 +385,38 @@
|
|||||||
message? (normalize-sign-message-params params typed?)
|
message? (normalize-sign-message-params params typed?)
|
||||||
:else [nil nil])]
|
:else [nil nil])]
|
||||||
(when (or (not message?) (and address data))
|
(when (or (not message?) (and address data))
|
||||||
(signing/sign cofx (merge
|
(signing/sign cofx
|
||||||
(if message?
|
(merge
|
||||||
{:message {:address address
|
(if message?
|
||||||
:data data
|
{:message {:address address
|
||||||
:v4 (= constants/web3-sign-typed-data-v4 method)
|
:data data
|
||||||
:typed? typed?
|
:v4 (= constants/web3-sign-typed-data-v4 method)
|
||||||
:pinless? (= method constants/web3-keycard-sign-typed-data)
|
:typed? typed?
|
||||||
:from dapps-address}}
|
:pinless? (= method constants/web3-keycard-sign-typed-data)
|
||||||
{:tx-obj (-> params
|
:from dapps-address}}
|
||||||
first
|
{:tx-obj (-> params
|
||||||
(update :from #(or % dapps-address))
|
first
|
||||||
(dissoc :gasPrice))})
|
(update :from #(or % dapps-address))
|
||||||
{:on-result [:browser.dapp/transaction-on-result message-id id]
|
(dissoc :gasPrice))})
|
||||||
:on-error [:browser.dapp/transaction-on-error message-id]}))))
|
{:on-result [:browser.dapp/transaction-on-result message-id id]
|
||||||
|
:on-error [:browser.dapp/transaction-on-error message-id]}))))
|
||||||
(cond
|
(cond
|
||||||
(#{"eth_accounts" "eth_coinbase"} method)
|
(#{"eth_accounts" "eth_coinbase"} method)
|
||||||
(send-to-bridge cofx {:type constants/web3-send-async-callback
|
(send-to-bridge
|
||||||
:messageId message-id
|
cofx
|
||||||
:result {:jsonrpc "2.0"
|
{:type constants/web3-send-async-callback
|
||||||
:id (int id)
|
:messageId message-id
|
||||||
:result (if (= method "eth_coinbase") dapps-address [dapps-address])}})
|
:result {:jsonrpc "2.0"
|
||||||
|
:id (int id)
|
||||||
|
:result (if (= method "eth_coinbase") dapps-address [dapps-address])}})
|
||||||
(= method "personal_ecRecover")
|
(= method "personal_ecRecover")
|
||||||
{:signing.fx/recover-message {:params {:message (first params)
|
{:signing.fx/recover-message {:params {:message (first params)
|
||||||
:signature (second params)}
|
:signature (second params)}
|
||||||
:on-completed #(re-frame/dispatch [:browser.callback/call-rpc
|
:on-completed #(re-frame/dispatch
|
||||||
{:type constants/web3-send-async-callback
|
[:browser.callback/call-rpc
|
||||||
:messageId message-id
|
{:type constants/web3-send-async-callback
|
||||||
:result (types/json->clj %)}])}}
|
:messageId message-id
|
||||||
|
:result (types/json->clj %)}])}}
|
||||||
(= method "wallet_switchEthereumChain")
|
(= method "wallet_switchEthereumChain")
|
||||||
(eip3326/handle-switch-ethereum-chain cofx dapp-name id message-id (first params))
|
(eip3326/handle-switch-ethereum-chain cofx dapp-name id message-id (first params))
|
||||||
|
|
||||||
@@ -401,7 +431,8 @@
|
|||||||
:error %1
|
:error %1
|
||||||
:result %2}])]}))))
|
:result %2}])]}))))
|
||||||
|
|
||||||
(fx/defn handle-no-permissions [cofx {:keys [method id]} message-id]
|
(rf/defn handle-no-permissions
|
||||||
|
[cofx {:keys [method id]} message-id]
|
||||||
(if (= method "eth_accounts")
|
(if (= method "eth_accounts")
|
||||||
;; eth_accounts returns empty array for compatibility with meta-mask
|
;; eth_accounts returns empty array for compatibility with meta-mask
|
||||||
(send-to-bridge cofx
|
(send-to-bridge cofx
|
||||||
@@ -420,41 +451,48 @@
|
|||||||
"keycard_signTypedData"
|
"keycard_signTypedData"
|
||||||
"eth_signTypedData" "personal_sign" "personal_ecRecover"})
|
"eth_signTypedData" "personal_sign" "personal_ecRecover"})
|
||||||
|
|
||||||
(defn has-permissions? [{:dapps/keys [permissions]} dapp-name method]
|
(defn has-permissions?
|
||||||
|
[{:dapps/keys [permissions]} dapp-name method]
|
||||||
(boolean
|
(boolean
|
||||||
(and (permissioned-method method)
|
(and (permissioned-method method)
|
||||||
(not (some #{constants/dapp-permission-web3} (get-in permissions [dapp-name :permissions]))))))
|
(not (some #{constants/dapp-permission-web3} (get-in permissions [dapp-name :permissions]))))))
|
||||||
|
|
||||||
(fx/defn web3-send-async-read-only
|
(rf/defn web3-send-async-read-only
|
||||||
[{:keys [db] :as cofx} dapp-name {:keys [method] :as payload} message-id]
|
[{:keys [db] :as cofx} dapp-name {:keys [method] :as payload} message-id]
|
||||||
(if (has-permissions? db dapp-name method)
|
(if (has-permissions? db dapp-name method)
|
||||||
(handle-no-permissions cofx payload message-id)
|
(handle-no-permissions cofx payload message-id)
|
||||||
(web3-send-async cofx dapp-name payload message-id)))
|
(web3-send-async cofx dapp-name payload message-id)))
|
||||||
|
|
||||||
(fx/defn handle-scanned-qr-code
|
(rf/defn handle-scanned-qr-code
|
||||||
{:events [:browser.bridge.callback/qr-code-scanned]}
|
{:events [:browser.bridge.callback/qr-code-scanned]}
|
||||||
[cofx data {{:keys [dapp-name permission message-id]} :data}]
|
[cofx data {{:keys [dapp-name permission message-id]} :data}]
|
||||||
(fx/merge (assoc-in cofx [:db :browser/options :yielding-control?] false)
|
(rf/merge (assoc-in cofx [:db :browser/options :yielding-control?] false)
|
||||||
(browser.permissions/send-response-to-bridge permission message-id true data)
|
(browser.permissions/send-response-to-bridge permission message-id true data)
|
||||||
(browser.permissions/process-next-permission dapp-name)
|
(browser.permissions/process-next-permission dapp-name)
|
||||||
(navigation/navigate-back)))
|
(navigation/navigate-back)))
|
||||||
|
|
||||||
(fx/defn handle-canceled-qr-code
|
(rf/defn handle-canceled-qr-code
|
||||||
{:events [:browser.bridge.callback/qr-code-canceled]}
|
{:events [:browser.bridge.callback/qr-code-canceled]}
|
||||||
[cofx {{:keys [dapp-name permission message-id]} :data}]
|
[cofx {{:keys [dapp-name permission message-id]} :data}]
|
||||||
(fx/merge (assoc-in cofx [:db :browser/options :yielding-control?] false)
|
(rf/merge (assoc-in cofx [:db :browser/options :yielding-control?] false)
|
||||||
(browser.permissions/send-response-to-bridge permission message-id true nil)
|
(browser.permissions/send-response-to-bridge permission message-id true nil)
|
||||||
(browser.permissions/process-next-permission dapp-name)))
|
(browser.permissions/process-next-permission dapp-name)))
|
||||||
|
|
||||||
(fx/defn process-bridge-message
|
(rf/defn process-bridge-message
|
||||||
{:events [:browser/bridge-message-received]}
|
{:events [:browser/bridge-message-received]}
|
||||||
[{:keys [db] :as cofx} message]
|
[{:keys [db] :as cofx} message]
|
||||||
(let [browser (get-current-browser db)
|
(let [browser (get-current-browser
|
||||||
url-original (get-current-url browser)
|
db)
|
||||||
data (types/json->clj message)
|
url-original (get-current-url
|
||||||
|
browser)
|
||||||
|
data (types/json->clj
|
||||||
|
message)
|
||||||
{{:keys [url]} :navState :keys [type permission payload messageId params]} data
|
{{:keys [url]} :navState :keys [type permission payload messageId params]} data
|
||||||
{:keys [dapp? name]} browser
|
{:keys [dapp? name]} browser
|
||||||
dapp-name (if dapp? name (http/url-host url-original))]
|
dapp-name (if dapp?
|
||||||
|
name
|
||||||
|
(http/url-host
|
||||||
|
url-original))]
|
||||||
(cond
|
(cond
|
||||||
(and (= type constants/history-state-changed)
|
(and (= type constants/history-state-changed)
|
||||||
(not= "about:blank" url))
|
(not= "about:blank" url))
|
||||||
@@ -474,10 +512,13 @@
|
|||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
:browser/send-to-bridge
|
:browser/send-to-bridge
|
||||||
(fn [message]
|
(fn [message]
|
||||||
(let [^js webview @webview-ref/webview-ref
|
(let
|
||||||
msg (str "(function() { var __send = function() { if (ReactNativeWebView.onMessage) { ReactNativeWebView.onMessage('"
|
[^js webview @webview-ref/webview-ref
|
||||||
(types/clj->json message)
|
msg
|
||||||
"');} else {setTimeout(__send, 0)}}; __send();})();")]
|
(str
|
||||||
|
"(function() { var __send = function() { if (ReactNativeWebView.onMessage) { ReactNativeWebView.onMessage('"
|
||||||
|
(types/clj->json message)
|
||||||
|
"');} else {setTimeout(__send, 0)}}; __send();})();")]
|
||||||
(when (and message webview)
|
(when (and message webview)
|
||||||
(.injectJavaScript webview msg)))))
|
(.injectJavaScript webview msg)))))
|
||||||
|
|
||||||
@@ -508,59 +549,61 @@
|
|||||||
(fn []
|
(fn []
|
||||||
(status/clear-web-data)))
|
(status/clear-web-data)))
|
||||||
|
|
||||||
(defn share-link [url]
|
(defn share-link
|
||||||
|
[url]
|
||||||
(let [link (links/generate-link :browse :external url)
|
(let [link (links/generate-link :browse :external url)
|
||||||
message (i18n/label :t/share-dapp-text {:link link})]
|
message (i18n/label :t/share-dapp-text {:link link})]
|
||||||
(list-selection/open-share {:message message})))
|
(list-selection/open-share {:message message})))
|
||||||
|
|
||||||
(fx/defn dapps-account-selected
|
(rf/defn dapps-account-selected
|
||||||
{:events [:dapps-account-selected]}
|
{:events [:dapps-account-selected]}
|
||||||
[{:keys [db] :as cofx} address]
|
[{:keys [db] :as cofx} address]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:browser/clear-web-data nil}
|
{:browser/clear-web-data nil}
|
||||||
(bottom-sheet/hide-bottom-sheet)
|
(bottom-sheet/hide-bottom-sheet)
|
||||||
(browser.permissions/clear-dapps-permissions)
|
(browser.permissions/clear-dapps-permissions)
|
||||||
(multiaccounts.update/multiaccount-update :dapps-address address {})
|
(multiaccounts.update/multiaccount-update :dapps-address address {})
|
||||||
#(when (= (:view-id db) :browser)
|
#(when (= (:view-id db) :browser)
|
||||||
(merge (navigation/navigate-back %)
|
(merge (navigation/navigate-back %)
|
||||||
{:dispatch [:browser.ui/browser-item-selected (get-in db [:browser/options :browser-id])]}))))
|
{:dispatch [:browser.ui/browser-item-selected
|
||||||
|
(get-in db [:browser/options :browser-id])]}))))
|
||||||
|
|
||||||
(fx/defn open-empty-tab
|
(rf/defn open-empty-tab
|
||||||
{:events [:browser.ui/open-empty-tab]}
|
{:events [:browser.ui/open-empty-tab]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(debounce/clear :browser/navigation-state-changed)
|
(debounce/clear :browser/navigation-state-changed)
|
||||||
(navigation/set-stack-root cofx :browser-stack :empty-tab))
|
(navigation/set-stack-root cofx :browser-stack :empty-tab))
|
||||||
|
|
||||||
(fx/defn url-input-pressed
|
(rf/defn url-input-pressed
|
||||||
{:events [:browser.ui/url-input-pressed]}
|
{:events [:browser.ui/url-input-pressed]}
|
||||||
[cofx _]
|
[cofx _]
|
||||||
(update-browser-option cofx :url-editing? true))
|
(update-browser-option cofx :url-editing? true))
|
||||||
|
|
||||||
(fx/defn url-input-blured
|
(rf/defn url-input-blured
|
||||||
{:events [:browser.ui/url-input-blured]}
|
{:events [:browser.ui/url-input-blured]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(update-browser-option cofx :url-editing? false))
|
(update-browser-option cofx :url-editing? false))
|
||||||
|
|
||||||
(fx/defn lock-pressed
|
(rf/defn lock-pressed
|
||||||
{:events [:browser.ui/lock-pressed]}
|
{:events [:browser.ui/lock-pressed]}
|
||||||
[cofx secure?]
|
[cofx secure?]
|
||||||
(update-browser-option cofx :show-tooltip (if secure? :secure :not-secure)))
|
(update-browser-option cofx :show-tooltip (if secure? :secure :not-secure)))
|
||||||
|
|
||||||
(fx/defn close-tooltip-pressed
|
(rf/defn close-tooltip-pressed
|
||||||
{:events [:browser.ui/close-tooltip-pressed]}
|
{:events [:browser.ui/close-tooltip-pressed]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(update-browser-option cofx :show-tooltip nil))
|
(update-browser-option cofx :show-tooltip nil))
|
||||||
|
|
||||||
(fx/defn loading-started
|
(rf/defn loading-started
|
||||||
{:events [:browser/loading-started]}
|
{:events [:browser/loading-started]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(update-browser-options cofx {:error? false :loading? true}))
|
(update-browser-options cofx {:error? false :loading? true}))
|
||||||
|
|
||||||
(fx/defn handle-bookmarks
|
(rf/defn handle-bookmarks
|
||||||
[{:keys [db]} bookmarks]
|
[{:keys [db]} bookmarks]
|
||||||
(let [changed-bookmarks (reduce (fn [acc {:keys [url] :as bookmark}]
|
(let [changed-bookmarks (reduce (fn [acc {:keys [url] :as bookmark}]
|
||||||
(assoc acc url bookmark))
|
(assoc acc url bookmark))
|
||||||
{}
|
{}
|
||||||
bookmarks)
|
bookmarks)
|
||||||
stored-bookmarks (get-in db [:bookmarks/bookmarks])]
|
stored-bookmarks (get-in db [:bookmarks/bookmarks])]
|
||||||
{:db (assoc-in db [:bookmarks/bookmarks] (merge stored-bookmarks changed-bookmarks))}))
|
{:db (assoc-in db [:bookmarks/bookmarks] (merge stored-bookmarks changed-bookmarks))}))
|
||||||
|
|||||||
@@ -1,69 +1,76 @@
|
|||||||
;reference https://eips.ethereum.org/EIPS/eip-3085 EIP-3085: Wallet Add Ethereum Chain RPC Method (`wallet_addEthereumChain`)
|
;reference https://eips.ethereum.org/EIPS/eip-3085 EIP-3085: Wallet Add Ethereum Chain RPC Method
|
||||||
|
;(`wallet_addEthereumChain`)
|
||||||
(ns status-im.browser.eip3085
|
(ns status-im.browser.eip3085
|
||||||
(:require [status-im.constants :as constants]
|
(:require [clojure.string :as string]
|
||||||
[clojure.string :as string]
|
|
||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
[status-im.utils.fx :as fx]
|
[status-im.constants :as constants]
|
||||||
[status-im.network.core :as network]
|
|
||||||
[taoensso.timbre :as log]
|
|
||||||
[status-im.utils.random :as random]
|
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
[status-im.ui.screens.browser.eip3085.sheet :as sheet]))
|
[status-im.network.core :as network]
|
||||||
|
[status-im.ui.screens.browser.eip3085.sheet :as sheet]
|
||||||
|
[status-im.utils.random :as random]
|
||||||
|
[taoensso.timbre :as log]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(fx/defn send-success-call-to-bridge
|
(rf/defn send-success-call-to-bridge
|
||||||
{:events [:eip3085/send-success-call-to-bridge]}
|
{:events [:eip3085/send-success-call-to-bridge]}
|
||||||
[_ id messageId]
|
[_ id messageId]
|
||||||
{:browser/send-to-bridge {:type constants/web3-send-async-callback
|
{:browser/send-to-bridge {:type constants/web3-send-async-callback
|
||||||
:messageId messageId
|
:messageId messageId
|
||||||
:result {:jsonrpc "2.0"
|
:result {:jsonrpc "2.0"
|
||||||
:id (int id)
|
:id (int id)
|
||||||
:result nil}}})
|
:result nil}}})
|
||||||
|
|
||||||
(fx/defn allow-permission
|
(rf/defn allow-permission
|
||||||
{:events [:eip3085.ui/dapp-permission-allowed]}
|
{:events [:eip3085.ui/dapp-permission-allowed]}
|
||||||
[{:keys [db] :as cofx} message-id {:keys [new-networks id]}]
|
[{:keys [db] :as cofx} message-id {:keys [new-networks id]}]
|
||||||
{:db (assoc db :networks/networks new-networks)
|
{:db (assoc db :networks/networks new-networks)
|
||||||
::json-rpc/call [{:method "settings_saveSetting"
|
::json-rpc/call [{:method "settings_saveSetting"
|
||||||
:params [:networks/networks (vals new-networks)]
|
:params [:networks/networks (vals new-networks)]
|
||||||
:on-success #(re-frame/dispatch [:eip3085/send-success-call-to-bridge cofx id message-id])
|
:on-success #(re-frame/dispatch [:eip3085/send-success-call-to-bridge cofx id
|
||||||
|
message-id])
|
||||||
:on-error #(log/error "failed to perform settings_saveSetting" %)}]
|
:on-error #(log/error "failed to perform settings_saveSetting" %)}]
|
||||||
:dispatch [:bottom-sheet/hide]})
|
:dispatch [:bottom-sheet/hide]})
|
||||||
|
|
||||||
(fx/defn deny-permission
|
(rf/defn deny-permission
|
||||||
{:events [:eip3085.ui/dapp-permission-denied]}
|
{:events [:eip3085.ui/dapp-permission-denied]}
|
||||||
[_ message-id _]
|
[_ message-id _]
|
||||||
{:browser/send-to-bridge {:type constants/web3-send-async-callback
|
{:browser/send-to-bridge {:type constants/web3-send-async-callback
|
||||||
:messageId message-id
|
:messageId message-id
|
||||||
:error {:code 4001
|
:error {:code 4001
|
||||||
:message "User rejected the request."}}
|
:message "User rejected the request."}}
|
||||||
:dispatch [:bottom-sheet/hide]})
|
:dispatch [:bottom-sheet/hide]})
|
||||||
|
|
||||||
(fx/defn handle-add-ethereum-chain
|
(rf/defn handle-add-ethereum-chain
|
||||||
{:events [:eip3085/handle-add-ethereum-chain]}
|
{:events [:eip3085/handle-add-ethereum-chain]}
|
||||||
[{{:networks/keys [networks] :as db} :db :as cofx}
|
[{{:networks/keys [networks] :as db} :db :as cofx}
|
||||||
dapp-name id message-id {:keys [chainId blockExplorerUrls chainName iconUrls nativeCurrency rpcUrls] :as params}]
|
dapp-name id message-id
|
||||||
(let [manage {:name {:value chainName}
|
{:keys [chainId blockExplorerUrls chainName iconUrls nativeCurrency rpcUrls] :as params}]
|
||||||
:symbol {:value (:symbol nativeCurrency)}
|
(let [manage {:name {:value chainName}
|
||||||
:url {:value (first rpcUrls)}
|
:symbol {:value (:symbol nativeCurrency)}
|
||||||
|
:url {:value (first rpcUrls)}
|
||||||
:network-id {:value chainId}
|
:network-id {:value chainId}
|
||||||
:chain {:value :custom}}]
|
:chain {:value :custom}}]
|
||||||
(if (network/valid-manage? manage)
|
(if (network/valid-manage? manage)
|
||||||
(let [{:keys [name url chain network-id symbol]} manage
|
(let [{:keys [name url chain network-id symbol]} manage
|
||||||
random-id (string/replace (random/id) "-" "")
|
random-id (string/replace (random/id) "-" "")
|
||||||
network (network/new-network random-id
|
network (network/new-network random-id
|
||||||
(:value name)
|
(:value name)
|
||||||
(:value symbol)
|
(:value symbol)
|
||||||
(:value url)
|
(:value url)
|
||||||
(:value chain)
|
(:value chain)
|
||||||
(:value network-id))
|
(:value network-id))
|
||||||
new-networks (assoc networks random-id network)
|
new-networks (assoc networks random-id network)
|
||||||
params (assoc params :new-networks new-networks :id id :new-network network)]
|
params (assoc params
|
||||||
|
:new-networks new-networks
|
||||||
|
:id id
|
||||||
|
:new-network network)]
|
||||||
(if (network/chain-id-available? networks network)
|
(if (network/chain-id-available? networks network)
|
||||||
{:dispatch [:bottom-sheet/show-sheet {:content (fn []
|
{:dispatch [:bottom-sheet/show-sheet
|
||||||
[sheet/permissions-panel dapp-name message-id params])}]}
|
{:content (fn []
|
||||||
|
[sheet/permissions-panel dapp-name message-id params])}]}
|
||||||
(send-success-call-to-bridge cofx id message-id)))
|
(send-success-call-to-bridge cofx id message-id)))
|
||||||
{:browser/send-to-bridge {:type constants/web3-send-async-callback
|
{:browser/send-to-bridge {:type constants/web3-send-async-callback
|
||||||
:messageId message-id
|
:messageId message-id
|
||||||
:error {:code -32602
|
:error {:code -32602
|
||||||
:message "invalid network parameters"}}})))
|
:message "invalid network parameters"}}})))
|
||||||
|
|
||||||
|
|||||||
@@ -1,43 +1,54 @@
|
|||||||
;reference https://eips.ethereum.org/EIPS/eip-3326 EIP-3326: Wallet Switch Ethereum Chain RPC Method (`wallet_switchEthereumChain`)
|
;reference https://eips.ethereum.org/EIPS/eip-3326 EIP-3326: Wallet Switch Ethereum Chain RPC Method
|
||||||
|
;(`wallet_switchEthereumChain`)
|
||||||
(ns status-im.browser.eip3326
|
(ns status-im.browser.eip3326
|
||||||
(:require [status-im.constants :as constants]
|
(:require [status-im.constants :as constants]
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[status-im.ethereum.core :as ethereum]
|
[status-im.ethereum.core :as ethereum]
|
||||||
[status-im.ui.screens.browser.eip3326.sheet :as sheet]))
|
[status-im.ui.screens.browser.eip3326.sheet :as sheet]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(fx/defn deny-permission
|
(rf/defn deny-permission
|
||||||
{:events [:eip3326.ui/dapp-permission-denied]}
|
{:events [:eip3326.ui/dapp-permission-denied]}
|
||||||
[{:keys [db] :as cofx} message-id _]
|
[{:keys [db] :as cofx} message-id _]
|
||||||
{:browser/send-to-bridge {:type constants/web3-send-async-callback
|
{:browser/send-to-bridge {:type constants/web3-send-async-callback
|
||||||
:messageId message-id
|
:messageId message-id
|
||||||
:error {:code 4001
|
:error {:code 4001
|
||||||
:message "User rejected the request."}}
|
:message "User rejected the request."}}
|
||||||
:dispatch [:bottom-sheet/hide]})
|
:dispatch [:bottom-sheet/hide]})
|
||||||
|
|
||||||
(fx/defn handle-switch-ethereum-chain
|
(rf/defn handle-switch-ethereum-chain
|
||||||
{:events [:eip3326/handle-switch-ethereum-chain]}
|
{:events [:eip3326/handle-switch-ethereum-chain]}
|
||||||
[{:keys [db] :as cofx} dapp-name id message-id {:keys [chainId] :as params}]
|
[{:keys [db] :as cofx} dapp-name id message-id {:keys [chainId] :as params}]
|
||||||
(let [target-chain-id (js/parseInt chainId 16)
|
(let [target-chain-id (js/parseInt chainId 16)
|
||||||
networks (vals (get-in db [:networks/networks]))
|
networks (vals (get-in db [:networks/networks]))
|
||||||
exist-chain-ids (set (map ethereum/network->chain-id networks))
|
exist-chain-ids (set (map ethereum/network->chain-id networks))
|
||||||
current-chain-id (ethereum/chain-id db)]
|
current-chain-id (ethereum/chain-id db)]
|
||||||
(if (exist-chain-ids target-chain-id)
|
(if (exist-chain-ids target-chain-id)
|
||||||
(if (= current-chain-id target-chain-id)
|
(if (= current-chain-id target-chain-id)
|
||||||
{:browser/send-to-bridge {:type constants/web3-send-async-callback
|
{:browser/send-to-bridge {:type constants/web3-send-async-callback
|
||||||
:messageId message-id
|
:messageId message-id
|
||||||
:result {:jsonrpc "2.0"
|
:result {:jsonrpc "2.0"
|
||||||
:id (int id)
|
:id (int id)
|
||||||
:result nil}}}
|
:result nil}}}
|
||||||
(let [target-network (first (filter #(= (ethereum/network->chain-id %1) target-chain-id) networks))
|
(let [target-network (first (filter #(= (ethereum/network->chain-id %1) target-chain-id)
|
||||||
|
networks))
|
||||||
target-network-id (:id target-network)
|
target-network-id (:id target-network)
|
||||||
current-network (ethereum/current-network db)
|
current-network (ethereum/current-network db)
|
||||||
network-from (:name current-network)
|
network-from (:name current-network)
|
||||||
network-to (:name target-network)
|
network-to (:name target-network)
|
||||||
params (assoc params :target-network-id target-network-id :network-from network-from :network-to network-to)]
|
params (assoc params
|
||||||
{:dispatch [:bottom-sheet/show-sheet {:content (fn []
|
:target-network-id target-network-id
|
||||||
[sheet/permissions-panel dapp-name message-id params])}]}))
|
:network-from network-from
|
||||||
{:browser/send-to-bridge {:type constants/web3-send-async-callback
|
:network-to network-to)]
|
||||||
|
{:dispatch [:bottom-sheet/show-sheet
|
||||||
|
{:content (fn []
|
||||||
|
[sheet/permissions-panel dapp-name message-id params])}]}))
|
||||||
|
{:browser/send-to-bridge {:type constants/web3-send-async-callback
|
||||||
:messageId message-id
|
:messageId message-id
|
||||||
:error {:code 4902
|
:error
|
||||||
:message (str "Unrecognized chain ID: " target-chain-id ". Try adding the chain using wallet_addEthereumChain first.")}}})))
|
{:code 4902
|
||||||
|
:message
|
||||||
|
(str
|
||||||
|
"Unrecognized chain ID: "
|
||||||
|
target-chain-id
|
||||||
|
". Try adding the chain using wallet_addEthereumChain first.")}}})))
|
||||||
|
|
||||||
|
|||||||
@@ -2,51 +2,53 @@
|
|||||||
(:require [status-im.constants :as constants]
|
(:require [status-im.constants :as constants]
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
[status-im.i18n.i18n :as i18n]
|
[status-im.i18n.i18n :as i18n]
|
||||||
[status-im2.navigation.events :as navigation]
|
|
||||||
[status-im.qr-scanner.core :as qr-scanner]
|
[status-im.qr-scanner.core :as qr-scanner]
|
||||||
[status-im.utils.fx :as fx]))
|
[status-im2.navigation.events :as navigation]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(declare process-next-permission)
|
(declare process-next-permission)
|
||||||
(declare send-response-to-bridge)
|
(declare send-response-to-bridge)
|
||||||
|
|
||||||
(def supported-permissions
|
(def supported-permissions
|
||||||
{constants/dapp-permission-qr-code {:yield-control? true
|
{constants/dapp-permission-qr-code {:yield-control? true
|
||||||
:allowed? true}
|
:allowed? true}
|
||||||
constants/dapp-permission-contact-code {:type :profile
|
constants/dapp-permission-contact-code {:type :profile
|
||||||
:title (i18n/label :t/wants-to-access-profile)
|
:title (i18n/label :t/wants-to-access-profile)
|
||||||
:description (i18n/label :t/your-contact-code)
|
:description (i18n/label :t/your-contact-code)
|
||||||
:icon :main-icons/profile}
|
:icon :main-icons/profile}
|
||||||
constants/dapp-permission-web3 {:type :wallet
|
constants/dapp-permission-web3 {:type :wallet
|
||||||
:title (i18n/label :t/dapp-would-like-to-connect-wallet)
|
:title (i18n/label :t/dapp-would-like-to-connect-wallet)
|
||||||
:description (i18n/label :t/allowing-authorizes-this-dapp)
|
:description (i18n/label :t/allowing-authorizes-this-dapp)
|
||||||
:icon :main-icons/wallet}})
|
:icon :main-icons/wallet}})
|
||||||
|
|
||||||
(fx/defn permission-yield-control
|
(rf/defn permission-yield-control
|
||||||
[{:keys [db] :as cofx} dapp-name permission message-id params]
|
[{:keys [db] :as cofx} dapp-name permission message-id params]
|
||||||
(cond
|
(cond
|
||||||
(= permission constants/dapp-permission-qr-code)
|
(= permission constants/dapp-permission-qr-code)
|
||||||
(fx/merge (assoc-in cofx [:db :browser/options :yielding-control?] true)
|
(rf/merge (assoc-in cofx [:db :browser/options :yielding-control?] true)
|
||||||
(qr-scanner/scan-qr-code {:handler :browser.bridge.callback/qr-code-scanned
|
(qr-scanner/scan-qr-code {:handler :browser.bridge.callback/qr-code-scanned
|
||||||
:cancel-handler :browser.bridge.callback/qr-code-canceled
|
:cancel-handler :browser.bridge.callback/qr-code-canceled
|
||||||
:data {:dapp-name dapp-name
|
:data {:dapp-name dapp-name
|
||||||
:permission permission
|
:permission permission
|
||||||
:message-id message-id}}))))
|
:message-id message-id}}))))
|
||||||
|
|
||||||
(fx/defn permission-show-permission
|
(rf/defn permission-show-permission
|
||||||
[{:keys [db] :as cofx} dapp-name permission message-id yield-control?]
|
[{:keys [db] :as cofx} dapp-name permission message-id yield-control?]
|
||||||
{:db (assoc-in db [:browser/options :show-permission]
|
{:db (assoc-in db
|
||||||
{:requested-permission permission
|
[:browser/options :show-permission]
|
||||||
:message-id message-id
|
{:requested-permission permission
|
||||||
:dapp-name dapp-name
|
:message-id message-id
|
||||||
:yield-control? yield-control?})})
|
:dapp-name dapp-name
|
||||||
|
:yield-control? yield-control?})})
|
||||||
|
|
||||||
(defn get-permission-data [cofx allowed-permission]
|
(defn get-permission-data
|
||||||
|
[cofx allowed-permission]
|
||||||
(let [multiaccount (get-in cofx [:db :multiaccount])]
|
(let [multiaccount (get-in cofx [:db :multiaccount])]
|
||||||
(get {constants/dapp-permission-contact-code (:public-key multiaccount)
|
(get {constants/dapp-permission-contact-code (:public-key multiaccount)
|
||||||
constants/dapp-permission-web3 [(:dapps-address multiaccount)]}
|
constants/dapp-permission-web3 [(:dapps-address multiaccount)]}
|
||||||
allowed-permission)))
|
allowed-permission)))
|
||||||
|
|
||||||
(fx/defn send-response-to-bridge
|
(rf/defn send-response-to-bridge
|
||||||
"Send response to the bridge. If the permission is allowed, send data associated
|
"Send response to the bridge. If the permission is allowed, send data associated
|
||||||
with the permission"
|
with the permission"
|
||||||
[{:keys [db] :as cofx} permission message-id allowed? data]
|
[{:keys [db] :as cofx} permission message-id allowed? data]
|
||||||
@@ -57,7 +59,7 @@
|
|||||||
allowed?
|
allowed?
|
||||||
(assoc :data data))})
|
(assoc :data data))})
|
||||||
|
|
||||||
(fx/defn update-dapp-permissions
|
(rf/defn update-dapp-permissions
|
||||||
[{:keys [db]} dapp-name permission allowed?]
|
[{:keys [db]} dapp-name permission allowed?]
|
||||||
(let [dapp-permissions-set (set (get-in db [:dapps/permissions dapp-name :permissions]))
|
(let [dapp-permissions-set (set (get-in db [:dapps/permissions dapp-name :permissions]))
|
||||||
allowed-permissions-set (if allowed?
|
allowed-permissions-set (if allowed?
|
||||||
@@ -65,28 +67,28 @@
|
|||||||
(disj dapp-permissions-set permission))
|
(disj dapp-permissions-set permission))
|
||||||
allowed-permissions {:dapp dapp-name
|
allowed-permissions {:dapp dapp-name
|
||||||
:permissions (vec allowed-permissions-set)}]
|
:permissions (vec allowed-permissions-set)}]
|
||||||
{:db (assoc-in db [:dapps/permissions dapp-name] allowed-permissions)
|
{:db (assoc-in db [:dapps/permissions dapp-name] allowed-permissions)
|
||||||
::json-rpc/call [{:method "permissions_addDappPermissions"
|
::json-rpc/call [{:method "permissions_addDappPermissions"
|
||||||
:params [allowed-permissions]
|
:params [allowed-permissions]
|
||||||
:on-success #()}]}))
|
:on-success #()}]}))
|
||||||
|
|
||||||
(fx/defn revoke-permissions
|
(rf/defn revoke-permissions
|
||||||
{:events [:browser/revoke-dapp-permissions]}
|
{:events [:browser/revoke-dapp-permissions]}
|
||||||
[{:keys [db] :as cofx} dapp]
|
[{:keys [db] :as cofx} dapp]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (update-in db [:dapps/permissions] dissoc dapp)
|
{:db (update-in db [:dapps/permissions] dissoc dapp)
|
||||||
::json-rpc/call [{:method "permissions_deleteDappPermissions"
|
::json-rpc/call [{:method "permissions_deleteDappPermissions"
|
||||||
:params [dapp]
|
:params [dapp]
|
||||||
:on-success #()}]}))
|
:on-success #()}]}))
|
||||||
|
|
||||||
(fx/defn revoke-dapp-permissions
|
(rf/defn revoke-dapp-permissions
|
||||||
{:events [:dapps/revoke-access]}
|
{:events [:dapps/revoke-access]}
|
||||||
[cofx dapp]
|
[cofx dapp]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(revoke-permissions dapp)
|
(revoke-permissions dapp)
|
||||||
(navigation/navigate-back)))
|
(navigation/navigate-back)))
|
||||||
|
|
||||||
(fx/defn clear-dapps-permissions
|
(rf/defn clear-dapps-permissions
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(let [dapp-permissions (keys (:dapps/permissions db))]
|
(let [dapp-permissions (keys (:dapps/permissions db))]
|
||||||
{:db (dissoc db :dapps/permissions)
|
{:db (dissoc db :dapps/permissions)
|
||||||
@@ -95,7 +97,7 @@
|
|||||||
:params [dapp]
|
:params [dapp]
|
||||||
:on-success #()})}))
|
:on-success #()})}))
|
||||||
|
|
||||||
(fx/defn process-next-permission
|
(rf/defn process-next-permission
|
||||||
"Process next permission by removing it from pending permissions and prompting user
|
"Process next permission by removing it from pending permissions and prompting user
|
||||||
if there is no pending permissions left, save all granted permissions
|
if there is no pending permissions left, save all granted permissions
|
||||||
and return the result to the bridge"
|
and return the result to the bridge"
|
||||||
@@ -105,46 +107,47 @@
|
|||||||
{:db db}
|
{:db db}
|
||||||
(let [pending-permissions (get-in db [:browser/options :pending-permissions])
|
(let [pending-permissions (get-in db [:browser/options :pending-permissions])
|
||||||
next-permission (last pending-permissions)
|
next-permission (last pending-permissions)
|
||||||
new-cofx (update-in cofx [:db :browser/options :pending-permissions] butlast)]
|
new-cofx (update-in cofx [:db :browser/options :pending-permissions] butlast)]
|
||||||
(when-let [{:keys [yield-control? permission message-id allowed? params]} next-permission]
|
(when-let [{:keys [yield-control? permission message-id allowed? params]} next-permission]
|
||||||
(if (and yield-control? allowed?)
|
(if (and yield-control? allowed?)
|
||||||
(permission-yield-control new-cofx dapp-name permission message-id params)
|
(permission-yield-control new-cofx dapp-name permission message-id params)
|
||||||
(permission-show-permission new-cofx dapp-name permission message-id yield-control?)))))))
|
(permission-show-permission new-cofx dapp-name permission message-id yield-control?)))))))
|
||||||
|
|
||||||
(fx/defn send-response-and-process-next-permission
|
(rf/defn send-response-and-process-next-permission
|
||||||
[{:keys [db] :as cofx} dapp-name requested-permission message-id]
|
[{:keys [db] :as cofx} dapp-name requested-permission message-id]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(send-response-to-bridge requested-permission
|
(send-response-to-bridge requested-permission
|
||||||
message-id
|
message-id
|
||||||
true
|
true
|
||||||
(get-permission-data cofx requested-permission))
|
(get-permission-data cofx requested-permission))
|
||||||
(process-next-permission dapp-name)))
|
(process-next-permission dapp-name)))
|
||||||
|
|
||||||
(fx/defn allow-permission
|
(rf/defn allow-permission
|
||||||
"Add permission to set of allowed permission and process next permission"
|
"Add permission to set of allowed permission and process next permission"
|
||||||
{:events [:browser.permissions.ui/dapp-permission-allowed]}
|
{:events [:browser.permissions.ui/dapp-permission-allowed]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [{:keys [requested-permission message-id dapp-name yield-control? params]}
|
(let [{:keys [requested-permission message-id dapp-name yield-control? params]}
|
||||||
(get-in db [:browser/options :show-permission])]
|
(get-in db [:browser/options :show-permission])]
|
||||||
(fx/merge (assoc-in cofx [:db :browser/options :show-permission] nil)
|
(rf/merge (assoc-in cofx [:db :browser/options :show-permission] nil)
|
||||||
(update-dapp-permissions dapp-name requested-permission true)
|
(update-dapp-permissions dapp-name requested-permission true)
|
||||||
(if yield-control?
|
(if yield-control?
|
||||||
(permission-yield-control dapp-name requested-permission message-id params)
|
(permission-yield-control dapp-name requested-permission message-id params)
|
||||||
(send-response-and-process-next-permission dapp-name requested-permission message-id)))))
|
(send-response-and-process-next-permission dapp-name requested-permission message-id)))))
|
||||||
|
|
||||||
(fx/defn deny-permission
|
(rf/defn deny-permission
|
||||||
"Add permission to set of allowed permission and process next permission"
|
"Add permission to set of allowed permission and process next permission"
|
||||||
{:events [:browser.permissions.ui/dapp-permission-denied]}
|
{:events [:browser.permissions.ui/dapp-permission-denied]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [{:keys [requested-permission message-id dapp-name]} (get-in db [:browser/options :show-permission])]
|
(let [{:keys [requested-permission message-id dapp-name]} (get-in db
|
||||||
(fx/merge (assoc-in cofx [:db :browser/options :show-permission] nil)
|
[:browser/options :show-permission])]
|
||||||
|
(rf/merge (assoc-in cofx [:db :browser/options :show-permission] nil)
|
||||||
(send-response-to-bridge requested-permission
|
(send-response-to-bridge requested-permission
|
||||||
message-id
|
message-id
|
||||||
false
|
false
|
||||||
(get-permission-data cofx requested-permission))
|
(get-permission-data cofx requested-permission))
|
||||||
(process-next-permission dapp-name))))
|
(process-next-permission dapp-name))))
|
||||||
|
|
||||||
(fx/defn process-permission
|
(rf/defn process-permission
|
||||||
"Process the permission requested by a dapp
|
"Process the permission requested by a dapp
|
||||||
If supported permission is already granted, return the result immediatly to the bridge
|
If supported permission is already granted, return the result immediatly to the bridge
|
||||||
Otherwise process the first permission which will prompt user"
|
Otherwise process the first permission which will prompt user"
|
||||||
@@ -156,15 +159,18 @@
|
|||||||
(not supported-permission)
|
(not supported-permission)
|
||||||
(send-response-to-bridge cofx permission message-id false nil)
|
(send-response-to-bridge cofx permission message-id false nil)
|
||||||
|
|
||||||
(and (or permission-allowed? (:allowed? supported-permission)) (not (:yield-control? supported-permission)))
|
(and (or permission-allowed? (:allowed? supported-permission))
|
||||||
|
(not (:yield-control? supported-permission)))
|
||||||
(send-response-to-bridge cofx permission message-id true (get-permission-data cofx permission))
|
(send-response-to-bridge cofx permission message-id true (get-permission-data cofx permission))
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(process-next-permission (update-in cofx [:db :browser/options :pending-permissions]
|
(process-next-permission (update-in cofx
|
||||||
conj {:permission permission
|
[:db :browser/options :pending-permissions]
|
||||||
:allowed? (or permission-allowed?
|
conj
|
||||||
(:allowed? supported-permission))
|
{:permission permission
|
||||||
:yield-control? (:yield-control? supported-permission)
|
:allowed? (or permission-allowed?
|
||||||
:params params
|
(:allowed? supported-permission))
|
||||||
:message-id message-id})
|
:yield-control? (:yield-control? supported-permission)
|
||||||
|
:params params
|
||||||
|
:message-id message-id})
|
||||||
dapp-name))))
|
dapp-name))))
|
||||||
|
|||||||
+164
-150
@@ -1,31 +1,33 @@
|
|||||||
(ns status-im.chat.models
|
(ns status-im.chat.models
|
||||||
(:require [re-frame.core :as re-frame]
|
(:require [clojure.set :as set]
|
||||||
[taoensso.timbre :as log]
|
[quo.design-system.colors :as colors]
|
||||||
[status-im.multiaccounts.model :as multiaccounts.model]
|
[re-frame.core :as re-frame]
|
||||||
|
[status-im.add-new.db :as new-public-chat.db]
|
||||||
|
[status-im.chat.models.loading :as loading]
|
||||||
[status-im.chat.models.message-list :as message-list]
|
[status-im.chat.models.message-list :as message-list]
|
||||||
[status-im2.contexts.chat.messages.message.delete-message.events :as delete-message]
|
[status-im.constants :as constants]
|
||||||
[status-im2.contexts.chat.messages.message.delete-message-for-me.events :as delete-for-me]
|
|
||||||
[status-im.data-store.chats :as chats-store]
|
[status-im.data-store.chats :as chats-store]
|
||||||
[status-im.mailserver.core :as mailserver]
|
|
||||||
[status-im.data-store.contacts :as contacts-store]
|
[status-im.data-store.contacts :as contacts-store]
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
[status-im.i18n.i18n :as i18n]
|
[status-im.i18n.i18n :as i18n]
|
||||||
[quo.design-system.colors :as colors]
|
[status-im.mailserver.core :as mailserver]
|
||||||
[status-im.constants :as constants]
|
[status-im.multiaccounts.model :as multiaccounts.model]
|
||||||
[status-im.utils.clocks :as utils.clocks]
|
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[status-im.utils.utils :as utils]
|
|
||||||
[status-im.utils.types :as types]
|
|
||||||
[status-im.add-new.db :as new-public-chat.db]
|
|
||||||
[status-im.chat.models.loading :as loading]
|
|
||||||
[status-im.ui.screens.chat.state :as chat.state]
|
[status-im.ui.screens.chat.state :as chat.state]
|
||||||
[clojure.set :as set]
|
[status-im.utils.clocks :as utils.clocks]
|
||||||
[status-im2.navigation.events :as navigation]))
|
[status-im.utils.types :as types]
|
||||||
|
[status-im.utils.utils :as utils]
|
||||||
|
[status-im2.contexts.chat.messages.message.delete-message-for-me.events :as delete-for-me]
|
||||||
|
[status-im2.contexts.chat.messages.message.delete-message.events :as delete-message]
|
||||||
|
[status-im2.navigation.events :as navigation]
|
||||||
|
[taoensso.timbre :as log]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(defn chats []
|
(defn chats
|
||||||
|
[]
|
||||||
(:chats (types/json->clj (js/require "./chats.js"))))
|
(:chats (types/json->clj (js/require "./chats.js"))))
|
||||||
|
|
||||||
(defn- get-chat [cofx chat-id]
|
(defn- get-chat
|
||||||
|
[cofx chat-id]
|
||||||
(get-in cofx [:db :chats chat-id]))
|
(get-in cofx [:db :chats chat-id]))
|
||||||
|
|
||||||
(defn multi-user-chat?
|
(defn multi-user-chat?
|
||||||
@@ -49,7 +51,8 @@
|
|||||||
([cofx chat-id]
|
([cofx chat-id]
|
||||||
(community-chat? (get-chat cofx chat-id))))
|
(community-chat? (get-chat cofx chat-id))))
|
||||||
|
|
||||||
(defn active-chat? [cofx chat-id]
|
(defn active-chat?
|
||||||
|
[cofx chat-id]
|
||||||
(let [chat (get-chat cofx chat-id)]
|
(let [chat (get-chat cofx chat-id)]
|
||||||
(:active chat)))
|
(:active chat)))
|
||||||
|
|
||||||
@@ -85,52 +88,56 @@
|
|||||||
(defn- create-new-chat
|
(defn- create-new-chat
|
||||||
[chat-id {:keys [db now]}]
|
[chat-id {:keys [db now]}]
|
||||||
(let [name (get-in db [:contacts/contacts chat-id :name])]
|
(let [name (get-in db [:contacts/contacts chat-id :name])]
|
||||||
{:chat-id chat-id
|
{:chat-id chat-id
|
||||||
:name (or name "")
|
:name (or name "")
|
||||||
:color (rand-nth colors/chat-colors)
|
:color (rand-nth colors/chat-colors)
|
||||||
:chat-type constants/one-to-one-chat-type
|
:chat-type constants/one-to-one-chat-type
|
||||||
:group-chat false
|
:group-chat false
|
||||||
:timestamp now
|
:timestamp now
|
||||||
:contacts #{chat-id}
|
:contacts #{chat-id}
|
||||||
:last-clock-value 0}))
|
:last-clock-value 0}))
|
||||||
|
|
||||||
(defn map-chats [{:keys [db] :as cofx}]
|
(defn map-chats
|
||||||
|
[{:keys [db] :as cofx}]
|
||||||
(fn [val]
|
(fn [val]
|
||||||
(assoc
|
(assoc
|
||||||
(merge
|
(merge
|
||||||
(or (get (:chats db) (:chat-id val))
|
(or (get (:chats db) (:chat-id val))
|
||||||
(create-new-chat (:chat-id val) cofx))
|
(create-new-chat (:chat-id val) cofx))
|
||||||
val)
|
val)
|
||||||
:invitation-admin (:invitation-admin val))))
|
:invitation-admin
|
||||||
|
(:invitation-admin val))))
|
||||||
|
|
||||||
(defn filter-chats [db]
|
(defn filter-chats
|
||||||
|
[db]
|
||||||
(fn [val]
|
(fn [val]
|
||||||
(and (not (get-in db [:chats (:chat-id val)])) (:public? val))))
|
(and (not (get-in db [:chats (:chat-id val)])) (:public? val))))
|
||||||
|
|
||||||
(fx/defn leave-removed-chat
|
(rf/defn leave-removed-chat
|
||||||
[{{:keys [view-id current-chat-id chats]} :db
|
[{{:keys [view-id current-chat-id chats]} :db
|
||||||
:as cofx}]
|
:as cofx}]
|
||||||
(when (and (= view-id :chat)
|
(when (and (= view-id :chat)
|
||||||
(not (contains? chats current-chat-id)))
|
(not (contains? chats current-chat-id)))
|
||||||
(navigation/navigate-back cofx)))
|
(navigation/navigate-back cofx)))
|
||||||
|
|
||||||
(fx/defn ensure-chats
|
(rf/defn ensure-chats
|
||||||
"Add chats to db and update"
|
"Add chats to db and update"
|
||||||
[{:keys [db] :as cofx} chats]
|
[{:keys [db] :as cofx} chats]
|
||||||
(let [{:keys [all-chats chats-home-list removed-chats]}
|
(let [{:keys [all-chats chats-home-list removed-chats]}
|
||||||
(reduce (fn [acc {:keys [chat-id profile-public-key timeline? community-id active muted] :as chat}]
|
(reduce
|
||||||
(if (not (or active muted))
|
(fn [acc {:keys [chat-id profile-public-key timeline? community-id active muted] :as chat}]
|
||||||
(update acc :removed-chats conj chat-id)
|
(if (not (or active muted))
|
||||||
(cond-> acc
|
(update acc :removed-chats conj chat-id)
|
||||||
(and (not profile-public-key) (not timeline?) (not community-id) active)
|
(cond-> acc
|
||||||
(update :chats-home-list conj chat-id)
|
(and (not profile-public-key) (not timeline?) (not community-id) active)
|
||||||
:always
|
(update :chats-home-list conj chat-id)
|
||||||
(assoc-in [:all-chats chat-id] chat))))
|
:always
|
||||||
{:all-chats {}
|
(assoc-in [:all-chats chat-id] chat))))
|
||||||
:chats-home-list #{}
|
{:all-chats {}
|
||||||
:removed-chats #{}}
|
:chats-home-list #{}
|
||||||
(map (map-chats cofx) chats))]
|
:removed-chats #{}}
|
||||||
(fx/merge
|
(map (map-chats cofx) chats))]
|
||||||
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
(merge {:db (-> db
|
(merge {:db (-> db
|
||||||
(update :chats merge all-chats)
|
(update :chats merge all-chats)
|
||||||
@@ -143,62 +150,66 @@
|
|||||||
(get-in db [:multiaccount :remote-push-notifications-enabled?])]}))
|
(get-in db [:multiaccount :remote-push-notifications-enabled?])]}))
|
||||||
leave-removed-chat)))
|
leave-removed-chat)))
|
||||||
|
|
||||||
(fx/defn clear-history
|
(rf/defn clear-history
|
||||||
"Clears history of the particular chat"
|
"Clears history of the particular chat"
|
||||||
[{:keys [db] :as cofx} chat-id remove-chat?]
|
[{:keys [db] :as cofx} chat-id remove-chat?]
|
||||||
(let [{:keys [last-message public?
|
(let [{:keys [last-message public?
|
||||||
deleted-at-clock-value]} (get-in db [:chats chat-id])
|
deleted-at-clock-value]}
|
||||||
|
(get-in db [:chats chat-id])
|
||||||
last-message-clock-value (if (and public? remove-chat?)
|
last-message-clock-value (if (and public? remove-chat?)
|
||||||
0
|
0
|
||||||
(or (:clock-value last-message)
|
(or (:clock-value last-message)
|
||||||
deleted-at-clock-value
|
deleted-at-clock-value
|
||||||
(utils.clocks/send 0)))]
|
(utils.clocks/send 0)))]
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:messages chat-id] {})
|
(assoc-in [:messages chat-id] {})
|
||||||
(update-in [:message-lists] dissoc chat-id)
|
(update-in [:message-lists] dissoc chat-id)
|
||||||
(update :chats (fn [chats]
|
(update :chats
|
||||||
(if (contains? chats chat-id)
|
(fn [chats]
|
||||||
(update chats chat-id merge
|
(if (contains? chats chat-id)
|
||||||
{:last-message nil
|
(update chats
|
||||||
:unviewed-messages-count 0
|
chat-id
|
||||||
:unviewed-mentions-count 0
|
merge
|
||||||
:deleted-at-clock-value last-message-clock-value})
|
{:last-message nil
|
||||||
chats))))}))
|
:unviewed-messages-count 0
|
||||||
|
:unviewed-mentions-count 0
|
||||||
|
:deleted-at-clock-value last-message-clock-value})
|
||||||
|
chats))))}))
|
||||||
|
|
||||||
(fx/defn clear-history-handler
|
(rf/defn clear-history-handler
|
||||||
"Clears history of the particular chat"
|
"Clears history of the particular chat"
|
||||||
{:events [:chat.ui/clear-history]}
|
{:events [:chat.ui/clear-history]}
|
||||||
[{:keys [db] :as cofx} chat-id remove-chat?]
|
[{:keys [db] :as cofx} chat-id remove-chat?]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db db
|
{:db db
|
||||||
::json-rpc/call [{:method "wakuext_clearHistory"
|
::json-rpc/call [{:method "wakuext_clearHistory"
|
||||||
:params [{:id chat-id}]
|
:params [{:id chat-id}]
|
||||||
:on-success #(re-frame/dispatch [::history-cleared chat-id %])
|
:on-success #(re-frame/dispatch [::history-cleared chat-id %])
|
||||||
:on-error #(log/error "failed to clear history " chat-id %)}]}
|
:on-error #(log/error "failed to clear history " chat-id %)}]}
|
||||||
(clear-history chat-id remove-chat?)))
|
(clear-history chat-id remove-chat?)))
|
||||||
|
|
||||||
(fx/defn chat-deactivated
|
(rf/defn chat-deactivated
|
||||||
{:events [::chat-deactivated]}
|
{:events [::chat-deactivated]}
|
||||||
[_ chat-id]
|
[_ chat-id]
|
||||||
(log/debug "chat deactivated" chat-id))
|
(log/debug "chat deactivated" chat-id))
|
||||||
|
|
||||||
(fx/defn deactivate-chat
|
(rf/defn deactivate-chat
|
||||||
"Deactivate chat in db, no side effects"
|
"Deactivate chat in db, no side effects"
|
||||||
[{:keys [db now] :as cofx} chat-id]
|
[{:keys [db now] :as cofx} chat-id]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (-> (if (get-in db [:chats chat-id :muted])
|
{:db (-> (if (get-in db [:chats chat-id :muted])
|
||||||
(assoc-in db [:chats chat-id :active] false)
|
(assoc-in db [:chats chat-id :active] false)
|
||||||
(update db :chats dissoc chat-id))
|
(update db :chats dissoc chat-id))
|
||||||
(update :chats-home-list disj chat-id)
|
(update :chats-home-list disj chat-id)
|
||||||
(assoc :current-chat-id nil))
|
(assoc :current-chat-id nil))
|
||||||
::json-rpc/call [{:method "wakuext_deactivateChat"
|
::json-rpc/call [{:method "wakuext_deactivateChat"
|
||||||
:params [{:id chat-id}]
|
:params [{:id chat-id}]
|
||||||
:on-success #(re-frame/dispatch [::chat-deactivated chat-id])
|
:on-success #(re-frame/dispatch [::chat-deactivated chat-id])
|
||||||
:on-error #(log/error "failed to create public chat" chat-id %)}]}
|
:on-error #(log/error "failed to create public chat" chat-id %)}]}
|
||||||
(clear-history chat-id true)))
|
(clear-history chat-id true)))
|
||||||
|
|
||||||
(fx/defn offload-messages
|
(rf/defn offload-messages
|
||||||
{:events [:offload-messages]}
|
{:events [:offload-messages]}
|
||||||
[{:keys [db]} chat-id]
|
[{:keys [db]} chat-id]
|
||||||
(merge {:db (-> db
|
(merge {:db (-> db
|
||||||
@@ -208,52 +219,52 @@
|
|||||||
(when (and (= chat-id constants/timeline-chat-id) (= (:view-id db) :status))
|
(when (and (= chat-id constants/timeline-chat-id) (= (:view-id db) :status))
|
||||||
{:dispatch [:init-timeline-chat]})))
|
{:dispatch [:init-timeline-chat]})))
|
||||||
|
|
||||||
(fx/defn close-chat
|
(rf/defn close-chat
|
||||||
{:events [:close-chat]}
|
{:events [:close-chat]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(when-let [chat-id (:current-chat-id db)]
|
(when-let [chat-id (:current-chat-id db)]
|
||||||
(chat.state/reset-visible-item)
|
(chat.state/reset-visible-item)
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (dissoc db :current-chat-id)}
|
{:db (dissoc db :current-chat-id)}
|
||||||
(delete-for-me/sync-all)
|
(delete-for-me/sync-all)
|
||||||
(delete-message/send-all)
|
(delete-message/send-all)
|
||||||
(offload-messages chat-id))))
|
(offload-messages chat-id))))
|
||||||
|
|
||||||
(fx/defn force-close-chat
|
(rf/defn force-close-chat
|
||||||
[{:keys [db] :as cofx} chat-id]
|
[{:keys [db] :as cofx} chat-id]
|
||||||
(do
|
(do
|
||||||
(chat.state/reset-visible-item)
|
(chat.state/reset-visible-item)
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (dissoc db :current-chat-id)}
|
{:db (dissoc db :current-chat-id)}
|
||||||
(offload-messages chat-id))))
|
(offload-messages chat-id))))
|
||||||
|
|
||||||
(fx/defn remove-chat
|
(rf/defn remove-chat
|
||||||
"Removes chat completely from app, producing all necessary effects for that"
|
"Removes chat completely from app, producing all necessary effects for that"
|
||||||
{:events [:chat.ui/remove-chat]}
|
{:events [:chat.ui/remove-chat]}
|
||||||
[{:keys [db now] :as cofx} chat-id]
|
[{:keys [db now] :as cofx} chat-id]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:clear-message-notifications
|
{:clear-message-notifications
|
||||||
[[chat-id] (get-in db [:multiaccount :remote-push-notifications-enabled?])]}
|
[[chat-id] (get-in db [:multiaccount :remote-push-notifications-enabled?])]}
|
||||||
(deactivate-chat chat-id)
|
(deactivate-chat chat-id)
|
||||||
(offload-messages chat-id)))
|
(offload-messages chat-id)))
|
||||||
|
|
||||||
(fx/defn show-more-chats
|
(rf/defn show-more-chats
|
||||||
{:events [:chat.ui/show-more-chats]}
|
{:events [:chat.ui/show-more-chats]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(when (< (:home-items-show-number db) (count (:chats db)))
|
(when (< (:home-items-show-number db) (count (:chats db)))
|
||||||
{:db (update db :home-items-show-number + 40)}))
|
{:db (update db :home-items-show-number + 40)}))
|
||||||
|
|
||||||
(fx/defn preload-chat-data
|
(rf/defn preload-chat-data
|
||||||
"Takes chat-id and coeffects map, returns effects necessary when navigating to chat"
|
"Takes chat-id and coeffects map, returns effects necessary when navigating to chat"
|
||||||
{:events [:chat.ui/preload-chat-data]}
|
{:events [:chat.ui/preload-chat-data]}
|
||||||
[cofx chat-id]
|
[cofx chat-id]
|
||||||
(loading/load-messages cofx chat-id))
|
(loading/load-messages cofx chat-id))
|
||||||
|
|
||||||
(fx/defn navigate-to-chat
|
(rf/defn navigate-to-chat
|
||||||
"Takes coeffects map and chat-id, returns effects necessary for navigation and preloading data"
|
"Takes coeffects map and chat-id, returns effects necessary for navigation and preloading data"
|
||||||
{:events [:chat.ui/navigate-to-chat]}
|
{:events [:chat.ui/navigate-to-chat]}
|
||||||
[{db :db :as cofx} chat-id]
|
[{db :db :as cofx} chat-id]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:dispatch [:navigate-to :chat]}
|
{:dispatch [:navigate-to :chat]}
|
||||||
(navigation/change-tab :chat)
|
(navigation/change-tab :chat)
|
||||||
(when-not (= (:view-id db) :community)
|
(when-not (= (:view-id db) :community)
|
||||||
@@ -266,11 +277,11 @@
|
|||||||
#(when (group-chat? cofx chat-id)
|
#(when (group-chat? cofx chat-id)
|
||||||
(loading/load-chat % chat-id))))
|
(loading/load-chat % chat-id))))
|
||||||
|
|
||||||
(fx/defn navigate-to-chat-nav2
|
(rf/defn navigate-to-chat-nav2
|
||||||
"Takes coeffects map and chat-id, returns effects necessary for navigation and preloading data"
|
"Takes coeffects map and chat-id, returns effects necessary for navigation and preloading data"
|
||||||
{:events [:chat.ui/navigate-to-chat-nav2]}
|
{:events [:chat.ui/navigate-to-chat-nav2]}
|
||||||
[{db :db :as cofx} chat-id from-shell?]
|
[{db :db :as cofx} chat-id from-shell?]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:dispatch [:navigate-to-nav2 :chat chat-id from-shell?]}
|
{:dispatch [:navigate-to-nav2 :chat chat-id from-shell?]}
|
||||||
(when-not (= (:view-id db) :community)
|
(when-not (= (:view-id db) :community)
|
||||||
(navigation/pop-to-root-tab :shell-stack))
|
(navigation/pop-to-root-tab :shell-stack))
|
||||||
@@ -282,65 +293,68 @@
|
|||||||
#(when (group-chat? cofx chat-id)
|
#(when (group-chat? cofx chat-id)
|
||||||
(loading/load-chat % chat-id))))
|
(loading/load-chat % chat-id))))
|
||||||
|
|
||||||
(fx/defn handle-clear-history-response
|
(rf/defn handle-clear-history-response
|
||||||
{:events [::history-cleared]}
|
{:events [::history-cleared]}
|
||||||
[{:keys [db]} chat-id response]
|
[{:keys [db]} chat-id response]
|
||||||
(let [chat (chats-store/<-rpc (first (:chats response)))]
|
(let [chat (chats-store/<-rpc (first (:chats response)))]
|
||||||
{:db (assoc-in db [:chats chat-id] chat)}))
|
{:db (assoc-in db [:chats chat-id] chat)}))
|
||||||
|
|
||||||
(fx/defn handle-one-to-one-chat-created
|
(rf/defn handle-one-to-one-chat-created
|
||||||
{:events [::one-to-one-chat-created]}
|
{:events [::one-to-one-chat-created]}
|
||||||
[{:keys [db]} chat-id response]
|
[{:keys [db]} chat-id response]
|
||||||
(let [chat (chats-store/<-rpc (first (:chats response)))
|
(let [chat (chats-store/<-rpc (first (:chats response)))
|
||||||
contact-rpc (first (:contacts response))
|
contact-rpc (first (:contacts response))
|
||||||
contact (when contact-rpc (contacts-store/<-rpc contact-rpc))]
|
contact (when contact-rpc (contacts-store/<-rpc contact-rpc))]
|
||||||
{:db (cond-> db
|
{:db (cond-> db
|
||||||
contact
|
contact
|
||||||
(assoc-in [:contacts/contacts chat-id] contact)
|
(assoc-in [:contacts/contacts chat-id] contact)
|
||||||
:always
|
:always
|
||||||
(assoc-in [:chats chat-id] chat)
|
(assoc-in [:chats chat-id] chat)
|
||||||
:always
|
:always
|
||||||
(update :chats-home-list conj chat-id))
|
(update :chats-home-list conj chat-id))
|
||||||
:dispatch [:chat.ui/navigate-to-chat chat-id]}))
|
:dispatch [:chat.ui/navigate-to-chat chat-id]}))
|
||||||
|
|
||||||
(fx/defn navigate-to-user-pinned-messages
|
(rf/defn navigate-to-user-pinned-messages
|
||||||
"Takes coeffects map and chat-id, returns effects necessary for navigation and preloading data"
|
"Takes coeffects map and chat-id, returns effects necessary for navigation and preloading data"
|
||||||
{:events [:chat.ui/navigate-to-pinned-messages]}
|
{:events [:chat.ui/navigate-to-pinned-messages]}
|
||||||
[cofx chat-id]
|
[cofx chat-id]
|
||||||
(navigation/navigate-to cofx :chat-pinned-messages {:chat-id chat-id}))
|
(navigation/navigate-to cofx :chat-pinned-messages {:chat-id chat-id}))
|
||||||
|
|
||||||
(fx/defn start-chat
|
(rf/defn start-chat
|
||||||
"Start a chat, making sure it exists"
|
"Start a chat, making sure it exists"
|
||||||
{:events [:chat.ui/start-chat]}
|
{:events [:chat.ui/start-chat]}
|
||||||
[{:keys [db] :as cofx} chat-id ens-name]
|
[{:keys [db] :as cofx} chat-id ens-name]
|
||||||
;; don't allow to open chat with yourself
|
;; don't allow to open chat with yourself
|
||||||
(when (not= (multiaccounts.model/current-public-key cofx) chat-id)
|
(when (not= (multiaccounts.model/current-public-key cofx) chat-id)
|
||||||
{::json-rpc/call [{:method "wakuext_createOneToOneChat"
|
{::json-rpc/call [{:method "wakuext_createOneToOneChat"
|
||||||
:params [{:id chat-id :ensName ens-name}]
|
:params [{:id chat-id :ensName ens-name}]
|
||||||
:on-success #(re-frame/dispatch [::one-to-one-chat-created chat-id %])
|
:on-success #(re-frame/dispatch [::one-to-one-chat-created chat-id %])
|
||||||
:on-error #(log/error "failed to create one-to-on chat" chat-id %)}]}))
|
:on-error #(log/error "failed to create one-to-on chat" chat-id %)}]}))
|
||||||
|
|
||||||
(defn profile-chat-topic [public-key]
|
(defn profile-chat-topic
|
||||||
|
[public-key]
|
||||||
(str "@" public-key))
|
(str "@" public-key))
|
||||||
|
|
||||||
(defn my-profile-chat-topic [db]
|
(defn my-profile-chat-topic
|
||||||
|
[db]
|
||||||
(profile-chat-topic (get-in db [:multiaccount :public-key])))
|
(profile-chat-topic (get-in db [:multiaccount :public-key])))
|
||||||
|
|
||||||
(fx/defn handle-public-chat-created
|
(rf/defn handle-public-chat-created
|
||||||
{:events [::public-chat-created]}
|
{:events [::public-chat-created]}
|
||||||
[{:keys [db]} chat-id response]
|
[{:keys [db]} chat-id response]
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:chats chat-id] (chats-store/<-rpc (first (:chats response))))
|
(assoc-in [:chats chat-id] (chats-store/<-rpc (first (:chats response))))
|
||||||
(update :chats-home-list conj chat-id))
|
(update :chats-home-list conj chat-id))
|
||||||
:dispatch [:chat.ui/navigate-to-chat chat-id]})
|
:dispatch [:chat.ui/navigate-to-chat chat-id]})
|
||||||
|
|
||||||
(fx/defn create-public-chat-go [_ chat-id]
|
(rf/defn create-public-chat-go
|
||||||
{::json-rpc/call [{:method "wakuext_createPublicChat"
|
[_ chat-id]
|
||||||
:params [{:id chat-id}]
|
{::json-rpc/call [{:method "wakuext_createPublicChat"
|
||||||
|
:params [{:id chat-id}]
|
||||||
:on-success #(re-frame/dispatch [::public-chat-created chat-id %])
|
:on-success #(re-frame/dispatch [::public-chat-created chat-id %])
|
||||||
:on-error #(log/error "failed to create public chat" chat-id %)}]})
|
:on-error #(log/error "failed to create public chat" chat-id %)}]})
|
||||||
|
|
||||||
(fx/defn start-public-chat
|
(rf/defn start-public-chat
|
||||||
"Starts a new public chat"
|
"Starts a new public chat"
|
||||||
{:events [:chat.ui/start-public-chat]}
|
{:events [:chat.ui/start-public-chat]}
|
||||||
[cofx topic]
|
[cofx topic]
|
||||||
@@ -353,10 +367,10 @@
|
|||||||
{:utils/show-popup {:title (i18n/label :t/cant-open-public-chat)
|
{:utils/show-popup {:title (i18n/label :t/cant-open-public-chat)
|
||||||
:content (i18n/label :t/invalid-public-chat-topic)}}))
|
:content (i18n/label :t/invalid-public-chat-topic)}}))
|
||||||
|
|
||||||
(fx/defn profile-chat-created
|
(rf/defn profile-chat-created
|
||||||
{:events [::profile-chat-created]}
|
{:events [::profile-chat-created]}
|
||||||
[{:keys [db] :as cofx} chat-id response navigate-to?]
|
[{:keys [db] :as cofx} chat-id response navigate-to?]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db db}
|
{:db db}
|
||||||
#(when response
|
#(when response
|
||||||
@@ -366,19 +380,19 @@
|
|||||||
{:dispatch-n [[:chat.ui/preload-chat-data chat-id]
|
{:dispatch-n [[:chat.ui/preload-chat-data chat-id]
|
||||||
[:open-modal :profile]]})))
|
[:open-modal :profile]]})))
|
||||||
|
|
||||||
(fx/defn start-profile-chat
|
(rf/defn start-profile-chat
|
||||||
"Starts a new profile chat"
|
"Starts a new profile chat"
|
||||||
{:events [:start-profile-chat]}
|
{:events [:start-profile-chat]}
|
||||||
[cofx profile-public-key navigate-to?]
|
[cofx profile-public-key navigate-to?]
|
||||||
(let [chat-id (profile-chat-topic profile-public-key)]
|
(let [chat-id (profile-chat-topic profile-public-key)]
|
||||||
(if (active-chat? cofx chat-id)
|
(if (active-chat? cofx chat-id)
|
||||||
{:dispatch [::profile-chat-created chat-id nil navigate-to?]}
|
{:dispatch [::profile-chat-created chat-id nil navigate-to?]}
|
||||||
{::json-rpc/call [{:method "wakuext_createProfileChat"
|
{::json-rpc/call [{:method "wakuext_createProfileChat"
|
||||||
:params [{:id profile-public-key}]
|
:params [{:id profile-public-key}]
|
||||||
:on-success #(re-frame/dispatch [::profile-chat-created chat-id % navigate-to?])
|
:on-success #(re-frame/dispatch [::profile-chat-created chat-id % navigate-to?])
|
||||||
:on-error #(log/error "failed to create profile chat" chat-id %)}]})))
|
:on-error #(log/error "failed to create profile chat" chat-id %)}]})))
|
||||||
|
|
||||||
(fx/defn disable-chat-cooldown
|
(rf/defn disable-chat-cooldown
|
||||||
"Turns off chat cooldown (protection against message spamming)"
|
"Turns off chat cooldown (protection against message spamming)"
|
||||||
{:events [:chat/disable-cooldown]}
|
{:events [:chat/disable-cooldown]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
@@ -392,40 +406,40 @@
|
|||||||
(i18n/label :cooldown/warning-message)
|
(i18n/label :cooldown/warning-message)
|
||||||
#())))
|
#())))
|
||||||
|
|
||||||
(fx/defn mute-chat-failed
|
(rf/defn mute-chat-failed
|
||||||
{:events [::mute-chat-failed]}
|
{:events [::mute-chat-failed]}
|
||||||
[{:keys [db] :as cofx} chat-id muted? error]
|
[{:keys [db] :as cofx} chat-id muted? error]
|
||||||
(log/error "mute chat failed" chat-id error)
|
(log/error "mute chat failed" chat-id error)
|
||||||
{:db (assoc-in db [:chats chat-id :muted] (not muted?))})
|
{:db (assoc-in db [:chats chat-id :muted] (not muted?))})
|
||||||
|
|
||||||
(fx/defn mute-chat-toggled-successfully
|
(rf/defn mute-chat-toggled-successfully
|
||||||
{:events [::mute-chat-toggled-successfully]}
|
{:events [::mute-chat-toggled-successfully]}
|
||||||
[_ chat-id]
|
[_ chat-id]
|
||||||
(log/debug "muted chat successfully" chat-id))
|
(log/debug "muted chat successfully" chat-id))
|
||||||
|
|
||||||
(fx/defn mute-chat
|
(rf/defn mute-chat
|
||||||
{:events [::mute-chat-toggled]}
|
{:events [::mute-chat-toggled]}
|
||||||
[{:keys [db] :as cofx} chat-id muted?]
|
[{:keys [db] :as cofx} chat-id muted?]
|
||||||
(let [method (if muted? "wakuext_muteChat" "wakuext_unmuteChat")]
|
(let [method (if muted? "wakuext_muteChat" "wakuext_unmuteChat")]
|
||||||
{:db (assoc-in db [:chats chat-id :muted] muted?)
|
{:db (assoc-in db [:chats chat-id :muted] muted?)
|
||||||
::json-rpc/call [{:method method
|
::json-rpc/call [{:method method
|
||||||
:params [chat-id]
|
:params [chat-id]
|
||||||
:on-error #(re-frame/dispatch [::mute-chat-failed chat-id muted? %])
|
:on-error #(re-frame/dispatch [::mute-chat-failed chat-id muted? %])
|
||||||
:on-success #(re-frame/dispatch [::mute-chat-toggled-successfully chat-id])}]}))
|
:on-success #(re-frame/dispatch [::mute-chat-toggled-successfully chat-id])}]}))
|
||||||
|
|
||||||
(fx/defn show-profile
|
(rf/defn show-profile
|
||||||
{:events [:chat.ui/show-profile]}
|
{:events [:chat.ui/show-profile]}
|
||||||
[{:keys [db] :as cofx} identity ens-name]
|
[{:keys [db] :as cofx} identity ens-name]
|
||||||
(let [my-public-key (get-in db [:multiaccount :public-key])]
|
(let [my-public-key (get-in db [:multiaccount :public-key])]
|
||||||
(when (not= my-public-key identity)
|
(when (not= my-public-key identity)
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc :contacts/identity identity)
|
(assoc :contacts/identity identity)
|
||||||
(assoc :contacts/ens-name ens-name))}
|
(assoc :contacts/ens-name ens-name))}
|
||||||
(start-profile-chat identity true)))))
|
(start-profile-chat identity true)))))
|
||||||
|
|
||||||
(fx/defn clear-history-pressed
|
(rf/defn clear-history-pressed
|
||||||
{:events [:chat.ui/clear-history-pressed]}
|
{:events [:chat.ui/clear-history-pressed]}
|
||||||
[_ chat-id]
|
[_ chat-id]
|
||||||
{:ui/show-confirmation
|
{:ui/show-confirmation
|
||||||
@@ -436,19 +450,19 @@
|
|||||||
(re-frame/dispatch [:bottom-sheet/hide])
|
(re-frame/dispatch [:bottom-sheet/hide])
|
||||||
(re-frame/dispatch [:chat.ui/clear-history chat-id false]))}})
|
(re-frame/dispatch [:chat.ui/clear-history chat-id false]))}})
|
||||||
|
|
||||||
(fx/defn gaps-failed
|
(rf/defn gaps-failed
|
||||||
{:events [::gaps-failed]}
|
{:events [::gaps-failed]}
|
||||||
[{:keys [db]} chat-id gap-ids error]
|
[{:keys [db]} chat-id gap-ids error]
|
||||||
(log/error "failed to fetch gaps" chat-id gap-ids error)
|
(log/error "failed to fetch gaps" chat-id gap-ids error)
|
||||||
{:db (dissoc db :mailserver/fetching-gaps-in-progress)})
|
{:db (dissoc db :mailserver/fetching-gaps-in-progress)})
|
||||||
|
|
||||||
(fx/defn sync-chat-from-sync-from-failed
|
(rf/defn sync-chat-from-sync-from-failed
|
||||||
{:events [::sync-chat-from-sync-from-failed]}
|
{:events [::sync-chat-from-sync-from-failed]}
|
||||||
[{:keys [db]} chat-id error]
|
[{:keys [db]} chat-id error]
|
||||||
(log/error "failed to sync chat" chat-id error)
|
(log/error "failed to sync chat" chat-id error)
|
||||||
{:db (dissoc db :mailserver/fetching-gaps-in-progress)})
|
{:db (dissoc db :mailserver/fetching-gaps-in-progress)})
|
||||||
|
|
||||||
(fx/defn sync-chat-from-sync-from-success
|
(rf/defn sync-chat-from-sync-from-success
|
||||||
{:events [::sync-chat-from-sync-from-success]}
|
{:events [::sync-chat-from-sync-from-success]}
|
||||||
[{:keys [db] :as cofx} chat-id synced-from]
|
[{:keys [db] :as cofx} chat-id synced-from]
|
||||||
(log/debug "synced success" chat-id synced-from)
|
(log/debug "synced success" chat-id synced-from)
|
||||||
@@ -457,44 +471,44 @@
|
|||||||
(assoc-in [:chats chat-id :synced-from] synced-from)
|
(assoc-in [:chats chat-id :synced-from] synced-from)
|
||||||
(dissoc :mailserver/fetching-gaps-in-progress))})
|
(dissoc :mailserver/fetching-gaps-in-progress))})
|
||||||
|
|
||||||
(fx/defn gaps-filled
|
(rf/defn gaps-filled
|
||||||
{:events [::gaps-filled]}
|
{:events [::gaps-filled]}
|
||||||
[{:keys [db] :as cofx} chat-id message-ids]
|
[{:keys [db] :as cofx} chat-id message-ids]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(update-in [:messages chat-id] (fn [messages] (apply dissoc messages message-ids)))
|
(update-in [:messages chat-id] (fn [messages] (apply dissoc messages message-ids)))
|
||||||
(dissoc :mailserver/fetching-gaps-in-progress))}
|
(dissoc :mailserver/fetching-gaps-in-progress))}
|
||||||
(message-list/rebuild-message-list chat-id)))
|
(message-list/rebuild-message-list chat-id)))
|
||||||
|
|
||||||
(fx/defn fill-gaps
|
(rf/defn fill-gaps
|
||||||
[cofx chat-id gap-ids]
|
[cofx chat-id gap-ids]
|
||||||
{::json-rpc/call [{:method "wakuext_fillGaps"
|
{::json-rpc/call [{:method "wakuext_fillGaps"
|
||||||
:params [chat-id gap-ids]
|
:params [chat-id gap-ids]
|
||||||
:on-success #(re-frame/dispatch [::gaps-filled chat-id gap-ids %])
|
:on-success #(re-frame/dispatch [::gaps-filled chat-id gap-ids %])
|
||||||
:on-error #(re-frame/dispatch [::gaps-failed chat-id gap-ids %])}]})
|
:on-error #(re-frame/dispatch [::gaps-failed chat-id gap-ids %])}]})
|
||||||
|
|
||||||
(fx/defn sync-chat-from-sync-from
|
(rf/defn sync-chat-from-sync-from
|
||||||
[cofx chat-id]
|
[cofx chat-id]
|
||||||
(log/debug "syncing chat from sync from")
|
(log/debug "syncing chat from sync from")
|
||||||
{::json-rpc/call [{:method "wakuext_syncChatFromSyncedFrom"
|
{::json-rpc/call [{:method "wakuext_syncChatFromSyncedFrom"
|
||||||
:params [chat-id]
|
:params [chat-id]
|
||||||
:on-success #(re-frame/dispatch [::sync-chat-from-sync-from-success chat-id %])
|
:on-success #(re-frame/dispatch [::sync-chat-from-sync-from-success chat-id %])
|
||||||
:on-error #(re-frame/dispatch [::sync-chat-from-sync-from-failed chat-id %])}]})
|
:on-error #(re-frame/dispatch [::sync-chat-from-sync-from-failed chat-id %])}]})
|
||||||
|
|
||||||
(fx/defn chat-ui-fill-gaps
|
(rf/defn chat-ui-fill-gaps
|
||||||
{:events [:chat.ui/fill-gaps]}
|
{:events [:chat.ui/fill-gaps]}
|
||||||
[{:keys [db] :as cofx} chat-id gap-ids]
|
[{:keys [db] :as cofx} chat-id gap-ids]
|
||||||
(let [use-status-nodes? (mailserver/fetch-use-mailservers? {:db db})]
|
(let [use-status-nodes? (mailserver/fetch-use-mailservers? {:db db})]
|
||||||
(log/info "filling gaps if use-status-nodes = true" chat-id gap-ids)
|
(log/info "filling gaps if use-status-nodes = true" chat-id gap-ids)
|
||||||
(when use-status-nodes?
|
(when use-status-nodes?
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc db :mailserver/fetching-gaps-in-progress gap-ids)}
|
{:db (assoc db :mailserver/fetching-gaps-in-progress gap-ids)}
|
||||||
(if (= gap-ids #{:first-gap})
|
(if (= gap-ids #{:first-gap})
|
||||||
(sync-chat-from-sync-from chat-id)
|
(sync-chat-from-sync-from chat-id)
|
||||||
(fill-gaps chat-id gap-ids))))))
|
(fill-gaps chat-id gap-ids))))))
|
||||||
|
|
||||||
(fx/defn chat-ui-remove-chat-pressed
|
(rf/defn chat-ui-remove-chat-pressed
|
||||||
{:events [:chat.ui/remove-chat-pressed]}
|
{:events [:chat.ui/remove-chat-pressed]}
|
||||||
[_ chat-id]
|
[_ chat-id]
|
||||||
{:ui/show-confirmation
|
{:ui/show-confirmation
|
||||||
@@ -505,7 +519,7 @@
|
|||||||
(re-frame/dispatch [:bottom-sheet/hide])
|
(re-frame/dispatch [:bottom-sheet/hide])
|
||||||
(re-frame/dispatch [:chat.ui/remove-chat chat-id]))}})
|
(re-frame/dispatch [:chat.ui/remove-chat chat-id]))}})
|
||||||
|
|
||||||
(fx/defn decrease-unviewed-count
|
(rf/defn decrease-unviewed-count
|
||||||
{:events [:chat/decrease-unviewed-count]}
|
{:events [:chat/decrease-unviewed-count]}
|
||||||
[{:keys [db]} chat-id {:keys [count countWithMentions]}]
|
[{:keys [db]} chat-id {:keys [count countWithMentions]}]
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
|
|||||||
@@ -1,24 +1,25 @@
|
|||||||
(ns status-im.chat.models.images
|
(ns status-im.chat.models.images
|
||||||
(:require [re-frame.core :as re-frame]
|
(:require ["@react-native-community/cameraroll" :as CameraRoll]
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
["@react-native-community/cameraroll" :as CameraRoll]
|
|
||||||
["react-native-blob-util" :default ReactNativeBlobUtil]
|
["react-native-blob-util" :default ReactNativeBlobUtil]
|
||||||
[status-im.utils.types :as types]
|
[clojure.string :as string]
|
||||||
[status-im.utils.config :as config]
|
[re-frame.core :as re-frame]
|
||||||
|
[status-im.chat.models :as chat]
|
||||||
|
[status-im.i18n.i18n :as i18n]
|
||||||
[status-im.ui.components.permissions :as permissions]
|
[status-im.ui.components.permissions :as permissions]
|
||||||
[status-im.ui.components.react :as react]
|
[status-im.ui.components.react :as react]
|
||||||
[status-im.utils.image-processing :as image-processing]
|
[status-im.utils.config :as config]
|
||||||
[taoensso.timbre :as log]
|
|
||||||
[clojure.string :as string]
|
|
||||||
[status-im.i18n.i18n :as i18n]
|
|
||||||
[status-im.utils.utils :as utils]
|
|
||||||
[status-im.utils.platform :as platform]
|
|
||||||
[status-im.utils.fs :as fs]
|
[status-im.utils.fs :as fs]
|
||||||
[status-im.chat.models :as chat]))
|
[status-im.utils.image-processing :as image-processing]
|
||||||
|
[status-im.utils.platform :as platform]
|
||||||
|
[status-im.utils.types :as types]
|
||||||
|
[status-im.utils.utils :as utils]
|
||||||
|
[taoensso.timbre :as log]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(def maximum-image-size-px 2000)
|
(def maximum-image-size-px 2000)
|
||||||
|
|
||||||
(defn- resize-and-call [uri cb]
|
(defn- resize-and-call
|
||||||
|
[uri cb]
|
||||||
(react/image-get-size
|
(react/image-get-size
|
||||||
uri
|
uri
|
||||||
(fn [width height]
|
(fn [width height]
|
||||||
@@ -34,16 +35,19 @@
|
|||||||
(cb path)))
|
(cb path)))
|
||||||
#(log/error "could not resize image" %))))))
|
#(log/error "could not resize image" %))))))
|
||||||
|
|
||||||
(defn result->id [^js result]
|
(defn result->id
|
||||||
|
[^js result]
|
||||||
(if platform/ios?
|
(if platform/ios?
|
||||||
(.-localIdentifier result)
|
(.-localIdentifier result)
|
||||||
(.-path result)))
|
(.-path result)))
|
||||||
|
|
||||||
(def temp-image-url (str (fs/cache-dir) "/StatusIm_Image.jpeg"))
|
(def temp-image-url (str (fs/cache-dir) "/StatusIm_Image.jpeg"))
|
||||||
|
|
||||||
(defn download-image-http [base64-uri on-success]
|
(defn download-image-http
|
||||||
(-> (.config ReactNativeBlobUtil (clj->js {:trusty platform/ios?
|
[base64-uri on-success]
|
||||||
:path temp-image-url}))
|
(-> (.config ReactNativeBlobUtil
|
||||||
|
(clj->js {:trusty platform/ios?
|
||||||
|
:path temp-image-url}))
|
||||||
(.fetch "GET" base64-uri)
|
(.fetch "GET" base64-uri)
|
||||||
(.then #(on-success (.path %)))
|
(.then #(on-success (.path %)))
|
||||||
(.catch #(log/error "could not save image"))))
|
(.catch #(log/error "could not save image"))))
|
||||||
@@ -70,15 +74,16 @@
|
|||||||
::chat-open-image-picker-camera
|
::chat-open-image-picker-camera
|
||||||
(fn [current-chat-id]
|
(fn [current-chat-id]
|
||||||
(react/show-image-picker-camera
|
(react/show-image-picker-camera
|
||||||
#(re-frame/dispatch [:chat.ui/image-captured current-chat-id (.-path %)]) {})))
|
#(re-frame/dispatch [:chat.ui/image-captured current-chat-id (.-path %)])
|
||||||
|
{})))
|
||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
::chat-open-image-picker
|
::chat-open-image-picker
|
||||||
(fn [chat-id]
|
(fn [chat-id]
|
||||||
(react/show-image-picker
|
(react/show-image-picker
|
||||||
(fn [^js images]
|
(fn [^js images]
|
||||||
;; NOTE(Ferossgp): Because we can't highlight the already selected images inside
|
;; NOTE(Ferossgp): Because we can't highlight the already selected images inside
|
||||||
;; gallery, we just clean previous state and set all newly picked images
|
;; gallery, we just clean previous state and set all newly picked images
|
||||||
(when (and platform/ios? (pos? (count images)))
|
(when (and platform/ios? (pos? (count images)))
|
||||||
(re-frame/dispatch [:chat.ui/clear-sending-images chat-id]))
|
(re-frame/dispatch [:chat.ui/clear-sending-images chat-id]))
|
||||||
(doseq [^js result (if platform/ios?
|
(doseq [^js result (if platform/ios?
|
||||||
@@ -86,8 +91,8 @@
|
|||||||
[images])]
|
[images])]
|
||||||
(resize-and-call (.-path result)
|
(resize-and-call (.-path result)
|
||||||
#(re-frame/dispatch [:chat.ui/image-selected chat-id (result->id result) %]))))
|
#(re-frame/dispatch [:chat.ui/image-selected chat-id (result->id result) %]))))
|
||||||
;; NOTE(Ferossgp): On android you cannot set max limit on images, when a user
|
;; NOTE(Ferossgp): On android you cannot set max limit on images, when a user
|
||||||
;; selects too many images the app crashes.
|
;; selects too many images the app crashes.
|
||||||
{:media-type "photo"
|
{:media-type "photo"
|
||||||
:multiple platform/ios?})))
|
:multiple platform/ios?})))
|
||||||
|
|
||||||
@@ -105,13 +110,17 @@
|
|||||||
{:permissions [:read-external-storage]
|
{:permissions [:read-external-storage]
|
||||||
:on-allowed (fn []
|
:on-allowed (fn []
|
||||||
(-> (if end-cursor
|
(-> (if end-cursor
|
||||||
(.getPhotos CameraRoll #js {:first num :after end-cursor :assetType "Photos" :groupTypes "All"})
|
(.getPhotos
|
||||||
(.getPhotos CameraRoll #js {:first num :assetType "Photos" :groupTypes "All"}))
|
CameraRoll
|
||||||
|
#js {:first num :after end-cursor :assetType "Photos" :groupTypes "All"})
|
||||||
|
(.getPhotos CameraRoll
|
||||||
|
#js {:first num :assetType "Photos" :groupTypes "All"}))
|
||||||
(.then #(let [response (types/js->clj %)]
|
(.then #(let [response (types/js->clj %)]
|
||||||
(re-frame/dispatch [:on-camera-roll-get-photos (:edges response) (:page_info response) end-cursor])))
|
(re-frame/dispatch [:on-camera-roll-get-photos (:edges response)
|
||||||
|
(:page_info response) end-cursor])))
|
||||||
(.catch #(log/warn "could not get camera roll photos"))))})))
|
(.catch #(log/warn "could not get camera roll photos"))))})))
|
||||||
|
|
||||||
(fx/defn image-captured
|
(rf/defn image-captured
|
||||||
{:events [:chat.ui/image-captured]}
|
{:events [:chat.ui/image-captured]}
|
||||||
[{:keys [db]} chat-id uri]
|
[{:keys [db]} chat-id uri]
|
||||||
(let [current-chat-id (or chat-id (:current-chat-id db))
|
(let [current-chat-id (or chat-id (:current-chat-id db))
|
||||||
@@ -120,24 +129,24 @@
|
|||||||
(not (get images uri)))
|
(not (get images uri)))
|
||||||
{::image-selected [uri current-chat-id]})))
|
{::image-selected [uri current-chat-id]})))
|
||||||
|
|
||||||
(fx/defn on-end-reached
|
(rf/defn on-end-reached
|
||||||
{:events [:camera-roll/on-end-reached]}
|
{:events [:camera-roll/on-end-reached]}
|
||||||
[_ end-cursor loading? has-next-page?]
|
[_ end-cursor loading? has-next-page?]
|
||||||
(when (and (not loading?) has-next-page?)
|
(when (and (not loading?) has-next-page?)
|
||||||
(re-frame/dispatch [:chat.ui/camera-roll-loading-more true])
|
(re-frame/dispatch [:chat.ui/camera-roll-loading-more true])
|
||||||
(re-frame/dispatch [:chat.ui/camera-roll-get-photos 20 end-cursor])))
|
(re-frame/dispatch [:chat.ui/camera-roll-get-photos 20 end-cursor])))
|
||||||
|
|
||||||
(fx/defn camera-roll-get-photos
|
(rf/defn camera-roll-get-photos
|
||||||
{:events [:chat.ui/camera-roll-get-photos]}
|
{:events [:chat.ui/camera-roll-get-photos]}
|
||||||
[_ num end-cursor]
|
[_ num end-cursor]
|
||||||
{::camera-roll-get-photos [num end-cursor]})
|
{::camera-roll-get-photos [num end-cursor]})
|
||||||
|
|
||||||
(fx/defn camera-roll-loading-more
|
(rf/defn camera-roll-loading-more
|
||||||
{:events [:chat.ui/camera-roll-loading-more]}
|
{:events [:chat.ui/camera-roll-loading-more]}
|
||||||
[{:keys [db]} is-loading]
|
[{:keys [db]} is-loading]
|
||||||
{:db (assoc db :camera-roll/loading-more is-loading)})
|
{:db (assoc db :camera-roll/loading-more is-loading)})
|
||||||
|
|
||||||
(fx/defn on-camera-roll-get-photos
|
(rf/defn on-camera-roll-get-photos
|
||||||
{:events [:on-camera-roll-get-photos]}
|
{:events [:on-camera-roll-get-photos]}
|
||||||
[{:keys [db] :as cofx} photos page-info end-cursor]
|
[{:keys [db] :as cofx} photos page-info end-cursor]
|
||||||
(let [photos_x (when end-cursor (:camera-roll/photos db))]
|
(let [photos_x (when end-cursor (:camera-roll/photos db))]
|
||||||
@@ -147,34 +156,34 @@
|
|||||||
(assoc :camera-roll/has-next-page (:has_next_page page-info))
|
(assoc :camera-roll/has-next-page (:has_next_page page-info))
|
||||||
(assoc :camera-roll/loading-more false))}))
|
(assoc :camera-roll/loading-more false))}))
|
||||||
|
|
||||||
(fx/defn clear-sending-images
|
(rf/defn clear-sending-images
|
||||||
{:events [:chat.ui/clear-sending-images]}
|
{:events [:chat.ui/clear-sending-images]}
|
||||||
[{:keys [db]} current-chat-id]
|
[{:keys [db]} current-chat-id]
|
||||||
{:db (update-in db [:chat/inputs current-chat-id :metadata] assoc :sending-image {})})
|
{:db (update-in db [:chat/inputs current-chat-id :metadata] assoc :sending-image {})})
|
||||||
|
|
||||||
(fx/defn cancel-sending-image
|
(rf/defn cancel-sending-image
|
||||||
{:events [:chat.ui/cancel-sending-image]}
|
{:events [:chat.ui/cancel-sending-image]}
|
||||||
[{:keys [db] :as cofx} chat-id]
|
[{:keys [db] :as cofx} chat-id]
|
||||||
(let [current-chat-id (or chat-id (:current-chat-id db))]
|
(let [current-chat-id (or chat-id (:current-chat-id db))]
|
||||||
(clear-sending-images cofx current-chat-id)))
|
(clear-sending-images cofx current-chat-id)))
|
||||||
|
|
||||||
(fx/defn cancel-sending-image-timeline
|
(rf/defn cancel-sending-image-timeline
|
||||||
{:events [:chat.ui/cancel-sending-image-timeline]}
|
{:events [:chat.ui/cancel-sending-image-timeline]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(cancel-sending-image cofx (chat/my-profile-chat-topic db)))
|
(cancel-sending-image cofx (chat/my-profile-chat-topic db)))
|
||||||
|
|
||||||
(fx/defn image-selected
|
(rf/defn image-selected
|
||||||
{:events [:chat.ui/image-selected]}
|
{:events [:chat.ui/image-selected]}
|
||||||
[{:keys [db]} current-chat-id original uri]
|
[{:keys [db]} current-chat-id original uri]
|
||||||
{:db (update-in db [:chat/inputs current-chat-id :metadata :sending-image original] merge {:uri uri})})
|
{:db (update-in db [:chat/inputs current-chat-id :metadata :sending-image original] merge {:uri uri})})
|
||||||
|
|
||||||
(fx/defn image-unselected
|
(rf/defn image-unselected
|
||||||
{:events [:chat.ui/image-unselected]}
|
{:events [:chat.ui/image-unselected]}
|
||||||
[{:keys [db]} original]
|
[{:keys [db]} original]
|
||||||
(let [current-chat-id (:current-chat-id db)]
|
(let [current-chat-id (:current-chat-id db)]
|
||||||
{:db (update-in db [:chat/inputs current-chat-id :metadata :sending-image] dissoc original)}))
|
{:db (update-in db [:chat/inputs current-chat-id :metadata :sending-image] dissoc original)}))
|
||||||
|
|
||||||
(fx/defn chat-open-image-picker
|
(rf/defn chat-open-image-picker
|
||||||
{:events [:chat.ui/open-image-picker]}
|
{:events [:chat.ui/open-image-picker]}
|
||||||
[{:keys [db]} chat-id]
|
[{:keys [db]} chat-id]
|
||||||
(let [current-chat-id (or chat-id (:current-chat-id db))
|
(let [current-chat-id (or chat-id (:current-chat-id db))
|
||||||
@@ -182,12 +191,12 @@
|
|||||||
(when (< (count images) config/max-images-batch)
|
(when (< (count images) config/max-images-batch)
|
||||||
{::chat-open-image-picker current-chat-id})))
|
{::chat-open-image-picker current-chat-id})))
|
||||||
|
|
||||||
(fx/defn chat-open-image-picker-timeline
|
(rf/defn chat-open-image-picker-timeline
|
||||||
{:events [:chat.ui/open-image-picker-timeline]}
|
{:events [:chat.ui/open-image-picker-timeline]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(chat-open-image-picker cofx (chat/my-profile-chat-topic db)))
|
(chat-open-image-picker cofx (chat/my-profile-chat-topic db)))
|
||||||
|
|
||||||
(fx/defn chat-show-image-picker-camera
|
(rf/defn chat-show-image-picker-camera
|
||||||
{:events [:chat.ui/show-image-picker-camera]}
|
{:events [:chat.ui/show-image-picker-camera]}
|
||||||
[{:keys [db]} chat-id]
|
[{:keys [db]} chat-id]
|
||||||
(let [current-chat-id (or chat-id (:current-chat-id db))
|
(let [current-chat-id (or chat-id (:current-chat-id db))
|
||||||
@@ -195,12 +204,12 @@
|
|||||||
(when (< (count images) config/max-images-batch)
|
(when (< (count images) config/max-images-batch)
|
||||||
{::chat-open-image-picker-camera current-chat-id})))
|
{::chat-open-image-picker-camera current-chat-id})))
|
||||||
|
|
||||||
(fx/defn chat-show-image-picker-camera-timeline
|
(rf/defn chat-show-image-picker-camera-timeline
|
||||||
{:events [:chat.ui/show-image-picker-camera-timeline]}
|
{:events [:chat.ui/show-image-picker-camera-timeline]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(chat-show-image-picker-camera cofx (chat/my-profile-chat-topic db)))
|
(chat-show-image-picker-camera cofx (chat/my-profile-chat-topic db)))
|
||||||
|
|
||||||
(fx/defn camera-roll-pick
|
(rf/defn camera-roll-pick
|
||||||
{:events [:chat.ui/camera-roll-pick]}
|
{:events [:chat.ui/camera-roll-pick]}
|
||||||
[{:keys [db]} uri chat-id]
|
[{:keys [db]} uri chat-id]
|
||||||
(let [current-chat-id (or chat-id (:current-chat-id db))
|
(let [current-chat-id (or chat-id (:current-chat-id db))
|
||||||
@@ -212,12 +221,12 @@
|
|||||||
(not (get images uri)))
|
(not (get images uri)))
|
||||||
{::image-selected [uri current-chat-id]}))))
|
{::image-selected [uri current-chat-id]}))))
|
||||||
|
|
||||||
(fx/defn camera-roll-pick-timeline
|
(rf/defn camera-roll-pick-timeline
|
||||||
{:events [:chat.ui/camera-roll-pick-timeline]}
|
{:events [:chat.ui/camera-roll-pick-timeline]}
|
||||||
[{:keys [db] :as cofx} uri]
|
[{:keys [db] :as cofx} uri]
|
||||||
(camera-roll-pick cofx uri (chat/my-profile-chat-topic db)))
|
(camera-roll-pick cofx uri (chat/my-profile-chat-topic db)))
|
||||||
|
|
||||||
(fx/defn save-image-to-gallery
|
(rf/defn save-image-to-gallery
|
||||||
{:events [:chat.ui/save-image-to-gallery]}
|
{:events [:chat.ui/save-image-to-gallery]}
|
||||||
[_ base64-uri]
|
[_ base64-uri]
|
||||||
{::save-image-to-gallery base64-uri})
|
{::save-image-to-gallery base64-uri})
|
||||||
|
|||||||
@@ -12,9 +12,9 @@
|
|||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
[status-im.i18n.i18n :as i18n]
|
[status-im.i18n.i18n :as i18n]
|
||||||
[status-im.utils.datetime :as datetime]
|
[status-im.utils.datetime :as datetime]
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[status-im.utils.utils :as utils]
|
[status-im.utils.utils :as utils]
|
||||||
[taoensso.timbre :as log]))
|
[taoensso.timbre :as log]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(defn text->emoji
|
(defn text->emoji
|
||||||
"Replaces emojis in a specified `text`"
|
"Replaces emojis in a specified `text`"
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
(.-char ^js emoji-map)
|
(.-char ^js emoji-map)
|
||||||
original))))
|
original))))
|
||||||
|
|
||||||
(fx/defn set-chat-input-text
|
(rf/defn set-chat-input-text
|
||||||
"Set input text for current-chat. Takes db and input text and cofx
|
"Set input text for current-chat. Takes db and input text and cofx
|
||||||
as arguments and returns new fx. Always clear all validation messages."
|
as arguments and returns new fx. Always clear all validation messages."
|
||||||
{:events [:chat.ui/set-chat-input-text]}
|
{:events [:chat.ui/set-chat-input-text]}
|
||||||
@@ -34,24 +34,25 @@
|
|||||||
(let [current-chat-id (or chat-id (:current-chat-id db))]
|
(let [current-chat-id (or chat-id (:current-chat-id db))]
|
||||||
{:db (assoc-in db [:chat/inputs current-chat-id :input-text] (text->emoji new-input))}))
|
{:db (assoc-in db [:chat/inputs current-chat-id :input-text] (text->emoji new-input))}))
|
||||||
|
|
||||||
(fx/defn set-timeline-input-text
|
(rf/defn set-timeline-input-text
|
||||||
{:events [:chat.ui/set-timeline-input-text]}
|
{:events [:chat.ui/set-timeline-input-text]}
|
||||||
[{db :db} new-input]
|
[{db :db} new-input]
|
||||||
{:db (assoc-in db [:chat/inputs (chat/my-profile-chat-topic db) :input-text]
|
{:db (assoc-in db
|
||||||
(text->emoji new-input))})
|
[:chat/inputs (chat/my-profile-chat-topic db) :input-text]
|
||||||
|
(text->emoji new-input))})
|
||||||
|
|
||||||
(fx/defn select-mention
|
(rf/defn select-mention
|
||||||
{:events [:chat.ui/select-mention]}
|
{:events [:chat.ui/select-mention]}
|
||||||
[{:keys [db] :as cofx} text-input-ref {:keys [alias name searched-text match] :as user}]
|
[{:keys [db] :as cofx} text-input-ref {:keys [alias name searched-text match] :as user}]
|
||||||
(let [chat-id (:current-chat-id db)
|
(let [chat-id (:current-chat-id db)
|
||||||
new-text (mentions/new-input-text-with-mention cofx user)
|
new-text (mentions/new-input-text-with-mention cofx user)
|
||||||
at-sign-idx (get-in db [:chats/mentions chat-id :mentions :at-sign-idx])
|
at-sign-idx (get-in db [:chats/mentions chat-id :mentions :at-sign-idx])
|
||||||
cursor (+ at-sign-idx (count name) 2)]
|
cursor (+ at-sign-idx (count name) 2)]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:chats/cursor chat-id] cursor)
|
(assoc-in [:chats/cursor chat-id] cursor)
|
||||||
(assoc-in [:chats/mention-suggestions chat-id] nil))
|
(assoc-in [:chats/mention-suggestions chat-id] nil))
|
||||||
:set-text-input-value [chat-id new-text text-input-ref]}
|
:set-text-input-value [chat-id new-text text-input-ref]}
|
||||||
(set-chat-input-text new-text chat-id)
|
(set-chat-input-text new-text chat-id)
|
||||||
;; NOTE(rasom): Some keyboards do not react on selection property passed to
|
;; NOTE(rasom): Some keyboards do not react on selection property passed to
|
||||||
@@ -74,67 +75,77 @@
|
|||||||
:end end}))
|
:end end}))
|
||||||
(mentions/recheck-at-idxs {alias user}))))
|
(mentions/recheck-at-idxs {alias user}))))
|
||||||
|
|
||||||
(defn- start-cooldown [{:keys [db]} cooldowns]
|
(defn- start-cooldown
|
||||||
|
[{:keys [db]} cooldowns]
|
||||||
{:dispatch-later [{:dispatch [:chat/disable-cooldown]
|
{:dispatch-later [{:dispatch [:chat/disable-cooldown]
|
||||||
:ms (chat.constants/cooldown-periods-ms
|
:ms (chat.constants/cooldown-periods-ms
|
||||||
cooldowns
|
cooldowns
|
||||||
chat.constants/default-cooldown-period-ms)}]
|
chat.constants/default-cooldown-period-ms)}]
|
||||||
:show-cooldown-warning nil
|
:show-cooldown-warning nil
|
||||||
:db (assoc db
|
:db (assoc db
|
||||||
:chat/cooldowns (if (= chat.constants/cooldown-reset-threshold cooldowns)
|
:chat/cooldowns (if
|
||||||
0
|
(=
|
||||||
cooldowns)
|
chat.constants/cooldown-reset-threshold
|
||||||
|
cooldowns)
|
||||||
|
0
|
||||||
|
cooldowns)
|
||||||
:chat/spam-messages-frequency 0
|
:chat/spam-messages-frequency 0
|
||||||
:chat/cooldown-enabled? true)})
|
:chat/cooldown-enabled? true)})
|
||||||
|
|
||||||
(fx/defn process-cooldown
|
(rf/defn process-cooldown
|
||||||
"Process cooldown to protect against message spammers"
|
"Process cooldown to protect against message spammers"
|
||||||
[{{:keys [chat/last-outgoing-message-sent-at
|
[{{:keys [chat/last-outgoing-message-sent-at
|
||||||
chat/cooldowns
|
chat/cooldowns
|
||||||
chat/spam-messages-frequency
|
chat/spam-messages-frequency
|
||||||
current-chat-id] :as db} :db :as cofx}]
|
current-chat-id]
|
||||||
|
:as db}
|
||||||
|
:db
|
||||||
|
:as cofx}]
|
||||||
(when (chat/public-chat? cofx current-chat-id)
|
(when (chat/public-chat? cofx current-chat-id)
|
||||||
(let [spamming-fast? (< (- (datetime/timestamp) last-outgoing-message-sent-at)
|
(let [spamming-fast? (< (- (datetime/timestamp) last-outgoing-message-sent-at)
|
||||||
(+ chat.constants/spam-interval-ms (* 1000 cooldowns)))
|
(+ chat.constants/spam-interval-ms (* 1000 cooldowns)))
|
||||||
spamming-frequently? (= chat.constants/spam-message-frequency-threshold spam-messages-frequency)]
|
spamming-frequently? (= chat.constants/spam-message-frequency-threshold
|
||||||
|
spam-messages-frequency)]
|
||||||
(cond-> {:db (assoc db
|
(cond-> {:db (assoc db
|
||||||
:chat/last-outgoing-message-sent-at (datetime/timestamp)
|
:chat/last-outgoing-message-sent-at (datetime/timestamp)
|
||||||
:chat/spam-messages-frequency (if spamming-fast?
|
:chat/spam-messages-frequency (if spamming-fast?
|
||||||
(inc spam-messages-frequency)
|
(inc spam-messages-frequency)
|
||||||
0))}
|
0))}
|
||||||
|
|
||||||
(and spamming-fast? spamming-frequently?)
|
(and spamming-fast? spamming-frequently?)
|
||||||
(start-cooldown (inc cooldowns))))))
|
(start-cooldown (inc cooldowns))))))
|
||||||
|
|
||||||
(fx/defn reply-to-message
|
(rf/defn reply-to-message
|
||||||
"Sets reference to previous chat message and focuses on input"
|
"Sets reference to previous chat message and focuses on input"
|
||||||
{:events [:chat.ui/reply-to-message]}
|
{:events [:chat.ui/reply-to-message]}
|
||||||
[{:keys [db] :as cofx} message]
|
[{:keys [db] :as cofx} message]
|
||||||
(let [current-chat-id (:current-chat-id db)]
|
(let [current-chat-id (:current-chat-id db)]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:chat/inputs current-chat-id :metadata :responding-to-message]
|
(assoc-in [:chat/inputs current-chat-id :metadata :responding-to-message]
|
||||||
message)
|
message)
|
||||||
(assoc-in [:chat/inputs current-chat-id :metadata :editing-message] nil)
|
(assoc-in [:chat/inputs current-chat-id :metadata :editing-message] nil)
|
||||||
(update-in [:chat/inputs current-chat-id :metadata]
|
(update-in [:chat/inputs current-chat-id :metadata]
|
||||||
dissoc :sending-image))})))
|
dissoc
|
||||||
|
:sending-image))})))
|
||||||
|
|
||||||
(fx/defn edit-message
|
(rf/defn edit-message
|
||||||
"Sets reference to previous chat message and focuses on input"
|
"Sets reference to previous chat message and focuses on input"
|
||||||
{:events [:chat.ui/edit-message]}
|
{:events [:chat.ui/edit-message]}
|
||||||
[{:keys [db] :as cofx} message]
|
[{:keys [db] :as cofx} message]
|
||||||
(let [current-chat-id (:current-chat-id db)
|
(let [current-chat-id (:current-chat-id db)
|
||||||
|
|
||||||
text (get-in message [:content :text])]
|
text (get-in message [:content :text])]
|
||||||
{:dispatch [:chat.ui.input/set-chat-input-text text current-chat-id]
|
{:dispatch [:chat.ui.input/set-chat-input-text text current-chat-id]
|
||||||
:db (-> db
|
:db (-> db
|
||||||
(assoc-in [:chat/inputs current-chat-id :metadata :editing-message]
|
(assoc-in [:chat/inputs current-chat-id :metadata :editing-message]
|
||||||
message)
|
message)
|
||||||
(assoc-in [:chat/inputs current-chat-id :metadata :responding-to-message] nil)
|
(assoc-in [:chat/inputs current-chat-id :metadata :responding-to-message] nil)
|
||||||
(update-in [:chat/inputs current-chat-id :metadata]
|
(update-in [:chat/inputs current-chat-id :metadata]
|
||||||
dissoc :sending-image))}))
|
dissoc
|
||||||
|
:sending-image))}))
|
||||||
|
|
||||||
(fx/defn show-contact-request-input
|
(rf/defn show-contact-request-input
|
||||||
"Sets reference to previous chat message and focuses on input"
|
"Sets reference to previous chat message and focuses on input"
|
||||||
{:events [:chat.ui/send-contact-request]}
|
{:events [:chat.ui/send-contact-request]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
@@ -146,9 +157,10 @@
|
|||||||
nil)
|
nil)
|
||||||
(assoc-in [:chat/inputs current-chat-id :metadata :editing-message] nil)
|
(assoc-in [:chat/inputs current-chat-id :metadata :editing-message] nil)
|
||||||
(update-in [:chat/inputs current-chat-id :metadata]
|
(update-in [:chat/inputs current-chat-id :metadata]
|
||||||
dissoc :sending-image))}))
|
dissoc
|
||||||
|
:sending-image))}))
|
||||||
|
|
||||||
(fx/defn cancel-message-reply
|
(rf/defn cancel-message-reply
|
||||||
"Cancels stage message reply"
|
"Cancels stage message reply"
|
||||||
{:events [:chat.ui/cancel-message-reply]}
|
{:events [:chat.ui/cancel-message-reply]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
@@ -160,16 +172,16 @@
|
|||||||
(when-not (string/blank? input-text)
|
(when-not (string/blank? input-text)
|
||||||
(let [{:keys [message-id]}
|
(let [{:keys [message-id]}
|
||||||
(get-in db [:chat/inputs current-chat-id :metadata :responding-to-message])
|
(get-in db [:chat/inputs current-chat-id :metadata :responding-to-message])
|
||||||
preferred-name (get-in db [:multiaccount :preferred-name])
|
preferred-name (get-in db [:multiaccount :preferred-name])
|
||||||
emoji? (message-content/emoji-only-content? {:text input-text
|
emoji? (message-content/emoji-only-content? {:text input-text
|
||||||
:response-to message-id})]
|
:response-to message-id})]
|
||||||
{:chat-id current-chat-id
|
{:chat-id current-chat-id
|
||||||
:content-type (if emoji?
|
:content-type (if emoji?
|
||||||
constants/content-type-emoji
|
constants/content-type-emoji
|
||||||
constants/content-type-text)
|
constants/content-type-text)
|
||||||
:text input-text
|
:text input-text
|
||||||
:response-to message-id
|
:response-to message-id
|
||||||
:ens-name preferred-name})))
|
:ens-name preferred-name})))
|
||||||
|
|
||||||
(defn build-image-messages
|
(defn build-image-messages
|
||||||
[{db :db} chat-id]
|
[{db :db} chat-id]
|
||||||
@@ -181,8 +193,9 @@
|
|||||||
:text (i18n/label :t/update-to-see-image {"locale" "en"})})
|
:text (i18n/label :t/update-to-see-image {"locale" "en"})})
|
||||||
images)))
|
images)))
|
||||||
|
|
||||||
(fx/defn clean-input [{:keys [db] :as cofx} current-chat-id]
|
(rf/defn clean-input
|
||||||
(fx/merge cofx
|
[{:keys [db] :as cofx} current-chat-id]
|
||||||
|
(rf/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:chat/inputs current-chat-id :metadata :sending-contact-request] nil)
|
(assoc-in [:chat/inputs current-chat-id :metadata :sending-contact-request] nil)
|
||||||
(assoc-in [:chat/inputs current-chat-id :metadata :sending-image] nil)
|
(assoc-in [:chat/inputs current-chat-id :metadata :sending-image] nil)
|
||||||
@@ -190,131 +203,137 @@
|
|||||||
(assoc-in [:chat/inputs current-chat-id :metadata :responding-to-message] nil))}
|
(assoc-in [:chat/inputs current-chat-id :metadata :responding-to-message] nil))}
|
||||||
(set-chat-input-text nil current-chat-id)))
|
(set-chat-input-text nil current-chat-id)))
|
||||||
|
|
||||||
(fx/defn cancel-message-edit
|
(rf/defn cancel-message-edit
|
||||||
"Cancels stage message edit"
|
"Cancels stage message edit"
|
||||||
{:events [:chat.ui/cancel-message-edit]}
|
{:events [:chat.ui/cancel-message-edit]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [current-chat-id (:current-chat-id db)]
|
(let [current-chat-id (:current-chat-id db)]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:set-text-input-value [current-chat-id ""]}
|
{:set-text-input-value [current-chat-id ""]}
|
||||||
(clean-input current-chat-id)
|
(clean-input current-chat-id)
|
||||||
(mentions/clear-mentions)
|
(mentions/clear-mentions)
|
||||||
(mentions/clear-cursor))))
|
(mentions/clear-cursor))))
|
||||||
|
|
||||||
(fx/defn send-messages [{:keys [db] :as cofx} input-text current-chat-id]
|
(rf/defn send-messages
|
||||||
|
[{:keys [db] :as cofx} input-text current-chat-id]
|
||||||
(let [image-messages (build-image-messages cofx current-chat-id)
|
(let [image-messages (build-image-messages cofx current-chat-id)
|
||||||
text-message (build-text-message cofx input-text current-chat-id)
|
text-message (build-text-message cofx input-text current-chat-id)
|
||||||
messages (keep identity (conj image-messages text-message))]
|
messages (keep identity (conj image-messages text-message))]
|
||||||
(when (seq messages)
|
(when (seq messages)
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(clean-input (:current-chat-id db))
|
(clean-input (:current-chat-id db))
|
||||||
(process-cooldown)
|
(process-cooldown)
|
||||||
(chat.message/send-messages messages)))))
|
(chat.message/send-messages messages)))))
|
||||||
|
|
||||||
(fx/defn send-my-status-message
|
(rf/defn send-my-status-message
|
||||||
"when not empty, proceed by sending text message with public key topic"
|
"when not empty, proceed by sending text message with public key topic"
|
||||||
{:events [:profile.ui/send-my-status-message]}
|
{:events [:profile.ui/send-my-status-message]}
|
||||||
[{db :db :as cofx}]
|
[{db :db :as cofx}]
|
||||||
(let [current-chat-id (chat/my-profile-chat-topic db)
|
(let [current-chat-id (chat/my-profile-chat-topic db)
|
||||||
{:keys [input-text]} (get-in db [:chat/inputs current-chat-id])
|
{:keys [input-text]} (get-in db [:chat/inputs current-chat-id])
|
||||||
image-messages (build-image-messages cofx current-chat-id)
|
image-messages (build-image-messages cofx current-chat-id)
|
||||||
text-message (build-text-message cofx input-text current-chat-id)
|
text-message (build-text-message cofx input-text current-chat-id)
|
||||||
messages (keep identity (conj image-messages text-message))]
|
messages (keep identity (conj image-messages text-message))]
|
||||||
(when (seq messages)
|
(when (seq messages)
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(clean-input current-chat-id)
|
(clean-input current-chat-id)
|
||||||
(chat.message/send-messages messages)))))
|
(chat.message/send-messages messages)))))
|
||||||
|
|
||||||
(fx/defn send-audio-message
|
(rf/defn send-audio-message
|
||||||
[cofx audio-path duration current-chat-id]
|
[cofx audio-path duration current-chat-id]
|
||||||
(when-not (string/blank? audio-path)
|
(when-not (string/blank? audio-path)
|
||||||
(chat.message/send-message cofx {:chat-id current-chat-id
|
(chat.message/send-message
|
||||||
:content-type constants/content-type-audio
|
cofx
|
||||||
:audio-path audio-path
|
{:chat-id current-chat-id
|
||||||
:audio-duration-ms duration
|
:content-type constants/content-type-audio
|
||||||
:text (i18n/label :t/update-to-listen-audio {"locale" "en"})})))
|
:audio-path audio-path
|
||||||
|
:audio-duration-ms duration
|
||||||
|
:text (i18n/label :t/update-to-listen-audio {"locale" "en"})})))
|
||||||
|
|
||||||
(fx/defn send-sticker-message
|
(rf/defn send-sticker-message
|
||||||
[cofx {:keys [hash packID pack]} current-chat-id]
|
[cofx {:keys [hash packID pack]} current-chat-id]
|
||||||
(when-not (or (string/blank? hash) (and (string/blank? packID) (string/blank? pack)))
|
(when-not (or (string/blank? hash) (and (string/blank? packID) (string/blank? pack)))
|
||||||
(chat.message/send-message cofx {:chat-id current-chat-id
|
(chat.message/send-message cofx
|
||||||
:content-type constants/content-type-sticker
|
{:chat-id current-chat-id
|
||||||
:sticker {:hash hash
|
:content-type constants/content-type-sticker
|
||||||
|
:sticker {:hash hash
|
||||||
:pack (int (if (string/blank? packID) pack packID))}
|
:pack (int (if (string/blank? packID) pack packID))}
|
||||||
:text (i18n/label :t/update-to-see-sticker {"locale" "en"})})))
|
:text (i18n/label :t/update-to-see-sticker {"locale" "en"})})))
|
||||||
|
|
||||||
(fx/defn send-edited-message [{:keys [db] :as cofx} text {:keys [message-id quoted-message]}]
|
(rf/defn send-edited-message
|
||||||
(fx/merge
|
[{:keys [db] :as cofx} text {:keys [message-id quoted-message]}]
|
||||||
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{::json-rpc/call [{:method "wakuext_editMessage"
|
{::json-rpc/call [{:method "wakuext_editMessage"
|
||||||
:params [{:id message-id
|
:params [{:id message-id
|
||||||
:text text
|
:text text
|
||||||
:content-type (if (message-content/emoji-only-content? {:text text :response-to quoted-message})
|
:content-type (if (message-content/emoji-only-content?
|
||||||
constants/content-type-emoji
|
{:text text :response-to quoted-message})
|
||||||
constants/content-type-text)}]
|
constants/content-type-emoji
|
||||||
|
constants/content-type-text)}]
|
||||||
:js-response true
|
:js-response true
|
||||||
:on-error #(log/error "failed to edit message " %)
|
:on-error #(log/error "failed to edit message " %)
|
||||||
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])}]}
|
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])}]}
|
||||||
(cancel-message-edit)
|
(cancel-message-edit)
|
||||||
(process-cooldown)))
|
(process-cooldown)))
|
||||||
|
|
||||||
(fx/defn send-current-message
|
(rf/defn send-current-message
|
||||||
"Sends message from current chat input"
|
"Sends message from current chat input"
|
||||||
{:events [:chat.ui/send-current-message]}
|
{:events [:chat.ui/send-current-message]}
|
||||||
[{{:keys [current-chat-id] :as db} :db :as cofx}]
|
[{{:keys [current-chat-id] :as db} :db :as cofx}]
|
||||||
(let [{:keys [input-text metadata]} (get-in db [:chat/inputs current-chat-id])
|
(let [{:keys [input-text metadata]} (get-in db [:chat/inputs current-chat-id])
|
||||||
editing-message (:editing-message metadata)
|
editing-message (:editing-message metadata)
|
||||||
input-text-with-mentions (mentions/check-mentions cofx input-text)]
|
input-text-with-mentions (mentions/check-mentions cofx input-text)]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(if editing-message
|
(if editing-message
|
||||||
(send-edited-message input-text-with-mentions editing-message)
|
(send-edited-message input-text-with-mentions editing-message)
|
||||||
(send-messages input-text-with-mentions current-chat-id))
|
(send-messages input-text-with-mentions current-chat-id))
|
||||||
(mentions/clear-mentions)
|
(mentions/clear-mentions)
|
||||||
(mentions/clear-cursor))))
|
(mentions/clear-cursor))))
|
||||||
|
|
||||||
(fx/defn send-contact-request
|
(rf/defn send-contact-request
|
||||||
{:events [:contacts/send-contact-request]}
|
{:events [:contacts/send-contact-request]}
|
||||||
[{:keys [db] :as cofx} public-key message]
|
[{:keys [db] :as cofx} public-key message]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:chat.ui/clear-inputs nil
|
{:chat.ui/clear-inputs nil
|
||||||
:chat.ui/clear-inputs-old nil
|
:chat.ui/clear-inputs-old nil
|
||||||
::json-rpc/call [{:method "wakuext_sendContactRequest"
|
::json-rpc/call [{:method "wakuext_sendContactRequest"
|
||||||
:js-response true
|
:js-response true
|
||||||
:params [{:id public-key :message message}]
|
:params [{:id public-key :message message}]
|
||||||
:on-error #(log/warn "failed to send a contact request" %)
|
:on-error #(log/warn "failed to send a contact request" %)
|
||||||
:on-success #(re-frame/dispatch [:transport/message-sent %])}]}
|
:on-success #(re-frame/dispatch [:transport/message-sent %])}]}
|
||||||
(mentions/clear-mentions)
|
(mentions/clear-mentions)
|
||||||
(mentions/clear-cursor)
|
(mentions/clear-cursor)
|
||||||
(clean-input (:current-chat-id db))
|
(clean-input (:current-chat-id db))
|
||||||
(process-cooldown)))
|
(process-cooldown)))
|
||||||
|
|
||||||
(fx/defn cancel-contact-request
|
(rf/defn cancel-contact-request
|
||||||
"Cancels contact request"
|
"Cancels contact request"
|
||||||
{:events [:chat.ui/cancel-contact-request]}
|
{:events [:chat.ui/cancel-contact-request]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [current-chat-id (:current-chat-id db)]
|
(let [current-chat-id (:current-chat-id db)]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc-in db [:chat/inputs current-chat-id :metadata :sending-contact-request] nil)}
|
{:db (assoc-in db [:chat/inputs current-chat-id :metadata :sending-contact-request] nil)}
|
||||||
(mentions/clear-mentions)
|
(mentions/clear-mentions)
|
||||||
(mentions/clear-cursor)
|
(mentions/clear-cursor)
|
||||||
(clean-input (:current-chat-id db))
|
(clean-input (:current-chat-id db))
|
||||||
(process-cooldown))))
|
(process-cooldown))))
|
||||||
|
|
||||||
(fx/defn chat-send-sticker
|
(rf/defn chat-send-sticker
|
||||||
{:events [:chat/send-sticker]}
|
{:events [:chat/send-sticker]}
|
||||||
[{{:keys [current-chat-id] :as db} :db :as cofx} {:keys [hash packID pack] :as sticker}]
|
[{{:keys [current-chat-id] :as db} :db :as cofx} {:keys [hash packID pack] :as sticker}]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (update db
|
{:db (update db
|
||||||
:stickers/recent-stickers
|
:stickers/recent-stickers
|
||||||
(fn [recent]
|
(fn [recent]
|
||||||
(conj (remove #(= hash (:hash %)) recent) sticker)))
|
(conj (remove #(= hash (:hash %)) recent) sticker)))
|
||||||
::json-rpc/call [{:method "stickers_addRecent"
|
::json-rpc/call [{:method "stickers_addRecent"
|
||||||
:params [(int (if (string/blank? packID) pack packID)) hash]
|
:params [(int (if (string/blank? packID) pack packID)) hash]
|
||||||
:on-success #()}]}
|
:on-success #()}]}
|
||||||
(send-sticker-message sticker current-chat-id)))
|
(send-sticker-message sticker current-chat-id)))
|
||||||
|
|
||||||
(fx/defn chat-send-audio
|
(rf/defn chat-send-audio
|
||||||
{:events [:chat/send-audio]}
|
{:events [:chat/send-audio]}
|
||||||
[{{:keys [current-chat-id]} :db :as cofx} audio-path duration]
|
[{{:keys [current-chat-id]} :db :as cofx} audio-path duration]
|
||||||
(send-audio-message cofx audio-path duration current-chat-id))
|
(send-audio-message cofx audio-path duration current-chat-id))
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
(ns status-im.chat.models.link-preview
|
(ns status-im.chat.models.link-preview
|
||||||
(:require [re-frame.core :as re-frame]
|
(:require [re-frame.core :as re-frame]
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[status-im.multiaccounts.update.core :as multiaccounts.update]
|
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
|
||||||
[status-im.communities.core :as models.communities]
|
[status-im.communities.core :as models.communities]
|
||||||
[taoensso.timbre :as log]))
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
|
[status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||||
|
[taoensso.timbre :as log]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(fx/defn enable
|
(rf/defn enable
|
||||||
{:events [::enable]}
|
{:events [::enable]}
|
||||||
[{{:keys [multiaccount]} :db :as cofx} site enabled?]
|
[{{:keys [multiaccount]} :db :as cofx} site enabled?]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(multiaccounts.update/multiaccount-update
|
(multiaccounts.update/multiaccount-update
|
||||||
:link-previews-enabled-sites
|
:link-previews-enabled-sites
|
||||||
(if enabled?
|
(if enabled?
|
||||||
@@ -17,10 +17,10 @@
|
|||||||
(disj (get multiaccount :link-previews-enabled-sites #{}) site))
|
(disj (get multiaccount :link-previews-enabled-sites #{}) site))
|
||||||
{})))
|
{})))
|
||||||
|
|
||||||
(fx/defn enable-all
|
(rf/defn enable-all
|
||||||
{:events [::enable-all]}
|
{:events [::enable-all]}
|
||||||
[{{:keys [multiaccount]} :db :as cofx} link-previews-whitelist enabled?]
|
[{{:keys [multiaccount]} :db :as cofx} link-previews-whitelist enabled?]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(multiaccounts.update/multiaccount-update
|
(multiaccounts.update/multiaccount-update
|
||||||
:link-previews-enabled-sites
|
:link-previews-enabled-sites
|
||||||
(if enabled?
|
(if enabled?
|
||||||
@@ -28,37 +28,42 @@
|
|||||||
#{})
|
#{})
|
||||||
{})))
|
{})))
|
||||||
|
|
||||||
(defn community-resolved [db community-id]
|
(defn community-resolved
|
||||||
|
[db community-id]
|
||||||
(update db :communities/resolve-community-info dissoc community-id))
|
(update db :communities/resolve-community-info dissoc community-id))
|
||||||
|
|
||||||
(defn community-failed-to-resolve [db community-id]
|
(defn community-failed-to-resolve
|
||||||
|
[db community-id]
|
||||||
(update db :communities/resolve-community-info dissoc community-id))
|
(update db :communities/resolve-community-info dissoc community-id))
|
||||||
|
|
||||||
(defn community-resolving [db community-id]
|
(defn community-resolving
|
||||||
|
[db community-id]
|
||||||
(assoc-in db [:communities/resolve-community-info community-id] true))
|
(assoc-in db [:communities/resolve-community-info community-id] true))
|
||||||
|
|
||||||
(fx/defn handle-community-failed-to-resolve
|
(rf/defn handle-community-failed-to-resolve
|
||||||
{:events [::community-failed-to-resolve]}
|
{:events [::community-failed-to-resolve]}
|
||||||
[{:keys [db]} community-id]
|
[{:keys [db]} community-id]
|
||||||
{:db (community-failed-to-resolve db community-id)})
|
{:db (community-failed-to-resolve db community-id)})
|
||||||
|
|
||||||
(defn community-link [id]
|
(defn community-link
|
||||||
|
[id]
|
||||||
(str "https://join.status.im/c/" id))
|
(str "https://join.status.im/c/" id))
|
||||||
|
|
||||||
(fx/defn handle-community-resolved
|
(rf/defn handle-community-resolved
|
||||||
{:events [::community-resolved]}
|
{:events [::community-resolved]}
|
||||||
[{:keys [db] :as cofx} community-id community]
|
[{:keys [db] :as cofx} community-id community]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(cond-> {:db (community-resolved db community-id)}
|
(cond-> {:db (community-resolved db community-id)}
|
||||||
(some? community)
|
(some? community)
|
||||||
(assoc :dispatch [::cache-link-preview-data
|
(assoc :dispatch
|
||||||
(community-link community-id) community]))
|
[::cache-link-preview-data
|
||||||
|
(community-link community-id) community]))
|
||||||
(models.communities/handle-community community)))
|
(models.communities/handle-community community)))
|
||||||
|
|
||||||
(fx/defn resolve-community-info
|
(rf/defn resolve-community-info
|
||||||
{:events [::resolve-community-info]}
|
{:events [::resolve-community-info]}
|
||||||
[{:keys [db]} community-id]
|
[{:keys [db]} community-id]
|
||||||
{:db (community-resolving db community-id)
|
{:db (community-resolving db community-id)
|
||||||
::json-rpc/call [{:method "wakuext_requestCommunityInfoFromMailserver"
|
::json-rpc/call [{:method "wakuext_requestCommunityInfoFromMailserver"
|
||||||
:params [community-id]
|
:params [community-id]
|
||||||
:on-success #(re-frame/dispatch [::community-resolved community-id %])
|
:on-success #(re-frame/dispatch [::community-resolved community-id %])
|
||||||
@@ -66,17 +71,18 @@
|
|||||||
(re-frame/dispatch [::community-failed-to-resolve community-id])
|
(re-frame/dispatch [::community-failed-to-resolve community-id])
|
||||||
(log/error "Failed to request community info from mailserver"))}]})
|
(log/error "Failed to request community info from mailserver"))}]})
|
||||||
|
|
||||||
(fx/defn load-link-preview-data
|
(rf/defn load-link-preview-data
|
||||||
{:events [::load-link-preview-data]}
|
{:events [::load-link-preview-data]}
|
||||||
[cofx link]
|
[cofx link]
|
||||||
{::json-rpc/call [{:method "wakuext_getLinkPreviewData"
|
{::json-rpc/call [{:method "wakuext_getLinkPreviewData"
|
||||||
:params [link]
|
:params [link]
|
||||||
:on-success #(re-frame/dispatch [::cache-link-preview-data link %])
|
:on-success #(re-frame/dispatch [::cache-link-preview-data link %])
|
||||||
:on-error #(re-frame/dispatch [::cache-link-preview-data
|
:on-error #(re-frame/dispatch
|
||||||
link
|
[::cache-link-preview-data
|
||||||
{:error (str "Can't get preview data for " link)}])}]})
|
link
|
||||||
|
{:error (str "Can't get preview data for " link)}])}]})
|
||||||
|
|
||||||
(fx/defn cache-link-preview-data
|
(rf/defn cache-link-preview-data
|
||||||
{:events [::cache-link-preview-data]}
|
{:events [::cache-link-preview-data]}
|
||||||
[{{:keys [multiaccount]} :db :as cofx} site data]
|
[{{:keys [multiaccount]} :db :as cofx} site data]
|
||||||
(multiaccounts.update/optimistic
|
(multiaccounts.update/optimistic
|
||||||
@@ -90,23 +96,25 @@
|
|||||||
(community-link id)
|
(community-link id)
|
||||||
community]))
|
community]))
|
||||||
|
|
||||||
(fx/defn should-suggest-link-preview
|
(rf/defn should-suggest-link-preview
|
||||||
{:events [::should-suggest-link-preview]}
|
{:events [::should-suggest-link-preview]}
|
||||||
[{:keys [db] :as cofx} enabled?]
|
[{:keys [db] :as cofx} enabled?]
|
||||||
(multiaccounts.update/multiaccount-update
|
(multiaccounts.update/multiaccount-update
|
||||||
cofx
|
cofx
|
||||||
:link-preview-request-enabled (boolean enabled?)
|
:link-preview-request-enabled
|
||||||
|
(boolean enabled?)
|
||||||
{}))
|
{}))
|
||||||
|
|
||||||
(fx/defn request-link-preview-whitelist
|
(rf/defn request-link-preview-whitelist
|
||||||
[_]
|
[_]
|
||||||
{::json-rpc/call [{:method "wakuext_getLinkPreviewWhitelist"
|
{::json-rpc/call [{:method "wakuext_getLinkPreviewWhitelist"
|
||||||
:params []
|
:params []
|
||||||
:on-success #(re-frame/dispatch [::link-preview-whitelist-received %])
|
:on-success #(re-frame/dispatch [::link-preview-whitelist-received %])
|
||||||
:on-error #(log/error "Failed to get link preview whitelist")}]})
|
:on-error #(log/error "Failed to get link preview whitelist")}]})
|
||||||
|
|
||||||
(fx/defn save-link-preview-whitelist
|
(rf/defn save-link-preview-whitelist
|
||||||
{:events [::link-preview-whitelist-received]}
|
{:events [::link-preview-whitelist-received]}
|
||||||
[{:keys [db]} whitelist]
|
[{:keys [db]} whitelist]
|
||||||
{:db (assoc db :link-previews-whitelist
|
{:db (assoc db
|
||||||
|
:link-previews-whitelist
|
||||||
whitelist)})
|
whitelist)})
|
||||||
|
|||||||
@@ -1,24 +1,25 @@
|
|||||||
(ns status-im.chat.models.loading
|
(ns status-im.chat.models.loading
|
||||||
(:require [re-frame.core :as re-frame]
|
(:require [re-frame.core :as re-frame]
|
||||||
|
[status-im.chat.models.message-list :as message-list]
|
||||||
[status-im.constants :as constants]
|
[status-im.constants :as constants]
|
||||||
[status-im.data-store.chats :as data-store.chats]
|
[status-im.data-store.chats :as data-store.chats]
|
||||||
[status-im.data-store.messages :as data-store.messages]
|
[status-im.data-store.messages :as data-store.messages]
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[status-im.chat.models.message-list :as message-list]
|
|
||||||
[taoensso.timbre :as log]
|
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
[status-im2.contexts.activity-center.events :as activity-center]))
|
[status-im2.contexts.activity-center.events :as activity-center]
|
||||||
|
[taoensso.timbre :as log]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(defn cursor->clock-value
|
(defn cursor->clock-value
|
||||||
[^js cursor]
|
[^js cursor]
|
||||||
(js/parseInt (.substring cursor 51 64)))
|
(js/parseInt (.substring cursor 51 64)))
|
||||||
|
|
||||||
(defn clock-value->cursor [clock-value]
|
(defn clock-value->cursor
|
||||||
|
[clock-value]
|
||||||
(str "000000000000000000000000000000000000000000000000000"
|
(str "000000000000000000000000000000000000000000000000000"
|
||||||
clock-value
|
clock-value
|
||||||
"0x0000000000000000000000000000000000000000000000000000000000000000"))
|
"0x0000000000000000000000000000000000000000000000000000000000000000"))
|
||||||
|
|
||||||
(fx/defn update-chats-in-app-db
|
(rf/defn update-chats-in-app-db
|
||||||
{:events [:chats-list/load-success]}
|
{:events [:chats-list/load-success]}
|
||||||
[{:keys [db]} ^js new-chats-js]
|
[{:keys [db]} ^js new-chats-js]
|
||||||
(let [{:keys [all-chats chats-home-list]}
|
(let [{:keys [all-chats chats-home-list]}
|
||||||
@@ -30,27 +31,28 @@
|
|||||||
(update :chats-home-list conj chat-id)
|
(update :chats-home-list conj chat-id)
|
||||||
:always
|
:always
|
||||||
(assoc-in [:all-chats chat-id] chat))))
|
(assoc-in [:all-chats chat-id] chat))))
|
||||||
{:all-chats {}
|
{:all-chats {}
|
||||||
:chats-home-list #{}}
|
:chats-home-list #{}}
|
||||||
new-chats-js)]
|
new-chats-js)]
|
||||||
{:db (assoc db :chats all-chats
|
{:db (assoc db
|
||||||
|
:chats all-chats
|
||||||
:chats-home-list chats-home-list
|
:chats-home-list chats-home-list
|
||||||
:chats/loading? false)}))
|
:chats/loading? false)}))
|
||||||
|
|
||||||
(fx/defn load-chat-success
|
(rf/defn load-chat-success
|
||||||
{:events [:chats-list/load-chat-success]}
|
{:events [:chats-list/load-chat-success]}
|
||||||
[{:keys [db]} ^js chat]
|
[{:keys [db]} ^js chat]
|
||||||
(let [{:keys [chat-id] :as chat} (data-store.chats/<-rpc chat)]
|
(let [{:keys [chat-id] :as chat} (data-store.chats/<-rpc chat)]
|
||||||
{:db (update-in db [:chats chat-id] merge chat)}))
|
{:db (update-in db [:chats chat-id] merge chat)}))
|
||||||
|
|
||||||
(fx/defn load-chat
|
(rf/defn load-chat
|
||||||
[_ chat-id]
|
[_ chat-id]
|
||||||
{::json-rpc/call [{:method "wakuext_chat"
|
{::json-rpc/call [{:method "wakuext_chat"
|
||||||
:params [chat-id]
|
:params [chat-id]
|
||||||
:on-success #(re-frame/dispatch [:chats-list/load-chat-success %])
|
:on-success #(re-frame/dispatch [:chats-list/load-chat-success %])
|
||||||
:on-error #(log/error "failed to fetch chats" 0 -1 %)}]})
|
:on-error #(log/error "failed to fetch chats" 0 -1 %)}]})
|
||||||
|
|
||||||
(fx/defn handle-failed-loading-messages
|
(rf/defn handle-failed-loading-messages
|
||||||
{:events [::failed-loading-messages]}
|
{:events [::failed-loading-messages]}
|
||||||
[{:keys [db]} current-chat-id _ err]
|
[{:keys [db]} current-chat-id _ err]
|
||||||
(log/error "failed loading messages" current-chat-id err)
|
(log/error "failed loading messages" current-chat-id err)
|
||||||
@@ -59,52 +61,55 @@
|
|||||||
|
|
||||||
(defn mark-chat-all-read
|
(defn mark-chat-all-read
|
||||||
[db chat-id]
|
[db chat-id]
|
||||||
(update-in db [:chats chat-id] assoc
|
(update-in db
|
||||||
|
[:chats chat-id]
|
||||||
|
assoc
|
||||||
:unviewed-messages-count 0
|
:unviewed-messages-count 0
|
||||||
:unviewed-mentions-count 0
|
:unviewed-mentions-count 0
|
||||||
:highlight false))
|
:highlight false))
|
||||||
|
|
||||||
(fx/defn handle-mark-all-read-successful
|
(rf/defn handle-mark-all-read-successful
|
||||||
{:events [::mark-all-read-successful]}
|
{:events [::mark-all-read-successful]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(activity-center/notifications-fetch-unread-count cofx))
|
(activity-center/notifications-fetch-unread-count cofx))
|
||||||
|
|
||||||
(fx/defn handle-mark-all-read-in-community-successful
|
(rf/defn handle-mark-all-read-in-community-successful
|
||||||
{:events [::mark-all-read-in-community-successful]}
|
{:events [::mark-all-read-in-community-successful]}
|
||||||
[{:keys [db] :as cofx} chat-ids]
|
[{:keys [db] :as cofx} chat-ids]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (reduce mark-chat-all-read db chat-ids)}
|
{:db (reduce mark-chat-all-read db chat-ids)}
|
||||||
(activity-center/notifications-fetch-unread-count)))
|
(activity-center/notifications-fetch-unread-count)))
|
||||||
|
|
||||||
(fx/defn handle-mark-all-read
|
(rf/defn handle-mark-all-read
|
||||||
{:events [:chat.ui/mark-all-read-pressed :chat/mark-all-as-read]}
|
{:events [:chat.ui/mark-all-read-pressed :chat/mark-all-as-read]}
|
||||||
[{db :db} chat-id]
|
[{db :db} chat-id]
|
||||||
{:db (mark-chat-all-read db chat-id)
|
{:db (mark-chat-all-read db chat-id)
|
||||||
:clear-message-notifications [[chat-id]
|
:clear-message-notifications [[chat-id]
|
||||||
(get-in db [:multiaccount :remote-push-notifications-enabled?])]
|
(get-in db [:multiaccount :remote-push-notifications-enabled?])]
|
||||||
::json-rpc/call [{:method "wakuext_markAllRead"
|
::json-rpc/call [{:method "wakuext_markAllRead"
|
||||||
:params [chat-id]
|
:params [chat-id]
|
||||||
:on-success #(re-frame/dispatch [::mark-all-read-successful])}]})
|
:on-success #(re-frame/dispatch [::mark-all-read-successful])}]})
|
||||||
|
|
||||||
(fx/defn handle-mark-mark-all-read-in-community
|
(rf/defn handle-mark-mark-all-read-in-community
|
||||||
{:events [:chat.ui/mark-all-read-in-community-pressed]}
|
{:events [:chat.ui/mark-all-read-in-community-pressed]}
|
||||||
[{db :db} community-id]
|
[{db :db} community-id]
|
||||||
(let [community-chat-ids (map #(str community-id %)
|
(let [community-chat-ids (map #(str community-id %)
|
||||||
(keys (get-in db [:communities community-id :chats])))]
|
(keys (get-in db [:communities community-id :chats])))]
|
||||||
{:clear-message-notifications [community-chat-ids
|
{:clear-message-notifications [community-chat-ids
|
||||||
(get-in db [:multiaccount :remote-push-notifications-enabled?])]
|
(get-in db [:multiaccount :remote-push-notifications-enabled?])]
|
||||||
::json-rpc/call [{:method "wakuext_markAllReadInCommunity"
|
::json-rpc/call [{:method "wakuext_markAllReadInCommunity"
|
||||||
:params [community-id]
|
:params [community-id]
|
||||||
:on-success #(re-frame/dispatch [::mark-all-read-in-community-successful %])}]}))
|
:on-success #(re-frame/dispatch
|
||||||
|
[::mark-all-read-in-community-successful %])}]}))
|
||||||
|
|
||||||
(fx/defn messages-loaded
|
(rf/defn messages-loaded
|
||||||
"Loads more messages for current chat"
|
"Loads more messages for current chat"
|
||||||
{:events [::messages-loaded]}
|
{:events [::messages-loaded]}
|
||||||
[{db :db} chat-id session-id {:keys [cursor messages]}]
|
[{db :db} chat-id session-id {:keys [cursor messages]}]
|
||||||
(when-not (and (get-in db [:pagination-info chat-id :messages-initialized?])
|
(when-not (and (get-in db [:pagination-info chat-id :messages-initialized?])
|
||||||
(not= session-id
|
(not= session-id
|
||||||
(get-in db [:pagination-info chat-id :messages-initialized?])))
|
(get-in db [:pagination-info chat-id :messages-initialized?])))
|
||||||
(let [already-loaded-messages (get-in db [:messages chat-id])
|
(let [already-loaded-messages (get-in db [:messages chat-id])
|
||||||
;; We remove those messages that are already loaded, as we might get some duplicates
|
;; We remove those messages that are already loaded, as we might get some duplicates
|
||||||
{:keys [all-messages new-messages senders contacts]}
|
{:keys [all-messages new-messages senders contacts]}
|
||||||
(reduce (fn [{:keys [all-messages] :as acc}
|
(reduce (fn [{:keys [all-messages] :as acc}
|
||||||
@@ -124,8 +129,11 @@
|
|||||||
:contacts {}
|
:contacts {}
|
||||||
:new-messages []}
|
:new-messages []}
|
||||||
messages)
|
messages)
|
||||||
current-clock-value (get-in db [:pagination-info chat-id :cursor-clock-value])
|
current-clock-value (get-in db
|
||||||
clock-value (when cursor (cursor->clock-value cursor))]
|
[:pagination-info chat-id
|
||||||
|
:cursor-clock-value])
|
||||||
|
clock-value (when cursor
|
||||||
|
(cursor->clock-value cursor))]
|
||||||
{:dispatch [:chat/add-senders-to-chat-users (vals senders)]
|
{:dispatch [:chat/add-senders-to-chat-users (vals senders)]
|
||||||
:db (-> db
|
:db (-> db
|
||||||
(update-in [:pagination-info chat-id :cursor-clock-value]
|
(update-in [:pagination-info chat-id :cursor-clock-value]
|
||||||
@@ -134,7 +142,9 @@
|
|||||||
%))
|
%))
|
||||||
|
|
||||||
(update-in [:pagination-info chat-id :cursor]
|
(update-in [:pagination-info chat-id :cursor]
|
||||||
#(if (or (empty? cursor) (not current-clock-value) (< clock-value current-clock-value))
|
#(if (or (empty? cursor)
|
||||||
|
(not current-clock-value)
|
||||||
|
(< clock-value current-clock-value))
|
||||||
cursor
|
cursor
|
||||||
%))
|
%))
|
||||||
(assoc-in [:pagination-info chat-id :loading-messages?] false)
|
(assoc-in [:pagination-info chat-id :loading-messages?] false)
|
||||||
@@ -144,7 +154,7 @@
|
|||||||
(empty? cursor))
|
(empty? cursor))
|
||||||
(update :contacts/contacts merge contacts))})))
|
(update :contacts/contacts merge contacts))})))
|
||||||
|
|
||||||
(fx/defn load-more-messages
|
(rf/defn load-more-messages
|
||||||
{:events [:chat.ui/load-more-messages]}
|
{:events [:chat.ui/load-more-messages]}
|
||||||
[{:keys [db]} chat-id first-request]
|
[{:keys [db]} chat-id first-request]
|
||||||
(when-let [session-id (get-in db [:pagination-info chat-id :messages-initialized?])]
|
(when-let [session-id (get-in db [:pagination-info chat-id :messages-initialized?])]
|
||||||
@@ -163,16 +173,16 @@
|
|||||||
#(re-frame/dispatch [::messages-loaded chat-id session-id %])
|
#(re-frame/dispatch [::messages-loaded chat-id session-id %])
|
||||||
#(re-frame/dispatch [::failed-loading-messages chat-id session-id %]))))))))
|
#(re-frame/dispatch [::failed-loading-messages chat-id session-id %]))))))))
|
||||||
|
|
||||||
(fx/defn load-more-messages-for-current-chat
|
(rf/defn load-more-messages-for-current-chat
|
||||||
{:events [:chat.ui/load-more-messages-for-current-chat]}
|
{:events [:chat.ui/load-more-messages-for-current-chat]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(load-more-messages cofx (:current-chat-id db) false))
|
(load-more-messages cofx (:current-chat-id db) false))
|
||||||
|
|
||||||
(fx/defn load-messages
|
(rf/defn load-messages
|
||||||
[{:keys [db now] :as cofx} chat-id]
|
[{:keys [db now] :as cofx} chat-id]
|
||||||
(when-not (get-in db [:pagination-info chat-id :messages-initialized?])
|
(when-not (get-in db [:pagination-info chat-id :messages-initialized?])
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc-in db [:pagination-info chat-id :messages-initialized?] now)
|
{:db (assoc-in db [:pagination-info chat-id :messages-initialized?] now)
|
||||||
:utils/dispatch-later [{:ms 50 :dispatch [:chat.ui/mark-all-read-pressed chat-id]}
|
:utils/dispatch-later [{:ms 50 :dispatch [:chat.ui/mark-all-read-pressed chat-id]}
|
||||||
(when-not (get-in cofx [:db :chats chat-id :public?])
|
(when-not (get-in cofx [:db :chats chat-id :public?])
|
||||||
{:ms 100 :dispatch [:pin-message/load-pin-messages chat-id]})]}
|
{:ms 100 :dispatch [:pin-message/load-pin-messages chat-id]})]}
|
||||||
|
|||||||
@@ -1,23 +1,26 @@
|
|||||||
(ns status-im.chat.models.mentions
|
(ns status-im.chat.models.mentions
|
||||||
(:require [clojure.string :as string]
|
(:require [clojure.string :as string]
|
||||||
|
[quo.react :as react]
|
||||||
|
[quo.react-native :as rn]
|
||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
[status-im.constants :as constants]
|
[status-im.constants :as constants]
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[status-im.contact.db :as contact.db]
|
[status-im.contact.db :as contact.db]
|
||||||
[status-im.utils.platform :as platform]
|
[status-im.multiaccounts.core :as multiaccounts]
|
||||||
[taoensso.timbre :as log]
|
|
||||||
[status-im.utils.utils :as utils]
|
|
||||||
[status-im.native-module.core :as status]
|
[status-im.native-module.core :as status]
|
||||||
[quo.react-native :as rn]
|
[status-im.utils.platform :as platform]
|
||||||
[quo.react :as react]
|
[status-im.utils.utils :as utils]
|
||||||
[status-im.multiaccounts.core :as multiaccounts]))
|
[taoensso.timbre :as log]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(def at-sign "@")
|
(def at-sign "@")
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
(defn re-pos [re s]
|
(defn re-pos
|
||||||
(loop [res [] s s last-idx 0]
|
[re s]
|
||||||
|
(loop [res []
|
||||||
|
s s
|
||||||
|
last-idx 0]
|
||||||
(if-let [m (.exec re s)]
|
(if-let [m (.exec re s)]
|
||||||
(let [new-idx (.-index m)
|
(let [new-idx (.-index m)
|
||||||
idx (+ last-idx new-idx)
|
idx (+ last-idx new-idx)
|
||||||
@@ -25,7 +28,8 @@
|
|||||||
(recur (conj res [idx c]) (subs s (inc new-idx)) (inc idx)))
|
(recur (conj res [idx c]) (subs s (inc new-idx)) (inc idx)))
|
||||||
res)))
|
res)))
|
||||||
|
|
||||||
(defn check-style-tag [text idxs idx]
|
(defn check-style-tag
|
||||||
|
[text idxs idx]
|
||||||
(let [[pos c] (get idxs idx)
|
(let [[pos c] (get idxs idx)
|
||||||
[pos2 c2] (get idxs (inc idx))
|
[pos2 c2] (get idxs (inc idx))
|
||||||
[pos3 c3] (get idxs (+ 2 idx))
|
[pos3 c3] (get idxs (+ 2 idx))
|
||||||
@@ -63,7 +67,8 @@
|
|||||||
(doall
|
(doall
|
||||||
((fnil concat []) checked new-idxs)))))))
|
((fnil concat []) checked new-idxs)))))))
|
||||||
|
|
||||||
(defn apply-style-tag [data idx pos c len start? end?]
|
(defn apply-style-tag
|
||||||
|
[data idx pos c len start? end?]
|
||||||
(let [was-started? (get data c)
|
(let [was-started? (get data c)
|
||||||
tripple-tilde? (and (= "~" c) (= 3 len))]
|
tripple-tilde? (and (= "~" c) (= 3 len))]
|
||||||
(cond
|
(cond
|
||||||
@@ -87,8 +92,9 @@
|
|||||||
|
|
||||||
start?
|
start?
|
||||||
{:data (-> data
|
{:data (-> data
|
||||||
(assoc c {:len len
|
(assoc c
|
||||||
:idx pos})
|
{:len len
|
||||||
|
:idx pos})
|
||||||
(clear-pending-at-signs pos))
|
(clear-pending-at-signs pos))
|
||||||
:next-idx (+ idx len)}
|
:next-idx (+ idx len)}
|
||||||
|
|
||||||
@@ -96,7 +102,8 @@
|
|||||||
{:data data
|
{:data data
|
||||||
:next-idx (+ idx len)})))
|
:next-idx (+ idx len)})))
|
||||||
|
|
||||||
(defn code-tag-len [idxs idx]
|
(defn code-tag-len
|
||||||
|
[idxs idx]
|
||||||
(let [[pos c] (get idxs idx)
|
(let [[pos c] (get idxs idx)
|
||||||
[pos2 c2] (get idxs (inc idx))
|
[pos2 c2] (get idxs (inc idx))
|
||||||
[pos3 c3] (get idxs (+ 2 idx))]
|
[pos3 c3] (get idxs (+ 2 idx))]
|
||||||
@@ -147,7 +154,8 @@
|
|||||||
(string/blank? (subs text (first prev-newlines) (dec pos)))))
|
(string/blank? (subs text (first prev-newlines) (dec pos)))))
|
||||||
(recur (-> data
|
(recur (-> data
|
||||||
(dissoc :newline "*" "_" "~" "`")
|
(dissoc :newline "*" "_" "~" "`")
|
||||||
(assoc ">" {:idx pos})) (inc idx))
|
(assoc ">" {:idx pos}))
|
||||||
|
(inc idx))
|
||||||
(recur data (inc idx))))
|
(recur data (inc idx))))
|
||||||
|
|
||||||
at-sign?
|
at-sign?
|
||||||
@@ -155,7 +163,7 @@
|
|||||||
(inc idx))
|
(inc idx))
|
||||||
|
|
||||||
code-tag?
|
code-tag?
|
||||||
(let [len (code-tag-len idxs idx)
|
(let [len (code-tag-len idxs idx)
|
||||||
{:keys [data next-idx]}
|
{:keys [data next-idx]}
|
||||||
(apply-style-tag data idx pos c len true true)]
|
(apply-style-tag data idx pos c len true true)]
|
||||||
(recur data next-idx))
|
(recur data next-idx))
|
||||||
@@ -167,7 +175,7 @@
|
|||||||
(apply-style-tag data idx pos c len can-be-start? can-be-end?)]
|
(apply-style-tag data idx pos c len can-be-start? can-be-end?)]
|
||||||
(recur data next-idx))
|
(recur data next-idx))
|
||||||
|
|
||||||
:else (recur data (inc idx)))))))))
|
:else (recur data (inc idx)))))))))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
@@ -201,7 +209,8 @@
|
|||||||
:ens-verified ens-verified
|
:ens-verified ens-verified
|
||||||
:public-key public-key})))
|
:public-key public-key})))
|
||||||
|
|
||||||
(defn mentionable-contacts [contacts]
|
(defn mentionable-contacts
|
||||||
|
[contacts]
|
||||||
(reduce
|
(reduce
|
||||||
(fn [acc [key contact]]
|
(fn [acc [key contact]]
|
||||||
(let [mentionable-contact (add-searchable-phrases-to-contact contact false)]
|
(let [mentionable-contact (add-searchable-phrases-to-contact contact false)]
|
||||||
@@ -211,38 +220,49 @@
|
|||||||
{}
|
{}
|
||||||
contacts))
|
contacts))
|
||||||
|
|
||||||
(defn mentionable-contacts-from-identites [contacts my-public-key identities]
|
(defn mentionable-contacts-from-identites
|
||||||
|
[contacts my-public-key identities]
|
||||||
(reduce (fn [acc identity]
|
(reduce (fn [acc identity]
|
||||||
(let [contact (multiaccounts/contact-by-identity
|
(let [contact (multiaccounts/contact-by-identity
|
||||||
contacts identity)
|
contacts
|
||||||
|
identity)
|
||||||
contact (if (string/blank? (:alias contact))
|
contact (if (string/blank? (:alias contact))
|
||||||
(assoc contact :alias
|
(assoc contact
|
||||||
|
:alias
|
||||||
(get-in contact [:names :three-words-name]))
|
(get-in contact [:names :three-words-name]))
|
||||||
contact)
|
contact)
|
||||||
mentionable-contact (add-searchable-phrases-to-contact
|
mentionable-contact (add-searchable-phrases-to-contact
|
||||||
contact true)]
|
contact
|
||||||
(if (nil? mentionable-contact) acc
|
true)]
|
||||||
(assoc acc identity mentionable-contact))))
|
(if (nil? mentionable-contact)
|
||||||
|
acc
|
||||||
|
(assoc acc identity mentionable-contact))))
|
||||||
{}
|
{}
|
||||||
(remove #(= my-public-key %) identities)))
|
(remove #(= my-public-key %) identities)))
|
||||||
|
|
||||||
(defn get-mentionable-users [chat all-contacts current-multiaccount community-members]
|
(defn get-mentionable-users
|
||||||
(let [{:keys [name preferred-name public-key]} current-multiaccount
|
[chat all-contacts current-multiaccount community-members]
|
||||||
|
(let [{:keys [name preferred-name public-key]} current-multiaccount
|
||||||
{:keys [chat-id users contacts chat-type]} chat
|
{:keys [chat-id users contacts chat-type]} chat
|
||||||
mentionable-contacts (mentionable-contacts all-contacts)
|
mentionable-contacts (mentionable-contacts all-contacts)
|
||||||
mentionable-users (assoc users public-key {:alias name
|
mentionable-users (assoc users
|
||||||
:name (or preferred-name name)
|
public-key
|
||||||
:public-key public-key})]
|
{:alias name
|
||||||
|
:name (or preferred-name name)
|
||||||
|
:public-key public-key})]
|
||||||
(cond
|
(cond
|
||||||
(= chat-type constants/private-group-chat-type)
|
(= chat-type constants/private-group-chat-type)
|
||||||
(merge mentionable-users
|
(merge mentionable-users
|
||||||
(mentionable-contacts-from-identites all-contacts public-key contacts))
|
(mentionable-contacts-from-identites all-contacts public-key contacts))
|
||||||
|
|
||||||
(= chat-type constants/one-to-one-chat-type)
|
(= chat-type constants/one-to-one-chat-type)
|
||||||
(assoc mentionable-users chat-id (get mentionable-contacts chat-id
|
(assoc mentionable-users
|
||||||
(-> chat-id
|
chat-id
|
||||||
contact.db/public-key->new-contact
|
(get mentionable-contacts
|
||||||
contact.db/enrich-contact)))
|
chat-id
|
||||||
|
(-> chat-id
|
||||||
|
contact.db/public-key->new-contact
|
||||||
|
contact.db/enrich-contact)))
|
||||||
|
|
||||||
(= chat-type constants/community-chat-type)
|
(= chat-type constants/community-chat-type)
|
||||||
(mentionable-contacts-from-identites
|
(mentionable-contacts-from-identites
|
||||||
@@ -253,13 +273,14 @@
|
|||||||
(= chat-type constants/public-chat-type)
|
(= chat-type constants/public-chat-type)
|
||||||
(merge mentionable-users (select-keys mentionable-contacts (keys mentionable-users)))
|
(merge mentionable-users (select-keys mentionable-contacts (keys mentionable-users)))
|
||||||
|
|
||||||
:else mentionable-users)))
|
:else mentionable-users)))
|
||||||
|
|
||||||
(def ending-chars "[\\s\\.,;:]")
|
(def ending-chars "[\\s\\.,;:]")
|
||||||
(def ending-chars-regex (re-pattern ending-chars))
|
(def ending-chars-regex (re-pattern ending-chars))
|
||||||
(def word-regex (re-pattern (str "^[\\w\\d]*" ending-chars "|^[\\S]*$")))
|
(def word-regex (re-pattern (str "^[\\w\\d]*" ending-chars "|^[\\S]*$")))
|
||||||
|
|
||||||
(defn mentioned? [{:keys [alias name]} text]
|
(defn mentioned?
|
||||||
|
[{:keys [alias name]} text]
|
||||||
(let [lcase-name (string/lower-case name)
|
(let [lcase-name (string/lower-case name)
|
||||||
lcase-alias (string/lower-case alias)
|
lcase-alias (string/lower-case alias)
|
||||||
regex (re-pattern
|
regex (re-pattern
|
||||||
@@ -272,7 +293,8 @@
|
|||||||
lcase-text (string/lower-case text)]
|
lcase-text (string/lower-case text)]
|
||||||
(re-find regex lcase-text)))
|
(re-find regex lcase-text)))
|
||||||
|
|
||||||
(defn get-user-suggestions [users searched-text]
|
(defn get-user-suggestions
|
||||||
|
[users searched-text]
|
||||||
(reduce
|
(reduce
|
||||||
(fn [acc [k {:keys [alias name nickname searchable-phrases] :as user}]]
|
(fn [acc [k {:keys [alias name nickname searchable-phrases] :as user}]]
|
||||||
(if-let [match
|
(if-let [match
|
||||||
@@ -301,9 +323,11 @@
|
|||||||
(string/lower-case name)
|
(string/lower-case name)
|
||||||
searched-text)
|
searched-text)
|
||||||
name))]
|
name))]
|
||||||
(assoc acc k (assoc user
|
(assoc acc
|
||||||
:match match
|
k
|
||||||
:searched-text searched-text))
|
(assoc user
|
||||||
|
:match match
|
||||||
|
:searched-text searched-text))
|
||||||
acc))
|
acc))
|
||||||
{}
|
{}
|
||||||
users))
|
users))
|
||||||
@@ -324,21 +348,25 @@
|
|||||||
text))
|
text))
|
||||||
user-suggestions (get-user-suggestions users searched-text)
|
user-suggestions (get-user-suggestions users searched-text)
|
||||||
user-suggestions-cnt (count user-suggestions)]
|
user-suggestions-cnt (count user-suggestions)]
|
||||||
(cond (zero? user-suggestions-cnt)
|
(cond
|
||||||
nil
|
(zero? user-suggestions-cnt)
|
||||||
|
nil
|
||||||
|
|
||||||
(and (= 1 user-suggestions-cnt)
|
(and (= 1 user-suggestions-cnt)
|
||||||
(mentioned? (second (first user-suggestions))
|
(mentioned? (second (first user-suggestions))
|
||||||
(subs text (inc mention-key-idx))))
|
(subs text (inc mention-key-idx))))
|
||||||
(second (first user-suggestions))
|
(second (first user-suggestions))
|
||||||
|
|
||||||
(> user-suggestions-cnt 1)
|
(> user-suggestions-cnt 1)
|
||||||
(let [word-len (count word)
|
(let [word-len (count word)
|
||||||
text-len (count text)
|
text-len (count text)
|
||||||
next-word-start (+ next-word-idx word-len)]
|
next-word-start (+ next-word-idx word-len)]
|
||||||
(when (> text-len next-word-start)
|
(when (> text-len next-word-start)
|
||||||
(match-mention text users mention-key-idx
|
(match-mention text
|
||||||
next-word-start new-words))))))))
|
users
|
||||||
|
mention-key-idx
|
||||||
|
next-word-start
|
||||||
|
new-words))))))))
|
||||||
|
|
||||||
(defn replace-mentions
|
(defn replace-mentions
|
||||||
([text users]
|
([text users]
|
||||||
@@ -360,18 +388,25 @@
|
|||||||
(let [new-text (string/join
|
(let [new-text (string/join
|
||||||
[(subs text 0 (inc mention-key-idx))
|
[(subs text 0 (inc mention-key-idx))
|
||||||
public-key
|
public-key
|
||||||
(subs text (+ (inc mention-key-idx)
|
(subs text
|
||||||
(count match)))])]
|
(+ (inc mention-key-idx)
|
||||||
(recur new-text users (rest idxs)
|
(count match)))])]
|
||||||
|
(recur new-text
|
||||||
|
users
|
||||||
|
(rest idxs)
|
||||||
(+ diff (- (count text) (count new-text)))))))))))))
|
(+ diff (- (count text) (count new-text)))))))))))))
|
||||||
|
|
||||||
(defn check-mentions [{:keys [db]} text]
|
(defn check-mentions
|
||||||
|
[{:keys [db]} text]
|
||||||
(let [current-chat-id (:current-chat-id db)
|
(let [current-chat-id (:current-chat-id db)
|
||||||
chat (get-in db [:chats current-chat-id])
|
chat (get-in db [:chats current-chat-id])
|
||||||
all-contacts (:contacts/contacts db)
|
all-contacts (:contacts/contacts db)
|
||||||
current-multiaccount (:multiaccount db)
|
current-multiaccount (:multiaccount db)
|
||||||
community-members (get-in db [:communities (:community-id chat) :members])
|
community-members (get-in db [:communities (:community-id chat) :members])
|
||||||
mentionable-users (get-mentionable-users chat all-contacts current-multiaccount community-members)]
|
mentionable-users (get-mentionable-users chat
|
||||||
|
all-contacts
|
||||||
|
current-multiaccount
|
||||||
|
community-members)]
|
||||||
(replace-mentions text mentionable-users)))
|
(replace-mentions text mentionable-users)))
|
||||||
|
|
||||||
(defn get-at-sign-idxs
|
(defn get-at-sign-idxs
|
||||||
@@ -396,7 +431,7 @@
|
|||||||
{:from idx
|
{:from idx
|
||||||
:checked? false})
|
:checked? false})
|
||||||
new-idxs)
|
new-idxs)
|
||||||
(let [diff (- new-text-len old-text-len)
|
(let [diff (- new-text-len old-text-len)
|
||||||
{:keys [state added?]}
|
{:keys [state added?]}
|
||||||
(->> at-idxs
|
(->> at-idxs
|
||||||
(keep (fn [{:keys [from to] :as entry}]
|
(keep (fn [{:keys [from to] :as entry}]
|
||||||
@@ -406,7 +441,7 @@
|
|||||||
(>= from old-end)
|
(>= from old-end)
|
||||||
(assoc entry
|
(assoc entry
|
||||||
:from (+ from diff)
|
:from (+ from diff)
|
||||||
:to (+ to diff))
|
:to (+ to diff))
|
||||||
|
|
||||||
;; starts and end before change
|
;; starts and end before change
|
||||||
(and
|
(and
|
||||||
@@ -431,20 +466,22 @@
|
|||||||
(> from last-new-idx)
|
(> from last-new-idx)
|
||||||
(not added?))
|
(not added?))
|
||||||
{:state (conj
|
{:state (conj
|
||||||
(into state (map (fn [idx]
|
(into state
|
||||||
{:from idx
|
(map (fn [idx]
|
||||||
:checked? false})
|
{:from idx
|
||||||
new-idxs))
|
:checked? false})
|
||||||
|
new-idxs))
|
||||||
entry)
|
entry)
|
||||||
:added? true}
|
:added? true}
|
||||||
(update acc :state conj entry)))
|
(update acc :state conj entry)))
|
||||||
{:state []}))]
|
{:state []}))]
|
||||||
(if added?
|
(if added?
|
||||||
state
|
state
|
||||||
(into state (map (fn [idx]
|
(into state
|
||||||
{:from idx
|
(map (fn [idx]
|
||||||
:checked? false})
|
{:from idx
|
||||||
new-idxs)))))))
|
:checked? false})
|
||||||
|
new-idxs)))))))
|
||||||
|
|
||||||
(defn check-entry
|
(defn check-entry
|
||||||
[text {:keys [from checked?] :as entry} mentionable-users]
|
[text {:keys [from checked?] :as entry} mentionable-users]
|
||||||
@@ -453,14 +490,14 @@
|
|||||||
(let [{user-match :match}
|
(let [{user-match :match}
|
||||||
(match-mention (str text "@") mentionable-users from)]
|
(match-mention (str text "@") mentionable-users from)]
|
||||||
(if user-match
|
(if user-match
|
||||||
{:from from
|
{:from from
|
||||||
:to (+ from (count user-match))
|
:to (+ from (count user-match))
|
||||||
:checked? true
|
:checked? true
|
||||||
:mention? true}
|
:mention? true}
|
||||||
{:from from
|
{:from from
|
||||||
:to (count text)
|
:to (count text)
|
||||||
:checked? true
|
:checked? true
|
||||||
:mention false}))))
|
:mention false}))))
|
||||||
|
|
||||||
(defn check-idx-for-mentions
|
(defn check-idx-for-mentions
|
||||||
[text idxs mentionable-users]
|
[text idxs mentionable-users]
|
||||||
@@ -489,7 +526,7 @@
|
|||||||
(assoc-in [last-idx :to] (dec (count text)))
|
(assoc-in [last-idx :to] (dec (count text)))
|
||||||
(assoc-in [last-idx :checked?] false)))))))
|
(assoc-in [last-idx :checked?] false)))))))
|
||||||
|
|
||||||
(fx/defn on-text-input
|
(rf/defn on-text-input
|
||||||
{:events [::on-text-input]}
|
{:events [::on-text-input]}
|
||||||
[{:keys [db]} {:keys [previous-text start end] :as args}]
|
[{:keys [db]} {:keys [previous-text start end] :as args}]
|
||||||
(log/debug "[mentions] on-text-input args" args)
|
(log/debug "[mentions] on-text-input args" args)
|
||||||
@@ -499,31 +536,34 @@
|
|||||||
(if platform/android?
|
(if platform/android?
|
||||||
previous-text
|
previous-text
|
||||||
(subs previous-text start end))
|
(subs previous-text start end))
|
||||||
chat-id (:current-chat-id db)
|
chat-id (:current-chat-id db)
|
||||||
previous-state (get-in db [:chats/mentions chat-id :mentions])
|
previous-state (get-in db [:chats/mentions chat-id :mentions])
|
||||||
new-state (-> previous-state
|
new-state (-> previous-state
|
||||||
(merge args)
|
(merge args)
|
||||||
(assoc :previous-text normalized-previous-text))
|
(assoc :previous-text normalized-previous-text))
|
||||||
new-at-idxs (calc-at-idxs new-state)
|
new-at-idxs (calc-at-idxs new-state)
|
||||||
new-state (assoc new-state :at-idxs new-at-idxs)]
|
new-state (assoc new-state :at-idxs new-at-idxs)]
|
||||||
(log/debug "[mentions] on-text-input state" new-state)
|
(log/debug "[mentions] on-text-input state" new-state)
|
||||||
{:db (assoc-in db [:chats/mentions chat-id :mentions] new-state)}))
|
{:db (assoc-in db [:chats/mentions chat-id :mentions] new-state)}))
|
||||||
|
|
||||||
(defn calculate-input [text [first-idx :as idxs]]
|
(defn calculate-input
|
||||||
|
[text [first-idx :as idxs]]
|
||||||
(if-not first-idx
|
(if-not first-idx
|
||||||
[[:text text]]
|
[[:text text]]
|
||||||
(let [idx-cnt (count idxs)
|
(let [idx-cnt (count idxs)
|
||||||
last-from (get-in idxs [(dec idx-cnt) :from])]
|
last-from (get-in idxs [(dec idx-cnt) :from])]
|
||||||
(reduce
|
(reduce
|
||||||
(fn [acc {:keys [from to next-at-idx mention?]}]
|
(fn [acc {:keys [from to next-at-idx mention?]}]
|
||||||
(cond
|
(cond
|
||||||
(and mention? next-at-idx)
|
(and mention? next-at-idx)
|
||||||
(into acc [[:mention (subs text from (inc to))]
|
(into acc
|
||||||
[:text (subs text (inc to) next-at-idx)]])
|
[[:mention (subs text from (inc to))]
|
||||||
|
[:text (subs text (inc to) next-at-idx)]])
|
||||||
|
|
||||||
(and mention? (= last-from from))
|
(and mention? (= last-from from))
|
||||||
(into acc [[:mention (subs text from (inc to))]
|
(into acc
|
||||||
[:text (subs text (inc to))]])
|
[[:mention (subs text from (inc to))]
|
||||||
|
[:text (subs text (inc to))]])
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(conj acc [:text (subs text from (inc to))])))
|
(conj acc [:text (subs text from (inc to))])))
|
||||||
@@ -533,79 +573,82 @@
|
|||||||
[[:text (subs text 0 first-from)]]))
|
[[:text (subs text 0 first-from)]]))
|
||||||
idxs))))
|
idxs))))
|
||||||
|
|
||||||
(fx/defn recheck-at-idxs
|
(rf/defn recheck-at-idxs
|
||||||
[{:keys [db]} mentionable-users]
|
[{:keys [db]} mentionable-users]
|
||||||
(let [chat-id (:current-chat-id db)
|
(let [chat-id (:current-chat-id db)
|
||||||
text (get-in db [:chat/inputs chat-id :input-text])
|
text (get-in db [:chat/inputs chat-id :input-text])
|
||||||
state (get-in db [:chats/mentions chat-id :mentions])
|
state (get-in db [:chats/mentions chat-id :mentions])
|
||||||
new-at-idxs (check-idx-for-mentions
|
new-at-idxs (check-idx-for-mentions
|
||||||
text
|
text
|
||||||
(:at-idxs state)
|
(:at-idxs state)
|
||||||
mentionable-users)
|
mentionable-users)
|
||||||
calculated-input (calculate-input text new-at-idxs)]
|
calculated-input (calculate-input text new-at-idxs)]
|
||||||
(log/debug "[mentions] new-at-idxs" new-at-idxs calculated-input)
|
(log/debug "[mentions] new-at-idxs" new-at-idxs calculated-input)
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(update-in
|
(update-in
|
||||||
[:chats/mentions chat-id :mentions]
|
[:chats/mentions chat-id :mentions]
|
||||||
assoc
|
assoc
|
||||||
:at-idxs new-at-idxs)
|
:at-idxs
|
||||||
|
new-at-idxs)
|
||||||
(assoc-in [:chat/inputs-with-mentions chat-id] calculated-input))}))
|
(assoc-in [:chat/inputs-with-mentions chat-id] calculated-input))}))
|
||||||
|
|
||||||
(fx/defn calculate-suggestions
|
(rf/defn calculate-suggestions
|
||||||
{:events [::calculate-suggestions]}
|
{:events [::calculate-suggestions]}
|
||||||
[{:keys [db]} mentionable-users]
|
[{:keys [db]} mentionable-users]
|
||||||
(let [chat-id (:current-chat-id db)
|
(let [chat-id (:current-chat-id db)
|
||||||
text (get-in db [:chat/inputs chat-id :input-text])
|
text (get-in db [:chat/inputs chat-id :input-text])
|
||||||
{:keys [new-text at-idxs start end] :as state}
|
{:keys [new-text at-idxs start end] :as state}
|
||||||
(get-in db [:chats/mentions chat-id :mentions])
|
(get-in db [:chats/mentions chat-id :mentions])
|
||||||
new-text (or new-text text)]
|
new-text (or new-text text)]
|
||||||
(log/info "[mentions] calculate suggestions"
|
(log/info "[mentions] calculate suggestions"
|
||||||
"state" state)
|
"state"
|
||||||
|
state)
|
||||||
(if-not (seq at-idxs)
|
(if-not (seq at-idxs)
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:chats/mention-suggestions chat-id] nil)
|
(assoc-in [:chats/mention-suggestions chat-id] nil)
|
||||||
(assoc-in [:chats/mentions chat-id :mentions :at-idxs] nil)
|
(assoc-in [:chats/mentions chat-id :mentions :at-idxs] nil)
|
||||||
(assoc-in [:chat/inputs-with-mentions chat-id] [[:text text]]))}
|
(assoc-in [:chat/inputs-with-mentions chat-id] [[:text text]]))}
|
||||||
(let [new-at-idxs (check-idx-for-mentions
|
(let [new-at-idxs (check-idx-for-mentions
|
||||||
text
|
text
|
||||||
at-idxs
|
at-idxs
|
||||||
mentionable-users)
|
mentionable-users)
|
||||||
calculated-input (calculate-input text new-at-idxs)
|
calculated-input (calculate-input text new-at-idxs)
|
||||||
addition? (<= start end)
|
addition? (<= start end)
|
||||||
end (if addition?
|
end (if addition?
|
||||||
(+ start (count new-text))
|
(+ start (count new-text))
|
||||||
start)
|
start)
|
||||||
at-sign-idx (string/last-index-of text at-sign start)
|
at-sign-idx (string/last-index-of text at-sign start)
|
||||||
searched-text (string/lower-case (subs text (inc at-sign-idx) end))
|
searched-text (string/lower-case (subs text (inc at-sign-idx) end))
|
||||||
mentions
|
mentions
|
||||||
(when (and (not (> at-sign-idx start))
|
(when (and (not (> at-sign-idx start))
|
||||||
(not (> (- end at-sign-idx) 100)))
|
(not (> (- end at-sign-idx) 100)))
|
||||||
(get-user-suggestions mentionable-users searched-text))]
|
(get-user-suggestions mentionable-users searched-text))]
|
||||||
(log/debug "[mentions] mention check"
|
(log/debug "[mentions] mention check"
|
||||||
"addition" addition?
|
"addition" addition?
|
||||||
"at-sign-idx" at-sign-idx
|
"at-sign-idx" at-sign-idx
|
||||||
"start" start
|
"start" start
|
||||||
"end" end
|
"end" end
|
||||||
"searched-text" (pr-str searched-text)
|
"searched-text" (pr-str searched-text)
|
||||||
"mentions" (count mentions))
|
"mentions" (count mentions))
|
||||||
(log/debug "[mentions] new-at-idxs" new-at-idxs calculated-input)
|
(log/debug "[mentions] new-at-idxs" new-at-idxs calculated-input)
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(update-in [:chats/mentions chat-id :mentions]
|
(update-in [:chats/mentions chat-id :mentions]
|
||||||
assoc
|
assoc
|
||||||
:at-sign-idx at-sign-idx
|
:at-sign-idx at-sign-idx
|
||||||
:at-idxs new-at-idxs
|
:at-idxs new-at-idxs
|
||||||
:mention-end end)
|
:mention-end end)
|
||||||
(assoc-in [:chat/inputs-with-mentions chat-id] calculated-input)
|
(assoc-in [:chat/inputs-with-mentions chat-id] calculated-input)
|
||||||
(assoc-in [:chats/mention-suggestions chat-id] mentions))}))))
|
(assoc-in [:chats/mention-suggestions chat-id] mentions))}))))
|
||||||
|
|
||||||
(defn new-input-text-with-mention
|
(defn new-input-text-with-mention
|
||||||
[{:keys [db]} {:keys [name]}]
|
[{:keys [db]} {:keys [name]}]
|
||||||
(let [chat-id (:current-chat-id db)
|
(let [chat-id (:current-chat-id db)
|
||||||
text (get-in db [:chat/inputs chat-id :input-text])
|
text (get-in db [:chat/inputs chat-id :input-text])
|
||||||
{:keys [mention-end at-sign-idx]}
|
{:keys [mention-end at-sign-idx]}
|
||||||
(get-in db [:chats/mentions chat-id :mentions])]
|
(get-in db [:chats/mentions chat-id :mentions])]
|
||||||
(log/debug "[mentions] clear suggestions"
|
(log/debug "[mentions] clear suggestions"
|
||||||
"state" new-input-text-with-mention)
|
"state"
|
||||||
|
new-input-text-with-mention)
|
||||||
(string/join
|
(string/join
|
||||||
[(subs text 0 (inc at-sign-idx))
|
[(subs text 0 (inc at-sign-idx))
|
||||||
name
|
name
|
||||||
@@ -616,36 +659,36 @@
|
|||||||
" "))
|
" "))
|
||||||
(subs text mention-end)])))
|
(subs text mention-end)])))
|
||||||
|
|
||||||
(fx/defn clear-suggestions
|
(rf/defn clear-suggestions
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(log/debug "[mentions] clear suggestions")
|
(log/debug "[mentions] clear suggestions")
|
||||||
(let [chat-id (:current-chat-id db)]
|
(let [chat-id (:current-chat-id db)]
|
||||||
{:db (update db :chats/mention-suggestions dissoc chat-id)}))
|
{:db (update db :chats/mention-suggestions dissoc chat-id)}))
|
||||||
|
|
||||||
(fx/defn clear-mentions
|
(rf/defn clear-mentions
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(log/debug "[mentions] clear mentions")
|
(log/debug "[mentions] clear mentions")
|
||||||
(let [chat-id (:current-chat-id db)]
|
(let [chat-id (:current-chat-id db)]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(update-in [:chats/mentions chat-id] dissoc :mentions)
|
(update-in [:chats/mentions chat-id] dissoc :mentions)
|
||||||
(update :chat/inputs-with-mentions dissoc chat-id))}
|
(update :chat/inputs-with-mentions dissoc chat-id))}
|
||||||
(clear-suggestions))))
|
(clear-suggestions))))
|
||||||
|
|
||||||
(fx/defn clear-cursor
|
(rf/defn clear-cursor
|
||||||
{:events [::clear-cursor]}
|
{:events [::clear-cursor]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(log/debug "[mentions] clear cursor")
|
(log/debug "[mentions] clear cursor")
|
||||||
{:db
|
{:db
|
||||||
(update db :chats/cursor dissoc (:current-chat-id db))})
|
(update db :chats/cursor dissoc (:current-chat-id db))})
|
||||||
|
|
||||||
(fx/defn check-selection
|
(rf/defn check-selection
|
||||||
{:events [::on-selection-change]}
|
{:events [::on-selection-change]}
|
||||||
[{:keys [db] :as cofx}
|
[{:keys [db] :as cofx}
|
||||||
{:keys [start end] :as selection}
|
{:keys [start end] :as selection}
|
||||||
mentionable-users]
|
mentionable-users]
|
||||||
(let [chat-id (:current-chat-id db)
|
(let [chat-id (:current-chat-id db)
|
||||||
{:keys [mention-end at-idxs]}
|
{:keys [mention-end at-idxs]}
|
||||||
(get-in db [:chats/mentions chat-id :mentions])]
|
(get-in db [:chats/mentions chat-id :mentions])]
|
||||||
(when (seq at-idxs)
|
(when (seq at-idxs)
|
||||||
@@ -655,12 +698,13 @@
|
|||||||
(<= (dec end) to))
|
(<= (dec end) to))
|
||||||
idx))
|
idx))
|
||||||
at-idxs)
|
at-idxs)
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (update-in db [:chats/mentions chat-id :mentions]
|
{:db (update-in db
|
||||||
|
[:chats/mentions chat-id :mentions]
|
||||||
assoc
|
assoc
|
||||||
:start end
|
:start end
|
||||||
:end end
|
:end end
|
||||||
:new-text "")}
|
:new-text "")}
|
||||||
(calculate-suggestions mentionable-users))
|
(calculate-suggestions mentionable-users))
|
||||||
(clear-suggestions cofx)))))
|
(clear-suggestions cofx)))))
|
||||||
@@ -673,26 +717,28 @@
|
|||||||
(rn/find-node-handle (react/current-ref ref))
|
(rn/find-node-handle (react/current-ref ref))
|
||||||
cursor))))
|
cursor))))
|
||||||
|
|
||||||
(fx/defn reset-text-input-cursor
|
(rf/defn reset-text-input-cursor
|
||||||
[_ ref cursor]
|
[_ ref cursor]
|
||||||
{::reset-text-input-cursor [ref cursor]})
|
{::reset-text-input-cursor [ref cursor]})
|
||||||
|
|
||||||
(defn is-valid-terminating-character? [c]
|
(defn is-valid-terminating-character?
|
||||||
|
[c]
|
||||||
(case c
|
(case c
|
||||||
"\t" true ; tab
|
"\t" true ; tab
|
||||||
"\n" true ; newline
|
"\n" true ; newline
|
||||||
"\f" true ; new page
|
"\f" true ; new page
|
||||||
"\r" true ; carriage return
|
"\r" true ; carriage return
|
||||||
" " true ; whitespace
|
" " true ; whitespace
|
||||||
"," true
|
"," true
|
||||||
"." true
|
"." true
|
||||||
":" true
|
":" true
|
||||||
";" true
|
";" true
|
||||||
false))
|
false))
|
||||||
|
|
||||||
(def hex-reg #"[0-9a-f]")
|
(def hex-reg #"[0-9a-f]")
|
||||||
|
|
||||||
(defn is-public-key-character? [c]
|
(defn is-public-key-character?
|
||||||
|
[c]
|
||||||
(.test hex-reg c))
|
(.test hex-reg c))
|
||||||
|
|
||||||
(def mention-length 133)
|
(def mention-length 133)
|
||||||
@@ -710,7 +756,7 @@
|
|||||||
current-text
|
current-text
|
||||||
current-mention
|
current-mention
|
||||||
current-mention-length]} character]
|
current-mention-length]} character]
|
||||||
(let [is-pk-character (is-public-key-character? character)
|
(let [is-pk-character (is-public-key-character? character)
|
||||||
is-termination-character (is-valid-terminating-character? character)]
|
is-termination-character (is-valid-terminating-character? character)]
|
||||||
(cond
|
(cond
|
||||||
;; It's a valid mention.
|
;; It's a valid mention.
|
||||||
@@ -720,13 +766,13 @@
|
|||||||
(and (= current-mention-length mention-length)
|
(and (= current-mention-length mention-length)
|
||||||
is-termination-character)
|
is-termination-character)
|
||||||
{:current-mention-length 0
|
{:current-mention-length 0
|
||||||
:current-mention ""
|
:current-mention ""
|
||||||
:current-text character
|
:current-text character
|
||||||
:text (cond-> text
|
:text (cond-> text
|
||||||
(seq current-text)
|
(seq current-text)
|
||||||
(conj [:text current-text])
|
(conj [:text current-text])
|
||||||
:always
|
:always
|
||||||
(conj [:mention current-mention]))}
|
(conj [:mention current-mention]))}
|
||||||
|
|
||||||
|
|
||||||
;; It's either a pk character, or the `x` in the pk
|
;; It's either a pk character, or the `x` in the pk
|
||||||
@@ -739,9 +785,9 @@
|
|||||||
(and (= 2 current-mention-length)
|
(and (= 2 current-mention-length)
|
||||||
(= "x" character)))
|
(= "x" character)))
|
||||||
{:current-mention-length (inc current-mention-length)
|
{:current-mention-length (inc current-mention-length)
|
||||||
:current-text current-text
|
:current-text current-text
|
||||||
:current-mention (str current-mention character)
|
:current-mention (str current-mention character)
|
||||||
:text text}
|
:text text}
|
||||||
|
|
||||||
|
|
||||||
;; The beginning of a mention, discard the @ sign
|
;; The beginning of a mention, discard the @ sign
|
||||||
@@ -750,29 +796,29 @@
|
|||||||
|
|
||||||
(= "@" character)
|
(= "@" character)
|
||||||
{:current-mention-length 1
|
{:current-mention-length 1
|
||||||
:current-mention ""
|
:current-mention ""
|
||||||
:current-text current-text
|
:current-text current-text
|
||||||
:text text}
|
:text text}
|
||||||
|
|
||||||
;; Not a mention character, but we were following a mention
|
;; Not a mention character, but we were following a mention
|
||||||
;; discard everything up to know an count as text
|
;; discard everything up to know an count as text
|
||||||
(and (not is-pk-character)
|
(and (not is-pk-character)
|
||||||
(pos? current-mention-length))
|
(pos? current-mention-length))
|
||||||
{:current-mention-length 0
|
{:current-mention-length 0
|
||||||
:current-text (str current-text "@" current-mention character)
|
:current-text (str current-text "@" current-mention character)
|
||||||
:current-mention ""
|
:current-mention ""
|
||||||
:text text}
|
:text text}
|
||||||
|
|
||||||
;; Just a normal text character
|
;; Just a normal text character
|
||||||
:else
|
:else
|
||||||
{:current-mention-length 0
|
{:current-mention-length 0
|
||||||
:current-mention ""
|
:current-mention ""
|
||||||
:current-text (str current-text character)
|
:current-text (str current-text character)
|
||||||
:text text})))
|
:text text})))
|
||||||
{:current-mention-length 0
|
{:current-mention-length 0
|
||||||
:current-text ""
|
:current-text ""
|
||||||
:current-mention ""
|
:current-mention ""
|
||||||
:text []}
|
:text []}
|
||||||
text)]
|
text)]
|
||||||
;; Process any remaining mention/text
|
;; Process any remaining mention/text
|
||||||
(cond-> text
|
(cond-> text
|
||||||
@@ -788,32 +834,32 @@
|
|||||||
[m]
|
[m]
|
||||||
(reduce (fn [{:keys [start end at-idxs at-sign-idx mention-end]} [t text]]
|
(reduce (fn [{:keys [start end at-idxs at-sign-idx mention-end]} [t text]]
|
||||||
(if (= :mention t)
|
(if (= :mention t)
|
||||||
(let [new-mention {:checked? true
|
(let [new-mention {:checked? true
|
||||||
:mention? true
|
:mention? true
|
||||||
:from mention-end
|
:from mention-end
|
||||||
:to (+ start (count text))}
|
:to (+ start (count text))}
|
||||||
has-previous? (seq at-idxs)]
|
has-previous? (seq at-idxs)]
|
||||||
{:new-text (last text)
|
{:new-text (last text)
|
||||||
:previous-text ""
|
:previous-text ""
|
||||||
:start (+ start (count text))
|
:start (+ start (count text))
|
||||||
:end (+ end (count text))
|
:end (+ end (count text))
|
||||||
:at-idxs (cond-> at-idxs
|
:at-idxs (cond-> at-idxs
|
||||||
has-previous?
|
has-previous?
|
||||||
(-> pop
|
(-> pop
|
||||||
(conj (assoc (peek at-idxs) :next-at-idx mention-end)))
|
(conj (assoc (peek at-idxs) :next-at-idx mention-end)))
|
||||||
:always
|
:always
|
||||||
(conj new-mention))
|
(conj new-mention))
|
||||||
:at-sign-idx mention-end
|
:at-sign-idx mention-end
|
||||||
:mention-end (+ mention-end (count text))})
|
:mention-end (+ mention-end (count text))})
|
||||||
{:new-text (last text)
|
{:new-text (last text)
|
||||||
:previous-text ""
|
:previous-text ""
|
||||||
:start (+ start (count text))
|
:start (+ start (count text))
|
||||||
:end (+ end (count text))
|
:end (+ end (count text))
|
||||||
:at-idxs at-idxs
|
:at-idxs at-idxs
|
||||||
:at-sign-idx at-sign-idx
|
:at-sign-idx at-sign-idx
|
||||||
:mention-end (+ mention-end (count text))}))
|
:mention-end (+ mention-end (count text))}))
|
||||||
{:start -1
|
{:start -1
|
||||||
:end -1
|
:end -1
|
||||||
:at-idxs []
|
:at-idxs []
|
||||||
:mention-end 0}
|
:mention-end 0}
|
||||||
m))
|
m))
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
(:require [clojure.string :as string]
|
(:require [clojure.string :as string]
|
||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
[status-im.chat.models :as chat-model]
|
[status-im.chat.models :as chat-model]
|
||||||
[status-im2.contexts.chat.messages.message.delete-message.events :as delete-message]
|
|
||||||
[status-im.chat.models.loading :as chat.loading]
|
[status-im.chat.models.loading :as chat.loading]
|
||||||
[status-im.chat.models.mentions :as mentions]
|
[status-im.chat.models.mentions :as mentions]
|
||||||
[status-im.chat.models.message-list :as message-list]
|
[status-im.chat.models.message-list :as message-list]
|
||||||
@@ -11,11 +10,12 @@
|
|||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
[status-im.transport.message.protocol :as protocol]
|
[status-im.transport.message.protocol :as protocol]
|
||||||
[status-im.ui.screens.chat.state :as view.state]
|
[status-im.ui.screens.chat.state :as view.state]
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[status-im.utils.gfycat.core :as gfycat]
|
[status-im.utils.gfycat.core :as gfycat]
|
||||||
[status-im.utils.platform :as platform]
|
[status-im.utils.platform :as platform]
|
||||||
[status-im.utils.types :as types]
|
[status-im.utils.types :as types]
|
||||||
[taoensso.timbre :as log]))
|
[status-im2.contexts.chat.messages.message.delete-message.events :as delete-message]
|
||||||
|
[taoensso.timbre :as log]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(defn- message-loaded?
|
(defn- message-loaded?
|
||||||
[db chat-id message-id]
|
[db chat-id message-id]
|
||||||
@@ -25,7 +25,8 @@
|
|||||||
[db chat-id clock-value]
|
[db chat-id clock-value]
|
||||||
(>= (get-in db [:chats chat-id :deleted-at-clock-value]) clock-value))
|
(>= (get-in db [:chats chat-id :deleted-at-clock-value]) clock-value))
|
||||||
|
|
||||||
(defn add-timeline-message [acc chat-id message-id message]
|
(defn add-timeline-message
|
||||||
|
[acc chat-id message-id message]
|
||||||
(-> acc
|
(-> acc
|
||||||
(update-in [:db :messages chat-id] assoc message-id message)
|
(update-in [:db :messages chat-id] assoc message-id message)
|
||||||
(update-in [:db :message-lists chat-id] message-list/add message)))
|
(update-in [:db :message-lists chat-id] message-list/add message)))
|
||||||
@@ -36,14 +37,16 @@
|
|||||||
;; TODO this is too expensive, probably we could mark message somehow and just hide it in the UI
|
;; TODO this is too expensive, probably we could mark message somehow and just hide it in the UI
|
||||||
(message-list/rebuild-message-list {:db (update-in db [:messages chat-id] dissoc message-id)} chat-id))
|
(message-list/rebuild-message-list {:db (update-in db [:messages chat-id] dissoc message-id)} chat-id))
|
||||||
|
|
||||||
(fx/defn add-senders-to-chat-users
|
(rf/defn add-senders-to-chat-users
|
||||||
{:events [:chat/add-senders-to-chat-users]}
|
{:events [:chat/add-senders-to-chat-users]}
|
||||||
[{:keys [db]} messages]
|
[{:keys [db]} messages]
|
||||||
(reduce (fn [acc {:keys [chat-id alias name identicon from]}]
|
(reduce (fn [acc {:keys [chat-id alias name identicon from]}]
|
||||||
(let [alias (if (string/blank? alias)
|
(let [alias (if (string/blank? alias)
|
||||||
(gfycat/generate-gfy from)
|
(gfycat/generate-gfy from)
|
||||||
alias)]
|
alias)]
|
||||||
(update-in acc [:db :chats chat-id :users] assoc
|
(update-in acc
|
||||||
|
[:db :chats chat-id :users]
|
||||||
|
assoc
|
||||||
from
|
from
|
||||||
(mentions/add-searchable-phrases
|
(mentions/add-searchable-phrases
|
||||||
{:alias alias
|
{:alias alias
|
||||||
@@ -54,7 +57,8 @@
|
|||||||
{:db db}
|
{:db db}
|
||||||
messages))
|
messages))
|
||||||
|
|
||||||
(defn timeline-message? [db chat-id]
|
(defn timeline-message?
|
||||||
|
[db chat-id]
|
||||||
(and
|
(and
|
||||||
(get-in db [:pagination-info constants/timeline-chat-id :messages-initialized?])
|
(get-in db [:pagination-info constants/timeline-chat-id :messages-initialized?])
|
||||||
(or
|
(or
|
||||||
@@ -62,11 +66,13 @@
|
|||||||
(when-let [pub-key (get-in db [:chats chat-id :profile-public-key])]
|
(when-let [pub-key (get-in db [:chats chat-id :profile-public-key])]
|
||||||
(get-in db [:contacts/contacts pub-key :added])))))
|
(get-in db [:contacts/contacts pub-key :added])))))
|
||||||
|
|
||||||
(defn get-timeline-message [db chat-id message-js]
|
(defn get-timeline-message
|
||||||
|
[db chat-id message-js]
|
||||||
(when (timeline-message? db chat-id)
|
(when (timeline-message? db chat-id)
|
||||||
(data-store.messages/<-rpc (types/js->clj message-js))))
|
(data-store.messages/<-rpc (types/js->clj message-js))))
|
||||||
|
|
||||||
(defn add-message [{:keys [db] :as acc} message-js chat-id message-id cursor-clock-value]
|
(defn add-message
|
||||||
|
[{:keys [db] :as acc} message-js chat-id message-id cursor-clock-value]
|
||||||
(let [{:keys [replace from clock-value] :as message}
|
(let [{:keys [replace from clock-value] :as message}
|
||||||
(data-store.messages/<-rpc (types/js->clj message-js))]
|
(data-store.messages/<-rpc (types/js->clj message-js))]
|
||||||
(if (message-loaded? db chat-id message-id)
|
(if (message-loaded? db chat-id message-id)
|
||||||
@@ -82,8 +88,9 @@
|
|||||||
(update-in [:db :message-lists chat-id] message-list/add message)
|
(update-in [:db :message-lists chat-id] message-list/add message)
|
||||||
|
|
||||||
(or (not cursor-clock-value) (< clock-value cursor-clock-value))
|
(or (not cursor-clock-value) (< clock-value cursor-clock-value))
|
||||||
(update-in [:db :pagination-info chat-id] assoc
|
(update-in [:db :pagination-info chat-id]
|
||||||
:cursor (chat.loading/clock-value->cursor clock-value)
|
assoc
|
||||||
|
:cursor (chat.loading/clock-value->cursor clock-value)
|
||||||
:cursor-clock-value clock-value)
|
:cursor-clock-value clock-value)
|
||||||
|
|
||||||
;;conj sender for add-sender-to-chat-users
|
;;conj sender for add-sender-to-chat-users
|
||||||
@@ -94,11 +101,12 @@
|
|||||||
;;TODO this is expensive
|
;;TODO this is expensive
|
||||||
(hide-message chat-id replace)))))
|
(hide-message chat-id replace)))))
|
||||||
|
|
||||||
(defn reduce-js-messages [{:keys [db] :as acc} ^js message-js]
|
(defn reduce-js-messages
|
||||||
(let [chat-id (.-localChatId message-js)
|
[{:keys [db] :as acc} ^js message-js]
|
||||||
clock-value (.-clock message-js)
|
(let [chat-id (.-localChatId message-js)
|
||||||
message-id (.-id message-js)
|
clock-value (.-clock message-js)
|
||||||
current-chat-id (:current-chat-id db)
|
message-id (.-id message-js)
|
||||||
|
current-chat-id (:current-chat-id db)
|
||||||
cursor-clock-value (get-in db [:pagination-info current-chat-id :cursor-clock-value])]
|
cursor-clock-value (get-in db [:pagination-info current-chat-id :cursor-clock-value])]
|
||||||
;;ignore not opened chats and earlier clock
|
;;ignore not opened chats and earlier clock
|
||||||
(if (and (get-in db [:pagination-info chat-id :messages-initialized?])
|
(if (and (get-in db [:pagination-info chat-id :messages-initialized?])
|
||||||
@@ -110,26 +118,30 @@
|
|||||||
(add-message acc message-js chat-id message-id cursor-clock-value)
|
(add-message acc message-js chat-id message-id cursor-clock-value)
|
||||||
;; Not in the current view, set all-loaded to false
|
;; Not in the current view, set all-loaded to false
|
||||||
;; and offload to db and update cursor if necessary
|
;; and offload to db and update cursor if necessary
|
||||||
;;TODO if we'll offload messages , it will conflict with end reached, so probably if we reached the end of visible area,
|
;;TODO if we'll offload messages , it will conflict with end reached, so probably if we reached
|
||||||
;; we need to drop other messages with (< clock-value cursor-clock-value) from response-js so we don't update
|
;;the end of visible area,
|
||||||
|
;; we need to drop other messages with (< clock-value cursor-clock-value) from response-js so we
|
||||||
|
;; don't update
|
||||||
;; :cursor-clock-value because it will be changed when we loadMore message
|
;; :cursor-clock-value because it will be changed when we loadMore message
|
||||||
{:db (cond-> (assoc-in db [:pagination-info chat-id :all-loaded?] false)
|
{:db (cond-> (assoc-in db [:pagination-info chat-id :all-loaded?] false)
|
||||||
(> clock-value cursor-clock-value)
|
(> clock-value cursor-clock-value)
|
||||||
;;TODO cut older messages from messages-list
|
;;TODO cut older messages from messages-list
|
||||||
(update-in [:pagination-info chat-id] assoc
|
(update-in [:pagination-info chat-id]
|
||||||
:cursor (chat.loading/clock-value->cursor clock-value)
|
assoc
|
||||||
|
:cursor (chat.loading/clock-value->cursor clock-value)
|
||||||
:cursor-clock-value clock-value))})
|
:cursor-clock-value clock-value))})
|
||||||
acc)))
|
acc)))
|
||||||
|
|
||||||
(defn receive-many [{:keys [db]} ^js response-js]
|
(defn receive-many
|
||||||
(let [messages-js ^js (.splice (.-messages response-js) 0 (if platform/low-device? 3 10))
|
[{:keys [db]} ^js response-js]
|
||||||
|
(let [messages-js ^js (.splice (.-messages response-js) 0 (if platform/low-device? 3 10))
|
||||||
{:keys [db senders]}
|
{:keys [db senders]}
|
||||||
(reduce reduce-js-messages
|
(reduce reduce-js-messages
|
||||||
{:db db :chats #{} :senders {} :transactions #{}}
|
{:db db :chats #{} :senders {} :transactions #{}}
|
||||||
messages-js)]
|
messages-js)]
|
||||||
;;we want to render new messages as soon as possible
|
;;we want to render new messages as soon as possible
|
||||||
;;so we dispatch later all other events which can be handled async
|
;;so we dispatch later all other events which can be handled async
|
||||||
{:db db
|
{:db db
|
||||||
:utils/dispatch-later
|
:utils/dispatch-later
|
||||||
(concat [{:ms 20 :dispatch [:process-response response-js]}]
|
(concat [{:ms 20 :dispatch [:process-response response-js]}]
|
||||||
(when (and (:current-chat-id db) (= "active" (:app-state db)))
|
(when (and (:current-chat-id db) (= "active" (:app-state db)))
|
||||||
@@ -137,7 +149,8 @@
|
|||||||
(when (seq senders)
|
(when (seq senders)
|
||||||
[{:ms 100 :dispatch [:chat/add-senders-to-chat-users (vals senders)]}]))}))
|
[{:ms 100 :dispatch [:chat/add-senders-to-chat-users (vals senders)]}]))}))
|
||||||
|
|
||||||
(defn reduce-js-statuses [db ^js message-js]
|
(defn reduce-js-statuses
|
||||||
|
[db ^js message-js]
|
||||||
(let [chat-id (.-localChatId message-js)
|
(let [chat-id (.-localChatId message-js)
|
||||||
profile-initialized (get-in db [:pagination-info chat-id :messages-initialized?])
|
profile-initialized (get-in db [:pagination-info chat-id :messages-initialized?])
|
||||||
timeline-message (timeline-message? db chat-id)
|
timeline-message (timeline-message? db chat-id)
|
||||||
@@ -155,60 +168,66 @@
|
|||||||
(update-in [:message-lists constants/timeline-chat-id] message-list/add message)))
|
(update-in [:message-lists constants/timeline-chat-id] message-list/add message)))
|
||||||
db)))
|
db)))
|
||||||
|
|
||||||
(fx/defn process-statuses
|
(rf/defn process-statuses
|
||||||
{:events [:process-statuses]}
|
{:events [:process-statuses]}
|
||||||
[{:keys [db]} statuses]
|
[{:keys [db]} statuses]
|
||||||
{:db (reduce reduce-js-statuses db statuses)})
|
{:db (reduce reduce-js-statuses db statuses)})
|
||||||
|
|
||||||
(fx/defn update-db-message-status
|
(rf/defn update-db-message-status
|
||||||
[{:keys [db] :as cofx} chat-id message-id status]
|
[{:keys [db] :as cofx} chat-id message-id status]
|
||||||
(when (get-in db [:messages chat-id message-id])
|
(when (get-in db [:messages chat-id message-id])
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc-in db
|
{:db (assoc-in db
|
||||||
[:messages chat-id message-id :outgoing-status]
|
[:messages chat-id message-id :outgoing-status]
|
||||||
status)})))
|
status)})))
|
||||||
|
|
||||||
(fx/defn update-message-status
|
(rf/defn update-message-status
|
||||||
[{:keys [db] :as cofx} chat-id message-id status]
|
[{:keys [db] :as cofx} chat-id message-id status]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(update-db-message-status chat-id message-id status)))
|
(update-db-message-status chat-id message-id status)))
|
||||||
|
|
||||||
(fx/defn resend-message
|
(rf/defn resend-message
|
||||||
[{:keys [db] :as cofx} chat-id message-id]
|
[{:keys [db] :as cofx} chat-id message-id]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{::json-rpc/call [{:method "wakuext_reSendChatMessage"
|
{::json-rpc/call [{:method "wakuext_reSendChatMessage"
|
||||||
:params [message-id]
|
:params [message-id]
|
||||||
:on-success #(log/debug "re-sent message successfully")
|
:on-success #(log/debug "re-sent message successfully")
|
||||||
:on-error #(log/error "failed to re-send message" %)}]}
|
:on-error #(log/error "failed to re-send message" %)}]}
|
||||||
(update-message-status chat-id message-id :sending)))
|
(update-message-status chat-id message-id :sending)))
|
||||||
|
|
||||||
(fx/defn send-message
|
(rf/defn send-message
|
||||||
[cofx message]
|
[cofx message]
|
||||||
(protocol/send-chat-messages cofx [message]))
|
(protocol/send-chat-messages cofx [message]))
|
||||||
|
|
||||||
(fx/defn send-messages
|
(rf/defn send-messages
|
||||||
[cofx messages]
|
[cofx messages]
|
||||||
(protocol/send-chat-messages cofx messages))
|
(protocol/send-chat-messages cofx messages))
|
||||||
|
|
||||||
(fx/defn handle-removed-messages
|
(rf/defn handle-removed-messages
|
||||||
{:events [::handle-removed-messages]}
|
{:events [::handle-removed-messages]}
|
||||||
[{:keys [db] :as cofx} removed-messages]
|
[{:keys [db] :as cofx} removed-messages]
|
||||||
(let [mark-as-deleted-fx (->> removed-messages
|
(let [mark-as-deleted-fx (->> removed-messages
|
||||||
(map #(assoc % :message-id (:messageId %)))
|
(map #(assoc % :message-id (:messageId %)))
|
||||||
(group-by :chatId)
|
(group-by :chatId)
|
||||||
(mapv (fn [[chat-id messages]] (delete-message/delete-messages-localy messages chat-id))))
|
(mapv (fn [[chat-id messages]]
|
||||||
mark-as-seen-fx (mapv (fn [removed-message]
|
(delete-message/delete-messages-localy messages chat-id))))
|
||||||
(let [chat-id (:chatId removed-message)
|
mark-as-seen-fx (mapv
|
||||||
message-id (:messageId removed-message)]
|
(fn [removed-message]
|
||||||
(data-store.messages/mark-messages-seen chat-id
|
(let [chat-id (:chatId removed-message)
|
||||||
[message-id]
|
message-id (:messageId removed-message)]
|
||||||
#(re-frame/dispatch [:chat/decrease-unviewed-count chat-id %3]))))
|
(data-store.messages/mark-messages-seen chat-id
|
||||||
removed-messages)
|
[message-id]
|
||||||
|
#(re-frame/dispatch
|
||||||
|
[:chat/decrease-unviewed-count
|
||||||
|
chat-id %3]))))
|
||||||
|
removed-messages)
|
||||||
remove-messages-fx (fn [{:keys [db]}]
|
remove-messages-fx (fn [{:keys [db]}]
|
||||||
{:dispatch [:activity-center.notifications/fetch-unread-count]})]
|
{:dispatch [:activity-center.notifications/fetch-unread-count]})]
|
||||||
(apply fx/merge cofx (-> mark-as-deleted-fx
|
(apply rf/merge
|
||||||
(concat mark-as-seen-fx)
|
cofx
|
||||||
(conj remove-messages-fx)))))
|
(-> mark-as-deleted-fx
|
||||||
|
(concat mark-as-seen-fx)
|
||||||
|
(conj remove-messages-fx)))))
|
||||||
|
|
||||||
(comment
|
(comment
|
||||||
(handle-removed-messages
|
(handle-removed-messages
|
||||||
@@ -218,15 +237,20 @@
|
|||||||
:m4 {:chat-id :c2 :message-id :m4}}}}}
|
:m4 {:chat-id :c2 :message-id :m4}}}}}
|
||||||
[:m1 :m3]))
|
[:m1 :m3]))
|
||||||
|
|
||||||
(defn remove-cleared-message [messages cleared-at]
|
(defn remove-cleared-message
|
||||||
(into {} (remove #(let [message-clock (:clock-value (second %))]
|
[messages cleared-at]
|
||||||
(<= message-clock cleared-at))
|
(into {}
|
||||||
messages)))
|
(remove #(let [message-clock (:clock-value (second %))]
|
||||||
|
(<= message-clock cleared-at))
|
||||||
|
messages)))
|
||||||
|
|
||||||
(fx/defn handle-cleared-histories-messages
|
(rf/defn handle-cleared-histories-messages
|
||||||
{:events [::handle-cleared-hisotories-messages]}
|
{:events [::handle-cleared-hisotories-messages]}
|
||||||
[{:keys [db]} cleared-histories]
|
[{:keys [db]} cleared-histories]
|
||||||
{:db (reduce (fn [acc current]
|
{:db (reduce (fn [acc current]
|
||||||
(update-in acc [:messages (:chatId current)] remove-cleared-message (:clearedAt current)))
|
(update-in acc
|
||||||
|
[:messages (:chatId current)]
|
||||||
|
remove-cleared-message
|
||||||
|
(:clearedAt current)))
|
||||||
db
|
db
|
||||||
cleared-histories)})
|
cleared-histories)})
|
||||||
|
|||||||
@@ -2,22 +2,25 @@
|
|||||||
(:require ["functional-red-black-tree" :as rb-tree]
|
(:require ["functional-red-black-tree" :as rb-tree]
|
||||||
[status-im.constants :as constants]
|
[status-im.constants :as constants]
|
||||||
[status-im.utils.datetime :as time]
|
[status-im.utils.datetime :as time]
|
||||||
[status-im.utils.fx :as fx]))
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(defn- add-datemark [{:keys [whisper-timestamp] :as msg}]
|
(defn- add-datemark
|
||||||
|
[{:keys [whisper-timestamp] :as msg}]
|
||||||
;;TODO this is slow
|
;;TODO this is slow
|
||||||
(assoc msg :datemark (time/day-relative whisper-timestamp)))
|
(assoc msg :datemark (time/day-relative whisper-timestamp)))
|
||||||
|
|
||||||
(defn- add-timestamp [{:keys [whisper-timestamp] :as msg}]
|
(defn- add-timestamp
|
||||||
|
[{:keys [whisper-timestamp] :as msg}]
|
||||||
(assoc msg :timestamp-str (time/timestamp->time whisper-timestamp)))
|
(assoc msg :timestamp-str (time/timestamp->time whisper-timestamp)))
|
||||||
|
|
||||||
(defn prepare-message [{:keys [message-id
|
(defn prepare-message
|
||||||
clock-value
|
[{:keys [message-id
|
||||||
message-type
|
clock-value
|
||||||
from
|
message-type
|
||||||
outgoing
|
from
|
||||||
whisper-timestamp
|
outgoing
|
||||||
deleted-for-me?]}]
|
whisper-timestamp
|
||||||
|
deleted-for-me?]}]
|
||||||
(-> {:whisper-timestamp whisper-timestamp
|
(-> {:whisper-timestamp whisper-timestamp
|
||||||
:from from
|
:from from
|
||||||
:one-to-one? (= constants/message-type-one-to-one message-type)
|
:one-to-one? (= constants/message-type-one-to-one message-type)
|
||||||
@@ -69,7 +72,8 @@
|
|||||||
the most recent message, similarly :first-in-group? is the most recent message
|
the most recent message, similarly :first-in-group? is the most recent message
|
||||||
in a group."
|
in a group."
|
||||||
[{:keys [system-message?
|
[{:keys [system-message?
|
||||||
one-to-one? outgoing] :as current-message}
|
one-to-one? outgoing]
|
||||||
|
:as current-message}
|
||||||
{:keys [outgoing-seen?] :as previous-message}
|
{:keys [outgoing-seen?] :as previous-message}
|
||||||
next-message]
|
next-message]
|
||||||
(let [last-in-group? (or (nil? next-message)
|
(let [last-in-group? (or (nil? next-message)
|
||||||
@@ -87,7 +91,7 @@
|
|||||||
(not system-message?)
|
(not system-message?)
|
||||||
(not outgoing)
|
(not outgoing)
|
||||||
(not one-to-one?))
|
(not one-to-one?))
|
||||||
:display-photo? (display-photo? current-message))))
|
:display-photo? (display-photo? current-message))))
|
||||||
|
|
||||||
(defn update-next-message
|
(defn update-next-message
|
||||||
"Update next message in the list, we set :first? to false, and check if it
|
"Update next message in the list, we set :first? to false, and check if it
|
||||||
@@ -95,26 +99,28 @@
|
|||||||
[current-message next-message]
|
[current-message next-message]
|
||||||
(assoc
|
(assoc
|
||||||
next-message
|
next-message
|
||||||
:first? false
|
:first? false
|
||||||
:first-outgoing? (and
|
:first-outgoing? (and
|
||||||
(not (:first-outgoing? current-message))
|
(not (:first-outgoing? current-message))
|
||||||
(:first-outgoing? next-message))
|
(:first-outgoing? next-message))
|
||||||
:outgoing-seen? (:outgoing-seen? current-message)
|
:outgoing-seen? (:outgoing-seen? current-message)
|
||||||
:first-in-group?
|
:first-in-group?
|
||||||
(not (same-group? current-message next-message))))
|
(not (same-group? current-message next-message))))
|
||||||
|
|
||||||
(defn update-previous-message
|
(defn update-previous-message
|
||||||
"If this is a new group, we mark the previous as the last one in the group"
|
"If this is a new group, we mark the previous as the last one in the group"
|
||||||
[current-message {:keys [one-to-one?
|
[current-message
|
||||||
system-message?
|
{:keys [one-to-one?
|
||||||
outgoing] :as previous-message}]
|
system-message?
|
||||||
|
outgoing]
|
||||||
|
:as previous-message}]
|
||||||
(let [last-in-group? (not (same-group? current-message previous-message))]
|
(let [last-in-group? (not (same-group? current-message previous-message))]
|
||||||
(assoc previous-message
|
(assoc previous-message
|
||||||
:display-username? (and last-in-group?
|
:display-username? (and last-in-group?
|
||||||
(not system-message?)
|
(not system-message?)
|
||||||
(not outgoing)
|
(not outgoing)
|
||||||
(not one-to-one?))
|
(not one-to-one?))
|
||||||
:last-in-group? last-in-group?)))
|
:last-in-group? last-in-group?)))
|
||||||
|
|
||||||
(defn get-prev-element
|
(defn get-prev-element
|
||||||
"Get previous item in the iterator, and wind it back to the initial state"
|
"Get previous item in the iterator, and wind it back to the initial state"
|
||||||
@@ -135,11 +141,11 @@
|
|||||||
(defn update-message
|
(defn update-message
|
||||||
"Update the message and siblings with positional info"
|
"Update the message and siblings with positional info"
|
||||||
[^js tree message]
|
[^js tree message]
|
||||||
(let [^js iter (.find tree message)
|
(let [^js iter (.find tree message)
|
||||||
^js previous-message (when (.-hasPrev iter)
|
^js previous-message (when (.-hasPrev iter)
|
||||||
(get-prev-element iter))
|
(get-prev-element iter))
|
||||||
^js next-message (when (.-hasNext iter)
|
^js next-message (when (.-hasNext iter)
|
||||||
(get-next-element iter))
|
(get-next-element iter))
|
||||||
^js message-with-pos-data (add-group-info message previous-message next-message)]
|
^js message-with-pos-data (add-group-info message previous-message next-message)]
|
||||||
(cond-> (.update iter message-with-pos-data)
|
(cond-> (.update iter message-with-pos-data)
|
||||||
next-message
|
next-message
|
||||||
@@ -157,9 +163,9 @@
|
|||||||
(let [iter (.find tree prepared-message)]
|
(let [iter (.find tree prepared-message)]
|
||||||
(if (not iter)
|
(if (not iter)
|
||||||
tree
|
tree
|
||||||
(let [^js new-tree (.remove iter)
|
(let [^js new-tree (.remove iter)
|
||||||
^js next-message (when (.-hasNext iter)
|
^js next-message (when (.-hasNext iter)
|
||||||
(get-next-element iter))]
|
(get-next-element iter))]
|
||||||
(if (not next-message)
|
(if (not next-message)
|
||||||
new-tree
|
new-tree
|
||||||
(update-message new-tree next-message))))))
|
(update-message new-tree next-message))))))
|
||||||
@@ -173,21 +179,26 @@
|
|||||||
(let [^js tree (.insert old-message-list prepared-message prepared-message)]
|
(let [^js tree (.insert old-message-list prepared-message prepared-message)]
|
||||||
(update-message tree prepared-message)))
|
(update-message tree prepared-message)))
|
||||||
|
|
||||||
(defn add [message-list message]
|
(defn add
|
||||||
|
[message-list message]
|
||||||
(insert-message (or message-list (rb-tree compare-fn)) (prepare-message message)))
|
(insert-message (or message-list (rb-tree compare-fn)) (prepare-message message)))
|
||||||
|
|
||||||
(defn add-many [message-list messages]
|
(defn add-many
|
||||||
|
[message-list messages]
|
||||||
(reduce add
|
(reduce add
|
||||||
message-list
|
message-list
|
||||||
messages))
|
messages))
|
||||||
|
|
||||||
(defn ->seq [^js message-list]
|
(defn ->seq
|
||||||
|
[^js message-list]
|
||||||
(if message-list
|
(if message-list
|
||||||
(array-seq (.-values message-list))
|
(array-seq (.-values message-list))
|
||||||
[]))
|
[]))
|
||||||
|
|
||||||
;; NOTE(performance): this is too expensive, probably we could mark message somehow and just hide it in the UI
|
;; NOTE(performance): this is too expensive, probably we could mark message somehow and just hide it in
|
||||||
(fx/defn rebuild-message-list
|
;; the UI
|
||||||
|
(rf/defn rebuild-message-list
|
||||||
[{:keys [db]} chat-id]
|
[{:keys [db]} chat-id]
|
||||||
{:db (assoc-in db [:message-lists chat-id]
|
{:db (assoc-in db
|
||||||
(add-many nil (vals (get-in db [:messages chat-id]))))})
|
[:message-lists chat-id]
|
||||||
|
(add-many nil (vals (get-in db [:messages chat-id]))))})
|
||||||
|
|||||||
@@ -1,28 +1,36 @@
|
|||||||
(ns status-im.chat.models.reactions
|
(ns status-im.chat.models.reactions
|
||||||
(:require [status-im.constants :as constants]
|
(:require [re-frame.core :as re-frame]
|
||||||
[re-frame.core :as re-frame]
|
[status-im.constants :as constants]
|
||||||
[status-im.utils.fx :as fx]
|
[status-im.data-store.reactions :as data-store.reactions]
|
||||||
[taoensso.timbre :as log]
|
|
||||||
[status-im.transport.message.protocol :as message.protocol]
|
[status-im.transport.message.protocol :as message.protocol]
|
||||||
[status-im.data-store.reactions :as data-store.reactions]))
|
[taoensso.timbre :as log]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(defn update-reaction [acc retracted chat-id message-id emoji-id emoji-reaction-id reaction]
|
(defn update-reaction
|
||||||
|
[acc retracted chat-id message-id emoji-id emoji-reaction-id reaction]
|
||||||
;; NOTE(Ferossgp): For a better performance, better to not keep in db all retracted reactions
|
;; NOTE(Ferossgp): For a better performance, better to not keep in db all retracted reactions
|
||||||
;; retraction will always come after the reaction so there shouldn't be a conflict
|
;; retraction will always come after the reaction so there shouldn't be a conflict
|
||||||
(if retracted
|
(if retracted
|
||||||
(update-in acc [chat-id message-id emoji-id] dissoc emoji-reaction-id)
|
(update-in acc [chat-id message-id emoji-id] dissoc emoji-reaction-id)
|
||||||
(assoc-in acc [chat-id message-id emoji-id emoji-reaction-id] reaction)))
|
(assoc-in acc [chat-id message-id emoji-id emoji-reaction-id] reaction)))
|
||||||
|
|
||||||
(defn process-reactions [chats]
|
(defn process-reactions
|
||||||
|
[chats]
|
||||||
(fn [reactions new-reactions]
|
(fn [reactions new-reactions]
|
||||||
;; TODO(Ferossgp): handling own reaction in subscription could be expensive,
|
;; TODO(Ferossgp): handling own reaction in subscription could be expensive,
|
||||||
;; for better performance we can here separate own reaction into 2 maps
|
;; for better performance we can here separate own reaction into 2 maps
|
||||||
(reduce
|
(reduce
|
||||||
(fn [acc {:keys [chat-id message-id emoji-id emoji-reaction-id retracted]
|
(fn [acc
|
||||||
:as reaction}]
|
{:keys [chat-id message-id emoji-id emoji-reaction-id retracted]
|
||||||
|
:as reaction}]
|
||||||
(cond-> (update-reaction acc retracted chat-id message-id emoji-id emoji-reaction-id reaction)
|
(cond-> (update-reaction acc retracted chat-id message-id emoji-id emoji-reaction-id reaction)
|
||||||
(get-in chats [chat-id :profile-public-key])
|
(get-in chats [chat-id :profile-public-key])
|
||||||
(update-reaction retracted constants/timeline-chat-id message-id emoji-id emoji-reaction-id reaction)))
|
(update-reaction retracted
|
||||||
|
constants/timeline-chat-id
|
||||||
|
message-id
|
||||||
|
emoji-id
|
||||||
|
emoji-reaction-id
|
||||||
|
reaction)))
|
||||||
reactions
|
reactions
|
||||||
new-reactions)))
|
new-reactions)))
|
||||||
|
|
||||||
@@ -32,12 +40,12 @@
|
|||||||
(get-in db [:chats chat-id])]
|
(get-in db [:chats chat-id])]
|
||||||
(>= deleted-at-clock-value clock-value)))
|
(>= deleted-at-clock-value clock-value)))
|
||||||
|
|
||||||
(fx/defn receive-signal
|
(rf/defn receive-signal
|
||||||
[{:keys [db] :as cofx} reactions]
|
[{:keys [db] :as cofx} reactions]
|
||||||
(let [reactions (filter (partial earlier-than-deleted-at? cofx) reactions)]
|
(let [reactions (filter (partial earlier-than-deleted-at? cofx) reactions)]
|
||||||
{:db (update db :reactions (process-reactions (:chats db)) reactions)}))
|
{:db (update db :reactions (process-reactions (:chats db)) reactions)}))
|
||||||
|
|
||||||
(fx/defn load-more-reactions
|
(rf/defn load-more-reactions
|
||||||
{:events [:load-more-reactions]}
|
{:events [:load-more-reactions]}
|
||||||
[{:keys [db]} cursor chat-id]
|
[{:keys [db]} cursor chat-id]
|
||||||
(when-let [session-id (get-in db [:pagination-info chat-id :messages-initialized?])]
|
(when-let [session-id (get-in db [:pagination-info chat-id :messages-initialized?])]
|
||||||
@@ -48,7 +56,7 @@
|
|||||||
#(re-frame/dispatch [::reactions-loaded chat-id session-id %])
|
#(re-frame/dispatch [::reactions-loaded chat-id session-id %])
|
||||||
#(log/error "failed loading reactions" chat-id %))))
|
#(log/error "failed loading reactions" chat-id %))))
|
||||||
|
|
||||||
(fx/defn reactions-loaded
|
(rf/defn reactions-loaded
|
||||||
{:events [::reactions-loaded]}
|
{:events [::reactions-loaded]}
|
||||||
[{db :db}
|
[{db :db}
|
||||||
chat-id
|
chat-id
|
||||||
@@ -64,33 +72,36 @@
|
|||||||
;; Send reactions
|
;; Send reactions
|
||||||
|
|
||||||
|
|
||||||
(fx/defn send-emoji-reaction
|
(rf/defn send-emoji-reaction
|
||||||
{:events [::send-emoji-reaction]}
|
{:events [::send-emoji-reaction]}
|
||||||
[{{:keys [current-chat-id]} :db :as cofx} reaction]
|
[{{:keys [current-chat-id]} :db :as cofx} reaction]
|
||||||
(message.protocol/send-reaction cofx
|
(message.protocol/send-reaction cofx
|
||||||
(update reaction :chat-id #(or % current-chat-id))))
|
(update reaction :chat-id #(or % current-chat-id))))
|
||||||
|
|
||||||
(fx/defn send-retract-emoji-reaction
|
(rf/defn send-retract-emoji-reaction
|
||||||
{:events [::send-emoji-reaction-retraction]}
|
{:events [::send-emoji-reaction-retraction]}
|
||||||
[{{:keys [current-chat-id]} :db :as cofx} reaction]
|
[{{:keys [current-chat-id]} :db :as cofx} reaction]
|
||||||
(message.protocol/send-retract-reaction cofx
|
(message.protocol/send-retract-reaction cofx
|
||||||
(update reaction :chat-id #(or % current-chat-id))))
|
(update reaction :chat-id #(or % current-chat-id))))
|
||||||
|
|
||||||
(fx/defn receive-one
|
(rf/defn receive-one
|
||||||
{:events [::receive-one]}
|
{:events [::receive-one]}
|
||||||
[{:keys [db]} reaction]
|
[{:keys [db]} reaction]
|
||||||
{:db (update db :reactions (process-reactions (:chats db)) [reaction])})
|
{:db (update db :reactions (process-reactions (:chats db)) [reaction])})
|
||||||
|
|
||||||
(defn message-reactions [current-public-key reactions]
|
(defn message-reactions
|
||||||
|
[current-public-key reactions]
|
||||||
(reduce
|
(reduce
|
||||||
(fn [acc [emoji-id reactions]]
|
(fn [acc [emoji-id reactions]]
|
||||||
(if (pos? (count reactions))
|
(if (pos? (count reactions))
|
||||||
(let [own (first (filter (fn [[_ {:keys [from]}]]
|
(let [own (first (filter (fn [[_ {:keys [from]}]]
|
||||||
(= from current-public-key)) reactions))]
|
(= from current-public-key))
|
||||||
(conj acc {:emoji-id emoji-id
|
reactions))]
|
||||||
:own (boolean (seq own))
|
(conj acc
|
||||||
:emoji-reaction-id (:emoji-reaction-id (second own))
|
{:emoji-id emoji-id
|
||||||
:quantity (count reactions)}))
|
:own (boolean (seq own))
|
||||||
|
:emoji-reaction-id (:emoji-reaction-id (second own))
|
||||||
|
:quantity (count reactions)}))
|
||||||
acc))
|
acc))
|
||||||
[]
|
[]
|
||||||
reactions))
|
reactions))
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
;;this ns is needed because of cycled deps
|
;;this ns is needed because of cycled deps
|
||||||
(ns status-im.chat.models.transport
|
(ns status-im.chat.models.transport
|
||||||
(:require [status-im.utils.fx :as fx]
|
(:require [status-im.chat.models.message :as chat.message]
|
||||||
[status-im.transport.message.core :as transport.message]
|
[status-im.transport.message.core :as transport.message]
|
||||||
[status-im.chat.models.message :as chat.message]))
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(fx/defn chat-ui-resend-message
|
(rf/defn chat-ui-resend-message
|
||||||
{:events [:chat.ui/resend-message]}
|
{:events [:chat.ui/resend-message]}
|
||||||
[{:keys [db] :as cofx} chat-id message-id]
|
[{:keys [db] :as cofx} chat-id message-id]
|
||||||
(let [message (get-in db [:messages chat-id message-id])]
|
(let [message (get-in db [:messages chat-id message-id])]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
(transport.message/set-message-envelope-hash chat-id message-id (:message-type message))
|
(transport.message/set-message-envelope-hash chat-id message-id (:message-type message))
|
||||||
(chat.message/resend-message chat-id message-id))))
|
(chat.message/resend-message chat-id message-id))))
|
||||||
|
|||||||
@@ -2,44 +2,44 @@
|
|||||||
(:require [re-frame.core :as re-frame]
|
(:require [re-frame.core :as re-frame]
|
||||||
[status-im.ethereum.core :as ethereum]
|
[status-im.ethereum.core :as ethereum]
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
[status-im.utils.fx :as fx]))
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(fx/defn handle-prepare-accept-request-address-for-transaction
|
(rf/defn handle-prepare-accept-request-address-for-transaction
|
||||||
{:events [::prepare-accept-request-address-for-transaction]}
|
{:events [::prepare-accept-request-address-for-transaction]}
|
||||||
[{:keys [db]} message]
|
[{:keys [db]} message]
|
||||||
{:db (assoc db
|
{:db (assoc db
|
||||||
:commands/select-account
|
:commands/select-account
|
||||||
{:message message
|
{:message message
|
||||||
:from (ethereum/get-default-account (:multiaccount/accounts db))})
|
:from (ethereum/get-default-account (:multiaccount/accounts db))})
|
||||||
:show-select-acc-sheet nil})
|
:show-select-acc-sheet nil})
|
||||||
|
|
||||||
(fx/defn set-selected-account
|
(rf/defn set-selected-account
|
||||||
{:events [::set-selected-account]}
|
{:events [::set-selected-account]}
|
||||||
[{:keys [db]} _ account]
|
[{:keys [db]} _ account]
|
||||||
{:db (-> (assoc-in db [:commands/select-account :from] account)
|
{:db (-> (assoc-in db [:commands/select-account :from] account)
|
||||||
(assoc :bottom-sheet/show? false))})
|
(assoc :bottom-sheet/show? false))})
|
||||||
|
|
||||||
(fx/defn handle-accept-request-address-for-transaction
|
(rf/defn handle-accept-request-address-for-transaction
|
||||||
{:events [::accept-request-address-for-transaction]}
|
{:events [::accept-request-address-for-transaction]}
|
||||||
[{:keys [db]} message-id address]
|
[{:keys [db]} message-id address]
|
||||||
{:db (dissoc db :commands/select-account)
|
{:db (dissoc db :commands/select-account)
|
||||||
::json-rpc/call [{:method "wakuext_acceptRequestAddressForTransaction"
|
::json-rpc/call [{:method "wakuext_acceptRequestAddressForTransaction"
|
||||||
:params [message-id address]
|
:params [message-id address]
|
||||||
:js-response true
|
:js-response true
|
||||||
:on-success #(re-frame/dispatch [:transport/message-sent %])}]})
|
:on-success #(re-frame/dispatch [:transport/message-sent %])}]})
|
||||||
|
|
||||||
(fx/defn handle-decline-request-address-for-transaction
|
(rf/defn handle-decline-request-address-for-transaction
|
||||||
{:events [::decline-request-address-for-transaction]}
|
{:events [::decline-request-address-for-transaction]}
|
||||||
[_ message-id]
|
[_ message-id]
|
||||||
{::json-rpc/call [{:method "wakuext_declineRequestAddressForTransaction"
|
{::json-rpc/call [{:method "wakuext_declineRequestAddressForTransaction"
|
||||||
:params [message-id]
|
:params [message-id]
|
||||||
:js-response true
|
:js-response true
|
||||||
:on-success #(re-frame/dispatch [:transport/message-sent %])}]})
|
:on-success #(re-frame/dispatch [:transport/message-sent %])}]})
|
||||||
|
|
||||||
(fx/defn handle-decline-request-transaction
|
(rf/defn handle-decline-request-transaction
|
||||||
{:events [::decline-request-transaction]}
|
{:events [::decline-request-transaction]}
|
||||||
[cofx message-id]
|
[cofx message-id]
|
||||||
{::json-rpc/call [{:method "wakuext_declineRequestTransaction"
|
{::json-rpc/call [{:method "wakuext_declineRequestTransaction"
|
||||||
:params [message-id]
|
:params [message-id]
|
||||||
:js-response true
|
:js-response true
|
||||||
:on-success #(re-frame/dispatch [:transport/message-sent %])}]})
|
:on-success #(re-frame/dispatch [:transport/message-sent %])}]})
|
||||||
|
|||||||
+201
-155
@@ -1,25 +1,24 @@
|
|||||||
(ns status-im.communities.core
|
(ns status-im.communities.core
|
||||||
(:require
|
(:require [clojure.set :as clojure.set]
|
||||||
[re-frame.core :as re-frame]
|
[clojure.string :as string]
|
||||||
[clojure.walk :as walk]
|
[clojure.walk :as walk]
|
||||||
[clojure.string :as string]
|
[quo.design-system.colors :as colors]
|
||||||
[clojure.set :as clojure.set]
|
[re-frame.core :as re-frame]
|
||||||
[taoensso.timbre :as log]
|
[status-im.async-storage.core :as async-storage]
|
||||||
[status-im.async-storage.core :as async-storage]
|
[status-im.bottom-sheet.core :as bottom-sheet]
|
||||||
[status-im.utils.fx :as fx]
|
[status-im.constants :as constants]
|
||||||
[status-im.constants :as constants]
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
[status-im.bottom-sheet.core :as bottom-sheet]
|
[status-im.ui.components.emoji-thumbnail.styles :as emoji-thumbnail-styles]
|
||||||
[status-im.utils.universal-links.core :as universal-links]
|
[status-im.utils.universal-links.core :as universal-links]
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
[status-im2.contexts.activity-center.events :as activity-center]
|
||||||
[quo.design-system.colors :as colors]
|
[status-im2.navigation.events :as navigation]
|
||||||
[status-im2.navigation.events :as navigation]
|
[taoensso.timbre :as log]
|
||||||
[status-im.utils.handlers :refer [>evt]]
|
[utils.re-frame :as rf]))
|
||||||
[status-im.ui.components.emoji-thumbnail.styles :as emoji-thumbnail-styles]
|
|
||||||
[status-im2.contexts.activity-center.events :as activity-center]))
|
|
||||||
|
|
||||||
(def crop-size 1000)
|
(def crop-size 1000)
|
||||||
|
|
||||||
(defn universal-link [community-id]
|
(defn universal-link
|
||||||
|
[community-id]
|
||||||
(str (:external universal-links/domains)
|
(str (:external universal-links/domains)
|
||||||
"/c/"
|
"/c/"
|
||||||
community-id))
|
community-id))
|
||||||
@@ -28,18 +27,22 @@
|
|||||||
[{:name "Status"
|
[{:name "Status"
|
||||||
:id constants/status-community-id}])
|
:id constants/status-community-id}])
|
||||||
|
|
||||||
(defn <-request-to-join-community-rpc [r]
|
(defn <-request-to-join-community-rpc
|
||||||
(clojure.set/rename-keys r {:communityId :community-id
|
[r]
|
||||||
:publicKey :public-key
|
(clojure.set/rename-keys r
|
||||||
:chatId :chat-id}))
|
{:communityId :community-id
|
||||||
|
:publicKey :public-key
|
||||||
|
:chatId :chat-id}))
|
||||||
|
|
||||||
(defn <-requests-to-join-community-rpc [requests]
|
(defn <-requests-to-join-community-rpc
|
||||||
|
[requests]
|
||||||
(reduce (fn [acc r]
|
(reduce (fn [acc r]
|
||||||
(assoc acc (:id r) (<-request-to-join-community-rpc r)))
|
(assoc acc (:id r) (<-request-to-join-community-rpc r)))
|
||||||
{}
|
{}
|
||||||
requests))
|
requests))
|
||||||
|
|
||||||
(defn <-chats-rpc [chats]
|
(defn <-chats-rpc
|
||||||
|
[chats]
|
||||||
(reduce-kv (fn [acc k v]
|
(reduce-kv (fn [acc k v]
|
||||||
(assoc acc
|
(assoc acc
|
||||||
(name k)
|
(name k)
|
||||||
@@ -50,7 +53,8 @@
|
|||||||
{}
|
{}
|
||||||
chats))
|
chats))
|
||||||
|
|
||||||
(defn <-categories-rpc [categ]
|
(defn <-categories-rpc
|
||||||
|
[categ]
|
||||||
(reduce-kv (fn [acc k v]
|
(reduce-kv (fn [acc k v]
|
||||||
(assoc acc
|
(assoc acc
|
||||||
(name k)
|
(name k)
|
||||||
@@ -58,7 +62,8 @@
|
|||||||
{}
|
{}
|
||||||
categ))
|
categ))
|
||||||
|
|
||||||
(defn <-rpc [c]
|
(defn <-rpc
|
||||||
|
[c]
|
||||||
(-> c
|
(-> c
|
||||||
(clojure.set/rename-keys {:canRequestAccess :can-request-access?
|
(clojure.set/rename-keys {:canRequestAccess :can-request-access?
|
||||||
:canManageUsers :can-manage-users?
|
:canManageUsers :can-manage-users?
|
||||||
@@ -70,25 +75,28 @@
|
|||||||
(update :chats <-chats-rpc)
|
(update :chats <-chats-rpc)
|
||||||
(update :categories <-categories-rpc)))
|
(update :categories <-categories-rpc)))
|
||||||
|
|
||||||
(defn fetch-community-id-input [{:keys [db]}]
|
(defn fetch-community-id-input
|
||||||
|
[{:keys [db]}]
|
||||||
(:communities/community-id-input db))
|
(:communities/community-id-input db))
|
||||||
|
|
||||||
(fx/defn handle-request-to-join [{:keys [db]} r]
|
(rf/defn handle-request-to-join
|
||||||
|
[{:keys [db]} r]
|
||||||
(let [{:keys [id community-id] :as request} (<-request-to-join-community-rpc r)]
|
(let [{:keys [id community-id] :as request} (<-request-to-join-community-rpc r)]
|
||||||
{:db (assoc-in db [:communities/requests-to-join community-id id] request)}))
|
{:db (assoc-in db [:communities/requests-to-join community-id id] request)}))
|
||||||
|
|
||||||
(fx/defn handle-removed-chats [{:keys [db]} chat-ids]
|
(rf/defn handle-removed-chats
|
||||||
|
[{:keys [db]} chat-ids]
|
||||||
{:db (reduce (fn [db chat-id]
|
{:db (reduce (fn [db chat-id]
|
||||||
(update db :chats dissoc chat-id))
|
(update db :chats dissoc chat-id))
|
||||||
db
|
db
|
||||||
chat-ids)})
|
chat-ids)})
|
||||||
|
|
||||||
(fx/defn handle-community
|
(rf/defn handle-community
|
||||||
[{:keys [db]} {:keys [id] :as community}]
|
[{:keys [db]} {:keys [id] :as community}]
|
||||||
(when id
|
(when id
|
||||||
{:db (assoc-in db [:communities id] (<-rpc community))}))
|
{:db (assoc-in db [:communities id] (<-rpc community))}))
|
||||||
|
|
||||||
(fx/defn handle-communities
|
(rf/defn handle-communities
|
||||||
{:events [::fetched]}
|
{:events [::fetched]}
|
||||||
[{:keys [db]} communities]
|
[{:keys [db]} communities]
|
||||||
{:db (reduce (fn [db {:keys [id] :as community}]
|
{:db (reduce (fn [db {:keys [id] :as community}]
|
||||||
@@ -96,34 +104,36 @@
|
|||||||
db
|
db
|
||||||
communities)})
|
communities)})
|
||||||
|
|
||||||
(fx/defn handle-response [_ response-js]
|
(rf/defn handle-response
|
||||||
|
[_ response-js]
|
||||||
{:dispatch [:sanitize-messages-and-process-response response-js]})
|
{:dispatch [:sanitize-messages-and-process-response response-js]})
|
||||||
|
|
||||||
(fx/defn left
|
(rf/defn left
|
||||||
{:events [::left]}
|
{:events [::left]}
|
||||||
[cofx response-js]
|
[cofx response-js]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(handle-response cofx response-js)
|
(handle-response cofx response-js)
|
||||||
(navigation/pop-to-root-tab :chat-stack)
|
(navigation/pop-to-root-tab :chat-stack)
|
||||||
(activity-center/notifications-fetch-unread-count)))
|
(activity-center/notifications-fetch-unread-count)))
|
||||||
|
|
||||||
(fx/defn joined
|
(rf/defn joined
|
||||||
{:events [::joined ::requested-to-join]}
|
{:events [::joined ::requested-to-join]}
|
||||||
[cofx response-js]
|
[cofx response-js]
|
||||||
(handle-response cofx response-js))
|
(handle-response cofx response-js))
|
||||||
|
|
||||||
(fx/defn export
|
(rf/defn export
|
||||||
{:events [::export-pressed]}
|
{:events [::export-pressed]}
|
||||||
[cofx community-id]
|
[cofx community-id]
|
||||||
{::json-rpc/call [{:method "wakuext_exportCommunity"
|
{::json-rpc/call [{:method "wakuext_exportCommunity"
|
||||||
:params [community-id]
|
:params [community-id]
|
||||||
:on-success #(re-frame/dispatch [:show-popover {:view :export-community
|
:on-success #(re-frame/dispatch [:show-popover
|
||||||
:community-key %}])
|
{:view :export-community
|
||||||
|
:community-key %}])
|
||||||
:on-error #(do
|
:on-error #(do
|
||||||
(log/error "failed to export community" community-id %)
|
(log/error "failed to export community" community-id %)
|
||||||
(re-frame/dispatch [::failed-to-export %]))}]})
|
(re-frame/dispatch [::failed-to-export %]))}]})
|
||||||
|
|
||||||
(fx/defn import-community
|
(rf/defn import-community
|
||||||
{:events [::import]}
|
{:events [::import]}
|
||||||
[cofx community-key]
|
[cofx community-key]
|
||||||
{::json-rpc/call [{:method "wakuext_importCommunity"
|
{::json-rpc/call [{:method "wakuext_importCommunity"
|
||||||
@@ -134,7 +144,7 @@
|
|||||||
(log/error "failed to import community" %)
|
(log/error "failed to import community" %)
|
||||||
(re-frame/dispatch [::failed-to-import %]))}]})
|
(re-frame/dispatch [::failed-to-import %]))}]})
|
||||||
|
|
||||||
(fx/defn join
|
(rf/defn join
|
||||||
{:events [:communities/join]}
|
{:events [:communities/join]}
|
||||||
[cofx community-id]
|
[cofx community-id]
|
||||||
{::json-rpc/call [{:method "wakuext_joinCommunity"
|
{::json-rpc/call [{:method "wakuext_joinCommunity"
|
||||||
@@ -145,7 +155,7 @@
|
|||||||
(log/error "failed to join community" community-id %)
|
(log/error "failed to join community" community-id %)
|
||||||
(re-frame/dispatch [::failed-to-join %]))}]})
|
(re-frame/dispatch [::failed-to-join %]))}]})
|
||||||
|
|
||||||
(fx/defn request-to-join
|
(rf/defn request-to-join
|
||||||
{:events [::request-to-join]}
|
{:events [::request-to-join]}
|
||||||
[cofx community-id]
|
[cofx community-id]
|
||||||
{::json-rpc/call [{:method "wakuext_requestToJoinCommunity"
|
{::json-rpc/call [{:method "wakuext_requestToJoinCommunity"
|
||||||
@@ -156,7 +166,7 @@
|
|||||||
(log/error "failed to request to join community" community-id %)
|
(log/error "failed to request to join community" community-id %)
|
||||||
(re-frame/dispatch [::failed-to-request-to-join %]))}]})
|
(re-frame/dispatch [::failed-to-request-to-join %]))}]})
|
||||||
|
|
||||||
(fx/defn leave
|
(rf/defn leave
|
||||||
{:events [:communities/leave]}
|
{:events [:communities/leave]}
|
||||||
[{:keys [db]} community-id]
|
[{:keys [db]} community-id]
|
||||||
(let [community-chat-ids (map #(str community-id %)
|
(let [community-chat-ids (map #(str community-id %)
|
||||||
@@ -168,10 +178,13 @@
|
|||||||
:js-response true
|
:js-response true
|
||||||
:on-success #(re-frame/dispatch [::left %])
|
:on-success #(re-frame/dispatch [::left %])
|
||||||
:on-error #(do
|
:on-error #(do
|
||||||
(log/error "failed to leave community" community-id %)
|
(log/error "failed to leave community"
|
||||||
|
community-id
|
||||||
|
%)
|
||||||
(re-frame/dispatch [::failed-to-leave %]))}]}))
|
(re-frame/dispatch [::failed-to-leave %]))}]}))
|
||||||
|
|
||||||
(fx/defn fetch [_]
|
(rf/defn fetch
|
||||||
|
[_]
|
||||||
{::json-rpc/call [{:method "wakuext_communities"
|
{::json-rpc/call [{:method "wakuext_communities"
|
||||||
:params []
|
:params []
|
||||||
:on-success #(re-frame/dispatch [::fetched %])
|
:on-success #(re-frame/dispatch [::fetched %])
|
||||||
@@ -179,7 +192,7 @@
|
|||||||
(log/error "failed to fetch communities" %)
|
(log/error "failed to fetch communities" %)
|
||||||
(re-frame/dispatch [::failed-to-fetch %]))}]})
|
(re-frame/dispatch [::failed-to-fetch %]))}]})
|
||||||
|
|
||||||
(fx/defn chat-created
|
(rf/defn chat-created
|
||||||
{:events [::chat-created]}
|
{:events [::chat-created]}
|
||||||
[_ community-id user-pk]
|
[_ community-id user-pk]
|
||||||
{::json-rpc/call [{:method "wakuext_sendChatMessage"
|
{::json-rpc/call [{:method "wakuext_sendChatMessage"
|
||||||
@@ -193,7 +206,7 @@
|
|||||||
:on-error
|
:on-error
|
||||||
#(log/error "failed to send a message" %)}]})
|
#(log/error "failed to send a message" %)}]})
|
||||||
|
|
||||||
(fx/defn invite-users
|
(rf/defn invite-users
|
||||||
{:events [::invite-people-confirmation-pressed]}
|
{:events [::invite-people-confirmation-pressed]}
|
||||||
[cofx user-pk contacts]
|
[cofx user-pk contacts]
|
||||||
(let [community-id (fetch-community-id-input cofx)
|
(let [community-id (fetch-community-id-input cofx)
|
||||||
@@ -209,7 +222,7 @@
|
|||||||
:on-error #(do
|
:on-error #(do
|
||||||
(log/error "failed to invite-user community" %)
|
(log/error "failed to invite-user community" %)
|
||||||
(re-frame/dispatch [::failed-to-invite-people %]))}]})))
|
(re-frame/dispatch [::failed-to-invite-people %]))}]})))
|
||||||
(fx/defn share-community
|
(rf/defn share-community
|
||||||
{:events [::share-community-confirmation-pressed]}
|
{:events [::share-community-confirmation-pressed]}
|
||||||
[cofx user-pk contacts]
|
[cofx user-pk contacts]
|
||||||
(let [community-id (fetch-community-id-input cofx)
|
(let [community-id (fetch-community-id-input cofx)
|
||||||
@@ -226,7 +239,7 @@
|
|||||||
(log/error "failed to invite-user community" %)
|
(log/error "failed to invite-user community" %)
|
||||||
(re-frame/dispatch [::failed-to-share-community %]))}]})))
|
(re-frame/dispatch [::failed-to-share-community %]))}]})))
|
||||||
|
|
||||||
(fx/defn create
|
(rf/defn create
|
||||||
{:events [::create-confirmation-pressed]}
|
{:events [::create-confirmation-pressed]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(let [{:keys [name description membership image]} (get db :communities/create)]
|
(let [{:keys [name description membership image]} (get db :communities/create)]
|
||||||
@@ -248,7 +261,7 @@
|
|||||||
(log/error "failed to create community" %)
|
(log/error "failed to create community" %)
|
||||||
(re-frame/dispatch [::failed-to-create-community %]))}]})))
|
(re-frame/dispatch [::failed-to-create-community %]))}]})))
|
||||||
|
|
||||||
(fx/defn edit
|
(rf/defn edit
|
||||||
{:events [::edit-confirmation-pressed]}
|
{:events [::edit-confirmation-pressed]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(let [{:keys [id name description membership new-image color]} (get db :communities/create)]
|
(let [{:keys [id name description membership new-image color]} (get db :communities/create)]
|
||||||
@@ -268,10 +281,10 @@
|
|||||||
(log/error "failed to edit community" %)
|
(log/error "failed to edit community" %)
|
||||||
(re-frame/dispatch [::failed-to-edit-community %]))}]}))
|
(re-frame/dispatch [::failed-to-edit-community %]))}]}))
|
||||||
|
|
||||||
(fx/defn create-channel
|
(rf/defn create-channel
|
||||||
{:events [::create-channel-confirmation-pressed]}
|
{:events [::create-channel-confirmation-pressed]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [community-id (fetch-community-id-input cofx)
|
(let [community-id (fetch-community-id-input cofx)
|
||||||
{:keys [name description color emoji]} (get db :communities/create-channel)]
|
{:keys [name description color emoji]} (get db :communities/create-channel)]
|
||||||
{::json-rpc/call [{:method "wakuext_createCommunityChat"
|
{::json-rpc/call [{:method "wakuext_createCommunityChat"
|
||||||
:params [community-id
|
:params [community-id
|
||||||
@@ -279,7 +292,8 @@
|
|||||||
:description description
|
:description description
|
||||||
:color color
|
:color color
|
||||||
:emoji emoji}
|
:emoji emoji}
|
||||||
:permissions {:access constants/community-channel-access-no-membership}}]
|
:permissions {:access
|
||||||
|
constants/community-channel-access-no-membership}}]
|
||||||
:js-response true
|
:js-response true
|
||||||
:on-success #(re-frame/dispatch [::community-channel-created %])
|
:on-success #(re-frame/dispatch [::community-channel-created %])
|
||||||
:on-error #(do
|
:on-error #(do
|
||||||
@@ -288,10 +302,11 @@
|
|||||||
|
|
||||||
(def community-chat-id-length 68)
|
(def community-chat-id-length 68)
|
||||||
|
|
||||||
(defn to-community-chat-id [chat-id]
|
(defn to-community-chat-id
|
||||||
|
[chat-id]
|
||||||
(subs chat-id community-chat-id-length))
|
(subs chat-id community-chat-id-length))
|
||||||
|
|
||||||
(fx/defn edit-channel
|
(rf/defn edit-channel
|
||||||
{:events [::edit-channel-confirmation-pressed]}
|
{:events [::edit-channel-confirmation-pressed]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [{:keys [name description color community-id emoji edit-channel-id category-id position]}
|
(let [{:keys [name description color community-id emoji edit-channel-id category-id position]}
|
||||||
@@ -305,161 +320,171 @@
|
|||||||
:emoji emoji}
|
:emoji emoji}
|
||||||
:category_id category-id
|
:category_id category-id
|
||||||
:position position
|
:position position
|
||||||
:permissions {:access constants/community-channel-access-no-membership}}]
|
:permissions {:access
|
||||||
|
constants/community-channel-access-no-membership}}]
|
||||||
:js-response true
|
:js-response true
|
||||||
:on-success #(re-frame/dispatch [::community-channel-edited %])
|
:on-success #(re-frame/dispatch [::community-channel-edited %])
|
||||||
:on-error #(do
|
:on-error #(do
|
||||||
(log/error "failed to edit community channel" %)
|
(log/error "failed to edit community channel" %)
|
||||||
(re-frame/dispatch [::failed-to-edit-community-channel %]))}]}))
|
(re-frame/dispatch [::failed-to-edit-community-channel %]))}]}))
|
||||||
|
|
||||||
(defn require-membership? [permissions]
|
(defn require-membership?
|
||||||
|
[permissions]
|
||||||
(not= constants/community-no-membership-access (:access permissions)))
|
(not= constants/community-no-membership-access (:access permissions)))
|
||||||
|
|
||||||
(defn can-post? [community _ local-chat-id]
|
(defn can-post?
|
||||||
|
[community _ local-chat-id]
|
||||||
(let [chat-id (to-community-chat-id local-chat-id)]
|
(let [chat-id (to-community-chat-id local-chat-id)]
|
||||||
(get-in community [:chats chat-id :can-post?])))
|
(get-in community [:chats chat-id :can-post?])))
|
||||||
|
|
||||||
(fx/defn reset-community-id-input [{:keys [db]} id]
|
(rf/defn reset-community-id-input
|
||||||
|
[{:keys [db]} id]
|
||||||
{:db (assoc db :communities/community-id-input id)})
|
{:db (assoc db :communities/community-id-input id)})
|
||||||
|
|
||||||
(fx/defn reset-channel-info [{:keys [db]}]
|
(rf/defn reset-channel-info
|
||||||
|
[{:keys [db]}]
|
||||||
{:db (assoc db :communities/create-channel {})})
|
{:db (assoc db :communities/create-channel {})})
|
||||||
|
|
||||||
(fx/defn invite-people-pressed
|
(rf/defn invite-people-pressed
|
||||||
{:events [:communities/invite-people-pressed]}
|
{:events [:communities/invite-people-pressed]}
|
||||||
[cofx id]
|
[cofx id]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(reset-community-id-input id)
|
(reset-community-id-input id)
|
||||||
(bottom-sheet/hide-bottom-sheet)
|
(bottom-sheet/hide-bottom-sheet)
|
||||||
(navigation/open-modal :invite-people-community {:invite? true})))
|
(navigation/open-modal :invite-people-community {:invite? true})))
|
||||||
|
|
||||||
(fx/defn share-community-pressed
|
(rf/defn share-community-pressed
|
||||||
{:events [:communities/share-community-pressed]}
|
{:events [:communities/share-community-pressed]}
|
||||||
[cofx id]
|
[cofx id]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(reset-community-id-input id)
|
(reset-community-id-input id)
|
||||||
(bottom-sheet/hide-bottom-sheet)
|
(bottom-sheet/hide-bottom-sheet)
|
||||||
(navigation/open-modal :invite-people-community {})))
|
(navigation/open-modal :invite-people-community {})))
|
||||||
|
|
||||||
(fx/defn create-channel-pressed
|
(rf/defn create-channel-pressed
|
||||||
{:events [::create-channel-pressed]}
|
{:events [::create-channel-pressed]}
|
||||||
[{:keys [db] :as cofx} id]
|
[{:keys [db] :as cofx} id]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(reset-community-id-input id)
|
(reset-community-id-input id)
|
||||||
(reset-channel-info)
|
(reset-channel-info)
|
||||||
(>evt [::create-channel-fields (rand-nth emoji-thumbnail-styles/emoji-picker-default-thumbnails)])
|
(rf/dispatch [::create-channel-fields
|
||||||
|
(rand-nth emoji-thumbnail-styles/emoji-picker-default-thumbnails)])
|
||||||
(navigation/open-modal :create-community-channel {:community-id id})))
|
(navigation/open-modal :create-community-channel {:community-id id})))
|
||||||
|
|
||||||
(fx/defn edit-channel-pressed
|
(rf/defn edit-channel-pressed
|
||||||
{:events [::edit-channel-pressed]}
|
{:events [::edit-channel-pressed]}
|
||||||
[{:keys [db] :as cofx} community-id chat-name description color emoji chat-id category-id position]
|
[{:keys [db] :as cofx} community-id chat-name description color emoji chat-id category-id position]
|
||||||
(let [{:keys [color emoji]} (if (string/blank? emoji)
|
(let [{:keys [color emoji]} (if (string/blank? emoji)
|
||||||
(rand-nth emoji-thumbnail-styles/emoji-picker-default-thumbnails)
|
(rand-nth emoji-thumbnail-styles/emoji-picker-default-thumbnails)
|
||||||
{:color color :emoji emoji})]
|
{:color color :emoji emoji})]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc db :communities/create-channel {:name chat-name
|
{:db (assoc db
|
||||||
:description description
|
:communities/create-channel
|
||||||
:color color
|
{:name chat-name
|
||||||
:community-id community-id
|
:description description
|
||||||
:emoji emoji
|
:color color
|
||||||
:edit-channel-id chat-id
|
:community-id community-id
|
||||||
:category-id category-id
|
:emoji emoji
|
||||||
:position position})}
|
:edit-channel-id chat-id
|
||||||
|
:category-id category-id
|
||||||
|
:position position})}
|
||||||
(navigation/open-modal :edit-community-channel nil))))
|
(navigation/open-modal :edit-community-channel nil))))
|
||||||
|
|
||||||
(fx/defn community-created
|
(rf/defn community-created
|
||||||
{:events [::community-created]}
|
{:events [::community-created]}
|
||||||
[cofx response-js]
|
[cofx response-js]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(navigation/navigate-back)
|
(navigation/navigate-back)
|
||||||
(handle-response response-js)))
|
(handle-response response-js)))
|
||||||
|
|
||||||
(fx/defn community-edited
|
(rf/defn community-edited
|
||||||
{:events [::community-edited]}
|
{:events [::community-edited]}
|
||||||
[cofx response-js]
|
[cofx response-js]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(navigation/navigate-back)
|
(navigation/navigate-back)
|
||||||
(handle-response response-js)))
|
(handle-response response-js)))
|
||||||
|
|
||||||
(fx/defn open-create-community
|
(rf/defn open-create-community
|
||||||
{:events [::open-create-community]}
|
{:events [::open-create-community]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc db :communities/create {:membership constants/community-no-membership-access})}
|
{:db (assoc db :communities/create {:membership constants/community-no-membership-access})}
|
||||||
(navigation/navigate-to :community-create nil)))
|
(navigation/navigate-to :community-create nil)))
|
||||||
|
|
||||||
(fx/defn open-edit-community
|
(rf/defn open-edit-community
|
||||||
{:events [::open-edit-community]}
|
{:events [::open-edit-community]}
|
||||||
[{:keys [db] :as cofx} id]
|
[{:keys [db] :as cofx} id]
|
||||||
(let [{:keys [name description images permissions color]} (get-in db [:communities id])
|
(let [{:keys [name description images permissions color]} (get-in db [:communities id])
|
||||||
{:keys [access]} permissions]
|
{:keys [access]} permissions]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc db :communities/create {:id id
|
{:db (assoc db
|
||||||
:name name
|
:communities/create
|
||||||
:description description
|
{:id id
|
||||||
:image (get-in images [:large :uri])
|
:name name
|
||||||
:membership access
|
:description description
|
||||||
:color color
|
:image (get-in images [:large :uri])
|
||||||
:editing? true})}
|
:membership access
|
||||||
|
:color color
|
||||||
|
:editing? true})}
|
||||||
(navigation/navigate-to :community-edit nil))))
|
(navigation/navigate-to :community-edit nil))))
|
||||||
|
|
||||||
(fx/defn community-imported
|
(rf/defn community-imported
|
||||||
{:events [::community-imported]}
|
{:events [::community-imported]}
|
||||||
[cofx response-js]
|
[cofx response-js]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(navigation/navigate-back)
|
(navigation/navigate-back)
|
||||||
(handle-response response-js)))
|
(handle-response response-js)))
|
||||||
|
|
||||||
(fx/defn people-invited
|
(rf/defn people-invited
|
||||||
{:events [::people-invited]}
|
{:events [::people-invited]}
|
||||||
[cofx response-js]
|
[cofx response-js]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(navigation/navigate-back)
|
(navigation/navigate-back)
|
||||||
(handle-response response-js)))
|
(handle-response response-js)))
|
||||||
|
|
||||||
(fx/defn community-channel-created
|
(rf/defn community-channel-created
|
||||||
{:events [::community-channel-created]}
|
{:events [::community-channel-created]}
|
||||||
[cofx response-js]
|
[cofx response-js]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(navigation/navigate-back)
|
(navigation/navigate-back)
|
||||||
(handle-response response-js)))
|
(handle-response response-js)))
|
||||||
|
|
||||||
(fx/defn community-channel-edited
|
(rf/defn community-channel-edited
|
||||||
{:events [::community-channel-edited]}
|
{:events [::community-channel-edited]}
|
||||||
[cofx response-js]
|
[cofx response-js]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(navigation/navigate-back)
|
(navigation/navigate-back)
|
||||||
(handle-response response-js)))
|
(handle-response response-js)))
|
||||||
|
|
||||||
(fx/defn create-field
|
(rf/defn create-field
|
||||||
{:events [::create-field]}
|
{:events [::create-field]}
|
||||||
[{:keys [db]} field value]
|
[{:keys [db]} field value]
|
||||||
{:db (assoc-in db [:communities/create field] value)})
|
{:db (assoc-in db [:communities/create field] value)})
|
||||||
|
|
||||||
(fx/defn remove-field
|
(rf/defn remove-field
|
||||||
{:events [::remove-field]}
|
{:events [::remove-field]}
|
||||||
[{:keys [db]} field]
|
[{:keys [db]} field]
|
||||||
{:db (update-in db [:communities/create] dissoc field)})
|
{:db (update-in db [:communities/create] dissoc field)})
|
||||||
|
|
||||||
(fx/defn create-channel-field
|
(rf/defn create-channel-field
|
||||||
{:events [::create-channel-field]}
|
{:events [::create-channel-field]}
|
||||||
[{:keys [db]} field value]
|
[{:keys [db]} field value]
|
||||||
{:db (assoc-in db [:communities/create-channel field] value)})
|
{:db (assoc-in db [:communities/create-channel field] value)})
|
||||||
|
|
||||||
(fx/defn create-channel-fields
|
(rf/defn create-channel-fields
|
||||||
{:events [::create-channel-fields]}
|
{:events [::create-channel-fields]}
|
||||||
[{:keys [db]} field-values]
|
[{:keys [db]} field-values]
|
||||||
{:db (update-in db [:communities/create-channel] merge field-values)})
|
{:db (update-in db [:communities/create-channel] merge field-values)})
|
||||||
|
|
||||||
(fx/defn member-banned
|
(rf/defn member-banned
|
||||||
{:events [::member-banned]}
|
{:events [::member-banned]}
|
||||||
[cofx response-js]
|
[cofx response-js]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(bottom-sheet/hide-bottom-sheet)
|
(bottom-sheet/hide-bottom-sheet)
|
||||||
(handle-response response-js)
|
(handle-response response-js)
|
||||||
(activity-center/notifications-fetch-unread-count)))
|
(activity-center/notifications-fetch-unread-count)))
|
||||||
|
|
||||||
(fx/defn member-ban
|
(rf/defn member-ban
|
||||||
{:events [::member-ban]}
|
{:events [::member-ban]}
|
||||||
[cofx community-id public-key]
|
[cofx community-id public-key]
|
||||||
{::json-rpc/call [{:method "wakuext_banUserFromCommunity"
|
{::json-rpc/call [{:method "wakuext_banUserFromCommunity"
|
||||||
@@ -467,35 +492,43 @@
|
|||||||
:user public-key}]
|
:user public-key}]
|
||||||
:js-response true
|
:js-response true
|
||||||
:on-success #(re-frame/dispatch [::member-banned %])
|
:on-success #(re-frame/dispatch [::member-banned %])
|
||||||
:on-error #(log/error "failed to ban user from community" community-id public-key %)}]})
|
:on-error #(log/error "failed to ban user from community"
|
||||||
|
community-id
|
||||||
|
public-key
|
||||||
|
%)}]})
|
||||||
|
|
||||||
(fx/defn member-kicked
|
(rf/defn member-kicked
|
||||||
{:events [::member-kicked]}
|
{:events [::member-kicked]}
|
||||||
[cofx response-js]
|
[cofx response-js]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(bottom-sheet/hide-bottom-sheet)
|
(bottom-sheet/hide-bottom-sheet)
|
||||||
(handle-response response-js)))
|
(handle-response response-js)))
|
||||||
|
|
||||||
(fx/defn member-kick
|
(rf/defn member-kick
|
||||||
{:events [::member-kick]}
|
{:events [::member-kick]}
|
||||||
[cofx community-id public-key]
|
[cofx community-id public-key]
|
||||||
{::json-rpc/call [{:method "wakuext_removeUserFromCommunity"
|
{::json-rpc/call [{:method "wakuext_removeUserFromCommunity"
|
||||||
:params [community-id public-key]
|
:params [community-id public-key]
|
||||||
:js-response true
|
:js-response true
|
||||||
:on-success #(re-frame/dispatch [::member-kicked %])
|
:on-success #(re-frame/dispatch [::member-kicked %])
|
||||||
:on-error #(log/error "failed to remove user from community" community-id public-key %)}]})
|
:on-error #(log/error "failed to remove user from community"
|
||||||
|
community-id
|
||||||
|
public-key
|
||||||
|
%)}]})
|
||||||
|
|
||||||
(fx/defn delete-community
|
(rf/defn delete-community
|
||||||
{:events [::delete-community]}
|
{:events [::delete-community]}
|
||||||
[cofx community-id]
|
[cofx community-id]
|
||||||
(log/error "Community delete is not yet implemented"))
|
(log/error "Community delete is not yet implemented"))
|
||||||
|
|
||||||
(fx/defn requests-to-join-fetched
|
(rf/defn requests-to-join-fetched
|
||||||
{:events [::requests-to-join-fetched]}
|
{:events [::requests-to-join-fetched]}
|
||||||
[{:keys [db]} community-id requests]
|
[{:keys [db]} community-id requests]
|
||||||
{:db (assoc-in db [:communities/requests-to-join community-id] (<-requests-to-join-community-rpc requests))})
|
{:db (assoc-in db
|
||||||
|
[:communities/requests-to-join community-id]
|
||||||
|
(<-requests-to-join-community-rpc requests))})
|
||||||
|
|
||||||
(fx/defn fetch-requests-to-join
|
(rf/defn fetch-requests-to-join
|
||||||
{:events [::fetch-requests-to-join]}
|
{:events [::fetch-requests-to-join]}
|
||||||
[cofx community-id]
|
[cofx community-id]
|
||||||
{::json-rpc/call [{:method "wakuext_pendingRequestsToJoinForCommunity"
|
{::json-rpc/call [{:method "wakuext_pendingRequestsToJoinForCommunity"
|
||||||
@@ -503,48 +536,56 @@
|
|||||||
:on-success #(re-frame/dispatch [::requests-to-join-fetched community-id %])
|
:on-success #(re-frame/dispatch [::requests-to-join-fetched community-id %])
|
||||||
:on-error #(log/error "failed to fetch requests-to-join" community-id %)}]})
|
:on-error #(log/error "failed to fetch requests-to-join" community-id %)}]})
|
||||||
|
|
||||||
(defn fetch-requests-to-join! [community-id]
|
(defn fetch-requests-to-join!
|
||||||
|
[community-id]
|
||||||
(re-frame/dispatch [::fetch-requests-to-join community-id]))
|
(re-frame/dispatch [::fetch-requests-to-join community-id]))
|
||||||
|
|
||||||
(fx/defn request-to-join-accepted
|
(rf/defn request-to-join-accepted
|
||||||
{:events [::request-to-join-accepted]}
|
{:events [::request-to-join-accepted]}
|
||||||
[{:keys [db] :as cofx} community-id request-id response-js]
|
[{:keys [db] :as cofx} community-id request-id response-js]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (update-in db [:communities/requests-to-join community-id] dissoc request-id)}
|
{:db (update-in db [:communities/requests-to-join community-id] dissoc request-id)}
|
||||||
(handle-response response-js)))
|
(handle-response response-js)))
|
||||||
|
|
||||||
(fx/defn request-to-join-declined
|
(rf/defn request-to-join-declined
|
||||||
{:events [::request-to-join-declined]}
|
{:events [::request-to-join-declined]}
|
||||||
[{:keys [db] :as cofx} community-id request-id response-js]
|
[{:keys [db] :as cofx} community-id request-id response-js]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (update-in db [:communities/requests-to-join community-id] dissoc request-id)}
|
{:db (update-in db [:communities/requests-to-join community-id] dissoc request-id)}
|
||||||
(handle-response response-js)))
|
(handle-response response-js)))
|
||||||
|
|
||||||
(fx/defn accept-request-to-join-pressed
|
(rf/defn accept-request-to-join-pressed
|
||||||
{:events [:communities.ui/accept-request-to-join-pressed]}
|
{:events [:communities.ui/accept-request-to-join-pressed]}
|
||||||
[cofx community-id request-id]
|
[cofx community-id request-id]
|
||||||
{::json-rpc/call [{:method "wakuext_acceptRequestToJoinCommunity"
|
{::json-rpc/call [{:method "wakuext_acceptRequestToJoinCommunity"
|
||||||
:params [{:id request-id}]
|
:params [{:id request-id}]
|
||||||
:js-response true
|
:js-response true
|
||||||
:on-success #(re-frame/dispatch [::request-to-join-accepted community-id request-id %])
|
:on-success #(re-frame/dispatch [::request-to-join-accepted community-id request-id
|
||||||
:on-error #(log/error "failed to accept requests-to-join" community-id request-id %)}]})
|
%])
|
||||||
|
:on-error #(log/error "failed to accept requests-to-join"
|
||||||
|
community-id
|
||||||
|
request-id
|
||||||
|
%)}]})
|
||||||
|
|
||||||
(fx/defn decline-request-to-join-pressed
|
(rf/defn decline-request-to-join-pressed
|
||||||
{:events [:communities.ui/decline-request-to-join-pressed]}
|
{:events [:communities.ui/decline-request-to-join-pressed]}
|
||||||
[cofx community-id request-id]
|
[cofx community-id request-id]
|
||||||
{::json-rpc/call [{:method "wakuext_declineRequestToJoinCommunity"
|
{::json-rpc/call [{:method "wakuext_declineRequestToJoinCommunity"
|
||||||
:params [{:id request-id}]
|
:params [{:id request-id}]
|
||||||
:js-response true
|
:js-response true
|
||||||
:on-success #(re-frame/dispatch [::request-to-join-declined community-id request-id %])
|
:on-success #(re-frame/dispatch [::request-to-join-declined community-id request-id
|
||||||
:on-error #(log/error "failed to decline requests-to-join" community-id request-id)}]})
|
%])
|
||||||
|
:on-error #(log/error "failed to decline requests-to-join"
|
||||||
|
community-id
|
||||||
|
request-id)}]})
|
||||||
|
|
||||||
(fx/defn switch-communities-enabled
|
(rf/defn switch-communities-enabled
|
||||||
{:events [:multiaccounts.ui/switch-communities-enabled]}
|
{:events [:multiaccounts.ui/switch-communities-enabled]}
|
||||||
[{:keys [db]} enabled?]
|
[{:keys [db]} enabled?]
|
||||||
{::async-storage/set! {:communities-enabled? enabled?}
|
{::async-storage/set! {:communities-enabled? enabled?}
|
||||||
:db (assoc db :communities/enabled? enabled?)})
|
:db (assoc db :communities/enabled? enabled?)})
|
||||||
|
|
||||||
(fx/defn create-category
|
(rf/defn create-category
|
||||||
{:events [::create-category-confirmation-pressed]}
|
{:events [::create-category-confirmation-pressed]}
|
||||||
[_ community-id category-title chat-ids]
|
[_ community-id category-title chat-ids]
|
||||||
{::json-rpc/call [{:method "wakuext_createCommunityCategory"
|
{::json-rpc/call [{:method "wakuext_createCommunityCategory"
|
||||||
@@ -557,12 +598,13 @@
|
|||||||
(re-frame/dispatch [:sanitize-messages-and-process-response %]))
|
(re-frame/dispatch [:sanitize-messages-and-process-response %]))
|
||||||
:on-error #(log/error "failed to create community category" %)}]})
|
:on-error #(log/error "failed to create community category" %)}]})
|
||||||
|
|
||||||
(fx/defn remove-chat-from-category
|
(rf/defn remove-chat-from-category
|
||||||
{:events [:remove-chat-from-community-category]}
|
{:events [:remove-chat-from-community-category]}
|
||||||
[{:keys [db]} community-id id categoryID]
|
[{:keys [db]} community-id id categoryID]
|
||||||
(let [category (get-in db [:communities community-id :categories categoryID])
|
(let [category (get-in db [:communities community-id :categories categoryID])
|
||||||
category-chats (map :id (filter #(and (= (:categoryID %) categoryID) (not= id (:id %)))
|
category-chats (map :id
|
||||||
(vals (get-in db [:communities community-id :chats]))))]
|
(filter #(and (= (:categoryID %) categoryID) (not= id (:id %)))
|
||||||
|
(vals (get-in db [:communities community-id :chats]))))]
|
||||||
{::json-rpc/call [{:method "wakuext_editCommunityCategory"
|
{::json-rpc/call [{:method "wakuext_editCommunityCategory"
|
||||||
:params [{:communityId community-id
|
:params [{:communityId community-id
|
||||||
:categoryId categoryID
|
:categoryId categoryID
|
||||||
@@ -572,7 +614,7 @@
|
|||||||
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
|
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
|
||||||
:on-error #(log/error "failed to remove chat from community" %)}]}))
|
:on-error #(log/error "failed to remove chat from community" %)}]}))
|
||||||
|
|
||||||
(fx/defn delete-community-chat
|
(rf/defn delete-community-chat
|
||||||
{:events [:delete-community-chat]}
|
{:events [:delete-community-chat]}
|
||||||
[_ community-id chat-id]
|
[_ community-id chat-id]
|
||||||
{::json-rpc/call [{:method "wakuext_deleteCommunityChat"
|
{::json-rpc/call [{:method "wakuext_deleteCommunityChat"
|
||||||
@@ -581,7 +623,7 @@
|
|||||||
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
|
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
|
||||||
:on-error #(log/error "failed to delete community chat" %)}]})
|
:on-error #(log/error "failed to delete community chat" %)}]})
|
||||||
|
|
||||||
(fx/defn delete-category
|
(rf/defn delete-category
|
||||||
{:events [:delete-community-category]}
|
{:events [:delete-community-category]}
|
||||||
[_ community-id category-id]
|
[_ community-id category-id]
|
||||||
{::json-rpc/call [{:method "wakuext_deleteCommunityCategory"
|
{::json-rpc/call [{:method "wakuext_deleteCommunityCategory"
|
||||||
@@ -591,7 +633,7 @@
|
|||||||
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
|
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
|
||||||
:on-error #(log/error "failed to delete community category" %)}]})
|
:on-error #(log/error "failed to delete community category" %)}]})
|
||||||
|
|
||||||
(fx/defn change-category
|
(rf/defn change-category
|
||||||
{:events [::change-category-confirmation-pressed]}
|
{:events [::change-category-confirmation-pressed]}
|
||||||
[cofx community-id category-id {:keys [id position categoryID]}]
|
[cofx community-id category-id {:keys [id position categoryID]}]
|
||||||
(if (not (string/blank? category-id))
|
(if (not (string/blank? category-id))
|
||||||
@@ -605,11 +647,11 @@
|
|||||||
(re-frame/dispatch [:navigate-back])
|
(re-frame/dispatch [:navigate-back])
|
||||||
(re-frame/dispatch [:sanitize-messages-and-process-response %]))
|
(re-frame/dispatch [:sanitize-messages-and-process-response %]))
|
||||||
:on-error #(log/error "failed to change community category" %)}]}
|
:on-error #(log/error "failed to change community category" %)}]}
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(navigation/navigate-back)
|
(navigation/navigate-back)
|
||||||
(remove-chat-from-category community-id id categoryID))))
|
(remove-chat-from-category community-id id categoryID))))
|
||||||
|
|
||||||
(fx/defn reorder-category-chat
|
(rf/defn reorder-category-chat
|
||||||
{:events [::reorder-community-category-chat]}
|
{:events [::reorder-community-category-chat]}
|
||||||
[_ community-id category-id chat-id new-position]
|
[_ community-id category-id chat-id new-position]
|
||||||
{::json-rpc/call [{:method "wakuext_reorderCommunityChat"
|
{::json-rpc/call [{:method "wakuext_reorderCommunityChat"
|
||||||
@@ -621,7 +663,7 @@
|
|||||||
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
|
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
|
||||||
:on-error #(log/error "failed to reorder community category chat" %)}]})
|
:on-error #(log/error "failed to reorder community category chat" %)}]})
|
||||||
|
|
||||||
(fx/defn reorder-category
|
(rf/defn reorder-category
|
||||||
{:events [::reorder-community-category]}
|
{:events [::reorder-community-category]}
|
||||||
[_ community-id category-id new-position]
|
[_ community-id category-id new-position]
|
||||||
{::json-rpc/call [{:method "wakuext_reorderCommunityCategories"
|
{::json-rpc/call [{:method "wakuext_reorderCommunityCategories"
|
||||||
@@ -632,17 +674,18 @@
|
|||||||
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
|
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
|
||||||
:on-error #(log/error "failed to reorder community category" %)}]})
|
:on-error #(log/error "failed to reorder community category" %)}]})
|
||||||
|
|
||||||
(defn category-hash [public-key community-id category-id]
|
(defn category-hash
|
||||||
|
[public-key community-id category-id]
|
||||||
(hash (str public-key community-id category-id)))
|
(hash (str public-key community-id category-id)))
|
||||||
|
|
||||||
(fx/defn store-category-state
|
(rf/defn store-category-state
|
||||||
{:events [::store-category-state]}
|
{:events [::store-category-state]}
|
||||||
[{:keys [db]} community-id category-id state-open?]
|
[{:keys [db]} community-id category-id state-open?]
|
||||||
(let [public-key (get-in db [:multiaccount :public-key])
|
(let [public-key (get-in db [:multiaccount :public-key])
|
||||||
hash (category-hash public-key community-id category-id)]
|
hash (category-hash public-key community-id category-id)]
|
||||||
{::async-storage/set! {hash state-open?}}))
|
{::async-storage/set! {hash state-open?}}))
|
||||||
|
|
||||||
(fx/defn update-category-states-in-db
|
(rf/defn update-category-states-in-db
|
||||||
{:events [::category-states-loaded]}
|
{:events [::category-states-loaded]}
|
||||||
[{:keys [db]} community-id hashes states]
|
[{:keys [db]} community-id hashes states]
|
||||||
(let [public-key (get-in db [:multiaccount :public-key])
|
(let [public-key (get-in db [:multiaccount :public-key])
|
||||||
@@ -652,10 +695,11 @@
|
|||||||
state (get states hash)
|
state (get states hash)
|
||||||
category-updated (assoc category :state state)]
|
category-updated (assoc category :state state)]
|
||||||
(assoc acc category-id category-updated)))
|
(assoc acc category-id category-updated)))
|
||||||
{} categories-old)]
|
{}
|
||||||
|
categories-old)]
|
||||||
{:db (update-in db [:communities community-id :categories] merge categories)}))
|
{:db (update-in db [:communities community-id :categories] merge categories)}))
|
||||||
|
|
||||||
(fx/defn load-category-states
|
(rf/defn load-category-states
|
||||||
{:events [:communities/load-category-states]}
|
{:events [:communities/load-category-states]}
|
||||||
[{:keys [db]} community-id]
|
[{:keys [db]} community-id]
|
||||||
(let [public-key (get-in db [:multiaccount :public-key])
|
(let [public-key (get-in db [:multiaccount :public-key])
|
||||||
@@ -669,26 +713,27 @@
|
|||||||
(-> acc
|
(-> acc
|
||||||
(assoc-in [:hashes category-id] hash)
|
(assoc-in [:hashes category-id] hash)
|
||||||
(update :keys #(conj % hash)))))
|
(update :keys #(conj % hash)))))
|
||||||
{} categories)]
|
{}
|
||||||
|
categories)]
|
||||||
{::async-storage/get {:keys keys
|
{::async-storage/get {:keys keys
|
||||||
:cb #(re-frame/dispatch
|
:cb #(re-frame/dispatch
|
||||||
[::category-states-loaded community-id hashes %])}}))
|
[::category-states-loaded community-id hashes %])}}))
|
||||||
|
|
||||||
(fx/defn navigate-to-community
|
(rf/defn navigate-to-community
|
||||||
{:events [:communities/navigate-to-community]}
|
{:events [:communities/navigate-to-community]}
|
||||||
[cofx community-id]
|
[cofx community-id]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(navigation/pop-to-root-tab :shell-stack)
|
(navigation/pop-to-root-tab :shell-stack)
|
||||||
(navigation/navigate-to-nav2 :community community-id true)))
|
(navigation/navigate-to-nav2 :community community-id true)))
|
||||||
|
|
||||||
(fx/defn member-role-updated
|
(rf/defn member-role-updated
|
||||||
{:events [:community.member/role-updated]}
|
{:events [:community.member/role-updated]}
|
||||||
[cofx response-js]
|
[cofx response-js]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(bottom-sheet/hide-bottom-sheet)
|
(bottom-sheet/hide-bottom-sheet)
|
||||||
(handle-response response-js)))
|
(handle-response response-js)))
|
||||||
|
|
||||||
(fx/defn add-role-to-member
|
(rf/defn add-role-to-member
|
||||||
{:events [:community.member/add-role]}
|
{:events [:community.member/add-role]}
|
||||||
[cofx community-id public-key role-id]
|
[cofx community-id public-key role-id]
|
||||||
{::json-rpc/call [{:method "wakuext_addRoleToMember"
|
{::json-rpc/call [{:method "wakuext_addRoleToMember"
|
||||||
@@ -702,7 +747,7 @@
|
|||||||
:public-key public-key
|
:public-key public-key
|
||||||
:role-id role-id})}]})
|
:role-id role-id})}]})
|
||||||
|
|
||||||
(fx/defn remove-role-from-member
|
(rf/defn remove-role-from-member
|
||||||
{:events [:community.member/remove-role]}
|
{:events [:community.member/remove-role]}
|
||||||
[_ community-id public-key role-id]
|
[_ community-id public-key role-id]
|
||||||
{::json-rpc/call [{:method "wakuext_removeRoleFromMember"
|
{::json-rpc/call [{:method "wakuext_removeRoleFromMember"
|
||||||
@@ -710,8 +755,9 @@
|
|||||||
:user public-key
|
:user public-key
|
||||||
:role role-id}]}
|
:role role-id}]}
|
||||||
:on-success #(re-frame/dispatch [:community.member/role-updated %])
|
:on-success #(re-frame/dispatch [:community.member/role-updated %])
|
||||||
:on-error #(log/error "failed to remove role from member"
|
:on-error
|
||||||
{:error %
|
#(log/error "failed to remove role from member"
|
||||||
:community-id community-id
|
{:error %
|
||||||
:public-key public-key
|
:community-id community-id
|
||||||
:role-id role-id})]})
|
:public-key public-key
|
||||||
|
:role-id role-id})]})
|
||||||
|
|||||||
@@ -4,12 +4,12 @@
|
|||||||
[status-im.contact.db :as contact.db]
|
[status-im.contact.db :as contact.db]
|
||||||
[status-im.data-store.chats :as chats-store]
|
[status-im.data-store.chats :as chats-store]
|
||||||
[status-im.data-store.contacts :as contacts-store]
|
[status-im.data-store.contacts :as contacts-store]
|
||||||
[status-im2.navigation.events :as navigation]
|
|
||||||
[status-im.utils.types :as types]
|
[status-im.utils.types :as types]
|
||||||
[status-im2.contexts.activity-center.events :as activity-center]
|
[status-im2.contexts.activity-center.events :as activity-center]
|
||||||
[status-im.utils.fx :as fx]))
|
[status-im2.navigation.events :as navigation]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(fx/defn clean-up-chat
|
(rf/defn clean-up-chat
|
||||||
[{:keys [db] :as cofx}
|
[{:keys [db] :as cofx}
|
||||||
public-key
|
public-key
|
||||||
{:keys [chat-id
|
{:keys [chat-id
|
||||||
@@ -21,60 +21,63 @@
|
|||||||
(when (= from public-key)
|
(when (= from public-key)
|
||||||
message-id))
|
message-id))
|
||||||
(get-in db [:messages chat-id]))
|
(get-in db [:messages chat-id]))
|
||||||
db (-> db
|
db (-> db
|
||||||
;; remove messages
|
;; remove messages
|
||||||
(update-in [:messages chat-id]
|
(update-in [:messages chat-id]
|
||||||
#(apply dissoc % removed-messages-ids))
|
#(apply dissoc % removed-messages-ids))
|
||||||
(update-in [:chats chat-id]
|
(update-in [:chats chat-id]
|
||||||
assoc
|
assoc
|
||||||
:unviewed-messages-count unviewed-messages-count
|
:unviewed-messages-count unviewed-messages-count
|
||||||
:unviewed-mentions-count unviewed-mentions-count
|
:unviewed-mentions-count unviewed-mentions-count
|
||||||
:last-message last-message))]
|
:last-message last-message))]
|
||||||
{:db (assoc-in db [:message-lists chat-id]
|
{:db (assoc-in db
|
||||||
(message-list/add-many nil (vals (get-in db [:messages chat-id]))))}))
|
[:message-lists chat-id]
|
||||||
|
(message-list/add-many nil (vals (get-in db [:messages chat-id]))))}))
|
||||||
|
|
||||||
(fx/defn contact-blocked
|
(rf/defn contact-blocked
|
||||||
{:events [::contact-blocked]}
|
{:events [::contact-blocked]}
|
||||||
[{:keys [db] :as cofx} {:keys [public-key]} chats]
|
[{:keys [db] :as cofx} {:keys [public-key]} chats]
|
||||||
(let [fxs (when chats
|
(let [fxs (when chats
|
||||||
(map #(->> (chats-store/<-rpc %)
|
(map #(->> (chats-store/<-rpc %)
|
||||||
(clean-up-chat public-key)) (types/js->clj chats)))]
|
(clean-up-chat public-key))
|
||||||
(apply fx/merge
|
(types/js->clj chats)))]
|
||||||
|
(apply rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(update :chats dissoc public-key)
|
(update :chats dissoc public-key)
|
||||||
(update :chats-home-list disj public-key)
|
(update :chats-home-list disj public-key)
|
||||||
(assoc-in [:contacts/contacts public-key :added] false))
|
(assoc-in [:contacts/contacts public-key :added] false))
|
||||||
:clear-message-notifications
|
:clear-message-notifications
|
||||||
[[public-key] (get-in db [:multiaccount :remote-push-notifications-enabled?])]}
|
[[public-key] (get-in db [:multiaccount :remote-push-notifications-enabled?])]}
|
||||||
(activity-center/notifications-fetch-unread-count)
|
(activity-center/notifications-fetch-unread-count)
|
||||||
fxs)))
|
fxs)))
|
||||||
|
|
||||||
(fx/defn block-contact
|
(rf/defn block-contact
|
||||||
{:events [:contact.ui/block-contact-confirmed]}
|
{:events [:contact.ui/block-contact-confirmed]}
|
||||||
[{:keys [db] :as cofx} public-key]
|
[{:keys [db] :as cofx} public-key]
|
||||||
(let [contact (-> (contact.db/public-key->contact
|
(let [contact (-> (contact.db/public-key->contact
|
||||||
(:contacts/contacts db)
|
(:contacts/contacts db)
|
||||||
public-key)
|
public-key)
|
||||||
(assoc :blocked true
|
(assoc :blocked true
|
||||||
:added false))
|
:added false))
|
||||||
from-one-to-one-chat? (not (get-in db [:chats (:current-chat-id db) :group-chat]))]
|
from-one-to-one-chat? (not (get-in db [:chats (:current-chat-id db) :group-chat]))]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
;; add the contact to blocked contacts
|
;; add the contact to blocked contacts
|
||||||
(update :contacts/blocked (fnil conj #{}) public-key)
|
(update :contacts/blocked (fnil conj #{}) public-key)
|
||||||
;; update the contact in contacts list
|
;; update the contact in contacts list
|
||||||
(assoc-in [:contacts/contacts public-key] contact))}
|
(assoc-in [:contacts/contacts public-key] contact))}
|
||||||
(contacts-store/block
|
(contacts-store/block
|
||||||
public-key #(do (re-frame/dispatch [::contact-blocked contact (.-chats %)])
|
public-key
|
||||||
(re-frame/dispatch [:sanitize-messages-and-process-response %])
|
#(do (re-frame/dispatch [::contact-blocked contact (.-chats %)])
|
||||||
(re-frame/dispatch [:hide-popover])))
|
(re-frame/dispatch [:sanitize-messages-and-process-response %])
|
||||||
|
(re-frame/dispatch [:hide-popover])))
|
||||||
;; reset navigation to avoid going back to non existing one to one chat
|
;; reset navigation to avoid going back to non existing one to one chat
|
||||||
(if from-one-to-one-chat?
|
(if from-one-to-one-chat?
|
||||||
(navigation/pop-to-root-tab :chat-stack)
|
(navigation/pop-to-root-tab :chat-stack)
|
||||||
(navigation/navigate-back)))))
|
(navigation/navigate-back)))))
|
||||||
|
|
||||||
(fx/defn contact-unblocked
|
(rf/defn contact-unblocked
|
||||||
{:events [::contact-unblocked]}
|
{:events [::contact-unblocked]}
|
||||||
[{:keys [db]} contact-id]
|
[{:keys [db]} contact-id]
|
||||||
(let [contact (-> (get-in db [:contacts/contacts contact-id])
|
(let [contact (-> (get-in db [:contacts/contacts contact-id])
|
||||||
@@ -83,7 +86,7 @@
|
|||||||
(update :contacts/blocked disj contact-id)
|
(update :contacts/blocked disj contact-id)
|
||||||
(assoc-in [:contacts/contacts contact-id] contact))}))
|
(assoc-in [:contacts/contacts contact-id] contact))}))
|
||||||
|
|
||||||
(fx/defn unblock-contact
|
(rf/defn unblock-contact
|
||||||
{:events [:contact.ui/unblock-contact-pressed]}
|
{:events [:contact.ui/unblock-contact-pressed]}
|
||||||
[cofx contact-id]
|
[cofx contact-id]
|
||||||
(contacts-store/unblock
|
(contacts-store/unblock
|
||||||
|
|||||||
@@ -1,29 +1,29 @@
|
|||||||
(ns status-im.contact.chat
|
(ns status-im.contact.chat
|
||||||
(:require [re-frame.core :as re-frame]
|
(:require [re-frame.core :as re-frame]
|
||||||
[status-im2.navigation.events :as navigation]
|
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[status-im.chat.models :as chat]
|
[status-im.chat.models :as chat]
|
||||||
[status-im.contact.core :as contact]))
|
[status-im.contact.core :as contact]
|
||||||
|
[status-im2.navigation.events :as navigation]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(fx/defn send-message-pressed
|
(rf/defn send-message-pressed
|
||||||
{:events [:contact.ui/send-message-pressed]
|
{:events [:contact.ui/send-message-pressed]
|
||||||
:interceptors [(re-frame/inject-cofx :random-id-generator)]}
|
:interceptors [(re-frame/inject-cofx :random-id-generator)]}
|
||||||
[cofx {:keys [public-key ens-name]}]
|
[cofx {:keys [public-key ens-name]}]
|
||||||
(chat/start-chat cofx public-key ens-name))
|
(chat/start-chat cofx public-key ens-name))
|
||||||
|
|
||||||
(fx/defn contact-code-submitted
|
(rf/defn contact-code-submitted
|
||||||
{:events [:contact.ui/contact-code-submitted]
|
{:events [:contact.ui/contact-code-submitted]
|
||||||
:interceptors [(re-frame/inject-cofx :random-id-generator)]}
|
:interceptors [(re-frame/inject-cofx :random-id-generator)]}
|
||||||
[{{:contacts/keys [new-identity]} :db :as cofx} new-contact? nickname]
|
[{{:contacts/keys [new-identity]} :db :as cofx} new-contact? nickname]
|
||||||
(let [{:keys [public-key ens-name]} new-identity]
|
(let [{:keys [public-key ens-name]} new-identity]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
#(if new-contact?
|
#(if new-contact?
|
||||||
(contact/add-contact % public-key nickname ens-name)
|
(contact/add-contact % public-key nickname ens-name)
|
||||||
(chat/start-chat % public-key ens-name))
|
(chat/start-chat % public-key ens-name))
|
||||||
#(when new-contact?
|
#(when new-contact?
|
||||||
(navigation/navigate-back %)))))
|
(navigation/navigate-back %)))))
|
||||||
|
|
||||||
(fx/defn pinned-messages-pressed
|
(rf/defn pinned-messages-pressed
|
||||||
{:events [:contact.ui/pinned-messages-pressed]}
|
{:events [:contact.ui/pinned-messages-pressed]}
|
||||||
[cofx public-key]
|
[cofx public-key]
|
||||||
(chat/navigate-to-user-pinned-messages cofx public-key))
|
(chat/navigate-to-user-pinned-messages cofx public-key))
|
||||||
|
|||||||
@@ -1,42 +1,44 @@
|
|||||||
(ns status-im.contact.core
|
(ns status-im.contact.core
|
||||||
(:require [re-frame.core :as re-frame]
|
(:require [re-frame.core :as re-frame]
|
||||||
|
[status-im.constants :as constants]
|
||||||
|
[status-im.contact.block :as contact.block]
|
||||||
[status-im.contact.db :as contact.db]
|
[status-im.contact.db :as contact.db]
|
||||||
[status-im.data-store.contacts :as contacts-store]
|
[status-im.data-store.contacts :as contacts-store]
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
[status-im2.navigation.events :as navigation]
|
|
||||||
[status-im.multiaccounts.update.core :as multiaccounts.update]
|
[status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||||
[status-im.utils.fx :as fx]
|
[status-im2.navigation.events :as navigation]
|
||||||
[taoensso.timbre :as log]
|
[taoensso.timbre :as log]
|
||||||
[status-im.constants :as constants]
|
[utils.re-frame :as rf]))
|
||||||
[status-im.contact.block :as contact.block]))
|
|
||||||
|
|
||||||
(fx/defn load-contacts
|
(rf/defn load-contacts
|
||||||
{:events [::contacts-loaded]}
|
{:events [::contacts-loaded]}
|
||||||
[{:keys [db] :as cofx} all-contacts]
|
[{:keys [db] :as cofx} all-contacts]
|
||||||
(let [contacts-list (map #(vector (:public-key %) (if (empty? (:address %))
|
(let [contacts-list (map #(vector (:public-key %)
|
||||||
(dissoc % :address)
|
(if (empty? (:address %))
|
||||||
%))
|
(dissoc % :address)
|
||||||
|
%))
|
||||||
all-contacts)
|
all-contacts)
|
||||||
contacts (into {} contacts-list)]
|
contacts (into {} contacts-list)]
|
||||||
{:db (cond-> (-> db
|
{:db (cond-> (-> db
|
||||||
(update :contacts/contacts #(merge contacts %))
|
(update :contacts/contacts #(merge contacts %))
|
||||||
(assoc :contacts/blocked (contact.db/get-blocked-contacts all-contacts))))}))
|
(assoc :contacts/blocked (contact.db/get-blocked-contacts all-contacts))))}))
|
||||||
|
|
||||||
(defn build-contact
|
(defn build-contact
|
||||||
[{{:keys [multiaccount]
|
[{{:keys [multiaccount]
|
||||||
:contacts/keys [contacts]} :db} public-key]
|
:contacts/keys [contacts]}
|
||||||
|
:db} public-key]
|
||||||
(cond-> (contact.db/public-key->contact contacts public-key)
|
(cond-> (contact.db/public-key->contact contacts public-key)
|
||||||
(= public-key (:public-key multiaccount))
|
(= public-key (:public-key multiaccount))
|
||||||
(assoc :name (:name multiaccount))))
|
(assoc :name (:name multiaccount))))
|
||||||
|
|
||||||
(fx/defn ensure-contacts
|
(rf/defn ensure-contacts
|
||||||
[{:keys [db]} contacts chats]
|
[{:keys [db]} contacts chats]
|
||||||
(let [events
|
(let [events
|
||||||
(reduce
|
(reduce
|
||||||
(fn [acc {:keys [public-key] :as contact}]
|
(fn [acc {:keys [public-key] :as contact}]
|
||||||
(let [added (:added contact)
|
(let [added (:added contact)
|
||||||
was-added (contact.db/added? db public-key)
|
was-added (contact.db/added? db public-key)
|
||||||
blocked (:blocked contact)
|
blocked (:blocked contact)
|
||||||
was-blocked (contact.db/blocked? db public-key)]
|
was-blocked (contact.db/blocked? db public-key)]
|
||||||
(cond-> acc
|
(cond-> acc
|
||||||
(and added (not was-added))
|
(and added (not was-added))
|
||||||
@@ -51,7 +53,8 @@
|
|||||||
[:activity-center.notifications/fetch-unread-count]]
|
[:activity-center.notifications/fetch-unread-count]]
|
||||||
contacts)]
|
contacts)]
|
||||||
(merge
|
(merge
|
||||||
{:db (update db :contacts/contacts
|
{:db (update db
|
||||||
|
:contacts/contacts
|
||||||
#(reduce (fn [acc {:keys [public-key] :as contact}]
|
#(reduce (fn [acc {:keys [public-key] :as contact}]
|
||||||
(-> acc
|
(-> acc
|
||||||
(update public-key merge contact)
|
(update public-key merge contact)
|
||||||
@@ -68,15 +71,15 @@
|
|||||||
:profile-image identicon
|
:profile-image identicon
|
||||||
:address address}))
|
:address address}))
|
||||||
|
|
||||||
(fx/defn send-contact-request
|
(rf/defn send-contact-request
|
||||||
{:events [::send-contact-request]}
|
{:events [::send-contact-request]}
|
||||||
[{:keys [db] :as cofx} public-key]
|
[{:keys [db] :as cofx} public-key]
|
||||||
(let [{:keys [name profile-image]} (own-info db)]
|
(let [{:keys [name profile-image]} (own-info db)]
|
||||||
{::json-rpc/call [{:method "wakuext_sendContactUpdate"
|
{::json-rpc/call [{:method "wakuext_sendContactUpdate"
|
||||||
:params [public-key name profile-image]
|
:params [public-key name profile-image]
|
||||||
:on-success #(log/debug "contact request sent" public-key)}]}))
|
:on-success #(log/debug "contact request sent" public-key)}]}))
|
||||||
|
|
||||||
(fx/defn add-contact
|
(rf/defn add-contact
|
||||||
"Add a contact and set pending to false"
|
"Add a contact and set pending to false"
|
||||||
{:events [:contact.ui/add-to-contact-pressed]}
|
{:events [:contact.ui/add-to-contact-pressed]}
|
||||||
[{:keys [db] :as cofx} public-key nickname ens-name]
|
[{:keys [db] :as cofx} public-key nickname ens-name]
|
||||||
@@ -90,60 +93,62 @@
|
|||||||
(re-frame/dispatch [:sanitize-messages-and-process-response %])
|
(re-frame/dispatch [:sanitize-messages-and-process-response %])
|
||||||
(re-frame/dispatch [:offload-messages constants/timeline-chat-id])))))
|
(re-frame/dispatch [:offload-messages constants/timeline-chat-id])))))
|
||||||
|
|
||||||
(fx/defn remove-contact
|
(rf/defn remove-contact
|
||||||
"Remove a contact from current account's contact list"
|
"Remove a contact from current account's contact list"
|
||||||
{:events [:contact.ui/remove-contact-pressed]}
|
{:events [:contact.ui/remove-contact-pressed]}
|
||||||
[{:keys [db]} {:keys [public-key]}]
|
[{:keys [db]} {:keys [public-key]}]
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:contacts/contacts public-key :added] false)
|
(assoc-in [:contacts/contacts public-key :added] false)
|
||||||
(assoc-in [:contacts/contacts public-key :contact-request-state] constants/contact-request-state-none))
|
(assoc-in [:contacts/contacts public-key :contact-request-state]
|
||||||
::json-rpc/call [{:method "wakuext_removeContact"
|
constants/contact-request-state-none))
|
||||||
:params [public-key]
|
::json-rpc/call [{:method "wakuext_removeContact"
|
||||||
|
:params [public-key]
|
||||||
:on-success #(log/debug "contact removed successfully")}
|
:on-success #(log/debug "contact removed successfully")}
|
||||||
{:method "wakuext_retractContactRequest"
|
{:method "wakuext_retractContactRequest"
|
||||||
:params [{:contactId public-key}]
|
:params [{:contactId public-key}]
|
||||||
:on-success #(log/debug "contact removed successfully")}]
|
:on-success #(log/debug "contact removed successfully")}]
|
||||||
:dispatch [:offload-messages constants/timeline-chat-id]})
|
:dispatch [:offload-messages constants/timeline-chat-id]})
|
||||||
|
|
||||||
(fx/defn accept-contact-request
|
(rf/defn accept-contact-request
|
||||||
{:events [:contact-requests.ui/accept-request]}
|
{:events [:contact-requests.ui/accept-request]}
|
||||||
[{:keys [db]} id]
|
[{:keys [db]} id]
|
||||||
{::json-rpc/call [{:method "wakuext_acceptContactRequest"
|
{::json-rpc/call [{:method "wakuext_acceptContactRequest"
|
||||||
:params [{:id id}]
|
:params [{:id id}]
|
||||||
:js-response true
|
:js-response true
|
||||||
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])}]})
|
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])}]})
|
||||||
|
|
||||||
(fx/defn decline-contact-request
|
(rf/defn decline-contact-request
|
||||||
{:events [:contact-requests.ui/decline-request]}
|
{:events [:contact-requests.ui/decline-request]}
|
||||||
[{:keys [db]} id]
|
[{:keys [db]} id]
|
||||||
{::json-rpc/call [{:method "wakuext_dismissContactRequest"
|
{::json-rpc/call [{:method "wakuext_dismissContactRequest"
|
||||||
:params [{:id id}]
|
:params [{:id id}]
|
||||||
:js-response true
|
:js-response true
|
||||||
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])}]})
|
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])}]})
|
||||||
|
|
||||||
(fx/defn initialize-contacts [cofx]
|
(rf/defn initialize-contacts
|
||||||
|
[cofx]
|
||||||
(contacts-store/fetch-contacts-rpc cofx #(re-frame/dispatch [::contacts-loaded %])))
|
(contacts-store/fetch-contacts-rpc cofx #(re-frame/dispatch [::contacts-loaded %])))
|
||||||
|
|
||||||
(fx/defn open-contact-toggle-list
|
(rf/defn open-contact-toggle-list
|
||||||
{:events [:contact.ui/start-group-chat-pressed]}
|
{:events [:contact.ui/start-group-chat-pressed]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc db
|
{:db (assoc db
|
||||||
:group/selected-contacts #{}
|
:group/selected-contacts #{}
|
||||||
:new-chat-name "")}
|
:new-chat-name "")}
|
||||||
(navigation/navigate-to-cofx :contact-toggle-list nil)))
|
(navigation/navigate-to-cofx :contact-toggle-list nil)))
|
||||||
|
|
||||||
(fx/defn update-nickname
|
(rf/defn update-nickname
|
||||||
{:events [:contacts/update-nickname]}
|
{:events [:contacts/update-nickname]}
|
||||||
[{:keys [db] :as cofx} public-key nickname]
|
[{:keys [db] :as cofx} public-key nickname]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(contacts-store/set-nickname
|
(contacts-store/set-nickname
|
||||||
public-key
|
public-key
|
||||||
nickname
|
nickname
|
||||||
#(re-frame/dispatch [:sanitize-messages-and-process-response %]))
|
#(re-frame/dispatch [:sanitize-messages-and-process-response %]))
|
||||||
(navigation/navigate-back)))
|
(navigation/navigate-back)))
|
||||||
|
|
||||||
(fx/defn switch-mutual-contact-requests-enabled
|
(rf/defn switch-mutual-contact-requests-enabled
|
||||||
{:events [:multiaccounts.ui/switch-mutual-contact-requests-enabled]}
|
{:events [:multiaccounts.ui/switch-mutual-contact-requests-enabled]}
|
||||||
[cofx enabled?]
|
[cofx enabled?]
|
||||||
(multiaccounts.update/multiaccount-update
|
(multiaccounts.update/multiaccount-update
|
||||||
@@ -152,7 +157,7 @@
|
|||||||
enabled?
|
enabled?
|
||||||
nil))
|
nil))
|
||||||
|
|
||||||
(fx/defn set-search-query
|
(rf/defn set-search-query
|
||||||
{:events [:contacts/set-search-query]}
|
{:events [:contacts/set-search-query]}
|
||||||
[{:keys [db] :as cofx} value]
|
[{:keys [db] :as cofx} value]
|
||||||
{:db (assoc db :contacts/search-query value)})
|
{:db (assoc db :contacts/search-query value)})
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
(ns status-im.currency.core
|
(ns status-im.currency.core
|
||||||
(:require [status-im.multiaccounts.update.core :as multiaccounts.update]
|
(:require [status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||||
[status-im.utils.fx :as fx]
|
[status-im.wallet.prices :as prices]
|
||||||
[status-im.wallet.prices :as prices]))
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(defn get-currency [db]
|
(defn get-currency
|
||||||
|
[db]
|
||||||
(get-in db [:multiaccount :currency] :usd))
|
(get-in db [:multiaccount :currency] :usd))
|
||||||
|
|
||||||
(fx/defn set-currency
|
(rf/defn set-currency
|
||||||
{:events [:wallet.settings.ui/currency-selected]}
|
{:events [:wallet.settings.ui/currency-selected]}
|
||||||
[{:keys [db] :as cofx} currency]
|
[{:keys [db] :as cofx} currency]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(multiaccounts.update/multiaccount-update
|
(multiaccounts.update/multiaccount-update
|
||||||
:currency currency
|
:currency
|
||||||
|
currency
|
||||||
{})
|
{})
|
||||||
(prices/update-prices)))
|
(prices/update-prices)))
|
||||||
|
|||||||
@@ -1,31 +1,34 @@
|
|||||||
(ns status-im.data-store.chats
|
(ns status-im.data-store.chats
|
||||||
(:require [clojure.set :as clojure.set]
|
(:require [clojure.set :as clojure.set]
|
||||||
|
[status-im.constants :as constants]
|
||||||
[status-im.data-store.messages :as messages]
|
[status-im.data-store.messages :as messages]
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
[status-im.constants :as constants]
|
[status-im.utils.types :as types]
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[taoensso.timbre :as log]
|
[taoensso.timbre :as log]
|
||||||
[status-im.utils.types :as types]))
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(defn rpc->type [{:keys [chat-type name] :as chat}]
|
(defn rpc->type
|
||||||
|
[{:keys [chat-type name] :as chat}]
|
||||||
(cond
|
(cond
|
||||||
(or (= constants/public-chat-type chat-type)
|
(or (= constants/public-chat-type chat-type)
|
||||||
(= constants/profile-chat-type chat-type)
|
(= constants/profile-chat-type chat-type)
|
||||||
(= constants/timeline-chat-type chat-type)) (assoc chat
|
(= constants/timeline-chat-type chat-type))
|
||||||
:chat-name (str "#" name)
|
(assoc chat
|
||||||
:public? true
|
:chat-name (str "#" name)
|
||||||
:group-chat true
|
:public? true
|
||||||
:timeline? (= constants/timeline-chat-type chat-type))
|
:group-chat true
|
||||||
|
:timeline? (= constants/timeline-chat-type chat-type))
|
||||||
(= constants/community-chat-type chat-type) (assoc chat
|
(= constants/community-chat-type chat-type) (assoc chat
|
||||||
:chat-name name
|
:chat-name name
|
||||||
:group-chat true)
|
:group-chat true)
|
||||||
(= constants/private-group-chat-type chat-type) (assoc chat
|
(= constants/private-group-chat-type chat-type) (assoc chat
|
||||||
:chat-name name
|
:chat-name name
|
||||||
:public? false
|
:public? false
|
||||||
:group-chat true)
|
:group-chat true)
|
||||||
:else (assoc chat :public? false :group-chat false)))
|
:else (assoc chat :public? false :group-chat false)))
|
||||||
|
|
||||||
(defn members-reducer [acc member]
|
(defn members-reducer
|
||||||
|
[acc member]
|
||||||
(cond-> acc
|
(cond-> acc
|
||||||
(:admin member)
|
(:admin member)
|
||||||
(update :admins conj (:id member))
|
(update :admins conj (:id member))
|
||||||
@@ -34,45 +37,48 @@
|
|||||||
:always
|
:always
|
||||||
(update :contacts conj (:id member))))
|
(update :contacts conj (:id member))))
|
||||||
|
|
||||||
(defn- unmarshal-members [{:keys [members chat-type] :as chat}]
|
(defn- unmarshal-members
|
||||||
|
[{:keys [members chat-type] :as chat}]
|
||||||
(cond
|
(cond
|
||||||
(= constants/public-chat-type chat-type) (assoc chat
|
(= constants/public-chat-type chat-type) (assoc chat
|
||||||
:contacts #{}
|
:contacts #{}
|
||||||
:admins #{}
|
:admins #{}
|
||||||
:members-joined #{})
|
:members-joined #{})
|
||||||
(= constants/private-group-chat-type chat-type) (merge chat
|
(= constants/private-group-chat-type chat-type) (merge chat
|
||||||
(reduce members-reducer
|
(reduce members-reducer
|
||||||
{:admins #{}
|
{:admins #{}
|
||||||
:members-joined #{}
|
:members-joined #{}
|
||||||
:contacts #{}}
|
:contacts #{}}
|
||||||
members))
|
members))
|
||||||
:else
|
:else
|
||||||
(assoc chat
|
(assoc chat
|
||||||
:contacts #{(:id chat)}
|
:contacts #{(:id chat)}
|
||||||
:admins #{}
|
:admins #{}
|
||||||
:members-joined #{})))
|
:members-joined #{})))
|
||||||
|
|
||||||
(defn <-rpc [chat]
|
(defn <-rpc
|
||||||
|
[chat]
|
||||||
(-> chat
|
(-> chat
|
||||||
(clojure.set/rename-keys {:id :chat-id
|
(clojure.set/rename-keys {:id :chat-id
|
||||||
:communityId :community-id
|
:communityId :community-id
|
||||||
:syncedFrom :synced-from
|
:syncedFrom :synced-from
|
||||||
:syncedTo :synced-to
|
:syncedTo :synced-to
|
||||||
:membershipUpdateEvents :membership-update-events
|
:membershipUpdateEvents :membership-update-events
|
||||||
:deletedAtClockValue :deleted-at-clock-value
|
:deletedAtClockValue :deleted-at-clock-value
|
||||||
:chatType :chat-type
|
:chatType :chat-type
|
||||||
:unviewedMessagesCount :unviewed-messages-count
|
:unviewedMessagesCount :unviewed-messages-count
|
||||||
:unviewedMentionsCount :unviewed-mentions-count
|
:unviewedMentionsCount :unviewed-mentions-count
|
||||||
:lastMessage :last-message
|
:lastMessage :last-message
|
||||||
:lastClockValue :last-clock-value
|
:lastClockValue :last-clock-value
|
||||||
:invitationAdmin :invitation-admin
|
:invitationAdmin :invitation-admin
|
||||||
:profile :profile-public-key})
|
:profile :profile-public-key})
|
||||||
rpc->type
|
rpc->type
|
||||||
unmarshal-members
|
unmarshal-members
|
||||||
(update :last-message #(when % (messages/<-rpc %)))
|
(update :last-message #(when % (messages/<-rpc %)))
|
||||||
(dissoc :members)))
|
(dissoc :members)))
|
||||||
|
|
||||||
(defn <-rpc-js [^js chat]
|
(defn <-rpc-js
|
||||||
|
[^js chat]
|
||||||
(-> {:name (.-name chat)
|
(-> {:name (.-name chat)
|
||||||
:description (.-description chat)
|
:description (.-description chat)
|
||||||
:color (.-color chat)
|
:color (.-color chat)
|
||||||
@@ -103,9 +109,10 @@
|
|||||||
rpc->type
|
rpc->type
|
||||||
unmarshal-members))
|
unmarshal-members))
|
||||||
|
|
||||||
(fx/defn fetch-chats-rpc [_ {:keys [on-success]}]
|
(rf/defn fetch-chats-rpc
|
||||||
{::json-rpc/call [{:method "wakuext_chatsPreview"
|
[_ {:keys [on-success]}]
|
||||||
:params []
|
{::json-rpc/call [{:method "wakuext_chatsPreview"
|
||||||
|
:params []
|
||||||
:js-response true
|
:js-response true
|
||||||
:on-success #(on-success ^js %)
|
:on-success #(on-success ^js %)
|
||||||
:on-error #(log/error "failed to fetch chats" 0 -1 %)}]})
|
:on-error #(log/error "failed to fetch chats" 0 -1 %)}]})
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
(ns status-im.data-store.contacts
|
(ns status-im.data-store.contacts
|
||||||
(:require [clojure.set :as clojure.set]
|
(:require [clojure.set :as clojure.set]
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
[status-im.utils.fx :as fx]
|
[taoensso.timbre :as log]
|
||||||
[taoensso.timbre :as log]))
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(defn <-rpc [contact]
|
(defn <-rpc
|
||||||
|
[contact]
|
||||||
(-> contact
|
(-> contact
|
||||||
(clojure.set/rename-keys
|
(clojure.set/rename-keys
|
||||||
{:id :public-key
|
{:id :public-key
|
||||||
@@ -17,48 +18,54 @@
|
|||||||
:lastENSClockValue :last-ens-clock-value
|
:lastENSClockValue :last-ens-clock-value
|
||||||
:lastUpdated :last-updated
|
:lastUpdated :last-updated
|
||||||
:localNickname :nickname})
|
:localNickname :nickname})
|
||||||
(assoc :mutual? (and (:added contact)
|
(assoc :mutual?
|
||||||
(:hasAddedUs contact)))))
|
(and (:added contact)
|
||||||
|
(:hasAddedUs contact)))))
|
||||||
|
|
||||||
(fx/defn fetch-contacts-rpc
|
(rf/defn fetch-contacts-rpc
|
||||||
[_ on-success]
|
[_ on-success]
|
||||||
{::json-rpc/call [{:method "wakuext_contacts"
|
{::json-rpc/call [{:method "wakuext_contacts"
|
||||||
:params []
|
:params []
|
||||||
:on-success #(on-success (map <-rpc %))
|
:on-success #(on-success (map <-rpc %))
|
||||||
:on-error #(log/error "failed to fetch contacts" %)}]})
|
:on-error #(log/error "failed to fetch contacts" %)}]})
|
||||||
|
|
||||||
(fx/defn add
|
(rf/defn add
|
||||||
[_ public-key nickname ens-name on-success]
|
[_ public-key nickname ens-name on-success]
|
||||||
{::json-rpc/call [{:method "wakuext_addContact"
|
{::json-rpc/call [{:method "wakuext_addContact"
|
||||||
:params [{:id public-key :nickname nickname :ensName ens-name}]
|
:params [{:id public-key :nickname nickname :ensName ens-name}]
|
||||||
:js-response true
|
:js-response true
|
||||||
:on-success #(do
|
:on-success #(do
|
||||||
(log/info "saved contact" public-key "successfuly")
|
(log/info "saved contact" public-key "successfuly")
|
||||||
(when on-success
|
(when on-success
|
||||||
(on-success %)))
|
(on-success %)))
|
||||||
:on-error #(log/error "failed to add contact" public-key %)}]})
|
:on-error #(log/error "failed to add contact" public-key %)}]})
|
||||||
|
|
||||||
(fx/defn set-nickname
|
(rf/defn set-nickname
|
||||||
[_ public-key nickname on-success]
|
[_ public-key nickname on-success]
|
||||||
{::json-rpc/call [{:method "wakuext_setContactLocalNickname"
|
{::json-rpc/call [{:method "wakuext_setContactLocalNickname"
|
||||||
:params [{:id public-key :nickname nickname}]
|
:params [{:id public-key :nickname nickname}]
|
||||||
:js-response true
|
:js-response true
|
||||||
:on-success #(do
|
:on-success #(do
|
||||||
(log/debug "set contact nickname" public-key "successfuly" nickname)
|
(log/debug "set contact nickname" public-key "successfuly" nickname)
|
||||||
(when on-success
|
(when on-success
|
||||||
(on-success %)))
|
(on-success %)))
|
||||||
:on-error #(log/error "failed to set contact nickname " public-key nickname %)}]})
|
:on-error #(log/error "failed to set contact nickname "
|
||||||
|
public-key
|
||||||
|
nickname
|
||||||
|
%)}]})
|
||||||
|
|
||||||
(fx/defn block [_ contact-id on-success]
|
(rf/defn block
|
||||||
{::json-rpc/call [{:method "wakuext_blockContact"
|
[_ contact-id on-success]
|
||||||
:params [contact-id]
|
{::json-rpc/call [{:method "wakuext_blockContact"
|
||||||
|
:params [contact-id]
|
||||||
:js-response true
|
:js-response true
|
||||||
:on-success on-success
|
:on-success on-success
|
||||||
:on-error #(log/error "failed to block contact" % contact-id)}]})
|
:on-error #(log/error "failed to block contact" % contact-id)}]})
|
||||||
|
|
||||||
(fx/defn unblock [_ contact-id on-success]
|
(rf/defn unblock
|
||||||
{::json-rpc/call [{:method "wakuext_unblockContact"
|
[_ contact-id on-success]
|
||||||
:params [contact-id]
|
{::json-rpc/call [{:method "wakuext_unblockContact"
|
||||||
:on-success on-success
|
:params [contact-id]
|
||||||
|
:on-success on-success
|
||||||
:js-response true
|
:js-response true
|
||||||
:on-error #(log/error "failed to unblock contact" % contact-id)}]})
|
:on-error #(log/error "failed to unblock contact" % contact-id)}]})
|
||||||
|
|||||||
@@ -1,103 +1,118 @@
|
|||||||
(ns status-im.data-store.messages
|
(ns status-im.data-store.messages
|
||||||
(:require [clojure.set :as clojure.set]
|
(:require [clojure.set :as clojure.set]
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
[status-im.utils.fx :as fx]
|
[taoensso.timbre :as log]
|
||||||
[taoensso.timbre :as log]))
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(defn ->rpc [{:keys [content] :as message}]
|
(defn ->rpc
|
||||||
|
[{:keys [content] :as message}]
|
||||||
(cond-> message
|
(cond-> message
|
||||||
content
|
content
|
||||||
(assoc :text (:text content)
|
(assoc :text (:text content)
|
||||||
:sticker (:sticker content))
|
:sticker (:sticker content))
|
||||||
:always
|
:always
|
||||||
(clojure.set/rename-keys {:chat-id :chat_id
|
(clojure.set/rename-keys {:chat-id :chat_id
|
||||||
:whisper-timestamp :whisperTimestamp
|
:whisper-timestamp :whisperTimestamp
|
||||||
:community-id :communityId
|
:community-id :communityId
|
||||||
:clock-value :clock})))
|
:clock-value :clock})))
|
||||||
|
|
||||||
(defn <-rpc [message]
|
(defn <-rpc
|
||||||
|
[message]
|
||||||
(-> message
|
(-> message
|
||||||
(clojure.set/rename-keys {:id :message-id
|
(clojure.set/rename-keys {:id :message-id
|
||||||
:whisperTimestamp :whisper-timestamp
|
:whisperTimestamp :whisper-timestamp
|
||||||
:editedAt :edited-at
|
:editedAt :edited-at
|
||||||
:contactVerificationState :contact-verification-state
|
:contactVerificationState :contact-verification-state
|
||||||
:contactRequestState :contact-request-state
|
:contactRequestState :contact-request-state
|
||||||
:commandParameters :command-parameters
|
:commandParameters :command-parameters
|
||||||
:gapParameters :gap-parameters
|
:gapParameters :gap-parameters
|
||||||
:messageType :message-type
|
:messageType :message-type
|
||||||
:localChatId :chat-id
|
:localChatId :chat-id
|
||||||
:communityId :community-id
|
:communityId :community-id
|
||||||
:contentType :content-type
|
:contentType :content-type
|
||||||
:clock :clock-value
|
:clock :clock-value
|
||||||
:quotedMessage :quoted-message
|
:quotedMessage :quoted-message
|
||||||
:outgoingStatus :outgoing-status
|
:outgoingStatus :outgoing-status
|
||||||
:audioDurationMs :audio-duration-ms
|
:audioDurationMs :audio-duration-ms
|
||||||
:deleted :deleted?
|
:deleted :deleted?
|
||||||
:deletedForMe :deleted-for-me?
|
:deletedForMe :deleted-for-me?
|
||||||
:new :new?})
|
:new :new?})
|
||||||
|
|
||||||
(update :quoted-message clojure.set/rename-keys {:parsedText :parsed-text :communityId :community-id})
|
(update :quoted-message
|
||||||
|
clojure.set/rename-keys
|
||||||
|
{:parsedText :parsed-text :communityId :community-id})
|
||||||
(update :outgoing-status keyword)
|
(update :outgoing-status keyword)
|
||||||
(update :command-parameters clojure.set/rename-keys {:transactionHash :transaction-hash
|
(update :command-parameters
|
||||||
:commandState :command-state})
|
clojure.set/rename-keys
|
||||||
(assoc :content {:chat-id (:chatId message)
|
{:transactionHash :transaction-hash
|
||||||
:text (:text message)
|
:commandState :command-state})
|
||||||
:image (:image message)
|
(assoc :content {:chat-id (:chatId message)
|
||||||
:sticker (:sticker message)
|
:text (:text message)
|
||||||
:ens-name (:ensName message)
|
:image (:image message)
|
||||||
:line-count (:lineCount message)
|
:sticker (:sticker message)
|
||||||
:parsed-text (:parsedText message)
|
:ens-name (:ensName message)
|
||||||
:links (:links message)
|
:line-count (:lineCount message)
|
||||||
:rtl? (:rtl message)
|
:parsed-text (:parsedText message)
|
||||||
:response-to (:responseTo message)}
|
:links (:links message)
|
||||||
|
:rtl? (:rtl message)
|
||||||
|
:response-to (:responseTo message)}
|
||||||
:outgoing (boolean (:outgoingStatus message)))
|
:outgoing (boolean (:outgoingStatus message)))
|
||||||
(dissoc :ensName :chatId :text :rtl :responseTo :image :sticker :lineCount :parsedText :links)))
|
(dissoc :ensName :chatId :text :rtl :responseTo :image :sticker :lineCount :parsedText :links)))
|
||||||
|
|
||||||
(defn messages-by-chat-id-rpc [chat-id
|
(defn messages-by-chat-id-rpc
|
||||||
cursor
|
[chat-id
|
||||||
limit
|
cursor
|
||||||
on-success
|
limit
|
||||||
on-error]
|
on-success
|
||||||
|
on-error]
|
||||||
{::json-rpc/call [{:method "wakuext_chatMessages"
|
{::json-rpc/call [{:method "wakuext_chatMessages"
|
||||||
:params [chat-id cursor limit]
|
:params [chat-id cursor limit]
|
||||||
:on-success (fn [result]
|
:on-success (fn [result]
|
||||||
(on-success (update result :messages #(map <-rpc %))))
|
(on-success (update result :messages #(map <-rpc %))))
|
||||||
:on-error on-error}]})
|
:on-error on-error}]})
|
||||||
|
|
||||||
(defn mark-seen-rpc [chat-id ids on-success]
|
(defn mark-seen-rpc
|
||||||
{::json-rpc/call [{:method "wakuext_markMessagesSeen"
|
[chat-id ids on-success]
|
||||||
:params [chat-id ids]
|
{::json-rpc/call [{:method "wakuext_markMessagesSeen"
|
||||||
|
:params [chat-id ids]
|
||||||
:on-success #(do
|
:on-success #(do
|
||||||
(log/debug "successfully marked as seen" %)
|
(log/debug "successfully marked as seen" %)
|
||||||
(when on-success (on-success chat-id ids %)))
|
(when on-success (on-success chat-id ids %)))
|
||||||
:on-error #(log/error "failed to get messages" %)}]})
|
:on-error #(log/error "failed to get messages" %)}]})
|
||||||
|
|
||||||
(defn delete-message-rpc [id]
|
(defn delete-message-rpc
|
||||||
{::json-rpc/call [{:method "wakuext_deleteMessage"
|
[id]
|
||||||
:params [id]
|
{::json-rpc/call [{:method "wakuext_deleteMessage"
|
||||||
|
:params [id]
|
||||||
:on-success #(log/debug "successfully deleted message" id)
|
:on-success #(log/debug "successfully deleted message" id)
|
||||||
:on-error #(log/error "failed to delete message" % id)}]})
|
:on-error #(log/error "failed to delete message" % id)}]})
|
||||||
|
|
||||||
(defn delete-messages-from-rpc [author]
|
(defn delete-messages-from-rpc
|
||||||
{::json-rpc/call [{:method "wakuext_deleteMessagesFrom"
|
[author]
|
||||||
:params [author]
|
{::json-rpc/call [{:method "wakuext_deleteMessagesFrom"
|
||||||
|
:params [author]
|
||||||
:on-success #(log/debug "successfully deleted messages from" author)
|
:on-success #(log/debug "successfully deleted messages from" author)
|
||||||
:on-error #(log/error "failed to delete messages from" % author)}]})
|
:on-error #(log/error "failed to delete messages from" % author)}]})
|
||||||
|
|
||||||
(defn delete-messages-by-chat-id-rpc [chat-id]
|
(defn delete-messages-by-chat-id-rpc
|
||||||
{::json-rpc/call [{:method "wakuext_deleteMessagesByChatID"
|
[chat-id]
|
||||||
:params [chat-id]
|
{::json-rpc/call [{:method "wakuext_deleteMessagesByChatID"
|
||||||
|
:params [chat-id]
|
||||||
:on-success #(log/debug "successfully deleted messages by chat-id" chat-id)
|
:on-success #(log/debug "successfully deleted messages by chat-id" chat-id)
|
||||||
:on-error #(log/error "failed to delete messages by chat-id" % chat-id)}]})
|
:on-error #(log/error "failed to delete messages by chat-id" % chat-id)}]})
|
||||||
|
|
||||||
(fx/defn delete-message [cofx id]
|
(rf/defn delete-message
|
||||||
|
[cofx id]
|
||||||
(delete-message-rpc id))
|
(delete-message-rpc id))
|
||||||
|
|
||||||
(fx/defn delete-messages-from [cofx author]
|
(rf/defn delete-messages-from
|
||||||
|
[cofx author]
|
||||||
(delete-messages-from-rpc author))
|
(delete-messages-from-rpc author))
|
||||||
|
|
||||||
(fx/defn mark-messages-seen [cofx chat-id ids on-success]
|
(rf/defn mark-messages-seen
|
||||||
|
[cofx chat-id ids on-success]
|
||||||
(mark-seen-rpc chat-id ids on-success))
|
(mark-seen-rpc chat-id ids on-success))
|
||||||
|
|
||||||
(fx/defn delete-messages-by-chat-id [cofx chat-id]
|
(rf/defn delete-messages-by-chat-id
|
||||||
|
[cofx chat-id]
|
||||||
(delete-messages-by-chat-id-rpc chat-id))
|
(delete-messages-by-chat-id-rpc chat-id))
|
||||||
|
|||||||
@@ -1,31 +1,36 @@
|
|||||||
(ns status-im.data-store.pin-messages
|
(ns status-im.data-store.pin-messages
|
||||||
(:require [clojure.set :as clojure.set]
|
(:require [clojure.set :as clojure.set]
|
||||||
|
[status-im.data-store.messages :as messages]
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[taoensso.timbre :as log]
|
[taoensso.timbre :as log]
|
||||||
[status-im.data-store.messages :as messages]))
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(defn <-rpc [message]
|
(defn <-rpc
|
||||||
|
[message]
|
||||||
(-> message
|
(-> message
|
||||||
(merge (messages/<-rpc (message :message)))
|
(merge (messages/<-rpc (message :message)))
|
||||||
(clojure.set/rename-keys {:pinnedAt :pinned-at
|
(clojure.set/rename-keys {:pinnedAt :pinned-at
|
||||||
:pinnedBy :pinned-by})
|
:pinnedBy :pinned-by})
|
||||||
(dissoc :message)))
|
(dissoc :message)))
|
||||||
|
|
||||||
(defn pinned-message-by-chat-id-rpc [chat-id
|
(defn pinned-message-by-chat-id-rpc
|
||||||
cursor
|
[chat-id
|
||||||
limit
|
cursor
|
||||||
on-success
|
limit
|
||||||
on-error]
|
on-success
|
||||||
|
on-error]
|
||||||
{::json-rpc/call [{:method "wakuext_chatPinnedMessages"
|
{::json-rpc/call [{:method "wakuext_chatPinnedMessages"
|
||||||
:params [chat-id cursor limit]
|
:params [chat-id cursor limit]
|
||||||
:on-success (fn [result]
|
:on-success (fn [result]
|
||||||
(let [result (clojure.set/rename-keys result {:pinnedMessages :pinned-messages})]
|
(let [result (clojure.set/rename-keys result
|
||||||
|
{:pinnedMessages
|
||||||
|
:pinned-messages})]
|
||||||
(on-success (update result :pinned-messages #(map <-rpc %)))))
|
(on-success (update result :pinned-messages #(map <-rpc %)))))
|
||||||
:on-error on-error}]})
|
:on-error on-error}]})
|
||||||
|
|
||||||
(fx/defn send-pin-message [cofx pin-message]
|
(rf/defn send-pin-message
|
||||||
{::json-rpc/call [{:method "wakuext_sendPinMessage"
|
[cofx pin-message]
|
||||||
:params [(messages/->rpc pin-message)]
|
{::json-rpc/call [{:method "wakuext_sendPinMessage"
|
||||||
|
:params [(messages/->rpc pin-message)]
|
||||||
:on-success #(log/debug "successfully pinned message" pin-message)
|
:on-success #(log/debug "successfully pinned message" pin-message)
|
||||||
:on-error #(log/error "failed to pin message" % pin-message)}]})
|
:on-error #(log/error "failed to pin message" % pin-message)}]})
|
||||||
|
|||||||
@@ -2,23 +2,28 @@
|
|||||||
(:require [clojure.set :as clojure.set]
|
(:require [clojure.set :as clojure.set]
|
||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
[status-im.utils.fx :as fx]
|
[taoensso.timbre :as log]
|
||||||
[taoensso.timbre :as log]))
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(defn <-rpc [visibility-status-update]
|
(defn <-rpc
|
||||||
(clojure.set/rename-keys visibility-status-update {:publicKey :public-key
|
[visibility-status-update]
|
||||||
:statusType :status-type}))
|
(clojure.set/rename-keys visibility-status-update
|
||||||
(defn <-rpc-settings [settings]
|
{:publicKey :public-key
|
||||||
|
:statusType :status-type}))
|
||||||
|
(defn <-rpc-settings
|
||||||
|
[settings]
|
||||||
(-> settings
|
(-> settings
|
||||||
(clojure.set/rename-keys
|
(clojure.set/rename-keys
|
||||||
{:current-user-status :current-user-visibility-status})
|
{:current-user-status :current-user-visibility-status})
|
||||||
(update :current-user-visibility-status <-rpc)))
|
(update :current-user-visibility-status <-rpc)))
|
||||||
|
|
||||||
(fx/defn fetch-visibility-status-updates-rpc [_]
|
(rf/defn fetch-visibility-status-updates-rpc
|
||||||
|
[_]
|
||||||
{::json-rpc/call [{:method "wakuext_statusUpdates"
|
{::json-rpc/call [{:method "wakuext_statusUpdates"
|
||||||
:params []
|
:params []
|
||||||
:on-success #(re-frame/dispatch
|
:on-success #(re-frame/dispatch
|
||||||
[:visibility-status-updates/visibility-status-updates-loaded
|
[:visibility-status-updates/visibility-status-updates-loaded
|
||||||
(:statusUpdates ^js %)])
|
(:statusUpdates ^js %)])
|
||||||
:on-error #(log/error
|
:on-error #(log/error
|
||||||
"failed to fetch visibility-status-updates" %)}]})
|
"failed to fetch visibility-status-updates"
|
||||||
|
%)}]})
|
||||||
|
|||||||
+104
-74
@@ -2,18 +2,19 @@
|
|||||||
(:refer-clojure :exclude [name])
|
(:refer-clojure :exclude [name])
|
||||||
(:require [clojure.string :as string]
|
(:require [clojure.string :as string]
|
||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
|
[status-im.bottom-sheet.core :as bottom-sheet]
|
||||||
[status-im.ethereum.core :as ethereum]
|
[status-im.ethereum.core :as ethereum]
|
||||||
[status-im.ethereum.eip55 :as eip55]
|
[status-im.ethereum.eip55 :as eip55]
|
||||||
[status-im.ethereum.ens :as ens]
|
[status-im.ethereum.ens :as ens]
|
||||||
[status-im.ethereum.stateofus :as stateofus]
|
[status-im.ethereum.stateofus :as stateofus]
|
||||||
[status-im.multiaccounts.update.core :as multiaccounts.update]
|
[status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||||
[status-im2.navigation.events :as navigation]
|
|
||||||
[status-im.utils.datetime :as datetime]
|
[status-im.utils.datetime :as datetime]
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[status-im.utils.random :as random]
|
[status-im.utils.random :as random]
|
||||||
[status-im.bottom-sheet.core :as bottom-sheet]))
|
[status-im2.navigation.events :as navigation]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(defn fullname [custom-domain? username]
|
(defn fullname
|
||||||
|
[custom-domain? username]
|
||||||
(if custom-domain?
|
(if custom-domain?
|
||||||
username
|
username
|
||||||
(stateofus/subdomain username)))
|
(stateofus/subdomain username)))
|
||||||
@@ -38,14 +39,16 @@
|
|||||||
(fn [[chain-id name cb]]
|
(fn [[chain-id name cb]]
|
||||||
(ens/expire-at chain-id name cb)))
|
(ens/expire-at chain-id name cb)))
|
||||||
|
|
||||||
(fx/defn update-ens-tx-state
|
(rf/defn update-ens-tx-state
|
||||||
{:events [:update-ens-tx-state]}
|
{:events [:update-ens-tx-state]}
|
||||||
[{:keys [db]} new-state username custom-domain? tx-hash]
|
[{:keys [db]} new-state username custom-domain? tx-hash]
|
||||||
{:db (assoc-in db [:ens/registrations tx-hash] {:state new-state
|
{:db (assoc-in db
|
||||||
:username username
|
[:ens/registrations tx-hash]
|
||||||
:custom-domain? custom-domain?})})
|
{:state new-state
|
||||||
|
:username username
|
||||||
|
:custom-domain? custom-domain?})})
|
||||||
|
|
||||||
(fx/defn redirect-to-ens-summary
|
(rf/defn redirect-to-ens-summary
|
||||||
{:events [::redirect-to-ens-summary]}
|
{:events [::redirect-to-ens-summary]}
|
||||||
[cofx]
|
[cofx]
|
||||||
;; we reset navigation so that navigate back doesn't return
|
;; we reset navigation so that navigate back doesn't return
|
||||||
@@ -55,19 +58,19 @@
|
|||||||
[:my-profile
|
[:my-profile
|
||||||
:ens-confirmation]))
|
:ens-confirmation]))
|
||||||
|
|
||||||
(fx/defn update-ens-tx-state-and-redirect
|
(rf/defn update-ens-tx-state-and-redirect
|
||||||
{:events [:update-ens-tx-state-and-redirect]}
|
{:events [:update-ens-tx-state-and-redirect]}
|
||||||
[cofx new-state username custom-domain? tx-hash]
|
[cofx new-state username custom-domain? tx-hash]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(update-ens-tx-state new-state username custom-domain? tx-hash)
|
(update-ens-tx-state new-state username custom-domain? tx-hash)
|
||||||
(redirect-to-ens-summary)))
|
(redirect-to-ens-summary)))
|
||||||
|
|
||||||
(fx/defn clear-ens-registration
|
(rf/defn clear-ens-registration
|
||||||
{:events [:clear-ens-registration]}
|
{:events [:clear-ens-registration]}
|
||||||
[{:keys [db]} tx-hash]
|
[{:keys [db]} tx-hash]
|
||||||
{:db (update db :ens/registrations dissoc tx-hash)})
|
{:db (update db :ens/registrations dissoc tx-hash)})
|
||||||
|
|
||||||
(fx/defn set-state
|
(rf/defn set-state
|
||||||
{:events [::name-resolved]}
|
{:events [::name-resolved]}
|
||||||
[{:keys [db]} username state address]
|
[{:keys [db]} username state address]
|
||||||
(when (= username
|
(when (= username
|
||||||
@@ -76,37 +79,43 @@
|
|||||||
(assoc-in [:ens/registration :state] state)
|
(assoc-in [:ens/registration :state] state)
|
||||||
(assoc-in [:ens/registration :address] address))}))
|
(assoc-in [:ens/registration :address] address))}))
|
||||||
|
|
||||||
(fx/defn save-username
|
(rf/defn save-username
|
||||||
{:events [::save-username]}
|
{:events [::save-username]}
|
||||||
[{:keys [db] :as cofx} custom-domain? username redirectToSummary]
|
[{:keys [db] :as cofx} custom-domain? username redirectToSummary]
|
||||||
(let [name (fullname custom-domain? username)
|
(let [name (fullname custom-domain? username)
|
||||||
names (get-in db [:multiaccount :usernames] [])
|
names (get-in db [:multiaccount :usernames] [])
|
||||||
new-names (conj names name)]
|
new-names (conj names name)]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(multiaccounts.update/multiaccount-update
|
(multiaccounts.update/multiaccount-update
|
||||||
:usernames new-names
|
:usernames
|
||||||
|
new-names
|
||||||
(when redirectToSummary
|
(when redirectToSummary
|
||||||
{:on-success #(re-frame/dispatch [::redirect-to-ens-summary])}))
|
{:on-success #(re-frame/dispatch [::redirect-to-ens-summary])}))
|
||||||
(when (empty? names)
|
(when (empty? names)
|
||||||
(multiaccounts.update/multiaccount-update
|
(multiaccounts.update/multiaccount-update
|
||||||
:preferred-name name {})))))
|
:preferred-name
|
||||||
|
name
|
||||||
|
{})))))
|
||||||
|
|
||||||
(fx/defn set-pub-key
|
(rf/defn set-pub-key
|
||||||
{:events [::set-pub-key]}
|
{:events [::set-pub-key]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(let [{:keys [username address custom-domain?]} (:ens/registration db)
|
(let [{:keys [username address custom-domain?]} (:ens/registration db)
|
||||||
address (or address (ethereum/default-address db))
|
address (or address (ethereum/default-address db))
|
||||||
{:keys [public-key]} (:multiaccount db)
|
{:keys [public-key]} (:multiaccount db)
|
||||||
chain-id (ethereum/chain-id db)
|
chain-id (ethereum/chain-id db)
|
||||||
username (fullname custom-domain? username)]
|
username (fullname custom-domain? username)]
|
||||||
(ens/set-pub-key-prepare-tx
|
(ens/set-pub-key-prepare-tx
|
||||||
chain-id address username public-key
|
chain-id
|
||||||
|
address
|
||||||
|
username
|
||||||
|
public-key
|
||||||
#(re-frame/dispatch [:signing.ui/sign
|
#(re-frame/dispatch [:signing.ui/sign
|
||||||
{:tx-obj %
|
{:tx-obj %
|
||||||
:on-result [::save-username custom-domain? username true]
|
:on-result [::save-username custom-domain? username true]
|
||||||
:on-error [::on-registration-failure]}]))))
|
:on-error [::on-registration-failure]}]))))
|
||||||
|
|
||||||
(fx/defn on-input-submitted
|
(rf/defn on-input-submitted
|
||||||
{:events [::input-submitted]}
|
{:events [::input-submitted]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [{:keys [state username custom-domain?]} (:ens/registration db)]
|
(let [{:keys [state username custom-domain?]} (:ens/registration db)]
|
||||||
@@ -135,14 +144,16 @@
|
|||||||
(ens/pubkey
|
(ens/pubkey
|
||||||
chain-id
|
chain-id
|
||||||
(fullname custom-domain? username)
|
(fullname custom-domain? username)
|
||||||
#(re-frame/dispatch [::name-resolved username
|
#(re-frame/dispatch
|
||||||
(cond
|
[::name-resolved username
|
||||||
(not public-key) :owned
|
(cond
|
||||||
(and (string/ends-with? % "0000000000000000000000000000000000000000000000000000000000000000") (not custom-domain?))
|
(not public-key) :owned
|
||||||
:invalid-ens
|
(and (string/ends-with? % "0000000000000000000000000000000000000000000000000000000000000000")
|
||||||
(= % public-key) :connected
|
(not custom-domain?))
|
||||||
:else :connected-with-different-key)
|
:invalid-ens
|
||||||
(eip55/address->checksum response)]))
|
(= % public-key) :connected
|
||||||
|
:else :connected-with-different-key)
|
||||||
|
(eip55/address->checksum response)]))
|
||||||
:else
|
:else
|
||||||
(re-frame/dispatch [::name-resolved username :taken]))))
|
(re-frame/dispatch [::name-resolved username :taken]))))
|
||||||
|
|
||||||
@@ -153,33 +164,40 @@
|
|||||||
5 10
|
5 10
|
||||||
1 10))
|
1 10))
|
||||||
|
|
||||||
(fx/defn register-name
|
(rf/defn register-name
|
||||||
{:events [::register-name-pressed]}
|
{:events [::register-name-pressed]}
|
||||||
[{:keys [db]} address]
|
[{:keys [db]} address]
|
||||||
(let [{:keys [username]}
|
(let [{:keys [username]}
|
||||||
(:ens/registration db)
|
(:ens/registration db)
|
||||||
{:keys [public-key]} (:multiaccount db)
|
{:keys [public-key]} (:multiaccount db)
|
||||||
chain-id (ethereum/chain-id db)]
|
chain-id (ethereum/chain-id db)]
|
||||||
(ens/register-prepare-tx
|
(ens/register-prepare-tx
|
||||||
chain-id address username public-key
|
chain-id
|
||||||
|
address
|
||||||
|
username
|
||||||
|
public-key
|
||||||
#(re-frame/dispatch [:signing.ui/sign
|
#(re-frame/dispatch [:signing.ui/sign
|
||||||
{:tx-obj %
|
{:tx-obj %
|
||||||
:on-result [:update-ens-tx-state-and-redirect :submitted username false]
|
:on-result [:update-ens-tx-state-and-redirect :submitted username false]
|
||||||
:on-error [::on-registration-failure]}]))))
|
:on-error [::on-registration-failure]}]))))
|
||||||
|
|
||||||
(defn- valid-custom-domain? [username]
|
(defn- valid-custom-domain?
|
||||||
|
[username]
|
||||||
(and (ens/is-valid-eth-name? username)
|
(and (ens/is-valid-eth-name? username)
|
||||||
(stateofus/lower-case? username)))
|
(stateofus/lower-case? username)))
|
||||||
|
|
||||||
(defn- valid-username? [custom-domain? username]
|
(defn- valid-username?
|
||||||
|
[custom-domain? username]
|
||||||
(if custom-domain?
|
(if custom-domain?
|
||||||
(valid-custom-domain? username)
|
(valid-custom-domain? username)
|
||||||
(stateofus/valid-username? username)))
|
(stateofus/valid-username? username)))
|
||||||
|
|
||||||
(defn- state [custom-domain? username usernames]
|
(defn- state
|
||||||
|
[custom-domain? username usernames]
|
||||||
(cond
|
(cond
|
||||||
(or (string/blank? username)
|
(or (string/blank? username)
|
||||||
(> 4 (count username))) :too-short
|
(> 4 (count username)))
|
||||||
|
:too-short
|
||||||
(valid-username? custom-domain? username)
|
(valid-username? custom-domain? username)
|
||||||
(if (usernames (fullname custom-domain? username))
|
(if (usernames (fullname custom-domain? username))
|
||||||
:already-added
|
:already-added
|
||||||
@@ -189,79 +207,88 @@
|
|||||||
;;NOTE we want to handle only last resolve
|
;;NOTE we want to handle only last resolve
|
||||||
(def resolve-last-id (atom nil))
|
(def resolve-last-id (atom nil))
|
||||||
|
|
||||||
(fx/defn set-username-candidate
|
(rf/defn set-username-candidate
|
||||||
{:events [::set-username-candidate]}
|
{:events [::set-username-candidate]}
|
||||||
[{:keys [db]} username]
|
[{:keys [db]} username]
|
||||||
(let [{:keys [custom-domain?]} (:ens/registration db)
|
(let [{:keys [custom-domain?]} (:ens/registration db)
|
||||||
usernames (into #{} (get-in db [:multiaccount :usernames]))
|
usernames (into #{} (get-in db [:multiaccount :usernames]))
|
||||||
state (state custom-domain? username usernames)]
|
state (state custom-domain? username usernames)]
|
||||||
(reset! resolve-last-id (random/id))
|
(reset! resolve-last-id (random/id))
|
||||||
(merge
|
(merge
|
||||||
{:db (update db :ens/registration assoc
|
{:db (update db
|
||||||
:username username
|
:ens/registration assoc
|
||||||
:state state)}
|
:username username
|
||||||
|
:state state)}
|
||||||
(when (= state :searching)
|
(when (= state :searching)
|
||||||
(let [{:keys [multiaccount]} db
|
(let [{:keys [multiaccount]} db
|
||||||
{:keys [public-key]} multiaccount
|
{:keys [public-key]} multiaccount
|
||||||
addresses (ethereum/addresses-without-watch db)
|
addresses (ethereum/addresses-without-watch db)
|
||||||
chain-id (ethereum/chain-id db)]
|
chain-id (ethereum/chain-id db)]
|
||||||
{::resolve-owner [chain-id
|
{::resolve-owner [chain-id
|
||||||
(fullname custom-domain? username)
|
(fullname custom-domain? username)
|
||||||
#(on-resolve-owner
|
#(on-resolve-owner
|
||||||
chain-id custom-domain? username addresses public-key %
|
chain-id
|
||||||
resolve-last-id @resolve-last-id)]})))))
|
custom-domain?
|
||||||
|
username
|
||||||
|
addresses
|
||||||
|
public-key
|
||||||
|
%
|
||||||
|
resolve-last-id
|
||||||
|
@resolve-last-id)]})))))
|
||||||
|
|
||||||
(fx/defn return-to-ens-main-screen
|
(rf/defn return-to-ens-main-screen
|
||||||
{:events [::got-it-pressed ::cancel-pressed]}
|
{:events [::got-it-pressed ::cancel-pressed]}
|
||||||
[{:keys [db] :as cofx} _]
|
[{:keys [db] :as cofx} _]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
;; clear registration data
|
;; clear registration data
|
||||||
{:db (dissoc db :ens/registration)}
|
{:db (dissoc db :ens/registration)}
|
||||||
;; we reset navigation so that navigate back doesn't return
|
;; we reset navigation so that navigate back doesn't return
|
||||||
;; into the registration flow
|
;; into the registration flow
|
||||||
(navigation/set-stack-root :profile-stack [:my-profile
|
(navigation/set-stack-root :profile-stack
|
||||||
:ens-main])))
|
[:my-profile
|
||||||
|
:ens-main])))
|
||||||
|
|
||||||
(fx/defn switch-domain-type
|
(rf/defn switch-domain-type
|
||||||
{:events [::switch-domain-type]}
|
{:events [::switch-domain-type]}
|
||||||
[{:keys [db] :as cofx} _]
|
[{:keys [db] :as cofx} _]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(update :ens/registration dissoc :username :state)
|
(update :ens/registration dissoc :username :state)
|
||||||
(update-in [:ens/registration :custom-domain?] not))}))
|
(update-in [:ens/registration :custom-domain?] not))}))
|
||||||
|
|
||||||
(fx/defn change-address
|
(rf/defn change-address
|
||||||
{:events [::change-address]}
|
{:events [::change-address]}
|
||||||
[{:keys [db] :as cofx} _ {:keys [address]}]
|
[{:keys [db] :as cofx} _ {:keys [address]}]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc-in db [:ens/registration :address] address)}
|
{:db (assoc-in db [:ens/registration :address] address)}
|
||||||
(bottom-sheet/hide-bottom-sheet)))
|
(bottom-sheet/hide-bottom-sheet)))
|
||||||
|
|
||||||
(fx/defn save-preferred-name
|
(rf/defn save-preferred-name
|
||||||
{:events [::save-preferred-name]}
|
{:events [::save-preferred-name]}
|
||||||
[cofx name]
|
[cofx name]
|
||||||
(multiaccounts.update/multiaccount-update cofx
|
(multiaccounts.update/multiaccount-update cofx
|
||||||
:preferred-name name
|
:preferred-name
|
||||||
|
name
|
||||||
{}))
|
{}))
|
||||||
|
|
||||||
(fx/defn on-registration-failure
|
(rf/defn on-registration-failure
|
||||||
"TODO not sure there is actually anything to do here
|
"TODO not sure there is actually anything to do here
|
||||||
it should only be called if the user cancels the signing
|
it should only be called if the user cancels the signing
|
||||||
Actual registration failure has not been implemented properly"
|
Actual registration failure has not been implemented properly"
|
||||||
{:events [::on-registration-failure]}
|
{:events [::on-registration-failure]}
|
||||||
[_ _])
|
[_ _])
|
||||||
|
|
||||||
(fx/defn store-name-address
|
(rf/defn store-name-address
|
||||||
{:events [::address-resolved]}
|
{:events [::address-resolved]}
|
||||||
[{:keys [db]} username address]
|
[{:keys [db]} username address]
|
||||||
{:db (assoc-in db [:ens/names username :address] address)})
|
{:db (assoc-in db [:ens/names username :address] address)})
|
||||||
|
|
||||||
(fx/defn store-name-public-key
|
(rf/defn store-name-public-key
|
||||||
{:events [::public-key-resolved]}
|
{:events [::public-key-resolved]}
|
||||||
[{:keys [db]} username public-key]
|
[{:keys [db]} username public-key]
|
||||||
{:db (assoc-in db [:ens/names username :public-key] public-key)})
|
{:db (assoc-in db [:ens/names username :public-key] public-key)})
|
||||||
|
|
||||||
(fx/defn store-expiration-date
|
(rf/defn store-expiration-date
|
||||||
{:events [::get-expiration-time-success]}
|
{:events [::get-expiration-time-success]}
|
||||||
[{:keys [now db]} username timestamp]
|
[{:keys [now db]} username timestamp]
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
@@ -269,11 +296,11 @@
|
|||||||
(datetime/timestamp->year-month-day-date timestamp))
|
(datetime/timestamp->year-month-day-date timestamp))
|
||||||
(assoc-in [:ens/names username :releasable?] (<= timestamp now)))})
|
(assoc-in [:ens/names username :releasable?] (<= timestamp now)))})
|
||||||
|
|
||||||
(fx/defn navigate-to-name
|
(rf/defn navigate-to-name
|
||||||
{:events [::navigate-to-name]}
|
{:events [::navigate-to-name]}
|
||||||
[{:keys [db] :as cofx} username]
|
[{:keys [db] :as cofx} username]
|
||||||
(let [chain-id (ethereum/chain-id db)]
|
(let [chain-id (ethereum/chain-id db)]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{::get-expiration-time
|
{::get-expiration-time
|
||||||
[chain-id
|
[chain-id
|
||||||
(stateofus/username username)
|
(stateofus/username username)
|
||||||
@@ -286,24 +313,27 @@
|
|||||||
#(re-frame/dispatch [::public-key-resolved username %])]}
|
#(re-frame/dispatch [::public-key-resolved username %])]}
|
||||||
(navigation/navigate-to-cofx :ens-name-details username))))
|
(navigation/navigate-to-cofx :ens-name-details username))))
|
||||||
|
|
||||||
(fx/defn start-registration
|
(rf/defn start-registration
|
||||||
{:events [::add-username-pressed ::get-started-pressed]}
|
{:events [::add-username-pressed ::get-started-pressed]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(set-username-candidate (get-in db [:ens/registration :username] ""))
|
(set-username-candidate (get-in db [:ens/registration :username] ""))
|
||||||
(navigation/navigate-to-cofx :ens-search {})))
|
(navigation/navigate-to-cofx :ens-search {})))
|
||||||
|
|
||||||
(fx/defn remove-username
|
(rf/defn remove-username
|
||||||
{:events [::remove-username]}
|
{:events [::remove-username]}
|
||||||
[{:keys [db] :as cofx} name]
|
[{:keys [db] :as cofx} name]
|
||||||
(let [names (get-in db [:multiaccount :usernames] [])
|
(let [names (get-in db [:multiaccount :usernames] [])
|
||||||
preferred-name (get-in db [:multiaccount :preferred-name])
|
preferred-name (get-in db [:multiaccount :preferred-name])
|
||||||
new-names (remove #(= name %) names)]
|
new-names (remove #(= name %) names)]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(multiaccounts.update/multiaccount-update
|
(multiaccounts.update/multiaccount-update
|
||||||
:usernames new-names
|
:usernames
|
||||||
|
new-names
|
||||||
{})
|
{})
|
||||||
(when (= name preferred-name)
|
(when (= name preferred-name)
|
||||||
(multiaccounts.update/multiaccount-update
|
(multiaccounts.update/multiaccount-update
|
||||||
:preferred-name (first new-names) {}))
|
:preferred-name
|
||||||
|
(first new-names)
|
||||||
|
{}))
|
||||||
(navigation/navigate-back))))
|
(navigation/navigate-back))))
|
||||||
|
|||||||
@@ -1,22 +1,23 @@
|
|||||||
(ns status-im.ethereum.subscriptions
|
(ns status-im.ethereum.subscriptions
|
||||||
(:require [status-im.ethereum.eip55 :as eip55]
|
(:require [status-im.ethereum.eip55 :as eip55]
|
||||||
[status-im.wallet.db :as wallet]
|
|
||||||
[status-im.wallet.core :as wallet.core]
|
|
||||||
[status-im.ethereum.transactions.core :as transactions]
|
[status-im.ethereum.transactions.core :as transactions]
|
||||||
[status-im.utils.fx :as fx]
|
[status-im.wallet.core :as wallet.core]
|
||||||
[taoensso.timbre :as log]))
|
[status-im.wallet.db :as wallet]
|
||||||
|
[taoensso.timbre :as log]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(fx/defn new-transfers
|
(rf/defn new-transfers
|
||||||
[cofx block-number accounts]
|
[cofx block-number accounts]
|
||||||
(log/debug "[wallet-subs] new-transfers"
|
(log/debug "[wallet-subs] new-transfers"
|
||||||
"accounts" accounts
|
"accounts" accounts
|
||||||
"block" block-number)
|
"block" block-number)
|
||||||
(transactions/check-watched-transactions cofx))
|
(transactions/check-watched-transactions cofx))
|
||||||
|
|
||||||
(fx/defn recent-history-fetching-started
|
(rf/defn recent-history-fetching-started
|
||||||
[{:keys [db]} accounts]
|
[{:keys [db]} accounts]
|
||||||
(log/debug "[wallet-subs] recent-history-fetching-started"
|
(log/debug "[wallet-subs] recent-history-fetching-started"
|
||||||
"accounts" accounts)
|
"accounts"
|
||||||
|
accounts)
|
||||||
(let [event (get db :wallet/on-recent-history-fetching)]
|
(let [event (get db :wallet/on-recent-history-fetching)]
|
||||||
(cond-> {:db (-> db
|
(cond-> {:db (-> db
|
||||||
(transactions/update-fetching-status accounts :recent? true)
|
(transactions/update-fetching-status accounts :recent? true)
|
||||||
@@ -25,20 +26,21 @@
|
|||||||
event
|
event
|
||||||
(assoc :dispatch event))))
|
(assoc :dispatch event))))
|
||||||
|
|
||||||
(fx/defn recent-history-fetching-ended
|
(rf/defn recent-history-fetching-ended
|
||||||
[{:keys [db]} {:keys [accounts blockNumber]}]
|
[{:keys [db]} {:keys [accounts blockNumber]}]
|
||||||
(log/debug "[wallet-subs] recent-history-fetching-ended"
|
(log/debug "[wallet-subs] recent-history-fetching-ended"
|
||||||
"accounts" accounts
|
"accounts" accounts
|
||||||
"block" blockNumber)
|
"block" blockNumber)
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc :ethereum/current-block blockNumber)
|
(assoc :ethereum/current-block blockNumber)
|
||||||
(update-in [:wallet :accounts]
|
(update-in [:wallet :accounts]
|
||||||
wallet/remove-transactions-since-block blockNumber)
|
wallet/remove-transactions-since-block
|
||||||
(transactions/update-fetching-status accounts :recent? false)
|
blockNumber)
|
||||||
(dissoc :wallet/waiting-for-recent-history?
|
(transactions/update-fetching-status accounts :recent? false)
|
||||||
:wallet/refreshing-history?
|
(dissoc :wallet/waiting-for-recent-history?
|
||||||
:wallet/fetching-error
|
:wallet/refreshing-history?
|
||||||
:wallet/recent-history-fetching-started?))
|
:wallet/fetching-error
|
||||||
|
:wallet/recent-history-fetching-started?))
|
||||||
:transactions/get-transfers
|
:transactions/get-transfers
|
||||||
{:chain-tokens (:wallet/all-tokens db)
|
{:chain-tokens (:wallet/all-tokens db)
|
||||||
:addresses (reduce
|
:addresses (reduce
|
||||||
@@ -53,27 +55,27 @@
|
|||||||
:before-block blockNumber
|
:before-block blockNumber
|
||||||
:limit 20}})
|
:limit 20}})
|
||||||
|
|
||||||
(fx/defn fetching-error
|
(rf/defn fetching-error
|
||||||
[{:keys [db] :as cofx} {:keys [message]}]
|
[{:keys [db] :as cofx} {:keys [message]}]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (assoc db :wallet/fetching-error message)}
|
{:db (assoc db :wallet/fetching-error message)}
|
||||||
(wallet.core/after-checking-history)))
|
(wallet.core/after-checking-history)))
|
||||||
|
|
||||||
(fx/defn non-archival-node-detected
|
(rf/defn non-archival-node-detected
|
||||||
[{:keys [db]} _]
|
[{:keys [db]} _]
|
||||||
{:db (assoc db :wallet/non-archival-node true)})
|
{:db (assoc db :wallet/non-archival-node true)})
|
||||||
|
|
||||||
(fx/defn new-wallet-event
|
(rf/defn new-wallet-event
|
||||||
[cofx {:keys [type blockNumber accounts] :as event}]
|
[cofx {:keys [type blockNumber accounts] :as event}]
|
||||||
(log/info "[wallet-subs] new-wallet-event"
|
(log/info "[wallet-subs] new-wallet-event"
|
||||||
"event-type" type
|
"event-type" type
|
||||||
"blockNumber" blockNumber
|
"blockNumber" blockNumber
|
||||||
"accounts" accounts)
|
"accounts" accounts)
|
||||||
(case type
|
(case type
|
||||||
"new-transfers" (new-transfers cofx blockNumber accounts)
|
"new-transfers" (new-transfers cofx blockNumber accounts)
|
||||||
"recent-history-fetching" (recent-history-fetching-started cofx accounts)
|
"recent-history-fetching" (recent-history-fetching-started cofx accounts)
|
||||||
"recent-history-ready" (recent-history-fetching-ended cofx event)
|
"recent-history-ready" (recent-history-fetching-ended cofx event)
|
||||||
"fetching-history-error" (fetching-error cofx event)
|
"fetching-history-error" (fetching-error cofx event)
|
||||||
"non-archival-node-detected" (non-archival-node-detected cofx event)
|
"non-archival-node-detected" (non-archival-node-detected cofx event)
|
||||||
(log/warn ::unknown-wallet-event :type type :event event)))
|
(log/warn ::unknown-wallet-event :type type :event event)))
|
||||||
|
|||||||
@@ -7,10 +7,10 @@
|
|||||||
[status-im.ethereum.eip55 :as eip55]
|
[status-im.ethereum.eip55 :as eip55]
|
||||||
[status-im.ethereum.encode :as encode]
|
[status-im.ethereum.encode :as encode]
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[status-im.utils.mobile-sync :as utils.mobile-sync]
|
[status-im.utils.mobile-sync :as utils.mobile-sync]
|
||||||
[status-im.wallet.core :as wallet]
|
[status-im.wallet.core :as wallet]
|
||||||
[taoensso.timbre :as log]))
|
[taoensso.timbre :as log]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(def confirmations-count-threshold 12)
|
(def confirmations-count-threshold 12)
|
||||||
|
|
||||||
@@ -23,8 +23,9 @@
|
|||||||
|
|
||||||
(def network->subdomain {5 "goerli"})
|
(def network->subdomain {5 "goerli"})
|
||||||
|
|
||||||
(defn get-transaction-details-url [chain-id hash]
|
(defn get-transaction-details-url
|
||||||
{:pre [(number? chain-id) (string? hash)]
|
[chain-id hash]
|
||||||
|
{:pre [(number? chain-id) (string? hash)]
|
||||||
:post [(or (nil? %) (string? %))]}
|
:post [(or (nil? %) (string? %))]}
|
||||||
(cond
|
(cond
|
||||||
(etherscan-supported? chain-id)
|
(etherscan-supported? chain-id)
|
||||||
@@ -51,15 +52,16 @@
|
|||||||
|
|
||||||
(defn- parse-token-transfer
|
(defn- parse-token-transfer
|
||||||
[chain-tokens contract]
|
[chain-tokens contract]
|
||||||
(let [{:keys [symbol] :as token} (get chain-tokens contract
|
(let [{:keys [symbol] :as token} (get chain-tokens
|
||||||
|
contract
|
||||||
default-erc20-token)]
|
default-erc20-token)]
|
||||||
{:symbol symbol
|
{:symbol symbol
|
||||||
:token token
|
:token token
|
||||||
;; NOTE(goranjovic) - just a flag we need when we merge this entry
|
;; NOTE(goranjovic) - just a flag we need when we merge this entry
|
||||||
;; with the existing entry in the app, e.g. transaction info with
|
;; with the existing entry in the app, e.g. transaction info with
|
||||||
;; gas details, or a previous transfer entry with old confirmations
|
;; gas details, or a previous transfer entry with old confirmations
|
||||||
;; count.
|
;; count.
|
||||||
:transfer true}))
|
:transfer true}))
|
||||||
|
|
||||||
(defn enrich-transfer
|
(defn enrich-transfer
|
||||||
[chain-tokens
|
[chain-tokens
|
||||||
@@ -105,7 +107,7 @@
|
|||||||
|
|
||||||
(def default-transfers-limit 20)
|
(def default-transfers-limit 20)
|
||||||
|
|
||||||
(fx/defn watch-transaction
|
(rf/defn watch-transaction
|
||||||
"Set a watch for the given transaction
|
"Set a watch for the given transaction
|
||||||
`watch-params` needs to contain a `trigger-fn` and `on-trigger` functions
|
`watch-params` needs to contain a `trigger-fn` and `on-trigger` functions
|
||||||
`trigger-fn` is a function that returns true if the watch has been triggered
|
`trigger-fn` is a function that returns true if the watch has been triggered
|
||||||
@@ -114,10 +116,11 @@
|
|||||||
[{:keys [db]} transaction-id {:keys [trigger-fn on-trigger] :as watch-params}]
|
[{:keys [db]} transaction-id {:keys [trigger-fn on-trigger] :as watch-params}]
|
||||||
(when (and (fn? trigger-fn)
|
(when (and (fn? trigger-fn)
|
||||||
(fn? on-trigger))
|
(fn? on-trigger))
|
||||||
{:db (assoc-in db [:ethereum/watched-transactions transaction-id]
|
{:db (assoc-in db
|
||||||
watch-params)}))
|
[:ethereum/watched-transactions transaction-id]
|
||||||
|
watch-params)}))
|
||||||
|
|
||||||
(fx/defn check-transaction
|
(rf/defn check-transaction
|
||||||
"Check if the transaction has been triggered and applies the effects returned
|
"Check if the transaction has been triggered and applies the effects returned
|
||||||
by `on-trigger` if that is the case"
|
by `on-trigger` if that is the case"
|
||||||
[{:keys [db] :as cofx} {:keys [hash] :as transaction}]
|
[{:keys [db] :as cofx} {:keys [hash] :as transaction}]
|
||||||
@@ -125,12 +128,14 @@
|
|||||||
(get-in db [:ethereum/watched-transactions hash])]
|
(get-in db [:ethereum/watched-transactions hash])]
|
||||||
(let [{:keys [trigger-fn on-trigger]} watch-params]
|
(let [{:keys [trigger-fn on-trigger]} watch-params]
|
||||||
(when (trigger-fn db transaction)
|
(when (trigger-fn db transaction)
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (update db :ethereum/watched-transactions
|
{:db (update db
|
||||||
dissoc hash)}
|
:ethereum/watched-transactions
|
||||||
|
dissoc
|
||||||
|
hash)}
|
||||||
(on-trigger transaction))))))
|
(on-trigger transaction))))))
|
||||||
|
|
||||||
(fx/defn check-watched-transactions
|
(rf/defn check-watched-transactions
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [watched-transactions
|
(let [watched-transactions
|
||||||
(reduce-kv (fn [acc _ {:keys [transactions]}]
|
(reduce-kv (fn [acc _ {:keys [transactions]}]
|
||||||
@@ -139,13 +144,13 @@
|
|||||||
(keys (get db :ethereum/watched-transactions)))))
|
(keys (get db :ethereum/watched-transactions)))))
|
||||||
{}
|
{}
|
||||||
(get-in db [:wallet :accounts]))]
|
(get-in db [:wallet :accounts]))]
|
||||||
(apply fx/merge
|
(apply rf/merge
|
||||||
cofx
|
cofx
|
||||||
(map (fn [[_ transaction]]
|
(map (fn [[_ transaction]]
|
||||||
(check-transaction transaction))
|
(check-transaction transaction))
|
||||||
watched-transactions))))
|
watched-transactions))))
|
||||||
|
|
||||||
(fx/defn add-transfer
|
(rf/defn add-transfer
|
||||||
"We determine a unique id for the transfer before adding it because some
|
"We determine a unique id for the transfer before adding it because some
|
||||||
transaction can contain multiple transfers and they would overwrite each other
|
transaction can contain multiple transfers and they would overwrite each other
|
||||||
in the transfer map if identified by hash"
|
in the transfer map if identified by hash"
|
||||||
@@ -157,25 +162,30 @@
|
|||||||
(:type transfer-by-hash))))
|
(:type transfer-by-hash))))
|
||||||
id
|
id
|
||||||
hash))]
|
hash))]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc-in db [:wallet :accounts address :transactions unique-id]
|
{:db (assoc-in db
|
||||||
(assoc transfer :hash unique-id))}
|
[:wallet :accounts address :transactions unique-id]
|
||||||
|
(assoc transfer :hash unique-id))}
|
||||||
(check-transaction transfer)))))
|
(check-transaction transfer)))))
|
||||||
|
|
||||||
(defn get-min-known-block [db address]
|
(defn get-min-known-block
|
||||||
|
[db address]
|
||||||
(get-in db [:wallet :accounts (eip55/address->checksum address) :min-block]))
|
(get-in db [:wallet :accounts (eip55/address->checksum address) :min-block]))
|
||||||
|
|
||||||
(defn get-max-block-with-transfers [db address]
|
(defn get-max-block-with-transfers
|
||||||
|
[db address]
|
||||||
(get-in db [:wallet :accounts (eip55/address->checksum address) :max-block]))
|
(get-in db [:wallet :accounts (eip55/address->checksum address) :max-block]))
|
||||||
|
|
||||||
(defn min-block-transfers-count [db address]
|
(defn min-block-transfers-count
|
||||||
(get-in db [:wallet :accounts
|
[db address]
|
||||||
(eip55/address->checksum address)
|
(get-in db
|
||||||
:min-block-transfers-count]))
|
[:wallet :accounts
|
||||||
|
(eip55/address->checksum address)
|
||||||
|
:min-block-transfers-count]))
|
||||||
|
|
||||||
(fx/defn set-lowest-fetched-block
|
(rf/defn set-lowest-fetched-block
|
||||||
[{:keys [db]} address transfers]
|
[{:keys [db]} address transfers]
|
||||||
(let [checksum (eip55/address->checksum address)
|
(let [checksum (eip55/address->checksum address)
|
||||||
{:keys [min-block min-block-transfers-count]}
|
{:keys [min-block min-block-transfers-count]}
|
||||||
(reduce
|
(reduce
|
||||||
(fn [{:keys [min-block] :as acc}
|
(fn [{:keys [min-block] :as acc}
|
||||||
@@ -198,43 +208,47 @@
|
|||||||
(min-block-transfers-count db address)}
|
(min-block-transfers-count db address)}
|
||||||
transfers)]
|
transfers)]
|
||||||
(log/debug "[transactions] set-lowest-fetched-block"
|
(log/debug "[transactions] set-lowest-fetched-block"
|
||||||
"address" address
|
"address" address
|
||||||
"min-block" min-block
|
"min-block" min-block
|
||||||
"min-block-transfers-count" min-block-transfers-count)
|
"min-block-transfers-count" min-block-transfers-count)
|
||||||
{:db (update-in db [:wallet :accounts checksum] assoc
|
{:db (update-in db
|
||||||
:min-block min-block
|
[:wallet :accounts checksum]
|
||||||
|
assoc
|
||||||
|
:min-block min-block
|
||||||
:min-block-transfers-count min-block-transfers-count)}))
|
:min-block-transfers-count min-block-transfers-count)}))
|
||||||
|
|
||||||
(defn update-fetching-status
|
(defn update-fetching-status
|
||||||
[db addresses fetching-type state]
|
[db addresses fetching-type state]
|
||||||
(update-in
|
(update-in
|
||||||
db [:wallet :fetching]
|
db
|
||||||
|
[:wallet :fetching]
|
||||||
(fn [accounts]
|
(fn [accounts]
|
||||||
(reduce
|
(reduce
|
||||||
(fn [accounts address]
|
(fn [accounts address]
|
||||||
(assoc-in accounts
|
(assoc-in accounts
|
||||||
[(eip55/address->checksum address) fetching-type]
|
[(eip55/address->checksum address) fetching-type]
|
||||||
state))
|
state))
|
||||||
accounts
|
accounts
|
||||||
addresses))))
|
addresses))))
|
||||||
|
|
||||||
(fx/defn tx-fetching-in-progress
|
(rf/defn tx-fetching-in-progress
|
||||||
[{:keys [db]} addresses]
|
[{:keys [db]} addresses]
|
||||||
{:db (update-fetching-status db addresses :history? true)})
|
{:db (update-fetching-status db addresses :history? true)})
|
||||||
|
|
||||||
(fx/defn tx-fetching-ended
|
(rf/defn tx-fetching-ended
|
||||||
[{:keys [db]} addresses]
|
[{:keys [db]} addresses]
|
||||||
{:db (update-fetching-status db addresses :history? false)})
|
{:db (update-fetching-status db addresses :history? false)})
|
||||||
|
|
||||||
(fx/defn tx-history-end-reached
|
(rf/defn tx-history-end-reached
|
||||||
[{:keys [db] :as cofx} address]
|
[{:keys [db] :as cofx} address]
|
||||||
(let [syncing-allowed? (utils.mobile-sync/syncing-allowed? cofx)]
|
(let [syncing-allowed? (utils.mobile-sync/syncing-allowed? cofx)]
|
||||||
{:db (assoc-in db [:wallet :fetching address :all-fetched?]
|
{:db (assoc-in db
|
||||||
(if syncing-allowed?
|
[:wallet :fetching address :all-fetched?]
|
||||||
:all
|
(if syncing-allowed?
|
||||||
:all-preloaded))}))
|
:all
|
||||||
|
:all-preloaded))}))
|
||||||
|
|
||||||
(fx/defn delete-pending-transactions
|
(rf/defn delete-pending-transactions
|
||||||
[{:keys [db]} address transactions]
|
[{:keys [db]} address transactions]
|
||||||
(let [all-transactions
|
(let [all-transactions
|
||||||
(get-in db [:wallet :accounts (eip55/address->checksum address) :transactions])
|
(get-in db [:wallet :accounts (eip55/address->checksum address) :transactions])
|
||||||
@@ -247,38 +261,38 @@
|
|||||||
transactions)]
|
transactions)]
|
||||||
{:wallet/delete-pending-transactions pending-tx-hashes}))
|
{:wallet/delete-pending-transactions pending-tx-hashes}))
|
||||||
|
|
||||||
(fx/defn handle-new-transfer
|
(rf/defn handle-new-transfer
|
||||||
[{:keys [db] :as cofx} transfers {:keys [address limit]}]
|
[{:keys [db] :as cofx} transfers {:keys [address limit]}]
|
||||||
(log/debug "[transfers] new-transfers"
|
(log/debug "[transfers] new-transfers"
|
||||||
"address" address
|
"address" address
|
||||||
"count" (count transfers)
|
"count" (count transfers)
|
||||||
"limit" limit)
|
"limit" limit)
|
||||||
(let [checksum (eip55/address->checksum address)
|
(let [checksum (eip55/address->checksum address)
|
||||||
max-known-block (get-max-block-with-transfers db address)
|
max-known-block (get-max-block-with-transfers db address)
|
||||||
effects (cond-> [(when (seq transfers)
|
effects (cond-> [(when (seq transfers)
|
||||||
(set-lowest-fetched-block checksum transfers))
|
(set-lowest-fetched-block checksum transfers))
|
||||||
(wallet/set-max-block-with-transfers checksum transfers)]
|
(wallet/set-max-block-with-transfers checksum transfers)]
|
||||||
|
|
||||||
(seq transfers)
|
(seq transfers)
|
||||||
(concat
|
(concat
|
||||||
[(delete-pending-transactions address transfers)]
|
[(delete-pending-transactions address transfers)]
|
||||||
(mapv add-transfer transfers))
|
(mapv add-transfer transfers))
|
||||||
|
|
||||||
(and max-known-block
|
(and max-known-block
|
||||||
(some #(> (:block %) max-known-block) transfers))
|
(some #(> (:block %) max-known-block) transfers))
|
||||||
(conj (wallet/update-balances
|
(conj (wallet/update-balances
|
||||||
[address]
|
[address]
|
||||||
(zero? max-known-block)))
|
(zero? max-known-block)))
|
||||||
|
|
||||||
(and (zero? max-known-block)
|
(and (zero? max-known-block)
|
||||||
(empty? transfers))
|
(empty? transfers))
|
||||||
(conj (wallet/set-zero-balances {:address address}))
|
(conj (wallet/set-zero-balances {:address address}))
|
||||||
|
|
||||||
(< (count transfers) limit)
|
(< (count transfers) limit)
|
||||||
(conj (tx-history-end-reached checksum)))]
|
(conj (tx-history-end-reached checksum)))]
|
||||||
(apply fx/merge cofx (tx-fetching-ended [checksum]) effects)))
|
(apply rf/merge cofx (tx-fetching-ended [checksum]) effects)))
|
||||||
|
|
||||||
(fx/defn check-ens-transactions
|
(rf/defn check-ens-transactions
|
||||||
[{:keys [db] :as cofx} transfers]
|
[{:keys [db] :as cofx} transfers]
|
||||||
(let [set-of-transactions-hash (reduce (fn [acc {:keys [hash]}] (conj acc hash)) #{} transfers)
|
(let [set-of-transactions-hash (reduce (fn [acc {:keys [hash]}] (conj acc hash)) #{} transfers)
|
||||||
registrations (filter
|
registrations (filter
|
||||||
@@ -288,12 +302,15 @@
|
|||||||
(contains? set-of-transactions-hash hash)))
|
(contains? set-of-transactions-hash hash)))
|
||||||
(get db :ens/registrations))
|
(get db :ens/registrations))
|
||||||
fxs (map (fn [[hash {:keys [username custom-domain?]}]]
|
fxs (map (fn [[hash {:keys [username custom-domain?]}]]
|
||||||
(let [transfer (first (filter (fn [transfer] (let [transfer-hash (get transfer :hash)] (= transfer-hash hash))) transfers))
|
(let [transfer (first (filter (fn [transfer]
|
||||||
type (get transfer :type)
|
(let [transfer-hash (get transfer :hash)]
|
||||||
|
(= transfer-hash hash)))
|
||||||
|
transfers))
|
||||||
|
type (get transfer :type)
|
||||||
transaction-success (get transfer :transfer)]
|
transaction-success (get transfer :transfer)]
|
||||||
(cond
|
(cond
|
||||||
(= transaction-success true)
|
(= transaction-success true)
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(ens/clear-ens-registration hash)
|
(ens/clear-ens-registration hash)
|
||||||
(ens/save-username custom-domain? username false))
|
(ens/save-username custom-domain? username false))
|
||||||
(= type :failed)
|
(= type :failed)
|
||||||
@@ -301,69 +318,72 @@
|
|||||||
:else
|
:else
|
||||||
nil)))
|
nil)))
|
||||||
registrations)]
|
registrations)]
|
||||||
(apply fx/merge cofx fxs)))
|
(apply rf/merge cofx fxs)))
|
||||||
|
|
||||||
(fx/defn new-transfers
|
(rf/defn new-transfers
|
||||||
{:events [::new-transfers]}
|
{:events [::new-transfers]}
|
||||||
[cofx transfers params]
|
[cofx transfers params]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(handle-new-transfer transfers params)
|
(handle-new-transfer transfers params)
|
||||||
(wallet/stop-fetching-on-empty-tx-history transfers)
|
(wallet/stop-fetching-on-empty-tx-history transfers)
|
||||||
(check-ens-transactions transfers)))
|
(check-ens-transactions transfers)))
|
||||||
|
|
||||||
(fx/defn tx-fetching-failed
|
(rf/defn tx-fetching-failed
|
||||||
{:events [::tx-fetching-failed]}
|
{:events [::tx-fetching-failed]}
|
||||||
[cofx error address]
|
[cofx error address]
|
||||||
(log/debug "[transactions] tx-fetching-failed"
|
(log/debug "[transactions] tx-fetching-failed"
|
||||||
"address" address
|
"address" address
|
||||||
"error" error)
|
"error" error)
|
||||||
(tx-fetching-ended cofx [address]))
|
(tx-fetching-ended cofx [address]))
|
||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
:transactions/get-transfers
|
:transactions/get-transfers
|
||||||
(fn [{:keys [chain-tokens addresses before-block limit
|
(fn
|
||||||
limit-per-address fetch-more?]
|
[{:keys [chain-tokens addresses before-block limit
|
||||||
:as params
|
limit-per-address fetch-more?]
|
||||||
:or {limit default-transfers-limit
|
:as params
|
||||||
|
:or {limit default-transfers-limit
|
||||||
fetch-more? true}}]
|
fetch-more? true}}]
|
||||||
{:pre [(spec/valid?
|
{:pre [(spec/valid?
|
||||||
(spec/coll-of string?)
|
(spec/coll-of string?)
|
||||||
addresses)]}
|
addresses)]}
|
||||||
(log/debug "[transactions] get-transfers"
|
(log/debug "[transactions] get-transfers"
|
||||||
"addresses" addresses
|
"addresses" addresses
|
||||||
"block" before-block
|
"block" before-block
|
||||||
"limit" limit
|
"limit" limit
|
||||||
"limit-per-address" limit-per-address
|
"limit-per-address" limit-per-address
|
||||||
"fetch-more?" fetch-more?)
|
"fetch-more?" fetch-more?)
|
||||||
(doseq [address addresses]
|
(doseq [address addresses]
|
||||||
(let [limit (or (get limit-per-address address)
|
(let [limit (or (get limit-per-address address)
|
||||||
limit)]
|
limit)]
|
||||||
(json-rpc/call
|
(json-rpc/call
|
||||||
{:method "wallet_getTransfersByAddress"
|
{:method "wallet_getTransfersByAddress"
|
||||||
:params [address (encode/uint before-block) (encode/uint limit) fetch-more?]
|
:params [address (encode/uint before-block) (encode/uint limit) fetch-more?]
|
||||||
:on-success #(re-frame/dispatch
|
:on-success #(re-frame/dispatch
|
||||||
[::new-transfers
|
[::new-transfers
|
||||||
(enrich-transfers chain-tokens %)
|
(enrich-transfers chain-tokens %)
|
||||||
(assoc params :address address
|
(assoc params
|
||||||
:limit limit)])
|
:address address
|
||||||
:on-error #(re-frame/dispatch [::tx-fetching-failed address])})))))
|
:limit limit)])
|
||||||
|
:on-error #(re-frame/dispatch [::tx-fetching-failed address])})))))
|
||||||
|
|
||||||
(defn some-transactions-loaded? [db address]
|
(defn some-transactions-loaded?
|
||||||
|
[db address]
|
||||||
(not-empty (get-in db [:wallet :accounts address :transactions])))
|
(not-empty (get-in db [:wallet :accounts address :transactions])))
|
||||||
|
|
||||||
(fx/defn fetch-more-tx
|
(rf/defn fetch-more-tx
|
||||||
{:events [:transactions/fetch-more]}
|
{:events [:transactions/fetch-more]}
|
||||||
[{:keys [db] :as cofx} address]
|
[{:keys [db] :as cofx} address]
|
||||||
(let [min-known-block (or (get-min-known-block db address)
|
(let [min-known-block (or (get-min-known-block db address)
|
||||||
(:ethereum/current-block db))
|
(:ethereum/current-block db))
|
||||||
min-block-transfers-count (or (min-block-transfers-count db address) 0)]
|
min-block-transfers-count (or (min-block-transfers-count db address) 0)]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:transactions/get-transfers
|
{:transactions/get-transfers
|
||||||
{:chain-tokens (:wallet/all-tokens db)
|
{:chain-tokens (:wallet/all-tokens db)
|
||||||
:addresses [address]
|
:addresses [address]
|
||||||
:before-block min-known-block
|
:before-block min-known-block
|
||||||
:fetch-more? (utils.mobile-sync/syncing-allowed? cofx)
|
:fetch-more? (utils.mobile-sync/syncing-allowed? cofx)
|
||||||
;; Transfers are requested before and including `min-known-block` because
|
;; Transfers are requested before and including `min-known-block` because
|
||||||
;; there is no guarantee that all transfers from that block are shown
|
;; there is no guarantee that all transfers from that block are shown
|
||||||
;; already. To make sure that we fetch the whole `default-transfers-limit`
|
;; already. To make sure that we fetch the whole `default-transfers-limit`
|
||||||
@@ -373,7 +393,7 @@
|
|||||||
min-block-transfers-count)}}}
|
min-block-transfers-count)}}}
|
||||||
(tx-fetching-in-progress [address]))))
|
(tx-fetching-in-progress [address]))))
|
||||||
|
|
||||||
(fx/defn get-fetched-transfers
|
(rf/defn get-fetched-transfers
|
||||||
{:events [:transaction/get-fetched-transfers]}
|
{:events [:transaction/get-fetched-transfers]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
{:transactions/get-transfers
|
{:transactions/get-transfers
|
||||||
|
|||||||
+137
-122
@@ -1,64 +1,65 @@
|
|||||||
(ns status-im.events
|
(ns status-im.events
|
||||||
(:require clojure.set
|
(:require
|
||||||
[re-frame.core :as re-frame]
|
clojure.set
|
||||||
status-im.add-new.core
|
[re-frame.core :as re-frame]
|
||||||
[status-im.async-storage.core :as async-storage]
|
status-im.add-new.core
|
||||||
status-im.backup.core
|
[status-im.async-storage.core :as async-storage]
|
||||||
status-im.bootnodes.core
|
status-im.backup.core
|
||||||
status-im.browser.core
|
status-im.bootnodes.core
|
||||||
status-im.browser.permissions
|
status-im.browser.core
|
||||||
[status-im.chat.models :as chat]
|
status-im.browser.permissions
|
||||||
status-im.chat.models.images
|
[status-im.chat.models :as chat]
|
||||||
status-im.chat.models.input
|
status-im.chat.models.images
|
||||||
status-im.chat.models.loading
|
status-im.chat.models.input
|
||||||
status-im.chat.models.transport
|
status-im.chat.models.loading
|
||||||
[status-im.constants :as constants]
|
status-im.chat.models.transport
|
||||||
status-im.contact.block
|
[status-im.constants :as constants]
|
||||||
status-im.contact.chat
|
status-im.contact.block
|
||||||
status-im.contact.core
|
status-im.contact.chat
|
||||||
status-im.currency.core
|
status-im.contact.core
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
status-im.currency.core
|
||||||
status-im.ethereum.subscriptions
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
status-im.fleet.core
|
status-im.ethereum.subscriptions
|
||||||
status-im.http.core
|
status-im.fleet.core
|
||||||
[status-im.i18n.i18n :as i18n]
|
status-im.http.core
|
||||||
[status-im.keycard.core :as keycard]
|
[status-im.i18n.i18n :as i18n]
|
||||||
status-im.log-level.core
|
[status-im.keycard.core :as keycard]
|
||||||
status-im.mailserver.constants
|
status-im.log-level.core
|
||||||
[status-im.mailserver.core :as mailserver]
|
status-im.mailserver.constants
|
||||||
[status-im.multiaccounts.biometric.core :as biometric]
|
[status-im.mailserver.core :as mailserver]
|
||||||
status-im.multiaccounts.login.core
|
[status-im.multiaccounts.biometric.core :as biometric]
|
||||||
status-im.multiaccounts.logout.core
|
status-im.multiaccounts.login.core
|
||||||
status-im.multiaccounts.update.core
|
status-im.multiaccounts.logout.core
|
||||||
[status-im.native-module.core :as status]
|
[status-im.multiaccounts.model :as multiaccounts.model]
|
||||||
[status-im2.navigation.events :as navigation]
|
status-im.multiaccounts.update.core
|
||||||
status-im2.contexts.activity-center.events
|
[status-im.native-module.core :as status]
|
||||||
status-im.pairing.core
|
status-im.network.net-info
|
||||||
status-im.profile.core
|
status-im.pairing.core
|
||||||
status-im.search.core
|
status-im.profile.core
|
||||||
status-im.signals.core
|
status-im.search.core
|
||||||
status-im.stickers.core
|
status-im.signals.core
|
||||||
status-im.transport.core
|
status-im.stickers.core
|
||||||
[status-im.ui.components.permissions :as permissions]
|
status-im.transport.core
|
||||||
[status-im.ui.components.react :as react]
|
[status-im.ui.components.permissions :as permissions]
|
||||||
status-im.ui.screens.privacy-and-security-settings.events
|
[status-im.ui.components.react :as react]
|
||||||
[status-im.utils.dimensions :as dimensions]
|
status-im.ui.screens.privacy-and-security-settings.events
|
||||||
[status-im.utils.fx :as fx]
|
[status-im.utils.dimensions :as dimensions]
|
||||||
status-im.utils.logging.core
|
status-im.utils.logging.core
|
||||||
[status-im.utils.universal-links.core :as universal-links]
|
[status-im.utils.universal-links.core :as universal-links]
|
||||||
[status-im.utils.utils :as utils]
|
[status-im.utils.utils :as utils]
|
||||||
status-im.visibility-status-updates.core
|
status-im.visibility-status-popover.core
|
||||||
status-im.waku.core
|
status-im.visibility-status-updates.core
|
||||||
status-im.wallet.accounts.core
|
status-im.waku.core
|
||||||
status-im.wallet.choose-recipient.core
|
status-im.wallet-connect-legacy.core
|
||||||
[status-im.wallet.core :as wallet]
|
status-im.wallet-connect.core
|
||||||
status-im.wallet.custom-tokens.core
|
status-im.wallet.accounts.core
|
||||||
status-im.wallet-connect.core
|
status-im.wallet.choose-recipient.core
|
||||||
status-im.wallet-connect-legacy.core
|
[status-im.wallet.core :as wallet]
|
||||||
status-im.network.net-info
|
status-im.wallet.custom-tokens.core
|
||||||
status-im.visibility-status-popover.core
|
status-im2.contexts.activity-center.events
|
||||||
status-im2.contexts.shell.events
|
status-im2.contexts.shell.events
|
||||||
[status-im.multiaccounts.model :as multiaccounts.model]))
|
[status-im2.navigation.events :as navigation]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
:dismiss-keyboard
|
:dismiss-keyboard
|
||||||
@@ -95,53 +96,58 @@
|
|||||||
(fn []
|
(fn []
|
||||||
(dimensions/add-event-listener)))
|
(dimensions/add-event-listener)))
|
||||||
|
|
||||||
(fx/defn dismiss-keyboard
|
(rf/defn dismiss-keyboard
|
||||||
{:events [:dismiss-keyboard]}
|
{:events [:dismiss-keyboard]}
|
||||||
[_]
|
[_]
|
||||||
{:dismiss-keyboard nil})
|
{:dismiss-keyboard nil})
|
||||||
|
|
||||||
(fx/defn identicon-generated
|
(rf/defn identicon-generated
|
||||||
{:events [:identicon-generated]}
|
{:events [:identicon-generated]}
|
||||||
[{:keys [db]} path identicon]
|
[{:keys [db]} path identicon]
|
||||||
{:db (assoc-in db path identicon)})
|
{:db (assoc-in db path identicon)})
|
||||||
|
|
||||||
(fx/defn gfycat-generated
|
(rf/defn gfycat-generated
|
||||||
{:events [:gfycat-generated]}
|
{:events [:gfycat-generated]}
|
||||||
[{:keys [db]} path gfycat]
|
[{:keys [db]} path gfycat]
|
||||||
{:db (assoc-in db path gfycat)})
|
{:db (assoc-in db path gfycat)})
|
||||||
|
|
||||||
(fx/defn system-theme-mode-changed
|
(rf/defn system-theme-mode-changed
|
||||||
{:events [:system-theme-mode-changed]}
|
{:events [:system-theme-mode-changed]}
|
||||||
[cofx _]
|
[cofx _]
|
||||||
(when (multiaccounts.model/logged-in? cofx)
|
(when (multiaccounts.model/logged-in? cofx)
|
||||||
{:multiaccounts.ui/switch-theme (get-in cofx [:db :multiaccount :appearance])
|
{:multiaccounts.ui/switch-theme (get-in cofx [:db :multiaccount :appearance])
|
||||||
:dispatch [:reload-new-ui]}))
|
:dispatch [:reload-new-ui]}))
|
||||||
|
|
||||||
(def authentication-options
|
(def authentication-options
|
||||||
{:reason (i18n/label :t/biometric-auth-reason-login)})
|
{:reason (i18n/label :t/biometric-auth-reason-login)})
|
||||||
|
|
||||||
(defn- on-biometric-auth-result [{:keys [bioauth-success bioauth-code bioauth-message]}]
|
(defn- on-biometric-auth-result
|
||||||
|
[{:keys [bioauth-success bioauth-code bioauth-message]}]
|
||||||
(when-not bioauth-success
|
(when-not bioauth-success
|
||||||
(if (= bioauth-code "USER_FALLBACK")
|
(if (= bioauth-code "USER_FALLBACK")
|
||||||
(re-frame/dispatch [:multiaccounts.logout.ui/logout-confirmed])
|
(re-frame/dispatch [:multiaccounts.logout.ui/logout-confirmed])
|
||||||
(utils/show-confirmation {:title (i18n/label :t/biometric-auth-confirm-title)
|
(utils/show-confirmation
|
||||||
:content (or bioauth-message (i18n/label :t/biometric-auth-confirm-message))
|
{:title (i18n/label :t/biometric-auth-confirm-title)
|
||||||
:confirm-button-text (i18n/label :t/biometric-auth-confirm-try-again)
|
:content (or bioauth-message (i18n/label :t/biometric-auth-confirm-message))
|
||||||
:cancel-button-text (i18n/label :t/biometric-auth-confirm-logout)
|
:confirm-button-text (i18n/label :t/biometric-auth-confirm-try-again)
|
||||||
:on-accept #(biometric/authenticate nil on-biometric-auth-result authentication-options)
|
:cancel-button-text (i18n/label :t/biometric-auth-confirm-logout)
|
||||||
:on-cancel #(re-frame/dispatch [:multiaccounts.logout.ui/logout-confirmed])}))))
|
:on-accept #(biometric/authenticate nil
|
||||||
|
on-biometric-auth-result
|
||||||
|
authentication-options)
|
||||||
|
:on-cancel #(re-frame/dispatch [:multiaccounts.logout.ui/logout-confirmed])}))))
|
||||||
|
|
||||||
(fx/defn on-return-from-background [{:keys [db now] :as cofx}]
|
(rf/defn on-return-from-background
|
||||||
|
[{:keys [db now] :as cofx}]
|
||||||
(let [app-in-background-since (get db :app-in-background-since)
|
(let [app-in-background-since (get db :app-in-background-since)
|
||||||
signed-up? (get-in db [:multiaccount :signed-up?])
|
signed-up? (get-in db [:multiaccount :signed-up?])
|
||||||
biometric-auth? (= (:auth-method db) "biometric")
|
biometric-auth? (= (:auth-method db) "biometric")
|
||||||
requires-bio-auth (and
|
requires-bio-auth (and
|
||||||
signed-up?
|
signed-up?
|
||||||
biometric-auth?
|
biometric-auth?
|
||||||
(some? app-in-background-since)
|
(some? app-in-background-since)
|
||||||
(>= (- now app-in-background-since)
|
(>= (- now app-in-background-since)
|
||||||
constants/ms-in-bg-for-require-bioauth))]
|
constants/ms-in-bg-for-require-bioauth))]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (dissoc db :app-in-background-since)}
|
{:db (dissoc db :app-in-background-since)}
|
||||||
(mailserver/process-next-messages-request)
|
(mailserver/process-next-messages-request)
|
||||||
(wallet/restart-wallet-service-after-background app-in-background-since)
|
(wallet/restart-wallet-service-after-background app-in-background-since)
|
||||||
@@ -151,17 +157,17 @@
|
|||||||
#(when requires-bio-auth
|
#(when requires-bio-auth
|
||||||
(biometric/authenticate % on-biometric-auth-result authentication-options)))))
|
(biometric/authenticate % on-biometric-auth-result authentication-options)))))
|
||||||
|
|
||||||
(fx/defn on-going-in-background
|
(rf/defn on-going-in-background
|
||||||
[{:keys [db now]}]
|
[{:keys [db now]}]
|
||||||
{:db (assoc db :app-in-background-since now)
|
{:db (assoc db :app-in-background-since now)
|
||||||
:dispatch-n [[:audio-recorder/on-background] [:audio-message/on-background]]})
|
:dispatch-n [[:audio-recorder/on-background] [:audio-message/on-background]]})
|
||||||
|
|
||||||
(fx/defn app-state-change
|
(rf/defn app-state-change
|
||||||
{:events [:app-state-change]}
|
{:events [:app-state-change]}
|
||||||
[{:keys [db] :as cofx} state]
|
[{:keys [db] :as cofx} state]
|
||||||
(let [app-coming-from-background? (= state "active")
|
(let [app-coming-from-background? (= state "active")
|
||||||
app-going-in-background? (= state "background")]
|
app-going-in-background? (= state "background")]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{::app-state-change-fx state
|
{::app-state-change-fx state
|
||||||
:db (assoc db :app-state state)}
|
:db (assoc db :app-state state)}
|
||||||
#(when app-coming-from-background?
|
#(when app-coming-from-background?
|
||||||
@@ -169,31 +175,31 @@
|
|||||||
#(when app-going-in-background?
|
#(when app-going-in-background?
|
||||||
(on-going-in-background %)))))
|
(on-going-in-background %)))))
|
||||||
|
|
||||||
(fx/defn request-permissions
|
(rf/defn request-permissions
|
||||||
{:events [:request-permissions]}
|
{:events [:request-permissions]}
|
||||||
[_ options]
|
[_ options]
|
||||||
{:request-permissions-fx options})
|
{:request-permissions-fx options})
|
||||||
|
|
||||||
(fx/defn update-window-dimensions
|
(rf/defn update-window-dimensions
|
||||||
{:events [:update-window-dimensions]}
|
{:events [:update-window-dimensions]}
|
||||||
[{:keys [db]} dimensions]
|
[{:keys [db]} dimensions]
|
||||||
{:db (assoc db :dimensions/window (dimensions/window dimensions))})
|
{:db (assoc db :dimensions/window (dimensions/window dimensions))})
|
||||||
|
|
||||||
(fx/defn init-timeline-chat
|
(rf/defn init-timeline-chat
|
||||||
{:events [:init-timeline-chat]}
|
{:events [:init-timeline-chat]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(when-not (get-in db [:pagination-info constants/timeline-chat-id :messages-initialized?])
|
(when-not (get-in db [:pagination-info constants/timeline-chat-id :messages-initialized?])
|
||||||
(chat/preload-chat-data cofx constants/timeline-chat-id)))
|
(chat/preload-chat-data cofx constants/timeline-chat-id)))
|
||||||
|
|
||||||
(fx/defn on-will-focus
|
(rf/defn on-will-focus
|
||||||
{:events [:screens/on-will-focus]}
|
{:events [:screens/on-will-focus]}
|
||||||
[{:keys [db] :as cofx} view-id]
|
[{:keys [db] :as cofx} view-id]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(cond
|
(cond
|
||||||
(= :chat view-id)
|
(= :chat view-id)
|
||||||
{::async-storage/set! {:chat-id (get-in cofx [:db :current-chat-id])
|
{::async-storage/set! {:chat-id (get-in cofx [:db :current-chat-id])
|
||||||
:key-uid (get-in cofx [:db :multiaccount :key-uid])}
|
:key-uid (get-in cofx [:db :multiaccount :key-uid])}
|
||||||
:db (assoc db :screens/was-focused-once? true)}
|
:db (assoc db :screens/was-focused-once? true)}
|
||||||
|
|
||||||
(= :login view-id)
|
(= :login view-id)
|
||||||
{}
|
{}
|
||||||
@@ -204,47 +210,49 @@
|
|||||||
:else
|
:else
|
||||||
{::async-storage/set! {:chat-id nil
|
{::async-storage/set! {:chat-id nil
|
||||||
:key-uid nil}
|
:key-uid nil}
|
||||||
:db (assoc db :screens/was-focused-once? true)})
|
:db (assoc db :screens/was-focused-once? true)})
|
||||||
#(case view-id
|
#(case view-id
|
||||||
:keycard-settings (keycard/settings-screen-did-load %)
|
:keycard-settings (keycard/settings-screen-did-load %)
|
||||||
:reset-card (keycard/reset-card-screen-did-load %)
|
:reset-card (keycard/reset-card-screen-did-load %)
|
||||||
:enter-pin-settings (keycard/enter-pin-screen-did-load %)
|
:enter-pin-settings (keycard/enter-pin-screen-did-load %)
|
||||||
:keycard-login-pin (keycard/login-pin-screen-did-load %)
|
:keycard-login-pin (keycard/login-pin-screen-did-load %)
|
||||||
:add-new-account-pin (keycard/enter-pin-screen-did-load %)
|
:add-new-account-pin (keycard/enter-pin-screen-did-load %)
|
||||||
:keycard-authentication-method (keycard/authentication-method-screen-did-load %)
|
:keycard-authentication-method (keycard/authentication-method-screen-did-load %)
|
||||||
:multiaccounts (keycard/multiaccounts-screen-did-load %)
|
:multiaccounts (keycard/multiaccounts-screen-did-load %)
|
||||||
:wallet (wallet/wallet-will-focus %)
|
:wallet (wallet/wallet-will-focus %)
|
||||||
nil)))
|
nil)))
|
||||||
|
|
||||||
;;TODO :replace by named events
|
;;TODO :replace by named events
|
||||||
(fx/defn set-event
|
(rf/defn set-event
|
||||||
{:events [:set]}
|
{:events [:set]}
|
||||||
[{:keys [db]} k v]
|
[{:keys [db]} k v]
|
||||||
{:db (assoc db k v)})
|
{:db (assoc db k v)})
|
||||||
|
|
||||||
(fx/defn set-view-id
|
(rf/defn set-view-id
|
||||||
{:events [:set-view-id]}
|
{:events [:set-view-id]}
|
||||||
[{:keys [db]} view-id]
|
[{:keys [db]} view-id]
|
||||||
{:db (assoc db :view-id view-id)})
|
{:db (assoc db :view-id view-id)})
|
||||||
|
|
||||||
;;TODO :replace by named events
|
;;TODO :replace by named events
|
||||||
(fx/defn set-once-event
|
(rf/defn set-once-event
|
||||||
{:events [:set-once]}
|
{:events [:set-once]}
|
||||||
[{:keys [db]} k v]
|
[{:keys [db]} k v]
|
||||||
(when-not (get db k)
|
(when-not (get db k)
|
||||||
{:db (assoc db k v)}))
|
{:db (assoc db k v)}))
|
||||||
|
|
||||||
;;TODO :replace by named events
|
;;TODO :replace by named events
|
||||||
(fx/defn set-in-event
|
(rf/defn set-in-event
|
||||||
{:events [:set-in]}
|
{:events [:set-in]}
|
||||||
[{:keys [db]} path v]
|
[{:keys [db]} path v]
|
||||||
{:db (assoc-in db path v)})
|
{:db (assoc-in db path v)})
|
||||||
|
|
||||||
(defn on-ramp<-rpc [on-ramp]
|
(defn on-ramp<-rpc
|
||||||
(clojure.set/rename-keys on-ramp {:logoUrl :logo-url
|
[on-ramp]
|
||||||
:siteUrl :site-url}))
|
(clojure.set/rename-keys on-ramp
|
||||||
|
{:logoUrl :logo-url
|
||||||
|
:siteUrl :site-url}))
|
||||||
|
|
||||||
(fx/defn crypto-loaded-event
|
(rf/defn crypto-loaded-event
|
||||||
{:events [::crypto-loaded]}
|
{:events [::crypto-loaded]}
|
||||||
[{:keys [db]} on-ramps]
|
[{:keys [db]} on-ramps]
|
||||||
{:db (assoc
|
{:db (assoc
|
||||||
@@ -252,7 +260,7 @@
|
|||||||
:buy-crypto/on-ramps
|
:buy-crypto/on-ramps
|
||||||
(map on-ramp<-rpc on-ramps))})
|
(map on-ramp<-rpc on-ramps))})
|
||||||
|
|
||||||
(fx/defn buy-crypto-ui-loaded
|
(rf/defn buy-crypto-ui-loaded
|
||||||
{:events [:buy-crypto.ui/loaded]}
|
{:events [:buy-crypto.ui/loaded]}
|
||||||
[_]
|
[_]
|
||||||
{::json-rpc/call [{:method "wallet_getCryptoOnRamps"
|
{::json-rpc/call [{:method "wallet_getCryptoOnRamps"
|
||||||
@@ -260,10 +268,10 @@
|
|||||||
:on-success (fn [on-ramps]
|
:on-success (fn [on-ramps]
|
||||||
(re-frame/dispatch [::crypto-loaded on-ramps]))}]})
|
(re-frame/dispatch [::crypto-loaded on-ramps]))}]})
|
||||||
|
|
||||||
(fx/defn open-buy-crypto-screen
|
(rf/defn open-buy-crypto-screen
|
||||||
{:events [:buy-crypto.ui/open-screen]}
|
{:events [:buy-crypto.ui/open-screen]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
(navigation/open-modal :buy-crypto nil)
|
(navigation/open-modal :buy-crypto nil)
|
||||||
(wallet/keep-watching-history)))
|
(wallet/keep-watching-history)))
|
||||||
@@ -275,38 +283,45 @@
|
|||||||
:global? true/false (close information box across all profiles)}]"
|
:global? true/false (close information box across all profiles)}]"
|
||||||
[])
|
[])
|
||||||
|
|
||||||
(defn information-box-id-hash [id public-key global?]
|
(defn information-box-id-hash
|
||||||
|
[id public-key global?]
|
||||||
(if global?
|
(if global?
|
||||||
(hash id)
|
(hash id)
|
||||||
(hash (str public-key id))))
|
(hash (str public-key id))))
|
||||||
|
|
||||||
(fx/defn close-information-box
|
(rf/defn close-information-box
|
||||||
{:events [:close-information-box]}
|
{:events [:close-information-box]}
|
||||||
[{:keys [db]} id global?]
|
[{:keys [db]} id global?]
|
||||||
(let [public-key (get-in db [:multiaccount :public-key])
|
(let [public-key (get-in db [:multiaccount :public-key])
|
||||||
hash (information-box-id-hash id public-key global?)]
|
hash (information-box-id-hash id public-key global?)]
|
||||||
{::async-storage/set! {hash true}
|
{::async-storage/set! {hash true}
|
||||||
:db (assoc-in db [:information-box-states id] true)}))
|
:db (assoc-in db [:information-box-states id] true)}))
|
||||||
|
|
||||||
(fx/defn information-box-states-loaded
|
(rf/defn information-box-states-loaded
|
||||||
{:events [:information-box-states-loaded]}
|
{:events [:information-box-states-loaded]}
|
||||||
[{:keys [db]} hashes states]
|
[{:keys [db]} hashes states]
|
||||||
{:db (assoc db :information-box-states (reduce
|
{:db (assoc db
|
||||||
(fn [acc [id hash]]
|
:information-box-states
|
||||||
(assoc acc id (get states hash)))
|
(reduce
|
||||||
{} hashes))})
|
(fn [acc [id hash]]
|
||||||
|
(assoc acc id (get states hash)))
|
||||||
|
{}
|
||||||
|
hashes))})
|
||||||
|
|
||||||
(fx/defn load-information-box-states
|
(rf/defn load-information-box-states
|
||||||
{:events [:load-information-box-states]}
|
{:events [:load-information-box-states]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(let [public-key (get-in db [:multiaccount :public-key])
|
(let [public-key (get-in db [:multiaccount :public-key])
|
||||||
{:keys [keys hashes]} (reduce (fn [acc {:keys [id global?]}]
|
{:keys [keys hashes]} (reduce (fn [acc {:keys [id global?]}]
|
||||||
(let [hash (information-box-id-hash
|
(let [hash (information-box-id-hash
|
||||||
id public-key global?)]
|
id
|
||||||
|
public-key
|
||||||
|
global?)]
|
||||||
(-> acc
|
(-> acc
|
||||||
(assoc-in [:hashes id] hash)
|
(assoc-in [:hashes id] hash)
|
||||||
(update :keys #(conj % hash)))))
|
(update :keys #(conj % hash)))))
|
||||||
{} closable-information-boxes)]
|
{}
|
||||||
|
closable-information-boxes)]
|
||||||
{::async-storage/get {:keys keys
|
{::async-storage/get {:keys keys
|
||||||
:cb #(re-frame/dispatch
|
:cb #(re-frame/dispatch
|
||||||
[:information-box-states-loaded hashes %])}}))
|
[:information-box-states-loaded hashes %])}}))
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
[status-im.multiaccounts.update.core :as multiaccounts.update]
|
[status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||||
[status-im.node.core :as node]
|
[status-im.node.core :as node]
|
||||||
[status-im.utils.config :as config]
|
[status-im.utils.config :as config]
|
||||||
[status-im.utils.fx :as fx]))
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(defn current-fleet-sub
|
(defn current-fleet-sub
|
||||||
[multiaccount]
|
[multiaccount]
|
||||||
@@ -14,10 +14,10 @@
|
|||||||
|
|
||||||
(defn format-mailserver
|
(defn format-mailserver
|
||||||
[mailserver address]
|
[mailserver address]
|
||||||
{:id mailserver
|
{:id mailserver
|
||||||
:name (name mailserver)
|
:name (name mailserver)
|
||||||
:password constants/mailserver-password
|
:password constants/mailserver-password
|
||||||
:address address})
|
:address address})
|
||||||
|
|
||||||
(defn format-mailservers
|
(defn format-mailservers
|
||||||
[mailservers]
|
[mailservers]
|
||||||
@@ -26,13 +26,14 @@
|
|||||||
{}
|
{}
|
||||||
mailservers))
|
mailservers))
|
||||||
|
|
||||||
(defn default-mailservers [db]
|
(defn default-mailservers
|
||||||
|
[db]
|
||||||
(reduce (fn [acc [fleet node-by-type]]
|
(reduce (fn [acc [fleet node-by-type]]
|
||||||
(assoc acc fleet (format-mailservers (:mail node-by-type))))
|
(assoc acc fleet (format-mailservers (:mail node-by-type))))
|
||||||
{}
|
{}
|
||||||
(node/fleets db)))
|
(node/fleets db)))
|
||||||
|
|
||||||
(fx/defn show-save-confirmation
|
(rf/defn show-save-confirmation
|
||||||
{:events [:fleet.ui/fleet-selected]}
|
{:events [:fleet.ui/fleet-selected]}
|
||||||
[_ fleet]
|
[_ fleet]
|
||||||
{:ui/show-confirmation
|
{:ui/show-confirmation
|
||||||
@@ -44,7 +45,8 @@
|
|||||||
#(re-frame/dispatch [:fleet.ui/save-fleet-confirmed (keyword fleet)])
|
#(re-frame/dispatch [:fleet.ui/save-fleet-confirmed (keyword fleet)])
|
||||||
:on-cancel nil}})
|
:on-cancel nil}})
|
||||||
|
|
||||||
(defn nodes->fleet [nodes]
|
(defn nodes->fleet
|
||||||
|
[nodes]
|
||||||
(letfn [(format-nodes [nodes]
|
(letfn [(format-nodes [nodes]
|
||||||
(reduce (fn [acc n]
|
(reduce (fn [acc n]
|
||||||
(assoc acc
|
(assoc acc
|
||||||
@@ -52,28 +54,30 @@
|
|||||||
n))
|
n))
|
||||||
{}
|
{}
|
||||||
nodes))]
|
nodes))]
|
||||||
{:boot (format-nodes nodes)
|
{:boot (format-nodes nodes)
|
||||||
:mail (format-nodes nodes)
|
:mail (format-nodes nodes)
|
||||||
:whisper (format-nodes nodes)}))
|
:whisper (format-nodes nodes)}))
|
||||||
|
|
||||||
(fx/defn set-nodes [{:keys [db]} fleet nodes]
|
(rf/defn set-nodes
|
||||||
|
[{:keys [db]} fleet nodes]
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:custom-fleets fleet] (nodes->fleet nodes))
|
(assoc-in [:custom-fleets fleet] (nodes->fleet nodes))
|
||||||
(assoc-in [:mailserver/mailservers fleet] (format-mailservers
|
(assoc-in [:mailserver/mailservers fleet]
|
||||||
(reduce
|
(format-mailservers
|
||||||
(fn [acc e]
|
(reduce
|
||||||
(assoc acc
|
(fn [acc e]
|
||||||
(keyword e)
|
(assoc acc
|
||||||
e))
|
(keyword e)
|
||||||
{}
|
e))
|
||||||
nodes))))})
|
{}
|
||||||
|
nodes))))})
|
||||||
|
|
||||||
(fx/defn save
|
(rf/defn save
|
||||||
{:events [:fleet.ui/save-fleet-confirmed]}
|
{:events [:fleet.ui/save-fleet-confirmed]}
|
||||||
[{:keys [db now] :as cofx} fleet]
|
[{:keys [db now] :as cofx} fleet]
|
||||||
(let [old-fleet (get-in db [:multiaccount :fleet])]
|
(let [old-fleet (get-in db [:multiaccount :fleet])]
|
||||||
(when (not= fleet old-fleet)
|
(when (not= fleet old-fleet)
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
(multiaccounts.update/multiaccount-update :fleet fleet {})
|
(multiaccounts.update/multiaccount-update :fleet fleet {})
|
||||||
(node/prepare-new-config
|
(node/prepare-new-config
|
||||||
|
|||||||
@@ -4,35 +4,36 @@
|
|||||||
[clojure.string :as string]
|
[clojure.string :as string]
|
||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
[status-im.chat.models :as models.chat]
|
[status-im.chat.models :as models.chat]
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
|
||||||
[status-im2.navigation.events :as navigation]
|
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[status-im.constants :as constants]
|
[status-im.constants :as constants]
|
||||||
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
[status-im.i18n.i18n :as i18n]
|
[status-im.i18n.i18n :as i18n]
|
||||||
[status-im2.contexts.activity-center.events :as activity-center]))
|
[status-im2.contexts.activity-center.events :as activity-center]
|
||||||
|
[status-im2.navigation.events :as navigation]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(fx/defn navigate-chat-updated
|
(rf/defn navigate-chat-updated
|
||||||
{:events [:navigate-chat-updated]}
|
{:events [:navigate-chat-updated]}
|
||||||
[cofx chat-id]
|
[cofx chat-id]
|
||||||
(when (get-in cofx [:db :chats chat-id])
|
(when (get-in cofx [:db :chats chat-id])
|
||||||
(models.chat/navigate-to-chat cofx chat-id)))
|
(models.chat/navigate-to-chat cofx chat-id)))
|
||||||
|
|
||||||
(fx/defn handle-chat-removed
|
(rf/defn handle-chat-removed
|
||||||
{:events [:chat-removed]}
|
{:events [:chat-removed]}
|
||||||
[cofx response]
|
[cofx response]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (dissoc (:db cofx) :current-chat-id)
|
{:db (dissoc (:db cofx) :current-chat-id)
|
||||||
:dispatch-n [[:sanitize-messages-and-process-response response]
|
:dispatch-n [[:sanitize-messages-and-process-response response]
|
||||||
[:pop-to-root-tab :chat-stack]]}
|
[:pop-to-root-tab :chat-stack]]}
|
||||||
(activity-center/notifications-fetch-unread-count)))
|
(activity-center/notifications-fetch-unread-count)))
|
||||||
|
|
||||||
(fx/defn handle-chat-update
|
(rf/defn handle-chat-update
|
||||||
{:events [:chat-updated]}
|
{:events [:chat-updated]}
|
||||||
[_ response do-not-navigate?]
|
[_ response do-not-navigate?]
|
||||||
{:dispatch-n [[:sanitize-messages-and-process-response response]
|
{:dispatch-n [[:sanitize-messages-and-process-response response]
|
||||||
(when-not do-not-navigate? [:navigate-chat-updated (.-id (aget (.-chats response) 0))])]})
|
(when-not do-not-navigate?
|
||||||
|
[:navigate-chat-updated (.-id (aget (.-chats response) 0))])]})
|
||||||
|
|
||||||
(fx/defn remove-member
|
(rf/defn remove-member
|
||||||
"Format group update message and sign membership"
|
"Format group update message and sign membership"
|
||||||
{:events [:group-chats.ui/remove-member-pressed]}
|
{:events [:group-chats.ui/remove-member-pressed]}
|
||||||
[_ chat-id member do-not-navigate?]
|
[_ chat-id member do-not-navigate?]
|
||||||
@@ -41,7 +42,7 @@
|
|||||||
:js-response true
|
:js-response true
|
||||||
:on-success #(re-frame/dispatch [:chat-updated % do-not-navigate?])}]})
|
:on-success #(re-frame/dispatch [:chat-updated % do-not-navigate?])}]})
|
||||||
|
|
||||||
(fx/defn join-chat
|
(rf/defn join-chat
|
||||||
{:events [:group-chats.ui/join-pressed]}
|
{:events [:group-chats.ui/join-pressed]}
|
||||||
[_ chat-id]
|
[_ chat-id]
|
||||||
{::json-rpc/call [{:method "wakuext_confirmJoiningGroup"
|
{::json-rpc/call [{:method "wakuext_confirmJoiningGroup"
|
||||||
@@ -49,7 +50,7 @@
|
|||||||
:js-response true
|
:js-response true
|
||||||
:on-success #(re-frame/dispatch [:chat-updated %])}]})
|
:on-success #(re-frame/dispatch [:chat-updated %])}]})
|
||||||
|
|
||||||
(fx/defn create
|
(rf/defn create
|
||||||
{:events [:group-chats.ui/create-pressed]
|
{:events [:group-chats.ui/create-pressed]
|
||||||
:interceptors [(re-frame/inject-cofx :random-guid-generator)]}
|
:interceptors [(re-frame/inject-cofx :random-guid-generator)]}
|
||||||
[{:keys [db] :as cofx} group-name]
|
[{:keys [db] :as cofx} group-name]
|
||||||
@@ -59,7 +60,7 @@
|
|||||||
:js-response true
|
:js-response true
|
||||||
:on-success #(re-frame/dispatch [:chat-updated %])}]}))
|
:on-success #(re-frame/dispatch [:chat-updated %])}]}))
|
||||||
|
|
||||||
(fx/defn create-from-link
|
(rf/defn create-from-link
|
||||||
[cofx {:keys [chat-id invitation-admin chat-name]}]
|
[cofx {:keys [chat-id invitation-admin chat-name]}]
|
||||||
(if (get-in cofx [:db :chats chat-id])
|
(if (get-in cofx [:db :chats chat-id])
|
||||||
{:dispatch [:chat.ui/navigate-to-chat chat-id]}
|
{:dispatch [:chat.ui/navigate-to-chat chat-id]}
|
||||||
@@ -68,7 +69,7 @@
|
|||||||
:js-response true
|
:js-response true
|
||||||
:on-success #(re-frame/dispatch [:chat-updated %])}]}))
|
:on-success #(re-frame/dispatch [:chat-updated %])}]}))
|
||||||
|
|
||||||
(fx/defn make-admin
|
(rf/defn make-admin
|
||||||
{:events [:group-chats.ui/make-admin-pressed]}
|
{:events [:group-chats.ui/make-admin-pressed]}
|
||||||
[_ chat-id member]
|
[_ chat-id member]
|
||||||
{::json-rpc/call [{:method "wakuext_addAdminsToGroupChat"
|
{::json-rpc/call [{:method "wakuext_addAdminsToGroupChat"
|
||||||
@@ -76,7 +77,7 @@
|
|||||||
:js-response true
|
:js-response true
|
||||||
:on-success #(re-frame/dispatch [:chat-updated %])}]})
|
:on-success #(re-frame/dispatch [:chat-updated %])}]})
|
||||||
|
|
||||||
(fx/defn add-members
|
(rf/defn add-members
|
||||||
"Add members to a group chat"
|
"Add members to a group chat"
|
||||||
{:events [:group-chats.ui/add-members-pressed]}
|
{:events [:group-chats.ui/add-members-pressed]}
|
||||||
[{{:keys [current-chat-id selected-participants]} :db :as cofx}]
|
[{{:keys [current-chat-id selected-participants]} :db :as cofx}]
|
||||||
@@ -85,7 +86,7 @@
|
|||||||
:js-response true
|
:js-response true
|
||||||
:on-success #(re-frame/dispatch [:chat-updated %])}]})
|
:on-success #(re-frame/dispatch [:chat-updated %])}]})
|
||||||
|
|
||||||
(fx/defn add-members-from-invitation
|
(rf/defn add-members-from-invitation
|
||||||
"Add members to a group chat"
|
"Add members to a group chat"
|
||||||
{:events [:group-chats.ui/add-members-from-invitation]}
|
{:events [:group-chats.ui/add-members-from-invitation]}
|
||||||
[{{:keys [current-chat-id] :as db} :db :as cofx} id participant]
|
[{{:keys [current-chat-id] :as db} :db :as cofx} id participant]
|
||||||
@@ -95,7 +96,7 @@
|
|||||||
:js-response true
|
:js-response true
|
||||||
:on-success #(re-frame/dispatch [:chat-updated %])}]})
|
:on-success #(re-frame/dispatch [:chat-updated %])}]})
|
||||||
|
|
||||||
(fx/defn leave
|
(rf/defn leave
|
||||||
"Leave chat"
|
"Leave chat"
|
||||||
{:events [:group-chats.ui/leave-chat-confirmed]}
|
{:events [:group-chats.ui/leave-chat-confirmed]}
|
||||||
[{:keys [db] :as cofx} chat-id]
|
[{:keys [db] :as cofx} chat-id]
|
||||||
@@ -104,21 +105,22 @@
|
|||||||
:js-response true
|
:js-response true
|
||||||
:on-success #(re-frame/dispatch [:chat-removed %])}]})
|
:on-success #(re-frame/dispatch [:chat-removed %])}]})
|
||||||
|
|
||||||
(fx/defn remove
|
(rf/defn remove
|
||||||
"Remove chat"
|
"Remove chat"
|
||||||
{:events [:group-chats.ui/remove-chat-confirmed]}
|
{:events [:group-chats.ui/remove-chat-confirmed]}
|
||||||
[cofx chat-id]
|
[cofx chat-id]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(models.chat/deactivate-chat chat-id)
|
(models.chat/deactivate-chat chat-id)
|
||||||
(navigation/pop-to-root-tab :chat-stack)))
|
(navigation/pop-to-root-tab :chat-stack)))
|
||||||
|
|
||||||
(def not-blank?
|
(def not-blank?
|
||||||
(complement string/blank?))
|
(complement string/blank?))
|
||||||
|
|
||||||
(defn- valid-name? [name]
|
(defn- valid-name?
|
||||||
|
[name]
|
||||||
(spec/valid? not-blank? name))
|
(spec/valid? not-blank? name))
|
||||||
|
|
||||||
(fx/defn name-changed
|
(rf/defn name-changed
|
||||||
"Save chat from edited profile"
|
"Save chat from edited profile"
|
||||||
{:events [:group-chats.ui/name-changed]}
|
{:events [:group-chats.ui/name-changed]}
|
||||||
[{:keys [db] :as cofx} chat-id new-name]
|
[{:keys [db] :as cofx} chat-id new-name]
|
||||||
@@ -129,29 +131,29 @@
|
|||||||
:js-response true
|
:js-response true
|
||||||
:on-success #(re-frame/dispatch [:chat-updated %])}]}))
|
:on-success #(re-frame/dispatch [:chat-updated %])}]}))
|
||||||
|
|
||||||
(fx/defn membership-retry
|
(rf/defn membership-retry
|
||||||
{:events [:group-chats.ui/membership-retry]}
|
{:events [:group-chats.ui/membership-retry]}
|
||||||
[{{:keys [current-chat-id] :as db} :db}]
|
[{{:keys [current-chat-id] :as db} :db}]
|
||||||
{:db (assoc-in db [:chat/memberships current-chat-id :retry?] true)})
|
{:db (assoc-in db [:chat/memberships current-chat-id :retry?] true)})
|
||||||
|
|
||||||
(fx/defn membership-message
|
(rf/defn membership-message
|
||||||
{:events [:group-chats.ui/update-membership-message]}
|
{:events [:group-chats.ui/update-membership-message]}
|
||||||
[{{:keys [current-chat-id] :as db} :db} message]
|
[{{:keys [current-chat-id] :as db} :db} message]
|
||||||
{:db (assoc-in db [:chat/memberships current-chat-id :message] message)})
|
{:db (assoc-in db [:chat/memberships current-chat-id :message] message)})
|
||||||
|
|
||||||
(fx/defn send-group-chat-membership-request
|
(rf/defn send-group-chat-membership-request
|
||||||
"Send group chat membership request"
|
"Send group chat membership request"
|
||||||
{:events [:send-group-chat-membership-request]}
|
{:events [:send-group-chat-membership-request]}
|
||||||
[{{:keys [current-chat-id chats] :as db} :db :as cofx}]
|
[{{:keys [current-chat-id chats] :as db} :db :as cofx}]
|
||||||
(let [{:keys [invitation-admin]} (get chats current-chat-id)
|
(let [{:keys [invitation-admin]} (get chats current-chat-id)
|
||||||
message (get-in db [:chat/memberships current-chat-id :message])]
|
message (get-in db [:chat/memberships current-chat-id :message])]
|
||||||
{:db (assoc-in db [:chat/memberships current-chat-id] nil)
|
{:db (assoc-in db [:chat/memberships current-chat-id] nil)
|
||||||
::json-rpc/call [{:method "wakuext_sendGroupChatInvitationRequest"
|
::json-rpc/call [{:method "wakuext_sendGroupChatInvitationRequest"
|
||||||
:params [nil current-chat-id invitation-admin message]
|
:params [nil current-chat-id invitation-admin message]
|
||||||
:js-response true
|
:js-response true
|
||||||
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])}]}))
|
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])}]}))
|
||||||
|
|
||||||
(fx/defn send-group-chat-membership-rejection
|
(rf/defn send-group-chat-membership-rejection
|
||||||
"Send group chat membership rejection"
|
"Send group chat membership rejection"
|
||||||
{:events [:send-group-chat-membership-rejection]}
|
{:events [:send-group-chat-membership-rejection]}
|
||||||
[cofx invitation-id]
|
[cofx invitation-id]
|
||||||
@@ -160,14 +162,17 @@
|
|||||||
:js-response true
|
:js-response true
|
||||||
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])}]})
|
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])}]})
|
||||||
|
|
||||||
(fx/defn handle-invitations
|
(rf/defn handle-invitations
|
||||||
[{db :db} invitations]
|
[{db :db} invitations]
|
||||||
{:db (update db :group-chat/invitations #(reduce (fn [acc {:keys [id] :as inv}]
|
{:db (update db
|
||||||
(assoc acc id inv))
|
:group-chat/invitations
|
||||||
%
|
#(reduce (fn [acc {:keys [id] :as inv}]
|
||||||
invitations))})
|
(assoc acc id inv))
|
||||||
|
%
|
||||||
|
invitations))})
|
||||||
|
|
||||||
(defn member-removed? [{:keys [membership-update-events]} pk]
|
(defn member-removed?
|
||||||
|
[{:keys [membership-update-events]} pk]
|
||||||
(->> membership-update-events
|
(->> membership-update-events
|
||||||
(filter #(contains? (set (:members %)) pk))
|
(filter #(contains? (set (:members %)) pk))
|
||||||
(sort-by :clockValue >)
|
(sort-by :clockValue >)
|
||||||
@@ -175,41 +180,41 @@
|
|||||||
:type
|
:type
|
||||||
(= constants/invitation-state-removed)))
|
(= constants/invitation-state-removed)))
|
||||||
|
|
||||||
(fx/defn deselect-contact
|
(rf/defn deselect-contact
|
||||||
{:events [:deselect-contact]}
|
{:events [:deselect-contact]}
|
||||||
[{:keys [db]} id]
|
[{:keys [db]} id]
|
||||||
{:db (update db :group/selected-contacts disj id)})
|
{:db (update db :group/selected-contacts disj id)})
|
||||||
|
|
||||||
(fx/defn select-contact
|
(rf/defn select-contact
|
||||||
{:events [:select-contact]}
|
{:events [:select-contact]}
|
||||||
[{:keys [db]} id]
|
[{:keys [db]} id]
|
||||||
{:db (update db :group/selected-contacts conj id)})
|
{:db (update db :group/selected-contacts conj id)})
|
||||||
|
|
||||||
(fx/defn deselect-participant
|
(rf/defn deselect-participant
|
||||||
{:events [:deselect-participant]}
|
{:events [:deselect-participant]}
|
||||||
[{:keys [db]} id]
|
[{:keys [db]} id]
|
||||||
{:db (update db :selected-participants disj id)})
|
{:db (update db :selected-participants disj id)})
|
||||||
|
|
||||||
(fx/defn select-participant
|
(rf/defn select-participant
|
||||||
{:events [:select-participant]}
|
{:events [:select-participant]}
|
||||||
[{:keys [db]} id]
|
[{:keys [db]} id]
|
||||||
{:db (update db :selected-participants conj id)})
|
{:db (update db :selected-participants conj id)})
|
||||||
|
|
||||||
(fx/defn add-participants-toggle-list
|
(rf/defn add-participants-toggle-list
|
||||||
{:events [:group/add-participants-toggle-list]}
|
{:events [:group/add-participants-toggle-list]}
|
||||||
[{db :db}]
|
[{db :db}]
|
||||||
{:db (assoc db :selected-participants #{})})
|
{:db (assoc db :selected-participants #{})})
|
||||||
|
|
||||||
(fx/defn show-group-chat-profile
|
(rf/defn show-group-chat-profile
|
||||||
{:events [:show-group-chat-profile]}
|
{:events [:show-group-chat-profile]}
|
||||||
[{:keys [db] :as cofx} chat-id]
|
[{:keys [db] :as cofx} chat-id]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc :new-chat-name (get-in db [:chats chat-id :name]))
|
(assoc :new-chat-name (get-in db [:chats chat-id :name]))
|
||||||
(assoc :current-chat-id chat-id))}
|
(assoc :current-chat-id chat-id))}
|
||||||
(navigation/navigate-to-cofx :group-chat-profile nil)))
|
(navigation/navigate-to-cofx :group-chat-profile nil)))
|
||||||
|
|
||||||
(fx/defn ui-leave-chat-pressed
|
(rf/defn ui-leave-chat-pressed
|
||||||
{:events [:group-chats.ui/leave-chat-pressed]}
|
{:events [:group-chats.ui/leave-chat-pressed]}
|
||||||
[{:keys [db]} chat-id]
|
[{:keys [db]} chat-id]
|
||||||
(let [chat-name (get-in db [:chats chat-id :name])]
|
(let [chat-name (get-in db [:chats chat-id :name])]
|
||||||
|
|||||||
@@ -1,69 +1,72 @@
|
|||||||
(ns status-im.keycard.backup-key
|
(ns status-im.keycard.backup-key
|
||||||
(:require [status-im.utils.fx :as fx]
|
(:require [re-frame.core :as re-frame]
|
||||||
[re-frame.core :as re-frame]
|
|
||||||
[status-im.utils.utils :as utils]
|
|
||||||
[status-im.i18n.i18n :as i18n]
|
|
||||||
[status-im.ethereum.mnemonic :as mnemonic]
|
[status-im.ethereum.mnemonic :as mnemonic]
|
||||||
|
[status-im.i18n.i18n :as i18n]
|
||||||
[status-im.keycard.common :as common]
|
[status-im.keycard.common :as common]
|
||||||
[status-im.multiaccounts.recover.core :as multiaccounts.recover]
|
[status-im.multiaccounts.recover.core :as multiaccounts.recover]
|
||||||
[status-im2.navigation.events :as navigation]
|
|
||||||
[status-im.signing.core :as signing.core]
|
[status-im.signing.core :as signing.core]
|
||||||
[taoensso.timbre :as log]))
|
[status-im.utils.utils :as utils]
|
||||||
|
[status-im2.navigation.events :as navigation]
|
||||||
|
[taoensso.timbre :as log]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(fx/defn backup-card-pressed
|
(rf/defn backup-card-pressed
|
||||||
{:events [:keycard-settings.ui/backup-card-pressed]}
|
{:events [:keycard-settings.ui/backup-card-pressed]}
|
||||||
[{:keys [db] :as cofx} backup-type]
|
[{:keys [db] :as cofx} backup-type]
|
||||||
(log/debug "[keycard] start backup")
|
(log/debug "[keycard] start backup")
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:keycard :creating-backup?] backup-type))}
|
(assoc-in [:keycard :creating-backup?] backup-type))}
|
||||||
(when (:multiaccount db)
|
(when (:multiaccount db)
|
||||||
(navigation/change-tab :profile))
|
(navigation/change-tab :profile))
|
||||||
(navigation/navigate-to-cofx :seed-phrase nil)))
|
(navigation/navigate-to-cofx :seed-phrase nil)))
|
||||||
|
|
||||||
(fx/defn recovery-card-pressed
|
(rf/defn recovery-card-pressed
|
||||||
{:events [:keycard-settings.ui/recovery-card-pressed]}
|
{:events [:keycard-settings.ui/recovery-card-pressed]}
|
||||||
[{:keys [db] :as cofx} show-warning]
|
[{:keys [db] :as cofx} show-warning]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
;setting pin-retry-counter is a workaround for the way the PIN view decides if it should accept PUK or PIN
|
;setting pin-retry-counter is a workaround for the way the PIN view
|
||||||
(assoc-in [:keycard :application-info :pin-retry-counter] 3)
|
;decides if it should accept PUK or PIN
|
||||||
(assoc-in [:keycard :factory-reset-card?] true)
|
(assoc-in [:keycard :application-info :pin-retry-counter] 3)
|
||||||
(dissoc :popover/popover))
|
(assoc-in [:keycard :factory-reset-card?] true)
|
||||||
|
(dissoc :popover/popover))
|
||||||
:hide-popover nil}
|
:hide-popover nil}
|
||||||
(signing.core/discard)
|
(signing.core/discard)
|
||||||
(if show-warning
|
(if show-warning
|
||||||
(utils/show-confirmation {:title (i18n/label :t/keycard-recover-title)
|
(utils/show-confirmation
|
||||||
:content (i18n/label :t/keycard-recover-text)
|
{:title (i18n/label :t/keycard-recover-title)
|
||||||
:confirm-button-text (i18n/label :t/yes)
|
:content (i18n/label :t/keycard-recover-text)
|
||||||
:cancel-button-text (i18n/label :t/no)
|
:confirm-button-text (i18n/label :t/yes)
|
||||||
:on-accept #(re-frame/dispatch [:keycard-settings.ui/backup-card-pressed :recovery-card])
|
:cancel-button-text (i18n/label :t/no)
|
||||||
:on-cancel #()})
|
:on-accept #(re-frame/dispatch [:keycard-settings.ui/backup-card-pressed
|
||||||
|
:recovery-card])
|
||||||
|
:on-cancel #()})
|
||||||
(backup-card-pressed :recovery-card))))
|
(backup-card-pressed :recovery-card))))
|
||||||
|
|
||||||
(fx/defn start-keycard-backup
|
(rf/defn start-keycard-backup
|
||||||
{:events [::start-keycard-backup]}
|
{:events [::start-keycard-backup]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
{::multiaccounts.recover/import-multiaccount {:passphrase (-> db
|
{::multiaccounts.recover/import-multiaccount {:passphrase (-> db
|
||||||
:multiaccounts/key-storage
|
:multiaccounts/key-storage
|
||||||
:seed-phrase
|
:seed-phrase
|
||||||
mnemonic/sanitize-passphrase)
|
mnemonic/sanitize-passphrase)
|
||||||
:password nil
|
:password nil
|
||||||
:success-event ::create-backup-card}})
|
:success-event ::create-backup-card}})
|
||||||
|
|
||||||
(fx/defn create-backup-card
|
(rf/defn create-backup-card
|
||||||
{:events [::create-backup-card]}
|
{:events [::create-backup-card]}
|
||||||
[{:keys [db] :as cofx} root-data derived-data]
|
[{:keys [db] :as cofx} root-data derived-data]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(update :intro-wizard
|
(update :intro-wizard
|
||||||
assoc
|
assoc
|
||||||
:root-key root-data
|
:root-key root-data
|
||||||
:derived derived-data
|
:derived derived-data
|
||||||
:recovering? true
|
:recovering? true
|
||||||
:selected-storage-type :advanced)
|
:selected-storage-type :advanced)
|
||||||
(assoc-in [:keycard :flow] :recovery)
|
(assoc-in [:keycard :flow] :recovery)
|
||||||
(update :multiaccounts/key-storage dissoc :seed-phrase))
|
(update :multiaccounts/key-storage dissoc :seed-phrase))
|
||||||
:dismiss-keyboard nil}
|
:dismiss-keyboard nil}
|
||||||
(common/listen-to-hardware-back-button)
|
(common/listen-to-hardware-back-button)
|
||||||
(navigation/navigate-to-cofx :keycard-onboarding-intro nil)))
|
(navigation/navigate-to-cofx :keycard-onboarding-intro nil)))
|
||||||
|
|||||||
@@ -1,71 +1,74 @@
|
|||||||
(ns status-im.keycard.change-pin
|
(ns status-im.keycard.change-pin
|
||||||
(:require [status-im.i18n.i18n :as i18n]
|
(:require [status-im.i18n.i18n :as i18n]
|
||||||
[status-im2.navigation.events :as navigation]
|
|
||||||
[status-im.keycard.onboarding :as onboarding]
|
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[taoensso.timbre :as log]
|
|
||||||
[status-im.keycard.common :as common]
|
[status-im.keycard.common :as common]
|
||||||
|
[status-im.keycard.onboarding :as onboarding]
|
||||||
|
[status-im2.navigation.events :as navigation]
|
||||||
|
[taoensso.timbre :as log]
|
||||||
|
[utils.re-frame :as rf]
|
||||||
[utils.security.core :as security]))
|
[utils.security.core :as security]))
|
||||||
|
|
||||||
(fx/defn change-credentials-pressed
|
(rf/defn change-credentials-pressed
|
||||||
{:events [:keycard-settings.ui/change-credentials-pressed]}
|
{:events [:keycard-settings.ui/change-credentials-pressed]}
|
||||||
[{:keys [db] :as cofx} changing]
|
[{:keys [db] :as cofx} changing]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db
|
{:db
|
||||||
(assoc-in db [:keycard :pin] {:enter-step :current
|
(assoc-in db
|
||||||
:current []
|
[:keycard :pin]
|
||||||
:puk []
|
{:enter-step :current
|
||||||
:original []
|
:current []
|
||||||
:confirmation []
|
:puk []
|
||||||
:puk-original []
|
:original []
|
||||||
:puk-confirmation []
|
:confirmation []
|
||||||
:status nil
|
:puk-original []
|
||||||
:error-label nil
|
:puk-confirmation []
|
||||||
:on-verified (case changing
|
:status nil
|
||||||
:pin :keycard/proceed-to-change-pin
|
:error-label nil
|
||||||
:puk :keycard/proceed-to-change-puk
|
:on-verified (case changing
|
||||||
:pairing :keycard/proceed-to-change-pairing)})}
|
:pin :keycard/proceed-to-change-pin
|
||||||
|
:puk :keycard/proceed-to-change-puk
|
||||||
|
:pairing :keycard/proceed-to-change-pairing)})}
|
||||||
(common/navigate-to-enter-pin-screen)))
|
(common/navigate-to-enter-pin-screen)))
|
||||||
|
|
||||||
(fx/defn proceed-to-change-pin
|
(rf/defn proceed-to-change-pin
|
||||||
{:events [:keycard/proceed-to-change-pin]}
|
{:events [:keycard/proceed-to-change-pin]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:keycard :pin :enter-step] :original)
|
(assoc-in [:keycard :pin :enter-step] :original)
|
||||||
(assoc-in [:keycard :pin :status] nil))}
|
(assoc-in [:keycard :pin :status] nil))}
|
||||||
(navigation/navigate-replace :enter-pin-settings nil)))
|
(navigation/navigate-replace :enter-pin-settings nil)))
|
||||||
|
|
||||||
(fx/defn proceed-to-change-puk
|
(rf/defn proceed-to-change-puk
|
||||||
{:events [:keycard/proceed-to-change-puk]}
|
{:events [:keycard/proceed-to-change-puk]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:keycard :pin :enter-step] :puk-original)
|
(assoc-in [:keycard :pin :enter-step] :puk-original)
|
||||||
(assoc-in [:keycard :pin :status] nil))}
|
(assoc-in [:keycard :pin :status] nil))}
|
||||||
(navigation/navigate-replace :enter-pin-settings nil)))
|
(navigation/navigate-replace :enter-pin-settings nil)))
|
||||||
|
|
||||||
(fx/defn proceed-to-change-pairing
|
(rf/defn proceed-to-change-pairing
|
||||||
{:events [:keycard/proceed-to-change-pairing]}
|
{:events [:keycard/proceed-to-change-pairing]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(navigation/navigate-replace cofx :change-pairing-code nil))
|
(navigation/navigate-replace cofx :change-pairing-code nil))
|
||||||
|
|
||||||
(fx/defn discard-pin-change
|
(rf/defn discard-pin-change
|
||||||
{:events [::on-cancel]}
|
{:events [::on-cancel]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(common/clear-pin)
|
(common/clear-pin)
|
||||||
(common/hide-connection-sheet)
|
(common/hide-connection-sheet)
|
||||||
(if (get-in db [:keycard :pin :puk-restore?])
|
(if (get-in db [:keycard :pin :puk-restore?])
|
||||||
(navigation/navigate-to-cofx :multiaccounts nil)
|
(navigation/navigate-to-cofx :multiaccounts nil)
|
||||||
(navigation/set-stack-root :profile-stack [:my-profile :keycard-settings]))))
|
(navigation/set-stack-root :profile-stack [:my-profile :keycard-settings]))))
|
||||||
|
|
||||||
(fx/defn change-pin
|
(rf/defn change-pin
|
||||||
{:events [:keycard/change-pin]}
|
{:events [:keycard/change-pin]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [setup-step (get-in db [:keycard :setup-step])]
|
(let [setup-step (get-in db [:keycard :setup-step])]
|
||||||
(log/debug "[keycard] change-pin"
|
(log/debug "[keycard] change-pin"
|
||||||
"setup-step" setup-step)
|
"setup-step"
|
||||||
|
setup-step)
|
||||||
(if (= setup-step :pin)
|
(if (= setup-step :pin)
|
||||||
(onboarding/load-preparing-screen cofx)
|
(onboarding/load-preparing-screen cofx)
|
||||||
(common/show-connection-sheet
|
(common/show-connection-sheet
|
||||||
@@ -78,15 +81,15 @@
|
|||||||
(get-in db [:keycard :pin :original]))
|
(get-in db [:keycard :pin :original]))
|
||||||
current-pin (common/vector->string
|
current-pin (common/vector->string
|
||||||
(get-in db [:keycard :pin :current]))]
|
(get-in db [:keycard :pin :current]))]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (assoc-in db [:keycard :pin :status] :verifying)
|
{:db (assoc-in db [:keycard :pin :status] :verifying)
|
||||||
|
|
||||||
:keycard/change-pin
|
:keycard/change-pin
|
||||||
{:new-pin new-pin
|
{:new-pin new-pin
|
||||||
:current-pin current-pin}})))}))))
|
:current-pin current-pin}})))}))))
|
||||||
|
|
||||||
(fx/defn change-puk
|
(rf/defn change-puk
|
||||||
{:events [:keycard/change-puk]}
|
{:events [:keycard/change-puk]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(common/show-connection-sheet
|
(common/show-connection-sheet
|
||||||
@@ -99,13 +102,13 @@
|
|||||||
(get-in db [:keycard :pin :puk-original]))
|
(get-in db [:keycard :pin :puk-original]))
|
||||||
pin (common/vector->string
|
pin (common/vector->string
|
||||||
(get-in db [:keycard :pin :current]))]
|
(get-in db [:keycard :pin :current]))]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (assoc-in db [:keycard :pin :status] :verifying)
|
{:db (assoc-in db [:keycard :pin :status] :verifying)
|
||||||
:keycard/change-puk {:puk puk
|
:keycard/change-puk {:puk puk
|
||||||
:pin pin}})))}))
|
:pin pin}})))}))
|
||||||
|
|
||||||
(fx/defn change-pairing
|
(rf/defn change-pairing
|
||||||
{:events [:keycard/change-pairing]}
|
{:events [:keycard/change-pairing]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(common/show-connection-sheet
|
(common/show-connection-sheet
|
||||||
@@ -117,30 +120,32 @@
|
|||||||
(let [pairing (get-in db [:keycard :pin :pairing-code])
|
(let [pairing (get-in db [:keycard :pin :pairing-code])
|
||||||
pin (common/vector->string
|
pin (common/vector->string
|
||||||
(get-in db [:keycard :pin :current]))]
|
(get-in db [:keycard :pin :current]))]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (assoc-in db [:keycard :pin :status] :verifying)
|
{:db (assoc-in db [:keycard :pin :status] :verifying)
|
||||||
:keycard/change-pairing {:pairing pairing
|
:keycard/change-pairing {:pairing pairing
|
||||||
:pin pin}})))}))
|
:pin pin}})))}))
|
||||||
|
|
||||||
(fx/defn change-pairing-code
|
(rf/defn change-pairing-code
|
||||||
{:events [:keycard/change-pairing-code]}
|
{:events [:keycard/change-pairing-code]}
|
||||||
[{:keys [db] :as cofx} pairing]
|
[{:keys [db] :as cofx} pairing]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (assoc-in db [:keycard :pin :pairing-code] (security/unmask pairing))}
|
{:db (assoc-in db [:keycard :pin :pairing-code] (security/unmask pairing))}
|
||||||
(change-pairing)))
|
(change-pairing)))
|
||||||
|
|
||||||
(fx/defn on-change-pin-success
|
(rf/defn on-change-pin-success
|
||||||
{:events [:keycard.callback/on-change-pin-success]}
|
{:events [:keycard.callback/on-change-pin-success]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [pin (get-in db [:keycard :pin :original])
|
(let [pin (get-in db [:keycard :pin :original])
|
||||||
puk-restore? (get-in db [:keycard :pin :puk-restore?])]
|
puk-restore? (get-in db [:keycard :pin :puk-restore?])]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc-in db [:keycard :pin] {:status nil
|
{:db (assoc-in db
|
||||||
:login pin
|
[:keycard :pin]
|
||||||
:confirmation []
|
{:status nil
|
||||||
:error-label nil})
|
:login pin
|
||||||
|
:confirmation []
|
||||||
|
:error-label nil})
|
||||||
:utils/show-popup {:title ""
|
:utils/show-popup {:title ""
|
||||||
:content (i18n/label :t/pin-changed)}}
|
:content (i18n/label :t/pin-changed)}}
|
||||||
(common/hide-connection-sheet)
|
(common/hide-connection-sheet)
|
||||||
@@ -150,55 +155,61 @@
|
|||||||
(when (:multiaccounts/login db)
|
(when (:multiaccounts/login db)
|
||||||
(common/get-keys-from-keycard)))))
|
(common/get-keys-from-keycard)))))
|
||||||
|
|
||||||
(fx/defn on-change-puk-success
|
(rf/defn on-change-puk-success
|
||||||
{:events [:keycard.callback/on-change-puk-success]}
|
{:events [:keycard.callback/on-change-puk-success]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc-in db [:keycard :pin] {:status nil
|
{:db (assoc-in db
|
||||||
:puk-original []
|
[:keycard :pin]
|
||||||
:puk-confirmation []
|
{:status nil
|
||||||
:error-label nil})
|
:puk-original []
|
||||||
|
:puk-confirmation []
|
||||||
|
:error-label nil})
|
||||||
:utils/show-popup {:title ""
|
:utils/show-popup {:title ""
|
||||||
:content (i18n/label :t/puk-changed)}}
|
:content (i18n/label :t/puk-changed)}}
|
||||||
(common/hide-connection-sheet)
|
(common/hide-connection-sheet)
|
||||||
(navigation/set-stack-root :profile-stack [:my-profile :keycard-settings])))
|
(navigation/set-stack-root :profile-stack [:my-profile :keycard-settings])))
|
||||||
|
|
||||||
(fx/defn on-change-pairing-success
|
(rf/defn on-change-pairing-success
|
||||||
{:events [:keycard.callback/on-change-pairing-success]}
|
{:events [:keycard.callback/on-change-pairing-success]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc-in db [:keycard :pin] {:status nil
|
{:db (assoc-in db
|
||||||
:pairing-code nil
|
[:keycard :pin]
|
||||||
:error-label nil})
|
{:status nil
|
||||||
|
:pairing-code nil
|
||||||
|
:error-label nil})
|
||||||
:utils/show-popup {:title ""
|
:utils/show-popup {:title ""
|
||||||
:content (i18n/label :t/pairing-changed)}}
|
:content (i18n/label :t/pairing-changed)}}
|
||||||
(common/hide-connection-sheet)
|
(common/hide-connection-sheet)
|
||||||
(navigation/set-stack-root :profile-stack [:my-profile :keycard-settings])))
|
(navigation/set-stack-root :profile-stack [:my-profile :keycard-settings])))
|
||||||
|
|
||||||
(fx/defn on-change-pin-error
|
(rf/defn on-change-pin-error
|
||||||
{:events [:keycard.callback/on-change-pin-error]}
|
{:events [:keycard.callback/on-change-pin-error]}
|
||||||
[{:keys [db] :as cofx} error]
|
[{:keys [db] :as cofx} error]
|
||||||
(log/debug "[keycard] change pin error" error)
|
(log/debug "[keycard] change pin error" error)
|
||||||
(let [tag-was-lost? (common/tag-lost? (:error error))
|
(let [tag-was-lost? (common/tag-lost? (:error error))
|
||||||
pin-retries (common/pin-retries (:error error))]
|
pin-retries (common/pin-retries (:error error))]
|
||||||
(fx/merge cofx
|
(rf/merge
|
||||||
(if tag-was-lost?
|
cofx
|
||||||
(fx/merge cofx
|
(if tag-was-lost?
|
||||||
{:db (assoc-in db [:keycard :pin :status] nil)}
|
(rf/merge cofx
|
||||||
(common/set-on-card-connected :keycard/change-pin))
|
{:db (assoc-in db [:keycard :pin :status] nil)}
|
||||||
(if-not (nil? pin-retries)
|
(common/set-on-card-connected :keycard/change-pin))
|
||||||
(fx/merge cofx
|
(if-not (nil? pin-retries)
|
||||||
{:db (-> db
|
(rf/merge cofx
|
||||||
(assoc-in [:keycard :application-info :pin-retry-counter] pin-retries)
|
{:db (-> db
|
||||||
(update-in [:keycard :pin] assoc
|
(assoc-in [:keycard :application-info :pin-retry-counter] pin-retries)
|
||||||
:status :error
|
(update-in [:keycard :pin]
|
||||||
:enter-step :current
|
assoc
|
||||||
:puk []
|
:status :error
|
||||||
:current []
|
:enter-step :current
|
||||||
:original []
|
:puk []
|
||||||
:confirmation []
|
:current []
|
||||||
:sign []
|
:original []
|
||||||
:error-label :t/pin-mismatch))}
|
:confirmation []
|
||||||
(when (zero? pin-retries) (common/frozen-keycard-popup))
|
:sign []
|
||||||
(navigation/navigate-to-cofx :enter-pin-settings nil))
|
:error-label :t/pin-mismatch))}
|
||||||
(common/show-wrong-keycard-alert))))))
|
(when (zero? pin-retries) (common/frozen-keycard-popup))
|
||||||
|
(navigation/navigate-to-cofx :enter-pin-settings nil))
|
||||||
|
(common/show-wrong-keycard-alert))))))
|
||||||
|
|||||||
+147
-129
@@ -1,28 +1,30 @@
|
|||||||
(ns status-im.keycard.common
|
(ns status-im.keycard.common
|
||||||
(:require [clojure.string :as string]
|
(:require [clojure.string :as string]
|
||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
[status-im.ethereum.core :as ethereum]
|
|
||||||
[status-im.keycard.nfc :as nfc]
|
|
||||||
[status-im.i18n.i18n :as i18n]
|
|
||||||
[status-im2.navigation.events :as navigation]
|
|
||||||
[status-im.ui.screens.keycard.keycard-interaction :as keycard-sheet]
|
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[status-im.utils.keychain.core :as keychain]
|
|
||||||
[status-im.utils.types :as types]
|
|
||||||
[taoensso.timbre :as log]
|
|
||||||
[status-im.utils.datetime :as utils.datetime]
|
|
||||||
[status-im.bottom-sheet.core :as bottom-sheet]
|
[status-im.bottom-sheet.core :as bottom-sheet]
|
||||||
|
[status-im.ethereum.core :as ethereum]
|
||||||
|
[status-im.i18n.i18n :as i18n]
|
||||||
|
[status-im.keycard.nfc :as nfc]
|
||||||
|
[status-im.popover.core :as popover]
|
||||||
|
[status-im.ui.screens.keycard.keycard-interaction :as keycard-sheet]
|
||||||
|
[status-im.utils.datetime :as utils.datetime]
|
||||||
|
[status-im.utils.keychain.core :as keychain]
|
||||||
[status-im.utils.platform :as platform]
|
[status-im.utils.platform :as platform]
|
||||||
[status-im.popover.core :as popover]))
|
[status-im.utils.types :as types]
|
||||||
|
[status-im2.navigation.events :as navigation]
|
||||||
|
[taoensso.timbre :as log]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(def default-pin "000000")
|
(def default-pin "000000")
|
||||||
|
|
||||||
(def pin-mismatch-error #"Unexpected error SW, 0x63C(\d+)|wrongPIN\(retryCounter: (\d+)\)")
|
(def pin-mismatch-error #"Unexpected error SW, 0x63C(\d+)|wrongPIN\(retryCounter: (\d+)\)")
|
||||||
|
|
||||||
(defn pin-retries [error]
|
(defn pin-retries
|
||||||
(when-let [matched-error (re-matches pin-mismatch-error error)] (js/parseInt (second (filter some? matched-error)))))
|
[error]
|
||||||
|
(when-let [matched-error (re-matches pin-mismatch-error error)]
|
||||||
|
(js/parseInt (second (filter some? matched-error)))))
|
||||||
|
|
||||||
(fx/defn dispatch-event
|
(rf/defn dispatch-event
|
||||||
[_ event]
|
[_ event]
|
||||||
{:dispatch [event]})
|
{:dispatch [event]})
|
||||||
|
|
||||||
@@ -56,7 +58,8 @@
|
|||||||
(zero? free-pairing-slots))
|
(zero? free-pairing-slots))
|
||||||
:no-pairing-slots))
|
:no-pairing-slots))
|
||||||
|
|
||||||
(defn tag-lost? [error]
|
(defn tag-lost?
|
||||||
|
[error]
|
||||||
(or
|
(or
|
||||||
(= error "Tag was lost.")
|
(= error "Tag was lost.")
|
||||||
(= error "NFCError:100")
|
(= error "NFCError:100")
|
||||||
@@ -94,24 +97,24 @@
|
|||||||
(fn [supported?]
|
(fn [supported?]
|
||||||
(nfc/set-nfc-supported? supported?)))
|
(nfc/set-nfc-supported? supported?)))
|
||||||
|
|
||||||
(fx/defn listen-to-hardware-back-button
|
(rf/defn listen-to-hardware-back-button
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(when-not (get-in db [:keycard :back-button-listener])
|
(when-not (get-in db [:keycard :back-button-listener])
|
||||||
{:keycard/listen-to-hardware-back-button nil}))
|
{:keycard/listen-to-hardware-back-button nil}))
|
||||||
|
|
||||||
(fx/defn remove-listener-to-hardware-back-button
|
(rf/defn remove-listener-to-hardware-back-button
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(when-let [listener (get-in db [:keycard :back-button-listener])]
|
(when-let [listener (get-in db [:keycard :back-button-listener])]
|
||||||
{:keycard/remove-listener-to-hardware-back-button listener}))
|
{:keycard/remove-listener-to-hardware-back-button listener}))
|
||||||
|
|
||||||
(fx/defn set-on-card-connected
|
(rf/defn set-on-card-connected
|
||||||
[{:keys [db]} on-connect]
|
[{:keys [db]} on-connect]
|
||||||
(log/debug "[keycard] set-on-card-connected" on-connect)
|
(log/debug "[keycard] set-on-card-connected" on-connect)
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:keycard :on-card-connected] on-connect)
|
(assoc-in [:keycard :on-card-connected] on-connect)
|
||||||
(assoc-in [:keycard :last-on-card-connected] nil))})
|
(assoc-in [:keycard :last-on-card-connected] nil))})
|
||||||
|
|
||||||
(fx/defn stash-on-card-connected
|
(rf/defn stash-on-card-connected
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(let [on-connect (get-in db [:keycard :on-card-connected])]
|
(let [on-connect (get-in db [:keycard :on-card-connected])]
|
||||||
(log/debug "[keycard] stash-on-card-connected" on-connect)
|
(log/debug "[keycard] stash-on-card-connected" on-connect)
|
||||||
@@ -119,7 +122,7 @@
|
|||||||
(assoc-in [:keycard :last-on-card-connected] on-connect)
|
(assoc-in [:keycard :last-on-card-connected] on-connect)
|
||||||
(assoc-in [:keycard :on-card-connected] nil))}))
|
(assoc-in [:keycard :on-card-connected] nil))}))
|
||||||
|
|
||||||
(fx/defn restore-on-card-connected
|
(rf/defn restore-on-card-connected
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(let [on-connect (or
|
(let [on-connect (or
|
||||||
(get-in db [:keycard :on-card-connected])
|
(get-in db [:keycard :on-card-connected])
|
||||||
@@ -129,21 +132,21 @@
|
|||||||
(assoc-in [:keycard :on-card-connected] on-connect)
|
(assoc-in [:keycard :on-card-connected] on-connect)
|
||||||
(assoc-in [:keycard :last-on-card-connect] nil))}))
|
(assoc-in [:keycard :last-on-card-connect] nil))}))
|
||||||
|
|
||||||
(fx/defn clear-on-card-connected
|
(rf/defn clear-on-card-connected
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(log/debug "[keycard] clear-on-card-connected")
|
(log/debug "[keycard] clear-on-card-connected")
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:keycard :on-card-connected] nil)
|
(assoc-in [:keycard :on-card-connected] nil)
|
||||||
(assoc-in [:keycard :last-on-card-connected] nil))})
|
(assoc-in [:keycard :last-on-card-connected] nil))})
|
||||||
|
|
||||||
(fx/defn set-on-card-read
|
(rf/defn set-on-card-read
|
||||||
[{:keys [db]} on-connect]
|
[{:keys [db]} on-connect]
|
||||||
(log/debug "[keycard] set-on-card-read" on-connect)
|
(log/debug "[keycard] set-on-card-read" on-connect)
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:keycard :on-card-read] on-connect)
|
(assoc-in [:keycard :on-card-read] on-connect)
|
||||||
(assoc-in [:keycard :last-on-card-read] nil))})
|
(assoc-in [:keycard :last-on-card-read] nil))})
|
||||||
|
|
||||||
(fx/defn stash-on-card-read
|
(rf/defn stash-on-card-read
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(let [on-connect (get-in db [:keycard :on-card-read])]
|
(let [on-connect (get-in db [:keycard :on-card-read])]
|
||||||
(log/debug "[keycard] stash-on-card-read" on-connect)
|
(log/debug "[keycard] stash-on-card-read" on-connect)
|
||||||
@@ -151,7 +154,7 @@
|
|||||||
(assoc-in [:keycard :last-on-card-read] on-connect)
|
(assoc-in [:keycard :last-on-card-read] on-connect)
|
||||||
(assoc-in [:keycard :on-card-read] nil))}))
|
(assoc-in [:keycard :on-card-read] nil))}))
|
||||||
|
|
||||||
(fx/defn restore-on-card-read
|
(rf/defn restore-on-card-read
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(let [on-connect (or
|
(let [on-connect (or
|
||||||
(get-in db [:keycard :on-card-read])
|
(get-in db [:keycard :on-card-read])
|
||||||
@@ -161,14 +164,15 @@
|
|||||||
(assoc-in [:keycard :on-card-read] on-connect)
|
(assoc-in [:keycard :on-card-read] on-connect)
|
||||||
(assoc-in [:keycard :last-on-card-connect] nil))}))
|
(assoc-in [:keycard :last-on-card-connect] nil))}))
|
||||||
|
|
||||||
(fx/defn clear-on-card-read
|
(rf/defn clear-on-card-read
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(log/debug "[keycard] clear-on-card-read")
|
(log/debug "[keycard] clear-on-card-read")
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:keycard :on-card-read] nil)
|
(assoc-in [:keycard :on-card-read] nil)
|
||||||
(assoc-in [:keycard :last-on-card-read] nil))})
|
(assoc-in [:keycard :last-on-card-read] nil))})
|
||||||
|
|
||||||
(defn keycard-sheet-content [on-cancel connected? params]
|
(defn keycard-sheet-content
|
||||||
|
[on-cancel connected? params]
|
||||||
(fn []
|
(fn []
|
||||||
[keycard-sheet/connect-keycard
|
[keycard-sheet/connect-keycard
|
||||||
{:on-cancel #(re-frame/dispatch on-cancel)
|
{:on-cancel #(re-frame/dispatch on-cancel)
|
||||||
@@ -177,17 +181,19 @@
|
|||||||
:on-connect ::on-card-connected
|
:on-connect ::on-card-connected
|
||||||
:on-disconnect ::on-card-disconnected}]))
|
:on-disconnect ::on-card-disconnected}]))
|
||||||
|
|
||||||
(fx/defn show-connection-sheet-component
|
(rf/defn show-connection-sheet-component
|
||||||
[{:keys [db] :as cofx} {:keys [on-card-connected on-card-read handler]
|
[{:keys [db] :as cofx}
|
||||||
{:keys [on-cancel]
|
{:keys [on-card-connected on-card-read handler]
|
||||||
:or {on-cancel [::cancel-sheet-confirm]}}
|
{:keys [on-cancel]
|
||||||
:sheet-options}]
|
:or {on-cancel [::cancel-sheet-confirm]}}
|
||||||
|
:sheet-options}]
|
||||||
(assert (keyword? on-card-connected))
|
(assert (keyword? on-card-connected))
|
||||||
(assert (fn? handler))
|
(assert (fn? handler))
|
||||||
(let [connected? (get-in db [:keycard :card-connected?])]
|
(let [connected? (get-in db [:keycard :card-connected?])]
|
||||||
(log/debug "[keycard] show-sheet-with-connection-check"
|
(log/debug "[keycard] show-sheet-with-connection-check"
|
||||||
"card-connected?" connected?)
|
"card-connected?"
|
||||||
(fx/merge
|
connected?)
|
||||||
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:dismiss-keyboard true}
|
{:dismiss-keyboard true}
|
||||||
(bottom-sheet/show-bottom-sheet
|
(bottom-sheet/show-bottom-sheet
|
||||||
@@ -205,7 +211,7 @@
|
|||||||
(when connected?
|
(when connected?
|
||||||
handler))))
|
handler))))
|
||||||
|
|
||||||
(fx/defn show-connection-sheet
|
(rf/defn show-connection-sheet
|
||||||
[{:keys [db] :as cofx} args]
|
[{:keys [db] :as cofx} args]
|
||||||
(let [nfc-running? (get-in db [:keycard :nfc-running?])]
|
(let [nfc-running? (get-in db [:keycard :nfc-running?])]
|
||||||
(log/debug "show connection; already running?" nfc-running?)
|
(log/debug "show connection; already running?" nfc-running?)
|
||||||
@@ -213,59 +219,59 @@
|
|||||||
(show-connection-sheet-component cofx args)
|
(show-connection-sheet-component cofx args)
|
||||||
{:keycard/start-nfc-and-show-connection-sheet args})))
|
{:keycard/start-nfc-and-show-connection-sheet args})))
|
||||||
|
|
||||||
(fx/defn on-nfc-ready-for-sheet
|
(rf/defn on-nfc-ready-for-sheet
|
||||||
{:events [:keycard.callback/show-connection-sheet]}
|
{:events [:keycard.callback/show-connection-sheet]}
|
||||||
[cofx args]
|
[cofx args]
|
||||||
(log/debug "on-nfc-ready-for-sheet")
|
(log/debug "on-nfc-ready-for-sheet")
|
||||||
(show-connection-sheet-component cofx args))
|
(show-connection-sheet-component cofx args))
|
||||||
|
|
||||||
(fx/defn hide-connection-sheet-component
|
(rf/defn hide-connection-sheet-component
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc-in db [:keycard :card-read-in-progress?] false)}
|
{:db (assoc-in db [:keycard :card-read-in-progress?] false)}
|
||||||
(restore-on-card-connected)
|
(restore-on-card-connected)
|
||||||
(restore-on-card-read)
|
(restore-on-card-read)
|
||||||
(bottom-sheet/hide-bottom-sheet)))
|
(bottom-sheet/hide-bottom-sheet)))
|
||||||
|
|
||||||
(fx/defn hide-connection-sheet
|
(rf/defn hide-connection-sheet
|
||||||
[cofx]
|
[cofx]
|
||||||
(log/debug "hide-connection-sheet")
|
(log/debug "hide-connection-sheet")
|
||||||
{:keycard/stop-nfc-and-hide-connection-sheet nil})
|
{:keycard/stop-nfc-and-hide-connection-sheet nil})
|
||||||
|
|
||||||
(fx/defn on-nfc-ready-to-close-sheet
|
(rf/defn on-nfc-ready-to-close-sheet
|
||||||
{:events [:keycard.callback/hide-connection-sheet]}
|
{:events [:keycard.callback/hide-connection-sheet]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(log/debug "on-nfc-ready-to-close-sheet")
|
(log/debug "on-nfc-ready-to-close-sheet")
|
||||||
(hide-connection-sheet-component cofx))
|
(hide-connection-sheet-component cofx))
|
||||||
|
|
||||||
(fx/defn clear-pin
|
(rf/defn clear-pin
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (assoc-in db
|
{:db (assoc-in db
|
||||||
[:keycard :pin]
|
[:keycard :pin]
|
||||||
{:status nil
|
{:status nil
|
||||||
:login (get-in db [:keycard :pin :original])
|
:login (get-in db [:keycard :pin :original])
|
||||||
:export-key []
|
:export-key []
|
||||||
:sign []
|
:sign []
|
||||||
:puk []
|
:puk []
|
||||||
:current []
|
:current []
|
||||||
:original []
|
:original []
|
||||||
:confirmation []
|
:confirmation []
|
||||||
:error-label nil
|
:error-label nil
|
||||||
:on-verified (get-in db [:keycard :pin :on-verified])
|
:on-verified (get-in db [:keycard :pin :on-verified])
|
||||||
:on-verified-failure (get-in db [:keycard :pin :on-verified])})}))
|
:on-verified-failure (get-in db [:keycard :pin :on-verified])})}))
|
||||||
|
|
||||||
(fx/defn cancel-sheet-confirm
|
(rf/defn cancel-sheet-confirm
|
||||||
{:events [::cancel-sheet-confirm
|
{:events [::cancel-sheet-confirm
|
||||||
:keycard/back-button-pressed]}
|
:keycard/back-button-pressed]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(when-not (get-in db [:keycard :card-connected?])
|
(when-not (get-in db [:keycard :card-connected?])
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(hide-connection-sheet)
|
(hide-connection-sheet)
|
||||||
(clear-pin))))
|
(clear-pin))))
|
||||||
|
|
||||||
(fx/defn cancel-sheet
|
(rf/defn cancel-sheet
|
||||||
{:events [::cancel-sheet]}
|
{:events [::cancel-sheet]}
|
||||||
[_]
|
[_]
|
||||||
{:ui/show-confirmation {:title (i18n/label :t/keycard-cancel-setup-title)
|
{:ui/show-confirmation {:title (i18n/label :t/keycard-cancel-setup-title)
|
||||||
@@ -275,7 +281,7 @@
|
|||||||
:on-accept #(re-frame/dispatch [::cancel-sheet-confirm])
|
:on-accept #(re-frame/dispatch [::cancel-sheet-confirm])
|
||||||
:on-cancel #()}})
|
:on-cancel #()}})
|
||||||
|
|
||||||
(fx/defn on-add-listener-to-hardware-back-button
|
(rf/defn on-add-listener-to-hardware-back-button
|
||||||
"Adds listener to hardware back button on Android.
|
"Adds listener to hardware back button on Android.
|
||||||
During keycard setup we show user a warning that setup will be cancelled
|
During keycard setup we show user a warning that setup will be cancelled
|
||||||
when back button pressed. This prevents user from going back during setup
|
when back button pressed. This prevents user from going back during setup
|
||||||
@@ -284,120 +290,126 @@
|
|||||||
[{:keys [db]} listener]
|
[{:keys [db]} listener]
|
||||||
{:db (assoc-in db [:keycard :back-button-listener] listener)})
|
{:db (assoc-in db [:keycard :back-button-listener] listener)})
|
||||||
|
|
||||||
(fx/defn show-wrong-keycard-alert
|
(rf/defn show-wrong-keycard-alert
|
||||||
[_]
|
[_]
|
||||||
(log/debug "show-wrong-keycard-alert")
|
(log/debug "show-wrong-keycard-alert")
|
||||||
{:utils/show-popup {:title (i18n/label :t/wrong-card)
|
{:utils/show-popup {:title (i18n/label :t/wrong-card)
|
||||||
:content (i18n/label :t/wrong-card-text)}})
|
:content (i18n/label :t/wrong-card-text)}})
|
||||||
|
|
||||||
(fx/defn unauthorized-operation
|
(rf/defn unauthorized-operation
|
||||||
[cofx]
|
[cofx]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:utils/show-popup {:title ""
|
{:utils/show-popup {:title ""
|
||||||
:content (i18n/label :t/keycard-unauthorized-operation)}}
|
:content (i18n/label :t/keycard-unauthorized-operation)}}
|
||||||
(clear-on-card-connected)
|
(clear-on-card-connected)
|
||||||
(navigation/set-stack-root :profile-stack [:my-profile :keycard-settings])))
|
(navigation/set-stack-root :profile-stack [:my-profile :keycard-settings])))
|
||||||
|
|
||||||
(fx/defn navigate-to-enter-pin-screen
|
(rf/defn navigate-to-enter-pin-screen
|
||||||
{:events [:keycard/navigate-to-enter-pin-screen]}
|
{:events [:keycard/navigate-to-enter-pin-screen]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc-in db [:keycard :pin :current] [])}
|
{:db (assoc-in db [:keycard :pin :current] [])}
|
||||||
(navigation/navigate-to-cofx :enter-pin-settings nil)))
|
(navigation/navigate-to-cofx :enter-pin-settings nil)))
|
||||||
|
|
||||||
(defn- tag-lost-exception? [code error]
|
(defn- tag-lost-exception?
|
||||||
|
[code error]
|
||||||
(or
|
(or
|
||||||
(= code "android.nfc.TagLostException")
|
(= code "android.nfc.TagLostException")
|
||||||
(= error "Tag was lost.")
|
(= error "Tag was lost.")
|
||||||
(= error "NFCError:100")))
|
(= error "NFCError:100")))
|
||||||
|
|
||||||
(fx/defn process-error [{:keys [db]} code error]
|
(rf/defn process-error
|
||||||
|
[{:keys [db]} code error]
|
||||||
(when-not (tag-lost-exception? code error)
|
(when-not (tag-lost-exception? code error)
|
||||||
{:db (assoc-in db [:keycard :setup-step] :error)}))
|
{:db (assoc-in db [:keycard :setup-step] :error)}))
|
||||||
|
|
||||||
(fx/defn get-keys-from-keycard
|
(rf/defn get-keys-from-keycard
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(let [key-uid (get-in db [:multiaccounts/login :key-uid])
|
(let [key-uid (get-in db [:multiaccounts/login :key-uid])
|
||||||
pin (string/join (get-in db [:keycard :pin :login]))]
|
pin (string/join (get-in db [:keycard :pin :login]))]
|
||||||
(log/debug "[keycard] get-keys-from-keycard"
|
(log/debug "[keycard] get-keys-from-keycard"
|
||||||
", not empty pin:" (boolean (seq pin)))
|
", not empty pin:"
|
||||||
|
(boolean (seq pin)))
|
||||||
(when (seq pin)
|
(when (seq pin)
|
||||||
{:db (assoc-in db [:keycard :pin :status] :verifying)
|
{:db (assoc-in db [:keycard :pin :status] :verifying)
|
||||||
:keycard/get-keys {:pin pin}})))
|
:keycard/get-keys {:pin pin}})))
|
||||||
|
|
||||||
(fx/defn on-get-keys-success
|
(rf/defn on-get-keys-success
|
||||||
{:events [:keycard.callback/on-get-keys-success]}
|
{:events [:keycard.callback/on-get-keys-success]}
|
||||||
[{:keys [db] :as cofx} data]
|
[{:keys [db] :as cofx} data]
|
||||||
(let [{:keys [key-uid encryption-public-key whisper-private-key]
|
(let [{:keys [key-uid encryption-public-key whisper-private-key]
|
||||||
:as account-data} (js->clj data :keywordize-keys true)
|
:as account-data}
|
||||||
|
(js->clj data :keywordize-keys true)
|
||||||
{:keys [identicon name]} (get-in db [:multiaccounts/multiaccounts key-uid])
|
{:keys [identicon name]} (get-in db [:multiaccounts/multiaccounts key-uid])
|
||||||
key-uid (get-in db [:keycard :application-info :key-uid])
|
key-uid (get-in db [:keycard :application-info :key-uid])
|
||||||
multiaccount-data (types/clj->json {:name name
|
multiaccount-data (types/clj->json {:name name
|
||||||
:key-uid key-uid
|
:key-uid key-uid
|
||||||
:identicon identicon})
|
:identicon identicon})
|
||||||
save-keys? (get-in db [:multiaccounts/login :save-password?])]
|
save-keys? (get-in db [:multiaccounts/login :save-password?])]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db
|
{:db
|
||||||
(-> db
|
(-> db
|
||||||
(assoc-in [:keycard :pin :status] nil)
|
(assoc-in [:keycard :pin :status] nil)
|
||||||
(assoc-in [:keycard :pin :login] [])
|
(assoc-in [:keycard :pin :login] [])
|
||||||
(update-in [:keycard :application-info] assoc
|
(update-in [:keycard :application-info]
|
||||||
|
assoc
|
||||||
:puk-retry-counter 5
|
:puk-retry-counter 5
|
||||||
:pin-retry-counter 3)
|
:pin-retry-counter 3)
|
||||||
(assoc-in [:keycard :multiaccount]
|
(assoc-in [:keycard :multiaccount]
|
||||||
(update account-data :whisper-public-key ethereum/normalized-hex))
|
(update account-data :whisper-public-key ethereum/normalized-hex))
|
||||||
(assoc-in [:keycard :flow] nil)
|
(assoc-in [:keycard :flow] nil)
|
||||||
(update :multiaccounts/login assoc
|
(update :multiaccounts/login assoc
|
||||||
:password encryption-public-key
|
:password encryption-public-key
|
||||||
:key-uid key-uid
|
:key-uid key-uid
|
||||||
:identicon identicon
|
:identicon identicon
|
||||||
:name name))
|
:name name))
|
||||||
|
|
||||||
:keycard/login-with-keycard {:multiaccount-data multiaccount-data
|
:keycard/login-with-keycard {:multiaccount-data multiaccount-data
|
||||||
:password encryption-public-key
|
:password encryption-public-key
|
||||||
:chat-key whisper-private-key
|
:chat-key whisper-private-key
|
||||||
:key-uid key-uid}}
|
:key-uid key-uid}}
|
||||||
(when save-keys?
|
(when save-keys?
|
||||||
(keychain/save-keycard-keys key-uid encryption-public-key whisper-private-key))
|
(keychain/save-keycard-keys key-uid encryption-public-key whisper-private-key))
|
||||||
(clear-on-card-connected)
|
(clear-on-card-connected)
|
||||||
(clear-on-card-read)
|
(clear-on-card-read)
|
||||||
(hide-connection-sheet))))
|
(hide-connection-sheet))))
|
||||||
|
|
||||||
(fx/defn blocked-or-frozen-keycard-popup
|
(rf/defn blocked-or-frozen-keycard-popup
|
||||||
[{:keys [db] :as cofx} card-status]
|
[{:keys [db] :as cofx} card-status]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (assoc-in db [:keycard :pin :status] card-status)}
|
{:db (assoc-in db [:keycard :pin :status] card-status)}
|
||||||
(hide-connection-sheet)
|
(hide-connection-sheet)
|
||||||
; do not try to display the popover if it is already open or
|
; do not try to display the popover if it is already open or
|
||||||
; we are in the login interface (which has a different handling)
|
; we are in the login interface (which has a different handling)
|
||||||
(when-not (or (:multiaccounts/login db) (:popover/popover db))
|
(when-not (or (:multiaccounts/login db) (:popover/popover db))
|
||||||
(popover/show-popover {:view card-status}))))
|
(popover/show-popover {:view card-status}))))
|
||||||
|
|
||||||
(fx/defn blocked-keycard-popup
|
(rf/defn blocked-keycard-popup
|
||||||
[cofx]
|
[cofx]
|
||||||
(blocked-or-frozen-keycard-popup cofx :blocked-card))
|
(blocked-or-frozen-keycard-popup cofx :blocked-card))
|
||||||
|
|
||||||
(fx/defn frozen-keycard-popup
|
(rf/defn frozen-keycard-popup
|
||||||
[cofx]
|
[cofx]
|
||||||
(blocked-or-frozen-keycard-popup cofx :frozen-card))
|
(blocked-or-frozen-keycard-popup cofx :frozen-card))
|
||||||
|
|
||||||
(fx/defn on-get-keys-error
|
(rf/defn on-get-keys-error
|
||||||
{:events [:keycard.callback/on-get-keys-error]}
|
{:events [:keycard.callback/on-get-keys-error]}
|
||||||
[{:keys [db] :as cofx} error]
|
[{:keys [db] :as cofx} error]
|
||||||
(log/debug "[keycard] get keys error: " error)
|
(log/debug "[keycard] get keys error: " error)
|
||||||
(let [tag-was-lost? (tag-lost? (:error error))
|
(let [tag-was-lost? (tag-lost? (:error error))
|
||||||
key-uid (get-in db [:keycard :application-info :key-uid])
|
key-uid (get-in db [:keycard :application-info :key-uid])
|
||||||
flow (get-in db [:keycard :flow])
|
flow (get-in db [:keycard :flow])
|
||||||
pin-retries-count (pin-retries (:error error))]
|
pin-retries-count (pin-retries (:error error))]
|
||||||
(if tag-was-lost?
|
(if tag-was-lost?
|
||||||
{:db (assoc-in db [:keycard :pin :status] nil)}
|
{:db (assoc-in db [:keycard :pin :status] nil)}
|
||||||
(if-not (nil? pin-retries-count)
|
(if-not (nil? pin-retries-count)
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:keycard :application-info :pin-retry-counter] pin-retries-count)
|
(assoc-in [:keycard :application-info :pin-retry-counter] pin-retries-count)
|
||||||
(update-in [:keycard :pin] assoc
|
(update-in [:keycard :pin]
|
||||||
|
assoc
|
||||||
:status :error
|
:status :error
|
||||||
:login []
|
:login []
|
||||||
:import-multiaccount []
|
:import-multiaccount []
|
||||||
@@ -406,42 +418,45 @@
|
|||||||
(when (zero? pin-retries-count) (frozen-keycard-popup)))
|
(when (zero? pin-retries-count) (frozen-keycard-popup)))
|
||||||
(show-wrong-keycard-alert)))))
|
(show-wrong-keycard-alert)))))
|
||||||
|
|
||||||
(fx/defn factory-reset
|
(rf/defn factory-reset
|
||||||
{:events [:keycard/factory-reset]}
|
{:events [:keycard/factory-reset]}
|
||||||
[{:keys [db]} on-card-read]
|
[{:keys [db]} on-card-read]
|
||||||
(log/debug "[keycard] factory-reset")
|
(log/debug "[keycard] factory-reset")
|
||||||
{:db (update db :keycard dissoc :factory-reset-card?)
|
{:db (update db :keycard dissoc :factory-reset-card?)
|
||||||
:keycard/factory-reset {:on-success on-card-read}})
|
:keycard/factory-reset {:on-success on-card-read}})
|
||||||
|
|
||||||
;; Get application info
|
;; Get application info
|
||||||
|
|
||||||
(fx/defn update-pairings
|
(rf/defn update-pairings
|
||||||
[{:keys [db]} instance-uid pairing]
|
[{:keys [db]} instance-uid pairing]
|
||||||
(let [paired-on (utils.datetime/timestamp)
|
(let [paired-on (utils.datetime/timestamp)
|
||||||
pairings (-> (get-in db [:keycard :pairings])
|
pairings (-> (get-in db [:keycard :pairings])
|
||||||
(assoc instance-uid {:pairing pairing :paired-on paired-on}))]
|
(assoc instance-uid {:pairing pairing :paired-on paired-on}))]
|
||||||
{:keycard/persist-pairings pairings
|
{:keycard/persist-pairings pairings
|
||||||
:db (assoc-in db [:keycard :pairings] pairings)}))
|
:db (assoc-in db [:keycard :pairings] pairings)}))
|
||||||
|
|
||||||
(fx/defn get-application-info
|
(rf/defn get-application-info
|
||||||
{:events [:keycard/get-application-info]}
|
{:events [:keycard/get-application-info]}
|
||||||
[{:keys [db]} on-card-read]
|
[{:keys [db]} on-card-read]
|
||||||
(log/debug "[keycard] get-application-info")
|
(log/debug "[keycard] get-application-info")
|
||||||
{:keycard/get-application-info {:on-success on-card-read}})
|
{:keycard/get-application-info {:on-success on-card-read}})
|
||||||
|
|
||||||
(fx/defn on-get-application-info-success
|
(rf/defn on-get-application-info-success
|
||||||
{:events [:keycard.callback/on-get-application-info-success]}
|
{:events [:keycard.callback/on-get-application-info-success]}
|
||||||
[{:keys [db] :as cofx} info on-success]
|
[{:keys [db] :as cofx} info on-success]
|
||||||
(let [{:keys [pin-retry-counter puk-retry-counter instance-uid new-pairing]} info
|
(let [{:keys [pin-retry-counter puk-retry-counter instance-uid new-pairing]} info
|
||||||
view-id (:view-id db)
|
view-id (:view-id db)
|
||||||
{:keys [on-card-read]} (:keycard db)
|
{:keys [on-card-read]} (:keycard db)
|
||||||
on-success' (or on-success on-card-read)
|
on-success' (or on-success
|
||||||
enter-step (get-in db [:keycard :pin :enter-step])]
|
on-card-read)
|
||||||
|
enter-step (get-in db
|
||||||
|
[:keycard :pin
|
||||||
|
:enter-step])]
|
||||||
(log/debug "[keycard] on-get-application-info-success"
|
(log/debug "[keycard] on-get-application-info-success"
|
||||||
"on-success" on-success'
|
"on-success" on-success'
|
||||||
"pin-retry-counter" pin-retry-counter
|
"pin-retry-counter" pin-retry-counter
|
||||||
"puk-retry-counter" puk-retry-counter)
|
"puk-retry-counter" puk-retry-counter)
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:keycard :pin :enter-step] enter-step)
|
(assoc-in [:keycard :pin :enter-step] enter-step)
|
||||||
@@ -461,7 +476,7 @@
|
|||||||
(when on-success'
|
(when on-success'
|
||||||
(dispatch-event cofx on-success')))))))
|
(dispatch-event cofx on-success')))))))
|
||||||
|
|
||||||
(fx/defn on-get-application-info-error
|
(rf/defn on-get-application-info-error
|
||||||
{:events [:keycard.callback/on-get-application-info-error]}
|
{:events [:keycard.callback/on-get-application-info-error]}
|
||||||
[{:keys [db] :as cofx} error]
|
[{:keys [db] :as cofx} error]
|
||||||
(let [on-card-read (get-in db [:keycard :on-card-read])
|
(let [on-card-read (get-in db [:keycard :on-card-read])
|
||||||
@@ -475,10 +490,10 @@
|
|||||||
last-on-card-connected)
|
last-on-card-connected)
|
||||||
(when-not tag-was-lost?
|
(when-not tag-was-lost?
|
||||||
(if login?
|
(if login?
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(clear-on-card-read)
|
(clear-on-card-read)
|
||||||
(navigation/navigate-to-cofx :not-keycard nil))
|
(navigation/navigate-to-cofx :not-keycard nil))
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc-in db [:keycard :application-info-error] error)}
|
{:db (assoc-in db [:keycard :application-info-error] error)}
|
||||||
|
|
||||||
(when (contains?
|
(when (contains?
|
||||||
@@ -489,7 +504,7 @@
|
|||||||
(when on-card-read
|
(when on-card-read
|
||||||
(dispatch-event on-card-read)))))))
|
(dispatch-event on-card-read)))))))
|
||||||
|
|
||||||
(fx/defn on-card-connected
|
(rf/defn on-card-connected
|
||||||
{:events [::on-card-connected]}
|
{:events [::on-card-connected]}
|
||||||
[{:keys [db] :as cofx} _]
|
[{:keys [db] :as cofx} _]
|
||||||
(let [instance-uid (get-in db [:keycard :application-info :instance-uid])
|
(let [instance-uid (get-in db [:keycard :application-info :instance-uid])
|
||||||
@@ -500,9 +515,9 @@
|
|||||||
should-read-instance-uid? :keycard/get-application-info
|
should-read-instance-uid? :keycard/get-application-info
|
||||||
:else (get-in db [:keycard :on-card-read]))]
|
:else (get-in db [:keycard :on-card-read]))]
|
||||||
(log/debug "[keycard] on-card-connected" on-card-connected
|
(log/debug "[keycard] on-card-connected" on-card-connected
|
||||||
"on-card-read" on-card-read)
|
"on-card-read" on-card-read)
|
||||||
(when on-card-connected
|
(when on-card-connected
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:keycard :card-read-in-progress?] (boolean on-card-read)))}
|
(assoc-in [:keycard :card-read-in-progress?] (boolean on-card-read)))}
|
||||||
(when on-card-connected
|
(when on-card-connected
|
||||||
@@ -512,20 +527,21 @@
|
|||||||
(nil? on-card-connected))
|
(nil? on-card-connected))
|
||||||
(get-application-info on-card-read))))))
|
(get-application-info on-card-read))))))
|
||||||
|
|
||||||
(fx/defn on-card-disconnected
|
(rf/defn on-card-disconnected
|
||||||
{:events [::on-card-disconnected]}
|
{:events [::on-card-disconnected]}
|
||||||
[{:keys [db] :as cofx} _]
|
[{:keys [db] :as cofx} _]
|
||||||
(log/debug "[keycard] card disconnected")
|
(log/debug "[keycard] card disconnected")
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:keycard :card-read-in-progress?] false))}
|
(assoc-in [:keycard :card-read-in-progress?] false))}
|
||||||
(restore-on-card-connected)
|
(restore-on-card-connected)
|
||||||
(restore-on-card-read)))
|
(restore-on-card-read)))
|
||||||
|
|
||||||
(defn keycard-multiaccount? [db]
|
(defn keycard-multiaccount?
|
||||||
|
[db]
|
||||||
(boolean (get-in db [:multiaccount :keycard-pairing])))
|
(boolean (get-in db [:multiaccount :keycard-pairing])))
|
||||||
|
|
||||||
(fx/defn verify-pin
|
(rf/defn verify-pin
|
||||||
{:events [:keycard/verify-pin]}
|
{:events [:keycard/verify-pin]}
|
||||||
[{:keys [db] :as cofx} {:keys [pin-step on-card-connected on-failure on-success]}]
|
[{:keys [db] :as cofx} {:keys [pin-step on-card-connected on-failure on-success]}]
|
||||||
(let [on-success (or on-success
|
(let [on-success (or on-success
|
||||||
@@ -534,23 +550,25 @@
|
|||||||
(get-in db [:keycard :pin :on-verified-failure]))
|
(get-in db [:keycard :pin :on-verified-failure]))
|
||||||
pin-step (or pin-step
|
pin-step (or pin-step
|
||||||
(get-in db [:keycard :pin :step]))]
|
(get-in db [:keycard :pin :step]))]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (update-in db [:keycard :pin] assoc
|
{:db (update-in db
|
||||||
:step pin-step
|
[:keycard :pin]
|
||||||
:on-verified on-success
|
assoc
|
||||||
|
:step pin-step
|
||||||
|
:on-verified on-success
|
||||||
:on-verified-failure on-failure)}
|
:on-verified-failure on-failure)}
|
||||||
(show-connection-sheet
|
(show-connection-sheet
|
||||||
{:on-card-connected (or on-card-connected :keycard/verify-pin)
|
{:on-card-connected (or on-card-connected :keycard/verify-pin)
|
||||||
:handler
|
:handler
|
||||||
(fn [{:keys [db] :as cofx}]
|
(fn [{:keys [db] :as cofx}]
|
||||||
(let [pin (vector->string (get-in db [:keycard :pin pin-step]))]
|
(let [pin (vector->string (get-in db [:keycard :pin pin-step]))]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (assoc-in db [:keycard :pin :status] :verifying)
|
{:db (assoc-in db [:keycard :pin :status] :verifying)
|
||||||
:keycard/verify-pin {:pin pin}})))}))))
|
:keycard/verify-pin {:pin pin}})))}))))
|
||||||
|
|
||||||
(fx/defn navigete-to-keycard-settings
|
(rf/defn navigete-to-keycard-settings
|
||||||
{:events [::navigate-to-keycard-settings]}
|
{:events [::navigate-to-keycard-settings]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(navigation/set-stack-root :profile-stack [:my-profile :keycard-settings]))
|
(navigation/set-stack-root :profile-stack [:my-profile :keycard-settings]))
|
||||||
|
|||||||
+186
-143
@@ -1,70 +1,74 @@
|
|||||||
(ns status-im.keycard.core
|
(ns status-im.keycard.core
|
||||||
(:require [re-frame.db]
|
(:require [re-frame.db]
|
||||||
|
[status-im.i18n.i18n :as i18n]
|
||||||
|
status-im.keycard.backup-key
|
||||||
|
[status-im.keycard.card :as card]
|
||||||
[status-im.keycard.change-pin :as change-pin]
|
[status-im.keycard.change-pin :as change-pin]
|
||||||
[status-im.keycard.common :as common]
|
[status-im.keycard.common :as common]
|
||||||
status-im.keycard.delete-key
|
status-im.keycard.delete-key
|
||||||
status-im.keycard.export-key
|
status-im.keycard.export-key
|
||||||
status-im.keycard.unpair
|
|
||||||
status-im.keycard.backup-key
|
|
||||||
[status-im.keycard.login :as login]
|
[status-im.keycard.login :as login]
|
||||||
[status-im.keycard.mnemonic :as mnemonic]
|
[status-im.keycard.mnemonic :as mnemonic]
|
||||||
[status-im.keycard.onboarding :as onboarding]
|
[status-im.keycard.onboarding :as onboarding]
|
||||||
[status-im.keycard.recovery :as recovery]
|
[status-im.keycard.recovery :as recovery]
|
||||||
[status-im.keycard.sign :as sign]
|
[status-im.keycard.sign :as sign]
|
||||||
|
status-im.keycard.unpair
|
||||||
[status-im.keycard.wallet :as wallet]
|
[status-im.keycard.wallet :as wallet]
|
||||||
[status-im.keycard.card :as card]
|
|
||||||
[status-im.i18n.i18n :as i18n]
|
|
||||||
[status-im.multiaccounts.recover.core :as multiaccounts.recover]
|
[status-im.multiaccounts.recover.core :as multiaccounts.recover]
|
||||||
[status-im.multiaccounts.update.core :as multiaccounts.update]
|
[status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||||
[status-im2.navigation.events :as navigation]
|
|
||||||
[status-im.utils.datetime :as utils.datetime]
|
[status-im.utils.datetime :as utils.datetime]
|
||||||
[status-im.utils.fx :as fx]
|
[status-im2.navigation.events :as navigation]
|
||||||
[taoensso.timbre :as log]))
|
[taoensso.timbre :as log]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(fx/defn show-keycard-has-multiaccount-alert
|
(rf/defn show-keycard-has-multiaccount-alert
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc-in db [:keycard :setup-step] nil)
|
{:db (assoc-in db [:keycard :setup-step] nil)
|
||||||
:utils/show-confirmation {:title nil
|
:utils/show-confirmation {:title nil
|
||||||
:content (i18n/label :t/keycard-has-multiaccount-on-it)
|
:content (i18n/label
|
||||||
|
:t/keycard-has-multiaccount-on-it)
|
||||||
:cancel-button-text ""
|
:cancel-button-text ""
|
||||||
:confirm-button-text :t/okay}}))
|
:confirm-button-text :t/okay}}))
|
||||||
|
|
||||||
(fx/defn load-pin-screen
|
(rf/defn load-pin-screen
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:keycard :setup-step] :pin)
|
(assoc-in [:keycard :setup-step] :pin)
|
||||||
(assoc-in [:keycard :pin] {:enter-step :original
|
(assoc-in [:keycard :pin]
|
||||||
:original []
|
{:enter-step :original
|
||||||
:confirmation []}))}
|
:original []
|
||||||
|
:confirmation []}))}
|
||||||
(navigation/navigate-to-cofx :keycard-onboarding-pin nil)))
|
(navigation/navigate-to-cofx :keycard-onboarding-pin nil)))
|
||||||
|
|
||||||
(fx/defn load-recovery-pin-screen
|
(rf/defn load-recovery-pin-screen
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:keycard :pin] {:enter-step :import-multiaccount
|
(assoc-in [:keycard :pin]
|
||||||
:import-multiaccount []
|
{:enter-step :import-multiaccount
|
||||||
:current []}))}
|
:import-multiaccount []
|
||||||
|
:current []}))}
|
||||||
(common/listen-to-hardware-back-button)
|
(common/listen-to-hardware-back-button)
|
||||||
(navigation/navigate-replace :keycard-recovery-pin nil)))
|
(navigation/navigate-replace :keycard-recovery-pin nil)))
|
||||||
|
|
||||||
(fx/defn load-pairing
|
(rf/defn load-pairing
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(let [instance-uid (get-in db [:keycard :application-info :instance-uid])
|
(let [instance-uid (get-in db [:keycard :application-info :instance-uid])
|
||||||
pairing-data (or (get-in db [:keycard :pairings (keyword instance-uid)])
|
pairing-data (or (get-in db [:keycard :pairings (keyword instance-uid)])
|
||||||
(get-in db [:keycard :pairings instance-uid]))]
|
(get-in db [:keycard :pairings instance-uid]))]
|
||||||
{:db (update-in db [:keycard :secrets] merge pairing-data)}))
|
{:db (update-in db [:keycard :secrets] merge pairing-data)}))
|
||||||
|
|
||||||
(fx/defn proceed-setup-with-initialized-card
|
(rf/defn proceed-setup-with-initialized-card
|
||||||
[{:keys [db] :as cofx} flow instance-uid paired?]
|
[{:keys [db] :as cofx} flow instance-uid paired?]
|
||||||
(log/debug "[keycard] proceed-setup-with-initialized-card"
|
(log/debug "[keycard] proceed-setup-with-initialized-card"
|
||||||
"instance-uid" instance-uid)
|
"instance-uid"
|
||||||
|
instance-uid)
|
||||||
(if (= flow :import)
|
(if (= flow :import)
|
||||||
(navigation/navigate-to-cofx cofx :keycard-recovery-no-key nil)
|
(navigation/navigate-to-cofx cofx :keycard-recovery-no-key nil)
|
||||||
(if paired?
|
(if paired?
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(common/listen-to-hardware-back-button)
|
(common/listen-to-hardware-back-button)
|
||||||
(when (= flow :create)
|
(when (= flow :create)
|
||||||
(mnemonic/set-mnemonic))
|
(mnemonic/set-mnemonic))
|
||||||
@@ -74,25 +78,25 @@
|
|||||||
(onboarding/load-pairing-screen cofx)
|
(onboarding/load-pairing-screen cofx)
|
||||||
(recovery/load-pair-screen cofx)))))
|
(recovery/load-pair-screen cofx)))))
|
||||||
|
|
||||||
(fx/defn navigate-to-keycard-settings
|
(rf/defn navigate-to-keycard-settings
|
||||||
{:events [:profile.ui/keycard-settings-button-pressed]}
|
{:events [:profile.ui/keycard-settings-button-pressed]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:keycard :pin :on-verified] nil)
|
(assoc-in [:keycard :pin :on-verified] nil)
|
||||||
(assoc-in [:keycard :setup-step] nil))}
|
(assoc-in [:keycard :setup-step] nil))}
|
||||||
(common/clear-on-card-connected)
|
(common/clear-on-card-connected)
|
||||||
(navigation/navigate-to-cofx :keycard-settings nil)))
|
(navigation/navigate-to-cofx :keycard-settings nil)))
|
||||||
|
|
||||||
(fx/defn password-option-pressed
|
(rf/defn password-option-pressed
|
||||||
{:eevents [:keycard.ui/password-option-pressed]}
|
{:eevents [:keycard.ui/password-option-pressed]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(when (= (get-in db [:keycard :flow]) :create)
|
(when (= (get-in db [:keycard :flow]) :create)
|
||||||
#())) ;;TODO with v1 flow
|
#())) ;;TODO with v1 flow
|
||||||
|
|
||||||
(fx/defn settings-screen-did-load
|
(rf/defn settings-screen-did-load
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:keycard :pin :on-verified] nil)
|
(assoc-in [:keycard :pin :on-verified] nil)
|
||||||
(assoc-in [:keycard :setup-step] nil))}
|
(assoc-in [:keycard :setup-step] nil))}
|
||||||
@@ -111,7 +115,7 @@
|
|||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(let [enter-step (get-in db [:keycard :pin :enter-step])]
|
(let [enter-step (get-in db [:keycard :pin :enter-step])]
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:keycard :pin enter-step] [])
|
(assoc-in [:keycard :pin enter-step] [])
|
||||||
(dissoc :intro-wizard :recovered-account?))}))
|
(dissoc :intro-wizard :recovered-account?))}))
|
||||||
|
|
||||||
(defn multiaccounts-screen-did-load
|
(defn multiaccounts-screen-did-load
|
||||||
@@ -122,44 +126,51 @@
|
|||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
{:db (assoc-in db [:keycard :setup-step] nil)})
|
{:db (assoc-in db [:keycard :setup-step] nil)})
|
||||||
|
|
||||||
(fx/defn set-nfc-supported
|
(rf/defn set-nfc-supported
|
||||||
{:events [:keycard.callback/check-nfc-support-success]}
|
{:events [:keycard.callback/check-nfc-support-success]}
|
||||||
[_ supported?]
|
[_ supported?]
|
||||||
{:keycard/set-nfc-supported supported?})
|
{:keycard/set-nfc-supported supported?})
|
||||||
|
|
||||||
;; TODO: Should be listener and replace the view in bottom sheet to avoid this
|
;; TODO: Should be listener and replace the view in bottom sheet to avoid this
|
||||||
(fx/defn on-check-nfc-enabled-success
|
(rf/defn on-check-nfc-enabled-success
|
||||||
{:events [:keycard.callback/check-nfc-enabled-success]}
|
{:events [:keycard.callback/check-nfc-enabled-success]}
|
||||||
[{:keys [db]} nfc-enabled?]
|
[{:keys [db]} nfc-enabled?]
|
||||||
(log/debug "[keycard] check-nfc-enabled-success"
|
(log/debug "[keycard] check-nfc-enabled-success"
|
||||||
"nfc-enabled?" nfc-enabled?)
|
"nfc-enabled?"
|
||||||
|
nfc-enabled?)
|
||||||
{:db (assoc-in db [:keycard :nfc-enabled?] nfc-enabled?)})
|
{:db (assoc-in db [:keycard :nfc-enabled?] nfc-enabled?)})
|
||||||
|
|
||||||
(defn- proceed-to-pin-confirmation [fx]
|
(defn- proceed-to-pin-confirmation
|
||||||
|
[fx]
|
||||||
(assoc-in fx [:db :keycard :pin :enter-step] :confirmation))
|
(assoc-in fx [:db :keycard :pin :enter-step] :confirmation))
|
||||||
|
|
||||||
(defn- proceed-to-change-puk-confirmation [fx]
|
(defn- proceed-to-change-puk-confirmation
|
||||||
|
[fx]
|
||||||
(assoc-in fx [:db :keycard :pin :enter-step] :puk-confirmation))
|
(assoc-in fx [:db :keycard :pin :enter-step] :puk-confirmation))
|
||||||
|
|
||||||
(defn- proceed-to-pin-reset-confirmation [fx]
|
(defn- proceed-to-pin-reset-confirmation
|
||||||
|
[fx]
|
||||||
(-> fx
|
(-> fx
|
||||||
(update-in [:db :keycard :pin] dissoc :reset-confirmation)
|
(update-in [:db :keycard :pin] dissoc :reset-confirmation)
|
||||||
(assoc-in [:db :keycard :pin :enter-step] :reset-confirmation)))
|
(assoc-in [:db :keycard :pin :enter-step] :reset-confirmation)))
|
||||||
|
|
||||||
(defn- proceed-to-puk-confirmation [fx]
|
(defn- proceed-to-puk-confirmation
|
||||||
|
[fx]
|
||||||
(assoc-in fx [:db :keycard :pin :enter-step] :puk))
|
(assoc-in fx [:db :keycard :pin :enter-step] :puk))
|
||||||
|
|
||||||
(fx/defn on-unblock-pin-success
|
(rf/defn on-unblock-pin-success
|
||||||
{:events [:keycard.callback/on-unblock-pin-success]}
|
{:events [:keycard.callback/on-unblock-pin-success]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [reset-pin (get-in db [:keycard :pin :reset])]
|
(let [reset-pin (get-in db [:keycard :pin :reset])]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db
|
{:db
|
||||||
(-> db
|
(-> db
|
||||||
(update-in [:keycard :application-info] assoc
|
(update-in [:keycard :application-info]
|
||||||
|
assoc
|
||||||
:puk-retry-counter 5
|
:puk-retry-counter 5
|
||||||
:pin-retry-counter 3)
|
:pin-retry-counter 3)
|
||||||
(update-in [:keycard :pin] assoc
|
(update-in [:keycard :pin]
|
||||||
|
assoc
|
||||||
:status :after-unblocking
|
:status :after-unblocking
|
||||||
:enter-step :login
|
:enter-step :login
|
||||||
:login reset-pin
|
:login reset-pin
|
||||||
@@ -171,18 +182,19 @@
|
|||||||
(common/clear-on-card-connected)
|
(common/clear-on-card-connected)
|
||||||
(common/clear-on-card-read))))
|
(common/clear-on-card-read))))
|
||||||
|
|
||||||
(fx/defn on-unblock-pin-error
|
(rf/defn on-unblock-pin-error
|
||||||
{:events [:keycard.callback/on-unblock-pin-error]}
|
{:events [:keycard.callback/on-unblock-pin-error]}
|
||||||
[{:keys [db] :as cofx} error]
|
[{:keys [db] :as cofx} error]
|
||||||
(let [tag-was-lost? (common/tag-lost? (:error error))
|
(let [tag-was-lost? (common/tag-lost? (:error error))
|
||||||
puk-retries (common/pin-retries (:error error))]
|
puk-retries (common/pin-retries (:error error))]
|
||||||
(log/debug "[keycard] unblock pin error" error)
|
(log/debug "[keycard] unblock pin error" error)
|
||||||
(when-not tag-was-lost?
|
(when-not tag-was-lost?
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db
|
{:db
|
||||||
(-> db
|
(-> db
|
||||||
(assoc-in [:keycard :application-info :puk-retry-counter] puk-retries)
|
(assoc-in [:keycard :application-info :puk-retry-counter] puk-retries)
|
||||||
(update-in [:keycard :pin] merge
|
(update-in [:keycard :pin]
|
||||||
|
merge
|
||||||
{:status (if (zero? puk-retries) :blocked-card :error)
|
{:status (if (zero? puk-retries) :blocked-card :error)
|
||||||
:error-label :t/puk-mismatch
|
:error-label :t/puk-mismatch
|
||||||
:enter-step :puk
|
:enter-step :puk
|
||||||
@@ -190,19 +202,25 @@
|
|||||||
|
|
||||||
(common/hide-connection-sheet)))))
|
(common/hide-connection-sheet)))))
|
||||||
|
|
||||||
(fx/defn clear-on-verify-handlers
|
(rf/defn clear-on-verify-handlers
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
{:db (update-in db [:keycard :pin]
|
{:db (update-in db
|
||||||
dissoc :on-verified-failure :on-verified)})
|
[:keycard :pin]
|
||||||
|
dissoc
|
||||||
|
:on-verified-failure
|
||||||
|
:on-verified)})
|
||||||
|
|
||||||
(fx/defn on-verify-pin-success
|
(rf/defn on-verify-pin-success
|
||||||
{:events [:keycard.callback/on-verify-pin-success]}
|
{:events [:keycard.callback/on-verify-pin-success]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [on-verified (get-in db [:keycard :pin :on-verified])]
|
(let [on-verified (get-in db [:keycard :pin :on-verified])]
|
||||||
(log/debug "[hardwaller] success pin verification. on-verified" on-verified)
|
(log/debug "[hardwaller] success pin verification. on-verified" on-verified)
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (update-in db [:keycard :pin] merge {:status nil
|
{:db (update-in db
|
||||||
:error-label nil})}
|
[:keycard :pin]
|
||||||
|
merge
|
||||||
|
{:status nil
|
||||||
|
:error-label nil})}
|
||||||
(common/clear-on-card-connected)
|
(common/clear-on-card-connected)
|
||||||
(common/clear-on-card-read)
|
(common/clear-on-card-read)
|
||||||
;; TODO(Ferossgp): Each pin input should handle this event on it's own,
|
;; TODO(Ferossgp): Each pin input should handle this event on it's own,
|
||||||
@@ -211,33 +229,36 @@
|
|||||||
(when-not (contains? #{:keycard/generate-and-load-key
|
(when-not (contains? #{:keycard/generate-and-load-key
|
||||||
:wallet.accounts/generate-new-keycard-account
|
:wallet.accounts/generate-new-keycard-account
|
||||||
:keycard/remove-key-with-unpair
|
:keycard/remove-key-with-unpair
|
||||||
:keycard/unpair-and-delete} on-verified)
|
:keycard/unpair-and-delete}
|
||||||
|
on-verified)
|
||||||
(common/hide-connection-sheet))
|
(common/hide-connection-sheet))
|
||||||
(when-not (contains? #{:keycard/unpair
|
(when-not (contains? #{:keycard/unpair
|
||||||
:keycard/generate-and-load-key
|
:keycard/generate-and-load-key
|
||||||
:keycard/remove-key-with-unpair
|
:keycard/remove-key-with-unpair
|
||||||
:keycard/unpair-and-delete
|
:keycard/unpair-and-delete
|
||||||
:wallet.accounts/generate-new-keycard-account} on-verified)
|
:wallet.accounts/generate-new-keycard-account}
|
||||||
|
on-verified)
|
||||||
(common/get-application-info nil))
|
(common/get-application-info nil))
|
||||||
(when on-verified
|
(when on-verified
|
||||||
(common/dispatch-event on-verified))
|
(common/dispatch-event on-verified))
|
||||||
(clear-on-verify-handlers))))
|
(clear-on-verify-handlers))))
|
||||||
|
|
||||||
(fx/defn on-verify-pin-error
|
(rf/defn on-verify-pin-error
|
||||||
{:events [:keycard.callback/on-verify-pin-error]}
|
{:events [:keycard.callback/on-verify-pin-error]}
|
||||||
[{:keys [db] :as cofx} error]
|
[{:keys [db] :as cofx} error]
|
||||||
(let [tag-was-lost? (common/tag-lost? (:error error))
|
(let [tag-was-lost? (common/tag-lost? (:error error))
|
||||||
setup? (boolean (get-in db [:keycard :setup-step]))
|
setup? (boolean (get-in db [:keycard :setup-step]))
|
||||||
on-verified-failure (get-in db [:keycard :pin :on-verified-failure])
|
on-verified-failure (get-in db [:keycard :pin :on-verified-failure])
|
||||||
exporting? (get-in db [:keycard :on-export-success])
|
exporting? (get-in db [:keycard :on-export-success])
|
||||||
pin-retries (common/pin-retries (:error error))]
|
pin-retries (common/pin-retries (:error error))]
|
||||||
(log/debug "[keycard] verify pin error" error)
|
(log/debug "[keycard] verify pin error" error)
|
||||||
(when-not tag-was-lost?
|
(when-not tag-was-lost?
|
||||||
(if-not (nil? pin-retries)
|
(if-not (nil? pin-retries)
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:keycard :application-info :pin-retry-counter] pin-retries)
|
(assoc-in [:keycard :application-info :pin-retry-counter] pin-retries)
|
||||||
(update-in [:keycard :pin] assoc
|
(update-in [:keycard :pin]
|
||||||
|
assoc
|
||||||
:status :error
|
:status :error
|
||||||
:enter-step :current
|
:enter-step :current
|
||||||
:puk []
|
:puk []
|
||||||
@@ -251,20 +272,21 @@
|
|||||||
(not on-verified-failure))
|
(not on-verified-failure))
|
||||||
(when exporting?
|
(when exporting?
|
||||||
(navigation/navigate-back)))
|
(navigation/navigate-back)))
|
||||||
;(navigation/navigate-to-cofx :enter-pin-settings nil)))
|
;(navigation/navigate-to-cofx :enter-pin-settings nil)))
|
||||||
(when (zero? pin-retries) (common/frozen-keycard-popup))
|
(when (zero? pin-retries) (common/frozen-keycard-popup))
|
||||||
(when on-verified-failure
|
(when on-verified-failure
|
||||||
(fn [_] {:utils/dispatch-later
|
(fn [_]
|
||||||
[{:dispatch [on-verified-failure]
|
{:utils/dispatch-later
|
||||||
:ms 200}]}))
|
[{:dispatch [on-verified-failure]
|
||||||
|
:ms 200}]}))
|
||||||
#_(clear-on-verify-handlers))
|
#_(clear-on-verify-handlers))
|
||||||
|
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(common/hide-connection-sheet)
|
(common/hide-connection-sheet)
|
||||||
(common/show-wrong-keycard-alert)
|
(common/show-wrong-keycard-alert)
|
||||||
(clear-on-verify-handlers))))))
|
(clear-on-verify-handlers))))))
|
||||||
|
|
||||||
(fx/defn unblock-pin
|
(rf/defn unblock-pin
|
||||||
{:events [:keycard/unblock-pin]}
|
{:events [:keycard/unblock-pin]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(common/show-connection-sheet
|
(common/show-connection-sheet
|
||||||
@@ -275,7 +297,7 @@
|
|||||||
(let [puk (common/vector->string (get-in db [:keycard :pin :puk]))
|
(let [puk (common/vector->string (get-in db [:keycard :pin :puk]))
|
||||||
pin (common/vector->string (get-in db [:keycard :pin :reset]))
|
pin (common/vector->string (get-in db [:keycard :pin :reset]))
|
||||||
key-uid (get-in db [:keycard :application-info :key-uid])]
|
key-uid (get-in db [:keycard :application-info :key-uid])]
|
||||||
{:db (assoc-in db [:keycard :pin :status] :verifying)
|
{:db (assoc-in db [:keycard :pin :status] :verifying)
|
||||||
:keycard/unblock-pin
|
:keycard/unblock-pin
|
||||||
{:puk puk
|
{:puk puk
|
||||||
:new-pin pin}}))}))
|
:new-pin pin}}))}))
|
||||||
@@ -283,22 +305,24 @@
|
|||||||
(def pin-code-length 6)
|
(def pin-code-length 6)
|
||||||
(def puk-code-length 12)
|
(def puk-code-length 12)
|
||||||
|
|
||||||
(fx/defn handle-pin-input
|
(rf/defn handle-pin-input
|
||||||
[{:keys [db]} enter-step]
|
[{:keys [db]} enter-step]
|
||||||
(let [numbers-entered (count (get-in db [:keycard :pin enter-step]))]
|
(let [numbers-entered (count (get-in db [:keycard :pin enter-step]))]
|
||||||
(when (or (= numbers-entered pin-code-length)
|
(when (or (= numbers-entered pin-code-length)
|
||||||
(= numbers-entered puk-code-length))
|
(= numbers-entered puk-code-length))
|
||||||
{:dispatch [:keycard/process-pin-input]})))
|
{:dispatch [:keycard/process-pin-input]})))
|
||||||
|
|
||||||
(fx/defn update-pin
|
(rf/defn update-pin
|
||||||
{:events [:keycard.ui/pin-numpad-button-pressed]}
|
{:events [:keycard.ui/pin-numpad-button-pressed]}
|
||||||
[{:keys [db] :as cofx} number enter-step]
|
[{:keys [db] :as cofx} number enter-step]
|
||||||
(log/debug "update-pin" enter-step)
|
(log/debug "update-pin" enter-step)
|
||||||
(let [numbers-entered (count (get-in db [:keycard :pin enter-step]))
|
(let [numbers-entered (count (get-in db [:keycard :pin enter-step]))
|
||||||
need-update? (if (or (= enter-step :puk) (= enter-step :puk-original) (= enter-step :puk-confirmation))
|
need-update? (if (or (= enter-step :puk)
|
||||||
(< numbers-entered puk-code-length)
|
(= enter-step :puk-original)
|
||||||
(< numbers-entered pin-code-length))]
|
(= enter-step :puk-confirmation))
|
||||||
(fx/merge cofx
|
(< numbers-entered puk-code-length)
|
||||||
|
(< numbers-entered pin-code-length))]
|
||||||
|
(rf/merge cofx
|
||||||
{:db (cond-> (-> db
|
{:db (cond-> (-> db
|
||||||
(assoc-in [:keycard :pin :enter-step] enter-step)
|
(assoc-in [:keycard :pin :enter-step] enter-step)
|
||||||
(assoc-in [:keycard :pin :status] nil))
|
(assoc-in [:keycard :pin :status] nil))
|
||||||
@@ -306,26 +330,38 @@
|
|||||||
(when need-update?
|
(when need-update?
|
||||||
(handle-pin-input enter-step)))))
|
(handle-pin-input enter-step)))))
|
||||||
|
|
||||||
(defn- pin-enter-error [fx error-label]
|
(defn- pin-enter-error
|
||||||
(update-in fx [:db :keycard :pin] merge {:status :error
|
[fx error-label]
|
||||||
:error-label error-label
|
(update-in fx
|
||||||
:enter-step :original
|
[:db :keycard :pin]
|
||||||
:original []
|
merge
|
||||||
:confirmation []}))
|
{:status :error
|
||||||
|
:error-label error-label
|
||||||
|
:enter-step :original
|
||||||
|
:original []
|
||||||
|
:confirmation []}))
|
||||||
|
|
||||||
(defn- puk-enter-error [fx error-label]
|
(defn- puk-enter-error
|
||||||
(update-in fx [:db :keycard :pin] merge {:status :error
|
[fx error-label]
|
||||||
:error-label error-label
|
(update-in fx
|
||||||
:enter-step :puk-original
|
[:db :keycard :pin]
|
||||||
:puk-original []
|
merge
|
||||||
:puk-confirmation []}))
|
{:status :error
|
||||||
|
:error-label error-label
|
||||||
|
:enter-step :puk-original
|
||||||
|
:puk-original []
|
||||||
|
:puk-confirmation []}))
|
||||||
|
|
||||||
(defn- pin-reset-error [fx error-label]
|
(defn- pin-reset-error
|
||||||
(update-in fx [:db :keycard :pin] merge {:status :error
|
[fx error-label]
|
||||||
:error-label error-label
|
(update-in fx
|
||||||
:enter-step :reset
|
[:db :keycard :pin]
|
||||||
:reset []
|
merge
|
||||||
:reset-confirmation []}))
|
{:status :error
|
||||||
|
:error-label error-label
|
||||||
|
:enter-step :reset
|
||||||
|
:reset []
|
||||||
|
:reset-confirmation []}))
|
||||||
|
|
||||||
; PIN enter steps:
|
; PIN enter steps:
|
||||||
; login - PIN is used to login
|
; login - PIN is used to login
|
||||||
@@ -333,14 +369,14 @@
|
|||||||
; current - current PIN to perform actions which require PIN auth
|
; current - current PIN to perform actions which require PIN auth
|
||||||
; original - new PIN when user changes it or creates new one
|
; original - new PIN when user changes it or creates new one
|
||||||
; confirmation - confirmation for new PIN
|
; confirmation - confirmation for new PIN
|
||||||
(fx/defn process-pin-input
|
(rf/defn process-pin-input
|
||||||
{:events [:keycard/process-pin-input]}
|
{:events [:keycard/process-pin-input]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(let [enter-step (get-in db [:keycard :pin :enter-step])
|
(let [enter-step (get-in db [:keycard :pin :enter-step])
|
||||||
pin (get-in db [:keycard :pin enter-step])
|
pin (get-in db [:keycard :pin enter-step])
|
||||||
numbers-entered (count pin)]
|
numbers-entered (count pin)]
|
||||||
(log/debug "[keycard] process-pin-input"
|
(log/debug "[keycard] process-pin-input"
|
||||||
"enter-step" enter-step
|
"enter-step" enter-step
|
||||||
"numbers-entered" numbers-entered)
|
"numbers-entered" numbers-entered)
|
||||||
(cond-> {:db (assoc-in db [:keycard :pin :status] nil)}
|
(cond-> {:db (assoc-in db [:keycard :pin :status] nil)}
|
||||||
|
|
||||||
@@ -417,15 +453,19 @@
|
|||||||
(get-in db [:keycard :pin :reset-confirmation])))
|
(get-in db [:keycard :pin :reset-confirmation])))
|
||||||
(pin-reset-error :t/pin-mismatch))))
|
(pin-reset-error :t/pin-mismatch))))
|
||||||
|
|
||||||
(fx/defn set-multiaccount-pairing
|
(rf/defn set-multiaccount-pairing
|
||||||
[cofx _ pairing paired-on]
|
[cofx _ pairing paired-on]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(multiaccounts.update/multiaccount-update
|
(multiaccounts.update/multiaccount-update
|
||||||
:keycard-pairing pairing {})
|
:keycard-pairing
|
||||||
|
pairing
|
||||||
|
{})
|
||||||
(multiaccounts.update/multiaccount-update
|
(multiaccounts.update/multiaccount-update
|
||||||
:keycard-paired-on paired-on {})))
|
:keycard-paired-on
|
||||||
|
paired-on
|
||||||
|
{})))
|
||||||
|
|
||||||
(fx/defn on-retrieve-pairings-success
|
(rf/defn on-retrieve-pairings-success
|
||||||
{:events [:keycard.callback/on-retrieve-pairings-success]}
|
{:events [:keycard.callback/on-retrieve-pairings-success]}
|
||||||
[{:keys [db]} pairings]
|
[{:keys [db]} pairings]
|
||||||
(card/set-pairings pairings)
|
(card/set-pairings pairings)
|
||||||
@@ -438,7 +478,7 @@
|
|||||||
;; with setup and skip the pairing step if the pairing was already done during a previous
|
;; with setup and skip the pairing step if the pairing was already done during a previous
|
||||||
;; unfinished setup.
|
;; unfinished setup.
|
||||||
|
|
||||||
(fx/defn on-pair-success
|
(rf/defn on-pair-success
|
||||||
{:events [:keycard.callback/on-pair-success]}
|
{:events [:keycard.callback/on-pair-success]}
|
||||||
[{:keys [db] :as cofx} pairing]
|
[{:keys [db] :as cofx} pairing]
|
||||||
(let [setup-step (get-in db [:keycard :setup-step])
|
(let [setup-step (get-in db [:keycard :setup-step])
|
||||||
@@ -448,19 +488,20 @@
|
|||||||
paired-on (utils.datetime/timestamp)
|
paired-on (utils.datetime/timestamp)
|
||||||
pairings (-> (get-in db [:keycard :pairings])
|
pairings (-> (get-in db [:keycard :pairings])
|
||||||
(dissoc (keyword instance-uid))
|
(dissoc (keyword instance-uid))
|
||||||
(assoc instance-uid {:pairing pairing :paired-on paired-on}))
|
(assoc instance-uid {:pairing pairing :paired-on paired-on}))
|
||||||
next-step (if (= setup-step :pair)
|
next-step (if (= setup-step :pair)
|
||||||
:begin
|
:begin
|
||||||
:card-ready)]
|
:card-ready)]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:keycard/persist-pairings pairings
|
{:keycard/persist-pairings pairings
|
||||||
:db (-> db
|
:db (-> db
|
||||||
(assoc-in [:keycard :pairings] pairings)
|
(assoc-in [:keycard :pairings] pairings)
|
||||||
(assoc-in [:keycard :application-info :paired?] true)
|
(assoc-in [:keycard :application-info :paired?] true)
|
||||||
(assoc-in [:keycard :setup-step] next-step)
|
(assoc-in [:keycard :setup-step] next-step)
|
||||||
(assoc-in [:keycard :secrets :pairing] pairing)
|
(assoc-in [:keycard :secrets :pairing] pairing)
|
||||||
(assoc-in [:keycard :secrets :paired-on] paired-on))}
|
(assoc-in [:keycard :secrets :paired-on] paired-on))}
|
||||||
(when-not (and (= flow :recovery) (= next-step :card-ready)) (common/hide-connection-sheet))
|
(when-not (and (= flow :recovery) (= next-step :card-ready))
|
||||||
|
(common/hide-connection-sheet))
|
||||||
(when multiaccount
|
(when multiaccount
|
||||||
(set-multiaccount-pairing multiaccount pairing paired-on))
|
(set-multiaccount-pairing multiaccount pairing paired-on))
|
||||||
(when (= flow :login)
|
(when (= flow :login)
|
||||||
@@ -474,7 +515,7 @@
|
|||||||
(when (= flow :create)
|
(when (= flow :create)
|
||||||
(mnemonic/set-mnemonic)))))
|
(mnemonic/set-mnemonic)))))
|
||||||
|
|
||||||
(fx/defn on-pair-error
|
(rf/defn on-pair-error
|
||||||
{:events [:keycard.callback/on-pair-error]}
|
{:events [:keycard.callback/on-pair-error]}
|
||||||
[{:keys [db] :as cofx} {:keys [error code]}]
|
[{:keys [db] :as cofx} {:keys [error code]}]
|
||||||
(log/debug "[keycard] pair error: " error)
|
(log/debug "[keycard] pair error: " error)
|
||||||
@@ -483,7 +524,7 @@
|
|||||||
flow (get-in db [:keycard :flow])]
|
flow (get-in db [:keycard :flow])]
|
||||||
(log/debug "[keycard] on-pair-error" setup-step "flow:" flow)
|
(log/debug "[keycard] on-pair-error" setup-step "flow:" flow)
|
||||||
(when-not tag-was-lost?
|
(when-not tag-was-lost?
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc-in db [:keycard :setup-error] (i18n/label :t/invalid-pairing-password))}
|
{:db (assoc-in db [:keycard :setup-error] (i18n/label :t/invalid-pairing-password))}
|
||||||
(common/set-on-card-connected (if (= setup-step :pairing)
|
(common/set-on-card-connected (if (= setup-step :pairing)
|
||||||
:keycard/load-pairing-screen
|
:keycard/load-pairing-screen
|
||||||
@@ -494,17 +535,19 @@
|
|||||||
(when (not= setup-step :enter-pair-code)
|
(when (not= setup-step :enter-pair-code)
|
||||||
(common/process-error code error))))))
|
(common/process-error code error))))))
|
||||||
|
|
||||||
(fx/defn set-setup-step
|
(rf/defn set-setup-step
|
||||||
[{:keys [db]} card-state]
|
[{:keys [db]} card-state]
|
||||||
{:db (assoc-in db [:keycard :setup-step]
|
{:db (assoc-in db
|
||||||
(case card-state
|
[:keycard :setup-step]
|
||||||
:not-paired :pair
|
(case card-state
|
||||||
:no-pairing-slots :no-slots
|
:not-paired :pair
|
||||||
:init :card-ready
|
:no-pairing-slots :no-slots
|
||||||
:multiaccount :import-multiaccount
|
:init :card-ready
|
||||||
:begin))})
|
:multiaccount :import-multiaccount
|
||||||
|
:begin))})
|
||||||
|
|
||||||
(fx/defn show-no-keycard-applet-alert [_]
|
(rf/defn show-no-keycard-applet-alert
|
||||||
|
[_]
|
||||||
{:utils/show-confirmation {:title (i18n/label :t/no-keycard-applet-on-card)
|
{:utils/show-confirmation {:title (i18n/label :t/no-keycard-applet-on-card)
|
||||||
:content (i18n/label :t/keycard-applet-install-instructions)
|
:content (i18n/label :t/keycard-applet-install-instructions)
|
||||||
:cancel-button-text ""
|
:cancel-button-text ""
|
||||||
@@ -512,17 +555,17 @@
|
|||||||
|
|
||||||
;; NOTE: Maybe replaced by multiple events based on on flow to make it easier to maintain.
|
;; NOTE: Maybe replaced by multiple events based on on flow to make it easier to maintain.
|
||||||
;; Because there are many execution paths it is harder to follow all possible states.
|
;; Because there are many execution paths it is harder to follow all possible states.
|
||||||
(fx/defn check-card-state
|
(rf/defn check-card-state
|
||||||
{:events [:keycard/check-card-state]}
|
{:events [:keycard/check-card-state]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [app-info (get-in db [:keycard :application-info])
|
(let [app-info (get-in db [:keycard :application-info])
|
||||||
flow (get-in db [:keycard :flow])
|
flow (get-in db [:keycard :flow])
|
||||||
{:keys [instance-uid key-uid paired?]} app-info
|
{:keys [instance-uid key-uid paired?]} app-info
|
||||||
card-state (common/get-card-state app-info)]
|
card-state (common/get-card-state app-info)]
|
||||||
(log/debug "[keycard] check-card-state"
|
(log/debug "[keycard] check-card-state"
|
||||||
"card-state" card-state
|
"card-state" card-state
|
||||||
"flow" flow)
|
"flow" flow)
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc-in db [:keycard :card-state] card-state)}
|
{:db (assoc-in db [:keycard :card-state] card-state)}
|
||||||
(set-setup-step card-state)
|
(set-setup-step card-state)
|
||||||
|
|
||||||
@@ -538,7 +581,7 @@
|
|||||||
(if (= flow :import)
|
(if (= flow :import)
|
||||||
(navigation/navigate-to-cofx :keycard-recovery-no-key nil)
|
(navigation/navigate-to-cofx :keycard-recovery-no-key nil)
|
||||||
(fn [cofx]
|
(fn [cofx]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
(common/clear-on-card-read)
|
(common/clear-on-card-read)
|
||||||
(load-pin-screen)))))
|
(load-pin-screen)))))
|
||||||
@@ -560,72 +603,72 @@
|
|||||||
(#{:create :recovery} flow))
|
(#{:create :recovery} flow))
|
||||||
(show-keycard-has-multiaccount-alert)))))
|
(show-keycard-has-multiaccount-alert)))))
|
||||||
|
|
||||||
(fx/defn on-card-connected
|
(rf/defn on-card-connected
|
||||||
{:events [:keycard.callback/on-card-connected]}
|
{:events [:keycard.callback/on-card-connected]}
|
||||||
[{:keys [db]} _]
|
[{:keys [db]} _]
|
||||||
(log/debug "[keycard] card globally connected")
|
(log/debug "[keycard] card globally connected")
|
||||||
{:db (assoc-in db [:keycard :card-connected?] true)})
|
{:db (assoc-in db [:keycard :card-connected?] true)})
|
||||||
|
|
||||||
(fx/defn on-card-disconnected
|
(rf/defn on-card-disconnected
|
||||||
{:events [:keycard.callback/on-card-disconnected]}
|
{:events [:keycard.callback/on-card-disconnected]}
|
||||||
[{:keys [db]} _]
|
[{:keys [db]} _]
|
||||||
(log/debug "[keycard] card disconnected")
|
(log/debug "[keycard] card disconnected")
|
||||||
{:db (assoc-in db [:keycard :card-connected?] false)})
|
{:db (assoc-in db [:keycard :card-connected?] false)})
|
||||||
|
|
||||||
(fx/defn on-nfc-user-cancelled
|
(rf/defn on-nfc-user-cancelled
|
||||||
{:events [:keycard.callback/on-nfc-user-cancelled]}
|
{:events [:keycard.callback/on-nfc-user-cancelled]}
|
||||||
[{:keys [db]} _]
|
[{:keys [db]} _]
|
||||||
(log/debug "[keycard] nfc user cancelled")
|
(log/debug "[keycard] nfc user cancelled")
|
||||||
{:dispatch [:signing.ui/cancel-is-pressed]})
|
{:dispatch [:signing.ui/cancel-is-pressed]})
|
||||||
|
|
||||||
(fx/defn on-nfc-timeout
|
(rf/defn on-nfc-timeout
|
||||||
{:events [:keycard.callback/on-nfc-timeout]}
|
{:events [:keycard.callback/on-nfc-timeout]}
|
||||||
[{:keys [db]} _]
|
[{:keys [db]} _]
|
||||||
(log/debug "[keycard] nfc timeout")
|
(log/debug "[keycard] nfc timeout")
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:keycard :nfc-running?] false)
|
(assoc-in [:keycard :nfc-running?] false)
|
||||||
(assoc-in [:keycard :card-connected?] false))
|
(assoc-in [:keycard :card-connected?] false))
|
||||||
:dispatch-later [{:ms 500 :dispatch [:keycard.ui/start-nfc]}]})
|
:dispatch-later [{:ms 500 :dispatch [:keycard.ui/start-nfc]}]})
|
||||||
|
|
||||||
(fx/defn on-register-card-events
|
(rf/defn on-register-card-events
|
||||||
{:events [:keycard.callback/on-register-card-events]}
|
{:events [:keycard.callback/on-register-card-events]}
|
||||||
[{:keys [db]} listeners]
|
[{:keys [db]} listeners]
|
||||||
{:db (update-in db [:keycard :listeners] merge listeners)})
|
{:db (update-in db [:keycard :listeners] merge listeners)})
|
||||||
|
|
||||||
(fx/defn ui-recovery-phrase-cancel-pressed
|
(rf/defn ui-recovery-phrase-cancel-pressed
|
||||||
{:events [:keycard.ui/recovery-phrase-cancel-pressed]}
|
{:events [:keycard.ui/recovery-phrase-cancel-pressed]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
{:db (assoc-in db [:keycard :setup-step] :recovery-phrase)})
|
{:db (assoc-in db [:keycard :setup-step] :recovery-phrase)})
|
||||||
|
|
||||||
(fx/defn ui-pin-numpad-delete-button-pressed
|
(rf/defn ui-pin-numpad-delete-button-pressed
|
||||||
{:events [:keycard.ui/pin-numpad-delete-button-pressed]}
|
{:events [:keycard.ui/pin-numpad-delete-button-pressed]}
|
||||||
[{:keys [db]} step]
|
[{:keys [db]} step]
|
||||||
(when-not (empty? (get-in db [:keycard :pin step]))
|
(when-not (empty? (get-in db [:keycard :pin step]))
|
||||||
{:db (update-in db [:keycard :pin step] pop)}))
|
{:db (update-in db [:keycard :pin step] pop)}))
|
||||||
|
|
||||||
(fx/defn start-nfc
|
(rf/defn start-nfc
|
||||||
{:events [:keycard.ui/start-nfc]}
|
{:events [:keycard.ui/start-nfc]}
|
||||||
[cofx]
|
[cofx]
|
||||||
{:keycard/start-nfc nil})
|
{:keycard/start-nfc nil})
|
||||||
|
|
||||||
(fx/defn stop-nfc
|
(rf/defn stop-nfc
|
||||||
{:events [:keycard.ui/stop-nfc]}
|
{:events [:keycard.ui/stop-nfc]}
|
||||||
[cofx]
|
[cofx]
|
||||||
{:keycard/stop-nfc nil
|
{:keycard/stop-nfc nil
|
||||||
:keycard.callback/on-card-disconnected nil})
|
:keycard.callback/on-card-disconnected nil})
|
||||||
|
|
||||||
(fx/defn start-nfc-success
|
(rf/defn start-nfc-success
|
||||||
{:events [:keycard.callback/start-nfc-success]}
|
{:events [:keycard.callback/start-nfc-success]}
|
||||||
[{:keys [db]} _]
|
[{:keys [db]} _]
|
||||||
(log/debug "[keycard] nfc started success")
|
(log/debug "[keycard] nfc started success")
|
||||||
{:db (assoc-in db [:keycard :nfc-running?] true)})
|
{:db (assoc-in db [:keycard :nfc-running?] true)})
|
||||||
|
|
||||||
(fx/defn start-nfc-failure
|
(rf/defn start-nfc-failure
|
||||||
{:events [:keycard.callback/start-nfc-failure]}
|
{:events [:keycard.callback/start-nfc-failure]}
|
||||||
[{:keys [db]} _]
|
[{:keys [db]} _]
|
||||||
(log/debug "[keycard] nfc failed starting")) ;; leave current value on :nfc-running
|
(log/debug "[keycard] nfc failed starting")) ;; leave current value on :nfc-running
|
||||||
|
|
||||||
(fx/defn stop-nfc-success
|
(rf/defn stop-nfc-success
|
||||||
{:events [:keycard.callback/stop-nfc-success]}
|
{:events [:keycard.callback/stop-nfc-success]}
|
||||||
[{:keys [db]} _]
|
[{:keys [db]} _]
|
||||||
(log/debug "[keycard] nfc stopped success")
|
(log/debug "[keycard] nfc stopped success")
|
||||||
@@ -634,7 +677,7 @@
|
|||||||
(assoc-in [:keycard :nfc-running?] false)
|
(assoc-in [:keycard :nfc-running?] false)
|
||||||
(assoc-in [:keycard :card-connected?] false))})
|
(assoc-in [:keycard :card-connected?] false))})
|
||||||
|
|
||||||
(fx/defn stop-nfc-failure
|
(rf/defn stop-nfc-failure
|
||||||
{:events [:keycard.callback/stop-nfc-failure]}
|
{:events [:keycard.callback/stop-nfc-failure]}
|
||||||
[{:keys [db]} _]
|
[{:keys [db]} _]
|
||||||
(log/debug "[keycard] nfc failed stopping")) ;; leave current value on :nfc-running
|
(log/debug "[keycard] nfc failed stopping")) ;; leave current value on :nfc-running
|
||||||
|
|||||||
@@ -1,44 +1,46 @@
|
|||||||
(ns status-im.keycard.delete-key
|
(ns status-im.keycard.delete-key
|
||||||
(:require [status-im2.navigation.events :as navigation]
|
(:require [status-im.keycard.common :as common]
|
||||||
[status-im.utils.fx :as fx]
|
[status-im2.navigation.events :as navigation]
|
||||||
[status-im.keycard.common :as common]))
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(fx/defn reset-card-pressed
|
(rf/defn reset-card-pressed
|
||||||
{:events [:keycard-settings.ui/reset-card-pressed]}
|
{:events [:keycard-settings.ui/reset-card-pressed]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(navigation/navigate-to-cofx cofx :reset-card nil))
|
(navigation/navigate-to-cofx cofx :reset-card nil))
|
||||||
|
|
||||||
(fx/defn delete-card
|
(rf/defn delete-card
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [key-uid (get-in db [:keycard :application-info :key-uid])
|
(let [key-uid (get-in db [:keycard :application-info :key-uid])
|
||||||
multiaccount-key-uid (get-in db [:multiaccount :key-uid])]
|
multiaccount-key-uid (get-in db [:multiaccount :key-uid])]
|
||||||
(if (and key-uid
|
(if (and key-uid
|
||||||
(= key-uid multiaccount-key-uid))
|
(= key-uid multiaccount-key-uid))
|
||||||
{:keycard/delete nil}
|
{:keycard/delete nil}
|
||||||
(common/unauthorized-operation cofx))))
|
(common/unauthorized-operation cofx))))
|
||||||
|
|
||||||
(fx/defn navigate-to-reset-card-screen
|
(rf/defn navigate-to-reset-card-screen
|
||||||
{:events [:keycard/navigate-to-reset-card-screen]}
|
{:events [:keycard/navigate-to-reset-card-screen]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(navigation/navigate-to-cofx cofx :reset-card nil))
|
(navigation/navigate-to-cofx cofx :reset-card nil))
|
||||||
|
|
||||||
(fx/defn reset-card-next-button-pressed
|
(rf/defn reset-card-next-button-pressed
|
||||||
{:events [:keycard-settings.ui/reset-card-next-button-pressed]}
|
{:events [:keycard-settings.ui/reset-card-next-button-pressed]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
{:db (assoc-in db [:keycard :reset-card :disabled?] true)
|
{:db (assoc-in db [:keycard :reset-card :disabled?] true)
|
||||||
:dispatch [:keycard/proceed-to-reset-card false]})
|
:dispatch [:keycard/proceed-to-reset-card false]})
|
||||||
|
|
||||||
(fx/defn proceed-to-reset-card
|
(rf/defn proceed-to-reset-card
|
||||||
{:events [:keycard/proceed-to-reset-card]}
|
{:events [:keycard/proceed-to-reset-card]}
|
||||||
[{:keys [db] :as cofx} keep-keys-on-keycard?]
|
[{:keys [db] :as cofx} keep-keys-on-keycard?]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc-in db [:keycard :pin] {:enter-step :current
|
{:db (assoc-in db
|
||||||
:current []
|
[:keycard :pin]
|
||||||
:puk []
|
{:enter-step :current
|
||||||
:status nil
|
:current []
|
||||||
:error-label nil
|
:puk []
|
||||||
:on-verified (if keep-keys-on-keycard?
|
:status nil
|
||||||
:keycard/unpair-and-delete
|
:error-label nil
|
||||||
:keycard/remove-key-with-unpair)})}
|
:on-verified (if keep-keys-on-keycard?
|
||||||
|
:keycard/unpair-and-delete
|
||||||
|
:keycard/remove-key-with-unpair)})}
|
||||||
(common/set-on-card-connected :keycard/navigate-to-enter-pin-screen)
|
(common/set-on-card-connected :keycard/navigate-to-enter-pin-screen)
|
||||||
(common/navigate-to-enter-pin-screen)))
|
(common/navigate-to-enter-pin-screen)))
|
||||||
|
|||||||
@@ -1,47 +1,49 @@
|
|||||||
(ns status-im.keycard.export-key
|
(ns status-im.keycard.export-key
|
||||||
(:require [status-im.utils.fx :as fx]
|
(:require [status-im.keycard.common :as common]
|
||||||
[taoensso.timbre :as log]
|
|
||||||
[status-im.keycard.wallet :as wallet]
|
[status-im.keycard.wallet :as wallet]
|
||||||
[status-im.keycard.common :as common]))
|
[taoensso.timbre :as log]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(fx/defn on-export-key-error
|
(rf/defn on-export-key-error
|
||||||
{:events [:keycard.callback/on-export-key-error]}
|
{:events [:keycard.callback/on-export-key-error]}
|
||||||
[{:keys [db] :as cofx} error]
|
[{:keys [db] :as cofx} error]
|
||||||
(log/debug "[keycard] export key error" error)
|
(log/debug "[keycard] export key error" error)
|
||||||
(let [tag-was-lost? (common/tag-lost? (:error error))
|
(let [tag-was-lost? (common/tag-lost? (:error error))
|
||||||
pin-retries (common/pin-retries (:error error))]
|
pin-retries (common/pin-retries (:error error))]
|
||||||
(cond tag-was-lost?
|
(cond
|
||||||
(fx/merge cofx
|
tag-was-lost?
|
||||||
{:db (assoc-in db [:keycard :pin :status] nil)}
|
(rf/merge cofx
|
||||||
(common/set-on-card-connected :wallet.accounts/generate-new-keycard-account))
|
{:db (assoc-in db [:keycard :pin :status] nil)}
|
||||||
|
(common/set-on-card-connected :wallet.accounts/generate-new-keycard-account))
|
||||||
|
|
||||||
(not (nil? pin-retries))
|
(not (nil? pin-retries))
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:keycard :application-info :pin-retry-counter] pin-retries)
|
(assoc-in [:keycard :application-info :pin-retry-counter] pin-retries)
|
||||||
(update-in [:keycard :pin] assoc
|
(update-in [:keycard :pin]
|
||||||
:status :error
|
assoc
|
||||||
:enter-step :export-key
|
:status :error
|
||||||
:puk []
|
:enter-step :export-key
|
||||||
:current []
|
:puk []
|
||||||
:original []
|
:current []
|
||||||
:confirmation []
|
:original []
|
||||||
:sign []
|
:confirmation []
|
||||||
:export-key []
|
:sign []
|
||||||
:error-label :t/pin-mismatch))}
|
:export-key []
|
||||||
(common/hide-connection-sheet)
|
:error-label :t/pin-mismatch))}
|
||||||
(when (zero? pin-retries) (common/frozen-keycard-popup)))
|
(common/hide-connection-sheet)
|
||||||
:else
|
(when (zero? pin-retries) (common/frozen-keycard-popup)))
|
||||||
(fx/merge cofx
|
:else
|
||||||
(common/show-wrong-keycard-alert)
|
(rf/merge cofx
|
||||||
(common/clear-pin)
|
(common/show-wrong-keycard-alert)
|
||||||
(common/hide-connection-sheet)))))
|
(common/clear-pin)
|
||||||
|
(common/hide-connection-sheet)))))
|
||||||
|
|
||||||
(fx/defn on-export-key-success
|
(rf/defn on-export-key-success
|
||||||
{:events [:keycard.callback/on-export-key-success]}
|
{:events [:keycard.callback/on-export-key-success]}
|
||||||
[{:keys [db] :as cofx} pubkey]
|
[{:keys [db] :as cofx} pubkey]
|
||||||
(let [callback-fn (get-in db [:keycard :on-export-success])]
|
(let [callback-fn (get-in db [:keycard :on-export-success])]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:dispatch (callback-fn pubkey)}
|
{:dispatch (callback-fn pubkey)}
|
||||||
(wallet/hide-pin-sheet)
|
(wallet/hide-pin-sheet)
|
||||||
(common/clear-pin)
|
(common/clear-pin)
|
||||||
|
|||||||
@@ -1,70 +1,73 @@
|
|||||||
(ns status-im.keycard.login
|
(ns status-im.keycard.login
|
||||||
(:require [status-im.ethereum.core :as ethereum]
|
(:require [status-im.bottom-sheet.core :as bottom-sheet]
|
||||||
[status-im2.navigation.events :as navigation]
|
[status-im.ethereum.core :as ethereum]
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[status-im.utils.types :as types]
|
|
||||||
[taoensso.timbre :as log]
|
|
||||||
[status-im.keycard.common :as common]
|
[status-im.keycard.common :as common]
|
||||||
[status-im.keycard.recovery :as recovery]
|
|
||||||
[status-im.keycard.onboarding :as onboarding]
|
|
||||||
status-im.keycard.fx
|
status-im.keycard.fx
|
||||||
[status-im.bottom-sheet.core :as bottom-sheet]
|
[status-im.keycard.onboarding :as onboarding]
|
||||||
[status-im.signing.core :as signing.core]))
|
[status-im.keycard.recovery :as recovery]
|
||||||
|
[status-im.signing.core :as signing.core]
|
||||||
|
[status-im.utils.types :as types]
|
||||||
|
[status-im2.navigation.events :as navigation]
|
||||||
|
[taoensso.timbre :as log]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(fx/defn login-got-it-pressed
|
(rf/defn login-got-it-pressed
|
||||||
{:events [:keycard.login.pin.ui/got-it-pressed
|
{:events [:keycard.login.pin.ui/got-it-pressed
|
||||||
:keycard.login.pin.ui/cancel-pressed]}
|
:keycard.login.pin.ui/cancel-pressed]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db db}
|
{:db db}
|
||||||
(navigation/pop-to-root-tab :multiaccounts-stack)))
|
(navigation/pop-to-root-tab :multiaccounts-stack)))
|
||||||
|
|
||||||
(fx/defn login-pin-more-icon-pressed
|
(rf/defn login-pin-more-icon-pressed
|
||||||
{:events [:keycard.login.pin.ui/more-icon-pressed]}
|
{:events [:keycard.login.pin.ui/more-icon-pressed]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(bottom-sheet/show-bottom-sheet cofx {:view :keycard.login/more}))
|
(bottom-sheet/show-bottom-sheet cofx {:view :keycard.login/more}))
|
||||||
|
|
||||||
(fx/defn login-create-key-pressed
|
(rf/defn login-create-key-pressed
|
||||||
{:events [:keycard.login.ui/create-new-key-pressed]}
|
{:events [:keycard.login.ui/create-new-key-pressed]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(bottom-sheet/hide-bottom-sheet)
|
(bottom-sheet/hide-bottom-sheet)
|
||||||
(onboarding/start-onboarding-flow)))
|
(onboarding/start-onboarding-flow)))
|
||||||
|
|
||||||
(fx/defn login-add-key-pressed
|
(rf/defn login-add-key-pressed
|
||||||
{:events [:keycard.login.ui/add-key-pressed]}
|
{:events [:keycard.login.ui/add-key-pressed]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(recovery/start-import-flow cofx))
|
(recovery/start-import-flow cofx))
|
||||||
|
|
||||||
(fx/defn login-remember-me-changed
|
(rf/defn login-remember-me-changed
|
||||||
{:events [:keycard.login.ui/remember-me-changed]}
|
{:events [:keycard.login.ui/remember-me-changed]}
|
||||||
[{:keys [db] :as cofx} value]
|
[{:keys [db] :as cofx} value]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc-in db [:keycard :remember-me?] value)}))
|
{:db (assoc-in db [:keycard :remember-me?] value)}))
|
||||||
|
|
||||||
(fx/defn login-pair-card-pressed
|
(rf/defn login-pair-card-pressed
|
||||||
{:events [:keycard.login.ui/pair-card-pressed]}
|
{:events [:keycard.login.ui/pair-card-pressed]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(log/debug "[keycard] load-pair-card-pressed")
|
(log/debug "[keycard] load-pair-card-pressed")
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc-in db [:keycard :flow] :login)}
|
{:db (assoc-in db [:keycard :flow] :login)}
|
||||||
(navigation/navigate-to-cofx :keycard-recovery-pair nil)))
|
(navigation/navigate-to-cofx :keycard-recovery-pair nil)))
|
||||||
|
|
||||||
(fx/defn reset-pin
|
(rf/defn reset-pin
|
||||||
{:events [::reset-pin]}
|
{:events [::reset-pin]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
(signing.core/discard)
|
(signing.core/discard)
|
||||||
(fn [{:keys [db]}]
|
(fn [{:keys [db]}]
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(dissoc :popover/popover)
|
(dissoc :popover/popover)
|
||||||
(update-in [:keycard :pin] dissoc
|
(update-in [:keycard :pin]
|
||||||
:reset :puk)
|
dissoc
|
||||||
(update-in [:keycard :pin] assoc
|
:reset
|
||||||
:enter-step :reset
|
:puk)
|
||||||
:error nil
|
(update-in [:keycard :pin]
|
||||||
:status nil))
|
assoc
|
||||||
|
:enter-step :reset
|
||||||
|
:error nil
|
||||||
|
:status nil))
|
||||||
:hide-popover nil})
|
:hide-popover nil})
|
||||||
(when (:multiaccount db)
|
(when (:multiaccount db)
|
||||||
(navigation/change-tab :profile))
|
(navigation/change-tab :profile))
|
||||||
@@ -73,50 +76,51 @@
|
|||||||
(navigation/navigate-replace :keycard-pin nil)
|
(navigation/navigate-replace :keycard-pin nil)
|
||||||
(navigation/navigate-to-cofx :keycard-pin nil)))))
|
(navigation/navigate-to-cofx :keycard-pin nil)))))
|
||||||
|
|
||||||
(fx/defn dismiss-frozen-keycard-popover
|
(rf/defn dismiss-frozen-keycard-popover
|
||||||
{:events [::frozen-keycard-popover-dismissed]}
|
{:events [::frozen-keycard-popover-dismissed]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(dissoc :popover/popover)
|
(dissoc :popover/popover)
|
||||||
(update :keycard dissoc :setup-step))
|
(update :keycard dissoc :setup-step))
|
||||||
:hide-popover nil})
|
:hide-popover nil})
|
||||||
|
|
||||||
(fx/defn login-with-keycard
|
(rf/defn login-with-keycard
|
||||||
{:events [:keycard/login-with-keycard]}
|
{:events [:keycard/login-with-keycard]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [{:keys [:pin-retry-counter :puk-retry-counter]
|
(let [{:keys [:pin-retry-counter :puk-retry-counter]
|
||||||
:as application-info}
|
:as application-info}
|
||||||
(get-in db [:keycard :application-info])
|
(get-in db [:keycard :application-info])
|
||||||
|
|
||||||
key-uid (get-in db [:keycard :application-info :key-uid])
|
key-uid (get-in db [:keycard :application-info :key-uid])
|
||||||
paired? (get-in db [:keycard :application-info :paired?])
|
paired? (get-in db [:keycard :application-info :paired?])
|
||||||
multiaccount (get-in db [:multiaccounts/multiaccounts (get-in db [:multiaccounts/login :key-uid])])
|
multiaccount (get-in db
|
||||||
multiaccount-key-uid (get multiaccount :key-uid)
|
[:multiaccounts/multiaccounts (get-in db [:multiaccounts/login :key-uid])])
|
||||||
|
multiaccount-key-uid (get multiaccount :key-uid)
|
||||||
multiaccount-mismatch? (or (nil? multiaccount)
|
multiaccount-mismatch? (or (nil? multiaccount)
|
||||||
(not= multiaccount-key-uid key-uid))]
|
(not= multiaccount-key-uid key-uid))]
|
||||||
(log/debug "[keycard] login-with-keycard"
|
(log/debug "[keycard] login-with-keycard"
|
||||||
"empty application info" (empty? application-info)
|
"empty application info" (empty? application-info)
|
||||||
"no key-uid" (empty? key-uid)
|
"no key-uid" (empty? key-uid)
|
||||||
"multiaccount-mismatch?" multiaccount-mismatch?
|
"multiaccount-mismatch?" multiaccount-mismatch?
|
||||||
"no pairing" paired?)
|
"no pairing" paired?)
|
||||||
(cond
|
(cond
|
||||||
(empty? application-info)
|
(empty? application-info)
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(common/hide-connection-sheet)
|
(common/hide-connection-sheet)
|
||||||
(navigation/navigate-to-cofx :not-keycard nil))
|
(navigation/navigate-to-cofx :not-keycard nil))
|
||||||
|
|
||||||
(empty? key-uid)
|
(empty? key-uid)
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(common/hide-connection-sheet)
|
(common/hide-connection-sheet)
|
||||||
(navigation/navigate-to-cofx :keycard-blank nil))
|
(navigation/navigate-to-cofx :keycard-blank nil))
|
||||||
|
|
||||||
multiaccount-mismatch?
|
multiaccount-mismatch?
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(common/hide-connection-sheet)
|
(common/hide-connection-sheet)
|
||||||
(navigation/navigate-to-cofx :keycard-wrong nil))
|
(navigation/navigate-to-cofx :keycard-wrong nil))
|
||||||
|
|
||||||
(not paired?)
|
(not paired?)
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(common/hide-connection-sheet)
|
(common/hide-connection-sheet)
|
||||||
(navigation/navigate-to-cofx :keycard-unpaired nil))
|
(navigation/navigate-to-cofx :keycard-unpaired nil))
|
||||||
|
|
||||||
@@ -128,7 +132,7 @@
|
|||||||
:else
|
:else
|
||||||
(common/get-keys-from-keycard cofx))))
|
(common/get-keys-from-keycard cofx))))
|
||||||
|
|
||||||
(fx/defn proceed-to-login
|
(rf/defn proceed-to-login
|
||||||
{:events [::login-after-reset]}
|
{:events [::login-after-reset]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(log/debug "[keycard] proceed-to-login")
|
(log/debug "[keycard] proceed-to-login")
|
||||||
@@ -139,12 +143,14 @@
|
|||||||
:on-card-read :keycard/login-with-keycard
|
:on-card-read :keycard/login-with-keycard
|
||||||
:handler (common/get-application-info :keycard/login-with-keycard)}))
|
:handler (common/get-application-info :keycard/login-with-keycard)}))
|
||||||
|
|
||||||
(fx/defn on-keycard-keychain-keys
|
(rf/defn on-keycard-keychain-keys
|
||||||
{:events [:multiaccounts.login.callback/get-keycard-keys-success]}
|
{:events [:multiaccounts.login.callback/get-keycard-keys-success]}
|
||||||
[{:keys [db] :as cofx} key-uid [encryption-public-key whisper-private-key :as creds]]
|
[{:keys [db] :as cofx} key-uid [encryption-public-key whisper-private-key :as creds]]
|
||||||
(if (nil? creds)
|
(if (nil? creds)
|
||||||
(navigation/set-stack-root cofx :multiaccounts-stack [:multiaccounts
|
(navigation/set-stack-root cofx
|
||||||
:keycard-login-pin])
|
:multiaccounts-stack
|
||||||
|
[:multiaccounts
|
||||||
|
:keycard-login-pin])
|
||||||
(let [{:keys [identicon name]} (get-in db [:multiaccounts/multiaccounts key-uid])
|
(let [{:keys [identicon name]} (get-in db [:multiaccounts/multiaccounts key-uid])
|
||||||
multiaccount-data (types/clj->json {:name name
|
multiaccount-data (types/clj->json {:name name
|
||||||
:key-uid key-uid
|
:key-uid key-uid
|
||||||
@@ -160,18 +166,18 @@
|
|||||||
(update account-data :whisper-public-key ethereum/normalized-hex))
|
(update account-data :whisper-public-key ethereum/normalized-hex))
|
||||||
(assoc-in [:keycard :flow] nil)
|
(assoc-in [:keycard :flow] nil)
|
||||||
(update :multiaccounts/login assoc
|
(update :multiaccounts/login assoc
|
||||||
:password encryption-public-key
|
:password encryption-public-key
|
||||||
:key-uid key-uid
|
:key-uid key-uid
|
||||||
:identicon identicon
|
:identicon identicon
|
||||||
:name name
|
:name name
|
||||||
:save-password? true))
|
:save-password? true))
|
||||||
:keycard/login-with-keycard
|
:keycard/login-with-keycard
|
||||||
{:multiaccount-data multiaccount-data
|
{:multiaccount-data multiaccount-data
|
||||||
:key-uid key-uid
|
:key-uid key-uid
|
||||||
:password encryption-public-key
|
:password encryption-public-key
|
||||||
:chat-key whisper-private-key}})))
|
:chat-key whisper-private-key}})))
|
||||||
|
|
||||||
(fx/defn on-login-success
|
(rf/defn on-login-success
|
||||||
{:events [:keycard.login.callback/login-success]}
|
{:events [:keycard.login.callback/login-success]}
|
||||||
[_ result]
|
[_ result]
|
||||||
(log/debug "loginWithKeycard success: " result))
|
(log/debug "loginWithKeycard success: " result))
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
(ns status-im.keycard.mnemonic
|
(ns status-im.keycard.mnemonic
|
||||||
(:require [status-im2.navigation.events :as navigation]
|
(:require [status-im.keycard.common :as common]
|
||||||
[status-im.utils.fx :as fx]
|
status-im.keycard.fx
|
||||||
|
[status-im2.navigation.events :as navigation]
|
||||||
[taoensso.timbre :as log]
|
[taoensso.timbre :as log]
|
||||||
[status-im.keycard.common :as common]
|
[utils.re-frame :as rf]))
|
||||||
status-im.keycard.fx))
|
|
||||||
|
|
||||||
(fx/defn set-mnemonic
|
(rf/defn set-mnemonic
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(log/debug "[keycard] set-mnemonic")
|
(log/debug "[keycard] set-mnemonic")
|
||||||
(let [selected-id (get-in db [:intro-wizard :selected-id])
|
(let [selected-id (get-in db [:intro-wizard :selected-id])
|
||||||
mnemonic (reduce
|
mnemonic (reduce
|
||||||
(fn [_ {:keys [id mnemonic]}]
|
(fn [_ {:keys [id mnemonic]}]
|
||||||
(when (= selected-id id)
|
(when (= selected-id id)
|
||||||
(reduced mnemonic)))
|
(reduced mnemonic)))
|
||||||
nil
|
nil
|
||||||
(get-in db [:intro-wizard :multiaccounts]))]
|
(get-in db [:intro-wizard :multiaccounts]))]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:keycard :setup-step] :recovery-phrase)
|
(assoc-in [:keycard :setup-step] :recovery-phrase)
|
||||||
@@ -24,11 +24,11 @@
|
|||||||
(common/hide-connection-sheet)
|
(common/hide-connection-sheet)
|
||||||
(navigation/navigate-replace :keycard-onboarding-recovery-phrase nil))))
|
(navigation/navigate-replace :keycard-onboarding-recovery-phrase nil))))
|
||||||
|
|
||||||
(fx/defn load-loading-keys-screen
|
(rf/defn load-loading-keys-screen
|
||||||
{:events [:keycard.ui/recovery-phrase-confirm-pressed
|
{:events [:keycard.ui/recovery-phrase-confirm-pressed
|
||||||
:keycard/load-loading-keys-screen]}
|
:keycard/load-loading-keys-screen]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (assoc-in db [:keycard :setup-step] :loading-keys)}
|
{:db (assoc-in db [:keycard :setup-step] :loading-keys)}
|
||||||
(common/show-connection-sheet
|
(common/show-connection-sheet
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
(ns status-im.keycard.onboarding
|
(ns status-im.keycard.onboarding
|
||||||
(:require [clojure.string :as string]
|
(:require [clojure.string :as string]
|
||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
|
[status-im.constants :as constants]
|
||||||
[status-im.i18n.i18n :as i18n]
|
[status-im.i18n.i18n :as i18n]
|
||||||
[status-im2.navigation.events :as navigation]
|
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[status-im.utils.utils :as utils]
|
|
||||||
[status-im.keycard.common :as common]
|
[status-im.keycard.common :as common]
|
||||||
[status-im.keycard.mnemonic :as mnemonic]
|
|
||||||
[taoensso.timbre :as log]
|
|
||||||
status-im.keycard.fx
|
status-im.keycard.fx
|
||||||
|
[status-im.keycard.mnemonic :as mnemonic]
|
||||||
[status-im.ui.components.react :as react]
|
[status-im.ui.components.react :as react]
|
||||||
[status-im.constants :as constants]))
|
[status-im.utils.utils :as utils]
|
||||||
|
[status-im2.navigation.events :as navigation]
|
||||||
|
[taoensso.timbre :as log]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(fx/defn begin-setup-button-pressed
|
(rf/defn begin-setup-button-pressed
|
||||||
{:keys [:keycard.ui/begin-setup-button-pressed]}
|
{:keys [:keycard.ui/begin-setup-button-pressed]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
(assoc-in [:keycard :pin :original] [])
|
(assoc-in [:keycard :pin :original] [])
|
||||||
(assoc-in [:keycard :pin :confirmation] []))})
|
(assoc-in [:keycard :pin :confirmation] []))})
|
||||||
|
|
||||||
(fx/defn start-installation
|
(rf/defn start-installation
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [card-state (get-in db [:keycard :card-state])
|
(let [card-state (get-in db [:keycard :card-state])
|
||||||
pin (common/vector->string (get-in db [:keycard :pin :original]))]
|
pin (common/vector->string (get-in db [:keycard :pin :original]))]
|
||||||
@@ -33,12 +33,12 @@
|
|||||||
|
|
||||||
(do
|
(do
|
||||||
(log/debug (str "Cannot start keycard installation from state: " card-state))
|
(log/debug (str "Cannot start keycard installation from state: " card-state))
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:utils/show-popup {:title (i18n/label :t/error)
|
{:utils/show-popup {:title (i18n/label :t/error)
|
||||||
:content (i18n/label :t/something-went-wrong)}}
|
:content (i18n/label :t/something-went-wrong)}}
|
||||||
(navigation/navigate-to-cofx :keycard-authentication-method nil))))))
|
(navigation/navigate-to-cofx :keycard-authentication-method nil))))))
|
||||||
|
|
||||||
(fx/defn load-preparing-screen
|
(rf/defn load-preparing-screen
|
||||||
{:events [:keycard/load-preparing-screen]}
|
{:events [:keycard/load-preparing-screen]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(common/show-connection-sheet
|
(common/show-connection-sheet
|
||||||
@@ -47,11 +47,11 @@
|
|||||||
:on-card-connected :keycard/load-preparing-screen
|
:on-card-connected :keycard/load-preparing-screen
|
||||||
:handler start-installation}))
|
:handler start-installation}))
|
||||||
|
|
||||||
(fx/defn load-pairing-screen
|
(rf/defn load-pairing-screen
|
||||||
{:events [:keycard/load-pairing-screen
|
{:events [:keycard/load-pairing-screen
|
||||||
:keycard.onboarding.puk-code.ui/confirm-pressed]}
|
:keycard.onboarding.puk-code.ui/confirm-pressed]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (assoc-in db [:keycard :setup-step] :pairing)}
|
{:db (assoc-in db [:keycard :setup-step] :pairing)}
|
||||||
(common/show-connection-sheet
|
(common/show-connection-sheet
|
||||||
@@ -59,21 +59,22 @@
|
|||||||
:on-card-connected :keycard/load-pairing-screen
|
:on-card-connected :keycard/load-pairing-screen
|
||||||
:handler (common/dispatch-event :keycard/pair)})))
|
:handler (common/dispatch-event :keycard/pair)})))
|
||||||
|
|
||||||
(fx/defn puk-code-next-pressed
|
(rf/defn puk-code-next-pressed
|
||||||
{:events [:keycard.onboarding.puk-code.ui/next-pressed]}
|
{:events [:keycard.onboarding.puk-code.ui/next-pressed]}
|
||||||
[_]
|
[_]
|
||||||
{:ui/show-confirmation {:title (i18n/label :t/secret-keys-confirmation-title)
|
{:ui/show-confirmation {:title (i18n/label :t/secret-keys-confirmation-title)
|
||||||
:content (i18n/label :t/secret-keys-confirmation-text)
|
:content (i18n/label :t/secret-keys-confirmation-text)
|
||||||
:confirm-button-text (i18n/label :t/yes)
|
:confirm-button-text (i18n/label :t/yes)
|
||||||
:cancel-button-text (i18n/label :t/cancel)
|
:cancel-button-text (i18n/label :t/cancel)
|
||||||
:on-accept #(re-frame/dispatch [:keycard.onboarding.puk-code.ui/confirm-pressed])
|
:on-accept #(re-frame/dispatch
|
||||||
|
[:keycard.onboarding.puk-code.ui/confirm-pressed])
|
||||||
:on-cancel #()}})
|
:on-cancel #()}})
|
||||||
|
|
||||||
(fx/defn load-finishing-screen
|
(rf/defn load-finishing-screen
|
||||||
{:events [:keycard.onboarding.recovery-phrase-confirm-word2.ui/next-pressed
|
{:events [:keycard.onboarding.recovery-phrase-confirm-word2.ui/next-pressed
|
||||||
:keycard/load-finishing-screen]}
|
:keycard/load-finishing-screen]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (assoc-in db [:keycard :setup-step] :loading-keys)}
|
{:db (assoc-in db [:keycard :setup-step] :loading-keys)}
|
||||||
(common/show-connection-sheet
|
(common/show-connection-sheet
|
||||||
@@ -81,29 +82,30 @@
|
|||||||
:on-card-connected :keycard/load-finishing-screen
|
:on-card-connected :keycard/load-finishing-screen
|
||||||
:handler (common/dispatch-event :keycard/generate-and-load-key)})))
|
:handler (common/dispatch-event :keycard/generate-and-load-key)})))
|
||||||
|
|
||||||
(fx/defn recovery-phrase-learn-more-pressed
|
(rf/defn recovery-phrase-learn-more-pressed
|
||||||
{:events [:keycard.onboarding.recovery-phrase.ui/learn-more-pressed]}
|
{:events [:keycard.onboarding.recovery-phrase.ui/learn-more-pressed]}
|
||||||
[_]
|
[_]
|
||||||
(.openURL ^js react/linking constants/keycard-integration-link))
|
(.openURL ^js react/linking constants/keycard-integration-link))
|
||||||
|
|
||||||
(fx/defn recovery-phrase-next-pressed
|
(rf/defn recovery-phrase-next-pressed
|
||||||
{:events [:keycard.onboarding.recovery-phrase.ui/next-pressed
|
{:events [:keycard.onboarding.recovery-phrase.ui/next-pressed
|
||||||
:keycard.ui/recovery-phrase-next-button-pressed]}
|
:keycard.ui/recovery-phrase-next-button-pressed]}
|
||||||
[_]
|
[_]
|
||||||
{:ui/show-confirmation {:title (i18n/label :t/keycard-recovery-phrase-confirmation-title)
|
{:ui/show-confirmation {:title (i18n/label :t/keycard-recovery-phrase-confirmation-title)
|
||||||
:content (i18n/label :t/keycard-recovery-phrase-confirmation-text)
|
:content (i18n/label :t/keycard-recovery-phrase-confirmation-text)
|
||||||
:confirm-button-text (i18n/label :t/yes)
|
:confirm-button-text (i18n/label :t/yes)
|
||||||
:cancel-button-text (i18n/label :t/cancel)
|
:cancel-button-text (i18n/label :t/cancel)
|
||||||
:on-accept #(re-frame/dispatch [:keycard.onboarding.recovery-phrase.ui/confirm-pressed])
|
:on-accept #(re-frame/dispatch
|
||||||
:on-cancel #()}})
|
[:keycard.onboarding.recovery-phrase.ui/confirm-pressed])
|
||||||
|
:on-cancel #()}})
|
||||||
|
|
||||||
(fx/defn recovery-phrase-start-confirmation
|
(rf/defn recovery-phrase-start-confirmation
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [mnemonic (get-in db [:keycard :secrets :mnemonic])
|
(let [mnemonic (get-in db [:keycard :secrets :mnemonic])
|
||||||
[word1 word2] (shuffle (map-indexed vector (clojure.string/split mnemonic #" ")))
|
[word1 word2] (shuffle (map-indexed vector (clojure.string/split mnemonic #" ")))
|
||||||
word1 (zipmap [:idx :word] word1)
|
word1 (zipmap [:idx :word] word1)
|
||||||
word2 (zipmap [:idx :word] word2)]
|
word2 (zipmap [:idx :word] word2)]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:keycard :setup-step] :recovery-phrase-confirm-word1)
|
(assoc-in [:keycard :setup-step] :recovery-phrase-confirm-word1)
|
||||||
(assoc-in [:keycard :recovery-phrase :step] :word1)
|
(assoc-in [:keycard :recovery-phrase :step] :word1)
|
||||||
@@ -113,14 +115,14 @@
|
|||||||
(assoc-in [:keycard :recovery-phrase :word2] word2))}
|
(assoc-in [:keycard :recovery-phrase :word2] word2))}
|
||||||
(common/remove-listener-to-hardware-back-button))))
|
(common/remove-listener-to-hardware-back-button))))
|
||||||
|
|
||||||
(fx/defn recovery-phrase-confirm-pressed
|
(rf/defn recovery-phrase-confirm-pressed
|
||||||
{:events [:keycard.onboarding.recovery-phrase.ui/confirm-pressed]}
|
{:events [:keycard.onboarding.recovery-phrase.ui/confirm-pressed]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(recovery-phrase-start-confirmation)
|
(recovery-phrase-start-confirmation)
|
||||||
(navigation/navigate-to-cofx :keycard-onboarding-recovery-phrase-confirm-word1 nil)))
|
(navigation/navigate-to-cofx :keycard-onboarding-recovery-phrase-confirm-word1 nil)))
|
||||||
|
|
||||||
(fx/defn recovery-phrase-next-word
|
(rf/defn recovery-phrase-next-word
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:keycard :recovery-phrase :step] :word2)
|
(assoc-in [:keycard :recovery-phrase :step] :word2)
|
||||||
@@ -128,50 +130,52 @@
|
|||||||
(assoc-in [:keycard :recovery-phrase :input-word] nil)
|
(assoc-in [:keycard :recovery-phrase :input-word] nil)
|
||||||
(assoc-in [:keycard :setup-step] :recovery-phrase-confirm-word2))})
|
(assoc-in [:keycard :setup-step] :recovery-phrase-confirm-word2))})
|
||||||
|
|
||||||
(fx/defn proceed-with-generating-key
|
(rf/defn proceed-with-generating-key
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [pin (get-in db [:keycard :secrets :pin]
|
(let [pin (get-in db
|
||||||
|
[:keycard :secrets :pin]
|
||||||
(common/vector->string (get-in db [:keycard :pin :current])))]
|
(common/vector->string (get-in db [:keycard :pin :current])))]
|
||||||
(if (empty? pin)
|
(if (empty? pin)
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:keycard :pin] {:enter-step :current
|
(assoc-in [:keycard :pin]
|
||||||
:on-verified :keycard/generate-and-load-key
|
{:enter-step :current
|
||||||
:current []})
|
:on-verified :keycard/generate-and-load-key
|
||||||
|
:current []})
|
||||||
(assoc-in [:keycard :setup-step] :loading-keys))}
|
(assoc-in [:keycard :setup-step] :loading-keys))}
|
||||||
(navigation/navigate-to-cofx :keycard-onboarding-pin nil))
|
(navigation/navigate-to-cofx :keycard-onboarding-pin nil))
|
||||||
(load-finishing-screen cofx))))
|
(load-finishing-screen cofx))))
|
||||||
|
|
||||||
(fx/defn recovery-phrase-confirm-word-next-pressed
|
(rf/defn recovery-phrase-confirm-word-next-pressed
|
||||||
{:events [:keycard.onboarding.recovery-phrase-confirm-word.ui/next-pressed
|
{:events [:keycard.onboarding.recovery-phrase-confirm-word.ui/next-pressed
|
||||||
:keycard.onboarding.recovery-phrase-confirm-word.ui/input-submitted]}
|
:keycard.onboarding.recovery-phrase-confirm-word.ui/input-submitted]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [step (get-in db [:keycard :recovery-phrase :step])
|
(let [step (get-in db [:keycard :recovery-phrase :step])
|
||||||
input-word (get-in db [:keycard :recovery-phrase :input-word])
|
input-word (get-in db [:keycard :recovery-phrase :input-word])
|
||||||
{:keys [word]} (get-in db [:keycard :recovery-phrase step])]
|
{:keys [word]} (get-in db [:keycard :recovery-phrase step])]
|
||||||
(if (= word input-word)
|
(if (= word input-word)
|
||||||
(if (= (:view-id db) :keycard-onboarding-recovery-phrase-confirm-word1)
|
(if (= (:view-id db) :keycard-onboarding-recovery-phrase-confirm-word1)
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(recovery-phrase-next-word)
|
(recovery-phrase-next-word)
|
||||||
(navigation/navigate-replace :keycard-onboarding-recovery-phrase-confirm-word2 nil))
|
(navigation/navigate-replace :keycard-onboarding-recovery-phrase-confirm-word2 nil))
|
||||||
(proceed-with-generating-key cofx))
|
(proceed-with-generating-key cofx))
|
||||||
{:db (assoc-in db [:keycard :recovery-phrase :confirm-error] (i18n/label :t/wrong-word))})))
|
{:db (assoc-in db [:keycard :recovery-phrase :confirm-error] (i18n/label :t/wrong-word))})))
|
||||||
|
|
||||||
(fx/defn recovery-phrase-confirm-word-input-changed
|
(rf/defn recovery-phrase-confirm-word-input-changed
|
||||||
{:events [:keycard.onboarding.recovery-phrase-confirm-word.ui/input-changed]}
|
{:events [:keycard.onboarding.recovery-phrase-confirm-word.ui/input-changed]}
|
||||||
[{:keys [db]} input]
|
[{:keys [db]} input]
|
||||||
{:db (assoc-in db [:keycard :recovery-phrase :input-word] input)})
|
{:db (assoc-in db [:keycard :recovery-phrase :input-word] input)})
|
||||||
|
|
||||||
(fx/defn pair-code-input-changed
|
(rf/defn pair-code-input-changed
|
||||||
{:events [:keycard.onboarding.pair.ui/input-changed]}
|
{:events [:keycard.onboarding.pair.ui/input-changed]}
|
||||||
[{:keys [db]} input]
|
[{:keys [db]} input]
|
||||||
{:db (assoc-in db [:keycard :secrets :password] input)})
|
{:db (assoc-in db [:keycard :secrets :password] input)})
|
||||||
|
|
||||||
(fx/defn keycard-option-pressed
|
(rf/defn keycard-option-pressed
|
||||||
{:events [:onboarding.ui/keycard-option-pressed]}
|
{:events [:onboarding.ui/keycard-option-pressed]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [flow (get-in db [:keycard :flow])]
|
(let [flow (get-in db [:keycard :flow])]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:keycard/check-nfc-enabled nil}
|
{:keycard/check-nfc-enabled nil}
|
||||||
(if (= flow :import)
|
(if (= flow :import)
|
||||||
(navigation/navigate-to-cofx :keycard-recovery-intro nil)
|
(navigation/navigate-to-cofx :keycard-recovery-intro nil)
|
||||||
@@ -179,33 +183,36 @@
|
|||||||
(common/listen-to-hardware-back-button)
|
(common/listen-to-hardware-back-button)
|
||||||
(navigation/navigate-to-cofx :keycard-onboarding-intro nil))))))
|
(navigation/navigate-to-cofx :keycard-onboarding-intro nil))))))
|
||||||
|
|
||||||
(fx/defn start-onboarding-flow
|
(rf/defn start-onboarding-flow
|
||||||
{:events [:keycard/start-onboarding-flow]}
|
{:events [:keycard/start-onboarding-flow]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc-in db [:keycard :flow] :create)
|
{:db (assoc-in db [:keycard :flow] :create)
|
||||||
:keycard/check-nfc-enabled nil}
|
:keycard/check-nfc-enabled nil}
|
||||||
(common/listen-to-hardware-back-button)
|
(common/listen-to-hardware-back-button)
|
||||||
(navigation/navigate-to-cofx :keycard-onboarding-intro nil)))
|
(navigation/navigate-to-cofx :keycard-onboarding-intro nil)))
|
||||||
|
|
||||||
(fx/defn open-nfc-settings-pressed
|
(rf/defn open-nfc-settings-pressed
|
||||||
{:events [:keycard.onboarding.nfc-on/open-nfc-settings-pressed]}
|
{:events [:keycard.onboarding.nfc-on/open-nfc-settings-pressed]}
|
||||||
[_]
|
[_]
|
||||||
{:keycard/open-nfc-settings nil})
|
{:keycard/open-nfc-settings nil})
|
||||||
|
|
||||||
(defn- show-recover-confirmation []
|
(defn- show-recover-confirmation
|
||||||
|
[]
|
||||||
{:ui/show-confirmation {:title (i18n/label :t/are-you-sure?)
|
{:ui/show-confirmation {:title (i18n/label :t/are-you-sure?)
|
||||||
:content (i18n/label :t/are-you-sure-description)
|
:content (i18n/label :t/are-you-sure-description)
|
||||||
:confirm-button-text (clojure.string/upper-case (i18n/label :t/yes))
|
:confirm-button-text (clojure.string/upper-case (i18n/label :t/yes))
|
||||||
:cancel-button-text (i18n/label :t/see-it-again)
|
:cancel-button-text (i18n/label :t/see-it-again)
|
||||||
:on-accept #(re-frame/dispatch [:keycard.ui/recovery-phrase-confirm-pressed])
|
:on-accept #(re-frame/dispatch
|
||||||
:on-cancel #(re-frame/dispatch [:keycard.ui/recovery-phrase-cancel-pressed])}})
|
[:keycard.ui/recovery-phrase-confirm-pressed])
|
||||||
|
:on-cancel #(re-frame/dispatch
|
||||||
|
[:keycard.ui/recovery-phrase-cancel-pressed])}})
|
||||||
|
|
||||||
(fx/defn recovery-phrase-confirm-word
|
(rf/defn recovery-phrase-confirm-word
|
||||||
{:events [:keycard.ui/recovery-phrase-confirm-word-next-button-pressed]}
|
{:events [:keycard.ui/recovery-phrase-confirm-word-next-button-pressed]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(let [step (get-in db [:keycard :recovery-phrase :step])
|
(let [step (get-in db [:keycard :recovery-phrase :step])
|
||||||
input-word (get-in db [:keycard :recovery-phrase :input-word])
|
input-word (get-in db [:keycard :recovery-phrase :input-word])
|
||||||
{:keys [word]} (get-in db [:keycard :recovery-phrase step])]
|
{:keys [word]} (get-in db [:keycard :recovery-phrase step])]
|
||||||
(if (= word input-word)
|
(if (= word input-word)
|
||||||
(if (= step :word1)
|
(if (= step :word1)
|
||||||
@@ -213,21 +220,21 @@
|
|||||||
(show-recover-confirmation))
|
(show-recover-confirmation))
|
||||||
{:db (assoc-in db [:keycard :recovery-phrase :confirm-error] (i18n/label :t/wrong-word))})))
|
{:db (assoc-in db [:keycard :recovery-phrase :confirm-error] (i18n/label :t/wrong-word))})))
|
||||||
|
|
||||||
(fx/defn recovery-phrase-next-button-pressed
|
(rf/defn recovery-phrase-next-button-pressed
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(if (= (get-in db [:keycard :flow]) :create)
|
(if (= (get-in db [:keycard :flow]) :create)
|
||||||
(recovery-phrase-start-confirmation cofx)
|
(recovery-phrase-start-confirmation cofx)
|
||||||
(let [mnemonic (get-in db [:multiaccounts/recover :passphrase])]
|
(let [mnemonic (get-in db [:multiaccounts/recover :passphrase])]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc-in db [:keycard :secrets :mnemonic] mnemonic)}
|
{:db (assoc-in db [:keycard :secrets :mnemonic] mnemonic)}
|
||||||
(mnemonic/load-loading-keys-screen)))))
|
(mnemonic/load-loading-keys-screen)))))
|
||||||
|
|
||||||
(fx/defn on-install-applet-and-init-card-success
|
(rf/defn on-install-applet-and-init-card-success
|
||||||
{:events [:keycard.callback/on-install-applet-and-init-card-success
|
{:events [:keycard.callback/on-install-applet-and-init-card-success
|
||||||
:keycard.callback/on-init-card-success]}
|
:keycard.callback/on-init-card-success]}
|
||||||
[{:keys [db] :as cofx} secrets]
|
[{:keys [db] :as cofx} secrets]
|
||||||
(let [secrets' (js->clj secrets :keywordize-keys true)]
|
(let [secrets' (js->clj secrets :keywordize-keys true)]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:keycard :card-state] :init)
|
(assoc-in [:keycard :card-state] :init)
|
||||||
(assoc-in [:keycard :setup-step] :secret-keys)
|
(assoc-in [:keycard :setup-step] :secret-keys)
|
||||||
@@ -237,17 +244,17 @@
|
|||||||
:on-card-read :keycard/check-card-state
|
:on-card-read :keycard/check-card-state
|
||||||
:handler (common/get-application-info :keycard/check-card-state)}))))
|
:handler (common/get-application-info :keycard/check-card-state)}))))
|
||||||
|
|
||||||
(fx/defn on-install-applet-and-init-card-error
|
(rf/defn on-install-applet-and-init-card-error
|
||||||
{:events [:keycard.callback/on-install-applet-and-init-card-error
|
{:events [:keycard.callback/on-install-applet-and-init-card-error
|
||||||
:keycard.callback/on-init-card-error]}
|
:keycard.callback/on-init-card-error]}
|
||||||
[{:keys [db] :as cofx} {:keys [code error]}]
|
[{:keys [db] :as cofx} {:keys [code error]}]
|
||||||
(log/debug "[keycard] install applet and init card error: " error)
|
(log/debug "[keycard] install applet and init card error: " error)
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc-in db [:keycard :setup-error] error)}
|
{:db (assoc-in db [:keycard :setup-error] error)}
|
||||||
(common/set-on-card-connected :keycard/load-preparing-screen)
|
(common/set-on-card-connected :keycard/load-preparing-screen)
|
||||||
(common/process-error code error)))
|
(common/process-error code error)))
|
||||||
|
|
||||||
(fx/defn generate-and-load-key
|
(rf/defn generate-and-load-key
|
||||||
{:events [:keycard/generate-and-load-key]}
|
{:events [:keycard/generate-and-load-key]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [{:keys [pin]}
|
(let [{:keys [pin]}
|
||||||
@@ -256,36 +263,41 @@
|
|||||||
{:keys [selected-id multiaccounts]}
|
{:keys [selected-id multiaccounts]}
|
||||||
(:intro-wizard db)
|
(:intro-wizard db)
|
||||||
|
|
||||||
multiaccount (or (->> multiaccounts
|
multiaccount (or (->> multiaccounts
|
||||||
(filter #(= (:id %) selected-id))
|
(filter #(= (:id %) selected-id))
|
||||||
first)
|
first)
|
||||||
(assoc (get-in db [:intro-wizard :root-key])
|
(assoc (get-in db [:intro-wizard :root-key])
|
||||||
:derived
|
:derived
|
||||||
(get-in db [:intro-wizard :derived])))
|
(get-in db [:intro-wizard :derived])))
|
||||||
recovery-mnemonic (get-in db [:intro-wizard :passphrase])
|
recovery-mnemonic (get-in db [:intro-wizard :passphrase])
|
||||||
mnemonic (or (:mnemonic multiaccount)
|
mnemonic (or (:mnemonic multiaccount)
|
||||||
recovery-mnemonic)
|
recovery-mnemonic)
|
||||||
pin' (or pin (common/vector->string (get-in db [:keycard :pin :current])))]
|
pin' (or pin
|
||||||
(fx/merge cofx
|
(common/vector->string (get-in db
|
||||||
|
[:keycard :pin
|
||||||
|
:current])))]
|
||||||
|
(rf/merge cofx
|
||||||
{:keycard/generate-and-load-key
|
{:keycard/generate-and-load-key
|
||||||
{:mnemonic mnemonic
|
{:mnemonic mnemonic
|
||||||
:pin pin'
|
:pin pin'
|
||||||
:key-uid (:key-uid multiaccount)
|
:key-uid (:key-uid multiaccount)
|
||||||
:delete-multiaccount? (get-in db [:keycard :delete-account?])}})))
|
:delete-multiaccount? (get-in db [:keycard :delete-account?])}})))
|
||||||
|
|
||||||
(fx/defn factory-reset-card-toggle
|
(rf/defn factory-reset-card-toggle
|
||||||
{:events [:keycard.onboarding.intro.ui/factory-reset-card-toggle]}
|
{:events [:keycard.onboarding.intro.ui/factory-reset-card-toggle]}
|
||||||
[{:keys [db] :as cofx} checked?]
|
[{:keys [db] :as cofx} checked?]
|
||||||
{:db (assoc-in db [:keycard :factory-reset-card?] checked?)})
|
{:db (assoc-in db [:keycard :factory-reset-card?] checked?)})
|
||||||
|
|
||||||
(fx/defn begin-setup-pressed
|
(rf/defn begin-setup-pressed
|
||||||
{:events [:keycard.onboarding.intro.ui/begin-setup-pressed]}
|
{:events [:keycard.onboarding.intro.ui/begin-setup-pressed]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(update :keycard
|
(update :keycard
|
||||||
dissoc :secrets :card-state :multiaccount-wallet-address
|
dissoc
|
||||||
|
:secrets
|
||||||
|
:card-state :multiaccount-wallet-address
|
||||||
:multiaccount-whisper-public-key :application-info)
|
:multiaccount-whisper-public-key :application-info)
|
||||||
(assoc-in [:keycard :setup-step] :begin)
|
(assoc-in [:keycard :setup-step] :begin)
|
||||||
(assoc-in [:keycard :pin :on-verified] nil))}
|
(assoc-in [:keycard :pin :on-verified] nil))}
|
||||||
@@ -301,7 +313,7 @@
|
|||||||
:on-card-read :keycard/check-card-state
|
:on-card-read :keycard/check-card-state
|
||||||
:handler (common/get-application-info :keycard/check-card-state)}))))
|
:handler (common/get-application-info :keycard/check-card-state)}))))
|
||||||
|
|
||||||
(fx/defn factory-reset
|
(rf/defn factory-reset
|
||||||
{:events [::factory-reset]}
|
{:events [::factory-reset]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(common/show-connection-sheet
|
(common/show-connection-sheet
|
||||||
@@ -310,14 +322,14 @@
|
|||||||
:on-card-read :keycard/check-card-state
|
:on-card-read :keycard/check-card-state
|
||||||
:handler (common/factory-reset :keycard/check-card-state)}))
|
:handler (common/factory-reset :keycard/check-card-state)}))
|
||||||
|
|
||||||
(fx/defn factory-reset-cancel
|
(rf/defn factory-reset-cancel
|
||||||
{:events [::factory-reset-cancel]}
|
{:events [::factory-reset-cancel]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
{:db (update db :keycard dissoc :factory-reset-card?)})
|
{:db (update db :keycard dissoc :factory-reset-card?)})
|
||||||
|
|
||||||
(fx/defn cancel-pressed
|
(rf/defn cancel-pressed
|
||||||
{:events [::cancel-pressed]}
|
{:events [::cancel-pressed]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(navigation/navigate-back)
|
(navigation/navigate-back)
|
||||||
(common/cancel-sheet-confirm)))
|
(common/cancel-sheet-confirm)))
|
||||||
|
|||||||
+156
-136
@@ -1,30 +1,31 @@
|
|||||||
(ns status-im.keycard.recovery
|
(ns status-im.keycard.recovery
|
||||||
(:require [status-im2.navigation.events :as navigation]
|
(:require [clojure.string :as string]
|
||||||
[status-im.utils.datetime :as utils.datetime]
|
|
||||||
[status-im.multiaccounts.create.core :as multiaccounts.create]
|
|
||||||
[status-im.multiaccounts.model :as multiaccounts.model]
|
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
[clojure.string :as string]
|
[status-im.bottom-sheet.core :as bottom-sheet]
|
||||||
|
[status-im.constants :as constants]
|
||||||
|
[status-im.ethereum.core :as ethereum]
|
||||||
|
[status-im.ethereum.eip55 :as eip55]
|
||||||
[status-im.i18n.i18n :as i18n]
|
[status-im.i18n.i18n :as i18n]
|
||||||
[taoensso.timbre :as log]
|
|
||||||
[status-im.keycard.common :as common]
|
[status-im.keycard.common :as common]
|
||||||
status-im.keycard.fx
|
status-im.keycard.fx
|
||||||
[status-im.constants :as constants]
|
[status-im.multiaccounts.create.core :as multiaccounts.create]
|
||||||
[status-im.ethereum.eip55 :as eip55]
|
[status-im.multiaccounts.model :as multiaccounts.model]
|
||||||
[status-im.ethereum.core :as ethereum]
|
|
||||||
[status-im.bottom-sheet.core :as bottom-sheet]
|
|
||||||
[status-im.native-module.core :as status]
|
[status-im.native-module.core :as status]
|
||||||
[status-im.popover.core :as popover]
|
[status-im.popover.core :as popover]
|
||||||
[status-im.utils.types :as types]
|
[status-im.utils.datetime :as utils.datetime]
|
||||||
[utils.security.core :as security]
|
|
||||||
[status-im.utils.keychain.core :as keychain]
|
[status-im.utils.keychain.core :as keychain]
|
||||||
[status-im.utils.platform :as platform]))
|
[status-im.utils.platform :as platform]
|
||||||
|
[status-im.utils.types :as types]
|
||||||
|
[status-im2.navigation.events :as navigation]
|
||||||
|
[taoensso.timbre :as log]
|
||||||
|
[utils.re-frame :as rf]
|
||||||
|
[utils.security.core :as security]))
|
||||||
|
|
||||||
(fx/defn pair* [_ password]
|
(rf/defn pair*
|
||||||
|
[_ password]
|
||||||
{:keycard/pair {:password password}})
|
{:keycard/pair {:password password}})
|
||||||
|
|
||||||
(fx/defn pair
|
(rf/defn pair
|
||||||
{:events [:keycard/pair]}
|
{:events [:keycard/pair]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(let [{:keys [password]} (get-in cofx [:db :keycard :secrets])]
|
(let [{:keys [password]} (get-in cofx [:db :keycard :secrets])]
|
||||||
@@ -33,41 +34,41 @@
|
|||||||
{:on-card-connected :keycard/pair
|
{:on-card-connected :keycard/pair
|
||||||
:handler (pair* password)})))
|
:handler (pair* password)})))
|
||||||
|
|
||||||
(fx/defn pair-code-next-button-pressed
|
(rf/defn pair-code-next-button-pressed
|
||||||
{:events [:keycard.onboarding.pair.ui/input-submitted
|
{:events [:keycard.onboarding.pair.ui/input-submitted
|
||||||
:keycard.ui/pair-code-next-button-pressed
|
:keycard.ui/pair-code-next-button-pressed
|
||||||
:keycard.onboarding.pair.ui/next-pressed]}
|
:keycard.onboarding.pair.ui/next-pressed]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [pairing (get-in db [:keycard :secrets :pairing])
|
(let [pairing (get-in db [:keycard :secrets :pairing])
|
||||||
paired-on (get-in db [:keycard :secrets :paired-on] (utils.datetime/timestamp))]
|
paired-on (get-in db [:keycard :secrets :paired-on] (utils.datetime/timestamp))]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(if pairing
|
(if pairing
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:keycard :setup-step] :import-multiaccount)
|
(assoc-in [:keycard :setup-step] :import-multiaccount)
|
||||||
(assoc-in [:keycard :secrets :paired-on] paired-on))}
|
(assoc-in [:keycard :secrets :paired-on] paired-on))}
|
||||||
(pair)))))
|
(pair)))))
|
||||||
|
|
||||||
(fx/defn load-pair-screen
|
(rf/defn load-pair-screen
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(log/debug "[keycard] load-pair-screen")
|
(log/debug "[keycard] load-pair-screen")
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:keycard :setup-step] :pair))
|
(assoc-in [:keycard :setup-step] :pair))
|
||||||
:dispatch [:bottom-sheet/hide]}
|
:dispatch [:bottom-sheet/hide]}
|
||||||
(common/listen-to-hardware-back-button)
|
(common/listen-to-hardware-back-button)
|
||||||
(navigation/navigate-to-cofx :keycard-recovery-pair nil)))
|
(navigation/navigate-to-cofx :keycard-recovery-pair nil)))
|
||||||
|
|
||||||
(fx/defn keycard-storage-selected-for-recovery
|
(rf/defn keycard-storage-selected-for-recovery
|
||||||
{:events [:recovery.ui/keycard-storage-selected]}
|
{:events [:recovery.ui/keycard-storage-selected]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc-in db [:keycard :flow] :recovery)}
|
{:db (assoc-in db [:keycard :flow] :recovery)}
|
||||||
(navigation/navigate-to-cofx :keycard-recovery-enter-mnemonic nil)))
|
(navigation/navigate-to-cofx :keycard-recovery-enter-mnemonic nil)))
|
||||||
|
|
||||||
(fx/defn start-import-flow
|
(rf/defn start-import-flow
|
||||||
{:events [::recover-with-keycard-pressed]}
|
{:events [::recover-with-keycard-pressed]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db
|
{:db
|
||||||
(-> db
|
(-> db
|
||||||
(assoc-in [:keycard :flow] :import)
|
(assoc-in [:keycard :flow] :import)
|
||||||
@@ -76,35 +77,37 @@
|
|||||||
(bottom-sheet/hide-bottom-sheet)
|
(bottom-sheet/hide-bottom-sheet)
|
||||||
(navigation/navigate-to-cofx :keycard-recovery-intro nil)))
|
(navigation/navigate-to-cofx :keycard-recovery-intro nil)))
|
||||||
|
|
||||||
(fx/defn access-key-pressed
|
(rf/defn access-key-pressed
|
||||||
{:events [:multiaccounts.recover.ui/recover-multiaccount-button-pressed]}
|
{:events [:multiaccounts.recover.ui/recover-multiaccount-button-pressed]}
|
||||||
[_]
|
[_]
|
||||||
{:dispatch [:bottom-sheet/show-sheet :recover-sheet]})
|
{:dispatch [:bottom-sheet/show-sheet :recover-sheet]})
|
||||||
|
|
||||||
(fx/defn recovery-keycard-selected
|
(rf/defn recovery-keycard-selected
|
||||||
{:events [:recovery.ui/keycard-option-pressed]}
|
{:events [:recovery.ui/keycard-option-pressed]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc-in db [:keycard :flow] :recovery)
|
{:db (assoc-in db [:keycard :flow] :recovery)
|
||||||
:keycard/check-nfc-enabled nil}
|
:keycard/check-nfc-enabled nil}
|
||||||
(common/listen-to-hardware-back-button)
|
(common/listen-to-hardware-back-button)
|
||||||
(navigation/navigate-to-cofx :keycard-onboarding-intro nil)))
|
(navigation/navigate-to-cofx :keycard-onboarding-intro nil)))
|
||||||
|
|
||||||
(fx/defn cancel-pressed
|
(rf/defn cancel-pressed
|
||||||
{:events [::cancel-pressed]}
|
{:events [::cancel-pressed]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(common/cancel-sheet-confirm)
|
(common/cancel-sheet-confirm)
|
||||||
(navigation/navigate-back)))
|
(navigation/navigate-back)))
|
||||||
|
|
||||||
(fx/defn begin-setup-pressed
|
(rf/defn begin-setup-pressed
|
||||||
{:events [:keycard.recovery.intro.ui/begin-recovery-pressed]}
|
{:events [:keycard.recovery.intro.ui/begin-recovery-pressed]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(update :keycard
|
(update :keycard
|
||||||
dissoc :secrets :card-state :multiaccount-wallet-address
|
dissoc
|
||||||
|
:secrets
|
||||||
|
:card-state :multiaccount-wallet-address
|
||||||
:multiaccount-whisper-public-key
|
:multiaccount-whisper-public-key
|
||||||
:application-info)
|
:application-info)
|
||||||
(assoc-in [:keycard :setup-step] :begin)
|
(assoc-in [:keycard :setup-step] :begin)
|
||||||
@@ -115,21 +118,24 @@
|
|||||||
:sheet-options {:on-cancel [::cancel-pressed]}
|
:sheet-options {:on-cancel [::cancel-pressed]}
|
||||||
:handler (common/get-application-info :keycard/check-card-state)})))
|
:handler (common/get-application-info :keycard/check-card-state)})))
|
||||||
|
|
||||||
(fx/defn recovery-success-finish-pressed
|
(rf/defn recovery-success-finish-pressed
|
||||||
{:events [:keycard.recovery.success/finish-pressed]}
|
{:events [:keycard.recovery.success/finish-pressed]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (update db :keycard dissoc
|
{:db (update db
|
||||||
|
:keycard dissoc
|
||||||
:multiaccount-wallet-address
|
:multiaccount-wallet-address
|
||||||
:multiaccount-whisper-public-key)}
|
:multiaccount-whisper-public-key)}
|
||||||
(navigation/navigate-to-cofx (if platform/android?
|
(navigation/navigate-to-cofx (if platform/android?
|
||||||
:notifications-settings :welcome) nil)))
|
:notifications-settings
|
||||||
|
:welcome)
|
||||||
|
nil)))
|
||||||
|
|
||||||
(fx/defn intro-wizard
|
(rf/defn intro-wizard
|
||||||
{:events [:multiaccounts.create.ui/intro-wizard]}
|
{:events [:multiaccounts.create.ui/intro-wizard]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [accs (get db :multiaccounts/multiaccounts)]
|
(let [accs (get db :multiaccounts/multiaccounts)]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(update :keycard dissoc :flow)
|
(update :keycard dissoc :flow)
|
||||||
(dissoc :restored-account?))}
|
(dissoc :restored-account?))}
|
||||||
@@ -138,16 +144,16 @@
|
|||||||
(navigation/navigate-to-cofx :get-your-keys nil)
|
(navigation/navigate-to-cofx :get-your-keys nil)
|
||||||
(navigation/set-stack-root :onboarding [:get-your-keys])))))
|
(navigation/set-stack-root :onboarding [:get-your-keys])))))
|
||||||
|
|
||||||
(fx/defn recovery-no-key
|
(rf/defn recovery-no-key
|
||||||
{:events [:keycard.recovery.no-key.ui/generate-key-pressed]}
|
{:events [:keycard.recovery.no-key.ui/generate-key-pressed]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc-in db [:keycard :flow] :create)
|
{:db (assoc-in db [:keycard :flow] :create)
|
||||||
:keycard/check-nfc-enabled nil}
|
:keycard/check-nfc-enabled nil}
|
||||||
(intro-wizard)))
|
(intro-wizard)))
|
||||||
|
|
||||||
(fx/defn create-keycard-multiaccount
|
(rf/defn create-keycard-multiaccount
|
||||||
{:events [::create-keycard-multiaccount]
|
{:events [::create-keycard-multiaccount]
|
||||||
:interceptors [(re-frame/inject-cofx :random-guid-generator)
|
:interceptors [(re-frame/inject-cofx :random-guid-generator)
|
||||||
(re-frame/inject-cofx ::multiaccounts.create/get-signing-phrase)]}
|
(re-frame/inject-cofx ::multiaccounts.create/get-signing-phrase)]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
@@ -166,13 +172,14 @@
|
|||||||
encryption-public-key
|
encryption-public-key
|
||||||
instance-uid
|
instance-uid
|
||||||
key-uid
|
key-uid
|
||||||
recovered]} multiaccount
|
recovered]}
|
||||||
{:keys [pairing paired-on]} secrets
|
multiaccount
|
||||||
|
{:keys [pairing paired-on]} secrets
|
||||||
{:keys [name identicon]}
|
{:keys [name identicon]}
|
||||||
(if (nil? name)
|
(if (nil? name)
|
||||||
;; name might have been generated during recovery via passphrase
|
;; name might have been generated during recovery via passphrase
|
||||||
(get-in db [:intro-wizard :derived constants/path-whisper-keyword])
|
(get-in db [:intro-wizard :derived constants/path-whisper-keyword])
|
||||||
{:name name
|
{:name name
|
||||||
:identicon identicon})]
|
:identicon identicon})]
|
||||||
;; if a name is still `nil` we have to generate it before multiaccount's
|
;; if a name is still `nil` we have to generate it before multiaccount's
|
||||||
;; creation otherwise spec validation will fail
|
;; creation otherwise spec validation will fail
|
||||||
@@ -180,7 +187,7 @@
|
|||||||
{:keycard/generate-name-and-photo
|
{:keycard/generate-name-and-photo
|
||||||
{:public-key whisper-public-key
|
{:public-key whisper-public-key
|
||||||
:on-success ::on-name-and-photo-generated}}
|
:on-success ::on-name-and-photo-generated}}
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:keycard :setup-step] nil)
|
(assoc-in [:keycard :setup-step] nil)
|
||||||
(dissoc :intro-wizard))}
|
(dissoc :intro-wizard))}
|
||||||
@@ -193,7 +200,7 @@
|
|||||||
{:public-key whisper-public-key
|
{:public-key whisper-public-key
|
||||||
:address (eip55/address->checksum whisper-address)
|
:address (eip55/address->checksum whisper-address)
|
||||||
:name name
|
:name name
|
||||||
:identicon identicon}
|
:identicon identicon}
|
||||||
constants/path-default-wallet-keyword
|
constants/path-default-wallet-keyword
|
||||||
{:public-key wallet-public-key
|
{:public-key wallet-public-key
|
||||||
:address (eip55/address->checksum wallet-address)}}
|
:address (eip55/address->checksum wallet-address)}}
|
||||||
@@ -207,24 +214,29 @@
|
|||||||
encryption-public-key
|
encryption-public-key
|
||||||
{})))))
|
{})))))
|
||||||
|
|
||||||
(fx/defn return-to-keycard-login
|
(rf/defn return-to-keycard-login
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(update-in [:keycard :pin] assoc :enter-step :login
|
(update-in [:keycard :pin]
|
||||||
:status nil
|
assoc
|
||||||
:login [])
|
:enter-step :login
|
||||||
|
:status nil
|
||||||
|
:login [])
|
||||||
(update :keycard dissoc :application-info))}
|
(update :keycard dissoc :application-info))}
|
||||||
(navigation/set-stack-root :multiaccounts-stack [:multiaccounts
|
(navigation/set-stack-root :multiaccounts-stack
|
||||||
:keycard-login-pin])))
|
[:multiaccounts
|
||||||
|
:keycard-login-pin])))
|
||||||
|
|
||||||
(fx/defn on-backup-success
|
(rf/defn on-backup-success
|
||||||
[{:keys [db] :as cofx} backup-type]
|
[{:keys [db] :as cofx} backup-type]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:utils/show-popup {:title (i18n/label (if (= backup-type :recovery-card)
|
{:utils/show-popup {:title (i18n/label (if (= backup-type :recovery-card)
|
||||||
:t/keycard-access-reset :t/keycard-backup-success-title))
|
:t/keycard-access-reset
|
||||||
:content (i18n/label (if (= backup-type :recovery-card)
|
:t/keycard-backup-success-title))
|
||||||
:t/keycard-can-use-with-new-passcode :t/keycard-backup-success-body))}}
|
:content (i18n/label (if (= backup-type :recovery-card)
|
||||||
|
:t/keycard-can-use-with-new-passcode
|
||||||
|
:t/keycard-backup-success-body))}}
|
||||||
(cond
|
(cond
|
||||||
(multiaccounts.model/logged-in? cofx)
|
(multiaccounts.model/logged-in? cofx)
|
||||||
(navigation/set-stack-root :profile-stack [:my-profile :keycard-settings])
|
(navigation/set-stack-root :profile-stack [:my-profile :keycard-settings])
|
||||||
@@ -246,36 +258,40 @@
|
|||||||
#(let [{:keys [error]} (types/json->clj %)]
|
#(let [{:keys [error]} (types/json->clj %)]
|
||||||
(if (string/blank? error)
|
(if (string/blank? error)
|
||||||
(status/login-with-keycard login-params)
|
(status/login-with-keycard login-params)
|
||||||
(throw (js/Error. "Please shake the phone to report this error and restart the app. Migration failed unexpectedly.")))))))
|
(throw
|
||||||
|
(js/Error.
|
||||||
|
"Please shake the phone to report this error and restart the app. Migration failed unexpectedly.")))))))
|
||||||
|
|
||||||
(fx/defn migrate-account
|
(rf/defn migrate-account
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [pairing (get-in db [:keycard :secrets :pairing])
|
(let [pairing (get-in db [:keycard :secrets :pairing])
|
||||||
paired-on (get-in db [:keycard :secrets :paired-on])
|
paired-on (get-in db [:keycard :secrets :paired-on])
|
||||||
instance-uid (get-in db [:keycard :multiaccount :instance-uid])
|
instance-uid (get-in db [:keycard :multiaccount :instance-uid])
|
||||||
account (-> db
|
account (-> db
|
||||||
:multiaccounts/login
|
:multiaccounts/login
|
||||||
(assoc :keycard-pairing pairing)
|
(assoc :keycard-pairing pairing)
|
||||||
(assoc :save-password? false))
|
(assoc :save-password? false))
|
||||||
key-uid (-> account :key-uid)
|
key-uid (-> account :key-uid)
|
||||||
settings {:keycard-instance-uid instance-uid
|
settings {:keycard-instance-uid instance-uid
|
||||||
:keycard-paired-on paired-on
|
:keycard-paired-on paired-on
|
||||||
:keycard-pairing pairing}
|
:keycard-pairing pairing}
|
||||||
password (ethereum/sha3 (security/safe-unmask-data (get-in db [:keycard :migration-password])))
|
password (ethereum/sha3 (security/safe-unmask-data (get-in db
|
||||||
|
[:keycard
|
||||||
|
:migration-password])))
|
||||||
encryption-pass (get-in db [:keycard :multiaccount :encryption-public-key])
|
encryption-pass (get-in db [:keycard :multiaccount :encryption-public-key])
|
||||||
login-params {:key-uid key-uid
|
login-params {:key-uid key-uid
|
||||||
:multiaccount-data (types/clj->json account)
|
:multiaccount-data (types/clj->json account)
|
||||||
:password encryption-pass
|
:password encryption-pass
|
||||||
:chat-key (get-in db [:keycard :multiaccount :whisper-private-key])}]
|
:chat-key (get-in db [:keycard :multiaccount :whisper-private-key])}]
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:multiaccounts/multiaccounts key-uid :keycard-pairing] pairing)
|
(assoc-in [:multiaccounts/multiaccounts key-uid :keycard-pairing] pairing)
|
||||||
(assoc :multiaccounts/login account)
|
(assoc :multiaccounts/login account)
|
||||||
(assoc :auth-method keychain/auth-method-none)
|
(assoc :auth-method keychain/auth-method-none)
|
||||||
(update :keycard dissoc :flow :migration-password)
|
(update :keycard dissoc :flow :migration-password)
|
||||||
(dissoc :recovered-account?))
|
(dissoc :recovered-account?))
|
||||||
::finish-migration [account settings password encryption-pass login-params]}))
|
::finish-migration [account settings password encryption-pass login-params]}))
|
||||||
|
|
||||||
(fx/defn delete-multiaccount
|
(rf/defn delete-multiaccount
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(let [key-uid (get-in db [:multiaccounts/login :key-uid])]
|
(let [key-uid (get-in db [:multiaccounts/login :key-uid])]
|
||||||
{:keycard/delete-multiaccount-before-migration
|
{:keycard/delete-multiaccount-before-migration
|
||||||
@@ -283,61 +299,63 @@
|
|||||||
:on-error #(re-frame/dispatch [::delete-multiaccount-error %])
|
:on-error #(re-frame/dispatch [::delete-multiaccount-error %])
|
||||||
:on-success #(re-frame/dispatch [::create-keycard-multiaccount])}}))
|
:on-success #(re-frame/dispatch [::create-keycard-multiaccount])}}))
|
||||||
|
|
||||||
(fx/defn handle-delete-multiaccount-error
|
(rf/defn handle-delete-multiaccount-error
|
||||||
{:events [::delete-multiaccount-error]}
|
{:events [::delete-multiaccount-error]}
|
||||||
[cofx _]
|
[cofx _]
|
||||||
(popover/show-popover cofx {:view :transfer-multiaccount-unknown-error}))
|
(popover/show-popover cofx {:view :transfer-multiaccount-unknown-error}))
|
||||||
|
|
||||||
(fx/defn on-generate-and-load-key-success
|
(rf/defn on-generate-and-load-key-success
|
||||||
{:events [:keycard.callback/on-generate-and-load-key-success]
|
{:events [:keycard.callback/on-generate-and-load-key-success]
|
||||||
:interceptors [(re-frame/inject-cofx :random-guid-generator)
|
:interceptors [(re-frame/inject-cofx :random-guid-generator)
|
||||||
(re-frame/inject-cofx ::multiaccounts.create/get-signing-phrase)]}
|
(re-frame/inject-cofx ::multiaccounts.create/get-signing-phrase)]}
|
||||||
[{:keys [db random-guid-generator] :as cofx} data]
|
[{:keys [db random-guid-generator] :as cofx} data]
|
||||||
(let [account-data (js->clj data :keywordize-keys true)
|
(let [account-data (js->clj data :keywordize-keys true)
|
||||||
backup? (get-in db [:keycard :creating-backup?])
|
backup? (get-in db [:keycard :creating-backup?])
|
||||||
migration? (get-in db [:keycard :converting-account?])]
|
migration? (get-in db [:keycard :converting-account?])]
|
||||||
(fx/merge cofx
|
(rf/merge
|
||||||
{:db (-> db
|
cofx
|
||||||
(assoc-in [:keycard :multiaccount]
|
{:db (-> db
|
||||||
(-> account-data
|
(assoc-in
|
||||||
(update :address ethereum/normalized-hex)
|
[:keycard :multiaccount]
|
||||||
(update :whisper-address ethereum/normalized-hex)
|
(-> account-data
|
||||||
(update :wallet-address ethereum/normalized-hex)
|
(update :address ethereum/normalized-hex)
|
||||||
(update :wallet-root-address ethereum/normalized-hex)
|
(update :whisper-address ethereum/normalized-hex)
|
||||||
(update :public-key ethereum/normalized-hex)
|
(update :wallet-address ethereum/normalized-hex)
|
||||||
(update :whisper-public-key ethereum/normalized-hex)
|
(update :wallet-root-address ethereum/normalized-hex)
|
||||||
(update :wallet-public-key ethereum/normalized-hex)
|
(update :public-key ethereum/normalized-hex)
|
||||||
(update :wallet-root-public-key ethereum/normalized-hex)
|
(update :whisper-public-key ethereum/normalized-hex)
|
||||||
(update :instance-uid #(get-in db [:keycard :multiaccount :instance-uid] %))))
|
(update :wallet-public-key ethereum/normalized-hex)
|
||||||
(assoc-in [:keycard :multiaccount-wallet-address] (:wallet-address account-data))
|
(update :wallet-root-public-key ethereum/normalized-hex)
|
||||||
(assoc-in [:keycard :multiaccount-whisper-public-key] (:whisper-public-key account-data))
|
(update :instance-uid #(get-in db [:keycard :multiaccount :instance-uid] %))))
|
||||||
(assoc-in [:keycard :pin :status] nil)
|
(assoc-in [:keycard :multiaccount-wallet-address] (:wallet-address account-data))
|
||||||
(assoc-in [:keycard :application-info :key-uid]
|
(assoc-in [:keycard :multiaccount-whisper-public-key] (:whisper-public-key account-data))
|
||||||
(ethereum/normalized-hex (:key-uid account-data)))
|
(assoc-in [:keycard :pin :status] nil)
|
||||||
(update :keycard dissoc :recovery-phrase :creating-backup? :converting-account?)
|
(assoc-in [:keycard :application-info :key-uid]
|
||||||
(update-in [:keycard :secrets] dissoc :pin :puk :password :mnemonic)
|
(ethereum/normalized-hex (:key-uid account-data)))
|
||||||
(assoc :multiaccounts/new-installation-id (random-guid-generator)))}
|
(update :keycard dissoc :recovery-phrase :creating-backup? :converting-account?)
|
||||||
(common/remove-listener-to-hardware-back-button)
|
(update-in [:keycard :secrets] dissoc :pin :puk :password :mnemonic)
|
||||||
(common/hide-connection-sheet)
|
(assoc :multiaccounts/new-installation-id (random-guid-generator)))}
|
||||||
(cond backup? (on-backup-success backup?)
|
(common/remove-listener-to-hardware-back-button)
|
||||||
migration? (migrate-account)
|
(common/hide-connection-sheet)
|
||||||
|
(cond backup? (on-backup-success backup?)
|
||||||
|
migration? (migrate-account)
|
||||||
|
|
||||||
(get-in db [:keycard :delete-account?])
|
(get-in db [:keycard :delete-account?])
|
||||||
(delete-multiaccount)
|
(delete-multiaccount)
|
||||||
|
|
||||||
:else (create-keycard-multiaccount)))))
|
:else (create-keycard-multiaccount)))))
|
||||||
|
|
||||||
(fx/defn on-generate-and-load-key-error
|
(rf/defn on-generate-and-load-key-error
|
||||||
{:events [:keycard.callback/on-generate-and-load-key-error]}
|
{:events [:keycard.callback/on-generate-and-load-key-error]}
|
||||||
[{:keys [db] :as cofx} {:keys [error code]}]
|
[{:keys [db] :as cofx} {:keys [error code]}]
|
||||||
(log/debug "[keycard] generate and load key error: " error)
|
(log/debug "[keycard] generate and load key error: " error)
|
||||||
(when-not (common/tag-lost? error)
|
(when-not (common/tag-lost? error)
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc-in db [:keycard :setup-error] error)}
|
{:db (assoc-in db [:keycard :setup-error] error)}
|
||||||
(common/set-on-card-connected :keycard/load-loading-keys-screen)
|
(common/set-on-card-connected :keycard/load-loading-keys-screen)
|
||||||
(common/process-error code error))))
|
(common/process-error code error))))
|
||||||
|
|
||||||
(fx/defn import-multiaccount
|
(rf/defn import-multiaccount
|
||||||
{:events [:keycard/import-multiaccount]}
|
{:events [:keycard/import-multiaccount]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [{:keys [pairing]} (get-in db [:keycard :secrets])
|
(let [{:keys [pairing]} (get-in db [:keycard :secrets])
|
||||||
@@ -345,17 +363,18 @@
|
|||||||
key-uid (get-in db [:keycard :application-info :key-uid])
|
key-uid (get-in db [:keycard :application-info :key-uid])
|
||||||
pairing' (or pairing (common/get-pairing db key-uid))
|
pairing' (or pairing (common/get-pairing db key-uid))
|
||||||
pin (common/vector->string (get-in db [:keycard :pin :import-multiaccount]))]
|
pin (common/vector->string (get-in db [:keycard :pin :import-multiaccount]))]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:keycard :multiaccount :instance-uid] instance-uid)
|
(assoc-in [:keycard :multiaccount :instance-uid] instance-uid)
|
||||||
(assoc-in [:keycard :pin :status] :verifying)
|
(assoc-in [:keycard :pin :status] :verifying)
|
||||||
(assoc-in [:keycard :secrets] {:pairing pairing'
|
(assoc-in [:keycard :secrets]
|
||||||
:paired-on (utils.datetime/timestamp)}))
|
{:pairing pairing'
|
||||||
|
:paired-on (utils.datetime/timestamp)}))
|
||||||
:keycard/import-keys
|
:keycard/import-keys
|
||||||
{:pin pin
|
{:pin pin
|
||||||
:on-success :keycard.callback/on-generate-and-load-key-success}})))
|
:on-success :keycard.callback/on-generate-and-load-key-success}})))
|
||||||
|
|
||||||
(fx/defn load-recovering-key-screen
|
(rf/defn load-recovering-key-screen
|
||||||
{:events [:keycard/load-recovering-key-screen]}
|
{:events [:keycard/load-recovering-key-screen]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(common/show-connection-sheet
|
(common/show-connection-sheet
|
||||||
@@ -363,17 +382,18 @@
|
|||||||
{:on-card-connected :keycard/load-recovering-key-screen
|
{:on-card-connected :keycard/load-recovering-key-screen
|
||||||
:handler (common/dispatch-event :keycard/import-multiaccount)}))
|
:handler (common/dispatch-event :keycard/import-multiaccount)}))
|
||||||
|
|
||||||
(fx/defn on-name-and-photo-generated
|
(rf/defn on-name-and-photo-generated
|
||||||
{:events [::on-name-and-photo-generated]
|
{:events [::on-name-and-photo-generated]
|
||||||
:interceptors [(re-frame/inject-cofx :random-guid-generator)
|
:interceptors [(re-frame/inject-cofx :random-guid-generator)
|
||||||
(re-frame/inject-cofx ::multiaccounts.create/get-signing-phrase)]}
|
(re-frame/inject-cofx ::multiaccounts.create/get-signing-phrase)]}
|
||||||
[{:keys [db] :as cofx} whisper-name identicon]
|
[{:keys [db] :as cofx} whisper-name identicon]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (update-in db [:keycard :multiaccount]
|
{:db (update-in db
|
||||||
|
[:keycard :multiaccount]
|
||||||
(fn [multiacc]
|
(fn [multiacc]
|
||||||
(assoc multiacc
|
(assoc multiacc
|
||||||
:recovered (get db :recovered-account?)
|
:recovered (get db :recovered-account?)
|
||||||
:name whisper-name
|
:name whisper-name
|
||||||
:identicon identicon)))}
|
:identicon identicon)))}
|
||||||
(create-keycard-multiaccount)))
|
(create-keycard-multiaccount)))
|
||||||
|
|||||||
@@ -1,46 +1,49 @@
|
|||||||
(ns status-im.keycard.sign
|
(ns status-im.keycard.sign
|
||||||
(:require [re-frame.core :as re-frame]
|
(:require [clojure.string :as string]
|
||||||
|
[re-frame.core :as re-frame]
|
||||||
[status-im.ethereum.core :as ethereum]
|
[status-im.ethereum.core :as ethereum]
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
[status-im.utils.fx :as fx]
|
[status-im.keycard.common :as common]
|
||||||
[status-im.utils.money :as money]
|
[status-im.utils.money :as money]
|
||||||
[status-im.utils.types :as types]
|
[status-im.utils.types :as types]
|
||||||
[taoensso.timbre :as log]
|
[taoensso.timbre :as log]
|
||||||
[status-im.keycard.common :as common]
|
[utils.re-frame :as rf]))
|
||||||
[clojure.string :as string]))
|
|
||||||
|
|
||||||
(fx/defn sign
|
(rf/defn sign
|
||||||
{:events [:keycard/sign]}
|
{:events [:keycard/sign]}
|
||||||
[{:keys [db] :as cofx} hash on-success]
|
[{:keys [db] :as cofx} hash on-success]
|
||||||
(let [card-connected? (get-in db [:keycard :card-connected?])
|
(let [card-connected? (get-in db [:keycard :card-connected?])
|
||||||
key-uid (get-in db [:multiaccount :key-uid])
|
key-uid (get-in db [:multiaccount :key-uid])
|
||||||
keycard-key-uid (get-in db [:keycard :application-info :key-uid])
|
keycard-key-uid (get-in db [:keycard :application-info :key-uid])
|
||||||
keycard-pin-retries (get-in db [:keycard :application-info :pin-retry-counter])
|
keycard-pin-retries (get-in db [:keycard :application-info :pin-retry-counter])
|
||||||
keycard-match? (= key-uid keycard-key-uid)
|
keycard-match? (= key-uid keycard-key-uid)
|
||||||
hash (or hash (get-in db [:keycard :hash]))
|
hash (or hash (get-in db [:keycard :hash]))
|
||||||
data (get-in db [:keycard :data])
|
data (get-in db [:keycard :data])
|
||||||
typed? (get-in db [:keycard :typed?])
|
typed? (get-in db [:keycard :typed?])
|
||||||
pin (common/vector->string (get-in db [:keycard :pin :sign]))
|
pin (common/vector->string (get-in db [:keycard :pin :sign]))
|
||||||
from (or (get-in db [:signing/tx :from :address]) (get-in db [:signing/tx :message :from]) (ethereum/default-address db))
|
from (or (get-in db [:signing/tx :from :address])
|
||||||
path (reduce
|
(get-in db [:signing/tx :message :from])
|
||||||
(fn [_ {:keys [address path]}]
|
(ethereum/default-address db))
|
||||||
(when (ethereum/address= from address)
|
path (reduce
|
||||||
(reduced path)))
|
(fn [_ {:keys [address path]}]
|
||||||
nil
|
(when (ethereum/address= from address)
|
||||||
(:multiaccount/accounts db))]
|
(reduced path)))
|
||||||
|
nil
|
||||||
|
(:multiaccount/accounts db))]
|
||||||
(cond
|
(cond
|
||||||
(not keycard-match?)
|
(not keycard-match?)
|
||||||
(common/show-wrong-keycard-alert cofx)
|
(common/show-wrong-keycard-alert cofx)
|
||||||
|
|
||||||
(not card-connected?)
|
(not card-connected?)
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc-in db [:signing/sign :keycard-step] :signing)}
|
{:db (assoc-in db [:signing/sign :keycard-step] :signing)}
|
||||||
(common/set-on-card-connected :keycard/sign))
|
(common/set-on-card-connected :keycard/sign))
|
||||||
|
|
||||||
(pos? keycard-pin-retries) ; if 0, get-application-info will have already closed the connection sheet and opened the frozen card popup
|
(pos? keycard-pin-retries) ; if 0, get-application-info will have already closed the connection
|
||||||
{:db (-> db
|
; sheet and opened the frozen card popup
|
||||||
(assoc-in [:keycard :card-read-in-progress?] true)
|
{:db (-> db
|
||||||
(assoc-in [:keycard :pin :status] :verifying))
|
(assoc-in [:keycard :card-read-in-progress?] true)
|
||||||
|
(assoc-in [:keycard :pin :status] :verifying))
|
||||||
:keycard/sign {:hash (ethereum/naked-address hash)
|
:keycard/sign {:hash (ethereum/naked-address hash)
|
||||||
:data data
|
:data data
|
||||||
:typed? typed? ; this parameter is for e2e
|
:typed? typed? ; this parameter is for e2e
|
||||||
@@ -48,76 +51,80 @@
|
|||||||
:pin pin
|
:pin pin
|
||||||
:path path}})))
|
:path path}})))
|
||||||
|
|
||||||
(defn normalize-signature [signature]
|
(defn normalize-signature
|
||||||
|
[signature]
|
||||||
(-> signature
|
(-> signature
|
||||||
(string/replace-first #"00$", "1b")
|
(string/replace-first #"00$" "1b")
|
||||||
(string/replace-first #"01$", "1c")
|
(string/replace-first #"01$" "1c")
|
||||||
ethereum/normalized-hex))
|
ethereum/normalized-hex))
|
||||||
|
|
||||||
(fx/defn sign-message
|
(rf/defn sign-message
|
||||||
{:events [:keycard/sign-message]}
|
{:events [:keycard/sign-message]}
|
||||||
[cofx params result]
|
[cofx params result]
|
||||||
(let [{:keys [result error]} (types/json->clj result)
|
(let [{:keys [result error]} (types/json->clj result)
|
||||||
on-success #(re-frame/dispatch [:keycard/on-sign-message-success params
|
on-success #(re-frame/dispatch [:keycard/on-sign-message-success params
|
||||||
(normalize-signature %)])
|
(normalize-signature %)])
|
||||||
hash (ethereum/naked-address result)]
|
hash (ethereum/naked-address result)]
|
||||||
(sign cofx hash on-success)))
|
(sign cofx hash on-success)))
|
||||||
|
|
||||||
(fx/defn on-sign-message-success
|
(rf/defn on-sign-message-success
|
||||||
{:events [:keycard/on-sign-message-success]}
|
{:events [:keycard/on-sign-message-success]}
|
||||||
[{:keys [db] :as cofx} {:keys [tx-hash message-id chat-id value contract]} signature]
|
[{:keys [db] :as cofx} {:keys [tx-hash message-id chat-id value contract]} signature]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:dispatch
|
{:dispatch
|
||||||
(if message-id
|
(if message-id
|
||||||
[:sign/send-accept-transaction-message message-id tx-hash signature]
|
[:sign/send-accept-transaction-message message-id tx-hash signature]
|
||||||
[:sign/send-transaction-message chat-id value contract tx-hash signature])
|
[:sign/send-transaction-message chat-id value contract tx-hash signature])
|
||||||
:signing/show-transaction-result nil
|
:signing/show-transaction-result nil
|
||||||
:db (-> db
|
:db (-> db
|
||||||
(assoc-in [:keycard :pin :sign] [])
|
(assoc-in [:keycard :pin :sign] [])
|
||||||
(assoc-in [:keycard :pin :status] nil))}
|
(assoc-in [:keycard :pin :status] nil))}
|
||||||
(common/clear-on-card-connected)
|
(common/clear-on-card-connected)
|
||||||
(common/get-application-info nil)
|
(common/get-application-info nil)
|
||||||
(common/hide-connection-sheet)))
|
(common/hide-connection-sheet)))
|
||||||
|
|
||||||
(fx/defn sign-typed-data
|
(rf/defn sign-typed-data
|
||||||
{:events [:keycard/sign-typed-data]}
|
{:events [:keycard/sign-typed-data]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [card-connected? (get-in db [:keycard :card-connected?])
|
(let [card-connected? (get-in db [:keycard :card-connected?])
|
||||||
hash (get-in db [:keycard :hash])]
|
hash (get-in db [:keycard :hash])]
|
||||||
(if card-connected?
|
(if card-connected?
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:keycard :card-read-in-progress?] true)
|
(assoc-in [:keycard :card-read-in-progress?] true)
|
||||||
(assoc-in [:signing/sign :keycard-step] :signing))
|
(assoc-in [:signing/sign :keycard-step] :signing))
|
||||||
:keycard/sign-typed-data {:hash (ethereum/naked-address hash)}}
|
:keycard/sign-typed-data {:hash (ethereum/naked-address hash)}}
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(common/set-on-card-connected :keycard/sign-typed-data)
|
(common/set-on-card-connected :keycard/sign-typed-data)
|
||||||
{:db (assoc-in db [:signing/sign :keycard-step] :signing)}))))
|
{:db (assoc-in db [:signing/sign :keycard-step] :signing)}))))
|
||||||
|
|
||||||
(fx/defn fetch-currency-token-on-success
|
(rf/defn fetch-currency-token-on-success
|
||||||
{:events [:keycard/fetch-currency-token-on-success]}
|
{:events [:keycard/fetch-currency-token-on-success]}
|
||||||
[{:keys [db]} {:keys [decimals symbol]}]
|
[{:keys [db]} {:keys [decimals symbol]}]
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:signing/sign :formatted-data :message :formatted-currency] symbol)
|
(assoc-in [:signing/sign :formatted-data :message :formatted-currency] symbol)
|
||||||
(update-in [:signing/sign :formatted-data :message]
|
(update-in [:signing/sign :formatted-data :message]
|
||||||
#(assoc % :formatted-amount (.dividedBy ^js (money/bignumber (:amount %))
|
#(assoc %
|
||||||
(money/bignumber (money/from-decimal decimals))))))})
|
:formatted-amount
|
||||||
|
(.dividedBy ^js (money/bignumber (:amount %))
|
||||||
|
(money/bignumber (money/from-decimal decimals))))))})
|
||||||
|
|
||||||
(fx/defn store-hash-and-sign-typed
|
(rf/defn store-hash-and-sign-typed
|
||||||
{:events [:keycard/store-hash-and-sign-typed]}
|
{:events [:keycard/store-hash-and-sign-typed]}
|
||||||
[{:keys [db] :as cofx} result]
|
[{:keys [db] :as cofx} result]
|
||||||
(let [{:keys [result]} (types/json->clj result)
|
(let [{:keys [result]} (types/json->clj result)
|
||||||
message (get-in db [:signing/sign :formatted-data :message])
|
message (get-in db [:signing/sign :formatted-data :message])
|
||||||
currency-contract (:currency message)]
|
currency-contract (:currency message)]
|
||||||
(when currency-contract
|
(when currency-contract
|
||||||
{::json-rpc/call [{:method "wallet_discoverToken"
|
{::json-rpc/call [{:method "wallet_discoverToken"
|
||||||
:params [(ethereum/chain-id db) currency-contract]
|
:params [(ethereum/chain-id db) currency-contract]
|
||||||
:on-success #(re-frame/dispatch [:keycard/fetch-currency-token-on-success %])}]})
|
:on-success #(re-frame/dispatch [:keycard/fetch-currency-token-on-success
|
||||||
(fx/merge cofx
|
%])}]})
|
||||||
|
(rf/merge cofx
|
||||||
{:db (assoc-in db [:keycard :hash] result)}
|
{:db (assoc-in db [:keycard :hash] result)}
|
||||||
sign-typed-data)))
|
sign-typed-data)))
|
||||||
|
|
||||||
(fx/defn prepare-to-sign
|
(rf/defn prepare-to-sign
|
||||||
{:events [:keycard/prepare-to-sign]}
|
{:events [:keycard/prepare-to-sign]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(common/show-connection-sheet
|
(common/show-connection-sheet
|
||||||
@@ -125,30 +132,31 @@
|
|||||||
{:on-card-connected :keycard/prepare-to-sign
|
{:on-card-connected :keycard/prepare-to-sign
|
||||||
:handler (common/get-application-info :keycard/sign)}))
|
:handler (common/get-application-info :keycard/sign)}))
|
||||||
|
|
||||||
(fx/defn sign-message-completed
|
(rf/defn sign-message-completed
|
||||||
[_ signature]
|
[_ signature]
|
||||||
{:dispatch
|
{:dispatch
|
||||||
[:signing/sign-message-completed signature]})
|
[:signing/sign-message-completed signature]})
|
||||||
|
|
||||||
(fx/defn send-transaction-with-signature
|
(rf/defn send-transaction-with-signature
|
||||||
[_ data]
|
[_ data]
|
||||||
{:send-transaction-with-signature data})
|
{:send-transaction-with-signature data})
|
||||||
|
|
||||||
(fx/defn on-sign-success
|
(rf/defn on-sign-success
|
||||||
{:events [:keycard.callback/on-sign-success]}
|
{:events [:keycard.callback/on-sign-success]}
|
||||||
[{:keys [db] :as cofx} signature]
|
[{:keys [db] :as cofx} signature]
|
||||||
(log/debug "[keycard] sign success: " signature)
|
(log/debug "[keycard] sign success: " signature)
|
||||||
(let [signature-json (types/clj->json {:result (normalize-signature signature)})
|
(let [signature-json (types/clj->json {:result (normalize-signature signature)})
|
||||||
transaction (get-in db [:keycard :transaction])
|
transaction (get-in db [:keycard :transaction])
|
||||||
tx-obj (select-keys transaction [:from :to :value :gas :gasPrice :command? :chat-id :message-id])
|
tx-obj (select-keys transaction
|
||||||
|
[:from :to :value :gas :gasPrice :command? :chat-id :message-id])
|
||||||
command? (:command? transaction)]
|
command? (:command? transaction)]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:keycard :hash] nil)
|
(assoc-in [:keycard :hash] nil)
|
||||||
(assoc-in [:keycard :transaction] nil))}
|
(assoc-in [:keycard :transaction] nil))}
|
||||||
(when-not command?
|
(when-not command?
|
||||||
(fn [{:keys [db] :as cofx}]
|
(fn [{:keys [db] :as cofx}]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:keycard :pin :sign] [])
|
(assoc-in [:keycard :pin :sign] [])
|
||||||
@@ -163,18 +171,19 @@
|
|||||||
:on-completed #(re-frame/dispatch [:signing/transaction-completed % tx-obj])})
|
:on-completed #(re-frame/dispatch [:signing/transaction-completed % tx-obj])})
|
||||||
(sign-message-completed signature-json)))))
|
(sign-message-completed signature-json)))))
|
||||||
|
|
||||||
(fx/defn on-sign-error
|
(rf/defn on-sign-error
|
||||||
{:events [:keycard.callback/on-sign-error]}
|
{:events [:keycard.callback/on-sign-error]}
|
||||||
[{:keys [db] :as cofx} error]
|
[{:keys [db] :as cofx} error]
|
||||||
(log/debug "[keycard] sign error: " error)
|
(log/debug "[keycard] sign error: " error)
|
||||||
(let [tag-was-lost? (common/tag-lost? (:error error))
|
(let [tag-was-lost? (common/tag-lost? (:error error))
|
||||||
pin-retries (common/pin-retries (:error error))]
|
pin-retries (common/pin-retries (:error error))]
|
||||||
(when-not tag-was-lost?
|
(when-not tag-was-lost?
|
||||||
(if (not (nil? pin-retries))
|
(if (not (nil? pin-retries))
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:keycard :application-info :pin-retry-counter] pin-retries)
|
(assoc-in [:keycard :application-info :pin-retry-counter] pin-retries)
|
||||||
(update-in [:keycard :pin] assoc
|
(update-in [:keycard :pin]
|
||||||
|
assoc
|
||||||
:status :error
|
:status :error
|
||||||
:sign []
|
:sign []
|
||||||
:error-label :t/pin-mismatch)
|
:error-label :t/pin-mismatch)
|
||||||
@@ -182,6 +191,6 @@
|
|||||||
(common/hide-connection-sheet)
|
(common/hide-connection-sheet)
|
||||||
(when (zero? pin-retries) (common/frozen-keycard-popup)))
|
(when (zero? pin-retries) (common/frozen-keycard-popup)))
|
||||||
|
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(common/hide-connection-sheet)
|
(common/hide-connection-sheet)
|
||||||
(common/show-wrong-keycard-alert))))))
|
(common/show-wrong-keycard-alert))))))
|
||||||
|
|||||||
@@ -1,42 +1,45 @@
|
|||||||
(ns status-im.keycard.unpair
|
(ns status-im.keycard.unpair
|
||||||
(:require [re-frame.core :as re-frame]
|
(:require [re-frame.core :as re-frame]
|
||||||
[status-im.multiaccounts.update.core :as multiaccounts.update]
|
|
||||||
[status-im.i18n.i18n :as i18n]
|
[status-im.i18n.i18n :as i18n]
|
||||||
[status-im2.navigation.events :as navigation]
|
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[taoensso.timbre :as log]
|
|
||||||
[status-im.keycard.common :as common]
|
[status-im.keycard.common :as common]
|
||||||
[status-im.multiaccounts.key-storage.core :as key-storage]))
|
[status-im.multiaccounts.key-storage.core :as key-storage]
|
||||||
|
[status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||||
|
[status-im2.navigation.events :as navigation]
|
||||||
|
[taoensso.timbre :as log]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(fx/defn unpair-card-pressed
|
(rf/defn unpair-card-pressed
|
||||||
{:events [:keycard-settings.ui/unpair-card-pressed]}
|
{:events [:keycard-settings.ui/unpair-card-pressed]}
|
||||||
[_]
|
[_]
|
||||||
{:ui/show-confirmation {:title (i18n/label :t/unpair-card)
|
{:ui/show-confirmation {:title (i18n/label :t/unpair-card)
|
||||||
:content (i18n/label :t/unpair-card-confirmation)
|
:content (i18n/label :t/unpair-card-confirmation)
|
||||||
:confirm-button-text (i18n/label :t/yes)
|
:confirm-button-text (i18n/label :t/yes)
|
||||||
:cancel-button-text (i18n/label :t/no)
|
:cancel-button-text (i18n/label :t/no)
|
||||||
:on-accept #(re-frame/dispatch [:keycard-settings.ui/unpair-card-confirmed])
|
:on-accept #(re-frame/dispatch
|
||||||
|
[:keycard-settings.ui/unpair-card-confirmed])
|
||||||
:on-cancel #()}})
|
:on-cancel #()}})
|
||||||
|
|
||||||
(fx/defn unpair-card-confirmed
|
(rf/defn unpair-card-confirmed
|
||||||
{:events [:keycard-settings.ui/unpair-card-confirmed]}
|
{:events [:keycard-settings.ui/unpair-card-confirmed]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc-in db [:keycard :pin] {:enter-step :current
|
{:db (assoc-in db
|
||||||
:current []
|
[:keycard :pin]
|
||||||
:puk []
|
{:enter-step :current
|
||||||
:status nil
|
:current []
|
||||||
:error-label nil
|
:puk []
|
||||||
:on-verified :keycard/unpair})}
|
:status nil
|
||||||
|
:error-label nil
|
||||||
|
:on-verified :keycard/unpair})}
|
||||||
(common/navigate-to-enter-pin-screen)))
|
(common/navigate-to-enter-pin-screen)))
|
||||||
|
|
||||||
(fx/defn unpair
|
(rf/defn unpair
|
||||||
{:events [:keycard/unpair]}
|
{:events [:keycard/unpair]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(let [pin (common/vector->string (get-in db [:keycard :pin :current]))]
|
(let [pin (common/vector->string (get-in db [:keycard :pin :current]))]
|
||||||
{:keycard/unpair {:pin pin}}))
|
{:keycard/unpair {:pin pin}}))
|
||||||
|
|
||||||
(fx/defn unpair-and-delete
|
(rf/defn unpair-and-delete
|
||||||
{:events [:keycard/unpair-and-delete]}
|
{:events [:keycard/unpair-and-delete]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(common/show-connection-sheet
|
(common/show-connection-sheet
|
||||||
@@ -44,55 +47,65 @@
|
|||||||
{:on-card-connected :keycard/unpair-and-delete
|
{:on-card-connected :keycard/unpair-and-delete
|
||||||
:handler
|
:handler
|
||||||
(fn [{:keys [db]}]
|
(fn [{:keys [db]}]
|
||||||
(let [pin (common/vector->string (get-in db [:keycard :pin :current]))]
|
(let [pin (common/vector->string (get-in db [:keycard :pin :current]))]
|
||||||
{:keycard/unpair-and-delete
|
{:keycard/unpair-and-delete
|
||||||
{:pin pin}}))}))
|
{:pin pin}}))}))
|
||||||
|
|
||||||
(fx/defn remove-pairing-from-multiaccount
|
(rf/defn remove-pairing-from-multiaccount
|
||||||
[cofx {:keys [remove-instance-uid?]}]
|
[cofx {:keys [remove-instance-uid?]}]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(multiaccounts.update/multiaccount-update
|
(multiaccounts.update/multiaccount-update
|
||||||
:keycard-pairing nil {})
|
:keycard-pairing
|
||||||
|
nil
|
||||||
|
{})
|
||||||
(multiaccounts.update/multiaccount-update
|
(multiaccounts.update/multiaccount-update
|
||||||
:keycard-paired-on nil {})
|
:keycard-paired-on
|
||||||
|
nil
|
||||||
|
{})
|
||||||
(when remove-instance-uid?
|
(when remove-instance-uid?
|
||||||
(multiaccounts.update/multiaccount-update
|
(multiaccounts.update/multiaccount-update
|
||||||
:keycard-instance-uid nil {}))))
|
:keycard-instance-uid
|
||||||
|
nil
|
||||||
|
{}))))
|
||||||
|
|
||||||
(fx/defn on-unpair-success
|
(rf/defn on-unpair-success
|
||||||
{:events [:keycard.callback/on-unpair-success]}
|
{:events [:keycard.callback/on-unpair-success]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [instance-uid (get-in db [:keycard :application-info :instance-uid])
|
(let [instance-uid (get-in db [:keycard :application-info :instance-uid])
|
||||||
pairings (get-in db [:keycard :pairings])]
|
pairings (get-in db [:keycard :pairings])]
|
||||||
(fx/merge cofx
|
(rf/merge
|
||||||
{:db (-> db
|
cofx
|
||||||
(assoc-in [:keycard :secrets] nil)
|
{:db (-> db
|
||||||
(update-in [:keycard :pairings] dissoc (keyword instance-uid))
|
(assoc-in [:keycard :secrets] nil)
|
||||||
(assoc-in [:keycard :pin] {:status nil
|
(update-in [:keycard :pairings] dissoc (keyword instance-uid))
|
||||||
:error-label nil
|
(assoc-in [:keycard :pin]
|
||||||
:on-verified nil}))
|
{:status nil
|
||||||
:keycard/persist-pairings (dissoc pairings (keyword instance-uid))
|
:error-label nil
|
||||||
:utils/show-popup {:title ""
|
:on-verified nil}))
|
||||||
:content (i18n/label :t/card-unpaired)}}
|
:keycard/persist-pairings (dissoc pairings (keyword instance-uid))
|
||||||
(common/clear-on-card-connected)
|
:utils/show-popup {:title ""
|
||||||
(remove-pairing-from-multiaccount nil)
|
:content (i18n/label :t/card-unpaired)}}
|
||||||
(navigation/navigate-to-cofx :keycard-settings nil))))
|
(common/clear-on-card-connected)
|
||||||
|
(remove-pairing-from-multiaccount nil)
|
||||||
|
(navigation/navigate-to-cofx :keycard-settings nil))))
|
||||||
|
|
||||||
(fx/defn on-unpair-error
|
(rf/defn on-unpair-error
|
||||||
{:events [:keycard.callback/on-unpair-error]}
|
{:events [:keycard.callback/on-unpair-error]}
|
||||||
[{:keys [db] :as cofx} error]
|
[{:keys [db] :as cofx} error]
|
||||||
(log/debug "[keycard] unpair error" error)
|
(log/debug "[keycard] unpair error" error)
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc-in db [:keycard :pin] {:status nil
|
{:db (assoc-in db
|
||||||
:error-label nil
|
[:keycard :pin]
|
||||||
:on-verified nil})
|
{:status nil
|
||||||
|
:error-label nil
|
||||||
|
:on-verified nil})
|
||||||
:keycard/get-application-info nil
|
:keycard/get-application-info nil
|
||||||
:utils/show-popup {:title ""
|
:utils/show-popup {:title ""
|
||||||
:content (i18n/label :t/something-went-wrong)}}
|
:content (i18n/label :t/something-went-wrong)}}
|
||||||
(common/clear-on-card-connected)
|
(common/clear-on-card-connected)
|
||||||
(navigation/navigate-to-cofx :keycard-settings nil)))
|
(navigation/navigate-to-cofx :keycard-settings nil)))
|
||||||
|
|
||||||
(fx/defn remove-key-with-unpair
|
(rf/defn remove-key-with-unpair
|
||||||
{:events [:keycard/remove-key-with-unpair]}
|
{:events [:keycard/remove-key-with-unpair]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(common/show-connection-sheet
|
(common/show-connection-sheet
|
||||||
@@ -100,66 +113,75 @@
|
|||||||
{:on-card-connected :keycard/remove-key-with-unpair
|
{:on-card-connected :keycard/remove-key-with-unpair
|
||||||
:handler
|
:handler
|
||||||
(fn [{:keys [db]}]
|
(fn [{:keys [db]}]
|
||||||
(let [pin (common/vector->string (get-in db [:keycard :pin :current]))]
|
(let [pin (common/vector->string (get-in db [:keycard :pin :current]))]
|
||||||
{:keycard/remove-key-with-unpair
|
{:keycard/remove-key-with-unpair
|
||||||
{:pin pin}}))}))
|
{:pin pin}}))}))
|
||||||
|
|
||||||
(defn handle-account-removal [{:keys [db] :as cofx} keys-removed-from-card?]
|
(defn handle-account-removal
|
||||||
(let [key-uid (get-in db [:multiaccount :key-uid])
|
[{:keys [db] :as cofx} keys-removed-from-card?]
|
||||||
|
(let [key-uid (get-in db [:multiaccount :key-uid])
|
||||||
instance-uid (get-in db [:keycard :application-info :instance-uid])
|
instance-uid (get-in db [:keycard :application-info :instance-uid])
|
||||||
pairings (get-in db [:keycard :pairings])]
|
pairings (get-in db [:keycard :pairings])]
|
||||||
(fx/merge cofx
|
(rf/merge
|
||||||
{:db (-> db
|
cofx
|
||||||
(update :multiaccounts/multiaccounts dissoc key-uid)
|
{:db (-> db
|
||||||
(assoc-in [:keycard :secrets] nil)
|
(update :multiaccounts/multiaccounts dissoc key-uid)
|
||||||
(update-in [:keycard :pairings] dissoc (keyword instance-uid))
|
(assoc-in [:keycard :secrets] nil)
|
||||||
(update-in [:keycard :pairings] dissoc instance-uid)
|
(update-in [:keycard :pairings]
|
||||||
(assoc-in [:keycard :whisper-public-key] nil)
|
dissoc
|
||||||
(assoc-in [:keycard :wallet-address] nil)
|
(keyword instance-uid))
|
||||||
(assoc-in [:keycard :application-info] nil)
|
(update-in [:keycard :pairings] dissoc instance-uid)
|
||||||
(assoc-in [:keycard :pin] {:status nil
|
(assoc-in [:keycard :whisper-public-key] nil)
|
||||||
:error-label nil
|
(assoc-in [:keycard :wallet-address] nil)
|
||||||
:on-verified nil}))
|
(assoc-in [:keycard :application-info] nil)
|
||||||
:keycard/persist-pairings (dissoc pairings (keyword instance-uid))
|
(assoc-in [:keycard :pin]
|
||||||
:utils/show-popup {:title (i18n/label (if keys-removed-from-card? :t/profile-deleted-title :t/database-reset-title))
|
{:status nil
|
||||||
:content (i18n/label (if keys-removed-from-card? :t/profile-deleted-keycard :t/database-reset-content))
|
:error-label nil
|
||||||
:on-dismiss #(re-frame/dispatch [:logout])}
|
:on-verified nil}))
|
||||||
::key-storage/delete-multiaccount {:key-uid key-uid
|
:keycard/persist-pairings (dissoc pairings (keyword instance-uid))
|
||||||
:on-success #(log/debug "[keycard] remove account ok")
|
:utils/show-popup {:title (i18n/label (if keys-removed-from-card?
|
||||||
:on-error #(log/warn "[keycard] remove account: " %)}}
|
:t/profile-deleted-title
|
||||||
(common/clear-on-card-connected)
|
:t/database-reset-title))
|
||||||
(common/hide-connection-sheet))))
|
:content (i18n/label (if keys-removed-from-card?
|
||||||
|
:t/profile-deleted-keycard
|
||||||
|
:t/database-reset-content))
|
||||||
|
:on-dismiss #(re-frame/dispatch [:logout])}
|
||||||
|
::key-storage/delete-multiaccount {:key-uid key-uid
|
||||||
|
:on-success #(log/debug "[keycard] remove account ok")
|
||||||
|
:on-error #(log/warn "[keycard] remove account: " %)}}
|
||||||
|
(common/clear-on-card-connected)
|
||||||
|
(common/hide-connection-sheet))))
|
||||||
|
|
||||||
(fx/defn on-remove-key-success
|
(rf/defn on-remove-key-success
|
||||||
{:events [:keycard.callback/on-remove-key-success]}
|
{:events [:keycard.callback/on-remove-key-success]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(handle-account-removal cofx true))
|
(handle-account-removal cofx true))
|
||||||
|
|
||||||
(fx/defn on-remove-key-error
|
(rf/defn on-remove-key-error
|
||||||
{:events [:keycard.callback/on-remove-key-error]}
|
{:events [:keycard.callback/on-remove-key-error]}
|
||||||
[{:keys [db] :as cofx} error]
|
[{:keys [db] :as cofx} error]
|
||||||
(log/debug "[keycard] remove key error" error)
|
(log/debug "[keycard] remove key error" error)
|
||||||
(let [tag-was-lost? (common/tag-lost? (:error error))]
|
(let [tag-was-lost? (common/tag-lost? (:error error))]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(if tag-was-lost?
|
(if tag-was-lost?
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc-in db [:keycard :pin :status] nil)}
|
{:db (assoc-in db [:keycard :pin :status] nil)}
|
||||||
(common/set-on-card-connected :keycard/remove-key-with-unpair))
|
(common/set-on-card-connected :keycard/remove-key-with-unpair))
|
||||||
(common/show-wrong-keycard-alert)))))
|
(common/show-wrong-keycard-alert)))))
|
||||||
|
|
||||||
(fx/defn on-unpair-and-delete-success
|
(rf/defn on-unpair-and-delete-success
|
||||||
{:events [:keycard.callback/on-unpair-and-delete-success]}
|
{:events [:keycard.callback/on-unpair-and-delete-success]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(handle-account-removal cofx false))
|
(handle-account-removal cofx false))
|
||||||
|
|
||||||
(fx/defn on-unpair-and-delete-error
|
(rf/defn on-unpair-and-delete-error
|
||||||
{:events [:keycard.callback/on-unpair-and-delete-error]}
|
{:events [:keycard.callback/on-unpair-and-delete-error]}
|
||||||
[{:keys [db] :as cofx} error]
|
[{:keys [db] :as cofx} error]
|
||||||
(log/debug "[keycard] unpair and delete error" error)
|
(log/debug "[keycard] unpair and delete error" error)
|
||||||
(let [tag-was-lost? (common/tag-lost? (:error error))]
|
(let [tag-was-lost? (common/tag-lost? (:error error))]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(if tag-was-lost?
|
(if tag-was-lost?
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc-in db [:keycard :pin :status] nil)}
|
{:db (assoc-in db [:keycard :pin :status] nil)}
|
||||||
(common/set-on-card-connected :keycard/unpair-and-delete))
|
(common/set-on-card-connected :keycard/unpair-and-delete))
|
||||||
(common/show-wrong-keycard-alert)))))
|
(common/show-wrong-keycard-alert)))))
|
||||||
|
|||||||
@@ -1,37 +1,37 @@
|
|||||||
(ns status-im.keycard.wallet
|
(ns status-im.keycard.wallet
|
||||||
(:require [status-im.ethereum.core :as ethereum]
|
(:require [status-im.bottom-sheet.core :as bottom-sheet]
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[status-im.keycard.common :as common]
|
|
||||||
[status-im.constants :as constants]
|
[status-im.constants :as constants]
|
||||||
|
[status-im.ethereum.core :as ethereum]
|
||||||
[status-im.ethereum.eip55 :as eip55]
|
[status-im.ethereum.eip55 :as eip55]
|
||||||
[status-im.utils.hex :as utils.hex]
|
[status-im.keycard.common :as common]
|
||||||
[status-im.ui.screens.wallet.add-new.views :as add-new.views]
|
[status-im.ui.screens.wallet.add-new.views :as add-new.views]
|
||||||
[status-im.bottom-sheet.core :as bottom-sheet]))
|
[status-im.utils.hex :as utils.hex]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(fx/defn show-pin-sheet
|
(rf/defn show-pin-sheet
|
||||||
{:events [:keycard/new-account-pin-sheet]}
|
{:events [:keycard/new-account-pin-sheet]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:keycard :pin :enter-step] :export-key)
|
(assoc-in [:keycard :pin :enter-step] :export-key)
|
||||||
(update-in [:keycard :pin] dissoc :export-key))
|
(update-in [:keycard :pin] dissoc :export-key))
|
||||||
:dismiss-keyboard nil}
|
:dismiss-keyboard nil}
|
||||||
(bottom-sheet/show-bottom-sheet {:view {:content add-new.views/pin}})))
|
(bottom-sheet/show-bottom-sheet {:view {:content add-new.views/pin}})))
|
||||||
|
|
||||||
(fx/defn verify-pin-with-delay
|
(rf/defn verify-pin-with-delay
|
||||||
[cofx]
|
[cofx]
|
||||||
{:utils/dispatch-later
|
{:utils/dispatch-later
|
||||||
;; We need to give previous sheet some time to be fully hidden
|
;; We need to give previous sheet some time to be fully hidden
|
||||||
[{:ms 200
|
[{:ms 200
|
||||||
:dispatch [:wallet.accounts/verify-pin]}]})
|
:dispatch [:wallet.accounts/verify-pin]}]})
|
||||||
|
|
||||||
(fx/defn hide-pin-sheet
|
(rf/defn hide-pin-sheet
|
||||||
{:events [:keycard/new-account-pin-sheet-hide]}
|
{:events [:keycard/new-account-pin-sheet-hide]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(bottom-sheet/hide-bottom-sheet cofx))
|
(bottom-sheet/hide-bottom-sheet cofx))
|
||||||
|
|
||||||
(fx/defn generate-new-keycard-account
|
(rf/defn generate-new-keycard-account
|
||||||
{:events [:wallet.accounts/generate-new-keycard-account]}
|
{:events [:wallet.accounts/generate-new-keycard-account]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(let [path-num (inc (get-in db [:multiaccount :latest-derived-path]))
|
(let [path-num (inc (get-in db [:multiaccount :latest-derived-path]))
|
||||||
@@ -39,7 +39,8 @@
|
|||||||
pin (common/vector->string (get-in db [:keycard :pin :export-key]))]
|
pin (common/vector->string (get-in db [:keycard :pin :export-key]))]
|
||||||
{:db
|
{:db
|
||||||
(assoc-in
|
(assoc-in
|
||||||
db [:keycard :on-export-success]
|
db
|
||||||
|
[:keycard :on-export-success]
|
||||||
#(vector :wallet.accounts/account-stored
|
#(vector :wallet.accounts/account-stored
|
||||||
(let [public-key (utils.hex/normalize-hex %)]
|
(let [public-key (utils.hex/normalize-hex %)]
|
||||||
{;; Strip leading 04 prefix denoting uncompressed key format
|
{;; Strip leading 04 prefix denoting uncompressed key format
|
||||||
@@ -52,7 +53,7 @@
|
|||||||
|
|
||||||
:keycard/export-key {:pin pin :path path}}))
|
:keycard/export-key {:pin pin :path path}}))
|
||||||
|
|
||||||
(fx/defn verify-pin
|
(rf/defn verify-pin
|
||||||
{:events [:wallet.accounts/verify-pin]}
|
{:events [:wallet.accounts/verify-pin]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(common/verify-pin
|
(common/verify-pin
|
||||||
|
|||||||
@@ -1,23 +1,24 @@
|
|||||||
(ns status-im.log-level.core
|
(ns status-im.log-level.core
|
||||||
(:require [re-frame.core :as re-frame]
|
(:require [re-frame.core :as re-frame]
|
||||||
|
[status-im.i18n.i18n :as i18n]
|
||||||
[status-im.multiaccounts.update.core :as multiaccounts.update]
|
[status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||||
[status-im.node.core :as node]
|
[status-im.node.core :as node]
|
||||||
[status-im.i18n.i18n :as i18n]
|
[utils.re-frame :as rf]))
|
||||||
[status-im.utils.fx :as fx]))
|
|
||||||
|
|
||||||
(fx/defn save-log-level
|
(rf/defn save-log-level
|
||||||
{:events [:log-level.ui/change-log-level-confirmed]}
|
{:events [:log-level.ui/change-log-level-confirmed]}
|
||||||
[{:keys [db now] :as cofx} log-level]
|
[{:keys [db now] :as cofx} log-level]
|
||||||
(let [old-log-level (get-in db [:multiaccount :log-level])]
|
(let [old-log-level (get-in db [:multiaccount :log-level])]
|
||||||
(when (not= old-log-level log-level)
|
(when (not= old-log-level log-level)
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(multiaccounts.update/multiaccount-update
|
(multiaccounts.update/multiaccount-update
|
||||||
:log-level log-level
|
:log-level
|
||||||
|
log-level
|
||||||
{})
|
{})
|
||||||
(node/prepare-new-config
|
(node/prepare-new-config
|
||||||
{:on-success #(re-frame/dispatch [:logout])})))))
|
{:on-success #(re-frame/dispatch [:logout])})))))
|
||||||
|
|
||||||
(fx/defn show-change-log-level-confirmation
|
(rf/defn show-change-log-level-confirmation
|
||||||
{:events [:log-level.ui/log-level-selected]}
|
{:events [:log-level.ui/log-level-selected]}
|
||||||
[_ {:keys [name value]}]
|
[_ {:keys [name value]}]
|
||||||
{:ui/show-confirmation
|
{:ui/show-confirmation
|
||||||
|
|||||||
+142
-119
@@ -1,5 +1,4 @@
|
|||||||
(ns ^{:doc "Mailserver events and API"}
|
(ns ^{:doc "Mailserver events and API"} status-im.mailserver.core
|
||||||
status-im.mailserver.core
|
|
||||||
(:require [clojure.string :as string]
|
(:require [clojure.string :as string]
|
||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
@@ -8,8 +7,8 @@
|
|||||||
[status-im.node.core :as node]
|
[status-im.node.core :as node]
|
||||||
[status-im.utils.mobile-sync :as mobile-network-utils]
|
[status-im.utils.mobile-sync :as mobile-network-utils]
|
||||||
[status-im2.navigation.events :as navigation]
|
[status-im2.navigation.events :as navigation]
|
||||||
[status-im.utils.fx :as fx]
|
[taoensso.timbre :as log]
|
||||||
[taoensso.timbre :as log]))
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
;; How do mailserver work ?
|
;; How do mailserver work ?
|
||||||
;;
|
;;
|
||||||
@@ -24,22 +23,28 @@
|
|||||||
;; as soon as the mailserver becomes available
|
;; as soon as the mailserver becomes available
|
||||||
|
|
||||||
|
|
||||||
(defn connected? [db id]
|
(defn connected?
|
||||||
|
[db id]
|
||||||
(= (:mailserver/current-id db) id))
|
(= (:mailserver/current-id db) id))
|
||||||
|
|
||||||
(defn fetch [db id]
|
(defn fetch
|
||||||
|
[db id]
|
||||||
(get-in db [:mailserver/mailservers (node/current-fleet-key db) id]))
|
(get-in db [:mailserver/mailservers (node/current-fleet-key db) id]))
|
||||||
|
|
||||||
(defn fetch-current [db]
|
(defn fetch-current
|
||||||
|
[db]
|
||||||
(fetch db (:mailserver/current-id db)))
|
(fetch db (:mailserver/current-id db)))
|
||||||
|
|
||||||
(defn preferred-mailserver-id [db]
|
(defn preferred-mailserver-id
|
||||||
|
[db]
|
||||||
(get-in db [:multiaccount :pinned-mailservers (node/current-fleet-key db)]))
|
(get-in db [:multiaccount :pinned-mailservers (node/current-fleet-key db)]))
|
||||||
|
|
||||||
(defn connection-error-dismissed [db]
|
(defn connection-error-dismissed
|
||||||
|
[db]
|
||||||
(get-in db [:mailserver/connection-error-dismissed]))
|
(get-in db [:mailserver/connection-error-dismissed]))
|
||||||
|
|
||||||
(defn mailserver-address->id [db address]
|
(defn mailserver-address->id
|
||||||
|
[db address]
|
||||||
(let [current-fleet (node/current-fleet-key db)]
|
(let [current-fleet (node/current-fleet-key db)]
|
||||||
(:id (some #(when (= address (:address %))
|
(:id (some #(when (= address (:address %))
|
||||||
%)
|
%)
|
||||||
@@ -48,19 +53,21 @@
|
|||||||
current-fleet
|
current-fleet
|
||||||
vals)))))
|
vals)))))
|
||||||
|
|
||||||
(fx/defn disconnect-from-mailserver
|
(rf/defn disconnect-from-mailserver
|
||||||
{:events [::disconnect-from-mailserver]}
|
{:events [::disconnect-from-mailserver]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc :mailserver/state nil)
|
(assoc :mailserver/state nil)
|
||||||
(dissoc :mailserver/current-request :mailserver/fetching-gaps-in-progress))})
|
(dissoc :mailserver/current-request :mailserver/fetching-gaps-in-progress))})
|
||||||
|
|
||||||
(defn fetch-use-mailservers? [{:keys [db]}]
|
(defn fetch-use-mailservers?
|
||||||
|
[{:keys [db]}]
|
||||||
(get-in db [:multiaccount :use-mailservers?]))
|
(get-in db [:multiaccount :use-mailservers?]))
|
||||||
|
|
||||||
(defonce showing-connection-error-popup? (atom false))
|
(defonce showing-connection-error-popup? (atom false))
|
||||||
|
|
||||||
(defn cancel-connection-popup! []
|
(defn cancel-connection-popup!
|
||||||
|
[]
|
||||||
(reset! showing-connection-error-popup? false)
|
(reset! showing-connection-error-popup? false)
|
||||||
(re-frame/dispatch [:mailserver.ui/dismiss-connection-error true]))
|
(re-frame/dispatch [:mailserver.ui/dismiss-connection-error true]))
|
||||||
|
|
||||||
@@ -68,7 +75,8 @@
|
|||||||
::cancel-connection-popup
|
::cancel-connection-popup
|
||||||
cancel-connection-popup!)
|
cancel-connection-popup!)
|
||||||
|
|
||||||
(fx/defn show-connection-error! [cofx current-fleet preferred-mailserver]
|
(rf/defn show-connection-error!
|
||||||
|
[cofx current-fleet preferred-mailserver]
|
||||||
(reset! showing-connection-error-popup? true)
|
(reset! showing-connection-error-popup? true)
|
||||||
{:ui/show-confirmation
|
{:ui/show-confirmation
|
||||||
{:title (i18n/label :t/mailserver-error-title)
|
{:title (i18n/label :t/mailserver-error-title)
|
||||||
@@ -88,27 +96,28 @@
|
|||||||
preferred-mailserver]))
|
preferred-mailserver]))
|
||||||
:style "default"}]}})
|
:style "default"}]}})
|
||||||
|
|
||||||
(fx/defn handle-successful-request
|
(rf/defn handle-successful-request
|
||||||
{:events [::request-success]}
|
{:events [::request-success]}
|
||||||
[{:keys [db] :as cofx} response-js]
|
[{:keys [db] :as cofx} response-js]
|
||||||
{:db (dissoc db :mailserver/current-request)
|
{:db (dissoc db :mailserver/current-request)
|
||||||
:dispatch [:sanitize-messages-and-process-response response-js]})
|
:dispatch [:sanitize-messages-and-process-response response-js]})
|
||||||
|
|
||||||
(fx/defn handle-mailserver-not-working [{:keys [db] :as cofx}]
|
(rf/defn handle-mailserver-not-working
|
||||||
(let [current-fleet (node/current-fleet-key db)
|
[{:keys [db] :as cofx}]
|
||||||
error-dismissed? (connection-error-dismissed db)
|
(let [current-fleet (node/current-fleet-key db)
|
||||||
pinned-mailserver (get-in db [:multiaccount :pinned-mailservers current-fleet])]
|
error-dismissed? (connection-error-dismissed db)
|
||||||
|
pinned-mailserver (get-in db [:multiaccount :pinned-mailservers current-fleet])]
|
||||||
(when (and pinned-mailserver
|
(when (and pinned-mailserver
|
||||||
(not error-dismissed?)
|
(not error-dismissed?)
|
||||||
(not @showing-connection-error-popup?))
|
(not @showing-connection-error-popup?))
|
||||||
(show-connection-error! cofx current-fleet pinned-mailserver))))
|
(show-connection-error! cofx current-fleet pinned-mailserver))))
|
||||||
|
|
||||||
(fx/defn handle-request-error
|
(rf/defn handle-request-error
|
||||||
{:events [::request-error]}
|
{:events [::request-error]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
{:db (dissoc db :mailserver/current-request)})
|
{:db (dissoc db :mailserver/current-request)})
|
||||||
|
|
||||||
(fx/defn process-next-messages-request
|
(rf/defn process-next-messages-request
|
||||||
{:events [::request-messages]}
|
{:events [::request-messages]}
|
||||||
[{:keys [db now] :as cofx}]
|
[{:keys [db now] :as cofx}]
|
||||||
(when (and
|
(when (and
|
||||||
@@ -116,93 +125,99 @@
|
|||||||
(mobile-network-utils/syncing-allowed? cofx)
|
(mobile-network-utils/syncing-allowed? cofx)
|
||||||
(fetch-use-mailservers? cofx)
|
(fetch-use-mailservers? cofx)
|
||||||
(not (:mailserver/current-request db)))
|
(not (:mailserver/current-request db)))
|
||||||
{:db (assoc db :mailserver/current-request true)
|
{:db (assoc db :mailserver/current-request true)
|
||||||
::json-rpc/call [{:method "wakuext_requestAllHistoricMessagesWithRetries"
|
::json-rpc/call [{:method "wakuext_requestAllHistoricMessagesWithRetries"
|
||||||
:params []
|
:params []
|
||||||
:js-response true
|
:js-response true
|
||||||
:on-success #(do
|
:on-success #(do
|
||||||
(log/info "fetched historical messages")
|
(log/info "fetched historical messages")
|
||||||
(re-frame/dispatch [::request-success %]))
|
(re-frame/dispatch [::request-success %]))
|
||||||
:on-error #(do
|
:on-error #(do
|
||||||
(log/error "failed retrieve historical messages" %)
|
(log/error "failed retrieve historical messages" %)
|
||||||
(re-frame/dispatch [::request-error]))}]}))
|
(re-frame/dispatch [::request-error]))}]}))
|
||||||
|
|
||||||
(fx/defn handle-mailserver-changed
|
(rf/defn handle-mailserver-changed
|
||||||
[{:keys [db] :as cofx} ms]
|
[{:keys [db] :as cofx} ms]
|
||||||
(if (seq ms)
|
(if (seq ms)
|
||||||
{:db (assoc db :mailserver/state :connecting
|
{:db (assoc db
|
||||||
|
:mailserver/state :connecting
|
||||||
:mailserver/current-id (keyword ms))}
|
:mailserver/current-id (keyword ms))}
|
||||||
{:db (assoc db :mailserver/state nil)}))
|
{:db (assoc db :mailserver/state nil)}))
|
||||||
|
|
||||||
(fx/defn handle-mailserver-available
|
(rf/defn handle-mailserver-available
|
||||||
[{:keys [db] :as cofx} ms]
|
[{:keys [db] :as cofx} ms]
|
||||||
{::cancel-connection-popup []
|
{::cancel-connection-popup []
|
||||||
:db (assoc db :mailserver/state :connected
|
:db (assoc db
|
||||||
:mailserver/current-id (keyword ms))})
|
:mailserver/state :connected
|
||||||
|
:mailserver/current-id (keyword ms))})
|
||||||
|
|
||||||
(fx/defn connected-to-mailserver
|
(rf/defn connected-to-mailserver
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [{:keys [address]} (fetch-current db)]
|
(let [{:keys [address]} (fetch-current db)]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:mailserver/update-mailservers [[address] #(re-frame/dispatch [::request-messages])]})))
|
{:mailserver/update-mailservers [[address] #(re-frame/dispatch [::request-messages])]})))
|
||||||
|
|
||||||
(fx/defn handle-request-success
|
(rf/defn handle-request-success
|
||||||
{:events [:mailserver.callback/request-success]}
|
{:events [:mailserver.callback/request-success]}
|
||||||
[{{:keys [chats] :as db} :db} {:keys [request-id topics]}]
|
[{{:keys [chats] :as db} :db} {:keys [request-id topics]}]
|
||||||
(when (:mailserver/current-request db)
|
(when (:mailserver/current-request db)
|
||||||
{:db (assoc-in db [:mailserver/current-request :request-id]
|
{:db (assoc-in db
|
||||||
request-id)}))
|
[:mailserver/current-request :request-id]
|
||||||
|
request-id)}))
|
||||||
|
|
||||||
(fx/defn toggle-use-mailservers
|
(rf/defn toggle-use-mailservers
|
||||||
[cofx value]
|
[cofx value]
|
||||||
{::json-rpc/call
|
{::json-rpc/call
|
||||||
[{:method "wakuext_toggleUseMailservers"
|
[{:method "wakuext_toggleUseMailservers"
|
||||||
:params [value]
|
:params [value]
|
||||||
:on-success #(log/info "successfully toggled use-mailservers" value)
|
:on-success #(log/info "successfully toggled use-mailservers" value)
|
||||||
:on-failure #(log/error "failed to toggle use-mailserver" value %)}]})
|
:on-failure #(log/error "failed to toggle use-mailserver" value %)}]})
|
||||||
|
|
||||||
(fx/defn update-use-mailservers
|
(rf/defn update-use-mailservers
|
||||||
{:events [:mailserver.ui/use-history-switch-pressed]}
|
{:events [:mailserver.ui/use-history-switch-pressed]}
|
||||||
[cofx use-mailservers?]
|
[cofx use-mailservers?]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(multiaccounts.update/optimistic :use-mailservers? use-mailservers?)
|
(multiaccounts.update/optimistic :use-mailservers? use-mailservers?)
|
||||||
(toggle-use-mailservers use-mailservers?)
|
(toggle-use-mailservers use-mailservers?)
|
||||||
(when use-mailservers?
|
(when use-mailservers?
|
||||||
(disconnect-from-mailserver))))
|
(disconnect-from-mailserver))))
|
||||||
|
|
||||||
(fx/defn retry-next-messages-request
|
(rf/defn retry-next-messages-request
|
||||||
{:events [:mailserver.ui/retry-request-pressed]}
|
{:events [:mailserver.ui/retry-request-pressed]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (dissoc db :mailserver/request-error)}
|
{:db (dissoc db :mailserver/request-error)}
|
||||||
(process-next-messages-request)))
|
(process-next-messages-request)))
|
||||||
|
|
||||||
(fx/defn show-request-error-popup
|
(rf/defn show-request-error-popup
|
||||||
{:events [:mailserver.ui/request-error-pressed]}
|
{:events [:mailserver.ui/request-error-pressed]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(let [mailserver-error (:mailserver/request-error db)]
|
(let [mailserver-error (:mailserver/request-error db)]
|
||||||
{:utils/show-confirmation
|
{:utils/show-confirmation
|
||||||
{:title (i18n/label :t/mailserver-request-error-title)
|
{:title (i18n/label :t/mailserver-request-error-title)
|
||||||
:content (i18n/label :t/mailserver-request-error-content
|
:content (i18n/label :t/mailserver-request-error-content
|
||||||
{:error mailserver-error})
|
{:error mailserver-error})
|
||||||
:on-accept #(re-frame/dispatch [:mailserver.ui/retry-request-pressed])
|
:on-accept #(re-frame/dispatch [:mailserver.ui/retry-request-pressed])
|
||||||
:confirm-button-text (i18n/label :t/mailserver-request-retry)}}))
|
:confirm-button-text (i18n/label :t/mailserver-request-retry)}}))
|
||||||
|
|
||||||
(def enode-url-regex
|
(def enode-url-regex
|
||||||
#"enode://[a-zA-Z0-9]+\@\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b:(\d{1,5})")
|
#"enode://[a-zA-Z0-9]+\@\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b:(\d{1,5})")
|
||||||
|
|
||||||
(defn- extract-url-components [address]
|
(defn- extract-url-components
|
||||||
|
[address]
|
||||||
(rest (re-matches #"enode://(.*)@(.*)" address)))
|
(rest (re-matches #"enode://(.*)@(.*)" address)))
|
||||||
|
|
||||||
(defn valid-enode-url? [address]
|
(defn valid-enode-url?
|
||||||
|
[address]
|
||||||
(re-matches enode-url-regex address))
|
(re-matches enode-url-regex address))
|
||||||
|
|
||||||
(defn build-url [address]
|
(defn build-url
|
||||||
|
[address]
|
||||||
(let [[initial host] (extract-url-components address)]
|
(let [[initial host] (extract-url-components address)]
|
||||||
(str "enode://" initial "@" host)))
|
(str "enode://" initial "@" host)))
|
||||||
|
|
||||||
(fx/defn set-input
|
(rf/defn set-input
|
||||||
{:events [:mailserver.ui/input-changed]}
|
{:events [:mailserver.ui/input-changed]}
|
||||||
[{:keys [db]} input-key value]
|
[{:keys [db]} input-key value]
|
||||||
{:db (update
|
{:db (update
|
||||||
@@ -216,26 +231,28 @@
|
|||||||
:name (string/blank? value)
|
:name (string/blank? value)
|
||||||
:url (not (valid-enode-url? value)))})})
|
:url (not (valid-enode-url? value)))})})
|
||||||
|
|
||||||
(defn- address->mailserver [address]
|
(defn- address->mailserver
|
||||||
|
[address]
|
||||||
(let [[enode url :as response] (extract-url-components address)]
|
(let [[enode url :as response] (extract-url-components address)]
|
||||||
{:address (if (seq response)
|
{:address (if (seq response)
|
||||||
(str "enode://" enode "@" url)
|
(str "enode://" enode "@" url)
|
||||||
address)
|
address)
|
||||||
:custom true}))
|
:custom true}))
|
||||||
|
|
||||||
(defn- build [id mailserver-name address]
|
(defn- build
|
||||||
|
[id mailserver-name address]
|
||||||
(assoc (address->mailserver address)
|
(assoc (address->mailserver address)
|
||||||
:id id
|
:id id
|
||||||
:name mailserver-name))
|
:name mailserver-name))
|
||||||
|
|
||||||
(def default? (comp not :custom fetch))
|
(def default? (comp not :custom fetch))
|
||||||
|
|
||||||
(fx/defn edit
|
(rf/defn edit
|
||||||
{:events [:mailserver.ui/custom-mailserver-selected]}
|
{:events [:mailserver.ui/custom-mailserver-selected]}
|
||||||
[{:keys [db] :as cofx} id]
|
[{:keys [db] :as cofx} id]
|
||||||
(let [{:keys [id address name]} (fetch db id)
|
(let [{:keys [id address name]} (fetch db id)
|
||||||
url (when address (build-url address))]
|
url (when address (build-url address))]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(set-input :id id)
|
(set-input :id id)
|
||||||
(set-input :url (str url))
|
(set-input :url (str url))
|
||||||
(set-input :name (str name))
|
(set-input :name (str name))
|
||||||
@@ -247,14 +264,15 @@
|
|||||||
(assoc :fleet (name current-fleet))
|
(assoc :fleet (name current-fleet))
|
||||||
(update :id name)))
|
(update :id name)))
|
||||||
|
|
||||||
(fx/defn upsert
|
(rf/defn upsert
|
||||||
{:events [:mailserver.ui/save-pressed]
|
{:events [:mailserver.ui/save-pressed]
|
||||||
:interceptors [(re-frame/inject-cofx :random-id-generator)]}
|
:interceptors [(re-frame/inject-cofx :random-id-generator)]}
|
||||||
[{{:mailserver.edit/keys [mailserver] :keys [multiaccount] :as db} :db
|
[{{:mailserver.edit/keys [mailserver] :keys [multiaccount] :as db} :db
|
||||||
random-id-generator :random-id-generator :as cofx}]
|
random-id-generator :random-id-generator
|
||||||
|
:as cofx}]
|
||||||
|
|
||||||
(let [{:keys [name url id]} mailserver
|
(let [{:keys [name url id]} mailserver
|
||||||
current-fleet (node/current-fleet-key db)]
|
current-fleet (node/current-fleet-key db)]
|
||||||
(when (and (not (string/blank? (:value name)))
|
(when (and (not (string/blank? (:value name)))
|
||||||
(valid-enode-url? (:value url)))
|
(valid-enode-url? (:value url)))
|
||||||
|
|
||||||
@@ -263,14 +281,14 @@
|
|||||||
(keyword (string/replace (random-id-generator) "-" "")))
|
(keyword (string/replace (random-id-generator) "-" "")))
|
||||||
(:value name)
|
(:value name)
|
||||||
(:value url))
|
(:value url))
|
||||||
current (connected? db (:id mailserver))]
|
current (connected? db (:id mailserver))]
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(dissoc :mailserver.edit/mailserver)
|
(dissoc :mailserver.edit/mailserver)
|
||||||
(assoc-in [:mailserver/mailservers current-fleet (:id mailserver)]
|
(assoc-in [:mailserver/mailservers current-fleet (:id mailserver)]
|
||||||
mailserver))
|
mailserver))
|
||||||
::json-rpc/call
|
::json-rpc/call
|
||||||
[{:method "mailservers_addMailserver"
|
[{:method "mailservers_addMailserver"
|
||||||
:params [(mailserver->rpc mailserver current-fleet)]
|
:params [(mailserver->rpc mailserver current-fleet)]
|
||||||
:on-success (fn []
|
:on-success (fn []
|
||||||
;; we naively logout if the user is connected to
|
;; we naively logout if the user is connected to
|
||||||
;; the edited mailserver
|
;; the edited mailserver
|
||||||
@@ -279,47 +297,49 @@
|
|||||||
[:multiaccounts.logout.ui/logout-confirmed]))
|
[:multiaccounts.logout.ui/logout-confirmed]))
|
||||||
(log/debug "saved mailserver" id "successfuly"))
|
(log/debug "saved mailserver" id "successfuly"))
|
||||||
:on-failure #(log/error "failed to save mailserver" id %)}]
|
:on-failure #(log/error "failed to save mailserver" id %)}]
|
||||||
:dispatch [:navigate-back]}))))
|
:dispatch [:navigate-back]}))))
|
||||||
|
|
||||||
(defn can-delete?
|
(defn can-delete?
|
||||||
[db id]
|
[db id]
|
||||||
(not (or (default? db id)
|
(not (or (default? db id)
|
||||||
(connected? db id))))
|
(connected? db id))))
|
||||||
|
|
||||||
(fx/defn delete
|
(rf/defn delete
|
||||||
{:events [:mailserver.ui/delete-confirmed]}
|
{:events [:mailserver.ui/delete-confirmed]}
|
||||||
[{:keys [db] :as cofx} id]
|
[{:keys [db] :as cofx} id]
|
||||||
(if (can-delete? db id)
|
(if (can-delete? db id)
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(update-in
|
(update-in
|
||||||
[:mailserver/mailservers (node/current-fleet-key db)]
|
[:mailserver/mailservers (node/current-fleet-key db)]
|
||||||
dissoc id)
|
dissoc
|
||||||
(dissoc :mailserver.edit/mailserver))
|
id)
|
||||||
|
(dissoc :mailserver.edit/mailserver))
|
||||||
::json-rpc/call
|
::json-rpc/call
|
||||||
[{:method "mailservers_deleteMailserver"
|
[{:method "mailservers_deleteMailserver"
|
||||||
:params [(name id)]
|
:params [(name id)]
|
||||||
:on-success #(log/debug "deleted mailserver" id)
|
:on-success #(log/debug "deleted mailserver" id)
|
||||||
:on-failure #(log/error "failed to delete mailserver" id %)}]
|
:on-failure #(log/error "failed to delete mailserver" id %)}]
|
||||||
:dispatch [:navigate-back]}
|
:dispatch [:navigate-back]}
|
||||||
{:dispatch [:navigate-back]}))
|
{:dispatch [:navigate-back]}))
|
||||||
|
|
||||||
(fx/defn show-connection-confirmation
|
(rf/defn show-connection-confirmation
|
||||||
{:events [:mailserver.ui/default-mailserver-selected :mailserver.ui/connect-pressed]}
|
{:events [:mailserver.ui/default-mailserver-selected :mailserver.ui/connect-pressed]}
|
||||||
[{:keys [db]} mailserver-id]
|
[{:keys [db]} mailserver-id]
|
||||||
(let [current-fleet (node/current-fleet-key db)]
|
(let [current-fleet (node/current-fleet-key db)]
|
||||||
{:ui/show-confirmation
|
{:ui/show-confirmation
|
||||||
{:title (i18n/label :t/close-app-title)
|
{:title (i18n/label :t/close-app-title)
|
||||||
:content
|
:content
|
||||||
(i18n/label :t/connect-mailserver-content
|
(i18n/label :t/connect-mailserver-content
|
||||||
{:name (get-in db [:mailserver/mailservers
|
{:name (get-in db
|
||||||
current-fleet mailserver-id :name])})
|
[:mailserver/mailservers
|
||||||
|
current-fleet mailserver-id :name])})
|
||||||
:confirm-button-text (i18n/label :t/close-app-button)
|
:confirm-button-text (i18n/label :t/close-app-button)
|
||||||
:on-accept
|
:on-accept
|
||||||
#(re-frame/dispatch
|
#(re-frame/dispatch
|
||||||
[:mailserver.ui/connect-confirmed current-fleet mailserver-id])
|
[:mailserver.ui/connect-confirmed current-fleet mailserver-id])
|
||||||
:on-cancel nil}}))
|
:on-cancel nil}}))
|
||||||
|
|
||||||
(fx/defn show-delete-confirmation
|
(rf/defn show-delete-confirmation
|
||||||
{:events [:mailserver.ui/delete-pressed]}
|
{:events [:mailserver.ui/delete-pressed]}
|
||||||
[{:keys [db]} mailserver-id]
|
[{:keys [db]} mailserver-id]
|
||||||
{:ui/show-confirmation
|
{:ui/show-confirmation
|
||||||
@@ -329,64 +349,67 @@
|
|||||||
:on-accept #(re-frame/dispatch
|
:on-accept #(re-frame/dispatch
|
||||||
[:mailserver.ui/delete-confirmed mailserver-id])}})
|
[:mailserver.ui/delete-confirmed mailserver-id])}})
|
||||||
|
|
||||||
(fx/defn set-url-from-qr
|
(rf/defn set-url-from-qr
|
||||||
{:events [:mailserver.callback/qr-code-scanned]}
|
{:events [:mailserver.callback/qr-code-scanned]}
|
||||||
[cofx url]
|
[cofx url]
|
||||||
(assoc (set-input cofx :url url)
|
(assoc (set-input cofx :url url)
|
||||||
:dispatch [:navigate-back]))
|
:dispatch
|
||||||
|
[:navigate-back]))
|
||||||
|
|
||||||
(fx/defn dismiss-connection-error
|
(rf/defn dismiss-connection-error
|
||||||
{:events [:mailserver.ui/dismiss-connection-error]}
|
{:events [:mailserver.ui/dismiss-connection-error]}
|
||||||
[{:keys [db]} new-state]
|
[{:keys [db]} new-state]
|
||||||
{:db (assoc db :mailserver/connection-error-dismissed new-state)})
|
{:db (assoc db :mailserver/connection-error-dismissed new-state)})
|
||||||
|
|
||||||
(fx/defn pin-mailserver
|
(rf/defn pin-mailserver
|
||||||
{:events [:mailserver.ui/connect-confirmed]}
|
{:events [:mailserver.ui/connect-confirmed]}
|
||||||
[{:keys [db] :as cofx} current-fleet mailserver-id]
|
[{:keys [db] :as cofx} current-fleet mailserver-id]
|
||||||
(let [pinned-mailservers (-> db
|
(let [pinned-mailservers (-> db
|
||||||
(get-in [:multiaccount :pinned-mailservers])
|
(get-in [:multiaccount :pinned-mailservers])
|
||||||
(assoc current-fleet mailserver-id))]
|
(assoc current-fleet mailserver-id))]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc db :mailserver/current-id mailserver-id)
|
{:db (assoc db :mailserver/current-id mailserver-id)
|
||||||
::json-rpc/call [{:method "wakuext_setPinnedMailservers"
|
::json-rpc/call [{:method "wakuext_setPinnedMailservers"
|
||||||
:params [pinned-mailservers]
|
:params [pinned-mailservers]
|
||||||
:on-success #(log/info "successfully pinned mailserver")
|
:on-success #(log/info "successfully pinned mailserver")
|
||||||
:on-error #(log/error "failed to pin mailserver" %)}]}
|
:on-error #(log/error "failed to pin mailserver" %)}]}
|
||||||
(multiaccounts.update/optimistic :pinned-mailservers pinned-mailservers))))
|
(multiaccounts.update/optimistic :pinned-mailservers pinned-mailservers))))
|
||||||
|
|
||||||
(fx/defn unpin
|
(rf/defn unpin
|
||||||
{:events [:mailserver.ui/unpin-pressed]}
|
{:events [:mailserver.ui/unpin-pressed]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [current-fleet (node/current-fleet-key db)
|
(let [current-fleet (node/current-fleet-key db)
|
||||||
pinned-mailservers (-> db
|
pinned-mailservers (-> db
|
||||||
(get-in [:multiaccount :pinned-mailservers])
|
(get-in [:multiaccount :pinned-mailservers])
|
||||||
(dissoc current-fleet))]
|
(dissoc current-fleet))]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{::json-rpc/call [{:method "wakuext_setPinnedMailservers"
|
{::json-rpc/call [{:method "wakuext_setPinnedMailservers"
|
||||||
:params [pinned-mailservers]
|
:params [pinned-mailservers]
|
||||||
:on-success #(log/info "successfully unpinned mailserver")
|
:on-success #(log/info "successfully unpinned mailserver")
|
||||||
:on-error #(log/error "failed to unpin mailserver" %)}]}
|
:on-error #(log/error "failed to unpin mailserver" %)}]}
|
||||||
(multiaccounts.update/optimistic
|
(multiaccounts.update/optimistic
|
||||||
:pinned-mailservers pinned-mailservers)
|
:pinned-mailservers
|
||||||
|
pinned-mailservers)
|
||||||
(dismiss-connection-error false))))
|
(dismiss-connection-error false))))
|
||||||
|
|
||||||
(fx/defn pin
|
(rf/defn pin
|
||||||
{:events [:mailserver.ui/pin-pressed]}
|
{:events [:mailserver.ui/pin-pressed]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [current-fleet (node/current-fleet-key db)
|
(let [current-fleet (node/current-fleet-key db)
|
||||||
mailserver-id (:mailserver/current-id db)
|
mailserver-id (:mailserver/current-id db)
|
||||||
pinned-mailservers (get-in db [:multiaccount :pinned-mailservers])]
|
pinned-mailservers (get-in db [:multiaccount :pinned-mailservers])]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(multiaccounts.update/multiaccount-update
|
(multiaccounts.update/multiaccount-update
|
||||||
:pinned-mailservers (assoc pinned-mailservers
|
:pinned-mailservers
|
||||||
current-fleet
|
(assoc pinned-mailservers
|
||||||
mailserver-id)
|
current-fleet
|
||||||
|
mailserver-id)
|
||||||
{})
|
{})
|
||||||
(dismiss-connection-error false))))
|
(dismiss-connection-error false))))
|
||||||
|
|
||||||
(fx/defn mailserver-ui-add-pressed
|
(rf/defn mailserver-ui-add-pressed
|
||||||
{:events [:mailserver.ui/add-pressed]}
|
{:events [:mailserver.ui/add-pressed]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (dissoc db :mailserver.edit/mailserver)}
|
{:db (dissoc db :mailserver.edit/mailserver)}
|
||||||
(navigation/navigate-to-cofx :edit-mailserver nil)))
|
(navigation/navigate-to-cofx :edit-mailserver nil)))
|
||||||
|
|||||||
@@ -1,28 +1,29 @@
|
|||||||
(ns status-im.mobile-sync-settings.core
|
(ns status-im.mobile-sync-settings.core
|
||||||
(:require
|
(:require [status-im.bottom-sheet.core :as bottom-sheet]
|
||||||
[status-im.multiaccounts.update.core :as multiaccounts.update]
|
[status-im.mailserver.core :as mailserver]
|
||||||
[status-im.utils.fx :as fx]
|
[status-im.multiaccounts.model :as multiaccounts.model]
|
||||||
[status-im.wallet.core :as wallet]
|
[status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||||
[status-im.bottom-sheet.core :as bottom-sheet]
|
[status-im.utils.mobile-sync :as utils]
|
||||||
[status-im.multiaccounts.model :as multiaccounts.model]
|
[status-im.wallet.core :as wallet]
|
||||||
[status-im2.navigation.events :as navigation]
|
[status-im2.navigation.events :as navigation]
|
||||||
[status-im.mailserver.core :as mailserver]
|
[taoensso.timbre :as log]
|
||||||
[status-im.utils.mobile-sync :as utils]
|
[utils.re-frame :as rf]))
|
||||||
[taoensso.timbre :as log]))
|
|
||||||
|
|
||||||
(fx/defn sheet-defaults
|
(rf/defn sheet-defaults
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(let [remember-choice? (get-in db [:multiaccount :remember-syncing-choice?])]
|
(let [remember-choice? (get-in db [:multiaccount :remember-syncing-choice?])]
|
||||||
{:db (assoc db :mobile-network/remember-choice? (or (nil? remember-choice?)
|
{:db (assoc db
|
||||||
remember-choice?))}))
|
:mobile-network/remember-choice?
|
||||||
|
(or (nil? remember-choice?)
|
||||||
|
remember-choice?))}))
|
||||||
|
|
||||||
(fx/defn on-network-status-change
|
(rf/defn on-network-status-change
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [initialized? (get db :network-status/initialized?)
|
(let [initialized? (get db :network-status/initialized?)
|
||||||
logged-in? (multiaccounts.model/logged-in? cofx)
|
logged-in? (multiaccounts.model/logged-in? cofx)
|
||||||
{:keys [remember-syncing-choice?]} (:multiaccount db)]
|
{:keys [remember-syncing-choice?]} (:multiaccount db)]
|
||||||
(apply
|
(apply
|
||||||
fx/merge
|
rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (assoc db :network-status/initialized? true)}
|
{:db (assoc db :network-status/initialized? true)}
|
||||||
(cond
|
(cond
|
||||||
@@ -51,67 +52,71 @@
|
|||||||
([sync?] (apply-settings sync? :default))
|
([sync?] (apply-settings sync? :default))
|
||||||
([sync? remember?]
|
([sync? remember?]
|
||||||
(fn [{:keys [db] :as cofx}]
|
(fn [{:keys [db] :as cofx}]
|
||||||
(let [network (:network/type db)
|
(let [network (:network/type db)
|
||||||
remember-choice?
|
remember-choice?
|
||||||
(if (not= :default remember?)
|
(if (not= :default remember?)
|
||||||
remember?
|
remember?
|
||||||
(:mobile-network/remember-choice? db))
|
(:mobile-network/remember-choice? db))
|
||||||
cellular? (utils/cellular? network)]
|
cellular? (utils/cellular? network)]
|
||||||
(log/info "apply mobile network settings"
|
(log/info "apply mobile network settings"
|
||||||
"sunc?" sync?
|
"sunc?" sync?
|
||||||
"remember?" remember?
|
"remember?" remember?
|
||||||
"cellular?" cellular?)
|
"cellular?" cellular?)
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
(multiaccounts.update/multiaccount-update
|
(multiaccounts.update/multiaccount-update
|
||||||
:syncing-on-mobile-network? (boolean sync?) {})
|
:syncing-on-mobile-network?
|
||||||
|
(boolean sync?)
|
||||||
|
{})
|
||||||
(multiaccounts.update/multiaccount-update
|
(multiaccounts.update/multiaccount-update
|
||||||
:remember-syncing-choice? (boolean remember-choice?) {})
|
:remember-syncing-choice?
|
||||||
|
(boolean remember-choice?)
|
||||||
|
{})
|
||||||
(when (and cellular? sync?)
|
(when (and cellular? sync?)
|
||||||
(mailserver/process-next-messages-request))
|
(mailserver/process-next-messages-request))
|
||||||
(wallet/restart-wallet-service nil))))))
|
(wallet/restart-wallet-service nil))))))
|
||||||
|
|
||||||
(fx/defn mobile-network-continue-syncing
|
(rf/defn mobile-network-continue-syncing
|
||||||
{:events [:mobile-network/continue-syncing]}
|
{:events [:mobile-network/continue-syncing]}
|
||||||
[cofx]
|
[cofx]
|
||||||
((apply-settings true) cofx))
|
((apply-settings true) cofx))
|
||||||
|
|
||||||
(fx/defn mobile-network-stop-syncing
|
(rf/defn mobile-network-stop-syncing
|
||||||
{:events [:mobile-network/stop-syncing]}
|
{:events [:mobile-network/stop-syncing]}
|
||||||
[cofx]
|
[cofx]
|
||||||
((apply-settings false) cofx))
|
((apply-settings false) cofx))
|
||||||
|
|
||||||
(fx/defn mobile-network-set-syncing
|
(rf/defn mobile-network-set-syncing
|
||||||
{:events [:mobile-network/set-syncing]}
|
{:events [:mobile-network/set-syncing]}
|
||||||
[{:keys [db] :as cofx} syncing?]
|
[{:keys [db] :as cofx} syncing?]
|
||||||
(let [{:keys [remember-syncing-choice?]} (:multiaccount db)]
|
(let [{:keys [remember-syncing-choice?]} (:multiaccount db)]
|
||||||
((apply-settings syncing? remember-syncing-choice?) cofx)))
|
((apply-settings syncing? remember-syncing-choice?) cofx)))
|
||||||
|
|
||||||
(fx/defn mobile-network-ask-on-mobile-network?
|
(rf/defn mobile-network-ask-on-mobile-network?
|
||||||
{:events [:mobile-network/ask-on-mobile-network?]}
|
{:events [:mobile-network/ask-on-mobile-network?]}
|
||||||
[{:keys [db] :as cofx} ask?]
|
[{:keys [db] :as cofx} ask?]
|
||||||
(let [{:keys [syncing-on-mobile-network?]} (:multiaccount db)]
|
(let [{:keys [syncing-on-mobile-network?]} (:multiaccount db)]
|
||||||
((apply-settings syncing-on-mobile-network? (not ask?)) cofx)))
|
((apply-settings syncing-on-mobile-network? (not ask?)) cofx)))
|
||||||
|
|
||||||
(fx/defn mobile-network-restore-defaults
|
(rf/defn mobile-network-restore-defaults
|
||||||
{:events [:mobile-network/restore-defaults]}
|
{:events [:mobile-network/restore-defaults]}
|
||||||
[cofx]
|
[cofx]
|
||||||
((apply-settings false false) cofx))
|
((apply-settings false false) cofx))
|
||||||
|
|
||||||
(fx/defn mobile-network-remember-choice?
|
(rf/defn mobile-network-remember-choice?
|
||||||
{:events [:mobile-network/remember-choice?]}
|
{:events [:mobile-network/remember-choice?]}
|
||||||
[{:keys [db]} remember-choice?]
|
[{:keys [db]} remember-choice?]
|
||||||
{:db (assoc db :mobile-network/remember-choice? remember-choice?)})
|
{:db (assoc db :mobile-network/remember-choice? remember-choice?)})
|
||||||
|
|
||||||
(fx/defn mobile-network-navigate-to-settings
|
(rf/defn mobile-network-navigate-to-settings
|
||||||
{:events [:mobile-network/navigate-to-settings]}
|
{:events [:mobile-network/navigate-to-settings]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
(bottom-sheet/hide-bottom-sheet)
|
(bottom-sheet/hide-bottom-sheet)
|
||||||
(navigation/navigate-to-cofx :mobile-network-settings nil)))
|
(navigation/navigate-to-cofx :mobile-network-settings nil)))
|
||||||
|
|
||||||
(fx/defn mobile-network-show-offline-sheet
|
(rf/defn mobile-network-show-offline-sheet
|
||||||
{:events [:mobile-network/show-offline-sheet]}
|
{:events [:mobile-network/show-offline-sheet]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(bottom-sheet/show-bottom-sheet
|
(bottom-sheet/show-bottom-sheet
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
(ns status-im.multiaccounts.biometric.core
|
(ns status-im.multiaccounts.biometric.core
|
||||||
(:require [re-frame.core :as re-frame]
|
(:require ["react-native-touch-id" :default touchid]
|
||||||
|
[quo.design-system.colors :as colors]
|
||||||
|
[re-frame.core :as re-frame]
|
||||||
[status-im.i18n.i18n :as i18n]
|
[status-im.i18n.i18n :as i18n]
|
||||||
[status-im.native-module.core :as status]
|
[status-im.native-module.core :as status]
|
||||||
[status-im.popover.core :as popover]
|
[status-im.popover.core :as popover]
|
||||||
[quo.design-system.colors :as colors]
|
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[status-im.utils.keychain.core :as keychain]
|
[status-im.utils.keychain.core :as keychain]
|
||||||
[status-im.utils.platform :as platform]
|
[status-im.utils.platform :as platform]
|
||||||
[taoensso.timbre :as log]
|
[taoensso.timbre :as log]
|
||||||
["react-native-touch-id" :default touchid]))
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
;; currently, for android, react-native-touch-id
|
;; currently, for android, react-native-touch-id
|
||||||
;; is not returning supported biometric type
|
;; is not returning supported biometric type
|
||||||
@@ -28,11 +28,12 @@
|
|||||||
(def android-device-blacklisted?
|
(def android-device-blacklisted?
|
||||||
(cond
|
(cond
|
||||||
(= (:brand deviceinfo) "bannedbrand") true
|
(= (:brand deviceinfo) "bannedbrand") true
|
||||||
:else false))
|
:else false))
|
||||||
|
|
||||||
;; biometric auth config
|
;; biometric auth config
|
||||||
;; https://github.com/naoufal/react-native-touch-id#authenticatereason-config
|
;; https://github.com/naoufal/react-native-touch-id#authenticatereason-config
|
||||||
(defn- authenticate-options [ios-fallback-label]
|
(defn- authenticate-options
|
||||||
|
[ios-fallback-label]
|
||||||
(clj->js (merge
|
(clj->js (merge
|
||||||
{:unifiedErrors true}
|
{:unifiedErrors true}
|
||||||
(when platform/ios?
|
(when platform/ios?
|
||||||
@@ -46,7 +47,8 @@
|
|||||||
:sensorErrorDescription (i18n/label :t/biometric-auth-android-sensor-error-desc)
|
:sensorErrorDescription (i18n/label :t/biometric-auth-android-sensor-error-desc)
|
||||||
:cancelText (i18n/label :cancel)}))))
|
:cancelText (i18n/label :cancel)}))))
|
||||||
|
|
||||||
(defn get-label [supported-biometric-auth]
|
(defn get-label
|
||||||
|
[supported-biometric-auth]
|
||||||
(case supported-biometric-auth
|
(case supported-biometric-auth
|
||||||
:fingerprint (i18n/label :t/biometric-fingerprint)
|
:fingerprint (i18n/label :t/biometric-fingerprint)
|
||||||
:FaceID (i18n/label :t/biometric-faceid)
|
:FaceID (i18n/label :t/biometric-faceid)
|
||||||
@@ -61,29 +63,33 @@
|
|||||||
(= touchid-error-code "USER_FALLBACK") nil
|
(= touchid-error-code "USER_FALLBACK") nil
|
||||||
;; add here more specific errors if needed
|
;; add here more specific errors if needed
|
||||||
;; https://github.com/naoufal/react-native-touch-id#unified-errors
|
;; https://github.com/naoufal/react-native-touch-id#unified-errors
|
||||||
:else (i18n/label :t/biometric-auth-error {:code touchid-error-code})))
|
:else (i18n/label :t/biometric-auth-error
|
||||||
|
{:code touchid-error-code})))
|
||||||
|
|
||||||
(def success-result
|
(def success-result
|
||||||
{:bioauth-success true})
|
{:bioauth-success true})
|
||||||
|
|
||||||
(defn- generate-error-result [touchid-error-obj]
|
(defn- generate-error-result
|
||||||
|
[touchid-error-obj]
|
||||||
(let [code (aget touchid-error-obj "code")]
|
(let [code (aget touchid-error-obj "code")]
|
||||||
{:bioauth-success false
|
{:bioauth-success false
|
||||||
:bioauth-code code
|
:bioauth-code code
|
||||||
:bioauth-message (get-error-message code)}))
|
:bioauth-message (get-error-message code)}))
|
||||||
|
|
||||||
(defn- do-get-supported [callback]
|
(defn- do-get-supported
|
||||||
|
[callback]
|
||||||
(-> (.isSupported touchid)
|
(-> (.isSupported touchid)
|
||||||
(.then #(callback (or (keyword %) android-default-support)))
|
(.then #(callback (or (keyword %) android-default-support)))
|
||||||
(.catch #(callback nil))))
|
(.catch #(callback nil))))
|
||||||
|
|
||||||
(defn get-supported [callback]
|
(defn get-supported
|
||||||
|
[callback]
|
||||||
(log/debug "[biometric] get-supported")
|
(log/debug "[biometric] get-supported")
|
||||||
(cond platform/ios? (do-get-supported callback)
|
(cond platform/ios? (do-get-supported callback)
|
||||||
platform/android? (if android-device-blacklisted?
|
platform/android? (if android-device-blacklisted?
|
||||||
(callback nil)
|
(callback nil)
|
||||||
(do-get-supported callback))
|
(do-get-supported callback))
|
||||||
:else (callback nil)))
|
:else (callback nil)))
|
||||||
|
|
||||||
(defn authenticate-fx
|
(defn authenticate-fx
|
||||||
([cb]
|
([cb]
|
||||||
@@ -105,12 +111,12 @@
|
|||||||
(get-supported callback)
|
(get-supported callback)
|
||||||
(callback nil)))))))
|
(callback nil)))))))
|
||||||
|
|
||||||
(fx/defn set-supported-biometric-auth
|
(rf/defn set-supported-biometric-auth
|
||||||
{:events [:init.callback/get-supported-biometric-auth-success]}
|
{:events [:init.callback/get-supported-biometric-auth-success]}
|
||||||
[{:keys [db]} supported-biometric-auth]
|
[{:keys [db]} supported-biometric-auth]
|
||||||
{:db (assoc db :supported-biometric-auth supported-biometric-auth)})
|
{:db (assoc db :supported-biometric-auth supported-biometric-auth)})
|
||||||
|
|
||||||
(fx/defn authenticate
|
(rf/defn authenticate
|
||||||
[_ cb options]
|
[_ cb options]
|
||||||
{:biometric-auth/authenticate [cb options]})
|
{:biometric-auth/authenticate [cb options]})
|
||||||
|
|
||||||
@@ -119,10 +125,11 @@
|
|||||||
(fn [[cb options]]
|
(fn [[cb options]]
|
||||||
(authenticate-fx #(cb %) options)))
|
(authenticate-fx #(cb %) options)))
|
||||||
|
|
||||||
(fx/defn update-biometric [{db :db :as cofx} biometric-auth?]
|
(rf/defn update-biometric
|
||||||
|
[{db :db :as cofx} biometric-auth?]
|
||||||
(let [key-uid (or (get-in db [:multiaccount :key-uid])
|
(let [key-uid (or (get-in db [:multiaccount :key-uid])
|
||||||
(get-in db [:multiaccounts/login :key-uid]))]
|
(get-in db [:multiaccounts/login :key-uid]))]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(keychain/save-auth-method
|
(keychain/save-auth-method
|
||||||
key-uid
|
key-uid
|
||||||
(if biometric-auth?
|
(if biometric-auth?
|
||||||
@@ -131,7 +138,7 @@
|
|||||||
#(when-not biometric-auth?
|
#(when-not biometric-auth?
|
||||||
{:keychain/clear-user-password key-uid}))))
|
{:keychain/clear-user-password key-uid}))))
|
||||||
|
|
||||||
(fx/defn biometric-auth-switched
|
(rf/defn biometric-auth-switched
|
||||||
{:events [:multiaccounts.ui/biometric-auth-switched]}
|
{:events [:multiaccounts.ui/biometric-auth-switched]}
|
||||||
[cofx biometric-auth?]
|
[cofx biometric-auth?]
|
||||||
(if biometric-auth?
|
(if biometric-auth?
|
||||||
@@ -141,17 +148,17 @@
|
|||||||
{})
|
{})
|
||||||
(update-biometric cofx false)))
|
(update-biometric cofx false)))
|
||||||
|
|
||||||
(fx/defn show-message
|
(rf/defn show-message
|
||||||
[cofx bioauth-message bioauth-code]
|
[cofx bioauth-message bioauth-code]
|
||||||
(let [content (or (when (get #{"NOT_AVAILABLE" "NOT_ENROLLED"} bioauth-code)
|
(let [content (or (when (get #{"NOT_AVAILABLE" "NOT_ENROLLED"} bioauth-code)
|
||||||
(i18n/label :t/grant-face-id-permissions))
|
(i18n/label :t/grant-face-id-permissions))
|
||||||
bioauth-message)]
|
bioauth-message)]
|
||||||
(when content
|
(when content
|
||||||
{:utils/show-popup
|
{:utils/show-popup
|
||||||
{:title (i18n/label :t/biometric-auth-login-error-title)
|
{:title (i18n/label :t/biometric-auth-login-error-title)
|
||||||
:content content}})))
|
:content content}})))
|
||||||
|
|
||||||
(fx/defn biometric-init-done
|
(rf/defn biometric-init-done
|
||||||
{:events [:biometric-init-done]}
|
{:events [:biometric-init-done]}
|
||||||
[cofx {:keys [bioauth-success bioauth-message bioauth-code]}]
|
[cofx {:keys [bioauth-success bioauth-message bioauth-code]}]
|
||||||
(if bioauth-success
|
(if bioauth-success
|
||||||
@@ -161,7 +168,7 @@
|
|||||||
(popover/show-popover cofx {:view :enable-biometric}))
|
(popover/show-popover cofx {:view :enable-biometric}))
|
||||||
(show-message cofx bioauth-message bioauth-code)))
|
(show-message cofx bioauth-message bioauth-code)))
|
||||||
|
|
||||||
(fx/defn biometric-auth
|
(rf/defn biometric-auth
|
||||||
{:events [:biometric-authenticate]}
|
{:events [:biometric-authenticate]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(authenticate
|
(authenticate
|
||||||
@@ -170,31 +177,31 @@
|
|||||||
{:reason (i18n/label :t/biometric-auth-reason-login)
|
{:reason (i18n/label :t/biometric-auth-reason-login)
|
||||||
:ios-fallback-label (i18n/label :t/biometric-auth-login-ios-fallback-label)}))
|
:ios-fallback-label (i18n/label :t/biometric-auth-login-ios-fallback-label)}))
|
||||||
|
|
||||||
(fx/defn enable
|
(rf/defn enable
|
||||||
{:events [:biometric/enable]}
|
{:events [:biometric/enable]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
(popover/hide-popover)
|
(popover/hide-popover)
|
||||||
(authenticate #(re-frame/dispatch [:biometric/setup-done %]) {})))
|
(authenticate #(re-frame/dispatch [:biometric/setup-done %]) {})))
|
||||||
|
|
||||||
(fx/defn disable
|
(rf/defn disable
|
||||||
{:events [:biometric/disable]}
|
{:events [:biometric/disable]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc :auth-method keychain/auth-method-none)
|
(assoc :auth-method keychain/auth-method-none)
|
||||||
(assoc-in [:multiaccounts/login :save-password?] false))}
|
(assoc-in [:multiaccounts/login :save-password?] false))}
|
||||||
(popover/hide-popover)))
|
(popover/hide-popover)))
|
||||||
|
|
||||||
(fx/defn setup-done
|
(rf/defn setup-done
|
||||||
{:events [:biometric/setup-done]}
|
{:events [:biometric/setup-done]}
|
||||||
[{:keys [db] :as cofx} {:keys [bioauth-success bioauth-message bioauth-code]}]
|
[{:keys [db] :as cofx} {:keys [bioauth-success bioauth-message bioauth-code]}]
|
||||||
(log/debug "[biometric] setup-done"
|
(log/debug "[biometric] setup-done"
|
||||||
"bioauth-success" bioauth-success
|
"bioauth-success" bioauth-success
|
||||||
"bioauth-message" bioauth-message
|
"bioauth-message" bioauth-message
|
||||||
"bioauth-code" bioauth-code)
|
"bioauth-code" bioauth-code)
|
||||||
(if bioauth-success
|
(if bioauth-success
|
||||||
{:db (assoc db :auth-method keychain/auth-method-biometric-prepare)}
|
{:db (assoc db :auth-method keychain/auth-method-biometric-prepare)}
|
||||||
(show-message cofx bioauth-message bioauth-code)))
|
(show-message cofx bioauth-message bioauth-code)))
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
(ns status-im.multiaccounts.core
|
(ns status-im.multiaccounts.core
|
||||||
(:require [re-frame.core :as re-frame]
|
(:require [clojure.string :as string]
|
||||||
|
[quo.platform :as platform]
|
||||||
|
[re-frame.core :as re-frame]
|
||||||
|
[status-im.bottom-sheet.core :as bottom-sheet]
|
||||||
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
[status-im.ethereum.stateofus :as stateofus]
|
[status-im.ethereum.stateofus :as stateofus]
|
||||||
[status-im.multiaccounts.update.core :as multiaccounts.update]
|
[status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||||
[status-im.bottom-sheet.core :as bottom-sheet]
|
|
||||||
[status-im.native-module.core :as native-module]
|
[status-im.native-module.core :as native-module]
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
[status-im.theme.core :as theme]
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[status-im.utils.gfycat.core :as gfycat]
|
[status-im.utils.gfycat.core :as gfycat]
|
||||||
[status-im.utils.identicon :as identicon]
|
[status-im.utils.identicon :as identicon]
|
||||||
[status-im.theme.core :as theme]
|
|
||||||
[status-im.utils.utils :as utils]
|
[status-im.utils.utils :as utils]
|
||||||
[quo.platform :as platform]
|
[status-im2.common.theme.core :as utils.theme]
|
||||||
[taoensso.timbre :as log]
|
[taoensso.timbre :as log]
|
||||||
[clojure.string :as string]
|
[utils.re-frame :as rf]))
|
||||||
[status-im2.common.theme.core :as utils.theme]))
|
|
||||||
|
|
||||||
;; validate that the given mnemonic was generated from Status Dictionary
|
;; validate that the given mnemonic was generated from Status Dictionary
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
(cond-> {:nickname nickname
|
(cond-> {:nickname nickname
|
||||||
:display-name display-name
|
:display-name display-name
|
||||||
:three-words-name (or alias (gfycat/generate-gfy public-key))}
|
:three-words-name (or alias (gfycat/generate-gfy public-key))}
|
||||||
;; Preferred name is our own otherwise we make sure it's verified
|
;; Preferred name is our own otherwise we make sure it's verified
|
||||||
(or preferred-name (and ens-verified name))
|
(or preferred-name (and ens-verified name))
|
||||||
(assoc :ens-name (str "@" (or (stateofus/username ens-name) ens-name))))))
|
(assoc :ens-name (str "@" (or (stateofus/username ens-name) ens-name))))))
|
||||||
|
|
||||||
@@ -48,7 +48,8 @@
|
|||||||
(let [{:keys [nickname
|
(let [{:keys [nickname
|
||||||
ens-name
|
ens-name
|
||||||
display-name
|
display-name
|
||||||
three-words-name]} (or names (contact-names contact))
|
three-words-name]}
|
||||||
|
(or names (contact-names contact))
|
||||||
short-public-key (when public-key? (utils/get-shortened-address public-key))]
|
short-public-key (when public-key? (utils/get-shortened-address public-key))]
|
||||||
(->> [nickname ens-name display-name three-words-name short-public-key]
|
(->> [nickname ens-name display-name three-words-name short-public-key]
|
||||||
(remove string/blank?)
|
(remove string/blank?)
|
||||||
@@ -70,11 +71,13 @@
|
|||||||
(str "@" (or username ens-name)))
|
(str "@" (or username ens-name)))
|
||||||
(or alias (gfycat/generate-gfy public-key)))))
|
(or alias (gfycat/generate-gfy public-key)))))
|
||||||
|
|
||||||
(defn contact-by-identity [contacts identity]
|
(defn contact-by-identity
|
||||||
|
[contacts identity]
|
||||||
(or (get contacts identity)
|
(or (get contacts identity)
|
||||||
(contact-with-names {:public-key identity})))
|
(contact-with-names {:public-key identity})))
|
||||||
|
|
||||||
(defn contact-two-names-by-identity [contact current-multiaccount identity]
|
(defn contact-two-names-by-identity
|
||||||
|
[contact current-multiaccount identity]
|
||||||
(let [me? (= (:public-key current-multiaccount) identity)]
|
(let [me? (= (:public-key current-multiaccount) identity)]
|
||||||
(if me?
|
(if me?
|
||||||
[(or (:preferred-name current-multiaccount)
|
[(or (:preferred-name current-multiaccount)
|
||||||
@@ -110,53 +113,61 @@
|
|||||||
(fn [flag]
|
(fn [flag]
|
||||||
(native-module/set-blank-preview-flag flag)))
|
(native-module/set-blank-preview-flag flag)))
|
||||||
|
|
||||||
(fx/defn confirm-wallet-set-up
|
(rf/defn confirm-wallet-set-up
|
||||||
{:events [:multiaccounts.ui/wallet-set-up-confirmed]}
|
{:events [:multiaccounts.ui/wallet-set-up-confirmed]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(multiaccounts.update/multiaccount-update cofx
|
(multiaccounts.update/multiaccount-update cofx
|
||||||
:wallet-set-up-passed? true {}))
|
:wallet-set-up-passed?
|
||||||
|
true
|
||||||
|
{}))
|
||||||
|
|
||||||
(fx/defn confirm-home-tooltip
|
(rf/defn confirm-home-tooltip
|
||||||
{:events [:multiaccounts.ui/hide-home-tooltip]}
|
{:events [:multiaccounts.ui/hide-home-tooltip]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(multiaccounts.update/multiaccount-update cofx
|
(multiaccounts.update/multiaccount-update cofx
|
||||||
:hide-home-tooltip? true {}))
|
:hide-home-tooltip?
|
||||||
|
true
|
||||||
|
{}))
|
||||||
|
|
||||||
(fx/defn switch-webview-debug
|
(rf/defn switch-webview-debug
|
||||||
{:events [:multiaccounts.ui/switch-webview-debug]}
|
{:events [:multiaccounts.ui/switch-webview-debug]}
|
||||||
[{:keys [db] :as cofx} value]
|
[{:keys [db] :as cofx} value]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{::webview-debug-changed value}
|
{::webview-debug-changed value}
|
||||||
(multiaccounts.update/multiaccount-update
|
(multiaccounts.update/multiaccount-update
|
||||||
:webview-debug (boolean value)
|
:webview-debug
|
||||||
|
(boolean value)
|
||||||
{})))
|
{})))
|
||||||
|
|
||||||
(fx/defn switch-preview-privacy-mode
|
(rf/defn switch-preview-privacy-mode
|
||||||
{:events [:multiaccounts.ui/preview-privacy-mode-switched]}
|
{:events [:multiaccounts.ui/preview-privacy-mode-switched]}
|
||||||
[{:keys [db] :as cofx} private?]
|
[{:keys [db] :as cofx} private?]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{::blank-preview-flag-changed private?}
|
{::blank-preview-flag-changed private?}
|
||||||
(multiaccounts.update/multiaccount-update
|
(multiaccounts.update/multiaccount-update
|
||||||
:preview-privacy? (boolean private?)
|
:preview-privacy?
|
||||||
|
(boolean private?)
|
||||||
{})))
|
{})))
|
||||||
|
|
||||||
(fx/defn switch-webview-permission-requests?
|
(rf/defn switch-webview-permission-requests?
|
||||||
{:events [:multiaccounts.ui/webview-permission-requests-switched]}
|
{:events [:multiaccounts.ui/webview-permission-requests-switched]}
|
||||||
[cofx enabled?]
|
[cofx enabled?]
|
||||||
(multiaccounts.update/multiaccount-update
|
(multiaccounts.update/multiaccount-update
|
||||||
cofx
|
cofx
|
||||||
:webview-allow-permission-requests? (boolean enabled?)
|
:webview-allow-permission-requests?
|
||||||
|
(boolean enabled?)
|
||||||
{}))
|
{}))
|
||||||
|
|
||||||
(fx/defn switch-default-sync-period
|
(rf/defn switch-default-sync-period
|
||||||
{:events [:multiaccounts.ui/default-sync-period-switched]}
|
{:events [:multiaccounts.ui/default-sync-period-switched]}
|
||||||
[cofx value]
|
[cofx value]
|
||||||
(multiaccounts.update/multiaccount-update
|
(multiaccounts.update/multiaccount-update
|
||||||
cofx
|
cofx
|
||||||
:default-sync-period value
|
:default-sync-period
|
||||||
|
value
|
||||||
{}))
|
{}))
|
||||||
|
|
||||||
(fx/defn switch-preview-privacy-mode-flag
|
(rf/defn switch-preview-privacy-mode-flag
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(let [private? (get-in db [:multiaccount :preview-privacy?])]
|
(let [private? (get-in db [:multiaccount :preview-privacy?])]
|
||||||
{::blank-preview-flag-changed private?}))
|
{::blank-preview-flag-changed private?}))
|
||||||
@@ -169,48 +180,49 @@
|
|||||||
:light)]
|
:light)]
|
||||||
(theme/change-theme theme))))
|
(theme/change-theme theme))))
|
||||||
|
|
||||||
(fx/defn switch-appearance
|
(rf/defn switch-appearance
|
||||||
{:events [:multiaccounts.ui/appearance-switched]}
|
{:events [:multiaccounts.ui/appearance-switched]}
|
||||||
[cofx theme]
|
[cofx theme]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:multiaccounts.ui/switch-theme theme}
|
{:multiaccounts.ui/switch-theme theme}
|
||||||
(multiaccounts.update/multiaccount-update :appearance theme {})))
|
(multiaccounts.update/multiaccount-update :appearance theme {})))
|
||||||
|
|
||||||
(fx/defn switch-profile-picture-show-to
|
(rf/defn switch-profile-picture-show-to
|
||||||
{:events [:multiaccounts.ui/profile-picture-show-to-switched]}
|
{:events [:multiaccounts.ui/profile-picture-show-to-switched]}
|
||||||
[cofx id]
|
[cofx id]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{::json-rpc/call [{:method "wakuext_changeIdentityImageShowTo"
|
{::json-rpc/call [{:method "wakuext_changeIdentityImageShowTo"
|
||||||
:params [id]
|
:params [id]
|
||||||
:on-success #(log/debug "picture settings changed successfully")}]}
|
:on-success #(log/debug "picture settings changed successfully")}]}
|
||||||
(multiaccounts.update/optimistic :profile-pictures-show-to id)))
|
(multiaccounts.update/optimistic :profile-pictures-show-to id)))
|
||||||
|
|
||||||
(fx/defn switch-appearance-profile
|
(rf/defn switch-appearance-profile
|
||||||
{:events [:multiaccounts.ui/appearance-profile-switched]}
|
{:events [:multiaccounts.ui/appearance-profile-switched]}
|
||||||
[cofx id]
|
[cofx id]
|
||||||
(multiaccounts.update/multiaccount-update cofx :profile-pictures-visibility id {}))
|
(multiaccounts.update/multiaccount-update cofx :profile-pictures-visibility id {}))
|
||||||
|
|
||||||
(defn clean-path [path]
|
(defn clean-path
|
||||||
|
[path]
|
||||||
(if path
|
(if path
|
||||||
(string/replace-first path #"file://" "")
|
(string/replace-first path #"file://" "")
|
||||||
(log/warn "[native-module] Empty path was provided")))
|
(log/warn "[native-module] Empty path was provided")))
|
||||||
|
|
||||||
(fx/defn save-profile-picture
|
(rf/defn save-profile-picture
|
||||||
{:events [::save-profile-picture]}
|
{:events [::save-profile-picture]}
|
||||||
[cofx path ax ay bx by]
|
[cofx path ax ay bx by]
|
||||||
(let [key-uid (get-in cofx [:db :multiaccount :key-uid])]
|
(let [key-uid (get-in cofx [:db :multiaccount :key-uid])]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{::json-rpc/call [{:method "multiaccounts_storeIdentityImage"
|
{::json-rpc/call [{:method "multiaccounts_storeIdentityImage"
|
||||||
:params [key-uid (clean-path path) ax ay bx by]
|
:params [key-uid (clean-path path) ax ay bx by]
|
||||||
;; NOTE: In case of an error we can show a toast error
|
;; NOTE: In case of an error we can show a toast error
|
||||||
:on-success #(re-frame/dispatch [::update-local-picture %])}]}
|
:on-success #(re-frame/dispatch [::update-local-picture %])}]}
|
||||||
(bottom-sheet/hide-bottom-sheet))))
|
(bottom-sheet/hide-bottom-sheet))))
|
||||||
|
|
||||||
(fx/defn save-profile-picture-from-url
|
(rf/defn save-profile-picture-from-url
|
||||||
{:events [::save-profile-picture-from-url]}
|
{:events [::save-profile-picture-from-url]}
|
||||||
[cofx url]
|
[cofx url]
|
||||||
(let [key-uid (get-in cofx [:db :multiaccount :key-uid])]
|
(let [key-uid (get-in cofx [:db :multiaccount :key-uid])]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{::json-rpc/call [{:method "multiaccounts_storeIdentityImageFromURL"
|
{::json-rpc/call [{:method "multiaccounts_storeIdentityImageFromURL"
|
||||||
:params [key-uid url]
|
:params [key-uid url]
|
||||||
:on-error #(log/error "::save-profile-picture-from-url error" %)
|
:on-error #(log/error "::save-profile-picture-from-url error" %)
|
||||||
@@ -218,32 +230,37 @@
|
|||||||
(bottom-sheet/hide-bottom-sheet))))
|
(bottom-sheet/hide-bottom-sheet))))
|
||||||
|
|
||||||
(comment
|
(comment
|
||||||
(re-frame/dispatch [::save-profile-picture-from-url "https://lh3.googleusercontent.com/XuKjNm3HydsaxbPkbpGs9YyCKhn5QQk5oDC8XF2jzmPyYXeZofxFtfUDZuQ3EVmacS_BlBKzbX2ypm37YNX3n1fDJA3WndeFcPsp7Z0=w600"]))
|
(re-frame/dispatch
|
||||||
|
[::save-profile-picture-from-url
|
||||||
|
"https://lh3.googleusercontent.com/XuKjNm3HydsaxbPkbpGs9YyCKhn5QQk5oDC8XF2jzmPyYXeZofxFtfUDZuQ3EVmacS_BlBKzbX2ypm37YNX3n1fDJA3WndeFcPsp7Z0=w600"]))
|
||||||
|
|
||||||
(fx/defn delete-profile-picture
|
(rf/defn delete-profile-picture
|
||||||
{:events [::delete-profile-picture]}
|
{:events [::delete-profile-picture]}
|
||||||
[cofx name]
|
[cofx name]
|
||||||
(let [key-uid (get-in cofx [:db :multiaccount :key-uid])]
|
(let [key-uid (get-in cofx [:db :multiaccount :key-uid])]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{::json-rpc/call [{:method "multiaccounts_deleteIdentityImage"
|
{::json-rpc/call [{:method "multiaccounts_deleteIdentityImage"
|
||||||
:params [key-uid]
|
:params [key-uid]
|
||||||
;; NOTE: In case of an error we could fallback to previous image in UI with a toast error
|
;; NOTE: In case of an error we could fallback to previous image in UI
|
||||||
|
;; with a toast error
|
||||||
:on-success #(log/info "[multiaccount] Delete profile image" %)}]}
|
:on-success #(log/info "[multiaccount] Delete profile image" %)}]}
|
||||||
(multiaccounts.update/optimistic :images nil)
|
(multiaccounts.update/optimistic :images nil)
|
||||||
(bottom-sheet/hide-bottom-sheet))))
|
(bottom-sheet/hide-bottom-sheet))))
|
||||||
|
|
||||||
(fx/defn get-profile-picture
|
(rf/defn get-profile-picture
|
||||||
[cofx]
|
[cofx]
|
||||||
(let [key-uid (get-in cofx [:db :multiaccount :key-uid])]
|
(let [key-uid (get-in cofx [:db :multiaccount :key-uid])]
|
||||||
{::json-rpc/call [{:method "multiaccounts_getIdentityImages"
|
{::json-rpc/call [{:method "multiaccounts_getIdentityImages"
|
||||||
:params [key-uid]
|
:params [key-uid]
|
||||||
:on-success #(re-frame/dispatch [::update-local-picture %])}]}))
|
:on-success #(re-frame/dispatch [::update-local-picture %])}]}))
|
||||||
|
|
||||||
(fx/defn store-profile-picture
|
(rf/defn store-profile-picture
|
||||||
{:events [::update-local-picture]}
|
{:events [::update-local-picture]}
|
||||||
[cofx pics]
|
[cofx pics]
|
||||||
(multiaccounts.update/optimistic cofx :images pics))
|
(multiaccounts.update/optimistic cofx :images pics))
|
||||||
|
|
||||||
(comment
|
(comment
|
||||||
;; Test seed for Dim Venerated Yaffle, it's not here by mistake, this is just a test account
|
;; Test seed for Dim Venerated Yaffle, it's not here by mistake, this is just a test account
|
||||||
(native-module/validate-mnemonic "rocket mixed rebel affair umbrella legal resemble scene virus park deposit cargo" prn))
|
(native-module/validate-mnemonic
|
||||||
|
"rocket mixed rebel affair umbrella legal resemble scene virus park deposit cargo"
|
||||||
|
prn))
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
(ns status-im.multiaccounts.create.core
|
(ns status-im.multiaccounts.create.core
|
||||||
(:require [re-frame.core :as re-frame]
|
(:require [quo.design-system.colors :as colors]
|
||||||
|
[re-frame.core :as re-frame]
|
||||||
[status-im.constants :as constants]
|
[status-im.constants :as constants]
|
||||||
[status-im.data-store.settings :as data-store.settings]
|
[status-im.data-store.settings :as data-store.settings]
|
||||||
[status-im.ethereum.core :as ethereum]
|
[status-im.ethereum.core :as ethereum]
|
||||||
@@ -7,26 +8,27 @@
|
|||||||
[status-im.i18n.i18n :as i18n]
|
[status-im.i18n.i18n :as i18n]
|
||||||
[status-im.native-module.core :as status]
|
[status-im.native-module.core :as status]
|
||||||
[status-im.node.core :as node]
|
[status-im.node.core :as node]
|
||||||
[quo.design-system.colors :as colors]
|
|
||||||
[status-im.utils.config :as config]
|
[status-im.utils.config :as config]
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[utils.security.core :as security]
|
|
||||||
[status-im.utils.signing-phrase.core :as signing-phrase]
|
[status-im.utils.signing-phrase.core :as signing-phrase]
|
||||||
[status-im.utils.types :as types]))
|
[status-im.utils.types :as types]
|
||||||
|
[utils.re-frame :as rf]
|
||||||
|
[utils.security.core :as security]))
|
||||||
|
|
||||||
(defn normalize-derived-data-keys [derived-data]
|
(defn normalize-derived-data-keys
|
||||||
|
[derived-data]
|
||||||
(->> derived-data
|
(->> derived-data
|
||||||
(map (fn [[path {:keys [publicKey] :as data}]]
|
(map (fn [[path {:keys [publicKey] :as data}]]
|
||||||
[path (cond-> (-> data
|
[path
|
||||||
(dissoc :publicKey)
|
(cond-> (-> data
|
||||||
(assoc :public-key publicKey)))]))
|
(dissoc :publicKey)
|
||||||
|
(assoc :public-key publicKey)))]))
|
||||||
(into {})))
|
(into {})))
|
||||||
|
|
||||||
(defn normalize-multiaccount-data-keys
|
(defn normalize-multiaccount-data-keys
|
||||||
[{:keys [publicKey keyUid derived] :as data}]
|
[{:keys [publicKey keyUid derived] :as data}]
|
||||||
(cond-> (-> data
|
(cond-> (-> data
|
||||||
(dissoc :keyUid :publicKey)
|
(dissoc :keyUid :publicKey)
|
||||||
(assoc :key-uid keyUid
|
(assoc :key-uid keyUid
|
||||||
:public-key publicKey))
|
:public-key publicKey))
|
||||||
derived
|
derived
|
||||||
(update :derived normalize-derived-data-keys)))
|
(update :derived normalize-derived-data-keys)))
|
||||||
@@ -49,7 +51,7 @@
|
|||||||
hashed-password
|
hashed-password
|
||||||
callback)))
|
callback)))
|
||||||
|
|
||||||
(fx/defn create-multiaccount
|
(rf/defn create-multiaccount
|
||||||
{:events [:create-multiaccount]}
|
{:events [:create-multiaccount]}
|
||||||
[{:keys [db]} key-code]
|
[{:keys [db]} key-code]
|
||||||
(let [{:keys [selected-id]} (:intro-wizard db)]
|
(let [{:keys [selected-id]} (:intro-wizard db)]
|
||||||
@@ -63,14 +65,14 @@
|
|||||||
(ethereum/sha3 (security/safe-unmask-data key-code))
|
(ethereum/sha3 (security/safe-unmask-data key-code))
|
||||||
(fn [result]
|
(fn [result]
|
||||||
(let [derived-data (normalize-derived-data-keys (types/json->clj result))
|
(let [derived-data (normalize-derived-data-keys (types/json->clj result))
|
||||||
public-key (get-in derived-data [constants/path-whisper-keyword :public-key])]
|
public-key (get-in derived-data [constants/path-whisper-keyword :public-key])]
|
||||||
(status/gfycat-identicon-async
|
(status/gfycat-identicon-async
|
||||||
public-key
|
public-key
|
||||||
(fn [name identicon]
|
(fn [name identicon]
|
||||||
(let [derived-whisper (derived-data constants/path-whisper-keyword)
|
(let [derived-whisper (derived-data constants/path-whisper-keyword)
|
||||||
derived-data-extended (assoc-in derived-data
|
derived-data-extended (assoc-in derived-data
|
||||||
[constants/path-whisper-keyword]
|
[constants/path-whisper-keyword]
|
||||||
(merge derived-whisper {:name name :identicon identicon}))]
|
(merge derived-whisper {:name name :identicon identicon}))]
|
||||||
(re-frame/dispatch [::store-multiaccount-success key-code derived-data-extended]))))))]}))
|
(re-frame/dispatch [::store-multiaccount-success key-code derived-data-extended]))))))]}))
|
||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
@@ -86,32 +88,36 @@
|
|||||||
(mapv normalize-multiaccount-data-keys
|
(mapv normalize-multiaccount-data-keys
|
||||||
(types/json->clj %))]))))
|
(types/json->clj %))]))))
|
||||||
|
|
||||||
(fx/defn multiaccount-generate-and-derive-addresses-success
|
(rf/defn multiaccount-generate-and-derive-addresses-success
|
||||||
{:events [:multiaccount-generate-and-derive-addresses-success]}
|
{:events [:multiaccount-generate-and-derive-addresses-success]}
|
||||||
[{:keys [db]} result]
|
[{:keys [db]} result]
|
||||||
{:db (update db :intro-wizard
|
{:db (update db
|
||||||
(fn [data]
|
:intro-wizard
|
||||||
(-> data
|
(fn [data]
|
||||||
(dissoc :processing?)
|
(-> data
|
||||||
(assoc :multiaccounts result
|
(dissoc :processing?)
|
||||||
:selected-storage-type :default
|
(assoc :multiaccounts result
|
||||||
:selected-id (-> result first :id)
|
:selected-storage-type :default
|
||||||
:step :choose-key))))
|
:selected-id (-> result first :id)
|
||||||
|
:step :choose-key))))
|
||||||
:navigate-to-fx :choose-name})
|
:navigate-to-fx :choose-name})
|
||||||
|
|
||||||
(fx/defn generate-and-derive-addresses
|
(rf/defn generate-and-derive-addresses
|
||||||
{:events [:generate-and-derive-addresses]}
|
{:events [:generate-and-derive-addresses]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(update :intro-wizard #(-> % (assoc :processing? true) (dissoc :recovering?)))
|
(update :intro-wizard
|
||||||
(dissoc :recovered-account?))
|
#(-> %
|
||||||
|
(assoc :processing? true)
|
||||||
|
(dissoc :recovering?)))
|
||||||
|
(dissoc :recovered-account?))
|
||||||
:multiaccount-generate-and-derive-addresses nil})
|
:multiaccount-generate-and-derive-addresses nil})
|
||||||
|
|
||||||
(fx/defn prepare-intro-wizard
|
(rf/defn prepare-intro-wizard
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
{:db (assoc db :intro-wizard {})})
|
{:db (assoc db :intro-wizard {})})
|
||||||
|
|
||||||
(fx/defn save-multiaccount-and-login-with-keycard
|
(rf/defn save-multiaccount-and-login-with-keycard
|
||||||
[_ args]
|
[_ args]
|
||||||
{:keycard/save-multiaccount-and-login args})
|
{:keycard/save-multiaccount-and-login args})
|
||||||
|
|
||||||
@@ -126,7 +132,7 @@
|
|||||||
config
|
config
|
||||||
accounts-data)))
|
accounts-data)))
|
||||||
|
|
||||||
(fx/defn save-account-and-login
|
(rf/defn save-account-and-login
|
||||||
[_ key-uid multiaccount-data password settings node-config accounts-data]
|
[_ key-uid multiaccount-data password settings node-config accounts-data]
|
||||||
{::save-account-and-login [key-uid
|
{::save-account-and-login [key-uid
|
||||||
(types/clj->json multiaccount-data)
|
(types/clj->json multiaccount-data)
|
||||||
@@ -150,53 +156,57 @@
|
|||||||
{:public-key public-key
|
{:public-key public-key
|
||||||
:address (eip55/address->checksum address)
|
:address (eip55/address->checksum address)
|
||||||
:name name
|
:name name
|
||||||
:identicon identicon
|
:identicon identicon
|
||||||
:path constants/path-whisper
|
:path constants/path-whisper
|
||||||
:chat true})])
|
:chat true})])
|
||||||
|
|
||||||
(fx/defn on-multiaccount-created
|
(rf/defn on-multiaccount-created
|
||||||
[{:keys [signing-phrase random-guid-generator db] :as cofx}
|
[{:keys [signing-phrase random-guid-generator db] :as cofx}
|
||||||
{:keys [address chat-key keycard-instance-uid key-uid
|
{:keys [address chat-key keycard-instance-uid key-uid
|
||||||
keycard-pairing keycard-paired-on mnemonic recovered]
|
keycard-pairing keycard-paired-on mnemonic recovered]
|
||||||
:as multiaccount}
|
:as multiaccount}
|
||||||
password
|
password
|
||||||
{:keys [save-mnemonic? login?] :or {login? true save-mnemonic? false}}]
|
{:keys [save-mnemonic? login?] :or {login? true save-mnemonic? false}}]
|
||||||
(let [[wallet-account {:keys [public-key identicon name]} :as accounts-data] (prepare-accounts-data multiaccount)
|
(let [[wallet-account {:keys [public-key identicon name]} :as accounts-data] (prepare-accounts-data
|
||||||
multiaccount-data {:name name
|
multiaccount)
|
||||||
:address address
|
multiaccount-data {:name name
|
||||||
:identicon identicon
|
:address address
|
||||||
:key-uid key-uid
|
:identicon identicon
|
||||||
|
:key-uid key-uid
|
||||||
:keycard-pairing keycard-pairing}
|
:keycard-pairing keycard-pairing}
|
||||||
keycard-multiaccount? (boolean keycard-pairing)
|
keycard-multiaccount? (boolean keycard-pairing)
|
||||||
eip1581-address (get-in multiaccount [:derived
|
eip1581-address (get-in multiaccount
|
||||||
constants/path-eip1581-keyword
|
[:derived
|
||||||
:address])
|
constants/path-eip1581-keyword
|
||||||
|
:address])
|
||||||
new-multiaccount
|
new-multiaccount
|
||||||
(cond-> (merge
|
(cond->
|
||||||
{;; address of the master key
|
(merge
|
||||||
:address address
|
{;; address of the master key
|
||||||
;; sha256 of master public key
|
:address address
|
||||||
:key-uid key-uid
|
;; sha256 of master public key
|
||||||
;; The address from which we derive any wallet
|
:key-uid key-uid
|
||||||
:wallet-root-address
|
;; The address from which we derive any wallet
|
||||||
(get-in multiaccount [:derived
|
:wallet-root-address
|
||||||
constants/path-wallet-root-keyword
|
(get-in multiaccount
|
||||||
:address])
|
[:derived
|
||||||
:name name
|
constants/path-wallet-root-keyword
|
||||||
:identicon identicon
|
:address])
|
||||||
;; public key of the chat account
|
:name name
|
||||||
:public-key public-key
|
:identicon identicon
|
||||||
;; default address for Dapps
|
;; public key of the chat account
|
||||||
:dapps-address (:address wallet-account)
|
:public-key public-key
|
||||||
:latest-derived-path 0
|
;; default address for Dapps
|
||||||
:signing-phrase signing-phrase
|
:dapps-address (:address wallet-account)
|
||||||
:send-push-notifications? true
|
:latest-derived-path 0
|
||||||
:backup-enabled? true
|
:signing-phrase signing-phrase
|
||||||
:installation-id (random-guid-generator)
|
:send-push-notifications? true
|
||||||
;; default mailserver (history node) setting
|
:backup-enabled? true
|
||||||
:use-mailservers? true
|
:installation-id (random-guid-generator)
|
||||||
:recovered recovered}
|
;; default mailserver (history node) setting
|
||||||
config/default-multiaccount)
|
:use-mailservers? true
|
||||||
|
:recovered recovered}
|
||||||
|
config/default-multiaccount)
|
||||||
;; The address from which we derive any chat
|
;; The address from which we derive any chat
|
||||||
;; account/encryption keys
|
;; account/encryption keys
|
||||||
eip1581-address
|
eip1581-address
|
||||||
@@ -205,23 +215,23 @@
|
|||||||
(assoc :mnemonic mnemonic)
|
(assoc :mnemonic mnemonic)
|
||||||
keycard-multiaccount?
|
keycard-multiaccount?
|
||||||
(assoc :keycard-instance-uid keycard-instance-uid
|
(assoc :keycard-instance-uid keycard-instance-uid
|
||||||
:keycard-pairing keycard-pairing
|
:keycard-pairing keycard-pairing
|
||||||
:keycard-paired-on keycard-paired-on))
|
:keycard-paired-on keycard-paired-on))
|
||||||
db (assoc db
|
db (assoc db
|
||||||
:multiaccounts/login {:key-uid key-uid
|
:multiaccounts/login {:key-uid key-uid
|
||||||
:name name
|
:name name
|
||||||
:identicon identicon
|
:identicon identicon
|
||||||
:password password
|
:password password
|
||||||
:creating? true
|
:creating? true
|
||||||
:processing true}
|
:processing true}
|
||||||
:multiaccount new-multiaccount
|
:multiaccount new-multiaccount
|
||||||
:multiaccount/accounts [wallet-account]
|
:multiaccount/accounts [wallet-account]
|
||||||
:networks/current-network config/default-network
|
:networks/current-network config/default-network
|
||||||
:networks/networks (data-store.settings/rpc->networks config/default-networks))
|
:networks/networks (data-store.settings/rpc->networks config/default-networks))
|
||||||
settings (assoc new-multiaccount
|
settings (assoc new-multiaccount
|
||||||
:networks/current-network config/default-network
|
:networks/current-network config/default-network
|
||||||
:networks/networks config/default-networks)]
|
:networks/networks config/default-networks)]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db db}
|
{:db db}
|
||||||
(if keycard-multiaccount?
|
(if keycard-multiaccount?
|
||||||
(save-multiaccount-and-login-with-keycard
|
(save-multiaccount-and-login-with-keycard
|
||||||
@@ -240,26 +250,26 @@
|
|||||||
(node/get-new-config db)
|
(node/get-new-config db)
|
||||||
accounts-data)))))
|
accounts-data)))))
|
||||||
|
|
||||||
(fx/defn store-multiaccount-success
|
(rf/defn store-multiaccount-success
|
||||||
{:events [::store-multiaccount-success]
|
{:events [::store-multiaccount-success]
|
||||||
:interceptors [(re-frame/inject-cofx :random-guid-generator)
|
:interceptors [(re-frame/inject-cofx :random-guid-generator)
|
||||||
(re-frame/inject-cofx ::get-signing-phrase)]}
|
(re-frame/inject-cofx ::get-signing-phrase)]}
|
||||||
[{:keys [db] :as cofx} password derived]
|
[{:keys [db] :as cofx} password derived]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (dissoc db :intro-wizard)}
|
{:db (dissoc db :intro-wizard)}
|
||||||
(on-multiaccount-created (assoc (let [{:keys [selected-id multiaccounts]} (:intro-wizard db)]
|
(on-multiaccount-created (assoc (let [{:keys [selected-id multiaccounts]} (:intro-wizard db)]
|
||||||
(some #(when (= selected-id (:id %)) %) multiaccounts))
|
(some #(when (= selected-id (:id %)) %) multiaccounts))
|
||||||
:derived derived
|
:derived derived
|
||||||
:recovered (get-in db [:intro-wizard :recovering?]))
|
:recovered (get-in db [:intro-wizard :recovering?]))
|
||||||
password
|
password
|
||||||
{:save-mnemonic? true})))
|
{:save-mnemonic? true})))
|
||||||
|
|
||||||
(fx/defn on-key-selected
|
(rf/defn on-key-selected
|
||||||
{:events [:intro-wizard/on-key-selected]}
|
{:events [:intro-wizard/on-key-selected]}
|
||||||
[{:keys [db]} id]
|
[{:keys [db]} id]
|
||||||
{:db (assoc-in db [:intro-wizard :selected-id] id)})
|
{:db (assoc-in db [:intro-wizard :selected-id] id)})
|
||||||
|
|
||||||
(fx/defn on-key-storage-selected
|
(rf/defn on-key-storage-selected
|
||||||
{:events [:intro-wizard/on-key-storage-selected]}
|
{:events [:intro-wizard/on-key-storage-selected]}
|
||||||
[{:keys [db]} storage-type]
|
[{:keys [db]} storage-type]
|
||||||
{:db (assoc-in db [:intro-wizard :selected-storage-type] storage-type)})
|
{:db (assoc-in db [:intro-wizard :selected-storage-type] storage-type)})
|
||||||
|
|||||||
@@ -1,24 +1,24 @@
|
|||||||
(ns status-im.multiaccounts.key-storage.core
|
(ns status-im.multiaccounts.key-storage.core
|
||||||
(:require [clojure.string :as string]
|
(:require [clojure.string :as string]
|
||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
|
[status-im.bottom-sheet.core :as bottom-sheet]
|
||||||
|
[status-im.ethereum.core :as ethereum]
|
||||||
[status-im.ethereum.mnemonic :as mnemonic]
|
[status-im.ethereum.mnemonic :as mnemonic]
|
||||||
|
[status-im.i18n.i18n :as i18n]
|
||||||
|
[status-im.keycard.backup-key :as keycard.backup]
|
||||||
[status-im.keycard.common :as common]
|
[status-im.keycard.common :as common]
|
||||||
[status-im.multiaccounts.core :as multiaccounts]
|
[status-im.multiaccounts.core :as multiaccounts]
|
||||||
[status-im.multiaccounts.recover.core :as multiaccounts.recover]
|
|
||||||
[status-im.multiaccounts.model :as multiaccounts.model]
|
|
||||||
[status-im.multiaccounts.logout.core :as multiaccounts.logout]
|
[status-im.multiaccounts.logout.core :as multiaccounts.logout]
|
||||||
|
[status-im.multiaccounts.model :as multiaccounts.model]
|
||||||
|
[status-im.multiaccounts.recover.core :as multiaccounts.recover]
|
||||||
[status-im.native-module.core :as native-module]
|
[status-im.native-module.core :as native-module]
|
||||||
[status-im2.navigation.events :as navigation]
|
|
||||||
[status-im.popover.core :as popover]
|
[status-im.popover.core :as popover]
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[utils.security.core :as security]
|
|
||||||
[status-im.ethereum.core :as ethereum]
|
|
||||||
[status-im.i18n.i18n :as i18n]
|
|
||||||
[status-im.utils.types :as types]
|
[status-im.utils.types :as types]
|
||||||
[status-im.keycard.backup-key :as keycard.backup]
|
[status-im2.navigation.events :as navigation]
|
||||||
[status-im.bottom-sheet.core :as bottom-sheet]))
|
[utils.re-frame :as rf]
|
||||||
|
[utils.security.core :as security]))
|
||||||
|
|
||||||
(fx/defn key-and-storage-management-pressed
|
(rf/defn key-and-storage-management-pressed
|
||||||
"This event can be dispatched before login and from profile and needs to redirect accordingly"
|
"This event can be dispatched before login and from profile and needs to redirect accordingly"
|
||||||
{:events [::key-and-storage-management-pressed]}
|
{:events [::key-and-storage-management-pressed]}
|
||||||
[cofx]
|
[cofx]
|
||||||
@@ -29,52 +29,57 @@
|
|||||||
:actions-not-logged-in)
|
:actions-not-logged-in)
|
||||||
nil))
|
nil))
|
||||||
|
|
||||||
(fx/defn move-keystore-checked
|
(rf/defn move-keystore-checked
|
||||||
{:events [::move-keystore-checked]}
|
{:events [::move-keystore-checked]}
|
||||||
[{:keys [db] :as cofx} checked?]
|
[{:keys [db] :as cofx} checked?]
|
||||||
{:db (assoc-in db [:multiaccounts/key-storage :move-keystore-checked?] checked?)})
|
{:db (assoc-in db [:multiaccounts/key-storage :move-keystore-checked?] checked?)})
|
||||||
|
|
||||||
(fx/defn reset-db-checked
|
(rf/defn reset-db-checked
|
||||||
{:events [::reset-db-checked]}
|
{:events [::reset-db-checked]}
|
||||||
[{:keys [db] :as cofx} checked?]
|
[{:keys [db] :as cofx} checked?]
|
||||||
{:db (assoc-in db [:multiaccounts/key-storage :reset-db-checked?] checked?)})
|
{:db (assoc-in db [:multiaccounts/key-storage :reset-db-checked?] checked?)})
|
||||||
|
|
||||||
(fx/defn navigate-back
|
(rf/defn navigate-back
|
||||||
{:events [::navigate-back]}
|
{:events [::navigate-back]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(dissoc :recovered-account?)
|
(dissoc :recovered-account?)
|
||||||
(update :keycard dissoc :from-key-storage-and-migration? :creating-backup? :factory-reset-card?))}
|
(update :keycard
|
||||||
|
dissoc
|
||||||
|
:from-key-storage-and-migration?
|
||||||
|
:creating-backup?
|
||||||
|
:factory-reset-card?))}
|
||||||
(navigation/navigate-back)))
|
(navigation/navigate-back)))
|
||||||
|
|
||||||
(fx/defn enter-seed-pressed
|
(rf/defn enter-seed-pressed
|
||||||
"User is logged out and probably wants to move multiaccount to Keycard. Navigate to enter seed phrase screen"
|
"User is logged out and probably wants to move multiaccount to Keycard. Navigate to enter seed phrase screen"
|
||||||
{:events [::enter-seed-pressed]}
|
{:events [::enter-seed-pressed]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (assoc db :recovered-account? true)}
|
{:db (assoc db :recovered-account? true)}
|
||||||
(navigation/navigate-to-cofx :seed-phrase nil)))
|
(navigation/navigate-to-cofx :seed-phrase nil)))
|
||||||
|
|
||||||
(fx/defn seed-phrase-input-changed
|
(rf/defn seed-phrase-input-changed
|
||||||
{:events [::seed-phrase-input-changed]}
|
{:events [::seed-phrase-input-changed]}
|
||||||
[{:keys [db] :as cofx} masked-seed-phrase]
|
[{:keys [db] :as cofx} masked-seed-phrase]
|
||||||
(let [seed-phrase (security/safe-unmask-data masked-seed-phrase)]
|
(let [seed-phrase (security/safe-unmask-data masked-seed-phrase)]
|
||||||
{:db (update db :multiaccounts/key-storage assoc
|
{:db (update db
|
||||||
:seed-phrase (when seed-phrase
|
:multiaccounts/key-storage assoc
|
||||||
(string/lower-case seed-phrase))
|
:seed-phrase (when seed-phrase
|
||||||
:seed-shape-invalid? (or (empty? seed-phrase)
|
(string/lower-case seed-phrase))
|
||||||
(not (mnemonic/valid-length? seed-phrase)))
|
:seed-shape-invalid? (or (empty? seed-phrase)
|
||||||
:seed-word-count (mnemonic/words-count seed-phrase))}))
|
(not (mnemonic/valid-length? seed-phrase)))
|
||||||
|
:seed-word-count (mnemonic/words-count seed-phrase))}))
|
||||||
|
|
||||||
(fx/defn key-uid-seed-mismatch
|
(rf/defn key-uid-seed-mismatch
|
||||||
{:events [::show-seed-key-uid-mismatch-error-popup]}
|
{:events [::show-seed-key-uid-mismatch-error-popup]}
|
||||||
[cofx _]
|
[cofx _]
|
||||||
(popover/show-popover cofx {:view :seed-key-uid-mismatch}))
|
(popover/show-popover cofx {:view :seed-key-uid-mismatch}))
|
||||||
|
|
||||||
(fx/defn key-uid-matches
|
(rf/defn key-uid-matches
|
||||||
{:events [::key-uid-matches]}
|
{:events [::key-uid-matches]}
|
||||||
[{:keys [db] :as cofx} _]
|
[{:keys [db] :as cofx} _]
|
||||||
(let [backup? (get-in db [:keycard :creating-backup?])]
|
(let [backup? (get-in db [:keycard :creating-backup?])]
|
||||||
@@ -100,27 +105,32 @@
|
|||||||
::validate-seed-against-key-uid
|
::validate-seed-against-key-uid
|
||||||
(partial validate-seed-against-key-uid
|
(partial validate-seed-against-key-uid
|
||||||
{:import-mnemonic-fn native-module/multiaccount-import-mnemonic
|
{:import-mnemonic-fn native-module/multiaccount-import-mnemonic
|
||||||
:on-success #(re-frame/dispatch [::key-uid-matches])
|
:on-success #(re-frame/dispatch [::key-uid-matches])
|
||||||
:on-error #(re-frame/dispatch [::show-seed-key-uid-mismatch-error-popup])}))
|
:on-error #(re-frame/dispatch [::show-seed-key-uid-mismatch-error-popup])}))
|
||||||
|
|
||||||
(fx/defn seed-phrase-validated
|
(rf/defn seed-phrase-validated
|
||||||
{:events [::seed-phrase-validated]}
|
{:events [::seed-phrase-validated]}
|
||||||
[{:keys [db] :as cofx} validation-error]
|
[{:keys [db] :as cofx} validation-error]
|
||||||
(let [error? (-> validation-error
|
(let [error? (-> validation-error
|
||||||
types/json->clj
|
types/json->clj
|
||||||
:error
|
:error
|
||||||
string/blank?
|
string/blank?
|
||||||
not)
|
not)
|
||||||
onboarding? (not (or (:multiaccounts/login db) (:multiaccount db)))]
|
onboarding? (not (or (:multiaccounts/login db) (:multiaccount db)))]
|
||||||
(if error?
|
(if error?
|
||||||
(popover/show-popover cofx {:view :custom-seed-phrase})
|
(popover/show-popover cofx {:view :custom-seed-phrase})
|
||||||
{::validate-seed-against-key-uid {:seed-phrase (-> db :multiaccounts/key-storage :seed-phrase)
|
{::validate-seed-against-key-uid {:seed-phrase (-> db :multiaccounts/key-storage :seed-phrase)
|
||||||
;; Unique key-uid of the account for which we are going to move keys
|
;; Unique key-uid of the account for which we are going to move
|
||||||
:key-uid (or (-> db :multiaccounts/login :key-uid)
|
;; keys
|
||||||
(-> db :multiaccount :key-uid)
|
:key-uid (or (-> db :multiaccounts/login :key-uid)
|
||||||
(and onboarding? (-> db :keycard :application-info :key-uid)))}})))
|
(-> db :multiaccount :key-uid)
|
||||||
|
(and onboarding?
|
||||||
|
(-> db
|
||||||
|
:keycard
|
||||||
|
:application-info
|
||||||
|
:key-uid)))}})))
|
||||||
|
|
||||||
(fx/defn choose-storage-pressed
|
(rf/defn choose-storage-pressed
|
||||||
{:events [::choose-storage-pressed]}
|
{:events [::choose-storage-pressed]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [{:keys [seed-phrase]} (:multiaccounts/key-storage db)]
|
(let [{:keys [seed-phrase]} (:multiaccounts/key-storage db)]
|
||||||
@@ -128,7 +138,7 @@
|
|||||||
[(mnemonic/sanitize-passphrase seed-phrase)
|
[(mnemonic/sanitize-passphrase seed-phrase)
|
||||||
#(re-frame/dispatch [::seed-phrase-validated %])]}))
|
#(re-frame/dispatch [::seed-phrase-validated %])]}))
|
||||||
|
|
||||||
(fx/defn keycard-storage-pressed
|
(rf/defn keycard-storage-pressed
|
||||||
{:events [::keycard-storage-pressed]}
|
{:events [::keycard-storage-pressed]}
|
||||||
[{:keys [db]} selected?]
|
[{:keys [db]} selected?]
|
||||||
{:db (assoc-in db [:multiaccounts/key-storage :keycard-storage-selected?] selected?)})
|
{:db (assoc-in db [:multiaccounts/key-storage :keycard-storage-selected?] selected?)})
|
||||||
@@ -161,55 +171,56 @@ The exact events dispatched for this flow if consumed from the UI are:
|
|||||||
|
|
||||||
We don't need to take the exact steps, just set the required state and redirect to correct screen
|
We don't need to take the exact steps, just set the required state and redirect to correct screen
|
||||||
"
|
"
|
||||||
(fx/defn import-multiaccount
|
(rf/defn import-multiaccount
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
{:dispatch [:bottom-sheet/hide]
|
{:dispatch [:bottom-sheet/hide]
|
||||||
::multiaccounts.recover/import-multiaccount
|
::multiaccounts.recover/import-multiaccount
|
||||||
{:passphrase (get-in db [:multiaccounts/key-storage :seed-phrase])
|
{:passphrase (get-in db [:multiaccounts/key-storage :seed-phrase])
|
||||||
:password nil
|
:password nil
|
||||||
:success-event ::import-multiaccount-success}})
|
:success-event ::import-multiaccount-success}})
|
||||||
|
|
||||||
(fx/defn delete-multiaccount-and-init-keycard-onboarding
|
(rf/defn delete-multiaccount-and-init-keycard-onboarding
|
||||||
{:events [::delete-multiaccount-and-init-keycard-onboarding]}
|
{:events [::delete-multiaccount-and-init-keycard-onboarding]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
{:dispatch [:bottom-sheet/hide]
|
{:dispatch [:bottom-sheet/hide]
|
||||||
:db (assoc-in db [:multiaccounts/key-storage :reset-db-checked?] true)}
|
:db (assoc-in db [:multiaccounts/key-storage :reset-db-checked?] true)}
|
||||||
(import-multiaccount)))
|
(import-multiaccount)))
|
||||||
|
|
||||||
(fx/defn storage-selected
|
(rf/defn storage-selected
|
||||||
{:events [::storage-selected]}
|
{:events [::storage-selected]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(if (get-in db [:multiaccounts/key-storage :reset-db-checked?])
|
(if (get-in db [:multiaccounts/key-storage :reset-db-checked?])
|
||||||
(popover/show-popover cofx {:view :transfer-multiaccount-to-keycard-warning})
|
(popover/show-popover cofx {:view :transfer-multiaccount-to-keycard-warning})
|
||||||
(bottom-sheet/show-bottom-sheet cofx {:view :migrate-account-password})))
|
(bottom-sheet/show-bottom-sheet cofx {:view :migrate-account-password})))
|
||||||
|
|
||||||
(fx/defn skip-password-pressed
|
(rf/defn skip-password-pressed
|
||||||
{:events [::skip-password-pressed]}
|
{:events [::skip-password-pressed]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(popover/show-popover cofx {:view :transfer-multiaccount-to-keycard-warning}))
|
(popover/show-popover cofx {:view :transfer-multiaccount-to-keycard-warning}))
|
||||||
|
|
||||||
(fx/defn password-changed
|
(rf/defn password-changed
|
||||||
{:events [::password-changed]}
|
{:events [::password-changed]}
|
||||||
[{db :db} password]
|
[{db :db} password]
|
||||||
(let [unmasked-pass (security/safe-unmask-data password)]
|
(let [unmasked-pass (security/safe-unmask-data password)]
|
||||||
{:db (update db :keycard assoc
|
{:db (update db
|
||||||
:migration-password password
|
:keycard assoc
|
||||||
:migration-password-error nil
|
:migration-password password
|
||||||
|
:migration-password-error nil
|
||||||
:migration-password-valid? (and unmasked-pass (> (count unmasked-pass) 5)))}))
|
:migration-password-valid? (and unmasked-pass (> (count unmasked-pass) 5)))}))
|
||||||
|
|
||||||
(fx/defn verify-password-result
|
(rf/defn verify-password-result
|
||||||
{:events [::verify-password-result]}
|
{:events [::verify-password-result]}
|
||||||
[{:keys [db] :as cofx} result]
|
[{:keys [db] :as cofx} result]
|
||||||
(let [{:keys [error]} (types/json->clj result)]
|
(let [{:keys [error]} (types/json->clj result)]
|
||||||
(if (string/blank? error)
|
(if (string/blank? error)
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (update db :keycard dissoc :migration-password-error :migration-password-valid?)}
|
{:db (update db :keycard dissoc :migration-password-error :migration-password-valid?)}
|
||||||
(import-multiaccount))
|
(import-multiaccount))
|
||||||
{:db (assoc-in db [:keycard :migration-password-error] (i18n/label :t/wrong-password))})))
|
{:db (assoc-in db [:keycard :migration-password-error] (i18n/label :t/wrong-password))})))
|
||||||
|
|
||||||
(fx/defn verify-password
|
(rf/defn verify-password
|
||||||
{:events [::verify-password]}
|
{:events [::verify-password]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(native-module/verify-database-password
|
(native-module/verify-database-password
|
||||||
@@ -217,42 +228,43 @@ We don't need to take the exact steps, just set the required state and redirect
|
|||||||
(ethereum/sha3 (security/safe-unmask-data (get-in db [:keycard :migration-password])))
|
(ethereum/sha3 (security/safe-unmask-data (get-in db [:keycard :migration-password])))
|
||||||
#(re-frame/dispatch [::verify-password-result %])))
|
#(re-frame/dispatch [::verify-password-result %])))
|
||||||
|
|
||||||
(fx/defn handle-multiaccount-import
|
(rf/defn handle-multiaccount-import
|
||||||
{:events [::import-multiaccount-success]}
|
{:events [::import-multiaccount-success]}
|
||||||
[{:keys [db] :as cofx} root-data derived-data]
|
[{:keys [db] :as cofx} root-data derived-data]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(update :intro-wizard
|
(update :intro-wizard
|
||||||
assoc
|
assoc
|
||||||
:root-key root-data
|
:root-key root-data
|
||||||
:derived derived-data
|
:derived derived-data
|
||||||
:recovering? true
|
:recovering? true
|
||||||
:selected-storage-type :advanced)
|
:selected-storage-type :advanced)
|
||||||
(assoc-in [:keycard :flow] :recovery)
|
(assoc-in [:keycard :flow] :recovery)
|
||||||
(assoc-in [:keycard :from-key-storage-and-migration?] true)
|
(assoc-in [:keycard :from-key-storage-and-migration?] true)
|
||||||
(assoc-in [:keycard :converting-account?] (not (get-in db [:multiaccounts/key-storage :reset-db-checked?])))
|
(assoc-in [:keycard :converting-account?]
|
||||||
(assoc-in [:keycard :delete-account?]
|
(not (get-in db [:multiaccounts/key-storage :reset-db-checked?])))
|
||||||
(true? (get-in db [:multiaccounts/key-storage :reset-db-checked?])))
|
(assoc-in [:keycard :delete-account?]
|
||||||
(dissoc :multiaccounts/key-storage))}
|
(true? (get-in db [:multiaccounts/key-storage :reset-db-checked?])))
|
||||||
|
(dissoc :multiaccounts/key-storage))}
|
||||||
(popover/hide-popover)
|
(popover/hide-popover)
|
||||||
(common/listen-to-hardware-back-button)
|
(common/listen-to-hardware-back-button)
|
||||||
(navigation/navigate-to-cofx :keycard-onboarding-intro nil)))
|
(navigation/navigate-to-cofx :keycard-onboarding-intro nil)))
|
||||||
|
|
||||||
(fx/defn goto-multiaccounts-screen
|
(rf/defn goto-multiaccounts-screen
|
||||||
{:events [::hide-popover-and-goto-multiaccounts-screen]}
|
{:events [::hide-popover-and-goto-multiaccounts-screen]}
|
||||||
[cofx _]
|
[cofx _]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(popover/hide-popover)
|
(popover/hide-popover)
|
||||||
(navigation/navigate-to-cofx :multiaccounts nil)))
|
(navigation/navigate-to-cofx :multiaccounts nil)))
|
||||||
|
|
||||||
(fx/defn confirm-logout-and-goto-key-storage
|
(rf/defn confirm-logout-and-goto-key-storage
|
||||||
{:events [::confirm-logout-and-goto-key-storage]}
|
{:events [::confirm-logout-and-goto-key-storage]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc db :goto-key-storage? true)}
|
{:db (assoc db :goto-key-storage? true)}
|
||||||
(multiaccounts.logout/logout)))
|
(multiaccounts.logout/logout)))
|
||||||
|
|
||||||
(fx/defn logout-and-goto-key-storage
|
(rf/defn logout-and-goto-key-storage
|
||||||
{:events [::logout-and-goto-key-storage]}
|
{:events [::logout-and-goto-key-storage]}
|
||||||
[_]
|
[_]
|
||||||
{:ui/show-confirmation
|
{:ui/show-confirmation
|
||||||
@@ -264,9 +276,11 @@ We don't need to take the exact steps, just set the required state and redirect
|
|||||||
|
|
||||||
(comment
|
(comment
|
||||||
;; check import mnemonic output
|
;; check import mnemonic output
|
||||||
(native-module/multiaccount-import-mnemonic "rocket mixed rebel affair umbrella legal resemble scene virus park deposit cargo" nil
|
(native-module/multiaccount-import-mnemonic
|
||||||
(fn [result]
|
"rocket mixed rebel affair umbrella legal resemble scene virus park deposit cargo"
|
||||||
(prn (types/json->clj result))))
|
nil
|
||||||
|
(fn [result]
|
||||||
|
(prn (types/json->clj result))))
|
||||||
;; check delete account output
|
;; check delete account output
|
||||||
(native-module/delete-multiaccount "0x3831d0f22996a65970a214f0a94bfa9a63a21dac235d8dadb91be8e32e7d3ab7"
|
(native-module/delete-multiaccount "0x3831d0f22996a65970a214f0a94bfa9a63a21dac235d8dadb91be8e32e7d3ab7"
|
||||||
(fn [result]
|
(fn [result]
|
||||||
|
|||||||
@@ -1,48 +1,48 @@
|
|||||||
(ns status-im.multiaccounts.login.core
|
(ns status-im.multiaccounts.login.core
|
||||||
(:require [re-frame.core :as re-frame]
|
(:require [clojure.string :as string]
|
||||||
|
[re-frame.core :as re-frame]
|
||||||
|
[status-im.async-storage.core :as async-storage]
|
||||||
|
[status-im.chat.models.link-preview :as link-preview]
|
||||||
|
[status-im.communities.core :as communities]
|
||||||
[status-im.contact.core :as contact]
|
[status-im.contact.core :as contact]
|
||||||
[status-im.utils.config :as config]
|
[status-im.data-store.chats :as data-store.chats]
|
||||||
|
[status-im.data-store.invitations :as data-store.invitations]
|
||||||
[status-im.data-store.settings :as data-store.settings]
|
[status-im.data-store.settings :as data-store.settings]
|
||||||
|
[status-im.data-store.visibility-status-updates :as visibility-status-updates-store]
|
||||||
[status-im.ethereum.core :as ethereum]
|
[status-im.ethereum.core :as ethereum]
|
||||||
[status-im.ethereum.transactions.core :as transactions]
|
|
||||||
[status-im.ethereum.eip55 :as eip55]
|
[status-im.ethereum.eip55 :as eip55]
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
[status-im.keycard.common :as keycard.common]
|
[status-im.ethereum.tokens :as tokens]
|
||||||
|
[status-im.ethereum.transactions.core :as transactions]
|
||||||
[status-im.fleet.core :as fleet]
|
[status-im.fleet.core :as fleet]
|
||||||
[status-im.i18n.i18n :as i18n]
|
[status-im.i18n.i18n :as i18n]
|
||||||
|
[status-im.keycard.common :as keycard.common]
|
||||||
|
[status-im.mobile-sync-settings.core :as mobile-network]
|
||||||
[status-im.multiaccounts.biometric.core :as biometric]
|
[status-im.multiaccounts.biometric.core :as biometric]
|
||||||
[status-im.multiaccounts.core :as multiaccounts]
|
[status-im.multiaccounts.core :as multiaccounts]
|
||||||
[status-im.native-module.core :as status]
|
[status-im.native-module.core :as status]
|
||||||
|
[status-im.node.core :as node]
|
||||||
[status-im.notifications.core :as notifications]
|
[status-im.notifications.core :as notifications]
|
||||||
[status-im.popover.core :as popover]
|
[status-im.popover.core :as popover]
|
||||||
[status-im.communities.core :as communities]
|
[status-im.signing.eip1559 :as eip1559]
|
||||||
[status-im.transport.core :as transport]
|
[status-im.transport.core :as transport]
|
||||||
[status-im.mobile-sync-settings.core :as mobile-network]
|
[status-im.ui.components.react :as react]
|
||||||
[status-im.utils.fx :as fx]
|
[status-im.utils.config :as config]
|
||||||
[status-im.utils.keychain.core :as keychain]
|
[status-im.utils.keychain.core :as keychain]
|
||||||
[status-im2.setup.log :as logging]
|
[status-im.utils.mobile-sync :as utils.mobile-sync]
|
||||||
[utils.security.core :as security]
|
[status-im.utils.platform :as platform]
|
||||||
[status-im.utils.types :as types]
|
[status-im.utils.types :as types]
|
||||||
[status-im.utils.utils :as utils]
|
[status-im.utils.utils :as utils]
|
||||||
[status-im.wallet.core :as wallet]
|
[status-im.utils.wallet-connect :as wallet-connect]
|
||||||
[status-im.wallet-connect-legacy.core :as wallet-connect-legacy]
|
[status-im.wallet-connect-legacy.core :as wallet-connect-legacy]
|
||||||
|
[status-im.wallet.core :as wallet]
|
||||||
[status-im.wallet.prices :as prices]
|
[status-im.wallet.prices :as prices]
|
||||||
[taoensso.timbre :as log]
|
|
||||||
[status-im.data-store.invitations :as data-store.invitations]
|
|
||||||
[status-im.chat.models.link-preview :as link-preview]
|
|
||||||
[status-im.utils.mobile-sync :as utils.mobile-sync]
|
|
||||||
[status-im.async-storage.core :as async-storage]
|
|
||||||
[status-im2.contexts.activity-center.events :as activity-center]
|
[status-im2.contexts.activity-center.events :as activity-center]
|
||||||
[status-im2.navigation.events :as navigation]
|
[status-im2.navigation.events :as navigation]
|
||||||
[status-im.signing.eip1559 :as eip1559]
|
[status-im2.setup.log :as logging]
|
||||||
[status-im.data-store.chats :as data-store.chats]
|
[taoensso.timbre :as log]
|
||||||
[status-im.data-store.visibility-status-updates :as visibility-status-updates-store]
|
[utils.re-frame :as rf]
|
||||||
[status-im.ui.components.react :as react]
|
[utils.security.core :as security]))
|
||||||
[status-im.utils.platform :as platform]
|
|
||||||
[status-im.ethereum.tokens :as tokens]
|
|
||||||
[clojure.string :as string]
|
|
||||||
[status-im.utils.wallet-connect :as wallet-connect]
|
|
||||||
[status-im.node.core :as node]))
|
|
||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
::initialize-communities-enabled
|
::initialize-communities-enabled
|
||||||
@@ -89,11 +89,13 @@
|
|||||||
#(re-frame/dispatch [:wallet-connect/client-init %])
|
#(re-frame/dispatch [:wallet-connect/client-init %])
|
||||||
#(log/error "[wallet-connect]" %))))
|
#(log/error "[wallet-connect]" %))))
|
||||||
|
|
||||||
(defn rpc->accounts [accounts]
|
(defn rpc->accounts
|
||||||
|
[accounts]
|
||||||
(reduce (fn [acc {:keys [chat type wallet] :as account}]
|
(reduce (fn [acc {:keys [chat type wallet] :as account}]
|
||||||
(if chat
|
(if chat
|
||||||
acc
|
acc
|
||||||
(let [account (cond-> (update account :address
|
(let [account (cond-> (update account
|
||||||
|
:address
|
||||||
eip55/address->checksum)
|
eip55/address->checksum)
|
||||||
type
|
type
|
||||||
(update :type keyword))]
|
(update :type keyword))]
|
||||||
@@ -119,25 +121,28 @@
|
|||||||
"0x86a12d91c813f69a53349ff640e32af97d5f5c1f8d42d54cf4c8aa8dea231955"
|
"0x86a12d91c813f69a53349ff640e32af97d5f5c1f8d42d54cf4c8aa8dea231955"
|
||||||
"0x0011a30f5b2023bc228f6dd5608b3e7149646fa83f33350926ceb1925af78f08"})
|
"0x0011a30f5b2023bc228f6dd5608b3e7149646fa83f33350926ceb1925af78f08"})
|
||||||
|
|
||||||
(fx/defn check-invalid-ens [{:keys [db]}]
|
(rf/defn check-invalid-ens
|
||||||
|
[{:keys [db]}]
|
||||||
(async-storage/get-item
|
(async-storage/get-item
|
||||||
:invalid-ens-name-seen
|
:invalid-ens-name-seen
|
||||||
(fn [already-seen]
|
(fn [already-seen]
|
||||||
(when (and (not already-seen)
|
(when (and (not already-seen)
|
||||||
(boolean (get invalid-addrr (ethereum/sha3 (string/lower-case (ethereum/default-address db))))))
|
(boolean (get invalid-addrr
|
||||||
|
(ethereum/sha3 (string/lower-case (ethereum/default-address db))))))
|
||||||
(utils/show-popup
|
(utils/show-popup
|
||||||
(i18n/label :t/warning)
|
(i18n/label :t/warning)
|
||||||
(i18n/label :t/ens-username-invalid-name-warning)
|
(i18n/label :t/ens-username-invalid-name-warning)
|
||||||
#(async-storage/set-item! :invalid-ens-name-seen true)))))
|
#(async-storage/set-item! :invalid-ens-name-seen true)))))
|
||||||
nil)
|
nil)
|
||||||
|
|
||||||
(fx/defn initialize-wallet
|
(rf/defn initialize-wallet
|
||||||
{:events [::initialize-wallet]}
|
{:events [::initialize-wallet]}
|
||||||
[{:keys [db] :as cofx} accounts tokens custom-tokens
|
[{:keys [db] :as cofx} accounts tokens custom-tokens
|
||||||
favourites scan-all-tokens? new-account?]
|
favourites scan-all-tokens? new-account?]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (assoc db :multiaccount/accounts
|
{:db (assoc db
|
||||||
|
:multiaccount/accounts
|
||||||
(rpc->accounts accounts))
|
(rpc->accounts accounts))
|
||||||
;; NOTE: Local notifications should be enabled only after wallet was started
|
;; NOTE: Local notifications should be enabled only after wallet was started
|
||||||
::enable-local-notifications nil}
|
::enable-local-notifications nil}
|
||||||
@@ -146,16 +151,18 @@
|
|||||||
(wallet/initialize-favourites favourites)
|
(wallet/initialize-favourites favourites)
|
||||||
(wallet/get-pending-transactions)
|
(wallet/get-pending-transactions)
|
||||||
(wallet/fetch-collectibles-collection)
|
(wallet/fetch-collectibles-collection)
|
||||||
(cond (and new-account?
|
(cond
|
||||||
(not scan-all-tokens?))
|
(and new-account?
|
||||||
(wallet/set-zero-balances (first accounts))
|
(not scan-all-tokens?))
|
||||||
|
(wallet/set-zero-balances (first accounts))
|
||||||
|
|
||||||
(and new-account? scan-all-tokens?
|
(and new-account?
|
||||||
(not (utils.mobile-sync/cellular? (:network/type db))))
|
scan-all-tokens?
|
||||||
(wallet/set-max-block (get (first accounts) :address) 0)
|
(not (utils.mobile-sync/cellular? (:network/type db))))
|
||||||
|
(wallet/set-max-block (get (first accounts) :address) 0)
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(wallet/get-cached-balances scan-all-tokens?))
|
(wallet/get-cached-balances scan-all-tokens?))
|
||||||
(when-not (get db :wallet/new-account)
|
(when-not (get db :wallet/new-account)
|
||||||
(wallet/restart-wallet-service nil))
|
(wallet/restart-wallet-service nil))
|
||||||
(when (or (not (utils.mobile-sync/syncing-allowed? cofx))
|
(when (or (not (utils.mobile-sync/syncing-allowed? cofx))
|
||||||
@@ -166,21 +173,21 @@
|
|||||||
(prices/update-prices)
|
(prices/update-prices)
|
||||||
(wallet-connect-legacy/get-connector-session-from-db)))
|
(wallet-connect-legacy/get-connector-session-from-db)))
|
||||||
|
|
||||||
(fx/defn login
|
(rf/defn login
|
||||||
{:events [:multiaccounts.login.ui/password-input-submitted]}
|
{:events [:multiaccounts.login.ui/password-input-submitted]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(let [{:keys [key-uid password name identicon]} (:multiaccounts/login db)]
|
(let [{:keys [key-uid password name identicon]} (:multiaccounts/login db)]
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:multiaccounts/login :processing] true)
|
(assoc-in [:multiaccounts/login :processing] true)
|
||||||
(dissoc :intro-wizard :recovered-account?)
|
(dissoc :intro-wizard :recovered-account?)
|
||||||
(update :keycard dissoc :flow))
|
(update :keycard dissoc :flow))
|
||||||
::login [key-uid
|
::login [key-uid
|
||||||
(types/clj->json {:name name
|
(types/clj->json {:name name
|
||||||
:key-uid key-uid
|
:key-uid key-uid
|
||||||
:identicon identicon})
|
:identicon identicon})
|
||||||
(ethereum/sha3 (security/safe-unmask-data password))]}))
|
(ethereum/sha3 (security/safe-unmask-data password))]}))
|
||||||
|
|
||||||
(fx/defn export-db-submitted
|
(rf/defn export-db-submitted
|
||||||
{:events [:multiaccounts.login.ui/export-db-submitted]}
|
{:events [:multiaccounts.login.ui/export-db-submitted]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(let [{:keys [key-uid password name identicon]} (:multiaccounts/login db)]
|
(let [{:keys [key-uid password name identicon]} (:multiaccounts/login db)]
|
||||||
@@ -192,24 +199,25 @@
|
|||||||
(fn [path]
|
(fn [path]
|
||||||
(when platform/ios?
|
(when platform/ios?
|
||||||
(let [uri (str "file://" path)]
|
(let [uri (str "file://" path)]
|
||||||
(.share ^js react/sharing (clj->js {:title "Unencrypted database"
|
(.share ^js react/sharing
|
||||||
:url uri})))))]}))
|
(clj->js {:title "Unencrypted database"
|
||||||
|
:url uri})))))]}))
|
||||||
|
|
||||||
(fx/defn import-db-submitted
|
(rf/defn import-db-submitted
|
||||||
{:events [:multiaccounts.login.ui/import-db-submitted]}
|
{:events [:multiaccounts.login.ui/import-db-submitted]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(let [{:keys [key-uid password name identicon]} (:multiaccounts/login db)]
|
(let [{:keys [key-uid password name identicon]} (:multiaccounts/login db)]
|
||||||
{::import-db [key-uid
|
{::import-db [key-uid
|
||||||
(types/clj->json {:name name
|
(types/clj->json {:name name
|
||||||
:key-uid key-uid
|
:key-uid key-uid
|
||||||
:identicon identicon})
|
:identicon identicon})
|
||||||
(ethereum/sha3 (security/safe-unmask-data password))]}))
|
(ethereum/sha3 (security/safe-unmask-data password))]}))
|
||||||
|
|
||||||
(fx/defn finish-keycard-setup
|
(rf/defn finish-keycard-setup
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
{:db (update db :keycard dissoc :flow)})
|
{:db (update db :keycard dissoc :flow)})
|
||||||
|
|
||||||
(fx/defn initialize-dapp-permissions
|
(rf/defn initialize-dapp-permissions
|
||||||
{:events [::initialize-dapp-permissions]}
|
{:events [::initialize-dapp-permissions]}
|
||||||
[{:keys [db]} all-dapp-permissions]
|
[{:keys [db]} all-dapp-permissions]
|
||||||
(let [dapp-permissions (reduce (fn [acc {:keys [dapp] :as dapp-permissions}]
|
(let [dapp-permissions (reduce (fn [acc {:keys [dapp] :as dapp-permissions}]
|
||||||
@@ -218,7 +226,7 @@
|
|||||||
all-dapp-permissions)]
|
all-dapp-permissions)]
|
||||||
{:db (assoc db :dapps/permissions dapp-permissions)}))
|
{:db (assoc db :dapps/permissions dapp-permissions)}))
|
||||||
|
|
||||||
(fx/defn initialize-browsers
|
(rf/defn initialize-browsers
|
||||||
{:events [::initialize-browsers]}
|
{:events [::initialize-browsers]}
|
||||||
[{:keys [db]} all-stored-browsers]
|
[{:keys [db]} all-stored-browsers]
|
||||||
(let [browsers (reduce (fn [acc {:keys [browser-id] :as browser}]
|
(let [browsers (reduce (fn [acc {:keys [browser-id] :as browser}]
|
||||||
@@ -227,7 +235,7 @@
|
|||||||
all-stored-browsers)]
|
all-stored-browsers)]
|
||||||
{:db (assoc db :browser/browsers browsers)}))
|
{:db (assoc db :browser/browsers browsers)}))
|
||||||
|
|
||||||
(fx/defn initialize-bookmarks
|
(rf/defn initialize-bookmarks
|
||||||
{:events [::initialize-bookmarks]}
|
{:events [::initialize-bookmarks]}
|
||||||
[{:keys [db]} stored-bookmarks]
|
[{:keys [db]} stored-bookmarks]
|
||||||
(let [bookmarks (reduce (fn [acc {:keys [url] :as bookmark}]
|
(let [bookmarks (reduce (fn [acc {:keys [url] :as bookmark}]
|
||||||
@@ -236,28 +244,30 @@
|
|||||||
stored-bookmarks)]
|
stored-bookmarks)]
|
||||||
{:db (assoc db :bookmarks/bookmarks bookmarks)}))
|
{:db (assoc db :bookmarks/bookmarks bookmarks)}))
|
||||||
|
|
||||||
(fx/defn initialize-invitations
|
(rf/defn initialize-invitations
|
||||||
{:events [::initialize-invitations]}
|
{:events [::initialize-invitations]}
|
||||||
[{:keys [db]} invitations]
|
[{:keys [db]} invitations]
|
||||||
{:db (assoc db :group-chat/invitations (reduce (fn [acc {:keys [id] :as inv}]
|
{:db (assoc db
|
||||||
(assoc acc id (data-store.invitations/<-rpc inv)))
|
:group-chat/invitations
|
||||||
{}
|
(reduce (fn [acc {:keys [id] :as inv}]
|
||||||
invitations))})
|
(assoc acc id (data-store.invitations/<-rpc inv)))
|
||||||
|
{}
|
||||||
|
invitations))})
|
||||||
|
|
||||||
(fx/defn initialize-web3-client-version
|
(rf/defn initialize-web3-client-version
|
||||||
{:events [::initialize-web3-client-version]}
|
{:events [::initialize-web3-client-version]}
|
||||||
[{:keys [db]} node-version]
|
[{:keys [db]} node-version]
|
||||||
{:db (assoc db :web3-node-version node-version)})
|
{:db (assoc db :web3-node-version node-version)})
|
||||||
|
|
||||||
(fx/defn handle-close-app-confirmed
|
(rf/defn handle-close-app-confirmed
|
||||||
{:events [::close-app-confirmed]}
|
{:events [::close-app-confirmed]}
|
||||||
[_]
|
[_]
|
||||||
{:ui/close-application nil})
|
{:ui/close-application nil})
|
||||||
|
|
||||||
(fx/defn check-network-version
|
(rf/defn check-network-version
|
||||||
[_ network-id]
|
[_ network-id]
|
||||||
{::json-rpc/call
|
{::json-rpc/call
|
||||||
[{:method "net_version"
|
[{:method "net_version"
|
||||||
:on-success
|
:on-success
|
||||||
(fn [fetched-network-id]
|
(fn [fetched-network-id]
|
||||||
(when (not= network-id (str (int fetched-network-id)))
|
(when (not= network-id (str (int fetched-network-id)))
|
||||||
@@ -270,7 +280,8 @@
|
|||||||
:fetched-network-id fetched-network-id})
|
:fetched-network-id fetched-network-id})
|
||||||
#(re-frame/dispatch [::close-app-confirmed]))))}]})
|
#(re-frame/dispatch [::close-app-confirmed]))))}]})
|
||||||
|
|
||||||
(defn normalize-tokens [network-id tokens]
|
(defn normalize-tokens
|
||||||
|
[network-id tokens]
|
||||||
(mapv #(-> %
|
(mapv #(-> %
|
||||||
(update :symbol keyword)
|
(update :symbol keyword)
|
||||||
((partial tokens/update-icon (ethereum/chain-id->chain-keyword (int network-id)))))
|
((partial tokens/update-icon (ethereum/chain-id->chain-keyword (int network-id)))))
|
||||||
@@ -281,8 +292,8 @@
|
|||||||
(fn [[network-id accounts recovered-account?]]
|
(fn [[network-id accounts recovered-account?]]
|
||||||
(utils/set-timeout
|
(utils/set-timeout
|
||||||
(fn []
|
(fn []
|
||||||
(json-rpc/call {:method "wallet_getTokens"
|
(json-rpc/call {:method "wallet_getTokens"
|
||||||
:params [(int network-id)]
|
:params [(int network-id)]
|
||||||
:on-success #(re-frame/dispatch [::initialize-wallet
|
:on-success #(re-frame/dispatch [::initialize-wallet
|
||||||
accounts
|
accounts
|
||||||
(normalize-tokens network-id %)
|
(normalize-tokens network-id %)
|
||||||
@@ -299,25 +310,25 @@
|
|||||||
(clj->js
|
(clj->js
|
||||||
[(js/Promise.
|
[(js/Promise.
|
||||||
(fn [resolve reject]
|
(fn [resolve reject]
|
||||||
(json-rpc/call {:method "accounts_getAccounts"
|
(json-rpc/call {:method "accounts_getAccounts"
|
||||||
:on-success resolve
|
:on-success resolve
|
||||||
:on-error reject})))
|
:on-error reject})))
|
||||||
(js/Promise.
|
(js/Promise.
|
||||||
(fn [resolve _]
|
(fn [resolve _]
|
||||||
(json-rpc/call {:method "wallet_getTokens"
|
(json-rpc/call {:method "wallet_getTokens"
|
||||||
:params [(int network-id)]
|
:params [(int network-id)]
|
||||||
:on-success resolve
|
:on-success resolve
|
||||||
:on-error #(resolve nil)})))
|
:on-error #(resolve nil)})))
|
||||||
(js/Promise.
|
(js/Promise.
|
||||||
(fn [resolve reject]
|
(fn [resolve reject]
|
||||||
(json-rpc/call {:method "wallet_getCustomTokens"
|
(json-rpc/call {:method "wallet_getCustomTokens"
|
||||||
:on-success resolve
|
:on-success resolve
|
||||||
:on-error reject})))
|
:on-error reject})))
|
||||||
(js/Promise.
|
(js/Promise.
|
||||||
(fn [resolve reject]
|
(fn [resolve reject]
|
||||||
(json-rpc/call {:method "wallet_getSavedAddresses"
|
(json-rpc/call {:method "wallet_getSavedAddresses"
|
||||||
:on-success resolve
|
:on-success resolve
|
||||||
:on-error reject})))]))
|
:on-error reject})))]))
|
||||||
(.then (fn [[accounts tokens custom-tokens favourites]]
|
(.then (fn [[accounts tokens custom-tokens favourites]]
|
||||||
(callback accounts
|
(callback accounts
|
||||||
(normalize-tokens network-id tokens)
|
(normalize-tokens network-id tokens)
|
||||||
@@ -326,7 +337,8 @@
|
|||||||
(.catch (fn [_]
|
(.catch (fn [_]
|
||||||
(log/error "Failed to initialize wallet"))))))
|
(log/error "Failed to initialize wallet"))))))
|
||||||
|
|
||||||
(fx/defn initialize-browser [_]
|
(rf/defn initialize-browser
|
||||||
|
[_]
|
||||||
{::json-rpc/call
|
{::json-rpc/call
|
||||||
[{:method "wakuext_getBrowsers"
|
[{:method "wakuext_getBrowsers"
|
||||||
:on-success #(re-frame/dispatch [::initialize-browsers %])}
|
:on-success #(re-frame/dispatch [::initialize-browsers %])}
|
||||||
@@ -335,53 +347,57 @@
|
|||||||
{:method "permissions_getDappPermissions"
|
{:method "permissions_getDappPermissions"
|
||||||
:on-success #(re-frame/dispatch [::initialize-dapp-permissions %])}]})
|
:on-success #(re-frame/dispatch [::initialize-dapp-permissions %])}]})
|
||||||
|
|
||||||
(fx/defn initialize-appearance [cofx]
|
(rf/defn initialize-appearance
|
||||||
|
[cofx]
|
||||||
{:multiaccounts.ui/switch-theme (get-in cofx [:db :multiaccount :appearance])})
|
{:multiaccounts.ui/switch-theme (get-in cofx [:db :multiaccount :appearance])})
|
||||||
|
|
||||||
(fx/defn get-group-chat-invitations [_]
|
(rf/defn get-group-chat-invitations
|
||||||
|
[_]
|
||||||
{::json-rpc/call
|
{::json-rpc/call
|
||||||
[{:method "wakuext_getGroupChatInvitations"
|
[{:method "wakuext_getGroupChatInvitations"
|
||||||
:on-success #(re-frame/dispatch [::initialize-invitations %])}]})
|
:on-success #(re-frame/dispatch [::initialize-invitations %])}]})
|
||||||
|
|
||||||
(fx/defn initialize-communities-enabled
|
(rf/defn initialize-communities-enabled
|
||||||
[cofx]
|
[cofx]
|
||||||
{::initialize-communities-enabled nil})
|
{::initialize-communities-enabled nil})
|
||||||
|
|
||||||
(fx/defn initialize-transactions-management-enabled
|
(rf/defn initialize-transactions-management-enabled
|
||||||
[cofx]
|
[cofx]
|
||||||
{::initialize-transactions-management-enabled nil})
|
{::initialize-transactions-management-enabled nil})
|
||||||
|
|
||||||
(fx/defn initialize-wallet-connect
|
(rf/defn initialize-wallet-connect
|
||||||
[cofx]
|
[cofx]
|
||||||
{::initialize-wallet-connect nil})
|
{::initialize-wallet-connect nil})
|
||||||
|
|
||||||
(fx/defn get-node-config-callback
|
(rf/defn get-node-config-callback
|
||||||
{:events [::get-node-config-callback]}
|
{:events [::get-node-config-callback]}
|
||||||
[{:keys [db] :as cofx} node-config-json]
|
[{:keys [db] :as cofx} node-config-json]
|
||||||
(let [node-config (types/json->clj node-config-json)]
|
(let [node-config (types/json->clj node-config-json)]
|
||||||
{:db (assoc-in db [:multiaccount :wakuv2-config]
|
{:db (assoc-in db
|
||||||
(get node-config :WakuV2Config))}))
|
[:multiaccount :wakuv2-config]
|
||||||
|
(get node-config :WakuV2Config))}))
|
||||||
|
|
||||||
(fx/defn get-node-config
|
(rf/defn get-node-config
|
||||||
[_]
|
[_]
|
||||||
(status/get-node-config #(re-frame/dispatch [::get-node-config-callback %])))
|
(status/get-node-config #(re-frame/dispatch [::get-node-config-callback %])))
|
||||||
|
|
||||||
(fx/defn get-settings-callback
|
(rf/defn get-settings-callback
|
||||||
{:events [::get-settings-callback]}
|
{:events [::get-settings-callback]}
|
||||||
[{:keys [db] :as cofx} settings]
|
[{:keys [db] :as cofx} settings]
|
||||||
(let [{:networks/keys [current-network networks]
|
(let [{:networks/keys [current-network networks]
|
||||||
:as settings}
|
:as settings}
|
||||||
(data-store.settings/rpc->settings settings)
|
(data-store.settings/rpc->settings settings)
|
||||||
multiaccount (dissoc settings :networks/current-network :networks/networks)
|
multiaccount (dissoc settings :networks/current-network :networks/networks)
|
||||||
;;for some reason we save default networks in db, in case when we want to modify default-networks for
|
;;for some reason we save default networks in db, in case when we want to modify default-networks
|
||||||
|
;;for
|
||||||
;; existing accounts we have to merge them again into networks
|
;; existing accounts we have to merge them again into networks
|
||||||
merged-networks (merge networks config/default-networks-by-id)]
|
merged-networks (merge networks config/default-networks-by-id)]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(dissoc :multiaccounts/login)
|
(dissoc :multiaccounts/login)
|
||||||
(assoc :networks/current-network current-network
|
(assoc :networks/current-network current-network
|
||||||
:networks/networks merged-networks
|
:networks/networks merged-networks
|
||||||
:multiaccount multiaccount))}
|
:multiaccount multiaccount))}
|
||||||
(data-store.chats/fetch-chats-rpc
|
(data-store.chats/fetch-chats-rpc
|
||||||
{:on-success
|
{:on-success
|
||||||
#(do (re-frame/dispatch [:chats-list/load-success %])
|
#(do (re-frame/dispatch [:chats-list/load-success %])
|
||||||
@@ -408,31 +424,32 @@
|
|||||||
(when (= stored-key-uid key-uid)
|
(when (= stored-key-uid key-uid)
|
||||||
(re-frame/dispatch [:chat.ui/navigate-to-chat chat-id])))))))))
|
(re-frame/dispatch [:chat.ui/navigate-to-chat chat-id])))))))))
|
||||||
|
|
||||||
(fx/defn check-last-chat
|
(rf/defn check-last-chat
|
||||||
{:events [::check-last-chat]}
|
{:events [::check-last-chat]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
{::open-last-chat (get-in db [:multiaccount :key-uid])})
|
{::open-last-chat (get-in db [:multiaccount :key-uid])})
|
||||||
|
|
||||||
(fx/defn update-wallet-accounts
|
(rf/defn update-wallet-accounts
|
||||||
[{:keys [db]} accounts]
|
[{:keys [db]} accounts]
|
||||||
(let [existing-accounts (into {} (map #(vector (:address %1) %1) (:multiaccount/accounts db)))
|
(let [existing-accounts (into {} (map #(vector (:address %1) %1) (:multiaccount/accounts db)))
|
||||||
reduce-fn (fn [existing-accs new-acc]
|
reduce-fn (fn [existing-accs new-acc]
|
||||||
(let [address (:address new-acc)]
|
(let [address (:address new-acc)]
|
||||||
(if (:removed new-acc)
|
(if (:removed new-acc)
|
||||||
(dissoc existing-accs address)
|
(dissoc existing-accs address)
|
||||||
(assoc existing-accs address new-acc))))
|
(assoc existing-accs address new-acc))))
|
||||||
new-accounts (reduce reduce-fn existing-accounts (rpc->accounts accounts))]
|
new-accounts (reduce reduce-fn existing-accounts (rpc->accounts accounts))]
|
||||||
{:db (assoc db :multiaccount/accounts (vals new-accounts))}))
|
{:db (assoc db :multiaccount/accounts (vals new-accounts))}))
|
||||||
|
|
||||||
(fx/defn get-chats-callback
|
(rf/defn get-chats-callback
|
||||||
{:events [::get-chats-callback]}
|
{:events [::get-chats-callback]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [{:networks/keys [current-network networks]} db
|
(let [{:networks/keys [current-network networks]} db
|
||||||
notifications-enabled? (get-in db [:multiaccount :notifications-enabled?])
|
notifications-enabled? (get-in db [:multiaccount :notifications-enabled?])
|
||||||
network-id (str (get-in networks [current-network :config :NetworkId]))
|
network-id (str (get-in networks
|
||||||
|
[current-network :config :NetworkId]))
|
||||||
remote-push-notifications-enabled?
|
remote-push-notifications-enabled?
|
||||||
(get-in db [:multiaccount :remote-push-notifications-enabled?])]
|
(get-in db [:multiaccount :remote-push-notifications-enabled?])]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(cond-> {::eip1559/check-eip1559-activation
|
(cond-> {::eip1559/check-eip1559-activation
|
||||||
{:network-id network-id
|
{:network-id network-id
|
||||||
:on-enabled #(log/info "eip1550 is activated")
|
:on-enabled #(log/info "eip1550 is activated")
|
||||||
@@ -442,7 +459,7 @@
|
|||||||
(fn [accounts tokens custom-tokens favourites]
|
(fn [accounts tokens custom-tokens favourites]
|
||||||
(re-frame/dispatch [::initialize-wallet
|
(re-frame/dispatch [::initialize-wallet
|
||||||
accounts tokens custom-tokens favourites]))]
|
accounts tokens custom-tokens favourites]))]
|
||||||
::open-last-chat (get-in db [:multiaccount :key-uid])}
|
::open-last-chat (get-in db [:multiaccount :key-uid])}
|
||||||
(or notifications-enabled? remote-push-notifications-enabled?)
|
(or notifications-enabled? remote-push-notifications-enabled?)
|
||||||
(assoc ::notifications/enable remote-push-notifications-enabled?))
|
(assoc ::notifications/enable remote-push-notifications-enabled?))
|
||||||
(transport/start-messenger)
|
(transport/start-messenger)
|
||||||
@@ -457,7 +474,8 @@
|
|||||||
(link-preview/request-link-preview-whitelist)
|
(link-preview/request-link-preview-whitelist)
|
||||||
(visibility-status-updates-store/fetch-visibility-status-updates-rpc))))
|
(visibility-status-updates-store/fetch-visibility-status-updates-rpc))))
|
||||||
|
|
||||||
(defn get-new-auth-method [auth-method save-password?]
|
(defn get-new-auth-method
|
||||||
|
[auth-method save-password?]
|
||||||
(when save-password?
|
(when save-password?
|
||||||
(when-not (or (= keychain/auth-method-biometric auth-method)
|
(when-not (or (= keychain/auth-method-biometric auth-method)
|
||||||
(= keychain/auth-method-password auth-method))
|
(= keychain/auth-method-password auth-method))
|
||||||
@@ -472,15 +490,15 @@
|
|||||||
(re-frame/dispatch [:init-root (if config/new-ui-enabled? :shell-stack :chat-stack)])
|
(re-frame/dispatch [:init-root (if config/new-ui-enabled? :shell-stack :chat-stack)])
|
||||||
(re-frame/dispatch [:init-root :tos])))
|
(re-frame/dispatch [:init-root :tos])))
|
||||||
|
|
||||||
(fx/defn login-only-events
|
(rf/defn login-only-events
|
||||||
[{:keys [db] :as cofx} key-uid password save-password?]
|
[{:keys [db] :as cofx} key-uid password save-password?]
|
||||||
(let [auth-method (:auth-method db)
|
(let [auth-method (:auth-method db)
|
||||||
new-auth-method (get-new-auth-method auth-method save-password?)]
|
new-auth-method (get-new-auth-method auth-method save-password?)]
|
||||||
(log/debug "[login] login-only-events"
|
(log/debug "[login] login-only-events"
|
||||||
"auth-method" auth-method
|
"auth-method" auth-method
|
||||||
"new-auth-method" new-auth-method)
|
"new-auth-method" new-auth-method)
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc db :chats/loading? true)
|
{:db (assoc db :chats/loading? true)
|
||||||
::json-rpc/call
|
::json-rpc/call
|
||||||
[{:method "settings_getSettings"
|
[{:method "settings_getSettings"
|
||||||
:on-success #(do (re-frame/dispatch [::get-settings-callback %])
|
:on-success #(do (re-frame/dispatch [::get-settings-callback %])
|
||||||
@@ -488,24 +506,26 @@
|
|||||||
(notifications/load-notification-preferences)
|
(notifications/load-notification-preferences)
|
||||||
(when save-password?
|
(when save-password?
|
||||||
(keychain/save-user-password key-uid password))
|
(keychain/save-user-password key-uid password))
|
||||||
(keychain/save-auth-method key-uid (or new-auth-method auth-method keychain/auth-method-none)))))
|
(keychain/save-auth-method key-uid
|
||||||
|
(or new-auth-method auth-method keychain/auth-method-none)))))
|
||||||
|
|
||||||
(fx/defn create-only-events
|
(rf/defn create-only-events
|
||||||
[{:keys [db] :as cofx} recovered-account?]
|
[{:keys [db] :as cofx} recovered-account?]
|
||||||
(let [{:keys [multiaccount
|
(let [{:keys [multiaccount
|
||||||
:multiaccounts/multiaccounts
|
:multiaccounts/multiaccounts
|
||||||
:multiaccount/accounts]} db
|
:multiaccount/accounts]}
|
||||||
{:keys [creating?]} (:multiaccounts/login db)
|
db
|
||||||
first-account? (and creating?
|
{:keys [creating?]} (:multiaccounts/login db)
|
||||||
(empty? multiaccounts))
|
first-account? (and creating?
|
||||||
tos-accepted? (get db :tos/accepted?)
|
(empty? multiaccounts))
|
||||||
|
tos-accepted? (get db :tos/accepted?)
|
||||||
{:networks/keys [current-network networks]} db
|
{:networks/keys [current-network networks]} db
|
||||||
network-id (str (get-in networks [current-network :config :NetworkId]))]
|
network-id (str (get-in networks [current-network :config :NetworkId]))]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(dissoc :multiaccounts/login)
|
(dissoc :multiaccounts/login)
|
||||||
(assoc :tos/next-root :onboarding-notification :chats/loading? false)
|
(assoc :tos/next-root :onboarding-notification :chats/loading? false)
|
||||||
(assoc-in [:multiaccount :multiaccounts/first-account] first-account?))
|
(assoc-in [:multiaccount :multiaccounts/first-account] first-account?))
|
||||||
::get-tokens [network-id accounts recovered-account?]}
|
::get-tokens [network-id accounts recovered-account?]}
|
||||||
(finish-keycard-setup)
|
(finish-keycard-setup)
|
||||||
(transport/start-messenger)
|
(transport/start-messenger)
|
||||||
@@ -525,14 +545,16 @@
|
|||||||
(navigation/init-root :onboarding-notification)
|
(navigation/init-root :onboarding-notification)
|
||||||
(navigation/init-root :tos))))))
|
(navigation/init-root :tos))))))
|
||||||
|
|
||||||
(defn- keycard-setup? [cofx]
|
(defn- keycard-setup?
|
||||||
|
[cofx]
|
||||||
(boolean (get-in cofx [:db :keycard :flow])))
|
(boolean (get-in cofx [:db :keycard :flow])))
|
||||||
|
|
||||||
(defn on-login-update-db [db login-only? now]
|
(defn on-login-update-db
|
||||||
|
[db login-only? now]
|
||||||
(-> db
|
(-> db
|
||||||
(dissoc :connectivity/ui-status-properties)
|
(dissoc :connectivity/ui-status-properties)
|
||||||
(update :keycard dissoc :from-key-storage-and-migration?)
|
(update :keycard dissoc :from-key-storage-and-migration?)
|
||||||
(update :keycard dissoc
|
(update :keycard dissoc
|
||||||
:on-card-read
|
:on-card-read
|
||||||
:card-read-in-progress?
|
:card-read-in-progress?
|
||||||
:pin
|
:pin
|
||||||
@@ -544,23 +566,25 @@
|
|||||||
(assoc :logged-in-since now)
|
(assoc :logged-in-since now)
|
||||||
(assoc :view-id :home)))
|
(assoc :view-id :home)))
|
||||||
|
|
||||||
(fx/defn multiaccount-login-success
|
(rf/defn multiaccount-login-success
|
||||||
[{:keys [db now] :as cofx}]
|
[{:keys [db now] :as cofx}]
|
||||||
(let [{:keys [key-uid password save-password? creating?]}
|
(let [{:keys [key-uid password save-password? creating?]}
|
||||||
(:multiaccounts/login db)
|
(:multiaccounts/login db)
|
||||||
|
|
||||||
multiaccounts (:multiaccounts/multiaccounts db)
|
multiaccounts (:multiaccounts/multiaccounts db)
|
||||||
recovered-account? (get db :recovered-account?)
|
recovered-account? (get db :recovered-account?)
|
||||||
login-only? (not (or creating?
|
login-only? (not (or creating?
|
||||||
recovered-account?
|
recovered-account?
|
||||||
(keycard-setup? cofx)))
|
(keycard-setup? cofx)))
|
||||||
from-migration? (get-in db [:keycard :from-key-storage-and-migration?])
|
from-migration? (get-in db
|
||||||
nodes nil]
|
[:keycard
|
||||||
|
:from-key-storage-and-migration?])
|
||||||
|
nodes nil]
|
||||||
(log/debug "[multiaccount] multiaccount-login-success"
|
(log/debug "[multiaccount] multiaccount-login-success"
|
||||||
"login-only?" login-only?
|
"login-only?" login-only?
|
||||||
"recovered-account?" recovered-account?)
|
"recovered-account?" recovered-account?)
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (on-login-update-db db login-only? now)
|
{:db (on-login-update-db db login-only? now)
|
||||||
::json-rpc/call
|
::json-rpc/call
|
||||||
[{:method "web3_clientVersion"
|
[{:method "web3_clientVersion"
|
||||||
:on-success #(re-frame/dispatch [::initialize-web3-client-version %])}]}
|
:on-success #(re-frame/dispatch [::initialize-web3-client-version %])}]}
|
||||||
@@ -571,7 +595,8 @@
|
|||||||
(not recovered-account?))
|
(not recovered-account?))
|
||||||
(wallet/set-initial-blocks-range))
|
(wallet/set-initial-blocks-range))
|
||||||
(when from-migration?
|
(when from-migration?
|
||||||
(utils/show-popup (i18n/label :t/migration-successful) (i18n/label :t/migration-successful-text)))
|
(utils/show-popup (i18n/label :t/migration-successful)
|
||||||
|
(i18n/label :t/migration-successful-text)))
|
||||||
(if login-only?
|
(if login-only?
|
||||||
(login-only-events key-uid password save-password?)
|
(login-only-events key-uid password save-password?)
|
||||||
(create-only-events recovered-account?)))))
|
(create-only-events recovered-account?)))))
|
||||||
@@ -582,7 +607,7 @@
|
|||||||
;; are alreayd in `multiaccounts/login` and should not be overriden, as they come from
|
;; are alreayd in `multiaccounts/login` and should not be overriden, as they come from
|
||||||
;; the keychain (save-password), this is not very explicit and we should probably
|
;; the keychain (save-password), this is not very explicit and we should probably
|
||||||
;; make it clearer
|
;; make it clearer
|
||||||
(fx/defn open-login
|
(rf/defn open-login
|
||||||
[{:keys [db]} override-multiaccount]
|
[{:keys [db]} override-multiaccount]
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(update :multiaccounts/login
|
(update :multiaccounts/login
|
||||||
@@ -593,23 +618,26 @@
|
|||||||
:error
|
:error
|
||||||
:password))})
|
:password))})
|
||||||
|
|
||||||
(fx/defn open-login-callback
|
(rf/defn open-login-callback
|
||||||
{:events [:multiaccounts.login.callback/get-user-password-success]}
|
{:events [:multiaccounts.login.callback/get-user-password-success]}
|
||||||
[{:keys [db] :as cofx} password]
|
[{:keys [db] :as cofx} password]
|
||||||
(let [key-uid (get-in db [:multiaccounts/login :key-uid])
|
(let [key-uid (get-in db [:multiaccounts/login :key-uid])
|
||||||
keycard-account? (boolean (get-in db [:multiaccounts/multiaccounts
|
keycard-account? (boolean (get-in db
|
||||||
key-uid
|
[:multiaccounts/multiaccounts
|
||||||
:keycard-pairing]))
|
key-uid
|
||||||
|
:keycard-pairing]))
|
||||||
goto-key-storage? (:goto-key-storage? db)]
|
goto-key-storage? (:goto-key-storage? db)]
|
||||||
(if password
|
(if password
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (update-in db [:multiaccounts/login] assoc
|
{:db (update-in db
|
||||||
:password password
|
[:multiaccounts/login]
|
||||||
:save-password? true)
|
assoc
|
||||||
|
:password password
|
||||||
|
:save-password? true)
|
||||||
:init-root-fx :progress}
|
:init-root-fx :progress}
|
||||||
login)
|
login)
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (dissoc db :goto-key-storage?)}
|
{:db (dissoc db :goto-key-storage?)}
|
||||||
(when keycard-account?
|
(when keycard-account?
|
||||||
@@ -622,25 +650,28 @@
|
|||||||
#(when goto-key-storage?
|
#(when goto-key-storage?
|
||||||
(navigation/navigate-to-cofx % :actions-not-logged-in nil))))))
|
(navigation/navigate-to-cofx % :actions-not-logged-in nil))))))
|
||||||
|
|
||||||
(fx/defn get-credentials
|
(rf/defn get-credentials
|
||||||
[{:keys [db] :as cofx} key-uid]
|
[{:keys [db] :as cofx} key-uid]
|
||||||
(let [keycard-multiaccount? (boolean (get-in db [:multiaccounts/multiaccounts key-uid :keycard-pairing]))]
|
(let [keycard-multiaccount? (boolean (get-in db
|
||||||
|
[:multiaccounts/multiaccounts key-uid :keycard-pairing]))]
|
||||||
(log/debug "[login] get-credentials"
|
(log/debug "[login] get-credentials"
|
||||||
"keycard-multiacc?" keycard-multiaccount?)
|
"keycard-multiacc?"
|
||||||
|
keycard-multiaccount?)
|
||||||
(if keycard-multiaccount?
|
(if keycard-multiaccount?
|
||||||
(keychain/get-keycard-keys cofx key-uid)
|
(keychain/get-keycard-keys cofx key-uid)
|
||||||
(keychain/get-user-password cofx key-uid))))
|
(keychain/get-user-password cofx key-uid))))
|
||||||
|
|
||||||
(fx/defn get-auth-method-success
|
(rf/defn get-auth-method-success
|
||||||
"Auth method: nil - not supported, \"none\" - not selected, \"password\", \"biometric\", \"biometric-prepare\""
|
"Auth method: nil - not supported, \"none\" - not selected, \"password\", \"biometric\", \"biometric-prepare\""
|
||||||
{:events [:multiaccounts.login/get-auth-method-success]}
|
{:events [:multiaccounts.login/get-auth-method-success]}
|
||||||
[{:keys [db] :as cofx} auth-method]
|
[{:keys [db] :as cofx} auth-method]
|
||||||
(let [key-uid (get-in db [:multiaccounts/login :key-uid])
|
(let [key-uid (get-in db [:multiaccounts/login :key-uid])
|
||||||
keycard-multiaccount? (boolean (get-in db [:multiaccounts/multiaccounts key-uid :keycard-pairing]))]
|
keycard-multiaccount? (boolean (get-in db
|
||||||
|
[:multiaccounts/multiaccounts key-uid :keycard-pairing]))]
|
||||||
(log/debug "[login] get-auth-method-success"
|
(log/debug "[login] get-auth-method-success"
|
||||||
"auth-method" auth-method
|
"auth-method" auth-method
|
||||||
"keycard-multiacc?" keycard-multiaccount?)
|
"keycard-multiacc?" keycard-multiaccount?)
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (assoc db :auth-method auth-method)}
|
{:db (assoc db :auth-method auth-method)}
|
||||||
#(cond
|
#(cond
|
||||||
@@ -653,7 +684,7 @@
|
|||||||
(keycard.common/get-application-info % nil))
|
(keycard.common/get-application-info % nil))
|
||||||
(open-login-callback nil))))
|
(open-login-callback nil))))
|
||||||
|
|
||||||
(fx/defn biometric-auth-done
|
(rf/defn biometric-auth-done
|
||||||
{:events [:biometric-auth-done]}
|
{:events [:biometric-auth-done]}
|
||||||
[{:keys [db] :as cofx} {:keys [bioauth-success bioauth-message bioauth-code]}]
|
[{:keys [db] :as cofx} {:keys [bioauth-success bioauth-message bioauth-code]}]
|
||||||
(let [key-uid (get-in db [:multiaccounts/login :key-uid])
|
(let [key-uid (get-in db [:multiaccounts/login :key-uid])
|
||||||
@@ -661,28 +692,28 @@
|
|||||||
(log/debug "[biometric] biometric-auth-done"
|
(log/debug "[biometric] biometric-auth-done"
|
||||||
"bioauth-success" bioauth-success
|
"bioauth-success" bioauth-success
|
||||||
"bioauth-message" bioauth-message
|
"bioauth-message" bioauth-message
|
||||||
"bioauth-code" bioauth-code)
|
"bioauth-code" bioauth-code)
|
||||||
(if bioauth-success
|
(if bioauth-success
|
||||||
(get-credentials cofx key-uid)
|
(get-credentials cofx key-uid)
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc-in db
|
{:db (assoc-in db
|
||||||
[:multiaccounts/login :save-password?]
|
[:multiaccounts/login :save-password?]
|
||||||
(= auth-method keychain/auth-method-biometric))}
|
(= auth-method keychain/auth-method-biometric))}
|
||||||
(when-not (= auth-method keychain/auth-method-biometric)
|
(when-not (= auth-method keychain/auth-method-biometric)
|
||||||
(keychain/save-auth-method key-uid keychain/auth-method-none))
|
(keychain/save-auth-method key-uid keychain/auth-method-none))
|
||||||
(biometric/show-message bioauth-message bioauth-code)
|
(biometric/show-message bioauth-message bioauth-code)
|
||||||
(open-login-callback nil)))))
|
(open-login-callback nil)))))
|
||||||
|
|
||||||
(fx/defn save-password
|
(rf/defn save-password
|
||||||
{:events [:multiaccounts/save-password]}
|
{:events [:multiaccounts/save-password]}
|
||||||
[{:keys [db] :as cofx} save-password?]
|
[{:keys [db] :as cofx} save-password?]
|
||||||
(let [bioauth-supported? (boolean (get db :supported-biometric-auth))
|
(let [bioauth-supported? (boolean (get db :supported-biometric-auth))
|
||||||
previous-auth-method (get db :auth-method)]
|
previous-auth-method (get db :auth-method)]
|
||||||
(log/debug "[login] save-password"
|
(log/debug "[login] save-password"
|
||||||
"save-password?" save-password?
|
"save-password?" save-password?
|
||||||
"bioauth-supported?" bioauth-supported?
|
"bioauth-supported?" bioauth-supported?
|
||||||
"previous-auth-method" previous-auth-method)
|
"previous-auth-method" previous-auth-method)
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (cond-> db
|
{:db (cond-> db
|
||||||
(not= previous-auth-method
|
(not= previous-auth-method
|
||||||
@@ -700,54 +731,54 @@
|
|||||||
(when-not (= previous-auth-method keychain/auth-method-none)
|
(when-not (= previous-auth-method keychain/auth-method-none)
|
||||||
(popover/show-popover {:view :disable-password-saving})))))))
|
(popover/show-popover {:view :disable-password-saving})))))))
|
||||||
|
|
||||||
(fx/defn welcome-lets-go
|
(rf/defn welcome-lets-go
|
||||||
{:events [:welcome-lets-go]}
|
{:events [:welcome-lets-go]}
|
||||||
[_]
|
[_]
|
||||||
{:init-root-fx :chat-stack})
|
{:init-root-fx :chat-stack})
|
||||||
|
|
||||||
(fx/defn multiaccount-selected
|
(rf/defn multiaccount-selected
|
||||||
{:events [:multiaccounts.login.ui/multiaccount-selected]}
|
{:events [:multiaccounts.login.ui/multiaccount-selected]}
|
||||||
[{:keys [db] :as cofx} key-uid]
|
[{:keys [db] :as cofx} key-uid]
|
||||||
;; We specifically pass a bunch of fields instead of the whole multiaccount
|
;; We specifically pass a bunch of fields instead of the whole multiaccount
|
||||||
;; as we want store some fields in multiaccount that are not here
|
;; as we want store some fields in multiaccount that are not here
|
||||||
(let [multiaccount (get-in db [:multiaccounts/multiaccounts key-uid])
|
(let [multiaccount (get-in db [:multiaccounts/multiaccounts key-uid])
|
||||||
keycard-multiaccount? (boolean (:keycard-pairing multiaccount))]
|
keycard-multiaccount? (boolean (:keycard-pairing multiaccount))]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (update db :keycard dissoc :application-info)
|
{:db (update db :keycard dissoc :application-info)
|
||||||
:navigate-to-fx (if keycard-multiaccount? :keycard-login-pin :login)}
|
:navigate-to-fx (if keycard-multiaccount? :keycard-login-pin :login)}
|
||||||
(open-login (select-keys multiaccount [:key-uid :name :public-key :identicon :images])))))
|
(open-login (select-keys multiaccount [:key-uid :name :public-key :identicon :images])))))
|
||||||
|
|
||||||
(fx/defn hide-keycard-banner
|
(rf/defn hide-keycard-banner
|
||||||
{:events [:hide-keycard-banner]}
|
{:events [:hide-keycard-banner]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
{:db (assoc db :keycard/banner-hidden true)
|
{:db (assoc db :keycard/banner-hidden true)
|
||||||
::async-storage/set! {:keycard-banner-hidden true}})
|
::async-storage/set! {:keycard-banner-hidden true}})
|
||||||
|
|
||||||
(fx/defn get-keycard-banner-preference-cb
|
(rf/defn get-keycard-banner-preference-cb
|
||||||
{:events [:get-keycard-banner-preference-cb]}
|
{:events [:get-keycard-banner-preference-cb]}
|
||||||
[{:keys [db]} {:keys [keycard-banner-hidden]}]
|
[{:keys [db]} {:keys [keycard-banner-hidden]}]
|
||||||
{:db (assoc db :keycard/banner-hidden keycard-banner-hidden)})
|
{:db (assoc db :keycard/banner-hidden keycard-banner-hidden)})
|
||||||
|
|
||||||
(fx/defn get-keycard-banner-preference
|
(rf/defn get-keycard-banner-preference
|
||||||
{:events [:get-keycard-banner-preference]}
|
{:events [:get-keycard-banner-preference]}
|
||||||
[_]
|
[_]
|
||||||
{::async-storage/get {:keys [:keycard-banner-hidden]
|
{::async-storage/get {:keys [:keycard-banner-hidden]
|
||||||
:cb #(re-frame/dispatch [:get-keycard-banner-preference-cb %])}})
|
:cb #(re-frame/dispatch [:get-keycard-banner-preference-cb %])}})
|
||||||
|
|
||||||
(fx/defn get-opted-in-to-new-terms-of-service-cb
|
(rf/defn get-opted-in-to-new-terms-of-service-cb
|
||||||
{:events [:get-opted-in-to-new-terms-of-service-cb]}
|
{:events [:get-opted-in-to-new-terms-of-service-cb]}
|
||||||
[{:keys [db]} {:keys [new-terms-of-service-accepted]}]
|
[{:keys [db]} {:keys [new-terms-of-service-accepted]}]
|
||||||
{:db (assoc db :tos/accepted? new-terms-of-service-accepted)})
|
{:db (assoc db :tos/accepted? new-terms-of-service-accepted)})
|
||||||
|
|
||||||
(fx/defn get-opted-in-to-new-terms-of-service
|
(rf/defn get-opted-in-to-new-terms-of-service
|
||||||
"New TOS sprint https://github.com/status-im/status-mobile/pull/12240"
|
"New TOS sprint https://github.com/status-im/status-mobile/pull/12240"
|
||||||
{:events [:get-opted-in-to-new-terms-of-service]}
|
{:events [:get-opted-in-to-new-terms-of-service]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
{::async-storage/get {:keys [:new-terms-of-service-accepted]
|
{::async-storage/get {:keys [:new-terms-of-service-accepted]
|
||||||
:cb #(re-frame/dispatch [:get-opted-in-to-new-terms-of-service-cb %])}})
|
:cb #(re-frame/dispatch [:get-opted-in-to-new-terms-of-service-cb %])}})
|
||||||
|
|
||||||
(fx/defn hide-terms-of-services-opt-in-screen
|
(rf/defn hide-terms-of-services-opt-in-screen
|
||||||
{:events [:hide-terms-of-services-opt-in-screen]}
|
{:events [:hide-terms-of-services-opt-in-screen]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
{::async-storage/set! {:new-terms-of-service-accepted true}
|
{::async-storage/set! {:new-terms-of-service-accepted true}
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
(:require [cljs.test :as test]
|
(:require [cljs.test :as test]
|
||||||
[status-im.multiaccounts.biometric.core :as biometric]
|
[status-im.multiaccounts.biometric.core :as biometric]
|
||||||
[status-im.multiaccounts.login.core :as login]
|
[status-im.multiaccounts.login.core :as login]
|
||||||
[status-im.utils.fx :as fx]
|
[status-im.utils.keychain.core :as keychain]
|
||||||
[status-im.utils.keychain.core :as keychain]))
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(test/deftest save-password-test
|
(test/deftest save-password-test
|
||||||
(test/testing "check save password, biometric unavailable"
|
(test/testing "check save password, biometric unavailable"
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
"uncheck save password")
|
"uncheck save password")
|
||||||
(let [initial-cofx {:db {:auth-method keychain/auth-method-none
|
(let [initial-cofx {:db {:auth-method keychain/auth-method-none
|
||||||
:supported-biometric-auth true}}
|
:supported-biometric-auth true}}
|
||||||
{:keys [db]} (login/save-password (fx/merge
|
{:keys [db]} (login/save-password (rf/merge
|
||||||
initial-cofx
|
initial-cofx
|
||||||
(login/save-password true)
|
(login/save-password true)
|
||||||
(biometric/enable)
|
(biometric/enable)
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
(ns status-im.multiaccounts.logout.core
|
(ns status-im.multiaccounts.logout.core
|
||||||
(:require [re-frame.core :as re-frame]
|
(:require [re-frame.core :as re-frame]
|
||||||
[status-im.i18n.i18n :as i18n]
|
[status-im.i18n.i18n :as i18n]
|
||||||
[status-im.native-module.core :as status]
|
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[status-im.multiaccounts.core :as multiaccounts]
|
[status-im.multiaccounts.core :as multiaccounts]
|
||||||
[status-im.utils.keychain.core :as keychain]
|
[status-im.native-module.core :as status]
|
||||||
[status-im.notifications.core :as notifications]
|
[status-im.notifications.core :as notifications]
|
||||||
|
[status-im.utils.keychain.core :as keychain]
|
||||||
[status-im.wallet.core :as wallet]
|
[status-im.wallet.core :as wallet]
|
||||||
[status-im2.setup.events :as init]))
|
[status-im2.setup.events :as init]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(fx/defn logout-method
|
(rf/defn logout-method
|
||||||
{:events [::logout-method]}
|
{:events [::logout-method]}
|
||||||
[{:keys [db] :as cofx} {:keys [auth-method logout?]}]
|
[{:keys [db] :as cofx} {:keys [auth-method logout?]}]
|
||||||
(let [key-uid (get-in db [:multiaccount :key-uid])]
|
(let [key-uid (get-in db [:multiaccount :key-uid])]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:init-root-fx :progress
|
{:init-root-fx :progress
|
||||||
:chat.ui/clear-inputs nil
|
:chat.ui/clear-inputs nil
|
||||||
:chat.ui/clear-inputs-old nil
|
:chat.ui/clear-inputs-old nil
|
||||||
@@ -22,24 +22,26 @@
|
|||||||
::logout nil
|
::logout nil
|
||||||
::multiaccounts/webview-debug-changed false
|
::multiaccounts/webview-debug-changed false
|
||||||
:keychain/clear-user-password key-uid
|
:keychain/clear-user-password key-uid
|
||||||
:setup/open-multiaccounts #(re-frame/dispatch [:setup/initialize-multiaccounts % {:logout? logout?}])}
|
:setup/open-multiaccounts #(re-frame/dispatch [:setup/initialize-multiaccounts
|
||||||
|
% {:logout? logout?}])}
|
||||||
(keychain/save-auth-method key-uid auth-method)
|
(keychain/save-auth-method key-uid auth-method)
|
||||||
(wallet/clear-timeouts)
|
(wallet/clear-timeouts)
|
||||||
(init/initialize-app-db))))
|
(init/initialize-app-db))))
|
||||||
|
|
||||||
(fx/defn logout
|
(rf/defn logout
|
||||||
{:events [:logout :multiaccounts.logout.ui/logout-confirmed :multiaccounts.update.callback/save-settings-success]}
|
{:events [:logout :multiaccounts.logout.ui/logout-confirmed
|
||||||
|
:multiaccounts.update.callback/save-settings-success]}
|
||||||
[cofx]
|
[cofx]
|
||||||
;; we need to disable notifications before starting the logout process
|
;; we need to disable notifications before starting the logout process
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:dispatch [:wallet-connect-legacy/clean-up-sessions]
|
{:dispatch [:wallet-connect-legacy/clean-up-sessions]
|
||||||
:dispatch-later [{:ms 100
|
:dispatch-later [{:ms 100
|
||||||
:dispatch [::logout-method
|
:dispatch [::logout-method
|
||||||
{:auth-method keychain/auth-method-none
|
{:auth-method keychain/auth-method-none
|
||||||
:logout? true}]}]}
|
:logout? true}]}]}
|
||||||
(notifications/logout-disable)))
|
(notifications/logout-disable)))
|
||||||
|
|
||||||
(fx/defn show-logout-confirmation
|
(rf/defn show-logout-confirmation
|
||||||
{:events [:multiaccounts.logout.ui/logout-pressed]}
|
{:events [:multiaccounts.logout.ui/logout-pressed]}
|
||||||
[_]
|
[_]
|
||||||
{:ui/show-confirmation
|
{:ui/show-confirmation
|
||||||
@@ -49,10 +51,10 @@
|
|||||||
:on-accept #(re-frame/dispatch [:multiaccounts.logout.ui/logout-confirmed])
|
:on-accept #(re-frame/dispatch [:multiaccounts.logout.ui/logout-confirmed])
|
||||||
:on-cancel nil}})
|
:on-cancel nil}})
|
||||||
|
|
||||||
(fx/defn biometric-logout
|
(rf/defn biometric-logout
|
||||||
{:events [:biometric-logout]}
|
{:events [:biometric-logout]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(logout-method {:auth-method keychain/auth-method-biometric-prepare
|
(logout-method {:auth-method keychain/auth-method-biometric-prepare
|
||||||
:logout? false})
|
:logout? false})
|
||||||
(fn [{:keys [db]}]
|
(fn [{:keys [db]}]
|
||||||
|
|||||||
@@ -1,49 +1,52 @@
|
|||||||
(ns status-im.multiaccounts.recover.core
|
(ns status-im.multiaccounts.recover.core
|
||||||
(:require [clojure.string :as string]
|
(:require [clojure.string :as string]
|
||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
|
[status-im.bottom-sheet.core :as bottom-sheet]
|
||||||
[status-im.constants :as constants]
|
[status-im.constants :as constants]
|
||||||
[status-im.ethereum.core :as ethereum]
|
[status-im.ethereum.core :as ethereum]
|
||||||
[status-im.ethereum.mnemonic :as mnemonic]
|
[status-im.ethereum.mnemonic :as mnemonic]
|
||||||
[status-im.keycard.nfc :as nfc]
|
|
||||||
[status-im.i18n.i18n :as i18n]
|
[status-im.i18n.i18n :as i18n]
|
||||||
|
[status-im.keycard.nfc :as nfc]
|
||||||
[status-im.multiaccounts.core :as multiaccounts]
|
[status-im.multiaccounts.core :as multiaccounts]
|
||||||
[status-im.multiaccounts.create.core :as multiaccounts.create]
|
[status-im.multiaccounts.create.core :as multiaccounts.create]
|
||||||
[status-im.native-module.core :as status]
|
[status-im.native-module.core :as status]
|
||||||
[status-im.popover.core :as popover]
|
[status-im.popover.core :as popover]
|
||||||
[status-im2.navigation.events :as navigation]
|
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[utils.security.core :as security]
|
|
||||||
[status-im.utils.types :as types]
|
[status-im.utils.types :as types]
|
||||||
[status-im.utils.utils :as utils]
|
[status-im.utils.utils :as utils]
|
||||||
[status-im.bottom-sheet.core :as bottom-sheet]
|
[status-im2.navigation.events :as navigation]
|
||||||
[taoensso.timbre :as log]))
|
[taoensso.timbre :as log]
|
||||||
|
[utils.re-frame :as rf]
|
||||||
|
[utils.security.core :as security]))
|
||||||
|
|
||||||
(defn existing-account?
|
(defn existing-account?
|
||||||
[multiaccounts key-uid]
|
[multiaccounts key-uid]
|
||||||
{:pre [(not (nil? key-uid))]}
|
{:pre [(not (nil? key-uid))]}
|
||||||
(contains? multiaccounts key-uid))
|
(contains? multiaccounts key-uid))
|
||||||
|
|
||||||
(defn check-phrase-warnings [recovery-phrase]
|
(defn check-phrase-warnings
|
||||||
|
[recovery-phrase]
|
||||||
(cond (string/blank? recovery-phrase) :t/required-field))
|
(cond (string/blank? recovery-phrase) :t/required-field))
|
||||||
|
|
||||||
(fx/defn set-phrase
|
(rf/defn set-phrase
|
||||||
{:events [:multiaccounts.recover/passphrase-input-changed]}
|
{:events [:multiaccounts.recover/passphrase-input-changed]}
|
||||||
[{:keys [db]} masked-recovery-phrase]
|
[{:keys [db]} masked-recovery-phrase]
|
||||||
(let [recovery-phrase (security/safe-unmask-data masked-recovery-phrase)]
|
(let [recovery-phrase (security/safe-unmask-data masked-recovery-phrase)]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
{:db (update db :intro-wizard assoc
|
{:db (update db
|
||||||
:passphrase (string/lower-case recovery-phrase)
|
:intro-wizard assoc
|
||||||
:passphrase-error nil
|
:passphrase (string/lower-case recovery-phrase)
|
||||||
|
:passphrase-error nil
|
||||||
:next-button-disabled? (or (empty? recovery-phrase)
|
:next-button-disabled? (or (empty? recovery-phrase)
|
||||||
(not (mnemonic/valid-length? recovery-phrase))))})))
|
(not (mnemonic/valid-length? recovery-phrase))))})))
|
||||||
|
|
||||||
(fx/defn validate-phrase-for-warnings
|
(rf/defn validate-phrase-for-warnings
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(let [recovery-phrase (get-in db [:intro-wizard :passphrase])]
|
(let [recovery-phrase (get-in db [:intro-wizard :passphrase])]
|
||||||
{:db (update db :intro-wizard assoc
|
{:db (update db
|
||||||
|
:intro-wizard assoc
|
||||||
:passphrase-error (check-phrase-warnings recovery-phrase))}))
|
:passphrase-error (check-phrase-warnings recovery-phrase))}))
|
||||||
|
|
||||||
(fx/defn on-store-multiaccount-success
|
(rf/defn on-store-multiaccount-success
|
||||||
{:events [::store-multiaccount-success]
|
{:events [::store-multiaccount-success]
|
||||||
:interceptors [(re-frame/inject-cofx :random-guid-generator)
|
:interceptors [(re-frame/inject-cofx :random-guid-generator)
|
||||||
(re-frame/inject-cofx ::multiaccounts.create/get-signing-phrase)]}
|
(re-frame/inject-cofx ::multiaccounts.create/get-signing-phrase)]}
|
||||||
@@ -54,29 +57,32 @@
|
|||||||
:content (i18n/label :t/multiaccount-exists-title)
|
:content (i18n/label :t/multiaccount-exists-title)
|
||||||
:on-dismiss #(re-frame/dispatch [:pop-to-root-tab :multiaccounts])}}
|
:on-dismiss #(re-frame/dispatch [:pop-to-root-tab :multiaccounts])}}
|
||||||
(let [{:keys [key-uid] :as multiaccount} (get-in db [:intro-wizard :root-key])
|
(let [{:keys [key-uid] :as multiaccount} (get-in db [:intro-wizard :root-key])
|
||||||
keycard-multiaccount? (boolean (get-in db [:multiaccounts/multiaccounts key-uid :keycard-pairing]))]
|
keycard-multiaccount? (boolean (get-in db
|
||||||
|
[:multiaccounts/multiaccounts key-uid
|
||||||
|
:keycard-pairing]))]
|
||||||
(if keycard-multiaccount?
|
(if keycard-multiaccount?
|
||||||
;; trying to recover multiaccount created with keycard
|
;; trying to recover multiaccount created with keycard
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(update :intro-wizard assoc
|
(update :intro-wizard assoc
|
||||||
:processing? false
|
:processing? false
|
||||||
:passphrase-error :recover-keycard-multiaccount-not-supported)
|
:passphrase-error :recover-keycard-multiaccount-not-supported)
|
||||||
(update :intro-wizard dissoc
|
(update :intro-wizard
|
||||||
:passphrase-valid?))}
|
dissoc
|
||||||
|
:passphrase-valid?))}
|
||||||
(let [multiaccount (assoc multiaccount :derived (get-in db [:intro-wizard :derived]))]
|
(let [multiaccount (assoc multiaccount :derived (get-in db [:intro-wizard :derived]))]
|
||||||
(multiaccounts.create/on-multiaccount-created cofx
|
(multiaccounts.create/on-multiaccount-created cofx
|
||||||
multiaccount
|
multiaccount
|
||||||
password
|
password
|
||||||
{})))))))
|
{})))))))
|
||||||
|
|
||||||
(fx/defn store-multiaccount
|
(rf/defn store-multiaccount
|
||||||
{:events [::recover-multiaccount-confirmed]}
|
{:events [::recover-multiaccount-confirmed]}
|
||||||
[{:keys [db]} password]
|
[{:keys [db]} password]
|
||||||
(let [{:keys [root-key]} (:intro-wizard db)
|
(let [{:keys [root-key]} (:intro-wizard db)
|
||||||
{:keys [id key-uid]} root-key
|
{:keys [id key-uid]} root-key
|
||||||
callback #(re-frame/dispatch [::store-multiaccount-success % password])
|
callback #(re-frame/dispatch [::store-multiaccount-success % password])
|
||||||
hashed-password (ethereum/sha3 (security/safe-unmask-data password))]
|
hashed-password (ethereum/sha3 (security/safe-unmask-data password))]
|
||||||
{:db (assoc-in db [:intro-wizard :processing?] true)
|
{:db (assoc-in db [:intro-wizard :processing?] true)
|
||||||
::multiaccounts.create/store-multiaccount [id key-uid hashed-password callback]}))
|
::multiaccounts.create/store-multiaccount [id key-uid hashed-password callback]}))
|
||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
@@ -99,17 +105,18 @@
|
|||||||
(fn [result]
|
(fn [result]
|
||||||
(let [derived-data (multiaccounts.create/normalize-derived-data-keys
|
(let [derived-data (multiaccounts.create/normalize-derived-data-keys
|
||||||
(types/json->clj result))
|
(types/json->clj result))
|
||||||
public-key (get-in derived-data [constants/path-whisper-keyword :public-key])]
|
public-key (get-in derived-data [constants/path-whisper-keyword :public-key])]
|
||||||
(status/gfycat-identicon-async
|
(status/gfycat-identicon-async
|
||||||
public-key
|
public-key
|
||||||
(fn [name identicon]
|
(fn [name identicon]
|
||||||
(let [derived-data-extended
|
(let [derived-data-extended
|
||||||
(update derived-data
|
(update derived-data
|
||||||
constants/path-whisper-keyword
|
constants/path-whisper-keyword
|
||||||
merge {:name name :identicon identicon})]
|
merge
|
||||||
|
{:name name :identicon identicon})]
|
||||||
(re-frame/dispatch [success-event root-data derived-data-extended]))))))))))))
|
(re-frame/dispatch [success-event root-data derived-data-extended]))))))))))))
|
||||||
|
|
||||||
(fx/defn show-existing-multiaccount-alert
|
(rf/defn show-existing-multiaccount-alert
|
||||||
[_ key-uid]
|
[_ key-uid]
|
||||||
{:utils/show-confirmation
|
{:utils/show-confirmation
|
||||||
{:title (i18n/label :t/multiaccount-exists-title)
|
{:title (i18n/label :t/multiaccount-exists-title)
|
||||||
@@ -121,24 +128,26 @@
|
|||||||
[:multiaccounts.login.ui/multiaccount-selected key-uid]))
|
[:multiaccounts.login.ui/multiaccount-selected key-uid]))
|
||||||
:on-cancel #(re-frame/dispatch [:pop-to-root-tab :multiaccounts])}})
|
:on-cancel #(re-frame/dispatch [:pop-to-root-tab :multiaccounts])}})
|
||||||
|
|
||||||
(fx/defn on-import-multiaccount-success
|
(rf/defn on-import-multiaccount-success
|
||||||
{:events [::import-multiaccount-success]}
|
{:events [::import-multiaccount-success]}
|
||||||
[{:keys [db] :as cofx} {:keys [key-uid] :as root-data} derived-data]
|
[{:keys [db] :as cofx} {:keys [key-uid] :as root-data} derived-data]
|
||||||
(let [multiaccounts (:multiaccounts/multiaccounts db)]
|
(let [multiaccounts (:multiaccounts/multiaccounts db)]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (update db :intro-wizard
|
{:db (update db
|
||||||
assoc :root-key root-data
|
:intro-wizard
|
||||||
:derived derived-data
|
assoc
|
||||||
:step :recovery-success)}
|
:root-key root-data
|
||||||
|
:derived derived-data
|
||||||
|
:step :recovery-success)}
|
||||||
(when (existing-account? multiaccounts key-uid)
|
(when (existing-account? multiaccounts key-uid)
|
||||||
(show-existing-multiaccount-alert key-uid))
|
(show-existing-multiaccount-alert key-uid))
|
||||||
(navigation/navigate-to-cofx :recover-multiaccount-success nil))))
|
(navigation/navigate-to-cofx :recover-multiaccount-success nil))))
|
||||||
|
|
||||||
(fx/defn enter-phrase-pressed
|
(rf/defn enter-phrase-pressed
|
||||||
{:events [::enter-phrase-pressed]}
|
{:events [::enter-phrase-pressed]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc :intro-wizard
|
(assoc :intro-wizard
|
||||||
@@ -153,7 +162,7 @@
|
|||||||
(bottom-sheet/hide-bottom-sheet)
|
(bottom-sheet/hide-bottom-sheet)
|
||||||
(navigation/navigate-to-cofx :recover-multiaccount-enter-phrase nil)))
|
(navigation/navigate-to-cofx :recover-multiaccount-enter-phrase nil)))
|
||||||
|
|
||||||
(fx/defn proceed-to-import-mnemonic
|
(rf/defn proceed-to-import-mnemonic
|
||||||
{:events [:multiaccounts.recover/phrase-validated]}
|
{:events [:multiaccounts.recover/phrase-validated]}
|
||||||
[{:keys [db] :as cofx} phrase-warnings]
|
[{:keys [db] :as cofx} phrase-warnings]
|
||||||
(let [{:keys [password passphrase]} (:intro-wizard db)]
|
(let [{:keys [password passphrase]} (:intro-wizard db)]
|
||||||
@@ -165,37 +174,41 @@
|
|||||||
(security/safe-unmask-data password))
|
(security/safe-unmask-data password))
|
||||||
:success-event ::import-multiaccount-success}}))))
|
:success-event ::import-multiaccount-success}}))))
|
||||||
|
|
||||||
(fx/defn seed-phrase-next-pressed
|
(rf/defn seed-phrase-next-pressed
|
||||||
{:events [:multiaccounts.recover/enter-phrase-next-pressed]}
|
{:events [:multiaccounts.recover/enter-phrase-next-pressed]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [{:keys [passphrase]} (:intro-wizard db)]
|
(let [{:keys [passphrase]} (:intro-wizard db)]
|
||||||
{::multiaccounts/validate-mnemonic [passphrase #(re-frame/dispatch [:multiaccounts.recover/phrase-validated %])]}))
|
{::multiaccounts/validate-mnemonic [passphrase
|
||||||
|
#(re-frame/dispatch [:multiaccounts.recover/phrase-validated
|
||||||
|
%])]}))
|
||||||
|
|
||||||
(fx/defn continue-to-import-mnemonic
|
(rf/defn continue-to-import-mnemonic
|
||||||
{:events [::continue-pressed]}
|
{:events [::continue-pressed]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [{:keys [password passphrase]} (:multiaccounts/recover db)]
|
(let [{:keys [password passphrase]} (:multiaccounts/recover db)]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{::import-multiaccount {:passphrase passphrase
|
{::import-multiaccount {:passphrase passphrase
|
||||||
:password password
|
:password password
|
||||||
:success-event ::import-multiaccount-success}}
|
:success-event ::import-multiaccount-success}}
|
||||||
(popover/hide-popover))))
|
(popover/hide-popover))))
|
||||||
|
|
||||||
(fx/defn dec-step
|
(rf/defn dec-step
|
||||||
{:events [:multiaccounts.recover/dec-step]}
|
{:events [:multiaccounts.recover/dec-step]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [step (get-in db [:intro-wizard :step])]
|
(let [step (get-in db [:intro-wizard :step])]
|
||||||
(if (= step :enter-phrase)
|
(if (= step :enter-phrase)
|
||||||
{:db (dissoc db :intro-wizard)}
|
{:db (dissoc db :intro-wizard)}
|
||||||
{:db (update db :intro-wizard assoc :step
|
{:db (update db
|
||||||
|
:intro-wizard assoc
|
||||||
|
:step
|
||||||
(case step
|
(case step
|
||||||
:recovery-success :enter-phrase
|
:recovery-success :enter-phrase
|
||||||
:select-key-storage :recovery-success
|
:select-key-storage :recovery-success
|
||||||
:create-code :select-key-storage)
|
:create-code :select-key-storage)
|
||||||
:confirm-failure? false
|
:confirm-failure? false
|
||||||
:key-code nil)})))
|
:key-code nil)})))
|
||||||
|
|
||||||
(fx/defn cancel-pressed
|
(rf/defn cancel-pressed
|
||||||
{:events [:multiaccounts.recover/cancel-pressed]}
|
{:events [:multiaccounts.recover/cancel-pressed]}
|
||||||
[{:keys [db] :as cofx} skip-alert?]
|
[{:keys [db] :as cofx} skip-alert?]
|
||||||
;; Workaround for multiple Cancel button clicks
|
;; Workaround for multiple Cancel button clicks
|
||||||
@@ -207,11 +220,11 @@
|
|||||||
(i18n/label :t/are-you-sure-to-cancel)
|
(i18n/label :t/are-you-sure-to-cancel)
|
||||||
(i18n/label :t/you-will-start-from-scratch)
|
(i18n/label :t/you-will-start-from-scratch)
|
||||||
#(re-frame/dispatch [:multiaccounts.recover/cancel-pressed true]))
|
#(re-frame/dispatch [:multiaccounts.recover/cancel-pressed true]))
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
dec-step
|
dec-step
|
||||||
navigation/navigate-back)))))
|
navigation/navigate-back)))))
|
||||||
|
|
||||||
(fx/defn select-storage-next-pressed
|
(rf/defn select-storage-next-pressed
|
||||||
{:events [:multiaccounts.recover/select-storage-next-pressed]
|
{:events [:multiaccounts.recover/select-storage-next-pressed]
|
||||||
:interceptors [(re-frame/inject-cofx :random-guid-generator)]}
|
:interceptors [(re-frame/inject-cofx :random-guid-generator)]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
@@ -219,51 +232,55 @@
|
|||||||
(if (= storage-type :advanced)
|
(if (= storage-type :advanced)
|
||||||
;;TODO: fix circular dependency to remove dispatch here
|
;;TODO: fix circular dependency to remove dispatch here
|
||||||
{:dispatch [:recovery.ui/keycard-option-pressed]}
|
{:dispatch [:recovery.ui/keycard-option-pressed]}
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (update db :intro-wizard assoc :step :create-code)}
|
{:db (update db :intro-wizard assoc :step :create-code)}
|
||||||
(navigation/navigate-to-cofx :create-password nil)))))
|
(navigation/navigate-to-cofx :create-password nil)))))
|
||||||
|
|
||||||
(fx/defn re-encrypt-pressed
|
(rf/defn re-encrypt-pressed
|
||||||
{:events [:multiaccounts.recover/re-encrypt-pressed]}
|
{:events [:multiaccounts.recover/re-encrypt-pressed]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (update db :intro-wizard
|
{:db (update db
|
||||||
assoc :step :select-key-storage
|
:intro-wizard
|
||||||
|
assoc
|
||||||
|
:step :select-key-storage
|
||||||
:selected-storage-type :default)}
|
:selected-storage-type :default)}
|
||||||
(if (nfc/nfc-supported?)
|
(if (nfc/nfc-supported?)
|
||||||
(navigation/navigate-to-cofx :select-key-storage nil)
|
(navigation/navigate-to-cofx :select-key-storage nil)
|
||||||
(select-storage-next-pressed))))
|
(select-storage-next-pressed))))
|
||||||
|
|
||||||
(fx/defn confirm-password-next-button-pressed
|
(rf/defn confirm-password-next-button-pressed
|
||||||
{:events [:multiaccounts.recover/enter-password-next-pressed]
|
{:events [:multiaccounts.recover/enter-password-next-pressed]
|
||||||
:interceptors [(re-frame/inject-cofx :random-guid-generator)]}
|
:interceptors [(re-frame/inject-cofx :random-guid-generator)]}
|
||||||
[cofx key-code]
|
[cofx key-code]
|
||||||
(store-multiaccount cofx key-code))
|
(store-multiaccount cofx key-code))
|
||||||
|
|
||||||
(fx/defn count-words
|
(rf/defn count-words
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(let [passphrase (get-in db [:intro-wizard :passphrase])]
|
(let [passphrase (get-in db [:intro-wizard :passphrase])]
|
||||||
{:db (assoc-in db [:intro-wizard :passphrase-word-count]
|
{:db (assoc-in db
|
||||||
(mnemonic/words-count passphrase))}))
|
[:intro-wizard :passphrase-word-count]
|
||||||
|
(mnemonic/words-count passphrase))}))
|
||||||
|
|
||||||
(fx/defn run-validation
|
(rf/defn run-validation
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [passphrase (get-in db [:intro-wizard :passphrase])]
|
(let [passphrase (get-in db [:intro-wizard :passphrase])]
|
||||||
(when (= (last passphrase) " ")
|
(when (= (last passphrase) " ")
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(validate-phrase-for-warnings)))))
|
(validate-phrase-for-warnings)))))
|
||||||
|
|
||||||
(fx/defn enter-phrase-input-changed
|
(rf/defn enter-phrase-input-changed
|
||||||
{:events [:multiaccounts.recover/enter-phrase-input-changed]}
|
{:events [:multiaccounts.recover/enter-phrase-input-changed]}
|
||||||
[cofx input]
|
[cofx input]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(set-phrase input)
|
(set-phrase input)
|
||||||
(count-words)
|
(count-words)
|
||||||
(run-validation)))
|
(run-validation)))
|
||||||
|
|
||||||
(fx/defn enter-passphrase-input-changed
|
(rf/defn enter-passphrase-input-changed
|
||||||
{:events [:multiaccounts.recover/enter-passphrase-input-changed]}
|
{:events [:multiaccounts.recover/enter-passphrase-input-changed]}
|
||||||
[{:keys [db]} masked-passphrase]
|
[{:keys [db]} masked-passphrase]
|
||||||
{:db (update db :intro-wizard assoc
|
{:db (update db
|
||||||
:password masked-passphrase
|
:intro-wizard assoc
|
||||||
|
:password masked-passphrase
|
||||||
:password-error nil)})
|
:password-error nil)})
|
||||||
|
|||||||
@@ -1,44 +1,44 @@
|
|||||||
(ns status-im.multiaccounts.reset-password.core
|
(ns status-im.multiaccounts.reset-password.core
|
||||||
(:require [re-frame.core :as re-frame]
|
(:require [clojure.string :as string]
|
||||||
[status-im.utils.fx :as fx]
|
[re-frame.core :as re-frame]
|
||||||
[status-im.utils.types :as types]
|
[status-im.ethereum.core :as ethereum]
|
||||||
[clojure.string :as string]
|
|
||||||
[utils.security.core :as security]
|
|
||||||
[status-im.utils.keychain.core :as keychain]
|
|
||||||
[status-im.popover.core :as popover]
|
|
||||||
[status-im.native-module.core :as status]
|
[status-im.native-module.core :as status]
|
||||||
[status-im.ethereum.core :as ethereum]))
|
[status-im.popover.core :as popover]
|
||||||
|
[status-im.utils.keychain.core :as keychain]
|
||||||
|
[status-im.utils.types :as types]
|
||||||
|
[utils.re-frame :as rf]
|
||||||
|
[utils.security.core :as security]))
|
||||||
|
|
||||||
(fx/defn on-input-change
|
(rf/defn on-input-change
|
||||||
{:events [::handle-input-change]}
|
{:events [::handle-input-change]}
|
||||||
[{:keys [db]} input-id value]
|
[{:keys [db]} input-id value]
|
||||||
(let [new-password (get-in db [:multiaccount/reset-password-form-vals :new-password])
|
(let [new-password (get-in db [:multiaccount/reset-password-form-vals :new-password])
|
||||||
error (when (and (= input-id :confirm-new-password)
|
error (when (and (= input-id :confirm-new-password)
|
||||||
(pos? (count new-password))
|
(pos? (count new-password))
|
||||||
(pos? (count value))
|
(pos? (count value))
|
||||||
(not= value new-password))
|
(not= value new-password))
|
||||||
:t/password-mismatch)]
|
:t/password-mismatch)]
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:multiaccount/reset-password-form-vals input-id] value)
|
(assoc-in [:multiaccount/reset-password-form-vals input-id] value)
|
||||||
(assoc-in [:multiaccount/reset-password-errors input-id] error))}))
|
(assoc-in [:multiaccount/reset-password-errors input-id] error))}))
|
||||||
|
|
||||||
(fx/defn clear-form-vals
|
(rf/defn clear-form-vals
|
||||||
{:events [::clear-form-vals]}
|
{:events [::clear-form-vals]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
{:db (dissoc db :multiaccount/reset-password-form-vals :multiaccount/reset-password-errors)})
|
{:db (dissoc db :multiaccount/reset-password-form-vals :multiaccount/reset-password-errors)})
|
||||||
|
|
||||||
(fx/defn set-current-password-error
|
(rf/defn set-current-password-error
|
||||||
{:events [::handle-verification-error ::password-reset-error]}
|
{:events [::handle-verification-error ::password-reset-error]}
|
||||||
[{:keys [db]} error]
|
[{:keys [db]} error]
|
||||||
{:db (assoc-in db [:multiaccount/reset-password-errors :current-password] error)})
|
{:db (assoc-in db [:multiaccount/reset-password-errors :current-password] error)})
|
||||||
|
|
||||||
(fx/defn password-reset-success
|
(rf/defn password-reset-success
|
||||||
{:events [::password-reset-success]}
|
{:events [::password-reset-success]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [{:keys [key-uid]} (:multiaccount db)
|
(let [{:keys [key-uid]} (:multiaccount db)
|
||||||
auth-method (get db :auth-method keychain/auth-method-none)
|
auth-method (get db :auth-method keychain/auth-method-none)
|
||||||
new-password (get-in db [:multiaccount/reset-password-form-vals :new-password])]
|
new-password (get-in db [:multiaccount/reset-password-form-vals :new-password])]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (dissoc
|
{:db (dissoc
|
||||||
db
|
db
|
||||||
:multiaccount/reset-password-form-vals
|
:multiaccount/reset-password-form-vals
|
||||||
@@ -49,7 +49,8 @@
|
|||||||
(when (= auth-method keychain/auth-method-biometric)
|
(when (= auth-method keychain/auth-method-biometric)
|
||||||
(keychain/save-user-password key-uid new-password)))))
|
(keychain/save-user-password key-uid new-password)))))
|
||||||
|
|
||||||
(defn change-db-password-cb [res]
|
(defn change-db-password-cb
|
||||||
|
[res]
|
||||||
(let [{:keys [error]} (types/json->clj res)]
|
(let [{:keys [error]} (types/json->clj res)]
|
||||||
(if (not (string/blank? error))
|
(if (not (string/blank? error))
|
||||||
(re-frame/dispatch [::password-reset-error error])
|
(re-frame/dispatch [::password-reset-error error])
|
||||||
@@ -64,18 +65,20 @@
|
|||||||
(ethereum/sha3 (security/safe-unmask-data new-password))
|
(ethereum/sha3 (security/safe-unmask-data new-password))
|
||||||
change-db-password-cb)))
|
change-db-password-cb)))
|
||||||
|
|
||||||
(fx/defn handle-verification-success
|
(rf/defn handle-verification-success
|
||||||
{:events [::handle-verification-success]}
|
{:events [::handle-verification-success]}
|
||||||
[{:keys [db] :as cofx} form-vals]
|
[{:keys [db] :as cofx} form-vals]
|
||||||
(let [{:keys [key-uid name]} (:multiaccount db)]
|
(let [{:keys [key-uid name]} (:multiaccount db)]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{::change-db-password [key-uid form-vals]
|
{::change-db-password [key-uid form-vals]
|
||||||
:db (assoc db
|
:db (assoc db
|
||||||
:multiaccount/resetting-password? true)}
|
:multiaccount/resetting-password?
|
||||||
|
true)}
|
||||||
(popover/show-popover {:view :password-reset-popover
|
(popover/show-popover {:view :password-reset-popover
|
||||||
:prevent-closing? true}))))
|
:prevent-closing? true}))))
|
||||||
|
|
||||||
(defn handle-verification [form-vals result]
|
(defn handle-verification
|
||||||
|
[form-vals result]
|
||||||
(let [{:keys [error]} (types/json->clj result)]
|
(let [{:keys [error]} (types/json->clj result)]
|
||||||
(if (not (string/blank? error))
|
(if (not (string/blank? error))
|
||||||
(re-frame/dispatch [::handle-verification-error :t/wrong-password])
|
(re-frame/dispatch [::handle-verification-error :t/wrong-password])
|
||||||
@@ -83,12 +86,13 @@
|
|||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
::validate-current-password-and-reset
|
::validate-current-password-and-reset
|
||||||
(fn [{:keys [address current-password] :as form-vals}]
|
(fn [{:keys [address current-password] :as form-vals}]
|
||||||
(let [hashed-pass (ethereum/sha3 (security/safe-unmask-data current-password))]
|
(let [hashed-pass (ethereum/sha3 (security/safe-unmask-data current-password))]
|
||||||
(status/verify address hashed-pass
|
(status/verify address
|
||||||
|
hashed-pass
|
||||||
(partial handle-verification form-vals)))))
|
(partial handle-verification form-vals)))))
|
||||||
|
|
||||||
(fx/defn reset
|
(rf/defn reset
|
||||||
{:events [::reset]}
|
{:events [::reset]}
|
||||||
[{:keys [db]} form-vals]
|
[{:keys [db]} form-vals]
|
||||||
{::validate-current-password-and-reset
|
{::validate-current-password-and-reset
|
||||||
|
|||||||
@@ -1,18 +1,19 @@
|
|||||||
(ns status-im.multiaccounts.update.core
|
(ns status-im.multiaccounts.update.core
|
||||||
(:require [status-im.constants :as constants]
|
(:require [status-im.constants :as constants]
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[status-im.utils.types :as types]
|
[status-im.utils.types :as types]
|
||||||
[taoensso.timbre :as log]))
|
[taoensso.timbre :as log]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(fx/defn send-multiaccount-update [{:keys [db] :as cofx}]
|
(rf/defn send-multiaccount-update
|
||||||
(let [multiaccount (:multiaccount db)
|
[{:keys [db] :as cofx}]
|
||||||
|
(let [multiaccount (:multiaccount db)
|
||||||
{:keys [name preferred-name address]} multiaccount]
|
{:keys [name preferred-name address]} multiaccount]
|
||||||
{::json-rpc/call [{:method "wakuext_sendContactUpdates"
|
{::json-rpc/call [{:method "wakuext_sendContactUpdates"
|
||||||
:params [(or preferred-name name) ""]
|
:params [(or preferred-name name) ""]
|
||||||
:on-success #(log/debug "sent contact update")}]}))
|
:on-success #(log/debug "sent contact update")}]}))
|
||||||
|
|
||||||
(fx/defn multiaccount-update
|
(rf/defn multiaccount-update
|
||||||
"Takes effects (containing :db) + new multiaccount fields, adds all effects necessary for multiaccount update.
|
"Takes effects (containing :db) + new multiaccount fields, adds all effects necessary for multiaccount update.
|
||||||
Optionally, one can specify a success-event to be dispatched after fields are persisted."
|
Optionally, one can specify a success-event to be dispatched after fields are persisted."
|
||||||
[{:keys [db] :as cofx}
|
[{:keys [db] :as cofx}
|
||||||
@@ -22,20 +23,22 @@
|
|||||||
(if (empty? current-multiaccount)
|
(if (empty? current-multiaccount)
|
||||||
;; NOTE: this should never happen, but if it does this is a critical error
|
;; NOTE: this should never happen, but if it does this is a critical error
|
||||||
;; and it is better to crash than risk having an unstable state
|
;; and it is better to crash than risk having an unstable state
|
||||||
(throw (js/Error. "Please shake the phone to report this error and restart the app. multiaccount is currently empty, which means something went wrong when trying to update it with"))
|
(throw
|
||||||
(fx/merge cofx
|
(js/Error.
|
||||||
{:db (if setting-value
|
"Please shake the phone to report this error and restart the app. multiaccount is currently empty, which means something went wrong when trying to update it with"))
|
||||||
(assoc-in db [:multiaccount setting] setting-value)
|
(rf/merge cofx
|
||||||
(update db :multiaccount dissoc setting))
|
{:db (if setting-value
|
||||||
|
(assoc-in db [:multiaccount setting] setting-value)
|
||||||
|
(update db :multiaccount dissoc setting))
|
||||||
::json-rpc/call
|
::json-rpc/call
|
||||||
[{:method "settings_saveSetting"
|
[{:method "settings_saveSetting"
|
||||||
:params [setting setting-value]
|
:params [setting setting-value]
|
||||||
:on-success on-success}]}
|
:on-success on-success}]}
|
||||||
(when (and (not dont-sync?)
|
(when (and (not dont-sync?)
|
||||||
(#{:name :prefered-name} setting))
|
(#{:name :prefered-name} setting))
|
||||||
(send-multiaccount-update))))))
|
(send-multiaccount-update))))))
|
||||||
|
|
||||||
(fx/defn clean-seed-phrase
|
(rf/defn clean-seed-phrase
|
||||||
"A helper function that removes seed phrase from storage."
|
"A helper function that removes seed phrase from storage."
|
||||||
[cofx on-success]
|
[cofx on-success]
|
||||||
(multiaccount-update cofx :mnemonic nil on-success))
|
(multiaccount-update cofx :mnemonic nil on-success))
|
||||||
@@ -44,38 +47,47 @@
|
|||||||
"Add 'url' parameter to stickers that are synchronized from other devices.
|
"Add 'url' parameter to stickers that are synchronized from other devices.
|
||||||
It is not sent from aanother devices but we have it in our db."
|
It is not sent from aanother devices but we have it in our db."
|
||||||
[synced-stickers stickers-from-db]
|
[synced-stickers stickers-from-db]
|
||||||
(mapv #(assoc % :url (->> (get stickers-from-db (or (:packID %) (:pack %)))
|
(mapv #(assoc %
|
||||||
(:stickers)
|
:url
|
||||||
(filter (fn [sticker-db] (= (:hash sticker-db) (:hash %))))
|
(->> (get stickers-from-db (or (:packID %) (:pack %)))
|
||||||
(first)
|
(:stickers)
|
||||||
(:url)))
|
(filter (fn [sticker-db] (= (:hash sticker-db) (:hash %))))
|
||||||
|
(first)
|
||||||
|
(:url)))
|
||||||
synced-stickers))
|
synced-stickers))
|
||||||
|
|
||||||
(fx/defn optimistic
|
(rf/defn optimistic
|
||||||
[{:keys [db] :as cofx} setting setting-value]
|
[{:keys [db] :as cofx} setting setting-value]
|
||||||
(let [current-multiaccount (:multiaccount db)
|
(let [current-multiaccount (:multiaccount db)
|
||||||
setting-value (if (= :currency setting)
|
setting-value (if (= :currency setting)
|
||||||
(keyword setting-value)
|
(keyword setting-value)
|
||||||
setting-value)
|
setting-value)
|
||||||
db (case setting
|
db (case setting
|
||||||
:stickers/packs-pending
|
:stickers/packs-pending
|
||||||
(let [packs-pending (keys (js->clj setting-value))]
|
(let [packs-pending (keys (js->clj setting-value))]
|
||||||
(update db :stickers/packs-pending conj packs-pending))
|
(update db :stickers/packs-pending conj packs-pending))
|
||||||
:stickers/packs-installed
|
:stickers/packs-installed
|
||||||
(let [packs-installed-keys (keys (js->clj setting-value))]
|
(let [packs-installed-keys (keys (js->clj setting-value))]
|
||||||
(reduce #(assoc-in %1 [:stickers/packs %2 :status] constants/sticker-pack-status-installed) db packs-installed-keys))
|
(reduce #(assoc-in %1
|
||||||
:stickers/recent-stickers
|
[:stickers/packs %2 :status]
|
||||||
(let [recent-stickers-from-remote (augment-synchronized-recent-stickers (types/js->clj setting-value) (:stickers/packs db))
|
constants/sticker-pack-status-installed)
|
||||||
merged (into recent-stickers-from-remote (:stickers/recent-stickers db))]
|
db
|
||||||
(assoc db :stickers/recent-stickers recent-stickers-from-remote))
|
packs-installed-keys))
|
||||||
db)]
|
:stickers/recent-stickers
|
||||||
|
(let [recent-stickers-from-remote (augment-synchronized-recent-stickers
|
||||||
|
(types/js->clj setting-value)
|
||||||
|
(:stickers/packs db))
|
||||||
|
merged (into recent-stickers-from-remote
|
||||||
|
(:stickers/recent-stickers db))]
|
||||||
|
(assoc db :stickers/recent-stickers recent-stickers-from-remote))
|
||||||
|
db)]
|
||||||
{:db (if setting-value
|
{:db (if setting-value
|
||||||
(assoc-in db [:multiaccount setting] setting-value)
|
(assoc-in db [:multiaccount setting] setting-value)
|
||||||
(update db :multiaccount dissoc setting))}))
|
(update db :multiaccount dissoc setting))}))
|
||||||
|
|
||||||
(fx/defn set-many-js
|
(rf/defn set-many-js
|
||||||
[cofx settings-js]
|
[cofx settings-js]
|
||||||
(apply fx/merge
|
(apply rf/merge
|
||||||
cofx
|
cofx
|
||||||
(map
|
(map
|
||||||
#(optimistic
|
#(optimistic
|
||||||
@@ -83,15 +95,15 @@
|
|||||||
(.-value %))
|
(.-value %))
|
||||||
settings-js)))
|
settings-js)))
|
||||||
|
|
||||||
(fx/defn toggle-backup-enabled
|
(rf/defn toggle-backup-enabled
|
||||||
{:events [:multiaccounts.ui/switch-backup-enabled]}
|
{:events [:multiaccounts.ui/switch-backup-enabled]}
|
||||||
[cofx enabled?]
|
[cofx enabled?]
|
||||||
(multiaccount-update cofx :backup-enabled? enabled? {}))
|
(multiaccount-update cofx :backup-enabled? enabled? {}))
|
||||||
|
|
||||||
(fx/defn toggle-opensea-nfts-visibility
|
(rf/defn toggle-opensea-nfts-visibility
|
||||||
{:events [::toggle-opensea-nfts-visiblity]}
|
{:events [::toggle-opensea-nfts-visiblity]}
|
||||||
[cofx visible?]
|
[cofx visible?]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc-in (:db cofx) [:multiaccount :opensea-enabled?] visible?)
|
{:db (assoc-in (:db cofx) [:multiaccount :opensea-enabled?] visible?)
|
||||||
;; need to add fully qualified namespace to counter circular deps
|
;; need to add fully qualified namespace to counter circular deps
|
||||||
:dispatch [:status-im.wallet.core/fetch-collectibles-collection]}
|
:dispatch [:status-im.wallet.core/fetch-collectibles-collection]}
|
||||||
|
|||||||
+230
-203
@@ -1,31 +1,31 @@
|
|||||||
(ns status-im.navigation.core
|
(ns status-im.navigation.core
|
||||||
(:require
|
(:require ["react-native" :as rn]
|
||||||
["react-native" :as rn]
|
["react-native-gesture-handler" :refer (gestureHandlerRootHOC)]
|
||||||
["react-native-gesture-handler" :refer (gestureHandlerRootHOC)]
|
["react-native-navigation" :refer (Navigation)]
|
||||||
["react-native-navigation" :refer (Navigation)]
|
[clojure.set :as clojure.set]
|
||||||
[clojure.set :as clojure.set]
|
[quo.components.text-input :as quo.text-input]
|
||||||
[quo.components.text-input :as quo.text-input]
|
[quo.design-system.colors :as quo.colors]
|
||||||
[quo.design-system.colors :as quo.colors]
|
[re-frame.core :as re-frame]
|
||||||
[re-frame.core :as re-frame]
|
[status-im.multiaccounts.login.core :as login-core]
|
||||||
[status-im.multiaccounts.login.core :as login-core]
|
[status-im.navigation.roots :as roots]
|
||||||
[status-im.navigation.roots :as roots]
|
[status-im.navigation.state :as state]
|
||||||
[status-im.navigation.state :as state]
|
[status-im.ui.components.icons.icons :as icons]
|
||||||
[status-im.ui.components.icons.icons :as icons]
|
[status-im.ui.components.react :as react]
|
||||||
[status-im.ui.components.react :as react]
|
[status-im.ui.screens.views :as views]
|
||||||
[status-im.ui.screens.views :as views]
|
[status-im.utils.platform :as platform]
|
||||||
[status-im.utils.fx :as fx]
|
[taoensso.timbre :as log]
|
||||||
[status-im.utils.platform :as platform]
|
[utils.re-frame :as rf]))
|
||||||
[taoensso.timbre :as log]))
|
|
||||||
|
|
||||||
(def debug? ^boolean js/goog.DEBUG)
|
(def debug? ^boolean js/goog.DEBUG)
|
||||||
|
|
||||||
(def splash-screen (-> rn .-NativeModules .-SplashScreen))
|
(def splash-screen (-> rn .-NativeModules .-SplashScreen))
|
||||||
|
|
||||||
(defonce set-navigation-default-options
|
(defonce set-navigation-default-options
|
||||||
(.setDefaultOptions Navigation (clj->js {:layout {:orientation "portrait"}})))
|
(.setDefaultOptions Navigation (clj->js {:layout {:orientation "portrait"}})))
|
||||||
|
|
||||||
;; REGISTER COMPONENT (LAZY)
|
;; REGISTER COMPONENT (LAZY)
|
||||||
(defn reg-comp [key]
|
(defn reg-comp
|
||||||
|
[key]
|
||||||
(log/debug "reg-comp" key)
|
(log/debug "reg-comp" key)
|
||||||
(if-let [comp (get views/components (keyword key))]
|
(if-let [comp (get views/components (keyword key))]
|
||||||
(.registerComponent Navigation key (fn [] (views/component comp)))
|
(.registerComponent Navigation key (fn [] (views/component comp)))
|
||||||
@@ -33,9 +33,10 @@
|
|||||||
(.registerComponent Navigation key (fn [] (gestureHandlerRootHOC screen)) (fn [] screen)))))
|
(.registerComponent Navigation key (fn [] (gestureHandlerRootHOC screen)) (fn [] screen)))))
|
||||||
|
|
||||||
(defonce rset-lazy-reg
|
(defonce rset-lazy-reg
|
||||||
(.setLazyComponentRegistrator Navigation reg-comp))
|
(.setLazyComponentRegistrator Navigation reg-comp))
|
||||||
|
|
||||||
(defn dismiss-all-modals []
|
(defn dismiss-all-modals
|
||||||
|
[]
|
||||||
(log/debug "dissmiss-all-modals")
|
(log/debug "dissmiss-all-modals")
|
||||||
(when @state/curr-modal
|
(when @state/curr-modal
|
||||||
(reset! state/curr-modal false)
|
(reset! state/curr-modal false)
|
||||||
@@ -45,21 +46,24 @@
|
|||||||
(reset! state/modals [])))
|
(reset! state/modals [])))
|
||||||
|
|
||||||
;; PUSH SCREEN
|
;; PUSH SCREEN
|
||||||
(defn navigate [comp]
|
(defn navigate
|
||||||
|
[comp]
|
||||||
(log/debug "NAVIGATE" comp)
|
(log/debug "NAVIGATE" comp)
|
||||||
(let [{:keys [options]} (get views/screens comp)]
|
(let [{:keys [options]} (get views/screens comp)]
|
||||||
(.push Navigation
|
(.push Navigation
|
||||||
(name @state/root-comp-id)
|
(name @state/root-comp-id)
|
||||||
(clj->js {:component {:id comp
|
(clj->js
|
||||||
:name comp
|
{:component {:id comp
|
||||||
:options (merge options
|
:name comp
|
||||||
(roots/status-bar-options)
|
:options (merge options
|
||||||
(roots/merge-top-bar (roots/topbar-options) options))}}))
|
(roots/status-bar-options)
|
||||||
|
(roots/merge-top-bar (roots/topbar-options) options))}}))
|
||||||
;;if we push the screen from modal, we want to dismiss all modals
|
;;if we push the screen from modal, we want to dismiss all modals
|
||||||
(dismiss-all-modals)))
|
(dismiss-all-modals)))
|
||||||
|
|
||||||
;; OPEN MODAL
|
;; OPEN MODAL
|
||||||
(defn update-modal-topbar-options [options]
|
(defn update-modal-topbar-options
|
||||||
|
[options]
|
||||||
(log/debug "update-modal-topbar-options" options)
|
(log/debug "update-modal-topbar-options" options)
|
||||||
(merge options
|
(merge options
|
||||||
(roots/merge-top-bar {:elevation 0
|
(roots/merge-top-bar {:elevation 0
|
||||||
@@ -71,7 +75,8 @@
|
|||||||
:icon (icons/icon-source :main-icons/close)}}
|
:icon (icons/icon-source :main-icons/close)}}
|
||||||
options)))
|
options)))
|
||||||
|
|
||||||
(defn open-modal [comp]
|
(defn open-modal
|
||||||
|
[comp]
|
||||||
(log/debug "open-modal" comp)
|
(log/debug "open-modal" comp)
|
||||||
(let [{:keys [options]} (get views/screens comp)]
|
(let [{:keys [options]} (get views/screens comp)]
|
||||||
(if @state/dissmissing
|
(if @state/dissmissing
|
||||||
@@ -92,25 +97,27 @@
|
|||||||
(re-frame/reg-fx :open-modal-fx open-modal)
|
(re-frame/reg-fx :open-modal-fx open-modal)
|
||||||
|
|
||||||
;; DISSMISS MODAL
|
;; DISSMISS MODAL
|
||||||
(defn dissmissModal []
|
(defn dissmissModal
|
||||||
|
[]
|
||||||
(log/debug "dissmissModal")
|
(log/debug "dissmissModal")
|
||||||
(reset! state/dissmissing true)
|
(reset! state/dissmissing true)
|
||||||
(.dismissModal Navigation (name (last @state/modals))))
|
(.dismissModal Navigation (name (last @state/modals))))
|
||||||
|
|
||||||
(defonce register-nav-button-reg
|
(defonce register-nav-button-reg
|
||||||
(.registerNavigationButtonPressedListener
|
(.registerNavigationButtonPressedListener
|
||||||
(.events Navigation)
|
(.events Navigation)
|
||||||
(fn [^js evn]
|
(fn [^js evn]
|
||||||
(let [id (.-buttonId evn)]
|
(let [id (.-buttonId evn)]
|
||||||
(if (= "dismiss-modal" id)
|
(if (= "dismiss-modal" id)
|
||||||
(do
|
(do
|
||||||
(when-let [event (get-in views/screens [(last @state/modals) :on-dissmiss])]
|
(when-let [event (get-in views/screens [(last @state/modals) :on-dissmiss])]
|
||||||
(re-frame/dispatch event))
|
(re-frame/dispatch event))
|
||||||
(dissmissModal))
|
(dissmissModal))
|
||||||
(when-let [handler (get-in views/screens [(keyword id) :right-handler])]
|
(when-let [handler (get-in views/screens [(keyword id) :right-handler])]
|
||||||
(handler)))))))
|
(handler)))))))
|
||||||
|
|
||||||
(defn set-view-id [view-id]
|
(defn set-view-id
|
||||||
|
[view-id]
|
||||||
(log/debug "set-view-id" view-id)
|
(log/debug "set-view-id" view-id)
|
||||||
(when-let [{:keys [on-focus]} (get views/screens view-id)]
|
(when-let [{:keys [on-focus]} (get views/screens view-id)]
|
||||||
(re-frame/dispatch [:set-view-id view-id])
|
(re-frame/dispatch [:set-view-id view-id])
|
||||||
@@ -119,51 +126,53 @@
|
|||||||
(re-frame/dispatch on-focus))))
|
(re-frame/dispatch on-focus))))
|
||||||
|
|
||||||
(defonce register-modal-reg
|
(defonce register-modal-reg
|
||||||
(.registerModalDismissedListener
|
(.registerModalDismissedListener
|
||||||
(.events Navigation)
|
(.events Navigation)
|
||||||
(fn [_]
|
(fn [_]
|
||||||
(if (> (count @state/modals) 1)
|
(if (> (count @state/modals) 1)
|
||||||
(let [new-modals (butlast @state/modals)]
|
(let [new-modals (butlast @state/modals)]
|
||||||
(reset! state/modals (vec new-modals))
|
(reset! state/modals (vec new-modals))
|
||||||
(set-view-id (last new-modals)))
|
(set-view-id (last new-modals)))
|
||||||
(do
|
(do
|
||||||
(reset! state/modals [])
|
(reset! state/modals [])
|
||||||
(reset! state/curr-modal false)
|
(reset! state/curr-modal false)
|
||||||
(set-view-id @state/pushed-screen-id)))
|
(set-view-id @state/pushed-screen-id)))
|
||||||
|
|
||||||
(let [comp @state/dissmissing]
|
(let [comp @state/dissmissing]
|
||||||
(reset! state/dissmissing false)
|
(reset! state/dissmissing false)
|
||||||
(when (keyword? comp)
|
(when (keyword? comp)
|
||||||
(open-modal comp))))))
|
(open-modal comp))))))
|
||||||
|
|
||||||
;; SCREEN DID APPEAR
|
;; SCREEN DID APPEAR
|
||||||
(defonce screen-appear-reg
|
(defonce screen-appear-reg
|
||||||
(.registerComponentDidAppearListener
|
(.registerComponentDidAppearListener
|
||||||
(.events Navigation)
|
(.events Navigation)
|
||||||
(fn [^js evn]
|
(fn [^js evn]
|
||||||
(let [view-id (keyword (.-componentName evn))]
|
(let [view-id (keyword (.-componentName evn))]
|
||||||
(log/debug "screen-appear-reg" view-id)
|
(log/debug "screen-appear-reg" view-id)
|
||||||
(when (get views/screens view-id)
|
(when (get views/screens view-id)
|
||||||
(when (and (not= view-id :bottom-sheet)
|
(when (and (not= view-id :bottom-sheet)
|
||||||
(not= view-id :popover)
|
(not= view-id :popover)
|
||||||
(not= view-id :visibility-status-popover))
|
(not= view-id :visibility-status-popover))
|
||||||
(set-view-id view-id)
|
(set-view-id view-id)
|
||||||
(when-not @state/curr-modal
|
(when-not @state/curr-modal
|
||||||
(reset! state/pushed-screen-id view-id))))))))
|
(reset! state/pushed-screen-id view-id))))))))
|
||||||
|
|
||||||
;; SCREEN DID DISAPPEAR
|
;; SCREEN DID DISAPPEAR
|
||||||
(defonce screen-disappear-reg
|
(defonce screen-disappear-reg
|
||||||
(.registerComponentDidDisappearListener
|
(.registerComponentDidDisappearListener
|
||||||
(.events Navigation)
|
(.events Navigation)
|
||||||
(fn [^js evn]
|
(fn [^js evn]
|
||||||
(let [view-id (keyword (.-componentName evn))]
|
(let [view-id (keyword (.-componentName evn))]
|
||||||
(when-not (#{"popover" "bottom-sheet" "signing-sheet" "visibility-status-popover" "wallet-connect-sheet" "wallet-connect-success-sheet" "wallet-connect-app-management-sheet"}
|
(when-not (#{"popover" "bottom-sheet" "signing-sheet" "visibility-status-popover"
|
||||||
(.-componentName evn))
|
"wallet-connect-sheet" "wallet-connect-success-sheet"
|
||||||
(re-frame/dispatch [::view-disappeared view-id])
|
"wallet-connect-app-management-sheet"}
|
||||||
(doseq [[_ {:keys [ref value]}] @quo.text-input/text-input-refs]
|
(.-componentName evn))
|
||||||
(.setNativeProps ^js ref (clj->js {:text value})))
|
(re-frame/dispatch [::view-disappeared view-id])
|
||||||
(doseq [[^js text-input default-value] @react/text-input-refs]
|
(doseq [[_ {:keys [ref value]}] @quo.text-input/text-input-refs]
|
||||||
(.setNativeProps text-input (clj->js {:text default-value}))))))))
|
(.setNativeProps ^js ref (clj->js {:text value})))
|
||||||
|
(doseq [[^js text-input default-value] @react/text-input-refs]
|
||||||
|
(.setNativeProps text-input (clj->js {:text default-value}))))))))
|
||||||
|
|
||||||
;; SET ROOT
|
;; SET ROOT
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
@@ -182,31 +191,34 @@
|
|||||||
(reset! state/root-id @state/root-comp-id)
|
(reset! state/root-id @state/root-comp-id)
|
||||||
(.setRoot Navigation (clj->js (get (roots/roots) new-root-id)))))
|
(.setRoot Navigation (clj->js (get (roots/roots) new-root-id)))))
|
||||||
|
|
||||||
(fx/defn set-multiaccount-root
|
(rf/defn set-multiaccount-root
|
||||||
{:events [::set-multiaccount-root]}
|
{:events [::set-multiaccount-root]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(log/debug :set-multiaccounts-root)
|
(log/debug :set-multiaccounts-root)
|
||||||
(let [key-uid (get-in db [:multiaccounts/login :key-uid])
|
(let [key-uid (get-in db [:multiaccounts/login :key-uid])
|
||||||
keycard-account? (boolean (get-in db [:multiaccounts/multiaccounts
|
keycard-account? (boolean (get-in db
|
||||||
key-uid
|
[:multiaccounts/multiaccounts
|
||||||
:keycard-pairing]))]
|
key-uid
|
||||||
|
:keycard-pairing]))]
|
||||||
{:init-root-fx (if keycard-account? :multiaccounts-keycard :multiaccounts)}))
|
{:init-root-fx (if keycard-account? :multiaccounts-keycard :multiaccounts)}))
|
||||||
|
|
||||||
(defonce rset-app-launched
|
(defonce
|
||||||
(.registerAppLaunchedListener (.events Navigation)
|
rset-app-launched
|
||||||
(fn []
|
(.registerAppLaunchedListener (.events Navigation)
|
||||||
(reset! state/curr-modal false)
|
(fn []
|
||||||
(reset! state/dissmissing false)
|
(reset! state/curr-modal false)
|
||||||
(if (or (= @state/root-id :multiaccounts)
|
(reset! state/dissmissing false)
|
||||||
(= @state/root-id :multiaccounts-keycard))
|
(if (or (= @state/root-id :multiaccounts)
|
||||||
(re-frame/dispatch-sync [::set-multiaccount-root])
|
(= @state/root-id :multiaccounts-keycard))
|
||||||
(when @state/root-id
|
(re-frame/dispatch-sync [::set-multiaccount-root])
|
||||||
(reset! state/root-comp-id @state/root-id)
|
(when @state/root-id
|
||||||
(.setRoot Navigation (clj->js (get (roots/roots) @state/root-id)))
|
(reset! state/root-comp-id @state/root-id)
|
||||||
(re-frame/dispatch [::login-core/check-last-chat])))
|
(.setRoot Navigation (clj->js (get (roots/roots) @state/root-id)))
|
||||||
(.hide ^js splash-screen))))
|
(re-frame/dispatch [::login-core/check-last-chat])))
|
||||||
|
(.hide ^js splash-screen))))
|
||||||
|
|
||||||
(defn get-screen-component [comp]
|
(defn get-screen-component
|
||||||
|
[comp]
|
||||||
(log/debug :get-screen-component comp)
|
(log/debug :get-screen-component comp)
|
||||||
(let [{:keys [options]} (get views/screens comp)]
|
(let [{:keys [options]} (get views/screens comp)]
|
||||||
{:component {:id comp
|
{:component {:id comp
|
||||||
@@ -227,24 +239,28 @@
|
|||||||
(get-screen-component comp))))))
|
(get-screen-component comp))))))
|
||||||
|
|
||||||
;; BOTTOM TABS
|
;; BOTTOM TABS
|
||||||
(def tab-root-ids {0 :chat-stack
|
(def tab-root-ids
|
||||||
1 :browser-stack
|
{0 :chat-stack
|
||||||
2 :wallet-stack
|
1 :browser-stack
|
||||||
3 :status-stack
|
2 :wallet-stack
|
||||||
4 :profile-stack})
|
3 :status-stack
|
||||||
|
4 :profile-stack})
|
||||||
|
|
||||||
(def tab-key-idx {:chat 0
|
(def tab-key-idx
|
||||||
:browser 1
|
{:chat 0
|
||||||
:wallet 2
|
:browser 1
|
||||||
:status 3
|
:wallet 2
|
||||||
:profile 4})
|
:status 3
|
||||||
|
:profile 4})
|
||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
:change-tab-fx
|
:change-tab-fx
|
||||||
(fn [tab]
|
(fn [tab]
|
||||||
(log/debug :change-tab-fx)
|
(log/debug :change-tab-fx)
|
||||||
(reset! state/root-comp-id (get tab-root-ids (get tab-key-idx tab)))
|
(reset! state/root-comp-id (get tab-root-ids (get tab-key-idx tab)))
|
||||||
(.mergeOptions Navigation "tabs-stack" (clj->js {:bottomTabs {:currentTabIndex (get tab-key-idx tab)}}))
|
(.mergeOptions Navigation
|
||||||
|
"tabs-stack"
|
||||||
|
(clj->js {:bottomTabs {:currentTabIndex (get tab-key-idx tab)}}))
|
||||||
;;when we change tab we want to dismiss all modals
|
;;when we change tab we want to dismiss all modals
|
||||||
(dismiss-all-modals)))
|
(dismiss-all-modals)))
|
||||||
|
|
||||||
@@ -253,21 +269,22 @@
|
|||||||
:change-tab-count-fx
|
:change-tab-count-fx
|
||||||
(fn [[tab cnt]]
|
(fn [[tab cnt]]
|
||||||
(log/debug :change-tab-count-fx tab cnt)
|
(log/debug :change-tab-count-fx tab cnt)
|
||||||
(.mergeOptions Navigation
|
(.mergeOptions
|
||||||
(name (get tab-root-ids (get tab-key-idx tab)))
|
Navigation
|
||||||
(clj->js {:bottomTab (cond
|
(name (get tab-root-ids (get tab-key-idx tab)))
|
||||||
(or (pos? cnt) (pos? (:other cnt)))
|
(clj->js {:bottomTab (cond
|
||||||
(if (and (= :chat tab) platform/ios?)
|
(or (pos? cnt) (pos? (:other cnt)))
|
||||||
{:dotIndicator {:visible true}}
|
(if (and (= :chat tab) platform/ios?)
|
||||||
{:badge (str (or (:other cnt) cnt)) :dotIndicator {:visible false}})
|
{:dotIndicator {:visible true}}
|
||||||
(pos? (:public cnt))
|
{:badge (str (or (:other cnt) cnt)) :dotIndicator {:visible false}})
|
||||||
(if platform/ios?
|
(pos? (:public cnt))
|
||||||
{:dotIndicator {:visible true}}
|
(if platform/ios?
|
||||||
{:badge nil :dotIndicator {:visible true}})
|
{:dotIndicator {:visible true}}
|
||||||
:else
|
{:badge nil :dotIndicator {:visible true}})
|
||||||
(if (and (= :chat tab) platform/ios?)
|
:else
|
||||||
{:dotIndicator {:visible false}}
|
(if (and (= :chat tab) platform/ios?)
|
||||||
{:dotIndicator {:visible false} :badge ""}))}))))
|
{:dotIndicator {:visible false}}
|
||||||
|
{:dotIndicator {:visible false} :badge ""}))}))))
|
||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
:pop-to-root-tab-fx
|
:pop-to-root-tab-fx
|
||||||
@@ -277,54 +294,57 @@
|
|||||||
(.popToRoot Navigation (name comp))))
|
(.popToRoot Navigation (name comp))))
|
||||||
|
|
||||||
(defonce register-bottom-tab-reg
|
(defonce register-bottom-tab-reg
|
||||||
(.registerBottomTabSelectedListener
|
(.registerBottomTabSelectedListener
|
||||||
(.events Navigation)
|
(.events Navigation)
|
||||||
(fn [^js evn]
|
(fn [^js evn]
|
||||||
(let [selected-tab-index (.-selectedTabIndex evn)
|
(let [selected-tab-index (.-selectedTabIndex evn)
|
||||||
comp (get tab-root-ids selected-tab-index)
|
comp (get tab-root-ids selected-tab-index)
|
||||||
tab-key (get (clojure.set/map-invert tab-key-idx) selected-tab-index)]
|
tab-key (get (clojure.set/map-invert tab-key-idx) selected-tab-index)]
|
||||||
(re-frame/dispatch [:set :current-tab tab-key])
|
(re-frame/dispatch [:set :current-tab tab-key])
|
||||||
(when (= @state/root-comp-id comp)
|
(when (= @state/root-comp-id comp)
|
||||||
(when (= :chat tab-key)
|
(when (= :chat tab-key)
|
||||||
(re-frame/dispatch [:close-chat]))
|
(re-frame/dispatch [:close-chat]))
|
||||||
(when platform/android?
|
(when platform/android?
|
||||||
(.popToRoot Navigation (name comp))))
|
(.popToRoot Navigation (name comp))))
|
||||||
(reset! state/root-comp-id comp)))))
|
(reset! state/root-comp-id comp)))))
|
||||||
|
|
||||||
;; OVERLAY (Popover and bottom sheets)
|
;; OVERLAY (Popover and bottom sheets)
|
||||||
(defn dissmiss-overlay [comp]
|
(defn dissmiss-overlay
|
||||||
|
[comp]
|
||||||
(.catch (.dismissOverlay Navigation comp) #()))
|
(.catch (.dismissOverlay Navigation comp) #()))
|
||||||
|
|
||||||
(defn show-overlay [comp]
|
(defn show-overlay
|
||||||
|
[comp]
|
||||||
(dissmiss-overlay comp)
|
(dissmiss-overlay comp)
|
||||||
(.showOverlay Navigation
|
(.showOverlay
|
||||||
(clj->js
|
Navigation
|
||||||
{:component {:name comp
|
(clj->js
|
||||||
:id comp
|
{:component {:name comp
|
||||||
:options (merge (cond-> (roots/status-bar-options)
|
:id comp
|
||||||
(and platform/android? (not (quo.colors/dark?)))
|
:options (merge (cond-> (roots/status-bar-options)
|
||||||
(assoc-in [:statusBar :backgroundColor] "#99999A"))
|
(and platform/android? (not (quo.colors/dark?)))
|
||||||
{:layout {:componentBackgroundColor (if platform/android?
|
(assoc-in [:statusBar :backgroundColor] "#99999A"))
|
||||||
(:backdrop @quo.colors/theme)
|
{:layout {:componentBackgroundColor (if platform/android?
|
||||||
"transparent")}
|
(:backdrop @quo.colors/theme)
|
||||||
:overlay {:interceptTouchOutside true}})}})))
|
"transparent")}
|
||||||
|
:overlay {:interceptTouchOutside true}})}})))
|
||||||
|
|
||||||
;; POPOVER
|
;; POPOVER
|
||||||
(defonce popover-reg
|
(defonce popover-reg
|
||||||
(.registerComponent Navigation
|
(.registerComponent Navigation
|
||||||
"popover"
|
"popover"
|
||||||
(fn [] (gestureHandlerRootHOC views/popover-comp))
|
(fn [] (gestureHandlerRootHOC views/popover-comp))
|
||||||
(fn [] views/popover-comp)))
|
(fn [] views/popover-comp)))
|
||||||
|
|
||||||
(re-frame/reg-fx :show-popover (fn [] (show-overlay "popover")))
|
(re-frame/reg-fx :show-popover (fn [] (show-overlay "popover")))
|
||||||
(re-frame/reg-fx :hide-popover (fn [] (dissmiss-overlay "popover")))
|
(re-frame/reg-fx :hide-popover (fn [] (dissmiss-overlay "popover")))
|
||||||
|
|
||||||
;; VISIBILITY STATUS POPOVER
|
;; VISIBILITY STATUS POPOVER
|
||||||
(defonce visibility-status-popover-reg
|
(defonce visibility-status-popover-reg
|
||||||
(.registerComponent Navigation
|
(.registerComponent Navigation
|
||||||
"visibility-status-popover"
|
"visibility-status-popover"
|
||||||
(fn [] (gestureHandlerRootHOC views/visibility-status-popover-comp))
|
(fn [] (gestureHandlerRootHOC views/visibility-status-popover-comp))
|
||||||
(fn [] views/visibility-status-popover-comp)))
|
(fn [] views/visibility-status-popover-comp)))
|
||||||
|
|
||||||
(re-frame/reg-fx :show-visibility-status-popover
|
(re-frame/reg-fx :show-visibility-status-popover
|
||||||
(fn [] (show-overlay "visibility-status-popover")))
|
(fn [] (show-overlay "visibility-status-popover")))
|
||||||
@@ -333,10 +353,10 @@
|
|||||||
|
|
||||||
;; BOTTOM SHEETS
|
;; BOTTOM SHEETS
|
||||||
(defonce bottom-sheet-reg
|
(defonce bottom-sheet-reg
|
||||||
(.registerComponent Navigation
|
(.registerComponent Navigation
|
||||||
"bottom-sheet"
|
"bottom-sheet"
|
||||||
(fn [] (gestureHandlerRootHOC views/sheet-comp))
|
(fn [] (gestureHandlerRootHOC views/sheet-comp))
|
||||||
(fn [] views/sheet-comp)))
|
(fn [] views/sheet-comp)))
|
||||||
|
|
||||||
(re-frame/reg-fx :show-bottom-sheet (fn [] (show-overlay "bottom-sheet")))
|
(re-frame/reg-fx :show-bottom-sheet (fn [] (show-overlay "bottom-sheet")))
|
||||||
(re-frame/reg-fx :hide-bottom-sheet (fn [] (dissmiss-overlay "bottom-sheet")))
|
(re-frame/reg-fx :hide-bottom-sheet (fn [] (dissmiss-overlay "bottom-sheet")))
|
||||||
@@ -344,37 +364,41 @@
|
|||||||
;; WALLET CONNECT
|
;; WALLET CONNECT
|
||||||
|
|
||||||
(defonce wallet-connect-sheet-reg
|
(defonce wallet-connect-sheet-reg
|
||||||
(.registerComponent Navigation
|
(.registerComponent Navigation
|
||||||
"wallet-connect-sheet"
|
"wallet-connect-sheet"
|
||||||
(fn [] (gestureHandlerRootHOC views/wallet-connect-comp))
|
(fn [] (gestureHandlerRootHOC views/wallet-connect-comp))
|
||||||
(fn [] views/wallet-connect-comp)))
|
(fn [] views/wallet-connect-comp)))
|
||||||
|
|
||||||
(defonce wallet-connect-success-sheet-reg
|
(defonce wallet-connect-success-sheet-reg
|
||||||
(.registerComponent Navigation
|
(.registerComponent Navigation
|
||||||
"wallet-connect-success-sheet"
|
"wallet-connect-success-sheet"
|
||||||
(fn [] (gestureHandlerRootHOC views/wallet-connect-success-comp))
|
(fn [] (gestureHandlerRootHOC views/wallet-connect-success-comp))
|
||||||
(fn [] views/wallet-connect-success-comp)))
|
(fn [] views/wallet-connect-success-comp)))
|
||||||
|
|
||||||
(defonce wallet-connect-app-management-sheet-reg
|
(defonce wallet-connect-app-management-sheet-reg
|
||||||
(.registerComponent Navigation
|
(.registerComponent Navigation
|
||||||
"wallet-connect-app-management-sheet"
|
"wallet-connect-app-management-sheet"
|
||||||
(fn [] (gestureHandlerRootHOC views/wallet-connect-app-management-comp))
|
(fn [] (gestureHandlerRootHOC views/wallet-connect-app-management-comp))
|
||||||
(fn [] views/wallet-connect-app-management-comp)))
|
(fn [] views/wallet-connect-app-management-comp)))
|
||||||
|
|
||||||
(re-frame/reg-fx :show-wallet-connect-sheet (fn [] (show-overlay "wallet-connect-sheet")))
|
(re-frame/reg-fx :show-wallet-connect-sheet (fn [] (show-overlay "wallet-connect-sheet")))
|
||||||
(re-frame/reg-fx :hide-wallet-connect-sheet (fn [] (dissmiss-overlay "wallet-connect-sheet")))
|
(re-frame/reg-fx :hide-wallet-connect-sheet (fn [] (dissmiss-overlay "wallet-connect-sheet")))
|
||||||
(re-frame/reg-fx :show-wallet-connect-success-sheet (fn [] (show-overlay "wallet-connect-success-sheet")))
|
(re-frame/reg-fx :show-wallet-connect-success-sheet
|
||||||
(re-frame/reg-fx :hide-wallet-connect-success-sheet (fn [] (dissmiss-overlay "wallet-connect-success-sheet")))
|
(fn [] (show-overlay "wallet-connect-success-sheet")))
|
||||||
(re-frame/reg-fx :show-wallet-connect-app-management-sheet (fn [] (show-overlay "wallet-connect-app-management-sheet")))
|
(re-frame/reg-fx :hide-wallet-connect-success-sheet
|
||||||
(re-frame/reg-fx :hide-wallet-connect-app-management-sheet (fn [] (dissmiss-overlay "wallet-connect-app-management-sheet")))
|
(fn [] (dissmiss-overlay "wallet-connect-success-sheet")))
|
||||||
|
(re-frame/reg-fx :show-wallet-connect-app-management-sheet
|
||||||
|
(fn [] (show-overlay "wallet-connect-app-management-sheet")))
|
||||||
|
(re-frame/reg-fx :hide-wallet-connect-app-management-sheet
|
||||||
|
(fn [] (dissmiss-overlay "wallet-connect-app-management-sheet")))
|
||||||
|
|
||||||
;; SIGNING
|
;; SIGNING
|
||||||
|
|
||||||
(defonce signing-sheet-reg
|
(defonce signing-sheet-reg
|
||||||
(.registerComponent Navigation
|
(.registerComponent Navigation
|
||||||
"signing-sheet"
|
"signing-sheet"
|
||||||
(fn [] (gestureHandlerRootHOC views/signing-comp))
|
(fn [] (gestureHandlerRootHOC views/signing-comp))
|
||||||
(fn [] views/signing-comp)))
|
(fn [] views/signing-comp)))
|
||||||
|
|
||||||
(re-frame/reg-fx :show-signing-sheet (fn [] (show-overlay "signing-sheet")))
|
(re-frame/reg-fx :show-signing-sheet (fn [] (show-overlay "signing-sheet")))
|
||||||
(re-frame/reg-fx :hide-signing-sheet (fn [] (dissmiss-overlay "signing-sheet")))
|
(re-frame/reg-fx :hide-signing-sheet (fn [] (dissmiss-overlay "signing-sheet")))
|
||||||
@@ -383,10 +407,10 @@
|
|||||||
;; TODO why is this not a regular bottom sheet ?
|
;; TODO why is this not a regular bottom sheet ?
|
||||||
|
|
||||||
(defonce select-acc-sheet-reg
|
(defonce select-acc-sheet-reg
|
||||||
(.registerComponent Navigation
|
(.registerComponent Navigation
|
||||||
"select-acc-sheet"
|
"select-acc-sheet"
|
||||||
(fn [] (gestureHandlerRootHOC views/select-acc-comp))
|
(fn [] (gestureHandlerRootHOC views/select-acc-comp))
|
||||||
(fn [] views/select-acc-comp)))
|
(fn [] views/select-acc-comp)))
|
||||||
|
|
||||||
(re-frame/reg-fx :show-select-acc-sheet (fn [] (show-overlay "select-acc-sheet")))
|
(re-frame/reg-fx :show-select-acc-sheet (fn [] (show-overlay "select-acc-sheet")))
|
||||||
(re-frame/reg-fx :hide-select-acc-sheet (fn [] (dissmiss-overlay "select-acc-sheet")))
|
(re-frame/reg-fx :hide-select-acc-sheet (fn [] (dissmiss-overlay "select-acc-sheet")))
|
||||||
@@ -414,28 +438,31 @@
|
|||||||
(.pop Navigation (name @state/root-comp-id))
|
(.pop Navigation (name @state/root-comp-id))
|
||||||
(navigate view-id)))
|
(navigate view-id)))
|
||||||
|
|
||||||
(def community-screens '(:community-management
|
(def community-screens
|
||||||
:community-members
|
'(:community-management
|
||||||
:community-requests-to-join
|
:community-members
|
||||||
:create-community-channel
|
:community-requests-to-join
|
||||||
:community-emoji-thumbnail-picker
|
:create-community-channel
|
||||||
:create-community-category
|
:community-emoji-thumbnail-picker
|
||||||
:community-edit-chats
|
:create-community-category
|
||||||
:community-edit
|
:community-edit-chats
|
||||||
:community-reorder-categories))
|
:community-edit
|
||||||
|
:community-reorder-categories))
|
||||||
|
|
||||||
;; change view-id if it is still same after component is disappeared
|
;; change view-id if it is still same after component is disappeared
|
||||||
;; https://github.com/wix/react-native-navigation/issues/5744#issuecomment-563226820
|
;; https://github.com/wix/react-native-navigation/issues/5744#issuecomment-563226820
|
||||||
(fx/defn view-disappeared
|
(rf/defn view-disappeared
|
||||||
{:events [::view-disappeared]}
|
{:events [::view-disappeared]}
|
||||||
[{:keys [db]} view-id]
|
[{:keys [db]} view-id]
|
||||||
(when (= view-id (:view-id db))
|
(when (= view-id (:view-id db))
|
||||||
{:db (assoc db :view-id (cond
|
{:db (assoc db
|
||||||
(= view-id :community-emoji-thumbnail-picker)
|
:view-id
|
||||||
:create-community-channel
|
(cond
|
||||||
|
(= view-id :community-emoji-thumbnail-picker)
|
||||||
|
:create-community-channel
|
||||||
|
|
||||||
(some #(= view-id %) community-screens)
|
(some #(= view-id %) community-screens)
|
||||||
:community
|
:community
|
||||||
|
|
||||||
:else
|
:else
|
||||||
:home))}))
|
:home))}))
|
||||||
|
|||||||
@@ -5,37 +5,42 @@
|
|||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
[status-im.i18n.i18n :as i18n]
|
[status-im.i18n.i18n :as i18n]
|
||||||
[status-im.node.core :as node]
|
[status-im.node.core :as node]
|
||||||
[status-im2.navigation.events :as navigation]
|
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[status-im.utils.http :as http]
|
[status-im.utils.http :as http]
|
||||||
[status-im.utils.types :as types]))
|
[status-im.utils.types :as types]
|
||||||
|
[status-im2.navigation.events :as navigation]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(def url-regex
|
(def url-regex
|
||||||
#"https?://(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}(\.[a-z]{2,6})?\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)")
|
#"https?://(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}(\.[a-z]{2,6})?\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)")
|
||||||
|
|
||||||
(defn valid-rpc-url? [url]
|
(defn valid-rpc-url?
|
||||||
|
[url]
|
||||||
(boolean (re-matches url-regex (str url))))
|
(boolean (re-matches url-regex (str url))))
|
||||||
|
|
||||||
(def default-manage
|
(def default-manage
|
||||||
{:name {:value ""}
|
{:name {:value ""}
|
||||||
:url {:value ""}
|
:url {:value ""}
|
||||||
:symbol {:value ""}
|
:symbol {:value ""}
|
||||||
:chain {:value :mainnet}})
|
:chain {:value :mainnet}})
|
||||||
|
|
||||||
(defn validate-string [{:keys [value]}]
|
(defn validate-string
|
||||||
|
[{:keys [value]}]
|
||||||
{:value value
|
{:value value
|
||||||
:error (string/blank? value)})
|
:error (string/blank? value)})
|
||||||
|
|
||||||
(defn validate-network-id [{:keys [value]}]
|
(defn validate-network-id
|
||||||
|
[{:keys [value]}]
|
||||||
{:value value
|
{:value value
|
||||||
:error (and (not (string/blank? value))
|
:error (and (not (string/blank? value))
|
||||||
(= (int value) 0))})
|
(= (int value) 0))})
|
||||||
|
|
||||||
(defn validate-url [{:keys [value]}]
|
(defn validate-url
|
||||||
|
[{:keys [value]}]
|
||||||
{:value value
|
{:value value
|
||||||
:error (not (valid-rpc-url? value))})
|
:error (not (valid-rpc-url? value))})
|
||||||
|
|
||||||
(defn validate-manage [manage]
|
(defn validate-manage
|
||||||
|
[manage]
|
||||||
(-> manage
|
(-> manage
|
||||||
(update :url validate-url)
|
(update :url validate-url)
|
||||||
(update :name validate-string)
|
(update :name validate-string)
|
||||||
@@ -43,20 +48,23 @@
|
|||||||
(update :chain validate-string)
|
(update :chain validate-string)
|
||||||
(update :network-id validate-network-id)))
|
(update :network-id validate-network-id)))
|
||||||
|
|
||||||
(defn valid-manage? [manage]
|
(defn valid-manage?
|
||||||
|
[manage]
|
||||||
(->> (validate-manage manage)
|
(->> (validate-manage manage)
|
||||||
vals
|
vals
|
||||||
(map :error)
|
(map :error)
|
||||||
(not-any? identity)))
|
(not-any? identity)))
|
||||||
|
|
||||||
(defn chain-id-available? [current-networks network]
|
(defn chain-id-available?
|
||||||
|
[current-networks network]
|
||||||
(let [chain-id (get-in network [:config :NetworkId])]
|
(let [chain-id (get-in network [:config :NetworkId])]
|
||||||
(every? #(not= chain-id (get-in % [1 :config :NetworkId])) current-networks)))
|
(every? #(not= chain-id (get-in % [1 :config :NetworkId])) current-networks)))
|
||||||
|
|
||||||
(defn get-network [{:keys [db]} network-id]
|
(defn get-network
|
||||||
|
[{:keys [db]} network-id]
|
||||||
(get-in db [:networks/networks network-id]))
|
(get-in db [:networks/networks network-id]))
|
||||||
|
|
||||||
(fx/defn set-input
|
(rf/defn set-input
|
||||||
{:events [::input-changed]}
|
{:events [::input-changed]}
|
||||||
[{:keys [db]} input-key value]
|
[{:keys [db]} input-key value]
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
@@ -64,13 +72,13 @@
|
|||||||
(update-in [:networks/manage] validate-manage))})
|
(update-in [:networks/manage] validate-manage))})
|
||||||
|
|
||||||
;; No edit functionality actually implemented
|
;; No edit functionality actually implemented
|
||||||
(fx/defn edit
|
(rf/defn edit
|
||||||
{:events [::add-network-pressed]}
|
{:events [::add-network-pressed]}
|
||||||
[{db :db}]
|
[{db :db}]
|
||||||
{:db (assoc db :networks/manage (validate-manage default-manage))
|
{:db (assoc db :networks/manage (validate-manage default-manage))
|
||||||
:dispatch [:navigate-to :edit-network]})
|
:dispatch [:navigate-to :edit-network]})
|
||||||
|
|
||||||
(fx/defn connect-success
|
(rf/defn connect-success
|
||||||
{:events [::connect-success]}
|
{:events [::connect-success]}
|
||||||
[_ network-id]
|
[_ network-id]
|
||||||
{:ui/show-confirmation
|
{:ui/show-confirmation
|
||||||
@@ -80,14 +88,14 @@
|
|||||||
:on-accept #(re-frame/dispatch [::save-network-settings-pressed network-id])
|
:on-accept #(re-frame/dispatch [::save-network-settings-pressed network-id])
|
||||||
:on-cancel nil}})
|
:on-cancel nil}})
|
||||||
|
|
||||||
(fx/defn connect-failure
|
(rf/defn connect-failure
|
||||||
{:events [::connect-failure]}
|
{:events [::connect-failure]}
|
||||||
[_ reason]
|
[_ reason]
|
||||||
{:utils/show-popup
|
{:utils/show-popup
|
||||||
{:title (i18n/label :t/error)
|
{:title (i18n/label :t/error)
|
||||||
:content (str reason)}})
|
:content (str reason)}})
|
||||||
|
|
||||||
(fx/defn connect
|
(rf/defn connect
|
||||||
{:events [::connect-network-pressed]}
|
{:events [::connect-network-pressed]}
|
||||||
[{:keys [db] :as cofx} network-id]
|
[{:keys [db] :as cofx} network-id]
|
||||||
(if-let [config (get-in db [:networks/networks network-id :config])]
|
(if-let [config (get-in db [:networks/networks network-id :config])]
|
||||||
@@ -104,18 +112,20 @@
|
|||||||
(js/parseInt res))]
|
(js/parseInt res))]
|
||||||
(if (and network-id (= expected-network-id rpc-network-id))
|
(if (and network-id (= expected-network-id rpc-network-id))
|
||||||
(re-frame/dispatch [::connect-success network-id])
|
(re-frame/dispatch [::connect-success network-id])
|
||||||
(re-frame/dispatch [::connect-failure (if (not= expected-network-id rpc-network-id)
|
(re-frame/dispatch [::connect-failure
|
||||||
(i18n/label :t/network-invalid-network-id)
|
(if (not= expected-network-id rpc-network-id)
|
||||||
(i18n/label :t/network-invalid-url))]))))
|
(i18n/label :t/network-invalid-network-id)
|
||||||
|
(i18n/label :t/network-invalid-url))]))))
|
||||||
:on-error (fn [{:keys [response-body status-code]}]
|
:on-error (fn [{:keys [response-body status-code]}]
|
||||||
(let [reason (if status-code
|
(let [reason (if status-code
|
||||||
(i18n/label :t/network-invalid-status-code {:code status-code})
|
(i18n/label :t/network-invalid-status-code
|
||||||
|
{:code status-code})
|
||||||
(str response-body))]
|
(str response-body))]
|
||||||
(re-frame/dispatch [::connect-failure reason])))}}
|
(re-frame/dispatch [::connect-failure reason])))}}
|
||||||
(connect-success cofx network-id))
|
(connect-success cofx network-id))
|
||||||
(connect-failure cofx "A network with the specified id doesn't exist")))
|
(connect-failure cofx "A network with the specified id doesn't exist")))
|
||||||
|
|
||||||
(fx/defn delete
|
(rf/defn delete
|
||||||
{:events [::delete-network-pressed]}
|
{:events [::delete-network-pressed]}
|
||||||
[{:keys [db]} network]
|
[{:keys [db]} network]
|
||||||
(let [current-network? (= (:networks/current-network db) network)]
|
(let [current-network? (= (:networks/current-network db) network)]
|
||||||
@@ -125,26 +135,27 @@
|
|||||||
{:ui/show-confirmation {:title (i18n/label :t/delete-network-title)
|
{:ui/show-confirmation {:title (i18n/label :t/delete-network-title)
|
||||||
:content (i18n/label :t/delete-network-confirmation)
|
:content (i18n/label :t/delete-network-confirmation)
|
||||||
:confirm-button-text (i18n/label :t/delete)
|
:confirm-button-text (i18n/label :t/delete)
|
||||||
:on-accept #(re-frame/dispatch [::remove-network-confirmed network])
|
:on-accept #(re-frame/dispatch [::remove-network-confirmed
|
||||||
|
network])
|
||||||
:on-cancel nil}})))
|
:on-cancel nil}})))
|
||||||
|
|
||||||
(fx/defn save-network-settings
|
(rf/defn save-network-settings
|
||||||
{:events [::save-network-settings-pressed]}
|
{:events [::save-network-settings-pressed]}
|
||||||
[{:keys [db] :as cofx} network]
|
[{:keys [db] :as cofx} network]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc db :networks/current-network network)
|
{:db (assoc db :networks/current-network network)
|
||||||
::json-rpc/call [{:method "settings_saveSetting"
|
::json-rpc/call [{:method "settings_saveSetting"
|
||||||
:params [:networks/current-network network]
|
:params [:networks/current-network network]
|
||||||
:on-success #()}]}
|
:on-success #()}]}
|
||||||
(node/prepare-new-config {:on-success #(re-frame/dispatch [:logout])})))
|
(node/prepare-new-config {:on-success #(re-frame/dispatch [:logout])})))
|
||||||
|
|
||||||
(fx/defn remove-network
|
(rf/defn remove-network
|
||||||
{:events [::remove-network-confirmed]}
|
{:events [::remove-network-confirmed]}
|
||||||
[{:keys [db] :as cofx} network]
|
[{:keys [db] :as cofx} network]
|
||||||
(let [networks (dissoc (:networks/networks db) network)]
|
(let [networks (dissoc (:networks/networks db) network)]
|
||||||
{:db (assoc db :networks/networks networks)
|
{:db (assoc db :networks/networks networks)
|
||||||
::json-rpc/call [{:method "settings_saveSetting"
|
::json-rpc/call [{:method "settings_saveSetting"
|
||||||
:params [:networks/networks (vals networks)]
|
:params [:networks/networks (vals networks)]
|
||||||
:on-success #(re-frame/dispatch [:navigate-back])}]}))
|
:on-success #(re-frame/dispatch [:navigate-back])}]}))
|
||||||
|
|
||||||
(defn new-network
|
(defn new-network
|
||||||
@@ -155,40 +166,41 @@
|
|||||||
:DataDir data-dir
|
:DataDir data-dir
|
||||||
:UpstreamConfig {:Enabled true
|
:UpstreamConfig {:Enabled true
|
||||||
:URL upstream-url}}]
|
:URL upstream-url}}]
|
||||||
{:id random-id
|
{:id random-id
|
||||||
:name network-name
|
:name network-name
|
||||||
:symbol symbol
|
:symbol symbol
|
||||||
:config config}))
|
:config config}))
|
||||||
|
|
||||||
(fx/defn save
|
(rf/defn save
|
||||||
{:events [::save-network-pressed]
|
{:events [::save-network-pressed]
|
||||||
:interceptors [(re-frame/inject-cofx :random-id-generator)]}
|
:interceptors [(re-frame/inject-cofx :random-id-generator)]}
|
||||||
[{{:networks/keys [manage networks] :as db} :db
|
[{{:networks/keys [manage networks] :as db} :db
|
||||||
random-id-generator :random-id-generator :as cofx}]
|
random-id-generator :random-id-generator
|
||||||
|
:as cofx}]
|
||||||
(if (valid-manage? manage)
|
(if (valid-manage? manage)
|
||||||
;; rename network-id from UI to chain-id
|
;; rename network-id from UI to chain-id
|
||||||
(let [{:keys [name url chain network-id symbol]} manage
|
(let [{:keys [name url chain network-id symbol]} manage
|
||||||
random-id (string/replace (random-id-generator) "-" "")
|
random-id (string/replace (random-id-generator) "-" "")
|
||||||
network (new-network random-id
|
network (new-network random-id
|
||||||
(:value name)
|
(:value name)
|
||||||
(:value symbol)
|
(:value symbol)
|
||||||
(:value url)
|
(:value url)
|
||||||
(:value chain)
|
(:value chain)
|
||||||
(:value network-id))
|
(:value network-id))
|
||||||
custom-chain-type? (= :custom (:value chain))
|
custom-chain-type? (= :custom (:value chain))
|
||||||
new-networks (assoc networks random-id network)]
|
new-networks (assoc networks random-id network)]
|
||||||
(if (or (not custom-chain-type?)
|
(if (or (not custom-chain-type?)
|
||||||
(chain-id-available? networks network))
|
(chain-id-available? networks network))
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(dissoc :networks/manage)
|
(dissoc :networks/manage)
|
||||||
(assoc :networks/networks new-networks))
|
(assoc :networks/networks new-networks))
|
||||||
::json-rpc/call [{:method "settings_saveSetting"
|
::json-rpc/call [{:method "settings_saveSetting"
|
||||||
:params [:networks/networks (vals new-networks)]
|
:params [:networks/networks (vals new-networks)]
|
||||||
:on-success #(re-frame/dispatch [:navigate-back])}]}
|
:on-success #(re-frame/dispatch [:navigate-back])}]}
|
||||||
{:ui/show-error "chain-id already defined"}))
|
{:ui/show-error "chain-id already defined"}))
|
||||||
{:ui/show-error "invalid network parameters"}))
|
{:ui/show-error "invalid network parameters"}))
|
||||||
|
|
||||||
(fx/defn open-network-details
|
(rf/defn open-network-details
|
||||||
{:events [::network-entry-pressed]}
|
{:events [::network-entry-pressed]}
|
||||||
[cofx network]
|
[cofx network]
|
||||||
(navigation/navigate-to-cofx cofx :network-details {:networks/selected-network network}))
|
(navigation/navigate-to-cofx cofx :network-details {:networks/selected-network network}))
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
(ns status-im.network.net-info
|
(ns status-im.network.net-info
|
||||||
(:require [re-frame.core :as re-frame]
|
(:require ["@react-native-community/netinfo" :default net-info]
|
||||||
[status-im.native-module.core :as status]
|
[re-frame.core :as re-frame]
|
||||||
[status-im.mobile-sync-settings.core :as mobile-network]
|
[status-im.mobile-sync-settings.core :as mobile-network]
|
||||||
[status-im.utils.fx :as fx]
|
[status-im.native-module.core :as status]
|
||||||
[status-im.wallet.core :as wallet]
|
[status-im.wallet.core :as wallet]
|
||||||
["@react-native-community/netinfo" :default net-info]
|
[taoensso.timbre :as log]
|
||||||
[taoensso.timbre :as log]))
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(fx/defn change-network-status
|
(rf/defn change-network-status
|
||||||
[{:keys [db] :as cofx} is-connected?]
|
[{:keys [db] :as cofx} is-connected?]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc db :network-status (if is-connected? :online :offline))}
|
{:db (assoc db :network-status (if is-connected? :online :offline))}
|
||||||
(when (and is-connected?
|
(when (and is-connected?
|
||||||
(or (not= (count (get-in db [:wallet :accounts]))
|
(or (not= (count (get-in db [:wallet :accounts]))
|
||||||
@@ -17,14 +17,14 @@
|
|||||||
(wallet/has-empty-balances? db)))
|
(wallet/has-empty-balances? db)))
|
||||||
(wallet/update-balances nil nil))))
|
(wallet/update-balances nil nil))))
|
||||||
|
|
||||||
(fx/defn change-network-type
|
(rf/defn change-network-type
|
||||||
[{:keys [db] :as cofx} old-network-type network-type expensive?]
|
[{:keys [db] :as cofx} old-network-type network-type expensive?]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc db :network/type network-type)
|
{:db (assoc db :network/type network-type)
|
||||||
:network/notify-status-go [network-type expensive?]}
|
:network/notify-status-go [network-type expensive?]}
|
||||||
(mobile-network/on-network-status-change)))
|
(mobile-network/on-network-status-change)))
|
||||||
|
|
||||||
(fx/defn handle-network-info-change
|
(rf/defn handle-network-info-change
|
||||||
{:events [::network-info-changed]}
|
{:events [::network-info-changed]}
|
||||||
[{:keys [db] :as cofx} {:keys [isConnected type details] :as state}]
|
[{:keys [db] :as cofx} {:keys [isConnected type details] :as state}]
|
||||||
(let [old-network-status (:network-status db)
|
(let [old-network-status (:network-status db)
|
||||||
@@ -33,18 +33,19 @@
|
|||||||
status-changed? (= connectivity-status old-network-status)
|
status-changed? (= connectivity-status old-network-status)
|
||||||
type-changed? (= type old-network-type)]
|
type-changed? (= type old-network-type)]
|
||||||
(log/debug "[net-info]"
|
(log/debug "[net-info]"
|
||||||
"old-network-status" old-network-status
|
"old-network-status" old-network-status
|
||||||
"old-network-type" old-network-type
|
"old-network-type" old-network-type
|
||||||
"connectivity-status" connectivity-status
|
"connectivity-status" connectivity-status
|
||||||
"type" type
|
"type" type
|
||||||
"details" details)
|
"details" details)
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(when-not status-changed?
|
(when-not status-changed?
|
||||||
(change-network-status isConnected))
|
(change-network-status isConnected))
|
||||||
(when-not type-changed?
|
(when-not type-changed?
|
||||||
(change-network-type old-network-type type (:is-connection-expensive details))))))
|
(change-network-type old-network-type type (:is-connection-expensive details))))))
|
||||||
|
|
||||||
(defn add-net-info-listener []
|
(defn add-net-info-listener
|
||||||
|
[]
|
||||||
(when net-info
|
(when net-info
|
||||||
(.addEventListener ^js net-info
|
(.addEventListener ^js net-info
|
||||||
#(re-frame/dispatch [::network-info-changed
|
#(re-frame/dispatch [::network-info-changed
|
||||||
|
|||||||
@@ -3,11 +3,12 @@
|
|||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
[status-im.native-module.core :as status]
|
[status-im.native-module.core :as status]
|
||||||
[status-im.utils.config :as config]
|
[status-im.utils.config :as config]
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[status-im.utils.platform :as utils.platform]
|
[status-im.utils.platform :as utils.platform]
|
||||||
[status-im.utils.types :as types]))
|
[status-im.utils.types :as types]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(defn- add-custom-bootnodes [config network all-bootnodes]
|
(defn- add-custom-bootnodes
|
||||||
|
[config network all-bootnodes]
|
||||||
(let [bootnodes (as-> all-bootnodes $
|
(let [bootnodes (as-> all-bootnodes $
|
||||||
(get $ network)
|
(get $ network)
|
||||||
(vals $)
|
(vals $)
|
||||||
@@ -16,18 +17,19 @@
|
|||||||
(assoc-in config [:ClusterConfig :BootNodes] bootnodes)
|
(assoc-in config [:ClusterConfig :BootNodes] bootnodes)
|
||||||
config)))
|
config)))
|
||||||
|
|
||||||
(defn- add-log-level [config log-level]
|
(defn- add-log-level
|
||||||
|
[config log-level]
|
||||||
(if (empty? log-level)
|
(if (empty? log-level)
|
||||||
(assoc config
|
(assoc config
|
||||||
:MaxPeers 20
|
:MaxPeers 20
|
||||||
:MaxPendingPeers 20
|
:MaxPendingPeers 20
|
||||||
:LogLevel "ERROR"
|
:LogLevel "ERROR"
|
||||||
:LogEnabled false)
|
:LogEnabled false)
|
||||||
(assoc config
|
(assoc config
|
||||||
:MaxPeers 20
|
:MaxPeers 20
|
||||||
:MaxPendingPeers 20
|
:MaxPendingPeers 20
|
||||||
:LogLevel log-level
|
:LogLevel log-level
|
||||||
:LogEnabled true)))
|
:LogEnabled true)))
|
||||||
|
|
||||||
(defn get-network-genesis-hash-prefix
|
(defn get-network-genesis-hash-prefix
|
||||||
"returns the hex representation of the first 8 bytes of
|
"returns the hex representation of the first 8 bytes of
|
||||||
@@ -50,22 +52,25 @@
|
|||||||
(defn get-topics
|
(defn get-topics
|
||||||
[network]
|
[network]
|
||||||
(let [les-topic (get-les-topic network)]
|
(let [les-topic (get-les-topic network)]
|
||||||
(cond-> {"whisper" {:Min 2, :Max 2}}
|
(cond-> {"whisper" {:Min 2 :Max 2}}
|
||||||
les-topic (assoc les-topic {:Min 2, :Max 2}))))
|
les-topic (assoc les-topic {:Min 2 :Max 2}))))
|
||||||
|
|
||||||
(defn- get-base-node-config [config]
|
(defn- get-base-node-config
|
||||||
|
[config]
|
||||||
(cond-> (assoc config
|
(cond-> (assoc config
|
||||||
:Name "StatusIM")
|
:Name
|
||||||
|
"StatusIM")
|
||||||
config/dev-build?
|
config/dev-build?
|
||||||
(assoc :ListenAddr ":30304"
|
(assoc :ListenAddr ":30304"
|
||||||
:DataDir (str (:DataDir config) "_dev"))))
|
:DataDir (str (:DataDir config) "_dev"))))
|
||||||
|
|
||||||
(def login-node-config
|
(def login-node-config
|
||||||
{:WalletConfig (cond-> {:Enabled true}
|
{:WalletConfig (cond-> {:Enabled true}
|
||||||
(not= config/opensea-api-key "")
|
(not= config/opensea-api-key "")
|
||||||
(assoc :OpenseaAPIKey config/opensea-api-key))})
|
(assoc :OpenseaAPIKey config/opensea-api-key))})
|
||||||
|
|
||||||
(defn- get-login-node-config [config]
|
(defn- get-login-node-config
|
||||||
|
[config]
|
||||||
(merge config login-node-config))
|
(merge config login-node-config))
|
||||||
|
|
||||||
(defn- pick-nodes
|
(defn- pick-nodes
|
||||||
@@ -75,14 +80,17 @@
|
|||||||
[limit nodes]
|
[limit nodes]
|
||||||
(take limit (shuffle nodes)))
|
(take limit (shuffle nodes)))
|
||||||
|
|
||||||
(defn fleets [{:keys [custom-fleets]}]
|
(defn fleets
|
||||||
|
[{:keys [custom-fleets]}]
|
||||||
(as-> [(js/require "./fleets.js")] $
|
(as-> [(js/require "./fleets.js")] $
|
||||||
(mapv #(:fleets (types/json->clj %)) $)
|
(mapv #(:fleets (types/json->clj %)) $)
|
||||||
(conj $ custom-fleets)
|
(conj $ custom-fleets)
|
||||||
(reduce merge $)))
|
(reduce merge $)))
|
||||||
|
|
||||||
(defn current-fleet-key [db]
|
(defn current-fleet-key
|
||||||
(keyword (get-in db [:multiaccount :fleet]
|
[db]
|
||||||
|
(keyword (get-in db
|
||||||
|
[:multiaccount :fleet]
|
||||||
config/fleet)))
|
config/fleet)))
|
||||||
|
|
||||||
(defn get-current-fleet
|
(defn get-current-fleet
|
||||||
@@ -93,15 +101,16 @@
|
|||||||
(defn- get-multiaccount-node-config
|
(defn- get-multiaccount-node-config
|
||||||
[{:keys [multiaccount :networks/networks :networks/current-network]
|
[{:keys [multiaccount :networks/networks :networks/current-network]
|
||||||
:as db}]
|
:as db}]
|
||||||
(let [wakuv2-config (get multiaccount :wakuv2-config {})
|
(let [wakuv2-config (get multiaccount :wakuv2-config {})
|
||||||
current-fleet-key (current-fleet-key db)
|
current-fleet-key (current-fleet-key db)
|
||||||
current-fleet (get-current-fleet db)
|
current-fleet (get-current-fleet db)
|
||||||
wakuv2-enabled (boolean (:waku current-fleet))
|
wakuv2-enabled (boolean (:waku current-fleet))
|
||||||
waku-nodes (:waku-nodes current-fleet)
|
waku-nodes (:waku-nodes current-fleet)
|
||||||
rendezvous-nodes (pick-nodes 3 (vals (:rendezvous current-fleet)))
|
rendezvous-nodes (pick-nodes 3 (vals (:rendezvous current-fleet)))
|
||||||
{:keys [installation-id log-level
|
{:keys [installation-id log-level
|
||||||
waku-bloom-filter-mode
|
waku-bloom-filter-mode
|
||||||
custom-bootnodes custom-bootnodes-enabled?]} multiaccount
|
custom-bootnodes custom-bootnodes-enabled?]}
|
||||||
|
multiaccount
|
||||||
use-custom-bootnodes (get custom-bootnodes-enabled? current-network)]
|
use-custom-bootnodes (get custom-bootnodes-enabled? current-network)]
|
||||||
(cond-> (get-in networks [current-network :config])
|
(cond-> (get-in networks [current-network :config])
|
||||||
:always
|
:always
|
||||||
@@ -111,10 +120,10 @@
|
|||||||
(get-login-node-config)
|
(get-login-node-config)
|
||||||
|
|
||||||
current-fleet
|
current-fleet
|
||||||
(assoc :NoDiscovery wakuv2-enabled
|
(assoc :NoDiscovery wakuv2-enabled
|
||||||
:Rendezvous (if wakuv2-enabled false (boolean (seq rendezvous-nodes)))
|
:Rendezvous (if wakuv2-enabled false (boolean (seq rendezvous-nodes)))
|
||||||
:ClusterConfig {:Enabled true
|
:ClusterConfig {:Enabled true
|
||||||
:Fleet (name current-fleet-key)
|
:Fleet (name current-fleet-key)
|
||||||
:DiscV5BootstrapNodes
|
:DiscV5BootstrapNodes
|
||||||
(if wakuv2-enabled
|
(if wakuv2-enabled
|
||||||
waku-nodes
|
waku-nodes
|
||||||
@@ -124,29 +133,30 @@
|
|||||||
:TrustedMailServers
|
:TrustedMailServers
|
||||||
(if wakuv2-enabled [] (pick-nodes 6 (vals (:mail current-fleet))))
|
(if wakuv2-enabled [] (pick-nodes 6 (vals (:mail current-fleet))))
|
||||||
:StaticNodes
|
:StaticNodes
|
||||||
(if wakuv2-enabled []
|
(if wakuv2-enabled
|
||||||
(into (pick-nodes 2
|
[]
|
||||||
(vals (:whisper current-fleet)))
|
(into (pick-nodes 2
|
||||||
(vals (:static current-fleet))))
|
(vals (:whisper current-fleet)))
|
||||||
:RendezvousNodes (if wakuv2-enabled [] rendezvous-nodes)
|
(vals (:static current-fleet))))
|
||||||
:WakuNodes (or waku-nodes [])})
|
:RendezvousNodes (if wakuv2-enabled [] rendezvous-nodes)
|
||||||
|
:WakuNodes (or waku-nodes [])})
|
||||||
|
|
||||||
:always
|
:always
|
||||||
(assoc :LocalNotificationsConfig {:Enabled true}
|
(assoc :LocalNotificationsConfig {:Enabled true}
|
||||||
:BrowsersConfig {:Enabled true}
|
:BrowsersConfig {:Enabled true}
|
||||||
:PermissionsConfig {:Enabled true}
|
:PermissionsConfig {:Enabled true}
|
||||||
:MailserversConfig {:Enabled true}
|
:MailserversConfig {:Enabled true}
|
||||||
:EnableNTPSync true
|
:EnableNTPSync true
|
||||||
:WakuConfig
|
:WakuConfig
|
||||||
{:Enabled true
|
{:Enabled true
|
||||||
:BloomFilterMode waku-bloom-filter-mode
|
:BloomFilterMode waku-bloom-filter-mode
|
||||||
:LightClient true
|
:LightClient true
|
||||||
:MinimumPoW 0.000001}
|
:MinimumPoW 0.000001}
|
||||||
:WakuV2Config (assoc wakuv2-config
|
:WakuV2Config (assoc wakuv2-config
|
||||||
:DiscoveryLimit 20
|
:DiscoveryLimit 20
|
||||||
:EnableDiscV5 true
|
:EnableDiscV5 true
|
||||||
:Enabled wakuv2-enabled
|
:Enabled wakuv2-enabled
|
||||||
:Host "0.0.0.0")
|
:Host "0.0.0.0")
|
||||||
:ShhextConfig
|
:ShhextConfig
|
||||||
{:BackupDisabledDataDir (utils.platform/no-backup-directory)
|
{:BackupDisabledDataDir (utils.platform/no-backup-directory)
|
||||||
:InstallationID installation-id
|
:InstallationID installation-id
|
||||||
@@ -158,8 +168,8 @@
|
|||||||
:VerifyTransactionChainID config/verify-transaction-chain-id
|
:VerifyTransactionChainID config/verify-transaction-chain-id
|
||||||
:DataSyncEnabled true
|
:DataSyncEnabled true
|
||||||
:PFSEnabled true}
|
:PFSEnabled true}
|
||||||
:RequireTopics (get-topics current-network)
|
:RequireTopics (get-topics current-network)
|
||||||
:StatusAccountsConfig {:Enabled true})
|
:StatusAccountsConfig {:Enabled true})
|
||||||
|
|
||||||
(and
|
(and
|
||||||
config/bootnodes-settings-enabled?
|
config/bootnodes-settings-enabled?
|
||||||
@@ -173,7 +183,7 @@
|
|||||||
[db]
|
[db]
|
||||||
(types/clj->json (get-multiaccount-node-config db)))
|
(types/clj->json (get-multiaccount-node-config db)))
|
||||||
|
|
||||||
(fx/defn save-new-config
|
(rf/defn save-new-config
|
||||||
"Saves a new status-go config for the current account
|
"Saves a new status-go config for the current account
|
||||||
This RPC method is the only way to change the node config of an account.
|
This RPC method is the only way to change the node config of an account.
|
||||||
NOTE: it is better used indirectly through `prepare-new-config`,
|
NOTE: it is better used indirectly through `prepare-new-config`,
|
||||||
@@ -185,7 +195,7 @@ app-db"
|
|||||||
:params [:node-config config]
|
:params [:node-config config]
|
||||||
:on-success on-success}]})
|
:on-success on-success}]})
|
||||||
|
|
||||||
(fx/defn prepare-new-config
|
(rf/defn prepare-new-config
|
||||||
"Use this function to apply settings to the current account node config"
|
"Use this function to apply settings to the current account node config"
|
||||||
[{:keys [db]} {:keys [on-success]}]
|
[{:keys [db]} {:keys [on-success]}]
|
||||||
(let [key-uid (get-in db [:multiaccount :key-uid])]
|
(let [key-uid (get-in db [:multiaccount :key-uid])]
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
(ns status-im.notifications.core
|
(ns status-im.notifications.core
|
||||||
(:require [re-frame.core :as re-frame]
|
(:require ["@react-native-community/push-notification-ios" :default pn-ios]
|
||||||
[taoensso.timbre :as log]
|
[quo.platform :as platform]
|
||||||
[status-im.utils.fx :as fx]
|
[re-frame.core :as re-frame]
|
||||||
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
[status-im.multiaccounts.update.core :as multiaccounts.update]
|
[status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||||
["@react-native-community/push-notification-ios" :default pn-ios]
|
|
||||||
[status-im.notifications.android :as pn-android]
|
[status-im.notifications.android :as pn-android]
|
||||||
[status-im.notifications.local :as local]
|
[status-im.notifications.local :as local]
|
||||||
[quo.platform :as platform]
|
|
||||||
[status-im.utils.config :as config]
|
[status-im.utils.config :as config]
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]))
|
[taoensso.timbre :as log]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(def server-type-default 1)
|
(def server-type-default 1)
|
||||||
(def server-type-custom 2)
|
(def server-type-custom 2)
|
||||||
@@ -16,12 +16,14 @@
|
|||||||
(def apn-token-type 1)
|
(def apn-token-type 1)
|
||||||
(def firebase-token-type 2)
|
(def firebase-token-type 2)
|
||||||
(def listeners-added? (atom nil))
|
(def listeners-added? (atom nil))
|
||||||
(defn server<-rpc [{:keys [type publicKey registered]}]
|
(defn server<-rpc
|
||||||
|
[{:keys [type publicKey registered]}]
|
||||||
{:public-key publicKey
|
{:public-key publicKey
|
||||||
:type type
|
:type type
|
||||||
:registered registered})
|
:registered registered})
|
||||||
|
|
||||||
(defn add-event-listeners []
|
(defn add-event-listeners
|
||||||
|
[]
|
||||||
(when-not @listeners-added?
|
(when-not @listeners-added?
|
||||||
(reset! listeners-added? true)
|
(reset! listeners-added? true)
|
||||||
(.addEventListener
|
(.addEventListener
|
||||||
@@ -35,23 +37,27 @@
|
|||||||
(fn [error]
|
(fn [error]
|
||||||
(re-frame/dispatch [:notifications/switch-error true error])))))
|
(re-frame/dispatch [:notifications/switch-error true error])))))
|
||||||
|
|
||||||
(defn enable-ios-notifications []
|
(defn enable-ios-notifications
|
||||||
|
[]
|
||||||
(add-event-listeners)
|
(add-event-listeners)
|
||||||
(-> (.requestPermissions ^js pn-ios)
|
(-> (.requestPermissions ^js pn-ios)
|
||||||
(.then #())
|
(.then #())
|
||||||
(.catch #())))
|
(.catch #())))
|
||||||
|
|
||||||
(defn disable-ios-notifications []
|
(defn disable-ios-notifications
|
||||||
|
[]
|
||||||
(.abandonPermissions ^js pn-ios)
|
(.abandonPermissions ^js pn-ios)
|
||||||
(re-frame/dispatch [:notifications/unregistered-from-push-notifications]))
|
(re-frame/dispatch [:notifications/unregistered-from-push-notifications]))
|
||||||
|
|
||||||
(defn enable-android-notifications []
|
(defn enable-android-notifications
|
||||||
|
[]
|
||||||
(pn-android/create-channel
|
(pn-android/create-channel
|
||||||
{:channel-id "status-im-notifications"
|
{:channel-id "status-im-notifications"
|
||||||
:channel-name "Status push notifications"})
|
:channel-name "Status push notifications"})
|
||||||
(pn-android/enable-notifications))
|
(pn-android/enable-notifications))
|
||||||
|
|
||||||
(defn disable-android-notifications []
|
(defn disable-android-notifications
|
||||||
|
[]
|
||||||
(pn-android/disable-notifications))
|
(pn-android/disable-notifications))
|
||||||
|
|
||||||
;; FIXME: Repalce with request permission from audio messages PR lib
|
;; FIXME: Repalce with request permission from audio messages PR lib
|
||||||
@@ -59,7 +65,7 @@
|
|||||||
::request-permission
|
::request-permission
|
||||||
identity)
|
identity)
|
||||||
|
|
||||||
(fx/defn request-permission
|
(rf/defn request-permission
|
||||||
{:events [::request-permission]}
|
{:events [::request-permission]}
|
||||||
[_]
|
[_]
|
||||||
{::request-permission true})
|
{::request-permission true})
|
||||||
@@ -103,15 +109,16 @@
|
|||||||
(doseq [chat-id chat-ids]
|
(doseq [chat-id chat-ids]
|
||||||
(pn-android/clear-message-notifications chat-id))))))
|
(pn-android/clear-message-notifications chat-id))))))
|
||||||
|
|
||||||
(fx/defn handle-enable-notifications-event
|
(rf/defn handle-enable-notifications-event
|
||||||
{:events [:notifications/registered-for-push-notifications]}
|
{:events [:notifications/registered-for-push-notifications]}
|
||||||
[cofx token]
|
[cofx token]
|
||||||
{::json-rpc/call [{:method "wakuext_registerForPushNotifications"
|
{::json-rpc/call [{:method "wakuext_registerForPushNotifications"
|
||||||
:params [token (if platform/ios? config/apn-topic) (if platform/ios? apn-token-type firebase-token-type)]
|
:params [token (if platform/ios? config/apn-topic)
|
||||||
|
(if platform/ios? apn-token-type firebase-token-type)]
|
||||||
:on-success #(log/info "[push-notifications] register-success" %)
|
:on-success #(log/info "[push-notifications] register-success" %)
|
||||||
:on-error #(re-frame/dispatch [:notifications/switch-error true %])}]})
|
:on-error #(re-frame/dispatch [:notifications/switch-error true %])}]})
|
||||||
|
|
||||||
(fx/defn handle-disable-notifications-event
|
(rf/defn handle-disable-notifications-event
|
||||||
{:events [:notifications/unregistered-from-push-notifications]}
|
{:events [:notifications/unregistered-from-push-notifications]}
|
||||||
[cofx]
|
[cofx]
|
||||||
{::json-rpc/call [{:method "wakuext_unregisterFromPushNotifications"
|
{::json-rpc/call [{:method "wakuext_unregisterFromPushNotifications"
|
||||||
@@ -119,7 +126,7 @@
|
|||||||
:on-success #(log/info "[push-notifications] unregister-success" %)
|
:on-success #(log/info "[push-notifications] unregister-success" %)
|
||||||
:on-error #(re-frame/dispatch [:notifications/switch-error false %])}]})
|
:on-error #(re-frame/dispatch [:notifications/switch-error false %])}]})
|
||||||
|
|
||||||
(fx/defn logout-disable
|
(rf/defn logout-disable
|
||||||
[cofx]
|
[cofx]
|
||||||
(merge {::logout-disable nil}
|
(merge {::logout-disable nil}
|
||||||
{::json-rpc/call [{:method "wakuext_unregisterFromPushNotifications"
|
{::json-rpc/call [{:method "wakuext_unregisterFromPushNotifications"
|
||||||
@@ -127,113 +134,132 @@
|
|||||||
:on-success #(log/info "[push-notifications] unregister-success" %)
|
:on-success #(log/info "[push-notifications] unregister-success" %)
|
||||||
:on-error #(log/info "[push-notifications] unregister-error" %)}]}))
|
:on-error #(log/info "[push-notifications] unregister-error" %)}]}))
|
||||||
|
|
||||||
(fx/defn notification-switch-error
|
(rf/defn notification-switch-error
|
||||||
{:events [:notifications/switch-error]}
|
{:events [:notifications/switch-error]}
|
||||||
[cofx enabled?]
|
[cofx enabled?]
|
||||||
(multiaccounts.update/multiaccount-update
|
(multiaccounts.update/multiaccount-update
|
||||||
cofx :remote-push-notifications-enabled? (not enabled?) {}))
|
cofx
|
||||||
|
:remote-push-notifications-enabled?
|
||||||
|
(not enabled?)
|
||||||
|
{}))
|
||||||
|
|
||||||
(fx/defn notification-switch
|
(rf/defn notification-switch
|
||||||
{:events [::switch]}
|
{:events [::switch]}
|
||||||
[{:keys [db] :as cofx} enabled? remote-push-notifications?]
|
[{:keys [db] :as cofx} enabled? remote-push-notifications?]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(if enabled?
|
(if enabled?
|
||||||
{::enable remote-push-notifications?}
|
{::enable remote-push-notifications?}
|
||||||
{::disable nil})
|
{::disable nil})
|
||||||
(multiaccounts.update/multiaccount-update
|
(multiaccounts.update/multiaccount-update
|
||||||
:remote-push-notifications-enabled? (and remote-push-notifications? enabled?) {})
|
:remote-push-notifications-enabled?
|
||||||
|
(and remote-push-notifications? enabled?)
|
||||||
|
{})
|
||||||
(multiaccounts.update/multiaccount-update
|
(multiaccounts.update/multiaccount-update
|
||||||
:notifications-enabled? (and (not remote-push-notifications?) enabled?) {})))
|
:notifications-enabled?
|
||||||
|
(and (not remote-push-notifications?) enabled?)
|
||||||
|
{})))
|
||||||
|
|
||||||
(fx/defn notification-non-contacts-error
|
(rf/defn notification-non-contacts-error
|
||||||
{:events [::non-contacts-update-error]}
|
{:events [::non-contacts-update-error]}
|
||||||
[cofx enabled?]
|
[cofx enabled?]
|
||||||
(multiaccounts.update/optimistic cofx :push-notifications-from-contacts-only? (not (boolean enabled?))))
|
(multiaccounts.update/optimistic cofx
|
||||||
|
:push-notifications-from-contacts-only?
|
||||||
|
(not (boolean enabled?))))
|
||||||
|
|
||||||
(fx/defn notification-block-mentions-error
|
(rf/defn notification-block-mentions-error
|
||||||
{:events [::block-mentions-update-error]}
|
{:events [::block-mentions-update-error]}
|
||||||
[cofx enabled?]
|
[cofx enabled?]
|
||||||
(multiaccounts.update/optimistic cofx :push-notifications-block-mentions? (not (boolean enabled?))))
|
(multiaccounts.update/optimistic cofx :push-notifications-block-mentions? (not (boolean enabled?))))
|
||||||
|
|
||||||
(fx/defn notification-non-contacts
|
(rf/defn notification-non-contacts
|
||||||
{:events [::switch-non-contacts]}
|
{:events [::switch-non-contacts]}
|
||||||
[{:keys [db] :as cofx} enabled?]
|
[{:keys [db] :as cofx} enabled?]
|
||||||
(let [method (if enabled?
|
(let [method (if enabled?
|
||||||
"wakuext_enablePushNotificationsFromContactsOnly"
|
"wakuext_enablePushNotificationsFromContactsOnly"
|
||||||
"wakuext_disablePushNotificationsFromContactsOnly")]
|
"wakuext_disablePushNotificationsFromContactsOnly")]
|
||||||
(fx/merge cofx
|
(rf/merge
|
||||||
{::json-rpc/call [{:method method
|
cofx
|
||||||
:params []
|
{::json-rpc/call [{:method method
|
||||||
:on-success #(log/info "[push-notifications] contacts-notification-success" %)
|
:params []
|
||||||
:on-error #(re-frame/dispatch [::non-contacts-update-error enabled? %])}]}
|
:on-success #(log/info "[push-notifications] contacts-notification-success" %)
|
||||||
|
:on-error #(re-frame/dispatch [::non-contacts-update-error enabled? %])}]}
|
||||||
|
|
||||||
(multiaccounts.update/optimistic :push-notifications-from-contacts-only? (boolean enabled?)))))
|
(multiaccounts.update/optimistic :push-notifications-from-contacts-only? (boolean enabled?)))))
|
||||||
|
|
||||||
(fx/defn notification-block-mentions
|
(rf/defn notification-block-mentions
|
||||||
{:events [::switch-block-mentions]}
|
{:events [::switch-block-mentions]}
|
||||||
[{:keys [db] :as cofx} enabled?]
|
[{:keys [db] :as cofx} enabled?]
|
||||||
(let [method (if enabled?
|
(let [method (if enabled?
|
||||||
"wakuext_enablePushNotificationsBlockMentions"
|
"wakuext_enablePushNotificationsBlockMentions"
|
||||||
"wakuext_disablePushNotificationsBlockMentions")]
|
"wakuext_disablePushNotificationsBlockMentions")]
|
||||||
(log/info "USING METHOD" method enabled?)
|
(log/info "USING METHOD" method enabled?)
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{::json-rpc/call [{:method method
|
{::json-rpc/call [{:method method
|
||||||
:params []
|
:params []
|
||||||
:on-success #(log/info "[push-notifications] block-mentions-success" %)
|
:on-success #(log/info "[push-notifications] block-mentions-success" %)
|
||||||
:on-error #(re-frame/dispatch [::block-mentions-update-error enabled? %])}]}
|
:on-error #(re-frame/dispatch [::block-mentions-update-error enabled?
|
||||||
|
%])}]}
|
||||||
|
|
||||||
(multiaccounts.update/optimistic :push-notifications-block-mentions? (boolean enabled?)))))
|
(multiaccounts.update/optimistic :push-notifications-block-mentions? (boolean enabled?)))))
|
||||||
|
|
||||||
(fx/defn switch-push-notifications-server-enabled
|
(rf/defn switch-push-notifications-server-enabled
|
||||||
{:events [::switch-push-notifications-server-enabled]}
|
{:events [::switch-push-notifications-server-enabled]}
|
||||||
[{:keys [db] :as cofx} enabled?]
|
[{:keys [db] :as cofx} enabled?]
|
||||||
(let [method (if enabled?
|
(let [method (if enabled?
|
||||||
"wakuext_startPushNotificationsServer"
|
"wakuext_startPushNotificationsServer"
|
||||||
"wakuext_stopPushNotificationsServer")]
|
"wakuext_stopPushNotificationsServer")]
|
||||||
(fx/merge cofx
|
(rf/merge
|
||||||
{::json-rpc/call [{:method method
|
cofx
|
||||||
:params []
|
{::json-rpc/call [{:method method
|
||||||
:on-success #(log/info "[push-notifications] switch-server-enabled successful" %)
|
:params []
|
||||||
:on-error #(re-frame/dispatch [::push-notifications-server-update-error enabled? %])}]}
|
:on-success #(log/info "[push-notifications] switch-server-enabled successful" %)
|
||||||
|
:on-error #(re-frame/dispatch [::push-notifications-server-update-error
|
||||||
|
enabled? %])}]}
|
||||||
|
|
||||||
(multiaccounts.update/optimistic :push-notifications-server-enabled? (boolean enabled?)))))
|
(multiaccounts.update/optimistic :push-notifications-server-enabled? (boolean enabled?)))))
|
||||||
|
|
||||||
(fx/defn switch-send-notifications
|
(rf/defn switch-send-notifications
|
||||||
{:events [::switch-send-push-notifications]}
|
{:events [::switch-send-push-notifications]}
|
||||||
[{:keys [db] :as cofx} enabled?]
|
[{:keys [db] :as cofx} enabled?]
|
||||||
(let [method (if enabled?
|
(let [method (if enabled?
|
||||||
"wakuext_enableSendingNotifications"
|
"wakuext_enableSendingNotifications"
|
||||||
"wakuext_disableSendingNotifications")]
|
"wakuext_disableSendingNotifications")]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{::json-rpc/call [{:method method
|
{::json-rpc/call [{:method method
|
||||||
:params []
|
:params []
|
||||||
:on-success #(log/info "[push-notifications] switch-send-notifications successful" %)
|
:on-success
|
||||||
:on-error #(re-frame/dispatch [::push-notifications-send-update-error enabled? %])}]}
|
#(log/info "[push-notifications] switch-send-notifications successful"
|
||||||
|
%)
|
||||||
|
:on-error #(re-frame/dispatch [::push-notifications-send-update-error
|
||||||
|
enabled? %])}]}
|
||||||
|
|
||||||
(multiaccounts.update/optimistic :send-push-notifications? (boolean enabled?)))))
|
(multiaccounts.update/optimistic :send-push-notifications? (boolean enabled?)))))
|
||||||
|
|
||||||
(fx/defn handle-add-server-error
|
(rf/defn handle-add-server-error
|
||||||
{:events [::push-notifications-add-server-error]}
|
{:events [::push-notifications-add-server-error]}
|
||||||
[_ public-key error]
|
[_ public-key error]
|
||||||
(log/error "failed to add server", public-key, error))
|
(log/error "failed to add server" public-key error))
|
||||||
|
|
||||||
(fx/defn add-server
|
(rf/defn add-server
|
||||||
{:events [::add-server]}
|
{:events [::add-server]}
|
||||||
[{:keys [db] :as cofx} public-key]
|
[{:keys [db] :as cofx} public-key]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{::json-rpc/call [{:method "wakuext_addPushNotificationsServer"
|
{::json-rpc/call [{:method "wakuext_addPushNotificationsServer"
|
||||||
:params [public-key]
|
:params [public-key]
|
||||||
:on-success #(do
|
:on-success
|
||||||
(log/info "[push-notifications] switch-send-notifications successful" %)
|
#(do
|
||||||
(re-frame/dispatch [::fetch-servers]))
|
(log/info "[push-notifications] switch-send-notifications successful"
|
||||||
:on-error #(re-frame/dispatch [::push-notifications-add-server-error public-key %])}]}))
|
%)
|
||||||
|
(re-frame/dispatch [::fetch-servers]))
|
||||||
|
:on-error #(re-frame/dispatch [::push-notifications-add-server-error
|
||||||
|
public-key %])}]}))
|
||||||
|
|
||||||
(fx/defn handle-servers-fetched
|
(rf/defn handle-servers-fetched
|
||||||
{:events [::servers-fetched]}
|
{:events [::servers-fetched]}
|
||||||
[{:keys [db]} servers]
|
[{:keys [db]} servers]
|
||||||
{:db (assoc db :push-notifications/servers (map server<-rpc servers))})
|
{:db (assoc db :push-notifications/servers (map server<-rpc servers))})
|
||||||
|
|
||||||
(fx/defn fetch-push-notifications-servers
|
(rf/defn fetch-push-notifications-servers
|
||||||
{:events [::fetch-servers]}
|
{:events [::fetch-servers]}
|
||||||
[cofx]
|
[cofx]
|
||||||
{::json-rpc/call [{:method "wakuext_getPushNotificationsServers"
|
{::json-rpc/call [{:method "wakuext_getPushNotificationsServers"
|
||||||
@@ -244,34 +270,43 @@
|
|||||||
|
|
||||||
;; Wallet transactions
|
;; Wallet transactions
|
||||||
|
|
||||||
(fx/defn handle-preferences-load
|
(rf/defn handle-preferences-load
|
||||||
{:events [::preferences-loaded]}
|
{:events [::preferences-loaded]}
|
||||||
[{:keys [db]} preferences]
|
[{:keys [db]} preferences]
|
||||||
{:db (assoc db :push-notifications/preferences preferences)})
|
{:db (assoc db :push-notifications/preferences preferences)})
|
||||||
|
|
||||||
(fx/defn load-notification-preferences
|
(rf/defn load-notification-preferences
|
||||||
{:events [::load-notification-preferences]}
|
{:events [::load-notification-preferences]}
|
||||||
[cofx]
|
[cofx]
|
||||||
{::json-rpc/call [{:method "localnotifications_notificationPreferences"
|
{::json-rpc/call [{:method "localnotifications_notificationPreferences"
|
||||||
:params []
|
:params []
|
||||||
:on-success #(re-frame/dispatch [::preferences-loaded %])}]})
|
:on-success #(re-frame/dispatch [::preferences-loaded %])}]})
|
||||||
|
|
||||||
(defn preference= [x y]
|
(defn preference=
|
||||||
|
[x y]
|
||||||
(and (= (:service x) (:service y))
|
(and (= (:service x) (:service y))
|
||||||
(= (:event x) (:event y))
|
(= (:event x) (:event y))
|
||||||
(= (:identifier x) (:identifier y))))
|
(= (:identifier x) (:identifier y))))
|
||||||
|
|
||||||
(defn- update-preference [all new]
|
(defn- update-preference
|
||||||
|
[all new]
|
||||||
(conj (filter (comp not (partial preference= new)) all) new))
|
(conj (filter (comp not (partial preference= new)) all) new))
|
||||||
|
|
||||||
(fx/defn switch-transaction-notifications
|
(rf/defn switch-transaction-notifications
|
||||||
{:events [::switch-transaction-notifications]}
|
{:events [::switch-transaction-notifications]}
|
||||||
[{:keys [db] :as cofx} enabled?]
|
[{:keys [db] :as cofx} enabled?]
|
||||||
{:db (update db :push-notifications/preferences update-preference {:enabled (not enabled?)
|
{:db (update db
|
||||||
:service "wallet"
|
:push-notifications/preferences
|
||||||
:event "transaction"
|
update-preference
|
||||||
:identifier "all"})
|
{:enabled (not enabled?)
|
||||||
|
:service "wallet"
|
||||||
|
:event "transaction"
|
||||||
|
:identifier "all"})
|
||||||
::json-rpc/call [{:method "localnotifications_switchWalletNotifications"
|
::json-rpc/call [{:method "localnotifications_switchWalletNotifications"
|
||||||
:params [(not enabled?)]
|
:params [(not enabled?)]
|
||||||
:on-success #(log/info "[push-notifications] switch-transaction-notifications successful" %)
|
:on-success #(log/info
|
||||||
:on-error #(log/error "[push-notifications] switch-transaction-notifications error" %)}]})
|
"[push-notifications] switch-transaction-notifications successful"
|
||||||
|
%)
|
||||||
|
:on-error #(log/error
|
||||||
|
"[push-notifications] switch-transaction-notifications error"
|
||||||
|
%)}]})
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
(ns status-im.notifications.local
|
(ns status-im.notifications.local
|
||||||
(:require [status-im.async-storage.core :as async-storage]
|
(:require ["@react-native-community/push-notification-ios" :default pn-ios]
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[status-im.ethereum.decode :as decode]
|
|
||||||
["@react-native-community/push-notification-ios" :default pn-ios]
|
|
||||||
[status-im.notifications.android :as pn-android]
|
|
||||||
[status-im.ethereum.tokens :as tokens]
|
|
||||||
[status-im.utils.utils :as utils]
|
|
||||||
[status-im.utils.types :as types]
|
|
||||||
[status-im.utils.money :as money]
|
|
||||||
[status-im.i18n.i18n :as i18n]
|
|
||||||
[quo.platform :as platform]
|
|
||||||
[re-frame.core :as re-frame]
|
|
||||||
[cljs-bean.core :as bean]
|
[cljs-bean.core :as bean]
|
||||||
[clojure.string :as string]
|
[clojure.string :as string]
|
||||||
|
[quo.platform :as platform]
|
||||||
|
[re-frame.core :as re-frame]
|
||||||
|
[status-im.async-storage.core :as async-storage]
|
||||||
[status-im.chat.models :as chat.models]
|
[status-im.chat.models :as chat.models]
|
||||||
[status-im.utils.react-native :as react-native-utils]))
|
[status-im.ethereum.decode :as decode]
|
||||||
|
[status-im.ethereum.tokens :as tokens]
|
||||||
|
[status-im.i18n.i18n :as i18n]
|
||||||
|
[status-im.notifications.android :as pn-android]
|
||||||
|
[status-im.utils.money :as money]
|
||||||
|
[status-im.utils.react-native :as react-native-utils]
|
||||||
|
[status-im.utils.types :as types]
|
||||||
|
[status-im.utils.utils :as utils]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(def default-erc20-token
|
(def default-erc20-token
|
||||||
{:symbol :ERC20
|
{:symbol :ERC20
|
||||||
@@ -24,34 +24,39 @@
|
|||||||
(def notification-event-ios "localNotification")
|
(def notification-event-ios "localNotification")
|
||||||
(def notification-event-android "remoteNotificationReceived")
|
(def notification-event-android "remoteNotificationReceived")
|
||||||
|
|
||||||
(defn local-push-ios [{:keys [title message user-info body-type]}]
|
(defn local-push-ios
|
||||||
|
[{:keys [title message user-info body-type]}]
|
||||||
(when (not= body-type "message")
|
(when (not= body-type "message")
|
||||||
(.presentLocalNotification
|
(.presentLocalNotification
|
||||||
pn-ios
|
pn-ios
|
||||||
#js {:alertBody message
|
#js
|
||||||
:alertTitle title
|
{:alertBody message
|
||||||
;; NOTE: Use a special type to hide in Obj-C code other notifications
|
:alertTitle title
|
||||||
:userInfo (bean/->js (merge user-info
|
;; NOTE: Use a special type to hide in Obj-C code other notifications
|
||||||
{:notificationType "local-notification"}))})))
|
:userInfo (bean/->js (merge user-info
|
||||||
|
{:notificationType "local-notification"}))})))
|
||||||
|
|
||||||
(defn local-push-android
|
(defn local-push-android
|
||||||
[notification]
|
[notification]
|
||||||
(pn-android/present-local-notification notification))
|
(pn-android/present-local-notification notification))
|
||||||
|
|
||||||
(defn handle-notification-press [{{deep-link :deepLink} :userInfo
|
(defn handle-notification-press
|
||||||
interaction :userInteraction}]
|
[{{deep-link :deepLink} :userInfo
|
||||||
|
interaction :userInteraction}]
|
||||||
(async-storage/set-item! (str :chat-id) nil)
|
(async-storage/set-item! (str :chat-id) nil)
|
||||||
(when (and deep-link
|
(when (and deep-link
|
||||||
(or platform/ios?
|
(or platform/ios?
|
||||||
(and platform/android? interaction)))
|
(and platform/android? interaction)))
|
||||||
(re-frame/dispatch [:universal-links/handle-url deep-link])))
|
(re-frame/dispatch [:universal-links/handle-url deep-link])))
|
||||||
|
|
||||||
(defn listen-notifications []
|
(defn listen-notifications
|
||||||
|
[]
|
||||||
(if platform/ios?
|
(if platform/ios?
|
||||||
(.addEventListener ^js pn-ios
|
(.addEventListener ^js pn-ios
|
||||||
notification-event-ios
|
notification-event-ios
|
||||||
(fn [notification]
|
(fn [notification]
|
||||||
(handle-notification-press {:userInfo (bean/bean (.getData ^js notification))})))
|
(handle-notification-press {:userInfo (bean/bean (.getData ^js
|
||||||
|
notification))})))
|
||||||
(.addListener ^js react-native-utils/device-event-emitter
|
(.addListener ^js react-native-utils/device-event-emitter
|
||||||
notification-event-android
|
notification-event-android
|
||||||
(fn [^js data]
|
(fn [^js data]
|
||||||
@@ -72,21 +77,27 @@
|
|||||||
to (or (:name toAccount) (utils/get-shortened-address to))
|
to (or (:name toAccount) (utils/get-shortened-address to))
|
||||||
from (or (:name fromAccount) (utils/get-shortened-address from))
|
from (or (:name fromAccount) (utils/get-shortened-address from))
|
||||||
title (case state
|
title (case state
|
||||||
"inbound" (i18n/label :t/push-inbound-transaction {:value amount
|
"inbound" (i18n/label :t/push-inbound-transaction
|
||||||
:currency (:symbol token)})
|
{:value amount
|
||||||
"outbound" (i18n/label :t/push-outbound-transaction {:value amount
|
:currency (:symbol token)})
|
||||||
:currency (:symbol token)})
|
"outbound" (i18n/label :t/push-outbound-transaction
|
||||||
"failed" (i18n/label :t/push-failed-transaction {:value amount
|
{:value amount
|
||||||
:currency (:symbol token)})
|
:currency (:symbol token)})
|
||||||
|
"failed" (i18n/label :t/push-failed-transaction
|
||||||
|
{:value amount
|
||||||
|
:currency (:symbol token)})
|
||||||
nil)
|
nil)
|
||||||
description (case state
|
description (case state
|
||||||
"inbound" (i18n/label :t/push-inbound-transaction-body {:from from
|
"inbound" (i18n/label :t/push-inbound-transaction-body
|
||||||
:to to})
|
{:from from
|
||||||
"outbound" (i18n/label :t/push-outbound-transaction-body {:from from
|
:to to})
|
||||||
:to to})
|
"outbound" (i18n/label :t/push-outbound-transaction-body
|
||||||
"failed" (i18n/label :t/push-failed-transaction-body {:value amount
|
{:from from
|
||||||
:currency (:symbol token)
|
:to to})
|
||||||
:to to})
|
"failed" (i18n/label :t/push-failed-transaction-body
|
||||||
|
{:value amount
|
||||||
|
:currency (:symbol token)
|
||||||
|
:to to})
|
||||||
nil)]
|
nil)]
|
||||||
{:title title
|
{:title title
|
||||||
:icon (get-in token [:icon :source])
|
:icon (get-in token [:icon :source])
|
||||||
@@ -113,21 +124,22 @@
|
|||||||
"message" (when (show-message-pn? cofx notification) notification)
|
"message" (when (show-message-pn? cofx notification) notification)
|
||||||
"transaction" (create-transfer-notification cofx notification)
|
"transaction" (create-transfer-notification cofx notification)
|
||||||
nil)
|
nil)
|
||||||
:body-type bodyType)))
|
:body-type
|
||||||
|
bodyType)))
|
||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
::local-push-ios
|
::local-push-ios
|
||||||
(fn [evt]
|
(fn [evt]
|
||||||
(-> evt create-notification local-push-ios)))
|
(-> evt create-notification local-push-ios)))
|
||||||
|
|
||||||
(fx/defn local-notification-android
|
(rf/defn local-notification-android
|
||||||
{:events [::local-notification-android]}
|
{:events [::local-notification-android]}
|
||||||
[cofx event]
|
[cofx event]
|
||||||
(some->> event
|
(some->> event
|
||||||
(create-notification cofx)
|
(create-notification cofx)
|
||||||
local-push-android))
|
local-push-android))
|
||||||
|
|
||||||
(fx/defn process
|
(rf/defn process
|
||||||
[cofx evt]
|
[cofx evt]
|
||||||
(if platform/ios?
|
(if platform/ios?
|
||||||
{::local-push-ios evt}
|
{::local-push-ios evt}
|
||||||
|
|||||||
@@ -2,36 +2,40 @@
|
|||||||
(:require [re-frame.core :as re-frame]
|
(:require [re-frame.core :as re-frame]
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
[status-im.i18n.i18n :as i18n]
|
[status-im.i18n.i18n :as i18n]
|
||||||
[status-im2.navigation.events :as navigation]
|
[status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||||
[status-im.utils.config :as config]
|
[status-im.utils.config :as config]
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[status-im.utils.platform :as utils.platform]
|
[status-im.utils.platform :as utils.platform]
|
||||||
|
[status-im2.navigation.events :as navigation]
|
||||||
[taoensso.timbre :as log]
|
[taoensso.timbre :as log]
|
||||||
[status-im.multiaccounts.update.core :as multiaccounts.update]))
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(defn enable-installation-rpc [installation-id on-success on-error]
|
(defn enable-installation-rpc
|
||||||
|
[installation-id on-success on-error]
|
||||||
(json-rpc/call {:method "wakuext_enableInstallation"
|
(json-rpc/call {:method "wakuext_enableInstallation"
|
||||||
:params [installation-id]
|
:params [installation-id]
|
||||||
:on-success on-success
|
:on-success on-success
|
||||||
:on-error on-error}))
|
:on-error on-error}))
|
||||||
|
|
||||||
(defn disable-installation-rpc [installation-id on-success on-error]
|
(defn disable-installation-rpc
|
||||||
|
[installation-id on-success on-error]
|
||||||
(json-rpc/call {:method "wakuext_disableInstallation"
|
(json-rpc/call {:method "wakuext_disableInstallation"
|
||||||
:params [installation-id]
|
:params [installation-id]
|
||||||
:on-success on-success
|
:on-success on-success
|
||||||
:on-error on-error}))
|
:on-error on-error}))
|
||||||
|
|
||||||
(defn set-installation-metadata-rpc [installation-id metadata on-success on-error]
|
(defn set-installation-metadata-rpc
|
||||||
|
[installation-id metadata on-success on-error]
|
||||||
(json-rpc/call {:method "wakuext_setInstallationMetadata"
|
(json-rpc/call {:method "wakuext_setInstallationMetadata"
|
||||||
:params [installation-id metadata]
|
:params [installation-id metadata]
|
||||||
:on-success on-success
|
:on-success on-success
|
||||||
:on-error on-error}))
|
:on-error on-error}))
|
||||||
|
|
||||||
(defn get-our-installations-rpc [on-success on-error]
|
(defn get-our-installations-rpc
|
||||||
|
[on-success on-error]
|
||||||
(json-rpc/call {:method "wakuext_getOurInstallations"
|
(json-rpc/call {:method "wakuext_getOurInstallations"
|
||||||
:params []
|
:params []
|
||||||
:on-success on-success
|
:on-success on-success
|
||||||
:on-error on-error}))
|
:on-error on-error}))
|
||||||
|
|
||||||
(defn compare-installation
|
(defn compare-installation
|
||||||
"Sort installations, first by our installation-id, then on whether is
|
"Sort installations, first by our installation-id, then on whether is
|
||||||
@@ -52,56 +56,61 @@
|
|||||||
[our-installation-id installations]
|
[our-installation-id installations]
|
||||||
(sort (partial compare-installation our-installation-id) installations))
|
(sort (partial compare-installation our-installation-id) installations))
|
||||||
|
|
||||||
(fx/defn send-pair-installation
|
(rf/defn send-pair-installation
|
||||||
{:events [:pairing.ui/pair-devices-pressed]}
|
{:events [:pairing.ui/pair-devices-pressed]}
|
||||||
[_]
|
[_]
|
||||||
{::json-rpc/call [{:method "wakuext_sendPairInstallation"
|
{::json-rpc/call [{:method "wakuext_sendPairInstallation"
|
||||||
:params []
|
:params []
|
||||||
:on-success #(log/info "sent pair installation message")}]})
|
:on-success #(log/info "sent pair installation message")}]})
|
||||||
|
|
||||||
(fx/defn prompt-dismissed
|
(rf/defn prompt-dismissed
|
||||||
{:events [:pairing.ui/prompt-dismissed]}
|
{:events [:pairing.ui/prompt-dismissed]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
{:db (assoc-in db [:pairing/prompt-user-pop-up] false)})
|
{:db (assoc-in db [:pairing/prompt-user-pop-up] false)})
|
||||||
|
|
||||||
(fx/defn prompt-accepted
|
(rf/defn prompt-accepted
|
||||||
{:events [:pairing.ui/prompt-accepted]}
|
{:events [:pairing.ui/prompt-accepted]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc-in db [:pairing/prompt-user-pop-up] false)}
|
{:db (assoc-in db [:pairing/prompt-user-pop-up] false)}
|
||||||
(navigation/navigate-to-cofx :installations nil)))
|
(navigation/navigate-to-cofx :installations nil)))
|
||||||
|
|
||||||
(fx/defn prompt-user-on-new-installation [{:keys [db]}]
|
(rf/defn prompt-user-on-new-installation
|
||||||
|
[{:keys [db]}]
|
||||||
(when-not config/pairing-popup-disabled?
|
(when-not config/pairing-popup-disabled?
|
||||||
{:db (assoc-in db [:pairing/prompt-user-pop-up] true)
|
{:db (assoc-in db [:pairing/prompt-user-pop-up] true)
|
||||||
:ui/show-confirmation {:title (i18n/label :t/pairing-new-installation-detected-title)
|
:ui/show-confirmation {:title (i18n/label :t/pairing-new-installation-detected-title)
|
||||||
:content (i18n/label :t/pairing-new-installation-detected-content)
|
:content (i18n/label
|
||||||
|
:t/pairing-new-installation-detected-content)
|
||||||
:confirm-button-text (i18n/label :t/pairing-go-to-installation)
|
:confirm-button-text (i18n/label :t/pairing-go-to-installation)
|
||||||
:cancel-button-text (i18n/label :t/cancel)
|
:cancel-button-text (i18n/label :t/cancel)
|
||||||
:on-cancel #(re-frame/dispatch [:pairing.ui/prompt-dismissed])
|
:on-cancel #(re-frame/dispatch [:pairing.ui/prompt-dismissed])
|
||||||
:on-accept #(re-frame/dispatch [:pairing.ui/prompt-accepted])}}))
|
:on-accept #(re-frame/dispatch [:pairing.ui/prompt-accepted])}}))
|
||||||
|
|
||||||
(fx/defn set-name
|
(rf/defn set-name
|
||||||
"Set the name of the device"
|
"Set the name of the device"
|
||||||
{:events [:pairing.ui/set-name-pressed]}
|
{:events [:pairing.ui/set-name-pressed]}
|
||||||
[{:keys [db]} installation-name]
|
[{:keys [db]} installation-name]
|
||||||
(let [our-installation-id (get-in db [:multiaccount :installation-id])]
|
(let [our-installation-id (get-in db [:multiaccount :installation-id])]
|
||||||
{:pairing/set-installation-metadata [our-installation-id
|
{:pairing/set-installation-metadata [our-installation-id
|
||||||
{:name installation-name
|
{:name installation-name
|
||||||
:deviceType utils.platform/os}]}))
|
:deviceType utils.platform/os}]}))
|
||||||
|
|
||||||
(fx/defn init [cofx]
|
(rf/defn init
|
||||||
|
[cofx]
|
||||||
{:pairing/get-our-installations nil})
|
{:pairing/get-our-installations nil})
|
||||||
|
|
||||||
(fx/defn enable [{:keys [db]} installation-id]
|
(rf/defn enable
|
||||||
|
[{:keys [db]} installation-id]
|
||||||
{:db (assoc-in db
|
{:db (assoc-in db
|
||||||
[:pairing/installations installation-id :enabled?]
|
[:pairing/installations installation-id :enabled?]
|
||||||
true)})
|
true)})
|
||||||
|
|
||||||
(fx/defn disable [{:keys [db]} installation-id]
|
(rf/defn disable
|
||||||
|
[{:keys [db]} installation-id]
|
||||||
{:db (assoc-in db
|
{:db (assoc-in db
|
||||||
[:pairing/installations installation-id :enabled?]
|
[:pairing/installations installation-id :enabled?]
|
||||||
false)})
|
false)})
|
||||||
|
|
||||||
(defn handle-enable-installation-response-success
|
(defn handle-enable-installation-response-success
|
||||||
"Callback to dispatch on enable signature response"
|
"Callback to dispatch on enable signature response"
|
||||||
@@ -123,38 +132,43 @@
|
|||||||
[result]
|
[result]
|
||||||
(re-frame/dispatch [:pairing.callback/get-our-installations-success result]))
|
(re-frame/dispatch [:pairing.callback/get-our-installations-success result]))
|
||||||
|
|
||||||
(defn enable-installation! [installation-id]
|
(defn enable-installation!
|
||||||
|
[installation-id]
|
||||||
(enable-installation-rpc
|
(enable-installation-rpc
|
||||||
installation-id
|
installation-id
|
||||||
(partial handle-enable-installation-response-success installation-id)
|
(partial handle-enable-installation-response-success installation-id)
|
||||||
nil))
|
nil))
|
||||||
|
|
||||||
(defn disable-installation! [installation-id]
|
(defn disable-installation!
|
||||||
|
[installation-id]
|
||||||
(disable-installation-rpc
|
(disable-installation-rpc
|
||||||
installation-id
|
installation-id
|
||||||
(partial handle-disable-installation-response-success installation-id)
|
(partial handle-disable-installation-response-success installation-id)
|
||||||
nil))
|
nil))
|
||||||
|
|
||||||
(defn set-installation-metadata! [installation-id metadata]
|
(defn set-installation-metadata!
|
||||||
|
[installation-id metadata]
|
||||||
(set-installation-metadata-rpc
|
(set-installation-metadata-rpc
|
||||||
installation-id
|
installation-id
|
||||||
metadata
|
metadata
|
||||||
(partial handle-set-installation-metadata-response-success installation-id metadata)
|
(partial handle-set-installation-metadata-response-success installation-id metadata)
|
||||||
nil))
|
nil))
|
||||||
|
|
||||||
(defn get-our-installations []
|
(defn get-our-installations
|
||||||
|
[]
|
||||||
(get-our-installations-rpc handle-get-our-installations-response-success nil))
|
(get-our-installations-rpc handle-get-our-installations-response-success nil))
|
||||||
|
|
||||||
(fx/defn enable-fx
|
(rf/defn enable-fx
|
||||||
{:events [:pairing.ui/enable-installation-pressed]}
|
{:events [:pairing.ui/enable-installation-pressed]}
|
||||||
[cofx installation-id]
|
[cofx installation-id]
|
||||||
(if (< (count (filter :enabled? (vals (get-in cofx [:db :pairing/installations])))) (inc config/max-installations))
|
(if (< (count (filter :enabled? (vals (get-in cofx [:db :pairing/installations]))))
|
||||||
|
(inc config/max-installations))
|
||||||
{:pairing/enable-installation [installation-id]}
|
{:pairing/enable-installation [installation-id]}
|
||||||
{:utils/show-popup {:title (i18n/label :t/pairing-maximum-number-reached-title)
|
{:utils/show-popup {:title (i18n/label :t/pairing-maximum-number-reached-title)
|
||||||
|
|
||||||
:content (i18n/label :t/pairing-maximum-number-reached-content)}}))
|
:content (i18n/label :t/pairing-maximum-number-reached-content)}}))
|
||||||
|
|
||||||
(fx/defn disable-fx
|
(rf/defn disable-fx
|
||||||
{:events [:pairing.ui/disable-installation-pressed]}
|
{:events [:pairing.ui/disable-installation-pressed]}
|
||||||
[_ installation-id]
|
[_ installation-id]
|
||||||
{:pairing/disable-installation [installation-id]})
|
{:pairing/disable-installation [installation-id]})
|
||||||
@@ -178,58 +192,66 @@
|
|||||||
:pairing/get-our-installations
|
:pairing/get-our-installations
|
||||||
get-our-installations)
|
get-our-installations)
|
||||||
|
|
||||||
(fx/defn send-installation-messages
|
(rf/defn send-installation-messages
|
||||||
{:events [:pairing.ui/synchronize-installation-pressed]}
|
{:events [:pairing.ui/synchronize-installation-pressed]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(let [multiaccount (:multiaccount db)
|
(let [multiaccount (:multiaccount db)
|
||||||
{:keys [name preferred-name identicon]} multiaccount]
|
{:keys [name preferred-name identicon]} multiaccount]
|
||||||
{::json-rpc/call [{:method "wakuext_syncDevices"
|
{::json-rpc/call [{:method "wakuext_syncDevices"
|
||||||
:params [(or preferred-name name) identicon]
|
:params [(or preferred-name name) identicon]
|
||||||
:on-success #(log/debug "successfully synced devices")}]}))
|
:on-success #(log/debug "successfully synced devices")}]}))
|
||||||
|
|
||||||
(defn installation<-rpc [{:keys [metadata id enabled timestamp]}]
|
(defn installation<-rpc
|
||||||
|
[{:keys [metadata id enabled timestamp]}]
|
||||||
{:installation-id id
|
{:installation-id id
|
||||||
:name (:name metadata)
|
:name (:name metadata)
|
||||||
:timestamp timestamp
|
:timestamp timestamp
|
||||||
:device-type (:deviceType metadata)
|
:device-type (:deviceType metadata)
|
||||||
:enabled? enabled})
|
:enabled? enabled})
|
||||||
|
|
||||||
(fx/defn update-installation
|
(rf/defn update-installation
|
||||||
{:events [:pairing.callback/set-installation-metadata-success]}
|
{:events [:pairing.callback/set-installation-metadata-success]}
|
||||||
[{:keys [db]} installation-id metadata]
|
[{:keys [db]} installation-id metadata]
|
||||||
{:db (update-in db [:pairing/installations installation-id]
|
{:db (update-in db
|
||||||
|
[:pairing/installations installation-id]
|
||||||
assoc
|
assoc
|
||||||
:installation-id installation-id
|
:installation-id installation-id
|
||||||
:name (:name metadata)
|
:name (:name metadata)
|
||||||
:device-type (:deviceType metadata))})
|
:device-type (:deviceType metadata))})
|
||||||
|
|
||||||
(fx/defn handle-installations [{:keys [db]} installations]
|
(rf/defn handle-installations
|
||||||
{:db (update db :pairing/installations #(reduce
|
[{:keys [db]} installations]
|
||||||
(fn [acc {:keys [id] :as i}]
|
{:db (update db
|
||||||
(update acc id merge (installation<-rpc i)))
|
:pairing/installations
|
||||||
%
|
#(reduce
|
||||||
installations))})
|
(fn [acc {:keys [id] :as i}]
|
||||||
|
(update acc id merge (installation<-rpc i)))
|
||||||
|
%
|
||||||
|
installations))})
|
||||||
|
|
||||||
(fx/defn load-installations
|
(rf/defn load-installations
|
||||||
{:events [:pairing.callback/get-our-installations-success]}
|
{:events [:pairing.callback/get-our-installations-success]}
|
||||||
[{:keys [db]} installations]
|
[{:keys [db]} installations]
|
||||||
{:db (assoc db :pairing/installations (reduce
|
{:db (assoc db
|
||||||
(fn [acc {:keys [id] :as i}]
|
:pairing/installations
|
||||||
(assoc acc id
|
(reduce
|
||||||
(installation<-rpc i)))
|
(fn [acc {:keys [id] :as i}]
|
||||||
{}
|
(assoc acc
|
||||||
installations))})
|
id
|
||||||
|
(installation<-rpc i)))
|
||||||
|
{}
|
||||||
|
installations))})
|
||||||
|
|
||||||
(fx/defn enable-installation-success
|
(rf/defn enable-installation-success
|
||||||
{:events [:pairing.callback/enable-installation-success]}
|
{:events [:pairing.callback/enable-installation-success]}
|
||||||
[cofx installation-id]
|
[cofx installation-id]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(enable installation-id)
|
(enable installation-id)
|
||||||
(multiaccounts.update/send-multiaccount-update)))
|
(multiaccounts.update/send-multiaccount-update)))
|
||||||
|
|
||||||
(fx/defn disable-installation-success
|
(rf/defn disable-installation-success
|
||||||
{:events [:pairing.callback/disable-installation-success]}
|
{:events [:pairing.callback/disable-installation-success]}
|
||||||
[cofx installation-id]
|
[cofx installation-id]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(disable installation-id)
|
(disable installation-id)
|
||||||
(multiaccounts.update/send-multiaccount-update)))
|
(multiaccounts.update/send-multiaccount-update)))
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
(ns status-im.popover.core
|
(ns status-im.popover.core
|
||||||
(:require [status-im.utils.fx :as fx]))
|
(:require [utils.re-frame :as rf]))
|
||||||
|
|
||||||
(fx/defn show-popover
|
(rf/defn show-popover
|
||||||
{:events [:show-popover]}
|
{:events [:show-popover]}
|
||||||
[_ value]
|
[_ value]
|
||||||
{:show-popover nil
|
{:show-popover nil
|
||||||
;;TODO refactor popover just start animation on mount
|
;;TODO refactor popover just start animation on mount
|
||||||
:dispatch-later [{:ms 250 :dispatch [:show-popover-db value]}]
|
:dispatch-later [{:ms 250 :dispatch [:show-popover-db value]}]
|
||||||
:dismiss-keyboard nil})
|
:dismiss-keyboard nil})
|
||||||
|
|
||||||
(fx/defn show-popover-db
|
(rf/defn show-popover-db
|
||||||
{:events [:show-popover-db]}
|
{:events [:show-popover-db]}
|
||||||
[{:keys [db]} value]
|
[{:keys [db]} value]
|
||||||
{:db (assoc db :popover/popover value)})
|
{:db (assoc db :popover/popover value)})
|
||||||
|
|
||||||
(fx/defn hide-popover
|
(rf/defn hide-popover
|
||||||
{:events [:hide-popover]}
|
{:events [:hide-popover]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
{:db (dissoc db :popover/popover)
|
{:db (dissoc db :popover/popover)
|
||||||
:hide-popover nil})
|
:hide-popover nil})
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
(ns status-im.profile.core
|
(ns status-im.profile.core
|
||||||
(:require [re-frame.core :as re-frame]
|
(:require [clojure.string :as string]
|
||||||
[status-im.utils.fx :as fx]
|
[re-frame.core :as re-frame]
|
||||||
[status-im.ui.components.list-selection :as list-selection]
|
|
||||||
[status-im.utils.universal-links.utils :as universal-links]
|
|
||||||
[status-im.multiaccounts.update.core :as multiaccounts.update]
|
[status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||||
|
[status-im.ui.components.list-selection :as list-selection]
|
||||||
[status-im.ui.components.react :as react]
|
[status-im.ui.components.react :as react]
|
||||||
[clojure.string :as string]))
|
[status-im.utils.universal-links.utils :as universal-links]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
:copy-to-clipboard
|
:copy-to-clipboard
|
||||||
@@ -30,7 +30,9 @@
|
|||||||
(swap! tooltips dissoc interval-id))
|
(swap! tooltips dissoc interval-id))
|
||||||
(do (re-frame/dispatch [:set-in [:tooltips tooltip-id] opacity])
|
(do (re-frame/dispatch [:set-in [:tooltips tooltip-id] opacity])
|
||||||
(when (< 10 cnt)
|
(when (< 10 cnt)
|
||||||
(swap! tooltips assoc-in [tooltip-id :opacity] (- opacity 0.05)))))))
|
(swap! tooltips assoc-in
|
||||||
|
[tooltip-id :opacity]
|
||||||
|
(- opacity 0.05)))))))
|
||||||
100)]
|
100)]
|
||||||
(swap! tooltips assoc tooltip-id {:opacity 1.0 :interval-id interval-id :cnt 0}))))))
|
(swap! tooltips assoc tooltip-id {:opacity 1.0 :interval-id interval-id :cnt 0}))))))
|
||||||
|
|
||||||
@@ -40,43 +42,45 @@
|
|||||||
(let [link (universal-links/generate-link :user :external contact-code)]
|
(let [link (universal-links/generate-link :user :external contact-code)]
|
||||||
(list-selection/open-share {:message link}))))
|
(list-selection/open-share {:message link}))))
|
||||||
|
|
||||||
(fx/defn finish-success
|
(rf/defn finish-success
|
||||||
{:events [:my-profile/finish-success]}
|
{:events [:my-profile/finish-success]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
{:db (update db :my-profile/seed assoc :step :finish :error nil :word nil)})
|
{:db (update db :my-profile/seed assoc :step :finish :error nil :word nil)})
|
||||||
|
|
||||||
(fx/defn finish
|
(rf/defn finish
|
||||||
{:events [:my-profile/finish]}
|
{:events [:my-profile/finish]}
|
||||||
[cofx]
|
[cofx]
|
||||||
(multiaccounts.update/clean-seed-phrase
|
(multiaccounts.update/clean-seed-phrase
|
||||||
cofx
|
cofx
|
||||||
{:on-success #(re-frame/dispatch [:my-profile/finish-success])}))
|
{:on-success #(re-frame/dispatch [:my-profile/finish-success])}))
|
||||||
|
|
||||||
(fx/defn enter-two-random-words
|
(rf/defn enter-two-random-words
|
||||||
{:events [:my-profile/enter-two-random-words]}
|
{:events [:my-profile/enter-two-random-words]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(let [{:keys [mnemonic]} (:multiaccount db)
|
(let [{:keys [mnemonic]} (:multiaccount db)
|
||||||
shuffled-mnemonic (shuffle (map-indexed vector (string/split mnemonic #" ")))]
|
shuffled-mnemonic (shuffle (map-indexed vector (string/split mnemonic #" ")))]
|
||||||
{:db (assoc db :my-profile/seed {:step :first-word
|
{:db (assoc db
|
||||||
:first-word (first shuffled-mnemonic)
|
:my-profile/seed
|
||||||
:second-word (second shuffled-mnemonic)})}))
|
{:step :first-word
|
||||||
|
:first-word (first shuffled-mnemonic)
|
||||||
|
:second-word (second shuffled-mnemonic)})}))
|
||||||
|
|
||||||
(fx/defn set-step
|
(rf/defn set-step
|
||||||
{:events [:my-profile/set-step]}
|
{:events [:my-profile/set-step]}
|
||||||
[{:keys [db]} step]
|
[{:keys [db]} step]
|
||||||
{:db (update db :my-profile/seed assoc :step step :error nil :word nil)})
|
{:db (update db :my-profile/seed assoc :step step :error nil :word nil)})
|
||||||
|
|
||||||
(fx/defn copy-to-clipboard
|
(rf/defn copy-to-clipboard
|
||||||
{:events [:copy-to-clipboard]}
|
{:events [:copy-to-clipboard]}
|
||||||
[_ value]
|
[_ value]
|
||||||
{:copy-to-clipboard value})
|
{:copy-to-clipboard value})
|
||||||
|
|
||||||
(fx/defn show-tooltip
|
(rf/defn show-tooltip
|
||||||
{:events [:show-tooltip]}
|
{:events [:show-tooltip]}
|
||||||
[_ tooltip-id]
|
[_ tooltip-id]
|
||||||
{:show-tooltip tooltip-id})
|
{:show-tooltip tooltip-id})
|
||||||
|
|
||||||
(fx/defn share-profile-link
|
(rf/defn share-profile-link
|
||||||
{:events [:profile/share-profile-link]}
|
{:events [:profile/share-profile-link]}
|
||||||
[_ value]
|
[_ value]
|
||||||
{:profile/share-profile-link value})
|
{:profile/share-profile-link value})
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
(ns status-im.qr-scanner.core
|
(ns status-im.qr-scanner.core
|
||||||
(:require [re-frame.core :as re-frame]
|
(:require [clojure.string :as string]
|
||||||
[status-im.i18n.i18n :as i18n]
|
[re-frame.core :as re-frame]
|
||||||
[status-im.chat.models :as chat]
|
|
||||||
[status-im.router.core :as router]
|
|
||||||
[status-im2.navigation.events :as navigation]
|
|
||||||
[status-im.utils.utils :as utils]
|
|
||||||
[status-im.ethereum.core :as ethereum]
|
|
||||||
[status-im.add-new.db :as new-chat.db]
|
[status-im.add-new.db :as new-chat.db]
|
||||||
[status-im.utils.fx :as fx]
|
[status-im.chat.models :as chat]
|
||||||
|
[status-im.ethereum.core :as ethereum]
|
||||||
[status-im.group-chats.core :as group-chats]
|
[status-im.group-chats.core :as group-chats]
|
||||||
[clojure.string :as string]
|
[status-im.i18n.i18n :as i18n]
|
||||||
[taoensso.timbre :as log]))
|
[status-im.router.core :as router]
|
||||||
|
[status-im.utils.utils :as utils]
|
||||||
|
[status-im2.navigation.events :as navigation]
|
||||||
|
[taoensso.timbre :as log]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(fx/defn scan-qr-code
|
(rf/defn scan-qr-code
|
||||||
{:events [::scan-code]}
|
{:events [::scan-code]}
|
||||||
[_ opts]
|
[_ opts]
|
||||||
{:request-permissions-fx
|
{:request-permissions-fx
|
||||||
@@ -24,48 +24,52 @@
|
|||||||
(i18n/label :t/camera-access-error))
|
(i18n/label :t/camera-access-error))
|
||||||
50))}})
|
50))}})
|
||||||
|
|
||||||
(fx/defn set-qr-code
|
(rf/defn set-qr-code
|
||||||
{:events [:qr-scanner.callback/scan-qr-code-success]}
|
{:events [:qr-scanner.callback/scan-qr-code-success]}
|
||||||
[{:keys [db]} opts data]
|
[{:keys [db]} opts data]
|
||||||
(when-let [handler (:handler opts)]
|
(when-let [handler (:handler opts)]
|
||||||
{:dispatch [handler data opts]}))
|
{:dispatch [handler data opts]}))
|
||||||
|
|
||||||
(fx/defn set-qr-code-cancel
|
(rf/defn set-qr-code-cancel
|
||||||
{:events [:qr-scanner.callback/scan-qr-code-cancel]}
|
{:events [:qr-scanner.callback/scan-qr-code-cancel]}
|
||||||
[cofx opts]
|
[cofx opts]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(navigation/navigate-back)
|
(navigation/navigate-back)
|
||||||
(when-let [handler (:cancel-handler opts)]
|
(when-let [handler (:cancel-handler opts)]
|
||||||
(fn [] {:dispatch [handler opts]}))))
|
(fn [] {:dispatch [handler opts]}))))
|
||||||
|
|
||||||
(fx/defn handle-browse [cofx {:keys [url]}]
|
(rf/defn handle-browse
|
||||||
(fx/merge cofx
|
[cofx {:keys [url]}]
|
||||||
|
(rf/merge cofx
|
||||||
{:browser/show-browser-selection url}
|
{:browser/show-browser-selection url}
|
||||||
(navigation/navigate-back)))
|
(navigation/navigate-back)))
|
||||||
|
|
||||||
(fx/defn handle-private-chat [{:keys [db] :as cofx} {:keys [chat-id]}]
|
(rf/defn handle-private-chat
|
||||||
|
[{:keys [db] :as cofx} {:keys [chat-id]}]
|
||||||
(if-not (new-chat.db/own-public-key? db chat-id)
|
(if-not (new-chat.db/own-public-key? db chat-id)
|
||||||
(chat/start-chat cofx chat-id nil)
|
(chat/start-chat cofx chat-id nil)
|
||||||
{:utils/show-popup {:title (i18n/label :t/unable-to-read-this-code)
|
{:utils/show-popup {:title (i18n/label :t/unable-to-read-this-code)
|
||||||
:content (i18n/label :t/can-not-add-yourself)}}))
|
:content (i18n/label :t/can-not-add-yourself)}}))
|
||||||
|
|
||||||
(fx/defn handle-public-chat [cofx {:keys [topic]}]
|
(rf/defn handle-public-chat
|
||||||
|
[cofx {:keys [topic]}]
|
||||||
(when (seq topic)
|
(when (seq topic)
|
||||||
(chat/start-public-chat cofx topic)))
|
(chat/start-public-chat cofx topic)))
|
||||||
|
|
||||||
(fx/defn handle-group-chat [cofx params]
|
(rf/defn handle-group-chat
|
||||||
|
[cofx params]
|
||||||
(group-chats/create-from-link cofx params))
|
(group-chats/create-from-link cofx params))
|
||||||
|
|
||||||
(fx/defn handle-view-profile
|
(rf/defn handle-view-profile
|
||||||
[{:keys [db] :as cofx} {:keys [public-key ens-name]}]
|
[{:keys [db] :as cofx} {:keys [public-key ens-name]}]
|
||||||
(let [own (new-chat.db/own-public-key? db public-key)]
|
(let [own (new-chat.db/own-public-key? db public-key)]
|
||||||
(cond
|
(cond
|
||||||
(and public-key own)
|
(and public-key own)
|
||||||
{:change-tab-fx :profile
|
{:change-tab-fx :profile
|
||||||
:pop-to-root-tab-fx :profile-stack}
|
:pop-to-root-tab-fx :profile-stack}
|
||||||
|
|
||||||
(and public-key (not own))
|
(and public-key (not own))
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:dispatch [:chat.ui/show-profile public-key ens-name]}
|
{:dispatch [:chat.ui/show-profile public-key ens-name]}
|
||||||
(navigation/navigate-back))
|
(navigation/navigate-back))
|
||||||
|
|
||||||
@@ -74,13 +78,14 @@
|
|||||||
:content (i18n/label :t/ens-name-not-found)
|
:content (i18n/label :t/ens-name-not-found)
|
||||||
:on-dismiss #(re-frame/dispatch [:pop-to-root-tab :chat-stack])}})))
|
:on-dismiss #(re-frame/dispatch [:pop-to-root-tab :chat-stack])}})))
|
||||||
|
|
||||||
(fx/defn handle-eip681 [cofx data]
|
(rf/defn handle-eip681
|
||||||
(fx/merge cofx
|
[cofx data]
|
||||||
|
(rf/merge cofx
|
||||||
{:dispatch [:wallet/parse-eip681-uri-and-resolve-ens data]}
|
{:dispatch [:wallet/parse-eip681-uri-and-resolve-ens data]}
|
||||||
(navigation/change-tab :wallet)
|
(navigation/change-tab :wallet)
|
||||||
(navigation/pop-to-root-tab :wallet-stack)))
|
(navigation/pop-to-root-tab :wallet-stack)))
|
||||||
|
|
||||||
(fx/defn handle-wallet-connect
|
(rf/defn handle-wallet-connect
|
||||||
{:events [::handle-wallet-connect-uri]}
|
{:events [::handle-wallet-connect-uri]}
|
||||||
[cofx data]
|
[cofx data]
|
||||||
(let [wc-version (last (string/split (first (string/split data "?")) "@"))]
|
(let [wc-version (last (string/split (first (string/split data "?")) "@"))]
|
||||||
@@ -88,12 +93,12 @@
|
|||||||
{:dispatch [:wallet-connect-legacy/pair data]}
|
{:dispatch [:wallet-connect-legacy/pair data]}
|
||||||
{:dispatch [:wallet-connect/pair data]})))
|
{:dispatch [:wallet-connect/pair data]})))
|
||||||
|
|
||||||
(fx/defn handle-local-pairing
|
(rf/defn handle-local-pairing
|
||||||
{:events [::handle-local-pairing-uri]}
|
{:events [::handle-local-pairing-uri]}
|
||||||
[_ data]
|
[_ data]
|
||||||
{:dispatch [:syncing/input-connection-string-for-bootstrapping data]})
|
{:dispatch [:syncing/input-connection-string-for-bootstrapping data]})
|
||||||
|
|
||||||
(fx/defn match-scan
|
(rf/defn match-scan
|
||||||
{:events [::match-scanned-value]}
|
{:events [::match-scanned-value]}
|
||||||
[cofx {:keys [type] :as data}]
|
[cofx {:keys [type] :as data}]
|
||||||
(case type
|
(case type
|
||||||
@@ -109,11 +114,11 @@
|
|||||||
(log/info "Unable to find matcher for scanned value"
|
(log/info "Unable to find matcher for scanned value"
|
||||||
{:type type
|
{:type type
|
||||||
:event ::match-scanned-value})
|
:event ::match-scanned-value})
|
||||||
{:dispatch [:navigate-back]
|
{:dispatch [:navigate-back]
|
||||||
:utils/show-popup {:title (i18n/label :t/unable-to-read-this-code)
|
:utils/show-popup {:title (i18n/label :t/unable-to-read-this-code)
|
||||||
:on-dismiss #(re-frame/dispatch [:pop-to-root-tab :chat-stack])}})))
|
:on-dismiss #(re-frame/dispatch [:pop-to-root-tab :chat-stack])}})))
|
||||||
|
|
||||||
(fx/defn on-scan
|
(rf/defn on-scan
|
||||||
{:events [::on-scan-success]}
|
{:events [::on-scan-success]}
|
||||||
[{:keys [db]} uri]
|
[{:keys [db]} uri]
|
||||||
{::router/handle-uri {:chain (ethereum/chain-keyword db)
|
{::router/handle-uri {:chain (ethereum/chain-keyword db)
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
(ns status-im.search.core
|
(ns status-im.search.core
|
||||||
(:require [status-im.utils.fx :as fx]))
|
(:require [utils.re-frame :as rf]))
|
||||||
|
|
||||||
(fx/defn home-filter-changed
|
(rf/defn home-filter-changed
|
||||||
{:events [:search/home-filter-changed]}
|
{:events [:search/home-filter-changed]}
|
||||||
[cofx search-filter]
|
[cofx search-filter]
|
||||||
{:db (assoc-in (:db cofx) [:ui/search :home-filter] search-filter)})
|
{:db (assoc-in (:db cofx) [:ui/search :home-filter] search-filter)})
|
||||||
|
|
||||||
(fx/defn currency-filter-changed
|
(rf/defn currency-filter-changed
|
||||||
{:events [:search/currency-filter-changed]}
|
{:events [:search/currency-filter-changed]}
|
||||||
[cofx search-filter]
|
[cofx search-filter]
|
||||||
{:db (assoc-in (:db cofx) [:ui/search :currency-filter] search-filter)})
|
{:db (assoc-in (:db cofx) [:ui/search :currency-filter] search-filter)})
|
||||||
|
|
||||||
(fx/defn token-filter-changed
|
(rf/defn token-filter-changed
|
||||||
{:events [:search/token-filter-changed]}
|
{:events [:search/token-filter-changed]}
|
||||||
[cofx search-filter]
|
[cofx search-filter]
|
||||||
{:db (assoc-in (:db cofx) [:ui/search :token-filter] search-filter)})
|
{:db (assoc-in (:db cofx) [:ui/search :token-filter] search-filter)})
|
||||||
|
|
||||||
(fx/defn recipient-filter-changed
|
(rf/defn recipient-filter-changed
|
||||||
{:events [:search/recipient-filter-changed]}
|
{:events [:search/recipient-filter-changed]}
|
||||||
[cofx search-filter]
|
[cofx search-filter]
|
||||||
{:db (assoc-in (:db cofx) [:ui/search :recipient-filter] search-filter)})
|
{:db (assoc-in (:db cofx) [:ui/search :recipient-filter] search-filter)})
|
||||||
|
|||||||
@@ -1,85 +1,114 @@
|
|||||||
(ns status-im.signals.core
|
(ns status-im.signals.core
|
||||||
(:require [status-im.ethereum.subscriptions :as ethereum.subscriptions]
|
(:require [status-im.chat.models.link-preview :as link.preview]
|
||||||
|
[status-im.chat.models.message :as models.message]
|
||||||
|
[status-im.ethereum.subscriptions :as ethereum.subscriptions]
|
||||||
[status-im.i18n.i18n :as i18n]
|
[status-im.i18n.i18n :as i18n]
|
||||||
[status-im.mailserver.core :as mailserver]
|
[status-im.mailserver.core :as mailserver]
|
||||||
[status-im.multiaccounts.login.core :as login]
|
[status-im.multiaccounts.login.core :as login]
|
||||||
[status-im.transport.message.core :as transport.message]
|
|
||||||
[status-im.notifications.local :as local-notifications]
|
[status-im.notifications.local :as local-notifications]
|
||||||
[status-im.chat.models.message :as models.message]
|
[status-im.transport.message.core :as transport.message]
|
||||||
[status-im.chat.models.link-preview :as link.preview]
|
|
||||||
[status-im.visibility-status-updates.core :as visibility-status-updates]
|
[status-im.visibility-status-updates.core :as visibility-status-updates]
|
||||||
[status-im.utils.fx :as fx]
|
[taoensso.timbre :as log]
|
||||||
[taoensso.timbre :as log]))
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(fx/defn status-node-started
|
(rf/defn status-node-started
|
||||||
[{db :db :as cofx} {:keys [error]}]
|
[{db :db :as cofx} {:keys [error]}]
|
||||||
(log/debug "[signals] status-node-started"
|
(log/debug "[signals] status-node-started"
|
||||||
"error" error)
|
"error"
|
||||||
|
error)
|
||||||
(if error
|
(if error
|
||||||
(cond-> {:db (-> db
|
(cond->
|
||||||
(update :multiaccounts/login dissoc :processing)
|
{:db (-> db
|
||||||
(assoc-in [:multiaccounts/login :error]
|
(update :multiaccounts/login dissoc :processing)
|
||||||
;; NOTE: the only currently known error is
|
(assoc-in [:multiaccounts/login :error]
|
||||||
;; "file is not a database" which occurs
|
;; NOTE: the only currently known error is
|
||||||
;; when the user inputs the wrong password
|
;; "file is not a database" which occurs
|
||||||
;; if that is the error that is found
|
;; when the user inputs the wrong password
|
||||||
;; we show the i18n label for wrong password
|
;; if that is the error that is found
|
||||||
;; to the user
|
;; we show the i18n label for wrong password
|
||||||
;; in case of an unknown error we show the
|
;; to the user
|
||||||
;; error
|
;; in case of an unknown error we show the
|
||||||
(if (= error "file is not a database")
|
;; error
|
||||||
(i18n/label :t/wrong-password)
|
(if (= error "file is not a database")
|
||||||
error)))}
|
(i18n/label :t/wrong-password)
|
||||||
|
error)))}
|
||||||
(= (:view-id db) :progress)
|
(= (:view-id db) :progress)
|
||||||
(assoc :dispatch [:navigate-to :login]))
|
(assoc :dispatch [:navigate-to :login]))
|
||||||
(login/multiaccount-login-success cofx)))
|
(login/multiaccount-login-success cofx)))
|
||||||
|
|
||||||
(fx/defn summary
|
(rf/defn summary
|
||||||
[{:keys [db] :as cofx} peers-summary]
|
[{:keys [db] :as cofx} peers-summary]
|
||||||
(let [previous-summary (:peers-summary db)
|
(let [previous-summary (:peers-summary db)
|
||||||
peers-count (count peers-summary)]
|
peers-count (count peers-summary)]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc db
|
{:db (assoc db
|
||||||
:peers-summary peers-summary
|
:peers-summary peers-summary
|
||||||
:peers-count peers-count)}
|
:peers-count peers-count)}
|
||||||
(visibility-status-updates/peers-summary-change peers-count))))
|
(visibility-status-updates/peers-summary-change peers-count))))
|
||||||
|
|
||||||
(fx/defn wakuv2-peer-stats
|
(rf/defn wakuv2-peer-stats
|
||||||
[{:keys [db]} peer-stats]
|
[{:keys [db]} peer-stats]
|
||||||
(let [previous-stats (:peer-stats db)]
|
(let [previous-stats (:peer-stats db)]
|
||||||
{:db (assoc db :peer-stats peer-stats
|
{:db (assoc db
|
||||||
|
:peer-stats peer-stats
|
||||||
:peers-count (count (:peers peer-stats)))}))
|
:peers-count (count (:peers peer-stats)))}))
|
||||||
|
|
||||||
(defn handle-local-pairing-signals [signal-type]
|
(defn handle-local-pairing-signals
|
||||||
|
[signal-type]
|
||||||
(log/info "local pairing signal received"
|
(log/info "local pairing signal received"
|
||||||
{:signal-type signal-type}))
|
{:signal-type signal-type}))
|
||||||
|
|
||||||
(fx/defn process
|
(rf/defn process
|
||||||
{:events [:signals/signal-received]}
|
{:events [:signals/signal-received]}
|
||||||
[{:keys [db] :as cofx} event-str]
|
[{:keys [db] :as cofx} event-str]
|
||||||
;; We only convert to clojure when strictly necessary or we know it
|
;; We only convert to clojure when strictly necessary or we know it
|
||||||
;; won't impact performance, as it is a fairly costly operation on large-ish
|
;; won't impact performance, as it is a fairly costly operation on large-ish
|
||||||
;; data structures
|
;; data structures
|
||||||
(let [^js data (.parse js/JSON event-str)
|
(let [^js data (.parse js/JSON event-str)
|
||||||
^js event-js (.-event data)
|
^js event-js (.-event data)
|
||||||
type (.-type data)]
|
type (.-type data)]
|
||||||
(case type
|
(case type
|
||||||
"node.login" (status-node-started cofx (js->clj event-js :keywordize-keys true))
|
"node.login" (status-node-started cofx (js->clj event-js :keywordize-keys true))
|
||||||
"backup.performed" {:db (assoc-in db [:multiaccount :last-backup] (.-lastBackup event-js))}
|
"backup.performed" {:db (assoc-in db [:multiaccount :last-backup] (.-lastBackup event-js))}
|
||||||
"envelope.sent" (transport.message/update-envelopes-status cofx (:ids (js->clj event-js :keywordize-keys true)) :sent)
|
"envelope.sent" (transport.message/update-envelopes-status cofx
|
||||||
"envelope.expired" (transport.message/update-envelopes-status cofx (:ids (js->clj event-js :keywordize-keys true)) :not-sent)
|
(:ids
|
||||||
"message.delivered" (let [{:keys [chatID messageID]} (js->clj event-js :keywordize-keys true)]
|
(js->clj event-js
|
||||||
(models.message/update-db-message-status cofx chatID messageID :delivered))
|
:keywordize-keys
|
||||||
"mailserver.changed" (mailserver/handle-mailserver-changed cofx (.-id event-js))
|
true))
|
||||||
"mailserver.available" (mailserver/handle-mailserver-available cofx (.-id event-js))
|
:sent)
|
||||||
"mailserver.not.working" (mailserver/handle-mailserver-not-working cofx)
|
"envelope.expired" (transport.message/update-envelopes-status cofx
|
||||||
"discovery.summary" (summary cofx (js->clj event-js :keywordize-keys true))
|
(:ids
|
||||||
"mediaserver.started" {:db (assoc db :mediaserver/port (.-port event-js))}
|
(js->clj event-js
|
||||||
"wakuv2.peerstats" (wakuv2-peer-stats cofx (js->clj event-js :keywordize-keys true))
|
:keywordize-keys
|
||||||
"messages.new" (transport.message/sanitize-messages-and-process-response cofx event-js true)
|
true))
|
||||||
"wallet" (ethereum.subscriptions/new-wallet-event cofx (js->clj event-js :keywordize-keys true))
|
:not-sent)
|
||||||
"local-notifications" (local-notifications/process cofx (js->clj event-js :keywordize-keys true))
|
"message.delivered" (let [{:keys [chatID messageID]} (js->clj event-js
|
||||||
"community.found" (link.preview/cache-community-preview-data (js->clj event-js :keywordize-keys true))
|
:keywordize-keys
|
||||||
"status.updates.timedout" (visibility-status-updates/handle-visibility-status-updates cofx (js->clj event-js :keywordize-keys true))
|
true)]
|
||||||
"localPairing" (handle-local-pairing-signals event-str)
|
(models.message/update-db-message-status cofx
|
||||||
|
chatID
|
||||||
|
messageID
|
||||||
|
:delivered))
|
||||||
|
"mailserver.changed" (mailserver/handle-mailserver-changed cofx (.-id event-js))
|
||||||
|
"mailserver.available" (mailserver/handle-mailserver-available cofx (.-id event-js))
|
||||||
|
"mailserver.not.working" (mailserver/handle-mailserver-not-working cofx)
|
||||||
|
"discovery.summary" (summary cofx (js->clj event-js :keywordize-keys true))
|
||||||
|
"mediaserver.started" {:db (assoc db :mediaserver/port (.-port event-js))}
|
||||||
|
"wakuv2.peerstats" (wakuv2-peer-stats cofx (js->clj event-js :keywordize-keys true))
|
||||||
|
"messages.new" (transport.message/sanitize-messages-and-process-response cofx
|
||||||
|
event-js
|
||||||
|
true)
|
||||||
|
"wallet" (ethereum.subscriptions/new-wallet-event cofx
|
||||||
|
(js->clj event-js
|
||||||
|
:keywordize-keys
|
||||||
|
true))
|
||||||
|
"local-notifications" (local-notifications/process cofx
|
||||||
|
(js->clj event-js :keywordize-keys true))
|
||||||
|
"community.found" (link.preview/cache-community-preview-data (js->clj event-js
|
||||||
|
:keywordize-keys
|
||||||
|
true))
|
||||||
|
"status.updates.timedout" (visibility-status-updates/handle-visibility-status-updates
|
||||||
|
cofx
|
||||||
|
(js->clj event-js :keywordize-keys true))
|
||||||
|
"localPairing" (handle-local-pairing-signals event-str)
|
||||||
(log/debug "Event " type " not handled"))))
|
(log/debug "Event " type " not handled"))))
|
||||||
|
|||||||
+221
-192
@@ -1,27 +1,27 @@
|
|||||||
(ns status-im.signing.core
|
(ns status-im.signing.core
|
||||||
(:require [clojure.string :as string]
|
(:require [clojure.set :as clojure.set]
|
||||||
|
[clojure.string :as string]
|
||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
[status-im.constants :as constants]
|
[status-im.constants :as constants]
|
||||||
[status-im.ethereum.core :as ethereum]
|
[status-im.ethereum.core :as ethereum]
|
||||||
[status-im.ethereum.eip55 :as eip55]
|
[status-im.ethereum.eip55 :as eip55]
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
[status-im.ethereum.tokens :as tokens]
|
[status-im.ethereum.tokens :as tokens]
|
||||||
[status-im.keycard.common :as keycard.common]
|
|
||||||
[status-im.i18n.i18n :as i18n]
|
[status-im.i18n.i18n :as i18n]
|
||||||
[status-im.keycard.card :as keycard.card]
|
[status-im.keycard.card :as keycard.card]
|
||||||
|
[status-im.keycard.common :as keycard.common]
|
||||||
[status-im.native-module.core :as status]
|
[status-im.native-module.core :as status]
|
||||||
|
[status-im.signing.eip1559 :as eip1559]
|
||||||
[status-im.signing.keycard :as signing.keycard]
|
[status-im.signing.keycard :as signing.keycard]
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[status-im.utils.hex :as utils.hex]
|
[status-im.utils.hex :as utils.hex]
|
||||||
[status-im.utils.money :as money]
|
[status-im.utils.money :as money]
|
||||||
[utils.security.core :as security]
|
|
||||||
[status-im.utils.types :as types]
|
[status-im.utils.types :as types]
|
||||||
[status-im.utils.utils :as utils]
|
[status-im.utils.utils :as utils]
|
||||||
[status-im.wallet.prices :as prices]
|
|
||||||
[status-im.wallet.core :as wallet]
|
[status-im.wallet.core :as wallet]
|
||||||
|
[status-im.wallet.prices :as prices]
|
||||||
[taoensso.timbre :as log]
|
[taoensso.timbre :as log]
|
||||||
[clojure.set :as clojure.set]
|
[utils.re-frame :as rf]
|
||||||
[status-im.signing.eip1559 :as eip1559]))
|
[utils.security.core :as security]))
|
||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
:signing/send-transaction-fx
|
:signing/send-transaction-fx
|
||||||
@@ -59,42 +59,46 @@
|
|||||||
(status/sign-typed-data-v4 data account hashed-password on-completed)
|
(status/sign-typed-data-v4 data account hashed-password on-completed)
|
||||||
(status/sign-typed-data data account hashed-password on-completed))))
|
(status/sign-typed-data data account hashed-password on-completed))))
|
||||||
|
|
||||||
(defn get-contact [db to]
|
(defn get-contact
|
||||||
|
[db to]
|
||||||
(let [to (utils.hex/normalize-hex to)]
|
(let [to (utils.hex/normalize-hex to)]
|
||||||
(or
|
(or
|
||||||
(get-in db [:contacts/contacts to])
|
(get-in db [:contacts/contacts to])
|
||||||
{:address (ethereum/normalized-hex to)})))
|
{:address (ethereum/normalized-hex to)})))
|
||||||
|
|
||||||
(fx/defn change-password
|
(rf/defn change-password
|
||||||
{:events [:signing.ui/password-is-changed]}
|
{:events [:signing.ui/password-is-changed]}
|
||||||
[{db :db} password]
|
[{db :db} password]
|
||||||
(let [unmasked-pass (security/safe-unmask-data password)]
|
(let [unmasked-pass (security/safe-unmask-data password)]
|
||||||
{:db (update db :signing/sign assoc
|
{:db (update db
|
||||||
:password password
|
:signing/sign assoc
|
||||||
:error nil
|
:password password
|
||||||
:enabled? (and unmasked-pass (> (count unmasked-pass) 5)))}))
|
:error nil
|
||||||
|
:enabled? (and unmasked-pass (> (count unmasked-pass) 5)))}))
|
||||||
|
|
||||||
(fx/defn sign-message
|
(rf/defn sign-message
|
||||||
[{{:signing/keys [sign tx] :as db} :db}]
|
[{{:signing/keys [sign tx] :as db} :db}]
|
||||||
(let [{{:keys [data typed? from v4]} :message} tx
|
(let [{{:keys [data typed? from v4]} :message} tx
|
||||||
{:keys [in-progress? password]} sign
|
{:keys [in-progress? password]} sign
|
||||||
from (or from (ethereum/default-address db))
|
from (or from (ethereum/default-address db))
|
||||||
hashed-password (ethereum/sha3 (security/safe-unmask-data password))]
|
hashed-password (ethereum/sha3 (security/safe-unmask-data password))]
|
||||||
(when-not in-progress?
|
(when-not in-progress?
|
||||||
(merge
|
(merge
|
||||||
{:db (update db :signing/sign assoc :error nil :in-progress? true)}
|
{:db (update db :signing/sign assoc :error nil :in-progress? true)}
|
||||||
(if typed?
|
(if typed?
|
||||||
{:signing.fx/sign-typed-data {:v4 v4
|
{:signing.fx/sign-typed-data {:v4 v4
|
||||||
:data data
|
:data data
|
||||||
:account from
|
:account from
|
||||||
:hashed-password hashed-password
|
:hashed-password hashed-password
|
||||||
:on-completed #(re-frame/dispatch [:signing/sign-message-completed %])}}
|
:on-completed #(re-frame/dispatch
|
||||||
|
[:signing/sign-message-completed %])}}
|
||||||
{:signing.fx/sign-message {:params {:data data
|
{:signing.fx/sign-message {:params {:data data
|
||||||
:password hashed-password
|
:password hashed-password
|
||||||
:account from}
|
:account from}
|
||||||
:on-completed #(re-frame/dispatch [:signing/sign-message-completed %])}})))))
|
:on-completed #(re-frame/dispatch [:signing/sign-message-completed
|
||||||
|
%])}})))))
|
||||||
|
|
||||||
(fx/defn send-transaction
|
(rf/defn send-transaction
|
||||||
{:events [:signing.ui/sign-is-pressed]}
|
{:events [:signing.ui/sign-is-pressed]}
|
||||||
[{{:signing/keys [sign tx] :as db} :db :as cofx}]
|
[{{:signing/keys [sign tx] :as db} :db :as cofx}]
|
||||||
(let [{:keys [in-progress? password]} sign
|
(let [{:keys [in-progress? password]} sign
|
||||||
@@ -110,57 +114,62 @@
|
|||||||
(when nonce
|
(when nonce
|
||||||
{:nonce (str "0x" (status/number-to-hex nonce))})
|
{:nonce (str "0x" (status/number-to-hex nonce))})
|
||||||
(when maxPriorityFeePerGas
|
(when maxPriorityFeePerGas
|
||||||
{:maxPriorityFeePerGas (str "0x" (status/number-to-hex
|
{:maxPriorityFeePerGas (str "0x"
|
||||||
(js/parseInt maxPriorityFeePerGas)))})
|
(status/number-to-hex
|
||||||
|
(js/parseInt maxPriorityFeePerGas)))})
|
||||||
(when maxFeePerGas
|
(when maxFeePerGas
|
||||||
{:maxFeePerGas (str "0x" (status/number-to-hex
|
{:maxFeePerGas (str "0x"
|
||||||
(js/parseInt maxFeePerGas)))}))]
|
(status/number-to-hex
|
||||||
|
(js/parseInt maxFeePerGas)))}))]
|
||||||
(when-not in-progress?
|
(when-not in-progress?
|
||||||
{:db (update db :signing/sign assoc :error nil :in-progress? true)
|
{:db (update db :signing/sign assoc :error nil :in-progress? true)
|
||||||
:signing/send-transaction-fx {:tx-obj tx-obj-to-send
|
:signing/send-transaction-fx {:tx-obj tx-obj-to-send
|
||||||
:hashed-password hashed-password
|
:hashed-password hashed-password
|
||||||
:cb #(re-frame/dispatch [:signing/transaction-completed % tx-obj-to-send hashed-password])}})))))
|
:cb #(re-frame/dispatch
|
||||||
|
[:signing/transaction-completed %
|
||||||
|
tx-obj-to-send hashed-password])}})))))
|
||||||
|
|
||||||
(fx/defn prepare-unconfirmed-transaction
|
(rf/defn prepare-unconfirmed-transaction
|
||||||
[{:keys [db now]} new-tx-hash
|
[{:keys [db now]} new-tx-hash
|
||||||
{:keys [value gasPrice maxFeePerGas maxPriorityFeePerGas gas data to from hash]} symbol amount]
|
{:keys [value gasPrice maxFeePerGas maxPriorityFeePerGas gas data to from hash]} symbol amount]
|
||||||
(let [token (tokens/symbol->token (:wallet/all-tokens db) symbol)
|
(let [token (tokens/symbol->token (:wallet/all-tokens db) symbol)
|
||||||
from (eip55/address->checksum from)
|
from (eip55/address->checksum from)
|
||||||
;;if there is a hash in the tx object that means we resending transaction
|
;;if there is a hash in the tx object that means we resending transaction
|
||||||
old-tx-hash hash
|
old-tx-hash hash
|
||||||
gas-price (money/to-fixed (money/bignumber gasPrice))
|
gas-price (money/to-fixed (money/bignumber gasPrice))
|
||||||
gas-limit (money/to-fixed (money/bignumber gas))
|
gas-limit (money/to-fixed (money/bignumber gas))
|
||||||
tx {:timestamp now
|
tx {:timestamp now
|
||||||
:to to
|
:to to
|
||||||
:from from
|
:from from
|
||||||
:type :pending
|
:type :pending
|
||||||
:hash new-tx-hash
|
:hash new-tx-hash
|
||||||
:data data
|
:data data
|
||||||
:token token
|
:token token
|
||||||
:symbol symbol
|
:symbol symbol
|
||||||
:value (if token
|
:value (if token
|
||||||
(money/to-fixed (money/unit->token amount (:decimals token)))
|
(money/to-fixed (money/unit->token amount (:decimals token)))
|
||||||
(money/to-fixed (money/bignumber value)))
|
(money/to-fixed (money/bignumber value)))
|
||||||
:gas-price gas-price
|
:gas-price gas-price
|
||||||
:fee-cap maxFeePerGas
|
:fee-cap maxFeePerGas
|
||||||
:tip-cap maxPriorityFeePerGas
|
:tip-cap maxPriorityFeePerGas
|
||||||
:gas-limit gas-limit}]
|
:gas-limit gas-limit}]
|
||||||
(log/info "[signing] prepare-unconfirmed-transaction" tx)
|
(log/info "[signing] prepare-unconfirmed-transaction" tx)
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
;;remove old transaction, because we replace it with the new one
|
;;remove old transaction, because we replace it with the new one
|
||||||
(update-in [:wallet :accounts from :transactions] dissoc old-tx-hash)
|
(update-in [:wallet :accounts from :transactions] dissoc old-tx-hash)
|
||||||
(assoc-in [:wallet :accounts from :transactions new-tx-hash] tx))
|
(assoc-in [:wallet :accounts from :transactions new-tx-hash] tx))
|
||||||
::json-rpc/call [{:method "wallet_storePendingTransaction"
|
::json-rpc/call [{:method "wallet_storePendingTransaction"
|
||||||
:params [(-> tx
|
:params [(-> tx
|
||||||
(dissoc :gas-price :gas-limit)
|
(dissoc :gas-price :gas-limit)
|
||||||
(assoc :gasPrice
|
(assoc :gasPrice
|
||||||
(money/to-fixed (money/bignumber gasPrice))
|
(money/to-fixed (money/bignumber gasPrice))
|
||||||
:gasLimit (money/to-fixed (money/bignumber gas)))
|
:gasLimit (money/to-fixed (money/bignumber gas)))
|
||||||
clj->js)]
|
clj->js)]
|
||||||
:on-success #(log/info "pending transfer is saved")
|
:on-success #(log/info "pending transfer is saved")
|
||||||
:on-error #(log/info "pending transfer was not saved" %)}]}))
|
:on-error #(log/info "pending transfer was not saved" %)}]}))
|
||||||
|
|
||||||
(defn get-method-type [data]
|
(defn get-method-type
|
||||||
|
[data]
|
||||||
(cond
|
(cond
|
||||||
(string/starts-with? data constants/method-id-transfer)
|
(string/starts-with? data constants/method-id-transfer)
|
||||||
:transfer
|
:transfer
|
||||||
@@ -169,13 +178,16 @@
|
|||||||
(string/starts-with? data constants/method-id-approve-and-call)
|
(string/starts-with? data constants/method-id-approve-and-call)
|
||||||
:approve-and-call))
|
:approve-and-call))
|
||||||
|
|
||||||
(defn get-transfer-token [db to data]
|
(defn get-transfer-token
|
||||||
|
[db to data]
|
||||||
(let [{:keys [symbol decimals] :as token} (tokens/address->token (:wallet/all-tokens db) to)]
|
(let [{:keys [symbol decimals] :as token} (tokens/address->token (:wallet/all-tokens db) to)]
|
||||||
(when (and token data (string? data))
|
(when (and token data (string? data))
|
||||||
(when-let [type (get-method-type data)]
|
(when-let [type (get-method-type data)]
|
||||||
(let [[address value _] (status/decode-parameters
|
(let [[address value _] (status/decode-parameters
|
||||||
(str "0x" (subs data 10))
|
(str "0x" (subs data 10))
|
||||||
(if (= type :approve-and-call) ["address" "uint256" "bytes"] ["address" "uint256"]))]
|
(if (= type :approve-and-call)
|
||||||
|
["address" "uint256" "bytes"]
|
||||||
|
["address" "uint256"]))]
|
||||||
(when (and address value)
|
(when (and address value)
|
||||||
{:to address
|
{:to address
|
||||||
:contact (get-contact db address)
|
:contact (get-contact db address)
|
||||||
@@ -186,7 +198,8 @@
|
|||||||
:token token
|
:token token
|
||||||
:symbol symbol}))))))
|
:symbol symbol}))))))
|
||||||
|
|
||||||
(defn parse-tx-obj [db {:keys [from to value data cancel? hash]}]
|
(defn parse-tx-obj
|
||||||
|
[db {:keys [from to value data cancel? hash]}]
|
||||||
(merge {:from {:address from}
|
(merge {:from {:address from}
|
||||||
:cancel? cancel?
|
:cancel? cancel?
|
||||||
:hash hash}
|
:hash hash}
|
||||||
@@ -196,20 +209,23 @@
|
|||||||
eth-amount (when eth-value (money/to-fixed (money/wei->ether eth-value)))
|
eth-amount (when eth-value (money/to-fixed (money/wei->ether eth-value)))
|
||||||
token (get-transfer-token db to data)]
|
token (get-transfer-token db to data)]
|
||||||
(cond
|
(cond
|
||||||
(and eth-amount (or (not (.equals ^js (money/bignumber 0) ^js eth-amount)) (nil? data)))
|
(and eth-amount (or (not (.equals ^js (money/bignumber 0) ^js eth-amount)) (nil? data)))
|
||||||
{:to to
|
{:to to
|
||||||
:contact (get-contact db to)
|
:contact (get-contact db to)
|
||||||
:symbol :ETH
|
:symbol :ETH
|
||||||
:value value
|
:value value
|
||||||
:amount (str eth-amount)
|
:amount (str eth-amount)
|
||||||
:token (tokens/asset-for (:wallet/all-tokens db) (ethereum/get-current-network db) :ETH)}
|
:token (tokens/asset-for (:wallet/all-tokens db)
|
||||||
|
(ethereum/get-current-network db)
|
||||||
|
:ETH)}
|
||||||
(not (nil? token))
|
(not (nil? token))
|
||||||
token
|
token
|
||||||
:else
|
:else
|
||||||
{:to to
|
{:to to
|
||||||
:contact {:address (ethereum/normalized-hex to)}})))))
|
:contact {:address (ethereum/normalized-hex to)}})))))
|
||||||
|
|
||||||
(defn prepare-tx [db {{:keys [data gas gasPrice maxFeePerGas maxPriorityFeePerGas] :as tx-obj} :tx-obj :as tx}]
|
(defn prepare-tx
|
||||||
|
[db {{:keys [data gas gasPrice maxFeePerGas maxPriorityFeePerGas] :as tx-obj} :tx-obj :as tx}]
|
||||||
(merge
|
(merge
|
||||||
tx
|
tx
|
||||||
(parse-tx-obj db tx-obj)
|
(parse-tx-obj db tx-obj)
|
||||||
@@ -221,45 +237,52 @@
|
|||||||
:maxPriorityFeePerGas (when maxPriorityFeePerGas
|
:maxPriorityFeePerGas (when maxPriorityFeePerGas
|
||||||
(money/bignumber maxPriorityFeePerGas))}))
|
(money/bignumber maxPriorityFeePerGas))}))
|
||||||
|
|
||||||
(fx/defn show-sign [{:keys [db] :as cofx}]
|
(rf/defn show-sign
|
||||||
|
[{:keys [db] :as cofx}]
|
||||||
(let [{:signing/keys [queue]} db
|
(let [{:signing/keys [queue]} db
|
||||||
{{:keys [gas gasPrice maxFeePerGas] :as tx-obj} :tx-obj {:keys [data typed? pinless?] :as message} :message :as tx} (last queue)
|
{{:keys [gas gasPrice maxFeePerGas] :as tx-obj} :tx-obj
|
||||||
|
{:keys [data typed? pinless?] :as message} :message
|
||||||
|
:as tx}
|
||||||
|
(last queue)
|
||||||
keycard-multiaccount? (boolean (get-in db [:multiaccount :keycard-pairing]))
|
keycard-multiaccount? (boolean (get-in db [:multiaccount :keycard-pairing]))
|
||||||
wallet-set-up-passed? (get-in db [:multiaccount :wallet-set-up-passed?])]
|
wallet-set-up-passed? (get-in db [:multiaccount :wallet-set-up-passed?])]
|
||||||
(if message
|
(if message
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (assoc db
|
{:db (assoc db
|
||||||
:signing/queue (drop-last queue)
|
:signing/queue (drop-last queue)
|
||||||
:signing/tx tx
|
:signing/tx tx
|
||||||
:signing/sign {:type (cond pinless? :pinless
|
:signing/sign {:type (cond pinless? :pinless
|
||||||
keycard-multiaccount? :keycard
|
keycard-multiaccount? :keycard
|
||||||
:else :password)
|
:else :password)
|
||||||
:formatted-data (if typed?
|
:formatted-data (if typed?
|
||||||
(types/js->pretty-json (types/json->js data))
|
(types/js->pretty-json
|
||||||
(ethereum/hex->text data))
|
(types/json->js data))
|
||||||
:keycard-step (when pinless? :connect)})
|
(ethereum/hex->text data))
|
||||||
|
:keycard-step (when pinless? :connect)})
|
||||||
:show-signing-sheet nil}
|
:show-signing-sheet nil}
|
||||||
#(when-not wallet-set-up-passed?
|
#(when-not wallet-set-up-passed?
|
||||||
{:dispatch-later [{:dispatch [:show-popover {:view :signing-phrase}] :ms 200}]})
|
{:dispatch-later [{:dispatch [:show-popover {:view :signing-phrase}] :ms 200}]})
|
||||||
(when pinless?
|
(when pinless?
|
||||||
(keycard.card/start-nfc {:on-success #(re-frame/dispatch [:keycard.callback/start-nfc-success])
|
(keycard.card/start-nfc {:on-success #(re-frame/dispatch [:keycard.callback/start-nfc-success])
|
||||||
:on-failure #(re-frame/dispatch [:keycard.callback/start-nfc-failure])})
|
:on-failure #(re-frame/dispatch
|
||||||
(signing.keycard/hash-message {:data data
|
[:keycard.callback/start-nfc-failure])})
|
||||||
:typed? true
|
(signing.keycard/hash-message
|
||||||
:on-completed #(re-frame/dispatch [:keycard/store-hash-and-sign-typed %])})))
|
{:data data
|
||||||
(fx/merge
|
:typed? true
|
||||||
|
:on-completed #(re-frame/dispatch [:keycard/store-hash-and-sign-typed %])})))
|
||||||
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (assoc db
|
{:db (assoc db
|
||||||
:signing/queue (drop-last queue)
|
:signing/queue (drop-last queue)
|
||||||
:signing/tx (prepare-tx db tx))
|
:signing/tx (prepare-tx db tx))
|
||||||
:show-signing-sheet nil
|
:show-signing-sheet nil
|
||||||
:dismiss-keyboard nil}
|
:dismiss-keyboard nil}
|
||||||
#(when-not wallet-set-up-passed?
|
#(when-not wallet-set-up-passed?
|
||||||
{:dispatch-later [{:dispatch [:show-popover {:view :signing-phrase}] :ms 200}]})
|
{:dispatch-later [{:dispatch [:show-popover {:view :signing-phrase}] :ms 200}]})
|
||||||
(prices/update-prices)
|
(prices/update-prices)
|
||||||
#(when-not gas
|
#(when-not gas
|
||||||
{:db (assoc-in (:db %) [:signing/edit-fee :gas-loading?] true)
|
{:db (assoc-in (:db %) [:signing/edit-fee :gas-loading?] true)
|
||||||
:signing/update-estimated-gas {:obj (-> tx-obj
|
:signing/update-estimated-gas {:obj (-> tx-obj
|
||||||
(dissoc :gasPrice)
|
(dissoc :gasPrice)
|
||||||
(update :maxFeePerGas
|
(update :maxFeePerGas
|
||||||
@@ -269,9 +292,9 @@
|
|||||||
(money/mul 2)
|
(money/mul 2)
|
||||||
money/to-hex))))
|
money/to-hex))))
|
||||||
:success-event :signing/update-estimated-gas-success
|
:success-event :signing/update-estimated-gas-success
|
||||||
:error-event :signing/update-estimated-gas-error}})
|
:error-event :signing/update-estimated-gas-error}})
|
||||||
(fn [cofx]
|
(fn [cofx]
|
||||||
{:db (assoc-in (:db cofx) [:signing/edit-fee :gas-price-loading?] true)
|
{:db (assoc-in (:db cofx) [:signing/edit-fee :gas-price-loading?] true)
|
||||||
:signing/update-gas-price
|
:signing/update-gas-price
|
||||||
{:success-callback #(re-frame/dispatch
|
{:success-callback #(re-frame/dispatch
|
||||||
[:wallet.send/update-gas-price-success :signing/tx % tx-obj])
|
[:wallet.send/update-gas-price-success :signing/tx % tx-obj])
|
||||||
@@ -279,40 +302,41 @@
|
|||||||
:network-id (get-in (ethereum/current-network db)
|
:network-id (get-in (ethereum/current-network db)
|
||||||
[:config :NetworkId])}})))))
|
[:config :NetworkId])}})))))
|
||||||
|
|
||||||
(fx/defn check-queue [{:keys [db] :as cofx}]
|
(rf/defn check-queue
|
||||||
|
[{:keys [db] :as cofx}]
|
||||||
(let [{:signing/keys [tx queue]} db]
|
(let [{:signing/keys [tx queue]} db]
|
||||||
(when (and (not tx) (seq queue))
|
(when (and (not tx) (seq queue))
|
||||||
(show-sign cofx))))
|
(show-sign cofx))))
|
||||||
|
|
||||||
(fx/defn send-transaction-message
|
(rf/defn send-transaction-message
|
||||||
{:events [:sign/send-transaction-message]}
|
{:events [:sign/send-transaction-message]}
|
||||||
[cofx chat-id value contract transaction-hash signature]
|
[cofx chat-id value contract transaction-hash signature]
|
||||||
{::json-rpc/call [{:method "wakuext_sendTransaction"
|
{::json-rpc/call [{:method "wakuext_sendTransaction"
|
||||||
;; We make sure `value` is serialized as string, and not
|
;; We make sure `value` is serialized as string, and not
|
||||||
;; as an integer or big-int
|
;; as an integer or big-int
|
||||||
:params [chat-id (str value) contract transaction-hash
|
:params [chat-id (str value) contract transaction-hash
|
||||||
(or (:result (types/json->clj signature))
|
(or (:result (types/json->clj signature))
|
||||||
(ethereum/normalized-hex signature))]
|
(ethereum/normalized-hex signature))]
|
||||||
:js-response true
|
:js-response true
|
||||||
:on-success
|
:on-success
|
||||||
#(re-frame/dispatch [:transport/message-sent %])}]})
|
#(re-frame/dispatch [:transport/message-sent %])}]})
|
||||||
|
|
||||||
(fx/defn send-accept-request-transaction-message
|
(rf/defn send-accept-request-transaction-message
|
||||||
{:events [:sign/send-accept-transaction-message]}
|
{:events [:sign/send-accept-transaction-message]}
|
||||||
[cofx message-id transaction-hash signature]
|
[cofx message-id transaction-hash signature]
|
||||||
{::json-rpc/call [{:method "wakuext_acceptRequestTransaction"
|
{::json-rpc/call [{:method "wakuext_acceptRequestTransaction"
|
||||||
:params [transaction-hash message-id
|
:params [transaction-hash message-id
|
||||||
(or (:result (types/json->clj signature))
|
(or (:result (types/json->clj signature))
|
||||||
(ethereum/normalized-hex signature))]
|
(ethereum/normalized-hex signature))]
|
||||||
:js-response true
|
:js-response true
|
||||||
:on-success
|
:on-success
|
||||||
#(re-frame/dispatch [:transport/message-sent %])}]})
|
#(re-frame/dispatch [:transport/message-sent %])}]})
|
||||||
|
|
||||||
(fx/defn transaction-result
|
(rf/defn transaction-result
|
||||||
[{:keys [db] :as cofx} result tx-obj]
|
[{:keys [db] :as cofx} result tx-obj]
|
||||||
(let [{:keys [on-result symbol amount from]} (get db :signing/tx)]
|
(let [{:keys [on-result symbol amount from]} (get db :signing/tx)]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (dissoc db :signing/tx :signing/sign)
|
{:db (dissoc db :signing/tx :signing/sign)
|
||||||
:signing/show-transaction-result nil}
|
:signing/show-transaction-result nil}
|
||||||
(prepare-unconfirmed-transaction result tx-obj symbol amount)
|
(prepare-unconfirmed-transaction result tx-obj symbol amount)
|
||||||
(check-queue)
|
(check-queue)
|
||||||
@@ -320,35 +344,35 @@
|
|||||||
#(when on-result
|
#(when on-result
|
||||||
{:dispatch (conj on-result result)}))))
|
{:dispatch (conj on-result result)}))))
|
||||||
|
|
||||||
(fx/defn command-transaction-result
|
(rf/defn command-transaction-result
|
||||||
[{:keys [db] :as cofx} transaction-hash hashed-password
|
[{:keys [db] :as cofx} transaction-hash hashed-password
|
||||||
{:keys [message-id chat-id from] :as tx-obj}]
|
{:keys [message-id chat-id from] :as tx-obj}]
|
||||||
(let [{:keys [on-result symbol amount contract value]} (get db :signing/tx)
|
(let [{:keys [on-result symbol amount contract value]} (get db :signing/tx)
|
||||||
data (str (get-in db [:multiaccount :public-key])
|
data (str (get-in db [:multiaccount :public-key])
|
||||||
(subs transaction-hash 2))]
|
(subs transaction-hash 2))]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (dissoc db :signing/tx :signing/sign)}
|
{:db (dissoc db :signing/tx :signing/sign)}
|
||||||
(wallet/watch-tx (get from :address) transaction-hash)
|
(wallet/watch-tx (get from :address) transaction-hash)
|
||||||
(if (keycard.common/keycard-multiaccount? db)
|
(if (keycard.common/keycard-multiaccount? db)
|
||||||
(signing.keycard/hash-message
|
(signing.keycard/hash-message
|
||||||
{:data data
|
{:data data
|
||||||
:on-completed
|
:on-completed
|
||||||
(fn [hash]
|
(fn [hash]
|
||||||
(re-frame/dispatch
|
(re-frame/dispatch
|
||||||
[:keycard/sign-message
|
[:keycard/sign-message
|
||||||
{:tx-hash transaction-hash
|
{:tx-hash transaction-hash
|
||||||
:message-id message-id
|
:message-id message-id
|
||||||
:chat-id chat-id
|
:chat-id chat-id
|
||||||
:value value
|
:value value
|
||||||
:contract contract
|
:contract contract
|
||||||
:data data}
|
:data data}
|
||||||
hash]))})
|
hash]))})
|
||||||
(fn [_]
|
(fn [_]
|
||||||
{:signing.fx/sign-message
|
{:signing.fx/sign-message
|
||||||
{:params {:data data
|
{:params {:data data
|
||||||
:password hashed-password
|
:password hashed-password
|
||||||
:account from}
|
:account from}
|
||||||
:on-completed
|
:on-completed
|
||||||
(fn [res]
|
(fn [res]
|
||||||
(re-frame/dispatch
|
(re-frame/dispatch
|
||||||
@@ -362,7 +386,7 @@
|
|||||||
#(when on-result
|
#(when on-result
|
||||||
{:dispatch (conj on-result transaction-hash)}))))
|
{:dispatch (conj on-result transaction-hash)}))))
|
||||||
|
|
||||||
(fx/defn transaction-error
|
(rf/defn transaction-error
|
||||||
[{:keys [db]} {:keys [code message]}]
|
[{:keys [db]} {:keys [code message]}]
|
||||||
(let [on-error (get-in db [:signing/tx :on-error])]
|
(let [on-error (get-in db [:signing/tx :on-error])]
|
||||||
(if (= code constants/send-transaction-err-decrypt)
|
(if (= code constants/send-transaction-err-decrypt)
|
||||||
@@ -373,34 +397,36 @@
|
|||||||
(when on-error
|
(when on-error
|
||||||
{:dispatch (conj on-error message)})))))
|
{:dispatch (conj on-error message)})))))
|
||||||
|
|
||||||
(fx/defn dissoc-signing-db-entries-and-check-queue
|
(rf/defn dissoc-signing-db-entries-and-check-queue
|
||||||
{:events [:signing/dissoc-entries-and-check-queue]}
|
{:events [:signing/dissoc-entries-and-check-queue]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (dissoc db :signing/tx :signing/sign)}
|
{:db (dissoc db :signing/tx :signing/sign)}
|
||||||
check-queue))
|
check-queue))
|
||||||
|
|
||||||
(fx/defn sign-message-completed
|
(rf/defn sign-message-completed
|
||||||
{:events [:signing/sign-message-completed]}
|
{:events [:signing/sign-message-completed]}
|
||||||
[{:keys [db] :as cofx} result]
|
[{:keys [db] :as cofx} result]
|
||||||
(let [{:keys [result error]} (types/json->clj result)
|
(let [{:keys [result error]} (types/json->clj result)
|
||||||
on-result (get-in db [:signing/tx :on-result])]
|
on-result (get-in db [:signing/tx :on-result])]
|
||||||
(if error
|
(if error
|
||||||
{:db (update db :signing/sign
|
{:db (update db
|
||||||
assoc :error (if (= 5 (:code error))
|
:signing/sign
|
||||||
|
assoc
|
||||||
|
:error (if (= 5 (:code error))
|
||||||
(i18n/label :t/wrong-password)
|
(i18n/label :t/wrong-password)
|
||||||
(:message error))
|
(:message error))
|
||||||
:in-progress? false)}
|
:in-progress? false)}
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(when-not (= (-> db :signing/sign :type) :pinless)
|
(when-not (= (-> db :signing/sign :type) :pinless)
|
||||||
(dissoc-signing-db-entries-and-check-queue))
|
(dissoc-signing-db-entries-and-check-queue))
|
||||||
#(when (= (-> db :signing/sign :type) :pinless)
|
#(when (= (-> db :signing/sign :type) :pinless)
|
||||||
{:dispatch-later [{:ms 3000
|
{:dispatch-later [{:ms 3000
|
||||||
:dispatch [:signing/dissoc-entries-and-check-queue]}]})
|
:dispatch [:signing/dissoc-entries-and-check-queue]}]})
|
||||||
#(when on-result
|
#(when on-result
|
||||||
{:dispatch (conj on-result result)})))))
|
{:dispatch (conj on-result result)})))))
|
||||||
|
|
||||||
(fx/defn transaction-completed
|
(rf/defn transaction-completed
|
||||||
{:events [:signing/transaction-completed]
|
{:events [:signing/transaction-completed]
|
||||||
:interceptors [(re-frame/inject-cofx :random-id-generator)]}
|
:interceptors [(re-frame/inject-cofx :random-id-generator)]}
|
||||||
[cofx response tx-obj hashed-password]
|
[cofx response tx-obj hashed-password]
|
||||||
@@ -412,15 +438,15 @@
|
|||||||
(command-transaction-result cofx-in-progress-false result hashed-password tx-obj)
|
(command-transaction-result cofx-in-progress-false result hashed-password tx-obj)
|
||||||
(transaction-result cofx-in-progress-false result tx-obj)))))
|
(transaction-result cofx-in-progress-false result tx-obj)))))
|
||||||
|
|
||||||
(fx/defn discard
|
(rf/defn discard
|
||||||
"Discrad transaction signing"
|
"Discrad transaction signing"
|
||||||
{:events [:signing.ui/cancel-is-pressed]}
|
{:events [:signing.ui/cancel-is-pressed]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [{:keys [on-error]} (get-in db [:signing/tx])]
|
(let [{:keys [on-error]} (get-in db [:signing/tx])]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:keycard :pin :status] nil)
|
(assoc-in [:keycard :pin :status] nil)
|
||||||
(dissoc :signing/tx :signing/sign))
|
(dissoc :signing/tx :signing/sign))
|
||||||
:hide-signing-sheet nil}
|
:hide-signing-sheet nil}
|
||||||
(check-queue)
|
(check-queue)
|
||||||
(keycard.common/hide-connection-sheet)
|
(keycard.common/hide-connection-sheet)
|
||||||
@@ -428,10 +454,11 @@
|
|||||||
#(when on-error
|
#(when on-error
|
||||||
{:dispatch (conj on-error "transaction was cancelled by user")}))))
|
{:dispatch (conj on-error "transaction was cancelled by user")}))))
|
||||||
|
|
||||||
(defn normalize-tx-obj [db tx]
|
(defn normalize-tx-obj
|
||||||
|
[db tx]
|
||||||
(update-in tx [:tx-obj :from] #(eip55/address->checksum (or % (ethereum/default-address db)))))
|
(update-in tx [:tx-obj :from] #(eip55/address->checksum (or % (ethereum/default-address db)))))
|
||||||
|
|
||||||
(fx/defn sign
|
(rf/defn sign
|
||||||
"Signing transaction or message, shows signing sheet
|
"Signing transaction or message, shows signing sheet
|
||||||
tx
|
tx
|
||||||
{:tx-obj - transaction object to send https://github.com/ethereum/wiki/wiki/JavaScript-API#parameters-25
|
{:tx-obj - transaction object to send https://github.com/ethereum/wiki/wiki/JavaScript-API#parameters-25
|
||||||
@@ -440,80 +467,80 @@
|
|||||||
:on-error - re-frame event vector}"
|
:on-error - re-frame event vector}"
|
||||||
{:events [:signing.ui/sign]}
|
{:events [:signing.ui/sign]}
|
||||||
[{:keys [db] :as cofx} tx]
|
[{:keys [db] :as cofx} tx]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (update db :signing/queue conj (normalize-tx-obj db tx))}
|
{:db (update db :signing/queue conj (normalize-tx-obj db tx))}
|
||||||
(check-queue)))
|
(check-queue)))
|
||||||
|
|
||||||
(fx/defn sign-transaction-button-clicked-from-chat
|
(rf/defn sign-transaction-button-clicked-from-chat
|
||||||
{:events [:wallet.ui/sign-transaction-button-clicked-from-chat]}
|
{:events [:wallet.ui/sign-transaction-button-clicked-from-chat]}
|
||||||
[{:keys [db] :as cofx} {:keys [to amount from token]}]
|
[{:keys [db] :as cofx} {:keys [to amount from token]}]
|
||||||
(let [{:keys [symbol address]} token
|
(let [{:keys [symbol address]} token
|
||||||
amount-hex (str "0x" (status/number-to-hex amount))
|
amount-hex (str "0x" (status/number-to-hex amount))
|
||||||
to-norm (ethereum/normalized-hex (if (string? to) to (:address to)))
|
to-norm (ethereum/normalized-hex (if (string? to) to (:address to)))
|
||||||
from-address (:address from)
|
from-address (:address from)
|
||||||
identity (:current-chat-id db)
|
identity (:current-chat-id db)
|
||||||
db (dissoc db :wallet/prepare-transaction :signing/edit-fee)]
|
db (dissoc db :wallet/prepare-transaction :signing/edit-fee)]
|
||||||
(if to-norm
|
(if to-norm
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db db}
|
{:db db}
|
||||||
(sign {:tx-obj (if (= symbol :ETH)
|
(sign {:tx-obj (if (= symbol :ETH)
|
||||||
{:to to-norm
|
{:to to-norm
|
||||||
:from from-address
|
:from from-address
|
||||||
:chat-id identity
|
:chat-id identity
|
||||||
:command? true
|
:command? true
|
||||||
:value amount-hex}
|
:value amount-hex}
|
||||||
{:to (ethereum/normalized-hex address)
|
{:to (ethereum/normalized-hex address)
|
||||||
:from from-address
|
:from from-address
|
||||||
:chat-id identity
|
:chat-id identity
|
||||||
:command? true
|
:command? true
|
||||||
:data (status/encode-transfer to-norm amount-hex)})}))
|
:data (status/encode-transfer to-norm amount-hex)})}))
|
||||||
{:db db
|
{:db db
|
||||||
::json-rpc/call
|
::json-rpc/call
|
||||||
[{:method "wakuext_requestAddressForTransaction"
|
[{:method "wakuext_requestAddressForTransaction"
|
||||||
:params [(:current-chat-id db)
|
:params [(:current-chat-id db)
|
||||||
from-address
|
from-address
|
||||||
amount
|
amount
|
||||||
(when-not (= symbol :ETH)
|
(when-not (= symbol :ETH)
|
||||||
address)]
|
address)]
|
||||||
:js-response true
|
:js-response true
|
||||||
:on-success #(re-frame/dispatch [:transport/message-sent %])}]})))
|
:on-success #(re-frame/dispatch [:transport/message-sent %])}]})))
|
||||||
|
|
||||||
(fx/defn sign-transaction-button-clicked-from-request
|
(rf/defn sign-transaction-button-clicked-from-request
|
||||||
{:events [:wallet.ui/sign-transaction-button-clicked-from-request]}
|
{:events [:wallet.ui/sign-transaction-button-clicked-from-request]}
|
||||||
[{:keys [db] :as cofx} {:keys [amount from token]}]
|
[{:keys [db] :as cofx} {:keys [amount from token]}]
|
||||||
(let [{:keys [request-parameters chat-id]} (:wallet/prepare-transaction db)
|
(let [{:keys [request-parameters chat-id]} (:wallet/prepare-transaction db)
|
||||||
{:keys [symbol address]} token
|
{:keys [symbol address]} token
|
||||||
amount-hex (str "0x" (status/number-to-hex amount))
|
amount-hex (str "0x" (status/number-to-hex amount))
|
||||||
to-norm (:address request-parameters)
|
to-norm (:address request-parameters)
|
||||||
from-address (:address from)]
|
from-address (:address from)]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (dissoc db :wallet/prepare-transaction :signing/edit-fee)}
|
{:db (dissoc db :wallet/prepare-transaction :signing/edit-fee)}
|
||||||
(fn [cofx]
|
(fn [cofx]
|
||||||
(sign
|
(sign
|
||||||
cofx
|
cofx
|
||||||
{:tx-obj (if (= symbol :ETH)
|
{:tx-obj (if (= symbol :ETH)
|
||||||
{:to to-norm
|
{:to to-norm
|
||||||
:from from-address
|
:from from-address
|
||||||
:message-id (:id request-parameters)
|
:message-id (:id request-parameters)
|
||||||
:chat-id chat-id
|
:chat-id chat-id
|
||||||
:command? true
|
:command? true
|
||||||
:value amount-hex}
|
:value amount-hex}
|
||||||
{:to (ethereum/normalized-hex address)
|
{:to (ethereum/normalized-hex address)
|
||||||
:from from-address
|
:from from-address
|
||||||
:command? true
|
:command? true
|
||||||
:message-id (:id request-parameters)
|
:message-id (:id request-parameters)
|
||||||
:chat-id chat-id
|
:chat-id chat-id
|
||||||
:data (status/encode-transfer to-norm amount-hex)})})))))
|
:data (status/encode-transfer to-norm amount-hex)})})))))
|
||||||
|
|
||||||
(fx/defn sign-transaction-button-clicked
|
(rf/defn sign-transaction-button-clicked
|
||||||
{:events [:wallet.ui/sign-transaction-button-clicked]}
|
{:events [:wallet.ui/sign-transaction-button-clicked]}
|
||||||
[{:keys [db] :as cofx} {:keys [to amount from token gas gasPrice maxFeePerGas maxPriorityFeePerGas]}]
|
[{:keys [db] :as cofx} {:keys [to amount from token gas gasPrice maxFeePerGas maxPriorityFeePerGas]}]
|
||||||
(let [{:keys [symbol address]} token
|
(let [{:keys [symbol address]} token
|
||||||
amount-hex (str "0x" (status/number-to-hex amount))
|
amount-hex (str "0x" (status/number-to-hex amount))
|
||||||
to-norm (ethereum/normalized-hex (if (string? to) to (:address to)))
|
to-norm (ethereum/normalized-hex (if (string? to) to (:address to)))
|
||||||
from-address (:address from)]
|
from-address (:address from)]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (dissoc db :wallet/prepare-transaction :signing/edit-fee)}
|
{:db (dissoc db :wallet/prepare-transaction :signing/edit-fee)}
|
||||||
(sign
|
(sign
|
||||||
{:tx-obj (merge (if (eip1559/sync-enabled?)
|
{:tx-obj (merge (if (eip1559/sync-enabled?)
|
||||||
@@ -540,31 +567,33 @@
|
|||||||
:params [hash]
|
:params [hash]
|
||||||
:on-success handler})))
|
:on-success handler})))
|
||||||
|
|
||||||
(fx/defn cancel-transaction-pressed
|
(rf/defn cancel-transaction-pressed
|
||||||
{:events [:signing.ui/cancel-transaction-pressed]}
|
{:events [:signing.ui/cancel-transaction-pressed]}
|
||||||
[_ hash]
|
[_ hash]
|
||||||
{:signing/get-transaction-by-hash-fx [hash #(re-frame/dispatch [:signing/cancel-transaction %])]})
|
{:signing/get-transaction-by-hash-fx [hash #(re-frame/dispatch [:signing/cancel-transaction %])]})
|
||||||
|
|
||||||
(fx/defn increase-gas-pressed
|
(rf/defn increase-gas-pressed
|
||||||
{:events [:signing.ui/increase-gas-pressed]}
|
{:events [:signing.ui/increase-gas-pressed]}
|
||||||
[_ hash]
|
[_ hash]
|
||||||
{:signing/get-transaction-by-hash-fx [hash #(re-frame/dispatch [:signing/increase-gas %])]})
|
{:signing/get-transaction-by-hash-fx [hash #(re-frame/dispatch [:signing/increase-gas %])]})
|
||||||
|
|
||||||
(fx/defn cancel-transaction
|
(rf/defn cancel-transaction
|
||||||
{:events [:signing/cancel-transaction]}
|
{:events [:signing/cancel-transaction]}
|
||||||
[cofx {:keys [from nonce hash]}]
|
[cofx {:keys [from nonce hash]}]
|
||||||
(when (and from nonce hash)
|
(when (and from nonce hash)
|
||||||
(sign cofx {:tx-obj {:from from
|
(sign cofx
|
||||||
:to from
|
{:tx-obj {:from from
|
||||||
:nonce nonce
|
:to from
|
||||||
:value "0x0"
|
:nonce nonce
|
||||||
:cancel? true
|
:value "0x0"
|
||||||
:hash hash}})))
|
:cancel? true
|
||||||
|
:hash hash}})))
|
||||||
|
|
||||||
(fx/defn increase-gas
|
(rf/defn increase-gas
|
||||||
{:events [:signing/increase-gas]}
|
{:events [:signing/increase-gas]}
|
||||||
[cofx {:keys [from nonce] :as tx}]
|
[cofx {:keys [from nonce] :as tx}]
|
||||||
(when (and from nonce)
|
(when (and from nonce)
|
||||||
(sign cofx {:tx-obj (-> tx
|
(sign cofx
|
||||||
(select-keys [:from :to :value :input :gas :nonce :hash])
|
{:tx-obj (-> tx
|
||||||
(clojure.set/rename-keys {:input :data}))})))
|
(select-keys [:from :to :value :input :gas :nonce :hash])
|
||||||
|
(clojure.set/rename-keys {:input :data}))})))
|
||||||
|
|||||||
+130
-96
@@ -1,15 +1,15 @@
|
|||||||
(ns status-im.signing.gas
|
(ns status-im.signing.gas
|
||||||
(:require [re-frame.core :as re-frame]
|
(:require [clojure.string :as string]
|
||||||
|
[re-frame.core :as re-frame]
|
||||||
|
[status-im.bottom-sheet.core :as bottom-sheet]
|
||||||
|
[status-im.ethereum.core :as ethereum]
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
[status-im.i18n.i18n :as i18n]
|
[status-im.i18n.i18n :as i18n]
|
||||||
[status-im.bottom-sheet.core :as bottom-sheet]
|
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[status-im.utils.money :as money]
|
|
||||||
[status-im.signing.eip1559 :as eip1559]
|
|
||||||
[taoensso.timbre :as log]
|
|
||||||
[status-im.popover.core :as popover]
|
[status-im.popover.core :as popover]
|
||||||
[status-im.ethereum.core :as ethereum]
|
[status-im.signing.eip1559 :as eip1559]
|
||||||
[clojure.string :as string]))
|
[status-im.utils.money :as money]
|
||||||
|
[taoensso.timbre :as log]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(def min-gas-price-wei ^js (money/bignumber 1))
|
(def min-gas-price-wei ^js (money/bignumber 1))
|
||||||
|
|
||||||
@@ -17,19 +17,22 @@
|
|||||||
|
|
||||||
(defmulti get-error-label-key (fn [type _] type))
|
(defmulti get-error-label-key (fn [type _] type))
|
||||||
|
|
||||||
(defmethod get-error-label-key :gasPrice [_ value]
|
(defmethod get-error-label-key :gasPrice
|
||||||
|
[_ value]
|
||||||
(cond
|
(cond
|
||||||
(not value) :t/invalid-number
|
(not value) :t/invalid-number
|
||||||
(.lt ^js (money/->wei :gwei value) min-gas-price-wei) :t/wallet-send-min-wei
|
(.lt ^js (money/->wei :gwei value) min-gas-price-wei) :t/wallet-send-min-wei
|
||||||
(-> (money/->wei :gwei value) .decimalPlaces pos?) :t/invalid-number))
|
(-> (money/->wei :gwei value) .decimalPlaces pos?) :t/invalid-number))
|
||||||
|
|
||||||
(defmethod get-error-label-key :gas [_ ^js value]
|
(defmethod get-error-label-key :gas
|
||||||
|
[_ ^js value]
|
||||||
(cond
|
(cond
|
||||||
(not value) :t/invalid-number
|
(not value) :t/invalid-number
|
||||||
(.lt value min-gas-units) :t/wallet-send-min-units
|
(.lt value min-gas-units) :t/wallet-send-min-units
|
||||||
(-> value .decimalPlaces pos?) :t/invalid-number))
|
(-> value .decimalPlaces pos?) :t/invalid-number))
|
||||||
|
|
||||||
(defmethod get-error-label-key :default [_ value]
|
(defmethod get-error-label-key :default
|
||||||
|
[_ value]
|
||||||
(when (or (not value)
|
(when (or (not value)
|
||||||
(<= value 0))
|
(<= value 0))
|
||||||
:t/invalid-number))
|
:t/invalid-number))
|
||||||
@@ -40,7 +43,8 @@
|
|||||||
(money/to-fixed (money/wei->ether (.times gas gasPrice)))
|
(money/to-fixed (money/wei->ether (.times gas gasPrice)))
|
||||||
"0"))
|
"0"))
|
||||||
|
|
||||||
(defn edit-max-fee [edit]
|
(defn edit-max-fee
|
||||||
|
[edit]
|
||||||
(let [gasPrice (get-in edit [:gasPrice :value-number])
|
(let [gasPrice (get-in edit [:gasPrice :value-number])
|
||||||
gas (get-in edit [:gas :value-number])]
|
gas (get-in edit [:gas :value-number])]
|
||||||
(assoc edit :max-fee (calculate-max-fee gas gasPrice))))
|
(assoc edit :max-fee (calculate-max-fee gas gasPrice))))
|
||||||
@@ -50,7 +54,7 @@
|
|||||||
Wei for gas, and gwei for gas price.
|
Wei for gas, and gwei for gas price.
|
||||||
Validates them and sets max fee"
|
Validates them and sets max fee"
|
||||||
[edit-value key value]
|
[edit-value key value]
|
||||||
(let [^js bn-value (money/bignumber value)
|
(let [^js bn-value (money/bignumber value)
|
||||||
error-label-key (get-error-label-key key bn-value)
|
error-label-key (get-error-label-key key bn-value)
|
||||||
data (if error-label-key
|
data (if error-label-key
|
||||||
{:value value
|
{:value value
|
||||||
@@ -69,17 +73,20 @@
|
|||||||
(def minimum-priority-fee-gwei
|
(def minimum-priority-fee-gwei
|
||||||
(money/bignumber 0.3))
|
(money/bignumber 0.3))
|
||||||
|
|
||||||
(defn get-suggested-tip [latest-priority-fee]
|
(defn get-suggested-tip
|
||||||
|
[latest-priority-fee]
|
||||||
(money/bignumber latest-priority-fee))
|
(money/bignumber latest-priority-fee))
|
||||||
|
|
||||||
(defn get-minimum-priority-fee [latest-priority-fee]
|
(defn get-minimum-priority-fee
|
||||||
|
[latest-priority-fee]
|
||||||
(let [latest-priority-fee-bn (money/bignumber latest-priority-fee)
|
(let [latest-priority-fee-bn (money/bignumber latest-priority-fee)
|
||||||
suggested-tip-gwei (money/wei->gwei (get-suggested-tip latest-priority-fee-bn))]
|
suggested-tip-gwei (money/wei->gwei (get-suggested-tip latest-priority-fee-bn))]
|
||||||
(if (money/greater-than minimum-priority-fee-gwei suggested-tip-gwei)
|
(if (money/greater-than minimum-priority-fee-gwei suggested-tip-gwei)
|
||||||
(money/div suggested-tip-gwei 2)
|
(money/div suggested-tip-gwei 2)
|
||||||
minimum-priority-fee-gwei)))
|
minimum-priority-fee-gwei)))
|
||||||
|
|
||||||
(defn get-suggestions-range [latest-priority-fee]
|
(defn get-suggestions-range
|
||||||
|
[latest-priority-fee]
|
||||||
(let [current-minimum-fee (get-minimum-priority-fee latest-priority-fee)]
|
(let [current-minimum-fee (get-minimum-priority-fee latest-priority-fee)]
|
||||||
[(if (money/greater-than minimum-priority-fee-gwei current-minimum-fee)
|
[(if (money/greater-than minimum-priority-fee-gwei current-minimum-fee)
|
||||||
current-minimum-fee
|
current-minimum-fee
|
||||||
@@ -89,47 +96,52 @@
|
|||||||
(def average-priority-fee
|
(def average-priority-fee
|
||||||
(money/wei->gwei (money/->wei :gwei 1.5)))
|
(money/wei->gwei (money/->wei :gwei 1.5)))
|
||||||
|
|
||||||
(defn validate-max-fee [db]
|
(defn validate-max-fee
|
||||||
|
[db]
|
||||||
(let [{:keys [maxFeePerGas maxPriorityFeePerGas]} (get db :signing/edit-fee)
|
(let [{:keys [maxFeePerGas maxPriorityFeePerGas]} (get db :signing/edit-fee)
|
||||||
latest-base-fee (money/wei->gwei
|
latest-base-fee (money/wei->gwei
|
||||||
(money/bignumber
|
(money/bignumber
|
||||||
(get db :wallet/current-base-fee)))
|
(get db :wallet/current-base-fee)))
|
||||||
fee-error (cond
|
fee-error (cond
|
||||||
(or (:error maxFeePerGas)
|
(or (:error maxFeePerGas)
|
||||||
(:error maxPriorityFeePerGas))
|
(:error maxPriorityFeePerGas))
|
||||||
nil
|
nil
|
||||||
|
|
||||||
(money/greater-than latest-base-fee
|
(money/greater-than latest-base-fee
|
||||||
(:value-number maxFeePerGas))
|
(:value-number maxFeePerGas))
|
||||||
{:label (i18n/label :t/below-base-fee)
|
{:label (i18n/label :t/below-base-fee)
|
||||||
:severity :error})]
|
:severity :error})]
|
||||||
(if fee-error
|
(if fee-error
|
||||||
(assoc-in db [:signing/edit-fee :maxFeePerGas :fee-error] fee-error)
|
(assoc-in db [:signing/edit-fee :maxFeePerGas :fee-error] fee-error)
|
||||||
(update-in db [:signing/edit-fee :maxFeePerGas] dissoc :fee-error))))
|
(update-in db [:signing/edit-fee :maxFeePerGas] dissoc :fee-error))))
|
||||||
|
|
||||||
(defn validate-max-priority-fee [db]
|
(defn validate-max-priority-fee
|
||||||
|
[db]
|
||||||
(let [{:keys [maxPriorityFeePerGas]} (get db :signing/edit-fee)
|
(let [{:keys [maxPriorityFeePerGas]} (get db :signing/edit-fee)
|
||||||
latest-priority-fee (get db :wallet/current-priority-fee)
|
latest-priority-fee (get db :wallet/current-priority-fee)
|
||||||
fee-error (cond
|
fee-error (cond
|
||||||
(:error maxPriorityFeePerGas)
|
(:error maxPriorityFeePerGas)
|
||||||
nil
|
nil
|
||||||
|
|
||||||
(money/greater-than (get-minimum-priority-fee
|
(money/greater-than (get-minimum-priority-fee
|
||||||
(money/div
|
(money/div
|
||||||
(money/wei->gwei (money/bignumber latest-priority-fee)) 2))
|
(money/wei->gwei (money/bignumber
|
||||||
(:value-number maxPriorityFeePerGas))
|
latest-priority-fee))
|
||||||
{:label (i18n/label :t/low-tip)
|
2))
|
||||||
:severity :error}
|
(:value-number maxPriorityFeePerGas))
|
||||||
|
{:label (i18n/label :t/low-tip)
|
||||||
|
:severity :error}
|
||||||
|
|
||||||
#_(money/greater-than average-priority-fee
|
#_(money/greater-than average-priority-fee
|
||||||
(:value-number maxPriorityFeePerGas))
|
(:value-number maxPriorityFeePerGas))
|
||||||
#_{:label (i18n/label :t/lower-than-average-tip)
|
#_{:label (i18n/label :t/lower-than-average-tip)
|
||||||
:severity :error})]
|
:severity :error})]
|
||||||
(if fee-error
|
(if fee-error
|
||||||
(assoc-in db [:signing/edit-fee :maxPriorityFeePerGas :fee-error] fee-error)
|
(assoc-in db [:signing/edit-fee :maxPriorityFeePerGas :fee-error] fee-error)
|
||||||
(update-in db [:signing/edit-fee :maxPriorityFeePerGas] dissoc :fee-error))))
|
(update-in db [:signing/edit-fee :maxPriorityFeePerGas] dissoc :fee-error))))
|
||||||
|
|
||||||
(defn validate-eip1559-fees [db]
|
(defn validate-eip1559-fees
|
||||||
|
[db]
|
||||||
(if (eip1559/sync-enabled?)
|
(if (eip1559/sync-enabled?)
|
||||||
(reduce
|
(reduce
|
||||||
(fn [acc f]
|
(fn [acc f]
|
||||||
@@ -139,7 +151,7 @@
|
|||||||
validate-max-priority-fee])
|
validate-max-priority-fee])
|
||||||
db))
|
db))
|
||||||
|
|
||||||
(fx/defn edit-value
|
(rf/defn edit-value
|
||||||
{:events [:signing.edit-fee.ui/edit-value]}
|
{:events [:signing.edit-fee.ui/edit-value]}
|
||||||
[{:keys [db]} key value]
|
[{:keys [db]} key value]
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
@@ -147,7 +159,8 @@
|
|||||||
(update :signing/edit-fee build-edit key value)
|
(update :signing/edit-fee build-edit key value)
|
||||||
validate-eip1559-fees)})
|
validate-eip1559-fees)})
|
||||||
|
|
||||||
(defn get-fee-options [tip slow normal fast]
|
(defn get-fee-options
|
||||||
|
[tip slow normal fast]
|
||||||
(let [tip-bn (money/bignumber tip)
|
(let [tip-bn (money/bignumber tip)
|
||||||
normal-bn (money/bignumber normal)
|
normal-bn (money/bignumber normal)
|
||||||
slow-bn (money/bignumber slow)
|
slow-bn (money/bignumber slow)
|
||||||
@@ -165,7 +178,7 @@
|
|||||||
:tip tip-bn
|
:tip tip-bn
|
||||||
:fee (money/add fast-bn tip-bn)}}))
|
:fee (money/add fast-bn tip-bn)}}))
|
||||||
|
|
||||||
(fx/defn set-fee-option
|
(rf/defn set-fee-option
|
||||||
{:events [:signing.edit-fee.ui/set-option]}
|
{:events [:signing.edit-fee.ui/set-option]}
|
||||||
[{:keys [db] :as cofx} option]
|
[{:keys [db] :as cofx} option]
|
||||||
(let [tip (get db :wallet/current-priority-fee)
|
(let [tip (get db :wallet/current-priority-fee)
|
||||||
@@ -176,21 +189,23 @@
|
|||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:signing/edit-fee :selected-fee-option] option)
|
(assoc-in [:signing/edit-fee :selected-fee-option] option)
|
||||||
(update :signing/edit-fee
|
(update :signing/edit-fee
|
||||||
build-edit :maxFeePerGas (money/wei->gwei fee))
|
build-edit
|
||||||
|
:maxFeePerGas (money/wei->gwei fee))
|
||||||
(update :signing/edit-fee
|
(update :signing/edit-fee
|
||||||
build-edit :maxPriorityFeePerGas (money/wei->gwei tip)))}))
|
build-edit
|
||||||
|
:maxPriorityFeePerGas (money/wei->gwei tip)))}))
|
||||||
|
|
||||||
(fx/defn set-priority-fee
|
(rf/defn set-priority-fee
|
||||||
{:events [:signing.edit-fee.ui/set-priority-fee]}
|
{:events [:signing.edit-fee.ui/set-priority-fee]}
|
||||||
[{:keys [db]} value]
|
[{:keys [db]} value]
|
||||||
(let [{:keys [maxFeePerGas maxPriorityFeePerGas]}
|
(let [{:keys [maxFeePerGas maxPriorityFeePerGas]}
|
||||||
(get db :signing/edit-fee)
|
(get db :signing/edit-fee)
|
||||||
latest-base-fee (get db :wallet/current-base-fee)
|
latest-base-fee (get db :wallet/current-base-fee)
|
||||||
max-fee-value (:value-number maxFeePerGas)
|
max-fee-value (:value-number maxFeePerGas)
|
||||||
max-priority-fee-value (:value-number maxPriorityFeePerGas)
|
max-priority-fee-value (:value-number maxPriorityFeePerGas)
|
||||||
new-value (money/bignumber value)
|
new-value (money/bignumber value)
|
||||||
fee-without-tip (money/sub max-fee-value max-priority-fee-value)
|
fee-without-tip (money/sub max-fee-value max-priority-fee-value)
|
||||||
base-fee (money/wei->gwei (money/bignumber latest-base-fee))
|
base-fee (money/wei->gwei (money/bignumber latest-base-fee))
|
||||||
new-max-fee-value
|
new-max-fee-value
|
||||||
(money/to-fixed
|
(money/to-fixed
|
||||||
(if (money/greater-than base-fee fee-without-tip)
|
(if (money/greater-than base-fee fee-without-tip)
|
||||||
@@ -201,19 +216,21 @@
|
|||||||
(update :signing/edit-fee build-edit :maxFeePerGas new-max-fee-value)
|
(update :signing/edit-fee build-edit :maxFeePerGas new-max-fee-value)
|
||||||
validate-eip1559-fees)}))
|
validate-eip1559-fees)}))
|
||||||
|
|
||||||
(fx/defn update-estimated-gas-success
|
(rf/defn update-estimated-gas-success
|
||||||
{:events [:signing/update-estimated-gas-success]}
|
{:events [:signing/update-estimated-gas-success]}
|
||||||
[{db :db} gas]
|
[{db :db} gas]
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:signing/tx :gas] gas)
|
(assoc-in [:signing/tx :gas] gas)
|
||||||
(assoc-in [:signing/edit-fee :gas-loading?] false))})
|
(assoc-in [:signing/edit-fee :gas-loading?] false))})
|
||||||
|
|
||||||
(fx/defn update-gas-price-success
|
(rf/defn update-gas-price-success
|
||||||
{:events [:signing/update-gas-price-success]}
|
{:events [:signing/update-gas-price-success]}
|
||||||
[{db :db} price]
|
[{db :db} price]
|
||||||
(if (eip1559/sync-enabled?)
|
(if (eip1559/sync-enabled?)
|
||||||
(let [{:keys [normal-base-fee max-priority-fee]} price
|
(let [{:keys [normal-base-fee max-priority-fee]} price
|
||||||
max-priority-fee-bn (money/with-precision (get-suggested-tip max-priority-fee) 0)]
|
max-priority-fee-bn (money/with-precision (get-suggested-tip
|
||||||
|
max-priority-fee)
|
||||||
|
0)]
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:signing/tx :maxFeePerGas]
|
(assoc-in [:signing/tx :maxFeePerGas]
|
||||||
(money/to-hex (money/add max-priority-fee-bn
|
(money/to-hex (money/add max-priority-fee-bn
|
||||||
@@ -225,7 +242,7 @@
|
|||||||
(assoc-in [:signing/tx :gasPrice] price)
|
(assoc-in [:signing/tx :gasPrice] price)
|
||||||
(assoc-in [:signing/edit-fee :gas-price-loading?] false))}))
|
(assoc-in [:signing/edit-fee :gas-price-loading?] false))}))
|
||||||
|
|
||||||
(fx/defn update-estimated-gas-error
|
(rf/defn update-estimated-gas-error
|
||||||
{:events [:signing/update-estimated-gas-error]}
|
{:events [:signing/update-estimated-gas-error]}
|
||||||
[{db :db} {:keys [message]}]
|
[{db :db} {:keys [message]}]
|
||||||
(log/warn "signing/update-estimated-gas-error" message)
|
(log/warn "signing/update-estimated-gas-error" message)
|
||||||
@@ -233,28 +250,36 @@
|
|||||||
(assoc-in [:signing/edit-fee :gas-loading?] false)
|
(assoc-in [:signing/edit-fee :gas-loading?] false)
|
||||||
(assoc-in [:signing/tx :gas-error-message] message))})
|
(assoc-in [:signing/tx :gas-error-message] message))})
|
||||||
|
|
||||||
(fx/defn update-gas-price-error
|
(rf/defn update-gas-price-error
|
||||||
{:events [:signing/update-gas-price-error]}
|
{:events [:signing/update-gas-price-error]}
|
||||||
[{db :db}]
|
[{db :db}]
|
||||||
{:db (assoc-in db [:signing/edit-fee :gas-price-loading?] false)})
|
{:db (assoc-in db [:signing/edit-fee :gas-price-loading?] false)})
|
||||||
|
|
||||||
(fx/defn open-fee-sheet
|
(rf/defn open-fee-sheet
|
||||||
{:events [:signing.ui/open-fee-sheet]}
|
{:events [:signing.ui/open-fee-sheet]}
|
||||||
[{{:signing/keys [tx] :as db} :db :as cofx} sheet-opts]
|
[{{:signing/keys [tx] :as db} :db :as cofx} sheet-opts]
|
||||||
(let [{:keys [gas gasPrice maxFeePerGas maxPriorityFeePerGas]} tx
|
(let [{:keys [gas gasPrice maxFeePerGas maxPriorityFeePerGas]} tx
|
||||||
max-fee (money/to-fixed (money/wei->gwei maxFeePerGas))
|
max-fee (money/to-fixed (money/wei->gwei
|
||||||
max-priority-fee (money/to-fixed (money/wei->gwei maxPriorityFeePerGas))
|
maxFeePerGas))
|
||||||
edit-fee (reduce (partial apply build-edit)
|
max-priority-fee (money/to-fixed (money/wei->gwei
|
||||||
{:selected-fee-option (get-in db [:signing/edit-fee :selected-fee-option])}
|
maxPriorityFeePerGas))
|
||||||
{:gas (money/to-fixed gas)
|
edit-fee (reduce
|
||||||
:gasPrice (money/to-fixed (money/wei->gwei gasPrice))
|
(partial apply build-edit)
|
||||||
:maxFeePerGas max-fee
|
{:selected-fee-option
|
||||||
:maxPriorityFeePerGas max-priority-fee})]
|
(get-in db
|
||||||
(fx/merge cofx
|
[:signing/edit-fee
|
||||||
|
:selected-fee-option])}
|
||||||
|
{:gas (money/to-fixed gas)
|
||||||
|
:gasPrice (money/to-fixed
|
||||||
|
(money/wei->gwei gasPrice))
|
||||||
|
:maxFeePerGas max-fee
|
||||||
|
:maxPriorityFeePerGas
|
||||||
|
max-priority-fee})]
|
||||||
|
(rf/merge cofx
|
||||||
{:db (assoc db :signing/edit-fee edit-fee)}
|
{:db (assoc db :signing/edit-fee edit-fee)}
|
||||||
(bottom-sheet/show-bottom-sheet {:view sheet-opts}))))
|
(bottom-sheet/show-bottom-sheet {:view sheet-opts}))))
|
||||||
|
|
||||||
(fx/defn submit-fee
|
(rf/defn submit-fee
|
||||||
{:events [:signing.edit-fee.ui/submit]}
|
{:events [:signing.edit-fee.ui/submit]}
|
||||||
[{{:signing/keys [edit-fee] :as db} :db :as cofx} force?]
|
[{{:signing/keys [edit-fee] :as db} :db :as cofx} force?]
|
||||||
(let [{:keys [gas gasPrice maxFeePerGas maxPriorityFeePerGas]} edit-fee
|
(let [{:keys [gas gasPrice maxFeePerGas maxPriorityFeePerGas]} edit-fee
|
||||||
@@ -267,18 +292,20 @@
|
|||||||
(if (and (seq errors?)
|
(if (and (seq errors?)
|
||||||
(not force?))
|
(not force?))
|
||||||
(popover/show-popover cofx {:view :fees-warning})
|
(popover/show-popover cofx {:view :fees-warning})
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (update db :signing/tx assoc
|
{:db (update db
|
||||||
:gas (:value-number gas)
|
:signing/tx assoc
|
||||||
:gasPrice (:value-number gasPrice)
|
:gas (:value-number gas)
|
||||||
:maxFeePerGas (money/->wei :gwei (:value-number maxFeePerGas))
|
:gasPrice (:value-number gasPrice)
|
||||||
:maxPriorityFeePerGas (money/->wei :gwei (:value-number maxPriorityFeePerGas)))}
|
:maxFeePerGas (money/->wei :gwei (:value-number maxFeePerGas))
|
||||||
|
:maxPriorityFeePerGas (money/->wei :gwei
|
||||||
|
(:value-number maxPriorityFeePerGas)))}
|
||||||
(bottom-sheet/hide-bottom-sheet)))))
|
(bottom-sheet/hide-bottom-sheet)))))
|
||||||
|
|
||||||
(fx/defn submit-nonce
|
(rf/defn submit-nonce
|
||||||
{:events [:signing.nonce/submit]}
|
{:events [:signing.nonce/submit]}
|
||||||
[{db :db :as cofx} nonce]
|
[{db :db :as cofx} nonce]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (assoc-in db [:signing/tx :nonce] (if (string/blank? nonce) nil nonce))}
|
{:db (assoc-in db [:signing/tx :nonce] (if (string/blank? nonce) nil nonce))}
|
||||||
(bottom-sheet/hide-bottom-sheet)))
|
(bottom-sheet/hide-bottom-sheet)))
|
||||||
|
|
||||||
@@ -289,10 +316,10 @@
|
|||||||
network-id
|
network-id
|
||||||
(fn []
|
(fn []
|
||||||
(json-rpc/call
|
(json-rpc/call
|
||||||
{:method "eth_feeHistory"
|
{:method "eth_feeHistory"
|
||||||
;; NOTE(rasom): We don't need `reward` atm but if the last parameter is
|
;; NOTE(rasom): We don't need `reward` atm but if the last parameter is
|
||||||
;; `nil` request fails on some chains (particularly on xDai).
|
;; `nil` request fails on some chains (particularly on xDai).
|
||||||
:params [101 "latest" [100]]
|
:params [101 "latest" [100]]
|
||||||
:on-success #(re-frame/dispatch [::header-fetched
|
:on-success #(re-frame/dispatch [::header-fetched
|
||||||
(assoc params :fee-history %)])}))
|
(assoc params :fee-history %)])}))
|
||||||
(fn []
|
(fn []
|
||||||
@@ -303,7 +330,8 @@
|
|||||||
|
|
||||||
(def london-block-gas-limit (money/bignumber 30000000))
|
(def london-block-gas-limit (money/bignumber 30000000))
|
||||||
|
|
||||||
(defn calc-percentiles [v ps]
|
(defn calc-percentiles
|
||||||
|
[v ps]
|
||||||
(let [sorted-v (sort-by
|
(let [sorted-v (sort-by
|
||||||
identity
|
identity
|
||||||
(fn [a b]
|
(fn [a b]
|
||||||
@@ -319,7 +347,8 @@
|
|||||||
;; fee might be very small and using this value might slow transaction
|
;; fee might be very small and using this value might slow transaction
|
||||||
(def minimum-base-fee (money/->wei :gwei (money/bignumber 1)))
|
(def minimum-base-fee (money/->wei :gwei (money/bignumber 1)))
|
||||||
|
|
||||||
(defn recommended-base-fee [current perc20]
|
(defn recommended-base-fee
|
||||||
|
[current perc20]
|
||||||
(let [fee
|
(let [fee
|
||||||
(cond (money/greater-than-or-equals current perc20)
|
(cond (money/greater-than-or-equals current perc20)
|
||||||
current
|
current
|
||||||
@@ -332,13 +361,15 @@
|
|||||||
|
|
||||||
(defn slow-base-fee [_ perc10] perc10)
|
(defn slow-base-fee [_ perc10] perc10)
|
||||||
|
|
||||||
(defn fast-base-fee [current]
|
(defn fast-base-fee
|
||||||
|
[current]
|
||||||
(let [fee (money/mul current 2)]
|
(let [fee (money/mul current 2)]
|
||||||
(if (money/greater-than minimum-base-fee fee)
|
(if (money/greater-than minimum-base-fee fee)
|
||||||
(money/mul minimum-base-fee 2)
|
(money/mul minimum-base-fee 2)
|
||||||
fee)))
|
fee)))
|
||||||
|
|
||||||
(defn check-base-fee [{:keys [baseFeePerGas testnet?]}]
|
(defn check-base-fee
|
||||||
|
[{:keys [baseFeePerGas testnet?]}]
|
||||||
(let [all-base-fees (mapv money/bignumber baseFeePerGas)
|
(let [all-base-fees (mapv money/bignumber baseFeePerGas)
|
||||||
next-base-fee (peek all-base-fees)
|
next-base-fee (peek all-base-fees)
|
||||||
previous-fees (subvec all-base-fees 0 101)
|
previous-fees (subvec all-base-fees 0 101)
|
||||||
@@ -357,12 +388,13 @@
|
|||||||
:fast-base-fee (money/to-hex (fast-base-fee next-base-fee))
|
:fast-base-fee (money/to-hex (fast-base-fee next-base-fee))
|
||||||
:current-base-fee (money/to-hex current-base-fee)}))
|
:current-base-fee (money/to-hex current-base-fee)}))
|
||||||
|
|
||||||
(defn max-priority-fee-hex [gas-price base-fee]
|
(defn max-priority-fee-hex
|
||||||
|
[gas-price base-fee]
|
||||||
(money/to-hex
|
(money/to-hex
|
||||||
(money/sub (money/bignumber gas-price)
|
(money/sub (money/bignumber gas-price)
|
||||||
(money/bignumber base-fee))))
|
(money/bignumber base-fee))))
|
||||||
|
|
||||||
(fx/defn header-fetched
|
(rf/defn header-fetched
|
||||||
{:events [::header-fetched]}
|
{:events [::header-fetched]}
|
||||||
[{{:networks/keys [current-network networks]} :db}
|
[{{:networks/keys [current-network networks]} :db}
|
||||||
{:keys [error-callback success-callback fee-history] :as params}]
|
{:keys [error-callback success-callback fee-history] :as params}]
|
||||||
@@ -375,8 +407,9 @@
|
|||||||
(let [{:keys [current-base-fee] :as base-fees}
|
(let [{:keys [current-base-fee] :as base-fees}
|
||||||
(check-base-fee
|
(check-base-fee
|
||||||
(assoc fee-history
|
(assoc fee-history
|
||||||
:testnet? (ethereum/testnet?
|
:testnet?
|
||||||
(get-in networks [current-network :config :NetworkId]))))]
|
(ethereum/testnet?
|
||||||
|
(get-in networks [current-network :config :NetworkId]))))]
|
||||||
(merge {:max-priority-fee
|
(merge {:max-priority-fee
|
||||||
(max-priority-fee-hex (money/bignumber %) current-base-fee)}
|
(max-priority-fee-hex (money/bignumber %) current-base-fee)}
|
||||||
base-fees)))
|
base-fees)))
|
||||||
@@ -390,5 +423,6 @@
|
|||||||
(json-rpc/call
|
(json-rpc/call
|
||||||
{:method "eth_estimateGas"
|
{:method "eth_estimateGas"
|
||||||
:params [obj]
|
:params [obj]
|
||||||
:on-success #(re-frame/dispatch [success-event (money/bignumber (if (= (int %) 21000) % (int (* % 1.2))))])
|
:on-success #(re-frame/dispatch [success-event
|
||||||
|
(money/bignumber (if (= (int %) 21000) % (int (* % 1.2))))])
|
||||||
:on-error #(re-frame/dispatch [error-event %])})))
|
:on-error #(re-frame/dispatch [error-event %])})))
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
(ns status-im.signing.keycard
|
(ns status-im.signing.keycard
|
||||||
(:require [re-frame.core :as re-frame]
|
(:require [re-frame.core :as re-frame]
|
||||||
[status-im.native-module.core :as status]
|
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[status-im.i18n.i18n :as i18n]
|
[status-im.i18n.i18n :as i18n]
|
||||||
|
[status-im.native-module.core :as status]
|
||||||
[status-im.utils.types :as types]
|
[status-im.utils.types :as types]
|
||||||
[taoensso.timbre :as log]))
|
[taoensso.timbre :as log]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
::hash-transaction
|
::hash-transaction
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
[{:keys [gas gasPrice data nonce tx-obj] :as params}]
|
[{:keys [gas gasPrice data nonce tx-obj] :as params}]
|
||||||
(let [{:keys [from to value chat-id message-id command? maxPriorityFeePerGas maxFeePerGas]} tx-obj
|
(let [{:keys [from to value chat-id message-id command? maxPriorityFeePerGas maxFeePerGas]} tx-obj
|
||||||
maxPriorityFeePerGas (or maxPriorityFeePerGas (get params :maxPriorityFeePerGas))
|
maxPriorityFeePerGas (or maxPriorityFeePerGas (get params :maxPriorityFeePerGas))
|
||||||
maxFeePerGas (or maxFeePerGas (get params :maxFeePerGas))]
|
maxFeePerGas (or maxFeePerGas (get params :maxFeePerGas))]
|
||||||
(cond-> {:from from
|
(cond-> {:from from
|
||||||
:to to
|
:to to
|
||||||
:value value
|
:value value
|
||||||
@@ -35,11 +35,15 @@
|
|||||||
:message-id message-id
|
:message-id message-id
|
||||||
:command? command?}
|
:command? command?}
|
||||||
maxPriorityFeePerGas
|
maxPriorityFeePerGas
|
||||||
(assoc :maxPriorityFeePerGas (str "0x" (status/number-to-hex
|
(assoc :maxPriorityFeePerGas
|
||||||
(js/parseInt maxPriorityFeePerGas))))
|
(str "0x"
|
||||||
|
(status/number-to-hex
|
||||||
|
(js/parseInt maxPriorityFeePerGas))))
|
||||||
maxFeePerGas
|
maxFeePerGas
|
||||||
(assoc :maxFeePerGas (str "0x" (status/number-to-hex
|
(assoc :maxFeePerGas
|
||||||
(js/parseInt maxFeePerGas))))
|
(str "0x"
|
||||||
|
(status/number-to-hex
|
||||||
|
(js/parseInt maxFeePerGas))))
|
||||||
gas
|
gas
|
||||||
(assoc :gas (str "0x" (status/number-to-hex gas)))
|
(assoc :gas (str "0x" (status/number-to-hex gas)))
|
||||||
gasPrice
|
gasPrice
|
||||||
@@ -49,7 +53,7 @@
|
|||||||
nonce
|
nonce
|
||||||
(assoc :nonce nonce))))
|
(assoc :nonce nonce))))
|
||||||
|
|
||||||
(fx/defn hash-message
|
(rf/defn hash-message
|
||||||
[_ {:keys [v4 data typed? on-completed]}]
|
[_ {:keys [v4 data typed? on-completed]}]
|
||||||
(if typed?
|
(if typed?
|
||||||
{::hash-typed-data
|
{::hash-typed-data
|
||||||
@@ -68,7 +72,7 @@
|
|||||||
[:signing.keycard.callback/hash-message-completed
|
[:signing.keycard.callback/hash-message-completed
|
||||||
data typed? %]))}}))
|
data typed? %]))}}))
|
||||||
|
|
||||||
(fx/defn hash-message-completed
|
(rf/defn hash-message-completed
|
||||||
{:events [:signing.keycard.callback/hash-message-completed]}
|
{:events [:signing.keycard.callback/hash-message-completed]}
|
||||||
[{:keys [db]} data typed? result]
|
[{:keys [db]} data typed? result]
|
||||||
(let [{:keys [result error]} (types/json->clj result)]
|
(let [{:keys [result error]} (types/json->clj result)]
|
||||||
@@ -76,12 +80,13 @@
|
|||||||
{:dispatch [:signing.ui/cancel-is-pressed]
|
{:dispatch [:signing.ui/cancel-is-pressed]
|
||||||
:utils/show-popup {:title (i18n/label :t/sign-request-failed)
|
:utils/show-popup {:title (i18n/label :t/sign-request-failed)
|
||||||
:content (:message error)}}
|
:content (:message error)}}
|
||||||
{:db (update db :keycard assoc
|
{:db (update db
|
||||||
:hash result
|
:keycard assoc
|
||||||
:typed? typed?
|
:hash result
|
||||||
:data data)})))
|
:typed? typed?
|
||||||
|
:data data)})))
|
||||||
|
|
||||||
(fx/defn hash-transaction
|
(rf/defn hash-transaction
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(let [tx (prepare-transaction (:signing/tx db))]
|
(let [tx (prepare-transaction (:signing/tx db))]
|
||||||
(log/debug "hash-transaction" tx)
|
(log/debug "hash-transaction" tx)
|
||||||
@@ -90,7 +95,7 @@
|
|||||||
:on-completed #(re-frame/dispatch
|
:on-completed #(re-frame/dispatch
|
||||||
[:signing.keycard.callback/hash-transaction-completed tx %])}}))
|
[:signing.keycard.callback/hash-transaction-completed tx %])}}))
|
||||||
|
|
||||||
(fx/defn hash-transaction-completed
|
(rf/defn hash-transaction-completed
|
||||||
{:events [:signing.keycard.callback/hash-transaction-completed]}
|
{:events [:signing.keycard.callback/hash-transaction-completed]}
|
||||||
[{:keys [db]} original-tx result]
|
[{:keys [db]} original-tx result]
|
||||||
(let [{:keys [transaction hash]} (:result (types/json->clj result))]
|
(let [{:keys [transaction hash]} (:result (types/json->clj result))]
|
||||||
@@ -99,11 +104,11 @@
|
|||||||
(merge original-tx transaction))
|
(merge original-tx transaction))
|
||||||
(assoc-in [:keycard :hash] hash))}))
|
(assoc-in [:keycard :hash] hash))}))
|
||||||
|
|
||||||
(fx/defn sign-with-keycard
|
(rf/defn sign-with-keycard
|
||||||
{:events [:signing.ui/sign-with-keycard-pressed]}
|
{:events [:signing.ui/sign-with-keycard-pressed]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [{:keys [message maxPriorityFeePerGas maxFeePerGas]} (get db :signing/tx)]
|
(let [{:keys [message maxPriorityFeePerGas maxFeePerGas]} (get db :signing/tx)]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:keycard :pin :enter-step] :sign)
|
(assoc-in [:keycard :pin :enter-step] :sign)
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
(ns status-im.stickers.core
|
(ns status-im.stickers.core
|
||||||
(:require [clojure.string :as string]
|
(:require [clojure.string :as string]
|
||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
|
[status-im.constants :as constants]
|
||||||
[status-im.ethereum.core :as ethereum]
|
[status-im.ethereum.core :as ethereum]
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
[status-im2.navigation.events :as navigation]
|
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[status-im.utils.utils :as utils]
|
|
||||||
[status-im.utils.config :as config]
|
[status-im.utils.config :as config]
|
||||||
[status-im.constants :as constants]))
|
[status-im.utils.utils :as utils]
|
||||||
|
[status-im2.navigation.events :as navigation]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
:stickers/set-pending-timeout-fx
|
:stickers/set-pending-timeout-fx
|
||||||
@@ -15,17 +15,17 @@
|
|||||||
(utils/set-timeout #(re-frame/dispatch [:stickers/pending-timeout])
|
(utils/set-timeout #(re-frame/dispatch [:stickers/pending-timeout])
|
||||||
10000)))
|
10000)))
|
||||||
|
|
||||||
(fx/defn install-stickers-pack
|
(rf/defn install-stickers-pack
|
||||||
{:events [:stickers/install-pack]}
|
{:events [:stickers/install-pack]}
|
||||||
[{db :db :as cofx} id]
|
[{db :db :as cofx} id]
|
||||||
(fx/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (assoc-in db [:stickers/packs id :status] constants/sticker-pack-status-installed)
|
{:db (assoc-in db [:stickers/packs id :status] constants/sticker-pack-status-installed)
|
||||||
::json-rpc/call [{:method "stickers_install"
|
::json-rpc/call [{:method "stickers_install"
|
||||||
:params [(ethereum/chain-id db) id]
|
:params [(ethereum/chain-id db) id]
|
||||||
:on-success #()}]}))
|
:on-success #()}]}))
|
||||||
|
|
||||||
(fx/defn load-packs
|
(rf/defn load-packs
|
||||||
{:events [:stickers/load-packs]}
|
{:events [:stickers/load-packs]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
{::json-rpc/call [{:method "stickers_market"
|
{::json-rpc/call [{:method "stickers_market"
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
:params []
|
:params []
|
||||||
:on-success #(re-frame/dispatch [:stickers/stickers-recent-success %])}]})
|
:on-success #(re-frame/dispatch [:stickers/stickers-recent-success %])}]})
|
||||||
|
|
||||||
(fx/defn buy-pack
|
(rf/defn buy-pack
|
||||||
{:events [:stickers/buy-pack]}
|
{:events [:stickers/buy-pack]}
|
||||||
[{db :db} pack-id]
|
[{db :db} pack-id]
|
||||||
{::json-rpc/call [{:method "stickers_buyPrepareTx"
|
{::json-rpc/call [{:method "stickers_buyPrepareTx"
|
||||||
@@ -50,34 +50,36 @@
|
|||||||
{:tx-obj %
|
{:tx-obj %
|
||||||
:on-result [:stickers/pending-pack pack-id]}])}]})
|
:on-result [:stickers/pending-pack pack-id]}])}]})
|
||||||
|
|
||||||
(fx/defn pending-pack
|
(rf/defn pending-pack
|
||||||
{:events [:stickers/pending-pack]}
|
{:events [:stickers/pending-pack]}
|
||||||
[{db :db} id]
|
[{db :db} id]
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:stickers/packs id :status] constants/sticker-pack-status-pending)
|
(assoc-in [:stickers/packs id :status]
|
||||||
|
constants/sticker-pack-status-pending)
|
||||||
(update :stickers/packs-pending conj id))
|
(update :stickers/packs-pending conj id))
|
||||||
:stickers/set-pending-timeout-fx nil
|
:stickers/set-pending-timeout-fx nil
|
||||||
::json-rpc/call [{:method "stickers_addPending"
|
::json-rpc/call [{:method "stickers_addPending"
|
||||||
:params [(ethereum/chain-id db) (int id)]
|
:params [(ethereum/chain-id db) (int id)]
|
||||||
:on-success #()}]})
|
:on-success #()}]})
|
||||||
|
|
||||||
(fx/defn pending-timeout
|
(rf/defn pending-timeout
|
||||||
{:events [:stickers/pending-timeout]}
|
{:events [:stickers/pending-timeout]}
|
||||||
[{{:stickers/keys [packs-pending] :as db} :db}]
|
[{{:stickers/keys [packs-pending] :as db} :db}]
|
||||||
(when (seq packs-pending)
|
(when (seq packs-pending)
|
||||||
{::json-rpc/call [{:method "stickers_processPending"
|
{::json-rpc/call [{:method "stickers_processPending"
|
||||||
:params [(ethereum/chain-id db)]
|
:params [(ethereum/chain-id db)]
|
||||||
:on-success #(re-frame/dispatch [:stickers/stickers-process-pending-success %])}]}))
|
:on-success #(re-frame/dispatch [:stickers/stickers-process-pending-success
|
||||||
|
%])}]}))
|
||||||
|
|
||||||
(fx/defn stickers-process-pending-success
|
(rf/defn stickers-process-pending-success
|
||||||
{:events [:stickers/stickers-process-pending-success]}
|
{:events [:stickers/stickers-process-pending-success]}
|
||||||
[{{:stickers/keys [packs-pending packs] :as db} :db} purchased]
|
[{{:stickers/keys [packs-pending packs] :as db} :db} purchased]
|
||||||
(let [purchased-ids (map :id (vals purchased))
|
(let [purchased-ids (map :id (vals purchased))
|
||||||
packs-pending (apply disj packs-pending purchased-ids)
|
packs-pending (apply disj packs-pending purchased-ids)
|
||||||
packs (reduce (fn [packs id]
|
packs (reduce (fn [packs id]
|
||||||
(assoc-in packs [id :status] constants/sticker-pack-status-owned))
|
(assoc-in packs [id :status] constants/sticker-pack-status-owned))
|
||||||
packs
|
packs
|
||||||
purchased-ids)]
|
purchased-ids)]
|
||||||
(merge
|
(merge
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc :stickers/packs packs)
|
(assoc :stickers/packs packs)
|
||||||
@@ -85,19 +87,19 @@
|
|||||||
(when (seq packs-pending)
|
(when (seq packs-pending)
|
||||||
{:stickers/set-pending-timeout-fx nil}))))
|
{:stickers/set-pending-timeout-fx nil}))))
|
||||||
|
|
||||||
(fx/defn stickers-market-success
|
(rf/defn stickers-market-success
|
||||||
{:events [:stickers/stickers-market-success]}
|
{:events [:stickers/stickers-market-success]}
|
||||||
[{:keys [db]} packs]
|
[{:keys [db]} packs]
|
||||||
(let [packs (reduce (fn [acc pack] (assoc acc (:id pack) pack)) {} packs)]
|
(let [packs (reduce (fn [acc pack] (assoc acc (:id pack) pack)) {} packs)]
|
||||||
{:db (update db :stickers/packs merge packs)}))
|
{:db (update db :stickers/packs merge packs)}))
|
||||||
|
|
||||||
(fx/defn stickers-installed-success
|
(rf/defn stickers-installed-success
|
||||||
{:events [:stickers/stickers-installed-success]}
|
{:events [:stickers/stickers-installed-success]}
|
||||||
[{:keys [db]} packs]
|
[{:keys [db]} packs]
|
||||||
(let [packs (reduce (fn [acc [_ pack]] (assoc acc (:id pack) pack)) {} packs)]
|
(let [packs (reduce (fn [acc [_ pack]] (assoc acc (:id pack) pack)) {} packs)]
|
||||||
{:db (update db :stickers/packs merge packs)}))
|
{:db (update db :stickers/packs merge packs)}))
|
||||||
|
|
||||||
(fx/defn stickers-pending-success
|
(rf/defn stickers-pending-success
|
||||||
{:events [:stickers/stickers-pending-success]}
|
{:events [:stickers/stickers-pending-success]}
|
||||||
[{:keys [db]} packs]
|
[{:keys [db]} packs]
|
||||||
(let [packs (reduce (fn [acc [_ pack]] (assoc acc (:id pack) pack)) {} packs)]
|
(let [packs (reduce (fn [acc [_ pack]] (assoc acc (:id pack) pack)) {} packs)]
|
||||||
@@ -108,18 +110,18 @@
|
|||||||
(when (seq packs)
|
(when (seq packs)
|
||||||
{:stickers/set-pending-timeout-fx nil}))))
|
{:stickers/set-pending-timeout-fx nil}))))
|
||||||
|
|
||||||
(fx/defn stickers-recent-success
|
(rf/defn stickers-recent-success
|
||||||
{:events [:stickers/stickers-recent-success]}
|
{:events [:stickers/stickers-recent-success]}
|
||||||
[{:keys [db]} packs]
|
[{:keys [db]} packs]
|
||||||
{:db (assoc db :stickers/recent-stickers packs)})
|
{:db (assoc db :stickers/recent-stickers packs)})
|
||||||
|
|
||||||
(fx/defn open-sticker-pack
|
(rf/defn open-sticker-pack
|
||||||
{:events [:stickers/open-sticker-pack]}
|
{:events [:stickers/open-sticker-pack]}
|
||||||
[{{:networks/keys [current-network]} :db :as cofx} id]
|
[{{:networks/keys [current-network]} :db :as cofx} id]
|
||||||
(when (and id (or config/stickers-test-enabled? (string/starts-with? current-network "mainnet")))
|
(when (and id (or config/stickers-test-enabled? (string/starts-with? current-network "mainnet")))
|
||||||
(navigation/open-modal cofx :stickers-pack {:id id})))
|
(navigation/open-modal cofx :stickers-pack {:id id})))
|
||||||
|
|
||||||
(fx/defn select-pack
|
(rf/defn select-pack
|
||||||
{:events [:stickers/select-pack]}
|
{:events [:stickers/select-pack]}
|
||||||
[{:keys [db]} id]
|
[{:keys [db]} id]
|
||||||
{:db (assoc db :stickers/selected-pack id)})
|
{:db (assoc db :stickers/selected-pack id)})
|
||||||
|
|||||||
@@ -1,25 +1,30 @@
|
|||||||
(ns status-im.test-runner
|
(ns status-im.test-runner
|
||||||
{:dev/always true}
|
{:dev/always true}
|
||||||
(:require
|
(:require [cljs.test :as ct]
|
||||||
[cljs.test :as ct]
|
[clojure.string :as string]
|
||||||
[clojure.string :as string]
|
[shadow.test :as st]
|
||||||
[shadow.test :as st]
|
[shadow.test.env :as env]
|
||||||
[shadow.test.env :as env]))
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(defonce repl? (atom false))
|
(defonce repl? (atom false))
|
||||||
|
|
||||||
(defmethod ct/report [::ct/default :end-run-tests] [m]
|
(defmethod ct/report [::ct/default :end-run-tests]
|
||||||
|
[m]
|
||||||
(when-not @repl?
|
(when-not @repl?
|
||||||
(if (ct/successful? m)
|
(if (ct/successful? m)
|
||||||
(js/process.exit 0)
|
(js/process.exit 0)
|
||||||
(js/process.exit 1))))
|
(js/process.exit 1))))
|
||||||
|
|
||||||
;; get-test-data is a macro so this namespace REQUIRES :dev/always hint ns so that it is always recompiled
|
;; get-test-data is a macro so this namespace REQUIRES :dev/always hint ns so that it is always
|
||||||
(defn ^:dev/after-load reset-test-data! []
|
;; recompiled
|
||||||
|
(defn ^:dev/after-load reset-test-data!
|
||||||
|
[]
|
||||||
(-> (env/get-test-data)
|
(-> (env/get-test-data)
|
||||||
(env/reset-test-data!)))
|
(env/reset-test-data!)))
|
||||||
|
|
||||||
(defn parse-args [args]
|
(defn parse-args
|
||||||
|
[args]
|
||||||
(reduce
|
(reduce
|
||||||
(fn [opts arg]
|
(fn [opts arg]
|
||||||
(cond
|
(cond
|
||||||
@@ -33,7 +38,7 @@
|
|||||||
(assoc opts :repl true)
|
(assoc opts :repl true)
|
||||||
|
|
||||||
(string/starts-with? arg "--test=")
|
(string/starts-with? arg "--test=")
|
||||||
(let [test-arg (subs arg 7)
|
(let [test-arg (subs arg 7)
|
||||||
test-syms
|
test-syms
|
||||||
(->> (string/split test-arg ",")
|
(->> (string/split test-arg ",")
|
||||||
(map symbol))]
|
(map symbol))]
|
||||||
@@ -45,12 +50,17 @@
|
|||||||
{:test-syms []}
|
{:test-syms []}
|
||||||
args))
|
args))
|
||||||
|
|
||||||
(defn find-matching-test-vars [test-syms]
|
(defn find-matching-test-vars
|
||||||
|
[test-syms]
|
||||||
;; FIXME: should have some kind of wildcard support
|
;; FIXME: should have some kind of wildcard support
|
||||||
(let [test-namespaces
|
(let [test-namespaces
|
||||||
(->> test-syms (filter simple-symbol?) (set))
|
(->> test-syms
|
||||||
|
(filter simple-symbol?)
|
||||||
|
(set))
|
||||||
test-var-syms
|
test-var-syms
|
||||||
(->> test-syms (filter qualified-symbol?) (set))]
|
(->> test-syms
|
||||||
|
(filter qualified-symbol?)
|
||||||
|
(set))]
|
||||||
|
|
||||||
(->> (env/get-test-vars)
|
(->> (env/get-test-vars)
|
||||||
(filter (fn [the-var]
|
(filter (fn [the-var]
|
||||||
@@ -58,7 +68,8 @@
|
|||||||
(or (contains? test-namespaces ns)
|
(or (contains? test-namespaces ns)
|
||||||
(contains? test-var-syms (symbol ns name)))))))))
|
(contains? test-var-syms (symbol ns name)))))))))
|
||||||
|
|
||||||
(defn execute-cli [{:keys [test-syms help list repl] :as _opts}]
|
(defn execute-cli
|
||||||
|
[{:keys [test-syms help list repl] :as _opts}]
|
||||||
(let [test-env
|
(let [test-env
|
||||||
(-> (ct/empty-env)
|
(-> (ct/empty-env)
|
||||||
;; can't think of a proper way to let CLI specify custom reporter?
|
;; can't think of a proper way to let CLI specify custom reporter?
|
||||||
@@ -70,17 +81,19 @@
|
|||||||
|
|
||||||
(cond
|
(cond
|
||||||
help
|
help
|
||||||
(do (println "Usage:")
|
(do
|
||||||
(println " --list (list known test names)")
|
(println "Usage:")
|
||||||
(println " --test=<ns-to-test>,<fqn-symbol-to-test> (run test for namespace or single var, separated by comma)")
|
(println " --list (list known test names)")
|
||||||
(println " --repl (start node without automatically running tests)"))
|
(println
|
||||||
|
" --test=<ns-to-test>,<fqn-symbol-to-test> (run test for namespace or single var, separated by comma)")
|
||||||
|
(println " --repl (start node without automatically running tests)"))
|
||||||
|
|
||||||
list
|
list
|
||||||
(doseq [[ns ns-info]
|
(doseq [[ns ns-info]
|
||||||
(->> (env/get-tests)
|
(->> (env/get-tests)
|
||||||
(sort-by first))]
|
(sort-by first))]
|
||||||
(println "Namespace:" ns)
|
(println "Namespace:" ns)
|
||||||
(doseq [var (:vars ns-info)
|
(doseq [var (:vars ns-info)
|
||||||
:let [m (meta var)]]
|
:let [m (meta var)]]
|
||||||
(println (str " " (:ns m) "/" (:name m))))
|
(println (str " " (:ns m) "/" (:name m))))
|
||||||
(println "---------------------------------"))
|
(println "---------------------------------"))
|
||||||
@@ -97,8 +110,20 @@
|
|||||||
:else
|
:else
|
||||||
(st/run-all-tests test-env nil))))
|
(st/run-all-tests test-env nil))))
|
||||||
|
|
||||||
(defn ^:export main [& args]
|
(defn ^:export main
|
||||||
|
[& args]
|
||||||
(reset-test-data!)
|
(reset-test-data!)
|
||||||
|
|
||||||
|
(rf/set-mergeable-keys #{:filters/load-filters
|
||||||
|
:pairing/set-installation-metadata
|
||||||
|
:dispatch-n
|
||||||
|
:status-im.ens.core/verify-names
|
||||||
|
:shh/send-direct-message
|
||||||
|
:shh/remove-filter
|
||||||
|
:transport/confirm-messages-processed
|
||||||
|
:group-chats/extract-membership-signature
|
||||||
|
:utils/dispatch-later
|
||||||
|
::json-rpc/call})
|
||||||
|
|
||||||
(let [opts (parse-args args)]
|
(let [opts (parse-args args)]
|
||||||
(execute-cli opts)))
|
(execute-cli opts)))
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
(ns ^{:doc "API to init and stop whisper messaging"}
|
(ns ^{:doc "API to init and stop whisper messaging"} status-im.transport.core
|
||||||
status-im.transport.core
|
|
||||||
(:require [re-frame.core :as re-frame]
|
(:require [re-frame.core :as re-frame]
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
[status-im.pairing.core :as pairing]
|
[status-im.pairing.core :as pairing]
|
||||||
[status-im.utils.fx :as fx]
|
[status-im.stickers.core :as stickers]
|
||||||
status-im.transport.shh
|
status-im.transport.shh
|
||||||
[taoensso.timbre :as log]
|
|
||||||
[status-im.utils.universal-links.core :as universal-links]
|
[status-im.utils.universal-links.core :as universal-links]
|
||||||
[status-im.stickers.core :as stickers]))
|
[taoensso.timbre :as log]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(fx/defn set-node-info
|
(rf/defn set-node-info
|
||||||
{:events [:transport.callback/node-info-fetched]}
|
{:events [:transport.callback/node-info-fetched]}
|
||||||
[{:keys [db]} node-info]
|
[{:keys [db]} node-info]
|
||||||
{:db (assoc db :node-info node-info)})
|
{:db (assoc db :node-info node-info)})
|
||||||
|
|
||||||
(fx/defn fetch-node-info-fx [_]
|
(rf/defn fetch-node-info-fx
|
||||||
{::json-rpc/call [{:method "admin_nodeInfo"
|
[_]
|
||||||
|
{::json-rpc/call [{:method "admin_nodeInfo"
|
||||||
:on-success #(re-frame/dispatch [:transport.callback/node-info-fetched %])
|
:on-success #(re-frame/dispatch [:transport.callback/node-info-fetched %])
|
||||||
:on-error #(log/error "node-info: failed error" %)}]})
|
:on-error #(log/error "node-info: failed error" %)}]})
|
||||||
|
|
||||||
(defn add-mailservers
|
(defn add-mailservers
|
||||||
[db mailservers]
|
[db mailservers]
|
||||||
@@ -28,25 +28,25 @@
|
|||||||
(assoc :name (if (seq name) name id))
|
(assoc :name (if (seq name) name id))
|
||||||
(dissoc :fleet))]
|
(dissoc :fleet))]
|
||||||
(assoc-in db
|
(assoc-in db
|
||||||
[:mailserver/mailservers (keyword fleet) (keyword id)]
|
[:mailserver/mailservers (keyword fleet) (keyword id)]
|
||||||
updated-mailserver)))
|
updated-mailserver)))
|
||||||
db
|
db
|
||||||
mailservers))
|
mailservers))
|
||||||
|
|
||||||
(fx/defn start-messenger
|
(rf/defn start-messenger
|
||||||
"We should only start receiving messages/processing topics once all the
|
"We should only start receiving messages/processing topics once all the
|
||||||
initializiation is completed, otherwise we might receive messages/topics
|
initializiation is completed, otherwise we might receive messages/topics
|
||||||
when the state has not been properly initialized."
|
when the state has not been properly initialized."
|
||||||
[_]
|
[_]
|
||||||
{::json-rpc/call [{:method "wakuext_startMessenger"
|
{::json-rpc/call [{:method "wakuext_startMessenger"
|
||||||
:on-success #(re-frame/dispatch [::messenger-started %])
|
:on-success #(re-frame/dispatch [::messenger-started %])
|
||||||
:on-error #(log/error "failed to start messenger")}]})
|
:on-error #(log/error "failed to start messenger")}]})
|
||||||
|
|
||||||
(fx/defn messenger-started
|
(rf/defn messenger-started
|
||||||
{:events [::messenger-started]}
|
{:events [::messenger-started]}
|
||||||
[{:keys [db] :as cofx} {:keys [mailservers] :as response}]
|
[{:keys [db] :as cofx} {:keys [mailservers] :as response}]
|
||||||
(log/info "Messenger started")
|
(log/info "Messenger started")
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc :messenger/started? true)
|
(assoc :messenger/started? true)
|
||||||
(add-mailservers mailservers))}
|
(add-mailservers mailservers))}
|
||||||
|
|||||||
@@ -1,37 +1,36 @@
|
|||||||
(ns ^{:doc "Definition of the StatusMessage protocol"}
|
(ns ^{:doc "Definition of the StatusMessage protocol"} status-im.transport.message.core
|
||||||
status-im.transport.message.core
|
(:require [clojure.string :as string]
|
||||||
(:require [status-im2.contexts.activity-center.events :as activity-center]
|
|
||||||
[status-im.chat.models.message :as models.message]
|
|
||||||
[status-im2.contexts.chat.messages.pin.events :as messages.pin]
|
|
||||||
[status-im.chat.models :as models.chat]
|
|
||||||
[status-im.chat.models.reactions :as models.reactions]
|
|
||||||
[status-im.contact.core :as models.contact]
|
|
||||||
[status-im.communities.core :as models.communities]
|
|
||||||
[status-im.pairing.core :as models.pairing]
|
|
||||||
[status-im.data-store.reactions :as data-store.reactions]
|
|
||||||
[status-im.data-store.contacts :as data-store.contacts]
|
|
||||||
[status-im.data-store.chats :as data-store.chats]
|
|
||||||
[status-im.data-store.invitations :as data-store.invitations]
|
|
||||||
[status-im.data-store.activities :as data-store.activities]
|
|
||||||
[status-im.data-store.messages :as data-store.messages]
|
|
||||||
[status-im.group-chats.core :as models.group]
|
|
||||||
[status-im.multiaccounts.update.core :as update.core]
|
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[status-im.utils.types :as types]
|
|
||||||
[status-im.constants :as constants]
|
|
||||||
[status-im.multiaccounts.model :as multiaccounts.model]
|
|
||||||
[status-im.multiaccounts.login.core :as multiaccounts.login]
|
|
||||||
[status-im.visibility-status-updates.core :as models.visibility-status-updates]
|
|
||||||
[status-im.browser.core :as browser]
|
[status-im.browser.core :as browser]
|
||||||
[clojure.string :as string]))
|
[status-im.chat.models :as models.chat]
|
||||||
|
[status-im.chat.models.message :as models.message]
|
||||||
|
[status-im.chat.models.reactions :as models.reactions]
|
||||||
|
[status-im.communities.core :as models.communities]
|
||||||
|
[status-im.constants :as constants]
|
||||||
|
[status-im.contact.core :as models.contact]
|
||||||
|
[status-im.data-store.activities :as data-store.activities]
|
||||||
|
[status-im.data-store.chats :as data-store.chats]
|
||||||
|
[status-im.data-store.contacts :as data-store.contacts]
|
||||||
|
[status-im.data-store.invitations :as data-store.invitations]
|
||||||
|
[status-im.data-store.messages :as data-store.messages]
|
||||||
|
[status-im.data-store.reactions :as data-store.reactions]
|
||||||
|
[status-im.group-chats.core :as models.group]
|
||||||
|
[status-im.multiaccounts.login.core :as multiaccounts.login]
|
||||||
|
[status-im.multiaccounts.model :as multiaccounts.model]
|
||||||
|
[status-im.multiaccounts.update.core :as update.core]
|
||||||
|
[status-im.pairing.core :as models.pairing]
|
||||||
|
[status-im.utils.types :as types]
|
||||||
|
[status-im.visibility-status-updates.core :as models.visibility-status-updates]
|
||||||
|
[status-im2.contexts.activity-center.events :as activity-center]
|
||||||
|
[status-im2.contexts.chat.messages.pin.events :as messages.pin]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(fx/defn process-next
|
(rf/defn process-next
|
||||||
[cofx ^js response-js sync-handler]
|
[cofx ^js response-js sync-handler]
|
||||||
(if sync-handler
|
(if sync-handler
|
||||||
(sync-handler cofx response-js true)
|
(sync-handler cofx response-js true)
|
||||||
{:utils/dispatch-later [{:ms 20 :dispatch [:process-response response-js]}]}))
|
{:utils/dispatch-later [{:ms 20 :dispatch [:process-response response-js]}]}))
|
||||||
|
|
||||||
(fx/defn process-response
|
(rf/defn process-response
|
||||||
{:events [:process-response]}
|
{:events [:process-response]}
|
||||||
[{:keys [db] :as cofx} ^js response-js process-async]
|
[{:keys [db] :as cofx} ^js response-js process-async]
|
||||||
(let [^js communities (.-communities response-js)
|
(let [^js communities (.-communities response-js)
|
||||||
@@ -59,7 +58,7 @@
|
|||||||
(seq chats)
|
(seq chats)
|
||||||
(do
|
(do
|
||||||
(js-delete response-js "chats")
|
(js-delete response-js "chats")
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(process-next response-js sync-handler)
|
(process-next response-js sync-handler)
|
||||||
(models.chat/ensure-chats (map data-store.chats/<-rpc (types/js->clj chats)))))
|
(models.chat/ensure-chats (map data-store.chats/<-rpc (types/js->clj chats)))))
|
||||||
|
|
||||||
@@ -69,7 +68,7 @@
|
|||||||
(seq activity-notifications)
|
(seq activity-notifications)
|
||||||
(do
|
(do
|
||||||
(js-delete response-js "activityCenterNotifications")
|
(js-delete response-js "activityCenterNotifications")
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(->> activity-notifications
|
(->> activity-notifications
|
||||||
types/js->clj
|
types/js->clj
|
||||||
(map data-store.activities/<-rpc)
|
(map data-store.activities/<-rpc)
|
||||||
@@ -79,86 +78,87 @@
|
|||||||
(seq installations)
|
(seq installations)
|
||||||
(let [installations-clj (types/js->clj installations)]
|
(let [installations-clj (types/js->clj installations)]
|
||||||
(js-delete response-js "installations")
|
(js-delete response-js "installations")
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(process-next response-js sync-handler)
|
(process-next response-js sync-handler)
|
||||||
(models.pairing/handle-installations installations-clj)))
|
(models.pairing/handle-installations installations-clj)))
|
||||||
|
|
||||||
(seq contacts)
|
(seq contacts)
|
||||||
(let [contacts-clj (types/js->clj contacts)
|
(let [contacts-clj (types/js->clj contacts)
|
||||||
^js chats (.-chatsForContacts response-js)]
|
^js chats (.-chatsForContacts response-js)]
|
||||||
(js-delete response-js "contacts")
|
(js-delete response-js "contacts")
|
||||||
(js-delete response-js "chatsForContacts")
|
(js-delete response-js "chatsForContacts")
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(process-next response-js sync-handler)
|
(process-next response-js sync-handler)
|
||||||
(models.contact/ensure-contacts
|
(models.contact/ensure-contacts
|
||||||
(map data-store.contacts/<-rpc contacts-clj) chats)))
|
(map data-store.contacts/<-rpc contacts-clj)
|
||||||
|
chats)))
|
||||||
|
|
||||||
(seq communities)
|
(seq communities)
|
||||||
(let [communities-clj (types/js->clj communities)]
|
(let [communities-clj (types/js->clj communities)]
|
||||||
(js-delete response-js "communities")
|
(js-delete response-js "communities")
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(process-next response-js sync-handler)
|
(process-next response-js sync-handler)
|
||||||
(models.communities/handle-communities communities-clj)))
|
(models.communities/handle-communities communities-clj)))
|
||||||
|
|
||||||
(seq bookmarks)
|
(seq bookmarks)
|
||||||
(let [bookmarks-clj (types/js->clj bookmarks)]
|
(let [bookmarks-clj (types/js->clj bookmarks)]
|
||||||
(js-delete response-js "bookmarks")
|
(js-delete response-js "bookmarks")
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(process-next response-js sync-handler)
|
(process-next response-js sync-handler)
|
||||||
(browser/handle-bookmarks bookmarks-clj)))
|
(browser/handle-bookmarks bookmarks-clj)))
|
||||||
|
|
||||||
(seq pin-messages)
|
(seq pin-messages)
|
||||||
(let [pin-messages (types/js->clj pin-messages)]
|
(let [pin-messages (types/js->clj pin-messages)]
|
||||||
(js-delete response-js "pinMessages")
|
(js-delete response-js "pinMessages")
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(process-next response-js sync-handler)
|
(process-next response-js sync-handler)
|
||||||
(messages.pin/receive-signal (map data-store.messages/<-rpc pin-messages))))
|
(messages.pin/receive-signal (map data-store.messages/<-rpc pin-messages))))
|
||||||
|
|
||||||
(seq removed-chats)
|
(seq removed-chats)
|
||||||
(let [removed-chats-clj (types/js->clj removed-chats)]
|
(let [removed-chats-clj (types/js->clj removed-chats)]
|
||||||
(js-delete response-js "removedChats")
|
(js-delete response-js "removedChats")
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(process-next response-js sync-handler)
|
(process-next response-js sync-handler)
|
||||||
(models.communities/handle-removed-chats removed-chats-clj)))
|
(models.communities/handle-removed-chats removed-chats-clj)))
|
||||||
|
|
||||||
(seq requests-to-join-community)
|
(seq requests-to-join-community)
|
||||||
(let [request-js (types/js->clj (.pop requests-to-join-community))]
|
(let [request-js (types/js->clj (.pop requests-to-join-community))]
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(process-next response-js sync-handler)
|
(process-next response-js sync-handler)
|
||||||
(models.communities/handle-request-to-join request-js)))
|
(models.communities/handle-request-to-join request-js)))
|
||||||
|
|
||||||
(seq emoji-reactions)
|
(seq emoji-reactions)
|
||||||
(let [reactions (types/js->clj emoji-reactions)]
|
(let [reactions (types/js->clj emoji-reactions)]
|
||||||
(js-delete response-js "emojiReactions")
|
(js-delete response-js "emojiReactions")
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(process-next response-js sync-handler)
|
(process-next response-js sync-handler)
|
||||||
(models.reactions/receive-signal (map data-store.reactions/<-rpc reactions))))
|
(models.reactions/receive-signal (map data-store.reactions/<-rpc reactions))))
|
||||||
|
|
||||||
(seq invitations)
|
(seq invitations)
|
||||||
(let [invitations (types/js->clj invitations)]
|
(let [invitations (types/js->clj invitations)]
|
||||||
(js-delete response-js "invitations")
|
(js-delete response-js "invitations")
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(process-next response-js sync-handler)
|
(process-next response-js sync-handler)
|
||||||
(models.group/handle-invitations (map data-store.invitations/<-rpc invitations))))
|
(models.group/handle-invitations (map data-store.invitations/<-rpc invitations))))
|
||||||
|
|
||||||
(seq removed-messages)
|
(seq removed-messages)
|
||||||
(let [removed-messages-clj (types/js->clj removed-messages)]
|
(let [removed-messages-clj (types/js->clj removed-messages)]
|
||||||
(js-delete response-js "removedMessages")
|
(js-delete response-js "removedMessages")
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(process-next response-js sync-handler)
|
(process-next response-js sync-handler)
|
||||||
(models.message/handle-removed-messages removed-messages-clj)))
|
(models.message/handle-removed-messages removed-messages-clj)))
|
||||||
|
|
||||||
(seq cleared-histories)
|
(seq cleared-histories)
|
||||||
(let [cleared-histories-clj (types/js->clj cleared-histories)]
|
(let [cleared-histories-clj (types/js->clj cleared-histories)]
|
||||||
(js-delete response-js "clearedHistories")
|
(js-delete response-js "clearedHistories")
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(process-next response-js sync-handler)
|
(process-next response-js sync-handler)
|
||||||
(models.message/handle-cleared-histories-messages cleared-histories-clj)))
|
(models.message/handle-cleared-histories-messages cleared-histories-clj)))
|
||||||
|
|
||||||
(seq visibility-status-updates)
|
(seq visibility-status-updates)
|
||||||
(let [visibility-status-updates-clj (types/js->clj visibility-status-updates)]
|
(let [visibility-status-updates-clj (types/js->clj visibility-status-updates)]
|
||||||
(js-delete response-js "statusUpdates")
|
(js-delete response-js "statusUpdates")
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(process-next response-js sync-handler)
|
(process-next response-js sync-handler)
|
||||||
(models.visibility-status-updates/handle-visibility-status-updates
|
(models.visibility-status-updates/handle-visibility-status-updates
|
||||||
visibility-status-updates-clj)))
|
visibility-status-updates-clj)))
|
||||||
@@ -166,28 +166,28 @@
|
|||||||
(seq accounts)
|
(seq accounts)
|
||||||
(do
|
(do
|
||||||
(js-delete response-js "accounts")
|
(js-delete response-js "accounts")
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(process-next response-js sync-handler)
|
(process-next response-js sync-handler)
|
||||||
(multiaccounts.login/update-wallet-accounts (types/js->clj accounts))))
|
(multiaccounts.login/update-wallet-accounts (types/js->clj accounts))))
|
||||||
|
|
||||||
(seq settings)
|
(seq settings)
|
||||||
(do
|
(do
|
||||||
(js-delete response-js "settings")
|
(js-delete response-js "settings")
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(process-next response-js sync-handler)
|
(process-next response-js sync-handler)
|
||||||
(update.core/set-many-js settings)))
|
(update.core/set-many-js settings)))
|
||||||
|
|
||||||
(seq identity-images)
|
(seq identity-images)
|
||||||
(let [images-clj (map types/js->clj identity-images)]
|
(let [images-clj (map types/js->clj identity-images)]
|
||||||
(js-delete response-js "identityImages")
|
(js-delete response-js "identityImages")
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(process-next response-js sync-handler)
|
(process-next response-js sync-handler)
|
||||||
(update.core/optimistic :images images-clj)))
|
(update.core/optimistic :images images-clj)))
|
||||||
|
|
||||||
(some? current-visibility-status)
|
(some? current-visibility-status)
|
||||||
(let [current-visibility-status-clj (types/js->clj current-visibility-status)]
|
(let [current-visibility-status-clj (types/js->clj current-visibility-status)]
|
||||||
(js-delete response-js "currentStatus")
|
(js-delete response-js "currentStatus")
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
(process-next response-js sync-handler)
|
(process-next response-js sync-handler)
|
||||||
(models.visibility-status-updates/sync-visibility-status-update
|
(models.visibility-status-updates/sync-visibility-status-update
|
||||||
current-visibility-status-clj))))))
|
current-visibility-status-clj))))))
|
||||||
@@ -195,19 +195,21 @@
|
|||||||
(defn group-by-and-update-unviewed-counts
|
(defn group-by-and-update-unviewed-counts
|
||||||
"group messages by current chat, profile updates, transactions and update unviewed counters in db for not curent chats"
|
"group messages by current chat, profile updates, transactions and update unviewed counters in db for not curent chats"
|
||||||
[{:keys [current-chat-id db] :as acc} ^js message-js]
|
[{:keys [current-chat-id db] :as acc} ^js message-js]
|
||||||
(let [chat-id (.-localChatId message-js)
|
(let [chat-id (.-localChatId message-js)
|
||||||
message-type (.-messageType message-js)
|
message-type (.-messageType message-js)
|
||||||
from (.-from message-js)
|
from (.-from message-js)
|
||||||
mentioned (.-mentioned message-js)
|
mentioned (.-mentioned message-js)
|
||||||
profile (models.chat/profile-chat? {:db db} chat-id)
|
profile (models.chat/profile-chat? {:db db} chat-id)
|
||||||
new (.-new message-js)
|
new (.-new message-js)
|
||||||
current (= current-chat-id chat-id)
|
current (= current-chat-id chat-id)
|
||||||
should-update-unviewed? (and (not current)
|
should-update-unviewed? (and (not current)
|
||||||
new
|
new
|
||||||
(not profile)
|
(not profile)
|
||||||
(not (= message-type constants/message-type-private-group-system-message))
|
(not (= message-type
|
||||||
|
constants/message-type-private-group-system-message))
|
||||||
(not (= from (multiaccounts.model/current-public-key {:db db}))))
|
(not (= from (multiaccounts.model/current-public-key {:db db}))))
|
||||||
tx-hash (and (.-commandParameters message-js) (.-commandParameters.transactionHash message-js))]
|
tx-hash (and (.-commandParameters message-js)
|
||||||
|
(.-commandParameters.transactionHash message-js))]
|
||||||
(cond-> acc
|
(cond-> acc
|
||||||
current
|
current
|
||||||
(update :messages conj message-js)
|
(update :messages conj message-js)
|
||||||
@@ -235,46 +237,52 @@
|
|||||||
[response-js messages]
|
[response-js messages]
|
||||||
(if (seq messages)
|
(if (seq messages)
|
||||||
(set! (.-messages response-js)
|
(set! (.-messages response-js)
|
||||||
(.sort (to-array messages)
|
(.sort (to-array messages)
|
||||||
(fn [a b]
|
(fn [a b]
|
||||||
(- (.-clock b) (.-clock a)))))
|
(- (.-clock b) (.-clock a)))))
|
||||||
(js-delete response-js "messages")))
|
(js-delete response-js "messages")))
|
||||||
|
|
||||||
(fx/defn sanitize-messages-and-process-response
|
(rf/defn sanitize-messages-and-process-response
|
||||||
"before processing we want to filter and sort messages, so we can process first only messages which will be showed"
|
"before processing we want to filter and sort messages, so we can process first only messages which will be showed"
|
||||||
{:events [:sanitize-messages-and-process-response]}
|
{:events [:sanitize-messages-and-process-response]}
|
||||||
[{:keys [db] :as cofx} ^js response-js process-async]
|
[{:keys [db] :as cofx} ^js response-js process-async]
|
||||||
(when response-js
|
(when response-js
|
||||||
(let [current-chat-id (:current-chat-id db)
|
(let [current-chat-id (:current-chat-id db)
|
||||||
{:keys [db messages transactions chats statuses]}
|
{:keys [db messages transactions chats statuses]}
|
||||||
(reduce group-by-and-update-unviewed-counts
|
(reduce group-by-and-update-unviewed-counts
|
||||||
{:db db :chats #{} :transactions #{} :statuses [] :messages []
|
{:db db
|
||||||
|
:chats #{}
|
||||||
|
:transactions #{}
|
||||||
|
:statuses []
|
||||||
|
:messages []
|
||||||
:current-chat-id current-chat-id}
|
:current-chat-id current-chat-id}
|
||||||
(.-messages response-js))]
|
(.-messages response-js))]
|
||||||
(sort-js-messages! response-js messages)
|
(sort-js-messages! response-js messages)
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db db
|
{:db db
|
||||||
:utils/dispatch-later (concat []
|
:utils/dispatch-later (concat []
|
||||||
(when (seq statuses)
|
(when (seq statuses)
|
||||||
[{:ms 100 :dispatch [:process-statuses statuses]}])
|
[{:ms 100 :dispatch [:process-statuses statuses]}])
|
||||||
(when (seq transactions)
|
(when (seq transactions)
|
||||||
(for [transaction-hash transactions]
|
(for [transaction-hash transactions]
|
||||||
{:ms 100 :dispatch [:watch-tx nil transaction-hash]})))}
|
{:ms 100
|
||||||
|
:dispatch [:watch-tx nil transaction-hash]})))}
|
||||||
(process-response response-js process-async)))))
|
(process-response response-js process-async)))))
|
||||||
|
|
||||||
(fx/defn remove-hash
|
(rf/defn remove-hash
|
||||||
[{:keys [db]} envelope-hash]
|
[{:keys [db]} envelope-hash]
|
||||||
{:db (update db :transport/message-envelopes dissoc envelope-hash)})
|
{:db (update db :transport/message-envelopes dissoc envelope-hash)})
|
||||||
|
|
||||||
(fx/defn check-confirmations
|
(rf/defn check-confirmations
|
||||||
[{:keys [db] :as cofx} status chat-id message-id]
|
[{:keys [db] :as cofx} status chat-id message-id]
|
||||||
(when-let [{:keys [pending-confirmations not-sent]}
|
(when-let [{:keys [pending-confirmations not-sent]}
|
||||||
(get-in db [:transport/message-ids->confirmations message-id])]
|
(get-in db [:transport/message-ids->confirmations message-id])]
|
||||||
(if (zero? (dec pending-confirmations))
|
(if (zero? (dec pending-confirmations))
|
||||||
(fx/merge cofx
|
(rf/merge cofx
|
||||||
{:db (update db
|
{:db (update db
|
||||||
:transport/message-ids->confirmations
|
:transport/message-ids->confirmations
|
||||||
dissoc message-id)}
|
dissoc
|
||||||
|
message-id)}
|
||||||
(models.message/update-message-status chat-id
|
(models.message/update-message-status chat-id
|
||||||
message-id
|
message-id
|
||||||
(if not-sent
|
(if not-sent
|
||||||
@@ -282,13 +290,13 @@
|
|||||||
status))
|
status))
|
||||||
(remove-hash message-id))
|
(remove-hash message-id))
|
||||||
(let [confirmations {:pending-confirmations (dec pending-confirmations)
|
(let [confirmations {:pending-confirmations (dec pending-confirmations)
|
||||||
:not-sent (or not-sent
|
:not-sent (or not-sent
|
||||||
(= :not-sent status))}]
|
(= :not-sent status))}]
|
||||||
{:db (assoc-in db
|
{:db (assoc-in db
|
||||||
[:transport/message-ids->confirmations message-id]
|
[:transport/message-ids->confirmations message-id]
|
||||||
confirmations)}))))
|
confirmations)}))))
|
||||||
|
|
||||||
(fx/defn update-envelope-status
|
(rf/defn update-envelope-status
|
||||||
[{:keys [db] :as cofx} message-id status]
|
[{:keys [db] :as cofx} message-id status]
|
||||||
(if-let [{:keys [chat-id]}
|
(if-let [{:keys [chat-id]}
|
||||||
(get-in db [:transport/message-envelopes message-id])]
|
(get-in db [:transport/message-envelopes message-id])]
|
||||||
@@ -298,37 +306,38 @@
|
|||||||
;; came too early
|
;; came too early
|
||||||
{:db (update-in db [:transport/message-confirmations message-id] conj status)}))
|
{:db (update-in db [:transport/message-confirmations message-id] conj status)}))
|
||||||
|
|
||||||
(fx/defn update-envelopes-status
|
(rf/defn update-envelopes-status
|
||||||
[{:keys [db] :as cofx} message-id status]
|
[{:keys [db] :as cofx} message-id status]
|
||||||
(when (or (not= status :not-sent)
|
(when (or (not= status :not-sent)
|
||||||
(= :online (:network db)))
|
(= :online (:network db)))
|
||||||
(apply fx/merge cofx (map #(update-envelope-status % status) message-id))))
|
(apply rf/merge cofx (map #(update-envelope-status % status) message-id))))
|
||||||
|
|
||||||
(fx/defn set-message-envelope-hash
|
(rf/defn set-message-envelope-hash
|
||||||
"message-type is used for tracking"
|
"message-type is used for tracking"
|
||||||
[{:keys [db] :as cofx} chat-id message-id message-type]
|
[{:keys [db] :as cofx} chat-id message-id message-type]
|
||||||
;; Check first if the confirmation has already arrived
|
;; Check first if the confirmation has already arrived
|
||||||
(let [statuses (get-in db [:transport/message-confirmations message-id])
|
(let [statuses (get-in db [:transport/message-confirmations message-id])
|
||||||
check-confirmations-fx (map
|
check-confirmations-fx (map
|
||||||
#(check-confirmations % chat-id message-id)
|
#(check-confirmations % chat-id message-id)
|
||||||
statuses)
|
statuses)
|
||||||
|
|
||||||
add-envelope-data (fn [{:keys [db]}]
|
add-envelope-data (fn [{:keys [db]}]
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(update :transport/message-confirmations dissoc message-id)
|
(update :transport/message-confirmations dissoc message-id)
|
||||||
(assoc-in [:transport/message-envelopes message-id]
|
(assoc-in [:transport/message-envelopes message-id]
|
||||||
{:chat-id chat-id
|
{:chat-id chat-id
|
||||||
:message-type message-type})
|
:message-type message-type})
|
||||||
(update-in [:transport/message-ids->confirmations message-id]
|
(update-in [:transport/message-ids->confirmations message-id]
|
||||||
#(or % {:pending-confirmations 1})))})]
|
#(or % {:pending-confirmations 1})))})]
|
||||||
(apply fx/merge cofx (conj check-confirmations-fx add-envelope-data))))
|
(apply rf/merge cofx (conj check-confirmations-fx add-envelope-data))))
|
||||||
|
|
||||||
(fx/defn transport-message-sent
|
(rf/defn transport-message-sent
|
||||||
{:events [:transport/message-sent]}
|
{:events [:transport/message-sent]}
|
||||||
[cofx response-js]
|
[cofx response-js]
|
||||||
(let [set-hash-fxs (map (fn [{:keys [localChatId id messageType]}]
|
(let [set-hash-fxs (map (fn [{:keys [localChatId id messageType]}]
|
||||||
(set-message-envelope-hash localChatId id messageType))
|
(set-message-envelope-hash localChatId id messageType))
|
||||||
(types/js->clj (.-messages response-js)))]
|
(types/js->clj (.-messages response-js)))]
|
||||||
(apply fx/merge cofx
|
(apply rf/merge
|
||||||
|
cofx
|
||||||
(conj set-hash-fxs
|
(conj set-hash-fxs
|
||||||
#(sanitize-messages-and-process-response % response-js false)))))
|
#(sanitize-messages-and-process-response % response-js false)))))
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
(ns ^{:doc "Protocol API and protocol utils"}
|
(ns ^{:doc "Protocol API and protocol utils"} status-im.transport.message.protocol
|
||||||
status-im.transport.message.protocol
|
|
||||||
(:require [re-frame.core :as re-frame]
|
(:require [re-frame.core :as re-frame]
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
[status-im.utils.fx :as fx]
|
[taoensso.timbre :as log]
|
||||||
[taoensso.timbre :as log]))
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(defn build-message [{:keys [chat-id
|
(defn build-message
|
||||||
text
|
[{:keys [chat-id
|
||||||
response-to
|
text
|
||||||
ens-name
|
response-to
|
||||||
community-id
|
ens-name
|
||||||
image-path
|
community-id
|
||||||
audio-path
|
image-path
|
||||||
audio-duration-ms
|
audio-path
|
||||||
sticker
|
audio-duration-ms
|
||||||
content-type]}]
|
sticker
|
||||||
|
content-type]}]
|
||||||
{:chatId chat-id
|
{:chatId chat-id
|
||||||
:text text
|
:text text
|
||||||
:responseTo response-to
|
:responseTo response-to
|
||||||
@@ -26,25 +26,28 @@
|
|||||||
:sticker sticker
|
:sticker sticker
|
||||||
:contentType content-type})
|
:contentType content-type})
|
||||||
|
|
||||||
(fx/defn send-chat-messages [_ messages]
|
(rf/defn send-chat-messages
|
||||||
{::json-rpc/call [{:method "wakuext_sendChatMessages"
|
[_ messages]
|
||||||
:params [(mapv build-message messages)]
|
{::json-rpc/call [{:method "wakuext_sendChatMessages"
|
||||||
|
:params [(mapv build-message messages)]
|
||||||
:js-response true
|
:js-response true
|
||||||
:on-success #(re-frame/dispatch [:transport/message-sent %])
|
:on-success #(re-frame/dispatch [:transport/message-sent %])
|
||||||
:on-error #(do
|
:on-error #(do
|
||||||
(log/warn "failed to send a message" %)
|
(log/warn "failed to send a message" %)
|
||||||
(js/alert (str "failed to send a message: " %)))}]})
|
(js/alert (str "failed to send a message: " %)))}]})
|
||||||
|
|
||||||
(fx/defn send-reaction [_ {:keys [message-id chat-id emoji-id]}]
|
(rf/defn send-reaction
|
||||||
{::json-rpc/call [{:method "wakuext_sendEmojiReaction"
|
[_ {:keys [message-id chat-id emoji-id]}]
|
||||||
:params [chat-id message-id emoji-id]
|
{::json-rpc/call [{:method "wakuext_sendEmojiReaction"
|
||||||
|
:params [chat-id message-id emoji-id]
|
||||||
:js-response true
|
:js-response true
|
||||||
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
|
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
|
||||||
:on-error #(log/error "failed to send a reaction" %)}]})
|
:on-error #(log/error "failed to send a reaction" %)}]})
|
||||||
|
|
||||||
(fx/defn send-retract-reaction [_ {:keys [emoji-reaction-id]}]
|
(rf/defn send-retract-reaction
|
||||||
{::json-rpc/call [{:method "wakuext_sendEmojiReactionRetraction"
|
[_ {:keys [emoji-reaction-id]}]
|
||||||
:params [emoji-reaction-id]
|
{::json-rpc/call [{:method "wakuext_sendEmojiReactionRetraction"
|
||||||
|
:params [emoji-reaction-id]
|
||||||
:js-response true
|
:js-response true
|
||||||
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
|
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
|
||||||
:on-error #(log/error "failed to send a reaction retraction" %)}]})
|
:on-error #(log/error "failed to send a reaction retraction" %)}]})
|
||||||
|
|||||||
@@ -1,20 +1,22 @@
|
|||||||
(ns status-im.ui.components.invite.events
|
(ns status-im.ui.components.invite.events
|
||||||
(:require [re-frame.core :as re-frame]
|
(:require [re-frame.core :as re-frame]
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[status-im.i18n.i18n :as i18n]
|
[status-im.i18n.i18n :as i18n]
|
||||||
[status-im.ui.components.react :as react]
|
[status-im.ui.components.react :as react]
|
||||||
[status-im.utils.universal-links.utils :as universal-links]))
|
[status-im.utils.universal-links.utils :as universal-links]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
::share
|
::share
|
||||||
(fn [content]
|
(fn [content]
|
||||||
(.share ^js react/sharing (clj->js content))))
|
(.share ^js react/sharing (clj->js content))))
|
||||||
|
|
||||||
(fx/defn share-link
|
(rf/defn share-link
|
||||||
{:events [::share-link]}
|
{:events [::share-link]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(let [{:keys [public-key preferred-name]} (get db :multiaccount)
|
(let [{:keys [public-key preferred-name]} (get db :multiaccount)
|
||||||
profile-link (universal-links/generate-link :user :external
|
profile-link (universal-links/generate-link :user
|
||||||
(or preferred-name public-key))
|
:external
|
||||||
|
(or preferred-name
|
||||||
|
public-key))
|
||||||
message (i18n/label :t/join-me {:url profile-link})]
|
message (i18n/label :t/join-me {:url profile-link})]
|
||||||
{::share {:message message}}))
|
{::share {:message message}}))
|
||||||
|
|||||||
@@ -1,23 +1,22 @@
|
|||||||
(ns status-im.ui.screens.chat.audio-message.views
|
(ns status-im.ui.screens.chat.audio-message.views
|
||||||
(:require-macros [status-im.utils.views :refer [defview letsubs]])
|
(:require-macros [status-im.utils.views :refer [defview letsubs]])
|
||||||
(:require
|
(:require [goog.string :as gstring]
|
||||||
[goog.string :as gstring]
|
[quo.components.animated.pressable :as pressable]
|
||||||
[reagent.core :as reagent]
|
[quo.design-system.colors :as colors]
|
||||||
[status-im.audio.core :as audio]
|
[re-frame.core :as re-frame]
|
||||||
[status-im.ui.components.react :as react]
|
[reagent.core :as reagent]
|
||||||
[re-frame.core :as re-frame]
|
[status-im.audio.core :as audio]
|
||||||
[status-im.i18n.i18n :as i18n]
|
[status-im.i18n.i18n :as i18n]
|
||||||
[quo.components.animated.pressable :as pressable]
|
[status-im.native-module.core :as status]
|
||||||
[status-im.native-module.core :as status]
|
[status-im.ui.components.animation :as anim]
|
||||||
[status-im.ui.screens.chat.components.input :as input]
|
[status-im.ui.components.icons.icons :as icons]
|
||||||
[status-im.ui.screens.chat.components.style :as input.style]
|
[status-im.ui.components.react :as react]
|
||||||
[status-im.ui.screens.chat.audio-message.styles :as styles]
|
[status-im.ui.screens.chat.audio-message.styles :as styles]
|
||||||
[quo.design-system.colors :as colors]
|
[status-im.ui.screens.chat.components.input :as input]
|
||||||
[status-im.ui.components.animation :as anim]
|
[status-im.ui.screens.chat.components.style :as input.style]
|
||||||
[status-im.ui.components.icons.icons :as icons]
|
[status-im.utils.fs :as fs]
|
||||||
[status-im.utils.utils :as utils.utils]
|
[status-im.utils.utils :as utils.utils]
|
||||||
[status-im.utils.fs :as fs]
|
[utils.re-frame :as rf]))
|
||||||
[status-im.utils.fx :as fx]))
|
|
||||||
|
|
||||||
;; reference db levels
|
;; reference db levels
|
||||||
(def total-silence-db -160)
|
(def total-silence-db -160)
|
||||||
@@ -31,20 +30,23 @@
|
|||||||
;;ensure animation finishes before next meter update
|
;;ensure animation finishes before next meter update
|
||||||
(defonce metering-anim-duration (int (* metering-interval 0.9)))
|
(defonce metering-anim-duration (int (* metering-interval 0.9)))
|
||||||
|
|
||||||
(defn update-meter [meter-data]
|
(defn update-meter
|
||||||
|
[meter-data]
|
||||||
(let [value (if meter-data
|
(let [value (if meter-data
|
||||||
(.-value ^js meter-data)
|
(.-value ^js meter-data)
|
||||||
total-silence-db)]
|
total-silence-db)]
|
||||||
(anim/start (anim/timing visual-target-value {:toValue value
|
(anim/start (anim/timing visual-target-value
|
||||||
:duration metering-anim-duration
|
{:toValue value
|
||||||
:useNativeDriver true}))))
|
:duration metering-anim-duration
|
||||||
|
:useNativeDriver true}))))
|
||||||
|
|
||||||
(def base-filename "am.")
|
(def base-filename "am.")
|
||||||
(def default-format "aac")
|
(def default-format "aac")
|
||||||
(def rec-options (merge
|
(def rec-options
|
||||||
audio/default-recorder-options
|
(merge
|
||||||
{:filename (str base-filename default-format)
|
audio/default-recorder-options
|
||||||
:meteringInterval metering-interval}))
|
{:filename (str base-filename default-format)
|
||||||
|
:meteringInterval metering-interval}))
|
||||||
|
|
||||||
;; maximum 1 minute of recordings time to keep data at certain size
|
;; maximum 1 minute of recordings time to keep data at certain size
|
||||||
(def max-recording-ms (* 1 60 1000))
|
(def max-recording-ms (* 1 60 1000))
|
||||||
@@ -53,11 +55,13 @@
|
|||||||
(defonce recorder-ref (atom nil))
|
(defonce recorder-ref (atom nil))
|
||||||
(defonce player-ref (atom nil))
|
(defonce player-ref (atom nil))
|
||||||
|
|
||||||
(defn destroy-recorder []
|
(defn destroy-recorder
|
||||||
|
[]
|
||||||
(audio/destroy-recorder @recorder-ref)
|
(audio/destroy-recorder @recorder-ref)
|
||||||
(reset! recorder-ref nil))
|
(reset! recorder-ref nil))
|
||||||
|
|
||||||
(defn destroy-player []
|
(defn destroy-player
|
||||||
|
[]
|
||||||
(audio/destroy-player @player-ref)
|
(audio/destroy-player @player-ref)
|
||||||
(reset! player-ref nil))
|
(reset! player-ref nil))
|
||||||
|
|
||||||
@@ -70,7 +74,7 @@
|
|||||||
;; to be called when app goes in background
|
;; to be called when app goes in background
|
||||||
(defonce on-background-cb (atom #()))
|
(defonce on-background-cb (atom #()))
|
||||||
|
|
||||||
(fx/defn on-background
|
(rf/defn on-background
|
||||||
{:events [:audio-recorder/on-background]}
|
{:events [:audio-recorder/on-background]}
|
||||||
[_]
|
[_]
|
||||||
(when @on-background-cb
|
(when @on-background-cb
|
||||||
@@ -83,32 +87,38 @@
|
|||||||
(defonce recording-backlog-ms (atom 0))
|
(defonce recording-backlog-ms (atom 0))
|
||||||
|
|
||||||
;; updates timer UI
|
;; updates timer UI
|
||||||
(defn update-timer [timer]
|
(defn update-timer
|
||||||
|
[timer]
|
||||||
(let [ms (if @recording-start-ts
|
(let [ms (if @recording-start-ts
|
||||||
(+
|
(+
|
||||||
(- (js/Date.now) @recording-start-ts)
|
(- (js/Date.now) @recording-start-ts)
|
||||||
@recording-backlog-ms)
|
@recording-backlog-ms)
|
||||||
@recording-backlog-ms)
|
@recording-backlog-ms)
|
||||||
s (quot ms 1000)]
|
s (quot ms 1000)]
|
||||||
(if (> ms max-recording-ms)
|
(if (> ms max-recording-ms)
|
||||||
(@max-recording-reached-cb)
|
(@max-recording-reached-cb)
|
||||||
(reset! timer (gstring/format "%d:%02d" (quot s 60) (mod s 60))))))
|
(reset! timer (gstring/format "%d:%02d" (quot s 60) (mod s 60))))))
|
||||||
|
|
||||||
(defn reset-timer [timer]
|
(defn reset-timer
|
||||||
|
[timer]
|
||||||
(reset! timer "0:00")
|
(reset! timer "0:00")
|
||||||
(reset! recording-backlog-ms 0))
|
(reset! recording-backlog-ms 0))
|
||||||
|
|
||||||
(defn animate-buttons [rec? show-ctrl? {:keys [rec-button-anim-value ctrl-buttons-anim-value]}]
|
(defn animate-buttons
|
||||||
|
[rec? show-ctrl? {:keys [rec-button-anim-value ctrl-buttons-anim-value]}]
|
||||||
(anim/start
|
(anim/start
|
||||||
(anim/parallel
|
(anim/parallel
|
||||||
[(anim/timing rec-button-anim-value {:toValue (if rec? 1 0)
|
[(anim/timing rec-button-anim-value
|
||||||
:duration 100
|
{:toValue (if rec? 1 0)
|
||||||
:useNativeDriver true})
|
:duration 100
|
||||||
(anim/timing ctrl-buttons-anim-value {:toValue (if show-ctrl? 1 0)
|
:useNativeDriver true})
|
||||||
:duration 100
|
(anim/timing ctrl-buttons-anim-value
|
||||||
:useNativeDriver true})])))
|
{:toValue (if show-ctrl? 1 0)
|
||||||
|
:duration 100
|
||||||
|
:useNativeDriver true})])))
|
||||||
|
|
||||||
(defn start-recording [{:keys [timer] :as params}]
|
(defn start-recording
|
||||||
|
[{:keys [timer] :as params}]
|
||||||
(if (> @recording-backlog-ms max-recording-ms)
|
(if (> @recording-backlog-ms max-recording-ms)
|
||||||
(@max-recording-reached-cb)
|
(@max-recording-reached-cb)
|
||||||
(do
|
(do
|
||||||
@@ -120,7 +130,8 @@
|
|||||||
@state-cb
|
@state-cb
|
||||||
#(utils.utils/show-popup (i18n/label :t/audio-recorder-error) (:message %))))))
|
#(utils.utils/show-popup (i18n/label :t/audio-recorder-error) (:message %))))))
|
||||||
|
|
||||||
(defn reload-recorder []
|
(defn reload-recorder
|
||||||
|
[]
|
||||||
(when @recorder-ref
|
(when @recorder-ref
|
||||||
(destroy-recorder))
|
(destroy-recorder))
|
||||||
(reset! recorder-ref (audio/new-recorder rec-options #(update-meter %) @state-cb))
|
(reset! recorder-ref (audio/new-recorder rec-options #(update-meter %) @state-cb))
|
||||||
@@ -134,7 +145,7 @@
|
|||||||
(destroy-player))
|
(destroy-player))
|
||||||
(reset! player-ref (audio/new-player
|
(reset! player-ref (audio/new-player
|
||||||
(:filename rec-options)
|
(:filename rec-options)
|
||||||
{:autoDestroy false
|
{:autoDestroy false
|
||||||
:continuesToPlayInBackground false}
|
:continuesToPlayInBackground false}
|
||||||
@state-cb))
|
@state-cb))
|
||||||
(audio/prepare-player
|
(audio/prepare-player
|
||||||
@@ -142,7 +153,8 @@
|
|||||||
#(do (@state-cb) (when on-success (on-success)))
|
#(do (@state-cb) (when on-success (on-success)))
|
||||||
#(utils.utils/show-popup (i18n/label :t/audio-recorder-error) (:message %)))))
|
#(utils.utils/show-popup (i18n/label :t/audio-recorder-error) (:message %)))))
|
||||||
|
|
||||||
(defn stop-recording [{:keys [on-success timer max-recording-reached?] :as params}]
|
(defn stop-recording
|
||||||
|
[{:keys [on-success timer max-recording-reached?] :as params}]
|
||||||
(when @recording-timer
|
(when @recording-timer
|
||||||
(utils.utils/clear-interval @recording-timer)
|
(utils.utils/clear-interval @recording-timer)
|
||||||
(reset! recording-timer nil))
|
(reset! recording-timer nil))
|
||||||
@@ -158,7 +170,8 @@
|
|||||||
#(utils.utils/show-popup (i18n/label :t/audio-recorder-error) (:message %)))
|
#(utils.utils/show-popup (i18n/label :t/audio-recorder-error) (:message %)))
|
||||||
(animate-buttons false max-recording-reached? params))
|
(animate-buttons false max-recording-reached? params))
|
||||||
|
|
||||||
(defn pause-recording [{:keys [timer] :as params}]
|
(defn pause-recording
|
||||||
|
[{:keys [timer] :as params}]
|
||||||
(when @recording-timer
|
(when @recording-timer
|
||||||
(utils.utils/clear-interval @recording-timer)
|
(utils.utils/clear-interval @recording-timer)
|
||||||
(reset! recording-backlog-ms (+ @recording-backlog-ms (- (js/Date.now) @recording-start-ts)))
|
(reset! recording-backlog-ms (+ @recording-backlog-ms (- (js/Date.now) @recording-start-ts)))
|
||||||
@@ -181,28 +194,29 @@
|
|||||||
- :recording-paused
|
- :recording-paused
|
||||||
- :ready-to-record"
|
- :ready-to-record"
|
||||||
[state-ref]
|
[state-ref]
|
||||||
(let [player-state (audio/get-state @player-ref)
|
(let [player-state (audio/get-state @player-ref)
|
||||||
recorder-state (audio/get-state @recorder-ref)
|
recorder-state (audio/get-state @recorder-ref)
|
||||||
output-file (or
|
output-file (or
|
||||||
(audio/get-recorder-file-path @recorder-ref)
|
(audio/get-recorder-file-path @recorder-ref)
|
||||||
(:output-file @state-ref))
|
(:output-file @state-ref))
|
||||||
general (cond
|
general (cond
|
||||||
(= recorder-state audio/RECORDING) :recording
|
(= recorder-state audio/RECORDING) :recording
|
||||||
(= player-state audio/PLAYING) :playing
|
(= player-state audio/PLAYING) :playing
|
||||||
(= player-state audio/PREPARED) :ready-to-send
|
(= player-state audio/PREPARED) :ready-to-send
|
||||||
(= recorder-state audio/PAUSED) :recording-paused
|
(= recorder-state audio/PAUSED) :recording-paused
|
||||||
:else :ready-to-record)
|
:else :ready-to-record)
|
||||||
new-state {:general general
|
new-state {:general general
|
||||||
:cancel-disabled? (nil? (#{:recording :recording-paused :ready-to-send} general))
|
:cancel-disabled? (nil? (#{:recording :recording-paused :ready-to-send} general))
|
||||||
:output-file output-file
|
:output-file output-file
|
||||||
:duration (audio/get-player-duration @player-ref)}]
|
:duration (audio/get-player-duration @player-ref)}]
|
||||||
(if (#{:recording :recording-paused} general)
|
(if (#{:recording :recording-paused} general)
|
||||||
(status/activate-keep-awake)
|
(status/activate-keep-awake)
|
||||||
(status/deactivate-keep-awake))
|
(status/deactivate-keep-awake))
|
||||||
(when (not= @state-ref new-state)
|
(when (not= @state-ref new-state)
|
||||||
(reset! state-ref new-state))))
|
(reset! state-ref new-state))))
|
||||||
|
|
||||||
(defn send-audio-msessage [state-ref]
|
(defn send-audio-msessage
|
||||||
|
[state-ref]
|
||||||
(re-frame/dispatch [:chat/send-audio
|
(re-frame/dispatch [:chat/send-audio
|
||||||
(:output-file @state-ref)
|
(:output-file @state-ref)
|
||||||
(int (:duration @state-ref))])
|
(int (:duration @state-ref))])
|
||||||
@@ -210,52 +224,65 @@
|
|||||||
(@state-cb))
|
(@state-cb))
|
||||||
|
|
||||||
;; rec-button-anim-value 0 => stopped, 1 => recording
|
;; rec-button-anim-value 0 => stopped, 1 => recording
|
||||||
(defview rec-button-view [{:keys [rec-button-anim-value state] :as params}]
|
(defview rec-button-view
|
||||||
(letsubs [outer-scale (anim/interpolate visual-target-value {:inputRange [total-silence-db silence-db 0]
|
[{:keys [rec-button-anim-value state] :as params}]
|
||||||
:outputRange [1 0.8 1.2]})
|
(letsubs [outer-scale (anim/interpolate visual-target-value
|
||||||
inner-scale (anim/interpolate rec-button-anim-value {:inputRange [0 1]
|
{:inputRange [total-silence-db silence-db 0]
|
||||||
:outputRange [1 0.5]})
|
:outputRange [1 0.8 1.2]})
|
||||||
inner-border-radius (anim/interpolate rec-button-anim-value {:inputRange [0 1]
|
inner-scale (anim/interpolate rec-button-anim-value
|
||||||
:outputRange [styles/rec-button-base-size 16]})]
|
{:inputRange [0 1]
|
||||||
[react/touchable-highlight {:on-press #(if (= (:general @state) :recording)
|
:outputRange [1 0.5]})
|
||||||
(pause-recording params)
|
inner-border-radius (anim/interpolate rec-button-anim-value
|
||||||
(start-recording params))
|
{:inputRange [0 1]
|
||||||
:accessibility-label :start-stop-audio-recording-button}
|
:outputRange [styles/rec-button-base-size 16]})]
|
||||||
|
[react/touchable-highlight
|
||||||
|
{:on-press #(if (= (:general @state) :recording)
|
||||||
|
(pause-recording params)
|
||||||
|
(start-recording params))
|
||||||
|
:accessibility-label :start-stop-audio-recording-button}
|
||||||
[react/view {:style styles/rec-button-container}
|
[react/view {:style styles/rec-button-container}
|
||||||
[react/animated-view {:style (styles/rec-outer-circle outer-scale)}]
|
[react/animated-view {:style (styles/rec-outer-circle outer-scale)}]
|
||||||
[react/animated-view {:style (styles/rec-inner-circle inner-scale inner-border-radius)}]]]))
|
[react/animated-view {:style (styles/rec-inner-circle inner-scale inner-border-radius)}]]]))
|
||||||
|
|
||||||
(defn- cancel-button [disabled? on-press contact-request]
|
(defn- cancel-button
|
||||||
[pressable/pressable {:type :scale
|
[disabled? on-press contact-request]
|
||||||
:disabled disabled?
|
[pressable/pressable
|
||||||
:on-press on-press}
|
{:type :scale
|
||||||
|
:disabled disabled?
|
||||||
|
:on-press on-press}
|
||||||
[react/view {:style (input.style/send-message-button)}
|
[react/view {:style (input.style/send-message-button)}
|
||||||
[icons/icon :main-icons/close
|
[icons/icon :main-icons/close
|
||||||
{:container-style (merge (input.style/send-message-container contact-request) {:background-color colors/gray})
|
{:container-style (merge (input.style/send-message-container contact-request)
|
||||||
|
{:background-color colors/gray})
|
||||||
:accessibility-label :cancel-message-button
|
:accessibility-label :cancel-message-button
|
||||||
:color colors/white-persist}]]])
|
:color colors/white-persist}]]])
|
||||||
|
|
||||||
(defview audio-message-view []
|
(defview audio-message-view
|
||||||
(letsubs [rec-button-anim-value (anim/create-value 0)
|
[]
|
||||||
|
(letsubs [rec-button-anim-value (anim/create-value 0)
|
||||||
ctrl-buttons-anim-value (anim/create-value 0)
|
ctrl-buttons-anim-value (anim/create-value 0)
|
||||||
timer (reagent/atom "")
|
timer (reagent/atom "")
|
||||||
state (reagent/atom nil)]
|
state (reagent/atom nil)]
|
||||||
{:component-did-mount (fn []
|
{:component-did-mount (fn []
|
||||||
(reset-timer timer)
|
(reset-timer timer)
|
||||||
(reset! state-cb #(update-state state))
|
(reset! state-cb #(update-state state))
|
||||||
(reset! max-recording-reached-cb #(do
|
(reset! max-recording-reached-cb
|
||||||
(when (= (:general @state) :recording)
|
#(do
|
||||||
(stop-recording {:rec-button-anim-value rec-button-anim-value
|
(when (= (:general @state) :recording)
|
||||||
:ctrl-buttons-anim-value ctrl-buttons-anim-value
|
(stop-recording {:rec-button-anim-value rec-button-anim-value
|
||||||
:timer timer
|
:ctrl-buttons-anim-value ctrl-buttons-anim-value
|
||||||
:max-recording-reached? true}))
|
:timer timer
|
||||||
(utils.utils/show-popup (i18n/label :t/audio-recorder)
|
:max-recording-reached? true}))
|
||||||
(i18n/label :t/audio-recorder-max-ms-reached))))
|
(utils.utils/show-popup (i18n/label :t/audio-recorder)
|
||||||
(reset! on-background-cb #(when (= (:general @state) :recording)
|
(i18n/label
|
||||||
(pause-recording {:rec-button-anim-value rec-button-anim-value
|
:t/audio-recorder-max-ms-reached))))
|
||||||
:ctrl-buttons-anim-value ctrl-buttons-anim-value
|
(reset! on-background-cb #(when (= (:general @state) :recording)
|
||||||
:timer timer})))
|
(pause-recording
|
||||||
(reload-recorder))
|
{:rec-button-anim-value rec-button-anim-value
|
||||||
|
:ctrl-buttons-anim-value
|
||||||
|
ctrl-buttons-anim-value
|
||||||
|
:timer timer})))
|
||||||
|
(reload-recorder))
|
||||||
:component-will-unmount (fn []
|
:component-will-unmount (fn []
|
||||||
(when @recording-timer
|
(when @recording-timer
|
||||||
(utils.utils/clear-interval @recording-timer)
|
(utils.utils/clear-interval @recording-timer)
|
||||||
@@ -268,26 +295,29 @@
|
|||||||
(reset! state-cb nil)
|
(reset! state-cb nil)
|
||||||
(reset! max-recording-reached-cb nil)
|
(reset! max-recording-reached-cb nil)
|
||||||
(reset! on-background-cb nil))}
|
(reset! on-background-cb nil))}
|
||||||
(let [base-params {:rec-button-anim-value rec-button-anim-value
|
(let [base-params {:rec-button-anim-value rec-button-anim-value
|
||||||
:ctrl-buttons-anim-value ctrl-buttons-anim-value
|
:ctrl-buttons-anim-value ctrl-buttons-anim-value
|
||||||
:timer timer}
|
:timer timer}
|
||||||
contact-request @(re-frame/subscribe [:chats/sending-contact-request])]
|
contact-request @(re-frame/subscribe [:chats/sending-contact-request])]
|
||||||
[react/view {:style styles/container}
|
[react/view {:style styles/container}
|
||||||
[react/text {:style styles/timer
|
[react/text
|
||||||
:accessibility-label :audio-message-recorded-time} @timer]
|
{:style styles/timer
|
||||||
|
:accessibility-label :audio-message-recorded-time} @timer]
|
||||||
[react/view {:style styles/buttons-container}
|
[react/view {:style styles/buttons-container}
|
||||||
[react/animated-view {:style {:opacity ctrl-buttons-anim-value}}
|
[react/animated-view {:style {:opacity ctrl-buttons-anim-value}}
|
||||||
[cancel-button (:cancel-disabled? @state) #(stop-recording base-params) contact-request]]
|
[cancel-button (:cancel-disabled? @state) #(stop-recording base-params) contact-request]]
|
||||||
[rec-button-view (merge base-params {:state state})]
|
[rec-button-view (merge base-params {:state state})]
|
||||||
[react/animated-view {:style {:opacity ctrl-buttons-anim-value}}
|
[react/animated-view {:style {:opacity ctrl-buttons-anim-value}}
|
||||||
[input/send-button (fn [] (cond
|
[input/send-button
|
||||||
(= :ready-to-send (:general @state))
|
(fn []
|
||||||
(do
|
(cond
|
||||||
(reset-timer timer)
|
(= :ready-to-send (:general @state))
|
||||||
(animate-buttons false false base-params)
|
(do
|
||||||
(send-audio-msessage state))
|
(reset-timer timer)
|
||||||
|
(animate-buttons false false base-params)
|
||||||
|
(send-audio-msessage state))
|
||||||
|
|
||||||
(#{:recording :recording-paused} (:general @state))
|
(#{:recording :recording-paused} (:general @state))
|
||||||
(stop-recording (merge base-params
|
(stop-recording (merge base-params
|
||||||
{:on-success
|
{:on-success
|
||||||
#(send-audio-msessage state)}))))]]]])))
|
#(send-audio-msessage state)}))))]]]])))
|
||||||
|
|||||||
@@ -1,47 +1,54 @@
|
|||||||
(ns status-im.ui.screens.chat.components.input
|
(ns status-im.ui.screens.chat.components.input
|
||||||
(:require [status-im.ui.components.icons.icons :as icons]
|
(:require [clojure.string :as string]
|
||||||
[quo.react-native :as rn]
|
[quo.components.animated.pressable :as pressable]
|
||||||
[quo.react :as quo.react]
|
[quo.components.list.item :as list-item]
|
||||||
[quo.platform :as platform]
|
|
||||||
[quo.components.text :as text]
|
[quo.components.text :as text]
|
||||||
[quo.design-system.colors :as colors]
|
[quo.design-system.colors :as colors]
|
||||||
[status-im.ui.screens.chat.components.style :as styles]
|
[quo.platform :as platform]
|
||||||
[status-im.utils.fx :as fx]
|
[quo.react :as quo.react]
|
||||||
[status-im.ui.screens.chat.components.reply :as reply]
|
[quo.react-native :as rn]
|
||||||
[status-im.multiaccounts.core :as multiaccounts]
|
|
||||||
[status-im.chat.constants :as chat.constants]
|
|
||||||
[status-im.utils.utils :as utils.utils]
|
|
||||||
[quo.components.animated.pressable :as pressable]
|
|
||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
[status-im.i18n.i18n :as i18n]
|
|
||||||
[status-im.chat.models.mentions :as mentions]
|
|
||||||
[status-im.ui.components.list.views :as list]
|
|
||||||
[quo.components.list.item :as list-item]
|
|
||||||
[status-im.ui.screens.chat.photos :as photos]
|
|
||||||
[reagent.core :as reagent]
|
[reagent.core :as reagent]
|
||||||
[clojure.string :as string]))
|
[status-im.chat.constants :as chat.constants]
|
||||||
|
[status-im.chat.models.mentions :as mentions]
|
||||||
|
[status-im.i18n.i18n :as i18n]
|
||||||
|
[status-im.multiaccounts.core :as multiaccounts]
|
||||||
|
[status-im.ui.components.icons.icons :as icons]
|
||||||
|
[status-im.ui.components.list.views :as list]
|
||||||
|
[status-im.ui.screens.chat.components.reply :as reply]
|
||||||
|
[status-im.ui.screens.chat.components.style :as styles]
|
||||||
|
[status-im.ui.screens.chat.photos :as photos]
|
||||||
|
[status-im.utils.utils :as utils.utils]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(defn input-focus [text-input-ref]
|
(defn input-focus
|
||||||
(some-> ^js (quo.react/current-ref text-input-ref) .focus))
|
[text-input-ref]
|
||||||
|
(some-> ^js (quo.react/current-ref text-input-ref)
|
||||||
|
.focus))
|
||||||
|
|
||||||
(def panel->icons {:extensions :main-icons/commands
|
(def panel->icons
|
||||||
:images :main-icons/photo})
|
{:extensions :main-icons/commands
|
||||||
|
:images :main-icons/photo})
|
||||||
|
|
||||||
(defn touchable-icon [{:keys [panel active set-active accessibility-label]}]
|
(defn touchable-icon
|
||||||
[pressable/pressable {:type :scale
|
[{:keys [panel active set-active accessibility-label]}]
|
||||||
:accessibility-label accessibility-label
|
[pressable/pressable
|
||||||
:on-press #(set-active (when-not (= active panel) panel))}
|
{:type :scale
|
||||||
|
:accessibility-label accessibility-label
|
||||||
|
:on-press #(set-active (when-not (= active panel) panel))}
|
||||||
[rn/view {:style (styles/touchable-icon)}
|
[rn/view {:style (styles/touchable-icon)}
|
||||||
[icons/icon
|
[icons/icon
|
||||||
(panel->icons panel)
|
(panel->icons panel)
|
||||||
(styles/icon (= active panel))]]])
|
(styles/icon (= active panel))]]])
|
||||||
|
|
||||||
(defn touchable-stickers-icon [{:keys [panel active set-active accessibility-label input-focus]}]
|
(defn touchable-stickers-icon
|
||||||
[pressable/pressable {:type :scale
|
[{:keys [panel active set-active accessibility-label input-focus]}]
|
||||||
:accessibility-label accessibility-label
|
[pressable/pressable
|
||||||
:on-press #(if (= active panel)
|
{:type :scale
|
||||||
(input-focus)
|
:accessibility-label accessibility-label
|
||||||
(set-active panel))}
|
:on-press #(if (= active panel)
|
||||||
|
(input-focus)
|
||||||
|
(set-active panel))}
|
||||||
[rn/view {:style (styles/in-input-touchable-icon)}
|
[rn/view {:style (styles/in-input-touchable-icon)}
|
||||||
(if (= active panel)
|
(if (= active panel)
|
||||||
[icons/icon :main-icons/keyboard (styles/icon false)]
|
[icons/icon :main-icons/keyboard (styles/icon false)]
|
||||||
@@ -49,7 +56,8 @@
|
|||||||
|
|
||||||
;; TODO(Ferossgp): Move this into audio panel.
|
;; TODO(Ferossgp): Move this into audio panel.
|
||||||
;; Instead of not changing panel we can show a placeholder with no permission
|
;; Instead of not changing panel we can show a placeholder with no permission
|
||||||
(defn- request-record-audio-permission [set-active panel]
|
(defn- request-record-audio-permission
|
||||||
|
[set-active panel]
|
||||||
(re-frame/dispatch
|
(re-frame/dispatch
|
||||||
[:request-permissions
|
[:request-permissions
|
||||||
{:permissions [:record-audio]
|
{:permissions [:record-audio]
|
||||||
@@ -63,18 +71,21 @@
|
|||||||
(i18n/label :t/audio-recorder-permissions-error)))
|
(i18n/label :t/audio-recorder-permissions-error)))
|
||||||
50)}]))
|
50)}]))
|
||||||
|
|
||||||
(defn touchable-audio-icon [{:keys [panel active set-active accessibility-label input-focus]}]
|
(defn touchable-audio-icon
|
||||||
[pressable/pressable {:type :scale
|
[{:keys [panel active set-active accessibility-label input-focus]}]
|
||||||
:accessibility-label accessibility-label
|
[pressable/pressable
|
||||||
:on-press #(if (= active panel)
|
{:type :scale
|
||||||
(input-focus)
|
:accessibility-label accessibility-label
|
||||||
(request-record-audio-permission set-active panel))}
|
:on-press #(if (= active panel)
|
||||||
|
(input-focus)
|
||||||
|
(request-record-audio-permission set-active panel))}
|
||||||
[rn/view {:style (styles/in-input-touchable-icon)}
|
[rn/view {:style (styles/in-input-touchable-icon)}
|
||||||
(if (= active panel)
|
(if (= active panel)
|
||||||
[icons/icon :main-icons/keyboard (styles/icon false)]
|
[icons/icon :main-icons/keyboard (styles/icon false)]
|
||||||
[icons/icon :main-icons/speech (styles/icon false)])]])
|
[icons/icon :main-icons/speech (styles/icon false)])]])
|
||||||
|
|
||||||
(defn send-button [on-send contact-request]
|
(defn send-button
|
||||||
|
[on-send contact-request]
|
||||||
[rn/touchable-opacity {:on-press-in on-send}
|
[rn/touchable-opacity {:on-press-in on-send}
|
||||||
[rn/view {:style (styles/send-message-button)}
|
[rn/view {:style (styles/send-message-button)}
|
||||||
(when-not contact-request
|
(when-not contact-request
|
||||||
@@ -83,22 +94,23 @@
|
|||||||
:accessibility-label :send-message-button
|
:accessibility-label :send-message-button
|
||||||
:color (styles/send-icon-color)}])]])
|
:color (styles/send-icon-color)}])]])
|
||||||
|
|
||||||
(defn on-selection-change [timeout-id last-text-change mentionable-users args]
|
(defn on-selection-change
|
||||||
|
[timeout-id last-text-change mentionable-users args]
|
||||||
(let [selection (.-selection ^js (.-nativeEvent ^js args))
|
(let [selection (.-selection ^js (.-nativeEvent ^js args))
|
||||||
start (.-start selection)
|
start (.-start selection)
|
||||||
end (.-end selection)]
|
end (.-end selection)]
|
||||||
;; NOTE(rasom): on iOS we do not dispatch this event immediately
|
;; NOTE(rasom): on iOS we do not dispatch this event immediately
|
||||||
;; because it is needed only in case if selection is changed without
|
;; because it is needed only in case if selection is changed without
|
||||||
;; typing. Timeout might be canceled on `on-change`.
|
;; typing. Timeout might be canceled on `on-change`.
|
||||||
(when platform/ios?
|
(when platform/ios?
|
||||||
(reset!
|
(reset!
|
||||||
timeout-id
|
timeout-id
|
||||||
(utils.utils/set-timeout
|
(utils.utils/set-timeout
|
||||||
#(re-frame/dispatch [::mentions/on-selection-change
|
#(re-frame/dispatch [::mentions/on-selection-change
|
||||||
{:start start
|
{:start start
|
||||||
:end end}
|
:end end}
|
||||||
mentionable-users])
|
mentionable-users])
|
||||||
50)))
|
50)))
|
||||||
;; NOTE(rasom): on Android we dispatch event only in case if there
|
;; NOTE(rasom): on Android we dispatch event only in case if there
|
||||||
;; was no text changes during last 50ms. `on-selection-change` is
|
;; was no text changes during last 50ms. `on-selection-change` is
|
||||||
;; dispatched after `on-change`, that's why there is no another way
|
;; dispatched after `on-change`, that's why there is no another way
|
||||||
@@ -128,42 +140,51 @@
|
|||||||
[]
|
[]
|
||||||
(swap! chat-input-key inc))
|
(swap! chat-input-key inc))
|
||||||
|
|
||||||
(defn show-send [{:keys [actions-ref send-ref sticker-ref]}]
|
(defn show-send
|
||||||
|
[{:keys [actions-ref send-ref sticker-ref]}]
|
||||||
(when actions-ref
|
(when actions-ref
|
||||||
(quo.react/set-native-props actions-ref #js {:width 0 :left -88}))
|
(quo.react/set-native-props actions-ref #js {:width 0 :left -88}))
|
||||||
(quo.react/set-native-props send-ref #js {:width nil :right nil})
|
(quo.react/set-native-props send-ref #js {:width nil :right nil})
|
||||||
(when sticker-ref
|
(when sticker-ref
|
||||||
(quo.react/set-native-props sticker-ref #js {:width 0 :right -100})))
|
(quo.react/set-native-props sticker-ref #js {:width 0 :right -100})))
|
||||||
|
|
||||||
(defn hide-send [{:keys [actions-ref send-ref sticker-ref]}]
|
(defn hide-send
|
||||||
|
[{:keys [actions-ref send-ref sticker-ref]}]
|
||||||
(when actions-ref
|
(when actions-ref
|
||||||
(quo.react/set-native-props actions-ref #js {:width nil :left nil}))
|
(quo.react/set-native-props actions-ref #js {:width nil :left nil}))
|
||||||
(quo.react/set-native-props send-ref #js {:width 0 :right -100})
|
(quo.react/set-native-props send-ref #js {:width 0 :right -100})
|
||||||
(when sticker-ref
|
(when sticker-ref
|
||||||
(quo.react/set-native-props sticker-ref #js {:width nil :right nil})))
|
(quo.react/set-native-props sticker-ref #js {:width nil :right nil})))
|
||||||
|
|
||||||
(defn reset-input [refs chat-id]
|
(defn reset-input
|
||||||
(some-> ^js (quo.react/current-ref (:text-input-ref refs)) .clear)
|
[refs chat-id]
|
||||||
|
(some-> ^js (quo.react/current-ref (:text-input-ref refs))
|
||||||
|
.clear)
|
||||||
(swap! mentions-enabled update :render not)
|
(swap! mentions-enabled update :render not)
|
||||||
(swap! input-texts dissoc chat-id))
|
(swap! input-texts dissoc chat-id))
|
||||||
|
|
||||||
(defn clear-input [chat-id refs]
|
(defn clear-input
|
||||||
|
[chat-id refs]
|
||||||
(hide-send refs)
|
(hide-send refs)
|
||||||
(if (get @mentions-enabled chat-id)
|
(if (get @mentions-enabled chat-id)
|
||||||
(do
|
(do
|
||||||
(swap! mentions-enabled dissoc chat-id)
|
(swap! mentions-enabled dissoc chat-id)
|
||||||
;;we need this timeout, because if we clear text input and first index was a mention object with blue color,
|
;;we need this timeout, because if we clear text input and first index was a mention object with
|
||||||
;;after clearing text will be typed with this blue color, so we render white text first and then clear it
|
;;blue color,
|
||||||
|
;;after clearing text will be typed with this blue color, so we render white text first and then
|
||||||
|
;;clear it
|
||||||
(js/setTimeout #(reset-input refs chat-id) 50))
|
(js/setTimeout #(reset-input refs chat-id) 50))
|
||||||
(reset-input refs chat-id)))
|
(reset-input refs chat-id)))
|
||||||
|
|
||||||
(defn on-text-change [val chat-id]
|
(defn on-text-change
|
||||||
|
[val chat-id]
|
||||||
(swap! input-texts assoc chat-id val)
|
(swap! input-texts assoc chat-id val)
|
||||||
;;we still store it in app-db for mentions, we don't have reactions in views
|
;;we still store it in app-db for mentions, we don't have reactions in views
|
||||||
(re-frame/dispatch [:chat.ui/set-chat-input-text val]))
|
(re-frame/dispatch [:chat.ui/set-chat-input-text val]))
|
||||||
|
|
||||||
(defn on-change [last-text-change timeout-id mentionable-users refs chat-id sending-image args]
|
(defn on-change
|
||||||
(let [text (.-text ^js (.-nativeEvent ^js args))
|
[last-text-change timeout-id mentionable-users refs chat-id sending-image args]
|
||||||
|
(let [text (.-text ^js (.-nativeEvent ^js args))
|
||||||
prev-text (get @input-texts chat-id)]
|
prev-text (get @input-texts chat-id)]
|
||||||
(when (and (seq prev-text) (empty? text) (not sending-image))
|
(when (and (seq prev-text) (empty? text) (not sending-image))
|
||||||
(hide-send refs))
|
(hide-send refs))
|
||||||
@@ -187,7 +208,7 @@
|
|||||||
(when platform/ios?
|
(when platform/ios?
|
||||||
(re-frame/dispatch [::mentions/calculate-suggestions mentionable-users]))))
|
(re-frame/dispatch [::mentions/calculate-suggestions mentionable-users]))))
|
||||||
|
|
||||||
(fx/defn set-input-text
|
(rf/defn set-input-text
|
||||||
"Set input text for current-chat. Takes db and input text and cofx
|
"Set input text for current-chat. Takes db and input text and cofx
|
||||||
as arguments and returns new fx. Always clear all validation messages."
|
as arguments and returns new fx. Always clear all validation messages."
|
||||||
{:events [:chat.ui.input/set-chat-input-text]}
|
{:events [:chat.ui.input/set-chat-input-text]}
|
||||||
@@ -197,15 +218,21 @@
|
|||||||
chat (get-in db [:chats chat-id])
|
chat (get-in db [:chats chat-id])
|
||||||
current-multiaccount (:multiaccount db)
|
current-multiaccount (:multiaccount db)
|
||||||
mentionable-users (mentions/get-mentionable-users
|
mentionable-users (mentions/get-mentionable-users
|
||||||
chat all-contacts current-multiaccount nil)
|
chat
|
||||||
|
all-contacts
|
||||||
|
current-multiaccount
|
||||||
|
nil)
|
||||||
hydrated-mentions (map
|
hydrated-mentions (map
|
||||||
(fn [[t mention :as e]]
|
(fn [[t mention :as e]]
|
||||||
(if (= t :mention)
|
(if (= t :mention)
|
||||||
(let [mention (multiaccounts/displayed-name
|
(let [mention (multiaccounts/displayed-name
|
||||||
(get mentionable-users mention))]
|
(get mentionable-users mention))]
|
||||||
[:mention (if (string/starts-with? mention "@")
|
[:mention
|
||||||
mention (str "@" mention))])
|
(if (string/starts-with? mention "@")
|
||||||
e)) text-with-mentions)
|
mention
|
||||||
|
(str "@" mention))])
|
||||||
|
e))
|
||||||
|
text-with-mentions)
|
||||||
info (mentions/->info hydrated-mentions)
|
info (mentions/->info hydrated-mentions)
|
||||||
new-text (string/join (map second hydrated-mentions))]
|
new-text (string/join (map second hydrated-mentions))]
|
||||||
{:set-text-input-value [chat-id new-text]
|
{:set-text-input-value [chat-id new-text]
|
||||||
@@ -215,13 +242,14 @@
|
|||||||
(assoc-in [:chat/inputs-with-mentions chat-id] hydrated-mentions)
|
(assoc-in [:chat/inputs-with-mentions chat-id] hydrated-mentions)
|
||||||
(assoc-in [:chats/mentions chat-id :mentions] info))}))
|
(assoc-in [:chats/mentions chat-id :mentions] info))}))
|
||||||
|
|
||||||
(defn on-text-input [mentionable-users chat-id args]
|
(defn on-text-input
|
||||||
(let [native-event (.-nativeEvent ^js args)
|
[mentionable-users chat-id args]
|
||||||
text (.-text ^js native-event)
|
(let [native-event (.-nativeEvent ^js args)
|
||||||
|
text (.-text ^js native-event)
|
||||||
previous-text (.-previousText ^js native-event)
|
previous-text (.-previousText ^js native-event)
|
||||||
range (.-range ^js native-event)
|
range (.-range ^js native-event)
|
||||||
start (.-start ^js range)
|
start (.-start ^js range)
|
||||||
end (.-end ^js range)]
|
end (.-end ^js range)]
|
||||||
(when (and (not (get @mentions-enabled chat-id)) (string/index-of text "@"))
|
(when (and (not (get @mentions-enabled chat-id)) (string/index-of text "@"))
|
||||||
(swap! mentions-enabled assoc chat-id true))
|
(swap! mentions-enabled assoc chat-id true))
|
||||||
|
|
||||||
@@ -237,13 +265,14 @@
|
|||||||
(when platform/android?
|
(when platform/android?
|
||||||
(re-frame/dispatch [::mentions/calculate-suggestions mentionable-users]))))
|
(re-frame/dispatch [::mentions/calculate-suggestions mentionable-users]))))
|
||||||
|
|
||||||
(defn text-input [{:keys [set-active-panel refs chat-id sending-image]}]
|
(defn text-input
|
||||||
|
[{:keys [set-active-panel refs chat-id sending-image]}]
|
||||||
(let [cooldown-enabled? @(re-frame/subscribe [:chats/current-chat-cooldown-enabled?])
|
(let [cooldown-enabled? @(re-frame/subscribe [:chats/current-chat-cooldown-enabled?])
|
||||||
mentionable-users @(re-frame/subscribe [:chats/mentionable-users])
|
mentionable-users @(re-frame/subscribe [:chats/mentionable-users])
|
||||||
timeout-id (atom nil)
|
timeout-id (atom nil)
|
||||||
last-text-change (atom nil)
|
last-text-change (atom nil)
|
||||||
mentions-enabled (get @mentions-enabled chat-id)
|
mentions-enabled (get @mentions-enabled chat-id)
|
||||||
contact-request @(re-frame/subscribe [:chats/sending-contact-request])]
|
contact-request @(re-frame/subscribe [:chats/sending-contact-request])]
|
||||||
|
|
||||||
[rn/text-input
|
[rn/text-input
|
||||||
{:style (styles/text-input contact-request)
|
{:style (styles/text-input contact-request)
|
||||||
@@ -263,8 +292,12 @@
|
|||||||
(i18n/label :t/type-a-message))
|
(i18n/label :t/type-a-message))
|
||||||
:underline-color-android :transparent
|
:underline-color-android :transparent
|
||||||
:auto-capitalize :sentences
|
:auto-capitalize :sentences
|
||||||
:on-selection-change (partial on-selection-change timeout-id last-text-change mentionable-users)
|
:on-selection-change (partial on-selection-change
|
||||||
:on-change (partial on-change last-text-change timeout-id mentionable-users refs chat-id sending-image)
|
timeout-id
|
||||||
|
last-text-change
|
||||||
|
mentionable-users)
|
||||||
|
:on-change
|
||||||
|
(partial on-change last-text-change timeout-id mentionable-users refs chat-id sending-image)
|
||||||
:on-text-input (partial on-text-input mentionable-users chat-id)}
|
:on-text-input (partial on-text-input mentionable-users chat-id)}
|
||||||
(if mentions-enabled
|
(if mentions-enabled
|
||||||
(for [[idx [type text]] (map-indexed
|
(for [[idx [type text]] (map-indexed
|
||||||
@@ -280,39 +313,41 @@
|
|||||||
[[public-key {:keys [alias name nickname] :as user}] _ _ text-input-ref]
|
[[public-key {:keys [alias name nickname] :as user}] _ _ text-input-ref]
|
||||||
(let [ens-name? (not= alias name)]
|
(let [ens-name? (not= alias name)]
|
||||||
[list-item/list-item
|
[list-item/list-item
|
||||||
(cond-> {:icon [photos/member-photo public-key]
|
(cond->
|
||||||
:size :small
|
{:icon [photos/member-photo public-key]
|
||||||
:text-size :small
|
:size :small
|
||||||
:title
|
:text-size :small
|
||||||
[text/text
|
:title
|
||||||
{:weight :medium
|
[text/text
|
||||||
:ellipsize-mode :tail
|
{:weight :medium
|
||||||
:number-of-lines 1
|
:ellipsize-mode :tail
|
||||||
:size :small}
|
:number-of-lines 1
|
||||||
(if nickname
|
:size :small}
|
||||||
nickname
|
(if nickname
|
||||||
name)
|
nickname
|
||||||
(when nickname
|
name)
|
||||||
[text/text
|
(when nickname
|
||||||
{:weight :regular
|
[text/text
|
||||||
:color :secondary
|
{:weight :regular
|
||||||
:ellipsize-mode :tail
|
:color :secondary
|
||||||
:size :small}
|
:ellipsize-mode :tail
|
||||||
" "
|
:size :small}
|
||||||
(when ens-name?
|
" "
|
||||||
"@")
|
(when ens-name?
|
||||||
name])]
|
"@")
|
||||||
:title-text-weight :medium
|
name])]
|
||||||
:on-press
|
:title-text-weight :medium
|
||||||
(fn []
|
:on-press
|
||||||
(re-frame/dispatch [:chat.ui/select-mention text-input-ref user]))}
|
(fn []
|
||||||
|
(re-frame/dispatch [:chat.ui/select-mention text-input-ref user]))}
|
||||||
|
|
||||||
ens-name?
|
ens-name?
|
||||||
(assoc :subtitle alias))]))
|
(assoc :subtitle alias))]))
|
||||||
|
|
||||||
(def chat-toolbar-height (reagent/atom nil))
|
(def chat-toolbar-height (reagent/atom nil))
|
||||||
|
|
||||||
(defn autocomplete-mentions [text-input-ref bottom]
|
(defn autocomplete-mentions
|
||||||
|
[text-input-ref bottom]
|
||||||
(let [suggestions @(re-frame/subscribe [:chat/mention-suggestions])]
|
(let [suggestions @(re-frame/subscribe [:chat/mention-suggestions])]
|
||||||
(when (seq suggestions)
|
(when (seq suggestions)
|
||||||
(let [height (+ 16 (* 52 (min 4.5 (count suggestions))))]
|
(let [height (+ 16 (* 52 (min 4.5 (count suggestions))))]
|
||||||
@@ -330,36 +365,44 @@
|
|||||||
:render-data text-input-ref
|
:render-data text-input-ref
|
||||||
:render-fn mention-item}]]]))))
|
:render-fn mention-item}]]]))))
|
||||||
|
|
||||||
(defn on-chat-toolbar-layout [^js ev]
|
(defn on-chat-toolbar-layout
|
||||||
|
[^js ev]
|
||||||
(reset! chat-toolbar-height (-> ev .-nativeEvent .-layout .-height)))
|
(reset! chat-toolbar-height (-> ev .-nativeEvent .-layout .-height)))
|
||||||
|
|
||||||
(defn send-image []
|
(defn send-image
|
||||||
|
[]
|
||||||
(let [sending-image @(re-frame/subscribe [:chats/sending-image])]
|
(let [sending-image @(re-frame/subscribe [:chats/sending-image])]
|
||||||
(when (seq sending-image)
|
(when (seq sending-image)
|
||||||
[reply/send-image sending-image])))
|
[reply/send-image sending-image])))
|
||||||
|
|
||||||
(defn actions [extensions image show-send actions-ref active-panel set-active-panel contact-request]
|
(defn actions
|
||||||
[rn/view {:style (styles/actions-wrapper (and (not contact-request) show-send))
|
[extensions image show-send actions-ref active-panel set-active-panel contact-request]
|
||||||
:ref actions-ref}
|
[rn/view
|
||||||
|
{:style (styles/actions-wrapper (and (not contact-request) show-send))
|
||||||
|
:ref actions-ref}
|
||||||
(when extensions
|
(when extensions
|
||||||
[touchable-icon {:panel :extensions
|
[touchable-icon
|
||||||
:accessibility-label :show-extensions-icon
|
{:panel :extensions
|
||||||
:active active-panel
|
:accessibility-label :show-extensions-icon
|
||||||
:set-active set-active-panel}])
|
:active active-panel
|
||||||
|
:set-active set-active-panel}])
|
||||||
(when image
|
(when image
|
||||||
[touchable-icon {:panel :images
|
[touchable-icon
|
||||||
:accessibility-label :show-photo-icon
|
{:panel :images
|
||||||
:active active-panel
|
:accessibility-label :show-photo-icon
|
||||||
:set-active set-active-panel}])])
|
:active active-panel
|
||||||
|
:set-active set-active-panel}])])
|
||||||
|
|
||||||
(defn chat-toolbar [{:keys [chat-id]}]
|
(defn chat-toolbar
|
||||||
(let [actions-ref (quo.react/create-ref)
|
[{:keys [chat-id]}]
|
||||||
send-ref (quo.react/create-ref)
|
(let [actions-ref (quo.react/create-ref)
|
||||||
sticker-ref (quo.react/create-ref)
|
send-ref (quo.react/create-ref)
|
||||||
|
sticker-ref (quo.react/create-ref)
|
||||||
toolbar-options (re-frame/subscribe [:chats/chat-toolbar])
|
toolbar-options (re-frame/subscribe [:chats/chat-toolbar])
|
||||||
show-send (seq (get @input-texts chat-id))]
|
show-send (seq (get @input-texts chat-id))]
|
||||||
(fn [{:keys [active-panel set-active-panel text-input-ref chat-id]}]
|
(fn [{:keys [active-panel set-active-panel text-input-ref chat-id]}]
|
||||||
(let [;we want to control components on native level, so instead of RN state we set native props via reference
|
(let [;we want to control components on native level, so instead of RN state we set native props
|
||||||
|
;via reference
|
||||||
;we don't react on input text in this view, @input-texts below is a regular atom
|
;we don't react on input text in this view, @input-texts below is a regular atom
|
||||||
refs {:actions-ref actions-ref
|
refs {:actions-ref actions-ref
|
||||||
:send-ref send-ref
|
:send-ref send-ref
|
||||||
@@ -368,37 +411,43 @@
|
|||||||
{:keys [send stickers image extensions audio sending-image]} @toolbar-options
|
{:keys [send stickers image extensions audio sending-image]} @toolbar-options
|
||||||
show-send (or show-send sending-image)
|
show-send (or show-send sending-image)
|
||||||
contact-request @(re-frame/subscribe [:chats/sending-contact-request])]
|
contact-request @(re-frame/subscribe [:chats/sending-contact-request])]
|
||||||
[rn/view {:style (styles/toolbar)
|
[rn/view
|
||||||
:on-layout on-chat-toolbar-layout}
|
{:style (styles/toolbar)
|
||||||
|
:on-layout on-chat-toolbar-layout}
|
||||||
;; EXTENSIONS and IMAGE buttons
|
;; EXTENSIONS and IMAGE buttons
|
||||||
[actions extensions image show-send actions-ref active-panel set-active-panel contact-request]
|
[actions extensions image show-send actions-ref active-panel set-active-panel contact-request]
|
||||||
[rn/view {:style (styles/input-container contact-request)}
|
[rn/view {:style (styles/input-container contact-request)}
|
||||||
[send-image]
|
[send-image]
|
||||||
[rn/view {:style styles/input-row}
|
[rn/view {:style styles/input-row}
|
||||||
[text-input {:chat-id chat-id
|
[text-input
|
||||||
:sending-image sending-image
|
{:chat-id chat-id
|
||||||
:refs refs
|
:sending-image sending-image
|
||||||
:set-active-panel set-active-panel}]
|
:refs refs
|
||||||
|
:set-active-panel set-active-panel}]
|
||||||
;; SEND button
|
;; SEND button
|
||||||
[rn/view {:ref send-ref :style (when-not show-send {:width 0 :right -100})}
|
[rn/view {:ref send-ref :style (when-not show-send {:width 0 :right -100})}
|
||||||
(when send
|
(when send
|
||||||
[send-button #(do (clear-input chat-id refs)
|
[send-button
|
||||||
(re-frame/dispatch [:chat.ui/send-current-message]))
|
#(do (clear-input chat-id refs)
|
||||||
|
(re-frame/dispatch [:chat.ui/send-current-message]))
|
||||||
contact-request])]
|
contact-request])]
|
||||||
|
|
||||||
;; STICKERS and AUDIO buttons
|
;; STICKERS and AUDIO buttons
|
||||||
(when-not @(re-frame/subscribe [:chats/edit-message])
|
(when-not @(re-frame/subscribe [:chats/edit-message])
|
||||||
[rn/view {:style (merge {:flex-direction :row} (when show-send {:width 0 :right -100}))
|
[rn/view
|
||||||
:ref sticker-ref}
|
{:style (merge {:flex-direction :row} (when show-send {:width 0 :right -100}))
|
||||||
|
:ref sticker-ref}
|
||||||
(when stickers
|
(when stickers
|
||||||
[touchable-stickers-icon {:panel :stickers
|
[touchable-stickers-icon
|
||||||
:accessibility-label :show-stickers-icon
|
{:panel :stickers
|
||||||
:active active-panel
|
:accessibility-label :show-stickers-icon
|
||||||
:input-focus #(input-focus text-input-ref)
|
:active active-panel
|
||||||
:set-active set-active-panel}])
|
:input-focus #(input-focus text-input-ref)
|
||||||
|
:set-active set-active-panel}])
|
||||||
(when audio
|
(when audio
|
||||||
[touchable-audio-icon {:panel :audio
|
[touchable-audio-icon
|
||||||
:accessibility-label :show-audio-message-icon
|
{:panel :audio
|
||||||
:active active-panel
|
:accessibility-label :show-audio-message-icon
|
||||||
:input-focus #(input-focus text-input-ref)
|
:active active-panel
|
||||||
:set-active set-active-panel}])])]]]))))
|
:input-focus #(input-focus text-input-ref)
|
||||||
|
:set-active set-active-panel}])])]]]))))
|
||||||
|
|||||||
@@ -1,26 +1,27 @@
|
|||||||
(ns status-im.ui.screens.chat.message.audio-old
|
(ns status-im.ui.screens.chat.message.audio-old
|
||||||
(:require-macros [status-im.utils.views :refer [defview letsubs]])
|
(:require-macros [status-im.utils.views :refer [defview letsubs]])
|
||||||
(:require [status-im.utils.utils :as utils]
|
(:require ["react-native-blob-util" :default ReactNativeBlobUtil]
|
||||||
[reagent.core :as reagent]
|
|
||||||
[goog.string :as gstring]
|
[goog.string :as gstring]
|
||||||
[status-im.audio.core :as audio]
|
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[status-im.ui.screens.chat.styles.message.audio-old :as style]
|
|
||||||
[status-im.ui.components.animation :as anim]
|
|
||||||
[quo.design-system.colors :as colors]
|
[quo.design-system.colors :as colors]
|
||||||
|
[reagent.core :as reagent]
|
||||||
|
[status-im.audio.core :as audio]
|
||||||
|
[status-im.ui.components.animation :as anim]
|
||||||
[status-im.ui.components.icons.icons :as icons]
|
[status-im.ui.components.icons.icons :as icons]
|
||||||
[status-im.ui.components.react :as react]
|
[status-im.ui.components.react :as react]
|
||||||
[status-im.ui.components.slider :as slider]
|
[status-im.ui.components.slider :as slider]
|
||||||
["react-native-blob-util" :default ReactNativeBlobUtil]
|
[status-im.ui.screens.chat.styles.message.audio-old :as style]
|
||||||
[status-im.utils.platform :as platform]
|
[status-im.utils.platform :as platform]
|
||||||
[taoensso.timbre :as log]))
|
[status-im.utils.utils :as utils]
|
||||||
|
[taoensso.timbre :as log]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(defonce player-ref (atom nil))
|
(defonce player-ref (atom nil))
|
||||||
(defonce current-player-message-id (atom nil))
|
(defonce current-player-message-id (atom nil))
|
||||||
(defonce current-active-state-ref-ref (atom nil))
|
(defonce current-active-state-ref-ref (atom nil))
|
||||||
(defonce progress-timer (atom nil))
|
(defonce progress-timer (atom nil))
|
||||||
|
|
||||||
(defn start-stop-progress-timer [{:keys [state-ref progress-ref progress-anim]} start?]
|
(defn start-stop-progress-timer
|
||||||
|
[{:keys [state-ref progress-ref progress-anim]} start?]
|
||||||
(when @progress-timer
|
(when @progress-timer
|
||||||
(utils/clear-interval @progress-timer)
|
(utils/clear-interval @progress-timer)
|
||||||
(when-not start?
|
(when-not start?
|
||||||
@@ -28,48 +29,61 @@
|
|||||||
(when start?
|
(when start?
|
||||||
(when @progress-timer
|
(when @progress-timer
|
||||||
(utils/clear-interval @progress-timer))
|
(utils/clear-interval @progress-timer))
|
||||||
(reset! progress-timer (utils/set-interval
|
(reset! progress-timer
|
||||||
#(when (and @state-ref (not (:slider-seeking @state-ref)))
|
(utils/set-interval
|
||||||
(let [ct (audio/get-player-current-time @player-ref)]
|
#(when (and @state-ref (not (:slider-seeking @state-ref)))
|
||||||
(reset! progress-ref ct)
|
(let [ct (audio/get-player-current-time @player-ref)]
|
||||||
(when ct
|
(reset! progress-ref ct)
|
||||||
(anim/start (anim/timing progress-anim {:toValue @progress-ref
|
(when ct
|
||||||
:duration 100
|
(anim/start (anim/timing progress-anim
|
||||||
:easing (.-linear ^js anim/easing)
|
{:toValue @progress-ref
|
||||||
:useNativeDriver true})))))
|
:duration 100
|
||||||
100))))
|
:easing (.-linear ^js anim/easing)
|
||||||
|
:useNativeDriver true})))))
|
||||||
|
100))))
|
||||||
|
|
||||||
(defn update-state [{:keys [state-ref progress-ref progress-anim message-id seek-to-ms audio-duration-ms slider-new-state-seeking? unloaded? error]}]
|
(defn update-state
|
||||||
(let [player-state (audio/get-state @player-ref)
|
[{:keys [state-ref progress-ref progress-anim message-id seek-to-ms audio-duration-ms
|
||||||
|
slider-new-state-seeking? unloaded? error]}]
|
||||||
|
(let [player-state (audio/get-state @player-ref)
|
||||||
slider-seeking (if (some? slider-new-state-seeking?)
|
slider-seeking (if (some? slider-new-state-seeking?)
|
||||||
slider-new-state-seeking?
|
slider-new-state-seeking?
|
||||||
(:slider-seeking @state-ref))
|
(:slider-seeking @state-ref))
|
||||||
general (cond
|
general (cond
|
||||||
(some? error) :error
|
(some? error) :error
|
||||||
(or unloaded? (not= message-id @current-player-message-id)) :not-loaded
|
(or unloaded? (not= message-id @current-player-message-id)) :not-loaded
|
||||||
slider-seeking (:general @state-ref) ; persist player state at the time user started sliding
|
slider-seeking (:general
|
||||||
(= player-state audio/PLAYING) :playing
|
@state-ref) ; persist
|
||||||
(= player-state audio/PAUSED) :paused
|
; player
|
||||||
(= player-state audio/SEEKING) :seeking
|
; state
|
||||||
(= player-state audio/PREPARED) :ready-to-play
|
; at
|
||||||
:else :preparing)
|
; the
|
||||||
new-state {:general general
|
; time
|
||||||
:error-msg error
|
; user
|
||||||
:duration (cond (not (#{:preparing :not-loaded :error} general))
|
; started
|
||||||
(audio/get-player-duration @player-ref)
|
; sliding
|
||||||
|
(= player-state audio/PLAYING) :playing
|
||||||
|
(= player-state audio/PAUSED) :paused
|
||||||
|
(= player-state audio/SEEKING) :seeking
|
||||||
|
(= player-state audio/PREPARED) :ready-to-play
|
||||||
|
:else :preparing)
|
||||||
|
new-state {:general general
|
||||||
|
:error-msg error
|
||||||
|
:duration (cond (not (#{:preparing :not-loaded :error} general))
|
||||||
|
(audio/get-player-duration @player-ref)
|
||||||
|
|
||||||
audio-duration-ms audio-duration-ms
|
audio-duration-ms audio-duration-ms
|
||||||
|
|
||||||
:else (:duration @state-ref))
|
:else (:duration @state-ref))
|
||||||
:progress-ref (or progress-ref (:progress-ref @state-ref))
|
:progress-ref (or progress-ref (:progress-ref @state-ref))
|
||||||
:progress-anim (or progress-anim (:progress-anim @state-ref))
|
:progress-anim (or progress-anim (:progress-anim @state-ref))
|
||||||
:slider-seeking slider-seeking
|
:slider-seeking slider-seeking
|
||||||
|
|
||||||
; persist seek-to-ms while seeking or audio is not loaded
|
; persist seek-to-ms while seeking or audio is not loaded
|
||||||
:seek-to-ms (when (or
|
:seek-to-ms (when (or
|
||||||
slider-seeking
|
slider-seeking
|
||||||
(#{:preparing :not-loaded :error} general))
|
(#{:preparing :not-loaded :error} general))
|
||||||
(or seek-to-ms (:seek-to-ms @state-ref)))}]
|
(or seek-to-ms (:seek-to-ms @state-ref)))}]
|
||||||
; update state if needed
|
; update state if needed
|
||||||
(when (not= @state-ref new-state)
|
(when (not= @state-ref new-state)
|
||||||
(reset! state-ref new-state))
|
(reset! state-ref new-state))
|
||||||
@@ -87,9 +101,11 @@
|
|||||||
(reset! (:progress-ref new-state) 0)
|
(reset! (:progress-ref new-state) 0)
|
||||||
(anim/set-value (:progress-anim new-state) 0))))
|
(anim/set-value (:progress-anim new-state) 0))))
|
||||||
|
|
||||||
(defn destroy-player [{:keys [message-id reloading?]}]
|
(defn destroy-player
|
||||||
(when (and @player-ref (or reloading?
|
[{:keys [message-id reloading?]}]
|
||||||
(= message-id @current-player-message-id)))
|
(when (and @player-ref
|
||||||
|
(or reloading?
|
||||||
|
(= message-id @current-player-message-id)))
|
||||||
(audio/destroy-player @player-ref)
|
(audio/destroy-player @player-ref)
|
||||||
(reset! player-ref nil)
|
(reset! player-ref nil)
|
||||||
(when @current-active-state-ref-ref
|
(when @current-active-state-ref-ref
|
||||||
@@ -99,7 +115,8 @@
|
|||||||
|
|
||||||
(defonce last-seek (atom (js/Date.now)))
|
(defonce last-seek (atom (js/Date.now)))
|
||||||
|
|
||||||
(defn seek [{:keys [message-id] :as params} value immediate? on-success]
|
(defn seek
|
||||||
|
[{:keys [message-id] :as params} value immediate? on-success]
|
||||||
(when (and @player-ref (= message-id @current-player-message-id))
|
(when (and @player-ref (= message-id @current-player-message-id))
|
||||||
(let [now (js/Date.now)]
|
(let [now (js/Date.now)]
|
||||||
(when (or immediate? (> (- now @last-seek) 200))
|
(when (or immediate? (> (- now @last-seek) 200))
|
||||||
@@ -113,13 +130,15 @@
|
|||||||
#(update-state (merge params {:error (:message %)}))))))
|
#(update-state (merge params {:error (:message %)}))))))
|
||||||
(update-state (merge params {:seek-to-ms value})))
|
(update-state (merge params {:seek-to-ms value})))
|
||||||
|
|
||||||
(defn download-audio-http [base64-uri on-success]
|
(defn download-audio-http
|
||||||
|
[base64-uri on-success]
|
||||||
(-> (.config ReactNativeBlobUtil (clj->js {:trusty platform/ios?}))
|
(-> (.config ReactNativeBlobUtil (clj->js {:trusty platform/ios?}))
|
||||||
(.fetch "GET" (str base64-uri))
|
(.fetch "GET" (str base64-uri))
|
||||||
(.then #(on-success (.base64 ^js %)))
|
(.then #(on-success (.base64 ^js %)))
|
||||||
(.catch #(log/error "could not fetch audio"))))
|
(.catch #(log/error "could not fetch audio"))))
|
||||||
|
|
||||||
(defn reload-player [{:keys [message-id state-ref] :as params} audio-url on-success]
|
(defn reload-player
|
||||||
|
[{:keys [message-id state-ref] :as params} audio-url on-success]
|
||||||
;; to avoid reloading player while is initializing,
|
;; to avoid reloading player while is initializing,
|
||||||
;; we go ahead only if there is no player or
|
;; we go ahead only if there is no player or
|
||||||
;; if it is already prepared
|
;; if it is already prepared
|
||||||
@@ -131,7 +150,7 @@
|
|||||||
(fn [base64-data]
|
(fn [base64-data]
|
||||||
(reset! player-ref (audio/new-player
|
(reset! player-ref (audio/new-player
|
||||||
(str "data:audio/acc;base64," base64-data)
|
(str "data:audio/acc;base64," base64-data)
|
||||||
{:autoDestroy false
|
{:autoDestroy false
|
||||||
:continuesToPlayInBackground false}
|
:continuesToPlayInBackground false}
|
||||||
#(seek params 0 true nil)))
|
#(seek params 0 true nil)))
|
||||||
(audio/prepare-player
|
(audio/prepare-player
|
||||||
@@ -142,7 +161,8 @@
|
|||||||
(reset! current-active-state-ref-ref state-ref)
|
(reset! current-active-state-ref-ref state-ref)
|
||||||
(update-state params)))))
|
(update-state params)))))
|
||||||
|
|
||||||
(defn play-pause [{:keys [message-id state-ref] :as params} audio]
|
(defn play-pause
|
||||||
|
[{:keys [message-id state-ref] :as params} audio]
|
||||||
(if (not= message-id @current-player-message-id)
|
(if (not= message-id @current-player-message-id)
|
||||||
;; player has audio from another message, we need to reload
|
;; player has audio from another message, we need to reload
|
||||||
(reload-player params
|
(reload-player params
|
||||||
@@ -171,40 +191,43 @@
|
|||||||
(update-state params))
|
(update-state params))
|
||||||
#(update-state (merge params {:error (:message %)}))))))
|
#(update-state (merge params {:error (:message %)}))))))
|
||||||
|
|
||||||
(defn- play-pause-button [state-ref outgoing on-press]
|
(defn- play-pause-button
|
||||||
|
[state-ref outgoing on-press]
|
||||||
(let [color (if outgoing colors/blue colors/white-persist)]
|
(let [color (if outgoing colors/blue colors/white-persist)]
|
||||||
(if (= (:general @state-ref) :preparing)
|
(if (= (:general @state-ref) :preparing)
|
||||||
[react/view {:style (style/play-pause-container outgoing true)}
|
[react/view {:style (style/play-pause-container outgoing true)}
|
||||||
[react/small-loading-indicator color]]
|
[react/small-loading-indicator color]]
|
||||||
[react/touchable-highlight {:on-press on-press}
|
[react/touchable-highlight {:on-press on-press}
|
||||||
[icons/icon (case (:general @state-ref)
|
[icons/icon
|
||||||
:playing :main-icons/pause
|
(case (:general @state-ref)
|
||||||
:main-icons/play)
|
:playing :main-icons/pause
|
||||||
|
:main-icons/play)
|
||||||
{:container-style (style/play-pause-container outgoing false)
|
{:container-style (style/play-pause-container outgoing false)
|
||||||
:accessibility-label :play-pause-audio-message-button
|
:accessibility-label :play-pause-audio-message-button
|
||||||
:color color}]])))
|
:color color}]])))
|
||||||
|
|
||||||
(fx/defn on-background
|
(rf/defn on-background
|
||||||
{:events [:audio-message/on-background]}
|
{:events [:audio-message/on-background]}
|
||||||
[_]
|
[_]
|
||||||
(when (and @current-active-state-ref-ref
|
(when (and @current-active-state-ref-ref
|
||||||
@@current-active-state-ref-ref)
|
@@current-active-state-ref-ref)
|
||||||
(update-state {:state-ref @current-active-state-ref-ref
|
(update-state {:state-ref @current-active-state-ref-ref
|
||||||
:message-id @current-player-message-id}))
|
:message-id @current-player-message-id}))
|
||||||
nil)
|
nil)
|
||||||
|
|
||||||
(defview message-content [{:keys [audio audio-duration-ms message-id outgoing]}]
|
(defview message-content
|
||||||
(letsubs [state (reagent/atom nil)
|
[{:keys [audio audio-duration-ms message-id outgoing]}]
|
||||||
progress (reagent/atom 0)
|
(letsubs [state (reagent/atom nil)
|
||||||
|
progress (reagent/atom 0)
|
||||||
progress-anim (anim/create-value 0)
|
progress-anim (anim/create-value 0)
|
||||||
width [:dimensions/window-width]]
|
width [:dimensions/window-width]]
|
||||||
{:component-did-mount (fn []
|
{:component-did-mount (fn []
|
||||||
(update-state {:state-ref state
|
(update-state {:state-ref state
|
||||||
:audio-duration-ms audio-duration-ms
|
:audio-duration-ms audio-duration-ms
|
||||||
:message-id message-id
|
:message-id message-id
|
||||||
:unloaded? true
|
:unloaded? true
|
||||||
:progress-ref progress
|
:progress-ref progress
|
||||||
:progress-anim progress-anim}))
|
:progress-anim progress-anim}))
|
||||||
:component-will-unmount (fn []
|
:component-will-unmount (fn []
|
||||||
(destroy-player {:state-ref state :message-id message-id})
|
(destroy-player {:state-ref state :message-id message-id})
|
||||||
(when (= @current-player-message-id message-id)
|
(when (= @current-player-message-id message-id)
|
||||||
@@ -212,27 +235,38 @@
|
|||||||
(reset! current-player-message-id nil))
|
(reset! current-player-message-id nil))
|
||||||
(reset! state nil))}
|
(reset! state nil))}
|
||||||
|
|
||||||
(let [base-params {:state-ref state :message-id message-id :progress-ref progress :progress-anim progress-anim}]
|
(let [base-params {:state-ref state
|
||||||
|
:message-id message-id
|
||||||
|
:progress-ref progress
|
||||||
|
:progress-anim progress-anim}]
|
||||||
(if (= (:general @state) :error)
|
(if (= (:general @state) :error)
|
||||||
[react/text {:style {:typography :main-medium
|
[react/text
|
||||||
:margin-bottom 16}} (:error-msg @state)]
|
{:style {:typography :main-medium
|
||||||
|
:margin-bottom 16}} (:error-msg @state)]
|
||||||
[react/view (style/container width)
|
[react/view (style/container width)
|
||||||
[react/view style/play-pause-slider-container
|
[react/view style/play-pause-slider-container
|
||||||
[play-pause-button state outgoing #(play-pause base-params audio)]
|
[play-pause-button state outgoing #(play-pause base-params audio)]
|
||||||
[react/view style/slider-container
|
[react/view style/slider-container
|
||||||
[slider/animated-slider (merge (style/slider outgoing)
|
[slider/animated-slider
|
||||||
{:minimum-value 0
|
(merge (style/slider outgoing)
|
||||||
:maximum-value (:duration @state)
|
{:minimum-value 0
|
||||||
:value progress-anim
|
:maximum-value (:duration @state)
|
||||||
:on-value-change #(seek base-params % false nil)
|
:value progress-anim
|
||||||
:on-sliding-start #(seek (merge base-params {:slider-new-state-seeking? true}) % true nil)
|
:on-value-change #(seek base-params % false nil)
|
||||||
:on-sliding-complete #(seek (merge base-params {:slider-new-state-seeking? false}) % true nil)})]]]
|
:on-sliding-start #(seek (merge base-params {:slider-new-state-seeking? true})
|
||||||
|
%
|
||||||
|
true
|
||||||
|
nil)
|
||||||
|
:on-sliding-complete #(seek (merge base-params {:slider-new-state-seeking? false})
|
||||||
|
%
|
||||||
|
true
|
||||||
|
nil)})]]]
|
||||||
|
|
||||||
[react/view style/times-container
|
[react/view style/times-container
|
||||||
[react/text {:style (style/timestamp outgoing)}
|
[react/text {:style (style/timestamp outgoing)}
|
||||||
(let [time (cond
|
(let [time (cond
|
||||||
(or (:slider-seeking @state) (> (:seek-to-ms @state) 0)) (:seek-to-ms @state)
|
(or (:slider-seeking @state) (> (:seek-to-ms @state) 0)) (:seek-to-ms @state)
|
||||||
(#{:playing :paused :seeking} (:general @state)) @progress
|
(#{:playing :paused :seeking} (:general @state)) @progress
|
||||||
:else (:duration @state))
|
:else (:duration @state))
|
||||||
s (quot time 1000)]
|
s (quot time 1000)]
|
||||||
(gstring/format "%02d:%02d" (quot s 60) (mod s 60)))]]]))))
|
(gstring/format "%02d:%02d" (quot s 60) (mod s 60)))]]]))))
|
||||||
|
|||||||
@@ -1,87 +1,101 @@
|
|||||||
(ns status-im.ui.screens.chat.message.pinned-message
|
(ns status-im.ui.screens.chat.message.pinned-message
|
||||||
(:require [re-frame.core :as re-frame]
|
(:require [quo.core :as quo]
|
||||||
[status-im.i18n.i18n :as i18n]
|
|
||||||
[quo.design-system.colors :as colors]
|
[quo.design-system.colors :as colors]
|
||||||
[status-im.ui.components.react :as react]
|
[re-frame.core :as re-frame]
|
||||||
[quo.core :as quo]
|
|
||||||
[reagent.core :as reagent]
|
[reagent.core :as reagent]
|
||||||
|
[status-im.i18n.i18n :as i18n]
|
||||||
[status-im.ui.components.list.views :as list]
|
[status-im.ui.components.list.views :as list]
|
||||||
[status-im.utils.handlers :refer [<sub]]
|
[status-im.ui.components.react :as react]
|
||||||
[status-im.ui.screens.chat.message.message :as message]))
|
[status-im.ui.screens.chat.message.message :as message]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(def selected-unpin (reagent/atom nil))
|
(def selected-unpin (reagent/atom nil))
|
||||||
|
|
||||||
(defn render-pin-fn [{:keys [message-id outgoing] :as message}
|
(defn render-pin-fn
|
||||||
_
|
[{:keys [message-id outgoing] :as message}
|
||||||
_
|
_
|
||||||
{:keys [group-chat public? current-public-key space-keeper]}]
|
_
|
||||||
[react/touchable-without-feedback {:style {:width "100%"}
|
{:keys [group-chat public? current-public-key space-keeper]}]
|
||||||
:on-press #(reset! selected-unpin message-id)}
|
[react/touchable-without-feedback
|
||||||
[react/view {:style {:flex-direction :row
|
{:style {:width "100%"}
|
||||||
:align-items :center
|
:on-press #(reset! selected-unpin message-id)}
|
||||||
:justify-content :space-between
|
[react/view
|
||||||
:flex 1
|
{:style {:flex-direction :row
|
||||||
:padding-right 20}}
|
:align-items :center
|
||||||
|
:justify-content :space-between
|
||||||
|
:flex 1
|
||||||
|
:padding-right 20}}
|
||||||
[message/chat-message
|
[message/chat-message
|
||||||
(assoc message
|
(assoc message
|
||||||
:group-chat group-chat
|
:group-chat group-chat
|
||||||
:public? public?
|
:public? public?
|
||||||
:current-public-key current-public-key
|
:current-public-key current-public-key
|
||||||
:show-input? false
|
:show-input? false
|
||||||
:pinned false
|
:pinned false
|
||||||
:display-username? (not outgoing)
|
:display-username? (not outgoing)
|
||||||
:display-photo? false
|
:display-photo? false
|
||||||
:last-in-group? false
|
:last-in-group? false
|
||||||
:in-popover? true)
|
:in-popover? true)
|
||||||
space-keeper]
|
space-keeper]
|
||||||
[react/view {:style {:position :absolute
|
[react/view
|
||||||
:right 18
|
{:style {:position :absolute
|
||||||
:padding-top 4}}
|
:right 18
|
||||||
|
:padding-top 4}}
|
||||||
[quo/radio {:value (= @selected-unpin message-id)}]]]])
|
[quo/radio {:value (= @selected-unpin message-id)}]]]])
|
||||||
|
|
||||||
(def list-key-fn #(or (:message-id %) (:value %)))
|
(def list-key-fn #(or (:message-id %) (:value %)))
|
||||||
|
|
||||||
(defn pinned-messages-limit-list [chat-id]
|
(defn pinned-messages-limit-list
|
||||||
|
[chat-id]
|
||||||
(let [pinned-messages @(re-frame/subscribe [:chats/pinned-sorted-list chat-id])]
|
(let [pinned-messages @(re-frame/subscribe [:chats/pinned-sorted-list chat-id])]
|
||||||
[list/flat-list
|
[list/flat-list
|
||||||
{:key-fn list-key-fn
|
{:key-fn list-key-fn
|
||||||
:data (reverse pinned-messages)
|
:data (reverse pinned-messages)
|
||||||
:render-data {:chat-id chat-id}
|
:render-data {:chat-id chat-id}
|
||||||
:render-fn render-pin-fn
|
:render-fn render-pin-fn
|
||||||
:on-scroll-to-index-failed identity
|
:on-scroll-to-index-failed identity
|
||||||
:style {:flex-grow 0
|
:style {:flex-grow 0
|
||||||
:border-top-width 1
|
:border-top-width 1
|
||||||
:border-bottom-width 1
|
:border-bottom-width 1
|
||||||
:border-top-color colors/gray-lighter
|
:border-top-color colors/gray-lighter
|
||||||
:border-bottom-color colors/gray-lighter}
|
:border-bottom-color colors/gray-lighter}
|
||||||
:content-container-style {:padding-bottom 10
|
:content-container-style {:padding-bottom 10
|
||||||
:padding-top 10}}]))
|
:padding-top 10}}]))
|
||||||
|
|
||||||
(defn pin-limit-popover []
|
(defn pin-limit-popover
|
||||||
(let [{:keys [message]} (<sub [:popover/popover])]
|
[]
|
||||||
|
(let [{:keys [message]} (rf/sub [:popover/popover])]
|
||||||
[react/view {:style {:flex-shrink 1}}
|
[react/view {:style {:flex-shrink 1}}
|
||||||
[react/view {:style {:height 60
|
[react/view
|
||||||
:justify-content :center}}
|
{:style {:height 60
|
||||||
[react/text {:style {:padding-horizontal 40
|
:justify-content :center}}
|
||||||
:text-align :center}}
|
[react/text
|
||||||
|
{:style {:padding-horizontal 40
|
||||||
|
:text-align :center}}
|
||||||
(i18n/label :t/pin-limit-reached)]]
|
(i18n/label :t/pin-limit-reached)]]
|
||||||
[pinned-messages-limit-list (message :chat-id)]
|
[pinned-messages-limit-list (message :chat-id)]
|
||||||
[react/view {:flex-direction :row :padding-horizontal 16 :height 60 :justify-content :space-between :align-items :center}
|
[react/view
|
||||||
|
{:flex-direction :row
|
||||||
|
:padding-horizontal 16
|
||||||
|
:height 60
|
||||||
|
:justify-content :space-between
|
||||||
|
:align-items :center}
|
||||||
[quo/button
|
[quo/button
|
||||||
{:on-press #(do
|
{:on-press #(do
|
||||||
(reset! selected-unpin nil)
|
(reset! selected-unpin nil)
|
||||||
(re-frame/dispatch [:hide-popover]))
|
(re-frame/dispatch [:hide-popover]))
|
||||||
:type :secondary}
|
:type :secondary}
|
||||||
(i18n/label :t/cancel)]
|
(i18n/label :t/cancel)]
|
||||||
[quo/button
|
[quo/button
|
||||||
{:on-press #(do
|
{:on-press #(do
|
||||||
(re-frame/dispatch [:pin-message/send-pin-message {:chat-id (message :chat-id)
|
(re-frame/dispatch [:pin-message/send-pin-message
|
||||||
:message-id @selected-unpin
|
{:chat-id (message :chat-id)
|
||||||
:pinned false}])
|
:message-id @selected-unpin
|
||||||
|
:pinned false}])
|
||||||
(re-frame/dispatch [:pin-message/send-pin-message (assoc message :pinned true)])
|
(re-frame/dispatch [:pin-message/send-pin-message (assoc message :pinned true)])
|
||||||
(re-frame/dispatch [:hide-popover])
|
(re-frame/dispatch [:hide-popover])
|
||||||
(reset! selected-unpin nil))
|
(reset! selected-unpin nil))
|
||||||
:type :secondary
|
:type :secondary
|
||||||
:disabled (nil? @selected-unpin)
|
:disabled (nil? @selected-unpin)
|
||||||
:theme (if (nil? @selected-unpin) :disabled :negative)}
|
:theme (if (nil? @selected-unpin) :disabled :negative)}
|
||||||
(i18n/label :t/unpin)]]]))
|
(i18n/label :t/unpin)]]]))
|
||||||
|
|||||||
@@ -1,59 +1,67 @@
|
|||||||
(ns status-im.ui.screens.communities.channel-details
|
(ns status-im.ui.screens.communities.channel-details
|
||||||
(:require [quo.core :as quo]
|
(:require [clojure.string :as string]
|
||||||
[status-im.utils.handlers :refer [>evt <sub]]
|
[quo.core :as quo]
|
||||||
[status-im.ui.components.profile-header.view :as profile-header]
|
[re-frame.core :as re-frame]
|
||||||
[status-im.i18n.i18n :as i18n]
|
|
||||||
[clojure.string :as string]
|
|
||||||
[status-im.communities.core :as communities]
|
[status-im.communities.core :as communities]
|
||||||
[re-frame.core :as re-frame]))
|
[status-im.i18n.i18n :as i18n]
|
||||||
|
[status-im.ui.components.profile-header.view :as profile-header]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(defn view []
|
(defn view
|
||||||
(let [{:keys [chat-id]} (<sub [:get-screen-params])]
|
[]
|
||||||
|
(let [{:keys [chat-id]} (rf/sub [:get-screen-params])]
|
||||||
(fn []
|
(fn []
|
||||||
(let [current-chat (<sub [:chat-by-id chat-id])
|
(let [current-chat (rf/sub [:chat-by-id chat-id])
|
||||||
{:keys [chat-name color description community-id emoji]} current-chat
|
{:keys [chat-name color description community-id emoji]} current-chat
|
||||||
{:keys [position]} (<sub [:chats/community-chat-by-id community-id chat-id])
|
{:keys [position]} (rf/sub [:chats/community-chat-by-id
|
||||||
category (<sub [:chats/category-by-chat-id community-id chat-id])
|
community-id chat-id])
|
||||||
{:keys [admin]} (<sub [:communities/community community-id])
|
category (rf/sub [:chats/category-by-chat-id
|
||||||
pinned-messages (<sub [:chats/pinned chat-id])]
|
community-id chat-id])
|
||||||
[quo/animated-header {:left-accessories [{:icon :main-icons/arrow-left
|
{:keys [admin]} (rf/sub [:communities/community
|
||||||
:accessibility-label :back-button
|
community-id])
|
||||||
:on-press #(>evt [:navigate-back])}]
|
pinned-messages (rf/sub [:chats/pinned chat-id])]
|
||||||
:right-accessories (when admin [{:icon :edit
|
[quo/animated-header
|
||||||
:accessibility-label :invite-button
|
{:left-accessories [{:icon :main-icons/arrow-left
|
||||||
:on-press #(>evt [::communities/edit-channel-pressed
|
:accessibility-label :back-button
|
||||||
community-id
|
:on-press #(rf/dispatch [:navigate-back])}]
|
||||||
chat-name
|
:right-accessories (when admin
|
||||||
description
|
[{:icon :edit
|
||||||
color
|
:accessibility-label :invite-button
|
||||||
emoji
|
:on-press #(rf/dispatch [::communities/edit-channel-pressed
|
||||||
chat-id
|
community-id
|
||||||
(:id category)
|
chat-name
|
||||||
position])}])
|
description
|
||||||
:extended-header (profile-header/extended-header
|
color
|
||||||
{:title chat-name
|
emoji
|
||||||
:color color
|
chat-id
|
||||||
:emoji emoji
|
(:id category)
|
||||||
:subtitle (i18n/label :t/public-channel)})
|
position])}])
|
||||||
:use-insets true}
|
:extended-header (profile-header/extended-header
|
||||||
|
{:title chat-name
|
||||||
|
:color color
|
||||||
|
:emoji emoji
|
||||||
|
:subtitle (i18n/label :t/public-channel)})
|
||||||
|
:use-insets true}
|
||||||
(when-not (string/blank? description)
|
(when-not (string/blank? description)
|
||||||
[:<>
|
[:<>
|
||||||
[quo/list-footer {:color :main}
|
[quo/list-footer {:color :main}
|
||||||
description]
|
description]
|
||||||
[quo/separator {:style {:margin-vertical 8}}]
|
[quo/separator {:style {:margin-vertical 8}}]
|
||||||
(when admin
|
(when admin
|
||||||
[quo/list-item {:title (i18n/label :t/category)
|
[quo/list-item
|
||||||
:on-press #(>evt [:open-modal :select-category {:chat current-chat
|
{:title (i18n/label :t/category)
|
||||||
:category category
|
:on-press #(rf/dispatch [:open-modal :select-category
|
||||||
:community-id community-id}])
|
{:chat current-chat
|
||||||
:chevron true
|
:category category
|
||||||
:accessory :text
|
:community-id community-id}])
|
||||||
:accessory-text (if category
|
:chevron true
|
||||||
(:name category)
|
:accessory :text
|
||||||
(i18n/label :t/none))}])
|
:accessory-text (if category
|
||||||
|
(:name category)
|
||||||
|
(i18n/label :t/none))}])
|
||||||
[quo/list-item
|
[quo/list-item
|
||||||
{:title (i18n/label :t/pinned-messages)
|
{:title (i18n/label :t/pinned-messages)
|
||||||
:accessory :text
|
:accessory :text
|
||||||
:accessory-text (count pinned-messages)
|
:accessory-text (count pinned-messages)
|
||||||
:chevron true
|
:chevron true
|
||||||
:on-press #(re-frame/dispatch [:contact.ui/pinned-messages-pressed chat-id])}]])]))))
|
:on-press #(re-frame/dispatch [:contact.ui/pinned-messages-pressed chat-id])}]])]))))
|
||||||
|
|||||||
@@ -1,44 +1,52 @@
|
|||||||
(ns status-im.ui.screens.communities.community-emoji-thumbnail-picker
|
(ns status-im.ui.screens.communities.community-emoji-thumbnail-picker
|
||||||
(:require [quo.react-native :as rn]
|
(:require [clojure.string :as string]
|
||||||
[quo.core :as quo]
|
[quo.core :as quo]
|
||||||
[clojure.string :as string]
|
[quo.react-native :as rn]
|
||||||
[status-im.ui.components.react :as react]
|
|
||||||
[status-im.utils.handlers :refer [>evt <sub]]
|
|
||||||
[status-im.communities.core :as communities]
|
[status-im.communities.core :as communities]
|
||||||
[status-im.ui.components.keyboard-avoid-presentation :as kb-presentation]
|
[status-im.ui.components.emoji-thumbnail.color-picker :as color-picker]
|
||||||
[status-im.ui.components.emoji-thumbnail.styles :as styles]
|
|
||||||
[status-im.ui.components.emoji-thumbnail.preview :as emoji-thumbnail-preview]
|
[status-im.ui.components.emoji-thumbnail.preview :as emoji-thumbnail-preview]
|
||||||
[status-im.ui.components.emoji-thumbnail.color-picker :as color-picker]))
|
[status-im.ui.components.emoji-thumbnail.styles :as styles]
|
||||||
|
[status-im.ui.components.keyboard-avoid-presentation :as kb-presentation]
|
||||||
|
[status-im.ui.components.react :as react]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(defn thumbnail-preview-section []
|
(defn thumbnail-preview-section
|
||||||
(let [{:keys [color emoji]} (<sub [:communities/create-channel])
|
[]
|
||||||
size styles/emoji-thumbnail-preview-size]
|
(let [{:keys [color emoji]} (rf/sub [:communities/create-channel])
|
||||||
|
size styles/emoji-thumbnail-preview-size]
|
||||||
[rn/view styles/emoji-thumbnail-preview
|
[rn/view styles/emoji-thumbnail-preview
|
||||||
[emoji-thumbnail-preview/emoji-thumbnail
|
[emoji-thumbnail-preview/emoji-thumbnail
|
||||||
emoji color size]]))
|
emoji color size]]))
|
||||||
|
|
||||||
(defn color-circle [item]
|
(defn color-circle
|
||||||
(let [{:keys [color]} (<sub [:communities/create-channel])
|
[item]
|
||||||
item-color (:color item)
|
(let [{:keys [color]} (rf/sub [:communities/create-channel])
|
||||||
key (:key key)
|
item-color (:color item)
|
||||||
color-selected? (= (string/lower-case item-color) (string/lower-case color))]
|
key (:key key)
|
||||||
[react/touchable-opacity {:key key
|
color-selected? (= (string/lower-case item-color) (string/lower-case color))]
|
||||||
:accessibility-label :color-circle
|
[react/touchable-opacity
|
||||||
:on-press #(>evt [::communities/create-channel-field :color item-color])}
|
{:key key
|
||||||
|
:accessibility-label :color-circle
|
||||||
|
:on-press #(rf/dispatch [::communities/create-channel-field :color item-color])}
|
||||||
[rn/view {:style (styles/emoji-picker-color-border item-color color-selected?)}
|
[rn/view {:style (styles/emoji-picker-color-border item-color color-selected?)}
|
||||||
[rn/view {:style (styles/emoji-picker-color item-color)}]]]))
|
[rn/view {:style (styles/emoji-picker-color item-color)}]]]))
|
||||||
|
|
||||||
(defn update-emoji [emoji]
|
(defn update-emoji
|
||||||
|
[emoji]
|
||||||
(when-not (string/blank? emoji)
|
(when-not (string/blank? emoji)
|
||||||
(>evt [::communities/create-channel-field :emoji emoji])))
|
(rf/dispatch [::communities/create-channel-field :emoji emoji])))
|
||||||
|
|
||||||
(defn emoji-keyboard-section []
|
(defn emoji-keyboard-section
|
||||||
(let [{:keys [width height]} (<sub [:dimensions/window])
|
[]
|
||||||
keyboard_height (if (> width height) 400 (- height styles/emoji-picker-upper-components-size))]
|
(let [{:keys [width height]} (rf/sub [:dimensions/window])
|
||||||
|
keyboard_height (if (> width height)
|
||||||
|
400
|
||||||
|
(- height styles/emoji-picker-upper-components-size))]
|
||||||
[rn/view {:style {:height keyboard_height} :accessibility-label :emoji-keyboard-container}
|
[rn/view {:style {:height keyboard_height} :accessibility-label :emoji-keyboard-container}
|
||||||
[rn/emoji-keyboard (styles/emoji-keyboard #(update-emoji (.-emoji ^js %)))]]))
|
[rn/emoji-keyboard (styles/emoji-keyboard #(update-emoji (.-emoji ^js %)))]]))
|
||||||
|
|
||||||
(defn view []
|
(defn view
|
||||||
|
[]
|
||||||
[kb-presentation/keyboard-avoiding-view {:style {:flex 1}}
|
[kb-presentation/keyboard-avoiding-view {:style {:flex 1}}
|
||||||
[rn/scroll-view
|
[rn/scroll-view
|
||||||
[quo/separator]
|
[quo/separator]
|
||||||
|
|||||||
@@ -1,182 +1,214 @@
|
|||||||
(ns status-im.ui.screens.communities.create
|
(ns status-im.ui.screens.communities.create
|
||||||
(:require [quo.react-native :as rn]
|
(:require [clojure.string :as string]
|
||||||
[status-im.i18n.i18n :as i18n]
|
|
||||||
[quo.core :as quo]
|
[quo.core :as quo]
|
||||||
[clojure.string :as string]
|
|
||||||
[status-im.utils.handlers :refer [>evt <sub]]
|
|
||||||
[status-im.communities.core :as communities]
|
|
||||||
[status-im.ui.components.toolbar :as toolbar]
|
|
||||||
[status-im.utils.image :as utils.image]
|
|
||||||
[quo.design-system.colors :as colors]
|
[quo.design-system.colors :as colors]
|
||||||
[status-im.ui.components.react :as react]
|
[quo.react-native :as rn]
|
||||||
[status-im.ui.screens.communities.membership :as memberships]
|
[status-im.communities.core :as communities]
|
||||||
|
[status-im.i18n.i18n :as i18n]
|
||||||
[status-im.ui.components.icons.icons :as icons]
|
[status-im.ui.components.icons.icons :as icons]
|
||||||
[utils.debounce :as debounce]))
|
[status-im.ui.components.react :as react]
|
||||||
|
[status-im.ui.components.toolbar :as toolbar]
|
||||||
|
[status-im.ui.screens.communities.membership :as memberships]
|
||||||
|
[status-im.utils.image :as utils.image]
|
||||||
|
[utils.debounce :as debounce]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(def max-name-length 30)
|
(def max-name-length 30)
|
||||||
(def max-description-length 140)
|
(def max-description-length 140)
|
||||||
|
|
||||||
(defn valid? [community-name community-description]
|
(defn valid?
|
||||||
|
[community-name community-description]
|
||||||
(and (not (string/blank? community-name))
|
(and (not (string/blank? community-name))
|
||||||
(not (string/blank? community-description))
|
(not (string/blank? community-description))
|
||||||
(<= (count community-name) max-name-length)
|
(<= (count community-name) max-name-length)
|
||||||
(<= (count community-description) max-description-length)))
|
(<= (count community-description) max-description-length)))
|
||||||
|
|
||||||
(def crop-size 1000)
|
(def crop-size 1000)
|
||||||
(def crop-opts {:cropping true
|
(def crop-opts
|
||||||
:cropperCircleOverlay true
|
{:cropping true
|
||||||
:width crop-size
|
:cropperCircleOverlay true
|
||||||
:height crop-size})
|
:width crop-size
|
||||||
|
:height crop-size})
|
||||||
|
|
||||||
(defn pick-pic []
|
(defn pick-pic
|
||||||
|
[]
|
||||||
;;we need timeout because first we need to close bottom sheet and then open picker
|
;;we need timeout because first we need to close bottom sheet and then open picker
|
||||||
(js/setTimeout
|
(js/setTimeout
|
||||||
(fn []
|
(fn []
|
||||||
(react/show-image-picker
|
(react/show-image-picker
|
||||||
#(do (>evt [::communities/create-field :image (.-path ^js %)])
|
#(do (rf/dispatch [::communities/create-field :image (.-path ^js %)])
|
||||||
(>evt [::communities/create-field :new-image (.-path ^js %)]))
|
(rf/dispatch [::communities/create-field :new-image (.-path ^js %)]))
|
||||||
|
|
||||||
crop-opts))
|
crop-opts))
|
||||||
300))
|
300))
|
||||||
|
|
||||||
(defn take-pic []
|
(defn take-pic
|
||||||
|
[]
|
||||||
;;we need timeout because first we need to close bottom sheet and then open picker
|
;;we need timeout because first we need to close bottom sheet and then open picker
|
||||||
(js/setTimeout
|
(js/setTimeout
|
||||||
(fn []
|
(fn []
|
||||||
(react/show-image-picker-camera
|
(react/show-image-picker-camera
|
||||||
#(do (>evt [::communities/create-field :image (.-path ^js %)])
|
#(do (rf/dispatch [::communities/create-field :image (.-path ^js %)])
|
||||||
(>evt [::communities/create-field :new-image (.-path ^js %)]))
|
(rf/dispatch [::communities/create-field :new-image (.-path ^js %)]))
|
||||||
crop-opts))
|
crop-opts))
|
||||||
300))
|
300))
|
||||||
|
|
||||||
(defn bottom-sheet [has-picture editing?]
|
(defn bottom-sheet
|
||||||
|
[has-picture editing?]
|
||||||
(fn []
|
(fn []
|
||||||
[:<>
|
[:<>
|
||||||
[quo/list-item {:accessibility-label :take-photo
|
[quo/list-item
|
||||||
:theme :accent
|
{:accessibility-label :take-photo
|
||||||
:icon :main-icons/camera
|
:theme :accent
|
||||||
:title (i18n/label :t/community-image-take)
|
:icon :main-icons/camera
|
||||||
:on-press #(do
|
:title (i18n/label :t/community-image-take)
|
||||||
(>evt [:bottom-sheet/hide])
|
:on-press #(do
|
||||||
(take-pic))}]
|
(rf/dispatch [:bottom-sheet/hide])
|
||||||
[quo/list-item {:accessibility-label :pick-photo
|
(take-pic))}]
|
||||||
:icon :main-icons/gallery
|
[quo/list-item
|
||||||
:theme :accent
|
{:accessibility-label :pick-photo
|
||||||
:title (i18n/label :t/community-image-pick)
|
:icon :main-icons/gallery
|
||||||
:on-press #(do
|
:theme :accent
|
||||||
(>evt [:bottom-sheet/hide])
|
:title (i18n/label :t/community-image-pick)
|
||||||
(pick-pic))}]
|
:on-press #(do
|
||||||
|
(rf/dispatch [:bottom-sheet/hide])
|
||||||
|
(pick-pic))}]
|
||||||
(when (and has-picture (not editing?))
|
(when (and has-picture (not editing?))
|
||||||
[quo/list-item {:accessibility-label :remove-photo
|
[quo/list-item
|
||||||
:icon :main-icons/delete
|
{:accessibility-label :remove-photo
|
||||||
:theme :accent
|
:icon :main-icons/delete
|
||||||
:title (i18n/label :t/community-image-remove)
|
:theme :accent
|
||||||
:on-press #(do
|
:title (i18n/label :t/community-image-remove)
|
||||||
(>evt [:bottom-sheet/hide])
|
:on-press #(do
|
||||||
(>evt [::communities/remove-field :image]))}])]))
|
(rf/dispatch [:bottom-sheet/hide])
|
||||||
|
(rf/dispatch [::communities/remove-field :image]))}])]))
|
||||||
|
|
||||||
(defn photo-picker []
|
(defn photo-picker
|
||||||
(let [{:keys [image editing?]} (<sub [:communities/create])]
|
[]
|
||||||
[rn/view {:style {:padding-top 16
|
(let [{:keys [image editing?]} (rf/sub [:communities/create])]
|
||||||
:align-items :center}}
|
[rn/view
|
||||||
[rn/touchable-opacity {:on-press #(>evt [:bottom-sheet/show-sheet
|
{:style {:padding-top 16
|
||||||
{:content (bottom-sheet (boolean image) editing?)}])}
|
:align-items :center}}
|
||||||
[rn/view {:style {:width 128
|
[rn/touchable-opacity
|
||||||
:height 128}}
|
{:on-press #(rf/dispatch [:bottom-sheet/show-sheet
|
||||||
[rn/view {:style {:flex 1
|
{:content (bottom-sheet (boolean image) editing?)}])}
|
||||||
:border-radius 64
|
[rn/view
|
||||||
:background-color (colors/get-color :ui-01)
|
{:style {:width 128
|
||||||
:justify-content :center
|
:height 128}}
|
||||||
:align-items :center}}
|
[rn/view
|
||||||
|
{:style {:flex 1
|
||||||
|
:border-radius 64
|
||||||
|
:background-color (colors/get-color :ui-01)
|
||||||
|
:justify-content :center
|
||||||
|
:align-items :center}}
|
||||||
(if image
|
(if image
|
||||||
[rn/image {:source (utils.image/source image)
|
[rn/image
|
||||||
:style {:width 128
|
{:source (utils.image/source image)
|
||||||
:height 128
|
:style {:width 128
|
||||||
:border-radius 64}
|
:height 128
|
||||||
:resize-mode :cover
|
:border-radius 64}
|
||||||
:accessibility-label :community-image}]
|
:resize-mode :cover
|
||||||
|
:accessibility-label :community-image}]
|
||||||
[:<>
|
[:<>
|
||||||
[icons/icon :main-icons/photo {:color (colors/get-color :icon-02)}]
|
[icons/icon :main-icons/photo {:color (colors/get-color :icon-02)}]
|
||||||
[quo/text {:color :secondary}
|
[quo/text {:color :secondary}
|
||||||
(i18n/label :t/community-thumbnail-upload)]])]
|
(i18n/label :t/community-thumbnail-upload)]])]
|
||||||
[rn/view {:style {:position :absolute
|
[rn/view
|
||||||
:top 0
|
{:style {:position :absolute
|
||||||
:right 7}}
|
:top 0
|
||||||
[rn/view {:style {:width 40
|
:right 7}}
|
||||||
:height 40
|
[rn/view
|
||||||
:background-color (colors/get-color :interactive-01)
|
{:style {:width 40
|
||||||
:border-radius 20
|
:height 40
|
||||||
:align-items :center
|
:background-color (colors/get-color :interactive-01)
|
||||||
:justify-content :center
|
:border-radius 20
|
||||||
:shadow-offset {:width 0 :height 1}
|
:align-items :center
|
||||||
:shadow-radius 6
|
:justify-content :center
|
||||||
:shadow-opacity 1
|
:shadow-offset {:width 0 :height 1}
|
||||||
:shadow-color (colors/get-color :shadow-01)
|
:shadow-radius 6
|
||||||
:elevation 2}}
|
:shadow-opacity 1
|
||||||
|
:shadow-color (colors/get-color :shadow-01)
|
||||||
|
:elevation 2}}
|
||||||
[icons/icon :main-icons/add {:color colors/white}]]]]]]))
|
[icons/icon :main-icons/add {:color colors/white}]]]]]]))
|
||||||
|
|
||||||
(defn countable-label [{:keys [label text max-length]}]
|
(defn countable-label
|
||||||
[rn/view {:style {:padding-bottom 10
|
[{:keys [label text max-length]}]
|
||||||
:justify-content :space-between
|
[rn/view
|
||||||
:align-items :flex-end
|
{:style {:padding-bottom 10
|
||||||
:flex-direction :row
|
:justify-content :space-between
|
||||||
:flex-wrap :nowrap}}
|
:align-items :flex-end
|
||||||
|
:flex-direction :row
|
||||||
|
:flex-wrap :nowrap}}
|
||||||
[quo/text label]
|
[quo/text label]
|
||||||
[quo/text {:size :small
|
[quo/text
|
||||||
:color (if (> (count text) max-length)
|
{:size :small
|
||||||
:negative
|
:color (if (> (count text) max-length)
|
||||||
:secondary)}
|
:negative
|
||||||
|
:secondary)}
|
||||||
(str (count text) "/" max-length)]])
|
(str (count text) "/" max-length)]])
|
||||||
|
|
||||||
(defn form []
|
(defn form
|
||||||
(let [{:keys [name description membership editing?]} (<sub [:communities/create])]
|
[]
|
||||||
[rn/scroll-view {:keyboard-should-persist-taps :handled
|
(let [{:keys [name description membership editing?]} (rf/sub [:communities/create])]
|
||||||
:style {:flex 1}
|
[rn/scroll-view
|
||||||
:content-container-style {:padding-vertical 16}}
|
{:keyboard-should-persist-taps :handled
|
||||||
[rn/view {:style {:padding-bottom 16
|
:style {:flex 1}
|
||||||
:padding-top 10
|
:content-container-style {:padding-vertical 16}}
|
||||||
:padding-horizontal 16}}
|
[rn/view
|
||||||
[countable-label {:label (i18n/label :t/name-your-community)
|
{:style {:padding-bottom 16
|
||||||
:text name
|
:padding-top 10
|
||||||
:max-length max-name-length}]
|
:padding-horizontal 16}}
|
||||||
|
[countable-label
|
||||||
|
{:label (i18n/label :t/name-your-community)
|
||||||
|
:text name
|
||||||
|
:max-length max-name-length}]
|
||||||
[quo/text-input
|
[quo/text-input
|
||||||
{:placeholder (i18n/label :t/name-your-community-placeholder)
|
{:placeholder (i18n/label :t/name-your-community-placeholder)
|
||||||
:default-value name
|
:default-value name
|
||||||
:on-change-text #(>evt [::communities/create-field :name %])
|
:on-change-text #(rf/dispatch [::communities/create-field :name %])
|
||||||
:auto-focus true}]]
|
:auto-focus true}]]
|
||||||
[rn/view {:style {:padding-bottom 16
|
[rn/view
|
||||||
:padding-top 10
|
{:style {:padding-bottom 16
|
||||||
:padding-horizontal 16}}
|
:padding-top 10
|
||||||
[countable-label {:label (i18n/label :t/give-a-short-description-community)
|
:padding-horizontal 16}}
|
||||||
:text description
|
[countable-label
|
||||||
:max-length max-description-length}]
|
{:label (i18n/label :t/give-a-short-description-community)
|
||||||
|
:text description
|
||||||
|
:max-length max-description-length}]
|
||||||
[quo/text-input
|
[quo/text-input
|
||||||
{:placeholder (i18n/label :t/give-a-short-description-community)
|
{:placeholder (i18n/label :t/give-a-short-description-community)
|
||||||
:multiline true
|
:multiline true
|
||||||
:default-value description
|
:default-value description
|
||||||
:on-change-text #(>evt [::communities/create-field :description %])}]]
|
:on-change-text #(rf/dispatch [::communities/create-field :description %])}]]
|
||||||
[quo/list-header {:color :main}
|
[quo/list-header {:color :main}
|
||||||
(i18n/label :t/community-thumbnail-image)]
|
(i18n/label :t/community-thumbnail-image)]
|
||||||
[photo-picker]
|
[photo-picker]
|
||||||
(when-not editing? [:<>
|
(when-not editing?
|
||||||
[quo/separator {:style {:margin-vertical 10}}]
|
[:<>
|
||||||
[quo/list-item {:title (i18n/label :t/membership-button)
|
[quo/separator {:style {:margin-vertical 10}}]
|
||||||
:accessory-text (i18n/label (get-in memberships/options [membership :title] :t/membership-none))
|
[quo/list-item
|
||||||
:accessory :text
|
{:title (i18n/label :t/membership-button)
|
||||||
:on-press #(>evt [:navigate-to :community-membership])
|
:accessory-text (i18n/label (get-in memberships/options
|
||||||
:chevron true
|
[membership :title]
|
||||||
:size :small}]
|
:t/membership-none))
|
||||||
[quo/list-footer
|
:accessory :text
|
||||||
(i18n/label (get-in memberships/options [membership :description] :t/membership-none-placeholder))]])]))
|
:on-press #(rf/dispatch [:navigate-to :community-membership])
|
||||||
|
:chevron true
|
||||||
|
:size :small}]
|
||||||
|
[quo/list-footer
|
||||||
|
(i18n/label
|
||||||
|
(get-in memberships/options [membership :description] :t/membership-none-placeholder))]])]))
|
||||||
|
|
||||||
(defn view []
|
(defn view
|
||||||
(let [{:keys [name description]} (<sub [:communities/create])]
|
[]
|
||||||
|
(let [{:keys [name description]} (rf/sub [:communities/create])]
|
||||||
[rn/keyboard-avoiding-view {:style {:flex 1}}
|
[rn/keyboard-avoiding-view {:style {:flex 1}}
|
||||||
[form]
|
[form]
|
||||||
[toolbar/toolbar
|
[toolbar/toolbar
|
||||||
{:show-border? true
|
{:show-border? true
|
||||||
:center
|
:center
|
||||||
[quo/button {:disabled (not (valid? name description))
|
[quo/button
|
||||||
:type :secondary
|
{:disabled (not (valid? name description))
|
||||||
:on-press #(debounce/dispatch-and-chill [::communities/create-confirmation-pressed] 3000)}
|
:type :secondary
|
||||||
|
:on-press #(debounce/dispatch-and-chill [::communities/create-confirmation-pressed] 3000)}
|
||||||
(i18n/label :t/create)]}]]))
|
(i18n/label :t/create)]}]]))
|
||||||
|
|||||||
@@ -1,42 +1,46 @@
|
|||||||
(ns status-im.ui.screens.communities.create-category
|
(ns status-im.ui.screens.communities.create-category
|
||||||
(:require [status-im.ui.components.keyboard-avoid-presentation :as kb-presentation]
|
(:require [clojure.string :as string]
|
||||||
[status-im.utils.handlers :refer [<sub]]
|
|
||||||
[status-im.ui.components.toolbar :as toolbar]
|
|
||||||
[status-im.ui.components.react :as react]
|
|
||||||
[quo.core :as quo]
|
[quo.core :as quo]
|
||||||
[utils.debounce :as debounce]
|
[reagent.core :as reagent]
|
||||||
[status-im.i18n.i18n :as i18n]
|
|
||||||
[clojure.string :as string]
|
|
||||||
[status-im.ui.components.list.views :as list]
|
|
||||||
[status-im.ui.screens.home.views.inner-item :as inner-item]
|
|
||||||
[status-im.communities.core :as communities]
|
[status-im.communities.core :as communities]
|
||||||
[reagent.core :as reagent]))
|
[status-im.i18n.i18n :as i18n]
|
||||||
|
[status-im.ui.components.keyboard-avoid-presentation :as kb-presentation]
|
||||||
|
[status-im.ui.components.list.views :as list]
|
||||||
|
[status-im.ui.components.react :as react]
|
||||||
|
[status-im.ui.components.toolbar :as toolbar]
|
||||||
|
[status-im.ui.screens.home.views.inner-item :as inner-item]
|
||||||
|
[utils.debounce :as debounce]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(defn valid? [category-name]
|
(defn valid?
|
||||||
|
[category-name]
|
||||||
(and (not (string/blank? category-name))
|
(and (not (string/blank? category-name))
|
||||||
(<= (count category-name) 30)))
|
(<= (count category-name) 30)))
|
||||||
|
|
||||||
(def selected-items (reagent/atom #{}))
|
(def selected-items (reagent/atom #{}))
|
||||||
|
|
||||||
(defn render-fn [{:keys [chat-id] :as home-item}]
|
(defn render-fn
|
||||||
(let [selected (get @selected-items chat-id)
|
[{:keys [chat-id] :as home-item}]
|
||||||
|
(let [selected (get @selected-items chat-id)
|
||||||
on-change (fn []
|
on-change (fn []
|
||||||
(swap! selected-items #(if selected (disj % chat-id) (conj % chat-id))))]
|
(swap! selected-items #(if selected (disj % chat-id) (conj % chat-id))))]
|
||||||
[react/view {:flex-direction :row :flex 1 :align-items :center}
|
[react/view {:flex-direction :row :flex 1 :align-items :center}
|
||||||
[react/view {:padding-left 16}
|
[react/view {:padding-left 16}
|
||||||
[quo/checkbox {:value selected
|
[quo/checkbox
|
||||||
:on-change on-change}]]
|
{:value selected
|
||||||
|
:on-change on-change}]]
|
||||||
[react/view {:flex 1}
|
[react/view {:flex 1}
|
||||||
[inner-item/home-list-item-old
|
[inner-item/home-list-item-old
|
||||||
(assoc home-item :public? true)
|
(assoc home-item :public? true)
|
||||||
{:on-press on-change}]]]))
|
{:on-press on-change}]]]))
|
||||||
|
|
||||||
(defn view []
|
(defn view
|
||||||
(let [{:keys [community-id]} (<sub [:get-screen-params])
|
[]
|
||||||
category-name (reagent/atom "")
|
(let [{:keys [community-id]} (rf/sub [:get-screen-params])
|
||||||
|
category-name (reagent/atom "")
|
||||||
_ (reset! selected-items #{})]
|
_ (reset! selected-items #{})]
|
||||||
(fn []
|
(fn []
|
||||||
(let [chats (<sub [:chats/with-empty-category-by-community-id community-id])]
|
(let [chats (rf/sub [:chats/with-empty-category-by-community-id community-id])]
|
||||||
[kb-presentation/keyboard-avoiding-view {:style {:flex 1}}
|
[kb-presentation/keyboard-avoiding-view {:style {:flex 1}}
|
||||||
[react/view {:flex 1}
|
[react/view {:flex 1}
|
||||||
[react/view {:padding-horizontal 16}
|
[react/view {:padding-horizontal 16}
|
||||||
@@ -57,12 +61,13 @@
|
|||||||
[toolbar/toolbar
|
[toolbar/toolbar
|
||||||
{:show-border? true
|
{:show-border? true
|
||||||
:center
|
:center
|
||||||
[quo/button {:disabled (not (valid? @category-name))
|
[quo/button
|
||||||
:type :secondary
|
{:disabled (not (valid? @category-name))
|
||||||
:on-press #(debounce/dispatch-and-chill
|
:type :secondary
|
||||||
[::communities/create-category-confirmation-pressed
|
:on-press #(debounce/dispatch-and-chill
|
||||||
community-id
|
[::communities/create-category-confirmation-pressed
|
||||||
@category-name
|
community-id
|
||||||
(vec @selected-items)]
|
@category-name
|
||||||
3000)}
|
(vec @selected-items)]
|
||||||
|
3000)}
|
||||||
(i18n/label :t/create)]}]]))))
|
(i18n/label :t/create)]}]]))))
|
||||||
|
|||||||
@@ -1,65 +1,72 @@
|
|||||||
(ns status-im.ui.screens.communities.create-channel
|
(ns status-im.ui.screens.communities.create-channel
|
||||||
(:require [clojure.string :as string]
|
(:require [clojure.string :as string]
|
||||||
[quo.react-native :as rn]
|
|
||||||
[quo.core :as quo]
|
[quo.core :as quo]
|
||||||
[status-im.i18n.i18n :as i18n]
|
[quo.react-native :as rn]
|
||||||
[status-im.ui.components.toolbar :as toolbar]
|
|
||||||
[status-im.communities.core :as communities]
|
[status-im.communities.core :as communities]
|
||||||
[utils.debounce :as debounce]
|
[status-im.i18n.i18n :as i18n]
|
||||||
[status-im.utils.handlers :refer [>evt <sub]]
|
[status-im.ui.components.emoji-thumbnail.preview :as emoji-thumbnail-preview]
|
||||||
[status-im.ui.screens.communities.create :as create]
|
|
||||||
[status-im.ui.components.keyboard-avoid-presentation :as kb-presentation]
|
|
||||||
[status-im.ui.components.emoji-thumbnail.styles :as styles]
|
[status-im.ui.components.emoji-thumbnail.styles :as styles]
|
||||||
[status-im.ui.components.emoji-thumbnail.preview :as emoji-thumbnail-preview]))
|
[status-im.ui.components.keyboard-avoid-presentation :as kb-presentation]
|
||||||
|
[status-im.ui.components.toolbar :as toolbar]
|
||||||
|
[status-im.ui.screens.communities.create :as create]
|
||||||
|
[utils.debounce :as debounce]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(defn valid? [channel-name channel-description]
|
(defn valid?
|
||||||
|
[channel-name channel-description]
|
||||||
(and (not (string/blank? channel-name))
|
(and (not (string/blank? channel-name))
|
||||||
(not (string/blank? channel-description))
|
(not (string/blank? channel-description))
|
||||||
(<= (count channel-name) create/max-name-length)
|
(<= (count channel-name) create/max-name-length)
|
||||||
(<= (count channel-description) create/max-description-length)))
|
(<= (count channel-description) create/max-description-length)))
|
||||||
|
|
||||||
(defn thumbnail []
|
(defn thumbnail
|
||||||
(let [{:keys [color emoji]} (<sub [:communities/create-channel])
|
[]
|
||||||
size styles/emoji-thumbnail-preview-size]
|
(let [{:keys [color emoji]} (rf/sub [:communities/create-channel])
|
||||||
|
size styles/emoji-thumbnail-preview-size]
|
||||||
[rn/view styles/emoji-thumbnail-preview
|
[rn/view styles/emoji-thumbnail-preview
|
||||||
[emoji-thumbnail-preview/emoji-thumbnail-touchable
|
[emoji-thumbnail-preview/emoji-thumbnail-touchable
|
||||||
emoji color size
|
emoji color size
|
||||||
#(>evt [:open-modal :community-emoji-thumbnail-picker nil])]]))
|
#(rf/dispatch [:open-modal :community-emoji-thumbnail-picker nil])]]))
|
||||||
|
|
||||||
(defn form []
|
(defn form
|
||||||
(let [{:keys [name description]} (<sub [:communities/create-channel])]
|
[]
|
||||||
[rn/scroll-view {:style {:flex 1}
|
(let [{:keys [name description]} (rf/sub [:communities/create-channel])]
|
||||||
:content-container-style {:padding-bottom 16}}
|
[rn/scroll-view
|
||||||
|
{:style {:flex 1}
|
||||||
|
:content-container-style {:padding-bottom 16}}
|
||||||
[:<>
|
[:<>
|
||||||
[thumbnail]
|
[thumbnail]
|
||||||
[rn/view {:padding-horizontal 16}
|
[rn/view {:padding-horizontal 16}
|
||||||
[quo/text-input
|
[quo/text-input
|
||||||
{:placeholder (i18n/label :t/name-your-channel-placeholder)
|
{:placeholder (i18n/label :t/name-your-channel-placeholder)
|
||||||
:on-change-text #(>evt [::communities/create-channel-field :name %])
|
:on-change-text #(rf/dispatch [::communities/create-channel-field :name %])
|
||||||
:default-value name
|
:default-value name
|
||||||
:auto-focus false}]]
|
:auto-focus false}]]
|
||||||
[quo/separator {:style {:margin-vertical 16}}]
|
[quo/separator {:style {:margin-vertical 16}}]
|
||||||
[rn/view {:padding-horizontal 16}
|
[rn/view {:padding-horizontal 16}
|
||||||
[create/countable-label {:label (i18n/label :t/description)
|
[create/countable-label
|
||||||
:text description
|
{:label (i18n/label :t/description)
|
||||||
:max-length create/max-description-length}]
|
:text description
|
||||||
|
:max-length create/max-description-length}]
|
||||||
[quo/text-input
|
[quo/text-input
|
||||||
{:placeholder (i18n/label :t/give-a-short-description-community)
|
{:placeholder (i18n/label :t/give-a-short-description-community)
|
||||||
:multiline true
|
:multiline true
|
||||||
:default-value description
|
:default-value description
|
||||||
:on-change-text #(>evt [::communities/create-channel-field :description %])}]]]]))
|
:on-change-text #(rf/dispatch [::communities/create-channel-field :description %])}]]]]))
|
||||||
|
|
||||||
(defn view []
|
(defn view
|
||||||
(let [{:keys [name description]} (<sub [:communities/create-channel])]
|
[]
|
||||||
|
(let [{:keys [name description]} (rf/sub [:communities/create-channel])]
|
||||||
[kb-presentation/keyboard-avoiding-view {:style {:flex 1}}
|
[kb-presentation/keyboard-avoiding-view {:style {:flex 1}}
|
||||||
[quo/separator]
|
[quo/separator]
|
||||||
[form]
|
[form]
|
||||||
[toolbar/toolbar
|
[toolbar/toolbar
|
||||||
{:show-border? true
|
{:show-border? true
|
||||||
:center
|
:center
|
||||||
[quo/button {:disabled (not (valid? name description))
|
[quo/button
|
||||||
:type :secondary
|
{:disabled (not (valid? name description))
|
||||||
:on-press #(debounce/dispatch-and-chill
|
:type :secondary
|
||||||
[::communities/create-channel-confirmation-pressed]
|
:on-press #(debounce/dispatch-and-chill
|
||||||
3000)}
|
[::communities/create-channel-confirmation-pressed]
|
||||||
|
3000)}
|
||||||
(i18n/label :t/create)]}]]))
|
(i18n/label :t/create)]}]]))
|
||||||
|
|||||||
@@ -1,19 +1,21 @@
|
|||||||
(ns status-im.ui.screens.communities.edit
|
(ns status-im.ui.screens.communities.edit
|
||||||
(:require [quo.core :as quo]
|
(:require [quo.core :as quo]
|
||||||
[status-im.i18n.i18n :as i18n]
|
|
||||||
[status-im.ui.screens.communities.create :as community.create]
|
|
||||||
[status-im.utils.handlers :refer [>evt <sub]]
|
|
||||||
[status-im.communities.core :as communities]
|
[status-im.communities.core :as communities]
|
||||||
[status-im.ui.components.toolbar :as toolbar]))
|
[status-im.i18n.i18n :as i18n]
|
||||||
|
[status-im.ui.components.toolbar :as toolbar]
|
||||||
|
[status-im.ui.screens.communities.create :as community.create]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(defn edit []
|
(defn edit
|
||||||
(let [{:keys [name description]} (<sub [:communities/create])]
|
[]
|
||||||
|
(let [{:keys [name description]} (rf/sub [:communities/create])]
|
||||||
[:<>
|
[:<>
|
||||||
[community.create/form]
|
[community.create/form]
|
||||||
[toolbar/toolbar
|
[toolbar/toolbar
|
||||||
{:show-border? true
|
{:show-border? true
|
||||||
:center
|
:center
|
||||||
[quo/button {:disabled (not (community.create/valid? name description))
|
[quo/button
|
||||||
:type :secondary
|
{:disabled (not (community.create/valid? name description))
|
||||||
:on-press #(>evt [::communities/edit-confirmation-pressed])}
|
:type :secondary
|
||||||
|
:on-press #(rf/dispatch [::communities/edit-confirmation-pressed])}
|
||||||
(i18n/label :t/save)]}]]))
|
(i18n/label :t/save)]}]]))
|
||||||
|
|||||||
@@ -1,27 +1,30 @@
|
|||||||
(ns status-im.ui.screens.communities.edit-channel
|
(ns status-im.ui.screens.communities.edit-channel
|
||||||
(:require [clojure.string :as string]
|
(:require [clojure.string :as string]
|
||||||
[quo.core :as quo]
|
[quo.core :as quo]
|
||||||
|
[status-im.communities.core :as communities]
|
||||||
[status-im.i18n.i18n :as i18n]
|
[status-im.i18n.i18n :as i18n]
|
||||||
[status-im.ui.components.toolbar :as toolbar]
|
[status-im.ui.components.toolbar :as toolbar]
|
||||||
[status-im.communities.core :as communities]
|
[status-im.ui.screens.communities.create-channel :as create-channel]
|
||||||
[utils.debounce :as debounce]
|
[utils.debounce :as debounce]
|
||||||
[status-im.utils.handlers :refer [<sub]]
|
[utils.re-frame :as rf]))
|
||||||
[status-im.ui.screens.communities.create-channel :as create-channel]))
|
|
||||||
|
|
||||||
(defn valid? [community-name]
|
(defn valid?
|
||||||
|
[community-name]
|
||||||
(not (string/blank? community-name)))
|
(not (string/blank? community-name)))
|
||||||
|
|
||||||
(defn view []
|
(defn view
|
||||||
(let [{:keys [name]} (<sub [:communities/create-channel])]
|
[]
|
||||||
|
(let [{:keys [name]} (rf/sub [:communities/create-channel])]
|
||||||
(fn []
|
(fn []
|
||||||
[:<>
|
[:<>
|
||||||
[create-channel/form]
|
[create-channel/form]
|
||||||
[toolbar/toolbar
|
[toolbar/toolbar
|
||||||
{:show-border? true
|
{:show-border? true
|
||||||
:center
|
:center
|
||||||
[quo/button {:disabled (not (valid? name))
|
[quo/button
|
||||||
:type :secondary
|
{:disabled (not (valid? name))
|
||||||
:on-press #(debounce/dispatch-and-chill
|
:type :secondary
|
||||||
[::communities/edit-channel-confirmation-pressed]
|
:on-press #(debounce/dispatch-and-chill
|
||||||
3000)}
|
[::communities/edit-channel-confirmation-pressed]
|
||||||
|
3000)}
|
||||||
(i18n/label :t/save)]}]])))
|
(i18n/label :t/save)]}]])))
|
||||||
|
|||||||
@@ -1,20 +1,23 @@
|
|||||||
(ns status-im.ui.screens.communities.import
|
(ns status-im.ui.screens.communities.import
|
||||||
(:require [quo.react-native :as rn]
|
(:require [quo.core :as quo]
|
||||||
|
[quo.react-native :as rn]
|
||||||
[reagent.core :as reagent]
|
[reagent.core :as reagent]
|
||||||
[quo.core :as quo]
|
|
||||||
[status-im.i18n.i18n :as i18n]
|
|
||||||
[status-im.utils.handlers :refer [>evt]]
|
|
||||||
[status-im.communities.core :as communities]
|
[status-im.communities.core :as communities]
|
||||||
[status-im.ui.components.toolbar :as toolbar]))
|
[status-im.i18n.i18n :as i18n]
|
||||||
|
[status-im.ui.components.toolbar :as toolbar]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(defn view []
|
(defn view
|
||||||
|
[]
|
||||||
(let [community-key (reagent/atom "")]
|
(let [community-key (reagent/atom "")]
|
||||||
(fn []
|
(fn []
|
||||||
[:<>
|
[:<>
|
||||||
[rn/scroll-view {:style {:flex 1}
|
[rn/scroll-view
|
||||||
:content-container-style {:padding 16}}
|
{:style {:flex 1}
|
||||||
[rn/view {:style {:padding-bottom 16
|
:content-container-style {:padding 16}}
|
||||||
:padding-top 10}}
|
[rn/view
|
||||||
|
{:style {:padding-bottom 16
|
||||||
|
:padding-top 10}}
|
||||||
[quo/text-input
|
[quo/text-input
|
||||||
{:label (i18n/label :t/community-key)
|
{:label (i18n/label :t/community-key)
|
||||||
:placeholder (i18n/label :t/community-key-placeholder)
|
:placeholder (i18n/label :t/community-key-placeholder)
|
||||||
@@ -24,7 +27,8 @@
|
|||||||
|
|
||||||
[toolbar/toolbar
|
[toolbar/toolbar
|
||||||
{:show-border? true
|
{:show-border? true
|
||||||
:center [quo/button {:disabled (= @community-key "")
|
:center [quo/button
|
||||||
:type :secondary
|
{:disabled (= @community-key "")
|
||||||
:on-press #(>evt [::communities/import @community-key])}
|
:type :secondary
|
||||||
|
:on-press #(rf/dispatch [::communities/import @community-key])}
|
||||||
(i18n/label :t/import)]}]])))
|
(i18n/label :t/import)]}]])))
|
||||||
|
|||||||
@@ -1,21 +1,24 @@
|
|||||||
(ns status-im.ui.screens.communities.invite
|
(ns status-im.ui.screens.communities.invite
|
||||||
(:require [reagent.core :as reagent]
|
(:require [clojure.string :as string]
|
||||||
[quo.react-native :as rn]
|
|
||||||
[quo.core :as quo]
|
[quo.core :as quo]
|
||||||
[status-im.i18n.i18n :as i18n]
|
[quo.react-native :as rn]
|
||||||
[status-im.constants :as constants]
|
[reagent.core :as reagent]
|
||||||
[status-im.ui.components.toolbar :as toolbar]
|
|
||||||
[status-im.utils.handlers :refer [<sub >evt-once]]
|
|
||||||
[status-im.communities.core :as communities]
|
[status-im.communities.core :as communities]
|
||||||
[status-im.ui.components.topbar :as topbar]
|
[status-im.constants :as constants]
|
||||||
[status-im.ui.components.chat-icon.screen :as chat-icon.screen]
|
[status-im.i18n.i18n :as i18n]
|
||||||
[status-im.multiaccounts.core :as multiaccounts]
|
[status-im.multiaccounts.core :as multiaccounts]
|
||||||
[clojure.string :as string]))
|
[status-im.ui.components.chat-icon.screen :as chat-icon.screen]
|
||||||
|
[status-im.ui.components.toolbar :as toolbar]
|
||||||
|
[status-im.ui.components.topbar :as topbar]
|
||||||
|
[utils.debounce :as debounce]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(defn header [user-pk]
|
(defn header
|
||||||
|
[user-pk]
|
||||||
[:<>
|
[:<>
|
||||||
[rn/view {:style {:padding-horizontal 16
|
[rn/view
|
||||||
:padding-vertical 8}}
|
{:style {:padding-horizontal 16
|
||||||
|
:padding-vertical 8}}
|
||||||
[quo/text-input
|
[quo/text-input
|
||||||
{:label (i18n/label :t/enter-user-pk)
|
{:label (i18n/label :t/enter-user-pk)
|
||||||
:placeholder (i18n/label :t/enter-user-pk)
|
:placeholder (i18n/label :t/enter-user-pk)
|
||||||
@@ -25,7 +28,8 @@
|
|||||||
[quo/separator {:style {:margin-vertical 8}}]
|
[quo/separator {:style {:margin-vertical 8}}]
|
||||||
[quo/list-header (i18n/label :t/contacts)]])
|
[quo/list-header (i18n/label :t/contacts)]])
|
||||||
|
|
||||||
(defn contacts-list-item [{:keys [public-key active] :as contact} _ _ {:keys [selected]}]
|
(defn contacts-list-item
|
||||||
|
[{:keys [public-key active] :as contact} _ _ {:keys [selected]}]
|
||||||
(let [[first-name second-name] (multiaccounts/contact-two-names contact true)]
|
(let [[first-name second-name] (multiaccounts/contact-two-names contact true)]
|
||||||
[quo/list-item
|
[quo/list-item
|
||||||
{:title first-name
|
{:title first-name
|
||||||
@@ -39,44 +43,51 @@
|
|||||||
(swap! selected disj public-key)
|
(swap! selected disj public-key)
|
||||||
(swap! selected conj public-key)))}]))
|
(swap! selected conj public-key)))}]))
|
||||||
|
|
||||||
(defn invite []
|
(defn invite
|
||||||
|
[]
|
||||||
(let [user-pk (reagent/atom "")
|
(let [user-pk (reagent/atom "")
|
||||||
contacts-selected (reagent/atom #{})
|
contacts-selected (reagent/atom #{})
|
||||||
{:keys [invite?]} (<sub [:get-screen-params])]
|
{:keys [invite?]} (rf/sub [:get-screen-params])]
|
||||||
(fn []
|
(fn []
|
||||||
(let [contacts-data (<sub [:contacts/active])
|
(let [contacts-data (rf/sub [:contacts/active])
|
||||||
{:keys [permissions
|
{:keys [permissions
|
||||||
can-manage-users?]} (<sub [:communities/edited-community])
|
can-manage-users?]}
|
||||||
selected @contacts-selected
|
(rf/sub [:communities/edited-community])
|
||||||
contacts (map (fn [{:keys [public-key] :as contact}]
|
selected @contacts-selected
|
||||||
(assoc contact :active (contains? selected public-key)))
|
contacts (map (fn [{:keys [public-key] :as contact}]
|
||||||
contacts-data)
|
(assoc contact :active (contains? selected public-key)))
|
||||||
|
contacts-data)
|
||||||
;; no-membership communities can only be shared
|
;; no-membership communities can only be shared
|
||||||
can-invite? (and can-manage-users?
|
can-invite? (and can-manage-users?
|
||||||
invite?
|
invite?
|
||||||
(not= (:access permissions) constants/community-no-membership-access))]
|
(not= (:access permissions) constants/community-no-membership-access))]
|
||||||
[:<>
|
[:<>
|
||||||
[topbar/topbar {:title (i18n/label (if can-invite?
|
[topbar/topbar
|
||||||
:t/invite-people
|
{:title (i18n/label (if can-invite?
|
||||||
:t/community-share-title))
|
:t/invite-people
|
||||||
:modal? true}]
|
:t/community-share-title))
|
||||||
[rn/flat-list {:style {:flex 1}
|
:modal? true}]
|
||||||
:content-container-style {:padding-vertical 16}
|
[rn/flat-list
|
||||||
;:header [header user-pk]
|
{:style {:flex 1}
|
||||||
:render-data {:selected contacts-selected}
|
:content-container-style {:padding-vertical 16}
|
||||||
:render-fn contacts-list-item
|
;:header [header user-pk]
|
||||||
:key-fn (fn [{:keys [active public-key]}]
|
:render-data {:selected contacts-selected}
|
||||||
(str public-key active))
|
:render-fn contacts-list-item
|
||||||
:data contacts}]
|
:key-fn (fn [{:keys [active public-key]}]
|
||||||
|
(str public-key active))
|
||||||
|
:data contacts}]
|
||||||
[toolbar/toolbar
|
[toolbar/toolbar
|
||||||
{:show-border? true
|
{:show-border? true
|
||||||
:center
|
:center
|
||||||
[quo/button {:disabled (and (string/blank? @user-pk)
|
[quo/button
|
||||||
|
{:disabled (and (string/blank? @user-pk)
|
||||||
(zero? (count selected)))
|
(zero? (count selected)))
|
||||||
:accessibility-label :share-community-link
|
:accessibility-label :share-community-link
|
||||||
:type :secondary
|
:type :secondary
|
||||||
:on-press #(>evt-once
|
:on-press #(debounce/dispatch-and-chill
|
||||||
[(if can-invite?
|
[(if can-invite?
|
||||||
::communities/invite-people-confirmation-pressed
|
::communities/invite-people-confirmation-pressed
|
||||||
::communities/share-community-confirmation-pressed) @user-pk selected])}
|
::communities/share-community-confirmation-pressed) @user-pk
|
||||||
|
selected]
|
||||||
|
3000)}
|
||||||
(i18n/label (if can-invite? :t/invite :t/share))]}]]))))
|
(i18n/label (if can-invite? :t/invite :t/share))]}]]))))
|
||||||
|
|||||||
@@ -1,22 +1,24 @@
|
|||||||
(ns status-im.ui.screens.communities.members
|
(ns status-im.ui.screens.communities.members
|
||||||
(:require [quo.react-native :as rn]
|
(:require [quo.core :as quo]
|
||||||
[quo.core :as quo]
|
[quo.react-native :as rn]
|
||||||
[reagent.core :as reagent]
|
[reagent.core :as reagent]
|
||||||
|
[status-im.communities.core :as communities]
|
||||||
[status-im.constants :as constants]
|
[status-im.constants :as constants]
|
||||||
[status-im.ui.components.react :as react]
|
|
||||||
[status-im.utils.handlers :refer [<sub >evt]]
|
|
||||||
[status-im.ui.components.chat-icon.screen :as chat-icon]
|
|
||||||
[status-im.ui.components.unviewed-indicator :as unviewed-indicator]
|
|
||||||
[status-im.multiaccounts.core :as multiaccounts]
|
|
||||||
[status-im.ui.components.topbar :as topbar]
|
|
||||||
[status-im.i18n.i18n :as i18n]
|
[status-im.i18n.i18n :as i18n]
|
||||||
[status-im.communities.core :as communities]))
|
[status-im.multiaccounts.core :as multiaccounts]
|
||||||
|
[status-im.ui.components.chat-icon.screen :as chat-icon]
|
||||||
|
[status-im.ui.components.react :as react]
|
||||||
|
[status-im.ui.components.topbar :as topbar]
|
||||||
|
[status-im.ui.components.unviewed-indicator :as unviewed-indicator]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(defn hide-sheet-and-dispatch [event]
|
(defn hide-sheet-and-dispatch
|
||||||
(>evt [:bottom-sheet/hide])
|
[event]
|
||||||
(>evt event))
|
(rf/dispatch [:bottom-sheet/hide])
|
||||||
|
(rf/dispatch event))
|
||||||
|
|
||||||
(defn member-sheet [first-name {:keys [public-key] :as member} community-id can-kick-users? can-manage-users? admin?]
|
(defn member-sheet
|
||||||
|
[first-name {:keys [public-key] :as member} community-id can-kick-users? can-manage-users? admin?]
|
||||||
[:<>
|
[:<>
|
||||||
[quo/list-item
|
[quo/list-item
|
||||||
{:theme :accent
|
{:theme :accent
|
||||||
@@ -30,30 +32,36 @@
|
|||||||
(when can-kick-users?
|
(when can-kick-users?
|
||||||
[:<>
|
[:<>
|
||||||
[quo/separator {:style {:margin-vertical 8}}]
|
[quo/separator {:style {:margin-vertical 8}}]
|
||||||
[quo/list-item {:theme :negative
|
[quo/list-item
|
||||||
:icon :main-icons/arrow-left
|
{:theme :negative
|
||||||
:title (i18n/label :t/member-kick)
|
:icon :main-icons/arrow-left
|
||||||
:on-press #(>evt [::communities/member-kick community-id public-key])}]])
|
:title (i18n/label :t/member-kick)
|
||||||
|
:on-press #(rf/dispatch [::communities/member-kick community-id public-key])}]])
|
||||||
(when can-manage-users?
|
(when can-manage-users?
|
||||||
[:<>
|
[:<>
|
||||||
[quo/list-item {:theme :negative
|
[quo/list-item
|
||||||
:icon :main-icons/cancel
|
{:theme :negative
|
||||||
:title (i18n/label :t/member-ban)
|
:icon :main-icons/cancel
|
||||||
:on-press #(>evt [::communities/member-ban community-id public-key])}]])
|
:title (i18n/label :t/member-ban)
|
||||||
|
:on-press #(rf/dispatch [::communities/member-ban community-id public-key])}]])
|
||||||
(when admin?
|
(when admin?
|
||||||
[:<>
|
[:<>
|
||||||
[quo/list-item {:theme :accent
|
[quo/list-item
|
||||||
:icon :main-icons/make-admin
|
{:theme :accent
|
||||||
:title (i18n/label :t/make-moderator)
|
:icon :main-icons/make-admin
|
||||||
:on-press #(>evt [:community.member/add-role community-id public-key constants/community-member-role-moderator])}]])])
|
:title (i18n/label :t/make-moderator)
|
||||||
|
:on-press #(rf/dispatch [:community.member/add-role community-id public-key
|
||||||
|
constants/community-member-role-moderator])}]])])
|
||||||
|
|
||||||
(defn render-member [public-key _ _ {:keys [community-id
|
(defn render-member
|
||||||
my-public-key
|
[public-key _ _
|
||||||
can-manage-users?
|
{:keys [community-id
|
||||||
can-kick-users?
|
my-public-key
|
||||||
admin?]}]
|
can-manage-users?
|
||||||
(let [member (<sub [:contacts/contact-by-identity public-key])
|
can-kick-users?
|
||||||
[first-name second-name] (<sub [:contacts/contact-two-names-by-identity public-key])]
|
admin?]}]
|
||||||
|
(let [member (rf/sub [:contacts/contact-by-identity public-key])
|
||||||
|
[first-name second-name] (rf/sub [:contacts/contact-two-names-by-identity public-key])]
|
||||||
[quo/list-item
|
[quo/list-item
|
||||||
{:title first-name
|
{:title first-name
|
||||||
:subtitle second-name
|
:subtitle second-name
|
||||||
@@ -62,66 +70,78 @@
|
|||||||
{:public-key public-key
|
{:public-key public-key
|
||||||
:photo-path (multiaccounts/displayed-photo member)}]
|
:photo-path (multiaccounts/displayed-photo member)}]
|
||||||
:accessory (when (not= public-key my-public-key)
|
:accessory (when (not= public-key my-public-key)
|
||||||
[quo/button {:on-press
|
[quo/button
|
||||||
#(>evt [:bottom-sheet/show-sheet
|
{:on-press
|
||||||
{:content (fn []
|
#(rf/dispatch [:bottom-sheet/show-sheet
|
||||||
[member-sheet first-name member community-id can-kick-users? can-manage-users? admin?])}])
|
{:content (fn []
|
||||||
:type :icon
|
[member-sheet first-name member community-id
|
||||||
:theme :icon
|
can-kick-users? can-manage-users? admin?])}])
|
||||||
:accessibility-label :menu-option}
|
:type :icon
|
||||||
|
:theme :icon
|
||||||
|
:accessibility-label :menu-option}
|
||||||
:main-icons/more])}]))
|
:main-icons/more])}]))
|
||||||
|
|
||||||
(defn header [community-id]
|
(defn header
|
||||||
|
[community-id]
|
||||||
[:<>
|
[:<>
|
||||||
[quo/list-item {:icon :main-icons/share
|
[quo/list-item
|
||||||
:title (i18n/label :t/invite-people)
|
{:icon :main-icons/share
|
||||||
:accessibility-label :community-invite-people
|
:title (i18n/label :t/invite-people)
|
||||||
:theme :accent
|
:accessibility-label :community-invite-people
|
||||||
:on-press #(>evt [:communities/invite-people-pressed community-id])}]
|
:theme :accent
|
||||||
|
:on-press #(rf/dispatch [:communities/invite-people-pressed community-id])}]
|
||||||
[quo/separator {:style {:margin-vertical 8}}]])
|
[quo/separator {:style {:margin-vertical 8}}]])
|
||||||
|
|
||||||
(defn requests-to-join [community-id]
|
(defn requests-to-join
|
||||||
(let [requests (<sub [:communities/requests-to-join-for-community community-id])
|
[community-id]
|
||||||
|
(let [requests (rf/sub [:communities/requests-to-join-for-community community-id])
|
||||||
requests-count (count requests)]
|
requests-count (count requests)]
|
||||||
[:<>
|
[:<>
|
||||||
[quo/list-item {:chevron true
|
[quo/list-item
|
||||||
:accessory
|
{:chevron true
|
||||||
[react/view {:flex-direction :row}
|
:accessory
|
||||||
(when (pos? requests-count)
|
[react/view {:flex-direction :row}
|
||||||
[unviewed-indicator/unviewed-indicator requests-count])]
|
(when (pos? requests-count)
|
||||||
:on-press #(>evt [:navigate-to :community-requests-to-join {:community-id community-id}])
|
[unviewed-indicator/unviewed-indicator requests-count])]
|
||||||
:title (i18n/label :t/membership-requests)}]
|
:on-press #(rf/dispatch [:navigate-to :community-requests-to-join {:community-id community-id}])
|
||||||
|
:title (i18n/label :t/membership-requests)}]
|
||||||
[quo/separator {:style {:margin-vertical 8}}]]))
|
[quo/separator {:style {:margin-vertical 8}}]]))
|
||||||
|
|
||||||
(defn members []
|
(defn members
|
||||||
(let [{:keys [community-id]} (<sub [:get-screen-params])]
|
[]
|
||||||
|
(let [{:keys [community-id]} (rf/sub [:get-screen-params])]
|
||||||
(fn []
|
(fn []
|
||||||
(let [my-public-key (<sub [:multiaccount/public-key])
|
(let [my-public-key (rf/sub [:multiaccount/public-key])
|
||||||
{:keys [permissions
|
{:keys [permissions
|
||||||
can-manage-users?
|
can-manage-users?
|
||||||
admin]} (<sub [:communities/community community-id])
|
admin]}
|
||||||
sorted-members (<sub [:communities/sorted-community-members
|
(rf/sub [:communities/community community-id])
|
||||||
community-id])]
|
sorted-members (rf/sub [:communities/sorted-community-members
|
||||||
|
community-id])]
|
||||||
[:<>
|
[:<>
|
||||||
[topbar/topbar {:title (i18n/label :t/community-members-title)
|
[topbar/topbar
|
||||||
:subtitle (str (count sorted-members))}]
|
{:title (i18n/label :t/community-members-title)
|
||||||
|
:subtitle (str (count sorted-members))}]
|
||||||
[header community-id]
|
[header community-id]
|
||||||
(when (and can-manage-users? (= constants/community-on-request-access (:access permissions)))
|
(when (and can-manage-users? (= constants/community-on-request-access (:access permissions)))
|
||||||
[requests-to-join community-id])
|
[requests-to-join community-id])
|
||||||
[rn/flat-list {:data (keys sorted-members)
|
[rn/flat-list
|
||||||
:render-data {:community-id community-id
|
{:data (keys sorted-members)
|
||||||
:my-public-key my-public-key
|
:render-data {:community-id community-id
|
||||||
:can-kick-users? (and can-manage-users?
|
:my-public-key my-public-key
|
||||||
(not= (:access permissions)
|
:can-kick-users? (and can-manage-users?
|
||||||
constants/community-no-membership-access))
|
(not= (:access permissions)
|
||||||
:can-manage-users? can-manage-users?
|
constants/community-no-membership-access))
|
||||||
:admin? admin}
|
:can-manage-users? can-manage-users?
|
||||||
:key-fn identity
|
:admin? admin}
|
||||||
:render-fn render-member}]]))))
|
:key-fn identity
|
||||||
|
:render-fn render-member}]]))))
|
||||||
|
|
||||||
(defn members-container []
|
(defn members-container
|
||||||
|
[]
|
||||||
(reagent/create-class
|
(reagent/create-class
|
||||||
{:display-name "community-members-view"
|
{:display-name "community-members-view"
|
||||||
:component-did-mount (fn []
|
:component-did-mount (fn []
|
||||||
(communities/fetch-requests-to-join! (get (<sub [:get-screen-params]) :community-id)))
|
(communities/fetch-requests-to-join! (get (rf/sub [:get-screen-params])
|
||||||
|
:community-id)))
|
||||||
:reagent-render members}))
|
:reagent-render members}))
|
||||||
|
|||||||
@@ -1,41 +1,47 @@
|
|||||||
(ns status-im.ui.screens.communities.membership
|
(ns status-im.ui.screens.communities.membership
|
||||||
(:require [quo.react-native :as rn]
|
(:require [quo.core :as quo]
|
||||||
[status-im.ui.components.toolbar :as toolbar]
|
[quo.react-native :as rn]
|
||||||
[quo.core :as quo]
|
|
||||||
[status-im.i18n.i18n :as i18n]
|
|
||||||
[status-im.utils.handlers :refer [>evt <sub]]
|
|
||||||
[status-im.communities.core :as communities]
|
[status-im.communities.core :as communities]
|
||||||
[status-im.constants :as constants]))
|
[status-im.constants :as constants]
|
||||||
|
[status-im.i18n.i18n :as i18n]
|
||||||
|
[status-im.ui.components.toolbar :as toolbar]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(def options {constants/community-on-request-access
|
(def options
|
||||||
{:title :t/membership-approval
|
{constants/community-on-request-access
|
||||||
:description :t/membership-approval-description}
|
{:title :t/membership-approval
|
||||||
constants/community-no-membership-access
|
:description :t/membership-approval-description}
|
||||||
{:title :t/membership-free
|
constants/community-no-membership-access
|
||||||
:description :t/membership-free-description}})
|
{:title :t/membership-free
|
||||||
|
:description :t/membership-free-description}})
|
||||||
|
|
||||||
(defn option [{:keys [title description]} {:keys [selected on-select]}]
|
(defn option
|
||||||
|
[{:keys [title description]} {:keys [selected on-select]}]
|
||||||
[:<>
|
[:<>
|
||||||
[quo/list-item {:title (i18n/label title)
|
[quo/list-item
|
||||||
:size :small
|
{:title (i18n/label title)
|
||||||
:accessory :radio
|
:size :small
|
||||||
:active selected
|
:accessory :radio
|
||||||
:on-press on-select}]
|
:active selected
|
||||||
|
:on-press on-select}]
|
||||||
[quo/list-footer
|
[quo/list-footer
|
||||||
(i18n/label description)]
|
(i18n/label description)]
|
||||||
[quo/separator {:style {:margin-vertical 8}}]])
|
[quo/separator {:style {:margin-vertical 8}}]])
|
||||||
|
|
||||||
(defn membership []
|
(defn membership
|
||||||
(let [{:keys [membership]} (<sub [:communities/create])]
|
[]
|
||||||
|
(let [{:keys [membership]} (rf/sub [:communities/create])]
|
||||||
[:<>
|
[:<>
|
||||||
[rn/scroll-view {}
|
[rn/scroll-view {}
|
||||||
(doall
|
(doall
|
||||||
(for [[id o] options]
|
(for [[id o] options]
|
||||||
^{:key (str "option-" id)}
|
^{:key (str "option-" id)}
|
||||||
[option o {:selected (= id membership)
|
[option o
|
||||||
:on-select #(>evt [::communities/create-field :membership id])}]))]
|
{:selected (= id membership)
|
||||||
|
:on-select #(rf/dispatch [::communities/create-field :membership id])}]))]
|
||||||
[toolbar/toolbar
|
[toolbar/toolbar
|
||||||
{:show-border? true
|
{:show-border? true
|
||||||
:center [quo/button {:type :secondary
|
:center [quo/button
|
||||||
:on-press #(>evt [:navigate-back])}
|
{:type :secondary
|
||||||
|
:on-press #(rf/dispatch [:navigate-back])}
|
||||||
(i18n/label :t/done)]}]]))
|
(i18n/label :t/done)]}]]))
|
||||||
|
|||||||
@@ -1,52 +1,57 @@
|
|||||||
(ns status-im.ui.screens.communities.profile
|
(ns status-im.ui.screens.communities.profile
|
||||||
(:require [quo.core :as quo]
|
(:require [clojure.string :as string]
|
||||||
[status-im.utils.handlers :refer [>evt <sub]]
|
[quo.core :as quo]
|
||||||
[status-im.ui.components.profile-header.view :as profile-header]
|
|
||||||
[status-im.i18n.i18n :as i18n]
|
|
||||||
[reagent.core :as reagent]
|
|
||||||
[status-im.ui.components.copyable-text :as copyable-text]
|
|
||||||
[status-im.communities.core :as communities]
|
|
||||||
[quo.design-system.colors :as colors]
|
[quo.design-system.colors :as colors]
|
||||||
[status-im.ui.components.react :as react]
|
|
||||||
[status-im.constants :as constants]
|
|
||||||
[status-im.react-native.resources :as resources]
|
|
||||||
[status-im.ui.components.unviewed-indicator :as unviewed-indicator]
|
|
||||||
[quo.react-native :as rn]
|
[quo.react-native :as rn]
|
||||||
[clojure.string :as string]))
|
[reagent.core :as reagent]
|
||||||
|
[status-im.communities.core :as communities]
|
||||||
|
[status-im.constants :as constants]
|
||||||
|
[status-im.i18n.i18n :as i18n]
|
||||||
|
[status-im.react-native.resources :as resources]
|
||||||
|
[status-im.ui.components.copyable-text :as copyable-text]
|
||||||
|
[status-im.ui.components.profile-header.view :as profile-header]
|
||||||
|
[status-im.ui.components.react :as react]
|
||||||
|
[status-im.ui.components.unviewed-indicator :as unviewed-indicator]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(defn management []
|
(defn management
|
||||||
(let [{:keys [community-id]} (<sub [:get-screen-params])]
|
[]
|
||||||
|
(let [{:keys [community-id]} (rf/sub [:get-screen-params])]
|
||||||
(fn []
|
(fn []
|
||||||
(let [requests-to-join (<sub [:communities/requests-to-join-for-community community-id])
|
(let [requests-to-join (rf/sub [:communities/requests-to-join-for-community community-id])
|
||||||
community (<sub [:communities/community community-id])
|
community (rf/sub [:communities/community community-id])
|
||||||
{:keys [color members permissions description name admin]} community
|
{:keys [color members permissions description name admin]} community
|
||||||
roles false
|
roles false
|
||||||
notifications false
|
notifications false
|
||||||
show-members-count? (not= (:access permissions) constants/community-no-membership-access)
|
show-members-count? (not= (:access permissions) constants/community-no-membership-access)
|
||||||
request-membership? (= (:access permissions) constants/community-on-request-access)
|
request-membership? (= (:access permissions) constants/community-on-request-access)
|
||||||
members-count (count members)]
|
members-count (count members)]
|
||||||
[:<>
|
[:<>
|
||||||
[quo/animated-header {:left-accessories [{:icon :main-icons/arrow-left
|
[quo/animated-header
|
||||||
:accessibility-label :back-button
|
{:left-accessories [{:icon :main-icons/arrow-left
|
||||||
:on-press #(>evt [:navigate-back])}]
|
:accessibility-label :back-button
|
||||||
:right-accessories [{:icon :main-icons/share
|
:on-press #(rf/dispatch [:navigate-back])}]
|
||||||
:accessibility-label :invite-button
|
:right-accessories [{:icon :main-icons/share
|
||||||
:on-press #(>evt [:communities/share-community-pressed community-id])}]
|
:accessibility-label :invite-button
|
||||||
:extended-header (profile-header/extended-header
|
:on-press #(rf/dispatch [:communities/share-community-pressed
|
||||||
{:title name
|
community-id])}]
|
||||||
:color (or color (rand-nth colors/chat-colors))
|
:extended-header (profile-header/extended-header
|
||||||
:photo (if (= community-id constants/status-community-id)
|
{:title name
|
||||||
(:uri
|
:color (or color (rand-nth colors/chat-colors))
|
||||||
(rn/resolve-asset-source
|
:photo (if (= community-id constants/status-community-id)
|
||||||
(resources/get-image :status-logo)))
|
(:uri
|
||||||
(get-in community [:images :large :uri]))
|
(rn/resolve-asset-source
|
||||||
:membership (when request-membership?
|
(resources/get-image :status-logo)))
|
||||||
(i18n/label :t/membership-approval))
|
(get-in community [:images :large :uri]))
|
||||||
:subtitle (if show-members-count?
|
:membership (when request-membership?
|
||||||
(i18n/label-pluralize members-count :t/community-members {:count members-count})
|
(i18n/label :t/membership-approval))
|
||||||
(i18n/label :t/open-membership))
|
:subtitle (if show-members-count?
|
||||||
:community? true})
|
(i18n/label-pluralize members-count
|
||||||
:use-insets true}
|
:t/community-members
|
||||||
|
{:count members-count})
|
||||||
|
(i18n/label :t/open-membership))
|
||||||
|
:community? true})
|
||||||
|
:use-insets true}
|
||||||
[:<>
|
[:<>
|
||||||
(when-not (string/blank? description)
|
(when-not (string/blank? description)
|
||||||
[:<>
|
[:<>
|
||||||
@@ -55,57 +60,67 @@
|
|||||||
[quo/separator {:style {:margin-vertical 8}}]])
|
[quo/separator {:style {:margin-vertical 8}}]])
|
||||||
[:<>
|
[:<>
|
||||||
(let [link (communities/universal-link community-id)]
|
(let [link (communities/universal-link community-id)]
|
||||||
[react/view {:padding-vertical 10
|
[react/view
|
||||||
:padding-horizontal 16}
|
{:padding-vertical 10
|
||||||
|
:padding-horizontal 16}
|
||||||
[react/view {:margin-bottom 20}
|
[react/view {:margin-bottom 20}
|
||||||
[quo/text {:color :secondary} (i18n/label :t/community-link)]]
|
[quo/text {:color :secondary} (i18n/label :t/community-link)]]
|
||||||
[copyable-text/copyable-text-view
|
[copyable-text/copyable-text-view
|
||||||
{:copied-text link}
|
{:copied-text link}
|
||||||
[react/view {:border-radius 16
|
[react/view
|
||||||
:padding-horizontal 16
|
{:border-radius 16
|
||||||
:padding-vertical 11
|
:padding-horizontal 16
|
||||||
:background-color colors/blue-light}
|
:padding-vertical 11
|
||||||
|
:background-color colors/blue-light}
|
||||||
[quo/text {:color :link} (subs link 8)]]]])
|
[quo/text {:color :link} (subs link 8)]]]])
|
||||||
[quo/separator {:style {:margin-vertical 8}}]]
|
[quo/separator {:style {:margin-vertical 8}}]]
|
||||||
(when show-members-count?
|
(when show-members-count?
|
||||||
[quo/list-item {:chevron true
|
[quo/list-item
|
||||||
:accessory
|
{:chevron true
|
||||||
[react/view {:flex-direction :row}
|
:accessory
|
||||||
(when (pos? members-count)
|
[react/view {:flex-direction :row}
|
||||||
[quo/text {:color :secondary} (str members-count)])
|
(when (pos? members-count)
|
||||||
[unviewed-indicator/unviewed-indicator (count requests-to-join)]]
|
[quo/text {:color :secondary} (str members-count)])
|
||||||
:on-press #(>evt [:navigate-to :community-members {:community-id community-id}])
|
[unviewed-indicator/unviewed-indicator (count requests-to-join)]]
|
||||||
:title (i18n/label :t/members-label)
|
:on-press #(rf/dispatch [:navigate-to :community-members {:community-id community-id}])
|
||||||
:icon :main-icons/group-chat}])
|
:title (i18n/label :t/members-label)
|
||||||
|
:icon :main-icons/group-chat}])
|
||||||
(when (and admin roles)
|
(when (and admin roles)
|
||||||
[quo/list-item {:chevron true
|
[quo/list-item
|
||||||
:title (i18n/label :t/commonuity-role)
|
{:chevron true
|
||||||
:icon :main-icons/objects}])
|
:title (i18n/label :t/commonuity-role)
|
||||||
|
:icon :main-icons/objects}])
|
||||||
(when notifications
|
(when notifications
|
||||||
[quo/list-item {:chevron true
|
[quo/list-item
|
||||||
:title (i18n/label :t/chat-notification-preferences)
|
{:chevron true
|
||||||
:icon :main-icons/notification}])
|
:title (i18n/label :t/chat-notification-preferences)
|
||||||
|
:icon :main-icons/notification}])
|
||||||
(when (or show-members-count? notifications (and admin roles))
|
(when (or show-members-count? notifications (and admin roles))
|
||||||
[quo/separator {:style {:margin-vertical 8}}])
|
[quo/separator {:style {:margin-vertical 8}}])
|
||||||
(when admin
|
(when admin
|
||||||
[quo/list-item {:theme :accent
|
[quo/list-item
|
||||||
:icon :main-icons/edit
|
{:theme :accent
|
||||||
:title (i18n/label :t/edit-community)
|
:icon :main-icons/edit
|
||||||
:on-press #(>evt [::communities/open-edit-community community-id])}])
|
:title (i18n/label :t/edit-community)
|
||||||
[quo/list-item {:theme :accent
|
:on-press #(rf/dispatch [::communities/open-edit-community community-id])}])
|
||||||
:icon :main-icons/arrow-left
|
[quo/list-item
|
||||||
:title (i18n/label :t/leave-community)
|
{:theme :accent
|
||||||
:on-press #(>evt [:communities/leave community-id])}]
|
:icon :main-icons/arrow-left
|
||||||
|
:title (i18n/label :t/leave-community)
|
||||||
|
:on-press #(rf/dispatch [:communities/leave community-id])}]
|
||||||
;; Disable as not implemented yet
|
;; Disable as not implemented yet
|
||||||
(when false
|
(when false
|
||||||
[quo/list-item {:theme :negative
|
[quo/list-item
|
||||||
:icon :main-icons/delete
|
{:theme :negative
|
||||||
:title (i18n/label :t/delete)
|
:icon :main-icons/delete
|
||||||
:on-press #(>evt [::communities/delete-community community-id])}])]]]))))
|
:title (i18n/label :t/delete)
|
||||||
|
:on-press #(rf/dispatch [::communities/delete-community community-id])}])]]]))))
|
||||||
|
|
||||||
(defn management-container []
|
(defn management-container
|
||||||
|
[]
|
||||||
(reagent/create-class
|
(reagent/create-class
|
||||||
{:display-name "community-profile-view"
|
{:display-name "community-profile-view"
|
||||||
:component-did-mount (fn []
|
:component-did-mount (fn []
|
||||||
(communities/fetch-requests-to-join! (get (<sub [:get-screen-params]) :community-id)))
|
(communities/fetch-requests-to-join! (get (rf/sub [:get-screen-params])
|
||||||
:reagent-render management}))
|
:community-id)))
|
||||||
|
:reagent-render management}))
|
||||||
|
|||||||
@@ -1,43 +1,46 @@
|
|||||||
(ns status-im.ui.screens.communities.reorder-categories
|
(ns status-im.ui.screens.communities.reorder-categories
|
||||||
(:require [quo.core :as quo]
|
(:require [clojure.set :as clojure.set]
|
||||||
[clojure.walk :as walk]
|
|
||||||
[quo.react-native :as rn]
|
|
||||||
[reagent.core :as reagent]
|
|
||||||
[clojure.string :as string]
|
[clojure.string :as string]
|
||||||
[clojure.set :as clojure.set]
|
[clojure.walk :as walk]
|
||||||
[status-im.i18n.i18n :as i18n]
|
[quo.core :as quo]
|
||||||
[status-im.utils.utils :as utils]
|
|
||||||
[status-im.constants :as constants]
|
|
||||||
[quo.design-system.colors :as colors]
|
[quo.design-system.colors :as colors]
|
||||||
[status-im.utils.platform :as platform]
|
[quo.react-native :as rn]
|
||||||
[status-im.communities.core :as communities]
|
|
||||||
[status-im.utils.handlers :refer [>evt <sub]]
|
|
||||||
[status-im.ui.components.icons.icons :as icons]
|
|
||||||
[quo2.components.community.style :as styles]
|
[quo2.components.community.style :as styles]
|
||||||
[status-im.ui.components.topbar :as topbar]
|
[reagent.core :as reagent]
|
||||||
|
[status-im.communities.core :as communities]
|
||||||
|
[status-im.constants :as constants]
|
||||||
|
[status-im.i18n.i18n :as i18n]
|
||||||
|
[status-im.ui.components.icons.icons :as icons]
|
||||||
[status-im.ui.components.react :as react]
|
[status-im.ui.components.react :as react]
|
||||||
[status-im.ui.components.tabs :as tabs]
|
[status-im.ui.components.tabs :as tabs]
|
||||||
|
[status-im.ui.components.topbar :as topbar]
|
||||||
[status-im.ui.screens.communities.community :as community]
|
[status-im.ui.screens.communities.community :as community]
|
||||||
[status-im.ui.screens.home.views.inner-item :as inner-item]))
|
[status-im.ui.screens.home.views.inner-item :as inner-item]
|
||||||
|
[status-im.utils.platform :as platform]
|
||||||
|
[status-im.utils.utils :as utils]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(def data (reagent/atom []))
|
(def data (reagent/atom []))
|
||||||
(def state (reagent/atom {:tab :chats}))
|
(def state (reagent/atom {:tab :chats}))
|
||||||
|
|
||||||
(defn show-delete-chat-confirmation [community-id chat-id]
|
(defn show-delete-chat-confirmation
|
||||||
|
[community-id chat-id]
|
||||||
(utils/show-confirmation
|
(utils/show-confirmation
|
||||||
{:title (i18n/label :t/delete-confirmation)
|
{:title (i18n/label :t/delete-confirmation)
|
||||||
:content (i18n/label :t/delete-chat-confirmation)
|
:content (i18n/label :t/delete-chat-confirmation)
|
||||||
:confirm-button-text (i18n/label :t/delete)
|
:confirm-button-text (i18n/label :t/delete)
|
||||||
:on-accept #(>evt [:delete-community-chat community-id chat-id])}))
|
:on-accept #(rf/dispatch [:delete-community-chat community-id chat-id])}))
|
||||||
|
|
||||||
(defn show-delete-category-confirmation [community-id category-id]
|
(defn show-delete-category-confirmation
|
||||||
|
[community-id category-id]
|
||||||
(utils/show-confirmation
|
(utils/show-confirmation
|
||||||
{:title (i18n/label :t/delete-confirmation)
|
{:title (i18n/label :t/delete-confirmation)
|
||||||
:content (i18n/label :t/delete-category-confirmation)
|
:content (i18n/label :t/delete-category-confirmation)
|
||||||
:confirm-button-text (i18n/label :t/delete)
|
:confirm-button-text (i18n/label :t/delete)
|
||||||
:on-accept #(>evt [:delete-community-category community-id category-id])}))
|
:on-accept #(rf/dispatch [:delete-community-category community-id category-id])}))
|
||||||
|
|
||||||
(defn categories-tab? []
|
(defn categories-tab?
|
||||||
|
[]
|
||||||
(let [{:keys [tab]} @state]
|
(let [{:keys [tab]} @state]
|
||||||
(= tab :categories)))
|
(= tab :categories)))
|
||||||
|
|
||||||
@@ -46,19 +49,21 @@
|
|||||||
(let [chat-id (string/replace id community-id "")
|
(let [chat-id (string/replace id community-id "")
|
||||||
background-color (if is-active? colors/gray-lighter colors/white)
|
background-color (if is-active? colors/gray-lighter colors/white)
|
||||||
home-item (clojure.set/rename-keys home-item {:id :chat-id})]
|
home-item (clojure.set/rename-keys home-item {:id :chat-id})]
|
||||||
[rn/view {:accessibility-label :chat-item
|
[rn/view
|
||||||
:style (merge styles/category-item
|
{:accessibility-label :chat-item
|
||||||
{:background-color background-color})}
|
:style (merge styles/category-item
|
||||||
|
{:background-color background-color})}
|
||||||
[rn/touchable-opacity
|
[rn/touchable-opacity
|
||||||
{:accessibility-label :delete-community-chat
|
{:accessibility-label :delete-community-chat
|
||||||
:on-press #(show-delete-chat-confirmation community-id chat-id)}
|
:on-press #(show-delete-chat-confirmation community-id chat-id)}
|
||||||
[icons/icon :main-icons/delete-circle {:no-color true}]]
|
[icons/icon :main-icons/delete-circle {:no-color true}]]
|
||||||
[rn/view {:flex 1}
|
[rn/view {:flex 1}
|
||||||
[inner-item/home-list-item-old (assoc home-item :edit? true) {:active-opacity 1}]]
|
[inner-item/home-list-item-old (assoc home-item :edit? true) {:active-opacity 1}]]
|
||||||
[rn/touchable-opacity {:on-long-press drag
|
[rn/touchable-opacity
|
||||||
:delay-long-press 100
|
{:on-long-press drag
|
||||||
:accessibility-label :chat-drag-handle
|
:delay-long-press 100
|
||||||
:style {:padding 20}}
|
:accessibility-label :chat-drag-handle
|
||||||
|
:style {:padding 20}}
|
||||||
[icons/icon :main-icons/reorder-handle {:no-color true :width 18 :height 12}]]]))
|
[icons/icon :main-icons/reorder-handle {:no-color true :width 18 :height 12}]]]))
|
||||||
|
|
||||||
(defn category-item
|
(defn category-item
|
||||||
@@ -67,9 +72,10 @@
|
|||||||
category-none? (string/blank? id)]
|
category-none? (string/blank? id)]
|
||||||
[:<>
|
[:<>
|
||||||
[quo/separator]
|
[quo/separator]
|
||||||
[rn/view {:accessibility-label :category-item
|
[rn/view
|
||||||
:style (merge styles/category-item
|
{:accessibility-label :category-item
|
||||||
{:background-color background-color})}
|
:style (merge styles/category-item
|
||||||
|
{:background-color background-color})}
|
||||||
(if (not (categories-tab?))
|
(if (not (categories-tab?))
|
||||||
[icons/icon :main-icons/channel-category {:color colors/gray}]
|
[icons/icon :main-icons/channel-category {:color colors/gray}]
|
||||||
[rn/touchable-opacity
|
[rn/touchable-opacity
|
||||||
@@ -79,10 +85,11 @@
|
|||||||
[rn/view {:flex 1}
|
[rn/view {:flex 1}
|
||||||
[rn/text {:style {:font-size 17 :margin-left 10 :color colors/black}} name]]
|
[rn/text {:style {:font-size 17 :margin-left 10 :color colors/black}} name]]
|
||||||
(when (and (not category-none?) (categories-tab?))
|
(when (and (not category-none?) (categories-tab?))
|
||||||
[rn/touchable-opacity {:accessibility-label :category-drag-handle
|
[rn/touchable-opacity
|
||||||
:on-long-press drag
|
{:accessibility-label :category-drag-handle
|
||||||
:delay-long-press 100
|
:on-long-press drag
|
||||||
:style {:padding 20}}
|
:delay-long-press 100
|
||||||
|
:style {:padding 20}}
|
||||||
[icons/icon :main-icons/reorder-handle {:no-color true :width 18 :height 12}]])]]))
|
[icons/icon :main-icons/reorder-handle {:no-color true :width 18 :height 12}]])]]))
|
||||||
|
|
||||||
(defn render-fn
|
(defn render-fn
|
||||||
@@ -98,80 +105,105 @@
|
|||||||
(if going-up?
|
(if going-up?
|
||||||
(if (= chat-type constants/community-chat-type)
|
(if (= chat-type constants/community-chat-type)
|
||||||
[categoryID (if second-call? (inc position) position)]
|
[categoryID (if second-call? (inc position) position)]
|
||||||
(if second-call? [id 0]
|
(if second-call?
|
||||||
(calculate-chat-new-position-and-category (dec to) true old-category true)))
|
[id 0]
|
||||||
|
(calculate-chat-new-position-and-category (dec to) true old-category true)))
|
||||||
(if (= chat-type constants/community-chat-type)
|
(if (= chat-type constants/community-chat-type)
|
||||||
(if (= categoryID old-category)
|
(if (= categoryID old-category)
|
||||||
[categoryID position]
|
[categoryID position]
|
||||||
[categoryID (inc position)]) [id 0]))]
|
[categoryID (inc position)])
|
||||||
|
[id 0]))]
|
||||||
[new-category new-position]))
|
[new-category new-position]))
|
||||||
|
|
||||||
(defn update-local-atom [data-js]
|
(defn update-local-atom
|
||||||
|
[data-js]
|
||||||
(reset! data data-js)
|
(reset! data data-js)
|
||||||
(reagent/flush))
|
(reagent/flush))
|
||||||
|
|
||||||
(defn on-drag-end-chat [from to data-js]
|
(defn on-drag-end-chat
|
||||||
|
[from to data-js]
|
||||||
(let [{:keys [id community-id categoryID position]} (get @data from)
|
(let [{:keys [id community-id categoryID position]} (get @data from)
|
||||||
[new-category new-position] (calculate-chat-new-position-and-category
|
[new-category new-position] (calculate-chat-new-position-and-category
|
||||||
to false categoryID (> from to))
|
to
|
||||||
|
false
|
||||||
|
categoryID
|
||||||
|
(> from to))
|
||||||
chat-id (string/replace id community-id "")]
|
chat-id (string/replace id community-id "")]
|
||||||
(when-not (and (= new-position position) (= new-category categoryID))
|
(when-not (and (= new-position position) (= new-category categoryID))
|
||||||
(update-local-atom data-js)
|
(update-local-atom data-js)
|
||||||
(>evt [::communities/reorder-community-category-chat
|
(rf/dispatch [::communities/reorder-community-category-chat
|
||||||
community-id new-category chat-id new-position]))))
|
community-id new-category chat-id new-position]))))
|
||||||
|
|
||||||
(defn on-drag-end-category [from to data-js]
|
(defn on-drag-end-category
|
||||||
|
[from to data-js]
|
||||||
(let [{:keys [id community-id position]} (get @data from)]
|
(let [{:keys [id community-id position]} (get @data from)]
|
||||||
(when (and (< to (count @data)) (not= position to) (not= id ""))
|
(when (and (< to (count @data)) (not= position to) (not= id ""))
|
||||||
(update-local-atom data-js)
|
(update-local-atom data-js)
|
||||||
(>evt [::communities/reorder-community-category community-id id to]))))
|
(rf/dispatch [::communities/reorder-community-category community-id id to]))))
|
||||||
|
|
||||||
(defn on-drag-end-fn [from to data-js]
|
(defn on-drag-end-fn
|
||||||
|
[from to data-js]
|
||||||
(if (categories-tab?)
|
(if (categories-tab?)
|
||||||
(on-drag-end-category from to data-js)
|
(on-drag-end-category from to data-js)
|
||||||
(when-not (= to 0) (on-drag-end-chat from to data-js))))
|
(when-not (= to 0) (on-drag-end-chat from to data-js))))
|
||||||
|
|
||||||
(defn reset-data [categories chats]
|
(defn reset-data
|
||||||
(reset! data (if (categories-tab?)
|
[categories chats]
|
||||||
categories
|
(reset! data
|
||||||
(walk/postwalk-replace
|
(if (categories-tab?)
|
||||||
{:chat-id :id}
|
categories
|
||||||
(reduce (fn [acc category]
|
(walk/postwalk-replace
|
||||||
(-> acc
|
{:chat-id :id}
|
||||||
(conj category)
|
(reduce (fn [acc category]
|
||||||
(into (get chats (:id category))))) [] categories)))))
|
(-> acc
|
||||||
|
(conj category)
|
||||||
|
(into (get chats (:id category)))))
|
||||||
|
[]
|
||||||
|
categories)))))
|
||||||
|
|
||||||
(defn draggable-list []
|
(defn draggable-list
|
||||||
|
[]
|
||||||
[rn/draggable-flat-list
|
[rn/draggable-flat-list
|
||||||
{:key-fn :id
|
{:key-fn :id
|
||||||
:data @data
|
:data @data
|
||||||
:render-fn render-fn
|
:render-fn render-fn
|
||||||
:autoscroll-threshold (if platform/android? 150 250)
|
:autoscroll-threshold (if platform/android? 150 250)
|
||||||
:autoscroll-speed (if platform/android? 10 150) ;; TODO - Use same speed for both ios and android
|
:autoscroll-speed (if platform/android? 10 150) ;; TODO - Use same speed for both ios and android
|
||||||
:container-style {:margin-bottom 108} ;; after bumping react native version to > 0.64
|
:container-style {:margin-bottom 108} ;; after bumping react native version to >
|
||||||
|
;; 0.64
|
||||||
:on-drag-end-fn on-drag-end-fn}])
|
:on-drag-end-fn on-drag-end-fn}])
|
||||||
|
|
||||||
(defn chats_and_categories []
|
(defn chats_and_categories
|
||||||
|
[]
|
||||||
(let [{:keys [tab]} @state]
|
(let [{:keys [tab]} @state]
|
||||||
[:<>
|
[:<>
|
||||||
[react/view {:flex-direction :row :margin-horizontal 16 :margin-vertical 8
|
[react/view
|
||||||
:border-radius 8 :background-color colors/blue-light}
|
{:flex-direction :row
|
||||||
|
:margin-horizontal 16
|
||||||
|
:margin-vertical 8
|
||||||
|
:border-radius 8
|
||||||
|
:background-color colors/blue-light}
|
||||||
[tabs/tab-button state :chats (i18n/label :t/edit-chats) (= tab :chats)]
|
[tabs/tab-button state :chats (i18n/label :t/edit-chats) (= tab :chats)]
|
||||||
[tabs/tab-button state :categories (i18n/label :t/edit-categories) (= tab :categories)]]]))
|
[tabs/tab-button state :categories (i18n/label :t/edit-categories) (= tab :categories)]]]))
|
||||||
|
|
||||||
(defn view []
|
(defn view
|
||||||
(let [{:keys [community-id]} (<sub [:get-screen-params])
|
[]
|
||||||
|
(let [{:keys [community-id]} (rf/sub [:get-screen-params])
|
||||||
{:keys [id name images members permissions color]}
|
{:keys [id name images members permissions color]}
|
||||||
(<sub [:communities/community community-id])
|
(rf/sub [:communities/community community-id])
|
||||||
sorted-categories (<sub [:communities/sorted-categories community-id])
|
sorted-categories (rf/sub [:communities/sorted-categories
|
||||||
categories (if (categories-tab?)
|
community-id])
|
||||||
sorted-categories
|
categories (if (categories-tab?)
|
||||||
(conj sorted-categories
|
sorted-categories
|
||||||
{:id ""
|
(conj sorted-categories
|
||||||
:position (count sorted-categories)
|
{:id ""
|
||||||
:name (i18n/label :t/none)
|
:position (count
|
||||||
:community-id community-id}))
|
sorted-categories)
|
||||||
chats (<sub [:chats/sorted-categories-by-community-id community-id])]
|
:name (i18n/label :t/none)
|
||||||
|
:community-id community-id}))
|
||||||
|
chats (rf/sub
|
||||||
|
[:chats/sorted-categories-by-community-id
|
||||||
|
community-id])]
|
||||||
(reset-data categories chats)
|
(reset-data categories chats)
|
||||||
[:<>
|
[:<>
|
||||||
[topbar/topbar
|
[topbar/topbar
|
||||||
@@ -182,4 +214,4 @@
|
|||||||
[community/blank-page (i18n/label :t/welcome-community-blank-message-edit-chats)]
|
[community/blank-page (i18n/label :t/welcome-community-blank-message-edit-chats)]
|
||||||
[:<>
|
[:<>
|
||||||
[chats_and_categories]
|
[chats_and_categories]
|
||||||
[draggable-list]])]))
|
[draggable-list]])]))
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user