Compare commits

..
74 changed files with 505 additions and 1661 deletions
+1
View File
@@ -51,6 +51,7 @@ in {
};
# Package version adjustments
gradle = super.gradle_8.override { java = super.openjdk17_headless; };
nodejs = super.nodejs_20;
ruby = super.ruby_3_1;
yarn = super.yarn.override { nodejs = super.nodejs_20; };
+2 -18
View File
@@ -6,16 +6,8 @@ let
# For testing local version of nixpkgs
#nixpkgsSrc = (import <nixpkgs> { }).lib.cleanSource "/home/jakubgs/work/nixpkgs";
# We follow release 24-05 of nixpkgs
# https://github.com/NixOS/nixpkgs/releases/tag/24.05
nixpkgsSrc = builtins.fetchTarball {
url = "https://github.com/NixOS/nixpkgs/archive/df27247e6f3e636c119e2610bf12d38b5e98cc79.tar.gz";
sha256 = "sha256:0bbvimk7xb7akrx106mmsiwf9nzxnssisqmqffla03zz51d0kz2n";
};
# FIXME: remove this additional source when nixpkgs includes gradle 8.8 in stable channel
# We use a commit from the unstable channel of nixpkgs for gradle 8.8
gradleNixpkgsSrc = builtins.fetchTarball {
nixpkgsSrc = builtins.fetchTarball {
url = "https://github.com/NixOS/nixpkgs/archive/48d567fc7b299de90f70a48e4263e31f690ba03e.tar.gz";
sha256 = "sha256:0zynbk52khdfhg4qfv26h3r5156xff5p0cga2cin7b07i7lqminh";
};
@@ -29,14 +21,6 @@ let
# Override some packages and utilities
pkgsOverlay = import ./overlay.nix;
# FIXME: remove this additional source when nixpkgs includes gradle 8.8 in stable channel
gradleOverlay = final: prev: {
gradle = (import gradleNixpkgsSrc {
inherit (prev) system;
config = defaultConfig // config;
}).gradle_8.override { java = prev.openjdk17_headless; };
};
# Fix for lack of Android SDK for M1 Macs.
systemOverride = let
inherit (builtins) currentSystem getEnv;
@@ -51,5 +35,5 @@ in
(import nixpkgsSrc) {
config = defaultConfig // config;
system = systemOverride;
overlays = [ pkgsOverlay gradleOverlay ];
overlays = [ pkgsOverlay ];
}
+3 -3
View File
@@ -180,17 +180,17 @@
},
"shards.staging": {
"tcp/p2p/waku/boot": {
"boot-01.do-ams3.shards.staging": "/dns4/boot-01.do-ams3.shards.staging.status.im/tcp/30303/p2p/16Uiu2HAmQE7FXQc6iZHdBzYfw3qCSDa9dLc1wsBJKoP4aZvztq2d",
"boot-01.do-ams3.shards.staging": "/dns4/boot-01.do-ams3.shards.staging.status.im/tcp/30303/p2p/16Uiu2HAmEqqio4UR1SWqAc7KY19t6qyDvtmyjreZpzUBJvb4u65R",
"boot-01.gc-us-central1-a.shards.staging": "/dns4/boot-01.gc-us-central1-a.shards.staging.status.im/tcp/30303/p2p/16Uiu2HAmGAA54bBTE78MYidSy3P7Q9yAWFNTAEReJYD69VRvtL5r",
"boot-01.ac-cn-hongkong-c.shards.staging": "/dns4/boot-01.ac-cn-hongkong-c.shards.staging.status.im/tcp/30303/p2p/16Uiu2HAmNTpGnyZ8W1BK2sXEmgSCNWiyDKgRU3NBR2DXST2HzxRU"
},
"enr/p2p/waku/boot": {
"boot-01.do-ams3.shards.staging": "enr:-QEQuEBuiQgFlJNcv255042zwyl4pOBOivakX8N30Dr9vaaEU2q8-7N4GVY4Hk87iEKELjlIXTpE9Wj6EQq1lrBuc7ayAYJpZIJ2NIJpcISPxvrpim11bHRpYWRkcnO4YAAtNihib290LTAxLmRvLWFtczMuc3RhdHVzLnN0YWdpbmcuc3RhdHVzLmltBnZfAC82KGJvb3QtMDEuZG8tYW1zMy5zdGF0dXMuc3RhZ2luZy5zdGF0dXMuaW0GAbveA4Jyc40AEAUAAQAgAEAAgAEAiXNlY3AyNTZrMaEDq-yGgpuoUG6NKkbIDRmrMiT-bEVzFlpWLEK_rF3yKUaDdGNwgnZfg3VkcIIjKIV3YWt1Mg0",
"boot-01.do-ams3.shards.staging": "enr:-QEQuEDsh6FgAb_36cReaX7W4gWx_7_GNpsUki7bXMoMrrrWij5pDEyV3guR-urDW_6GJTAzpQiJV61F-CfNn_NxPbY-AYJpZIJ2NIJpcISPxvrpim11bHRpYWRkcnO4YAAtNihib290LTAxLmRvLWFtczMuc2hhcmRzLnN0YWdpbmcuc3RhdHVzLmltBnZfAC82KGJvb3QtMDEuZG8tYW1zMy5zaGFyZHMuc3RhZ2luZy5zdGF0dXMuaW0GAbveA4Jyc40AEAUAAQAgAEAAgAEAiXNlY3AyNTZrMaEDIH8BcuEzgnmwPQTu7BPYyg4u4om7K9qekKA2gT_H2wSDdGNwgnZfg3VkcIIjKIV3YWt1Mg0",
"boot-01.gc-us-central1-a.shards.staging": "enr:-QEiuECWCuk1CoefbPYUV_cff27t-471k_QhJ_MvgOUQmRE4vgI6h9fD4LgXy7TZNSFXeBBP9haWJB7lx8Wujx-LPmhrAYJpZIJ2NIJpcIRoxQVgim11bHRpYWRkcnO4cgA2NjFib290LTAxLmdjLXVzLWNlbnRyYWwxLWEuc2hhcmRzLnN0YWdpbmcuc3RhdHVzLmltBnZfADg2MWJvb3QtMDEuZ2MtdXMtY2VudHJhbDEtYS5zaGFyZHMuc3RhZ2luZy5zdGF0dXMuaW0GAbveA4Jyc40AEAUAAQAgAEAAgAEAiXNlY3AyNTZrMaEDNAvlGjekD1YV4WpmjwArGAH2g9kHFJnMRfgUhcIkoA2DdGNwgnZfg3VkcIIjKIV3YWt1Mg0",
"boot-01.ac-cn-hongkong-c.shards.staging": "enr:-QEiuEAcHWW7aNBtJhigTCAnKu9-H1b98SWpBJkGm3PAxth5QjJA0kdiabOfou4HgCD6RuyZEnFE5L8ymahouw3kWRiWAYJpZIJ2NIJpcIQvTKi6im11bHRpYWRkcnO4cgA2NjFib290LTAxLmFjLWNuLWhvbmdrb25nLWMuc2hhcmRzLnN0YWdpbmcuc3RhdHVzLmltBnZfADg2MWJvb3QtMDEuYWMtY24taG9uZ2tvbmctYy5zaGFyZHMuc3RhZ2luZy5zdGF0dXMuaW0GAbveA4Jyc40AEAUAAQAgAEAAgAEAiXNlY3AyNTZrMaEDkbgV7oqPNmFtX5FzSPi9WH8kkmrPB1R3n9xRXge91M-DdGNwgnZfg3VkcIIjKIV3YWt1Mg0"
},
"wss/p2p/waku/boot": {
"boot-01.do-ams3.shards.staging": "/dns4/boot-01.do-ams3.shards.staging.status.im/tcp/443/wss/p2p/16Uiu2HAmQE7FXQc6iZHdBzYfw3qCSDa9dLc1wsBJKoP4aZvztq2d",
"boot-01.do-ams3.shards.staging": "/dns4/boot-01.do-ams3.shards.staging.status.im/tcp/443/wss/p2p/16Uiu2HAmEqqio4UR1SWqAc7KY19t6qyDvtmyjreZpzUBJvb4u65R",
"boot-01.gc-us-central1-a.shards.staging": "/dns4/boot-01.gc-us-central1-a.shards.staging.status.im/tcp/443/wss/p2p/16Uiu2HAmGAA54bBTE78MYidSy3P7Q9yAWFNTAEReJYD69VRvtL5r",
"boot-01.ac-cn-hongkong-c.shards.staging": "/dns4/boot-01.ac-cn-hongkong-c.shards.staging.status.im/tcp/443/wss/p2p/16Uiu2HAmNTpGnyZ8W1BK2sXEmgSCNWiyDKgRU3NBR2DXST2HzxRU"
},
Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

+3 -4
View File
@@ -256,10 +256,9 @@
{:events [:pairing/pair-and-sync]}
[cofx installation-id]
{:fx [[:json-rpc/call
[{:method "wakuext_enableInstallationAndSync"
:params [{:installationId installation-id}]
:js-response true
:on-success [:sanitize-messages-and-process-response]}]]]})
[{:method "wakuext_enableInstallationAndSync"
:params [{:installationId installation-id}]
:on-success #(log/debug "successfully synced devices")}]]]})
(rf/defn enable-installation-success
{:events [:pairing.callback/enable-installation-success]}
@@ -65,7 +65,7 @@
:type type
:include-button? include-button?})
style)}
[icons/icon (or icon :i/info)
[icons/icon icon
{:color (style/get-color-by-type theme type :icon)
:no-color no-icon-color?
:size (or icon-size 16)
@@ -1,7 +1,6 @@
(ns quo.components.list-items.network-list.view
(:require
[clojure.string :as string]
[quo.components.icon :as icon]
[quo.components.list-items.network-list.style :as style]
[quo.components.markdown.text :as text]
[quo.theme :as quo.theme]
@@ -43,8 +42,8 @@
[:map {:closed true}
[:network-image :int]
[:label :string]
[:fiat-value {:optional true} [:maybe :string]]
[:token-value {:optional true} [:maybe :string]]
[:fiat-value :string]
[:token-value :string]
[:container-style {:optional true} [:maybe :map]]
[:customization-color {:optional true} [:maybe :schema.common/customization-color]]
[:state {:optional true} [:enum :pressed :active :disabled :default]]
@@ -52,7 +51,7 @@
:any])
(defn- view-internal
[{:keys [fiat-value token-value on-press container-style state customization-color]
[{:keys [on-press container-style state customization-color]
:as props
:or {customization-color :blue}}]
(let [theme (quo.theme/use-theme)
@@ -68,8 +67,6 @@
:on-press (when-not (= state :disabled) on-press)
:accessibility-label :network-list}
[info props]
(if (or token-value fiat-value)
[values props]
[icon/icon :i/chevron-right])]))
[values props]]))
(def view (schema/instrument #'view-internal ?schema))
+3 -1
View File
@@ -4,10 +4,12 @@
[container-style]
(merge container-style
{:flex-direction :row
:flex 1
:align-items :flex-start}))
(def index
{:margin-left 5})
(def text-container
{:margin-left 8})
{:margin-left 8
:flex 1})
@@ -75,16 +75,3 @@
(def fiat-amount
{:color colors/neutral-50})
(def gradient-common
{:width 64
:position :absolute
:top 0
:bottom 0
:z-index 1})
(def gradient-start
(assoc gradient-common :left 0))
(def gradient-end
(assoc gradient-common :right 0))
+32 -91
View File
@@ -11,7 +11,6 @@
[quo.foundations.colors :as colors]
quo.theme
[react-native.core :as rn]
[react-native.linear-gradient :as linear-gradient]
[schema.core :as schema]))
(def ?schema
@@ -19,7 +18,6 @@
[:catn
[:props
[:map {:closed true}
[:get-ref {:optional true} [:maybe fn?]]
[:type {:optional true} [:maybe [:enum :pay :receive]]]
[:status {:optional true} [:maybe [:enum :default :typing :disabled :loading]]]
[:token {:optional true} [:maybe :string]]
@@ -44,65 +42,26 @@
[:container-style {:optional true} [:maybe :map]]]]]
:any])
(def icon-size 32)
(def container-padding (* 2 (:padding (style/row-1 false))))
(def max-cursor-position 5)
(defn view-internal
[{:keys [type status token value fiat-value show-approval-label? error? network-tag-props
approval-label-props default-value auto-focus? input-disabled? enable-swap?
currency-symbol on-change-text show-keyboard? get-ref
currency-symbol on-change-text show-keyboard?
container-style on-swap-press on-token-press on-max-press on-input-focus]}]
(let [theme (quo.theme/use-theme)
pay? (= type :pay)
disabled? (= status :disabled)
loading? (= status :loading)
typing? (= status :typing)
controlled-input? (some? value)
[container-width
set-container-width] (rn/use-state)
[overflow?
set-overflow?] (rn/use-state false)
[cursor-close-to-start?
set-cursor-close-to-start?] (rn/use-state false)
[label-width
set-label-width] (rn/use-state 0)
input-ref (rn/use-ref-atom nil)
set-input-ref (rn/use-callback (fn [ref]
(reset! input-ref ref)
(when get-ref (get-ref ref)))
[])
focus-input (rn/use-callback (fn []
(some-> @input-ref
(oops/ocall "focus")))
[input-ref])
on-layout-container (rn/use-callback
(fn [e]
(let [width (oops/oget e "nativeEvent.layout.width")]
(set-container-width width))))
on-layout-text-input (rn/use-callback
(fn [e]
(let [width (oops/oget e "nativeEvent.layout.width")
max-width (- container-width
icon-size
container-padding
(* label-width 2))]
(set-overflow? (> width max-width))))
[container-width label-width])
on-layout-label (rn/use-callback
(fn [e]
(let [width (oops/oget e "nativeEvent.layout.width")]
(set-label-width width))))
on-selection-change (rn/use-callback
(fn [e]
(let [selection-start (oops/oget e
"nativeEvent.selection.start")]
(set-cursor-close-to-start?
(< selection-start max-cursor-position)))))]
(let [theme (quo.theme/use-theme)
pay? (= type :pay)
disabled? (= status :disabled)
loading? (= status :loading)
typing? (= status :typing)
controlled-input? (some? value)
input-ref (rn/use-ref-atom nil)
set-input-ref (rn/use-callback (fn [ref] (reset! input-ref ref)) [])
focus-input (rn/use-callback (fn []
(some-> @input-ref
(oops/ocall "focus")))
[input-ref])]
[rn/view
{:style container-style
:accessibility-label :swap-input
:on-layout on-layout-container}
:accessibility-label :swap-input}
[rn/view {:style (style/content typing? theme)}
[rn/view
{:style (style/row-1 loading?)}
@@ -116,43 +75,25 @@
[rn/pressable
{:style style/input-container
:on-press focus-input}
[rn/view {:style {:flex-shrink 1}}
(when (and overflow? typing? (not cursor-close-to-start?))
[linear-gradient/linear-gradient
{:start {:x 0 :y 0}
:end {:x 1 :y 0}
:colors [(colors/theme-colors colors/white colors/neutral-100 theme)
(colors/theme-colors colors/white-opa-10 colors/neutral-100-opa-10 theme)]
:style style/gradient-start}])
(when (and overflow? disabled?)
[linear-gradient/linear-gradient
{:start {:x 0 :y 0}
:end {:x 1 :y 0}
:colors [(colors/theme-colors colors/white-opa-10 colors/neutral-100-opa-10 theme)
(colors/theme-colors colors/white colors/neutral-100 theme)]
:style style/gradient-end}])
[rn/text-input
(cond-> {:ref set-input-ref
:style (style/input disabled? error? theme)
:placeholder-text-color (colors/theme-colors colors/neutral-40
colors/neutral-50
theme)
:keyboard-type :numeric
:editable (not input-disabled?)
:auto-focus auto-focus?
:on-focus on-input-focus
:on-change-text on-change-text
:on-layout on-layout-text-input
:on-selection-change on-selection-change
:show-soft-input-on-focus show-keyboard?
:default-value default-value
:placeholder "0"}
controlled-input? (assoc :value value))]]
[rn/text-input
(cond-> {:ref set-input-ref
:style (style/input disabled? error? theme)
:placeholder-text-color (colors/theme-colors colors/neutral-40
colors/neutral-50
theme)
:keyboard-type :numeric
:editable (not input-disabled?)
:auto-focus auto-focus?
:on-focus on-input-focus
:on-change-text on-change-text
:show-soft-input-on-focus show-keyboard?
:default-value default-value
:placeholder "0"}
controlled-input? (assoc :value value))]
[text/text
{:size :paragraph-2
:weight :semi-bold
:style (style/token-symbol theme)
:on-layout on-layout-label}
{:size :paragraph-2
:weight :semi-bold
:style (style/token-symbol theme)}
token]]
(when (and pay? enable-swap?)
[buttons/button
-1
View File
@@ -17,7 +17,6 @@
:generate-keys1 (js/require "../resources/images/ui2/generating-keys-1.png")
:ethereum-address (js/require "../resources/images/ui2/ethereum-address.png")
:use-keycard (js/require "../resources/images/ui2/keycard.png")
:check-your-keycard (js/require "../resources/images/ui2/check-your-keycard.png")
:onboarding-illustration (js/require "../resources/images/ui2/onboarding_illustration.png")
:qr-code (js/require "../resources/images/ui2/qr-code.png")
:keycard-logo (js/require "../resources/images/ui2/keycard-logo.png")
@@ -11,23 +11,25 @@
(defn view
[{:keys [contact-id]}]
(let [customization-color (rf/sub [:profile/customization-color])
[primary-name _] (rf/sub [:contacts/contact-two-names-by-identity contact-id])
{:keys [contact-request-state
community-id]} (rf/sub [:chats/current-chat-chat-view])
chat-type (rf/sub [:chats/chat-type])
community-chat? (= chat-type :community-chat)
joined (when community-chat?
(rf/sub [:communities/community-joined community-id]))
pending? (when community-chat?
(rf/sub [:communities/my-pending-request-to-join community-id]))
contact-request-send? (or (not contact-request-state)
(= contact-request-state
constants/contact-request-state-none))
contact-request-received? (= contact-request-state
constants/contact-request-state-received)
contact-request-pending? (= contact-request-state
constants/contact-request-state-sent)]
(let [customization-color (rf/sub [:profile/customization-color])
[primary-name _] (rf/sub [:contacts/contact-two-names-by-identity
contact-id])
{:keys [contact-request-state community-id]} (rf/sub [:chats/current-chat-chat-view])
chat-type (rf/sub [:chats/chat-type])
community-chat? (= chat-type :community-chat)
joined (when community-chat?
(rf/sub [:communities/community-joined
community-id]))
pending? (when community-chat?
(rf/sub [:communities/my-pending-request-to-join
community-id]))
contact-request-send? (or (not contact-request-state)
(= contact-request-state
constants/contact-request-state-none))
contact-request-received? (= contact-request-state
constants/contact-request-state-received)
contact-request-pending? (= contact-request-state
constants/contact-request-state-sent)]
[rn/view {:style style/container}
[quo/permission-context
{:blur? true
@@ -1,11 +1,11 @@
(ns status-im.contexts.chat.messenger.messages.list.style
(:require
[quo.foundations.colors :as colors]
[react-native.safe-area :as safe-area]
[quo.foundations.shadows :as shadows]
[react-native.reanimated :as reanimated]
[status-im.contexts.chat.messenger.messages.constants :as messages.constants]))
(def permission-context-height 46)
(def distance-from-last-message 4)
(defn keyboard-avoiding-container
[theme]
@@ -13,13 +13,70 @@
:background-color (colors/theme-colors colors/white colors/neutral-95 theme)
:z-index 2})
(def permission-context-sheet {:flex 3}) ; Pushes composer to bottom
(defn background-container
[background-color background-opacity top-margin]
(reanimated/apply-animations-to-style
{:opacity background-opacity}
{:background-color background-color
:position :absolute
:top 0
:left 0
:right 0
:height (+ top-margin messages.constants/header-container-radius)}))
(defn list-paddings
[add-padding-bottom?]
(let [{:keys [top bottom]} (safe-area/get-insets)]
;; WARNING: the flat-list is reversed, so the paddings are applied inverted
{:padding-top (if add-padding-bottom?
(+ distance-from-last-message permission-context-height bottom)
distance-from-last-message)
:padding-bottom (+ top messages.constants/top-bar-height)}))
(defn header-bottom-container
[bottom top-margin]
(reanimated/apply-animations-to-style
{:bottom bottom}
{:margin-top top-margin}))
(defn header-bottom-part
[theme]
{:background-color (colors/theme-colors colors/white colors/neutral-95 theme)
:padding-horizontal 20
:border-radius 20})
(defn header-bottom-shadow
[theme]
(assoc
(shadows/get 2 theme :inverted)
:left 0
:right 0
:height 40
:position :absolute
:border-radius 20))
(defn header-image
[scale top left theme]
(reanimated/apply-animations-to-style
{:transform [{:scale scale}]
:top top
:left left}
{:position :absolute
:border-width 4
:border-radius 50
:background-color (colors/theme-colors colors/white colors/neutral-95 theme)
:border-color (colors/theme-colors colors/white colors/neutral-95 theme)}))
(defn user-name-container
[top left]
(reanimated/apply-animations-to-style
{:top top
:left left}
{:z-index -1}))
(def user-name
{:align-items :center
:flex-direction :row
:margin-top 52})
(defn bio-and-actions
[top]
(reanimated/apply-animations-to-style
{:top top}
{:row-gap 16}))
(defn permission-context-sheet
[margin-bottom?]
{:flex 3 ;; Pushes composer to bottom
:margin-bottom (when margin-bottom? permission-context-height)})
@@ -10,9 +10,11 @@
[react-native.hooks :as hooks]
[react-native.platform :as platform]
[react-native.reanimated :as reanimated]
[react-native.safe-area :as safe-area]
[status-im.common.home.actions.view :as home.actions]
[status-im.constants :as constants]
[status-im.contexts.chat.messenger.composer.constants :as composer.constants]
[status-im.contexts.chat.messenger.messages.constants :as messages.constants]
[status-im.contexts.chat.messenger.messages.content.view :as message]
[status-im.contexts.chat.messenger.messages.list.state :as state]
[status-im.contexts.chat.messenger.messages.list.style :as style]
@@ -22,6 +24,7 @@
[utils.re-frame :as rf]
[utils.worklets.chat.messenger.messages :as worklets]))
(def ^:const distance-from-last-message 4)
(def ^:const loading-indicator-page-loading-height 100)
(defn list-key-fn [{:keys [message-id value]}] (or message-id value))
@@ -191,9 +194,10 @@
context (rf/sub [:chats/current-chat-message-list-view-context])
able-to-send-message? (:able-to-send-message? context)
messages (rf/sub [:chats/raw-chat-messages-stream chat-id])
add-padding-bottom? (and community-channel? (not able-to-send-message?))
recording? (rf/sub [:chats/recording?])]
[rn/view {:style style/permission-context-sheet}
margin-bottom? (and community-channel? (not able-to-send-message?))
recording? (rf/sub [:chats/recording?])
top-margin (+ (safe-area/get-top) messages.constants/top-bar-height)]
[rn/view {:style (style/permission-context-sheet margin-bottom?)}
[rn/view {:style {:flex-shrink 1}} ;; Keeps flat list on top
[reanimated/flat-list
{:key-fn list-key-fn
@@ -233,7 +237,8 @@
:style {:background-color (colors/theme-colors colors/white
colors/neutral-95
theme)}
:content-container-style (style/list-paddings add-padding-bottom?)
:content-container-style {:padding-top distance-from-last-message
:padding-bottom top-margin}
:inverted true
:on-layout #(on-layout
{:event %
@@ -1,35 +0,0 @@
(ns status-im.contexts.keycard.authorise.view
(:require [quo.core :as quo]
[react-native.core :as rn]
[status-im.common.events-helper :as events-helper]
[status-im.common.standard-authentication.core :as standard-auth]
[utils.i18n :as i18n]
[utils.re-frame :as rf]
[utils.security.core :as security]))
(defn view
[]
(let [profile-name (rf/sub [:profile/name])
profile-picture (rf/sub [:profile/image])
customization-color (rf/sub [:profile/customization-color])]
[:<>
[quo/page-nav
{:key :header
:background :blur
:icon-name :i/close
:on-press events-helper/navigate-back}]
[quo/page-top
{:title (i18n/label :t/authorise-with-password)
:description :context-tag
:context-tag {:full-name profile-name
:profile-picture profile-picture
:customization-color customization-color}}]
[rn/view {:style {:flex 1 :padding-horizontal 20 :justify-content :space-between}}
[quo/text (i18n/label :t/migrate-key-pair-authorise)]
[standard-auth/slide-button
{:size :size-48
:container-style {}
:customization-color customization-color
:track-text (i18n/label :t/slide-to-authorise)
:on-auth-success #(println "TBD" (security/safe-unmask-data %))
:auth-button-label (i18n/label :t/confirm)}]]]))
@@ -1,36 +0,0 @@
(ns status-im.contexts.keycard.check.view
(:require [quo.core :as quo]
[react-native.core :as rn]
[status-im.common.events-helper :as events-helper]
[status-im.common.resources :as resources]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn view
[]
[:<>
[quo/page-nav
{:key :header
:background :blur
:icon-name :i/arrow-left
:on-press events-helper/navigate-back}]
[quo/page-top
{:title (i18n/label :t/check-keycard)
:description :text
:description-text (i18n/label :t/see-keycard-ready)}]
[rn/view {:style {:flex 1 :align-items :center :justify-content :center}}
[rn/image
{:resize-mode :contain
:source (resources/get-image :check-your-keycard)}]]
[quo/divider-label (i18n/label :t/tips-scan-keycard)]
[rn/view {:style {:padding-horizontal 10}}
[quo/markdown-list
{:container-style {:padding-vertical 10}
:description (i18n/label :t/remove-phone-case)}]
[quo/markdown-list
{:container-style {:padding-bottom 25}
:description (i18n/label :t/keep-card-steady)}]]
[quo/button
{:on-press #(rf/dispatch [:keycard/connect])
:container-style {:margin-horizontal 20}}
(i18n/label :t/ready-to-scan)]])
+1 -8
View File
@@ -10,15 +10,10 @@
(defonce ^:private active-listeners (atom []))
(defn unregister-card-events
(defn register-card-events
[]
(doseq [listener @active-listeners]
(keycard/remove-event-listener listener))
(reset! active-listeners nil))
(defn register-card-events
[]
(unregister-card-events)
(reset! active-listeners
[(keycard/on-card-connected #(rf/dispatch [:keycard/on-card-connected]))
(keycard/on-card-disconnected #(rf/dispatch [:keycard/on-card-disconnected]))
@@ -28,9 +23,7 @@
(keycard/on-nfc-timeout #(rf/dispatch [:keycard.ios/on-nfc-timeout])))
(keycard/on-nfc-enabled #(rf/dispatch [:keycard/on-check-nfc-enabled-success true]))
(keycard/on-nfc-disabled #(rf/dispatch [:keycard/on-check-nfc-enabled-success false]))]))
(rf/reg-fx :effects.keycard/register-card-events register-card-events)
(rf/reg-fx :effects.keycard/unregister-card-events unregister-card-events)
(defn check-nfc-enabled
[]
@@ -1,36 +0,0 @@
(ns status-im.contexts.keycard.empty.view
(:require [quo.core :as quo]
[react-native.core :as rn]
[status-im.common.events-helper :as events-helper]
[status-im.common.resources :as resources]
[status-im.contexts.keycard.sheets.migrate.view :as sheets.migrate]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn view
[]
[:<>
[quo/page-nav
{:key :header
:background :blur
:icon-name :i/arrow-left
:on-press events-helper/navigate-back}]
[quo/page-top
{:title (i18n/label :t/keycard-empty)
:description :text
:description-text (i18n/label :t/what-to-do)}]
[rn/view {:style {:padding-horizontal 28 :padding-top 20}}
[quo/small-option-card
{:variant :main
:title (i18n/label :t/import-key-pair-keycard)
:subtitle (i18n/label :t/use-keycard-login-sign)
:button-label (i18n/label :t/import-profile-key-pair)
:accessibility-label :get-keycard
:image (resources/get-image :generate-keys)
:on-press #(rf/dispatch [:show-bottom-sheet
{:theme :dark
:content (fn [] [sheets.migrate/view])}])}]]
[quo/information-box
{:type :default
:style {:margin-top 32 :margin-horizontal 28}}
(i18n/label :t/empty-card-info)]])
@@ -1,42 +0,0 @@
(ns status-im.contexts.keycard.error.view
(:require [quo.core :as quo]
[react-native.core :as rn]
[react-native.safe-area :as safe-area]
[status-im.common.events-helper :as events-helper]
[utils.re-frame :as rf]))
(def titles
{:keycard/error.keycard-wrong {:title "Keycard is not empty"
:description "You cant use it to store new keys right now"}
:keycard/error.keycard-unpaired {:title "Keycard is full"
:description "All pairing slots are occupied"}
:keycard/error.keycard-frozen {:title "Keycard is locked"
:description "You cant use it right now"}
:keycard/error.keycard-locked {:title "Keycard is locked"
:description "You cant use it right now"}})
(defn view
[]
(let [{:keys [top bottom]} (safe-area/get-insets)
error (rf/sub [:keycard/application-info-error])
{:keys [title description]} (get titles error)]
[quo/overlay
{:type :shell
:container-style {:padding-top top
:padding-bottom bottom}}
[quo/page-nav
{:key :header
:background :blur
:icon-name :i/arrow-left
:on-press events-helper/navigate-back}]
[quo/page-top
{:title title
:description :text
:description-text description}]
[rn/view {:height 226}]
[rn/view {:padding-horizontal 20}
[quo/info-message
{:container-style {:padding-top 15}
:icon :i/info
:size :default}
"To unlock or factory reset the Keycard, please use the Status desktop app. If you'd like this features on mobile, feel free to upvote them and discuss in the Status community."]]]))
+11 -53
View File
@@ -1,8 +1,8 @@
(ns status-im.contexts.keycard.events
(:require [re-frame.core :as rf]
status-im.contexts.keycard.login.events
status-im.contexts.keycard.nfc-sheet.events
status-im.contexts.keycard.pin.events
status-im.contexts.keycard.sheet.events
status-im.contexts.keycard.sign.events
[status-im.contexts.keycard.utils :as keycard.utils]
[taoensso.timbre :as log]))
@@ -14,9 +14,7 @@
(rf/reg-event-fx :keycard.ios/on-nfc-user-cancelled
(fn [{:keys [db]}]
(log/debug "[keycard] nfc user cancelled")
{:db (-> db
(assoc-in [:keycard :pin :status] nil)
(assoc-in [:keycard :on-nfc-cancelled-event-vector] nil))
{:db (assoc-in db [:keycard :pin :status] nil)
:fx [(when-let [on-nfc-cancelled-event-vector (get-in db [:keycard :on-nfc-cancelled-event-vector])]
[:dispatch on-nfc-cancelled-event-vector])]}))
@@ -44,6 +42,12 @@
{:db (assoc-in db [:keycard :card-connected?] false)
:fx [[:dispatch-later [{:ms 500 :dispatch [:keycard.ios/start-nfc]}]]]}))
(rf/reg-event-fx :keycard/get-application-info
(fn [_ [{:keys [on-success on-failure]}]]
(log/debug "[keycard] get-application-info")
{:effects.keycard/get-application-info {:on-success on-success
:on-failure on-failure}}))
(rf/reg-event-fx :keycard/on-retrieve-pairings-success
(fn [{:keys [db]} [pairings]]
{:db (assoc-in db [:keycard :pairings] pairings)
@@ -56,7 +60,7 @@
(rf/reg-event-fx :keycard/on-action-with-pin-error
(fn [{:keys [db]} [error]]
(log/debug "[keycard] on-action-with-pin-error: " error)
(log/debug "[keycard] get keys error: " error)
(let [tag-was-lost? (keycard.utils/tag-lost? (:error error))
pin-retries-count (keycard.utils/pin-retries (:error error))]
(if tag-was-lost?
@@ -65,53 +69,7 @@
{:effects.utils/show-popup {:title "wrong-keycard"}}
{:db (-> db
(assoc-in [:keycard :application-info :pin-retry-counter] pin-retries-count)
(assoc-in [:keycard :pin :status] :error))
:fx [[:dispatch [:keycard/disconnect]]
(update-in [:keycard :pin] assoc :status :error))
:fx [[:dispatch [:keycard/hide-connection-sheet]]
(when (zero? pin-retries-count)
[:effects.utils/show-popup {:title "frozen-keycard"}])]})))))
(rf/reg-event-fx :keycard/on-get-application-info-success
(fn [{:keys [db]} [application-info {:keys [key-uid on-success-fx]}]]
(let [error (keycard.utils/validate-application-info key-uid application-info)]
(if error
(case error
:keycard/error.not-keycard
{:fx [[:dispatch [:keycard/disconnect]]
[:dispatch [:open-modal :screen/keycard.not-keycard]]]}
:keycard/error.keycard-blank
{:fx [[:dispatch [:keycard/disconnect]]
[:dispatch [:open-modal :screen/keycard.empty]]]}
{:db (assoc-in db [:keycard :application-info-error] error)
:fx [[:dispatch [:keycard/disconnect]]
[:dispatch [:open-modal :screen/keycard.error]]]})
{:db (-> db
(assoc-in [:keycard :application-info] application-info)
(assoc-in [:keycard :pin :status] :verifying))
:fx on-success-fx}))))
(rf/reg-event-fx :keycard/get-application-info
(fn [_ [{:keys [on-success on-failure]}]]
{:effects.keycard/get-application-info {:on-success on-success :on-failure on-failure}}))
(rf/reg-event-fx :keycard/cancel-connection
(fn [{:keys [db]}]
{:db (-> db
(assoc-in [:keycard :on-card-connected-event-vector] nil)
(assoc-in [:keycard :on-nfc-cancelled-event-vector] nil))}))
(rf/reg-event-fx :keycard/disconnect
(fn [_ _]
{:fx [[:dispatch [:keycard/cancel-connection]]
[:dispatch [:keycard/hide-connection-sheet]]]}))
(rf/reg-event-fx :keycard/connect
(fn [{:keys [db]} [args]]
(let [connected? (get-in db [:keycard :card-connected?])
event-vector [:keycard/get-application-info
{:on-success #(rf/dispatch [:keycard/on-get-application-info-success % args])}]]
{:db (assoc-in db [:keycard :on-card-connected-event-vector] event-vector)
:fx [[:dispatch
[:keycard/show-connection-sheet
{:on-cancel-event-vector [:keycard/cancel-connection]}]]
(when connected?
[:dispatch event-vector])]})))
@@ -1,5 +1,7 @@
(ns status-im.contexts.keycard.login.events
(:require [utils.re-frame :as rf]))
(:require [status-im.contexts.keycard.utils :as keycard.utils]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(rf/reg-event-fx :keycard.login/on-get-keys-success
(fn [{:keys [db]} [data]]
@@ -14,7 +16,7 @@
:password encryption-public-key
:key-uid key-uid
:name (:name profile)))
:fx [[:dispatch [:keycard/disconnect]]
:fx [[:dispatch [:keycard/hide-connection-sheet]]
[:effects.keycard/login-with-keycard
{:password encryption-public-key
:whisper-private-key whisper-private-key
@@ -31,8 +33,36 @@
:password encryption-public-key
:key-uid key-uid
:name (:name profile)))
:fx [[:dispatch [:keycard/disconnect]]
:fx [[:dispatch [:keycard/hide-connection-sheet]]
[:effects.keycard/login-with-keycard
{:password encryption-public-key
:whisper-private-key whisper-private-key
:key-uid key-uid}]]}))))
(rf/reg-event-fx :keycard.login/on-get-application-info-success
(fn [{:keys [db]} [application-info {:keys [key-uid on-read-fx]}]]
(let [error (keycard.utils/validate-application-info key-uid application-info)]
(if error
{:effects.utils/show-popup {:title (str error)}}
{:db (-> db
(assoc-in [:keycard :application-info] application-info)
(assoc-in [:keycard :pin :status] :verifying))
:fx on-read-fx}))))
(rf/reg-event-fx :keycard.login/cancel-reading-card
(fn [{:keys [db]}]
{:db (assoc-in db [:keycard :on-card-connected-event-vector] nil)}))
(rf/reg-event-fx :keycard/read-card
(fn [{:keys [db]} [args]]
(let [connected? (get-in db [:keycard :card-connected?])
event-vector [:keycard/get-application-info
{:on-success #(rf/dispatch [:keycard.login/on-get-application-info-success %
args])}]]
(log/debug "[keycard] proceed-to-login")
{:db (assoc-in db [:keycard :on-card-connected-event-vector] event-vector)
:fx [[:dispatch
[:keycard/show-connection-sheet
{:on-cancel-event-vector [:keycard.login/cancel-reading-card]}]]
(when connected?
[:dispatch event-vector])]})))
@@ -1,28 +0,0 @@
(ns status-im.contexts.keycard.not-keycard.view
(:require [quo.core :as quo]
[react-native.core :as rn]
[react-native.safe-area :as safe-area]
[status-im.common.events-helper :as events-helper]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn view
[]
(let [{:keys [top bottom]} (safe-area/get-insets)]
[quo/overlay
{:type :shell
:container-style {:padding-top top
:padding-bottom bottom}}
[quo/page-nav
{:key :header
:background :blur
:icon-name :i/arrow-left
:on-press events-helper/navigate-back}]
[quo/page-top
{:title (i18n/label :t/oops-not-keycard)
:description :text
:description-text (i18n/label :t/make-sure-keycard)}]
[rn/view {:flex 1}]
[rn/view {:padding-horizontal 20}
[quo/button {:on-press #(rf/dispatch [:keycard/connect])}
(i18n/label :t/try-again)]]]))
@@ -1,55 +0,0 @@
(ns status-im.contexts.keycard.pin.create.view
(:require [clojure.string :as string]
[quo.core :as quo]
[react-native.core :as rn]
[status-im.constants :as constants]
[utils.i18n :as i18n]))
(defn view
[{:keys [on-complete]}]
(let [[pin set-pin] (rn/use-state "")
[first-pin set-first-pin] (rn/use-state "")
[error? set-error] (rn/use-state false)
[stage set-stage] (rn/use-state :create)
pin-empty? (string/blank? pin)
on-delete (rn/use-callback
(fn []
(set-error false)
(if (= (count pin) 1)
(do
(set-pin "")
(set-stage :create))
(when (and pin (pos? (count pin)))
(set-pin (.slice pin 0 -1)))))
[pin])
on-press (rn/use-callback
(fn [new-symbol]
(let [new-pin (str pin new-symbol)]
(when (<= (count new-pin) constants/pincode-length)
(set-pin new-pin)
(when (= constants/pincode-length (count new-pin))
(if (= :repeat stage)
(if (= first-pin new-pin)
(on-complete new-pin)
(set-error true))
(do
(set-pin "")
(set-first-pin new-pin)
(set-stage :repeat)))))))
[pin stage first-pin])]
[rn/view {:style {:padding-bottom 12 :flex 1}}
[quo/drawer-top
{:title (if (= :create stage)
(i18n/label :t/create-keycard-pin)
(i18n/label :t/repeat-keycard-pin))}]
[rn/view {:style {:flex 1 :justify-content :center :align-items :center :padding-vertical 34}}
[quo/pin-input
{:blur? false
:number-of-pins constants/pincode-length
:number-of-filled-pins (count pin)
:error? error?
:info (when error? (i18n/label :t/pin-not-match))}]]
[quo/numbered-keyboard
{:delete-key? (not pin-empty?)
:on-delete on-delete
:on-press on-press}]]))
@@ -1,16 +1,18 @@
(ns status-im.contexts.keycard.nfc-sheet.events
(ns status-im.contexts.keycard.sheet.events
(:require [re-frame.core :as rf]
[react-native.platform :as platform]
[taoensso.timbre :as log]))
(rf/reg-event-fx :keycard/show-connection-sheet-component
(fn [{:keys [db]} [{:keys [on-cancel-event-vector]}]]
{:db (assoc-in db [:keycard :connection-sheet-opts] {:on-close #(rf/dispatch on-cancel-event-vector)})
:fx [[:dismiss-keyboard true]
[:show-nfc-sheet nil]]}))
(rf/reg-event-fx :keycard/show-connection-sheet
(fn [{:keys [db]} [{:keys [on-cancel-event-vector]} :as args]]
(fn [_ [args]]
(if platform/android?
{:db (assoc-in db
[:keycard :connection-sheet-opts]
{:on-close #(rf/dispatch on-cancel-event-vector)})
:fx [[:dismiss-keyboard true]
[:show-nfc-sheet nil]]}
{:dispatch [:keycard/show-connection-sheet-component args]}
{:effects.keycard.ios/start-nfc
{:on-success
(fn []
@@ -1,9 +1,8 @@
(ns status-im.contexts.keycard.nfc-sheet.view
(ns status-im.contexts.keycard.sheet.view
(:require [quo.foundations.colors :as colors]
quo.theme
[react-native.core :as rn]
[status-im.common.resources :as resources]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn connect-keycard
@@ -19,13 +18,13 @@
:padding-vertical 30
:background-color (colors/theme-colors colors/white colors/neutral-95 theme)}}
[rn/text {:style {:font-size 26 :color "#9F9FA5" :margin-bottom 36}}
(i18n/label :t/ready-to-scan)]
"Ready to Scan"]
[rn/image
{:source (resources/get-image :nfc-prompt)}]
[rn/text {:style {:font-size 16 :color :white :margin-vertical 36}}
(if connected?
(i18n/label :t/connected-dont-move)
(i18n/label :t/hold-phone-near-keycard))]
"Connected. Dont move your card."
"Hold your phone near a Status Keycard")]
[rn/pressable
{:on-press (fn []
(when on-close (on-close))
@@ -34,4 +33,4 @@
[rn/view
{:style {:background-color "#8E8E93" :flex 1 :align-items :center :padding 18 :border-radius 10}}
[rn/text {:style {:color :white :font-size 16}}
(i18n/label :t/cancel)]]]]]))
"Cancel"]]]]]))
@@ -1,33 +0,0 @@
(ns status-im.contexts.keycard.sheets.migrate.view
(:require [quo.core :as quo]
[react-native.core :as rn]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn view
[]
(let [profile-name (rf/sub [:profile/name])
profile-picture (rf/sub [:profile/image])
customization-color (rf/sub [:profile/customization-color])]
[:<>
[quo/drawer-top
{:type :context-tag
:context-tag-type :default
:title (i18n/label :t/migrate-key-pair-keycard)
:full-name profile-name
:profile-picture profile-picture
:customization-color customization-color}]
[rn/view {:style {:padding-horizontal 20}}
[quo/text {}
(i18n/label :t/migrate-key-pair-keycard-default-key {:name profile-name})]
[quo/information-box
{:type :default
:style {:margin-top 20 :margin-bottom 12}}
(i18n/label :t/migrate-key-pair-keycard-info)]]
[quo/bottom-actions
{:actions :two-actions
:button-one-label (i18n/label :t/continue)
:button-one-props {:on-press #()}
:button-two-label (i18n/label :t/cancel)
:button-two-props {:type :grey
:on-press #(rf/dispatch [:hide-bottom-sheet])}}]]))
+13 -14
View File
@@ -14,17 +14,16 @@
path (get-in db [:wallet :accounts current-address :path])
key-uid (get-in db [:profile/profile :key-uid])]
{:fx [[:dispatch
[:keycard/connect
{:key-uid key-uid
:on-success-fx [[:effects.keycard/sign
{:pin pin-text
:path path
:hash (utils.address/naked-address tx-hash)
:on-success
#(do
(rf/dispatch [:keycard/disconnect])
(rf/dispatch
[:wallet/proceed-with-transactions-signatures
(get-signature-map tx-hash %)]))
:on-failure #(rf/dispatch [:keycard/on-action-with-pin-error
%])}]]}]]]})))
[:keycard/read-card
{:key-uid key-uid
:on-read-fx [[:effects.keycard/sign
{:pin pin-text
:path path
:hash (utils.address/naked-address tx-hash)
:on-success
#(do
(rf/dispatch [:keycard/hide-connection-sheet])
(rf/dispatch
[:wallet/proceed-with-transactions-signatures
(get-signature-map tx-hash %)]))
:on-failure #(rf/dispatch [:keycard/on-action-with-pin-error %])}]]}]]]})))
+6 -9
View File
@@ -18,31 +18,28 @@
(defn validate-application-info
[profile-key-uid {:keys [key-uid paired? pin-retry-counter puk-retry-counter] :as application-info}]
(let [profile-mismatch? (or (nil? profile-key-uid) (not= profile-key-uid key-uid))]
(log/debug "[keycard]" "login-with-keycard"
(log/debug "[keycard] login-with-keycard"
"empty application info" (empty? application-info)
"no key-uid" (empty? key-uid)
"profile-mismatch?" profile-mismatch?
"no pairing" paired?)
(cond
(empty? application-info)
:keycard/error.not-keycard
:not-keycard
(empty? (:key-uid application-info))
:keycard/error.keycard-blank
:keycard-blank
profile-mismatch?
:keycard/error.keycard-wrong
:keycard-wrong
(not paired?)
:keycard/error.keycard-unpaired
:keycard-unpaired
(and (zero? pin-retry-counter)
(or (nil? puk-retry-counter)
(pos? puk-retry-counter)))
:keycard/error.keycard-frozen
(zero? puk-retry-counter)
:keycard/error.keycard-locked
nil
:else
nil)))
@@ -242,13 +242,12 @@
{:on-complete
(fn [pin-text]
(rf/dispatch
[:keycard/connect
{:key-uid key-uid
:on-success-fx [[:effects.keycard/get-keys
{:pin pin-text
:on-success #(rf/dispatch [:keycard.login/on-get-keys-success %])
:on-failure #(rf/dispatch [:keycard/on-action-with-pin-error
%])}]]}]))}]
[:keycard/read-card
{:key-uid key-uid
:on-read-fx [[:effects.keycard/get-keys
{:pin pin-text
:on-success #(rf/dispatch [:keycard.login/on-get-keys-success %])
:on-failure #(rf/dispatch [:keycard/on-action-with-pin-error %])}]]}]))}]
[password-input])]
(when-not keycard-pairing
[quo/button
@@ -1,7 +1,6 @@
(ns status-im.contexts.profile.settings.list-items
(:require [status-im.common.not-implemented :as not-implemented]
[status-im.config :as config]
[status-im.feature-flags :as ff]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
@@ -55,9 +54,9 @@
:image :icon
:blur? true
:action :arrow})
(when (ff/enabled? ::ff/keycard.migrate-profile)
(when config/show-not-implemented-features?
{:title (i18n/label :t/keycard)
:on-press #(rf/dispatch [:open-modal :screen/settings.keycard])
:on-press not-implemented/alert
:image-props :i/keycard
:image :icon
:blur? true
@@ -1,45 +0,0 @@
(ns status-im.contexts.settings.keycard.view
(:require [quo.core :as quo]
[quo.foundations.colors :as colors]
[react-native.core :as rn]
[status-im.common.events-helper :as events-helper]
[status-im.common.resources :as resources]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn view
[]
(let [keycard-profile? (rf/sub [:keycard/keycard-profile?])]
[:<>
[quo/page-nav
{:key :header
:background :blur
:icon-name :i/arrow-left
:on-press events-helper/navigate-back}]
[quo/page-top
{:title (i18n/label :t/keycard)}]
(if keycard-profile?
[:<>]
[rn/view {:style {:padding-horizontal 28 :padding-top 20}}
[quo/small-option-card
{:variant :main
:title (i18n/label :t/get-keycard)
:subtitle (i18n/label :t/secure-wallet-card)
:button-label (i18n/label :t/buy-keycard)
:accessibility-label :get-keycard
:image (resources/get-image :generate-keys)
:on-press #()}]
[rn/view {:style {:margin-top 24}}
[quo/text
{:style {:margin-bottom 12
:color colors/white-opa-70}
:size :paragraph-2
:weight :medium}
(i18n/label :t/own-keycard)]]
[quo/small-option-card
{:variant :icon
:title (i18n/label :t/setup-keycard)
:subtitle (i18n/label :t/ready-keycard)
:accessibility-label :setup-keycard
:image (resources/get-image :use-keycard)
:on-press #(rf/dispatch [:open-modal :screen/keycard.check])}]])]))
@@ -1,72 +0,0 @@
(ns status-im.contexts.wallet.buy-crypto.events
(:require [re-frame.core :as rf]
[react-native.core :as rn]
[status-im.contexts.wallet.sheets.buy-network-selection.view :as buy-network-selection]
[status-im.contexts.wallet.sheets.select-asset.view :as select-asset]
[utils.i18n :as i18n]))
(rf/reg-event-fx :wallet.buy-crypto/select-provider
(fn [{:keys [db]} [{:keys [account provider recurrent?]}]]
(let [swap-network (get-in db [:wallet :ui :swap :network])]
{:db (-> db
(assoc-in [:wallet :ui :buy-crypto :account] account)
(assoc-in [:wallet :ui :buy-crypto :provider] provider)
(assoc-in [:wallet :ui :buy-crypto :recurrent?] recurrent?))
:fx [(if swap-network
[:dispatch [:wallet.buy-crypto/select-network swap-network]]
[:dispatch
[:show-bottom-sheet
{:content
(fn []
[buy-network-selection/view
{:provider provider
:account account}])}]])]})))
(rf/reg-event-fx :wallet.buy-crypto/select-network
(fn [{:keys [db]} [network]]
(let [provider (get-in db [:wallet :ui :buy-crypto :provider])
network-chain-id (:chain-id network)
supported-tokens (:supported-tokens provider)
supported-tokens-on-network (set (map :symbol
(filter (fn [token]
(= (:chain-id token) network-chain-id))
supported-tokens)))]
{:db (assoc-in db [:wallet :ui :buy-crypto :network] network)
:fx [[:dispatch
[:show-bottom-sheet
{:content
(fn []
[select-asset/view
{:title (i18n/label :t/select-asset-to-buy)
:network network
:provider provider
:on-select (fn [token]
(rf/dispatch [:wallet/get-crypto-on-ramp-url {:token token}]))
:hide-token-fn (fn [_ token]
(not (contains? supported-tokens-on-network
(:symbol token))))}])}]]]})))
(rf/reg-event-fx
:wallet/get-crypto-on-ramp-url
(fn [{:keys [db]} [{:keys [token]}]]
(let [account (get-in db [:wallet :ui :buy-crypto :account])
provider (get-in db [:wallet :ui :buy-crypto :provider])
network (get-in db [:wallet :ui :buy-crypto :network])
recurrent? (get-in db [:wallet :ui :buy-crypto :recurrent?])
provider-id (:id provider)
parameters {:symbol (:symbol token)
:destAddress (:address account)
:chainID (:chain-id network)
:isRecurrent recurrent?}]
{:fx [[:json-rpc/call
[{:method "wallet_getCryptoOnRampURL"
:params [provider-id parameters]
:on-success (fn [url]
(rf/dispatch [:navigate-back])
(rf/dispatch [:wallet.buy-crypto/clean-all])
(rn/open-url url))
:on-error [:wallet/log-rpc-error {:event :wallet/get-crypto-on-ramps}]}]]]})))
(rf/reg-event-fx :wallet.buy-crypto/clean-all
(fn [{:keys [db]}]
{:db (update-in db [:wallet :ui] dissoc :buy-crypto)}))
@@ -8,20 +8,19 @@
[utils.re-frame :as rf]))
(defn get-bottom-sheet-args
[switcher-type params]
[switcher-type]
(case switcher-type
:account-options {:content account-options/view
:hide-handle? true}
:select-account {:content (fn []
[select-account/view params])}
:select-account {:content select-account/view}
nil))
(defn- on-dapps-press
[switcher-type params]
(rf/dispatch [:show-bottom-sheet (get-bottom-sheet-args switcher-type params)]))
[switcher-type]
(rf/dispatch [:show-bottom-sheet (get-bottom-sheet-args switcher-type)]))
(defn view
[{:keys [type on-press accessibility-label icon-name switcher-type margin-top params]
[{:keys [type on-press accessibility-label icon-name switcher-type margin-top]
:or {icon-name :i/close
accessibility-label :top-bar
switcher-type :account-options
@@ -46,6 +45,6 @@
(when-not sending-collectible?
{:content-type :account-switcher
:customization-color color
:on-press #(on-dapps-press switcher-type params)
:on-press #(on-dapps-press switcher-type)
:emoji emoji
:type (when watch-only? :watch-only)})]}]))
@@ -32,11 +32,9 @@
:selected)}]))
(defn view
[{:keys [content-container-style search-text on-token-press preselected-token-symbol chain-ids]
[{:keys [content-container-style search-text on-token-press preselected-token-symbol]
:or {content-container-style {:padding-horizontal 8}}}]
(let [filtered-tokens (rf/sub [:wallet/current-viewing-account-tokens-filtered
{:query search-text
:chain-ids chain-ids}])
(let [filtered-tokens (rf/sub [:wallet/current-viewing-account-tokens-filtered {:query search-text}])
currency (rf/sub [:profile/currency])
currency-symbol (rf/sub [:profile/currency-symbol])]
[gesture/flat-list
@@ -47,7 +47,7 @@
(rf/dispatch [:wallet/bridge-select-token params]))})
(defn- action-swap
[{:keys [token asset-to-receive token-symbol testnet-mode?]}]
[{:keys [token token-symbol testnet-mode?]}]
{:icon :i/swap
:accessibility-label :swap
:label (i18n/label :t/swap)
@@ -56,7 +56,6 @@
(rf/dispatch [:hide-bottom-sheet])
(rf/dispatch [:wallet.swap/start
{:asset-to-pay (or token {:symbol token-symbol})
:asset-to-receive asset-to-receive
:open-new-screen? true}]))})
(defn- action-manage-tokens
@@ -76,26 +75,23 @@
(defn token-value-drawer
[token watch-only? entry-point]
(let [token-symbol (:token token)
token-data (first (rf/sub [:wallet/current-viewing-account-tokens-filtered
{:query token-symbol}]))
selected-account (rf/sub [:wallet/current-viewing-account-address])
token-owners (rf/sub [:wallet/operable-addresses-with-token-symbol token-symbol])
testnet-mode? (rf/sub [:profile/test-networks-enabled?])
receive-token-symbol (if (= token-symbol "SNT") "ETH" "SNT")
asset-to-receive (rf/sub [:wallet/token-by-symbol receive-token-symbol])
params (cond-> {:start-flow? true
:owners token-owners
:testnet-mode? testnet-mode?
:asset-to-receive asset-to-receive}
selected-account
(assoc :token token-data
:stack-id :screen/wallet.accounts
:has-balance? (-> (get-in token [:values :fiat-unformatted-value])
(money/greater-than (money/bignumber "0"))))
(not selected-account)
(assoc :token-symbol token-symbol
:stack-id :wallet-stack))]
(let [token-symbol (:token token)
token-data (first (rf/sub [:wallet/current-viewing-account-tokens-filtered
{:query token-symbol}]))
selected-account (rf/sub [:wallet/current-viewing-account-address])
token-owners (rf/sub [:wallet/operable-addresses-with-token-symbol token-symbol])
testnet-mode? (rf/sub [:profile/test-networks-enabled?])
params (cond-> {:start-flow? true
:owners token-owners
:testnet-mode? testnet-mode?}
selected-account
(assoc :token token-data
:stack-id :screen/wallet.accounts
:has-balance? (-> (get-in token [:values :fiat-unformatted-value])
(money/greater-than (money/bignumber "0"))))
(not selected-account)
(assoc :token-symbol token-symbol
:stack-id :wallet-stack))]
[quo/action-drawer
[(cond->> [(when (ff/enabled? ::ff/wallet.assets-modal-manage-tokens)
(action-manage-tokens watch-only?))
@@ -15,17 +15,13 @@
[full-name]
(first (string/split full-name #" ")))
(defn cut-fiat-balance
[balance decimals]
(defn cut-fiat-balance-to-two-decimals
[balance]
(let [valid-balance? (and balance
(or (number? balance) (.-toFixed balance)))]
(as-> balance $
(if valid-balance? $ 0)
(.toFixed $ decimals))))
(defn cut-fiat-balance-to-two-decimals
[balance]
(cut-fiat-balance balance 2))
(.toFixed $ 2))))
(defn prettify-balance
[currency-symbol balance]
@@ -155,10 +151,6 @@
[accounts address]
(some #(when (= (:address %) address) %) accounts))
(defn get-default-account
[accounts]
(some #(when (:default-account? %) %) accounts))
(defn calculate-token-fiat-value
"Returns the token fiat value for provided raw balance"
[{:keys [currency balance token]}]
+8 -13
View File
@@ -8,7 +8,6 @@
[status-im.common.refreshable-flat-list.view :as refreshable-flat-list]
[status-im.contexts.wallet.home.style :as style]
[status-im.contexts.wallet.home.tabs.view :as tabs]
[status-im.contexts.wallet.send.transaction-details.view :as transaction-details]
[status-im.contexts.wallet.sheets.network-filter.view :as network-filter]
[status-im.feature-flags :as ff]
[utils.i18n :as i18n]
@@ -94,18 +93,14 @@
:tint-color colors/neutral-40
:on-refresh #(rf/dispatch [:wallet/get-accounts])}]
:header [rn/view {:style (style/header-container theme)}
[rn/pressable
{:on-press #(rf/dispatch
[:show-bottom-sheet
{:content transaction-details/sheet}])}
[quo/wallet-overview
{:state (if tokens-loading? :loading :default)
:time-frame :none
:metrics :none
:balance formatted-balance
:networks networks
:dropdown-on-press #(rf/dispatch [:show-bottom-sheet
{:content network-filter/view}])}]]
[quo/wallet-overview
{:state (if tokens-loading? :loading :default)
:time-frame :none
:metrics :none
:balance formatted-balance
:networks networks
:dropdown-on-press #(rf/dispatch [:show-bottom-sheet
{:content network-filter/view}])}]
(when (ff/enabled? ::ff/wallet.graph)
[quo/wallet-graph {:time-frame :empty}])
[render-cards cards account-list-ref]
@@ -158,14 +158,16 @@
active-screen? (= view-id current-screen-id)
bottom (safe-area/get-bottom)
[crypto-currency? set-crypto-currency] (rn/use-state initial-crypto-currency?)
on-navigate-back on-navigate-back
handle-on-confirm (fn [amount]
(rf/dispatch [:wallet/set-token-amount-to-send
{:amount amount
:stack-id current-screen-id}]))
{fiat-currency :currency} (rf/sub [:profile/profile])
{token-symbol :symbol
{token-symbol :symbol
token-networks :networks
:as token} (rf/sub [:wallet/wallet-send-token])
:as
token} (rf/sub [:wallet/wallet-send-token])
send-from-locked-amounts (rf/sub [:wallet/wallet-send-from-locked-amounts])
{:keys [total-balance]
:as token-by-symbol} (rf/sub [:wallet/token-by-symbol
@@ -194,8 +196,10 @@
(utils/cut-crypto-decimals-to-fit-usd-cents
token-balance
usd-conversion-rate)
(utils/cut-fiat-balance-to-two-decimals
(money/crypto->fiat token-balance conversion-rate)))
(-> (money/crypto->fiat
token-balance
conversion-rate)
utils/cut-fiat-balance-to-two-decimals))
input-value (controlled-input/input-value input-state)
valid-input? (not (or (controlled-input/empty-value? input-state)
(controlled-input/input-error input-state)))
@@ -385,8 +389,7 @@
:button-one-label (if should-try-again?
(i18n/label :t/try-again)
button-one-label)
:button-one-props (merge (when-not should-try-again?
button-one-props)
:button-one-props (merge (when-not should-try-again? button-one-props)
{:disabled? (or loading-routes?
(and (not should-try-again?) confirm-disabled?))
:on-press (cond
@@ -10,7 +10,8 @@
[input-amount/view
{:current-screen-id :screen/wallet.send-input-amount
:button-one-label (i18n/label :t/review-send)
:enabled-from-chain-ids (rf/sub [:wallet/wallet-send-enabled-from-chain-ids])
:enabled-from-chain-ids (rf/sub
[:wallet/wallet-send-enabled-from-chain-ids])
:from-enabled-networks (rf/sub [:wallet/wallet-send-enabled-networks])
:on-navigate-back (fn []
(rf/dispatch-sync [:wallet/stop-and-clean-suggested-routes])
@@ -9,7 +9,6 @@
[status-im.common.standard-authentication.core :as standard-auth]
[status-im.contexts.wallet.common.utils :as utils]
[status-im.contexts.wallet.send.transaction-confirmation.style :as style]
[status-im.contexts.wallet.send.transaction-details.view :as transaction-details]
[status-im.contexts.wallet.send.utils :as send-utils]
[utils.i18n :as i18n]
[utils.re-frame :as rf]
@@ -179,17 +178,6 @@
[rn/activity-indicator {:style {:flex 1}}]
route-loaded?
[:<>
[quo/button
{:icon-only? true
:type :outline
:size 32
:inner-style {:opacity 1}
:accessibility-label :advanced-button
:container-style {:margin-right 8}
:on-press #(rf/dispatch
[:show-bottom-sheet
{:content transaction-details/sheet}])}
:i/advanced]
[data-item
{:title (i18n/label :t/est-time)
:subtitle (i18n/label :t/time-in-mins {:minutes (str estimated-time-min)})}]
@@ -282,37 +270,33 @@
:gradient-cover? true
:customization-color (:color account)}
[rn/view
[rn/pressable
{:on-press #(rf/dispatch [:navigate-to-within-stack
[:screen/wallet.transaction-details
:screen/wallet.transaction-confirmation]])}
[transaction-title
{:token-display-name token-symbol
:amount amount
:account account
:type type
:recipient recipient
:route route
:to-network bridge-to-network
:image-url image-url
:transaction-type transaction-type
:collectible? collectible?}]
[user-summary
{:summary-type :status-account
:accessibility-label :summary-from-label
:label (i18n/label :t/from-capitalized)
:account-props from-account-props
:theme theme}]
[user-summary
{:summary-type (if (= transaction-type :tx/bridge)
:status-account
:account)
:accessibility-label :summary-to-label
:label (i18n/label :t/to-capitalized)
:account-props (if (= transaction-type :tx/bridge)
from-account-props
user-props)
:recipient recipient
:bridge-tx? (= transaction-type :tx/bridge)
:account-to? true
:theme theme}]]]]]))))
[transaction-title
{:token-display-name token-symbol
:amount amount
:account account
:type type
:recipient recipient
:route route
:to-network bridge-to-network
:image-url image-url
:transaction-type transaction-type
:collectible? collectible?}]
[user-summary
{:summary-type :status-account
:accessibility-label :summary-from-label
:label (i18n/label :t/from-capitalized)
:account-props from-account-props
:theme theme}]
[user-summary
{:summary-type (if (= transaction-type :tx/bridge)
:status-account
:account)
:accessibility-label :summary-to-label
:label (i18n/label :t/to-capitalized)
:account-props (if (= transaction-type :tx/bridge)
from-account-props
user-props)
:recipient recipient
:bridge-tx? (= transaction-type :tx/bridge)
:account-to? true
:theme theme}]]]]))))
@@ -1,14 +0,0 @@
(ns status-im.contexts.wallet.send.transaction-details.style
(:require
[quo.foundations.colors :as colors]))
(defn prop-text
[theme]
{:color (colors/theme-colors colors/neutral-100 colors/white theme)})
(def content-line
{:flex-direction :row
:margin-top 2
:align-items :center
:column-gap 4
:justify-content :flex-start})
@@ -1,49 +0,0 @@
(ns status-im.contexts.wallet.send.transaction-details.view
(:require
[quo.core :as quo]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[utils.i18n :as i18n]))
(defn sheet
[_]
[rn/view
[quo/drawer-top
{:title "Transaction settings"}]
[quo/category
{:list-type :settings
:data [{:title "Normal ~60s"
:image :icon
:image-props :i/placeholder
:description :text
:description-props {:text "€1.45"}
:on-press #()
:action :selector
:action-props {:type :radio}
:label :text
:preview-size :size-32}
{:title "Fast ~40s"
:image :icon
:image-props :i/placeholder
:description :text
:description-props {:text "€1.65"}
:on-press #()
:action :selector
:action-props {:type :radio}
:label :text
:preview-size :size-32}
{:title "Urget ~15s"
:image :icon
:image-props :i/placeholder
:description :text
:description-props {:text "€1.85"}
:on-press #()
:action :selector
:action-props {:type :radio}
:label :text
:preview-size :size-32}]}]
[quo/bottom-actions
{:actions :one-action
:button-one-props {:on-press #()}
:button-one-label (i18n/label :t/confirm)}]])
@@ -1,28 +0,0 @@
(ns status-im.contexts.wallet.sheets.buy-network-selection.style)
(defn network-list-container
[mainnet?]
{:margin-horizontal 8
:padding-vertical (when mainnet? 8)})
(def header-container
{:height 62
:padding-horizontal 20})
(def context-tag
{:margin-top 0})
(def divider-label
{:padding-top 0
:padding-bottom 0})
(def subheader-container
{:flex-direction :row
:align-items :center
:margin-top 4})
(def on
{:margin-right 4})
(def to
{:margin-horizontal 4})
@@ -1,78 +0,0 @@
(ns status-im.contexts.wallet.sheets.buy-network-selection.view
(:require [quo.core :as quo]
[quo.foundations.resources :as quo.resources]
[react-native.core :as rn]
[status-im.constants :as constants]
[status-im.contexts.wallet.sheets.buy-network-selection.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn- network-item
[{:keys [network on-select-network]}]
(let [{:keys [network-name]} network
mainnet? (= network-name constants/mainnet-network-name)]
[quo/network-list
{:label (name network-name)
:network-image (quo.resources/get-network network-name)
:on-press #(on-select-network network)
:container-style (style/network-list-container mainnet?)}]))
(defn- subheader
[{:keys [provider account]}]
[rn/view {:style style/subheader-container}
[quo/text
{:size :paragraph-2
:weight :medium
:style style/on}
(i18n/label :t/on-uppercase)]
[quo/context-tag
{:type :network
:network-logo (:logo-url provider)
:network-name (:name provider)
:size 24
:container-style style/context-tag}]
[quo/text
{:size :paragraph-2
:weight :medium
:style style/to}
(i18n/label :t/to)]
[quo/context-tag
{:type :account
:account-name (:name account)
:emoji (:emoji account)
:size 24
:container-style style/context-tag}]])
(defn view
[]
(let [provider (rf/sub [:wallet/wallet-buy-crypto-provider])
account (rf/sub [:wallet/wallet-buy-crypto-account])
network-details (rf/sub [:wallet/network-details])
mainnet-network (first network-details)
layer-2-networks (rest network-details)
render-fn (rn/use-callback (fn [network]
[network-item
{:network network
:on-select-network
(fn [network]
(rf/dispatch [:wallet.buy-crypto/select-network
network]))}]))]
[:<>
[rn/view {:style style/header-container}
[quo/text
{:size :heading-2
:weight :semi-bold}
(i18n/label :t/select-network-for-buying)]
[subheader
{:provider provider
:account account}]]
(when mainnet-network
[network-item
{:network mainnet-network
:on-select-network #(rf/dispatch [:wallet.buy-crypto/select-network mainnet-network])}])
[quo/divider-label {:container-style style/divider-label}
(i18n/label :t/layer-2)]
[rn/flat-list
{:data (vec layer-2-networks)
:render-fn render-fn
:scroll-enabled false}]]))
@@ -7,20 +7,11 @@
[utils.re-frame :as rf]))
(defn- crypto-on-ramp-item
[{:keys [name description fees logo-url site-url recurrent-site-url urls-need-parameters]
:as provider}
_
_
{:keys [account tab]}]
(let [open-url (rn/use-callback
(fn []
(if urls-need-parameters
(rf/dispatch [:wallet.buy-crypto/select-provider
{:account account
:provider provider
:recurrent? (= tab :recurrent)}])
(rn/open-url (if (= tab :recurrent) recurrent-site-url site-url))))
[site-url recurrent-site-url tab])]
[{:keys [name description fees logo-url site-url recurrent-site-url]} _ _ {:keys [tab]}]
(let [open-url (rn/use-callback (fn []
(rf/dispatch [:open-url
(if (= tab :recurrent) recurrent-site-url site-url)]))
[site-url recurrent-site-url tab])]
[quo/settings-item
{:title name
:description :text
@@ -48,7 +39,6 @@
(rn/use-mount (fn []
(rf/dispatch [:wallet/get-crypto-on-ramps])))
(let [crypto-on-ramps (rf/sub [:wallet/crypto-on-ramps])
account (rf/sub [:wallet/current-viewing-account-or-default])
[selected-tab set-selected-tab] (rn/use-state initial-tab)
[min-height set-min-height] (rn/use-state 0)
on-layout (rn/use-callback
@@ -68,6 +58,5 @@
(:one-time crypto-on-ramps))
:on-layout on-layout
:style (style/list-container min-height)
:render-data {:tab selected-tab
:account account}
:render-data {:tab selected-tab}
:render-fn crypto-on-ramp-item}]]))
@@ -2,60 +2,30 @@
(:require [quo.core :as quo]
quo.theme
[react-native.gesture :as gesture]
[status-im.contexts.wallet.common.utils :as wallet.utils]
[status-im.contexts.wallet.sheets.select-account.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn list-item
[{:keys [account selected-account-address]}]
(let [{:keys [color address]} account]
[quo/account-item
{:type :default
:account-props (assoc account :customization-color color)
:customization-color color
:state (if (= address selected-account-address) :selected :default)
:on-press (fn []
(rf/dispatch [:wallet/switch-current-viewing-account address])
(rf/dispatch [:hide-bottom-sheet]))}]))
(defn list-item-with-balance
[{:keys [account selected-account-address asset-symbol network]}]
(let [{:keys [color address tokens]} account
token (->> tokens
(filter #(= (:symbol %) asset-symbol))
first)
token-balance (get-in token [:balances-per-chain (:chain-id network) :balance])]
[quo/account-item
{:type (if (= address selected-account-address) :default :tag)
:token-props {:symbol asset-symbol
:value (wallet.utils/cut-fiat-balance (or (js/parseFloat token-balance) 0)
4)}
:account-props (assoc account :customization-color color)
:customization-color color
:state (if (= address selected-account-address) :selected :default)
:on-press (fn []
(rf/dispatch [:wallet/switch-current-viewing-account address])
(rf/dispatch [:hide-bottom-sheet]))}]))
(defn- render-account-item
[{:keys [color address] :as account} _ _ {:keys [selected-account-address]}]
[quo/account-item
{:type :default
:account-props (assoc account :customization-color color)
:customization-color color
:state (if (= address selected-account-address) :selected :default)
:on-press (fn []
(rf/dispatch [:wallet/switch-current-viewing-account address])
(rf/dispatch [:hide-bottom-sheet]))}])
(defn view
[{:keys [show-account-balances? asset-symbol network]}]
[]
(let [selected-account-address (rf/sub [:wallet/current-viewing-account-address])
accounts (rf/sub [:wallet/operable-accounts])]
[:<>
[quo/drawer-top {:title (i18n/label :t/select-account)}]
[gesture/flat-list
{:data accounts
:render-fn (fn [account _ _ {:keys [selected-account-address]}]
(if show-account-balances?
[list-item-with-balance
{:account account
:selected-account-address selected-account-address
:asset-symbol asset-symbol
:network network}]
[list-item
{:account account
:selected-account-address selected-account-address}]))
:render-fn render-account-item
:render-data {:selected-account-address selected-account-address}
:content-container-style style/list-container
:shows-vertical-scroll-indicator false}]]))
@@ -51,31 +51,14 @@
:network-name full-name
:type :network}])
(defn- provider-view
[{:keys [name logo-url]}]
[quo/context-tag
{:size 24
:network-logo logo-url
:network-name name
:type :network}])
(defn- subheader-view
[{:keys [provider account network]}]
[{:keys [account network]}]
[rn/view {:style style/subheader-container}
[quo/text
{:size :paragraph-2
:weight :medium}
(i18n/label :t/select-asset-on)]
(if provider
[provider-view provider]
[account-view account])
(when provider
[:<>
[quo/text
{:size :paragraph-2
:weight :medium}
(i18n/label :t/to)]
[account-view account]])
[account-view account]
[quo/text
{:size :paragraph-2
:weight :medium}
@@ -83,8 +66,9 @@
[network-view network]])
(defn view
[{:keys [title network provider on-select hide-token-fn disable-token-fn]}]
(let [account (rf/sub [:wallet/current-viewing-account-or-default])
[{:keys [title on-select hide-token-fn disable-token-fn]}]
(let [account (rf/sub [:wallet/current-viewing-account])
{:keys [network]} (rf/sub [:wallet/swap])
[search-text set-search-text] (rn/use-state "")
window-height (:height (rn/get-window))]
[rn/safe-area-view {:style (style/container window-height)}
@@ -97,9 +81,8 @@
{:title title
:title-accessibility-label :title-label}]
[subheader-view
{:account account
:network network
:provider provider}]
{:account account
:network network}]
[assets-view
{:search-text search-text
:on-change-text #(set-search-text %)
+14 -2
View File
@@ -14,7 +14,7 @@
[utils.number :as number]))
(rf/reg-event-fx :wallet.swap/start
(fn [{:keys [db]} [{:keys [network asset-to-receive open-new-screen?] :as data}]]
(fn [{:keys [db]} [{:keys [network open-new-screen?] :as data}]]
(let [{:keys [wallet]} db
test-networks-enabled? (get-in db [:profile/profile :test-networks-enabled?])
account (swap-utils/wallet-account wallet)
@@ -25,6 +25,12 @@
:account account
:test-networks-enabled? test-networks-enabled?
:token-symbol (get-in data [:asset-to-pay :symbol])}))
asset-to-receive (or (:asset-to-receive data)
(swap-utils/select-default-asset-to-receive
{:wallet wallet
:account account
:test-networks-enabled? test-networks-enabled?
:asset-to-pay asset-to-pay}))
network' (or network
(swap-utils/select-network asset-to-pay))]
{:db (-> db
@@ -70,7 +76,11 @@
(rf/reg-event-fx :wallet.swap/select-asset-to-receive
(fn [{:keys [db]} [{:keys [token]}]]
{:db (assoc-in db [:wallet :ui :swap :asset-to-receive] token)}))
{:db (update-in db
[:wallet :ui :swap]
#(-> %
(assoc :asset-to-receive token)
(assoc :loading-swap-proposal? true)))}))
(rf/reg-event-fx :wallet.swap/set-default-slippage
(fn [{:keys [db]}]
@@ -131,6 +141,8 @@
:amount amount
:amount-hex amount-in-hex
:loading-swap-proposal? true)
:always
(dissoc :error-response)
clean-approval-transaction?
(dissoc :approval-transaction-id :approved-amount :swap-proposal)))
:json-rpc/call [{:method "wallet_getSuggestedRoutesAsync"
@@ -20,15 +20,10 @@
(defn- assets-view
[search-text on-change-text]
(let [snt-token (rf/sub [:wallet/token-by-symbol "SNT"])
eth-token (rf/sub [:wallet/token-by-symbol "ETH"])
on-token-press (fn [token]
(let [pay-token-symbol (:symbol token)
asset-to-receive (if (= pay-token-symbol "SNT") eth-token snt-token)]
(rf/dispatch [:wallet.swap/start
{:asset-to-pay token
:asset-to-receive asset-to-receive
:open-new-screen? false}])))]
(let [on-token-press (fn [token]
(rf/dispatch [:wallet.swap/start
{:asset-to-pay token
:open-new-screen? false}]))]
[:<>
[search-input search-text on-change-text]
[asset-list/view
@@ -10,12 +10,8 @@
:height 36
:background-color :transparent})
(def floating-button-page-content-container
{:margin-bottom 168})
(def scroll-view-container
{:flex 1
:padding-bottom 20})
{:padding-bottom 150})
(def content-container
{:padding-top 12
@@ -60,5 +56,5 @@
(defn footer-container
[theme]
{:margin-bottom -12
:background-color (colors/theme-colors colors/white colors/neutral-95 theme)})
{:margin-bottom -10
:background-color (colors/theme-colors colors/white colors/neutral-100 theme)})
@@ -254,7 +254,6 @@
[rn/view {:style style/container}
[floating-button-page/view
{:footer-container-padding 0
:content-container-style style/floating-button-page-content-container
:header [quo/page-nav
{:icon-name :i/close
:on-press events-helper/navigate-back
@@ -1,29 +1,27 @@
(ns status-im.contexts.wallet.swap.setup-swap.view
(:require
[clojure.string :as string]
[oops.core :as oops]
[quo.core :as quo]
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[react-native.platform :as platform]
[react-native.safe-area :as safe-area]
[status-im.common.controlled-input.utils :as controlled-input]
[status-im.common.events-helper :as events-helper]
[status-im.constants :as constants]
[status-im.contexts.wallet.common.account-switcher.view :as account-switcher]
[status-im.contexts.wallet.common.utils :as utils]
[status-im.contexts.wallet.sheets.buy-token.view :as buy-token]
[status-im.contexts.wallet.sheets.select-asset.view :as select-asset]
[status-im.contexts.wallet.sheets.slippage-settings.view :as slippage-settings]
[status-im.contexts.wallet.swap.setup-swap.style :as style]
[status-im.contexts.wallet.swap.utils :as swap-utils]
[utils.debounce :as debounce]
[utils.i18n :as i18n]
[utils.money :as money]
[utils.number :as number]
[utils.re-frame :as rf]
[utils.string :as utils.string]))
(:require [clojure.string :as string]
[quo.core :as quo]
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[react-native.platform :as platform]
[react-native.safe-area :as safe-area]
[status-im.common.controlled-input.utils :as controlled-input]
[status-im.common.events-helper :as events-helper]
[status-im.constants :as constants]
[status-im.contexts.wallet.common.account-switcher.view :as account-switcher]
[status-im.contexts.wallet.common.utils :as utils]
[status-im.contexts.wallet.sheets.buy-token.view :as buy-token]
[status-im.contexts.wallet.sheets.select-asset.view :as select-asset]
[status-im.contexts.wallet.sheets.slippage-settings.view :as slippage-settings]
[status-im.contexts.wallet.swap.setup-swap.style :as style]
[status-im.contexts.wallet.swap.utils :as swap-utils]
[utils.debounce :as debounce]
[utils.i18n :as i18n]
[utils.money :as money]
[utils.number :as number]
[utils.re-frame :as rf]
[utils.string :as utils.string]))
(def ^:private default-text-for-unfocused-input "0.00")
@@ -87,7 +85,7 @@
[{:keys [input-state on-max-press on-input-focus on-token-press on-approve-press input-focused?]}]
(let [account-color (rf/sub [:wallet/current-viewing-account-color])
network (rf/sub [:wallet/swap-network])
pay-token-symbol (:symbol (rf/sub [:wallet/swap-asset-to-pay]))
asset-to-pay (rf/sub [:wallet/swap-asset-to-pay])
currency (rf/sub [:profile/currency])
loading-swap-proposal? (rf/sub [:wallet/swap-loading-swap-proposal?])
swap-proposal (rf/sub [:wallet/swap-proposal-without-fees])
@@ -98,19 +96,14 @@
approval-transaction-id (rf/sub [:wallet/swap-approval-transaction-id])
approved-amount (rf/sub [:wallet/swap-approved-amount])
error-response (rf/sub [:wallet/swap-error-response])
asset-to-pay (rf/sub [:wallet/token-by-symbol pay-token-symbol])
overlay-shown? (boolean (:sheets (rf/sub [:bottom-sheet])))
input-ref (rn/use-ref-atom nil)
set-input-ref (rn/use-callback (fn [ref] (reset! input-ref ref)))
pay-input-num-value (controlled-input/value-numeric input-state)
pay-input-amount (controlled-input/input-value input-state)
pay-token-symbol (:symbol asset-to-pay)
pay-token-decimals (:decimals asset-to-pay)
pay-token-balance-selected-chain (number/convert-to-whole-number
(get-in asset-to-pay
[:balances-per-chain
(:chain-id network) :raw-balance]
0)
pay-token-decimals)
pay-token-balance-selected-chain (get-in asset-to-pay
[:balances-per-chain
(:chain-id network) :balance]
0)
pay-token-fiat-value (str
(utils/calculate-token-fiat-value
{:currency currency
@@ -118,15 +111,10 @@
:token asset-to-pay}))
available-crypto-limit (money/bignumber
pay-token-balance-selected-chain)
display-decimals (min pay-token-decimals
constants/min-token-decimals-to-display)
available-crypto-limit-display (number/remove-trailing-zeroes
(.toFixed available-crypto-limit display-decimals))
available-crypto-limit-display (if (and (= available-crypto-limit-display "0")
(money/greater-than available-crypto-limit
(money/bignumber 0)))
(number/small-number-threshold display-decimals)
available-crypto-limit-display)
(.toFixed available-crypto-limit
(min pay-token-decimals
constants/min-token-decimals-to-display)))
approval-amount-required-num (when approval-amount-required
(str (number/hex->whole approval-amount-required
pay-token-decimals)))
@@ -134,7 +122,8 @@
(money/greater-than
(money/bignumber pay-input-amount)
available-crypto-limit))
(money/equal-to available-crypto-limit
(money/equal-to (money/bignumber
available-crypto-limit-display)
(money/bignumber 0)))
valid-pay-input? (and
(not (string/blank?
@@ -152,15 +141,8 @@
(fn []
(request-fetch-swap-proposal))
[pay-input-amount])
(rn/use-effect
(fn []
(when-not overlay-shown?
(some-> @input-ref
(oops/ocall "focus"))))
[overlay-shown?])
[quo/swap-input
{:get-ref set-input-ref
:type :pay
{:type :pay
:error? pay-input-error?
:token pay-token-symbol
:customization-color :blue
@@ -174,7 +156,7 @@
:else :disabled)
:currency-symbol currency-symbol
:on-token-press on-token-press
:on-max-press #(on-max-press (str pay-token-balance-selected-chain))
:on-max-press #(on-max-press (str available-crypto-limit))
:on-input-focus on-input-focus
:value pay-input-amount
:fiat-value pay-token-fiat-value
@@ -292,28 +274,23 @@
(defn- pay-token-bottom-sheet
[]
(let [asset-to-receive (rf/sub [:wallet/swap-asset-to-receive])
network (rf/sub [:wallet/swap-network])]
(let [asset-to-receive (rf/sub [:wallet/swap-asset-to-receive])]
[select-asset/view
{:title (i18n/label :t/select-asset-to-pay)
:network network
:on-select (fn [token]
(rf/dispatch [:wallet.swap/select-asset-to-pay {:token token}]))
:hide-token-fn (fn [type {:keys [balances-per-chain]}]
(let [balance (get-in balances-per-chain [(:chain-id network) :balance] "0")]
(and (= type constants/swap-tokens-my)
(= balance "0"))))
:hide-token-fn (fn [type {:keys [available-balance]}]
(and (= type constants/swap-tokens-my)
(= available-balance 0)))
:disable-token-fn (fn [_ token]
(= (:symbol token)
(:symbol asset-to-receive)))}]))
(defn- receive-token-bottom-sheet
[]
(let [asset-to-pay (rf/sub [:wallet/swap-asset-to-pay])
network (rf/sub [:wallet/swap-network])]
(let [asset-to-pay (rf/sub [:wallet/swap-asset-to-pay])]
[select-asset/view
{:title (i18n/label :t/select-asset-to-receive)
:network network
:on-select (fn [token]
(rf/dispatch [:wallet.swap/select-asset-to-receive {:token token}]))
:disable-token-fn (fn [_ token]
@@ -333,12 +310,10 @@
network (rf/sub [:wallet/swap-network])
pay-input-amount (controlled-input/input-value pay-input-state)
pay-token-decimals (:decimals asset-to-pay)
pay-token-balance-selected-chain (number/convert-to-whole-number
(get-in asset-to-pay
[:balances-per-chain
(:chain-id network) :raw-balance]
0)
pay-token-decimals)
pay-token-balance-selected-chain (get-in asset-to-pay
[:balances-per-chain
(:chain-id network) :balance]
0)
pay-input-error? (and (not (string/blank? pay-input-amount))
(money/greater-than
(money/bignumber pay-input-amount)
@@ -440,17 +415,13 @@
(when (and swap-amount refetch-interval)
(js/clearTimeout @refetch-interval)
(reset! refetch-interval nil))
(cond (and swap-amount (not= swap-amount pay-input-amount))
(set-pay-input-state
(fn [input-state]
(controlled-input/set-input-value
input-state
swap-amount)))
(and pay-input-amount
(not (number/valid-decimal-count? pay-input-amount (:decimals asset-to-pay))))
(set-pay-input-state controlled-input/delete-all)
:else
(refetch-swap-proposal)))))
(if (and swap-amount (not= swap-amount pay-input-amount))
(set-pay-input-state
(fn [input-state]
(controlled-input/set-input-value
input-state
swap-amount)))
(refetch-swap-proposal)))))
[asset-to-pay])
(rn/use-effect
refetch-swap-proposal
@@ -460,10 +431,7 @@
{:on-press on-close
:icon-name :i/arrow-left
:margin-top (safe-area/get-top)
:switcher-type :select-account
:params {:show-account-balances? true
:asset-symbol (:symbol asset-to-pay)
:network network}}]
:switcher-type :select-account}]
[rn/view {:style style/inputs-container}
[pay-token-input
{:input-state pay-input-state
@@ -485,7 +453,7 @@
:on-token-press #(rf/dispatch [:show-bottom-sheet {:content receive-token-bottom-sheet}])
:on-input-focus #(set-pay-input-focused? false)}]]
[rn/view {:style style/footer-container}
(when-not loading-swap-proposal? [alert-banner {:pay-input-error? pay-input-error?}])
[alert-banner {:pay-input-error? pay-input-error?}]
(when (or loading-swap-proposal? swap-proposal)
[transaction-details])
[action-button {:on-press on-review-swap-press}]]
@@ -34,8 +34,9 @@
(defn tokens-by-symbol
[props]
(tokens-by-key
(assoc props
:key-fn
(fn [{:keys [chainId address] :as token}]
(str chainId "-" (if (get-in token [:communityData :id]) address (:symbol token)))))))
(tokens-by-key (assoc props
:key-fn
(fn [{:keys [address] :as token}]
(if (get-in token [:communityData :id])
address
(:symbol token))))))
@@ -75,7 +75,7 @@
:image nil})
:by-symbol '({:address "0x0000000000000000000000000000000000000000"
:decimals 18
:key "1-ETH"
:key "ETH"
:community-id nil
:symbol "ETH"
:sources ["native"]
@@ -86,7 +86,7 @@
:image nil}
{:address "0x0000000000000000000000000000000000000001"
:decimals 18
:key "1-SNT"
:key "SNT"
:community-id nil
:symbol "SNT"
:sources ["native"]
@@ -174,7 +174,7 @@
:image nil})
:by-symbol '({:address "0x0000000000000000000000000000000000000000"
:decimals 18
:key "1-ETH"
:key "ETH"
:community-id nil
:symbol "ETH"
:sources ["native"]
@@ -185,7 +185,7 @@
:image nil}
{:address "0x0000000000000000000000000000000000000001"
:decimals 18
:key "1-SNT"
:key "SNT"
:community-id nil
:symbol "SNT"
:sources ["native" "second"]
@@ -196,7 +196,7 @@
:image nil}
{:address "0x0000000000000000000000000000000000000002"
:decimals 18
:key "1-ANOTHER1"
:key "ANOTHER1"
:community-id nil
:symbol "ANOTHER1"
:sources ["second"]
@@ -253,7 +253,7 @@
:image nil})
:by-symbol '({:address "0x0000000000000000000000000000000000000000"
:decimals 18
:key "1-ETH"
:key "ETH"
:community-id nil
:symbol "ETH"
:sources ["native"]
@@ -264,7 +264,7 @@
:image nil}
{:address "0x0000000000000000000000000000000000000000"
:decimals 18
:key "1-ANOTHER1"
:key "ANOTHER1"
:community-id nil
:symbol "ANOTHER1"
:sources ["native" "second"]
-1
View File
@@ -41,7 +41,6 @@
status-im.contexts.syncing.events
status-im.contexts.wallet.add-account.add-address-to-watch.events
status-im.contexts.wallet.add-account.create-account.events
status-im.contexts.wallet.buy-crypto.events
status-im.contexts.wallet.collectible.events
status-im.contexts.wallet.common.wizard.events
status-im.contexts.wallet.effects
+1 -2
View File
@@ -32,8 +32,7 @@
::wallet.long-press-watch-only-asset (enabled-in-env? :FLAG_LONG_PRESS_WATCH_ONLY_ASSET_ENABLED)
::wallet.saved-addresses (enabled-in-env? :WALLET_SAVED_ADDRESSES)
::wallet.wallet-connect (enabled-in-env? :FLAG_WALLET_CONNECT_ENABLED)
::wallet.custom-network-amounts (enabled-in-env? :FLAG_WALLET_CUSTOM_NETWORK_AMOUNTS_ENABLED)
::keycard.migrate-profile false})
::wallet.custom-network-amounts (enabled-in-env? :FLAG_WALLET_CUSTOM_NETWORK_AMOUNTS_ENABLED)})
(defonce ^:private feature-flags-config
(reagent/atom initial-flags))
-6
View File
@@ -69,12 +69,6 @@
transitions/new-to-status-modal-animations
transitions/push-animations-for-transparent-background)}))
(def keycard-modal-screen-options
(assoc transparent-modal-screen-options
:layout nil
:theme :dark
:insets {:top? true :bottom? true}))
(def sheet-options
{:layout {:componentBackgroundColor :transparent
:orientation ["portrait"]
+1 -32
View File
@@ -26,11 +26,6 @@
[status-im.contexts.communities.actions.share-community.view :as share-community]
[status-im.contexts.communities.discover.view :as communities.discover]
[status-im.contexts.communities.overview.view :as communities.overview]
[status-im.contexts.keycard.authorise.view :as keycard.authorise]
[status-im.contexts.keycard.check.view :as keycard.check]
[status-im.contexts.keycard.empty.view :as keycard.empty]
[status-im.contexts.keycard.error.view :as keycard.error]
[status-im.contexts.keycard.not-keycard.view :as keycard.not-keycard]
[status-im.contexts.onboarding.create-or-sync-profile.view :as create-or-sync-profile]
[status-im.contexts.onboarding.create-password.view :as create-password]
[status-im.contexts.onboarding.create-profile.view :as create-profile]
@@ -63,7 +58,6 @@
[status-im.contexts.profile.settings.screens.password.view :as settings-password]
[status-im.contexts.profile.settings.screens.syncing.view :as settings.syncing]
[status-im.contexts.profile.settings.view :as settings]
[status-im.contexts.settings.keycard.view :as settings.keycard]
[status-im.contexts.settings.language-and-currency.currency.view :as settings.currency-selection]
[status-im.contexts.settings.language-and-currency.view :as settings.language-and-currency]
[status-im.contexts.settings.privacy-and-security.share-usage.view :as settings.share-usage]
@@ -590,10 +584,6 @@
:options options/transparent-modal-screen-options
:component wallet-options/view}
{:name :screen/settings.keycard
:options options/keycard-modal-screen-options
:component settings.keycard/view}
{:name :screen/settings.rename-keypair
:options options/transparent-screen-options
:component keypair-rename/view}
@@ -681,28 +671,7 @@
:popGesture false
:hardwareBackButton {:dismissModalOnPress false
:popStackOnPress false})
:component change-password-loading/view}
;; Keycard
{:name :screen/keycard.check
:options options/keycard-modal-screen-options
:component keycard.check/view}
{:name :screen/keycard.empty
:options options/keycard-modal-screen-options
:component keycard.empty/view}
{:name :screen/keycard.error
:options options/keycard-modal-screen-options
:component keycard.error/view}
{:name :screen/keycard.not-keycard
:options options/keycard-modal-screen-options
:component keycard.not-keycard/view}
{:name :screen/keycard.authorise
:options options/keycard-modal-screen-options
:component keycard.authorise/view}]
:component change-password-loading/view}]
[{:name :shell
:options {:theme :dark}}]
+2 -2
View File
@@ -11,7 +11,7 @@
[status-im.common.bottom-sheet-screen.view :as bottom-sheet-screen]
[status-im.common.bottom-sheet.view :as bottom-sheet]
[status-im.common.toasts.view :as toasts]
[status-im.contexts.keycard.nfc-sheet.view :as keycard.sheet]
[status-im.contexts.keycard.sheet.view :as keycard.sheet]
[status-im.navigation.screens :as screens]
[status-im.setup.hot-reload :as reloader]
[utils.re-frame :as rf]))
@@ -47,7 +47,7 @@
(merge
{:flex 1
:margin-top alert-banners-top-margin
:background-color (or background-color (colors/theme-colors colors/white colors/neutral-95 theme))}
:background-color (or background-color (colors/theme-colors colors/white colors/neutral-100 theme))}
(when bottom?
{:padding-bottom (safe-area/get-bottom)})
(when top?
-5
View File
@@ -36,8 +36,3 @@
(fn [keycard]
(:connection-sheet-opts keycard)))
(rf/reg-sub
:keycard/application-info-error
:<- [:keycard]
(fn [keycard]
(:application-info-error keycard)))
-6
View File
@@ -326,12 +326,6 @@
(fn [profile]
(profile.utils/photo profile)))
(re-frame/reg-sub
:profile/name
:<- [:profile/profile]
(fn [profile]
(profile.utils/displayed-name profile)))
(re-frame/reg-sub
:profile/login-profile
:<- [:profile/login]
-25
View File
@@ -5,28 +5,3 @@
:wallet/crypto-on-ramps
:<- [:wallet]
:-> :crypto-on-ramps)
(rf/reg-sub
:wallet/wallet-buy-crypto
:<- [:wallet/ui]
:-> :buy-crypto)
(rf/reg-sub
:wallet/wallet-buy-crypto-account
:<- [:wallet/wallet-buy-crypto]
:-> :account)
(rf/reg-sub
:wallet/wallet-buy-crypto-provider
:<- [:wallet/wallet-buy-crypto]
:-> :provider)
(rf/reg-sub
:wallet/wallet-buy-crypto-recurrent?
:<- [:wallet/wallet-buy-crypto]
:-> :recurrent?)
(rf/reg-sub
:wallet/wallet-buy-crypto-network
:<- [:wallet/wallet-buy-crypto]
:-> :network)
+7 -28
View File
@@ -399,22 +399,6 @@
(assoc :balance balance
:formatted-balance formatted-balance)))))
(rf/reg-sub
:wallet/current-viewing-account-or-default
:<- [:wallet/accounts]
:<- [:wallet/current-viewing-account-address]
:<- [:wallet/balances-in-selected-networks]
:<- [:profile/currency-symbol]
(fn [[accounts current-viewing-account-address balances currency-symbol]]
(let [account (or (utils/get-account-by-address accounts current-viewing-account-address)
(utils/get-default-account accounts))
address (:address account)
balance (get balances address)
formatted-balance (utils/prettify-balance currency-symbol balance)]
(assoc account
:balance balance
:formatted-balance formatted-balance))))
(rf/reg-sub
:wallet/current-viewing-account-color
:<- [:wallet/current-viewing-account]
@@ -436,7 +420,7 @@
(rf/reg-sub
:wallet/current-viewing-account-tokens-filtered
:<- [:wallet/current-viewing-account-or-default]
:<- [:wallet/current-viewing-account]
:<- [:wallet/network-details]
:<- [:wallet/wallet-send]
(fn [[account networks send-data] [_ {:keys [query chain-ids hide-token-fn]}]]
@@ -470,19 +454,14 @@
(rf/reg-sub
:wallet/tokens-filtered
:<- [:wallet/tokens]
:<- [:profile/currency]
(fn [[{:keys [by-symbol market-values-per-token details-per-token prices-per-token]} currency]
(fn [{:keys [by-symbol market-values-per-token details-per-token]}
[_ {:keys [query chain-ids hide-token-fn]}]]
(let [tokens (->> by-symbol
(map (fn [token]
(let [token-symbol (keyword (:symbol token))
price (get-in prices-per-token [token-symbol currency])]
(-> token
(assoc :market-values
(get market-values-per-token token-symbol))
(assoc :details (get details-per-token token-symbol))
(assoc-in [:market-values-per-currency currency :price]
price)))))
(-> token
(assoc :market-values
(get market-values-per-token (:symbol token)))
(assoc :details (get details-per-token (:symbol token))))))
(filter (fn [{:keys [chain-id]}]
(some #{chain-id} chain-ids)))
(remove #(when hide-token-fn
@@ -497,7 +476,7 @@
(rf/reg-sub
:wallet/token-by-symbol
:<- [:wallet/current-viewing-account-or-default]
:<- [:wallet/current-viewing-account]
:<- [:wallet/network-details]
(fn [[{:keys [tokens]} networks] [_ token-symbol chain-ids]]
(->> (utils/tokens-with-balance tokens networks chain-ids)
+3 -6
View File
@@ -239,12 +239,9 @@
(defn crypto->fiat
[crypto fiat-price]
(let [^js crypto-bn (bignumber crypto)
^js fiat-price-bn (bignumber fiat-price)]
(when (and crypto-bn fiat-price-bn)
(-> crypto-bn
(.times fiat-price-bn)
(with-precision 2)))))
(when-let [^js bn (bignumber crypto)]
(-> (.times bn ^js (bignumber fiat-price))
(with-precision 2))))
(defn sufficient-funds?
[^js amount ^js balance]
+13 -32
View File
@@ -2,8 +2,7 @@
(:require [clojure.string :as string]
[native-module.core :as native-module]
[utils.hex :as utils.hex]
[utils.money :as utils.money]
[utils.money :as money]))
[utils.money :as utils.money]))
(defn naive-round
"Quickly and naively round number `n` up to `decimal-places`.
@@ -19,6 +18,17 @@
(/ (Math/round (* n scale))
scale)))
(defn convert-to-whole-number
"Converts a fractional `amount` to its corresponding whole number representation
by dividing it by 10 raised to the power of `decimals`. This is often used in financial
calculations where amounts are stored in their smallest units (e.g., cents) and need
to be converted to their whole number equivalents (e.g., dollars).
Example usage:
(convert-to-whole-number 12345 2) ; => 123.45"
[amount decimals]
(/ amount (Math/pow 10 decimals)))
(defn parse-int
"Parses `n` as an integer. Defaults to zero or `default` instead of NaN."
([n]
@@ -55,44 +65,15 @@
"")
""))))
(defn convert-to-whole-number
"Converts a fractional `amount` to its corresponding whole number representation
by dividing it by 10 raised to the power of `decimals`. This is often used in financial
calculations where amounts are stored in their smallest units (e.g., cents) and need
to be converted to their whole number equivalents (e.g., dollars).
Example usage:
(convert-to-whole-number 12345 2) ; => 123.45"
[amount decimals]
(-> amount
(/ (Math/pow 10 decimals))
(.toFixed decimals)
remove-trailing-zeroes))
(defn hex->whole
[num decimals]
(-> num
utils.hex/normalize-hex
native-module/hex-to-number
(convert-to-whole-number decimals)
money/bignumber))
(convert-to-whole-number decimals)))
(defn to-fixed
[num decimals]
(-> num
(utils.money/to-fixed decimals)
remove-trailing-zeroes))
(defn small-number-threshold
"Receives a decimal count and returns a string like '<0.001' if the decimal count is 3,
'<0.000001' if the decimal count is 6, etc."
[decimal-count]
(if (> decimal-count 0)
(str "<0." (apply str (repeat (dec decimal-count) "0")) "1")
"0"))
(defn valid-decimal-count?
"Returns false if the number has more decimals than the decimal count, otherwise true."
[num decimal-count]
(let [decimal-part (second (string/split (str num) #"\."))]
(or (nil? decimal-part) (<= (count decimal-part) decimal-count))))
+11 -44
View File
@@ -5,23 +5,23 @@
(deftest convert-to-whole-number-test
(testing "correctly converts fractional amounts to whole numbers"
(is (= "123.45" (utils.number/convert-to-whole-number 12345 2)))
(is (= "1.2345" (utils.number/convert-to-whole-number 12345 4)))
(is (= "12345" (utils.number/convert-to-whole-number 1234500 2)))
(is (= "0.123" (utils.number/convert-to-whole-number 123 3)))
(is (= "1000" (utils.number/convert-to-whole-number 1000000 3))))
(is (= 123.45 (utils.number/convert-to-whole-number 12345 2)))
(is (= 1.2345 (utils.number/convert-to-whole-number 12345 4)))
(is (= 12345.0 (utils.number/convert-to-whole-number 1234500 2)))
(is (= 0.123 (utils.number/convert-to-whole-number 123 3)))
(is (= 1000.0 (utils.number/convert-to-whole-number 1000000 3))))
(testing "handles zero decimals"
(is (= "12345" (utils.number/convert-to-whole-number 12345 0))))
(is (= 12345 (utils.number/convert-to-whole-number 12345 0))))
(testing "handles negative amounts"
(is (= "-123.45" (utils.number/convert-to-whole-number -12345 2)))
(is (= "-1.2345" (utils.number/convert-to-whole-number -12345 4)))
(is (= "-0.123" (utils.number/convert-to-whole-number -123 3))))
(is (= -123.45 (utils.number/convert-to-whole-number -12345 2)))
(is (= -1.2345 (utils.number/convert-to-whole-number -12345 4)))
(is (= -0.123 (utils.number/convert-to-whole-number -123 3))))
(testing "handles zero amount"
(is (= "0" (utils.number/convert-to-whole-number 0 2)))
(is (= "0" (utils.number/convert-to-whole-number 0 0)))))
(is (= 0 (utils.number/convert-to-whole-number 0 2)))
(is (= 0 (utils.number/convert-to-whole-number 0 0)))))
(deftest parse-int-test
(testing "defaults to zero"
@@ -50,36 +50,3 @@
(is (= 6 (utils.number/parse-float "6")))
(is (= 6.99 (utils.number/parse-float "6.99" 0)))
(is (= -6.9 (utils.number/parse-float "-6.9" 0)))))
(deftest small-number-threshold-test
(testing "correctly generates threshold strings based on decimal count"
(is (= "<0.1" (utils.number/small-number-threshold 1)))
(is (= "<0.01" (utils.number/small-number-threshold 2)))
(is (= "<0.001" (utils.number/small-number-threshold 3)))
(is (= "<0.000001" (utils.number/small-number-threshold 6)))
(is (= "<0.0000000001" (utils.number/small-number-threshold 10)))
(is (= "<0.000000000000000001" (utils.number/small-number-threshold 18)))
(is (= "<0.000000000000000000001" (utils.number/small-number-threshold 21))))
(testing "handles edge cases for decimal count"
(is (= "0" (utils.number/small-number-threshold 0)))
(is (= "0" (utils.number/small-number-threshold -1)))))
(deftest valid-decimal-count?-test
(testing "valid decimal count check for numbers with varying decimals"
(is (true? (utils.number/valid-decimal-count? 123 2)))
(is (true? (utils.number/valid-decimal-count? 123 0)))
(is (true? (utils.number/valid-decimal-count? 123.45 2)))
(is (true? (utils.number/valid-decimal-count? 123.4 2)))
(is (true? (utils.number/valid-decimal-count? 123.456 3)))
(is (false? (utils.number/valid-decimal-count? 123.456 2)))
(is (false? (utils.number/valid-decimal-count? 123.456789 4)))
(is (true? (utils.number/valid-decimal-count? 123.0 1)))
(is (true? (utils.number/valid-decimal-count? -123.45 2)))
(is (false? (utils.number/valid-decimal-count? -123.4567 3)))
(is (true? (utils.number/valid-decimal-count? 1234567890.12 2)))
(is (false? (utils.number/valid-decimal-count? 1234567890.12345 3)))))
+3 -3
View File
@@ -3,7 +3,7 @@
"_comment": "Instead use: scripts/update-status-go.sh <rev>",
"owner": "status-im",
"repo": "status-go",
"version": "v3.2.0",
"commit-sha1": "3f613a9281f470a91b5080d35d22e55847ac276e",
"src-sha256": "1ghxxlmz0swq6dwabx84m23ikbs1bkzwfgqm4sp7hrnglm7bvikc"
"version": "hop-path-processor-update",
"commit-sha1": "0af7eec514bbcd105461f779d8d794b037c37279",
"src-sha256": "1wfm28afb1mqn8vd1w426xvkg0nj9cycwc35swqdcqj6ga40cm1b"
}
-1
View File
@@ -125,7 +125,6 @@ class TestrailReport(BaseTestReport):
test_cases['nightly']['activity_centre_contact_request'] = 50984
test_cases['nightly']['activity_centre_other'] = 51005
test_cases['nightly']['wallet'] = 59443
test_cases['nightly']['fallback'] = 63472
## Upgrade e2e
# test_cases['upgrade']['general'] = 881
-199
View File
@@ -1,199 +0,0 @@
import pytest
from selenium.common import TimeoutException
from base_test_case import MultipleSharedDeviceTestCase, create_shared_drivers
from tests import marks, run_in_parallel, transl
from users import transaction_senders
from views.sign_in_view import SignInView
@pytest.mark.xdist_group(name="new_six_2")
@marks.nightly
class TestFallbackMultipleDevice(MultipleSharedDeviceTestCase):
def prepare_devices(self):
self.drivers, self.loop = create_shared_drivers(3)
self.sign_in_1, self.sign_in_2, self.sign_in_3 = SignInView(self.drivers[0]), SignInView(
self.drivers[1]), SignInView(self.drivers[2])
self.home_1, self.home_2, self.home_3 = self.sign_in_1.get_home_view(), self.sign_in_2.get_home_view(), \
self.sign_in_3.get_home_view()
self.sign_in_1.just_fyi("Device 1: create a new user")
self.sign_in_3.just_fyi("Device 3: create a new user")
self.user_name_1, self.user_name_3 = 'first user', 'third user'
self.loop.run_until_complete(
run_in_parallel(((self.sign_in_1.create_user, {'username': self.user_name_1}),
(self.sign_in_3.create_user, {'username': self.user_name_3}))))
self.profile_1 = self.home_1.profile_button.click()
self.profile_2 = self.home_2.get_profile_view()
self.sign_in_3.just_fyi("Device 3: get public key")
self.recovery_phrase, self.public_key_3 = self.loop.run_until_complete(
run_in_parallel(((self.profile_1.backup_recovery_phrase, {}),
(self.home_3.get_public_key, {}))))
self.home_2.driver.get_clipboard_text() # just pinging 2nd device to save the connection
self.profile_1.click_system_back_button()
self.home_1.chats_tab.click()
self.home_1.just_fyi("Device 1: add the 3rd user as a contact")
self.home_1.add_contact(self.public_key_3)
self.home_3.just_fyi("Device 3: accepting contact request from the 1st user")
self.home_3.handle_contact_request(self.user_name_1)
self.profile_1.just_fyi("Device 1: get sync code")
self.home_1.profile_button.click()
self.sync_code = self.profile_1.get_sync_code()
@marks.testrail_id(740220)
def test_fallback_sync_with_error(self):
self.sign_in_2.just_fyi("Device 2: try syncing profile")
self.sign_in_2.sync_profile(sync_code=self.sync_code)
self.sign_in_2.progress_screen_title.wait_for_element()
assert self.sign_in_2.progress_screen_title.text == "Oops, somethings wrong"
self.home_3.chats_tab.is_element_displayed() # just pinging 3rd device to save the connection
@marks.testrail_id(740221)
def test_fallback_with_correct_seed_phrase(self):
self.sign_in_2.just_fyi("Device 2: recover a profile with backed up seed phrase")
self.sign_in_2.try_seed_phrase_button.click()
self.sign_in_2.recover_access(passphrase=self.recovery_phrase, after_sync_code=True)
self.profile_1.click_system_back_button()
self.home_2.just_fyi("Getting device 2 name")
self.home_2.profile_button.click()
self.profile_2.syncing_button.scroll_and_click()
self.profile_2.paired_devices_button.click()
device_2_name = self.profile_2.get_current_device_name()
self.profile_2.click_system_back_button(times=3)
self.home_3.chats_tab.is_element_displayed() # just pinging 3rd device to save the connection
self.profile_1.just_fyi("Check device 2 is shown in not paired devices list in profile 1")
device_1_name = self.profile_1.get_current_device_name()
device_element = self.profile_1.get_paired_device_by_name(device_2_name)
if device_element.is_element_displayed():
if not device_element.get_pair_button.is_element_displayed():
self.errors.append(
"Pair button is absent for the device 2 inside Paired devices list of profile 1 before pairing")
else:
self.errors.append("Device 2 is not shown in Paired devices list for device 1 before pairing")
self.profile_1.click_system_back_button(times=3)
for home in self.home_1, self.home_2:
home.notifications_unread_badge.wait_for_visibility_of_element(30)
home.open_activity_center_button.click_until_presence_of_element(home.close_activity_centre)
self.home_1.just_fyi("Checking pairing request on device 1")
a_c_element = self.home_1.get_activity_center_element_by_text(transl['review-pairing-request'])
if a_c_element.title.text != transl['new-device-detected']:
self.errors.append(
"Notification with title '%s' is not shown in the activity center for the device 1" % transl[
'new-device-detected'])
a_c_element.review_pairing_request_button.click()
device_id_1 = self.home_1.get_new_device_installation_id()
self.home_3.chats_tab.is_element_displayed() # just pinging 3rd device to save the connection
self.home_2.just_fyi("Checking sync profile on device 2")
a_c_element = self.home_2.get_activity_center_element_by_text(transl['more-details'])
if a_c_element.title.text != transl['sync-your-profile']:
self.errors.append(
"Notification with title '%s' is not shown in the activity center for the device 2" % transl[
'sync-your-profile'])
a_c_element.more_details_button.click()
device_id_2 = self.home_2.get_new_device_installation_id()
if device_id_1 != device_id_2:
self.errors.append("Device ids don't match on the activity center notifications")
self.home_1.just_fyi("Confirm pairing request on device 1")
self.home_1.element_by_translation_id('pair-and-sync').click()
self.home_2.element_by_translation_id('close').click()
self.home_1.close_activity_centre.click()
self.home_2.close_activity_centre.click()
self.home_3.chats_tab.is_element_displayed() # just pinging 3rd device to save the connection
self.home_1.just_fyi("Device 1: Check that the device 2 is shown in paired devices list")
self.home_1.profile_button.click()
self.profile_1.syncing_button.scroll_and_click()
self.profile_1.paired_devices_button.click()
device_element = self.profile_1.get_paired_device_by_name(device_2_name)
if device_element.is_element_displayed():
if not device_element.get_unpair_button.is_element_displayed():
self.errors.append(
"Unpair button is absent for the device 2 inside Paired devices list of profile 1 after pairing")
else:
self.errors.append("Device 2 is not shown in Paired devices list for device 1 after pairing")
self.home_2.just_fyi("Device 2: Check that the device 1 is shown paired devices list")
self.home_2.profile_button.click()
self.profile_2.syncing_button.scroll_and_click()
self.profile_2.paired_devices_button.click()
device_element = self.profile_2.get_paired_device_by_name(device_1_name)
if device_element.is_element_displayed():
if not device_element.get_unpair_button.is_element_displayed():
self.errors.append(
"Unpair button is absent for the device 1 inside Paired devices list of profile 2 after pairing")
else:
self.errors.append("Device 1 is not shown in Paired devices list for device 2 after pairing")
self.home_3.just_fyi("Device 3: send a message to user 1")
self.home_3.chats_tab.click()
chat_3 = self.home_3.get_chat(self.user_name_1).click()
message = "Test message"
chat_3.send_message(message)
def _check_message(home_view, index):
home_view.just_fyi("Device %s: check the message from the user 3 is received" % index)
home_view.click_system_back_button(times=3)
home_view.chats_tab.click()
try:
chat_element = home_view.get_chat(self.user_name_3)
chat_element.wait_for_visibility_of_element(60)
chat_view = chat_element.click()
chat_view.chat_element_by_text(message).wait_for_visibility_of_element(60)
except TimeoutException:
self.errors.append("Message is not received by the user %s" % index)
self.loop.run_until_complete(
run_in_parallel(((_check_message, {'home_view': self.home_1, 'index': 1}),
(_check_message, {'home_view': self.home_2, 'index': 2}))))
self.errors.verify_no_errors()
@marks.testrail_id(740222)
def test_fallback_validate_seed_phrase(self):
self.sign_in_2.reopen_app(sign_in=False)
self.sign_in_2.just_fyi("Device 2: try syncing profile")
self.sign_in_2.sync_profile(sync_code=self.sync_code, first_user=False)
self.sign_in_2.progress_screen_title.wait_for_element()
assert self.sign_in_2.progress_screen_title.text == "Oops, somethings wrong"
self.sign_in_2.just_fyi("Device 2: try invalid passphrase")
self.sign_in_2.try_seed_phrase_button.click()
self.sign_in_2.passphrase_edit_box.send_keys(' '.join(['asset'] * 12))
self.sign_in_2.continue_button.click()
if not self.sign_in_2.element_by_translation_id('seed-phrase-invalid').is_element_displayed():
self.errors.append("Error message is not displayed for invalid recovery phrase")
self.sign_in_2.just_fyi("Device 2: try creating an account with another valid passphrase")
self.sign_in_2.passphrase_edit_box.clear()
self.sign_in_2.passphrase_edit_box.send_keys(transaction_senders['A']['passphrase'])
self.sign_in_2.continue_button.click()
if not self.sign_in_2.profile_title_input.is_element_displayed():
self.errors.append("Can't recover an access with a valid passphrase")
self.sign_in_2.click_system_back_button()
self.sign_in_2.just_fyi("Device 2: try recovering an account which is already synced")
self.sign_in_2.passphrase_edit_box.clear()
self.sign_in_2.passphrase_edit_box.send_keys(self.recovery_phrase)
self.sign_in_2.continue_button.click()
try:
self.sign_in_2.native_alert_title.wait_for_element()
shown_text = self.sign_in_2.native_alert_title.text
if shown_text != "Keys for this account already exist":
self.errors.append("Incorrect error message '%s' is shown for already synced account" % shown_text)
self.sign_in_2.cancel_button.click()
except TimeoutException:
self.errors.append("Error is not shown for already synced account")
self.errors.verify_no_errors()
+7 -8
View File
@@ -298,13 +298,14 @@ class BaseView(object):
self.deny_button = Button(self.driver, translation_id="deny", uppercase=True)
self.continue_button = Button(self.driver, translation_id="continue", uppercase=True)
self.ok_button = Button(self.driver, xpath="//*[@text='OK' or @text='Ok']")
self.next_button = Button(self.driver, translation_id="next")
self.add_button = Button(self.driver, translation_id="add")
self.save_button = Button(self.driver, translation_id="save")
self.done_button = Button(self.driver, accessibility_id="Done")
self.done_button = Button(self.driver, translation_id="done")
self.delete_button = Button(self.driver, translation_id="delete", uppercase=True)
self.ok_continue_button = Button(self.driver, accessibility_id="Okay, continue")
self.ok_continue_button = Button(self.driver, xpath="//*[@text='OK, CONTINUE' or @text='Okay, continue']")
self.discard_button = Button(self.driver, xpath="//*[@text='DISCARD']")
self.confirm_button = Button(self.driver, accessibility_id='Confirm')
self.confirm_button = Button(self.driver, translation_id='confirm', uppercase=True)
self.cross_icon = Button(self.driver, xpath="(//android.widget.ImageView[@content-desc='icon'])[1]")
self.close_sticker_view_icon = Button(self.driver, xpath="//androidx.appcompat.widget.LinearLayoutCompat")
@@ -313,7 +314,7 @@ class BaseView(object):
self.navigate_up_button = Button(self.driver, accessibility_id="Navigate Up")
self.show_roots_button = Button(self.driver, accessibility_id="Show roots")
self.get_started_button = Button(self.driver, translation_id="get-started")
self.ok_got_it_button = Button(self.driver, accessibility_id="Okay, got it")
self.ok_got_it_button = Button(self.driver, translation_id="ok-got-it")
self.cross_icon_inside_welcome_screen_button = Button(self.driver, accessibility_id='hide-home-button')
self.status_in_background_button = Button(self.driver, xpath="//*[contains(@content-desc,'Status')]")
self.cancel_button = Button(self.driver, translation_id="cancel", uppercase=True)
@@ -323,7 +324,6 @@ class BaseView(object):
self.sign_in_phrase = SignInPhraseText(self.driver)
self.toast_content_element = BaseElement(self.driver, accessibility_id="toast-content")
self.next_button = Button(self.driver, accessibility_id="next-button")
self.native_alert_title = Text(self.driver, xpath="//*[@resource-id='android:id/alertTitle']")
# share contact screen
self.show_qr_code_button = Button(self.driver, accessibility_id="show-qr-button")
@@ -332,8 +332,7 @@ class BaseView(object):
self.sharing_text_native = Text(self.driver, xpath="//*[@resource-id='android:id/content_preview_text']")
# checkboxes and toggles
self.checkbox_button = CheckBox(
self.driver, xpath="//*[@content-desc='checkbox-off'][@resource-id='checkbox-component']")
self.checkbox_button = CheckBox(self.driver, accessibility_id="checkbox-off")
self.slide_button_track = SlideButton(self.driver)
# external browser
@@ -771,7 +770,7 @@ class BaseView(object):
self.close_native_device_dialog("MmsService")
def set_device_to_offline(self):
# setting network connection to data only and switching off Wi-Fi
# setting network connection to data only and switching off wifi
self.driver.set_network_connection(2)
self.driver.toggle_wifi()
-13
View File
@@ -152,14 +152,6 @@ class ActivityCenterElement(SilentButton):
def pending_status_tag(self):
return Text(self.driver, xpath=self.locator + '//*[@content-desc="status-tag-pending"]')
@property
def review_pairing_request_button(self):
return Button(self.driver, accessibility_id='Review pairing request')
@property
def more_details_button(self):
return Button(self.driver, accessibility_id='More details')
def handle_cr(self, element_accessibility: str):
Button(
self.driver,
@@ -619,8 +611,3 @@ class HomeView(BaseView):
xpath="//*[@content-desc='%s'][descendant::*[@content-desc='chat-name-text'][@text='%s']]" % (
self.community_card_item.accessibility_id, community_name)
)
def get_new_device_installation_id(self):
element = Text(self.driver, accessibility_id='new-device-installation-id')
element.wait_for_visibility_of_element()
return element.text
+24 -35
View File
@@ -4,7 +4,7 @@ from selenium.common import NoSuchElementException
from tests import common_password
from tests.base_test_case import AbstractTestCase
from views.base_element import Text, Button, EditBox, SilentButton, BaseElement
from views.base_element import Text, Button, EditBox, SilentButton
from views.base_view import BaseView
@@ -68,6 +68,15 @@ class AdvancedButton(Button):
return self.navigate()
class BackupRecoveryPhraseButton(Button):
def __init__(self, driver):
super().__init__(driver, accessibility_id="back-up-recovery-phrase-button")
def click(self):
self.scroll_to_element().click()
return self.navigate()
class RecoveryPhraseTable(Text):
def __init__(self, driver):
super().__init__(driver, translation_id="your-recovery-phrase",
@@ -84,6 +93,11 @@ class RecoveryPhraseWordNumberText(Text):
return int(self.find_element().text.split('#')[1])
class RecoveryPhraseWordInput(EditBox):
def __init__(self, driver):
super(RecoveryPhraseWordInput, self).__init__(driver, xpath="//android.widget.EditText")
class HelpButton(Button):
def __init__(self, driver):
super().__init__(driver, accessibility_id="help-button")
@@ -221,13 +235,10 @@ class ProfileView(BaseView):
self.show_profile_pictures_of = Button(self.driver, accessibility_id="show-profile-pictures")
self.show_profile_pictures_to = Button(self.driver, accessibility_id="show-profile-pictures-to")
## Backup recovery phrase
self.backup_recovery_phrase_button = Button(
self.driver, accessibility_id="icon, Backup recovery phrase, label-component, icon")
self.backup_recovery_phrase_button = BackupRecoveryPhraseButton(self.driver)
self.recovery_phrase_table = RecoveryPhraseTable(self.driver)
self.recovery_phrase_word_number = RecoveryPhraseWordNumberText(self.driver)
self.recovery_phrase_next_button = Button(self.driver, accessibility_id="Next, icon")
self.recovery_phrase_word_input = EditBox(self.driver, xpath="//android.widget.EditText")
self.recovery_phrase_word_input = RecoveryPhraseWordInput(self.driver)
## Dapps permissions
self.dapp_permissions_button = DappPermissionsButton(self.driver)
self.revoke_access_button = Button(self.driver, translation_id="revoke-access")
@@ -279,8 +290,8 @@ class ProfileView(BaseView):
self.advertise_device_button = Button(self.driver, accessibility_id="advertise-device")
self.sync_all_button = Button(self.driver, translation_id="sync-all-devices")
self.syncing_button = Button(self.driver, accessibility_id="icon, Syncing, label-component, icon")
self.paired_devices_button = Button(
self.driver, xpath="//android.view.ViewGroup[contains(@content-desc,'icon, Paired devices,')]")
self.paired_devices_button = Button(self.driver,
accessibility_id="icon, Paired devices, 0 devices, label-component, icon")
self.sync_plus_button = Button(
self.driver,
xpath="//*[@text='Paired devices']/following-sibling::android.view.ViewGroup[@content-desc='icon']")
@@ -414,20 +425,20 @@ class ProfileView(BaseView):
return dict(zip(map(int, text[::2]), text[1::2]))
def backup_recovery_phrase(self):
self.just_fyi("Back up recovery phrase")
self.backup_recovery_phrase_button.click()
self.driver.info("## Back up seed phrase", device=False)
self.ok_continue_button.click()
recovery_phrase = self.get_recovery_phrase()
self.recovery_phrase_next_button.click()
self.next_button.click()
word_number = self.recovery_phrase_word_number.number
self.recovery_phrase_word_input.send_keys(recovery_phrase[word_number])
self.recovery_phrase_next_button.click()
self.next_button.click()
word_number_1 = self.recovery_phrase_word_number.number
self.recovery_phrase_word_input.send_keys(recovery_phrase[word_number_1])
self.done_button.click()
self.yes_button.click()
self.ok_got_it_button.click()
return ' '.join(recovery_phrase.values())
self.driver.info("## Seed phrase is backed up!", device=False)
return recovery_phrase
def edit_profile_picture(self, image_index: int, update_by="Gallery"):
self.driver.info("## Setting custom profile image", device=False)
@@ -544,25 +555,3 @@ class ProfileView(BaseView):
self.login_button.click()
self.wait_for_staleness_of_element(password_input)
return self.password_input.text
def get_current_device_name(self):
element = BaseElement(
self.driver,
xpath="//android.view.ViewGroup/android.view.ViewGroup[@content-desc='status-tag-positive']/..")
return element.attribute_value('content-desc').split(',')[1].strip()
def get_paired_device_by_name(self, device_name: str):
class PairedDeviceElement(BaseElement):
def __init__(self, driver, device_name):
super().__init__(driver, xpath="//*[@content-desc='icon, %s, label-component']" % device_name)
@property
def get_pair_button(self):
return Button(self.driver, xpath=self.locator + "//*[@content-desc='Pair']")
@property
def get_unpair_button(self):
return Button(self.driver, xpath=self.locator + "//*[@content-desc='Unpair']")
return PairedDeviceElement(self.driver, device_name)
+11 -37
View File
@@ -154,11 +154,6 @@ class SignInView(BaseView):
self.create_profile_button = Button(self.driver, accessibility_id='new-to-status-button')
self.not_now_button = Button(self.driver, xpath="//*[@text='Not now']")
self.sync_or_recover_profile_button = Button(self.driver, accessibility_id='already-use-status-button')
self.scan_sync_code_button = Button(self.driver, accessibility_id="scan-sync-code-option-card")
self.enter_sync_code_button = Button(self.driver, accessibility_id="Enter sync code")
self.enter_sync_code_input = EditBox(self.driver, accessibility_id="enter-sync-code-input")
self.progress_screen_title = Text(self.driver, accessibility_id="progress-screen-title")
self.try_seed_phrase_button = Button(self.driver, accessibility_id="try-seed-phrase-button")
self.migration_password_input = EditBox(self.driver, accessibility_id="enter-password-input")
self.access_key_button = AccessKeyButton(self.driver)
@@ -220,7 +215,6 @@ class SignInView(BaseView):
self.show_profiles_button = Button(self.driver, accessibility_id="show-profiles")
self.plus_profiles_button = Button(self.driver, accessibility_id="show-new-account-options")
self.create_new_profile_button = Button(self.driver, accessibility_id="create-new-profile")
self.sync_or_recover_new_profile_button = Button(self.driver, accessibility_id="multi-profile")
self.remove_profile_button = Button(self.driver, accessibility_id="remove-profile")
def set_password(self, password: str):
@@ -288,24 +282,21 @@ class SignInView(BaseView):
return self.get_home_view()
def recover_access(self, passphrase: str, password: str = common_password, keycard=False,
enable_notifications=False, second_user=False, username='Restore user', set_image=False,
after_sync_code=False):
enable_notifications=False, second_user=False, username='Restore user', set_image=False):
self.driver.info("## Recover access(password:%s, keycard:%s)" % (password, str(keycard)), device=False)
if not after_sync_code:
if not second_user:
self.terms_and_privacy_checkbox.click()
self.sync_or_recover_profile_button.click_until_presence_of_element(self.generate_keys_button)
self.not_now_button.wait_and_click()
else:
self.show_profiles_button.wait_and_click(20)
self.plus_profiles_button.click()
self.create_new_profile_button.click()
self.use_recovery_phrase_button.click()
if not second_user:
self.terms_and_privacy_checkbox.click()
self.sync_or_recover_profile_button.click_until_presence_of_element(self.generate_keys_button)
self.not_now_button.wait_and_click()
else:
self.show_profiles_button.wait_and_click(20)
self.plus_profiles_button.click()
self.create_new_profile_button.click()
self.use_recovery_phrase_button.click()
self.passphrase_edit_box.send_keys(passphrase)
self.continue_button.click_until_presence_of_element(self.profile_title_input)
if not after_sync_code:
self.set_profile(username, set_image)
self.set_profile(username, set_image)
self.set_password(password)
if enable_notifications:
self.enable_notifications_button.wait_and_click()
@@ -327,23 +318,6 @@ class SignInView(BaseView):
self.driver.info("## Multiaccount is recovered successfully!", device=False)
return self.get_home_view()
def sync_profile(self, sync_code: str, first_user: bool = True):
if first_user:
self.terms_and_privacy_checkbox.click()
self.sync_or_recover_profile_button.click()
self.not_now_button.click()
else:
self.show_profiles_button.click()
self.plus_profiles_button.click()
self.sync_or_recover_new_profile_button.click()
self.scan_sync_code_button.click()
for checkbox in self.checkbox_button.find_elements():
checkbox.click()
self.continue_button.click()
self.enter_sync_code_button.click()
self.enter_sync_code_input.send_keys(sync_code)
self.confirm_button.click()
def sign_in(self, password=common_password):
self.driver.info("## Sign in (password: %s)" % password, device=False)
self.password_input.wait_for_visibility_of_element(10)
-34
View File
@@ -163,7 +163,6 @@
"audio-recorder-max-ms-reached": "Maximum recording time reached",
"audio-recorder-permissions-error": "You have to give permission to send audio messages",
"aug": "Aug",
"authorise-with-password": "Authorise with password",
"authorize": "Authorize",
"available": "Available",
"available-participants": {
@@ -275,7 +274,6 @@
"buy-crypto-title": "Looks like your wallet is empty",
"buy-eth": "Buy ETH",
"buy-ethereum": "Buy Ethereum",
"buy-keycard": "Buy Keycard",
"by-continuing-you-accept": "By continuing you accept our ",
"camera-access-error": "To grant the required camera permission, please go to your system settings and make sure that Status > Camera is selected.",
"camera-permission-denied": "Permission denied",
@@ -364,7 +362,6 @@
"check-before-syncing-doc-checkbox-2": "Make sure you are logged in on the other device",
"check-before-syncing-doc-checkbox-3": "Disable the firewall and VPN on your devices",
"check-before-syncing-doc-description": "To sync your devices successfully, make sure to check and complete these steps:",
"check-keycard": "Check your Keycard",
"check-on-block-explorer": "Check on block explorer",
"check-on-opensea": "Check on opensea",
"check-other-device-for-pairing": "Check your other device for a pairing request.",
@@ -473,7 +470,6 @@
"connect-with-users": "Connect with users",
"connected": "Connected",
"connected-dapps": "Connected dApps",
"connected-dont-move": "Connected. Dont move your card.",
"connected-peers": "Connected and discovered peers",
"connected-to": "Connected to",
"connecting": "Connecting...",
@@ -540,7 +536,6 @@
"create-channel-title": "New channel",
"create-community": "Create a community",
"create-group-chat": "Create group chat",
"create-keycard-pin": "Create Keycard PIN",
"create-multiaccount": "Generate keys",
"create-new-key": "Get new keys",
"create-new-profile": "Create new profile",
@@ -832,7 +827,6 @@
"emojihash-description": "A visual representation of your chat key. It will help other users recognize your profile.",
"emojis": "Emojis",
"empty-activity-center": "Your chat notifications\nwill appear here",
"empty-card-info": "To generate new key pair, or import existent non-profile keys to the Keycard, please use the Status desktop app. If you'd like these features on mobile, feel free to upvote them and discuss them in Status community.",
"empty-chat-description": "There are no messages \nin this chat yet",
"empty-chat-description-community": "It's been quiet here for the last {{quiet-hours}}.",
"empty-chat-description-one-to-one": "Any messages you send here are encrypted and can only be read by you and ",
@@ -1079,7 +1073,6 @@
"generating-mnemonic": "Generating seed phrase",
"generic-error": "Error: {{generic-error}}",
"get-a-keycard": "Get a Keycard",
"get-keycard": "Get Keycard",
"get-started": "Get started",
"get-status-at": "Get Status at http://status.im",
"get-stickers": "Get Stickers",
@@ -1139,7 +1132,6 @@
"history-nodes": "Status nodes",
"hit-photos-limit": "You can only add {{max-photos}} photos to your message",
"hold-card": "Hold card to the back\n of your phone",
"hold-phone-near-keycard": "Hold your phone near a Status Keycard",
"hold-to-post-1": "Hold",
"hold-to-post-2": "to post",
"home": "Home",
@@ -1175,12 +1167,10 @@
"import-community-title": "Import a community",
"import-from-keycard": "Import from Keycard",
"import-key-pair": "Import key pair",
"import-key-pair-keycard": "Import profile key pair to Keycard",
"import-keypair-steps": "{{account-name}} was derived from your {{keypair-name}} key pair, which has not yet been imported to this device. To transact using this account, you will need to import the {{keypair-name}} key pair first.",
"import-keypair-to-use-account": "Import key pair to use this account",
"import-private-key": "Import private key",
"import-private-key-info": "New addresses cannot be derived from an account imported from a private key. Import using a seed phrase if you wish to derive addresses.",
"import-profile-key-pair": "Import profile key pair",
"import-to-use-derived-accounts": "Import to use derived accounts",
"import-using-phrase": "Import using recovery phrase",
"in": "in",
@@ -1305,7 +1295,6 @@
"jump-to": "Jump to",
"jun": "Jun",
"K": "K",
"keep-card-steady": "Keep the card steady under the phone",
"keep-key": "KeepKey",
"key": "Key",
"key-managment": "Key management",
@@ -1335,7 +1324,6 @@
"keycard-connected-title": "Connected",
"keycard-desc": "Own a Keycard? Store your keys on it; youll need it for transactions",
"keycard-dont-ask-card": "Don't ask for card to sign in",
"keycard-empty": "Keycard is empty",
"keycard-enter-new-passcode": "Enter new passcode {{step}}/2",
"keycard-error-description": "Connect the card again to continue",
"keycard-error-title": "Connection lost",
@@ -1490,7 +1478,6 @@
"make-admin": "Make admin",
"make-moderator": "Make moderator",
"make-one-it-is-easy-we-promise": "Make one, its easy, we promise!",
"make-sure-keycard": "Make sure the card you scanned is a Keycard.",
"make-sure-no-camera-warning": "Make sure no camera or person can see this screen before revealing",
"manage-connections": "Manage connections from within Application Connections",
"manage-keys-and-storage": "Manage keys and storage",
@@ -1570,10 +1557,6 @@
"messages-from-contacts-only-subtitle": "Only people you added as contacts can start a new chat with you or invite you to a group",
"messages-gap-warning": "Some messages might be missing",
"might-break": "Might break some ÐApps",
"migrate-key-pair-authorise": "To migrate profile key pair to Keycard you need to authorise with profile password.",
"migrate-key-pair-keycard": "Migrate profile key pair to Keycard",
"migrate-key-pair-keycard-default-key": "{{name}} is your default Status key pair. Migrating this key pair to Keycard will require you to use your Keycard to login to Status and to transact with the key pairs derived accounts on all synced devices.\n\nKey pair will be removed from device and stored on Keycard.",
"migrate-key-pair-keycard-info": "Re-encrypting your data with your new Keycard login method may take some time, during which you wont be able to use the app.",
"migration-successful": "Migration successful",
"migration-successful-text": "Account succesfully migrated to Keycard",
"migrations-failed-content": "{{message}}\nschema version: initial {{initial-version}}, current {{current-version}}, last {{last-version}}\n\nA database error occured. Your funds and chat key are safe. Other data, like your chats and contacts, cannot be restored. \"{{erase-multiaccounts-data-button-text}}\" button, will remove all other data and allows you to access your funds and send messages.",
@@ -1797,7 +1780,6 @@
"on-keycard": "On Keycard",
"on-status-tree": "On Status tree",
"on-the-web": "On the web",
"on-uppercase": "On",
"once-enabled-share-metadata": "Once enabled, links posted in the chat may share your metadata with the site",
"one-day": "One day",
"one-month": "One month",
@@ -1812,7 +1794,6 @@
"online-community-member": "Online",
"online-now": "Online now",
"only-mentions": "Only @mentions",
"oops-not-keycard": "Oops, this isnt a Keycard",
"oops-this-qr-does-not-contain-an-address": "Oops! This QR does not contain an address",
"oops-wrong-password": "Oops, wrong password!",
"oops-wrong-word": "Oops! Wrong word",
@@ -1843,7 +1824,6 @@
"outgoing": "Outgoing",
"outgoing-transaction": "Outgoing transaction",
"overview": "Overview",
"own-keycard": "Already own a Keycard?",
"own-your-crypto": "Own your crypto",
"owner": "Owner",
"page-camera-request-blocked": "camera requests blocked. To enable camera requests go to Settings",
@@ -1932,7 +1912,6 @@
"pin-code": "6-digit passcode",
"pin-limit-reached": "Pin limit reached. Unpin a previous message first.",
"pin-mismatch": "Wrong passcode",
"pin-not-match": "PIN do not match",
"pin-one-attempt": " one attempt ",
"pin-one-attempt-blocked-after": "before your Keycard gets blocked",
"pin-one-attempt-blocked-before": "Be careful, you have only",
@@ -2025,8 +2004,6 @@
"re-encrypt-key": "Re-encrypt your keys",
"read": "Read",
"read-more": "Read more",
"ready-keycard": "Get your Keycard ready",
"ready-to-scan": "Ready to Scan",
"rearrange-categories": "Rearrange Categories",
"receive": "Receive",
"receive-at-least": "Receive at least",
@@ -2081,7 +2058,6 @@
"remove-network": "Remove network",
"remove-nickname": "Remove nickname",
"remove-nickname-toast": "You have removed {{secondary-name}}'s nickname",
"remove-phone-case": "Remove your phone case if you have one",
"remove-private-key-address-desc": "The account will be removed from all of your synced devices. Make sure you have a backup of your key pair or recovery phrase.",
"remove-profile-confirm-message": "All profile data will removed from device.",
"remove-profile-message": "Remove profile from this device",
@@ -2096,7 +2072,6 @@
"removed-from-contacts": "Removed from contacts",
"rename": "Rename",
"rename-key-pair": "Rename key pair",
"repeat-keycard-pin": "Repeat Keycard PIN",
"repeat-pin": "Repeat new 6-digit passcode",
"repeat-puk": "Repeat new 12-digit PUK",
"replied": "Replied",
@@ -2191,11 +2166,9 @@
"searching-for-activity": "Searching for activity...",
"secret-keys-confirmation-text": "You will need them to continue to use your Keycard in case you ever lose your phone.",
"secret-keys-confirmation-title": "Written the codes down?",
"secure-wallet-card": "A secure and private cold wallet in a card format",
"security": "Security",
"see-details": "See details",
"see-it-again": "SEE IT AGAIN",
"see-keycard-ready": "Lets see whats on your Keycard. Ready?",
"see-recovery-phrase-again": "See recovery phrase again",
"see-sticker-set": "See the full sticker set",
"see-suggestions": "See suggestions",
@@ -2218,13 +2191,11 @@
"select-another-account": "Select another account",
"select-asset": "Select asset",
"select-asset-on": "On",
"select-asset-to-buy": "Select asset to buy",
"select-asset-to-pay": "Select asset to pay",
"select-asset-to-receive": "Select asset to receive",
"select-asset-via": "via",
"select-chat": "Select chat to start messaging",
"select-network": "Select network",
"select-network-for-buying": "Select network for buying",
"select-networks": "Select networks",
"select-new-location-for-keys": "Select a new location to save your private key(s)",
"select-token-to-receive": "Select token to receive",
@@ -2277,7 +2248,6 @@
"set-up-sync": "Set up sync",
"settings": "Settings",
"setup-group-chat": "Setup group chat",
"setup-keycard": "Setup Keycard",
"setup-syncing": "Pair devices to sync",
"share": "Share",
"share-account": "Share account",
@@ -2345,7 +2315,6 @@
"signing-phrase": "Signing phrase",
"simple": "Simple",
"skip": "Skip",
"slide-to-authorise": "Slide to authorise",
"slide-to-bridge": "Slide to bridge",
"slide-to-create-account": "Slide to create account",
"slide-to-import": "Slide to import",
@@ -2503,7 +2472,6 @@
"time-in-mins": "{{minutes}} min",
"timeline": "Timeline",
"tip-cap": "Tip cap",
"tips-scan-keycard": "Tips to scan your Keycard",
"to": "to",
"to-block": "Block",
"to-capitalized": "To",
@@ -2658,7 +2626,6 @@
"use-as-profile-picture": "Use as profile picture",
"use-biometrics": "Use biometrics to fill in your password",
"use-keycard": "Use Keycard",
"use-keycard-login-sign": "Use this Keycard to login and sign transactions",
"use-keycard-subtitle": "Keys will be stored on your Keycard",
"use-photo": "Use Photo",
"use-recovery-phrase": "Use recovery phrase",
@@ -2803,7 +2770,6 @@
"what-are-you-waiting-for": "What are you waiting for?",
"what-changed": "What changed",
"what-is-shared": "What is shared",
"what-to-do": "What you would like to do?",
"what-we-will-receive": "What we will receive:",
"what-we-wont-receive": "What we won't receive:",
"whats-on-your-mind": "Whats on your mind…",