Compare commits
26
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b5a48dc06d | ||
|
|
4c604abe5b | ||
|
|
de4e233884 | ||
|
|
55a99da2f5 | ||
|
|
6093d56c90 | ||
|
|
9cf4556b9d | ||
|
|
536ebf56cb | ||
|
|
3ad345519b | ||
|
|
dc587e493f | ||
|
|
f692ae2222 | ||
|
|
aa89ebdb93 | ||
|
|
198a4d74a5 | ||
|
|
3b5fe36717 | ||
|
|
03444ae4ff | ||
|
|
390bbdb6ec | ||
|
|
2bc7b62324 | ||
|
|
4376ee8908 | ||
|
|
195f0cfa40 | ||
|
|
ab61d8d5c0 | ||
|
|
aaf0b8e423 | ||
|
|
7e14846f0b | ||
|
|
5ebd133c63 | ||
|
|
563f1c588d | ||
|
|
6b612588c4 | ||
|
|
6ef113e821 | ||
|
|
c25f44c2a0 |
@@ -0,0 +1,4 @@
|
||||
{:linters
|
||||
{:unresolved-symbol
|
||||
{:exclude [(cljs.test/is [match? thrown-match?])
|
||||
(clojure.test/is [match? thrown-match?])]}}}
|
||||
@@ -641,6 +641,26 @@ keywords and concatenating them into a single string.
|
||||
```
|
||||
|
||||
### Tests
|
||||
#### Prefer `match?` over `=` when comparing data structures
|
||||
|
||||
Prefer the `match?` directive over `=` when comparing data structures, otherwise
|
||||
when the check fails the output can be too difficult to read. `match?` is
|
||||
defined by library https://github.com/nubank/matcher-combinators.
|
||||
|
||||
```clojure
|
||||
;; bad
|
||||
(deftest some-test
|
||||
(let [expected {...}
|
||||
actual {...}]
|
||||
(is (= expected actual))))
|
||||
|
||||
;; good
|
||||
(deftest some-test
|
||||
(let [expected {...}
|
||||
actual {...}]
|
||||
(is (match? expected actual))))
|
||||
```
|
||||
|
||||
#### Subscription tests
|
||||
|
||||
Test [layer-3 subscriptions](https://day8.github.io/re-frame/subscriptions/) by
|
||||
|
||||
@@ -602,6 +602,15 @@
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "nubank/matcher-combinators/3.8.8/matcher-combinators-3.8.8",
|
||||
"host": "https://repo.clojars.org",
|
||||
"jar": {
|
||||
"sha1": "4c94bd510f0c18a20191e46dd6becedebc640bbd",
|
||||
"sha256": "0wpla2hx0s4mda58ndyd8938zmnz1gyhgfr6pzfphy27xfbvsssl"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "org/apache/ant/ant/1.10.11/ant-1.10.11",
|
||||
"host": "https://repo1.maven.org/maven2",
|
||||
@@ -746,6 +755,15 @@
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "org/clojure/math.combinatorics/0.2.0/math.combinatorics-0.2.0",
|
||||
"host": "https://repo1.maven.org/maven2",
|
||||
"jar": {
|
||||
"sha1": "aa95d25ea98bfe1152ea540f6e58a303c8cacc86",
|
||||
"sha256": "0qvdsr5ryjmrpz622ivpyq5aayn42y4bk531vbasyj2yj7gcg35h"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "org/clojure/spec.alpha/0.3.218/spec.alpha-0.3.218",
|
||||
"host": "https://repo1.maven.org/maven2",
|
||||
|
||||
@@ -65,6 +65,7 @@ net/cgrand/macrovich/0.2.1/macrovich-0.2.1.jar
|
||||
net/java/dev/jna/jna/5.12.1/jna-5.12.1.jar
|
||||
nrepl/bencode/1.1.0/bencode-1.1.0.jar
|
||||
nrepl/nrepl/1.0.0/nrepl-1.0.0.jar
|
||||
nubank/matcher-combinators/3.8.8/matcher-combinators-3.8.8.jar
|
||||
org/apache/ant/ant/1.10.11/ant-1.10.11.jar
|
||||
org/apache/ant/ant-launcher/1.10.11/ant-launcher-1.10.11.jar
|
||||
org/babashka/sci/0.7.38/sci-0.7.38.jar
|
||||
@@ -81,6 +82,7 @@ org/clojure/data.json/2.4.0/data.json-2.4.0.jar
|
||||
org/clojure/data.priority-map/1.1.0/data.priority-map-1.1.0.jar
|
||||
org/clojure/google-closure-library/0.0-20230227-c7c0a541/google-closure-library-0.0-20230227-c7c0a541.jar
|
||||
org/clojure/google-closure-library-third-party/0.0-20230227-c7c0a541/google-closure-library-third-party-0.0-20230227-c7c0a541.jar
|
||||
org/clojure/math.combinatorics/0.2.0/math.combinatorics-0.2.0.jar
|
||||
org/clojure/spec.alpha/0.3.218/spec.alpha-0.3.218.jar
|
||||
org/clojure/test.check/1.1.1/test.check-1.1.1.jar
|
||||
org/clojure/tools.analyzer/1.1.0/tools.analyzer-1.1.0.jar
|
||||
|
||||
@@ -14,6 +14,7 @@ stdenv.mkDerivation {
|
||||
"patchJavaPhase"
|
||||
"patchReactNativePhase"
|
||||
"patchPodPhase"
|
||||
"patchGlogPhase"
|
||||
"installPhase"
|
||||
];
|
||||
|
||||
@@ -98,6 +99,14 @@ stdenv.mkDerivation {
|
||||
'[RCTConvert UIColor:options.tintColor() ? @(*options.tintColor()) : nil];'
|
||||
'';
|
||||
|
||||
# Fix pod issue after upgrading to MacOS Sonoma and Xcode 15
|
||||
# https://github.com/status-im/status-mobile/issues/17682
|
||||
patchGlogPhase = ''
|
||||
substituteInPlace ./node_modules/react-native/scripts/ios-configure-glog.sh \
|
||||
--replace 'export CC="' '#export CC="' \
|
||||
--replace 'export CXX="' '#export CXX="'
|
||||
'';
|
||||
|
||||
# The ELF types are incompatible with the host platform, so let's not even try
|
||||
# TODO: Use Android NDK to strip binaries manually
|
||||
dontPatchELF = true;
|
||||
|
||||
@@ -73,6 +73,7 @@ in {
|
||||
allowHigher = true;
|
||||
};
|
||||
go = super.go_1_19;
|
||||
clang = super.clang_15;
|
||||
buildGoPackage = super.buildGo119Package;
|
||||
buildGoModule = super.buildGo119Module;
|
||||
gomobile = (super.gomobile.overrideAttrs (old: {
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 851 B |
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
@@ -17,6 +17,7 @@
|
||||
[cider/piggieback "0.4.1"]
|
||||
[org.slf4j/slf4j-nop "2.0.9"]
|
||||
[re-frisk-remote "1.6.0"]
|
||||
[nubank/matcher-combinators "3.8.8"]
|
||||
|
||||
;; Use the same version specified in the Nix dependency.
|
||||
[clj-kondo/clj-kondo "2023.09.07"]
|
||||
|
||||
@@ -118,13 +118,61 @@
|
||||
"M2.79504 9.01494C2.89473 8.85584 3.00297 8.70977 3.11963 8.5761C3.90594 7.67512 4.97212 7.45024 5.99992 7.45024C7.02772 7.45024 8.0939 7.67512 8.88021 8.5761C8.99688 8.70978 9.10512 8.85585 9.2048 9.01495C8.9501 9.28561 8.66149 9.52401 8.34577 9.72335C8.25403 9.55824 8.15512 9.41818 8.05145 9.29939C7.56503 8.74204 6.88121 8.55024 5.99992 8.55024C5.11862 8.55024 4.43481 8.74204 3.94839 9.29939C3.84472 9.41818 3.74582 9.55824 3.65408 9.72334C3.33835 9.524 3.04975 9.2856 2.79504 9.01494ZM5.99992 3.5502C5.47525 3.5502 5.04992 3.97552 5.04992 4.5002C5.04992 5.02487 5.47525 5.4502 5.99992 5.4502C6.52459 5.4502 6.94992 5.02487 6.94992 4.5002C6.94992 3.97552 6.52459 3.5502 5.99992 3.5502ZM3.94992 4.5002C3.94992 3.36801 4.86773 2.4502 5.99992 2.4502C7.1321 2.4502 8.04992 3.36801 8.04992 4.5002C8.04992 5.63238 7.1321 6.5502 5.99992 6.5502C4.86773 6.5502 3.94992 5.63238 3.94992 4.5002Z"
|
||||
:fill color-2}]])
|
||||
|
||||
(defn- contact-20
|
||||
[{:keys [color color-2]
|
||||
:or {color colors/neutral-100
|
||||
color-2 colors/white}
|
||||
:as props}]
|
||||
[container props
|
||||
[svg/circle
|
||||
{:cx 10
|
||||
:cy 10
|
||||
:r 7.5
|
||||
:fill color}]
|
||||
[svg/path
|
||||
{:d
|
||||
"M8.65002 7.99998C8.65002 7.25439 9.25443 6.64998 10 6.64998C10.7456 6.64998 11.35 7.25439 11.35 7.99998C11.35 8.74556 10.7456 9.34998 10 9.34998C9.25443 9.34998 8.65002 8.74556 8.65002 7.99998ZM10 5.34998C8.53646 5.34998 7.35002 6.53642 7.35002 7.99998C7.35002 9.46353 8.53646 10.65 10 10.65C11.4636 10.65 12.65 9.46353 12.65 7.99998C12.65 6.53642 11.4636 5.34998 10 5.34998ZM10 13.65C8.67557 13.65 7.53064 14.4186 6.98692 15.5341C6.60094 15.3235 6.23942 15.0737 5.90771 14.79C6.69408 13.3369 8.23179 12.35 10 12.35C11.7682 12.35 13.306 13.3369 14.0923 14.79C13.7606 15.0737 13.3991 15.3235 13.0131 15.5341C12.4694 14.4186 11.3245 13.65 10 13.65Z"
|
||||
:fill color-2}]])
|
||||
|
||||
(defn- verified-20
|
||||
[{:keys [color color-2]
|
||||
:or {color colors/neutral-100
|
||||
color-2 colors/white}
|
||||
:as props}]
|
||||
[container props
|
||||
[svg/path
|
||||
{:d
|
||||
"M18 10C18 8.77003 17.1118 7.74751 15.9418 7.53891C16.6216 6.56407 16.5267 5.21294 15.6569 4.34321C14.7872 3.47344 13.436 3.37852 12.4611 4.05845C12.2526 2.88834 11.23 2 10 2C8.77 2 7.74747 2.88827 7.53889 4.05832C6.56406 3.37846 5.21292 3.47339 4.34318 4.34313C3.47343 5.21288 3.3785 6.56404 4.05839 7.53888C2.88831 7.74743 2 8.76998 2 10C2 11.23 2.88824 12.2525 4.05826 12.4611C3.3784 13.4359 3.47333 14.7871 4.34307 15.6568C5.21284 16.5266 6.56403 16.6215 7.53887 15.9416C7.74741 17.1117 8.76996 18 10 18C11.23 18 12.2525 17.1117 12.4611 15.9417C13.4359 16.6215 14.7871 16.5266 15.6568 15.6569C16.5265 14.7871 16.6215 13.436 15.9416 12.4611C17.1117 12.2526 18 11.23 18 10Z"
|
||||
:fill color}]
|
||||
[svg/path
|
||||
{:d "M7.25 10.75L9.25 12.25L12.75 7.75"
|
||||
:stroke color-2
|
||||
:stroke-width "1.2"}]])
|
||||
|
||||
(defn- untrustworthy-20
|
||||
[{:keys [color color-2]
|
||||
:or {color colors/neutral-100
|
||||
color-2 colors/white}
|
||||
:as props}]
|
||||
[container props
|
||||
[svg/path
|
||||
{:d "M10 2L15.6569 4.34315L18 10L15.6569 15.6569L10 18L4.34315 15.6569L2 10L4.34315 4.34315L10 2Z"
|
||||
:fill color}]
|
||||
[svg/path
|
||||
{:d
|
||||
"M10.75 5.5L10.55 11.5H9.45L9.25 5.5H10.75ZM10 13C10.4142 13 10.75 13.3358 10.75 13.75C10.75 14.1642 10.4142 14.5 10 14.5C9.58579 14.5 9.25 14.1642 9.25 13.75C9.25 13.3358 9.58579 13 10 13Z"
|
||||
:fill color-2}]])
|
||||
|
||||
(def ^:private icons
|
||||
{:i/clear-20 clear-20
|
||||
:i/dropdown-20 dropdown-20
|
||||
:i/pullup-20 pullup-20
|
||||
:i/dropdown-12 dropdown-12
|
||||
:i/pullup-12 pullup-12
|
||||
:i/contact-12 contact-12})
|
||||
{:i/clear-20 clear-20
|
||||
:i/dropdown-20 dropdown-20
|
||||
:i/pullup-20 pullup-20
|
||||
:i/dropdown-12 dropdown-12
|
||||
:i/pullup-12 pullup-12
|
||||
:i/contact-12 contact-12
|
||||
:i/contact-20 contact-20
|
||||
:i/verified-20 verified-20
|
||||
:i/untrustworthy-20 untrustworthy-20})
|
||||
|
||||
(defn- append-to-keyword
|
||||
[k & xs]
|
||||
|
||||
@@ -61,14 +61,10 @@
|
||||
value (reagent/atom "")
|
||||
focused? (atom false)]
|
||||
(fn [{:keys [scanned-value theme blur? on-change-text on-blur on-focus on-clear on-scan on-detect-ens
|
||||
on-detect-address
|
||||
ens-regex address-regex
|
||||
valid-ens-or-address?]}]
|
||||
on-detect-address address-regex valid-ens-or-address?]}]
|
||||
(let [on-change (fn [text]
|
||||
(when (not= @value text)
|
||||
(let [ens? (when ens-regex
|
||||
(boolean (re-matches ens-regex text)))
|
||||
address? (when address-regex
|
||||
(let [address? (when address-regex
|
||||
(boolean (re-matches address-regex text)))]
|
||||
(if (> (count text) 0)
|
||||
(reset! status :typing)
|
||||
@@ -76,9 +72,9 @@
|
||||
(reset! value text)
|
||||
(when on-change-text
|
||||
(on-change-text text))
|
||||
(when (and ens? on-detect-ens)
|
||||
(when (and on-detect-ens (> (count text) 0))
|
||||
(reset! status :loading)
|
||||
(on-detect-ens text))
|
||||
(on-detect-ens text #(reset! status :typing)))
|
||||
(when (and address? on-detect-address)
|
||||
(reset! status :loading)
|
||||
(on-detect-address text)))))
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
(ns quo.components.text-combinations.username.component-spec
|
||||
(:require [quo.components.text-combinations.username.view :as username]
|
||||
[test-helpers.component :as h]))
|
||||
|
||||
(defn test-all-status
|
||||
[component-to-render component-props]
|
||||
(h/test "Verified status"
|
||||
(h/render [component-to-render (assoc component-props :status :verified)])
|
||||
(h/is-truthy (h/get-by-label-text :username-status-icon)))
|
||||
|
||||
(h/test "Contact status"
|
||||
(h/render [component-to-render (assoc component-props :status :contact)])
|
||||
(h/is-truthy (h/get-by-label-text :username-status-icon)))
|
||||
|
||||
(h/test "Untrustworthy status"
|
||||
(h/render [component-to-render (assoc component-props :status :untrustworthy)])
|
||||
(h/is-truthy (h/get-by-label-text :username-status-icon)))
|
||||
|
||||
(h/test "Untrustworthy contact status"
|
||||
(h/render [component-to-render (assoc component-props :status :untrustworthy-contact)])
|
||||
(let [icons (h/get-all-by-label-text :username-status-icon)]
|
||||
(h/is-truthy (aget icons 0))
|
||||
(h/is-truthy (aget icons 1))))
|
||||
|
||||
(h/test "Blocked status"
|
||||
(h/render [component-to-render (assoc component-props :status :blocked)])
|
||||
(h/is-truthy (h/get-by-label-text :username-status-icon))))
|
||||
|
||||
(h/describe "Text combinations - Username"
|
||||
(h/test "Renders default"
|
||||
(h/render [username/view {:username "Test username"}])
|
||||
(h/is-truthy (h/get-by-text "Test username")))
|
||||
|
||||
(h/describe "Render different :name-type values"
|
||||
(h/describe "default"
|
||||
(let [props {:name-type :default
|
||||
:username "Test username"}]
|
||||
|
||||
(h/test "default render"
|
||||
(h/render [username/view props])
|
||||
(h/is-truthy (h/get-by-text "Test username")))
|
||||
|
||||
(h/describe "All status are rendered"
|
||||
(test-all-status username/view props))))
|
||||
|
||||
(h/describe "ens"
|
||||
(let [props {:name-type :ens
|
||||
:username "test-username.eth"}]
|
||||
|
||||
(h/test "no status render"
|
||||
(h/render [username/view props])
|
||||
(h/is-truthy (h/get-by-text "test-username.eth")))
|
||||
|
||||
(h/describe "All status are rendered"
|
||||
(test-all-status username/view props))))
|
||||
|
||||
(h/describe "nickname"
|
||||
(let [props {:name-type :nickname
|
||||
:username "Nickname"
|
||||
:name "Real name"}]
|
||||
|
||||
(h/test "no status render"
|
||||
(h/render [username/view props])
|
||||
(h/is-truthy (h/get-by-text "Nickname"))
|
||||
(h/is-truthy (h/get-by-text "Real name")))
|
||||
|
||||
(h/describe "All status are rendered"
|
||||
(test-all-status username/view props))))))
|
||||
@@ -0,0 +1,30 @@
|
||||
(ns quo.components.text-combinations.username.style
|
||||
(:require [quo.foundations.colors :as colors]))
|
||||
|
||||
(def container
|
||||
{:flex-direction :row
|
||||
:height 32})
|
||||
|
||||
(def username-text-container
|
||||
{:flex-direction :row
|
||||
:align-items :flex-end})
|
||||
|
||||
(defn real-name-text
|
||||
[theme blur?]
|
||||
{:color (if blur?
|
||||
(colors/theme-colors colors/neutral-80-opa-40 colors/white-opa-40 theme)
|
||||
(colors/theme-colors colors/neutral-60 colors/neutral-40 theme))})
|
||||
|
||||
(defn real-name-dot
|
||||
[theme blur?]
|
||||
(assoc (real-name-text theme blur?) :margin-horizontal 6))
|
||||
|
||||
(defn status-icon-container
|
||||
[name-type status]
|
||||
(cond-> {:flex-direction :row
|
||||
:margin-left 4}
|
||||
(#{:default :ens} name-type) (assoc :margin-top 8
|
||||
:margin-bottom 4)
|
||||
(= :nickname name-type) (assoc :margin-top 10
|
||||
:margin-bottom 2)
|
||||
(= status :untrustworthy-contact) (assoc :margin-right 2)))
|
||||
@@ -0,0 +1,57 @@
|
||||
(ns quo.components.text-combinations.username.view
|
||||
(:require [quo.components.icon :as icon]
|
||||
[quo.components.markdown.text :as text]
|
||||
[quo.components.text-combinations.username.style :as style]
|
||||
[quo.foundations.colors :as colors]
|
||||
[quo.theme]
|
||||
[react-native.core :as rn]))
|
||||
|
||||
(defn- username-text
|
||||
[{:keys [theme name-type username blur?]
|
||||
real-name :name}]
|
||||
[rn/view {:style style/username-text-container}
|
||||
[text/text
|
||||
{:size :heading-1
|
||||
:weight :semi-bold}
|
||||
username]
|
||||
(when (= name-type :nickname)
|
||||
[:<>
|
||||
[text/text
|
||||
{:style (style/real-name-dot theme blur?)
|
||||
:size :paragraph-1
|
||||
:weight :medium}
|
||||
"∙"]
|
||||
[text/text
|
||||
{:style (style/real-name-text theme blur?)
|
||||
:size :paragraph-1
|
||||
:weight :medium}
|
||||
real-name]])])
|
||||
|
||||
(defn- icon-20
|
||||
[icon-name theme color]
|
||||
[icon/icon icon-name
|
||||
{:accessibility-label :username-status-icon
|
||||
:size 20
|
||||
:color (colors/resolve-color color theme)}])
|
||||
|
||||
(defn status-icon
|
||||
[{:keys [theme name-type status]
|
||||
:or {name-type :default}}]
|
||||
[rn/view {:style (style/status-icon-container name-type status)}
|
||||
(case status
|
||||
:verified [icon-20 :i/verified theme :success]
|
||||
:contact [icon-20 :i/contact theme :blue]
|
||||
:untrustworthy [icon-20 :i/untrustworthy theme :danger]
|
||||
:blocked [icon-20 :i/block theme :danger]
|
||||
:untrustworthy-contact [:<>
|
||||
[icon-20 :i/untrustworthy theme :danger]
|
||||
[icon-20 :i/contact theme :blue]]
|
||||
nil)])
|
||||
|
||||
(defn view-internal
|
||||
[props]
|
||||
[rn/view {:style style/container}
|
||||
[username-text props]
|
||||
[status-icon props]])
|
||||
|
||||
(def view (quo.theme/with-theme view-internal))
|
||||
@@ -0,0 +1,99 @@
|
||||
(ns quo.components.wallet.confirmation-progress.component-spec
|
||||
(:require [quo.core :as quo]
|
||||
[reagent.core :as reagent]
|
||||
[test-helpers.component :as h]))
|
||||
|
||||
(defn- get-test-data
|
||||
[{:keys [state network]
|
||||
:or {state :pending network :mainnet}}]
|
||||
{:counter (reagent/atom 0)
|
||||
:total-box 85
|
||||
:progress-value "10"
|
||||
:network network
|
||||
:state state
|
||||
:customization-color :blue})
|
||||
|
||||
(h/describe "Confirmation Progress"
|
||||
(h/test "component renders when state is sending and network is optimism"
|
||||
(h/render [quo/confirmation-propgress
|
||||
(get-test-data {:state :sending
|
||||
:network :optimism})])
|
||||
(h/is-truthy (h/get-by-label-text :progress-box)))
|
||||
|
||||
(h/test "component renders when state is confirmed and network is optimism"
|
||||
(h/render [quo/confirmation-propgress
|
||||
(get-test-data {:state :confirmed
|
||||
:network :optimism})])
|
||||
(h/is-truthy (h/get-by-label-text :progress-box)))
|
||||
|
||||
(h/test "component renders when state is finalising and network is optimism"
|
||||
(h/render [quo/confirmation-propgress
|
||||
(get-test-data {:state :finalising
|
||||
:network :optimism})])
|
||||
(h/is-truthy (h/get-by-label-text :progress-box)))
|
||||
|
||||
(h/test "component renders when state is finalized and network is optimism"
|
||||
(h/render [quo/confirmation-propgress
|
||||
(get-test-data {:state :finalized
|
||||
:network :optimism})])
|
||||
(h/is-truthy (h/get-by-label-text :progress-box)))
|
||||
|
||||
(h/test "component renders when state is error and network is optimism"
|
||||
(h/render [quo/confirmation-propgress
|
||||
(get-test-data {:state :error
|
||||
:network :optimism})])
|
||||
(h/is-truthy (h/get-by-label-text :progress-box)))
|
||||
|
||||
(h/test "component renders when state is sending and network is arbitrum"
|
||||
(h/render [quo/confirmation-propgress
|
||||
(get-test-data {:state :sending
|
||||
:network :arbitrum})])
|
||||
(h/is-truthy (h/get-by-label-text :progress-box)))
|
||||
|
||||
(h/test "component renders when state is confirmed and network is arbitrum"
|
||||
(h/render [quo/confirmation-propgress
|
||||
(get-test-data {:state :confirmed
|
||||
:network :arbitrum})])
|
||||
(h/is-truthy (h/get-by-label-text :progress-box)))
|
||||
|
||||
(h/test "component renders when state is finalising and network is arbitrum"
|
||||
(h/render [quo/confirmation-propgress
|
||||
(get-test-data {:state :finalising
|
||||
:network :arbitrum})])
|
||||
(h/is-truthy (h/get-by-label-text :progress-box)))
|
||||
|
||||
(h/test "component renders when state is finalized and network is arbitrum"
|
||||
(h/render [quo/confirmation-propgress
|
||||
(get-test-data {:state :finalized
|
||||
:network :arbitrum})])
|
||||
(h/is-truthy (h/get-by-label-text :progress-box)))
|
||||
|
||||
(h/test "component renders when state is error and network is arbitrum"
|
||||
(h/render [quo/confirmation-propgress
|
||||
(get-test-data {:state :error
|
||||
:network :arbitrum})])
|
||||
(h/is-truthy (h/get-by-label-text :progress-box)))
|
||||
|
||||
(h/test "component renders when state is pending and network is mainnet"
|
||||
(h/render [quo/confirmation-propgress (get-test-data {})])
|
||||
(h/is-truthy (h/get-by-label-text :mainnet-progress-box)))
|
||||
|
||||
(h/test "component renders when state is sending and network is mainnet"
|
||||
(h/render [quo/confirmation-propgress (get-test-data {:state :sending})])
|
||||
(h/is-truthy (h/get-by-label-text :mainnet-progress-box)))
|
||||
|
||||
(h/test "component renders when state is confirmed and network is mainnet"
|
||||
(h/render [quo/confirmation-propgress (get-test-data {:state :confirmed})])
|
||||
(h/is-truthy (h/get-by-label-text :mainnet-progress-box)))
|
||||
|
||||
(h/test "component renders when state is finalising and network is mainnet"
|
||||
(h/render [quo/confirmation-propgress (get-test-data {:state :finalising})])
|
||||
(h/is-truthy (h/get-by-label-text :mainnet-progress-box)))
|
||||
|
||||
(h/test "component renders when state is finalized and network is mainnet"
|
||||
(h/render [quo/confirmation-propgress (get-test-data {:state :finalized})])
|
||||
(h/is-truthy (h/get-by-label-text :mainnet-progress-box)))
|
||||
|
||||
(h/test "component renders when state is error and network is mainnet"
|
||||
(h/render [quo/confirmation-propgress (get-test-data {:state :error})])
|
||||
(h/is-truthy (h/get-by-label-text :mainnet-progress-box))))
|
||||
@@ -0,0 +1,9 @@
|
||||
(ns quo.components.wallet.confirmation-progress.style)
|
||||
|
||||
(def progress-box-container
|
||||
{:flex-direction :row
|
||||
:align-items :center
|
||||
:padding-horizontal 12
|
||||
:padding-bottom 10
|
||||
:padding-top 4
|
||||
:flex-wrap :wrap})
|
||||
@@ -0,0 +1,69 @@
|
||||
(ns quo.components.wallet.confirmation-progress.view
|
||||
(:require [quo.components.wallet.confirmation-progress.style :as style]
|
||||
[quo.components.wallet.progress-bar.view :as progress-box]
|
||||
[quo.theme :as quo.theme]
|
||||
[react-native.core :as rn]))
|
||||
|
||||
(def ^:private max-progress 100)
|
||||
(def ^:private min-progress 0)
|
||||
|
||||
(defn- calculate-box-state
|
||||
[state counter index]
|
||||
(cond
|
||||
(and (= state :sending) (>= counter index) (< index 3)) :confirmed
|
||||
(and (= state :confirmed) (>= counter index) (< index 5)) :confirmed
|
||||
(and (= state :finalising) (>= counter index) (< index 5)) :confirmed
|
||||
(and (= state :finalising) (>= counter index) (> index 4) (< index 20)) :finalized
|
||||
(and (= state :finalized) (>= counter index) (< index 5)) :confirmed
|
||||
(and (= state :finalized) (>= counter index) (> index 4)) :finalized
|
||||
(and (= state :error) (>= counter index) (< index 2)) :error
|
||||
:else :pending))
|
||||
|
||||
(defn- calculate-box-state-sidenet
|
||||
[state]
|
||||
(case state
|
||||
:error :error
|
||||
(:confirmed :finalising :finalized) :finalized
|
||||
:pending))
|
||||
|
||||
(defn- calculate-progressed-value
|
||||
[state progress-value]
|
||||
(case state
|
||||
:finalising progress-value
|
||||
:finalized max-progress
|
||||
min-progress))
|
||||
|
||||
(defn- progress-boxes-mainnet
|
||||
[{:keys [state counter total-box]}]
|
||||
[rn/view
|
||||
{:accessibility-label :mainnet-progress-box
|
||||
:style style/progress-box-container}
|
||||
(let [numbers (range 1 total-box)]
|
||||
(doall (for [n numbers]
|
||||
[progress-box/view
|
||||
{:state (calculate-box-state state counter n)
|
||||
:customization-color :blue
|
||||
:key n}])))])
|
||||
|
||||
(defn- progress-boxes-sidenet
|
||||
[{:keys [state progress-value]}]
|
||||
[rn/view
|
||||
{:accessibility-label :progress-box
|
||||
:style style/progress-box-container}
|
||||
[progress-box/view
|
||||
{:state (calculate-box-state-sidenet state)
|
||||
:customization-color :success}]
|
||||
[progress-box/view
|
||||
{:state (calculate-box-state-sidenet state)
|
||||
:full-width? true
|
||||
:progressed-value (calculate-progressed-value state progress-value)
|
||||
:customization-color :blue}]])
|
||||
|
||||
(defn- view-internal
|
||||
[{:keys [network] :as props}]
|
||||
(case network
|
||||
:mainnet [progress-boxes-mainnet props]
|
||||
(:arbitrum :optimism) [progress-boxes-sidenet props]
|
||||
nil))
|
||||
|
||||
(def view (quo.theme/with-theme view-internal))
|
||||
@@ -39,7 +39,7 @@
|
||||
:width 8
|
||||
:borderRadius 3
|
||||
:borderColor colors/neutral-80-opa-5
|
||||
:backgroundColor (colors/custom-color (:customization-color props) 50)})))
|
||||
:backgroundColor (colors/resolve-color (:customization-color props) theme)})))
|
||||
|
||||
(h/test "finalized state with customtization-color blue in dark mode"
|
||||
(let [theme :dark
|
||||
@@ -51,7 +51,7 @@
|
||||
:width 8
|
||||
:borderRadius 3
|
||||
:borderColor colors/neutral-80-opa-5
|
||||
:backgroundColor (colors/custom-color (:customization-color props) 60)})))
|
||||
:backgroundColor (colors/resolve-color (:customization-color props) theme)})))
|
||||
|
||||
(h/test "finalized state with customtization-color army in light mode"
|
||||
(let [theme :light
|
||||
@@ -63,7 +63,7 @@
|
||||
:width 8
|
||||
:borderRadius 3
|
||||
:borderColor colors/neutral-80-opa-5
|
||||
:backgroundColor (colors/custom-color (:customization-color props) 50)})))
|
||||
:backgroundColor (colors/resolve-color (:customization-color props) theme)})))
|
||||
|
||||
(h/test "confirmed state in light mode"
|
||||
(let [theme :light
|
||||
@@ -75,7 +75,7 @@
|
||||
:width 8
|
||||
:borderRadius 3
|
||||
:borderColor colors/neutral-80-opa-5
|
||||
:backgroundColor colors/success-50})))
|
||||
:backgroundColor (colors/resolve-color :success theme)})))
|
||||
|
||||
(h/test "confirmed state in dark mode"
|
||||
(let [theme :dark
|
||||
@@ -99,7 +99,7 @@
|
||||
:width 8
|
||||
:borderRadius 3
|
||||
:borderColor colors/neutral-80-opa-5
|
||||
:backgroundColor colors/danger-50})))
|
||||
:backgroundColor (colors/resolve-color :danger theme)})))
|
||||
|
||||
(h/test "error state in dark mode"
|
||||
(let [theme :dark
|
||||
@@ -111,4 +111,4 @@
|
||||
:width 8
|
||||
:borderRadius 3
|
||||
:borderColor colors/white-opa-5
|
||||
:backgroundColor colors/danger-60}))))
|
||||
:backgroundColor (colors/resolve-color :danger theme)}))))
|
||||
|
||||
@@ -3,31 +3,48 @@
|
||||
[quo.foundations.colors :as colors]))
|
||||
|
||||
(defn- border-and-background-color
|
||||
[customization-color]
|
||||
[customization-color theme]
|
||||
{:light {:pending {:border-color colors/neutral-80-opa-5
|
||||
:background-color colors/neutral-5}
|
||||
:confirmed {:border-color colors/neutral-80-opa-5
|
||||
:background-color (colors/custom-color :success 50)}
|
||||
:background-color (colors/resolve-color :success theme)}
|
||||
:finalized {:border-color colors/neutral-80-opa-5
|
||||
:background-color (colors/custom-color customization-color 50)}
|
||||
:background-color (colors/resolve-color customization-color theme)}
|
||||
:error {:border-color colors/neutral-80-opa-5
|
||||
:background-color (colors/custom-color :danger 50)}}
|
||||
:background-color (colors/resolve-color :danger theme)}}
|
||||
:dark {:pending {:border-color colors/neutral-70
|
||||
:background-color colors/neutral-80}
|
||||
:confirmed {:border-color colors/white-opa-5
|
||||
:background-color (colors/custom-color :success 60)}
|
||||
:background-color (colors/resolve-color :success theme)}
|
||||
:finalized {:border-color colors/neutral-80-opa-5
|
||||
:background-color (colors/custom-color customization-color 60)}
|
||||
:background-color (colors/resolve-color customization-color theme)}
|
||||
:error {:border-color colors/white-opa-5
|
||||
:background-color (colors/custom-color :danger 60)}}})
|
||||
:background-color (colors/resolve-color :danger theme)}}})
|
||||
|
||||
(def max-value 100)
|
||||
|
||||
(defn root-container
|
||||
[{:keys [customization-color state theme]}]
|
||||
(let [{:keys [background-color border-color]} (get-in (border-and-background-color customization-color)
|
||||
[theme state])]
|
||||
[{:keys [customization-color state theme full-width?]}]
|
||||
(let [{:keys [background-color border-color]} (get-in (border-and-background-color customization-color
|
||||
theme)
|
||||
[theme (if full-width? :pending state)])]
|
||||
{:height 12
|
||||
:flex (when full-width? 1)
|
||||
:width (when (not full-width?) 8)
|
||||
:border-radius 3
|
||||
:border-width 1
|
||||
:border-color border-color
|
||||
:background-color background-color
|
||||
:margin-horizontal 1
|
||||
:margin-vertical 2}))
|
||||
|
||||
(defn progressed-bar
|
||||
[{:keys [customization-color state theme progressed-value]}]
|
||||
(let [{:keys [background-color]} (get-in (border-and-background-color customization-color theme)
|
||||
[theme state])
|
||||
progress (if (> progressed-value max-value) max-value progressed-value)]
|
||||
{:height 12
|
||||
:width 8
|
||||
:margin-top -1
|
||||
:width (str progress "%")
|
||||
:border-radius 3
|
||||
:border-width 1
|
||||
:border-color border-color
|
||||
:background-color background-color}))
|
||||
|
||||
@@ -5,9 +5,11 @@
|
||||
[react-native.core :as rn]))
|
||||
|
||||
(defn- view-internal
|
||||
[props]
|
||||
[{:keys [full-width?] :as props}]
|
||||
[rn/view
|
||||
{:accessibility-label :progress-bar
|
||||
:style (style/root-container props)}])
|
||||
:style (style/root-container props)}
|
||||
(when full-width?
|
||||
[rn/view {:style (style/progressed-bar props)}])])
|
||||
|
||||
(def view (quo.theme/with-theme view-internal))
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
(defn container
|
||||
[networks? theme]
|
||||
{:width 335
|
||||
{:width "100%"
|
||||
:height (if networks? 90 56)
|
||||
:border-radius 16
|
||||
:border-width 1
|
||||
|
||||
@@ -6,14 +6,14 @@
|
||||
(h/describe "Wallet: Token Input"
|
||||
(h/test "Token label renders"
|
||||
(h/render [token-input/view
|
||||
{:token :snt
|
||||
{:token {:symbol "snt"}
|
||||
:currency :eur
|
||||
:conversion 1}])
|
||||
(h/is-truthy (h/get-by-text "SNT")))
|
||||
|
||||
(h/test "Amount renders"
|
||||
(h/render [token-input/view
|
||||
{:token :snt
|
||||
{:token {:symbol "snt"}
|
||||
:currency :eur
|
||||
:conversion 1}])
|
||||
(h/is-truthy (h/get-by-text "€0.00"))))
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
:align-items :flex-end}}
|
||||
[rn/image
|
||||
{:style style/token
|
||||
:source (resources/get-token token)}]
|
||||
:source (resources/get-token (keyword (string/lower-case token)))}]
|
||||
[rn/text-input
|
||||
(cond-> {:auto-focus true
|
||||
:ref #(reset! input-ref %)
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
(ns quo.components.wallet.transaction-progress.component-spec
|
||||
(:require [quo.core :as quo]
|
||||
[reagent.core :as reagent]
|
||||
[test-helpers.component :as h]))
|
||||
|
||||
(defn- get-test-data
|
||||
[{:keys [state network]
|
||||
:or {state :pending network :mainnet}}]
|
||||
{:title "Title"
|
||||
:tag-name "Doodle"
|
||||
:tag-number "120"
|
||||
:network network
|
||||
:customization-color :blue
|
||||
:networks [{:network :mainnet
|
||||
:state state
|
||||
:counter (reagent/atom 0)
|
||||
:total-box 85
|
||||
:progress 30
|
||||
:epoch-number "123"}
|
||||
{:network :optimism
|
||||
:state state
|
||||
:progress "50"
|
||||
:epoch-number "123"}
|
||||
{:network :arbitrum
|
||||
:state state
|
||||
:progress "30"
|
||||
:epoch-number "123"}]
|
||||
:on-press (fn []
|
||||
(js/alert "Transaction progress item pressed"))})
|
||||
|
||||
(h/describe "Transaction Progress"
|
||||
(h/test "component renders without props"
|
||||
(h/render [quo/transaction-progress])
|
||||
(h/is-truthy (h/get-by-label-text :transaction-progress)))
|
||||
|
||||
(h/test "component renders when state is pending and network is mainnet"
|
||||
(h/render [quo/transaction-progress (get-test-data {:network :optimism-arbitrum})])
|
||||
(h/is-truthy (h/get-by-label-text :transaction-progress)))
|
||||
|
||||
(h/test "component renders when state is sending and network is optimism-arbitrum"
|
||||
(h/render [quo/transaction-progress
|
||||
(get-test-data {:state :sending
|
||||
:network :optimism-arbitrum})])
|
||||
(h/is-truthy (h/get-by-label-text :transaction-progress)))
|
||||
|
||||
(h/test "component renders when state is confirmed and network is optimism-arbitrum"
|
||||
(h/render [quo/transaction-progress
|
||||
(get-test-data {:state :confirmed
|
||||
:network :optimism-arbitrum})])
|
||||
(h/is-truthy (h/get-by-label-text :transaction-progress)))
|
||||
|
||||
(h/test "component renders when state is finalising and network is optimism-arbitrum"
|
||||
(h/render [quo/transaction-progress
|
||||
(get-test-data {:state :finalising
|
||||
:network :optimism-arbitrum})])
|
||||
(h/is-truthy (h/get-by-label-text :transaction-progress)))
|
||||
|
||||
(h/test "component renders when state is finalized and network is optimism-arbitrum"
|
||||
(h/render [quo/transaction-progress
|
||||
(get-test-data {:state :finalized
|
||||
:network :optimism-arbitrum})])
|
||||
(h/is-truthy (h/get-by-label-text :transaction-progress)))
|
||||
|
||||
(h/test "component renders when state is error and network is optimism-arbitrum"
|
||||
(h/render [quo/transaction-progress
|
||||
(get-test-data {:state :error
|
||||
:network :optimism-arbitrum})])
|
||||
(h/is-truthy (h/get-by-label-text :transaction-progress)))
|
||||
|
||||
(h/test "component renders when state is sending and network is optimism"
|
||||
(h/render [quo/transaction-progress
|
||||
(get-test-data {:state :sending
|
||||
:network :optimism})])
|
||||
(h/is-truthy (h/get-by-label-text :transaction-progress)))
|
||||
|
||||
(h/test "component renders when state is confirmed and network is optimism"
|
||||
(h/render [quo/transaction-progress
|
||||
(get-test-data {:state :confirmed
|
||||
:network :optimism})])
|
||||
(h/is-truthy (h/get-by-label-text :transaction-progress)))
|
||||
|
||||
(h/test "component renders when state is finalising and network is optimism"
|
||||
(h/render [quo/transaction-progress
|
||||
(get-test-data {:state :finalising
|
||||
:network :optimism})])
|
||||
(h/is-truthy (h/get-by-label-text :transaction-progress)))
|
||||
|
||||
(h/test "component renders when state is finalized and network is optimism"
|
||||
(h/render [quo/transaction-progress
|
||||
(get-test-data {:state :finalized
|
||||
:network :optimism})])
|
||||
(h/is-truthy (h/get-by-label-text :transaction-progress)))
|
||||
|
||||
(h/test "component renders when state is error and network is optimism"
|
||||
(h/render [quo/transaction-progress
|
||||
(get-test-data {:state :error
|
||||
:network :optimism})])
|
||||
(h/is-truthy (h/get-by-label-text :transaction-progress)))
|
||||
|
||||
(h/test "component renders when state is sending and network is arbitrum"
|
||||
(h/render [quo/transaction-progress
|
||||
(get-test-data {:state :sending
|
||||
:network :arbitrum})])
|
||||
(h/is-truthy (h/get-by-label-text :transaction-progress)))
|
||||
|
||||
(h/test "component renders when state is confirmed and network is arbitrum"
|
||||
(h/render [quo/transaction-progress
|
||||
(get-test-data {:state :confirmed
|
||||
:network :arbitrum})])
|
||||
(h/is-truthy (h/get-by-label-text :transaction-progress)))
|
||||
|
||||
(h/test "component renders when state is finalising and network is arbitrum"
|
||||
(h/render [quo/transaction-progress
|
||||
(get-test-data {:state :finalising
|
||||
:network :arbitrum})])
|
||||
(h/is-truthy (h/get-by-label-text :transaction-progress)))
|
||||
|
||||
(h/test "component renders when state is finalized and network is arbitrum"
|
||||
(h/render [quo/transaction-progress
|
||||
(get-test-data {:state :finalized
|
||||
:network :arbitrum})])
|
||||
(h/is-truthy (h/get-by-label-text :transaction-progress)))
|
||||
|
||||
(h/test "component renders when state is error and network is arbitrum"
|
||||
(h/render [quo/transaction-progress
|
||||
(get-test-data {:state :error
|
||||
:network :arbitrum})])
|
||||
(h/is-truthy (h/get-by-label-text :transaction-progress)))
|
||||
|
||||
(h/test "component renders when state is pending and network is mainnet"
|
||||
(h/render [quo/transaction-progress (get-test-data {})])
|
||||
(h/is-truthy (h/get-by-label-text :transaction-progress)))
|
||||
|
||||
(h/test "component renders when state is sending and network is mainnet"
|
||||
(h/render [quo/transaction-progress (get-test-data {:state :sending})])
|
||||
(h/is-truthy (h/get-by-label-text :transaction-progress)))
|
||||
|
||||
(h/test "component renders when state is confirmed and network is mainnet"
|
||||
(h/render [quo/transaction-progress (get-test-data {:state :confirmed})])
|
||||
(h/is-truthy (h/get-by-label-text :transaction-progress)))
|
||||
|
||||
(h/test "component renders when state is finalising and network is mainnet"
|
||||
(h/render [quo/transaction-progress (get-test-data {:state :finalising})])
|
||||
(h/is-truthy (h/get-by-label-text :transaction-progress)))
|
||||
|
||||
(h/test "component renders when state is finalized and network is mainnet"
|
||||
(h/render [quo/transaction-progress (get-test-data {:state :finalized})])
|
||||
(h/is-truthy (h/get-by-label-text :transaction-progress)))
|
||||
|
||||
(h/test "component renders when state is error and network is mainnet"
|
||||
(h/render [quo/transaction-progress (get-test-data {:state :error})])
|
||||
(h/is-truthy (h/get-by-label-text :transaction-progress)))
|
||||
|
||||
(h/test "mainnet progress box is visible network is mainnet"
|
||||
(h/render [quo/transaction-progress (get-test-data {})])
|
||||
(h/is-truthy (h/get-by-label-text :mainnet-progress-box)))
|
||||
|
||||
(h/test "arbitrum-optimism progress box is visible network is optimism-arbitrum"
|
||||
(h/render [quo/transaction-progress (get-test-data {:network :optimism-arbitrum})])
|
||||
(h/is-truthy (h/get-all-by-label-text :progress-box)))
|
||||
|
||||
(h/test "arbitrum progress box is visible network is arbitrum"
|
||||
(h/render [quo/transaction-progress (get-test-data {:network :arbitrum})])
|
||||
(h/is-truthy (h/get-all-by-label-text :progress-box)))
|
||||
|
||||
(h/test "optimism progress box is visible network is optimism"
|
||||
(h/render [quo/transaction-progress (get-test-data {:network :optimism})])
|
||||
(h/is-truthy (h/get-all-by-label-text :progress-box)))
|
||||
|
||||
(h/test "title is visible network is optimism-arbitrum"
|
||||
(h/render [quo/transaction-progress (get-test-data {:network :optimism-arbitrum})])
|
||||
(h/is-truthy (h/get-by-text "Title")))
|
||||
|
||||
(h/test "title is visible network is mainnet"
|
||||
(h/render [quo/transaction-progress (get-test-data {})])
|
||||
(h/is-truthy (h/get-by-text "Title")))
|
||||
|
||||
(h/test "title is visible network is optimism"
|
||||
(h/render [quo/transaction-progress (get-test-data {:network :optimism})])
|
||||
(h/is-truthy (h/get-by-text "Title")))
|
||||
|
||||
(h/test "title is visible network is arbitrum"
|
||||
(h/render [quo/transaction-progress (get-test-data {:network :arbitrum})])
|
||||
(h/is-truthy (h/get-by-text "Title")))
|
||||
|
||||
(h/test "context tag is visible network is optimism-arbitrum"
|
||||
(h/render [quo/transaction-progress (get-test-data {:network :optimism-arbitrum})])
|
||||
(h/is-truthy (h/get-by-label-text :context-tag)))
|
||||
|
||||
(h/test "context tag is visible network is mainnet"
|
||||
(h/render [quo/transaction-progress (get-test-data {})])
|
||||
(h/is-truthy (h/get-by-label-text :context-tag)))
|
||||
|
||||
(h/test "context tag is visible network is optimism"
|
||||
(h/render [quo/transaction-progress (get-test-data {:network :optimism})])
|
||||
(h/is-truthy (h/get-by-label-text :context-tag)))
|
||||
|
||||
(h/test "context tag is visible network is optimism"
|
||||
(h/render [quo/transaction-progress (get-test-data {:network :arbitrum})])
|
||||
(h/is-truthy (h/get-by-label-text :context-tag))))
|
||||
@@ -0,0 +1,38 @@
|
||||
(ns quo.components.wallet.transaction-progress.style
|
||||
(:require [quo.foundations.colors :as colors]))
|
||||
|
||||
(def title-text-container
|
||||
{:flex 1})
|
||||
|
||||
(def icon
|
||||
{:margin-right 4})
|
||||
|
||||
(defn box-style
|
||||
[theme]
|
||||
{:border-radius 16
|
||||
:border-width 1
|
||||
:border-color (colors/theme-colors colors/neutral-10 colors/neutral-80 theme)})
|
||||
|
||||
(def title-container
|
||||
{:align-items :center
|
||||
:flex-direction :row
|
||||
:padding-left 12
|
||||
:padding-top 8
|
||||
:padding-right 8
|
||||
:padding-bottom 4})
|
||||
|
||||
(def status-row-container
|
||||
{:flex-direction :row
|
||||
:align-items :center
|
||||
:flex 1
|
||||
:padding-horizontal 12
|
||||
:padding-top 8
|
||||
:padding-bottom 4})
|
||||
|
||||
(defn context-tag-container
|
||||
[theme]
|
||||
{:padding-horizontal 12
|
||||
:padding-bottom 8
|
||||
:flex-direction :row
|
||||
:border-bottom-width 1
|
||||
:border-color (colors/theme-colors colors/neutral-10 colors/neutral-80 theme)})
|
||||
@@ -0,0 +1,187 @@
|
||||
(ns quo.components.wallet.transaction-progress.view
|
||||
(:require [quo.components.buttons.button.view :as button]
|
||||
[quo.components.icon :as icons]
|
||||
[quo.components.markdown.text :as text]
|
||||
[quo.components.tags.context-tag.view :as context-tag]
|
||||
[quo.components.wallet.confirmation-progress.view :as confirmation-progress]
|
||||
[quo.components.wallet.transaction-progress.style :as style]
|
||||
[quo.foundations.colors :as colors]
|
||||
[quo.theme :as quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
(def ^:private max-mainnet-verifications 4)
|
||||
(def ^:private max-sidenet-verifications 1)
|
||||
|
||||
(defn- icon-internal
|
||||
([icon]
|
||||
(icon-internal icon nil 20))
|
||||
([icon color]
|
||||
(icon-internal icon color 20))
|
||||
([icon color size]
|
||||
[rn/view {:style style/icon}
|
||||
[icons/icon
|
||||
icon
|
||||
{:color color
|
||||
:size size
|
||||
:no-color (when (not color) true)}]]))
|
||||
|
||||
(defn- text-internal
|
||||
[{:keys [weight size accessibility-label color]
|
||||
:or {weight :semi-bold
|
||||
size :paragraph-1}}
|
||||
title]
|
||||
[text/text
|
||||
{:accessibility-label accessibility-label
|
||||
:ellipsize-mode :tail
|
||||
:number-of-lines 1
|
||||
:weight weight
|
||||
:size size
|
||||
:style {:color color}}
|
||||
title])
|
||||
|
||||
(defn- network-type-text
|
||||
[state]
|
||||
(case state
|
||||
(:sending :pending) (i18n/label :t/pending-on)
|
||||
(:confirmed :finalising) (i18n/label :t/confirmed-on)
|
||||
:finalized (i18n/label :t/finalized-on)
|
||||
:error (i18n/label :t/failed-on)
|
||||
nil))
|
||||
|
||||
(defn- calculate-counter
|
||||
[counter]
|
||||
(if (< counter 4) counter max-mainnet-verifications))
|
||||
|
||||
(defn mainnet-label
|
||||
[counter]
|
||||
(str counter "/" max-mainnet-verifications))
|
||||
|
||||
(defn subnet-label
|
||||
[counter]
|
||||
(str counter "/" max-sidenet-verifications))
|
||||
|
||||
(defn- text-steps
|
||||
[network state epoch-number counter]
|
||||
(let [steps (case network
|
||||
:mainnet
|
||||
{:pending (mainnet-label 0)
|
||||
:sending (mainnet-label (calculate-counter counter))
|
||||
:confirmed (mainnet-label (calculate-counter counter))
|
||||
:finalising (mainnet-label (calculate-counter counter))
|
||||
:finalized (i18n/label :t/epoch-number {:number epoch-number})
|
||||
:error (mainnet-label 0)}
|
||||
(or :optimism :arbitrum)
|
||||
{:pending (subnet-label 0)
|
||||
:sending (subnet-label 0)
|
||||
:confirmed (subnet-label 0)
|
||||
:finalising (subnet-label 1)
|
||||
:finalized (i18n/label :t/epoch-number {:number epoch-number})
|
||||
:error (subnet-label 0)}
|
||||
nil)]
|
||||
(get steps state)))
|
||||
|
||||
(defn- get-status-icon
|
||||
[theme state]
|
||||
(case state
|
||||
(:pending :sending) {:icon :i/pending-state
|
||||
:color (colors/theme-colors colors/neutral-50
|
||||
colors/neutral-40
|
||||
theme)}
|
||||
(:confirmed :finalising) {:icon :i/positive-state
|
||||
:color (colors/resolve-color :success theme)}
|
||||
:finalized {:icon :i/diamond}
|
||||
:error {:icon :i/negative-state
|
||||
:color (colors/resolve-color :danger theme)}
|
||||
nil))
|
||||
|
||||
(defn- get-network
|
||||
[networks network]
|
||||
(some #(when (= (:network %) network) %)
|
||||
networks))
|
||||
|
||||
(defn- calculate-error-state
|
||||
[networks]
|
||||
(some #(= (:state %) :error) networks))
|
||||
|
||||
(defn- title-internal
|
||||
[{:keys [title theme networks]}]
|
||||
[rn/view {:style style/title-container}
|
||||
[icon-internal :i/placeholder (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)]
|
||||
[rn/view {:style style/title-text-container}
|
||||
[text-internal nil title]]
|
||||
(when (calculate-error-state networks)
|
||||
[button/button
|
||||
{:size 24
|
||||
:icon-left :i/refresh}
|
||||
(i18n/label :t/retry)])])
|
||||
|
||||
(defn- tag-internal
|
||||
[tag-photo tag-name tag-number theme]
|
||||
[rn/view {:style (style/context-tag-container theme)}
|
||||
[context-tag/view
|
||||
{:size 24
|
||||
:collectible tag-photo
|
||||
:collectible-name tag-name
|
||||
:collectible-number tag-number
|
||||
:type :collectible}]])
|
||||
|
||||
(defn- get-network-text
|
||||
[network]
|
||||
(case network
|
||||
:arbitrum (i18n/label :t/arbitrum)
|
||||
:mainnet (i18n/label :t/mainnet)
|
||||
:optimism (i18n/label :t/optimism)
|
||||
nil))
|
||||
|
||||
(defn- status-row
|
||||
[{:keys [theme state network epoch-number counter]}]
|
||||
(let [{:keys [icon color]} (get-status-icon theme state)]
|
||||
[rn/view {:style style/status-row-container}
|
||||
[icon-internal icon color 16]
|
||||
[rn/view {:style style/title-text-container}
|
||||
[text-internal
|
||||
{:weight :regular
|
||||
:size :paragraph-2}
|
||||
(str (network-type-text state) " " (get-network-text network))]]
|
||||
[rn/view
|
||||
[text-internal
|
||||
{:weight :regular
|
||||
:size :paragraph-2
|
||||
:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)}
|
||||
(text-steps network state epoch-number counter)]]]))
|
||||
|
||||
(defn- view-network
|
||||
[{:keys [theme state epoch-number counter total-box progress network]}]
|
||||
[:<>
|
||||
[status-row
|
||||
{:theme theme
|
||||
:state state
|
||||
:network network
|
||||
:epoch-number epoch-number
|
||||
:counter counter}]
|
||||
[confirmation-progress/view
|
||||
{:state state
|
||||
:network network
|
||||
:counter counter
|
||||
:total-box total-box
|
||||
:progress-value progress}]])
|
||||
|
||||
(defn- view-internal
|
||||
[{:keys [title on-press accessibility-label theme tag-photo tag-name tag-number networks]
|
||||
:or {accessibility-label :transaction-progress}}]
|
||||
[rn/touchable-without-feedback
|
||||
{:on-press on-press
|
||||
:accessibility-label accessibility-label}
|
||||
[rn/view {:style (style/box-style theme)}
|
||||
[title-internal
|
||||
{:title title
|
||||
:theme theme
|
||||
:networks networks}]
|
||||
[tag-internal tag-photo tag-name tag-number theme]
|
||||
(for [network networks]
|
||||
^{:key (:network network)}
|
||||
(let [assoc-props #(get-network networks %)]
|
||||
[view-network (assoc-props (:network network))]))]])
|
||||
|
||||
(def view (quo.theme/with-theme view-internal))
|
||||
@@ -141,11 +141,13 @@
|
||||
quo.components.tags.token-tag.view
|
||||
quo.components.text-combinations.channel-name.view
|
||||
quo.components.text-combinations.standard-title.view
|
||||
quo.components.text-combinations.username.view
|
||||
quo.components.text-combinations.view
|
||||
quo.components.wallet.account-card.view
|
||||
quo.components.wallet.account-origin.view
|
||||
quo.components.wallet.account-overview.view
|
||||
quo.components.wallet.address-text.view
|
||||
quo.components.wallet.confirmation-progress.view
|
||||
quo.components.wallet.keypair.view
|
||||
quo.components.wallet.network-amount.view
|
||||
quo.components.wallet.network-bridge.view
|
||||
@@ -154,6 +156,7 @@
|
||||
quo.components.wallet.progress-bar.view
|
||||
quo.components.wallet.summary-info.view
|
||||
quo.components.wallet.token-input.view
|
||||
quo.components.wallet.transaction-progress.view
|
||||
quo.components.wallet.transaction-summary.view
|
||||
quo.components.wallet.wallet-activity.view
|
||||
quo.components.wallet.wallet-overview.view))
|
||||
@@ -383,12 +386,14 @@
|
||||
(def channel-name quo.components.text-combinations.channel-name.view/view)
|
||||
(def standard-title quo.components.text-combinations.standard-title.view/view)
|
||||
(def text-combinations quo.components.text-combinations.view/view)
|
||||
(def username quo.components.text-combinations.username.view/view)
|
||||
|
||||
;;;; Wallet
|
||||
(def account-card quo.components.wallet.account-card.view/view)
|
||||
(def account-origin quo.components.wallet.account-origin.view/view)
|
||||
(def account-overview quo.components.wallet.account-overview.view/view)
|
||||
(def address-text quo.components.wallet.address-text.view/view)
|
||||
(def confirmation-propgress quo.components.wallet.confirmation-progress.view/view)
|
||||
(def keypair quo.components.wallet.keypair.view/view)
|
||||
(def network-amount quo.components.wallet.network-amount.view/view)
|
||||
(def network-bridge quo.components.wallet.network-bridge.view/view)
|
||||
@@ -399,4 +404,5 @@
|
||||
(def token-input quo.components.wallet.token-input.view/view)
|
||||
(def wallet-overview quo.components.wallet.wallet-overview.view/view)
|
||||
(def wallet-activity quo.components.wallet.wallet-activity.view/view)
|
||||
(def transaction-progress quo.components.wallet.transaction-progress.view/view)
|
||||
(def transaction-summary quo.components.wallet.transaction-summary.view/view)
|
||||
|
||||
@@ -77,9 +77,11 @@
|
||||
[quo.components.tags.summary-tag.component-spec]
|
||||
[quo.components.tags.tiny-tag.component-spec]
|
||||
[quo.components.text-combinations.channel-name.component-spec]
|
||||
[quo.components.text-combinations.username.component-spec]
|
||||
[quo.components.wallet.account-card.component-spec]
|
||||
[quo.components.wallet.account-origin.component-spec]
|
||||
[quo.components.wallet.account-overview.component-spec]
|
||||
[quo.components.wallet.confirmation-progress.component-spec]
|
||||
[quo.components.wallet.keypair.component-spec]
|
||||
[quo.components.wallet.network-amount.component-spec]
|
||||
[quo.components.wallet.network-bridge.component-spec]
|
||||
@@ -87,6 +89,7 @@
|
||||
[quo.components.wallet.progress-bar.component-spec]
|
||||
[quo.components.wallet.summary-info.component-spec]
|
||||
[quo.components.wallet.token-input.component-spec]
|
||||
[quo.components.wallet.transaction-progress.component-spec]
|
||||
[quo.components.wallet.transaction-summary.component-spec]
|
||||
[quo.components.wallet.wallet-activity.component-spec]
|
||||
[quo.components.wallet.wallet-overview.component-spec]))
|
||||
|
||||
@@ -285,10 +285,6 @@
|
||||
(get-in colors-map [color suffix]))))
|
||||
|
||||
(defn- resolve-color*
|
||||
"(resolve-color color theme opacity)
|
||||
color hex string or keyword (resolves from custom, network and semantic colors)
|
||||
theme :light/:dark
|
||||
opacity 0-100 (optional) - if set theme is ignored and goes to 50 suffix internally"
|
||||
([color theme]
|
||||
(resolve-color* color theme nil))
|
||||
([color theme opacity]
|
||||
@@ -300,7 +296,12 @@
|
||||
suffix (get-from-colors-map suffix)
|
||||
opacity (alpha (/ opacity 100))))))
|
||||
|
||||
(def resolve-color (memoize resolve-color*))
|
||||
(def resolve-color
|
||||
"(resolve-color color theme opacity)
|
||||
color hex string or keyword (resolves from custom, network and semantic colors)
|
||||
theme :light/:dark
|
||||
opacity 0-100 (optional) - if set theme is ignored and goes to 50 suffix internally"
|
||||
(memoize resolve-color*))
|
||||
|
||||
(def ^{:deprecated true :superseded-by "resolve-color"}
|
||||
custom-color
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
{:db (update-in db [:chats chat-id] merge chat)}))
|
||||
|
||||
(rf/defn load-chat
|
||||
{:events [:chats-list/load-chat]}
|
||||
[_ chat-id]
|
||||
{:json-rpc/call [{:method "wakuext_chat"
|
||||
:params [chat-id]
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
(ns status-im.commands.core
|
||||
(:require
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.wallet.utils :as wallet.utils]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/defn handle-prepare-accept-request-address-for-transaction
|
||||
{:events [::prepare-accept-request-address-for-transaction]}
|
||||
[{:keys [db]} message]
|
||||
{:db (assoc db
|
||||
:commands/select-account
|
||||
{:message message
|
||||
:from (wallet.utils/get-default-account (:profile/wallet-accounts
|
||||
db))})
|
||||
:show-select-acc-sheet nil})
|
||||
|
||||
(rf/defn set-selected-account
|
||||
{:events [::set-selected-account]}
|
||||
[{:keys [db]} _ account]
|
||||
{:db (-> (assoc-in db [:commands/select-account :from] account)
|
||||
(assoc :bottom-sheet/show? false))})
|
||||
|
||||
(rf/defn handle-accept-request-address-for-transaction
|
||||
{:events [::accept-request-address-for-transaction]}
|
||||
[{:keys [db]} message-id address]
|
||||
{:db (dissoc db :commands/select-account)
|
||||
:json-rpc/call [{:method "wakuext_acceptRequestAddressForTransaction"
|
||||
:params [message-id address]
|
||||
:js-response true
|
||||
:on-success #(re-frame/dispatch [:transport/message-sent %])}]})
|
||||
|
||||
(rf/defn handle-decline-request-address-for-transaction
|
||||
{:events [::decline-request-address-for-transaction]}
|
||||
[_ message-id]
|
||||
{:json-rpc/call [{:method "wakuext_declineRequestAddressForTransaction"
|
||||
:params [message-id]
|
||||
:js-response true
|
||||
:on-success #(re-frame/dispatch [:transport/message-sent %])}]})
|
||||
|
||||
(rf/defn handle-decline-request-transaction
|
||||
{:events [::decline-request-transaction]}
|
||||
[cofx message-id]
|
||||
{:json-rpc/call [{:method "wakuext_declineRequestTransaction"
|
||||
:params [message-id]
|
||||
:js-response true
|
||||
:on-success #(re-frame/dispatch [:transport/message-sent %])}]})
|
||||
@@ -74,6 +74,7 @@
|
||||
:adminSettings :admin-settings
|
||||
:tokenPermissions :token-permissions
|
||||
:communityTokensMetadata :tokens-metadata
|
||||
:introMessage :intro-message
|
||||
:muteTill :muted-till})
|
||||
(update :admin-settings
|
||||
set/rename-keys
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
(ns status-im.contact.chat
|
||||
(:require
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im2.contexts.contacts.events :as contact]
|
||||
[status-im2.navigation.events :as navigation]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/defn contact-code-submitted
|
||||
{:events [:contact.ui/contact-code-submitted]
|
||||
:interceptors [(re-frame/inject-cofx :random-id-generator)]}
|
||||
[{{:contacts/keys [new-identity]} :db :as cofx} new-contact? nickname]
|
||||
(let [{:keys [public-key ens-name]} new-identity]
|
||||
(rf/merge cofx
|
||||
#(if new-contact?
|
||||
(contact/send-contact-request % public-key)
|
||||
{:dispatch [:chat.ui/start-chat public-key ens-name]})
|
||||
#(when new-contact?
|
||||
(navigation/navigate-back %)))))
|
||||
@@ -1,13 +0,0 @@
|
||||
(ns status-im.contact.core
|
||||
(:require
|
||||
[status-im2.navigation.events :as navigation]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/defn open-contact-toggle-list
|
||||
{:events [:contact.ui/start-group-chat-pressed]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(rf/merge cofx
|
||||
{:db (assoc db
|
||||
:group/selected-contacts #{}
|
||||
:new-chat-name "")}
|
||||
(navigation/navigate-to :contact-toggle-list nil)))
|
||||
@@ -85,12 +85,3 @@
|
||||
(assoc acc public-key (enrich-contact contact profile-pictures-visibility own-public-key)))
|
||||
{}
|
||||
contacts))
|
||||
|
||||
(defn get-blocked-contacts
|
||||
[contacts]
|
||||
(reduce (fn [acc {:keys [public-key] :as contact}]
|
||||
(if (:blocked? contact)
|
||||
(conj acc public-key)
|
||||
acc))
|
||||
#{}
|
||||
contacts))
|
||||
|
||||
+19
-14
@@ -91,11 +91,11 @@
|
||||
{:chainId :chain-id
|
||||
:removed :removed?})
|
||||
name-details)]
|
||||
{:db (reduce (fn [db {:keys [username removed?] :as name-detail}]
|
||||
{:db (reduce (fn [db {:keys [username removed? chain-id] :as name-detail}]
|
||||
(if removed?
|
||||
(update-in db [:ens/names] dissoc username)
|
||||
(let [old (get-in db [:ens/names username])]
|
||||
(assoc-in db [:ens/names username] (merge old name-detail)))))
|
||||
(update-in db [:ens/names chain-id] dissoc username)
|
||||
(let [old (get-in db [:ens/names chain-id username])]
|
||||
(assoc-in db [:ens/names chain-id username] (merge old name-detail)))))
|
||||
db
|
||||
name-details)}))
|
||||
|
||||
@@ -103,8 +103,8 @@
|
||||
{:events [:ens/save-username]}
|
||||
[{:keys [db] :as cofx} custom-domain? username redirect-to-summary? connected?]
|
||||
(let [name (fullname custom-domain? username)
|
||||
names (get-in db [:ens/names] [])
|
||||
chain-id (chain/chain-id db)]
|
||||
chain-id (chain/chain-id db)
|
||||
names (get-in db [:ens/names chain-id] [])]
|
||||
(rf/merge cofx
|
||||
(cond-> {:dispatch-n [[:ens/update-usernames [{:username name :chain-id chain-id}]]]}
|
||||
connected? (assoc :json-rpc/call
|
||||
@@ -240,7 +240,8 @@
|
||||
{:events [::set-username-candidate]}
|
||||
[{:keys [db]} username]
|
||||
(let [{:keys [custom-domain?]} (:ens/registration db)
|
||||
usernames (into #{} (keys (get-in db [:ens/names])))
|
||||
chain-id (chain/chain-id db)
|
||||
usernames (into #{} (keys (get-in db [:ens/names chain-id])))
|
||||
state (state custom-domain? username usernames)]
|
||||
(reset! resolve-last-id (random/id))
|
||||
(merge
|
||||
@@ -310,20 +311,23 @@
|
||||
(rf/defn store-name-address
|
||||
{:events [::address-resolved]}
|
||||
[{:keys [db]} username address]
|
||||
{:db (assoc-in db [:ens/names username :address] address)})
|
||||
(let [chain-id (chain/chain-id db)]
|
||||
{:db (assoc-in db [:ens/names chain-id username :address] address)}))
|
||||
|
||||
(rf/defn store-name-public-key
|
||||
{:events [::public-key-resolved]}
|
||||
[{:keys [db]} username public-key]
|
||||
{:db (assoc-in db [:ens/names username :public-key] public-key)})
|
||||
(let [chain-id (chain/chain-id db)]
|
||||
{:db (assoc-in db [:ens/names chain-id username :public-key] public-key)}))
|
||||
|
||||
(rf/defn store-expiration-date
|
||||
{:events [::get-expiration-time-success]}
|
||||
[{:keys [now db]} username timestamp]
|
||||
{:db (-> db
|
||||
(assoc-in [:ens/names username :expiration-date]
|
||||
(datetime/timestamp->year-month-day-date timestamp))
|
||||
(assoc-in [:ens/names username :releasable?] (<= timestamp now)))})
|
||||
(let [chain-id (chain/chain-id db)]
|
||||
{:db (-> db
|
||||
(assoc-in [:ens/names chain-id username :expiration-date]
|
||||
(datetime/timestamp->year-month-day-date timestamp))
|
||||
(assoc-in [:ens/names chain-id username :releasable?] (<= timestamp now)))}))
|
||||
|
||||
(rf/defn navigate-to-name
|
||||
{:events [::navigate-to-name]}
|
||||
@@ -352,7 +356,8 @@
|
||||
(rf/defn remove-username
|
||||
{:events [::remove-username]}
|
||||
[{:keys [db] :as cofx} name]
|
||||
(let [names (get-in db [:ens/names] [])
|
||||
(let [chain-id (chain/chain-id db)
|
||||
names (get-in db [:ens/names chain-id] [])
|
||||
preferred-name (get-in db [:profile/profile :preferred-name])
|
||||
new-names (remove #(= name %) (keys names))
|
||||
{:keys [chain-id username]} (get-in names [name])]
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
status-im.chat.models.input
|
||||
status-im.chat.models.loading
|
||||
status-im.contact.block
|
||||
status-im.contact.chat
|
||||
status-im.contact.core
|
||||
status-im.currency.core
|
||||
status-im.ethereum.subscriptions
|
||||
status-im.fleet.core
|
||||
@@ -43,12 +41,12 @@
|
||||
status-im.visibility-status-popover.core
|
||||
status-im.visibility-status-updates.core
|
||||
status-im.waku.core
|
||||
status-im.wallet-connect.core
|
||||
status-im.wallet.accounts.core
|
||||
status-im.wallet.choose-recipient.core
|
||||
[status-im.wallet.core :as wallet]
|
||||
status-im.wallet.custom-tokens.core
|
||||
[status-im2.common.biometric.events :as biometric]
|
||||
status-im2.common.standard-authentication.events
|
||||
[status-im2.common.theme.core :as theme]
|
||||
[status-im2.common.universal-links :as universal-links]
|
||||
[status-im2.constants :as constants]
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
[status-im.multiaccounts.model :as multiaccounts.model]
|
||||
[status-im.popover.core :as popover]
|
||||
[status-im.utils.deprecated-types :as types]
|
||||
[status-im.utils.keychain.core :as keychain]
|
||||
[status-im2.constants :as constants]
|
||||
[status-im2.navigation.events :as navigation]
|
||||
[taoensso.timbre :as log]
|
||||
@@ -278,7 +277,7 @@
|
||||
{:db (-> db
|
||||
(assoc-in [:profile/profiles-overview key-uid :keycard-pairing] pairing)
|
||||
(assoc :profile/login account)
|
||||
(assoc :auth-method keychain/auth-method-none)
|
||||
(assoc :auth-method "none")
|
||||
(update :keycard dissoc :flow :migration-password)
|
||||
(dissoc :recovered-account?))
|
||||
::finish-migration [account settings password encryption-pass login-params]}))
|
||||
|
||||
@@ -172,8 +172,7 @@
|
||||
:use-mailservers? true
|
||||
:recovered recovered}
|
||||
config/default-multiaccount)
|
||||
;; The address from which we derive any chat
|
||||
;; account/encryption keys
|
||||
;; The address from which we derive any chat account/encryption keys
|
||||
eip1581-address
|
||||
(assoc :eip1581-address eip1581-address)
|
||||
save-mnemonic?
|
||||
|
||||
@@ -60,10 +60,17 @@
|
||||
{:state state
|
||||
:username username}))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:ens/current-names
|
||||
:<- [:ens/names]
|
||||
:<- [:chain-id]
|
||||
(fn [[all-names chain-id]]
|
||||
(get all-names chain-id)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:ens.name/screen
|
||||
:<- [:get-screen-params :ens-name-details]
|
||||
:<- [:ens/names]
|
||||
:<- [:ens/current-names]
|
||||
(fn [[name ens]]
|
||||
(let [{:keys [address public-key expiration-date releasable?]} (get ens name)
|
||||
pending? (nil? address)]
|
||||
@@ -79,7 +86,7 @@
|
||||
|
||||
(re-frame/reg-sub
|
||||
:ens.main/screen
|
||||
:<- [:ens/names]
|
||||
:<- [:ens/current-names]
|
||||
:<- [:profile/profile]
|
||||
:<- [:ens/preferred-name]
|
||||
:<- [:ens/registrations]
|
||||
|
||||
@@ -7,6 +7,11 @@
|
||||
[utils.i18n :as i18n])
|
||||
(:require-macros [status-im.utils.views :as views]))
|
||||
|
||||
(defn hide-sheet-and-dispatch
|
||||
[event]
|
||||
(re-frame/dispatch [:bottom-sheet/hide-old])
|
||||
(re-frame/dispatch event))
|
||||
|
||||
(defn- normal-mode-settings-data
|
||||
[{:keys [network-name
|
||||
current-log-level
|
||||
@@ -103,7 +108,13 @@
|
||||
#(re-frame/dispatch
|
||||
[:multiaccounts.ui/waku-bloom-filter-mode-switched (not waku-bloom-filter-mode)])
|
||||
:accessory :switch
|
||||
:active waku-bloom-filter-mode}]))
|
||||
:active waku-bloom-filter-mode}
|
||||
{:size :small
|
||||
:title (i18n/label :t/set-currency)
|
||||
:accessibility-label :wallet-change-currency
|
||||
:on-press #(hide-sheet-and-dispatch
|
||||
[:navigate-to :currency-settings])
|
||||
:chevron true}]))
|
||||
|
||||
(defn- flat-list-data
|
||||
[options]
|
||||
|
||||
@@ -46,7 +46,8 @@
|
||||
:key :your-data-belongs-to-you-description}]
|
||||
[react/view {:style styles/intro-button}
|
||||
[quo/button
|
||||
{:on-press #(re-frame/dispatch [:set-in [:my-profile/seed :step] :12-words])}
|
||||
{:on-press #(do (re-frame/dispatch [:set-in [:my-profile/seed :step] :12-words])
|
||||
(re-frame/dispatch [:profile.settings/mnemonic-was-shown]))}
|
||||
(i18n/label :t/ok-continue)]]])
|
||||
|
||||
(defn six-words
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
(ns status-im.ui.screens.wallet.send.views
|
||||
(:require-macros [status-im.utils.views :refer [defview letsubs] :as views])
|
||||
(:require-macros [status-im.utils.views :as views])
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.commands.core :as commands]
|
||||
[status-im.ui.components.bottom-panel.views :as bottom-panel]
|
||||
[status-im.ui.components.chat-icon.screen :as chat-icon]
|
||||
[status-im.ui.components.colors :as colors]
|
||||
[status-im.ui.components.core :as components.core]
|
||||
@@ -129,47 +127,6 @@
|
||||
" "
|
||||
(:code wallet-currency))])))
|
||||
|
||||
(defn select-account-sheet
|
||||
[{:keys [from message]}]
|
||||
[react/view {:style (styles/acc-sheet)}
|
||||
[header
|
||||
{:small-screen? false
|
||||
:label :t/select-account}]
|
||||
[react/view
|
||||
{:flex-direction :row
|
||||
:padding-horizontal 24
|
||||
:align-items :center
|
||||
:margin-vertical 16}]
|
||||
[components.core/list-header
|
||||
(i18n/label :t/from-capitalized)]
|
||||
[react/view {:flex-direction :row :flex 1 :align-items :center}
|
||||
[react/view {:flex 1}
|
||||
[render-account from nil ::commands/set-selected-account]]]
|
||||
[toolbar/toolbar
|
||||
{:left
|
||||
[react/view {:padding-horizontal 8}
|
||||
[components.core/button
|
||||
{:type :secondary
|
||||
:on-press #(re-frame/dispatch [:set :commands/select-account nil])}
|
||||
(i18n/label :t/cancel)]]
|
||||
:right
|
||||
[components.core/button
|
||||
{:accessibility-label :select-account-bottom-sheet
|
||||
:disabled (nil? from)
|
||||
:on-press #(re-frame/dispatch
|
||||
[::commands/accept-request-address-for-transaction
|
||||
(:message-id message)
|
||||
(:address from)])}
|
||||
(i18n/label :t/share)]}]])
|
||||
|
||||
(defview select-account
|
||||
[]
|
||||
(letsubs [data [:commands/select-account]]
|
||||
[bottom-panel/animated-bottom-panel
|
||||
data
|
||||
select-account-sheet
|
||||
#(re-frame/dispatch [:hide-select-acc-sheet])]))
|
||||
|
||||
(views/defview request-transaction
|
||||
[_]
|
||||
(views/letsubs [{:keys [amount-error amount-text from token sign-enabled?] :as tx}
|
||||
|
||||
@@ -6,10 +6,6 @@
|
||||
[taoensso.timbre :as log]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(def auth-method-biometric "biometric")
|
||||
(def auth-method-biometric-prepare "biometric-prepare")
|
||||
(def auth-method-none "none")
|
||||
|
||||
(defn- whisper-key-name
|
||||
[address]
|
||||
(str address "-whisper"))
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
(ns ^{:doc "Pairing utils"} status-im.utils.pairing)
|
||||
|
||||
(defn has-paired-installations?
|
||||
[cofx]
|
||||
(let [our-installation-id (get-in cofx [:db :profile/profile :installation-id])]
|
||||
(->>
|
||||
(get-in cofx [:db :pairing/installations])
|
||||
vals
|
||||
(some (fn [{:keys [enabled? installation-id]}]
|
||||
(and (not= installation-id our-installation-id)
|
||||
enabled?))))))
|
||||
@@ -1,120 +0,0 @@
|
||||
(ns status-im.utils.snoopy
|
||||
(:require
|
||||
["react-native/Libraries/vendor/emitter/EventEmitter" :refer [EventEmitter]]
|
||||
["rn-snoopy" :default snoopy]
|
||||
["rn-snoopy/stream/bars" :default bars]
|
||||
["rn-snoopy/stream/buffer" :default buffer]
|
||||
["rn-snoopy/stream/filter" :default sn-filter]
|
||||
[clojure.string :as string]
|
||||
[status-im2.config :as config]))
|
||||
|
||||
(defn create-filter
|
||||
[f]
|
||||
(fn [^js message]
|
||||
(let [method (.-method message)
|
||||
module (.-module message)
|
||||
^js args (.-args message)
|
||||
first-arg (when (pos? (.-length args))
|
||||
(aget args 0))]
|
||||
(f {:method method
|
||||
:module module
|
||||
:first-arg first-arg}))))
|
||||
|
||||
(defn status-module-filter
|
||||
[{:keys [method module first-arg]}]
|
||||
(or (= module "Status")
|
||||
(and (= module "RCTNativeAppEventEmitter")
|
||||
(= method "emit")
|
||||
(= first-arg "gethEvent"))
|
||||
(and
|
||||
(string? method)
|
||||
(string/starts-with? method "<callback for Status."))))
|
||||
|
||||
(defn timer-filter
|
||||
[{:keys [method]}]
|
||||
(contains? #{"callTimers" "createTimer"} method))
|
||||
|
||||
(defn websocket-filter
|
||||
[{:keys [module first-arg]}]
|
||||
(or (= module "WebSocketModule")
|
||||
(and (= module "RCTDeviceEventEmitter")
|
||||
(contains? #{"websocketFailed" "websocketMessage"} first-arg))))
|
||||
|
||||
(defn ui-manager-filter
|
||||
[{:keys [module]}]
|
||||
(= module "UIManager"))
|
||||
|
||||
(defn touches-filter
|
||||
[{:keys [method module]}]
|
||||
(and (= module "RCTEventEmitter")
|
||||
(= method "receiveTouches")))
|
||||
|
||||
(defn native-animation-filter
|
||||
[{:keys [method module]}]
|
||||
(or (= module "NativeAnimatedModule")
|
||||
(and
|
||||
(string? method)
|
||||
(string/starts-with? method "<callback for NativeAnimatedModule."))))
|
||||
|
||||
(defn keyboard-observer-filter
|
||||
[{:keys [module]}]
|
||||
;; mostly all calls to KeyboardObserver are done by FlatList
|
||||
(= module "KeyboardObserver"))
|
||||
|
||||
(defn threshold-warnings
|
||||
[{:keys [filter-fn label tick? print-events? threshold events threshold-message]}]
|
||||
(.subscribe ^js
|
||||
((bars
|
||||
(fn [^js a] (.-length a))
|
||||
threshold
|
||||
tick?
|
||||
true
|
||||
label
|
||||
threshold-message)
|
||||
((buffer)
|
||||
((sn-filter (create-filter filter-fn)
|
||||
print-events?)
|
||||
events)))))
|
||||
|
||||
;; In order to enable snoopy set SNOOPY=1 in .env file.
|
||||
;; By default events are not printed and you will see warnings only when
|
||||
;; the number of events is exceeding the threshold.
|
||||
;; For debugging UI perf, in particular the number of bridge calls caused
|
||||
;; by view components set `:print-events?=true` for `ui-manager-filter`,
|
||||
;; and then collect printed data in logs.
|
||||
(defn subscribe!
|
||||
[]
|
||||
(when config/snoopy-enabled?
|
||||
(let [emitter-class EventEmitter
|
||||
emitter (emitter-class.)
|
||||
events (.stream snoopy emitter)]
|
||||
(threshold-warnings
|
||||
{:filter-fn (constantly true)
|
||||
:label "all messages"
|
||||
:threshold-message "too many calls to bridge, something suspicious is happening"
|
||||
:tick? false
|
||||
:print-events? false
|
||||
:threshold 400
|
||||
:events events})
|
||||
|
||||
(threshold-warnings
|
||||
{:filter-fn timer-filter
|
||||
:label "timer"
|
||||
:threshold-message "too many setTimeout/setInterval calls"
|
||||
:tick? false
|
||||
:print-events? false
|
||||
:threshold 70
|
||||
:events events})
|
||||
|
||||
(threshold-warnings
|
||||
{:filter-fn ui-manager-filter
|
||||
:label "timer"
|
||||
:threshold-message (str
|
||||
"too many calls to UIManager, most likely during navigation. "
|
||||
"Please consider preloading of screens or lazy loading of some components")
|
||||
:tick? false
|
||||
:print-events? true
|
||||
;; todo(rasom): revisit this number when/if
|
||||
;; https://github.com/status-im/status-mobile/pull/2849 will be merged
|
||||
:threshold 200
|
||||
:events events}))))
|
||||
@@ -1,31 +0,0 @@
|
||||
(ns status-im.utils.wallet-connect
|
||||
(:require
|
||||
["@react-native-async-storage/async-storage" :default AsyncStorage]
|
||||
["@walletconnect/client" :refer [CLIENT_EVENTS] :default WalletConnectClient]
|
||||
[clojure.string :as string]
|
||||
[status-im2.config :as config]))
|
||||
|
||||
(defn init
|
||||
[on-success on-error]
|
||||
(-> ^js WalletConnectClient
|
||||
(.init (clj->js {:controller true
|
||||
:projectId config/wallet-connect-project-id
|
||||
:logger "debug"
|
||||
:metadata config/default-wallet-connect-metadata
|
||||
:storageOptions {:asyncStorage ^js AsyncStorage}}))
|
||||
(.then on-success)
|
||||
(.catch on-error)))
|
||||
|
||||
(defn session-request-event [] (.-request (.-session CLIENT_EVENTS)))
|
||||
|
||||
(defn session-created-event [] (.-created (.-session CLIENT_EVENTS)))
|
||||
|
||||
(defn session-deleted-event [] (.-deleted (.-session CLIENT_EVENTS)))
|
||||
|
||||
(defn session-proposal-event [] (.-proposal (.-session CLIENT_EVENTS)))
|
||||
|
||||
(defn session-updated-event [] (.-updated (.-session CLIENT_EVENTS)))
|
||||
|
||||
(defn url?
|
||||
[url]
|
||||
(string/starts-with? url "wc:"))
|
||||
@@ -7,7 +7,6 @@
|
||||
[status-im.ethereum.ens :as ens]
|
||||
[status-im.ethereum.tokens :as tokens]
|
||||
[status-im.qr-scanner.core :as qr-scaner]
|
||||
[status-im.utils.wallet-connect :as wallet-connect]
|
||||
[status-im.wallet.utils :as wallet.utils]
|
||||
[status-im2.common.router :as router]
|
||||
[status-im2.navigation.events :as navigation]
|
||||
@@ -173,11 +172,7 @@
|
||||
(if (links/universal-link? uri)
|
||||
{:dispatch [:universal-links/handle-url uri]}
|
||||
{:browser/show-browser-selection uri})
|
||||
(if (wallet-connect/url? uri)
|
||||
{:ui/show-error "Wallet Connect not implemented"}
|
||||
;; Re-enable with https://github.com/status-im/status-mobile/issues/13429
|
||||
;; {:dispatch [::qr-scaner/handle-wallet-connect-uri {:data uri}]}
|
||||
{:ui/show-error (i18n/label :t/wallet-invalid-address {:data uri})}))))
|
||||
{:ui/show-error (i18n/label :t/wallet-invalid-address {:data uri})})))
|
||||
|
||||
(rf/defn qr-scanner-result
|
||||
{:events [:wallet-legacy.send/qr-scanner-result]}
|
||||
|
||||
@@ -1074,7 +1074,7 @@
|
||||
|
||||
;;TODO: this could be replaced by a single API call on status-go side
|
||||
(re-frame/reg-fx :wallet-legacy/initialize-wallet
|
||||
(fn [[network-id network callback]]
|
||||
(fn [[network-id _network callback]]
|
||||
(-> (js/Promise.all
|
||||
(clj->js
|
||||
[(js/Promise.
|
||||
@@ -1082,24 +1082,6 @@
|
||||
(json-rpc/call {:method "accounts_getAccounts"
|
||||
:on-success resolve-fn
|
||||
:on-error reject})))
|
||||
(js/Promise.
|
||||
(fn [resolve-fn _]
|
||||
(json-rpc/call
|
||||
{:method "wallet_addEthereumChain"
|
||||
:params
|
||||
[{:isTest false
|
||||
:tokenOverrides []
|
||||
:rpcUrl (get-in network [:config :UpstreamConfig :URL])
|
||||
:chainColor "green"
|
||||
:chainName (:name network)
|
||||
:nativeCurrencyDecimals 10
|
||||
:shortName "erc20"
|
||||
:layer 1
|
||||
:chainId (int network-id)
|
||||
:enabled false
|
||||
:fallbackURL (get-in network [:config :UpstreamConfig :URL])}]
|
||||
:on-success resolve-fn
|
||||
:on-error (fn [_] (resolve-fn nil))})))
|
||||
(js/Promise.
|
||||
(fn [resolve-fn _]
|
||||
(json-rpc/call {:method "wallet_getTokens"
|
||||
|
||||
@@ -1,288 +0,0 @@
|
||||
(ns status-im.wallet-connect.core
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.browser.core :as browser]
|
||||
[status-im.signing.core :as signing]
|
||||
[status-im.utils.deprecated-types :as types]
|
||||
[status-im.utils.wallet-connect :as wallet-connect]
|
||||
[status-im2.config :as config]
|
||||
[status-im2.constants :as constants]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.address :as address]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/defn proposal-handler
|
||||
{:events [:wallet-connect/proposal]}
|
||||
[{:keys [db] :as cofx} request-event]
|
||||
(let [proposal (types/js->clj request-event)
|
||||
proposer (:proposer proposal)
|
||||
metadata (:metadata proposer)]
|
||||
{:db (assoc db
|
||||
:wallet-connect/proposal proposal
|
||||
:wallet-connect/proposal-metadata metadata)
|
||||
:show-wallet-connect-sheet nil}))
|
||||
|
||||
(rf/defn session-connected
|
||||
{:events [:wallet-connect/created]}
|
||||
[{:keys [db]} session]
|
||||
(let [session (merge (types/js->clj session) {:wc-version 2})
|
||||
client (get db :wallet-connect/client)]
|
||||
(log/debug "[wallet connect] session created - " session)
|
||||
{:show-wallet-connect-success-sheet nil
|
||||
:db (assoc db
|
||||
:wallet-connect/session-connected session
|
||||
:wallet-connect/sessions (types/js->clj
|
||||
(.-values
|
||||
(.-session
|
||||
client))))}))
|
||||
|
||||
(rf/defn manage-app
|
||||
{:events [:wallet-connect/manage-app]}
|
||||
[{:keys [db]} session]
|
||||
(let [session (types/js->clj session)]
|
||||
{:db (assoc db
|
||||
:wallet-connect/session-managed session
|
||||
:wallet-connect/showing-app-management-sheet? true)
|
||||
:show-wallet-connect-app-management-sheet nil}))
|
||||
|
||||
(rf/defn request-handler
|
||||
{:events [:wallet-connect/request]}
|
||||
[{:keys [db] :as cofx} request-event]
|
||||
(let [request (types/js->clj request-event)
|
||||
params (:request request)
|
||||
pending-requests (or (:wallet-connect/pending-requests db) [])
|
||||
new-pending-requests (conj pending-requests request)
|
||||
client (get db :wallet-connect/client)
|
||||
topic (:topic request)]
|
||||
{:db (assoc db :wallet-connect/pending-requests new-pending-requests)
|
||||
:dispatch [:wallet-connect/request-received request]}))
|
||||
|
||||
(rf/defn request-handler-test
|
||||
{:events [:wallet-connect/request-test]}
|
||||
[{:keys [db] :as cofx}]
|
||||
{:show-wallet-connect-sheet nil})
|
||||
|
||||
(defn subscribe-to-events
|
||||
[^js wallet-connect-client]
|
||||
(.on wallet-connect-client
|
||||
(wallet-connect/session-request-event)
|
||||
#(re-frame/dispatch [:wallet-connect/request %]))
|
||||
(.on wallet-connect-client
|
||||
(wallet-connect/session-created-event)
|
||||
#(re-frame/dispatch [:wallet-connect/created %]))
|
||||
(.on wallet-connect-client
|
||||
(wallet-connect/session-deleted-event)
|
||||
#(re-frame/dispatch [:wallet-connect/update-sessions]))
|
||||
(.on wallet-connect-client
|
||||
(wallet-connect/session-updated-event)
|
||||
#(re-frame/dispatch [:wallet-connect/update-sessions]))
|
||||
(.on wallet-connect-client
|
||||
(wallet-connect/session-proposal-event)
|
||||
#(re-frame/dispatch [:wallet-connect/proposal %])))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:wc-2-init
|
||||
(fn []
|
||||
(wallet-connect/init
|
||||
#(re-frame/dispatch [:wallet-connect/client-init %])
|
||||
#(log/error "[wallet-connect]" %))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:wc-2-subscribe-to-events
|
||||
(fn [client]
|
||||
(subscribe-to-events client)))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:wc-2-client-approve-proposal
|
||||
(fn [[client proposal response]]
|
||||
(-> ^js client
|
||||
(.approve (clj->js {:proposal proposal :response response}))
|
||||
(.then #(log/debug "[wallet-connect] session proposal approved"))
|
||||
(.catch #(log/error "[wallet-connect] session proposal approval error:" %)))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:wc-2-client-reject-proposal
|
||||
(fn [[client proposal]]
|
||||
(-> ^js client
|
||||
(.reject (clj->js {:proposal proposal}))
|
||||
(.then #(log/debug "[wallet-connect] session proposal rejected"))
|
||||
(.catch #(log/error "[wallet-connect] " %)))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:wc-2-client-disconnect
|
||||
(fn [[client topic]]
|
||||
(-> ^js client
|
||||
(.disconnect (clj->js {:topic topic}))
|
||||
(.then #(log/debug "[wallet-connect] session disconnected - topic " topic))
|
||||
(.catch #(log/error "[wallet-connect] " %)))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:wc-2-change-session
|
||||
(fn [[client topic accounts]]
|
||||
(-> ^js client
|
||||
(.update (clj->js {:topic topic
|
||||
:state {:accounts accounts}}))
|
||||
(.then #(log/debug "[wallet-connect] session topic " topic
|
||||
" changed to account " (first accounts)))
|
||||
(.catch #(log/error "[wallet-connect] " %)))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:wc-2-pair
|
||||
(fn [[client uri]]
|
||||
(.pair client (clj->js {:uri uri}))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:wc-2-respond
|
||||
(fn [[client response]]
|
||||
(.respond client (clj->js response))))
|
||||
|
||||
(rf/defn approve-proposal
|
||||
{:events [:wallet-connect/approve-proposal]}
|
||||
[{:keys [db]} account]
|
||||
(let [client (get db :wallet-connect/client)
|
||||
proposal (get db :wallet-connect/proposal)
|
||||
topic (:topic proposal)
|
||||
permissions (:permissions proposal)
|
||||
blockchain (:blockchain permissions)
|
||||
proposal-chain-ids (map #(last (string/split % #":")) (:chains blockchain))
|
||||
available-chain-ids (map #(get-in % [:config :NetworkId]) (vals (get db :networks/networks)))
|
||||
supported-chain-ids (filter (fn [chain-id] #(boolean (some #{chain-id} available-chain-ids)))
|
||||
proposal-chain-ids)
|
||||
address (:address account)
|
||||
accounts (map #(str "eip155:" % ":" (address/normalized-hex address))
|
||||
supported-chain-ids)
|
||||
;; TODO: Check for unsupported
|
||||
metadata (get db :wallet-connect/proposal-metadata)
|
||||
response {:state {:accounts accounts}
|
||||
:metadata config/default-wallet-connect-metadata}]
|
||||
{:hide-wallet-connect-sheet nil
|
||||
:wc-2-client-approve-proposal [client proposal response]}))
|
||||
|
||||
(rf/defn reject-proposal
|
||||
{:events [:wallet-connect/reject-proposal]}
|
||||
[{:keys [db]} account]
|
||||
(let [client (get db :wallet-connect/client)
|
||||
proposal (get db :wallet-connect/proposal)]
|
||||
{:hide-wallet-connect-sheet nil
|
||||
:wc-2-client-reject-proposal client}))
|
||||
|
||||
(rf/defn change-session-account
|
||||
{:events [:wallet-connect/change-session-account]}
|
||||
[{:keys [db]} topic account]
|
||||
(let [client (get db :wallet-connect/client)
|
||||
sessions (get db :wallet-connect/sessions)
|
||||
session (first (filter #(= (:topic %) topic) sessions))
|
||||
permissions (:permissions session)
|
||||
blockchain (:blockchain permissions)
|
||||
proposal-chain-ids (map #(last (string/split % #":")) (:chains blockchain))
|
||||
address (:address account)
|
||||
available-chain-ids (map #(get-in % [:config :NetworkId]) (vals (get db :networks/networks)))
|
||||
supported-chain-ids (filter (fn [chain-id] #(boolean (some #{chain-id} available-chain-ids)))
|
||||
proposal-chain-ids)
|
||||
accounts (map #(str "eip155:" % ":" (address/normalized-hex address))
|
||||
supported-chain-ids)]
|
||||
{:db (assoc db
|
||||
:wallet-connect/showing-app-management-sheet?
|
||||
false)
|
||||
:hide-wallet-connect-app-management-sheet nil
|
||||
:wc-2-change-session [client topic accounts]}))
|
||||
|
||||
(rf/defn disconnect-session
|
||||
{:events [:wallet-connect/disconnect]}
|
||||
[{:keys [db]} topic]
|
||||
(let [client (get db :wallet-connect/client)]
|
||||
{:hide-wallet-connect-app-management-sheet nil
|
||||
:hide-wallet-connect-success-sheet nil
|
||||
:wc-2-client-disconnect [client topic]
|
||||
:db (-> db
|
||||
(assoc :wallet-connect/sessions
|
||||
(types/js->clj (.-values (.-session client))))
|
||||
(dissoc :wallet-connect/session-managed))}))
|
||||
|
||||
(rf/defn pair-session
|
||||
{:events [:wallet-connect/pair]}
|
||||
[{:keys [db]} {:keys [data]}]
|
||||
(let [client (get db :wallet-connect/client)]
|
||||
{:db (assoc db :wallet-connect/scanned-uri data)
|
||||
:dispatch [:navigate-back]
|
||||
:wc-2-pair [client data]}))
|
||||
|
||||
(rf/defn wallet-connect-client-initate
|
||||
{:events [:wallet-connect/client-init]}
|
||||
[{:keys [db] :as cofx} ^js client]
|
||||
{:db (assoc db
|
||||
:wallet-connect/client client
|
||||
:wallet-connect/sessions (types/js->clj (.-values (.-session
|
||||
client))))
|
||||
:wc-2-subscribe-to-events client})
|
||||
|
||||
(rf/defn update-sessions
|
||||
{:events [:wallet-connect/update-sessions]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [client (get db :wallet-connect/client)]
|
||||
{:db (-> db
|
||||
(assoc :wallet-connect/sessions (types/js->clj (.-values (.-session client))))
|
||||
(dissoc :wallet-connect/session-managed))}))
|
||||
|
||||
(rf/defn wallet-connect-complete-transaction
|
||||
{:events [:wallet-connect.dapp/transaction-on-result]}
|
||||
[{:keys [db]} message-id topic result]
|
||||
(let [client (get db :wallet-connect/client)
|
||||
response {:topic topic
|
||||
:response {:jsonrpc "2.0"
|
||||
:id message-id
|
||||
:result result}}]
|
||||
{:db (assoc db :wallet-connect/response response)
|
||||
:wc-2-respond [client response]}))
|
||||
|
||||
(rf/defn wallet-connect-send-async
|
||||
[cofx {:keys [method params id] :as payload} message-id topic]
|
||||
(let [message? (browser/web3-sign-message? method)
|
||||
dapps-address (get-in cofx [:db :profile/profile :dapps-address])
|
||||
accounts (get-in cofx [:db :multiaccount/visible-accounts])
|
||||
typed? (and (not= constants/web3-personal-sign method)
|
||||
(not= constants/web3-eth-sign method))]
|
||||
(if (or message? (= constants/web3-send-transaction method))
|
||||
(let [[address data] (cond (and (= method constants/web3-keycard-sign-typed-data)
|
||||
(not (vector? params)))
|
||||
;; We don't use signer argument for keycard sign-typed-data
|
||||
["0x0" params]
|
||||
message? (browser/normalize-sign-message-params
|
||||
params
|
||||
typed?)
|
||||
:else [nil nil])]
|
||||
(when (or (not message?) (and address data))
|
||||
(signing/sign cofx
|
||||
(merge
|
||||
(if message?
|
||||
{:message {:address address
|
||||
:data data
|
||||
:v4 (= constants/web3-sign-typed-data-v4 method)
|
||||
:typed? typed?
|
||||
:pinless? (= method constants/web3-keycard-sign-typed-data)
|
||||
:from address}}
|
||||
{:tx-obj (-> params
|
||||
first
|
||||
(update :from #(or % dapps-address))
|
||||
(dissoc :gasPrice))})
|
||||
{:on-result [:wallet-connect.dapp/transaction-on-result message-id topic]
|
||||
:on-error [:wallet-connect.dapp/transaction-on-error message-id topic]}))))
|
||||
(when (#{"eth_accounts" "eth_coinbase"} method)
|
||||
(wallet-connect-complete-transaction
|
||||
cofx
|
||||
message-id
|
||||
topic
|
||||
(if (= method "eth_coinbase") dapps-address [dapps-address]))))))
|
||||
|
||||
(rf/defn wallet-connect-send-async-read-only
|
||||
[{:keys [db] :as cofx} {:keys [method] :as payload} message-id topic]
|
||||
(wallet-connect-send-async cofx payload message-id topic))
|
||||
|
||||
(rf/defn process-request
|
||||
{:events [:wallet-connect/request-received]}
|
||||
[{:keys [db] :as cofx} session-request]
|
||||
(let [pending-requests (get db :wallet-connect/pending-requests)
|
||||
{:keys [topic request]} session-request
|
||||
{:keys [id]} request]
|
||||
(wallet-connect-send-async-read-only cofx request id topic)))
|
||||
@@ -1,7 +1,7 @@
|
||||
(ns status-im2.common.standard-authentication.core
|
||||
(:require
|
||||
status-im2.common.standard-authentication.standard-auth.button.view
|
||||
status-im2.common.standard-authentication.password-input.view
|
||||
status-im2.common.standard-authentication.standard-auth.slide-button.view))
|
||||
|
||||
(def button status-im2.common.standard-authentication.standard-auth.button.view/view)
|
||||
(def password-input status-im2.common.standard-authentication.password-input.view/view)
|
||||
(def slide-button status-im2.common.standard-authentication.standard-auth.slide-button.view/view)
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn view
|
||||
[{:keys [on-enter-password button-label button-icon-left]}]
|
||||
[{:keys [on-enter-password on-press-biometrics button-label button-icon-left]}]
|
||||
(let [{:keys [key-uid customization-color] :as profile} (rf/sub [:profile/profile-with-image])
|
||||
{:keys [error processing password]} (rf/sub [:profile/login])
|
||||
sign-in-enabled? (rf/sub [:sign-in-enabled?])]
|
||||
@@ -32,20 +32,21 @@
|
||||
:customization-color customization-color
|
||||
:size 24}]]
|
||||
[password-input/view
|
||||
{:processing processing
|
||||
:error error
|
||||
:default-password password
|
||||
:sign-in-enabled? sign-in-enabled?}]
|
||||
[rn/view {:style style/enter-password-button}
|
||||
[quo/button
|
||||
{:size 40
|
||||
:type :primary
|
||||
:customization-color (or customization-color :primary)
|
||||
:accessibility-label :login-button
|
||||
:icon-left button-icon-left
|
||||
:disabled? (or (not sign-in-enabled?) processing)
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:set-in [:profile/login :key-uid] key-uid])
|
||||
(rf/dispatch [:profile.login/verify-database-password password
|
||||
#(on-enter-password password)]))}
|
||||
button-label]]]]]))
|
||||
{:on-press-biometrics on-press-biometrics
|
||||
:processing processing
|
||||
:error error
|
||||
:default-password password
|
||||
:sign-in-enabled? sign-in-enabled?}]
|
||||
[quo/button
|
||||
{:size 40
|
||||
:container-style style/enter-password-button
|
||||
:type :primary
|
||||
:customization-color (or customization-color :primary)
|
||||
:accessibility-label :login-button
|
||||
:icon-left button-icon-left
|
||||
:disabled? (or (not sign-in-enabled?) processing)
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:set-in [:profile/login :key-uid] key-uid])
|
||||
(rf/dispatch [:profile.login/verify-database-password password
|
||||
#(on-enter-password password)]))}
|
||||
button-label]]]]))
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
(ns status-im2.common.standard-authentication.events
|
||||
(:require
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/reg-event-fx :standard-auth/on-biometric-success
|
||||
(fn [{:keys [db]} [callback]]
|
||||
(let [key-uid (get-in db [:profile/profile :key-uid])]
|
||||
{:fx [[:keychain/get-user-password [key-uid callback]]]})))
|
||||
@@ -4,3 +4,7 @@
|
||||
{:margin-top 8
|
||||
:flex-direction :row
|
||||
:align-items :center})
|
||||
|
||||
(def auth-button
|
||||
{:align-self :flex-end
|
||||
:margin-left 8})
|
||||
|
||||
@@ -27,21 +27,30 @@
|
||||
(rf/dispatch [:set-in [:profile/login :error] ""]))
|
||||
|
||||
(defn- view-internal
|
||||
[{:keys [default-password theme shell?]}]
|
||||
[{:keys [default-password theme shell? on-press-biometrics]}]
|
||||
(let [{:keys [error processing]} (rf/sub [:profile/login])
|
||||
error-message (get-error-message error)
|
||||
error? (boolean (seq error-message))]
|
||||
[:<>
|
||||
[quo/input
|
||||
{:type :password
|
||||
:blur? true
|
||||
:disabled? processing
|
||||
:placeholder (i18n/label :t/type-your-password)
|
||||
:auto-focus true
|
||||
:error? error?
|
||||
:label (i18n/label :t/profile-password)
|
||||
:on-change-text on-change-password
|
||||
:default-value (security/safe-unmask-data default-password)}]
|
||||
[rn/view {:style {:flex-direction :row}}
|
||||
[quo/input
|
||||
{:container-style {:flex 1}
|
||||
:type :password
|
||||
:blur? true
|
||||
:disabled? processing
|
||||
:placeholder (i18n/label :t/type-your-password)
|
||||
:auto-focus true
|
||||
:error? error?
|
||||
:label (i18n/label :t/profile-password)
|
||||
:on-change-text on-change-password
|
||||
:default-value (security/safe-unmask-data default-password)}]
|
||||
(when on-press-biometrics
|
||||
[quo/button
|
||||
{:container-style style/auth-button
|
||||
:on-press on-press-biometrics
|
||||
:icon-only? true
|
||||
:type :outline}
|
||||
:i/face-id])]
|
||||
(when error?
|
||||
[rn/view {:style style/error-message}
|
||||
[quo/info-message
|
||||
@@ -60,10 +69,7 @@
|
||||
:shell? shell?}]))}
|
||||
[rn/text
|
||||
{:style {:text-decoration-line :underline
|
||||
:color (colors/theme-colors
|
||||
(colors/custom-color :danger 50)
|
||||
(colors/custom-color :danger 60)
|
||||
theme)}
|
||||
:color (colors/resolve-color :danger theme)}
|
||||
:size :paragraph-2
|
||||
:suppress-highlighting true}
|
||||
(i18n/label :t/forgot-password)]]])]))
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
(ns status-im2.common.standard-authentication.standard-auth.authorize
|
||||
(:require
|
||||
[native-module.core :as native-module]
|
||||
[react-native.touch-id :as biometric]
|
||||
[status-im2.common.standard-authentication.enter-password.view :as enter-password]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
|
||||
(defn reset-password
|
||||
[]
|
||||
@@ -12,33 +14,49 @@
|
||||
(rf/dispatch [:set-in [:profile/login :error] ""]))
|
||||
|
||||
(defn authorize
|
||||
[{:keys [on-enter-password biometric-auth? on-auth-success on-auth-fail on-close
|
||||
[{:keys [biometric-auth? on-auth-success on-auth-fail on-close
|
||||
auth-button-label theme blur? auth-button-icon-left]}]
|
||||
(biometric/get-supported-type
|
||||
(fn [biometric-type]
|
||||
(if (and biometric-auth? biometric-type)
|
||||
(biometric/authenticate
|
||||
{:reason (i18n/label :t/biometric-auth-confirm-message)
|
||||
:on-success (fn [response]
|
||||
(when on-auth-success (on-auth-success response))
|
||||
(log/info "response" response))
|
||||
:on-fail (fn [error]
|
||||
(log/error "Authentication Failed. Error:" error)
|
||||
(when on-auth-fail (on-auth-fail error))
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:theme theme
|
||||
:shell? blur?
|
||||
:content (fn []
|
||||
[enter-password/view
|
||||
{:on-enter-password on-enter-password}])}]))})
|
||||
(do
|
||||
(reset-password)
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:on-close on-close
|
||||
:theme theme
|
||||
:shell? blur?
|
||||
:content (fn []
|
||||
[enter-password/view
|
||||
{:on-enter-password on-enter-password
|
||||
:button-icon-left auth-button-icon-left
|
||||
:button-label auth-button-label}])}]))))))
|
||||
(let [handle-auth-success (fn [biometric?]
|
||||
(fn [entered-password]
|
||||
(let [sha3-pwd (if biometric?
|
||||
(str (security/safe-unmask-data entered-password))
|
||||
(native-module/sha3 (str (security/safe-unmask-data
|
||||
entered-password))))]
|
||||
(on-auth-success sha3-pwd))))
|
||||
password-login (fn [{:keys [on-press-biometrics]}]
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:on-close on-close
|
||||
:theme theme
|
||||
:shell? blur?
|
||||
:content (fn []
|
||||
[enter-password/view
|
||||
{:on-enter-password (handle-auth-success
|
||||
false)
|
||||
:on-press-biometrics on-press-biometrics
|
||||
:button-icon-left auth-button-icon-left
|
||||
:button-label auth-button-label}])}]))
|
||||
; biometrics-login recursively passes itself as a parameter because if the user
|
||||
; fails biometric auth they will be shown the password bottom sheet with an option
|
||||
; to retrigger biometric auth, so they can endlessly repeat this cycle.
|
||||
biometrics-login (fn [on-press-biometrics]
|
||||
(rf/dispatch [:dismiss-keyboard])
|
||||
(biometric/authenticate
|
||||
{:reason (i18n/label :t/biometric-auth-confirm-message)
|
||||
:on-success (fn [_response]
|
||||
(on-close)
|
||||
(rf/dispatch [:standard-auth/on-biometric-success
|
||||
(handle-auth-success true)]))
|
||||
:on-fail (fn [error]
|
||||
(on-close)
|
||||
(log/error "Authentication Failed. Error:" error)
|
||||
(when on-auth-fail (on-auth-fail error))
|
||||
(password-login {:on-press-biometrics
|
||||
#(on-press-biometrics
|
||||
on-press-biometrics)}))}))]
|
||||
(biometric/get-supported-type
|
||||
(fn [biometric-type]
|
||||
(if (and biometric-auth? biometric-type)
|
||||
(biometrics-login biometrics-login)
|
||||
(do
|
||||
(reset-password)
|
||||
(password-login {})))))))
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
(ns status-im2.common.standard-authentication.standard-auth.button.view
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[quo.theme :as quo.theme]
|
||||
[reagent.core :as reagent]
|
||||
[status-im2.common.standard-authentication.standard-auth.authorize :as authorize]))
|
||||
|
||||
(defn- view-internal
|
||||
[_]
|
||||
(let [reset-slider? (reagent/atom false)
|
||||
on-close #(reset! reset-slider? true)]
|
||||
(fn [{:keys [biometric-auth?
|
||||
customization-color
|
||||
auth-button-label
|
||||
on-enter-password
|
||||
on-auth-success
|
||||
on-press
|
||||
on-auth-fail
|
||||
auth-button-icon-left
|
||||
size
|
||||
button-label
|
||||
theme
|
||||
blur?
|
||||
container-style
|
||||
icon-left]}]
|
||||
[quo/button
|
||||
{:size size
|
||||
:container-style container-style
|
||||
:customization-color customization-color
|
||||
:icon-left icon-left
|
||||
:on-press (if on-press
|
||||
on-press
|
||||
#(authorize/authorize {:on-close on-close
|
||||
:auth-button-icon-left auth-button-icon-left
|
||||
:theme theme
|
||||
:blur? blur?
|
||||
:on-enter-password on-enter-password
|
||||
:biometric-auth? biometric-auth?
|
||||
:on-auth-success on-auth-success
|
||||
:on-auth-fail on-auth-fail
|
||||
:auth-button-label auth-button-label}))}
|
||||
button-label])))
|
||||
|
||||
(def view (quo.theme/with-theme view-internal))
|
||||
@@ -4,17 +4,21 @@
|
||||
[quo.theme :as quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[status-im2.common.standard-authentication.standard-auth.authorize :as authorize]))
|
||||
[status-im2.common.standard-authentication.standard-auth.authorize :as authorize]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- view-internal
|
||||
[_]
|
||||
(let [reset-slider? (reagent/atom false)
|
||||
on-close #(reset! reset-slider? true)]
|
||||
(fn [{:keys [biometric-auth?
|
||||
track-text
|
||||
(let [reset-slider? (reagent/atom false)
|
||||
on-close (fn []
|
||||
(js/setTimeout
|
||||
#(reset! reset-slider? true)
|
||||
200))
|
||||
auth-method (rf/sub [:auth-method])
|
||||
biometric-auth? (= auth-method "biometric")]
|
||||
(fn [{:keys [track-text
|
||||
customization-color
|
||||
auth-button-label
|
||||
on-enter-password
|
||||
on-auth-success
|
||||
on-auth-fail
|
||||
auth-button-icon-left
|
||||
@@ -32,7 +36,6 @@
|
||||
:auth-button-icon-left auth-button-icon-left
|
||||
:theme theme
|
||||
:blur? blur?
|
||||
:on-enter-password on-enter-password
|
||||
:biometric-auth? biometric-auth?
|
||||
:on-auth-success on-auth-success
|
||||
:on-auth-fail on-auth-fail
|
||||
|
||||
@@ -390,3 +390,18 @@
|
||||
(def ^:const account-default-customization-color :blue)
|
||||
|
||||
(def ^:const wallet-account-name-max-length 20)
|
||||
|
||||
(def ^:const status-address-domain ".stateofus.eth")
|
||||
(def ^:const eth-address-domain ".eth")
|
||||
|
||||
(def ^:const gas-rate-low 0)
|
||||
(def ^:const gas-rate-medium 1)
|
||||
(def ^:const gas-rate-high 2)
|
||||
|
||||
(def ^:const send-type-transfer 0)
|
||||
(def ^:const send-type-ens-register 1)
|
||||
(def ^:const send-type-ens-release 2)
|
||||
(def ^:const send-type-ens-set-pub-key 3)
|
||||
(def ^:const send-type-stickers-buy 4)
|
||||
(def ^:const send-type-bridge 5)
|
||||
(def ^:const send-type-erc-721-transfer 6)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
(ns status-im2.contexts.add-new-contact.events-test
|
||||
(:require
|
||||
[cljs.test :refer-macros [deftest are]]
|
||||
matcher-combinators.test
|
||||
[status-im2.contexts.add-new-contact.events :as events]))
|
||||
|
||||
(def user-ukey
|
||||
@@ -18,10 +19,10 @@
|
||||
;;; unit tests (no app-db involved)
|
||||
|
||||
(deftest validate-contact-test
|
||||
(are [i e] (= (events/validate-contact (events/init-contact
|
||||
{:user-public-key user-ukey
|
||||
:input i}))
|
||||
(events/init-contact e))
|
||||
(are [i e] (match? (events/validate-contact (events/init-contact
|
||||
{:user-public-key user-ukey
|
||||
:input i}))
|
||||
(events/init-contact e))
|
||||
|
||||
"" {:user-public-key user-ukey
|
||||
:input ""
|
||||
@@ -90,7 +91,7 @@
|
||||
|
||||
(deftest set-new-identity-test
|
||||
(with-redefs [events/dispatcher (fn [& args] args)]
|
||||
(are [i edb] (= (events/set-new-identity {:db db} i nil) edb)
|
||||
(are [i edb] (match? (events/set-new-identity {:db db} i nil) edb)
|
||||
|
||||
"" {:db db}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
(ns status-im2.contexts.chat.composer.link-preview.events-test
|
||||
(:require
|
||||
[cljs.test :refer [deftest is testing]]
|
||||
matcher-combinators.test
|
||||
[status-im2.contexts.chat.composer.link-preview.events :as events]))
|
||||
|
||||
(def url-github "https://github.com")
|
||||
@@ -20,17 +21,17 @@
|
||||
(let [cofx {:db {:chat/link-previews {:unfurled {}
|
||||
:cache {}
|
||||
:request-id "123"}}}]
|
||||
(is (= {:db {:chat/link-previews {:cache {}}}}
|
||||
(events/unfurl-urls cofx " ")))))
|
||||
(is (match? {:db {:chat/link-previews {:cache {}}}}
|
||||
(events/unfurl-urls cofx " ")))))
|
||||
|
||||
(testing "fetches parsed URLs"
|
||||
(let [cofx {:db {:chat/link-previews {:unfurled {}
|
||||
:cache {}
|
||||
:request-id "123"}}}]
|
||||
(is (= {:json-rpc/call [{:method "wakuext_getTextURLs"
|
||||
:params [url-github]}]}
|
||||
(remove-rpc-callbacks
|
||||
(events/unfurl-urls cofx url-github)))))))
|
||||
(is (match? {:json-rpc/call [{:method "wakuext_getTextURLs"
|
||||
:params [url-github]}]}
|
||||
(remove-rpc-callbacks
|
||||
(events/unfurl-urls cofx url-github)))))))
|
||||
|
||||
(deftest unfurl-parsed-urls-test
|
||||
(with-redefs [events/new-request-id (constantly request-id)]
|
||||
@@ -38,30 +39,30 @@
|
||||
(let [cofx {:db {:chat/link-previews
|
||||
{:cache {}
|
||||
:unfurled []}}}]
|
||||
(is (= {:db {:chat/link-previews
|
||||
{:request-id request-id
|
||||
:cache {}
|
||||
:unfurled [{:url url-github :loading? true}
|
||||
{:url url-gitlab :loading? true}]}}
|
||||
:json-rpc/call [{:method "wakuext_unfurlURLs"
|
||||
:params [[url-github url-gitlab]]}]}
|
||||
(remove-rpc-callbacks
|
||||
(events/unfurl-parsed-urls cofx [url-github url-gitlab]))))))
|
||||
(is (match? {:db {:chat/link-previews
|
||||
{:request-id request-id
|
||||
:cache {}
|
||||
:unfurled [{:url url-github :loading? true}
|
||||
{:url url-gitlab :loading? true}]}}
|
||||
:json-rpc/call [{:method "wakuext_unfurlURLs"
|
||||
:params [[url-github url-gitlab]]}]}
|
||||
(remove-rpc-callbacks
|
||||
(events/unfurl-parsed-urls cofx [url-github url-gitlab]))))))
|
||||
|
||||
(testing "nothing unfurled, 1 cached URL and the other stale"
|
||||
(let [cache {url-github preview-github}
|
||||
cofx {:db {:chat/link-previews
|
||||
{:cache cache
|
||||
:unfurled []}}}]
|
||||
(is (= {:db {:chat/link-previews
|
||||
{:request-id request-id
|
||||
:cache cache
|
||||
:unfurled [preview-github
|
||||
{:url url-gitlab :loading? true}]}}
|
||||
:json-rpc/call [{:method "wakuext_unfurlURLs"
|
||||
:params [[url-gitlab]]}]}
|
||||
(remove-rpc-callbacks
|
||||
(events/unfurl-parsed-urls cofx [url-github url-gitlab]))))))
|
||||
(is (match? {:db {:chat/link-previews
|
||||
{:request-id request-id
|
||||
:cache cache
|
||||
:unfurled [preview-github
|
||||
{:url url-gitlab :loading? true}]}}
|
||||
:json-rpc/call [{:method "wakuext_unfurlURLs"
|
||||
:params [[url-gitlab]]}]}
|
||||
(remove-rpc-callbacks
|
||||
(events/unfurl-parsed-urls cofx [url-github url-gitlab]))))))
|
||||
|
||||
(testing "does nothing when the URLs are identical to the last cleared ones"
|
||||
(let [cofx {:db {:chat/link-previews
|
||||
@@ -75,24 +76,24 @@
|
||||
cofx {:db {:chat/link-previews
|
||||
{:cache cache
|
||||
:unfurled [preview-github]}}}]
|
||||
(is (= {:db {:chat/link-previews
|
||||
{:request-id request-id
|
||||
:cache cache
|
||||
:unfurled []}}}
|
||||
(remove-rpc-callbacks
|
||||
(events/unfurl-parsed-urls cofx []))))))
|
||||
(is (match? {:db {:chat/link-previews
|
||||
{:request-id request-id
|
||||
:cache cache
|
||||
:unfurled []}}}
|
||||
(remove-rpc-callbacks
|
||||
(events/unfurl-parsed-urls cofx []))))))
|
||||
|
||||
(testing "2 unfurled, 2 cached URLs"
|
||||
(let [cache {url-github preview-github url-gitlab preview-gitlab}
|
||||
cofx {:db {:chat/link-previews
|
||||
{:cache cache
|
||||
:unfurled [preview-github preview-gitlab]}}}]
|
||||
(is (= {:db {:chat/link-previews
|
||||
{:request-id request-id
|
||||
:cache cache
|
||||
:unfurled [preview-github preview-gitlab]}}}
|
||||
(remove-rpc-callbacks
|
||||
(events/unfurl-parsed-urls cofx [url-github url-gitlab]))))))
|
||||
(is (match? {:db {:chat/link-previews
|
||||
{:request-id request-id
|
||||
:cache cache
|
||||
:unfurled [preview-github preview-gitlab]}}}
|
||||
(remove-rpc-callbacks
|
||||
(events/unfurl-parsed-urls cofx [url-github url-gitlab]))))))
|
||||
|
||||
(testing "1 unfurled, 1 successful in the cache, 1 failed in the cache"
|
||||
(let [cache {url-github preview-github
|
||||
@@ -100,25 +101,25 @@
|
||||
cofx {:db {:chat/link-previews
|
||||
{:cache cache
|
||||
:unfurled [preview-github]}}}]
|
||||
(is (= {:db {:chat/link-previews
|
||||
{:request-id request-id
|
||||
:cache cache
|
||||
:unfurled [preview-github]}}}
|
||||
(events/unfurl-parsed-urls cofx [url-github url-gitlab])))))
|
||||
(is (match? {:db {:chat/link-previews
|
||||
{:request-id request-id
|
||||
:cache cache
|
||||
:unfurled [preview-github]}}}
|
||||
(events/unfurl-parsed-urls cofx [url-github url-gitlab])))))
|
||||
|
||||
(testing "nothing unfurled, 1 failed in the cache"
|
||||
(let [cache {url-gitlab (assoc preview-gitlab :failed? true)}
|
||||
cofx {:db {:chat/link-previews
|
||||
{:cache cache
|
||||
:unfurled []}}}]
|
||||
(is (= {:db {:chat/link-previews
|
||||
{:request-id request-id
|
||||
:cache cache
|
||||
:unfurled [{:url url-github :loading? true}]}}
|
||||
:json-rpc/call [{:method "wakuext_unfurlURLs"
|
||||
:params [[url-github]]}]}
|
||||
(remove-rpc-callbacks
|
||||
(events/unfurl-parsed-urls cofx [url-github url-gitlab]))))))
|
||||
(is (match? {:db {:chat/link-previews
|
||||
{:request-id request-id
|
||||
:cache cache
|
||||
:unfurled [{:url url-github :loading? true}]}}
|
||||
:json-rpc/call [{:method "wakuext_unfurlURLs"
|
||||
:params [[url-github]]}]}
|
||||
(remove-rpc-callbacks
|
||||
(events/unfurl-parsed-urls cofx [url-github url-gitlab]))))))
|
||||
|
||||
(testing "empties unfurled collection when there are no valid previews"
|
||||
(let [unknown-url "https://github.abcdef"
|
||||
@@ -127,12 +128,12 @@
|
||||
cofx {:db {:chat/link-previews
|
||||
{:cache cache
|
||||
:unfurled [preview-github]}}}]
|
||||
(is (= {:db {:chat/link-previews
|
||||
{:request-id request-id
|
||||
:cache cache
|
||||
:unfurled []}}}
|
||||
(remove-rpc-callbacks
|
||||
(events/unfurl-parsed-urls cofx [unknown-url]))))))))
|
||||
(is (match? {:db {:chat/link-previews
|
||||
{:request-id request-id
|
||||
:cache cache
|
||||
:unfurled []}}}
|
||||
(remove-rpc-callbacks
|
||||
(events/unfurl-parsed-urls cofx [unknown-url]))))))))
|
||||
|
||||
(deftest unfurl-parsed-urls-success-test
|
||||
(testing "does nothing if the success request-id is different than the current one"
|
||||
@@ -152,12 +153,12 @@
|
||||
cofx
|
||||
request-id
|
||||
{:linkPreviews [preview-gitlab]})]
|
||||
(is (= {:chat/link-previews
|
||||
{:request-id request-id
|
||||
:unfurled [preview-github preview-gitlab]
|
||||
:cache {url-github preview-github
|
||||
url-gitlab preview-gitlab}}}
|
||||
db))))
|
||||
(is (match? {:chat/link-previews
|
||||
{:request-id request-id
|
||||
:unfurled [preview-github preview-gitlab]
|
||||
:cache {url-github preview-github
|
||||
url-gitlab preview-gitlab}}}
|
||||
db))))
|
||||
|
||||
(testing "identify and write failed preview in the cache"
|
||||
(let [preview-youtube {:url "https://youtube.com" :thumbnail nil}
|
||||
@@ -172,13 +173,13 @@
|
||||
request-id
|
||||
{:linkPreviews [preview-github
|
||||
preview-youtube]})]
|
||||
(is (= {:chat/link-previews
|
||||
{:request-id request-id
|
||||
:unfurled [preview-github preview-youtube]
|
||||
:cache {(:url preview-youtube) preview-youtube
|
||||
url-github preview-github
|
||||
url-gitlab {:url "https://gitlab.com" :failed? true}}}}
|
||||
db)))))
|
||||
(is (match? {:chat/link-previews
|
||||
{:request-id request-id
|
||||
:unfurled [preview-github preview-youtube]
|
||||
:cache {(:url preview-youtube) preview-youtube
|
||||
url-github preview-github
|
||||
url-gitlab {:url "https://gitlab.com" :failed? true}}}}
|
||||
db)))))
|
||||
|
||||
(deftest clear-link-previews-test
|
||||
(let [cache {url-github preview-github}
|
||||
@@ -186,22 +187,22 @@
|
||||
{:db {:chat/link-previews {:unfurled [preview-github]
|
||||
:request-id request-id
|
||||
:cache cache}}})]
|
||||
(is (= {:db {:chat/link-previews {:cache cache
|
||||
:cleared #{url-github}}}}
|
||||
effects))))
|
||||
(is (match? {:db {:chat/link-previews {:cache cache
|
||||
:cleared #{url-github}}}}
|
||||
effects))))
|
||||
|
||||
(deftest reset-unfurled-test
|
||||
(let [cache {url-github preview-github}]
|
||||
(is (= {:db {:chat/link-previews {:cache cache}}}
|
||||
(events/reset-unfurled
|
||||
{:db {:chat/link-previews {:unfurled [preview-github]
|
||||
:request-id request-id
|
||||
:cleared #{url-github}
|
||||
:cache cache}}})))))
|
||||
(is (match? {:db {:chat/link-previews {:cache cache}}}
|
||||
(events/reset-unfurled
|
||||
{:db {:chat/link-previews {:unfurled [preview-github]
|
||||
:request-id request-id
|
||||
:cleared #{url-github}
|
||||
:cache cache}}})))))
|
||||
|
||||
(deftest reset-all-test
|
||||
(is (= {:db {:non-related-key :some-value}}
|
||||
(events/reset-all
|
||||
{:db {:non-related-key :some-value
|
||||
:chat/link-previews {:request-id request-id
|
||||
:any-other-key "farewell"}}}))))
|
||||
(is (match? {:db {:non-related-key :some-value}}
|
||||
(events/reset-all
|
||||
{:db {:non-related-key :some-value
|
||||
:chat/link-previews {:request-id request-id
|
||||
:any-other-key "farewell"}}}))))
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
(close))
|
||||
|
||||
(defn confirm-button
|
||||
[selected-images sending-image close]
|
||||
[{:keys [selected-images sending-image close customization-color]}]
|
||||
(when (not= selected-images sending-image)
|
||||
[linear-gradient/linear-gradient
|
||||
{:colors [:black :transparent]
|
||||
@@ -43,7 +43,8 @@
|
||||
:end {:x 0 :y 0}
|
||||
:style (style/gradient-container (safe-area/get-bottom))}
|
||||
[quo/button
|
||||
{:container-style {:align-self :stretch
|
||||
{:customization-color customization-color
|
||||
:container-style {:align-self :stretch
|
||||
:margin-horizontal 20
|
||||
:margin-top 12}
|
||||
:on-press #(on-press-confirm-selection selected-images close)
|
||||
@@ -94,10 +95,11 @@
|
||||
[{:keys [scroll-enabled on-scroll current-scroll close] :as sheet}]
|
||||
(rf/dispatch [:photo-selector/get-photos-for-selected-album])
|
||||
(rf/dispatch [:photo-selector/camera-roll-get-albums])
|
||||
(let [album? (reagent/atom false)
|
||||
sending-image (into [] (vals (rf/sub [:chats/sending-image])))
|
||||
selected-images (reagent/atom sending-image)
|
||||
window-width (:width (rn/get-window))]
|
||||
(let [album? (reagent/atom false)
|
||||
customization-color (rf/sub [:profile/customization-color])
|
||||
sending-image (into [] (vals (rf/sub [:chats/sending-image])))
|
||||
selected-images (reagent/atom sending-image)
|
||||
window-width (:width (rn/get-window))]
|
||||
[:f>
|
||||
(fn []
|
||||
(let [camera-roll-photos (rf/sub [:camera-roll/photos])
|
||||
@@ -140,7 +142,11 @@
|
||||
(rf/dispatch [:photo-selector/camera-roll-loading-more true])
|
||||
(rf/dispatch [:photo-selector/get-photos-for-selected-album
|
||||
end-cursor])))}]
|
||||
[confirm-button @selected-images sending-image close]]
|
||||
[confirm-button
|
||||
{:close close
|
||||
:customization-color customization-color
|
||||
:selected-images @selected-images
|
||||
:sending-image sending-image}]]
|
||||
[rn/view {:style style/buttons-container}
|
||||
[quo/dropdown
|
||||
{:type dropdown-type
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
(ns status-im2.contexts.communities.actions.accounts-selection.style
|
||||
(:require
|
||||
[quo.foundations.colors :as colors]))
|
||||
|
||||
(def screen-horizontal-padding 20)
|
||||
|
||||
(def container
|
||||
{:flex 1})
|
||||
|
||||
(def page-top
|
||||
{:padding-vertical 12
|
||||
:padding-horizontal screen-horizontal-padding})
|
||||
|
||||
(def content
|
||||
{:margin-bottom 20
|
||||
:padding-horizontal screen-horizontal-padding})
|
||||
|
||||
(defn bottom-actions
|
||||
[]
|
||||
{:position :absolute
|
||||
:background-color (colors/theme-colors colors/white colors/neutral-95)
|
||||
:bottom 0
|
||||
:left 0
|
||||
:right 0
|
||||
:padding-horizontal screen-horizontal-padding
|
||||
:padding-vertical 12
|
||||
:flex 1})
|
||||
@@ -4,11 +4,12 @@
|
||||
[react-native.core :as rn]
|
||||
[react-native.gesture :as gesture]
|
||||
[status-im2.common.password-authentication.view :as password-authentication]
|
||||
[status-im2.contexts.communities.actions.request-to-join.style :as style]
|
||||
[status-im2.contexts.communities.actions.accounts-selection.style :as style]
|
||||
[status-im2.contexts.communities.actions.community-rules.view :as community-rules]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn join-community-and-navigate-back
|
||||
(defn- join-community-and-navigate-back
|
||||
[id]
|
||||
(rf/dispatch [:password-authentication/show
|
||||
{:content (fn [] [password-authentication/view])}
|
||||
@@ -17,24 +18,46 @@
|
||||
{:community-id id :password %}])}])
|
||||
(rf/dispatch [:navigate-back]))
|
||||
|
||||
(defn- page-top
|
||||
[{:keys [community-name logo-uri]}]
|
||||
[rn/view {:style style/page-top}
|
||||
[quo/text
|
||||
{:size :heading-1
|
||||
:weight :semi-bold}
|
||||
(i18n/label :t/request-to-join)]
|
||||
[quo/context-tag
|
||||
{:type :community
|
||||
:size 24
|
||||
:community-logo logo-uri
|
||||
:community-name community-name
|
||||
:container-style {:margin-top 8}}]])
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(fn []
|
||||
(let [{:keys [_name
|
||||
id
|
||||
_images]} (rf/sub [:get-screen-params])]
|
||||
[rn/view {:flex 1}
|
||||
[gesture/scroll-view {:style {:flex 1}}
|
||||
[rn/view style/page-container
|
||||
[rn/view {:style (style/bottom-container)}
|
||||
[quo/button
|
||||
{:accessibility-label :cancel
|
||||
:on-press #(rf/dispatch [:navigate-back])
|
||||
:type :grey
|
||||
:container-style style/cancel-button}
|
||||
(i18n/label :t/cancel)]
|
||||
[quo/button
|
||||
{:accessibility-label :join-community-button
|
||||
:on-press #(join-community-and-navigate-back id)
|
||||
:container-style {:flex 1}}
|
||||
(i18n/label :t/request-to-join)]]]]])))
|
||||
(let [{id :community-id} (rf/sub [:get-screen-params])
|
||||
{:keys [name color images]} (rf/sub [:communities/community id])]
|
||||
[rn/view {:style style/container}
|
||||
[quo/page-nav
|
||||
{:text-align :left
|
||||
:icon-name :i/close
|
||||
:on-press #(rf/dispatch [:navigate-back])
|
||||
:accessibility-label :back-button}]
|
||||
[page-top
|
||||
{:community-name name
|
||||
:logo-uri (get-in images [:thumbnail :uri])}]
|
||||
[gesture/scroll-view
|
||||
[rn/view {:style style/content}
|
||||
[quo/text
|
||||
{:style {:margin-top 24}
|
||||
:accessibility-label :community-rules-title
|
||||
:weight :semi-bold
|
||||
:size :paragraph-1}
|
||||
(i18n/label :t/community-rules)]
|
||||
[community-rules/view id]]]
|
||||
[rn/view {:style (style/bottom-actions)}
|
||||
[quo/slide-button
|
||||
{:size :size-48
|
||||
:track-text (i18n/label :t/slide-to-request-to-join)
|
||||
:track-icon :i/face-id
|
||||
:customization-color color
|
||||
:on-complete #(join-community-and-navigate-back id)}]]]))
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
(ns status-im2.contexts.communities.actions.community-rules.style)
|
||||
|
||||
(def community-rule
|
||||
{:flex 1
|
||||
:align-items :flex-start
|
||||
:margin-top 16})
|
||||
|
||||
(def community-rule-text
|
||||
{:margin-left 6
|
||||
:flex 1})
|
||||
@@ -0,0 +1,16 @@
|
||||
(ns status-im2.contexts.communities.actions.community-rules.view
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im2.contexts.communities.actions.community-rules.style :as style]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn view
|
||||
[id]
|
||||
(let [rules (rf/sub [:communities/rules id])]
|
||||
[rn/view {:style style/community-rule}
|
||||
[quo/text
|
||||
{:style style/community-rule-text
|
||||
:weight :regular
|
||||
:size :paragraph-2}
|
||||
rules]]))
|
||||
@@ -1,6 +1,7 @@
|
||||
(ns status-im2.contexts.communities.discover.events-test
|
||||
(:require
|
||||
[cljs.test :refer-macros [deftest are]]
|
||||
matcher-combinators.test
|
||||
[status-im2.contexts.communities.discover.events :as events]))
|
||||
|
||||
(deftest rename-contract-community-key-test
|
||||
@@ -13,7 +14,7 @@
|
||||
:3f9e77b8-97c7 "3f9e77b8-97c7"))
|
||||
|
||||
(deftest rename-contract-community-keys-test
|
||||
(are [i e] (= (events/rename-contract-community-keys i) e)
|
||||
(are [i e] (match? (events/rename-contract-community-keys i) e)
|
||||
|
||||
{:contractCommunities
|
||||
["0x032aa2439b14eb2caaf724223951da89de1530fbfa5d5a639b93b82cd5341713fd"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
(ns status-im2.contexts.communities.overview.events-test
|
||||
(:require [cljs.test :refer [deftest is]]
|
||||
matcher-combinators.test
|
||||
[native-module.core :as native-module]
|
||||
[status-im2.contexts.communities.overview.events :as sut]))
|
||||
|
||||
@@ -14,10 +15,10 @@
|
||||
:params [account-pub-key community-id []]
|
||||
:on-success [:communities/sign-data community-id password]
|
||||
:on-error [:communities/requested-to-join-error community-id]}]]]}]
|
||||
(is (= expected
|
||||
(sut/request-to-join cofx
|
||||
[{:community-id community-id
|
||||
:password password}])))))
|
||||
(is (match? expected
|
||||
(sut/request-to-join cofx
|
||||
[{:community-id community-id
|
||||
:password password}])))))
|
||||
|
||||
(deftest sign-data-test
|
||||
(let [cofx {:db {}}
|
||||
@@ -32,8 +33,8 @@
|
||||
:on-success [:communities/request-to-join-with-signatures
|
||||
community-id addresses-to-reveal]
|
||||
:on-error [:communities/requested-to-join-error community-id]}]]]}]
|
||||
(is (= expected
|
||||
(sut/sign-data cofx [community-id password sign-params])))))
|
||||
(is (match? expected
|
||||
(sut/sign-data cofx [community-id password sign-params])))))
|
||||
|
||||
(deftest request-to-join-with-signatures-test
|
||||
(let [cofx {:db {}}
|
||||
@@ -49,5 +50,6 @@
|
||||
:on-success [:communities/requested-to-join]
|
||||
:on-error [:communities/requested-to-join-error
|
||||
community-id]}]]]}]
|
||||
(is (= expected
|
||||
(sut/request-to-join-with-signatures cofx [community-id addresses-to-reveal signatures])))))
|
||||
(is (match? expected
|
||||
(sut/request-to-join-with-signatures cofx
|
||||
[community-id addresses-to-reveal signatures])))))
|
||||
|
||||
@@ -173,7 +173,7 @@
|
||||
(i18n/label :t/join-open-community)]])))
|
||||
|
||||
(defn join-community
|
||||
[{:keys [joined color permissions token-permissions] :as community}
|
||||
[{:keys [joined color permissions token-permissions id] :as community}
|
||||
pending?]
|
||||
(let [access-type (get-access-type (:access permissions))
|
||||
unknown-access? (= access-type :unknown-access)
|
||||
@@ -185,7 +185,7 @@
|
||||
[quo/button
|
||||
{:on-press
|
||||
(if config/community-accounts-selection-enabled?
|
||||
#(rf/dispatch [:open-modal :community-account-selection community])
|
||||
#(rf/dispatch [:open-modal :community-account-selection {:community-id id}])
|
||||
#(rf/dispatch [:open-modal :community-requests-to-join community]))
|
||||
|
||||
:accessibility-label :show-request-to-join-screen-button
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
[status-im2.common.parallax.view :as parallax]
|
||||
[status-im2.common.parallax.whitelist :as whitelist]
|
||||
[status-im2.common.resources :as resources]
|
||||
[status-im2.common.standard-authentication.core :as standard-auth]
|
||||
[status-im2.contexts.onboarding.enable-biometrics.style :as style]
|
||||
[status-im2.navigation.state :as state]
|
||||
[utils.i18n :as i18n]
|
||||
@@ -31,13 +30,13 @@
|
||||
(rf/sub [:profile/customization-color]))
|
||||
syncing-results? (= :syncing-results @state/root-id)]
|
||||
[rn/view {:style (style/buttons insets)}
|
||||
[standard-auth/button
|
||||
[quo/button
|
||||
{:size 40
|
||||
:accessibility-label :enable-biometrics-button
|
||||
:icon-left :i/face-id
|
||||
:customization-color profile-color
|
||||
:on-press #(rf/dispatch [:onboarding/enable-biometrics])
|
||||
:button-label (i18n/label :t/biometric-enable-button {:bio-type-label bio-type-label})}]
|
||||
:on-press #(rf/dispatch [:onboarding/enable-biometrics])}
|
||||
(i18n/label :t/biometric-enable-button {:bio-type-label bio-type-label})]
|
||||
[quo/button
|
||||
{:accessibility-label :maybe-later-button
|
||||
:background :blur
|
||||
|
||||
@@ -133,13 +133,18 @@
|
||||
{:db (dissoc db :onboarding/profile)
|
||||
:dispatch [:navigate-to-within-stack [:create-profile :new-to-status]]})
|
||||
|
||||
(rf/reg-event-fx :onboarding/set-auth-method
|
||||
(fn [{:keys [db]} [auth-method]]
|
||||
{:db (assoc db :auth-method auth-method)}))
|
||||
|
||||
(rf/defn onboarding-new-account-finalize-setup
|
||||
{:events [:onboarding/finalize-setup]}
|
||||
[{:keys [db]}]
|
||||
(let [masked-password (get-in db [:onboarding/profile :password])
|
||||
key-uid (get-in db [:profile/profile :key-uid])
|
||||
syncing? (get-in db [:onboarding/profile :syncing?])
|
||||
biometric-enabled? (= (get-in db [:onboarding/profile :auth-method])
|
||||
auth-method (get-in db [:onboarding/profile :auth-method])
|
||||
biometric-enabled? (= auth-method
|
||||
constants/auth-method-biometric)]
|
||||
(cond-> {:db (assoc db :onboarding/generated-keys? true)}
|
||||
biometric-enabled?
|
||||
@@ -149,9 +154,9 @@
|
||||
masked-password
|
||||
(security/hash-masked-password masked-password))
|
||||
:on-success (fn []
|
||||
(if syncing?
|
||||
(rf/dispatch [:onboarding/navigate-to-enable-notifications])
|
||||
(log/error "successfully saved biometrics")))
|
||||
(rf/dispatch [:onboarding/set-auth-method auth-method])
|
||||
(when syncing?
|
||||
(rf/dispatch [:onboarding/navigate-to-enable-notifications])))
|
||||
:on-error #(log/error "failed to save biometrics"
|
||||
{:key-uid key-uid
|
||||
:error %})}))))
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
(ns status-im2.contexts.profile.create.events
|
||||
(:require
|
||||
[native-module.core :as native-module]
|
||||
[status-im2.contexts.emoji-picker.utils :as emoji-picker.utils]
|
||||
[status-im2.contexts.profile.config :as profile.config]
|
||||
status-im2.contexts.profile.create.effects
|
||||
[utils.re-frame :as rf]
|
||||
@@ -14,4 +15,5 @@
|
||||
:displayName display-name
|
||||
:password (native-module/sha3 (security/safe-unmask-data password))
|
||||
:imagePath (profile.config/strip-file-prefix image-path)
|
||||
:customizationColor color)})
|
||||
:customizationColor color
|
||||
:emoji (emoji-picker.utils/random-emoji))})
|
||||
|
||||
@@ -125,7 +125,7 @@
|
||||
accounts tokens custom-tokens favourites]))]
|
||||
:check-eip1559-activation {:network-id network-id}}
|
||||
(not (:universal-links/handling db))
|
||||
(assoc :chat/open-last-chat (get-in db [:profile/profile :key-uid]))
|
||||
(assoc :effects.chat/open-last-chat (get-in db [:profile/profile :key-uid]))
|
||||
notifications-enabled?
|
||||
(assoc :effects/push-notifications-enable nil))
|
||||
(contacts/initialize-contacts)
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
[react-native.safe-area :as safe-area]
|
||||
[reagent.core :as reagent]
|
||||
[status-im2.common.confirmation-drawer.view :as confirmation-drawer]
|
||||
[status-im2.common.standard-authentication.password-input.view :as password-input]
|
||||
[status-im2.common.standard-authentication.core :as standard-authentication]
|
||||
[status-im2.config :as config]
|
||||
[status-im2.constants :as constants]
|
||||
[status-im2.contexts.onboarding.common.background.view :as background]
|
||||
@@ -205,7 +205,7 @@
|
||||
:customization-color (or customization-color :primary)
|
||||
:profile-picture profile-picture
|
||||
:card-style style/login-profile-card}]
|
||||
[password-input/view
|
||||
[standard-authentication/password-input
|
||||
{:shell? true
|
||||
:default-password password}]]
|
||||
[quo/button
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
(ns status-im2.contexts.profile.recover.events
|
||||
(:require
|
||||
[native-module.core :as native-module]
|
||||
[status-im2.contexts.emoji-picker.utils :as emoji-picker.utils]
|
||||
[status-im2.contexts.profile.config :as profile.config]
|
||||
status-im2.contexts.profile.recover.effects
|
||||
[utils.re-frame :as rf]
|
||||
@@ -18,4 +19,5 @@
|
||||
:mnemonic (security/safe-unmask-data seed-phrase)
|
||||
:password (native-module/sha3 (security/safe-unmask-data password))
|
||||
:imagePath (profile.config/strip-file-prefix image-path)
|
||||
:customizationColor color})})
|
||||
:customizationColor color
|
||||
:emoji (emoji-picker.utils/random-emoji)})})
|
||||
|
||||
@@ -138,3 +138,10 @@
|
||||
{:events [:profile.settings/update-local-picture]}
|
||||
[cofx pics]
|
||||
(optimistic-profile-update cofx :images pics))
|
||||
|
||||
(rf/defn mark-mnemonic-as-shown
|
||||
{:events [:profile.settings/mnemonic-was-shown]}
|
||||
[cofx]
|
||||
{:json-rpc/call [{:method "settings_mnemonicWasShown"
|
||||
:on-success #(log/debug "mnemonic was marked as shown")
|
||||
:on-error #(log/error "mnemonic was not marked as shown" %)}]})
|
||||
|
||||
@@ -166,10 +166,12 @@
|
||||
[status-im2.contexts.quo-preview.text-combinations.preview :as
|
||||
text-combinations]
|
||||
[status-im2.contexts.quo-preview.text-combinations.standard-title :as standard-title]
|
||||
[status-im2.contexts.quo-preview.text-combinations.username :as username]
|
||||
[status-im2.contexts.quo-preview.wallet.account-card :as account-card]
|
||||
[status-im2.contexts.quo-preview.wallet.account-origin :as account-origin]
|
||||
[status-im2.contexts.quo-preview.wallet.account-overview :as
|
||||
account-overview]
|
||||
[status-im2.contexts.quo-preview.wallet.confirmation-progress :as confirmation-progress]
|
||||
[status-im2.contexts.quo-preview.wallet.keypair :as keypair]
|
||||
[status-im2.contexts.quo-preview.wallet.network-amount :as network-amount]
|
||||
[status-im2.contexts.quo-preview.wallet.network-bridge :as network-bridge]
|
||||
@@ -178,6 +180,7 @@
|
||||
[status-im2.contexts.quo-preview.wallet.progress-bar :as progress-bar]
|
||||
[status-im2.contexts.quo-preview.wallet.summary-info :as summary-info]
|
||||
[status-im2.contexts.quo-preview.wallet.token-input :as token-input]
|
||||
[status-im2.contexts.quo-preview.wallet.transaction-progress :as transaction-progress]
|
||||
[status-im2.contexts.quo-preview.wallet.transaction-summary :as
|
||||
transaction-summary]
|
||||
[status-im2.contexts.quo-preview.wallet.wallet-activity :as wallet-activity]
|
||||
@@ -459,11 +462,15 @@
|
||||
{:name :channel-name
|
||||
:component channel-name/view}
|
||||
{:name :standard-title
|
||||
:component standard-title/view}]
|
||||
:component standard-title/view}
|
||||
{:name :username
|
||||
:component username/view}]
|
||||
:wallet [{:name :account-card :component account-card/view}
|
||||
{:name :account-origin :component account-origin/view}
|
||||
{:name :account-overview
|
||||
:component account-overview/view}
|
||||
{:name :confirmation-progress
|
||||
:component confirmation-progress/view}
|
||||
{:name :keypair :component keypair/view}
|
||||
{:name :network-amount :component network-amount/view}
|
||||
{:name :network-bridge :component network-bridge/view}
|
||||
@@ -473,6 +480,7 @@
|
||||
{:name :summary-info :component summary-info/view}
|
||||
{:name :token-input :component token-input/view}
|
||||
{:name :wallet-activity :component wallet-activity/view}
|
||||
{:name :transaction-progress :component transaction-progress/view}
|
||||
{:name :transaction-summary :component transaction-summary/view}
|
||||
{:name :wallet-overview
|
||||
:component wallet-overview/view}]
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
(ns status-im2.contexts.quo-preview.text-combinations.username
|
||||
(:require [quo.core :as quo]
|
||||
[reagent.core :as reagent]
|
||||
[status-im2.contexts.quo-preview.preview :as preview]))
|
||||
|
||||
(def descriptor
|
||||
[{:key :name-type
|
||||
:type :select
|
||||
:options [{:key :default}
|
||||
{:key :ens
|
||||
:value "ENS"}
|
||||
{:key :nickname}]}
|
||||
{:key :username
|
||||
:type :text}
|
||||
{:key :name
|
||||
:type :text}
|
||||
{:key :status
|
||||
:type :select
|
||||
:options [{:key nil
|
||||
:value "(Nothing)"}
|
||||
{:key :verified}
|
||||
{:key :contact}
|
||||
{:key :untrustworthy}
|
||||
{:key :untrustworthy-contact}
|
||||
{:key :blocked}]}
|
||||
{:key :blur?
|
||||
:type :boolean}])
|
||||
|
||||
(defn- set-username-based-on-name-type
|
||||
[_ ratom {previous-type :name-type} {new-type :name-type}]
|
||||
(when (not= previous-type new-type)
|
||||
(swap! ratom assoc
|
||||
:username
|
||||
(if (= new-type :ens)
|
||||
"juan.eth"
|
||||
"Juanito Mdz"))))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [state (reagent/atom {:name-type :default
|
||||
:username "Juanito Mdz"
|
||||
:name "Juan Méndez"
|
||||
:status nil
|
||||
:blur? true})
|
||||
_ (add-watch state :on-state-change set-username-based-on-name-type)]
|
||||
(fn []
|
||||
[preview/preview-container
|
||||
{:state state
|
||||
:descriptor descriptor
|
||||
:show-blur-background? true
|
||||
:blur? (:blur? @state)}
|
||||
[quo/username @state]])))
|
||||
@@ -0,0 +1,85 @@
|
||||
(ns status-im2.contexts.quo-preview.wallet.confirmation-progress
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[status-im2.contexts.quo-preview.preview :as preview]))
|
||||
|
||||
(def descriptor
|
||||
[{:type :text
|
||||
:key :progress-value}
|
||||
{:type :select
|
||||
:key :network
|
||||
:options [{:key :mainnet}
|
||||
{:key :optimism}
|
||||
{:key :arbitrum}]}
|
||||
{:type :select
|
||||
:key :state
|
||||
:options [{:key :pending}
|
||||
{:key :sending}
|
||||
{:key :confirmed}
|
||||
{:key :finalising}
|
||||
{:key :finalized}
|
||||
{:key :error}]}
|
||||
(preview/customization-color-option)])
|
||||
|
||||
(def total-box 85)
|
||||
(def counter (reagent/atom 0))
|
||||
(def interval-id (reagent/atom nil))
|
||||
(def interval-ms 50)
|
||||
|
||||
(defn- stop-interval
|
||||
[]
|
||||
(when @interval-id
|
||||
(js/clearInterval @interval-id)
|
||||
(reset! interval-id nil)))
|
||||
|
||||
(defn- clear-counter
|
||||
[]
|
||||
(reset! counter 0))
|
||||
|
||||
(defn- update-counter
|
||||
[state]
|
||||
(let [new-counter-value (inc @counter)]
|
||||
(if (or (and (= state :pending) (> new-counter-value 0))
|
||||
(and (= state :sending) (> new-counter-value 2))
|
||||
(and (= state :confirmed) (> new-counter-value 4))
|
||||
(and (= state :finalising) (> new-counter-value 18))
|
||||
(and (= state :finalized) (> new-counter-value total-box))
|
||||
(and (= state :error) (> new-counter-value 2)))
|
||||
(stop-interval)
|
||||
(reset! counter new-counter-value))))
|
||||
|
||||
(defn- start-interval
|
||||
[state]
|
||||
(reset! interval-id
|
||||
(js/setInterval
|
||||
(fn []
|
||||
(update-counter state))
|
||||
interval-ms)))
|
||||
|
||||
(defn- f-view
|
||||
[state]
|
||||
(fn []
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(start-interval (:state @state))
|
||||
(clear-counter)
|
||||
(fn []
|
||||
(stop-interval)))
|
||||
[(:state @state)])
|
||||
[preview/preview-container {:state state :descriptor descriptor}
|
||||
[quo/confirmation-propgress
|
||||
(assoc @state
|
||||
:counter
|
||||
@counter)]]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [state (reagent/atom
|
||||
{:total-box total-box
|
||||
:progress-value "10"
|
||||
:network :mainnet
|
||||
:state :pending
|
||||
:customization-color :blue})]
|
||||
[:f> f-view state]))
|
||||
@@ -1,6 +1,7 @@
|
||||
(ns status-im2.contexts.quo-preview.wallet.progress-bar
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[status-im2.contexts.quo-preview.preview :as preview]))
|
||||
|
||||
@@ -11,11 +12,17 @@
|
||||
{:key :confirmed}
|
||||
{:key :finalized}
|
||||
{:key :error}]}
|
||||
{:key :full-width?
|
||||
:type :boolean}
|
||||
{:key :progressed-value
|
||||
:type :text}
|
||||
(preview/customization-color-option)])
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [state (reagent/atom {:state :pending
|
||||
:full-width? false
|
||||
:progressed-value "10"
|
||||
:customization-color :blue})]
|
||||
(fn []
|
||||
[preview/preview-container
|
||||
@@ -23,4 +30,5 @@
|
||||
:descriptor descriptor
|
||||
:component-container-style {:padding-top 40
|
||||
:align-items :center}}
|
||||
[quo/progress-bar @state]])))
|
||||
[rn/view {:style {:flex-direction :row}}
|
||||
[quo/progress-bar @state]]])))
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
(ns status-im2.contexts.quo-preview.wallet.transaction-progress
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[status-im2.common.resources :as resources]
|
||||
[status-im2.contexts.quo-preview.preview :as preview]))
|
||||
|
||||
(def descriptor
|
||||
[{:type :text
|
||||
:key :title}
|
||||
{:type :text
|
||||
:key :tag-name}
|
||||
{:type :text
|
||||
:key :epoch-number-mainnet}
|
||||
{:type :text
|
||||
:key :epoch-number-optimism}
|
||||
{:type :text
|
||||
:key :epoch-number-arbitrum}
|
||||
{:type :text
|
||||
:key :tag-number}
|
||||
{:type :text
|
||||
:key :optimism-progress-percentage}
|
||||
{:type :text
|
||||
:key :arbitrum-progress-percentage}
|
||||
{:type :select
|
||||
:key :network
|
||||
:options [{:key :mainnet}
|
||||
{:key :optimism}
|
||||
{:key :arbitrum}
|
||||
{:key :optimism-arbitrum}]}
|
||||
{:type :select
|
||||
:key :state-mainnet
|
||||
:options [{:key :pending}
|
||||
{:key :sending}
|
||||
{:key :confirmed}
|
||||
{:key :finalising}
|
||||
{:key :finalized}
|
||||
{:key :error}]}
|
||||
{:type :select
|
||||
:key :state-optimism
|
||||
:options [{:key :pending}
|
||||
{:key :sending}
|
||||
{:key :confirmed}
|
||||
{:key :finalising}
|
||||
{:key :finalized}
|
||||
{:key :error}]}
|
||||
{:type :select
|
||||
:key :state-arbitrum
|
||||
:options [{:key :pending}
|
||||
{:key :sending}
|
||||
{:key :confirmed}
|
||||
{:key :finalising}
|
||||
{:key :finalized}
|
||||
{:key :error}]}
|
||||
(preview/customization-color-option)])
|
||||
|
||||
(def total-box 85)
|
||||
(def counter (reagent/atom 0))
|
||||
(def interval-id (reagent/atom nil))
|
||||
(def interval-ms 50)
|
||||
|
||||
(defn- stop-interval
|
||||
[]
|
||||
(when @interval-id
|
||||
(js/clearInterval @interval-id)
|
||||
(reset! interval-id nil)))
|
||||
|
||||
(defn- clear-counter
|
||||
[]
|
||||
(reset! counter 0))
|
||||
|
||||
(defn- update-counter
|
||||
[state]
|
||||
(let [new-counter-value (inc @counter)]
|
||||
(if (or (and (= state :pending) (> new-counter-value 0))
|
||||
(and (= state :sending) (> new-counter-value 2))
|
||||
(and (= state :confirmed) (> new-counter-value 4))
|
||||
(and (= state :finalising) (> new-counter-value 18))
|
||||
(and (= state :finalized) (> new-counter-value total-box))
|
||||
(and (= state :error) (> new-counter-value 2)))
|
||||
(stop-interval)
|
||||
(reset! counter new-counter-value))))
|
||||
|
||||
(defn- start-interval
|
||||
[state]
|
||||
(reset! interval-id
|
||||
(js/setInterval
|
||||
(fn []
|
||||
(update-counter state))
|
||||
interval-ms)))
|
||||
|
||||
(defn- get-networks
|
||||
[state]
|
||||
(case (:network state)
|
||||
:mainnet [{:network :mainnet
|
||||
:state (:state-mainnet state)
|
||||
:counter @counter
|
||||
:total-box total-box
|
||||
:epoch-number (:epoch-number-mainnet state)}]
|
||||
:optimism [{:network :optimism
|
||||
:state (:state-optimism state)
|
||||
:progress (:optimism-progress-percentage state)
|
||||
:epoch-number (:epoch-number-optimism state)}]
|
||||
:arbitrum [{:network :arbitrum
|
||||
:state (:state-arbitrum state)
|
||||
:progress (:arbitrum-progress-percentage state)
|
||||
:epoch-number (:epoch-number-arbitrum state)}]
|
||||
:optimism-arbitrum [{:network :optimism
|
||||
:state (:state-optimism state)
|
||||
:progress (:optimism-progress-percentage state)
|
||||
:epoch-number (:epoch-number-optimism state)}
|
||||
{:network :arbitrum
|
||||
:state (:state-arbitrum state)
|
||||
:progress (:arbitrum-progress-percentage state)
|
||||
:epoch-number (:epoch-number-arbitrum state)}]))
|
||||
|
||||
(defn- f-view
|
||||
[state]
|
||||
(fn []
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(start-interval (:state-mainnet @state))
|
||||
(clear-counter)
|
||||
(fn []
|
||||
(stop-interval)))
|
||||
[(:state-mainnet @state)])
|
||||
[preview/preview-container {:state state :descriptor descriptor}
|
||||
[quo/transaction-progress
|
||||
(assoc @state
|
||||
:networks
|
||||
(get-networks @state))]]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [state (reagent/atom
|
||||
{:title "Title"
|
||||
:counter 40
|
||||
:total-box total-box
|
||||
:tag-name "Doodle"
|
||||
:tag-number "120"
|
||||
:epoch-number-mainnet "181,329"
|
||||
:epoch-number-optimism "181,329"
|
||||
:epoch-number-arbitrum "181,329"
|
||||
:optimism-progress-percentage "10"
|
||||
:arbitrum-progress-percentage "10"
|
||||
:network :mainnet
|
||||
:state-mainnet :pending
|
||||
:state-arbitrum :pending
|
||||
:state-optimism :pending
|
||||
:customization-color :blue
|
||||
:tag-photo (resources/get-mock-image :collectible)
|
||||
:on-press (fn []
|
||||
(js/alert "Transaction progress item pressed"))})]
|
||||
[:f> f-view state]))
|
||||
@@ -122,10 +122,13 @@
|
||||
:on-error [:activity-center/process-notification-failure notification-id
|
||||
:notification/mark-as-read]}]}))
|
||||
|
||||
(rf/defn mark-as-read-success
|
||||
{:events [:activity-center.notifications/mark-as-read-success]}
|
||||
[cofx notification]
|
||||
(notifications-reconcile cofx [(assoc notification :read true)]))
|
||||
(defn mark-as-read-success
|
||||
[_ [{:keys [chat-id] :as notification}]]
|
||||
{:fx [(when chat-id
|
||||
[:dispatch [:chats-list/load-chat chat-id]])
|
||||
[:dispatch [:activity-center.notifications/reconcile [(assoc notification :read true)]]]]})
|
||||
|
||||
(rf/reg-event-fx :activity-center.notifications/mark-as-read-success mark-as-read-success)
|
||||
|
||||
(rf/defn mark-as-unread
|
||||
{:events [:activity-center.notifications/mark-as-unread]}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
(ns status-im2.contexts.shell.activity-center.events-test
|
||||
(:require
|
||||
[cljs.test :refer [deftest is testing]]
|
||||
matcher-combinators.test
|
||||
[status-im2.constants :as constants]
|
||||
[status-im2.contexts.shell.activity-center.events :as events]
|
||||
[status-im2.contexts.shell.activity-center.notification-types :as types]
|
||||
@@ -14,18 +15,18 @@
|
||||
|
||||
(deftest open-activity-center-test
|
||||
(testing "opens the activity center with default filters"
|
||||
(is (= {:db {}
|
||||
:fx [[:dispatch [:open-modal :activity-center {}]]
|
||||
[:dispatch-later [{:ms 1000 :dispatch [:activity-center/mark-as-seen]}]]]}
|
||||
(events/open-activity-center {:db {}} [nil]))))
|
||||
(is (match? {:db {}
|
||||
:fx [[:dispatch [:open-modal :activity-center {}]]
|
||||
[:dispatch-later [{:ms 1000 :dispatch [:activity-center/mark-as-seen]}]]]}
|
||||
(events/open-activity-center {:db {}} [nil]))))
|
||||
|
||||
(testing "opens the activity center with filters enabled"
|
||||
(is (= {:db {:activity-center {:filter {:status :unread :type types/contact-request}}}
|
||||
:fx [[:dispatch [:open-modal :activity-center {}]]
|
||||
[:dispatch-later [{:ms 1000 :dispatch [:activity-center/mark-as-seen]}]]]}
|
||||
(events/open-activity-center {:db {}}
|
||||
[{:filter-type types/contact-request
|
||||
:filter-status :unread}])))))
|
||||
(is (match? {:db {:activity-center {:filter {:status :unread :type types/contact-request}}}
|
||||
:fx [[:dispatch [:open-modal :activity-center {}]]
|
||||
[:dispatch-later [{:ms 1000 :dispatch [:activity-center/mark-as-seen]}]]]}
|
||||
(events/open-activity-center {:db {}}
|
||||
[{:filter-type types/contact-request
|
||||
:filter-status :unread}])))))
|
||||
|
||||
(deftest process-notification-failure-test
|
||||
(testing "logs and returns nil"
|
||||
@@ -34,11 +35,11 @@
|
||||
notification-id
|
||||
:some-action-name
|
||||
:some-error)))
|
||||
(is (= {:args ["Failed to :some-action-name"
|
||||
{:notification-id notification-id
|
||||
:error :some-error}]
|
||||
:level :warn}
|
||||
(last @h/logs)))))
|
||||
(is (match? {:args ["Failed to :some-action-name"
|
||||
{:notification-id notification-id
|
||||
:error :some-error}]
|
||||
:level :warn}
|
||||
(last @h/logs)))))
|
||||
|
||||
;;;; Mark as read/unread
|
||||
|
||||
@@ -53,25 +54,21 @@
|
||||
(testing "dispatches RPC call"
|
||||
(let [notif {:id "0x1" :read false :type types/one-to-one-chat}
|
||||
cofx {:db {:activity-center {:notifications [notif]}}}]
|
||||
(is (= {:json-rpc/call
|
||||
[{:method "wakuext_markActivityCenterNotificationsRead"
|
||||
:params [[(:id notif)]]
|
||||
:on-success [:activity-center.notifications/mark-as-read-success notif]
|
||||
:on-error [:activity-center/process-notification-failure (:id notif)
|
||||
:notification/mark-as-read]}]}
|
||||
(events/mark-as-read cofx (:id notif)))))))
|
||||
(is (match? {:json-rpc/call
|
||||
[{:method "wakuext_markActivityCenterNotificationsRead"
|
||||
:params [[(:id notif)]]
|
||||
:on-success [:activity-center.notifications/mark-as-read-success notif]
|
||||
:on-error [:activity-center/process-notification-failure (:id notif)
|
||||
:notification/mark-as-read]}]}
|
||||
(events/mark-as-read cofx (:id notif)))))))
|
||||
|
||||
(deftest mark-as-read-success-test
|
||||
(let [f-args (atom [])
|
||||
cofx {:db {}}
|
||||
notif {:id "0x1" :read false :type types/one-to-one-chat}]
|
||||
(with-redefs [events/notifications-reconcile
|
||||
(fn [& args]
|
||||
(reset! f-args args)
|
||||
:result)]
|
||||
(is (= :result (events/mark-as-read-success cofx notif)))
|
||||
(is (= [cofx [(assoc notif :read true)]]
|
||||
@f-args)))))
|
||||
(let [cofx {:db {}}
|
||||
notif {:id "0x1" :read false :type types/one-to-one-chat :chat-id "chat-id"}
|
||||
expected-fx {:fx [[:dispatch [:chats-list/load-chat "chat-id"]]
|
||||
[:dispatch
|
||||
[:activity-center.notifications/reconcile [(assoc notif :read true)]]]]}]
|
||||
(is (match? expected-fx (events/mark-as-read-success cofx [notif])))))
|
||||
|
||||
(deftest mark-as-unread-test
|
||||
(testing "does nothing if the notification ID cannot be found in the app db"
|
||||
@@ -84,13 +81,13 @@
|
||||
(testing "dispatches RPC call"
|
||||
(let [notif {:id "0x1" :read true :type types/one-to-one-chat}
|
||||
cofx {:db {:activity-center {:notifications [notif]}}}]
|
||||
(is (= {:json-rpc/call
|
||||
[{:method "wakuext_markActivityCenterNotificationsUnread"
|
||||
:params [[(:id notif)]]
|
||||
:on-success [:activity-center.notifications/mark-as-unread-success notif]
|
||||
:on-error [:activity-center/process-notification-failure (:id notif)
|
||||
:notification/mark-as-unread]}]}
|
||||
(events/mark-as-unread cofx (:id notif)))))))
|
||||
(is (match? {:json-rpc/call
|
||||
[{:method "wakuext_markActivityCenterNotificationsUnread"
|
||||
:params [[(:id notif)]]
|
||||
:on-success [:activity-center.notifications/mark-as-unread-success notif]
|
||||
:on-error [:activity-center/process-notification-failure (:id notif)
|
||||
:notification/mark-as-unread]}]}
|
||||
(events/mark-as-unread cofx (:id notif)))))))
|
||||
|
||||
(deftest mark-as-unread-success-test
|
||||
(let [f-args (atom [])
|
||||
@@ -101,19 +98,19 @@
|
||||
(reset! f-args args)
|
||||
:reconciliation-result)]
|
||||
(is (= :reconciliation-result (events/mark-as-unread-success cofx notif)))
|
||||
(is (= [cofx [(assoc notif :read false)]]
|
||||
@f-args)))))
|
||||
(is (match? [cofx [(assoc notif :read false)]]
|
||||
@f-args)))))
|
||||
|
||||
;;;; Acceptance/dismissal
|
||||
|
||||
(deftest accept-notification-test
|
||||
(is (= {:json-rpc/call
|
||||
[{:method "wakuext_acceptActivityCenterNotifications"
|
||||
:params [[notification-id]]
|
||||
:on-success [:activity-center.notifications/accept-success notification-id]
|
||||
:on-error [:activity-center/process-notification-failure notification-id
|
||||
:notification/accept]}]}
|
||||
(events/accept-notification {:db {}} notification-id))))
|
||||
(is (match? {:json-rpc/call
|
||||
[{:method "wakuext_acceptActivityCenterNotifications"
|
||||
:params [[notification-id]]
|
||||
:on-success [:activity-center.notifications/accept-success notification-id]
|
||||
:on-error [:activity-center/process-notification-failure notification-id
|
||||
:notification/accept]}]}
|
||||
(events/accept-notification {:db {}} notification-id))))
|
||||
|
||||
(deftest accept-notification-success-test
|
||||
(testing "does nothing if the notification ID cannot be found in the app db"
|
||||
@@ -129,18 +126,18 @@
|
||||
notif-2-accepted (assoc notif-2 :accepted true :read true)
|
||||
cofx {:db {:activity-center {:filter {:type types/no-type :status :all}
|
||||
:notifications [notif-2 notif-1]}}}]
|
||||
(is (= {:fx [[:dispatch [:chat/ensure-chats []]]
|
||||
[:dispatch [:activity-center.notifications/reconcile [notif-2-accepted]]]]}
|
||||
(events/accept-notification-success cofx [(:id notif-2) nil]))))))
|
||||
(is (match? {:fx [[:dispatch [:chat/ensure-chats []]]
|
||||
[:dispatch [:activity-center.notifications/reconcile [notif-2-accepted]]]]}
|
||||
(events/accept-notification-success cofx [(:id notif-2) nil]))))))
|
||||
|
||||
(deftest dismiss-notification-test
|
||||
(is (= {:json-rpc/call
|
||||
[{:method "wakuext_dismissActivityCenterNotifications"
|
||||
:params [[notification-id]]
|
||||
:on-success [:activity-center.notifications/dismiss-success notification-id]
|
||||
:on-error [:activity-center/process-notification-failure notification-id
|
||||
:notification/dismiss]}]}
|
||||
(events/dismiss-notification {:db {}} notification-id))))
|
||||
(is (match? {:json-rpc/call
|
||||
[{:method "wakuext_dismissActivityCenterNotifications"
|
||||
:params [[notification-id]]
|
||||
:on-success [:activity-center.notifications/dismiss-success notification-id]
|
||||
:on-error [:activity-center/process-notification-failure notification-id
|
||||
:notification/dismiss]}]}
|
||||
(events/dismiss-notification {:db {}} notification-id))))
|
||||
|
||||
(deftest dismiss-notification-success-test
|
||||
(testing "does nothing if the notification ID cannot be found in the app db"
|
||||
@@ -156,11 +153,11 @@
|
||||
notif-2-dismissed (assoc notif-2 :dismissed true :read true)
|
||||
cofx {:db {:activity-center {:filter {:type types/no-type :status :all}
|
||||
:notifications [notif-2 notif-1]}}}]
|
||||
(is (= {:db {:activity-center {:filter {:type 0 :status :all}
|
||||
:notifications [notif-2-dismissed notif-1]}}
|
||||
:dispatch-n [[:activity-center.notifications/fetch-unread-count]
|
||||
[:activity-center.notifications/fetch-pending-contact-requests]]}
|
||||
(events/dismiss-notification-success cofx (:id notif-2)))))))
|
||||
(is (match? {:db {:activity-center {:filter {:type 0 :status :all}
|
||||
:notifications [notif-2-dismissed notif-1]}}
|
||||
:dispatch-n [[:activity-center.notifications/fetch-unread-count]
|
||||
[:activity-center.notifications/fetch-pending-contact-requests]]}
|
||||
(events/dismiss-notification-success cofx (:id notif-2)))))))
|
||||
|
||||
;;;; Contact verification
|
||||
|
||||
@@ -208,41 +205,41 @@
|
||||
:type types/contact-verification})
|
||||
|
||||
(deftest contact-verification-decline-test
|
||||
(is (= {:json-rpc/call
|
||||
[{:method "wakuext_declineContactVerificationRequest"
|
||||
:params [notification-id]
|
||||
:on-success [:activity-center/reconcile-notifications-from-response]
|
||||
:on-error [:activity-center/process-notification-failure notification-id
|
||||
:contact-verification/decline]}]}
|
||||
(events/contact-verification-decline {:db {}} notification-id))))
|
||||
(is (match? {:json-rpc/call
|
||||
[{:method "wakuext_declineContactVerificationRequest"
|
||||
:params [notification-id]
|
||||
:on-success [:activity-center/reconcile-notifications-from-response]
|
||||
:on-error [:activity-center/process-notification-failure notification-id
|
||||
:contact-verification/decline]}]}
|
||||
(events/contact-verification-decline {:db {}} notification-id))))
|
||||
|
||||
(deftest contact-verification-reply-test
|
||||
(let [reply "The answer is 42"]
|
||||
(is (= {:json-rpc/call
|
||||
[{:method "wakuext_acceptContactVerificationRequest"
|
||||
:params [notification-id reply]
|
||||
:on-success [:activity-center/reconcile-notifications-from-response]
|
||||
:on-error [:activity-center/process-notification-failure notification-id
|
||||
:contact-verification/reply]}]}
|
||||
(events/contact-verification-reply {:db {}} notification-id reply)))))
|
||||
(is (match? {:json-rpc/call
|
||||
[{:method "wakuext_acceptContactVerificationRequest"
|
||||
:params [notification-id reply]
|
||||
:on-success [:activity-center/reconcile-notifications-from-response]
|
||||
:on-error [:activity-center/process-notification-failure notification-id
|
||||
:contact-verification/reply]}]}
|
||||
(events/contact-verification-reply {:db {}} notification-id reply)))))
|
||||
|
||||
(deftest contact-verification-mark-as-trusted-test
|
||||
(is (= {:json-rpc/call
|
||||
[{:method "wakuext_verifiedTrusted"
|
||||
:params [{:id notification-id}]
|
||||
:on-success [:activity-center/reconcile-notifications-from-response]
|
||||
:on-error [:activity-center/process-notification-failure notification-id
|
||||
:contact-verification/mark-as-trusted]}]}
|
||||
(events/contact-verification-mark-as-trusted {:db {}} notification-id))))
|
||||
(is (match? {:json-rpc/call
|
||||
[{:method "wakuext_verifiedTrusted"
|
||||
:params [{:id notification-id}]
|
||||
:on-success [:activity-center/reconcile-notifications-from-response]
|
||||
:on-error [:activity-center/process-notification-failure notification-id
|
||||
:contact-verification/mark-as-trusted]}]}
|
||||
(events/contact-verification-mark-as-trusted {:db {}} notification-id))))
|
||||
|
||||
(deftest contact-verification-mark-as-untrustworthy-test
|
||||
(is (= {:json-rpc/call
|
||||
[{:method "wakuext_verifiedUntrustworthy"
|
||||
:params [{:id notification-id}]
|
||||
:on-success [:activity-center/reconcile-notifications-from-response]
|
||||
:on-error [:activity-center/process-notification-failure notification-id
|
||||
:contact-verification/mark-as-untrustworthy]}]}
|
||||
(events/contact-verification-mark-as-untrustworthy {:db {}} notification-id))))
|
||||
(is (match? {:json-rpc/call
|
||||
[{:method "wakuext_verifiedUntrustworthy"
|
||||
:params [{:id notification-id}]
|
||||
:on-success [:activity-center/reconcile-notifications-from-response]
|
||||
:on-error [:activity-center/process-notification-failure notification-id
|
||||
:contact-verification/mark-as-untrustworthy]}]}
|
||||
(events/contact-verification-mark-as-untrustworthy {:db {}} notification-id))))
|
||||
|
||||
;;;; Notification reconciliation
|
||||
|
||||
@@ -256,17 +253,17 @@
|
||||
cofx {:db {:activity-center
|
||||
{:filter {:type types/no-type :status :all}
|
||||
:notifications [notif-2 notif-1]}}}]
|
||||
(is (= {:db {:activity-center
|
||||
{:filter {:type types/no-type :status :all}
|
||||
:notifications [new-notif-4 new-notif-3 new-notif-2]}}
|
||||
:dispatch-n [[:activity-center.notifications/fetch-unread-count]
|
||||
[:activity-center.notifications/fetch-pending-contact-requests]]}
|
||||
(events/notifications-reconcile
|
||||
cofx
|
||||
[(assoc notif-1 :deleted true) ; will be removed
|
||||
new-notif-2
|
||||
new-notif-3
|
||||
new-notif-4])))))
|
||||
(is (match? {:db {:activity-center
|
||||
{:filter {:type types/no-type :status :all}
|
||||
:notifications [new-notif-4 new-notif-3 new-notif-2]}}
|
||||
:dispatch-n [[:activity-center.notifications/fetch-unread-count]
|
||||
[:activity-center.notifications/fetch-pending-contact-requests]]}
|
||||
(events/notifications-reconcile
|
||||
cofx
|
||||
[(assoc notif-1 :deleted true) ; will be removed
|
||||
new-notif-2
|
||||
new-notif-3
|
||||
new-notif-4])))))
|
||||
|
||||
(testing "All tab + Unread filter"
|
||||
(let [notif-1 {:id "0x1" :read false :type types/one-to-one-chat}
|
||||
@@ -278,18 +275,18 @@
|
||||
cofx {:db {:activity-center
|
||||
{:filter {:type types/no-type :status :unread}
|
||||
:notifications [notif-5 notif-2 notif-1]}}}]
|
||||
(is (= {:db {:activity-center
|
||||
{:filter {:type types/no-type :status :unread}
|
||||
:notifications [new-notif-3 notif-1]}}
|
||||
:dispatch-n [[:activity-center.notifications/fetch-unread-count]
|
||||
[:activity-center.notifications/fetch-pending-contact-requests]]}
|
||||
(events/notifications-reconcile
|
||||
cofx
|
||||
[new-notif-2 ; will be removed because it's read
|
||||
new-notif-3 ; will be inserted
|
||||
new-notif-4 ; will be ignored because it's read
|
||||
(assoc notif-5 :deleted true) ; will be removed
|
||||
])))))
|
||||
(is (match? {:db {:activity-center
|
||||
{:filter {:type types/no-type :status :unread}
|
||||
:notifications [new-notif-3 notif-1]}}
|
||||
:dispatch-n [[:activity-center.notifications/fetch-unread-count]
|
||||
[:activity-center.notifications/fetch-pending-contact-requests]]}
|
||||
(events/notifications-reconcile
|
||||
cofx
|
||||
[new-notif-2 ; will be removed because it's read
|
||||
new-notif-3 ; will be inserted
|
||||
new-notif-4 ; will be ignored because it's read
|
||||
(assoc notif-5 :deleted true) ; will be removed
|
||||
])))))
|
||||
|
||||
(testing "Contact request tab + All filter"
|
||||
(let [notif-1 {:id "0x1" :read true :type types/contact-request}
|
||||
@@ -301,18 +298,18 @@
|
||||
cofx {:db {:activity-center
|
||||
{:filter {:type types/contact-request :status :all}
|
||||
:notifications [notif-5 notif-2 notif-1]}}}]
|
||||
(is (= {:db {:activity-center
|
||||
{:filter {:type types/contact-request :status :all}
|
||||
:notifications [new-notif-3 new-notif-2 notif-1]}}
|
||||
:dispatch-n [[:activity-center.notifications/fetch-unread-count]
|
||||
[:activity-center.notifications/fetch-pending-contact-requests]]}
|
||||
(events/notifications-reconcile
|
||||
cofx
|
||||
[new-notif-2 ; will be updated
|
||||
new-notif-3 ; will be inserted
|
||||
new-notif-4 ; will be ignored because it's not a contact request
|
||||
(assoc notif-5 :deleted true) ; will be removed
|
||||
])))))
|
||||
(is (match? {:db {:activity-center
|
||||
{:filter {:type types/contact-request :status :all}
|
||||
:notifications [new-notif-3 new-notif-2 notif-1]}}
|
||||
:dispatch-n [[:activity-center.notifications/fetch-unread-count]
|
||||
[:activity-center.notifications/fetch-pending-contact-requests]]}
|
||||
(events/notifications-reconcile
|
||||
cofx
|
||||
[new-notif-2 ; will be updated
|
||||
new-notif-3 ; will be inserted
|
||||
new-notif-4 ; will be ignored because it's not a contact request
|
||||
(assoc notif-5 :deleted true) ; will be removed
|
||||
])))))
|
||||
|
||||
(testing "Contact request tab + Unread filter"
|
||||
(let [notif-1 {:id "0x1" :read false :type types/contact-request}
|
||||
@@ -326,20 +323,20 @@
|
||||
{:filter {:type types/contact-request
|
||||
:status :unread}
|
||||
:notifications [notif-6 notif-2 notif-1]}}}]
|
||||
(is (= {:db {:activity-center
|
||||
{:filter {:type types/contact-request
|
||||
:status :unread}
|
||||
:notifications [new-notif-3 notif-1]}}
|
||||
:dispatch-n [[:activity-center.notifications/fetch-unread-count]
|
||||
[:activity-center.notifications/fetch-pending-contact-requests]]}
|
||||
(events/notifications-reconcile
|
||||
cofx
|
||||
[new-notif-2 ; will be removed because it's read
|
||||
new-notif-3 ; will be inserted
|
||||
new-notif-4 ; will be ignored because it's read
|
||||
new-notif-5 ; will be ignored because it's not a contact request
|
||||
(assoc notif-6 :deleted true) ; will be removed
|
||||
])))))
|
||||
(is (match? {:db {:activity-center
|
||||
{:filter {:type types/contact-request
|
||||
:status :unread}
|
||||
:notifications [new-notif-3 notif-1]}}
|
||||
:dispatch-n [[:activity-center.notifications/fetch-unread-count]
|
||||
[:activity-center.notifications/fetch-pending-contact-requests]]}
|
||||
(events/notifications-reconcile
|
||||
cofx
|
||||
[new-notif-2 ; will be removed because it's read
|
||||
new-notif-3 ; will be inserted
|
||||
new-notif-4 ; will be ignored because it's read
|
||||
new-notif-5 ; will be ignored because it's not a contact request
|
||||
(assoc notif-6 :deleted true) ; will be removed
|
||||
])))))
|
||||
|
||||
;; Sorting by timestamp and ID is compatible with what the backend does when
|
||||
;; returning paginated results.
|
||||
@@ -354,15 +351,15 @@
|
||||
cofx {:db {:activity-center
|
||||
{:notifications [notif-1 notif-3 notif-4 notif-2
|
||||
notif-5]}}}]
|
||||
(is (= {:db {:activity-center
|
||||
{:notifications [notif-5
|
||||
new-notif-4
|
||||
notif-3
|
||||
notif-2
|
||||
new-notif-1]}}
|
||||
:dispatch-n [[:activity-center.notifications/fetch-unread-count]
|
||||
[:activity-center.notifications/fetch-pending-contact-requests]]}
|
||||
(events/notifications-reconcile cofx [new-notif-1 new-notif-4]))))))
|
||||
(is (match? {:db {:activity-center
|
||||
{:notifications [notif-5
|
||||
new-notif-4
|
||||
notif-3
|
||||
notif-2
|
||||
new-notif-1]}}
|
||||
:dispatch-n [[:activity-center.notifications/fetch-unread-count]
|
||||
[:activity-center.notifications/fetch-pending-contact-requests]]}
|
||||
(events/notifications-reconcile cofx [new-notif-1 new-notif-4]))))))
|
||||
|
||||
(deftest remove-pending-contact-request-test
|
||||
(testing "removes notification from all related filter types and status"
|
||||
@@ -376,26 +373,27 @@
|
||||
notif-2 ; will be removed
|
||||
notif-1 ; will be ignored because it's not from the same author
|
||||
]}}}]
|
||||
(is (= {:db {:activity-center {:notifications [notif-3 notif-1]}}}
|
||||
(events/notifications-remove-pending-contact-request cofx author))))))
|
||||
(is (match? {:db {:activity-center {:notifications [notif-3 notif-1]}}}
|
||||
(events/notifications-remove-pending-contact-request cofx author))))))
|
||||
|
||||
;;;; Notifications fetching and pagination
|
||||
|
||||
(deftest notifications-fetch-first-page-test
|
||||
(testing "fetches first page"
|
||||
(let [cofx {:db {}}]
|
||||
(is (= {:db {:activity-center {:filter {:type types/one-to-one-chat
|
||||
:status :unread}
|
||||
:loading? true}}
|
||||
:json-rpc/call [{:method "wakuext_activityCenterNotifications"
|
||||
:params [{:cursor ""
|
||||
:limit (:notifications-per-page events/defaults)
|
||||
:activityTypes [types/one-to-one-chat]
|
||||
:readType events/read-type-unread}]
|
||||
:on-success [:activity-center.notifications/fetch-success true]
|
||||
:on-error [:activity-center.notifications/fetch-error
|
||||
types/one-to-one-chat :unread]}]}
|
||||
(events/notifications-fetch-first-page cofx {:filter-type types/one-to-one-chat}))))))
|
||||
(is (match? {:db {:activity-center {:filter {:type types/one-to-one-chat
|
||||
:status :unread}
|
||||
:loading? true}}
|
||||
:json-rpc/call [{:method "wakuext_activityCenterNotifications"
|
||||
:params [{:cursor ""
|
||||
:limit (:notifications-per-page
|
||||
events/defaults)
|
||||
:activityTypes [types/one-to-one-chat]
|
||||
:readType events/read-type-unread}]
|
||||
:on-success [:activity-center.notifications/fetch-success true]
|
||||
:on-error [:activity-center.notifications/fetch-error
|
||||
types/one-to-one-chat :unread]}]}
|
||||
(events/notifications-fetch-first-page cofx {:filter-type types/one-to-one-chat}))))))
|
||||
|
||||
(deftest notifications-fetch-next-next-page-test
|
||||
(testing "does not fetch next page when pagination cursor reached the end"
|
||||
@@ -413,12 +411,12 @@
|
||||
(reset! f-args args)
|
||||
:result)]
|
||||
(is (= :result (events/notifications-fetch-next-page cofx)))
|
||||
(is (= [cofx
|
||||
{:cursor cursor
|
||||
:filter-type types/one-to-one-chat
|
||||
:filter-status :unread
|
||||
:reset-data? false}]
|
||||
@f-args))))))
|
||||
(is (match? [cofx
|
||||
{:cursor cursor
|
||||
:filter-type types/one-to-one-chat
|
||||
:filter-status :unread
|
||||
:reset-data? false}]
|
||||
@f-args))))))
|
||||
|
||||
(deftest notifications-fetch-error-test
|
||||
(testing "resets loading state"
|
||||
@@ -427,23 +425,23 @@
|
||||
:filter {:status :unread
|
||||
:type types/one-to-one-chat}
|
||||
:cursor ""}}}]
|
||||
(is (= {:db {:activity-center {:filter {:status :unread
|
||||
:type types/one-to-one-chat}
|
||||
:cursor ""}}}
|
||||
(events/notifications-fetch-error cofx :dummy-error))))))
|
||||
(is (match? {:db {:activity-center {:filter {:status :unread
|
||||
:type types/one-to-one-chat}
|
||||
:cursor ""}}}
|
||||
(events/notifications-fetch-error cofx :dummy-error))))))
|
||||
|
||||
(deftest seen-state-test
|
||||
(testing "update seen state"
|
||||
(is (= {:db {:activity-center {:seen? true}}}
|
||||
(events/reconcile-seen-state {:db {}} true))))
|
||||
(is (match? {:db {:activity-center {:seen? true}}}
|
||||
(events/reconcile-seen-state {:db {}} true))))
|
||||
|
||||
(testing "update seen state when the user is on other screen"
|
||||
(is (= {:db {:view-id :chats-stack
|
||||
:activity-center {:seen? false}}}
|
||||
(events/reconcile-seen-state {:db {:view-id :chats-stack}} false))))
|
||||
(is (match? {:db {:view-id :chats-stack
|
||||
:activity-center {:seen? false}}}
|
||||
(events/reconcile-seen-state {:db {:view-id :chats-stack}} false))))
|
||||
|
||||
(testing "update seen state when the user is on activity center"
|
||||
(is (= {:db {:view-id :activity-center
|
||||
:activity-center {:seen? false}}
|
||||
:dispatch [:activity-center/mark-as-seen]}
|
||||
(events/reconcile-seen-state {:db {:view-id :activity-center}} false)))))
|
||||
(is (match? {:db {:view-id :activity-center
|
||||
:activity-center {:seen? false}}
|
||||
:dispatch [:activity-center/mark-as-seen]}
|
||||
(events/reconcile-seen-state {:db {:view-id :activity-center}} false)))))
|
||||
|
||||
@@ -17,6 +17,5 @@
|
||||
(def load-chats-stack? (reagent/atom false))
|
||||
(def load-wallet-stack? (reagent/atom false))
|
||||
(def load-browser-stack? (reagent/atom false))
|
||||
|
||||
;NOTE temporary while we support old wallet
|
||||
(def load-new-wallet? (reagent/atom false))
|
||||
(def load-new-wallet? (reagent/atom true))
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
[status-im2.contexts.syncing.utils :as sync-utils]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]
|
||||
[utils.transforms :as transforms]))
|
||||
|
||||
(rf/defn local-pairing-update-role
|
||||
@@ -97,7 +96,7 @@
|
||||
|
||||
(rf/defn preparations-for-connection-string
|
||||
{:events [:syncing/get-connection-string]}
|
||||
[{:keys [db] :as cofx} entered-password on-valid-connection-string]
|
||||
[{:keys [db] :as cofx} sha3-pwd on-valid-connection-string]
|
||||
(let [error (get-in db [:profile/login :error])
|
||||
handle-connection (fn [response]
|
||||
(when (sync-utils/valid-connection-string? response)
|
||||
@@ -105,8 +104,7 @@
|
||||
(rf/dispatch [:syncing/update-role constants/local-pairing-role-sender])
|
||||
(rf/dispatch [:hide-bottom-sheet])))]
|
||||
(when-not (and error (string/blank? error))
|
||||
(let [key-uid (get-in db [:profile/login :key-uid])
|
||||
sha3-pwd (native-module/sha3 (str (security/safe-unmask-data entered-password)))
|
||||
(let [key-uid (get-in db [:profile/profile :key-uid])
|
||||
config-map (.stringify js/JSON
|
||||
(clj->js {:senderConfig {:keyUID key-uid
|
||||
:keystorePath ""
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
(reset! code nil)
|
||||
(reset! timestamp nil)
|
||||
(reset! valid-for-ms code-valid-for-ms))
|
||||
on-enter-password (fn [entered-password]
|
||||
on-auth-success (fn [entered-password]
|
||||
(rf/dispatch [:syncing/get-connection-string entered-password
|
||||
set-code]))]
|
||||
(fn []
|
||||
@@ -124,8 +124,7 @@
|
||||
:size :size-40
|
||||
:track-text (i18n/label :t/slide-to-reveal-code)
|
||||
:customization-color customization-color
|
||||
:on-enter-password on-enter-password
|
||||
:biometric-auth? false
|
||||
:on-auth-success on-auth-success
|
||||
:auth-button-label (i18n/label :t/reveal-sync-code)
|
||||
:auth-button-icon-left :i/reveal}]])]]
|
||||
[rn/view {:style style/sync-code}
|
||||
|
||||
@@ -43,8 +43,8 @@
|
||||
:bottom-action-props {:customization-color @account-color
|
||||
:disabled? (string/blank? @account-name)
|
||||
:on-press #(rf/dispatch [:wallet/add-account
|
||||
nil
|
||||
{:type :watch
|
||||
{:sha3-pwd nil
|
||||
:type :watch
|
||||
:account-name @account-name
|
||||
:emoji @account-emoji
|
||||
:color @account-color}
|
||||
|
||||
@@ -107,3 +107,7 @@
|
||||
:networks networks-list
|
||||
:state :default
|
||||
:customization-color :blue}])
|
||||
|
||||
(def secret-phrase
|
||||
["witch" "collapse" "practice" "feed" "shame" "open" "lion"
|
||||
"collapse" "umbrella" "fabric" "sadness" "obligue"])
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
(defn get-derivation-path
|
||||
[number-of-accounts]
|
||||
(str constants/path-wallet-root "/" number-of-accounts))
|
||||
|
||||
(defn format-derivation-path
|
||||
[path]
|
||||
(string/replace path "/" " / "))
|
||||
@@ -43,12 +44,15 @@
|
||||
(when balance-in-chain
|
||||
(calculate-raw-balance (:raw-balance balance-in-chain) decimals))))
|
||||
|
||||
(defn calculate-balance-for-token
|
||||
[token]
|
||||
(* (total-token-value-in-all-chains token)
|
||||
(-> token :market-values-per-currency :usd :price)))
|
||||
|
||||
(defn calculate-balance
|
||||
[tokens-in-account]
|
||||
(->> tokens-in-account
|
||||
(map (fn [token]
|
||||
(* (total-token-value-in-all-chains token)
|
||||
(-> token :market-values-per-currency :usd :price))))
|
||||
(map #(calculate-balance-for-token %))
|
||||
(reduce +)))
|
||||
|
||||
(defn network-list
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
(ns status-im2.contexts.wallet.create-account.backup-recovery-phrase.style
|
||||
(:require
|
||||
[quo.foundations.colors :as colors]
|
||||
[quo.theme :as quo.theme]
|
||||
[react-native.platform :as platform]))
|
||||
|
||||
(def header-container
|
||||
{:margin-horizontal 20
|
||||
:margin-vertical 12})
|
||||
|
||||
(defn seed-phrase-container
|
||||
[theme]
|
||||
{:margin-horizontal 20
|
||||
:padding-horizontal 12
|
||||
:border-width 1
|
||||
:border-color (colors/theme-colors colors/neutral-10 colors/neutral-80 theme)
|
||||
:border-radius 16
|
||||
:background-color (colors/theme-colors colors/white colors/neutral-80-opa-40 theme)
|
||||
:flex-direction :row})
|
||||
|
||||
(def word-item
|
||||
{:align-items :center
|
||||
:flex-direction :row})
|
||||
|
||||
(defn separator
|
||||
[theme]
|
||||
{:margin-vertical 12
|
||||
:margin-horizontal 12
|
||||
:border-width (when platform/ios? 1)
|
||||
:border-right-width (when platform/android? 1)
|
||||
:border-color (colors/theme-colors colors/neutral-10 colors/neutral-80 theme)
|
||||
:border-style :dashed})
|
||||
|
||||
(def step-item
|
||||
{:flex-direction :row
|
||||
:margin-vertical 8
|
||||
:align-items :center})
|
||||
|
||||
(def blur-container
|
||||
{:position :absolute
|
||||
:left 0
|
||||
:right 0
|
||||
:top 0
|
||||
:bottom 0
|
||||
:border-radius 16
|
||||
:overflow :hidden})
|
||||
|
||||
(defn blur
|
||||
[theme]
|
||||
{:style {:flex 1}
|
||||
:blur-radius 20
|
||||
:blur-type (quo.theme/theme-value :light :dark theme)
|
||||
:blur-amount 20})
|
||||
|
||||
(def slide-button
|
||||
{:position :absolute
|
||||
:bottom 12
|
||||
:left 0
|
||||
:right 0})
|
||||
|
||||
(defn description-text
|
||||
[theme]
|
||||
{:margin-horizontal 40
|
||||
:text-align :center
|
||||
:color (colors/theme-colors colors/neutral-80-opa-70 colors/white-opa-70 theme)})
|
||||
@@ -0,0 +1,95 @@
|
||||
(ns status-im2.contexts.wallet.create-account.backup-recovery-phrase.view
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[quo.theme :as quo.theme]
|
||||
[react-native.blur :as blur]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[status-im2.contexts.wallet.common.temp :as temp]
|
||||
[status-im2.contexts.wallet.create-account.backup-recovery-phrase.style :as style]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- word-item
|
||||
[item index _ increment]
|
||||
[rn/view {:style style/word-item}
|
||||
[quo/counter {:type :grey} (+ index increment)]
|
||||
[quo/text {:style {:margin-left 4}} item]])
|
||||
|
||||
(defn- words-column
|
||||
[words first-half?]
|
||||
[rn/flat-list
|
||||
{:style {:padding-vertical 8}
|
||||
:data (if first-half? (subvec words 0 6) (subvec words 6))
|
||||
:separator [rn/view {:style {:height 12}}]
|
||||
:render-fn word-item
|
||||
:render-data (if first-half? 1 7)
|
||||
:scroll-enabled false}])
|
||||
|
||||
(defn- step-item
|
||||
[item index _ checked?]
|
||||
[rn/view {:style style/step-item}
|
||||
[quo/selectors
|
||||
{:type :checkbox
|
||||
:on-change #(swap! checked? assoc (keyword (str index)) %)}]
|
||||
[quo/text {:style {:margin-left 12}} (i18n/label item)]])
|
||||
|
||||
(defn- view-internal
|
||||
[{:keys [theme]}]
|
||||
(let [step-labels [:t/backup-step-1 :t/backup-step-2 :t/backup-step-3
|
||||
:t/backup-step-4]
|
||||
checked? (reagent/atom
|
||||
{:0 false
|
||||
:1 false
|
||||
:2 false
|
||||
:3 false})
|
||||
revealed? (reagent/atom false)
|
||||
{:keys [customization-color]} (rf/sub [:profile/profile])]
|
||||
(fn []
|
||||
[rn/view {:style {:flex 1}}
|
||||
[quo/page-nav
|
||||
{:icon-name :i/close
|
||||
:on-press #(rf/dispatch [:navigate-back])
|
||||
:accessibility-label :top-bar}]
|
||||
[quo/text-combinations
|
||||
{:container-style style/header-container
|
||||
:title (i18n/label :t/backup-recovery-phrase)
|
||||
:description (i18n/label :t/backup-recovery-phrase-description)}]
|
||||
[rn/view {:style (style/seed-phrase-container theme)}
|
||||
[words-column temp/secret-phrase true]
|
||||
[rn/view {:style (style/separator theme)}]
|
||||
[words-column temp/secret-phrase false]
|
||||
(when-not @revealed?
|
||||
[rn/view {:style style/blur-container}
|
||||
[blur/view (style/blur theme)]])]
|
||||
(when-not @revealed?
|
||||
[rn/view
|
||||
{:style {:padding-horizontal 20
|
||||
:padding-top 20}}
|
||||
[quo/text
|
||||
{:weight :semi-bold
|
||||
:style {:margin-bottom 8}} (i18n/label :t/how-to-backup)]
|
||||
[rn/flat-list
|
||||
{:data step-labels
|
||||
:render-fn step-item
|
||||
:render-data checked?
|
||||
:scroll-enabled false}]])
|
||||
(if @revealed?
|
||||
[rn/view {:style style/slide-button}
|
||||
[quo/bottom-actions
|
||||
{:button-one-label (i18n/label :t/i-have-written)
|
||||
:button-one-props {:disabled? (some false? (vals @checked?))
|
||||
:customization-color customization-color
|
||||
:on-press #(js/alert "To be implemented")}}]
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:style (style/description-text theme)}
|
||||
(i18n/label :t/next-you-will)]]
|
||||
[quo/bottom-actions
|
||||
{:button-one-label (i18n/label :t/reveal-phrase)
|
||||
:button-one-props {:disabled? (some false? (vals @checked?))
|
||||
:customization-color customization-color
|
||||
:on-press #(reset! revealed? true)}
|
||||
:container-style style/slide-button}])])))
|
||||
|
||||
(def view (quo.theme/with-theme view-internal))
|
||||
@@ -8,6 +8,24 @@
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn keypair-options
|
||||
[]
|
||||
[quo/action-drawer
|
||||
[[{:icon :i/add
|
||||
:accessibility-label :generate-new-keypair
|
||||
:label (i18n/label :t/generate-new-keypair)
|
||||
:on-press #(rf/dispatch [:navigate-to :wallet-backup-recovery-phrase])}
|
||||
{:icon :i/seed
|
||||
:accessibility-label :import-using-phrase
|
||||
:label (i18n/label :t/import-using-phrase)
|
||||
:add-divider? true}
|
||||
{:icon :i/keycard-card
|
||||
:accessibility-label :import-from-keycard
|
||||
:label (i18n/label :t/import-from-keycard)}
|
||||
{:icon :i/key
|
||||
:accessibility-label :import-private-key
|
||||
:label (i18n/label :t/import-private-key)}]]])
|
||||
|
||||
(def accounts
|
||||
[{:account-props {:customization-color :turquoise
|
||||
:size 32
|
||||
@@ -38,7 +56,8 @@
|
||||
:title (i18n/label :t/keypairs)
|
||||
:description (i18n/label :t/keypairs-description)
|
||||
:button-icon :i/add
|
||||
:button-on-press #(js/alert "not implemented")
|
||||
:button-on-press #(rf/dispatch [:show-bottom-sheet
|
||||
{:content keypair-options}])
|
||||
:customization-color customization-color}]
|
||||
[quo/keypair
|
||||
(merge
|
||||
|
||||
@@ -118,14 +118,14 @@
|
||||
{:size :size-48
|
||||
:track-text (i18n/label :t/slide-to-create-account)
|
||||
:customization-color @account-color
|
||||
:on-enter-password (fn [entered-password]
|
||||
:on-auth-success (fn [entered-password]
|
||||
(prn entered-password)
|
||||
(rf/dispatch [:wallet/derive-address-and-add-account
|
||||
entered-password
|
||||
{:emoji @emoji
|
||||
{:sha3-pwd entered-password
|
||||
:emoji @emoji
|
||||
:color @account-color
|
||||
:path @derivation-path
|
||||
:account-name @account-name}]))
|
||||
:biometric-auth? false
|
||||
:auth-button-label (i18n/label :t/confirm)
|
||||
:container-style (style/slide-button-container bottom)}]])))
|
||||
|
||||
|
||||
@@ -3,17 +3,17 @@
|
||||
[camel-snake-kebab.core :as csk]
|
||||
[camel-snake-kebab.extras :as cske]
|
||||
[clojure.string :as string]
|
||||
[native-module.core :as native-module]
|
||||
[quo.foundations.colors :as colors]
|
||||
[react-native.background-timer :as background-timer]
|
||||
[status-im2.common.data-store.wallet :as data-store]
|
||||
[status-im2.contexts.wallet.item-types :as item-types]
|
||||
[status-im2.contexts.wallet.temp :as temp]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.ethereum.chain :as chain]
|
||||
[utils.ethereum.eip.eip55 :as eip55]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.number]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]
|
||||
[utils.transforms :as types]))
|
||||
|
||||
(rf/reg-event-fx :wallet/show-account-created-toast
|
||||
@@ -141,9 +141,8 @@
|
||||
{:db (dissoc db :wallet/scanned-address :wallet/send-address)})
|
||||
|
||||
(rf/reg-event-fx :wallet/create-derived-addresses
|
||||
(fn [{:keys [db]} [password {:keys [path]} on-success]]
|
||||
(let [{:keys [wallet-root-address]} (:profile/profile db)
|
||||
sha3-pwd (native-module/sha3 (str (security/safe-unmask-data password)))]
|
||||
(fn [{:keys [db]} [{:keys [sha3-pwd path]} on-success]]
|
||||
(let [{:keys [wallet-root-address]} (:profile/profile db)]
|
||||
{:fx [[:json-rpc/call
|
||||
[{:method "wallet_getDerivedAddresses"
|
||||
:params [sha3-pwd wallet-root-address [path]]
|
||||
@@ -160,11 +159,10 @@
|
||||
|
||||
(rf/reg-event-fx :wallet/add-account
|
||||
(fn [{:keys [db]}
|
||||
[password {:keys [emoji account-name color type] :or {type :generated}}
|
||||
[{:keys [sha3-pwd emoji account-name color type] :or {type :generated}}
|
||||
{:keys [public-key address path]}]]
|
||||
(let [lowercase-address (if address (string/lower-case address) address)
|
||||
key-uid (get-in db [:profile/profile :key-uid])
|
||||
sha3-pwd (native-module/sha3 (security/safe-unmask-data password))
|
||||
account-config {:key-uid (when (= type :generated) key-uid)
|
||||
:wallet false
|
||||
:chat false
|
||||
@@ -183,11 +181,11 @@
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/derive-address-and-add-account
|
||||
(fn [_ [password account-details]]
|
||||
(fn [_ [account-details]]
|
||||
(let [on-success (fn [derived-address-details]
|
||||
(rf/dispatch [:wallet/add-account password account-details
|
||||
(rf/dispatch [:wallet/add-account account-details
|
||||
(first derived-address-details)]))]
|
||||
{:fx [[:dispatch [:wallet/create-derived-addresses password account-details on-success]]]})))
|
||||
{:fx [[:dispatch [:wallet/create-derived-addresses account-details on-success]]]})))
|
||||
|
||||
(rf/defn get-ethereum-chains
|
||||
{:events [:wallet/get-ethereum-chains]}
|
||||
@@ -327,6 +325,45 @@
|
||||
{:event :wallet/get-collectible-details-done
|
||||
:response response})))))
|
||||
|
||||
(rf/reg-event-fx :wallet/find-ens
|
||||
(fn [{:keys [db]} [input contacts chain-id cb]]
|
||||
(let [result (if (empty? input)
|
||||
[]
|
||||
(filter #(string/starts-with? (or (:ens-name %) "") input) contacts))]
|
||||
(if (and input (empty? result))
|
||||
(rf/dispatch [:wallet/search-ens input chain-id cb ".stateofus.eth"])
|
||||
{:db (assoc db
|
||||
:wallet/local-suggestions
|
||||
(map #(assoc % :type item-types/saved-address) result)
|
||||
:wallet/valid-ens-or-address? (not-empty result))}))))
|
||||
|
||||
(rf/reg-event-fx :wallet/search-ens
|
||||
(fn [_ [input chain-id cb domain]]
|
||||
(let [ens (if (string/includes? input ".") input (str input domain))]
|
||||
{:fx [[:json-rpc/call
|
||||
[{:method "ens_addressOf"
|
||||
:params [chain-id ens]
|
||||
:on-success #(rf/dispatch [:wallet/set-ens-address % ens])
|
||||
:on-error (fn []
|
||||
(if (= domain ".stateofus.eth")
|
||||
(rf/dispatch [:wallet/search-ens input chain-id cb ".eth"])
|
||||
(do
|
||||
(rf/dispatch [:wallet/set-ens-address nil ens])
|
||||
(cb))))}]]]})))
|
||||
|
||||
(rf/reg-event-fx :wallet/set-ens-address
|
||||
(fn [{:keys [db]} [result ens]]
|
||||
{:db (assoc db
|
||||
:wallet/local-suggestions (if result
|
||||
[{:type item-types/address
|
||||
:ens ens
|
||||
:address (eip55/address->checksum result)
|
||||
:networks [:ethereum :optimism]}]
|
||||
[])
|
||||
:wallet/valid-ens-or-address? (boolean result))}))
|
||||
|
||||
|
||||
|
||||
(rf/reg-event-fx :wallet/fetch-address-suggestions
|
||||
(fn [{:keys [db]} [address]]
|
||||
{:db (assoc db
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
(ns status-im2.contexts.wallet.events-test
|
||||
(:require
|
||||
[cljs.test :refer-macros [deftest is testing]]
|
||||
matcher-combinators.test
|
||||
[status-im2.contexts.wallet.events :as events]))
|
||||
|
||||
(def address "0x2f88d65f3cb52605a54a833ae118fb1363acccd2")
|
||||
@@ -11,7 +12,7 @@
|
||||
(let [expected-db {:wallet/scanned-address address}
|
||||
effects (events/scan-address-success {:db db} address)
|
||||
result-db (:db effects)]
|
||||
(is (= result-db expected-db))))))
|
||||
(is (match? result-db expected-db))))))
|
||||
|
||||
(deftest clean-scanned-address
|
||||
(let [db {:wallet/scanned-address address}]
|
||||
@@ -19,7 +20,7 @@
|
||||
(let [expected-db {}
|
||||
effects (events/clean-scanned-address {:db db})
|
||||
result-db (:db effects)]
|
||||
(is (= result-db expected-db))))))
|
||||
(is (match? result-db expected-db))))))
|
||||
|
||||
(deftest store-collectibles
|
||||
(testing "(displayable-collectible?) helper function"
|
||||
@@ -34,7 +35,8 @@
|
||||
[false {:collectible-data {:image-url nil :animation-url ""}}]
|
||||
[false {:collectible-data {:image-url "" :animation-url ""}}]]]
|
||||
(doseq [[result collection] expected-results]
|
||||
(is (= result (events/displayable-collectible? collection))))))
|
||||
(is (match? result (events/displayable-collectible? collection))))))
|
||||
|
||||
(testing "save-collectibles-request-details"
|
||||
(let [db {:wallet {}}
|
||||
collectibles [{:collectible-data {:image-url "https://..." :animation-url "https://..."}}
|
||||
@@ -46,7 +48,7 @@
|
||||
{:image-url "" :animation-url "https://..."}}]}}
|
||||
effects (events/store-collectibles {:db db} [collectibles])
|
||||
result-db (:db effects)]
|
||||
(is (= result-db expected-db)))))
|
||||
(is (match? result-db expected-db)))))
|
||||
|
||||
(deftest clear-stored-collectibles
|
||||
(let [db {:wallet {:collectibles [{:id 1} {:id 2}]}}]
|
||||
@@ -54,7 +56,7 @@
|
||||
(let [expected-db {:wallet {}}
|
||||
effects (events/clear-stored-collectibles {:db db})
|
||||
result-db (:db effects)]
|
||||
(is (= result-db expected-db))))))
|
||||
(is (match? result-db expected-db))))))
|
||||
|
||||
(deftest store-last-collectible-details
|
||||
(testing "store-last-collectible-details"
|
||||
@@ -65,4 +67,4 @@
|
||||
:image-url "https://..."}}}
|
||||
effects (events/store-last-collectible-details {:db db} [last-collectible])
|
||||
result-db (:db effects)]
|
||||
(is (= result-db expected-db)))))
|
||||
(is (match? result-db expected-db)))))
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
(ns status-im2.contexts.wallet.send.events
|
||||
(:require
|
||||
[native-module.core :as native-module]
|
||||
[status-im2.constants :as constants]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.datetime :as datetime]
|
||||
[utils.money :as money]
|
||||
[utils.number]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
|
||||
(rf/reg-event-fx :wallet/suggested-routes-success
|
||||
(fn [{:keys [db]} [suggested-routes timestamp]]
|
||||
(when (= (get-in db [:wallet :ui :send :suggested-routes-call-timestamp]) timestamp)
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet :ui :send :suggested-routes] suggested-routes)
|
||||
(assoc-in [:wallet :ui :send :route] (first (:Best suggested-routes)))
|
||||
(assoc-in [:wallet :ui :send :loading-suggested-routes?] false))})))
|
||||
|
||||
(rf/reg-event-fx :wallet/suggested-routes-error
|
||||
(fn [{:keys [db]} [_error]]
|
||||
{:db (-> db
|
||||
(update-in [:wallet :ui :send] dissoc :suggested-routes)
|
||||
(update-in [:wallet :ui :send] dissoc :route)
|
||||
(assoc-in [:wallet :ui :send :loading-suggested-routes?] false))}))
|
||||
|
||||
(rf/reg-event-fx :wallet/clean-suggested-routes
|
||||
(fn [{:keys [db]}]
|
||||
{:db (-> db
|
||||
(update-in [:wallet :ui :send] dissoc :suggested-routes)
|
||||
(update-in [:wallet :ui :send] dissoc :route)
|
||||
(update-in [:wallet :ui :send] dissoc :loading-suggested-routes?))}))
|
||||
|
||||
(rf/reg-event-fx :wallet/select-send-address
|
||||
(fn [{:keys [db]} [address]]
|
||||
{:db (assoc-in db [:wallet :ui :send :to-address] address)}))
|
||||
|
||||
(rf/reg-event-fx :wallet/send-select-token
|
||||
(fn [{:keys [db]} [token stack-id]]
|
||||
{:db (assoc-in db [:wallet :ui :send :token] token)
|
||||
:fx [[:navigate-to-within-stack [:wallet-send-input-amount stack-id]]]}))
|
||||
|
||||
(rf/reg-event-fx :wallet/send-select-amount
|
||||
(fn [{:keys [db]} [amount stack-id]]
|
||||
{:db (assoc-in db [:wallet :ui :send :amount] amount)
|
||||
:fx [[:navigate-to-within-stack [:wallet-transaction-confirmation stack-id]]]}))
|
||||
|
||||
(rf/reg-event-fx :wallet/get-suggested-routes
|
||||
(fn [{:keys [db]} [amount]]
|
||||
(let [wallet-address (get-in db [:wallet :current-viewing-account-address])
|
||||
token (get-in db [:wallet :ui :send :token])
|
||||
to-address (get-in db [:wallet :ui :send :to-address])
|
||||
token-decimal (:decimals token)
|
||||
token-id (:symbol token)
|
||||
network-preferences [constants/mainnet-chain-id]
|
||||
gas-rates constants/gas-rate-low
|
||||
amount-in (money/mul (money/bignumber amount)
|
||||
(money/from-decimal token-decimal))
|
||||
from-address wallet-address
|
||||
request-params [constants/send-type-transfer
|
||||
from-address
|
||||
to-address
|
||||
(money/to-hex amount-in)
|
||||
token-id
|
||||
[]
|
||||
[]
|
||||
network-preferences
|
||||
gas-rates
|
||||
{}]
|
||||
timestamp (datetime/timestamp)]
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet :ui :send :loading-suggested-routes?] true)
|
||||
(assoc-in [:wallet :ui :send :suggested-routes-call-timestamp]
|
||||
timestamp))
|
||||
:json-rpc/call [{:method "wallet_getSuggestedRoutes"
|
||||
:params request-params
|
||||
:on-success (fn [suggested-routes]
|
||||
(rf/dispatch [:wallet/suggested-routes-success suggested-routes
|
||||
timestamp]))
|
||||
:on-error (fn [error]
|
||||
(rf/dispatch [:wallet/suggested-routes-error error])
|
||||
(log/error "failed to get suggested routes"
|
||||
{:event :wallet/get-suggested-routes
|
||||
:error error
|
||||
:params request-params}))}]})))
|
||||
|
||||
(rf/reg-event-fx :wallet/send-transaction
|
||||
(fn [{:keys [db]} [password]]
|
||||
(let [route (get-in db [:wallet :ui :send :route])
|
||||
from-address (get-in db [:wallet :current-viewing-account-address])
|
||||
to-address (get-in db [:wallet :ui :send :to-address])
|
||||
from (:From route)
|
||||
token (get-in db [:wallet :ui :send :token])
|
||||
token-id (:symbol token)
|
||||
from-asset token-id
|
||||
to-asset token-id
|
||||
bridge-name (:BridgeName route)
|
||||
chain-id (:chainId from)
|
||||
multi-transaction-command {:fromAddress from-address
|
||||
:toAddress to-address
|
||||
:fromAsset from-asset
|
||||
:toAsset to-asset
|
||||
:fromAmount (:AmountOut route)
|
||||
:type 0}
|
||||
transaction-bridge
|
||||
[{:BridgeName bridge-name
|
||||
:ChainID chain-id
|
||||
:TransferTx {:From from-address
|
||||
:To to-address
|
||||
:Gas (money/to-hex (:GasAmount route))
|
||||
:GasPrice (money/to-hex (money/->wei :gwei
|
||||
(:gasPrice (:GasFees route))))
|
||||
:Value (:AmountOut route)
|
||||
:Nonce nil
|
||||
:MaxFeePerGas (money/to-hex
|
||||
(money/->wei :gwei
|
||||
(:maxFeePerGasMedium (:GasFees route))))
|
||||
:MaxPriorityFeePerGas (money/to-hex (money/->wei :gwei
|
||||
(:maxPriorityFeePerGas
|
||||
(:GasFees
|
||||
route))))
|
||||
:Input ""
|
||||
:Data "0x"}}]
|
||||
sha3-pwd (native-module/sha3 (str (security/safe-unmask-data password)))
|
||||
request-params [multi-transaction-command transaction-bridge sha3-pwd]]
|
||||
{:json-rpc/call [{:method "wallet_createMultiTransaction"
|
||||
:params request-params
|
||||
:on-success #(rf/dispatch [:dismiss-modal :wallet-select-address])
|
||||
:on-error (fn [error]
|
||||
(log/error "failed to send transaction"
|
||||
{:event :wallet/send-transaction
|
||||
:error error
|
||||
:params request-params}))}]})))
|
||||
@@ -17,7 +17,13 @@
|
||||
:short-name "eth"
|
||||
:network-name :ethereum
|
||||
:chain-id 1
|
||||
:related-chain-id 5}]})
|
||||
:related-chain-id 5}]
|
||||
:wallet {:ui {:send {:token {:symbol "ETH"
|
||||
:decimals 18
|
||||
:total-balance 1
|
||||
:total-balance-fiat 10
|
||||
:loading-suggested-routes? false
|
||||
:route {}}}}}})
|
||||
|
||||
(h/describe "Send > input amount screen"
|
||||
(h/test "Default render"
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
[react-native.safe-area :as safe-area]
|
||||
[reagent.core :as reagent]
|
||||
[status-im2.contexts.wallet.send.input-amount.style :as style]
|
||||
[utils.debounce :as debounce]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
@@ -47,71 +48,88 @@
|
||||
current))
|
||||
|
||||
(defn- f-view-internal
|
||||
[{:keys [token limit rate]}]
|
||||
(let [bottom (safe-area/get-bottom)
|
||||
{:keys [currency]} (rf/sub [:profile/profile])
|
||||
networks (rf/sub [:wallet/network-details])
|
||||
;; Temporary values
|
||||
token (or token :eth)
|
||||
conversion-rate (or rate 10)
|
||||
limit-crypto (or limit 2860000.32)
|
||||
limit-fiat (* limit-crypto conversion-rate)
|
||||
input-value (reagent/atom "")
|
||||
current-limit (reagent/atom {:amount limit-crypto
|
||||
:currency token})
|
||||
handle-swap (fn [crypto?]
|
||||
(let [num-value (parse-double @input-value)]
|
||||
(reset! current-limit (if crypto?
|
||||
{:amount limit-crypto
|
||||
:currency token}
|
||||
{:amount limit-fiat
|
||||
:currency currency}))
|
||||
(when (> num-value (:amount @current-limit))
|
||||
(reset! input-value ""))))
|
||||
handle-keyboard-press (fn [v]
|
||||
(let [current-value @input-value
|
||||
new-value (make-new-input current-value v)
|
||||
num-value (or (parse-double new-value) 0)]
|
||||
(when (<= num-value (:amount @current-limit))
|
||||
(reset! input-value new-value)
|
||||
(reagent/flush))))
|
||||
handle-delete (fn [_]
|
||||
(swap! input-value #(subs % 0 (dec (count %))))
|
||||
(reagent/flush))
|
||||
handle-on-change (fn [v]
|
||||
(when (valid-input? @input-value v)
|
||||
(let [num-value (or (parse-double v) 0)
|
||||
current-limit-amount (:amount @current-limit)]
|
||||
(if (> num-value current-limit-amount)
|
||||
(reset! input-value (str current-limit-amount))
|
||||
(reset! input-value v))
|
||||
(reagent/flush))))]
|
||||
[{:keys [rate]}]
|
||||
(let [bottom (safe-area/get-bottom)
|
||||
{:keys [currency]} (rf/sub [:profile/profile])
|
||||
networks (rf/sub [:wallet/network-details])
|
||||
wallet-send (get-in (rf/sub [:wallet]) [:ui :send])
|
||||
token (:token wallet-send)
|
||||
token-symbol (:symbol token)
|
||||
limit-crypto (:total-balance token)
|
||||
limit-fiat (:total-balance-fiat token)
|
||||
conversion-rate (or rate 10)
|
||||
input-value (reagent/atom "")
|
||||
current-limit (reagent/atom {:amount limit-crypto
|
||||
:currency token-symbol})
|
||||
loading-suggested-routes? (:loading-suggested-routes? wallet-send)
|
||||
handle-swap (fn [crypto?]
|
||||
(let [num-value (parse-double @input-value)]
|
||||
(reset! current-limit (if crypto?
|
||||
{:amount limit-crypto
|
||||
:currency token-symbol}
|
||||
{:amount limit-fiat
|
||||
:currency currency}))
|
||||
(when (> num-value (:amount @current-limit))
|
||||
(reset! input-value ""))))
|
||||
handle-keyboard-press (fn [v]
|
||||
(let [current-value @input-value
|
||||
new-value (make-new-input current-value v)
|
||||
num-value (or (parse-double new-value) 0)]
|
||||
(when (and (not loading-suggested-routes?)
|
||||
(<= num-value (:amount @current-limit)))
|
||||
(reset! input-value new-value)
|
||||
(reagent/flush))))
|
||||
handle-delete (fn [_]
|
||||
(when-not loading-suggested-routes?
|
||||
(swap! input-value #(subs % 0 (dec (count %))))
|
||||
(reagent/flush)))
|
||||
handle-on-change (fn [v]
|
||||
(when (valid-input? @input-value v)
|
||||
(let [num-value (or (parse-double v) 0)
|
||||
current-limit-amount (:amount @current-limit)]
|
||||
(if (> num-value current-limit-amount)
|
||||
(reset! input-value (str current-limit-amount))
|
||||
(reset! input-value v))
|
||||
(reagent/flush))))]
|
||||
(fn [{:keys [on-confirm]
|
||||
:or {on-confirm #(js/alert "Confirmed")}}]
|
||||
(let [limit-label (make-limit-label @current-limit)
|
||||
input-num-value (parse-double @input-value)
|
||||
confirm-disabled? (or
|
||||
(empty? @input-value)
|
||||
(<= input-num-value 0)
|
||||
(> input-num-value (:amount @current-limit)))]
|
||||
:or {on-confirm #(rf/dispatch [:wallet/send-select-amount @input-value
|
||||
:wallet-send-input-amount])}}]
|
||||
(let [limit-label (make-limit-label @current-limit)
|
||||
input-num-value (parse-double @input-value)
|
||||
route (get-in (rf/sub [:wallet]) [:ui :send :route])
|
||||
loading-suggested-routes? (get-in (rf/sub [:wallet]) [:ui :send :loading-suggested-routes?])
|
||||
confirm-disabled? (or
|
||||
(nil? route)
|
||||
(empty? @input-value)
|
||||
(<= input-num-value 0)
|
||||
(> input-num-value (:amount @current-limit)))]
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(let [dismiss-keyboard-fn #(when (= % "active") (rn/dismiss-keyboard!))
|
||||
app-keyboard-listener (.addEventListener rn/app-state "change" dismiss-keyboard-fn)]
|
||||
#(.remove app-keyboard-listener))))
|
||||
(rn/use-effect (fn []
|
||||
(rf/dispatch [:wallet/clean-suggested-routes])
|
||||
(when-not (or
|
||||
(empty? @input-value)
|
||||
(<= input-num-value 0)
|
||||
(> input-num-value (:amount @current-limit)))
|
||||
(debounce/debounce-and-dispatch [:wallet/get-suggested-routes @input-value]
|
||||
100)))
|
||||
[@input-value])
|
||||
[rn/view
|
||||
{:style style/screen}
|
||||
[quo/page-nav
|
||||
{:background :blur
|
||||
:icon-name :i/arrow-left
|
||||
:on-press #(rf/dispatch [:navigate-back])
|
||||
:on-press #(rf/dispatch [:navigate-back-within-stack :wallet-send-input-amount])
|
||||
:right-side :account-switcher
|
||||
:account-switcher {:customization-color :yellow
|
||||
:emoji "🎮"
|
||||
:on-press #(js/alert "Switch account")}}]
|
||||
[quo/token-input
|
||||
{:container-style style/input-container
|
||||
:token token
|
||||
:token token-symbol
|
||||
:currency currency
|
||||
:networks networks
|
||||
:title (i18n/label :t/send-limit {:limit limit-label})
|
||||
@@ -122,7 +140,16 @@
|
||||
:on-change-text (fn [text]
|
||||
(handle-on-change text))}]
|
||||
;; Network routing content to be added
|
||||
[rn/scroll-view]
|
||||
[rn/scroll-view
|
||||
{:content-container-style {:flex-grow 1
|
||||
:align-items :center
|
||||
:justify-content :center}}
|
||||
(cond loading-suggested-routes?
|
||||
[quo/text "Loading routes"]
|
||||
(and (not loading-suggested-routes?) route)
|
||||
[quo/text "Route found"]
|
||||
(and (not loading-suggested-routes?) (nil? route))
|
||||
[quo/text "Route not found"])]
|
||||
[quo/bottom-actions
|
||||
{:actions :1-action
|
||||
:button-one-label (i18n/label :t/confirm)
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
(ns status-im2.contexts.wallet.send.select-address.style)
|
||||
|
||||
(defn container
|
||||
[margin-top]
|
||||
{:flex 1
|
||||
:margin-top margin-top})
|
||||
(def container
|
||||
{:flex 1})
|
||||
|
||||
(def title-container
|
||||
{:margin-horizontal 20
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user