Compare commits

..
Author SHA1 Message Date
pavloburykh a81151be3a check status go 5925 2025-02-03 13:07:40 +02:00
Brian Sztamfater 1da39e064d fix: prevent receiving routes for unsupported receiving chains on bridge flow (#21980)
https://github.com/status-im/status-go/compare/bec0c373...dcce8e9b

Signed-off-by: Brian Sztamfater <brian@status.im>
2025-02-03 00:46:42 -03:00
flexsurfer 3899368aa0 [#21930] Keycard - Back up keycard (#21990) 2025-01-31 18:42:08 +01:00
Yevheniia Berdnyk 5ff1c8f1e4 e2e: added wallet test for bridge flow 2025-01-30 20:13:34 +02:00
Brian Sztamfater 7289940653 fix: swap fees are not displayed if route estimated time is nil (#22001)
Signed-off-by: Brian Sztamfater <brian@status.im>
2025-01-30 10:08:37 -03:00
Yevheniia Berdnyk a253f8cedb e2e: updated tests with editing profile when starting chat 2025-01-30 11:49:58 +02:00
Ulises Manuel daf52102ce feat(onboarding): ask user to update their profile (#21862)
* Add `buttons-style` prop to bottom actions to allow same button dimensions

* Make events to update a profile more generic

* Fix tests

* Add modal screen to update the profile

* Add introduce yourself modal

* Ask user to update their profile before sending a message or contact request

* Fix color picker selected styles

* Remove some `:f>` now unnecessary

* No longer shows the modal if the user manually updates their profile
2025-01-29 19:50:01 -06:00
Yevheniia Berdnyk fa20d4d9c3 e2e: added wallet tests for send and swap flows on mainnet 2025-01-29 18:32:03 +02:00
Parvesh Monu dd26fcf42c Add Documentation drawer on Check your Keycard screen (#21997) 2025-01-29 19:25:34 +05:30
Lungu Cristian 8ac9cc08e1 Keycard signing for dapp interactions (#21785)
* feat: wip dapps signing with keycard

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* fix: hide the pin sheet before showing the connection sheet

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* fix: signing dapp request with password

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* fix: logic for getting the current dapp

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* fix: issues after endpoints update

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* feat: removed support for eth_sign and signTransaction

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* fix: removed unused event

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* feat: re-enable dapps interactions with keycard

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* fix: adapted to latest standard-auth changes

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* feat: enable connected dapps for keycard

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* ref: removed threading (->)

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* fix: get keycard keypair addresses manually

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* fix: wrong condition on utils/keycard-address?

---------

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>
2025-01-28 17:33:34 +02:00
Siddarth Kumar c1230319e1 nix: add fake git to status-go build derivation (#21989)
This commit adds a script that overrides `git` to echo version required by `status-go` derivation.

Also fixes error messages like this when building `status-go` :
```
fatal: not a git repository (or any of the parent directories): .git
```

These messages can be often misleading to some developers.
2025-01-27 18:14:27 +05:30
Lungu Cristian 1e48442d67 Fix dapps transactions instantly rejected (#21973)
* fix: upgraded status-go to fixed version

https://github.com/status-im/status-go/compare/4ec885a9...a2588ee5

* fix: use status-go develop branch

https://github.com/status-im/status-go/compare/4ec885a9...e71fdbc6

* build: using status-go v9.3.0

https://github.com/status-im/status-go/compare/4ec885a9...bec0c373
2025-01-27 13:20:40 +02:00
Sean Hagstrom 94fbbbcb3c fix: resolve UI glitches for chat, contacts, and keycard (#21946)
This change resolves some issues related to text-overflow in the app, and it also ensures we use the correct drawer title when editing a user nickname.
2025-01-24 15:51:46 +00:00
Yevheniia Berdnyk 4dfd616583 e2e: additional logging for errors in tests 2025-01-23 12:46:55 +02:00
Parvesh Monu 85d00e47af Keycard - Import a seed phrase into a new Keycard (#21947) 2025-01-23 12:23:33 +05:30
Ulises Manuel 438fd7a512 fix(chat): Same QR shown code for everyone in the Contacts tab (#21949) 2025-01-22 15:26:15 -06:00
Mohsen ee5f73f5ee [#21919] fix: remove on-ramp provider description and reinstate mecuryo (#21923)
* [#21919] fix: remove on-ramp provider description and reinstate mecuryo

https://github.com/status-im/status-go/compare/59caca61...07d07601

* [#21919] fix: rebase status-go

https://github.com/status-im/status-go/compare/4ec885a9...41743c6c
2025-01-22 17:59:08 +03:00
Volodymyr Kozieiev b49c0ae58a Fix local re-frisk launch (#21972) 2025-01-22 14:43:26 +00:00
Yevheniia Berdnyk f474edf67d e2e: fix for saving logs 2025-01-22 16:03:54 +02:00
Volodymyr Kozieiev dfd90617bf Backend server doc added to readme (#21966) 2025-01-21 12:14:27 +00:00
Yevheniia Berdnyk 9782ba2ac3 e2e: added verifications to fallback test 2025-01-21 11:54:44 +02:00
Brian Sztamfater f0e0c95fe0 feat: integrate base chain (#21876)
Signed-off-by: Brian Sztamfater <brian@status.im>
2025-01-21 01:44:02 -03:00
Mohsen ef7d977299 [#21305] fix: sort assets by value and collectibles by name (#21908)
* [#21305] fix: sort assets by value and collectibles by name

* [#21305] fix: use seq to check name is nil or empty

* [#21305] fix: normalize text to sort properly
2025-01-20 19:41:40 +03:00
Parvesh Monu 70a5ed255f fix keycard sign up ui issues (#21938) 2025-01-20 17:22:13 +05:30
flexsurfer be1347346c [#21578] Keycard - Factory reset a Keycard (#21914) 2025-01-20 12:35:06 +01:00
Volodymyr Kozieiev 803e83ae02 Screens for editing transaction settings (#21838)
* Screens for editing transaction settings

* extra lines removed

* review notes fixed
2025-01-20 11:21:55 +00:00
Yevheniia Berdnyk 64748c939b e2e: fix for test_community_mentions_push_notification 2025-01-20 03:33:27 +02:00
Sean Hagstrom 64fb344197 chore: add support for remote devices with re-frisk server (#21805)
This changes adds support for connecting remotely to re-frisk when running the app on a mobile device. This change is essentially aimed towards better support for introspecting on iOS devices, but these changes should also work for Android devices too. Note, that running in the Android simulator may still require port-forwarding with `adb reverse`.
2025-01-18 05:57:17 +00:00
Sean Hagstrom f27b402205 chore: update status-go with identity images fixes (#21931)
This change integrates status-go changes that fix an underlying issue with generating identity images. Now identity images will be generated with a populated `clock` field, so we no longer need our existing workaround.
2025-01-18 05:37:37 +00:00
Icaro Motta b22744f81e fix(settings): Show current mailserver in legacy settings (#21901)
A regression removed more code than we wanted in
https://github.com/status-im/status-mobile/pull/20730 and the result was
broken functionality in the Legacy settings.

We now show the current mailserver correctly. The data is kept in sync via
signals, just as the original code.

Fixes https://github.com/status-im/status-mobile/issues/21375
2025-01-17 14:26:20 -03:00
Mohamed Javid 174e44c77d fix(wallet)_: Dismiss collectible details screen after a is TX placed (#21909)
This commit fixes the user is not taken to the activity tab after the TX is placed if the user enters the send flow from collectible details screen (inside the account)

Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com>
2025-01-16 21:57:06 +05:30
150 changed files with 3315 additions and 1343 deletions
+4 -2
View File
@@ -267,9 +267,11 @@ run-metro: export TARGET := clojure
run-metro: ##@run Start Metro to build React Native changes
@scripts/run-metro.sh
export RE_FRISK_PORT ?= 4567
run-re-frisk: export TARGET := clojure
run-re-frisk: ##@run Start re-frisk server
yarn shadow-cljs run re-frisk-remote.core/start
yarn shadow-cljs run re-frisk-remote.core/start ${RE_FRISK_PORT}
# TODO: Migrate this to a Nix recipe, much the same way as nix/mobile/android/targets/release-android.nix
run-android: export TARGET := android
@@ -443,7 +445,7 @@ android-ports: export RCT_METRO_PORT ?= 8081
android-ports: ##@other Add proxies to Android Device/Simulator
adb reverse tcp:$(RCT_METRO_PORT) tcp:$(RCT_METRO_PORT) && \
adb reverse tcp:3449 tcp:3449 && \
adb reverse tcp:4567 tcp:4567 && \
adb reverse tcp:$(RE_FRISK_PORT) tcp:$(RE_FRISK_PORT) && \
adb reverse tcp:$(FLOWSTORM_PORT) tcp:$(FLOWSTORM_PORT) && \
adb forward tcp:5561 tcp:5561
+1
View File
@@ -16,6 +16,7 @@
- [Patching](patching.md)
- [Creating a pixel perfect UI](pixel-perfection.md)
- [Contributing to status-go](status-go-changes.md)
- [Status Backend Server](use-status-backend-server.md)
- [Malli schemas (recorded demo)](https://www.youtube.com/watch?v=SlRio70aYVI) ([slides](files/forging-code-with-schemas-sep-2023-slides.pdf))
## Testing
+4 -2
View File
@@ -1,4 +1,4 @@
{ callPackage, lib, buildGoPackage
{ callPackage, lib, buildGoPackage, pkgs
, androidPkgs, openjdk, gomobile, xcodeWrapper, removeReferencesTo
, go-bindata, mockgen, protobuf3_20, protoc-gen-go
, meta
@@ -15,6 +15,8 @@ let
isIOS = platform == "ios";
isAndroid = platform == "android";
enforceXCodeAvailable = callPackage ./enforceXCodeAvailable.nix { };
# Fixes fatal: not a git repository (or any of the parent directories): .git
fakeGit = pkgs.writeScriptBin "git" "echo ${source.version}";
in buildGoPackage rec {
pname = source.repo;
@@ -29,7 +31,7 @@ in buildGoPackage rec {
extraSrcPaths = [ gomobile ];
nativeBuildInputs = [
gomobile removeReferencesTo go-bindata mockgen protoc-gen-go protobuf3_20
gomobile removeReferencesTo go-bindata mockgen protoc-gen-go protobuf3_20 fakeGit
] ++ optional isAndroid openjdk
++ optional isIOS xcodeWrapper;
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 156 KiB

+2
View File
@@ -37,6 +37,8 @@ SECRETS_ENV_VARS=(
'ALCHEMY_ARBITRUM_SEPOLIA_TOKEN'
'ALCHEMY_OPTIMISM_MAINNET_TOKEN'
'ALCHEMY_OPTIMISM_SEPOLIA_TOKEN'
'ALCHEMY_BASE_MAINNET_TOKEN'
'ALCHEMY_BASE_SEPOLIA_TOKEN'
'RARIBLE_MAINNET_API_KEY'
'RARIBLE_TESTNET_API_KEY'
'INFURA_TOKEN'
+9 -3
View File
@@ -58,7 +58,7 @@
:preloads [;; The official recommendation is to
;; load the debugger preload first.
flow-storm.api
re-frisk-remote.preload
dev.re-frisk-preload
status-im.setup.schema-preload
;; In order to use component test helpers in the REPL we need to
;; preload namespaces that are not normally required by
@@ -87,7 +87,9 @@
status-im.config/ALCHEMY_ARBITRUM_MAINNET_TOKEN #shadow/env "ALCHEMY_ARBITRUM_MAINNET_TOKEN"
status-im.config/ALCHEMY_ARBITRUM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_ARBITRUM_SEPOLIA_TOKEN"
status-im.config/ALCHEMY_OPTIMISM_MAINNET_TOKEN #shadow/env "ALCHEMY_OPTIMISM_MAINNET_TOKEN"
status-im.config/ALCHEMY_OPTIMISM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_OPTIMISM_SEPOLIA_TOKEN"}
status-im.config/ALCHEMY_OPTIMISM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_OPTIMISM_SEPOLIA_TOKEN"
status-im.config/ALCHEMY_BASE_MAINNET_TOKEN #shadow/env "ALCHEMY_BASE_MAINNET_TOKEN"
status-im.config/ALCHEMY_BASE_SEPOLIA_TOKEN #shadow/env "ALCHEMY_BASE_SEPOLIA_TOKEN"}
:compiler-options {:output-feature-set :es5
;; We disable `:fn-deprecated` warnings because we
;; are managing deprecation via clj-kondo and we
@@ -123,7 +125,9 @@
status-im.config/ALCHEMY_ARBITRUM_MAINNET_TOKEN #shadow/env "ALCHEMY_ARBITRUM_MAINNET_TOKEN"
status-im.config/ALCHEMY_ARBITRUM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_ARBITRUM_SEPOLIA_TOKEN"
status-im.config/ALCHEMY_OPTIMISM_MAINNET_TOKEN #shadow/env "ALCHEMY_OPTIMISM_MAINNET_TOKEN"
status-im.config/ALCHEMY_OPTIMISM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_OPTIMISM_SEPOLIA_TOKEN"}
status-im.config/ALCHEMY_OPTIMISM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_OPTIMISM_SEPOLIA_TOKEN"
status-im.config/ALCHEMY_BASE_MAINNET_TOKEN #shadow/env "ALCHEMY_BASE_MAINNET_TOKEN"
status-im.config/ALCHEMY_BASE_SEPOLIA_TOKEN #shadow/env "ALCHEMY_BASE_SEPOLIA_TOKEN"}
:compiler-options {:output-feature-set :es6
;;disable for android build as there
;;is an intermittent warning with deftype
@@ -165,6 +169,8 @@
status-im.config/ALCHEMY_ARBITRUM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_ARBITRUM_SEPOLIA_TOKEN"
status-im.config/ALCHEMY_OPTIMISM_MAINNET_TOKEN #shadow/env "ALCHEMY_OPTIMISM_MAINNET_TOKEN"
status-im.config/ALCHEMY_OPTIMISM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_OPTIMISM_SEPOLIA_TOKEN"
status-im.config/ALCHEMY_BASE_MAINNET_TOKEN #shadow/env "ALCHEMY_BASE_MAINNET_TOKEN"
status-im.config/ALCHEMY_BASE_SEPOLIA_TOKEN #shadow/env "ALCHEMY_BASE_SEPOLIA_TOKEN"
status-im.config/WALLET_CONNECT_PROJECT_ID #shadow/env "WALLET_CONNECT_PROJECT_ID"}
:compiler-options
{;; needed because we override require and it
+5
View File
@@ -0,0 +1,5 @@
(ns dev.re-frisk-preload
(:require [re-frisk-remote.core :as re-frisk-remote]
[status-im.config]))
(re-frisk-remote/enable {:host (str status-im.config/re-frisk-host ":" status-im.config/re-frisk-port)})
+43
View File
@@ -0,0 +1,43 @@
(ns ^{:doc "Mailserver events and API"} legacy.status-im.mailserver.core
(:require
[legacy.status-im.multiaccounts.update.core :as multiaccounts.update]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(rf/defn handle-mailserver-changed
[{:keys [db]} ms]
(when (seq ms)
{:db (assoc db :mailserver/current-id (keyword ms))}))
(rf/defn handle-mailserver-available
[{:keys [db]} ms]
{:db (assoc db :mailserver/current-id (keyword ms))})
(rf/defn toggle-use-mailservers
[_ value]
{:json-rpc/call
[{:method "wakuext_toggleUseMailservers"
:params [value]
:on-success #(log/info "successfully toggled use-mailservers" value)
:on-error #(log/error "failed to toggle use-mailserver" value %)}]})
(rf/defn update-use-mailservers
{:events [:mailserver.ui/use-history-switch-pressed]}
[cofx use-mailservers?]
(rf/merge cofx
(multiaccounts.update/optimistic :use-mailservers? use-mailservers?)
(toggle-use-mailservers use-mailservers?)))
(defn add-mailservers
[db mailservers]
(reduce (fn [db {:keys [fleet id name] :as mailserver}]
(let [updated-mailserver
(-> mailserver
(update :id keyword)
(assoc :name (if (seq name) name id))
(dissoc :fleet))]
(assoc-in db
[:mailserver/mailservers (keyword fleet) (keyword id)]
updated-mailserver)))
db
mailservers))
@@ -1,6 +1,5 @@
(ns legacy.status-im.subs.mailservers
(:require
[legacy.status-im.fleet.core :as fleet]
[re-frame.core :as re-frame]))
(re-frame/reg-sub
@@ -17,10 +16,3 @@
:<- [:mailserver/mailservers]
(fn [[current-fleet mailservers]]
(current-fleet mailservers)))
(re-frame/reg-sub
:mailserver/preferred-id
:<- [:profile/profile]
(fn [multiaccount]
(get-in multiaccount
[:pinned-mailservers (fleet/current-fleet-sub multiaccount)])))
-5
View File
@@ -38,11 +38,6 @@
;;mailserver
(reg-root-key-sub :mailserver/current-id :mailserver/current-id)
(reg-root-key-sub :mailserver/mailservers :mailserver/mailservers)
(reg-root-key-sub :mailserver.edit/mailserver :mailserver.edit/mailserver)
(reg-root-key-sub :mailserver/state :mailserver/state)
(reg-root-key-sub :mailserver/pending-requests :mailserver/pending-requests)
(reg-root-key-sub :mailserver/request-error? :mailserver/request-error)
(reg-root-key-sub :mailserver/fetching-gaps-in-progress :mailserver/fetching-gaps-in-progress)
;;contacts
(reg-root-key-sub :contacts/contacts-raw :contacts/contacts)
@@ -1,41 +0,0 @@
(ns legacy.status-im.ui.screens.offline-messaging-settings.styles
(:require
[legacy.status-im.ui.components.colors :as colors]
[legacy.status-im.utils.styles :as styles]))
(def wrapper
{:flex 1})
(styles/defn mailserver-item
[]
{:flex-direction :row
:align-items :center
:justify-content :space-between
:padding-horizontal 16
:ios {:height 64}
:android {:height 56}})
(def mailserver-item-name-text
{:typography :title})
(def switch-container
{:height 52})
(def automatic-selection-container
{:border-top-width 1
:border-top-color colors/gray-lighter
:margin-top 16})
(def explanation-text
{:color colors/gray})
(def use-history-explanation-text-container
{:margin-right 16
:margin-left 16
:margin-top 8
:margin-bottom 16})
(def history-nodes-label
{:color colors/gray
:padding-horizontal 16
:margin-top 48})
@@ -1,88 +0,0 @@
(ns legacy.status-im.ui.screens.offline-messaging-settings.views
(:require-macros [legacy.status-im.utils.views :as views])
(:require
[legacy.status-im.ui.components.colors :as colors]
[legacy.status-im.ui.components.core :as quo]
[legacy.status-im.ui.components.icons.icons :as icons]
[legacy.status-im.ui.components.list.views :as list]
[legacy.status-im.ui.components.react :as react]
[legacy.status-im.ui.components.topbar :as topbar]
[legacy.status-im.ui.screens.offline-messaging-settings.styles :as styles]
[legacy.status-im.ui.screens.profile.components.views :as profile.components]
[re-frame.core :as re-frame]
[utils.i18n :as i18n]))
(defn pinned-state
[pinned?]
[react/view {:style styles/automatic-selection-container}
[react/view {:style styles/switch-container}
[profile.components/settings-switch-item
{:label-kw :t/mailserver-automatic
:value (not pinned?)
:action-fn #(if pinned?
(re-frame/dispatch [:mailserver.ui/unpin-pressed])
(re-frame/dispatch [:mailserver.ui/pin-pressed]))}]]
[react/view {:style {:padding-horizontal 16}}
[react/text {:style styles/explanation-text}
(i18n/label :t/mailserver-automatic-switch-explanation)]]])
(defn render-row
[{:keys [name id custom]} _ _ {:keys [current-mailserver-id preferred-mailserver-id]}]
(let [pinned? preferred-mailserver-id
connected? (= id current-mailserver-id)
visible? (or pinned? ; show everything when auto selection is turned off
(and (not pinned?) ; auto selection turned on
(= current-mailserver-id id)))] ; show only the selected server
(when visible?
[react/touchable-highlight
{:on-press (when pinned?
#(if custom
(re-frame/dispatch [:mailserver.ui/custom-mailserver-selected id])
(re-frame/dispatch [:mailserver.ui/default-mailserver-selected id])))
:accessibility-label :mailserver-item}
[react/view (styles/mailserver-item)
[react/text {:style styles/mailserver-item-name-text}
name]
(if pinned?
[quo/radio {:value connected?}]
[icons/icon :check {:color colors/blue}])]])))
(views/defview offline-messaging-settings
[]
(views/letsubs [current-mailserver-id [:mailserver/current-id]
preferred-mailserver-id [:mailserver/preferred-id]
mailservers [:mailserver/fleet-mailservers]
{:keys [use-mailservers?]} [:profile/profile]]
[react/view {:style styles/wrapper}
[topbar/topbar
{:title (i18n/label :t/history-nodes)
:right-accessories
[{:icon :main-icons/add-circle
:on-press #(re-frame/dispatch [:mailserver.ui/add-pressed])}]}]
[react/scroll-view
[react/view {:style styles/switch-container}
[profile.components/settings-switch-item
{:label-kw :t/offline-messaging-use-history-nodes
:value use-mailservers?
:action-fn #(re-frame/dispatch [:mailserver.ui/use-history-switch-pressed
(not use-mailservers?)])}]]
[react/view {:style styles/use-history-explanation-text-container}
[react/text {:style styles/explanation-text}
(i18n/label :t/offline-messaging-use-history-explanation)]]
(when use-mailservers?
[:<>
[pinned-state preferred-mailserver-id]
[react/text {:style styles/history-nodes-label}
(i18n/label :t/history-nodes)]
[list/flat-list
{:data (vals mailservers)
:default-separator? false
:key-fn :name
:render-data {:current-mailserver-id current-mailserver-id
:preferred-mailserver-id preferred-mailserver-id}
:render-fn render-row}]])]]))
@@ -12,7 +12,6 @@
[legacy.status-im.ui.screens.help-center.views :as help-center]
[legacy.status-im.ui.screens.log-level-settings.views :as log-level-settings]
[legacy.status-im.ui.screens.notifications-settings.views :as notifications-settings]
[legacy.status-im.ui.screens.offline-messaging-settings.views :as offline-messaging-settings]
[legacy.status-im.ui.screens.pairing.views :as pairing]
[legacy.status-im.ui.screens.peers-stats :as peers-stats]
[legacy.status-im.ui.screens.profile.seed.views :as profile.seed]
@@ -113,9 +112,6 @@
:options {:topBar (topbar-options (i18n/label :t/devices))
:insets {:top? true}}
:component pairing/installations}
{:name :offline-messaging-settings
:options {:insets {:top? true}}
:component offline-messaging-settings/offline-messaging-settings}
{:name :rpc-usage-info
:options {:topBar (topbar-options :t/rpc-usage-info)
:insets {:top? true}}
@@ -7,6 +7,7 @@
[legacy.status-im.ui.components.react :as react]
[quo.core :as quo]
[re-frame.core :as re-frame]
[react-native.clipboard :as clipboard]
[status-im.constants :as constants]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
@@ -67,10 +68,10 @@
{:size :small
:accessibility-label :offline-messages-settings-button
:title (i18n/label :t/history-nodes)
:on-press #(re-frame/dispatch [:navigate-to :offline-messaging-settings])
:on-press (fn []
(clipboard/set-string current-mailserver-name))
:accessory :text
:accessory-text (when use-mailservers? current-mailserver-name)
:chevron true}]
:accessory-text (when use-mailservers? current-mailserver-name)}]
;; TODO(Ferossgp): Devider componemt
[react/view
{:height 1
+10 -6
View File
@@ -253,15 +253,19 @@
(defn hash-typed-data
"used for keycard"
[data callback]
(log/debug "[native-module] hash-typed-data")
(.hashTypedData ^js (encryption) data callback))
([data]
(native-utils/promisify-native-module-call hash-typed-data data))
([data callback]
(log/debug "[native-module] hash-typed-data")
(.hashTypedData ^js (encryption) data callback)))
(defn hash-typed-data-v4
"used for keycard"
[data callback]
(log/debug "[native-module] hash-typed-data-v4")
(.hashTypedDataV4 ^js (encryption) data callback))
([data]
(native-utils/promisify-native-module-call hash-typed-data-v4 data))
([data callback]
(log/debug "[native-module] hash-typed-data-v4")
(.hashTypedDataV4 ^js (encryption) data callback)))
(defn send-transaction-with-signature
"used for keycard"
+2 -1
View File
@@ -30,7 +30,8 @@
selected? (assoc :border-top-color (colors/alpha color 0.4)
:border-end-color (colors/alpha color 0.4)
:border-bottom-color (colors/alpha color 0.2)
:border-start-color (colors/alpha color 0.2))
:border-start-color (colors/alpha color 0.2)
:border-color nil)
(zero? idx) (assoc :margin-left -4))))
(defn color-circle
@@ -31,7 +31,8 @@
[:scroll? {:optional true} [:maybe :boolean]]
[:blur? {:optional true} [:maybe :boolean]]
[:container-style {:optional true} [:maybe :map]]
[:buttons-container-style {:optional true} [:maybe :map]]]]]
[:buttons-container-style {:optional true} [:maybe :map]]
[:buttons-style {:optional true} [:maybe :map]]]]]
:any])
(def ^:private role-icon
@@ -43,10 +44,9 @@
(defn- view-internal
[{:keys [actions description description-text description-top-text error-message role button-one-label
button-two-label blur? button-one-props button-two-props scroll? container-style
buttons-container-style context-tag-props]}]
buttons-container-style buttons-style context-tag-props]}]
(let [theme (quo.theme/use-theme)]
[rn/view
{:style (merge (style/container scroll? blur? theme) container-style)}
[rn/view {:style (merge (style/container scroll? blur? theme) container-style)}
(when (= description :top-error)
[rn/view {:style style/error-message}
[icon/icon
@@ -82,7 +82,7 @@
[button/button
(merge
{:size 40
:container-style style/button-container
:container-style (merge style/button-container buttons-style)
:background (when (or blur? scroll?) :blur)
:theme theme
:accessibility-label :button-two}
@@ -91,7 +91,7 @@
[button/button
(merge
{:size 40
:container-style style/button-container
:container-style (merge style/button-container buttons-style)
:background (when (or blur? scroll?) :blur)
:theme theme
:accessibility-label :button-one}
+1 -1
View File
@@ -131,7 +131,7 @@
[variant-colors]
{:color (:label variant-colors)})
(def counter-container
(def right-label-container
{:flex 1
:align-items :flex-end})
+22 -13
View File
@@ -7,8 +7,8 @@
[react-native.core :as rn]
[react-native.platform :as platform]))
(defn- label-&-counter
[{:keys [label current-chars char-limit variant-colors theme]}]
(defn- label-line
[{:keys [label label-right current-chars char-limit variant-colors theme]}]
[rn/view
{:accessibility-label :input-labels
:style style/texts-container}
@@ -18,17 +18,24 @@
:weight :medium
:size :paragraph-2}
label]]
(when-let [count-text (some->> char-limit
(str current-chars "/"))]
[rn/view {:style style/counter-container}
(when label-right
[rn/view {:style style/right-label-container}
[text/text
{:style (style/counter-color {:current-chars current-chars
:char-limit char-limit
:variant-colors variant-colors
:theme theme})
{:style (style/label-color variant-colors)
:weight :regular
:size :paragraph-2}
count-text]])])
label-right]])
(when char-limit
(let [count-text (str current-chars "/" char-limit)]
[rn/view {:style style/right-label-container}
[text/text
{:style (style/counter-color {:current-chars current-chars
:char-limit char-limit
:variant-colors variant-colors
:theme theme})
:weight :regular
:size :paragraph-2}
count-text]]))])
(defn- left-accessory
[{:keys [variant-colors small? icon-name]}]
@@ -65,7 +72,7 @@
(defn- base-input
[{:keys [blur? error? right-icon left-icon disabled? small? button
label char-limit multiline? clearable? on-focus on-blur container-style input-container-style
on-change-text on-char-limit-reach weight default-value on-clear placeholder]
on-change-text on-char-limit-reach weight default-value on-clear placeholder label-right]
:as props}]
(let [theme (quo.theme/use-theme)
ref (rn/use-ref-atom nil)
@@ -115,10 +122,11 @@
;; https://github.com/facebook/react-native/issues/27687
modified-placeholder (if platform/android? (str "\u2009" placeholder) placeholder)]
[rn/view {:style container-style}
(when (or label char-limit)
[label-&-counter
(when (or label char-limit label-right)
[label-line
{:variant-colors variant-colors
:label label
:label-right label-right
:current-chars char-count
:char-limit char-limit
:theme theme}])
@@ -199,6 +207,7 @@
- :on-clear - Function executed when the clear button is pressed.
- :button - Map containing `:on-press` & `:text` keys, if provided renders a button
- :label - A string to set as label for this input.
- :label-right - Additional label aligned to the right
- :char-limit - A number to set a maximum char limit for this input.
- :on-char-limit-reach - Function executed each time char limit is reached or exceeded.
- :default-shown? - boolean to show password input initially
+3 -2
View File
@@ -21,13 +21,13 @@
[{:keys [type on-press on-check disabled? checked? child]} customization-color theme]
(if (= type :custom)
child
[rn/touchable-opacity
{:on-press on-press}
[rn/touchable-opacity {:on-press on-press}
(case type
:options
[icons/icon :i/options
{:size 20
:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)}]
:checkbox
[selectors/view
{:type :checkbox
@@ -36,6 +36,7 @@
:accessibility-label :user-list-toggle-check
:disabled? disabled?
:on-change (when on-check on-check)}]
:close
[text/text "not implemented"]
[rn/view])]))
@@ -35,7 +35,7 @@
subtitle]]])
(defn- main-variant
[{:keys [title subtitle button-label image max-height accessibility-label on-press]}]
[{:keys [title subtitle button-label image max-height accessibility-label on-press button-type]}]
[rn/view {:style style/main-variant}
[rn/view {:style style/main-variant-text-container}
[text/text
@@ -58,7 +58,7 @@
[button/button
{:on-press on-press
:accessibility-label accessibility-label
:type :grey
:type (or button-type :grey)
:size 40
:container-style style/main-button
:theme :dark
@@ -66,7 +66,8 @@
button-label]])
(defn small-option-card
[{:keys [variant title subtitle button-label image max-height on-press accessibility-label]
[{:keys [variant title subtitle button-label image max-height on-press accessibility-label
button-type container-style]
:or {variant :main accessibility-label :small-option-card}}]
(let [main-variant? (= variant :main)
card-component (if main-variant? main-variant icon-variant)
@@ -74,7 +75,7 @@
(not main-variant?) style/icon-variant-height
max-height (min max-height style/main-variant-height)
:else style/main-variant-height)]
[rn/view {:style (style/card card-height)}
[rn/view {:style (merge (style/card card-height) container-style)}
[card-component
{:title title
:subtitle subtitle
@@ -82,4 +83,5 @@
:on-press on-press
:accessibility-label accessibility-label
:image image
:max-height max-height}]]))
:max-height max-height
:button-type button-type}]]))
@@ -15,7 +15,8 @@
:border-color (colors/theme-colors colors/neutral-20 dark-border theme)}))
(def text
{:margin-left 8})
{:flex 1
:margin-left 8})
(def icon-container
{:align-items :flex-end
@@ -32,8 +32,8 @@
:padding-bottom 2})
(defn title-style
[{:keys [status theme]}]
{:padding-left 4
[{:keys [status theme networks-shown?]}]
{:padding-left (if networks-shown? 4 0)
:margin-top -1
:color (when (= status :error)
(colors/resolve-color :danger theme))})
@@ -14,14 +14,16 @@
:theme theme
:blur? blur?})
container-style)}
[preview-list/view
{:type :network
:number (count networks)
:size :size-16}
networks]
(when networks
[preview-list/view
{:type :network
:number (count networks)
:size :size-16}
networks])
[text/text
{:weight :medium
:size :paragraph-2
:style (style/title-style {:status status
:theme theme})}
:style (style/title-style {:status status
:theme theme
:networks-shown? networks})}
title]]))
@@ -30,13 +30,16 @@
(defn networks
[values theme]
(let [{:keys [ethereum optimism arbitrum]} values
show-optimism? (and optimism
(or (pos? (:amount optimism))
(= (:amount optimism) "<0.01")))
show-arbitrum? (and arbitrum
(or (pos? (:amount arbitrum))
(= (:amount arbitrum) "<0.01")))]
(let [{:keys [ethereum optimism arbitrum base]} values
show-optimism? (and optimism
(or (pos? (:amount optimism))
(= (:amount optimism) "<0.01")))
show-arbitrum? (and arbitrum
(or (pos? (:amount arbitrum))
(= (:amount arbitrum) "<0.01")))
show-base? (and base
(or (pos? (:amount base))
(= (:amount base) "<0.01")))]
[rn/view
{:style style/networks-container
:accessibility-label :networks}
@@ -56,6 +59,11 @@
[network-amount
{:network :arbitrum
:amount (str (:amount arbitrum) " " (or (:token-symbol arbitrum) "ARB"))
:theme theme}])
(when show-base?
[network-amount
{:network :base
:amount (str (:amount base) " " (or (:token-symbol base) "ETH"))
:theme theme}])]))
(defn- view-internal
@@ -9,9 +9,11 @@
[:currency-symbol [:maybe [:or :string :keyword]]]
[:hint-component {:optional true} [:maybe :schema.common/hiccup]]
[:on-token-press {:optional true} [:maybe fn?]]
[:on-swap [:maybe fn?]]
[:on-swap {:optional true} [:maybe fn?]]
[:container-style {:optional true} [:maybe :map]]
[:error? [:maybe :boolean]]
[:show-token-icon? {:optional true} [:maybe :boolean]]
[:value [:maybe :string]]
[:converted-value [:maybe :string]]]]]
[:converted-value {:optional true} [:maybe :string]]
[:swappable? {:optional true} [:maybe :boolean]]]]]
:any])
@@ -19,9 +19,8 @@
{:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)
:padding-bottom 3})
(defn input-container
[window-width]
{:width (- window-width 120)
(def input-container
{:flex 1
:margin-left 8
:margin-right 8
:flex-direction :row
+37 -28
View File
@@ -20,17 +20,18 @@
(string/upper-case (or (clj->js text) ""))])
(defn input-section
[{:keys [token-symbol on-token-press value error? on-swap currency-symbol]}]
(let [theme (quo.theme/use-theme)
window-width (:width (rn/get-window))]
[{:keys [token-symbol on-token-press value error? on-swap currency-symbol show-token-icon?
swappable?]}]
(let [theme (quo.theme/use-theme)]
[rn/pressable
{:style {:width "100%"
:flex-direction :row}
:on-press on-token-press}
[token/view
{:token token-symbol
:size :size-32}]
[rn/view {:style (style/input-container window-width)}
(when show-token-icon?
[token/view
{:token token-symbol
:size :size-32}])
[rn/view {:style style/input-container}
[rn/text-input
{:style (style/text-input theme error?)
:placeholder-text-color (style/placeholder-text theme)
@@ -39,14 +40,15 @@
:editable false
:value value}]
[token-name-text theme currency-symbol]]
[button/button
{:icon true
:icon-only? true
:size 32
:on-press #(when on-swap (on-swap))
:type :outline
:accessibility-label :reorder}
:i/reorder]]))
(when swappable?
[button/button
{:icon true
:icon-only? true
:size 32
:on-press #(when on-swap (on-swap))
:type :outline
:accessibility-label :reorder}
:i/reorder])]))
(defn- view-internal
[{:keys [token-symbol
@@ -57,26 +59,33 @@
on-swap
converted-value
hint-component
currency-symbol]}]
show-token-icon?
currency-symbol
swappable?]
:or {show-token-icon? true
swappable? true}}]
(let [theme (quo.theme/use-theme)
width (:width (rn/get-window))]
[rn/view {:style (merge (style/main-container width) container-style)}
[rn/view {:style style/amount-container}
[input-section
{:theme theme
:token-symbol token-symbol
:on-token-press on-token-press
:value value
:error? error?
:on-swap on-swap
:currency-symbol currency-symbol}]]
{:theme theme
:token-symbol token-symbol
:on-token-press on-token-press
:value value
:error? error?
:on-swap on-swap
:currency-symbol currency-symbol
:show-token-icon? show-token-icon?
:swappable? swappable?}]]
[divider-line/view {:container-style (style/divider theme)}]
[rn/view {:style style/data-container}
hint-component
[text/text
{:size :paragraph-2
:weight :medium
:style (style/converted-amount theme)}
converted-value]]]))
(when swappable?
[text/text
{:size :paragraph-2
:weight :medium
:style (style/converted-amount theme)}
converted-value])]]))
(def view (schema/instrument #'view-internal component-schema/?schema))
+1
View File
@@ -44,6 +44,7 @@
:hermez (js/require "../resources/images/networks/Hermez.png")
:optimism (js/require "../resources/images/networks/Optimism.png")
:paraswap (js/require "../resources/images/networks/Paraswap.png")
:base (js/require "../resources/images/networks/Base.png")
:polygon (js/require "../resources/images/networks/Polygon.png")
:scroll (js/require "../resources/images/networks/Scroll.png")
:taiko (js/require "../resources/images/networks/Taiko.png")
@@ -54,7 +54,7 @@
(when (money/bignumber? (value-bn state))
(money/greater-than (value-bn state) (upper-limit-bn state)))))
(defn- lower-limit-exceeded?
(defn lower-limit-exceeded?
[state]
(and (lower-limit state)
(when (money/bignumber? (value-bn state))
@@ -78,16 +78,19 @@
(defn set-upper-limit
[state limit]
(when limit
(if limit
(-> state
(assoc :upper-limit limit)
recheck-errorness)))
recheck-errorness)
state))
(defn set-lower-limit
[state limit]
(-> state
(assoc :lower-limit limit)
recheck-errorness))
(if limit
(-> state
(assoc :lower-limit limit)
recheck-errorness)
state))
(defn increase
[state]
+1 -6
View File
@@ -265,16 +265,11 @@
:sub-label nil
:chevron? false}))
;; TODO(OmarBasem): Requires design input.
(defn show-qr-entry
[public-key]
(entry {:icon :i/qr-code
:label (i18n/label :t/show-qr)
:on-press (fn []
(rf/dispatch [:universal-links/generate-profile-url
{:public-key public-key
:on-success #(rf/dispatch [:open-modal
:share-contact])}]))
:on-press #(rf/dispatch [:contacts/show-qr-code public-key])
:danger? false
:accessibility-label :show-qr-code
:sub-label nil
+3 -3
View File
@@ -73,10 +73,10 @@
[{:keys [scroll-ref tabs selected-tab on-tab-change scroll-shared-value content customization-color]}]
(let [theme (quo.theme/use-theme)]
[:<>
[:f> banner-card-blur-layer scroll-shared-value
[:f> banner-card-hiding-layer
[banner-card-blur-layer scroll-shared-value
[banner-card-hiding-layer
(assoc content :scroll-shared-value scroll-shared-value :theme theme)]]
[:f> banner-card-tabs-layer
[banner-card-tabs-layer
{:scroll-shared-value scroll-shared-value
:selected-tab selected-tab
:tabs tabs
+1 -1
View File
@@ -17,7 +17,7 @@
:music (js/require "../resources/images/ui2/music.png")
:podcasts (js/require "../resources/images/ui2/podcasts.png")
:generate-keys (js/require "../resources/images/ui2/generate-keys.png")
:generate-keys1 (js/require "../resources/images/ui2/generating-keys-1.png")
:add-key-to-keycard (js/require "../resources/images/ui2/add-key-to-keycard.png")
:ethereum-address (js/require "../resources/images/ui2/ethereum-address.png")
:use-keycard (js/require "../resources/images/ui2/keycard.png")
:use-recovery-phrase (js/require "../resources/images/ui2/recovery-phrase.png")
+7
View File
@@ -1,6 +1,7 @@
(ns status-im.common.signals.events
(:require
[legacy.status-im.chat.models.message :as models.message]
[legacy.status-im.mailserver.core :as mailserver]
[legacy.status-im.visibility-status-updates.core :as visibility-status-updates]
[oops.core :as oops]
[status-im.common.pairing.events :as pairing]
@@ -63,6 +64,12 @@
"messages.new"
(messages.transport/sanitize-messages-and-process-response cofx event-js true)
"mailserver.changed"
(mailserver/handle-mailserver-changed cofx (oops/oget event-js :id))
"mailserver.available"
(mailserver/handle-mailserver-available cofx (oops/oget event-js :id))
"discovery.summary"
(summary cofx (transforms/js->clj event-js))
+9 -7
View File
@@ -213,13 +213,15 @@
(defn save-profile-url
[{:keys [db]} [public-key url]]
(when url
{:db
(cond-> db
(get-in db [:contacts/contacts public-key])
(assoc-in [:contacts/contacts public-key :universal-profile-url] url)
(= public-key (get-in db [:profile/profile :public-key]))
(assoc-in [:profile/profile :universal-profile-url] url))}))
(let [contact-from-key (get-in db [:contacts/contacts public-key])
profile-public-key? (= public-key (get-in db [:profile/profile :public-key]))]
(when url
{:db (cond-> db
contact-from-key
(assoc-in [:contacts/contacts public-key :universal-profile-url] url)
profile-public-key?
(assoc-in [:profile/profile :universal-profile-url] url))})))
(schema/=> save-profile-url
[:=>
+7
View File
@@ -23,6 +23,8 @@
(goog-define ALCHEMY_ARBITRUM_SEPOLIA_TOKEN "")
(goog-define ALCHEMY_OPTIMISM_MAINNET_TOKEN "")
(goog-define ALCHEMY_OPTIMISM_SEPOLIA_TOKEN "")
(goog-define ALCHEMY_BASE_MAINNET_TOKEN "")
(goog-define ALCHEMY_BASE_SEPOLIA_TOKEN "")
(goog-define WALLET_CONNECT_PROJECT_ID "87815d72a81d739d2a7ce15c2cfdefb3")
(goog-define MIXPANEL_APP_ID "3350627")
(goog-define MIXPANEL_TOKEN "5c73bda2d36a9f688a5ee45641fb6775")
@@ -38,9 +40,11 @@
(def mainnet-tx-details-base-link "https://etherscan.io/tx")
(def optimism-mainnet-tx-details-base-link "https://optimistic.etherscan.io/tx")
(def arbitrum-mainnet-tx-details-base-link "https://arbiscan.io/tx")
(def base-mainnet-tx-details-base-link "https://basescan.org/tx")
(def mainnet-sepolia-tx-details-base-link "https://sepolia.etherscan.io/tx")
(def optimism-sepolia-tx-details-base-link "https://sepolia-optimistic.etherscan.io/tx")
(def arbitrum-sepolia-tx-details-base-link "https://sepolia.arbiscan.io/tx")
(def base-sepolia-tx-details-base-link "https://sepolia.basescan.org/tx")
(def opensea-link "https://opensea.io")
(def opensea-tesnet-link "https://testnets.opensea.io")
@@ -124,3 +128,6 @@
(goog-define STATUS_BACKEND_SERVER_ROOT_DATA_DIR "")
;; if you're using android simulator, I suggest set the env variable to "http://10.0.2.2:"
(goog-define STATUS_BACKEND_SERVER_IMAGE_SERVER_URI_PREFIX "https://localhost:")
(def re-frisk-host (get-config :RE_FRISK_HOST "localhost"))
(def re-frisk-port (get-config :RE_FRISK_PORT "4567"))
+11 -9
View File
@@ -221,10 +221,7 @@
(def ^:const wallet-connect-eth-sign-typed-v4-method "eth_signTypedData_v4")
(def ^:const wallet-connect-supported-methods
#{wallet-connect-personal-sign-method
wallet-connect-eth-sign-method
wallet-connect-eth-send-transaction-method
;; NOTE: disabled, as we have no clear use cases for it and other wallets don't support it
;; wallet-connect-eth-sign-transaction-method
wallet-connect-eth-sign-typed-method
wallet-connect-eth-sign-typed-v4-method})
(def ^:const wallet-connect-supported-events #{"accountsChanged" "chainChanged"})
@@ -237,11 +234,9 @@
(def ^:const wallet-connect-message-signing-methods
#{wallet-connect-personal-sign-method
wallet-connect-eth-sign-typed-method
wallet-connect-eth-sign-method
wallet-connect-eth-sign-typed-v4-method})
(def ^:const wallet-connect-transaction-methods
#{wallet-connect-eth-send-transaction-method
wallet-connect-eth-sign-transaction-method})
#{wallet-connect-eth-send-transaction-method})
(def ^:const transaction-pending-type-wallet-connect-transfer "WalletConnectTransfer")
@@ -396,29 +391,34 @@
(def ^:const arbitrum-sepolia-chain-id 421614)
(def ^:const optimism-mainnet-chain-id 10)
(def ^:const optimism-sepolia-chain-id 11155420)
(def ^:const base-mainnet-chain-id 8453)
(def ^:const base-sepolia-chain-id 84532)
(def opensea-url-names
{:ethereum "ethereum"
:sepolia "sepolia"})
(def ^:const mainnet-chain-ids
#{ethereum-mainnet-chain-id arbitrum-mainnet-chain-id optimism-mainnet-chain-id})
#{ethereum-mainnet-chain-id arbitrum-mainnet-chain-id optimism-mainnet-chain-id base-mainnet-chain-id})
(def ^:const sepolia-chain-ids
#{ethereum-sepolia-chain-id arbitrum-sepolia-chain-id optimism-sepolia-chain-id})
#{ethereum-sepolia-chain-id arbitrum-sepolia-chain-id optimism-sepolia-chain-id base-sepolia-chain-id})
(def ^:const mainnet-short-name "eth")
(def ^:const ethereum-short-name "eth")
(def ^:const optimism-short-name "oeth")
(def ^:const arbitrum-short-name "arb1")
(def ^:const base-short-name "base")
(def ^:const mainnet-abbreviated-name "Eth.")
(def ^:const optimism-abbreviated-name "Oeth.")
(def ^:const arbitrum-abbreviated-name "Arb1.")
(def ^:const base-abbreviated-name "Base")
(def ^:const mainnet-full-name "Mainnet")
(def ^:const optimism-full-name "Optimism")
(def ^:const arbitrum-full-name "Arbitrum")
(def ^:const base-full-name "Base")
(def ^:const sepolia-full-name "Sepolia")
@@ -426,11 +426,13 @@
(def ^:const ethereum-network-name :ethereum)
(def ^:const optimism-network-name :optimism)
(def ^:const arbitrum-network-name :arbitrum)
(def ^:const base-network-name :base)
(def ^:const layer-1-network 1)
(def ^:const layer-2-network 2)
(def ^:const default-network-names [mainnet-network-name optimism-network-name arbitrum-network-name])
(def ^:const default-network-names
[mainnet-network-name optimism-network-name arbitrum-network-name base-network-name])
(def ^:const default-network-count (count default-network-names))
@@ -151,3 +151,12 @@
error]]]})
(rf/reg-event-fx :contacts/update-nickname-error update-nickname-error)
(rf/reg-event-fx
:contacts/show-qr-code
(fn [{db :db} [public-key]]
{:db (assoc db :contacts/identity public-key)
:fx [[:dispatch
[:universal-links/generate-profile-url
{:public-key public-key
:on-success #(rf/dispatch [:open-modal :share-contact])}]]]}))
+6 -2
View File
@@ -114,13 +114,17 @@
{:scroll-input (oops/oget % "nativeEvent.contentOffset.y")
:shared-value scroll-shared-value})}])))
(defn- on-new-message-press
[]
(let [main-event [:show-bottom-sheet {:content chat.actions.view/new-chat}]]
(rf/dispatch [:profile/check-profile-update-prompt main-event])))
(defn- banner-data
[profile-link]
{:title-props
{:beta? true
:label (i18n/label :t/messages)
:handler #(rf/dispatch
[:show-bottom-sheet {:content chat.actions.view/new-chat}])
:handler on-new-message-press
:accessibility-label :new-chat-button}
:card-props
{:on-press #(rf/dispatch [:open-share {:options {:url profile-link}}])
@@ -159,7 +159,9 @@
[content]
(reduce (fn [acc e]
(conj acc (resolve-group-system-message e)))
[quo/text]
[rn/view
{:style {:flex-direction :row
:flex-wrap :wrap}}]
(:parsed-text content)))
(defn group-system-message
@@ -0,0 +1,133 @@
(ns status-im.contexts.keycard.backup.events
(:require [utils.re-frame :as rf]
[utils.security.core :as security]))
(rf/reg-event-fx :keycard/backup.generate-and-load-key
(fn [{:keys [db]}]
(let [{:keys [masked-phrase pin]} (get-in db [:keycard :backup])]
{:fx [[:effects.keycard/generate-and-load-key
{:mnemonic (security/safe-unmask-data masked-phrase)
:pin pin
:on-success (fn []
(rf/dispatch [:keycard/disconnect])
(rf/dispatch [:navigate-back])
(rf/dispatch [:open-modal :screen/keycard.backup.success]))
:on-failure #(rf/dispatch [:keycard/on-action-with-pin-error %])}]]})))
(defn- ready-to-add-not-empty
[error]
(rf/dispatch [:navigate-back])
(if (= error :keycard/error.not-keycard)
(rf/dispatch [:keycard/on-application-info-error error])
(do
(rf/dispatch [:keycard/disconnect])
(rf/dispatch [:open-modal :screen/keycard.backup.not-empty
{:on-press #(rf/dispatch [:keycard/backup.ready-to-add-connect])}]))))
(rf/reg-event-fx :keycard/backup.ready-to-add-connect
(fn [_]
{:fx [[:dispatch
[:keycard/connect
{:on-error
(fn [error]
(if (= error :keycard/error.keycard-blank)
(rf/dispatch [:keycard/backup.generate-and-load-key])
(ready-to-add-not-empty error)))}]]]}))
(defn- scan-empty-card-not-empty
[error]
(rf/dispatch [:navigate-back])
(if (= error :keycard/error.not-keycard)
(rf/dispatch [:keycard/on-application-info-error error])
(do
(rf/dispatch [:keycard/disconnect])
(rf/dispatch [:open-modal :screen/keycard.backup.not-empty
{:on-press #(rf/dispatch [:keycard/backup.scan-empty-card])}]))))
(rf/reg-event-fx :keycard/backup.scan-empty-card
(fn [_]
{:fx [[:dispatch
[:keycard/connect
{:on-error
(fn [error]
(if (= error :keycard/error.keycard-blank)
(do
(rf/dispatch [:keycard/disconnect])
(rf/dispatch [:keycard/backup.create-or-enter-pin]))
(scan-empty-card-not-empty error)))}]]]}))
(rf/reg-event-fx :keycard/backup.save-pin
(fn [{:keys [db]} [pin]]
{:db (assoc-in db [:keycard :backup :pin] pin)}))
(defn- save-pin-and-navigate-to-phrase
[pin]
(rf/dispatch [:keycard/disconnect])
(rf/dispatch [:navigate-back])
(rf/dispatch [:keycard/backup.save-pin pin])
(rf/dispatch
[:open-modal :screen/use-recovery-phrase-dark
{:on-success #(rf/dispatch [:keycard/backup.phrase-entered %])}]))
(defn- verify-entered-pin-and-continue
[pin]
(rf/dispatch
[:keycard/connect
{:on-error
(fn [error]
(if (= error :keycard/error.keycard-blank)
(rf/dispatch
[:keycard/verify-pin
{:pin pin
:on-success #(save-pin-and-navigate-to-phrase pin)
:on-failure #(rf/dispatch [:keycard/on-action-with-pin-error %])}])
(rf/dispatch [:keycard/on-application-info-error error])))}]))
(declare init-card-not-empty)
(defn- init-card-with-pin-and-continue
[pin]
(rf/dispatch
[:keycard/connect
{:on-error
(fn [error]
(if (= error :keycard/error.keycard-blank)
(rf/dispatch
[:keycard/init-card
{:pin pin
:on-success #(rf/dispatch
[:keycard/get-application-info
{:on-error
(fn [error]
(if (= error :keycard/error.keycard-blank)
(save-pin-and-navigate-to-phrase pin)
(init-card-not-empty pin error)))}])}])
(init-card-not-empty pin error)))}]))
(defn- init-card-not-empty
[pin error]
(rf/dispatch [:navigate-back])
(if (= error :keycard/error.not-keycard)
(rf/dispatch [:keycard/on-application-info-error error])
(do
(rf/dispatch [:keycard/disconnect])
(rf/dispatch [:open-modal :screen/keycard.backup.not-empty
{:on-press #(init-card-with-pin-and-continue pin)}]))))
(rf/reg-event-fx :keycard/backup.create-or-enter-pin
(fn [{:keys [db]}]
(let [{:keys [initialized?]} (get-in db [:keycard :application-info])]
{:fx [[:dispatch [:navigate-back]]
(if initialized?
[:dispatch
[:open-modal :screen/keycard.pin.enter
{:on-complete verify-entered-pin-and-continue}]]
[:dispatch
[:open-modal :screen/keycard.pin.create
{:on-complete init-card-with-pin-and-continue}]])]})))
(rf/reg-event-fx :keycard/backup.phrase-entered
(fn [{:keys [db]} [{:keys [phrase]}]]
{:db (assoc-in db [:keycard :backup :masked-phrase] phrase)
:fx [[:dispatch [:navigate-back]]
[:dispatch [:open-modal :screen/keycard.backup.ready-to-add]]]}))
@@ -0,0 +1,96 @@
(ns status-im.contexts.keycard.backup.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.common.view :as common.view]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn ready-to-add
[]
[:<>
[quo/page-nav
{:icon-name :i/close
:on-press events-helper/navigate-back}]
[quo/page-top
{:title (i18n/label :t/ready-add-keypair-keycard)}]
[rn/view {:style {:flex 1 :align-items :center :justify-content :center}}
[rn/image
{:resize-mode :contain
:source (resources/get-image :keycard-migration)}]]
[common.view/tips]
[quo/bottom-actions
{:actions :one-action
:button-one-label (i18n/label :t/scan-keycard)
:button-one-props {:on-press #(rf/dispatch [:keycard/backup.ready-to-add-connect])}}]])
(defn success-view
[]
[:<>
[quo/page-nav
{:icon-name :i/close
:on-press events-helper/navigate-back}]
[quo/page-top
{:title (i18n/label :t/backup-keycard-created)}]
[rn/view {:style {:flex 1}}]
[rn/view {:style {:padding-horizontal 20}}
[quo/button {:on-press events-helper/navigate-back}
(i18n/label :t/done)]]])
(defn not-empty-view
[]
(let [{:keys [on-press]} (rf/sub [:get-screen-params])]
[:<>
[quo/page-nav
{:icon-name :i/close
:on-press events-helper/navigate-back}]
[quo/page-top
{:title (i18n/label :t/keycard-not-empty)
:description :text
:description-text (i18n/label :t/scan-empty-keycard)}]
[rn/view {:style {:flex 1}}]
[common.view/tips]
[rn/view {:style {:padding-horizontal 20}}
[quo/button {:on-press on-press}
(i18n/label :t/try-again)]]]))
(defn scan-empty
[]
[:<>
[quo/page-nav
{:icon-name :i/close
:on-press events-helper/navigate-back}]
[quo/page-top
{:title (i18n/label :t/scan-empty-keycard)
:description :text
:description-text (i18n/label :t/backup-empty-keycard-only)}]
[rn/view {:style {:flex 1 :align-items :center :justify-content :center}}
[rn/image
{:resize-mode :contain
:source (resources/get-image :check-your-keycard)}]]
[common.view/tips]
[quo/bottom-actions
{:actions :one-action
:button-one-label (i18n/label :t/ready-to-scan)
:button-one-props {:on-press #(rf/dispatch [:keycard/backup.scan-empty-card])}}]])
(defn sheet
[{:keys [on-continue]}]
(let [customization-color (rf/sub [:profile/customization-color])]
[:<>
[quo/drawer-top {:title (i18n/label :t/create-backup-keycard)}]
[quo/text
{:style {:padding-horizontal 20
:padding-vertical 8}}
(i18n/label :t/backup-keycard-instructions)]
[quo/bottom-actions
{:actions :two-actions
:button-one-label (i18n/label :t/continue)
:button-one-props {:customization-color customization-color
:on-press (fn []
(rf/dispatch [:hide-bottom-sheet])
(on-continue))}
:button-two-label (i18n/label :t/cancel)
:button-two-props {:type :grey
:on-press #(rf/dispatch [:hide-bottom-sheet])}}]]))
@@ -0,0 +1,25 @@
(ns status-im.contexts.keycard.check.events
(:require [utils.re-frame :as rf]))
(rf/reg-event-fx :keycard/check-empty-card
(fn [{:keys [db]}]
(let [keycard-profile? (not (nil? (get-in db [:profile/profile :keycard-pairing])))]
{:fx [[:dispatch
[:keycard/connect
{:key-uid (get-in db [:profile/profile :key-uid])
:on-success
(fn []
(rf/dispatch [:keycard/disconnect])
(rf/dispatch [:navigate-back])
(if keycard-profile?
(rf/dispatch [:open-modal :screen/keycard.manage.profile-keys])
(rf/dispatch [:open-modal :screen/keycard.migrate.profile-keys])))
:on-error
(fn [error]
(rf/dispatch [:navigate-back])
(if (and (= error :keycard/error.keycard-blank)
(not keycard-profile?))
(do
(rf/dispatch [:keycard/disconnect])
(rf/dispatch [:open-modal :screen/keycard.empty]))
(rf/dispatch [:keycard/on-application-info-error error])))}]]]})))
+27 -5
View File
@@ -3,16 +3,40 @@
[react-native.core :as rn]
[status-im.common.events-helper :as events-helper]
[status-im.common.resources :as resources]
[status-im.constants :as constants]
[status-im.contexts.keycard.common.view :as common.view]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn- keycard-documentation
[]
[quo/documentation-drawers
{:title (i18n/label :t/keycard)
:shell? true}
[rn/view
[quo/text {:size :paragraph-2}
(i18n/label :t/keycard-documentation)]
[quo/button
{:size 40
:type :primary
:container-style {:margin-top 24 :margin-bottom 12}
:background :blur
:icon-right :i/external
:on-press #(rf/dispatch [:browser.ui/open-url constants/get-keycard-url])
:accessibility-label :get-keycard}
(i18n/label :t/buy-keycard)]]])
(defn view
[]
(let [{:keys [on-press]} (rf/sub [:get-screen-params])]
[:<>
[quo/page-nav
{:icon-name :i/arrow-left
:on-press events-helper/navigate-back}]
{:icon-name :i/arrow-left
:on-press events-helper/navigate-back
:right-side [{:icon-name :i/info
:on-press #(rf/dispatch [:show-bottom-sheet
{:content keycard-documentation
:shell? true}])}]}]
[quo/page-top
{:title (i18n/label :t/check-keycard)
:description :text
@@ -21,9 +45,7 @@
[rn/image
{:resize-mode :contain
:source (resources/get-image :check-your-keycard)}]]
[quo/divider-label (i18n/label :t/tips-scan-keycard)]
[quo/markdown-list {:description (i18n/label :t/remove-phone-case)}]
[quo/markdown-list {:description (i18n/label :t/keep-card-steady)}]
[common.view/tips]
[quo/bottom-actions
{:actions :one-action
:button-one-label (i18n/label :t/ready-to-scan)
@@ -0,0 +1,10 @@
(ns status-im.contexts.keycard.common.view
(:require [quo.core :as quo]
[utils.i18n :as i18n]))
(defn tips
[]
[:<>
[quo/divider-label (i18n/label :t/tips-scan-keycard)]
[quo/markdown-list {:description (i18n/label :t/remove-phone-case)}]
[quo/markdown-list {:description (i18n/label :t/keep-card-steady)}]])
@@ -90,7 +90,7 @@
(cond
(not initialized?)
{:fx [[:keycard/init-card
{:fx [[:effects.keycard/init-card
{:pin pin
:on-success get-application-info-and-continue}]]}
@@ -106,3 +106,10 @@
{:pin pin
:on-success #(rf/dispatch [:keycard.login/recover-profile-and-login %])
:on-failure #(rf/dispatch [:keycard/on-action-with-pin-error %])}]]}))))
(rf/reg-event-fx :keycard/create.seed-phrase-entered
(fn [{:keys [db]} [key-uid masked-seed-phrase]]
(if (contains? (:profile/profiles-overview db) key-uid)
{:fx [[:dispatch [:onboarding/multiaccount-already-exists key-uid]]]}
{:db (assoc-in db [:keycard :create :masked-phrase] masked-seed-phrase)
:fx [[:dispatch [:keycard/create.create-or-enter-pin]]]})))
+15 -13
View File
@@ -2,8 +2,11 @@
(:require [quo.core :as quo]
[react-native.core :as rn]
[status-im.common.events-helper :as events-helper]
[status-im.common.not-implemented :as not-implemented]
[status-im.common.resources :as resources]
[status-im.config :as config]
[status-im.constants :as constants]
[status-im.contexts.keycard.common.view :as common.view]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
@@ -35,28 +38,27 @@
:image (resources/get-image :use-keycard)
:on-press #(rf/dispatch [:browser.ui/open-url constants/get-keycard-url])}]]
[rn/view {:style {:flex 1}}]
[quo/divider-label (i18n/label :t/tips-scan-keycard)]
[quo/markdown-list {:description (i18n/label :t/remove-phone-case)}]
[quo/markdown-list {:description (i18n/label :t/keep-card-steady)}]])
[common.view/tips]])
(defn ready-to-add
[]
[:<>
[quo/page-nav
{:icon-name :i/arrow-left
:on-press events-helper/navigate-back}]
{:icon-name :i/close
:on-press events-helper/navigate-back
:right-side [(when config/show-not-implemented-features?
{:icon-name :i/info
:on-press not-implemented/alert})]}]
[quo/page-top
{:title (i18n/label :t/ready-add-keypair-keycard)
:description :text
:description-text ""}]
[rn/view {:style {:flex 1 :align-items :center :justify-content :center}}
[rn/image
{:resize-mode :contain
:source (resources/get-image :generate-keys1)}]]
[quo/divider-label (i18n/label :t/tips-scan-keycard)]
[quo/markdown-list {:description (i18n/label :t/remove-phone-case)}]
[quo/markdown-list {:description (i18n/label :t/keep-card-steady)}]
[rn/image
{:resize-mode :contain
:style {:flex 1 :align-self :center :margin-vertical 37}
:source (resources/get-image :add-key-to-keycard)}]
[common.view/tips]
[quo/bottom-actions
{:actions :one-action
:button-one-label (i18n/label :t/ready-to-scan)
:button-one-label (i18n/label :t/scan-keycard)
:button-one-props {:on-press #(rf/dispatch [:keycard/create.start])}}]])
@@ -0,0 +1,21 @@
(ns status-im.contexts.keycard.different-card.view
(:require [quo.core :as quo]
[react-native.core :as rn]
[status-im.common.events-helper :as events-helper]
[utils.i18n :as i18n]))
(defn view
[]
[:<>
[quo/page-nav
{:icon-name :i/close
:on-press events-helper/navigate-back}]
[quo/page-top
{:title (i18n/label :t/different-keycard)
:description :text
:description-text (i18n/label :t/scan-previous-keycard)}]
[rn/view {:style {:flex 1}}]
[rn/view {:style {:padding-horizontal 20}}
[quo/button {:on-press events-helper/navigate-back}
(i18n/label :t/try-again)]]])
+9 -1
View File
@@ -52,6 +52,14 @@
(fn [args]
(keycard/export-key (keycard.utils/wrap-handlers args))))
(rf/reg-fx :effects.keycard/factory-reset
(fn [args]
(keycard/factory-reset (keycard.utils/wrap-handlers args))))
(rf/reg-fx :effects.keycard/verify-pin
(fn [args]
(keycard/verify-pin (keycard.utils/wrap-handlers args))))
(rf/reg-fx :effects.keycard/sign
(fn [args]
(-> (keycard/sign args)
@@ -71,7 +79,7 @@
(promesa/then on-success)
(promesa/catch (keycard.utils/get-on-failure args)))))
(rf/reg-fx :keycard/init-card
(rf/reg-fx :effects.keycard/init-card
(fn [args]
(keycard/init-card (keycard.utils/wrap-handlers args))))
+21 -13
View File
@@ -17,19 +17,27 @@
{: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/create-new-profile)
:subtitle (i18n/label :t/new-key-pair-keycard)
:button-label (i18n/label :t/lets-go)
:accessibility-label :create-new-profile-keycard
:image (resources/get-image :keycard-buy)
:on-press #(rf/dispatch [:keycard/create.get-phrase])}]]
[quo/information-box
{:type :default
:style {:margin-top 32 :margin-horizontal 28}}
(i18n/label :t/add-key-pair-desktop)]])
[quo/small-option-card
{:variant :main
:title (i18n/label :t/create-new-profile)
:subtitle (i18n/label :t/new-key-pair-keycard)
:button-label (i18n/label :t/lets-go)
:accessibility-label :create-new-profile-keycard
:container-style {:margin-horizontal 20 :margin-top 8}
:image (resources/get-image :keycard-buy)
:button-type :primary
:on-press #(rf/dispatch [:keycard/create.get-phrase])}]
[quo/small-option-card
{:variant :icon
:title (i18n/label :t/import-recovery-phrase-to-keycard)
:subtitle (i18n/label :t/store-key-pair-on-keycard)
:accessibility-label :import-recovery-phrase-to-keycard
:container-style {:margin 20}
:image (resources/get-image :use-keycard)
:on-press #(rf/dispatch [:open-modal :screen/use-recovery-phrase-dark
{:on-success (fn [{:keys [key-uid phrase]}]
(rf/dispatch [:keycard/create.seed-phrase-entered
key-uid phrase]))}])}]])
(defn view
[]
+30 -4
View File
@@ -2,6 +2,8 @@
(:require [quo.core :as quo]
[react-native.core :as rn]
[status-im.common.events-helper :as events-helper]
[status-im.contexts.keycard.backup.view :as backup.view]
[status-im.contexts.keycard.factory-reset.view :as factory-reset]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
@@ -31,7 +33,31 @@
:description-text description}]
[rn/view {:style {:margin-horizontal 20}}
[quo/keycard {:holder-name ""}]
[quo/information-box
{:type :default
:style {:margin-top 20}}
(i18n/label :t/unlock-reset-instructions)]]]))
[quo/section-label
{:section (i18n/label :t/what-you-can-do) :container-style {:padding-vertical 8}}]
(if (= error :keycard/error.keycard-blank)
[quo/settings-item
{:title (i18n/label :t/use-backup-keycard)
:image :icon
:image-props :i/placeholder
:action :arrow
:description :text
:description-props {:text (i18n/label :t/create-backup-profile-keycard)}
:on-press (fn []
(rf/dispatch [:show-bottom-sheet
{:content
(fn []
[backup.view/sheet
{:on-continue
(rf/dispatch
[:keycard/backup.create-or-enter-pin])}])}]))}]
[quo/settings-item
{:title (i18n/label :t/factory-reset)
:image :icon
:image-props :i/placeholder
:action :arrow
:description :text
:description-props {:text (i18n/label :t/remove-keycard-content)}
:on-press (fn []
(rf/dispatch [:show-bottom-sheet
{:content factory-reset/sheet}]))}])]]))
@@ -1,5 +1,7 @@
(ns status-im.contexts.keycard.events
(:require [re-frame.core :as rf]
status-im.contexts.keycard.backup.events
status-im.contexts.keycard.check.events
status-im.contexts.keycard.create.events
status-im.contexts.keycard.login.events
status-im.contexts.keycard.migrate.events
@@ -56,6 +58,10 @@
[:keycard/on-application-info-error
:keycard/error.keycard-locked]])]}))))
(rf/reg-event-fx :keycard/init-card
(fn [_ [data]]
{:effects.keycard/init-card data}))
(rf/reg-event-fx :keycard/get-keys
(fn [_ [data]]
{:effects.keycard/get-keys data}))
@@ -68,6 +74,14 @@
(fn [_ [data]]
{:effects.keycard/export-key data}))
(rf/reg-event-fx :keycard/factory-reset
(fn [_ [data]]
{:effects.keycard/factory-reset data}))
(rf/reg-event-fx :keycard/verify-pin
(fn [_ [data]]
{:effects.keycard/verify-pin data}))
(rf/reg-event-fx :keycard/connect-derive-address-and-add-account
(fn [_ [{:keys [pin derivation-path key-uid account-preferences]}]]
{:fx [[:dispatch
@@ -0,0 +1,96 @@
(ns status-im.contexts.keycard.factory-reset.view
(:require [quo.core :as quo]
[react-native.core :as rn]
[status-im.common.events-helper :as events-helper]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn- reset-card
[]
(rf/dispatch
[:keycard/factory-reset
{:on-success (fn []
(rf/dispatch [:navigate-back])
(rf/dispatch [:keycard/disconnect])
(rf/dispatch [:open-modal :screen/keycard.factory-reset.success]))
:on-failure (fn []
(rf/dispatch [:navigate-back])
(rf/dispatch [:keycard/disconnect])
(rf/dispatch [:open-modal :screen/keycard.factory-reset.fail]))}]))
(defn- connect-and-reset
[key-uid]
(rf/dispatch
[:keycard/connect
{:key-uid key-uid
:on-success reset-card
:on-error (fn [error]
(if (or (= error :keycard/error.keycard-frozen)
(= error :keycard/error.keycard-locked)
(= error :keycard/error.keycard-unpaired))
(reset-card)
(do
(rf/dispatch [:navigate-back])
(if (= error :keycard/error.keycard-wrong-profile)
(do
(rf/dispatch [:keycard/disconnect])
(rf/dispatch [:open-modal :screen/keycard.different-card]))
(rf/dispatch [:keycard/on-application-info-error error])))))}]))
(defn success-view
[]
[:<>
[quo/page-nav
{:icon-name :i/close
:on-press events-helper/navigate-back}]
[quo/page-top
{:title (i18n/label :t/keycard-reset-success)
:description :text
:description-text (i18n/label :t/keycard-empty-ready)}]
[rn/view {:style {:flex 1}}]
[rn/view {:style {:padding-horizontal 20}}
[quo/button {:on-press events-helper/navigate-back}
(i18n/label :t/done)]]])
(defn failed-view
[]
[:<>
[quo/page-nav
{:icon-name :i/close
:on-press events-helper/navigate-back}]
[quo/page-top
{:title (i18n/label :t/keycard-reset-failed)}]
[rn/view {:style {:flex 1}}]
[rn/view {:style {:padding-horizontal 20}}
[quo/button {:on-press events-helper/navigate-back}
(i18n/label :t/try-again)]]])
(defn sheet
[]
(let [customization-color (rf/sub [:profile/customization-color])
key-uid (rf/sub [:keycard/key-uid])
[checked? set-checked] (rn/use-state false)]
[:<>
[quo/drawer-top {:title (i18n/label :t/factory-reset-keycard)}]
[quo/text
{:style {:padding-horizontal 20
:padding-top 8
:padding-bottom 8}}
(i18n/label :t/factory-reset-warning)]
[quo/disclaimer
{:checked? checked?
:container-style {:margin-horizontal 20}
:on-change #(set-checked (not checked?))}
(i18n/label :t/key-pair-erased)]
[quo/bottom-actions
{:actions :two-actions
:button-one-label (i18n/label :t/continue)
:button-one-props {:disabled? (not checked?)
:customization-color customization-color
:on-press (fn []
(rf/dispatch [:hide-bottom-sheet])
(connect-and-reset key-uid))}
:button-two-label (i18n/label :t/cancel)
:button-two-props {:type :grey
:on-press (fn []
(rf/dispatch [:hide-bottom-sheet]))}}]]))
@@ -0,0 +1,40 @@
(ns status-im.contexts.keycard.manage.profile-keys.view
(:require [quo.core :as quo]
[react-native.core :as rn]
[status-im.common.events-helper :as events-helper]
[status-im.contexts.keycard.backup.view :as backup.view]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn- backup-sheet
[]
[backup.view/sheet
{:on-continue
(fn []
(rf/dispatch [:navigate-back])
(rf/dispatch
[:open-modal :screen/keycard.backup.scan-empty]))}])
(defn view
[]
(let [profile-name (rf/sub [:profile/name])]
[:<>
[quo/page-nav
{:icon-name :i/close
:on-press events-helper/navigate-back}]
[quo/page-top
{:title profile-name}]
[rn/view {:style {:margin-horizontal 20}}
[rn/view {:style {:padding-top 8 :padding-bottom 20}}
[quo/keycard {:holder-name ""}]]
[quo/section-label
{:section (i18n/label :t/what-you-can-do) :container-style {:padding-vertical 8}}]
[quo/settings-item
{:title (i18n/label :t/backup-keycard)
:image :icon
:image-props :i/profile
:action :arrow
:description :text
:description-props {:text (i18n/label :t/create-backup-profile-keycard)}
:on-press (fn []
(rf/dispatch [:show-bottom-sheet {:content backup-sheet}]))}]]]))
@@ -3,23 +3,6 @@
[utils.re-frame :as rf]
[utils.security.core :as security]))
(rf/reg-event-fx :keycard/migration.check-empty-card
(fn [{:keys [db]}]
{:fx [[:dispatch
[:keycard/connect
{:key-uid (get-in db [:profile/profile :key-uid])
:on-success
(fn []
(rf/dispatch [:keycard/disconnect])
(rf/dispatch [:open-modal :screen/keycard.profile-keys]))
:on-error
(fn [error]
(if (= error :keycard/error.keycard-blank)
(do
(rf/dispatch [:keycard/disconnect])
(rf/dispatch [:open-modal :screen/keycard.empty]))
(rf/dispatch [:keycard/on-application-info-error error])))}]]]}))
(defn get-application-info-and-continue
[key-uid]
(rf/dispatch [:keycard/get-application-info
@@ -40,7 +23,7 @@
(cond
(not initialized?)
{:fx [[:keycard/init-card
{:fx [[:effects.keycard/init-card
{:pin pin
:on-success #(get-application-info-and-continue key-uid)}]]}
@@ -3,6 +3,7 @@
[react-native.core :as rn]
[status-im.common.events-helper :as events-helper]
[status-im.common.resources :as resources]
[status-im.contexts.keycard.common.view :as common.view]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
@@ -26,9 +27,7 @@
[rn/image
{:resize-mode :contain
:source (resources/get-image :keycard-migration)}]]
[quo/divider-label (i18n/label :t/tips-scan-keycard)]
[quo/markdown-list {:description (i18n/label :t/remove-phone-case)}]
[quo/markdown-list {:description (i18n/label :t/keep-card-steady)}]
[common.view/tips]
[quo/bottom-actions
{:actions :one-action
:button-one-label (if initialized? (i18n/label :t/enter-keycard-pin) (i18n/label :t/scan-keycard))
@@ -19,6 +19,6 @@
[rn/image
{:resize-mode :contain
:source (resources/get-image :not-keycard)}]]
[rn/view {:padding-horizontal 20}
[rn/view {:style {:padding-horizontal 20}}
[quo/button {:on-press events-helper/navigate-back}
(i18n/label :t/try-again)]]])
+13
View File
@@ -76,3 +76,16 @@
args
:on-success (get-on-success args)
:on-failure (get-on-failure args)))
(defn keycard-address?
[keypairs address]
(let [find-keycard-keypair (fn [kps] (some #(when-not (empty? (:keycards %)) %) kps))
keypair-addresses (fn [kp]
(->> (:accounts kp)
(map :address)
set))]
(-> keypairs
vals
find-keycard-keypair
keypair-addresses
(contains? (string/lower-case address)))))
+14 -8
View File
@@ -107,6 +107,19 @@
[:navigate-to-within-stack [:screen/onboarding.enable-biometrics from-screen]]
[:onboarding/create-account-and-login])]]})))
(rf/reg-event-fx
:onboarding/multiaccount-already-exists
(fn [_ [key-uid]]
{:fx [[:effects.utils/show-confirmation
{:title (i18n/label :t/multiaccount-exists-title)
:content (i18n/label :t/multiaccount-exists-content)
:confirm-button-text (i18n/label :t/unlock)
:on-accept (fn []
(re-frame/dispatch [:pop-to-root :screen/profile.profiles])
;; Note - Profile selection is not working
(re-frame/dispatch [:profile/profile-selected key-uid]))
:on-cancel #(re-frame/dispatch [:pop-to-root :screen/profile.profiles])}]]}))
(rf/reg-event-fx
:onboarding/seed-phrase-validated
(fn [{:keys [db]} [seed-phrase key-uid]]
@@ -115,14 +128,7 @@
:onboarding/navigated-to-enter-seed-phrase-from-screen
:screen/onboarding.create-profile)]
(if (contains? (:profile/profiles-overview db) key-uid)
{:fx [[:effects.utils/show-confirmation
{:title (i18n/label :t/multiaccount-exists-title)
:content (i18n/label :t/multiaccount-exists-content)
:confirm-button-text (i18n/label :t/unlock)
:on-accept (fn []
(re-frame/dispatch [:pop-to-root :screen/profile.profiles])
(re-frame/dispatch [:profile/profile-selected key-uid]))
:on-cancel #(re-frame/dispatch [:pop-to-root :multiaccounts])}]]}
{:fx [[:dispatch [:onboarding/multiaccount-already-exists key-uid]]]}
{:db (-> db
(assoc-in [:onboarding/profile :seed-phrase] seed-phrase)
(assoc-in [:onboarding/profile :key-uid] key-uid)
@@ -23,29 +23,31 @@
:key :title}
{:type :select
:key :networks
:options [{:key 1}
:options [{:key 0}
{:key 1}
{:key 2}
{:key 3}]}
{:type :boolean
:key :blur?}])
(defn view
[]
(let [state (reagent/atom {:title "Tag"
:status :default
:networks 3})]
(fn []
[preview/preview-container
{:state state
:descriptor descriptor
:blur? (:blur? @state)
:show-blur-background? true}
[rn/view
{:style {:align-self :center
:justify-content :center
:flex 1}}
[quo/network-tags
(assoc @state
:networks
(nth community-networks (dec (:networks @state))))]]])))
(let [selected-networks-id (dec (:networks @state))]
[preview/preview-container
{:state state
:descriptor descriptor
:blur? (:blur? @state)
:show-blur-background? true}
[rn/view
{:style {:align-self :center
:justify-content :center
:flex 1}}
[quo/network-tags
(assoc @state
:networks
(when (pos? selected-networks-id)
(nth community-networks selected-networks-id)))]]]))))
@@ -22,21 +22,29 @@
[{:key :token-symbol
:type :select
:options [{:key :eth}
{:key :snt}]}
{:key :snt}
{:key :gwei}
{:key :units}]}
{:key :currency
:type :select
:options [{:key "$"}
{:key "€"}]}
{:key :error?
:type :boolean}
{:key :show-token-icon?
:type :boolean}
{:key :swappable?
:type :boolean}])
(defn view
[]
(let [state (reagent/atom {:token-symbol :eth
:currency "$"
:crypto? true
:error? false})]
(let [state (reagent/atom {:token-symbol :eth
:currency "$"
:crypto? true
:error? false
:show-token-icon? true
:swappable? true})]
(fn []
(let [{:keys [currency token-symbol crypto? error?]} @state
[input-state set-input-state] (rn/use-state controlled-input/init-state)
@@ -67,18 +75,20 @@
:component-container-style {:flex 1
:justify-content :space-between}}
[quo/token-input
{:token-symbol token-symbol
:currency-symbol (if crypto? token-symbol currency)
:error? error?
:value input-amount
:converted-value converted-value
:on-swap (fn []
(swap! state assoc :crypto? (not crypto?))
(swap-between-fiat-and-crypto))
:hint-component [quo/network-tags
{:networks networks
:title title
:status (when (:error? @state) :error)}]}]
{:token-symbol token-symbol
:currency-symbol (if crypto? token-symbol currency)
:error? error?
:value input-amount
:converted-value converted-value
:on-swap (fn []
(swap! state assoc :crypto? (not crypto?))
(swap-between-fiat-and-crypto))
:hint-component [quo/network-tags
{:networks networks
:title title
:status (when (:error? @state) :error)}]
:show-token-icon? (:show-token-icon? @state)
:swappable? (:swappable? @state)}]
[quo/numbered-keyboard
{:container-style {:padding-bottom (safe-area/get-top)}
:left-action :dot
+3 -1
View File
@@ -26,7 +26,9 @@
:alchemyOptimismMainnetToken config/ALCHEMY_OPTIMISM_MAINNET_TOKEN
:alchemyOptimismSepoliaToken config/ALCHEMY_OPTIMISM_SEPOLIA_TOKEN
:alchemyArbitrumMainnetToken config/ALCHEMY_ARBITRUM_MAINNET_TOKEN
:alchemyArbitrumSepoliaToken config/ALCHEMY_ARBITRUM_SEPOLIA_TOKEN})
:alchemyArbitrumSepoliaToken config/ALCHEMY_ARBITRUM_SEPOLIA_TOKEN
:alchemyBaseMainnetToken config/ALCHEMY_BASE_MAINNET_TOKEN
:alchemyBaseSepoliaToken config/ALCHEMY_BASE_SEPOLIA_TOKEN})
(defn create
[]
@@ -52,7 +52,9 @@
[quo/drawer-top
{:type :context-tag
:context-tag-type :default
:title (i18n/label :t/add-nickname-title)
:title (if has-nickname?
(i18n/label :t/edit-nickname)
(i18n/label :t/add-nickname-title))
:full-name full-name
:profile-picture profile-picture
:customization-color customization-color}]
@@ -14,15 +14,14 @@
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn on-contact-request
(defn on-send-contact-request
[]
(rf/dispatch [:show-bottom-sheet
{:content (fn [] [contact-request/view])}]))
(let [main-event [:show-bottom-sheet {:content contact-request/view}]]
(rf/dispatch [:profile/check-profile-update-prompt main-event])))
(defn on-contact-review
[]
(rf/dispatch [:show-bottom-sheet
{:content (fn [] [contact-review/view])}]))
(rf/dispatch [:show-bottom-sheet {:content contact-review/view}]))
(defn view
[{:keys [scroll-y]}]
@@ -34,27 +33,27 @@
profile-picture (profile.utils/photo contact)
online? (rf/sub [:visibility-status-updates/online? public-key])
theme (quo.theme/use-theme)
contact-status (rn/use-memo (fn []
(cond
(= contact-request-state
constants/contact-request-state-mutual) :contact
blocked? :blocked
:else nil))
[blocked? contact-request-state])
on-start-chat (rn/use-callback #(rf/dispatch [:chat.ui/start-chat
public-key
ens-name])
[ens-name public-key])
on-unblock-press (rn/use-callback (fn []
(rf/dispatch [:contact/unblock-contact
public-key])
(rf/dispatch [:toasts/upsert
{:id :user-unblocked
:type :positive
:text (i18n/label :t/user-unblocked
{:username
full-name})}]))
[public-key full-name])]
contact-status (rn/use-memo
(fn []
(cond
(= contact-request-state
constants/contact-request-state-mutual) :contact
blocked? :blocked
:else nil))
[blocked? contact-request-state])
on-start-chat (rn/use-callback
#(rf/dispatch [:chat.ui/start-chat public-key ens-name])
[ens-name public-key])
on-unblock-press (rn/use-callback
(fn []
(rf/dispatch [:contact/unblock-contact
public-key])
(rf/dispatch [:toasts/upsert
{:id :user-unblocked
:type :positive
:text (i18n/label :t/user-unblocked
{:username full-name})}]))
[public-key full-name])]
[rn/view {:style style/header-container}
[rn/view {:style style/header-top-wrapper}
[rn/view {:style style/avatar-wrapper}
@@ -93,14 +92,12 @@
(cond
(and (not blocked?)
(or
(not contact-request-state)
(= contact-request-state constants/contact-request-state-none)
(= contact-request-state constants/contact-request-state-dismissed)))
(or (not contact-request-state)
(= contact-request-state constants/contact-request-state-none)
(= contact-request-state constants/contact-request-state-dismissed)))
[quo/button
{:container-style style/button-wrapper
:on-press on-contact-request
:on-press on-send-contact-request
:customization-color customization-color
:icon-left :i/add-user}
(i18n/label :t/send-contact-request)]
@@ -2,6 +2,7 @@
(: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]
[status-im.common.qr-codes.view :as qr-codes]
[status-im.contexts.profile.contact.share.style :as style]
[status-im.contexts.profile.utils :as profile.utils]
@@ -9,32 +10,32 @@
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn navigation-back [] (rf/dispatch [:navigate-back]))
(defn view
[]
(let [{:keys [universal-profile-url customization-color]
:as profile} (rf/sub [:contacts/current-contact])
abbreviated-url (rn/use-memo (fn []
(address/get-abbreviated-profile-url universal-profile-url))
[universal-profile-url])
on-share-press (rn/use-callback #(rf/dispatch [:open-share
{:options {:message universal-profile-url}}])
[universal-profile-url])
on-copy-press (rn/use-callback (fn []
(rf/dispatch [:share/copy-text-and-show-toast
{:text-to-copy universal-profile-url
:post-copy-message
(i18n/label
:t/link-to-profile-copied)}]))
[universal-profile-url])]
abbreviated-url (rn/use-memo
(fn []
(address/get-abbreviated-profile-url universal-profile-url))
[universal-profile-url])
on-share-press (rn/use-callback
#(rf/dispatch [:open-share
{:options {:message universal-profile-url}}])
[universal-profile-url])
on-copy-press (rn/use-callback
(fn []
(rf/dispatch
[:share/copy-text-and-show-toast
{:text-to-copy universal-profile-url
:post-copy-message (i18n/label :t/link-to-profile-copied)}]))
[universal-profile-url])]
[quo/overlay {:type :shell}
[rn/view
{:style {:padding-top (safe-area/get-top)}
:key :share-community}
[quo/page-nav
{:icon-name :i/close
:on-press navigation-back
:on-press events-helper/navigate-back
:background :blur
:accessibility-label :top-bar}]
[quo/page-top
@@ -4,27 +4,35 @@
[utils.re-frame :as rf]))
(rf/reg-event-fx :profile/edit-accent-colour-success
(fn [_ [customization-color]]
(fn [_ [{:keys [customization-color navigate-back? show-toast?]}]]
{:fx [[:dispatch [:profile/save-local-accent-color customization-color]]
[:dispatch [:navigate-back]]
[:dispatch
[:toasts/upsert
{:type :positive
:theme :dark
:text (i18n/label :t/accent-colour-updated)}]]]}))
(when navigate-back?
[:dispatch [:navigate-back]])
(when show-toast?
[:dispatch
[:toasts/upsert
{:type :positive
:theme :dark
:text (i18n/label :t/accent-colour-updated)}]])]}))
(rf/reg-event-fx :profile/save-local-accent-color
(fn [{:keys [db]} [customization-color]]
{:db (assoc-in db [:profile/profile :customization-color] customization-color)}))
(defn edit-accent-colour
[{:keys [db]} [customization-color]]
[{:keys [db]}
[{:keys [color navigate-back? show-toast?]
:or {navigate-back? true
show-toast? true}}]]
(let [key-uid (get-in db [:profile/profile :key-uid])]
{:fx [[:json-rpc/call
[{:method "wakuext_setCustomizationColor"
:params [{:customizationColor customization-color
:params [{:customizationColor color
:keyUid key-uid}]
:on-success [:profile/edit-accent-colour-success customization-color]
:on-success [:profile/edit-accent-colour-success
{:customization-color color
:navigate-back? navigate-back?
:show-toast? show-toast?}]
:on-error #(log/error "failed to edit accent color." {:error %})}]]]}))
(rf/reg-event-fx :profile/edit-accent-colour edit-accent-colour)
@@ -11,7 +11,10 @@
[{:method "wakuext_setCustomizationColor"
:params [{:customizationColor new-color
:keyUid key-uid}]
:on-success [:profile/edit-accent-colour-success new-color]
:on-success [:profile/edit-accent-colour-success
{:customization-color new-color
:navigate-back? true
:show-toast? true}]
:on-error fn?}]]]}]
(is (match? expected
(sut/edit-accent-colour cofx [new-color])))))
(sut/edit-accent-colour cofx [{:color new-color}])))))
@@ -58,7 +58,8 @@
{:type :primary
:customization-color @unsaved-custom-color
:on-press (fn []
(rf/dispatch [:profile/edit-accent-colour @unsaved-custom-color]))}
(rf/dispatch [:profile/edit-accent-colour
{:color @unsaved-custom-color}]))}
(i18n/label :t/save-colour)]]]]))))
(defn view
@@ -5,27 +5,28 @@
[utils.re-frame :as rf]))
(rf/reg-event-fx :profile/update-local-picture
(fn [{:keys [db now]} [images]]
(fn [{:keys [db]} [images]]
{:db (if images
(assoc-in db
[:profile/profile :images]
(map #(assoc % :clock now) images))
(assoc-in db [:profile/profile :images] images)
(update db :profile/profile dissoc :images))}))
(rf/reg-event-fx :profile/edit-profile-picture-success
(fn [_ [images]]
(let [has-picture? (rf/sub [:profile/has-picture])]
(fn [{db :db} [{:keys [show-toast?]} images]]
(let [has-picture? (-> db :profile/profile :images count pos?)]
{:fx [[:dispatch [:profile/update-local-picture (reverse images)]]
[:dispatch
[:toasts/upsert
{:type :positive
:theme :dark
:text (i18n/label (if has-picture?
:t/profile-picture-updated
:t/profile-picture-added))}]]]})))
(when show-toast?
[:dispatch
[:toasts/upsert
{:type :positive
:theme :dark
:text (i18n/label (if has-picture?
:t/profile-picture-updated
:t/profile-picture-added))}]])]})))
(defn edit-profile-picture
[{:keys [db]} [picture crop-width crop-height]]
[{:keys [db]}
[{:keys [picture crop-width crop-height show-toast?]
:or {show-toast? true}}]]
(let [key-uid (get-in db [:profile/profile :key-uid])
crop-width (or crop-width profile-picture-picker/crop-size)
crop-height (or crop-height profile-picture-picker/crop-size)
@@ -33,25 +34,28 @@
{:fx [[:json-rpc/call
[{:method "multiaccounts_storeIdentityImage"
:params [key-uid path 0 0 crop-width crop-height]
:on-success [:profile/edit-profile-picture-success]}]]]}))
:on-success [:profile/edit-profile-picture-success {:show-toast? show-toast?}]}]]]}))
(rf/reg-event-fx :profile/edit-picture edit-profile-picture)
(rf/reg-event-fx :profile/delete-profile-picture-success
(fn [_]
(fn [_ [{:keys [show-toast?]}]]
{:fx [[:dispatch [:profile/update-local-picture nil]]
[:dispatch
[:toasts/upsert
{:type :positive
:theme :dark
:text (i18n/label :t/profile-picture-removed)}]]]}))
(when show-toast?
[:dispatch
[:toasts/upsert
{:type :positive
:theme :dark
:text (i18n/label :t/profile-picture-removed)}]])]}))
(defn delete-profile-picture
[{:keys [db]}]
[{:keys [db]}
[{:keys [show-toast?]
:or {show-toast? true}}]]
(let [key-uid (get-in db [:profile/profile :key-uid])]
{:fx [[:json-rpc/call
[{:method "multiaccounts_deleteIdentityImage"
:params [key-uid]
:on-success [:profile/delete-profile-picture-success]}]]]}))
:on-success [:profile/delete-profile-picture-success {:show-toast? show-toast?}]}]]]}))
(rf/reg-event-fx :profile/delete-picture delete-profile-picture)
@@ -12,9 +12,9 @@
[{:method "multiaccounts_storeIdentityImage"
:params [key-uid picture 0 0 profile-picture-picker/crop-size
profile-picture-picker/crop-size]
:on-success [:profile/edit-profile-picture-success]}]]]}]
:on-success [:profile/edit-profile-picture-success {:show-toast? true}]}]]]}]
(is (match? expected
(sut/edit-profile-picture cofx [picture])))))
(sut/edit-profile-picture cofx [{:picture picture}])))))
(deftest delete-picture-test
(let [key-uid "key-uid"
@@ -22,6 +22,6 @@
expected {:fx [[:json-rpc/call
[{:method "multiaccounts_deleteIdentityImage"
:params [key-uid]
:on-success [:profile/delete-profile-picture-success]}]]]}]
:on-success [:profile/delete-profile-picture-success {:show-toast? true}]}]]]}]
(is (match? expected
(sut/delete-profile-picture cofx)))))
(sut/delete-profile-picture cofx [{}])))))
@@ -16,7 +16,7 @@
has-picture? (rf/sub [:profile/has-picture])
on-change-profile-pic (fn [picture]
(if picture
(rf/dispatch [:profile/edit-picture picture])
(rf/dispatch [:profile/edit-picture {:picture picture}])
(rf/dispatch [:profile/delete-picture])))]
[rn/view
{:key :edit-profile
@@ -0,0 +1,33 @@
(ns status-im.contexts.profile.edit.introduce-yourself.view
(:require [quo.core :as quo]
[react-native.core :as rn]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn sheet
[{:keys [pending-event]}]
(let [on-accept (fn []
(rf/dispatch [:open-modal :screen/profile.edit-profile-modal
{:pending-event pending-event}]))
on-reject #(rf/dispatch pending-event)]
[:<>
[rn/view {:style {:padding-horizontal 20}}
[quo/text
{:style {:padding-bottom 4}
:size :heading-2
:weight :semi-bold}
(i18n/label :t/just-introduce-yourself)]
[quo/text
{:style {:padding-top 4 :padding-bottom 12}
:size :paragraph-1
:weight :regular}
(i18n/label :t/add-display-name-and-picture)]]
[quo/bottom-actions
{:actions :two-actions
:buttons-style {:flex-shrink 1 :flex-basis 0}
:button-one-label (i18n/label :t/edit-profile)
:button-one-props {:type :primary
:on-press on-accept}
:button-two-label (i18n/label :t/skip)
:button-two-props {:type :grey
:on-press on-reject}}]]))
@@ -0,0 +1,62 @@
(ns status-im.contexts.profile.edit.modal.events
(:require [status-im.contexts.profile.edit.introduce-yourself.view :as introduce-yourself]
[utils.re-frame :as rf]))
(rf/reg-event-fx
:profile/edit-profile
(fn [_ [{:keys [display-name picture color on-success]}]]
{:fx (cond-> []
display-name
(conj [:dispatch
[:profile/edit-name
{:display-name display-name
:navigate-back? false
:show-toast? false}]])
color
(conj [:dispatch
[:profile/edit-accent-colour
{:color color
:navigate-back? false
:show-toast? false}]])
picture
(conj [:dispatch
[:profile/edit-picture
{:picture picture
:show-toast? false}]])
(nil? picture)
(conj [:dispatch [:profile/delete-picture {:show-toast? false}]])
:always
(conj [:dispatch [:navigate-back]]
[:dispatch on-success]))}))
(defn- profile-update-asked-storage-key
[key-uid]
(keyword :update-profile-asked key-uid))
(rf/reg-event-fx
:profile/set-profile-update-as-asked
(fn [{db :db}]
(let [storage-key (-> db :profile/profile :key-uid profile-update-asked-storage-key)]
{:fx [[:effects.async-storage/set {storage-key true}]]})))
(rf/reg-event-fx
:profile/ask-profile-update
(fn [_ [pending-event]]
{:fx [[:dispatch [:profile/set-profile-update-as-asked]]
[:dispatch
[:show-bottom-sheet
{:content (fn []
[introduce-yourself/sheet {:pending-event pending-event}])}]]]}))
(rf/reg-event-fx
:profile/check-profile-update-prompt
(fn [{db :db} [pending-event]]
(let [storage-key (-> db :profile/profile :key-uid profile-update-asked-storage-key)]
{:fx [[:effects.async-storage/get
{:keys [storage-key]
:cb (fn [profile-updated-data]
(rf/dispatch (if (storage-key profile-updated-data)
pending-event
[:profile/ask-profile-update pending-event])))}]]})))
@@ -0,0 +1,55 @@
(ns status-im.contexts.profile.edit.modal.style
(:require
[quo.foundations.colors :as colors]
[react-native.platform :as platform]))
(def continue-button
{:width "100%"
:margin-left :auto
:margin-top (if platform/android? :auto 0)
:margin-right :auto})
(def button-container
{:width "100%"
:padding-left 20
:padding-right 20
:padding-top 12
:align-self :flex-end
:height 64})
(defn view-button-container
[keyboard-shown?]
(merge button-container
(if platform/ios?
{:margin-bottom (if keyboard-shown? 0 34)}
{:margin-bottom (if keyboard-shown? 12 34)})))
(def blur-button-container
(merge button-container
(when platform/android? {:padding-bottom 12})))
(def page-container
{:flex 1})
(def info-message
{:margin-top 8})
(def title
{:color colors/white
:margin-top 12
:margin-bottom 18})
(def color-title
{:color colors/white-70-blur
:margin-top 20
:margin-bottom 16})
(def content-container
{:padding-horizontal 20})
(def input-container
{:align-items :flex-start})
(def profile-input-container
{:flex-direction :row
:justify-content :center})
@@ -0,0 +1,266 @@
(ns status-im.contexts.profile.edit.modal.view
(:require
[clojure.string :as string]
[oops.core :as oops]
[quo.core :as quo]
[quo.foundations.colors :as colors]
[react-native.core :as rn]
[react-native.hooks :as hooks]
[react-native.platform :as platform]
[react-native.safe-area :as safe-area]
[reagent.core :as reagent]
[status-im.common.avatar-picture-picker.view :as profile-picture-picker]
[status-im.common.events-helper :as events-helper]
[status-im.common.validation.profile :as profile-validator]
[status-im.constants :as c]
[status-im.contexts.profile.edit.modal.events]
[status-im.contexts.profile.edit.modal.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]
[utils.responsiveness :as responsiveness]))
(def scroll-view-height (reagent/atom 0))
(def content-container-height (reagent/atom 0))
(def set-scroll-view-height #(reset! scroll-view-height %))
(defn set-content-container-height
[e]
(reset! content-container-height (oops/oget e "nativeEvent.layout.height")))
(defn show-button-background?
[keyboard-height keyboard-shown content-scroll-y]
(let [button-container-height 64
keyboard-view-height (+ keyboard-height button-container-height)]
(when keyboard-shown
(cond
platform/android?
(< (- @scroll-view-height button-container-height) @content-container-height)
platform/ios?
(< (- @scroll-view-height keyboard-view-height) (- @content-container-height content-scroll-y))
:else
false))))
(defn button-container
[show-keyboard? keyboard-shown show-background? keyboard-height children]
(let [height (reagent/atom 0)]
(reset! height (if show-keyboard? (if keyboard-shown keyboard-height 0) 0))
[rn/view {:style {:margin-top :auto}}
(cond
(and (> @height 0) show-background?)
[quo/blur
(when keyboard-shown
{:blur-amount 34
:blur-type :transparent
:overlay-color :transparent
:background-color (if platform/android?
colors/neutral-100
colors/neutral-80-opa-1-blur)
:style style/blur-button-container})
children]
(and (> @height 0) (not show-background?))
[rn/view {:style (style/view-button-container true)}
children]
(not show-keyboard?)
[rn/view {:style (style/view-button-container false)}
children])]))
(defn- add-keyboard-listener
[e callback]
(oops/ocall rn/keyboard "addListener" e callback))
(defn- on-keyboard-show
[f]
(add-keyboard-listener (if platform/android? "keyboardDidShow" "keyboardWillShow") f))
(defn- on-keyboard-hide
[f]
(add-keyboard-listener (if platform/android? "keyboardDidHide" "keyboardWillHide") f))
(defn floating-button
[{:keys [custom-color scroll-y on-submit disabled?]}]
(reagent/with-let [show-keyboard? (reagent/atom false)
show-listener (on-keyboard-show #(reset! show-keyboard? true))
hide-listener (on-keyboard-hide #(reset! show-keyboard? false))]
(let [{:keys [keyboard-shown keyboard-height]} (hooks/use-keyboard)
show-background? (show-button-background? keyboard-height
keyboard-shown
scroll-y)]
[rn/keyboard-avoiding-view
{:style {:position :absolute
:top 0
:bottom 0
:left 0
:right 0}
:pointer-events :box-none}
[button-container @show-keyboard? keyboard-shown show-background? keyboard-height
[quo/button
{:accessibility-label :submit-create-profile-button
:type :primary
:customization-color custom-color
:on-press on-submit
:container-style style/continue-button
:disabled? disabled?}
(i18n/label :t/continue)]]])
(finally
(oops/ocall show-listener "remove")
(oops/ocall hide-listener "remove"))))
(defn- content
[{:keys [set-display-name set-validation-msg picture-picker]}]
(let [open-picture-picker (fn []
(rf/dispatch [:dismiss-keyboard])
(rf/dispatch [:show-bottom-sheet
{:content picture-picker
:shell? true
:theme :dark}]))
on-change-text (fn [s]
(set-validation-msg s)
(set-display-name s))]
(fn [{:keys [profile-image custom-color display-name validation-msg valid-name?
name-too-short? initial-display-name set-scroll set-scroll-height
set-custom-color]}]
(let [{window-width :width} (rn/get-window)
info-type (cond
validation-msg :error
name-too-short? :default
:else :success)
info-message (or validation-msg
(i18n/label :t/minimum-characters
{:min-chars profile-validator/min-length}))
full-name (if (seq display-name)
display-name
initial-display-name)]
[rn/scroll-view
{:on-layout set-scroll-height
:on-scroll set-scroll
:scroll-event-throttle 64
:content-container-style {:flex-grow 1}}
[rn/view {:on-layout set-content-container-height}
[rn/view {:style style/content-container}
[quo/text
{:style style/title
:size :heading-1
:weight :semi-bold}
(i18n/label :t/edit-profile)]
[rn/view {:style style/input-container}
[rn/view {:style style/profile-input-container}
[quo/profile-input
{:customization-color custom-color
:placeholder initial-display-name
:on-press open-picture-picker
:image-picker-props {:profile-picture profile-image
:full-name full-name
:customization-color custom-color}
:title-input-props {:default-value ""
:auto-focus true
:max-length c/profile-name-max-length
:on-change-text on-change-text}}]]
[quo/info-message
{:status info-type
:size :default
:icon (if valid-name? :i/positive-state :i/info)
:color (when (= :default info-type) colors/white-70-blur)
:container-style style/info-message}
info-message]
[quo/text
{:size :paragraph-2
:weight :medium
:style style/color-title}
(i18n/label :t/colour)]]]
[quo/color-picker
{:blur? true
:default-selected custom-color
:on-change set-custom-color
:window-width window-width
:container-style {:padding-left (responsiveness/iphone-11-Pro-20-pixel-from-width
window-width)}}]]]))))
(defn- submittable-state?
[{:keys [new-color? new-picture? new-name? valid-name?]}]
(let [acceptable-name? (or (not new-name?) valid-name?)]
(or (and new-color? acceptable-name?)
(and new-picture? acceptable-name?)
(and new-name? valid-name?))))
(defn view
[]
(let [{:keys [pending-event]} (rf/sub [:get-screen-params])
{initial-display-name :display-name
initial-color :customization-color
[initial-image] :images} (rf/sub [:profile/profile])
top (safe-area/get-top)
scroll-y (reagent/atom 0)
display-name (reagent/atom "")
validation-msg (reagent/atom (profile-validator/validation-name @display-name))
custom-color (reagent/atom (or initial-color c/profile-default-color))
profile-image (reagent/atom initial-image)
set-display-name #(reset! validation-msg (profile-validator/validation-name %))
set-validation-msg #(reset! display-name (string/trim %))
set-custom-color #(reset! custom-color %)
set-scroll (fn [e]
(reset! scroll-y (oops/oget e "nativeEvent.contentOffset.y")))
set-scroll-height (fn [e]
(reset! scroll-y 0)
(-> e
(oops/oget "nativeEvent.layout.height")
set-scroll-view-height))
picture-picker (fn []
[profile-picture-picker/view
{:on-result #(reset! profile-image %)
:has-picture? (some? @profile-image)}])
update-profile (fn []
(rf/dispatch
[:profile/edit-profile
(cond-> {:on-success pending-event}
(and (seq @display-name)
(not= initial-display-name @display-name))
(assoc :display-name @display-name)
(and (not= initial-image @profile-image))
(assoc :picture @profile-image)
(not= initial-color @custom-color)
(assoc :color @custom-color))]))
on-close (fn []
(events-helper/navigate-back)
(rf/dispatch pending-event))]
(fn []
(let [name-too-short? (profile-validator/name-too-short? @display-name)
valid-name? (and (not @validation-msg) (not name-too-short?))
disabled? (not
(submittable-state?
{:new-color? (not= initial-color @custom-color)
:new-picture? (not= @profile-image initial-image)
:new-name? (and (not= initial-display-name @display-name)
(seq @display-name))
:valid-name? valid-name?}))]
[quo/overlay {:type :shell}
[rn/view {:style style/page-container}
[quo/page-nav
{:margin-top top
:background :blur
:icon-name :i/close
:on-press on-close}]
[content
{:profile-image @profile-image
:custom-color @custom-color
:display-name @display-name
:validation-msg @validation-msg
:valid-name? valid-name?
:name-too-short? name-too-short?
:picture-picker picture-picker
:initial-display-name initial-display-name
:set-scroll set-scroll
:set-scroll-height set-scroll-height
:set-custom-color set-custom-color
:set-display-name set-display-name
:set-validation-msg set-validation-msg}]
[floating-button
{:custom-color @custom-color
:scroll-y @scroll-y
:on-submit update-profile
:disabled? disabled?}]]]))))
@@ -5,21 +5,26 @@
[utils.re-frame :as rf]))
(rf/reg-event-fx :profile/edit-profile-name-success
(fn [_]
{:fx [[:dispatch [:navigate-back]]
[:dispatch
[:toasts/upsert
{:type :positive
:theme :dark
:text (i18n/label :t/name-updated)}]]]}))
(fn [{:keys [db]} [display-name navigate-back? show-toast?]]
{:db (assoc-in db [:profile/profile :display-name] display-name)
:fx [(when navigate-back?
[:dispatch [:navigate-back]])
(when show-toast?
[:dispatch
[:toasts/upsert
{:type :positive
:theme :dark
:text (i18n/label :t/name-updated)}]])]}))
(defn edit-profile-name
[{:keys [db]} [name]]
{:db (assoc-in db [:profile/profile :display-name] name)
:fx [[:json-rpc/call
[_
[{:keys [display-name navigate-back? show-toast?]
:or {navigate-back? true
show-toast? true}}]]
{:fx [[:json-rpc/call
[{:method "wakuext_setDisplayName"
:params [name]
:on-success [:profile/edit-profile-name-success]}]]]})
:params [display-name]
:on-success [:profile/edit-profile-name-success display-name navigate-back? show-toast?]}]]]})
(rf/reg-event-fx :profile/edit-name edit-profile-name)
@@ -6,10 +6,9 @@
(deftest edit-name-test
(let [new-name "John Doe"
cofx {:db {:profile/profile {:display-name "Old name"}}}
expected {:db {:profile/profile {:display-name new-name}}
:fx [[:json-rpc/call
expected {:fx [[:json-rpc/call
[{:method "wakuext_setDisplayName"
:params [name]
:on-success [:profile/edit-profile-name-success]}]]]}]
:on-success [:profile/edit-profile-name-success new-name true true]}]]]}]
(is (match? expected
(sut/edit-profile-name cofx [new-name])))))
(sut/edit-profile-name cofx [{:display-name new-name}])))))
@@ -67,7 +67,8 @@
{:type :primary
:customization-color customization-color
:on-press (fn []
(rf/dispatch [:profile/edit-name @full-name]))
(rf/dispatch [:profile/edit-name {:display-name @full-name}])
(rf/dispatch [:profile/set-profile-update-as-asked]))
:disabled? (boolean (or @typing?
(string/blank? @full-name)
(not (string/blank? @error-msg))))}
@@ -1,7 +1,9 @@
(ns status-im.contexts.profile.login.events
(:require
[legacy.status-im.data-store.settings :as data-store.settings]
[legacy.status-im.mailserver.core :as mailserver]
[native-module.core :as native-module]
[oops.core :as oops]
[status-im.common.keychain.events :as keychain]
[status-im.config :as config]
[status-im.constants :as constants]
@@ -10,7 +12,8 @@
[taoensso.timbre :as log]
[utils.i18n :as i18n]
[utils.re-frame :as rf]
[utils.security.core :as security]))
[utils.security.core :as security]
[utils.transforms :as transforms]))
(rf/reg-event-fx :profile.login/login
(fn [{:keys [db]}]
@@ -132,9 +135,12 @@
:on-error #(log/error "node-info: failed error" %)}]]]})))
(rf/reg-event-fx :profile.login/messenger-started
(fn [{:keys [db]} [_]]
(let [new-account? (get db :onboarding/new-account?)]
{:db (assoc db :messenger/started? true)
(fn [{:keys [db]} [response-js]]
(let [mailservers (transforms/js->clj (oops/oget response-js :mailservers))
new-account? (get db :onboarding/new-account?)]
{:db (-> db
(assoc :messenger/started? true)
(mailserver/add-mailservers mailservers))
:fx [[:fetch-chats-preview
{:chat-preview-type constants/chat-preview-type-non-community
:on-success (fn [result]
@@ -129,10 +129,8 @@
[:dispatch [:hide-bottom-sheet]]]})))
(rf/reg-event-fx :profile.settings/update-local-picture
(fn [{:keys [db now]} [images]]
{:db (assoc-in db
[:profile/profile :images]
(map #(assoc % :clock now) images))}))
(fn [{:keys [db]} [images]]
{:db (assoc-in db [:profile/profile :images] images)}))
(rf/reg-event-fx :profile.settings/mnemonic-was-shown
(fn [_]
@@ -5,82 +5,42 @@
[status-im.common.events-helper :as events-helper]
[status-im.common.resources :as resources]
[status-im.constants :as constants]
[status-im.contexts.settings.keycard.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn registered-keycard
[{:keys [profile-name profile-image customization-color]}]
[rn/view {:style style/keycard-row}
[quo/icon :i/keycard-card
{:size 20
:color colors/white-70-blur}]
[rn/view
[quo/text profile-name]
[rn/view {:style style/keycard-owner}
[quo/user-avatar
{:full-name profile-name
:profile-picture profile-image
:customization-color customization-color
:status-indicator false
:ring? false
:size :xxxs}]
[quo/text
{:size :paragraph-2
:style style/keycard-owner-name}
profile-name]]]])
(defn registered-keycards
[]
(let [keycards (rf/sub [:keycard/registered-keycards])]
[:<>
[quo/divider-label
{:counter? false
:tight? true
:blur? true}
(i18n/label :t/registered-keycards)]
[rn/view {:style style/registered-keycards-container}
(for [keycard keycards]
^{:key (:keycard-uid keycard)}
[registered-keycard keycard])]]))
(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?
[registered-keycards]
[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 :keycard-buy)
:on-press #(rf/dispatch [:browser.ui/open-url constants/get-keycard-url])}]
[rn/view {:style {:margin-top 24}}
[quo/text
{:style {:margin-bottom 1
: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 (fn []
(rf/dispatch [:open-modal :screen/keycard.check
{:on-press
#(rf/dispatch
[:keycard/migration.check-empty-card])}]))}]])]))
[:<>
[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)}]
[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 :keycard-buy)
:on-press #(rf/dispatch [:browser.ui/open-url constants/get-keycard-url])}]
[rn/view {:style {:margin-top 24}}
[quo/text
{:style {:margin-bottom 1
: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/manage-keycard)
:subtitle (i18n/label :t/setup-keycard-description)
:accessibility-label :setup-keycard
:image (resources/get-image :use-keycard)
:on-press (fn []
(rf/dispatch [:open-modal :screen/keycard.check
{:on-press
#(rf/dispatch [:keycard/check-empty-card])}]))}]]])
@@ -45,6 +45,9 @@
[{:details (:optimism networks)
:testnet-mode? testnet-mode?
:testnet-label (i18n/label :t/sepolia-active)}
{:details (:base networks)
:testnet-mode? testnet-mode?
:testnet-label (i18n/label :t/sepolia-active)}
{:details (:arbitrum networks)
:testnet-mode? testnet-mode?
:testnet-label (i18n/label :t/sepolia-active)}])
@@ -29,8 +29,8 @@
:z-index (get shared-values
(get shell.constants/stacks-z-index-keywords stack-id))})}
(case stack-id
:communities-stack [:f> communities/view]
:chats-stack [:f> chat/view]
:communities-stack [communities/view]
:chats-stack [chat/view]
:wallet-stack [wallet/view]
:browser-stack [browser.stack/browser-stack]
[:<>])])
@@ -38,7 +38,7 @@
(defn lazy-screen
[stack-id shared-values]
(when (load-stack? stack-id)
[:f> f-stack-view stack-id shared-values]))
[f-stack-view stack-id shared-values]))
(defn view
[shared-values]
@@ -303,7 +303,7 @@
;; By doing it, we skip a blink while visiting the collectible detail page.
[:dispatch-later
{:ms 17
:dispatch [:navigate-to :screen/wallet.collectible]}]]})))
:dispatch [:open-modal :screen/wallet.collectible]}]]})))
(defn- keep-not-empty-value
[old-value new-value]
@@ -1,5 +1,6 @@
(ns status-im.contexts.wallet.collectible.utils
(:require [status-im.config :as config]
(:require [clojure.string :as string]
[status-im.config :as config]
[status-im.constants :as constants]
[status-im.contexts.wallet.common.utils.networks :as network-utils]
[taoensso.timbre :as log]
@@ -79,3 +80,12 @@
acc)))
{})
vals))
(defn sort-collectibles-by-name
[collectibles]
(sort-by (fn [collectible]
(let [name (-> collectible :collectible-data :name)
normalized-name (some-> name
string/lower-case)]
[(if (seq normalized-name) 0 1) normalized-name]))
collectibles))
@@ -44,3 +44,18 @@
:token-id token-id
:test-networks-enabled? true})
"https://testnets.opensea.io/assets/optimism-sepolia/0xC/0xT"))))
(deftest sort-collectibles-by-name-test
(testing "Sorts collectibles by name, moving nil or empty names to the end"
(let [collectibles [{:collectible-data {:name "Alpha"}}
{:collectible-data {:name nil}}
{:collectible-data {:name "Beta"}}
{:collectible-data {:name ""}}
{:collectible-data {:name "Zeta"}}]
sorted-collectibles (utils/sort-collectibles-by-name collectibles)
expected [{:collectible-data {:name "Alpha"}}
{:collectible-data {:name "Beta"}}
{:collectible-data {:name "Zeta"}}
{:collectible-data {:name nil}}
{:collectible-data {:name ""}}]]
(is (= sorted-collectibles expected)))))
@@ -30,8 +30,7 @@
type :no-title}}]
(let [{:keys [color emoji watch-only?]} (rf/sub [:wallet/current-viewing-account])
networks (rf/sub [:wallet/selected-network-details])
sending-collectible? (rf/sub [:wallet/sending-collectible?])
keycard? (rf/sub [:wallet/selected-keypair-keycard?])]
sending-collectible? (rf/sub [:wallet/sending-collectible?])]
[quo/page-nav
{:type type
:icon-name icon-name
@@ -46,11 +45,7 @@
(not watch-only?)
show-dapps-button?)
{:icon-name :i/dapps
:on-press #(rf/dispatch
(if keycard?
[:keycard/feature-unavailable-show
{:feature-name :wallet.show-connected-dapps}]
[:navigate-to :screen/wallet.connected-dapps]))})
:on-press #(rf/dispatch [:navigate-to :screen/wallet.connected-dapps])})
(when-not sending-collectible?
{:content-type :account-switcher
:customization-color color
@@ -10,15 +10,11 @@
token-name :name
total-balance :total-balance
disabled? :bridge-disabled?
fiat-value :fiat-value
:as token}
_ _
{:keys [currency currency-symbol on-token-press preselected-token-symbol prices-per-token]}]
(let [fiat-value (utils/calculate-token-fiat-value
{:currency currency
:balance total-balance
:token token
:prices-per-token prices-per-token})
crypto-formatted (utils/get-standard-crypto-format token total-balance prices-per-token)
{:keys [currency-symbol on-token-press preselected-token-symbol prices-per-token]}]
(let [crypto-formatted (utils/get-standard-crypto-format token total-balance prices-per-token)
fiat-formatted (utils/fiat-formatted-for-ui currency-symbol fiat-value)]
[quo/token-network
{:token token-symbol
@@ -38,13 +34,11 @@
(let [filtered-tokens (rf/sub [:wallet/current-viewing-account-tokens-filtered
{:query search-text
:chain-ids chain-ids}])
currency (rf/sub [:profile/currency])
currency-symbol (rf/sub [:profile/currency-symbol])
prices-per-token (rf/sub [:wallet/prices-per-token])]
[gesture/flat-list
{:data filtered-tokens
:render-data {:currency currency
:currency-symbol currency-symbol
:render-data {:currency-symbol currency-symbol
:on-token-press on-token-press
:preselected-token-symbol preselected-token-symbol
:prices-per-token prices-per-token}
@@ -409,13 +409,15 @@
(defn sort-tokens
[tokens]
(let [priority #(get constants/token-sort-priority (:symbol %) ##Inf)]
(sort-by (juxt (comp - :balance) priority) tokens)))
(sort-by (comp - :balance) tokens))
(defn sort-tokens-by-fiat-value
[tokens]
(sort-by (comp - :fiat-value) tokens))
(defn sort-tokens-by-name
[tokens]
(let [priority #(get constants/token-sort-priority (:symbol %) ##Inf)]
(sort-by (juxt :symbol priority) tokens)))
(sort-by :symbol tokens))
(defn token-with-balance
([token networks]
@@ -37,6 +37,9 @@
constants/optimism-mainnet-chain-id
config/optimism-mainnet-tx-details-base-link
constants/base-mainnet-chain-id
config/base-mainnet-tx-details-base-link
constants/ethereum-sepolia-chain-id
config/mainnet-sepolia-tx-details-base-link
@@ -46,6 +49,9 @@
constants/optimism-sepolia-chain-id
config/optimism-sepolia-tx-details-base-link
constants/base-sepolia-chain-id
config/base-sepolia-tx-details-base-link
config/mainnet-tx-details-base-link))
(defn get-link-to-tx-details
@@ -15,7 +15,9 @@
constants/optimism-mainnet-chain-id constants/optimism-network-name
constants/optimism-sepolia-chain-id constants/optimism-network-name
constants/arbitrum-mainnet-chain-id constants/arbitrum-network-name
constants/arbitrum-sepolia-chain-id constants/arbitrum-network-name})
constants/arbitrum-sepolia-chain-id constants/arbitrum-network-name
constants/base-mainnet-chain-id constants/base-network-name
constants/base-sepolia-chain-id constants/base-network-name})
(defn- get-chain-id
[{:keys [mainnet-chain-id sepolia-chain-id testnet-enabled?]}]
@@ -46,6 +48,12 @@
(get-chain-id
{:mainnet-chain-id constants/arbitrum-mainnet-chain-id
:sepolia-chain-id constants/arbitrum-sepolia-chain-id
:testnet-enabled? testnet-enabled?})
#{constants/base-network-name (keyword constants/base-short-name)}
(get-chain-id
{:mainnet-chain-id constants/base-mainnet-chain-id
:sepolia-chain-id constants/base-sepolia-chain-id
:testnet-enabled? testnet-enabled?}))))
(defn network-list
@@ -76,12 +84,14 @@
{constants/mainnet-network-name constants/mainnet-short-name
constants/optimism-network-name constants/optimism-short-name
constants/arbitrum-network-name constants/arbitrum-short-name
constants/ethereum-network-name constants/ethereum-short-name})
constants/ethereum-network-name constants/ethereum-short-name
constants/base-network-name constants/base-short-name})
(def short-name->network
{constants/mainnet-short-name constants/mainnet-network-name
constants/optimism-short-name constants/optimism-network-name
constants/arbitrum-short-name constants/arbitrum-network-name})
constants/arbitrum-short-name constants/arbitrum-network-name
constants/base-short-name constants/base-network-name})
(defn short-names->network-preference-prefix
[short-names]
@@ -152,6 +162,15 @@
:view-on-block-explorer-label :t/view-on-oeth
:link-to-block-explorer-label :t/share-link-to-oeth})
(def base-network-details
{:source (resources/get-network constants/base-network-name)
:short-name constants/base-short-name
:full-name constants/base-full-name
:network-name constants/base-network-name
:abbreviated-name constants/base-abbreviated-name
:view-on-block-explorer-label :t/view-on-base
:link-to-block-explorer-label :t/share-link-to-base})
(defn get-network-details
[chain-id]
(as-> chain-id $
@@ -165,6 +184,9 @@
#{constants/optimism-mainnet-chain-id constants/optimism-sepolia-chain-id}
optimism-network-details
#{constants/base-mainnet-chain-id constants/base-sepolia-chain-id}
base-network-details
nil)
(when $
(assoc $ :chain-id chain-id))))
@@ -345,3 +345,33 @@
expected []]
(is (= (utils/get-accounts-with-token-balance accounts token)
expected)))))
(deftest sort-tokens-test
(testing "Sort tokens by balance in descending order"
(let [tokens [{:symbol "BTC" :balance 2}
{:symbol "ETH" :balance 5}
{:symbol "DAI" :balance 10}]
expected [{:symbol "DAI" :balance 10}
{:symbol "ETH" :balance 5}
{:symbol "BTC" :balance 2}]]
(is (= (utils/sort-tokens tokens) expected)))))
(deftest sort-tokens-by-fiat-value-test
(testing "Sort tokens by fiat value in descending order"
(let [tokens [{:symbol "BTC" :fiat-value 50000}
{:symbol "ETH" :fiat-value 15000}
{:symbol "DAI" :fiat-value 1000}]
expected [{:symbol "BTC" :fiat-value 50000}
{:symbol "ETH" :fiat-value 15000}
{:symbol "DAI" :fiat-value 1000}]]
(is (= (utils/sort-tokens-by-fiat-value tokens) expected)))))
(deftest sort-tokens-by-name-test
(testing "Sort tokens by symbol in ascending order"
(let [tokens [{:symbol "ETH"}
{:symbol "DAI"}
{:symbol "BTC"}]
expected [{:symbol "BTC"}
{:symbol "DAI"}
{:symbol "ETH"}]]
(is (= (utils/sort-tokens-by-name tokens) expected)))))
@@ -123,3 +123,10 @@
(-> (sign-transaction-hashes hashes address password)
(promesa/then on-success)
(promesa/catch on-error))))
(rf/reg-fx
:effects.wallet/sign-message
(fn [{:keys [message address password on-success on-error]}]
(-> (wallet-rpc/sign-message message address (security/safe-unmask-data password))
(promesa/then on-success)
(promesa/catch on-error))))
+3 -3
View File
@@ -41,18 +41,18 @@
(rf/reg-event-fx :wallet/navigate-to-account
(fn [{:keys [db]} [address]]
{:db (assoc-in db [:wallet :current-viewing-account-address] address)
:fx [[:dispatch [:navigate-to :screen/wallet.accounts address]]]}))
:fx [[:dispatch [:navigate-to :screen/wallet.accounts]]]}))
(rf/reg-event-fx :wallet/navigate-to-account-within-stack
(fn [{:keys [db]} [address]]
{:db (assoc-in db [:wallet :current-viewing-account-address] address)
:fx [[:dispatch [:navigate-to-within-stack [:screen/wallet.accounts :shell-stack] address]]]}))
:fx [[:dispatch [:navigate-to-within-stack [:screen/wallet.accounts :shell-stack]]]]}))
(rf/reg-event-fx :wallet/navigate-to-new-account
(fn [{:keys [db]} [address]]
{:db (assoc-in db [:wallet :current-viewing-account-address] address)
:fx [[:dispatch [:hide-bottom-sheet]]
[:dispatch [:navigate-to :screen/wallet.accounts address]]
[:dispatch [:navigate-to :screen/wallet.accounts]]
[:dispatch [:wallet/show-account-created-toast address]]]}))
(rf/reg-event-fx :wallet/select-account-tab
+1 -1
View File
@@ -47,7 +47,7 @@
chain-id
constants/transaction-pending-type-wallet-connect-transfer
(transforms/js-stringify tx-args 0)
signature))
(utils.hex/normalize-hex signature)))
(defn sign-message
[message address password]

Some files were not shown because too many files have changed in this diff Show More