Compare commits

...
Author SHA1 Message Date
Omar Basem 5691049a41 lint 2024-07-08 11:39:50 +04:00
Omar Basem db6a014bbd fix sorting 2024-07-08 10:58:48 +04:00
John Ngei a13975f3f6 fix the warning message when the user enters the wrong password (#20605) 2024-07-06 00:15:36 +02:00
Icaro Motta c473b8c9b1 chore(settings): Add boilerplate for the new Privacy and security screen (#20668) 2024-07-05 14:07:01 -03:00
Parvesh Monu 1f333cc937 fix wallet send flow wrong status bar color on select assets screen (#20662) 2024-07-05 20:57:20 +05:30
Yevheniia Berdnyk 460aaedbca e2e: false failures fixes 2024-07-05 16:25:12 +03:00
mmilad75 66639fc3ed fix(wallet): fix checkbox (#19756) 2024-07-05 13:33:15 +01:00
Mohsen 2cc689a896 [#20638] fix: Scan missing keypair keep scanning after success attempt (#20640) 2024-07-05 14:33:38 +03:30
Ajay Sivan b4866ff728 Swap: Edit slippage drawer (#20554) 2024-07-05 02:44:38 -07:00
Sean Hagstrom eaa5016094 feat: add support for updating key-pairs and accounts from app signal (#20550)
This change adds support for processing app signals for syncing changes when adding, editing, or removing keypairs, accounts, and watch-only accounts.
2024-07-04 16:25:30 +01:00
Sean Hagstrom 66f77e1467 fix: configure selectable key-pair to use box-only for pointer-events (#20611)
This change attempts to only to override the default `pointer-events` behaviour for the `quo/keypair` component when the component uses the `selector` action. Now when the `quo/keypair` component is rendered with a selector, only the top-level view of the component will be pressable. And when the `quo/keypair` component is rendered without a selector it will allow for the children of the component to be pressable too.
2024-07-04 15:48:45 +01:00
Volodymyr Kozieiev d16c1a3c85 Disable possibility to changes amounts to send (#20639) 2024-07-04 15:02:57 +01:00
Mohamed Javid a049fd341e chore(docs)_: include new status-go tagging command in the merging PR process (#20607)
Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com>
2024-07-04 15:37:27 +05:30
Volodymyr Kozieiev 140fa3115c Add possibility to edit networks list when routes not found (#20642) 2024-07-04 10:54:17 +01:00
Siddarth Kumar 147676ae8c chore: add Xcode 15.4 to allowed versions (#20641)
This commit adds Xcode 15.4 to allowed versions in xcode-wrapper overlay.
2024-07-04 14:39:23 +05:30
Ulises Manuel 1e40d49369 feat(wallet): Add modal to remove :key and :seed accounts (#20569) 2024-07-03 11:48:10 -06:00
BalogunofAfrica b17f2892c7 feat: collectibles details loading (#20400) 2024-07-03 15:49:12 +01:00
Volodymyr Kozieiev b28a8e153e Fixes for screen where user locks network amounts to send (#20519) 2024-07-03 15:17:29 +01:00
Alexander 35a1905396 Fix auth slider resetting when wallet connect signing is finished (#20589)
* Fix auth slider resetting when wallet connect signing is finished

* Lint fix

* Fixes

* Fixes
2024-07-03 15:27:27 +02:00
Brian Sztamfater 2e8776d0a6 feat(swap): implement network selection drawer (#20368) 2024-07-03 09:15:07 -03:00
Alexander 99506c810d Re-hide connected dapps screen behind a feature flag (#20627)
* Connected dapps screen is not hidden behind a feature flag

* Style fix
2024-07-03 13:01:24 +02:00
jakub e83f6ff445 fix(ci): add missing import for JsonBuilder
Signed-off-by: Jakub Sokołowski <jakub@status.im>
2024-07-03 12:21:39 +02:00
Lungu Cristian f51f52ec27 Fix WalletConnect transactions (#20608)
* fix: sign-transaction

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

* fix: sendTranasaction not working

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

* ref: removing 0x from the signature

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

* ref: tx data from responding to processing events

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

* fix: request dapp subscription

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

* fix: tx data bug

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

---------

Signed-off-by: Lungu Cristian <lungucristian95@gmail.com>
2024-07-03 12:13:13 +02:00
Parvesh Monu e58e2209bb fix endless loading skeleton for some empty channels on IOS (#20602) 2024-07-03 15:26:43 +05:30
Parvesh Monu 8aa1cadc66 fix chat screen design issues (#20621) 2024-07-03 13:02:11 +05:30
Icaro Motta 91c22df498 Remove all integrations with signal wakuv2.peerstats (#20501)
Removes code integrating with the signal wakuv2.peerstats. The response from
this signal is rather large and it can sometimes happen in short bursts.

- Fixes https://github.com/status-im/status-mobile/issues/20176

We were using it to keep track of the number of peers in real-time. We now only
fetch the peer count in two instances (synchronously inside rn/use-mount):

- When the user opens the legacy screen Settings > Advanced > Peers stats.
- When the user opens the visibility status dropdown in Settings, because the
  peers count will be used when the user chooses "Offline" (status inactive).

Note: we don't send anymore the peers count when the user shakes the phone. We
assume this value is already available in :peers-summary (which will be shared
by the user).

status-go still publishes the signal, we just ignore it to remove the
performance overhead of transforming to cljs and mutating the app-db (thus
interrupting the queue from more important stuff).

Steps to test:

- Verify user can see peers count in Settings > Advanced > Peers stats
- Verify changing the visibility status of user Alice in the Settings screen
  leads to the desired effect to the other party seeing Alice's visibility
  status.
2024-07-02 19:48:15 -03:00
Ulises Manuel e221e23255 fix(wallet): Validation of addresses in send-to screen (#20570)
* Fix validation of addresses in send-to screen
2024-07-02 13:57:31 -06:00
Yevheniia Berdnyk e8e05e58e0 e2e: update for Syncing view 2024-07-02 18:30:06 +03:00
Lungu Cristian ac4ffd83db Wallet Connect session establish networks (#20576)
* feat: showing supported networks in wc connection

* feat: added :large size for quo/data-item

* feat: added required networks check
2024-07-02 16:39:33 +02:00
Shivek KhuranaandLungu Cristian b021b1e20a 🎛️ Account switcher UI for Wallet Connect sessions (#20573)
* 🎛️ Account switcher UI for Wallet Connect sessions

* 😢 Remove repl workflow

* 🔀 Merge current-proposal request and account

*  Remove redundant test

* 🐛 Lint fix

---------

Co-authored-by: Lungu Cristian <lungucristian95@gmail.com>
2024-07-02 18:48:48 +05:30
Ajay Sivan b650591e58 Refactor - Info/Info Message component (#20551) 2024-07-02 04:06:37 -07:00
Mohamed Javid 0581fc2f9d feat(wallet): sync saved addresses (#20546)
This commit adds syncing saved addresses across paired devices whenever a new saved address is added or an existing one is edited or removed.

Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com>
2024-07-02 15:33:54 +05:30
yqrashawn ef9cc55501 feat: check before syncing doc (#20504) 2024-07-02 16:36:42 +08:00
Yevheniia Berdnyk 3b3a39e37b e2e: fixes for community,wallet and removed outdated xfails 2024-07-02 01:50:29 +03:00
Icaro Motta b255874e95 fix(communities)_: Buggy scroll behavior in community channel member list (#20517)
Fixes the scroll behavior in a community channel member list. The problem was
that the code wasn't enforcing the correct height.

Partially solves https://github.com/status-im/status-mobile/issues/20514

Steps to test: Long press on any community channel and press View channel
members and details. The user should be able to correctly scroll throughout the
entire list of members.
2024-07-01 18:55:24 -03:00
Icaro Motta 1c83916fc3 fix: Make BigNumber comparator safe against unsupported data types (#20614)
BigNumber instances are not comparable to other data types, except numbers and
strings (supported directly by the library). This commit makes = safe on
bignumbers (no exceptions should be thrown), even when comparing a bignumber
with a nil value.

There's another important benefit from having a custom comparator: performance,
because re-frame will be able to correctly compare data with bignumbers and thus
reuse cached subscriptions and also Reagent will be able to skip processing when
props are equal.

The IComparable interface was not changed. Similarly to core CLJS data types,
sorting heterogeneous collections throws (ignore nils).

```clojure
;; This throws with message: cannot compare 10 to foo
(sort ["foo" 10])
```

We could make sorting work with heterogeneous collections, but then we would
need to extend many core data types to play nice with BigNumber and that sounds
more like a hack, and it's also not a problem we have nowadays.
2024-07-01 18:38:10 -03:00
jakub 31acf51b1e feat(ci): use s5cmd instead of obsolete s3cmd
It's actively maintained and has better concurrency support.

Depends on:
- https://github.com/status-im/status-jenkins-lib/pull/92

Signed-off-by: Jakub Sokołowski <jakub@status.im>
2024-07-01 16:31:29 +02:00
Parvesh Monu 424d2d4b5c fix can't pair with dApp on android with WalletConnect (#20600) 2024-07-01 18:01:58 +05:30
153 changed files with 2911 additions and 1060 deletions
+2 -2
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.8.12'
library 'status-jenkins-lib@v1.9.1'
/* Options section can't access functions in objects. */
def isPRBuild = utils.isPRBuild()
@@ -71,7 +71,7 @@ pipeline {
}
stage('Upload') {
steps { script {
def urls = apks.collect { s3.uploadArtifact(it) }
def urls = apks.collect { s5cmd.upload(it) }
if (urls.size() > 1) { /* Return only the universal APK. */
env.PKG_URL = urls.find { it.contains('universal') }
} else { /* If no universal is available pick first. */
+24 -3
View File
@@ -1,5 +1,7 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.8.12'
library 'status-jenkins-lib@v1.9.1'
import groovy.json.JsonBuilder
pipeline {
agent { label 'linux' }
@@ -72,7 +74,7 @@ pipeline {
iOS: utils.pkgUrl(ios),
Diawi: utils.getEnv(ios, 'DIAWI_URL'),
/* upload the sha256 checksums file too */
SHA: s3.uploadArtifact(sha),
SHA: s5cmd.upload(sha),
]
/* add URLs to the build description */
jenkins.setBuildDesc(urls)
@@ -83,7 +85,7 @@ pipeline {
steps { script {
switch (utils.getBuildType()) {
case 'nightly': /* Create JSON file with newest build URLs */
s3.updateBucketJSON(urls, 'latest.json');
updateBucketJSON(urls, 'latest.json');
break;
case 'release':
github.publishReleaseFiles(repo: 'status-mobile');
@@ -114,3 +116,22 @@ def Boolean getPublishDefault(Boolean previousValue) {
if (previousValue != null) { return previousValue }
return false
}
/* Helper for updating JSON with newest builds. */
def updateBucketJSON(urls, fileName) {
/* latest.json has slightly different key names */
def content = [
DIAWI: urls.Diawi,
APK: urls.Apk, IOS: urls.iOS,
APP: urls.App, MAC: urls.Mac,
WIN: urls.Win, SHA: urls.SHA
]
def filePath = "${pwd()}/pkg/${fileName}"
/* it might not exist */
sh "mkdir -p ${pwd()}/pkg"
def contentJson = new JsonBuilder(content).toPrettyString()
println "${filePath}:\n${contentJson}"
writeFile(file: filePath, text: contentJson)
return s5cmd.upload(filePath)
}
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.8.12'
library 'status-jenkins-lib@v1.9.1'
pipeline {
agent { label 'linux' }
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.8.12'
library 'status-jenkins-lib@v1.9.1'
/* Options section can't access functions in objects. */
def isPRBuild = utils.isPRBuild()
+2 -2
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.8.12'
library 'status-jenkins-lib@v1.9.1'
/* Options section can't access functions in objects. */
def isPRBuild = utils.isPRBuild()
@@ -75,7 +75,7 @@ pipeline {
stage('Upload') {
steps {
script {
env.PKG_URL = s3.uploadArtifact(LOG_FILE)
env.PKG_URL = s5cmd.upload(LOG_FILE)
}
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.8.12'
library 'status-jenkins-lib@v1.9.1'
pipeline {
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.8.12'
library 'status-jenkins-lib@v1.9.1'
pipeline {
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.8.12'
library 'status-jenkins-lib@v1.9.1'
pipeline {
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.8.12'
library 'status-jenkins-lib@v1.9.1'
pipeline {
agent { label 'macos' }
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.8.12'
library 'status-jenkins-lib@v1.9.1'
pipeline {
agent { label params.AGENT_LABEL }
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.8.12'
library 'status-jenkins-lib@v1.9.1'
pipeline {
agent { label 'linux' }
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.8.12'
library 'status-jenkins-lib@v1.9.1'
pipeline {
agent {
+5 -3
View File
@@ -32,14 +32,16 @@ status-mobile code that makes it to the `develop` branch, should always point to
In practice, this means that sometimes they need to be merged in lockstep.
1) Create a PR in status-go and status-mobile. Update the status-go version to the PR revision `scripts/update-status-go.sh $git_revision`.
2) Get both PRs reviewed and approved. Once status-mobile PR has been approved, go through manual QA testing if necessary. Don't merge status-mobile PR just yet.
3) Now that you know the integration between client & server is working, bump the `VERSION` in status-go and merge it.
4) Once merged, tag the version with the new version and push the tag:
3) Now that you know the integration between client & server is working, merge the status-go PR first.
4) Once merged, tag the merged commit with the new version and push the tag:
```
git checkout develop
git pull develop
git tag vx.y.z
make tag-version
git push origin vx.y.z
```
:warning: If a specific commit need to tagged in status-go, use `make tag-version TARGET_COMMIT={hash}`. More info about tagging in [status-go](https://github.com/status-im/status-go/blob/develop/RELEASING.md#tagging-versions).
5) Update status-mobile with the new status-go version, using the new tag `scripts/update-status-go.sh "vx.y.z"`
6) If you had to rebase status-go to include new changes, e2e test MUST be re-run. If there's any issue you will
have to fix in status-go with another PR and follow the same process.
+2 -2
View File
@@ -31,7 +31,7 @@ NOW:
(defn view
[{:keys [on-press on-long-press icon]}]
(let [[pressed? set-pressed] (rn/use-state false)
theme (theme/use-theme-value)
theme (theme/use-theme)
on-press-in (rn/use-callback #(set-pressed true))
on-press-out (rn/use-callback #(set-pressed nil))]
[rn/pressable
@@ -47,7 +47,7 @@ NOW:
- We no longer need to create an anonymous function for rendering. This removes unnecessary confusion and the need for specific knowledge on how it works and why it was needed.
- `rn/use-state` is used instead of `reagent/atom`
- State values no longer need to be dereferenced; they are accessible as regular symbols. This eliminates a common bug where the "@" symbol was inadvertently omitted.
- `theme/with-theme` wrapper is not needed anymore, `(theme/use-theme-value)` hook can be used directly in the components
- `theme/with-theme` wrapper is not needed anymore, `(theme/use-theme)` hook can be used directly in the components
- `:f>` not needed anymore, all components are functional by default
- `rn/use-callback` hook should be used for anon callback functions
+1 -1
View File
@@ -57,7 +57,7 @@ in {
yarn = super.yarn.override { nodejs = super.nodejs-18_x; };
openjdk = super.openjdk11_headless;
xcodeWrapper = callPackage ./pkgs/xcodeenv/compose-xcodewrapper.nix { } {
versions = ["15.1" "15.2" "15.3"];
versions = ["15.1" "15.2" "15.3" "15.4"];
};
go = super.go_1_21;
clang = super.clang_15;
+3 -2
View File
@@ -20,9 +20,10 @@
"@react-native-community/netinfo": "^4.4.0",
"@react-native-community/push-notification-ios": "^1.4.1",
"@react-native-community/slider": "^3.0.0",
"@walletconnect/react-native-compat": "^2.12.2",
"@walletconnect/web3wallet": "^1.11.2",
"@walletconnect/react-native-compat": "2.11.2",
"@walletconnect/web3wallet": "1.10.2",
"base-64": "^1.0.0",
"big-integer": "1.6.51",
"bignumber.js": "git+https://github.com/status-im/bignumber.js.git#refs/tags/v4.0.2-status",
"chance": "^1.1.0",
"emojilib": "^2.4.0",
Binary file not shown.

After

Width:  |  Height:  |  Size: 781 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

+1 -1
View File
@@ -17,7 +17,7 @@
(reg-root-key-sub :ui/search :ui/search)
(reg-root-key-sub :network/type :network/type)
(reg-root-key-sub :network-status :network-status)
(reg-root-key-sub :peers-count :peers-count)
(reg-root-key-sub :peer-stats/count :peer-stats/count)
(reg-root-key-sub :peers-summary :peers-summary)
(reg-root-key-sub :web3-node-version :web3-node-version)
@@ -1,14 +1,9 @@
(ns legacy.status-im.ui.components.connectivity.view
(:require
[clojure.string :as string]
[legacy.status-im.ui.components.animation :as animation]
[legacy.status-im.ui.components.colors :as colors]
[legacy.status-im.ui.components.core :as quo]
[legacy.status-im.ui.components.list.item :as list.item]
[legacy.status-im.ui.components.react :as react]
[re-frame.core :as re-frame]
[utils.i18n :as i18n])
(:require-macros [legacy.status-im.utils.views :as views :refer [defview letsubs]]))
[legacy.status-im.ui.components.react :as react])
(:require-macros [legacy.status-im.utils.views :as views]))
(defn easing
[direction n]
@@ -72,112 +67,3 @@
colors/white)
:left
(* 0.15 parent-width))}]]]))
(defview loading-indicator
[]
(letsubs [fetching? [:mailserver/fetching?]
window-width [:dimensions/window-width]]
(when fetching?
[loading-indicator-anim window-width])))
(defn hide-sheet-and-dispatch
[event]
(re-frame/dispatch [:bottom-sheet/hide-old])
(re-frame/dispatch event))
(defview connectivity-sheet
[]
(letsubs [{:keys [peers node mobile sync]} [:connectivity/state]
current-mailserver-name [:mailserver/current-name]
peers-count [:peers-count]
{:keys [syncing-on-mobile-network?]} [:profile/profile]]
[:<>
[quo/header {:title (i18n/label :t/connection-status) :border-bottom false}]
[quo/list-header (i18n/label :t/peer-to-peer)]
(if (= peers :offline)
[list.item/list-item
{:title (i18n/label :t/not-connected-to-peers)
:accessibility-label "not-connected-to-peers"
:subtitle (i18n/label :t/unable-to-send-messages)
:subtitle-max-lines 2
:theme :negative
:icon :main-icons/network}]
[list.item/list-item
{:title (str (i18n/label :t/connected-to)
" " peers-count
" " (string/lower-case (i18n/label :t/peers)))
:accessibility-label "connected-to-n-peers"
:subtitle (i18n/label :t/can-send-messages)
:subtitle-max-lines 2
:theme :positive
:icon :main-icons/network}])
[quo/list-header (i18n/label :t/history-nodes)]
(cond
(#{:error :offline} node)
[list.item/list-item
{:title (i18n/label :t/not-connected-nodes)
:accessibility-label "not-connected-nodes"
:subtitle (i18n/label :t/unable-to-fetch)
:theme :negative
:icon :main-icons/mailserver}]
(= node :disabled)
[list.item/list-item
{:title (i18n/label :t/nodes-disabled)
:accessibility-label "nodes-disabled"
:subtitle (i18n/label :t/unable-to-fetch)
:disabled true
:icon :main-icons/mailserver}]
(and mobile (not sync))
[list.item/list-item
{:title (i18n/label :t/waiting-wi-fi)
:accessibility-label "waiting-wi-fi"
:subtitle (i18n/label :t/unable-to-fetch)
:disabled true
:icon :main-icons/mailserver}]
(= node :connecting)
[list.item/list-item
{:title (i18n/label :t/connecting)
:accessibility-label "connecting"
:subtitle (i18n/label :t/unable-to-fetch)
:icon :main-icons/mailserver}]
(= node :online)
[list.item/list-item
{:title (str (i18n/label :t/connected-to) " " current-mailserver-name)
:accessibility-label "connected-to-mailserver"
:subtitle (i18n/label :t/you-can-fetch)
:theme :positive
:icon :main-icons/mailserver}])
[list.item/list-item
{:title (i18n/label :t/settings)
:accessibility-label "settings"
:theme :accent
:on-press #(hide-sheet-and-dispatch [:navigate-to :legacy-sync-settings])
:icon :main-icons/settings}]
(when mobile
[:<>
[react/view
{:margin-vertical 8
:background-color colors/gray-lighter
:height 36
:align-items :center
:justify-content :center}
[react/text {:style {:color colors/gray}} (i18n/label :t/youre-on-mobile-network)]]
[list.item/list-item
{:title (i18n/label :t/mobile-network-use-mobile)
:accessibility-label "mobile-network-use-mobile"
:accessory :switch
:on-press #(re-frame/dispatch [:mobile-network/set-syncing
(not syncing-on-mobile-network?)])
:active syncing-on-mobile-network?}]
[react/text {:style {:margin-horizontal 16 :margin-bottom 12 :color colors/gray}}
(i18n/label :t/status-mobile-descr)]])]))
(defn get-icon
[{:keys [peers node mobile sync]}]
(if (or (= peers :offline)
(= node :offline)
(= node :connecting))
:main-icons/offline
(if mobile
(if sync :main-icons/mobile-sync :main-icons/mobile-sync-off)
(when (#{:error :disabled} node) :main-icons/node-offline))))
@@ -1,17 +1,21 @@
(ns legacy.status-im.ui.screens.peers-stats
(:require
[react-native.core :as react-native.core]
[react-native.core :as rn]
[utils.i18n :as i18n]
[utils.re-frame :as re-frame]))
[utils.re-frame :as rf]))
(defn peers-stats
[]
(let [peers-count (re-frame/sub [:peers-count])]
[react-native.core/view
{:flex 1
:margin-horizontal 8}
[react-native.core/view
(let [peers-count (rf/sub [:peer-stats/count])]
(rn/use-mount
(fn []
(rf/dispatch [:peer-stats/get-count])))
[rn/view
{:style {:flex 1
:margin-horizontal 8}}
[rn/view
{:style {:flex-direction :row
:margin-vertical 8
:justify-content :space-between}}
[react-native.core/text (str (i18n/label :t/peers-count) ": " peers-count)]]]))
[rn/text (str (i18n/label :t/peers-count) ": " peers-count)]]]))
@@ -128,7 +128,6 @@
:current-chat-id
:network
:network-status
:peers-count
:peers-summary
:sync-state
:view-id
@@ -130,7 +130,7 @@
status-type]}]
(and
(= status-type constants/visibility-status-inactive)
(> (:peers-count db) 0))
(pos? (:peer-stats/count db)))
;; Disable broadcasting further updates
(conj {:ms 1000
:dispatch
@@ -2,7 +2,7 @@
(:require
[quo.components.buttons.button.view :as button]
[quo.components.buttons.predictive-keyboard.style :as style]
[quo.components.info.info-message :as info-message]
[quo.components.info.info-message.view :as info-message]
[quo.foundations.colors :as colors]
[quo.theme]
[react-native.core :as rn]
@@ -57,17 +57,17 @@
:key-fn str}]
:error
[info-message/info-message
{:icon :i/info
:size :default
:type :error}
[info-message/view
{:icon :i/info
:size :default
:status :error}
text]
:info
[info-message/info-message
(merge {:icon :i/info
:size :default
:type (if (= type :error) :error :default)}
[info-message/view
(merge {:icon :i/info
:size :default
:status (if (= type :error) :error :default)}
(when blur?
{:text-color colors/white-opa-70
:icon-color colors/white-opa-40}))
@@ -26,7 +26,8 @@
(reanimated/set-shared-value x-pos clamped-x)
(when (and reached-end? (not sliding-complete?))
(set-sliding-complete true)
(when on-complete (on-complete reset-fn))))))
(when on-complete
(on-complete reset-fn))))))
(gesture/on-end (fn [event]
(let [x-translation (oops/oget event "translationX")
reached-end? (>= x-translation track-width)]
@@ -54,9 +55,10 @@
on-track-layout (rn/use-callback
#(set-track-width (oops/oget % "nativeEvent.layout.width")))
reset-fn (rn/use-callback
(fn []
(fn [keep-at-end-after-slide?]
(set-sliding-complete false)
(animations/reset-track-position x-pos)))
(when-not keep-at-end-after-slide?
(animations/reset-track-position x-pos))))
dimensions (rn/use-callback
(partial utils/get-dimensions
(or track-width constants/default-width)
-48
View File
@@ -1,48 +0,0 @@
(ns quo.components.info.info-message
(:require
[quo.components.icon :as quo.icons]
[quo.components.markdown.text :as text]
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]))
(defn get-color
[k theme]
(case k
:success (colors/resolve-color :success theme)
:error (colors/resolve-color :danger theme)
:warning (colors/resolve-color :warning theme)
(colors/theme-colors colors/neutral-50 colors/neutral-40 theme)))
(defn info-message
"[info-message opts \"message\"]
opts
{:type :default/:success/:error
:size :default/:tiny
:icon :i/info ;; info message icon
:text-color colors/white ;; text color override
:icon-color colors/white ;; icon color override
:no-icon-color? false ;; disable tint color for icon"
[{:keys [type size icon text-color icon-color no-icon-color? style accessibility-label
container-style]} message]
(let [theme (quo.theme/use-theme)
weight (if (= size :default) :regular :medium)
icon-size (if (= size :default) 16 12)
size (if (= size :default) :paragraph-2 :label)
text-color (or text-color (get-color type theme))
icon-color (or icon-color text-color)]
[rn/view
{:style (merge {:flex-direction :row
:align-items :center}
style
container-style)}
[quo.icons/icon icon
{:color icon-color
:no-color no-icon-color?
:size icon-size}]
[text/text
{:accessibility-label accessibility-label
:size size
:weight weight
:style {:color text-color
:margin-horizontal 4}} message]]))
@@ -0,0 +1,32 @@
(ns quo.components.info.info-message.component-spec
(:require
[quo.components.info.info-message.view :as info-message]
[test-helpers.component :as h]))
(h/describe "Info: Info Message"
(h/test "basic render"
(h/render-with-theme-provider
[info-message/view
{:status :default
:size :default
:accessibility-label :info-message
:icon :i/placeholder} "Message"])
(h/is-truthy (h/get-by-label-text :info-message)))
(h/test "render with correct message"
(h/render-with-theme-provider
[info-message/view
{:status :default
:size :default
:accessibility-label :info-message
:icon :i/placeholder} "Message"])
(h/is-truthy (h/get-by-text "Message")))
(h/test "render icon"
(h/render-with-theme-provider
[info-message/view
{:status :default
:size :default
:accessibility-label :info-message
:icon :i/placeholder} "Message"])
(h/is-truthy (h/get-by-label-text :icon))))
@@ -0,0 +1,6 @@
(ns quo.components.info.info-message.style)
(def container
{:flex-direction :row
:gap 4
:align-items :center})
@@ -0,0 +1,53 @@
(ns quo.components.info.info-message.view
(:require [quo.components.icon :as icons]
[quo.components.info.info-message.style :as style]
[quo.components.markdown.text :as text]
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[schema.core :as schema]))
(def ?schema
[:=>
[:catn
[:props
[:map {:closed true}
[:status {:optional true} [:maybe [:enum :default :success :error :warning]]]
[:size {:optional true} [:maybe [:enum :default :tiny]]]
[:blur? {:optional true} [:maybe :boolean]]
[:icon :keyword]
[:color {:optional true} [:maybe :string]]
[:text-color {:optional true} [:maybe :string]]
[:icon-color {:optional true} [:maybe :string]]
[:no-icon-color? {:optional true} [:maybe :boolean]]
[:accessibility-label {:optional true} [:maybe :keyword]]
[:container-style {:optional true} [:maybe :map]]]]
[:message :string]]
:any])
(defn- get-color
[status theme blur?]
(case status
:success (if blur? colors/success-60 (colors/resolve-color :success theme))
:error (if blur? colors/danger-60 (colors/resolve-color :danger theme))
:warning (if blur? colors/warning-60 (colors/resolve-color :warning theme))
(if blur? colors/white-opa-40 (colors/theme-colors colors/neutral-50 colors/neutral-40 theme))))
(defn view-internal
[{:keys [status size blur? icon color icon-color text-color no-icon-color? container-style
accessibility-label]} message]
(let [theme (quo.theme/use-theme)
default-color (get-color status theme blur?)
text-color (or text-color color default-color)
icon-color (or icon-color color default-color)]
[rn/view {:style (merge style/container container-style)}
[icons/icon icon
{:size (if (= size :tiny) 12 16)
:color icon-color
:no-color? no-icon-color?}]
[text/text
{:size (if (= size :tiny) :label :paragraph-2)
:accessibility-label accessibility-label
:style {:color text-color}} message]]))
(def view (schema/instrument #'view-internal ?schema))
@@ -44,13 +44,14 @@
[:label :string]
[:fiat-value :string]
[:token-value :string]
[:container-style {:optional true} [:maybe :map]]
[:customization-color {:optional true} [:maybe :schema.common/customization-color]]
[:state {:optional true} [:enum :pressed :active :disabled :default]]
[:on-press {:optional true} [:maybe fn?]]]]]
:any])
(defn- view-internal
[{:keys [on-press state customization-color]
[{:keys [on-press container-style state customization-color]
:as props
:or {customization-color :blue}}]
(let [theme (quo.theme/use-theme)
@@ -59,7 +60,8 @@
on-press-out (rn/use-callback #(set-pressed false))
internal-state (if pressed? :pressed state)]
[rn/pressable
{:style (style/container internal-state customization-color theme)
{:style (merge (style/container internal-state customization-color theme)
container-style)
:on-press-in (when-not (= state :disabled) on-press-in)
:on-press-out (when-not (= state :disabled) on-press-out)
:on-press (when-not (= state :disabled) on-press)
+3 -3
View File
@@ -8,7 +8,7 @@
[quo.foundations.colors :as colors]
[react-native.core :as rn]))
(def container-style
(def container
{:margin-horizontal 8
:padding-vertical 8
:padding-horizontal 12
@@ -43,9 +43,9 @@
(defn user
[{:keys [short-chat-key primary-name secondary-name photo-path online? contact? verified?
untrustworthy? on-press on-long-press accessory customization-color theme
allow-multiple-presses? disabled?]}]
allow-multiple-presses? disabled? container-style]}]
[rn/touchable-highlight
{:style container-style
{:style (merge container container-style)
:underlay-color (colors/resolve-color customization-color theme 5)
:allow-multiple-presses? allow-multiple-presses?
:accessibility-label :user-list
@@ -34,6 +34,12 @@
(set-state (fn [prev-state]
(assoc prev-state :image-loaded? true)))))
(defn on-load
[evt set-state]
(let [source (.. evt -nativeEvent -source)
aspect-ratio (/ (.-width source) (.-height source))]
(set-state (fn [prev-state] (assoc prev-state :image-aspect-ratio aspect-ratio)))))
(defn on-load-error
[set-state]
(js/setTimeout (fn []
@@ -147,6 +153,7 @@
[reanimated/view {:style (style/supported-file image-opacity)}
[rn/image
{:style style/image
:on-load #(on-load % set-state)
:on-load-start #(set-load-time (fn [start-time] (- (datetime/now) start-time)))
:on-load-end #(on-load-end {:load-time load-time
:set-state set-state
@@ -197,6 +204,7 @@
[reanimated/view {:style (style/supported-file image-opacity)}
[rn/image
{:style style/image
:on-load #(on-load % set-state)
:on-load-start #(set-load-time (fn [start-time] (- (datetime/now) start-time)))
:on-load-end #(on-load-end {:load-time load-time
:set-state set-state
@@ -219,12 +227,13 @@
(defn- view-internal
[{:keys [container-style type on-press on-long-press supported-file?]
:as props}]
(let [[state set-state] (rn/use-state {:image-loaded? false
:image-error? false
:avatar-loaded? false})
(let [[state set-state] (rn/use-state {:image-loaded? false
:image-aspect-ratio nil
:image-error? false
:avatar-loaded? false})
collectible-ready? (or (:image-loaded? state) (not supported-file?))]
[rn/pressable
{:on-press (when collectible-ready? on-press)
{:on-press (when collectible-ready? #(on-press (:image-aspect-ratio state)))
:on-long-press (when collectible-ready? on-long-press)
:accessibility-label :collectible-list-item
:style container-style}
@@ -1,10 +1,13 @@
(ns quo.components.profile.expanded-collectible.style
(:require [quo.foundations.colors :as colors]))
(def container
{:align-items :center
:justify-content :center
:border-radius 16})
(defn container
[aspect-ratio]
(cond-> {:align-items :center
:justify-content :center
:border-radius 16}
aspect-ratio (assoc :width "100%"
:aspect-ratio aspect-ratio)))
(defn image
[square? aspect-ratio theme]
@@ -25,18 +28,43 @@
:border-color (colors/theme-colors colors/neutral-80-opa-5 colors/white-opa-5 theme)})
(defn fallback
[{:keys [theme]}]
{:background-color (colors/theme-colors colors/neutral-2_5 colors/neutral-90 theme)
:border-style :dashed
:border-color (colors/theme-colors colors/neutral-20 colors/neutral-80 theme)
:border-width 1
:border-radius 16
:width "100%"
:aspect-ratio 1
:align-items :center
:justify-content :center})
([theme]
(fallback theme 1))
([theme aspect-ratio]
{:background-color (colors/theme-colors colors/neutral-2_5 colors/neutral-90 theme)
:border-style :dashed
:border-color (colors/theme-colors colors/neutral-20 colors/neutral-80 theme)
:border-width 1
:border-radius 16
:width "100%"
:aspect-ratio aspect-ratio
:align-items :center
:justify-content :center}))
(def counter
{:position :absolute
:top 12
:right 12})
(defn loading-image-with-opacity
[opacity]
[{:align-items :center
:aspect-ratio 1
:border-radius 16
:justify-content :center
:opacity opacity
:position :absolute
:width "100%"
:z-index 1}])
(defn gradient-view
[aspect-ratio]
{:border-radius 16
:width "100%"
:aspect-ratio aspect-ratio
:align-items :center
:justify-content :center})
(defn supported-file
[opacity]
{:opacity opacity})
@@ -1,17 +1,53 @@
(ns quo.components.profile.expanded-collectible.view
(:require
[clojure.string :as string]
[promesa.core :as promesa]
[quo.components.counter.collectible-counter.view :as collectible-counter]
[quo.components.icon :as icon]
[quo.components.markdown.text :as text]
[quo.components.profile.expanded-collectible.style :as style]
[quo.foundations.colors :as colors]
[quo.foundations.gradients :as gradients]
[quo.theme]
[react-native.core :as rn]
[react-native.reanimated :as reanimated]
[schema.core :as schema]
[utils.datetime :as datetime]
[utils.i18n :as i18n]))
(def timing-options-out 650)
(def timing-options-in 1000)
(def first-load-time 500)
(def cached-load-time 200)
(def error-wait-time 800)
(defn on-load-end
[{:keys [load-time set-state loader-opacity image-opacity]}]
(reanimated/animate loader-opacity 0 timing-options-out)
(reanimated/animate image-opacity 1 timing-options-in)
(if (> load-time cached-load-time)
(js/setTimeout
(fn []
(set-state (fn [prev-state]
(assoc prev-state :image-loaded? true))))
first-load-time)
(set-state (fn [prev-state]
(assoc prev-state :image-loaded? true)))))
(defn on-load-error
[set-state]
(js/setTimeout (fn []
(set-state (fn [prev-state] (assoc prev-state :image-error? true))))
error-wait-time))
(defn- loading-image
[{:keys [theme gradient-color-index loader-opacity aspect-ratio]}]
[reanimated/view
{:style (style/loading-image-with-opacity loader-opacity)}
[gradients/view
{:theme theme
:container-style (style/gradient-view aspect-ratio)
:color-index gradient-color-index}]])
(defn- counter-view
[counter]
[collectible-counter/view
@@ -21,7 +57,7 @@
(defn- fallback-view
[{:keys [label theme counter on-mount]}]
(rn/use-mount on-mount)
[rn/view {:style (style/fallback {:theme theme})}
[rn/view {:style (style/fallback theme)}
[counter-view counter]
[rn/view
[icon/icon :i/sad {:color (colors/theme-colors colors/neutral-40 colors/neutral-50 theme)}]]
@@ -33,45 +69,57 @@
(defn view-internal
[{:keys [container-style square? on-press counter image-src native-ID supported-file?
on-collectible-load]}]
(let [theme (quo.theme/use-theme)
[image-size set-image-size] (rn/use-state {})
[image-error? set-image-error] (rn/use-state (or (nil? image-src)
(string/blank? image-src)))]
(rn/use-effect
(fn []
(promesa/let [[image-width image-height] (rn/image-get-size image-src)]
(set-image-size {:width image-width
:height image-height
:aspect-ratio (/ image-width image-height)})))
[image-src])
on-collectible-load aspect-ratio]}]
(let [theme (quo.theme/use-theme)
loader-opacity (reanimated/use-shared-value
(if supported-file? 1 0))
image-opacity (reanimated/use-shared-value
(if supported-file? 0 1))
[load-time set-load-time] (rn/use-state (datetime/now))
[state set-state] (rn/use-state {:image-loaded? false
:image-error? (or (nil? image-src)
(string/blank?
image-src))})]
[rn/pressable
{:on-press (when (and (not image-error?) supported-file?) on-press)
{:on-press (when (and (not (:image-error? state)) supported-file?) on-press)
:accessibility-label :expanded-collectible
:style (merge container-style style/container)}
:style (merge container-style
(style/container aspect-ratio))}
(cond
(not supported-file?)
[fallback-view
{:label (i18n/label :t/unsupported-file)
:counter counter
:theme theme
:on-mount on-collectible-load}]
{:aspect-ratio aspect-ratio
:label (i18n/label :t/unsupported-file)
:counter counter
:theme theme
:on-mount on-collectible-load}]
image-error?
(:image-error? state)
[fallback-view
{:label (i18n/label :t/cant-fetch-info)
:counter counter
:theme theme
:on-mount on-collectible-load}]
:else
[rn/view
(not (:image-loaded? state))
[loading-image
{:aspect-ratio aspect-ratio
:loader-opacity loader-opacity
:theme theme
:gradient-color-index :gradient-5}])
(when supported-file?
[reanimated/view {:style (style/supported-file image-opacity)}
[rn/image
{:style (style/image square? (:aspect-ratio image-size) theme)
:source image-src
:native-ID native-ID
:on-error #(set-image-error true)
:on-load on-collectible-load}]
{:style (style/image square? aspect-ratio theme)
:source image-src
:native-ID native-ID
:on-load-start #(set-load-time (fn [start-time] (- (datetime/now) start-time)))
:on-load-end #(on-load-end {:load-time load-time
:set-state set-state
:loader-opacity loader-opacity
:image-opacity image-opacity})
:on-error #(on-load-error set-state)
:on-load on-collectible-load}]
(when counter
[counter-view counter])
[rn/view {:style (style/collectible-border theme)}]])]))
@@ -81,6 +129,7 @@
[:catn
[:props
[:map {:closed true}
[:aspect-ratio {:optional true} [:maybe number?]]
[:image-src {:optional true} [:maybe string?]]
[:supported-file? {:optional true} [:maybe boolean?]]
[:container-style {:optional true} [:maybe :map]]
@@ -12,7 +12,8 @@
[{:keys [checked? blur? accessibility-label container-style on-change icon customization-color]} label]
(let [theme (quo.theme/use-theme)]
[rn/touchable-without-feedback
{:on-press on-change
{:on-press (when on-change
#(on-change (not checked?)))
:accessibility-label :disclaimer-touchable-opacity}
[rn/view {:style (merge container-style (style/container blur? theme))}
[selectors/view
@@ -6,8 +6,14 @@
[{:keys [size card? blur? actionable? theme]}]
{:flex-direction :row
:justify-content :space-between
:padding-vertical (when (= size :default) 8)
:padding-horizontal (when (= size :default) 12)
:padding-vertical (case size
:default 8
:large 12
nil)
:padding-horizontal (case size
:default 12
:large 16
nil)
:border-radius 16
:border-width (when (and card? (not= size :small)) 1)
:background-color (if blur?
@@ -24,15 +30,27 @@
(defn loading-container
[size blur? theme]
{:width (if (= size :default) 132 72)
:height (if (= size :default) 16 10)
{:width (case size
:large 132
:small 72
132)
:height (case size
:large 16
:small 10
16)
:background-color (if blur?
colors/white-opa-5
(colors/theme-colors colors/neutral-5
colors/neutral-90
theme))
:border-radius (if (= size :default) 6 3)
:margin-vertical (if (= size :default) 4 3)})
:border-radius (case size
:large 6
:small 3
6)
:margin-vertical (case size
:large 4
:small 3
4)})
(def subtitle-container
{:flex-direction :row
+1 -1
View File
@@ -102,7 +102,7 @@
:container-style container-style
:theme theme))
:on-press #(when (= action :selector) (on-press))
:pointer-events :box-only}
:pointer-events (when (= action :selector) :box-only)}
[rn/view {:style style/header-container}
[avatar props]
[rn/view
+2 -2
View File
@@ -68,7 +68,7 @@
quo.components.graph.wallet-graph.view
quo.components.header
quo.components.icon
quo.components.info.info-message
quo.components.info.info-message.view
quo.components.info.information-box.view
quo.components.inputs.address-input.view
quo.components.inputs.input.view
@@ -301,7 +301,7 @@
(def icon quo.components.icon/icon)
;;;; Info
(def info-message quo.components.info.info-message/info-message)
(def info-message quo.components.info.info-message.view/view)
(def information-box quo.components.info.information-box.view/view)
;;;; Inputs
+1
View File
@@ -41,6 +41,7 @@
quo.components.dropdowns.network-dropdown.component-spec
quo.components.gradient.gradient-cover.component-spec
quo.components.graph.wallet-graph.component-spec
quo.components.info.info-message.component-spec
quo.components.inputs.address-input.component-spec
quo.components.inputs.input.component-spec
quo.components.inputs.locked-input.component-spec
@@ -0,0 +1,24 @@
(ns status-im.common.check-before-syncing.style)
(def buttons-container
{:flex-direction :row
:justify-content :space-between
:gap 12
:padding-vertical 12})
(def button {:flex 1})
(def checkbox
{:margin-top 16
:flex-direction :row
:align-items :center})
(def checkbox-text {:margin-left 10})
(def checkboxes-container {:margin-bottom 10 :padding-right 10})
(def header {:margin-bottom 8})
(def description {:margin-right -33})
(def view-container {:padding-horizontal 33})
@@ -0,0 +1,74 @@
(ns status-im.common.check-before-syncing.view
(:require
[quo.core :as quo]
[react-native.core :as rn]
[status-im.common.check-before-syncing.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(def checks
[(i18n/label :t/check-before-syncing-doc-checkbox-1)
(i18n/label :t/check-before-syncing-doc-checkbox-2)
(i18n/label :t/check-before-syncing-doc-checkbox-3)])
(defn- checkbox
[on-change customization-color description]
[rn/view {:style style/checkbox}
[quo/selectors
{:type :checkbox
:blur? true
:customization-color customization-color
:on-change on-change}]
[quo/text {:style style/checkbox-text} description]])
(defn- compute-new-checked-count
[set-checked-count checked?]
(if checked?
(set-checked-count inc)
(set-checked-count dec)))
(defn- hide-bottom-sheet
[]
(rf/dispatch [:hide-bottom-sheet]))
(defn view
[{:keys [on-submit customization-color]}]
(let [[checked-count set-checked-count] (rn/use-state 0)
on-change (partial compute-new-checked-count set-checked-count)
render-checkbox (rn/use-callback
(partial checkbox on-change customization-color)
[customization-color])
on-cancel hide-bottom-sheet
on-continue (rn/use-callback
(fn []
(hide-bottom-sheet)
(on-submit))
[on-submit])]
[rn/view
{:style style/view-container
:accessibility-label :check-before-syncing-bottom-sheet}
[quo/text
{:weight :semi-bold
:size :heading-2
:style style/header} (i18n/label :t/check-before-syncing)]
[quo/text {:style style/description} (i18n/label :t/check-before-syncing-doc-description)]
(into
[rn/view {:style style/checkboxes-container}]
(mapv render-checkbox checks))
[rn/view {:style style/buttons-container}
[quo/button
{:type :grey
:container-style style/button
:accessibility-label :cancel-button
:on-press on-cancel}
(i18n/label :t/cancel)]
[quo/button
{:container-style style/button
:disabled? (not= checked-count (count checks))
:customization-color (or customization-color :blue)
:accessibility-label :continue-button
:on-press on-continue}
(i18n/label :t/continue)]]]))
@@ -6,7 +6,8 @@
(defn contact-list-item
[{:keys [on-press on-long-press accessory allow-multiple-presses? disabled?]}
{:keys [primary-name secondary-name public-key compressed-key ens-verified added?]}
{:keys [primary-name secondary-name public-key compressed-key ens-verified added?
container-style]}
theme]
(let [photo-path (rf/sub [:chats/photo-path public-key])
online? (rf/sub [:visibility-status-updates/online? public-key])
@@ -25,4 +26,5 @@
:on-press on-press
:on-long-press on-long-press
:accessory accessory
:container-style container-style
:disabled? disabled?}]))
@@ -31,10 +31,10 @@
:on-change-text #(reset! entered-password %)}]
(when (not-empty error)
[quo/info-message
{:type :error
:size :default
:icon :i/info
:containstyle {:margin-top 8}}
{:status :error
:size :default
:icon :i/info
:container-style {:margin-top 8}}
(i18n/label :t/oops-wrong-password)])
[quo/button
{:container-style {:margin-bottom 12 :margin-top 40}
@@ -0,0 +1,17 @@
(ns status-im.common.peer-stats.events
(:require
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(rf/reg-event-fx :peer-stats/get-count
(fn []
{:fx [[:json-rpc/call
[{:method :wakuext_peers
:on-success [:peer-stats/get-count-success]
:on-error (fn [error]
(log/error "failed to fetch wakuv2 peer count"
{:error error}))}]]]}))
(rf/reg-event-fx :peer-stats/get-count-success
(fn [{:keys [db]} [response]]
{:db (assoc db :peer-stats/count (count response))}))
+2 -4
View File
@@ -195,7 +195,7 @@
true)
(defn view
[{:keys [title subtitle validate-fn on-success-scan error-message share-button? import-keypair?]}]
[{:keys [title subtitle validate-fn on-success-scan error-message share-button?]}]
(let [insets (safe-area/get-insets)
qr-code-succeed? (reagent/atom false)
qr-view-finder (reagent/atom {})
@@ -233,9 +233,7 @@
:set-qr-code-succeeded (fn [value]
(when on-success-scan
(on-success-scan value))
(if import-keypair?
(set-rescan-timeout)
(rf/dispatch [:navigate-back])))
(rf/dispatch [:navigate-back]))
:set-rescan-timeout set-rescan-timeout}])
[rn/view {:style (style/root-container (:top insets))}
[header
+2 -13
View File
@@ -10,7 +10,6 @@
[status-im.contexts.communities.discover.events]
[status-im.contexts.profile.push-notifications.local.events :as local-notifications]
[taoensso.timbre :as log]
[utils.debounce :as debounce]
[utils.re-frame :as rf]
[utils.transforms :as transforms]))
@@ -20,17 +19,10 @@
peers-count (count peers-summary)]
(rf/merge cofx
{:db (assoc db
:peers-summary peers-summary
:peers-count peers-count)}
:peers-summary peers-summary
:peer-stats/count peers-count)}
(visibility-status-updates/peers-summary-change peers-count))))
(rf/reg-event-fx :wakuv2-peer-stats
(fn [{:keys [db]} [^js peer-stats-js]]
(let [peer-stats (transforms/js->clj peer-stats-js)]
{:db (assoc db
:peer-stats peer-stats
:peers-count (count (:peers peer-stats)))})))
(rf/defn process
{:events [:signals/signal-received]}
[{:keys [db] :as cofx} event-str]
@@ -46,9 +38,6 @@
"wallet"
{:fx [[:dispatch [:wallet/signal-received event-js]]]}
"wakuv2.peerstats"
(debounce/debounce-and-dispatch [:wakuv2-peer-stats event-js] 1000)
"envelope.sent"
(messages.transport/update-envelopes-status
cofx
@@ -32,9 +32,8 @@
:on-cancel #(rf/dispatch [:standard-auth/authorize-with-password
args-with-biometric-btn])
:on-success (fn []
(when (fn? on-close)
(on-close))
(rf/dispatch [:standard-auth/on-biometric-success on-auth-success]))
(rf/dispatch [:standard-auth/on-biometric-success on-auth-success])
(rf/dispatch [:standard-auth/close on-close]))
:on-fail (fn [err]
(rf/dispatch [:standard-auth/authorize-with-password
args-with-biometric-btn])
@@ -48,6 +47,7 @@
[{:keys [db]} [on-auth-success]]
(let [key-uid (get-in db [:profile/profile :key-uid])]
{:fx [[:keychain/get-user-password [key-uid on-auth-success]]
[:dispatch [:standard-auth/set-success true]]
[:dispatch [:standard-auth/reset-login-password]]]}))
(schema/=> on-biometric-success events-schema/?on-biometric-success)
@@ -74,6 +74,7 @@
(fn [password]
(let [sha3-pwd (security/hash-masked-password password)
on-auth-success-callback #(on-auth-success sha3-pwd)]
(rf/dispatch [:standard-auth/set-success true])
(rf/dispatch [:standard-auth/reset-login-password])
(if has-partially-operable-accounts?
(rf/dispatch [:wallet/make-partially-operable-accounts-fully-operable
@@ -92,10 +93,7 @@
{:fx [[:dispatch [:standard-auth/reset-login-password]]
[:dispatch
[:show-bottom-sheet
{:on-close (fn []
(rf/dispatch [:standard-auth/reset-login-password])
(when on-close
(on-close)))
{:on-close #(rf/dispatch [:standard-auth/close on-close])
:theme theme
:shell? blur?
:content #(bottom-sheet-password-view args)}]]]})
@@ -107,3 +105,23 @@
:standard-auth/reset-login-password
(fn [{:keys [db]}]
{:db (update db :profile/login dissoc :password :error)}))
(rf/reg-fx
:standard-auth/on-close
(fn [{:keys [on-close success?]}]
(when on-close
(on-close success?))))
(rf/reg-event-fx
:standard-auth/close
(fn [{:keys [db]} [on-close]]
{:db (assoc-in db [:profile/login :success?] false)
:fx [[:dispatch [:standard-auth/reset-login-password]]
[:standard-auth/on-close
{:on-close on-close
:success? (get-in db [:profile/login :success?])}]]}))
(rf/reg-event-fx
:standard-auth/set-success
(fn [{:keys [db]} [success?]]
{:db (assoc-in db [:profile/login :success?] success?)}))
@@ -16,8 +16,7 @@
[error]
(if (and (some? error)
(or (= error "file is not a database")
(string/starts-with? error "failed to set ")
(string/starts-with? error "Failed")))
(string/starts-with? (string/lower-case error) "failed")))
(i18n/label :t/oops-wrong-password)
error))
@@ -34,9 +33,9 @@
[theme])]
[rn/view {:style style/error-message}
[quo/info-message
{:type :error
:size :default
:icon :i/info}
{:status :error
:size :default
:icon :i/info}
error-message]
[rn/pressable
{:hit-slop {:top 6 :bottom 20 :left 0 :right 0}
@@ -16,7 +16,8 @@
on-complete (rn/use-callback
(fn [reset]
(rf/dispatch [:standard-auth/authorize
{:on-close #(js/setTimeout reset 200)
{:on-close (fn [success?]
(js/setTimeout #(reset success?) 200))
:auth-button-icon-left auth-button-icon-left
:theme theme
:blur? blur?
+12
View File
@@ -282,6 +282,8 @@
(def ^:const wallet-connect-session-proposal-event "session_proposal")
(def ^:const wallet-connect-session-request-event "session_request")
(def ^:const transaction-pending-type-wallet-connect-transfer "WalletConnectTransfer")
(def ^:const dapp-permission-contact-code "contact-code")
(def ^:const dapp-permission-web3 "web3")
(def ^:const dapp-permission-qr-code "qr-code")
@@ -503,6 +505,9 @@
(def ^:const optimism-network-name :optimism)
(def ^:const arbitrum-network-name :arbitrum)
(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-count (count default-network-names))
@@ -548,3 +553,10 @@
(def ^:const community-joined-notification-type "communityJoined")
(def ^:const default-telemetry-server-url "https://telemetry.status.im")
(def ^:const contact-item-height 56)
(def ^:const slippages [0.1 0.5 1])
(def ^:const default-slippage 0.5)
(def ^:const max-recommended-slippage 5)
(def ^:const max-slippage-decimal-places 2)
@@ -105,10 +105,10 @@
:max-length constants/max-group-chat-name-length}]
(when error-message
[quo/info-message
{:type :error
:icon :i/info
:size :default
:style {:margin-top 8 :margin-left 20 :margin-bottom 16}}
{:status :error
:icon :i/info
:size :default
:container-style {:margin-top 8 :margin-left 20 :margin-bottom 16}}
error-message])
[quo/divider-line]
[rn/view
@@ -173,20 +173,21 @@
(defn avatar-view
[{:keys [contact chat-id full-name color muted? image]}]
(if contact ; `contact` is passed when it's not a group chat
(let [online? (rf/sub [:visibility-status-updates/online? chat-id])
photo-path (rf/sub [:chats/photo-path chat-id])]
[quo/user-avatar
(cond-> {:full-name full-name
:size :small
:online? online?
:profile-picture photo-path}
muted?
(assoc :ring? false))])
[quo/group-avatar
{:customization-color color
:picture (when image {:uri image})
:size :size-32}]))
[rn/view {:style {:justify-content :center}}
(if contact ; `contact` is passed when it's not a group chat
(let [online? (rf/sub [:visibility-status-updates/online? chat-id])
photo-path (rf/sub [:chats/photo-path chat-id])]
[quo/user-avatar
(cond-> {:full-name full-name
:size :small
:online? online?
:profile-picture photo-path}
muted?
(assoc :ring? false))])
[quo/group-avatar
{:customization-color color
:picture (when image {:uri image})
:size :size-32}])])
(defn- notification-layout
[child]
+2 -1
View File
@@ -66,7 +66,8 @@
(chat-list-item/chat-list-item item theme))
:scroll-event-throttle 8
:content-container-style {:padding-bottom
jump-to.constants/floating-shell-button-height}
jump-to.constants/floating-shell-button-height
:padding-top 8}
:on-scroll #(common.banner/set-scroll-shared-value
{:scroll-input (oops/oget % "nativeEvent.contentOffset.y")
:shared-value scroll-shared-value})}])))
@@ -98,9 +98,8 @@
window-height
loading-indicator-page-loading-height)]
[rn/view {:padding-top top-spacing}
;; Only use animated loading skeleton for ios
;; https://github.com/status-im/status-mobile/issues/17426
[quo/skeleton-list (skeleton-list-props :messages parent-height platform/ios?)]]))
;; Don't use animated loading skeleton https://github.com/status-im/status-mobile/issues/17426
[quo/skeleton-list (skeleton-list-props :messages parent-height false)]]))
(defn header-height
[{:keys [insets able-to-send-message? images reply edit link-previews? input-content-height]}]
@@ -21,6 +21,7 @@
[status-im.contexts.chat.messenger.messages.pin.events :as messages.pin]
[status-im.contexts.communities.events :as communities]
[status-im.contexts.shell.activity-center.events :as activity-center]
[status-im.contexts.wallet.data-store :as wallet.data-store]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
@@ -54,8 +55,11 @@
^js cleared-histories (.-clearedHistories response-js)
^js identity-images (.-identityImages response-js)
^js accounts (.-accounts response-js)
^js keypairs (.-keypairs response-js)
^js ens-username-details-js (.-ensUsernameDetails response-js)
^js customization-color-js (.-customizationColor response-js)
^js saved-addresses-js (.-savedAddresses response-js)
^js watch-only-accounts (.-watchOnlyAccounts response-js)
sync-handler (when-not process-async process-response)]
(cond
@@ -177,6 +181,22 @@
(rf/merge cofx
(process-next response-js sync-handler)))
(seq watch-only-accounts)
(do
(js-delete response-js "watchOnlyAccounts")
(rf/merge cofx
{:fx [[:dispatch
[:wallet/reconcile-watch-only-accounts
(types/js->clj watch-only-accounts)]]]}
(process-next response-js sync-handler)))
(seq keypairs)
(do
(js-delete response-js "keypairs")
(rf/merge cofx
{:fx [[:dispatch [:wallet/reconcile-keypairs (types/js->clj keypairs)]]]}
(process-next response-js sync-handler)))
(seq settings)
(do
(js-delete response-js "settings")
@@ -199,6 +219,13 @@
(models.visibility-status-updates/sync-visibility-status-update
current-visibility-status-clj)))
(seq saved-addresses-js)
(let [saved-addresses (-> saved-addresses-js types/js->clj wallet.data-store/rpc->saved-addresses)]
(js-delete response-js "savedAddresses")
(rf/merge cofx
{:fx [[:dispatch [:wallet/reconcile-saved-addresses saved-addresses]]]}
(process-next response-js sync-handler)))
(seq ens-username-details-js)
(let [ens-username-details-clj (types/js->clj ens-username-details-js)]
(js-delete response-js "ensUsernameDetails")
@@ -6,32 +6,44 @@
[status-im.common.contact-list-item.view :as contact-list-item]
[status-im.common.contact-list.view :as contact-list]
[status-im.common.home.actions.view :as home.actions]
[status-im.constants :as constants]
[status-im.contexts.communities.actions.channel-view-details.style :as style]
[status-im.feature-flags :as ff]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn- contact-item
[public-key]
(let [show-profile-actions #(rf/dispatch
[:show-bottom-sheet
{:content (fn [] [home.actions/contact-actions
{:public-key public-key}])}])
[primary-name secondary-name] (rf/sub [:contacts/contact-two-names-by-identity
public-key])
{:keys [ens-verified added? compressed-key]} (rf/sub [:contacts/contact-by-address public-key])
theme (quo.theme/use-theme)]
[public-key _ _ {:keys [theme]}]
(let [show-profile-actions (rn/use-callback
(fn []
(rf/dispatch
[:show-bottom-sheet
{:content (fn [] [home.actions/contact-actions
{:public-key public-key}])}]))
[public-key])
on-press (rn/use-callback
(fn []
(rf/dispatch [:chat.ui/show-profile public-key]))
[public-key])
[primary-name
secondary-name] (rf/sub [:contacts/contact-two-names-by-identity public-key])
{:keys [ens-verified
added?
compressed-key]} (rf/sub [:contacts/contact-by-address public-key])]
[contact-list-item/contact-list-item
{:on-press #(rf/dispatch [:chat.ui/show-profile public-key])
{:on-press on-press
:on-long-press show-profile-actions
:accessory {:type :options
:on-press show-profile-actions}}
{:primary-name primary-name
:secondary-name secondary-name
:compressed-key compressed-key
:public-key public-key
:ens-verified ens-verified
:added? added?}
{:primary-name primary-name
:secondary-name secondary-name
:compressed-key compressed-key
:public-key public-key
:ens-verified ens-verified
:added? added?
;; We hardcode the height of the container to match exactly the height
;; used in the `get-item-layout` function.
:container-style {:height constants/contact-item-height}}
theme]))
(defn- footer
@@ -40,10 +52,12 @@
(defn- get-item-layout
[_ index]
#js {:length 200 :offset (* 200 index) :index index})
#js {:length constants/contact-item-height
:offset (* constants/contact-item-height index)
:index index})
(defn- members
[items]
[items theme]
[rn/section-list
{:key-fn :public-key
:content-container-style {:padding-bottom 20}
@@ -53,70 +67,70 @@
:sticky-section-headers-enabled false
:render-section-header-fn contact-list/contacts-section-header
:render-section-footer-fn footer
:render-data {:theme theme}
:render-fn contact-item
:scroll-event-throttle 8}])
:scroll-event-throttle 32}])
(defn view
[_args]
(fn []
(let [{:keys [chat-id community-id]} (rf/sub [:get-screen-params
:screen/chat.view-channel-members-and-details])
{:keys [description chat-name emoji muted chat-type color]
:as chat} (rf/sub [:chats/chat-by-id chat-id])
pins-count (rf/sub [:chats/pin-messages-count chat-id])
items (rf/sub [:communities/sorted-community-members-section-list
community-id chat-id])
theme (quo.theme/use-theme)]
(rn/use-mount (fn []
(rf/dispatch [:pin-message/load-pin-messages chat-id])))
[:<>
(when (ff/enabled? ::ff/shell.jump-to)
[quo/floating-shell-button
{:jump-to {:on-press #(rf/dispatch [:shell/navigate-to-jump-to])
:customization-color color
:label (i18n/label :t/jump-to)}}
style/floating-shell-button])
[quo/gradient-cover {:customization-color color :opacity 0.4}]
[quo/page-nav
{:background :blur
:icon-name :i/arrow-left
:on-press #(rf/dispatch [:navigate-back])
:right-side [{:icon-name :i/options
:on-press #(rf/dispatch [:show-bottom-sheet
{:content (fn [] [home.actions/chat-actions
chat
false
true])}])}]}]
[quo/text-combinations
{:container-style style/text-combinations
:title [quo/channel-name
{:channel-name chat-name
:unlocked? true}]
:theme theme
:emoji (when (not (string/blank? emoji)) (string/trim emoji))
:customization-color color
:title-accessibility-label :welcome-title
:description description
:description-accessibility-label :welcome-sub-title}]
[rn/view {:style style/wrapper}
[rn/view
{:style style/channel-actions-wrapper}
[quo/channel-actions
{:actions
[{:big? true
:label (i18n/label :t/pinned-messages-2)
:customization-color color
:icon :i/pin
:counter-value pins-count
:on-press (fn []
(rf/dispatch [:dismiss-keyboard])
(rf/dispatch [:pin-message/show-pins-bottom-sheet
chat-id]))}
{:label (if muted (i18n/label :t/unmute-channel) (i18n/label :t/mute-channel))
:customization-color color
:icon (if muted :i/muted :i/activity-center)
:on-press (fn []
(if muted
(home.actions/unmute-chat-action chat-id)
(home.actions/mute-chat-action chat-id chat-type muted)))}]}]]]
[members items color]])))
[]
(let [{:keys [chat-id community-id]} (rf/sub [:get-screen-params
:screen/chat.view-channel-members-and-details])
{:keys [description chat-name emoji muted chat-type color]
:as chat} (rf/sub [:chats/chat-by-id chat-id])
pins-count (rf/sub [:chats/pin-messages-count chat-id])
items (rf/sub [:communities/sorted-community-members-section-list
community-id chat-id])
theme (quo.theme/use-theme)]
(rn/use-mount (fn []
(rf/dispatch [:pin-message/load-pin-messages chat-id])))
[:<>
(when (ff/enabled? ::ff/shell.jump-to)
[quo/floating-shell-button
{:jump-to {:on-press #(rf/dispatch [:shell/navigate-to-jump-to])
:customization-color color
:label (i18n/label :t/jump-to)}}
style/floating-shell-button])
[quo/gradient-cover {:customization-color color :opacity 0.4}]
[quo/page-nav
{:background :blur
:icon-name :i/arrow-left
:on-press #(rf/dispatch [:navigate-back])
:right-side [{:icon-name :i/options
:on-press #(rf/dispatch [:show-bottom-sheet
{:content (fn [] [home.actions/chat-actions
chat
false
true])}])}]}]
[quo/text-combinations
{:container-style style/text-combinations
:title [quo/channel-name
{:channel-name chat-name
:unlocked? true}]
:theme theme
:emoji (when (not (string/blank? emoji)) (string/trim emoji))
:customization-color color
:title-accessibility-label :welcome-title
:description description
:description-accessibility-label :welcome-sub-title}]
[rn/view {:style style/wrapper}
[rn/view
{:style style/channel-actions-wrapper}
[quo/channel-actions
{:actions
[{:big? true
:label (i18n/label :t/pinned-messages-2)
:customization-color color
:icon :i/pin
:counter-value pins-count
:on-press (fn []
(rf/dispatch [:dismiss-keyboard])
(rf/dispatch [:pin-message/show-pins-bottom-sheet
chat-id]))}
{:label (if muted (i18n/label :t/unmute-channel) (i18n/label :t/mute-channel))
:customization-color color
:icon (if muted :i/muted :i/activity-center)
:on-press (fn []
(if muted
(home.actions/unmute-chat-action chat-id)
(home.actions/mute-chat-action chat-id chat-type muted)))}]}]]]
[members items theme]]))
@@ -4,6 +4,7 @@
re-frame.db
[react-native.core :as rn]
[react-native.safe-area :as safe-area]
[status-im.common.check-before-syncing.view :as check-before-syncing]
[status-im.common.not-implemented :as not-implemented]
[status-im.common.resources :as resources]
[status-im.config :as config]
@@ -25,6 +26,14 @@
[:onboarding/navigate-to-sign-in-by-syncing]
1000))
(defn- show-check-before-syncing
[]
(rf/dispatch
[:show-bottom-sheet
{:content (fn [] [check-before-syncing/view
{:on-submit navigate-to-sign-in-by-syncing}])
:shell? true}]))
(defn- navigate-to-sign-in-by-seed-phrase
[create-profile?]
(rf/dispatch [:onboarding/navigate-to-sign-in-by-seed-phrase
@@ -62,7 +71,7 @@
:accessibility-label :scan-sync-code-option-card
:image (resources/get-image :generate-keys)
:max-height (option-card-max-height window-height)
:on-press navigate-to-sign-in-by-syncing}])
:on-press show-check-before-syncing}])
(defn sign-in-options
[sign-in-type]
@@ -38,14 +38,11 @@
[rn/view {:style style/info-message}
(when shown
[quo/info-message
{:type status
:size :default
:icon (if (= status :success) :i/positive-state :i/info)
:text-color (when (= status :default)
colors/white-70-blur)
:icon-color (when (= status :default)
colors/white-70-blur)
:style {}}
{:status status
:size :default
:icon (if (= status :success) :i/positive-state :i/info)
:color (when (= status :default)
colors/white-70-blur)}
text])]])
(defn password-inputs
@@ -158,12 +158,11 @@
:on-change-text on-change-text}}]]
[quo/info-message
{:type info-type
:size :default
:icon (if valid-name? :i/positive-state :i/info)
:text-color (when (= :default info-type) colors/white-70-blur)
:icon-color (when (= :default info-type) colors/white-70-blur)
:style style/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
@@ -1,7 +1,6 @@
(ns status-im.contexts.preview.quo.buttons.slide-button
(:require
[quo.core :as quo]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]))
@@ -18,41 +17,36 @@
:type :boolean}
{:key :blur?
:type :boolean}
{:key :keep-at-end-after-slide?
:type :boolean}
(preview/customization-color-option {:key :color})])
(defn f-view
[]
(let [state (reagent/atom {:disabled? false
:color :blue
:size :size-48})
color (reagent/cursor state [:color])
blur? (reagent/cursor state [:blur?])
complete? (reagent/atom false)]
(let [state (reagent/atom {:disabled? false
:color :blue
:size :size-48
:keep-at-end-after-slide? false})
color (reagent/cursor state [:color])
blur? (reagent/cursor state [:blur?])
keep-at-end-after-slide? (reagent/cursor state [:keep-at-end-after-slide?])]
(fn []
(rn/use-effect (fn []
(reset! complete? true)
(js/setTimeout #(reset! complete? false) 50))
[(:size @state)])
[preview/preview-container
{:state state
:descriptor descriptor
:component-container-style (when-not @blur? (:align-items :center))
:blur? @blur?
:show-blur-background? true}
(if (not @complete?)
[quo/slide-button
{:track-text "We gotta slide"
:track-icon :face-id
:customization-color @color
:size (:size @state)
:disabled? (:disabled? @state)
:blur? @blur?
:type (:type @state)
:on-complete (fn [_]
(js/setTimeout (fn [] (reset! complete? true))
1000)
(js/alert "I don't wanna slide anymore"))}]
[quo/button {:on-press (fn [] (reset! complete? false))}
"Try again"])])))
[quo/slide-button
{:track-text "We gotta slide"
:track-icon :face-id
:customization-color @color
:size (:size @state)
:disabled? (:disabled? @state)
:blur? @blur?
:type (:type @state)
:on-complete (fn [reset-fn]
(js/alert "Slide complete")
(reset-fn @keep-at-end-after-slide?))}]])))
(defn view [] [:f> f-view])
@@ -1,28 +1,43 @@
(ns status-im.contexts.preview.quo.info.info-message
(:require
[quo.core :as quo]
[reagent.core :as reagent]
[react-native.core :as rn]
[status-im.contexts.preview.quo.preview :as preview]))
(def descriptor
[{:key :type
[{:key :status
:type :select
:options [{:key :default}
{:key :success}
{:key :error}]}
{:key :error}
{:key :warning}]}
{:key :size
:type :select
:options [{:key :default}
{:key :tiny}]}
{:key :blur?
:type :boolean}
{:key :icon
:type :select
:options [{:key :i/placeholder}
{:key :i/info}]}
{:key :message
:type :text}])
(defn view
[]
(let [state (reagent/atom {:type :default
:size :default
:icon :i/placeholder
:message "This is a message"})]
(fn []
[preview/preview-container {:state state :descriptor descriptor}
[quo/info-message @state (:message @state)]])))
(let [[state set-state] (rn/use-state
{:status :default
:size :default
:message "This is a message"
:blur? false
:icon :i/placeholder})
blur? (:blur? state)]
[preview/preview-container
{:state state
:descriptor descriptor
:blur-dark-only? true
:show-blur-background? blur?
:blur? blur?
:set-state set-state}
[quo/info-message (dissoc state :message) (:message state)]]))
@@ -65,9 +65,9 @@
:customization-color :blue}
:header [rn/view
[quo/info-message
{:type :success
:size :tiny
:icon :i/placeholder}
{:status :success
:size :tiny
:icon :i/placeholder}
"info-message as title"]]
:body [quo/snippet {:language :clojure :max-lines 15 :syntax true}
snippet-preview/clojure-example]
@@ -55,7 +55,8 @@
{:type :select
:key :size
:options [{:key :default}
{:key :small}]}])
{:key :small}
{:key :large}]}])
(defn view
[]
@@ -68,9 +68,9 @@
:on-change-text on-nickname-change
:on-submit-editing on-nickname-submit}]
[quo/info-message
{:icon :i/info
:size :default
:type (if-not (string/blank? error-msg) :error :default)}
{:icon :i/info
:size :default
:status (if-not (string/blank? error-msg) :error :default)}
(if-not (string/blank? error-msg)
error-msg
(i18n/label :t/nickname-visible-to-you))]]
@@ -58,9 +58,9 @@
:on-change-text on-change-text}]
(when-not (string/blank? error-msg)
[quo/info-message
{:type :error
:size :default
:icon :i/info}
{:status :error
:size :default
:icon :i/info}
error-msg])]
[rn/view {:style style/button-wrapper}
[quo/button
@@ -58,9 +58,9 @@
:on-change-text on-change-text}]
(when-not (string/blank? @error-msg)
[quo/info-message
{:type :error
:size :default
:icon :i/info}
{:status :error
:size :default
:icon :i/info}
@error-msg])]
[rn/view {:style style/button-wrapper}
[quo/button
@@ -5,6 +5,7 @@
[react-native.core :as rn]
[react-native.reanimated :as reanimated]
[react-native.safe-area :as safe-area]
[status-im.common.check-before-syncing.view :as check-before-syncing]
[status-im.common.confirmation-drawer.view :as confirmation-drawer]
[status-im.common.standard-authentication.core :as standard-authentication]
[status-im.config :as config]
@@ -41,6 +42,17 @@
:linear
50))
(defn- show-check-before-syncing
[]
(rf/dispatch
[:show-bottom-sheet
{:content (fn [] [check-before-syncing/view
{:on-submit
#(debounce/throttle-and-dispatch
[:open-modal :screen/onboarding.sign-in]
1000)}])
:shell? true}]))
(defn new-account-options
[]
[quo/action-drawer
@@ -55,9 +67,7 @@
:accessibility-label :create-new-profile}
{:icon :i/multi-profile
:label (i18n/label :t/add-existing-status-profile)
:on-press #(debounce/throttle-and-dispatch
[:open-modal :screen/onboarding.sign-in]
1000)
:on-press show-check-before-syncing
:accessibility-label :multi-profile}]]])
(defn show-new-account-options
@@ -61,7 +61,14 @@
:image :icon
:blur? true
:action :arrow})]
[{:title (i18n/label :t/syncing)
[(when config/show-not-implemented-features?
{:title (i18n/label :t/privacy-and-security)
:on-press #(rf/dispatch [:open-modal :screen/settings-privacy-and-security])
:image-props :i/privacy
:image :icon
:blur? true
:action :arrow})
{:title (i18n/label :t/syncing)
:on-press #(rf/dispatch [:open-modal :settings-syncing])
:image-props :i/syncing
:image :icon
@@ -24,12 +24,11 @@
[rn/view {:style style/info-message}
(when shown?
[quo/info-message
(cond-> {:type status
:size :default}
(cond-> {:status status
:size :default}
(not= :success status) (assoc :icon :i/info)
(= :success status) (assoc :icon :i/positive-state)
(= :default status) (assoc :text-color colors/white-70-blur
:icon-color colors/white-70-blur))
(= :default status) (assoc :color colors/white-70-blur))
text])]])
(defn- calc-password-strength
@@ -43,9 +43,9 @@
{:style style/error-container}
(when error
[quo/info-message
{:type :error
:size :default
:icon :i/info}
{:status :error
:size :default
:icon :i/info}
(i18n/label :t/oops-wrong-password)])]
[quo/information-box
{:type :error
@@ -1,5 +1,6 @@
(ns status-im.contexts.profile.settings.visibility-sheet.view
(:require [quo.core :as quo]
[react-native.core :as rn]
[status-im.constants :as constants]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
@@ -17,6 +18,10 @@
[:visibility-status-updates/visibility-status-update
public-key])
customization-color (rf/sub [:profile/customization-color])]
(rn/use-mount
(fn []
(rf/dispatch [:peer-stats/get-count])))
[quo/action-drawer
[[{:icon :i/online
:no-icon-color? true
@@ -0,0 +1,11 @@
(ns status-im.contexts.settings.privacy-and-security.style)
(def title-container
{:flex 0
:padding-horizontal 20
:margin-vertical 12})
(defn page-wrapper
[top-inset]
{:padding-top top-inset
:flex 1})
@@ -0,0 +1,42 @@
(ns status-im.contexts.settings.privacy-and-security.view
(:require
[quo.core :as quo]
[quo.theme]
[react-native.safe-area :as safe-area]
[status-im.contexts.settings.privacy-and-security.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn navigate-back
[]
(rf/dispatch [:navigate-back]))
(defn view
[]
(let [insets (safe-area/get-insets)
customization-color (rf/sub [:profile/customization-color])]
[quo/overlay
{:type :shell
:container-style (style/page-wrapper (:top insets))}
[quo/page-nav
{:key :header
:background :blur
:icon-name :i/arrow-left
:on-press navigate-back}]
[quo/standard-title
{:title (i18n/label :t/privacy-and-security)
:container-style style/title-container
:accessibility-label :privacy-and-security-header
:customization-color customization-color}]
[quo/category
{:key :category
:data [{:title "Dummy"
:image-props :i/placeholder
:image :icon
:blur? true
:action :selector
:action-props {:on-change identity
:checked? false}
:on-press identity}]
:blur? true
:list-type :settings}]]))
@@ -92,7 +92,7 @@
(rf/reg-event-fx :wallet/make-keypairs-accounts-fully-operable make-keypairs-accounts-fully-operable)
(defn connection-string-for-import-keypair
[{:keys [db]} [{:keys [sha3-pwd keypairs-key-uids connection-string on-success]}]]
[{:keys [db]} [{:keys [sha3-pwd keypairs-key-uids connection-string]}]]
(let [key-uid (get-in db [:profile/profile :key-uid])]
{:fx [[:effects.syncing/import-keypairs-keystores
{:key-uid key-uid
@@ -100,7 +100,6 @@
:keypairs-key-uids keypairs-key-uids
:connection-string connection-string
:on-success (fn [key-uids]
(rf/call-continuation on-success)
(rf/dispatch [:wallet/make-keypairs-accounts-fully-operable key-uids]))
:on-fail (fn [error]
(log/error "failed to import missing key pairs with connection string"
@@ -113,7 +112,7 @@
(rf/reg-event-fx :wallet/connection-string-for-import-keypair connection-string-for-import-keypair)
(defn success-keypair-qr-scan
[_ [connection-string keypairs-key-uids on-import-success]]
[_ [connection-string keypairs-key-uids]]
{:fx [[:dispatch
[:standard-auth/authorize-with-password
{:blur? true
@@ -125,8 +124,7 @@
[:wallet/connection-string-for-import-keypair
{:connection-string connection-string
:keypairs-key-uids keypairs-key-uids
:sha3-pwd password
:on-success on-import-success}]))}]]]})
:sha3-pwd password}]))}]]]})
(rf/reg-event-fx :wallet/success-keypair-qr-scan success-keypair-qr-scan)
@@ -128,9 +128,9 @@
:default-value private-key}]
(when flow-state
[quo/info-message
{:type (if (= flow-state :correct-private-key) :success :error)
:size :default
:icon :i/info}
{:status (if (= flow-state :correct-private-key) :success :error)
:size :default
:icon :i/info}
(case flow-state
:correct-private-key (i18n/label :t/correct-private-key)
:invalid-private-key (i18n/label :t/invalid-private-key)
@@ -13,14 +13,12 @@
on-success-scan (rn/use-callback (fn [scanned-text]
(rf/dispatch [:wallet/success-keypair-qr-scan
scanned-text
keypairs-key-uids
[:navigate-back]])
keypairs-key-uids])
[keypairs-key-uids]))]
[scan-qr-code/view
{:title (i18n/label :t/scan-key-pairs-qr-code)
:subtitle (i18n/label :t/find-it-in-setting)
:share-button? false
:import-keypair? true
:validate-fn sync-utils/valid-connection-string?
:error-message (i18n/label :t/invalid-key-pair-qr)
:on-success-scan on-success-scan}]))
@@ -94,9 +94,8 @@
:error? (not (string/blank? error-msg))}]
(when-not (string/blank? error-msg)
[quo/info-message
{:type :error
{:status :error
:size :default
:icon :i/info
:container-style style/error-container}
error-msg])]]))
@@ -85,8 +85,8 @@
{:accessibility-label :error-message
:size :default
:icon :i/alert
:type :error
:style style/info-message}
:status :error
:container-style style/info-message}
error-msg])))
(defn- existing-saved-address
@@ -23,15 +23,29 @@
(rf/reg-event-fx :wallet/save-address save-address)
(defn- update-saved-addresses
[saved-addresses-db new-saved-addresses]
(reduce
(fn [acc {:keys [address removed? test?] :as saved-address}]
(let [db-key (if test? :test :prod)]
(if removed?
(update acc db-key dissoc address)
(assoc-in acc [db-key address] saved-address))))
(or saved-addresses-db
{:test {}
:prod {}})
new-saved-addresses))
(defn reconcile-saved-addresses
[{:keys [db]} [saved-addresses]]
{:db (update-in db [:wallet :saved-addresses] update-saved-addresses saved-addresses)})
(rf/reg-event-fx :wallet/reconcile-saved-addresses reconcile-saved-addresses)
(defn get-saved-addresses-success
[{:keys [db]} [raw-saved-addresses]]
(let [saved-addresses (reduce
(fn [result {:keys [address test?] :as saved-address}]
(assoc-in result [(if test? :test :prod) address] saved-address))
{:test {}
:prod {}}
(data-store/rpc->saved-addresses raw-saved-addresses))]
{:db (assoc-in db [:wallet :saved-addresses] saved-addresses)}))
[_ [raw-saved-addresses]]
(let [saved-addresses (data-store/rpc->saved-addresses raw-saved-addresses)]
{:fx [[:dispatch [:wallet/reconcile-saved-addresses saved-addresses]]]}))
(rf/reg-event-fx :wallet/get-saved-addresses-success get-saved-addresses-success)
@@ -52,15 +66,17 @@
(rf/reg-event-fx :wallet/get-saved-addresses get-saved-addresses)
(defn delete-saved-address-success
[_ [toast-message]]
{:fx [[:dispatch [:wallet/get-saved-addresses]]
[:dispatch [:hide-bottom-sheet]]
[:dispatch-later
{:ms 100
:dispatch [:toasts/upsert
{:type :positive
:theme :dark
:text toast-message}]}]]})
[{:keys [db]} [{:keys [address test-networks-enabled? toast-message]}]]
(let [db-key (if test-networks-enabled? :test :prod)
saved-address (get-in db [:wallet :saved-addresses db-key address])]
{:fx [[:dispatch [:wallet/reconcile-saved-addresses [(assoc saved-address :removed? true)]]]
[:dispatch [:hide-bottom-sheet]]
[:dispatch-later
{:ms 100
:dispatch [:toasts/upsert
{:type :positive
:theme :dark
:text toast-message}]}]]}))
(rf/reg-event-fx :wallet/delete-saved-address-success delete-saved-address-success)
@@ -82,7 +98,10 @@
{:fx [[:json-rpc/call
[{:method "wakuext_deleteSavedAddress"
:params [address test-networks-enabled?]
:on-success [:wallet/delete-saved-address-success toast-message]
:on-success [:wallet/delete-saved-address-success
{:address address
:test-networks-enabled? test-networks-enabled?
:toast-message toast-message}]
:on-error [:wallet/delete-saved-address-failed]}]]]}))
(rf/reg-event-fx :wallet/delete-saved-address delete-saved-address)
@@ -2,7 +2,8 @@
(:require
[cljs.test :refer-macros [deftest is testing]]
matcher-combinators.test
[status-im.contexts.settings.wallet.saved-addresses.events :as events]))
[status-im.contexts.settings.wallet.saved-addresses.events :as events]
[status-im.contexts.wallet.data-store :as data-store]))
(deftest get-saved-addresses-test
(testing "get saved addresses - dispatches RPC call"
@@ -15,7 +16,7 @@
:on-error [:wallet/saved-addresses-rpc-error :get-saved-addresses]}]]]]
(is (match? expected-fx result-fx)))))
(def saved-address-1
(def saved-address-rpc-1
{:isTest false
:address "0x1"
:mixedcaseAddress "0x1"
@@ -26,21 +27,45 @@
:colorId "purple"
:removed false})
(def saved-address-1
{:test? true
:address "0x1"
:mixedcase-address "0x1"
:chain-short-names "eth:oeth:"
:network-preferences-names `(:mainnet :optimism)
:name "Bob"
:created-at 1716826714
:ens ""
:ens? false
:customization-color :blue
:removed? false})
(def saved-address-2
{:isTest true
:address "0x2"
:mixedcaseAddress "0x2"
:chainShortNames "eth:arb1:oeth:"
:name "Bob"
:createdAt 1716826714
:ens ""
:colorId "blue"
:removed false})
{:test? false
:address "0x2"
:mixedcase-address "0x2"
:chain-short-names "eth:arb1:oeth:"
:network-preferences-names `(:mainnet :arbitrum :optimism)
:name "Alicia Keys"
:created-at 1716826806
:ens "alicia.eth"
:ens? true
:customization-color :purple
:removed? false})
(deftest get-saved-addresses-success-test
(let [cofx {:db {}}
raw-saved-addresses [saved-address-rpc-1]
effects (events/get-saved-addresses-success cofx [raw-saved-addresses])
saved-addresses (data-store/rpc->saved-addresses raw-saved-addresses)
result-fx (:fx effects)
expected-fx [[:dispatch [:wallet/reconcile-saved-addresses saved-addresses]]]]
(is (match? expected-fx result-fx))))
(deftest reconcile-saved-addresses-test
(testing "no saved addresses"
(let [cofx {:db {}}
effects (events/get-saved-addresses-success cofx nil)
effects (events/reconcile-saved-addresses cofx nil)
result-db (:db effects)
expected-db {:wallet {:saved-addresses {:test {}
:prod {}}}}]
@@ -48,15 +73,15 @@
(testing "one test saved address"
(let [cofx {:db {}}
effects (events/get-saved-addresses-success cofx [[saved-address-2]])
effects (events/reconcile-saved-addresses cofx [[saved-address-1]])
result-db (:db effects)
expected-db {:wallet {:saved-addresses
{:test {"0x2" {:test? true
:address "0x2"
:mixedcase-address "0x2"
:chain-short-names "eth:arb1:oeth:"
{:test {"0x1" {:test? true
:address "0x1"
:mixedcase-address "0x1"
:chain-short-names "eth:oeth:"
:ens? false
:network-preferences-names `(:mainnet :arbitrum :optimism)
:network-preferences-names `(:mainnet :optimism)
:name "Bob"
:created-at 1716826714
:ens ""
@@ -67,29 +92,73 @@
(testing "two saved addresses (test and prod)"
(let [cofx {:db {}}
effects (events/get-saved-addresses-success cofx [[saved-address-1 saved-address-2]])
effects (events/reconcile-saved-addresses cofx [[saved-address-1 saved-address-2]])
result-db (:db effects)
expected-db {:wallet {:saved-addresses
{:test {"0x2" {:test? true
:address "0x2"
:mixedcase-address "0x2"
:chain-short-names "eth:arb1:oeth:"
:network-preferences-names `(:mainnet :arbitrum :optimism)
{:test {"0x1" {:test? true
:address "0x1"
:mixedcase-address "0x1"
:chain-short-names "eth:oeth:"
:ens? false
:network-preferences-names `(:mainnet :optimism)
:name "Bob"
:created-at 1716826714
:ens ""
:customization-color :blue
:removed? false}}
:prod {"0x1" {:test? false
:address "0x1"
:mixedcase-address "0x1"
:prod {"0x2" {:test? false
:address "0x2"
:mixedcase-address "0x2"
:chain-short-names "eth:arb1:oeth:"
:network-preferences-names `(:mainnet :arbitrum :optimism)
:ens? false
:name "Amy"
:ens? true
:name "Alicia Keys"
:created-at 1716826806
:ens ""
:ens "alicia.eth"
:customization-color :purple
:removed? false}}}}}]
(is (match? expected-db result-db))))
(testing "remove a test saved addresses"
(let [cofx {:db {:wallet {:saved-addresses
{:test {"0x1" {:test? true
:address "0x1"
:mixedcase-address "0x1"
:chain-short-names "eth:oeth:"
:ens? false
:network-preferences-names `(:mainnet :optimism)
:name "Bob"
:created-at 1716826714
:ens ""
:customization-color :blue
:removed? false}}
:prod {"0x2" {:test? false
:address "0x2"
:mixedcase-address "0x2"
:chain-short-names "eth:arb1:oeth:"
:network-preferences-names `(:mainnet :arbitrum
:optimism)
:ens? true
:name "Alicia Keys"
:created-at 1716826806
:ens "alicia.eth"
:customization-color :purple
:removed? false}}}}}}
effects (events/reconcile-saved-addresses cofx
[[(assoc saved-address-1 :removed? true)
saved-address-2]])
result-db (:db effects)
expected-db {:wallet {:saved-addresses
{:test {}
:prod {"0x2" {:test? false
:address "0x2"
:mixedcase-address "0x2"
:chain-short-names "eth:arb1:oeth:"
:network-preferences-names `(:mainnet :arbitrum :optimism)
:ens? true
:name "Alicia Keys"
:created-at 1716826806
:ens "alicia.eth"
:customization-color :purple
:removed? false}}}}}]
(is (match? expected-db result-db)))))
@@ -141,7 +210,10 @@
expected-fx [[:json-rpc/call
[{:method "wakuext_deleteSavedAddress"
:params [address test-networks-enabled?]
:on-success [:wallet/delete-saved-address-success toast-message]
:on-success [:wallet/delete-saved-address-success
{:address address
:test-networks-enabled? test-networks-enabled?
:toast-message toast-message}]
:on-error [:wallet/delete-saved-address-failed]}]]]]
(is (match? expected-fx result-fx)))))
@@ -109,7 +109,7 @@
:on-press open-show-address-qr
:accessibility-label :show-address-qr-code}
{:icon :i/edit
:label (i18n/label :t/edit-account)
:label (i18n/label :t/edit-details)
:blur? true
:on-press open-edit-saved-address
:accessibility-label :edit-saved-address}
@@ -3,6 +3,7 @@
[quo.core :as quo]
[quo.foundations.colors :as colors]
[react-native.core :as rn]
[status-im.common.check-before-syncing.view :as check-before-syncing]
[status-im.contexts.syncing.device.view :as device]
[status-im.contexts.syncing.syncing-devices-list.style :as style]
[utils.i18n :as i18n]
@@ -13,19 +14,31 @@
(rf/dispatch [:navigate-back]))
(defn open-setup-syncing
[]
(rf/dispatch [:open-modal :settings-setup-syncing]))
[customization-color]
(rf/dispatch
[:show-bottom-sheet
{:theme :dark
:shell? true
:content
(fn [] [check-before-syncing/view
{:customization-color customization-color
:on-submit #(rf/dispatch [:open-modal :settings-setup-syncing])}])}]))
(defn view
[]
(let [devices (rf/sub [:pairing/installations])
devices-with-button (map #(assoc % :show-button? true) devices)
user-device (first devices-with-button)
other-devices (rest devices-with-button)
profile-color (rf/sub [:profile/customization-color])
{:keys [paired-devices unpaired-devices]} (group-by
#(if (:enabled? %) :paired-devices :unpaired-devices)
other-devices)]
(let [devices (rf/sub [:pairing/installations])
devices-with-button (map #(assoc % :show-button? true) devices)
user-device (first devices-with-button)
other-devices (rest devices-with-button)
profile-color (rf/sub [:profile/customization-color])
open-setup-syncing-with-customization-color (rn/use-callback (partial open-setup-syncing
profile-color)
[profile-color])
{:keys [paired-devices unpaired-devices]} (group-by
#(if (:enabled? %)
:paired-devices
:unpaired-devices)
other-devices)]
[quo/overlay {:type :shell :top-inset? true}
[quo/page-nav
{:type :no-title
@@ -47,7 +60,7 @@
:type :primary
:customization-color profile-color
:icon-only? true
:on-press open-setup-syncing}
:on-press open-setup-syncing-with-customization-color}
:i/add]]
[device/view (merge user-device {:this-device? true})]
(when (seq paired-devices)
@@ -12,8 +12,8 @@
[utils.re-frame :as rf]))
(defn- on-collectible-press
[{:keys [id]}]
(rf/dispatch [:wallet/get-collectible-details id]))
[{:keys [id]} aspect-ratio]
(rf/dispatch [:wallet/get-collectible-details id aspect-ratio]))
(defn- on-collectible-long-press
[{:keys [preview-url collectible-details id]}]
@@ -103,8 +103,8 @@
(when activity-state
[quo/info-message
(assoc props
:style style/info-message
:size :default)
:container-style style/info-message
:size :default)
(i18n/label message)])))
(defn view
@@ -163,7 +163,7 @@
{:accessibility-label :error-message
:size :default
:icon :i/info
:type :error
:style style/info-message}
:status :error
:container-style style/info-message}
@validation-msg]
[activity-indicator activity-state])]]))))
[activity-indicator])]]))))
@@ -117,12 +117,12 @@
{:weight :monospace}
(:address derivation-path)]]
[quo/info-message
{:type (case state
:has-activity :success
:no-activity :warning
:default)
:icon (if (= state :scanning) :i/scanning :i/done)
:style style/info}
{:status (case state
:has-activity :success
:no-activity :warning
:default)
:icon (if (= state :scanning) :i/scanning :i/done)
:style style/info}
(i18n/label (case state
:has-activity :t/address-activity
:no-activity :t/address-no-activity
@@ -91,7 +91,7 @@
:error error}]
(when error
[quo/info-message
{:type :error
{:status :error
:size :default
:icon :i/info
:container-style style/error-container}
@@ -87,7 +87,7 @@
:container-style (style/title-input-container error)}]
(when error
[quo/info-message
{:type :error
{:status :error
:size :default
:icon :i/info
:container-style {:margin-left 20
@@ -167,12 +167,13 @@
(rf/reg-event-fx
:wallet/get-collectible-details
(fn [_ [collectible-id]]
(fn [{:keys [db]} [collectible-id aspect-ratio]]
(let [request-id 0
collectible-id-converted (cske/transform-keys transforms/->PascalCaseKeyword collectible-id)
data-type (collectible-data-types :details)
request-params [request-id [collectible-id-converted] data-type]]
{:fx [[:json-rpc/call
{:db (assoc-in db [:wallet :last-collectible-aspect-ratio] aspect-ratio)
:fx [[:json-rpc/call
[{:method "wallet_getCollectiblesByUniqueIDAsync"
:params request-params
:on-error (fn [error]
@@ -197,7 +198,7 @@
(rf/reg-event-fx
:wallet/clear-last-collectible-details
(fn [{:keys [db]}]
{:db (update-in db [:wallet] dissoc :last-collectible-details)}))
{:db (update-in db [:wallet] dissoc :last-collectible-details :last-collectible-aspect-ratio)}))
(rf/reg-event-fx :wallet/trigger-share-collectible
(fn [_ [{:keys [title uri]}]]
@@ -12,8 +12,8 @@
(defn preview-container
[]
{:margin-horizontal 8
:margin-top (+ (header-height) 12)})
{:padding-horizontal 8
:margin-top (+ (header-height) 12)})
(def header
{:margin-horizontal 20
@@ -150,6 +150,7 @@
set-title-ref (rn/use-callback #(reset! title-ref %))
animation-shared-element-id (rf/sub [:animation-shared-element-id])
collectible-owner (rf/sub [:wallet/last-collectible-details-owner])
aspect-ratio (rf/sub [:wallet/last-collectible-aspect-ratio])
{:keys [id
preview-url
collection-data
@@ -180,7 +181,8 @@
[rn/view
[gradient-layer preview-uri]
[quo/expanded-collectible
{:image-src preview-uri
{:aspect-ratio aspect-ratio
:image-src preview-uri
:container-style (style/preview-container)
:counter (utils/collectible-owned-counter total-owned)
:native-ID (when (= animation-shared-element-id token-id) :shared-element)
@@ -4,6 +4,7 @@
[status-im.contexts.wallet.sheets.account-options.view :as account-options]
[status-im.contexts.wallet.sheets.network-filter.view :as network-filter]
[status-im.contexts.wallet.sheets.select-account.view :as select-account]
[status-im.feature-flags :as ff]
[utils.re-frame :as rf]))
(defn get-bottom-sheet-args
@@ -36,7 +37,7 @@
:networks networks
:align-center? true
:networks-on-press #(rf/dispatch [:show-bottom-sheet {:content network-filter/view}])
:right-side [(when (and true
:right-side [(when (and (ff/enabled? ::wallet.wallet-connect)
(not watch-only?))
{:icon-name :i/dapps
:on-press #(rf/dispatch [:navigate-to :screen/wallet.connected-dapps])})
@@ -14,7 +14,7 @@
:as collectible}
index]
(let [on-press-fn (rn/use-callback #(when on-press
(on-press collectible)))
(on-press collectible %)))
on-long-press-fn (rn/use-callback #(when on-long-press
(on-long-press collectible)))]
[quo/collectible-list-item
@@ -62,7 +62,7 @@
:container-style (style/title-input-container error)}]
(when error
[quo/info-message
{:type :error
{:status :error
:size :default
:icon :i/info
:container-style {:margin-left 20
@@ -177,7 +177,7 @@
"This function returns token values in the props of token-value (quo) component"
[{:keys [token color currency currency-symbol]}]
(let [balance (calculate-total-token-balance token)
fiat-value (calculate-token-fiat-value
fiat-unformatted-value (calculate-token-fiat-value
{:currency currency
:balance balance
:token token})
@@ -191,7 +191,7 @@
crypto-value (get-standard-crypto-format token balance)
fiat-value (get-standard-fiat-format crypto-value
currency-symbol
fiat-value)]
fiat-unformatted-value)]
{:token (:symbol token)
:token-name (:name token)
:state :default
@@ -201,10 +201,11 @@
(neg? change-pct-24hour) :negative
:else :empty)
:customization-color color
:values {:crypto-value crypto-value
:fiat-value fiat-value
:fiat-change formatted-token-price
:percentage-change percentage-change}}))
:values {:crypto-value crypto-value
:fiat-value fiat-value
:fiat-unformatted-value fiat-unformatted-value
:fiat-change formatted-token-price
:percentage-change percentage-change}}))
(defn get-multichain-address
[networks address]
+28 -1
View File
@@ -5,6 +5,7 @@
[clojure.string :as string]
[status-im.constants :as constants]
[status-im.contexts.wallet.common.utils.networks :as network-utils]
[utils.collection :as utils.collection]
[utils.money :as money]
[utils.number :as utils.number]
[utils.transforms :as transforms]))
@@ -154,9 +155,35 @@
:colorId :customization-color
:mixedcaseAddress :mixedcase-address
:removed :removed?})
(update :customization-color keyword)
(update :customization-color (comp keyword string/lower-case))
add-keys-to-saved-address))
(defn rpc->saved-addresses
[saved-addresses]
(map rpc->saved-address saved-addresses))
(defn reconcile-keypairs
[keypairs]
(let [received-keypairs (rpc->keypairs keypairs)
keypair-label #(if % :removed-keypairs :updated-keypairs)
{:keys [removed-keypairs
updated-keypairs]
:or {updated-keypairs []
removed-keypairs []}} (group-by (comp keypair-label :removed) received-keypairs)
updated-keypairs-by-id (utils.collection/index-by :key-uid updated-keypairs)
updated-accounts-by-address (transduce (comp (mapcat :accounts)
(filter (comp not :chat))
(map #(vector (:address %) %)))
conj
{}
updated-keypairs)
removed-keypairs-ids (set (map :key-uid removed-keypairs))
removed-account-addresses (transduce (comp (mapcat :accounts)
(map :address))
conj
#{}
removed-keypairs)]
{:removed-keypair-ids removed-keypairs-ids
:removed-account-addresses removed-account-addresses
:updated-keypairs-by-id updated-keypairs-by-id
:updated-accounts-by-address updated-accounts-by-address}))
@@ -0,0 +1,240 @@
(ns status-im.contexts.wallet.data-store-test
(:require
[cljs.test :refer-macros [deftest is testing]]
[matcher-combinators.matchers :as matchers]
matcher-combinators.test
[status-im.contexts.wallet.data-store :as sut]))
(def raw-account
{:path "m/44'/60'/0'/0/0"
:name "Account name"
:wallet true
:chat false
:emoji "🍙"
:colorId "blue"
:type "generated"
:createdAt 1716548742000
:prodPreferredChainIds "1:42161"
:testPreferredChainIds "11155111:421614"
:removed false
:operable "fully"})
(def account
{:path "m/44'/60'/0'/0/0"
:emoji "🍙"
:color :blue
:wallet true
:default-account? true
:name "Account name"
:type :generated
:chat false
:test-preferred-chain-ids #{11155111 421614}
:watch-only? false
:prod-preferred-chain-ids #{1 42161}
:created-at 1716548742000
:operable :fully
:removed false})
(defn make-raw-account
[overrides]
(merge raw-account overrides))
(def raw-keypair-profile
{:type "profile"
:key-uid "0x000"
:accounts [(make-raw-account {:key-uid "0x000"
:address "1x000"
:wallet false
:chat true})
(make-raw-account {:key-uid "0x000"
:address "2x000"})]})
(def raw-keypair-seed-phrase
{:type "seed"
:key-uid "0x123"
:accounts [(make-raw-account {:key-uid "0x123"
:address "1x123"})]})
(def raw-keypair-private-key
{:type "key"
:key-uid "0x456"
:accounts [(make-raw-account {:key-uid "0x456"
:address "1x456"
:operable "no"})]})
(deftest chain-ids-string->set-test
(testing "chaind-ids-string->set splits and parses chain-ids from string"
(is (match? #{1 42161}
(sut/chain-ids-string->set (:prodPreferredChainIds raw-account))))
(is (match? #{11155111 421614}
(sut/chain-ids-string->set (:testPreferredChainIds raw-account))))))
(deftest rpc->keypair-test
(testing "rpc->keypair transforms a profile keypair"
(is
(match? {:type :profile
:key-uid "0x000"
:lowest-operability :fully
:accounts [{:key-uid "0x000"
:operable :fully
:chat true
:wallet false
:address "1x000"
:path (:path raw-account)
:name (:name raw-account)
:emoji (:emoji raw-account)
:removed (:removed raw-account)
:color (keyword (:colorId raw-account))
:created-at (:createdAt raw-account)
:prod-preferred-chain-ids (sut/chain-ids-string->set
(:prodPreferredChainIds raw-account))
:test-preferred-chain-ids (sut/chain-ids-string->set
(:testPreferredChainIds raw-account))}
{:key-uid "0x000"
:operable :fully
:chat false
:wallet true
:address "2x000"
:path (:path raw-account)
:name (:name raw-account)
:emoji (:emoji raw-account)
:removed (:removed raw-account)
:color (keyword (:colorId raw-account))
:created-at (:createdAt raw-account)
:prod-preferred-chain-ids (sut/chain-ids-string->set
(:prodPreferredChainIds raw-account))
:test-preferred-chain-ids (sut/chain-ids-string->set
(:testPreferredChainIds raw-account))}]}
(sut/rpc->keypair raw-keypair-profile))))
(testing "rpc->keypair transforms a seed-phrase keypair"
(is
(match? {:type :seed
:key-uid "0x123"
:lowest-operability :fully
:accounts [{:key-uid "0x123"
:address "1x123"
:operable :fully
:path (:path raw-account)
:name (:name raw-account)
:emoji (:emoji raw-account)
:wallet (:wallet raw-account)
:removed (:removed raw-account)
:color (keyword (:colorId raw-account))
:created-at (:createdAt raw-account)
:prod-preferred-chain-ids (sut/chain-ids-string->set
(:prodPreferredChainIds raw-account))
:test-preferred-chain-ids (sut/chain-ids-string->set
(:testPreferredChainIds raw-account))}]}
(sut/rpc->keypair raw-keypair-seed-phrase))))
(testing "rpc->keypair transforms a raw private-key keypair with inoperable accounts"
(is
(match? {:type :key
:key-uid "0x456"
:lowest-operability :no
:accounts [{:key-uid "0x456"
:address "1x456"
:operable :no
:path (:path raw-account)
:name (:name raw-account)
:emoji (:emoji raw-account)
:wallet (:wallet raw-account)
:removed (:removed raw-account)
:color (keyword (:colorId raw-account))
:created-at (:createdAt raw-account)
:prod-preferred-chain-ids (sut/chain-ids-string->set
(:prodPreferredChainIds raw-account))
:test-preferred-chain-ids (sut/chain-ids-string->set
(:testPreferredChainIds
raw-account))}]}
(sut/rpc->keypair raw-keypair-private-key)))))
(deftest rpc->keypairs-test
(testing "rpc->keypairs transforms and sorts raw keypairs"
(is
(match? [(sut/rpc->keypair raw-keypair-profile)
(sut/rpc->keypair raw-keypair-seed-phrase)
(sut/rpc->keypair raw-keypair-private-key)]
(sut/rpc->keypairs [raw-keypair-seed-phrase
raw-keypair-private-key
raw-keypair-profile])))))
(deftest reconcile-keypairs-test
(testing "reconcile-keypairs represents updated key pairs and accounts"
(is
(match?
(matchers/match-with
[set? matchers/set-equals
map? matchers/equals]
{:removed-keypair-ids #{}
:removed-account-addresses #{}
:updated-accounts-by-address {"1x123" (merge account
{:key-uid "0x123"
:address "1x123"})
"1x456" (merge account
{:key-uid "0x456"
:address "1x456"
:operable :no})}
:updated-keypairs-by-id {"0x123" {:key-uid "0x123"
:type :seed
:lowest-operability :fully
:accounts [(merge account
{:key-uid "0x123"
:address "1x123"})]}
"0x456" {:key-uid "0x456"
:type :key
:lowest-operability :no
:accounts [(merge account
{:key-uid "0x456"
:address "1x456"
:operable :no})]}}})
(sut/reconcile-keypairs [raw-keypair-seed-phrase
raw-keypair-private-key]))))
(testing "reconcile-keypairs represents removed key pairs and accounts"
(is
(match?
(matchers/match-with
[set? matchers/set-equals
map? matchers/equals]
{:removed-keypair-ids #{"0x456"}
:removed-account-addresses #{"1x456"}
:updated-accounts-by-address {"1x123" (merge account
{:key-uid "0x123"
:address "1x123"})}
:updated-keypairs-by-id {"0x123" {:key-uid "0x123"
:type :seed
:lowest-operability :fully
:accounts [(merge account
{:key-uid "0x123"
:address "1x123"})]}}})
(sut/reconcile-keypairs [raw-keypair-seed-phrase
(assoc raw-keypair-private-key :removed true)]))))
(testing "reconcile-keypairs ignores chat accounts inside updated accounts"
(is
(match?
(matchers/match-with
[set? matchers/set-equals
map? matchers/equals]
{:removed-keypair-ids #{}
:removed-account-addresses #{}
:updated-accounts-by-address {"2x000" (merge account
{:key-uid "0x000"
:address "2x000"
:chat false
:wallet true
:default-account? true})}
:updated-keypairs-by-id {"0x000" {:key-uid "0x000"
:type :profile
:lowest-operability :fully
:accounts [(merge account
{:key-uid "0x000"
:address "1x000"
:chat true
:wallet false
:default-account? false})
(merge account
{:key-uid "0x000"
:address "2x000"
:chat false
:wallet true
:default-account? true})]}}})
(sut/reconcile-keypairs [raw-keypair-profile])))))
+90 -8
View File
@@ -1,6 +1,7 @@
(ns status-im.contexts.wallet.events
(:require
[camel-snake-kebab.extras :as cske]
[clojure.set]
[clojure.string :as string]
[react-native.platform :as platform]
[status-im.constants :as constants]
@@ -81,6 +82,11 @@
(rf/reg-event-fx :wallet/log-rpc-error log-rpc-error)
(def refresh-accounts-fx-dispatches
[[:dispatch [:wallet/get-wallet-token-for-all-accounts]]
[:dispatch [:wallet/request-collectibles-for-all-accounts {:new-request? true}]]
[:dispatch [:wallet/check-recent-history-for-all-accounts]]])
(rf/reg-event-fx
:wallet/get-accounts-success
(fn [{:keys [db]} [accounts]]
@@ -91,11 +97,9 @@
{:db (assoc-in db
[:wallet :accounts]
(utils.collection/index-by :address wallet-accounts))
:fx [[:dispatch [:wallet/get-wallet-token-for-all-accounts]]
[:dispatch [:wallet/request-collectibles-for-all-accounts {:new-request? true}]]
[:dispatch [:wallet/check-recent-history-for-all-accounts]]
(when new-account?
[:dispatch [:wallet/navigate-to-new-account navigate-to-account]])]})))
:fx (concat refresh-accounts-fx-dispatches
[(when new-account?
[:dispatch [:wallet/navigate-to-new-account navigate-to-account]])])})))
(rf/reg-event-fx
:wallet/get-accounts
@@ -309,7 +313,7 @@
[]
(filter #(string/starts-with? (or (:ens-name %) "") input) contacts))]
(if (and input (empty? result))
(rf/dispatch [:wallet/search-ens input on-error-fn ".stateofus.eth"])
{:fx [[:dispatch [:wallet/search-ens input on-error-fn ".stateofus.eth"]]]}
{:db (-> db
(assoc-in [:wallet :ui :search-address :local-suggestions]
(map #(assoc % :type item-types/saved-address) result))
@@ -358,11 +362,15 @@
(rf/reg-event-fx :wallet/address-validation-success
(fn [{:keys [db]}]
{:db (assoc-in db [:wallet :ui :search-address :valid-ens-or-address?] true)}))
{:db (-> db
(assoc-in [:wallet :ui :search-address :valid-ens-or-address?] true)
(assoc-in [:wallet :ui :search-address :loading?] false))}))
(rf/reg-event-fx :wallet/address-validation-failed
(fn [{:keys [db]}]
{:db (assoc-in db [:wallet :ui :search-address :valid-ens-or-address?] false)}))
{:db (-> db
(assoc-in [:wallet :ui :search-address :valid-ens-or-address?] false)
(assoc-in [:wallet :ui :search-address :loading?] false))}))
(rf/reg-event-fx :wallet/clean-local-suggestions
(fn [{:keys [db]}]
@@ -370,6 +378,10 @@
(assoc-in [:wallet :ui :search-address :local-suggestions] [])
(assoc-in [:wallet :ui :search-address :valid-ens-or-address?] false))}))
(rf/reg-event-fx :wallet/searching-address
(fn [{:keys [db]}]
{:db (assoc-in db [:wallet :ui :search-address :loading?] true)}))
(rf/reg-event-fx
:wallet/navigate-to-chain-explorer-from-bottom-sheet
(fn [_ [explorer-link address]]
@@ -545,3 +557,73 @@
:wallet/process-watch-only-account-from-backup
(fn [_ [{:keys [backedUpWatchOnlyAccount]}]]
{:fx [[:dispatch [:wallet/process-account-from-signal backedUpWatchOnlyAccount]]]}))
(defn reconcile-watch-only-accounts
[{:keys [db]} [watch-only-accounts]]
(let [existing-accounts-by-address (get-in db [:wallet :accounts])
group-label #(if % :removed-accounts :updated-accounts)
{:keys [removed-accounts
updated-accounts]} (->> watch-only-accounts
(map data-store/rpc->account)
(group-by (comp group-label :removed)))
existing-account-addresses (set (keys existing-accounts-by-address))
removed-account-addresses (set (map :address removed-accounts))
updated-account-addresses (set (map :address updated-accounts))
new-account-addresses (clojure.set/difference updated-account-addresses
existing-account-addresses)]
{:db (update-in db
[:wallet :accounts]
(fn [existing-accounts]
(merge-with merge
(apply dissoc existing-accounts removed-account-addresses)
(utils.collection/index-by :address updated-accounts))))
:fx (mapcat (fn [address]
[[:dispatch [:wallet/get-wallet-token-for-account address]]
[:dispatch
[:wallet/request-new-collectibles-for-account-from-signal address]]
[:dispatch [:wallet/check-recent-history-for-account address]]])
new-account-addresses)}))
(rf/reg-event-fx :wallet/reconcile-watch-only-accounts reconcile-watch-only-accounts)
(defn reconcile-keypairs
[{:keys [db]} [keypairs]]
(let [existing-keypairs-by-id (get-in db [:wallet :keypairs])
existing-accounts-by-address (get-in db [:wallet :accounts])
{:keys [removed-keypair-ids
removed-account-addresses
updated-keypairs-by-id
updated-accounts-by-address]} (data-store/reconcile-keypairs keypairs)
updated-keypair-ids (set (keys updated-keypairs-by-id))
updated-account-addresses (set (keys updated-accounts-by-address))
existing-account-addresses (set (keys existing-accounts-by-address))
new-account-addresses (clojure.set/difference updated-account-addresses
existing-account-addresses)
old-account-addresses (->> (vals existing-accounts-by-address)
(filter (fn [{:keys [address key-uid]}]
(and (contains? updated-keypair-ids key-uid)
(not (contains?
updated-accounts-by-address
address)))))
(map :address))]
(cond-> {:db (-> db
(assoc-in [:wallet :keypairs]
(-> (apply dissoc existing-keypairs-by-id removed-keypair-ids)
(merge updated-keypairs-by-id)))
(assoc-in [:wallet :accounts]
(merge-with merge
(apply dissoc
existing-accounts-by-address
(into removed-account-addresses
old-account-addresses))
updated-accounts-by-address)))}
(seq new-account-addresses)
(assoc :fx
(mapcat (fn [address]
[[:dispatch [:wallet/get-wallet-token-for-account address]]
[:dispatch
[:wallet/request-new-collectibles-for-account-from-signal address]]
[:dispatch [:wallet/check-recent-history-for-account address]]])
new-account-addresses)))))
(rf/reg-event-fx :wallet/reconcile-keypairs reconcile-keypairs)
@@ -1,6 +1,7 @@
(ns status-im.contexts.wallet.events-test
(:require
[cljs.test :refer-macros [is testing]]
[matcher-combinators.matchers :as matchers]
matcher-combinators.test
[re-frame.db :as rf-db]
[status-im.constants :as constants]
@@ -150,3 +151,187 @@
[:dispatch [:wallet/check-recent-history-for-account address]]]}]
(reset! rf-db/app-db {:wallet {:accounts {}}})
(is (match? expected-effects (dispatch [event-id raw-account])))))
(h/deftest-event :wallet/reconcile-keypairs
[event-id dispatch]
(let [keypair-key-uid (:key-uid raw-account)]
(testing "event adds new key pairs"
(reset! rf-db/app-db {:wallet {:accounts {}
:keypairs {}}})
(is
(match?
(matchers/match-with
[set? matchers/set-equals
vector? matchers/equals
map? matchers/equals]
{:db {:wallet {:accounts {(:address account) account}
:keypairs {keypair-key-uid {:key-uid keypair-key-uid
:type :seed
:lowest-operability :fully
:accounts [account]}}}}
:fx [[:dispatch [:wallet/get-wallet-token-for-account address]]
[:dispatch [:wallet/request-new-collectibles-for-account-from-signal address]]
[:dispatch [:wallet/check-recent-history-for-account address]]]})
(dispatch [event-id
[{:key-uid keypair-key-uid
:type "seed"
:accounts [raw-account]}]]))))
(testing "event removes key pairs and accounts that are marked as removed"
(reset! rf-db/app-db {:wallet {:accounts {(:address account) account}
:keypairs {keypair-key-uid
{:key-uid keypair-key-uid
:type :seed
:lowest-operability :fully
:accounts [account]}}}})
(is
(match?
(matchers/match-with
[set? matchers/set-equals
vector? matchers/equals
map? matchers/equals]
{:db {:wallet {:accounts {}
:keypairs {}}}})
(dispatch [event-id
[{:key-uid keypair-key-uid
:type "seed"
:removed true
:accounts [raw-account]}]]))))
(testing "event removes accounts not present with key pair"
(reset! rf-db/app-db {:wallet {:accounts {(:address account) account
"1x001" (assoc account
:address "1x001"
:key-uid "0x001")}
:keypairs {keypair-key-uid
{:key-uid keypair-key-uid
:type :seed
:lowest-operability :fully
:accounts [account]}
"0x001"
{:key-uid "0x001"
:type :seed
:lowest-operability :fully
:accounts [(assoc account
:address "1x001"
:key-uid "0x001")]}}}})
(is
(match?
(matchers/match-with
[set? matchers/set-equals
vector? matchers/equals
map? matchers/equals]
{:db {:wallet {:accounts {(:address account) account}
:keypairs {keypair-key-uid
{:key-uid keypair-key-uid
:type :seed
:lowest-operability :fully
:accounts [account]}
"0x001"
{:key-uid "0x001"
:type :seed
:lowest-operability :fully
:accounts []}}}}})
(dispatch [event-id
[{:key-uid "0x001"
:type "seed"
:accounts []}]]))))
(testing "event updates existing key pairs"
(reset! rf-db/app-db {:wallet
{:accounts {(:address account)
(assoc account :operable :no)}
:keypairs {keypair-key-uid
{:key-uid keypair-key-uid
:type :seed
:lowest-operability :no
:accounts [(assoc account :operable :no)]}}}})
(is
(match?
(matchers/match-with
[set? matchers/set-equals
vector? matchers/equals
map? matchers/equals]
{:db {:wallet {:accounts {(:address account) account}
:keypairs {keypair-key-uid
{:key-uid keypair-key-uid
:type :seed
:lowest-operability :fully
:accounts [account]}}}}})
(dispatch [event-id
[{:key-uid keypair-key-uid
:type "seed"
:accounts [raw-account]}]]))))
(testing "event ignores chat accounts for key pairs"
(reset! rf-db/app-db {:wallet {:accounts {(:address account) account}
:keypairs {keypair-key-uid
{:key-uid keypair-key-uid
:type :profile
:lowest-operability :fully
:accounts [account
(assoc account
:address "1x001"
:chat true)]}}}})
(is
(match?
(matchers/match-with
[set? matchers/set-equals
vector? matchers/equals
map? matchers/equals]
{:db {:wallet {:accounts {(:address account) account}
:keypairs {keypair-key-uid
{:key-uid keypair-key-uid
:type :profile
:lowest-operability :fully
:accounts [account
(assoc account
:address "1x001"
:chat true)]}}}}})
(dispatch [event-id
[{:key-uid keypair-key-uid
:type "profile"
:accounts [raw-account
(assoc raw-account
:address "1x001"
:chat true)]}]]))))))
(h/deftest-event :wallet/reconcile-watch-only-accounts
[event-id dispatch]
(testing "event adds new watch-only accounts"
(reset! rf-db/app-db {:wallet {:accounts {}}})
(is
(match?
(matchers/match-with
[set? matchers/set-equals
vector? matchers/equals
map? matchers/equals]
{:db {:wallet {:accounts {(:address account) account}}}
:fx [[:dispatch [:wallet/get-wallet-token-for-account address]]
[:dispatch
[:wallet/request-new-collectibles-for-account-from-signal address]]
[:dispatch [:wallet/check-recent-history-for-account address]]]})
(dispatch [event-id [raw-account]]))))
(testing "event removes watch-only accounts that are marked as removed"
(reset! rf-db/app-db {:wallet {:accounts {(:address account) account}}})
(is
(match?
(matchers/match-with
[set? matchers/set-equals
vector? matchers/equals
map? matchers/equals]
{:db {:wallet {:accounts {}}}
:fx []})
(dispatch [event-id [(assoc raw-account :removed true)]]))))
(testing "event updates existing watch-only accounts"
(reset! rf-db/app-db {:wallet
{:accounts {address account}}})
(is
(match?
(matchers/match-with
[set? matchers/set-equals
vector? matchers/equals
map? matchers/equals]
{:db {:wallet {:accounts {address (assoc account :name "Test")}}}
:fx []})
(dispatch [event-id
[(assoc raw-account
:address address
:name "Test")]])))))
(cljs.test/run-tests)
@@ -18,8 +18,8 @@
:image (:uri preview-url)}])}]))
(defn- on-collectible-press
[{:keys [id]}]
(rf/dispatch [:wallet/get-collectible-details id]))
[{:keys [id]} aspect-ratio]
(rf/dispatch [:wallet/get-collectible-details id aspect-ratio]))
(defn view
[{:keys [selected-tab]}]
@@ -82,8 +82,12 @@
:token-networks-ids token-networks-ids
:tx-type tx-type
:receiver? true})
(send-utils/reset-loading-network-amounts-to-zero
receiver-network-values))
(->
(send-utils/reset-loading-network-amounts-to-zero
receiver-network-values)
vec
(conj {:type :edit})))
network-links (when routes-available?
(send-utils/network-links chosen-route
sender-network-values
@@ -237,7 +241,8 @@
(assoc-in [:wallet :ui :send :token-not-supported-in-receiver-networks?]
token-not-supported-in-receiver-networks?))
:fx [[:dispatch [:hide-bottom-sheet]]
[:dispatch [:wallet/clean-suggested-routes]]]})))
[:dispatch [:wallet/clean-suggested-routes]]
[:dispatch [:wallet/clean-from-locked-amounts]]]})))
(rf/reg-event-fx :wallet/clean-selected-token
(fn [{:keys [db]}]

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