Compare commits
36
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1e7c701b90 | ||
|
|
f05261a1e9 | ||
|
|
f8eee09d1b | ||
|
|
42d2690c85 | ||
|
|
b0133e97cf | ||
|
|
3c4f72c061 | ||
|
|
265b712fe3 | ||
|
|
13f87020eb | ||
|
|
4f5480e36f | ||
|
|
9fab422e0c | ||
|
|
6f8aa15b17 | ||
|
|
4469717cc1 | ||
|
|
5d00c09597 | ||
|
|
fee8ef5524 | ||
|
|
7e228d0e66 | ||
|
|
3c12ac870a | ||
|
|
321ff9257b | ||
|
|
28f43acb83 | ||
|
|
cfaed80066 | ||
|
|
fa9b53854b | ||
|
|
680bc33971 | ||
|
|
c7aa10c789 | ||
|
|
ae08cb161f | ||
|
|
ae75eaeb33 | ||
|
|
424bbc39c4 | ||
|
|
5a7bfc61cc | ||
|
|
50f6c1ef1b | ||
|
|
3c6b38aeea | ||
|
|
c44ba69676 | ||
|
|
f394fcc3d5 | ||
|
|
107f263fb1 | ||
|
|
678bc548ca | ||
|
|
d77033e346 | ||
|
|
8f85e3c726 | ||
|
|
ed427cf485 | ||
|
|
9362d12bbd |
+2
-2
@@ -195,5 +195,5 @@ test/appium/tests/users.py
|
||||
## git hooks
|
||||
lefthook.yml
|
||||
|
||||
## metro server logs
|
||||
metro-server-logs.log
|
||||
## build time logs
|
||||
/logs/*.log
|
||||
|
||||
@@ -36,6 +36,8 @@ endif
|
||||
export TMPDIR = /tmp/tmp-status-mobile-$(BUILD_TAG)
|
||||
# This has to be specified for both the Node.JS server process and the Qt process.
|
||||
export REACT_SERVER_PORT ?= 5001
|
||||
# Default metro port used by scripts/run-android.sh.
|
||||
export RCT_METRO_PORT ?= 8081
|
||||
# Fix for ERR_OSSL_EVP_UNSUPPORTED error.
|
||||
export NODE_OPTIONS += --openssl-legacy-provider
|
||||
# The path can be anything, but home is usually safest.
|
||||
@@ -54,12 +56,6 @@ export _NIX_KEEP ?= TMPDIR,BUILD_ENV,\
|
||||
# Useful for Android release builds
|
||||
TMP_BUILD_NUMBER := $(shell ./scripts/version/gen_build_no.sh | cut -c1-10)
|
||||
|
||||
# MacOS root is read-only, read nix/README.md for details
|
||||
UNAME_S := $(shell uname -s)
|
||||
ifeq ($(UNAME_S),Darwin)
|
||||
export NIX_IGNORE_SYMLINK_STORE=1
|
||||
endif
|
||||
|
||||
#----------------
|
||||
# Nix targets
|
||||
#----------------
|
||||
@@ -294,11 +290,8 @@ show-ios-devices: ##@other shows connected ios device and its name
|
||||
# TODO: fix IOS_STATUS_GO_TARGETS to be either amd64 or arm64 when RN is upgraded
|
||||
run-ios-device: export TARGET := ios
|
||||
run-ios-device: export IOS_STATUS_GO_TARGETS := ios/arm64;iossimulator/amd64
|
||||
run-ios-device: ##@run iOS app and start it on a connected device by its name
|
||||
ifndef DEVICE_NAME
|
||||
$(error Usage: make run-ios-device DEVICE_NAME=your-device-name)
|
||||
endif
|
||||
react-native run-ios --device "$(DEVICE_NAME)"
|
||||
run-ios-device: ##@run iOS app and start it on the first connected iPhone
|
||||
@scripts/run-ios-device.sh
|
||||
|
||||
#--------------
|
||||
# Tests
|
||||
|
||||
@@ -37,7 +37,7 @@ project dependencies, coding guidelines and testing procedures.
|
||||
Check out our [coding guidelines](doc/new-guidelines.md).
|
||||
|
||||
- **Community Management**
|
||||
Metcalfe's law states that the value of a network is proportional to the square of the number of connected users of the system - without community Status is meaningless. We're looking to create a positive, fun environment to explore new ideas, experiment and grow the Status community. Building a community takes a lot of work but the people you'll meet and the long-lasting relationships you form will be well worth it, check out our [Mission and Community Principles](https://status.im/about)
|
||||
Metcalfe's law states that the value of a network is proportional to the square of the number of connected users of the system - without community Status is meaningless. We're looking to create a positive, fun environment to explore new ideas, experiment and grow the Status community. Building a community takes a lot of work but the people you'll meet and the long-lasting relationships you form will be well worth it, check out our [Mission and Community Principles](https://status.app/manifesto)
|
||||
|
||||
- **Specification / Documentation**
|
||||
John Dewey once said, "Education is not preparation for life; education is life *itself* ". Developers and Designers need guidance and it all starts from documentation and specifications. Our software is only as good as its documentation, check out our [docs](doc/) and see how you can improve what we have.
|
||||
@@ -53,10 +53,10 @@ Status is a visual interface to make permanent changes on the Blockchain, it han
|
||||
|
||||
- **Evangelism**
|
||||
Help us spread the word! Tell a friend *right now*, in fact, tell **everyone** - yell from a mountain if you have to, every person counts! If you've got a great story to tell or have some interesting way you've spread the word about Status let us know about it in our [chat](https://join.status.im/chat/public/status)
|
||||
|
||||
|
||||
## Give me Binaries!
|
||||
|
||||
You can get our Beta builds for both Android and iOS on our [website](https://status.im), through our [nightly builds](https://status.im/nightly/), or by [building it yourself](https://status.im/technical/build_status/).
|
||||
You can get our Beta builds for both Android and iOS on our [website](https://status.app), through our [nightly builds](https://status.im/nightly/), or by [building it yourself](doc/starting-guide.md).
|
||||
|
||||
## Core Contributors
|
||||
|
||||
|
||||
@@ -35,8 +35,6 @@ pipeline {
|
||||
stage('Prep') {
|
||||
steps { script {
|
||||
println("Current JOB: ${env.JOB_NAME}")
|
||||
/* just for a shorter access */
|
||||
btype = utils.getBuildType()
|
||||
} }
|
||||
}
|
||||
stage('Build') {
|
||||
@@ -84,10 +82,8 @@ pipeline {
|
||||
when { expression { params.PUBLISH } }
|
||||
steps { script {
|
||||
switch (btype) {
|
||||
case 'nightly':
|
||||
/* Create JSON file with newest build URLs */
|
||||
case 'nightly': /* Create JSON file with newest build URLs */
|
||||
s3.updateBucketJSON(urls, 'latest.json');
|
||||
build(job: 'website/status.im', wait: false);
|
||||
break;
|
||||
case 'release':
|
||||
github.publishReleaseFiles(repo: 'status-mobile');
|
||||
|
||||
+1
-3
@@ -39,8 +39,6 @@ pipeline {
|
||||
LANGUAGE = "en_US.UTF-8"
|
||||
TARGET = 'ios'
|
||||
NIX_CONF_DIR = "${env.WORKSPACE}/nix"
|
||||
/* See nix/README.md */
|
||||
NIX_IGNORE_SYMLINK_STORE = 1
|
||||
FASTLANE_DISABLE_COLORS = 1
|
||||
BUNDLE_PATH = "${HOME}/.bundle"
|
||||
}
|
||||
@@ -65,7 +63,7 @@ pipeline {
|
||||
}
|
||||
post {
|
||||
failure {
|
||||
archiveArtifacts 'ios/logs/*'
|
||||
archiveArtifacts 'logs/*'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,8 +10,6 @@ pipeline {
|
||||
LC_ALL = 'en_US.UTF-8'
|
||||
TARGET = 'ios'
|
||||
FASTLANE_DISABLE_COLORS = 1
|
||||
/* See nix/README.md */
|
||||
NIX_IGNORE_SYMLINK_STORE = 1
|
||||
/* avoid writing to r/o /nix */
|
||||
GEM_HOME = '~/.rubygems'
|
||||
}
|
||||
|
||||
@@ -18,8 +18,6 @@ pipeline {
|
||||
}
|
||||
|
||||
environment {
|
||||
/* See nix/README.md */
|
||||
NIX_IGNORE_SYMLINK_STORE = 1
|
||||
/* we source .bash_profile to be able to use nix-store */
|
||||
NIX_SSHOPTS = "-oStrictHostKeyChecking=no"
|
||||
NIX_CONF_DIR = "${env.WORKSPACE}/nix"
|
||||
|
||||
@@ -10,8 +10,6 @@ pipeline {
|
||||
LC_ALL = 'en_US.UTF-8'
|
||||
TARGET = 'ios'
|
||||
FASTLANE_DISABLE_COLORS = 1
|
||||
/* See nix/README.md */
|
||||
NIX_IGNORE_SYMLINK_STORE = 1
|
||||
/* avoid writing to r/o /nix */
|
||||
GEM_HOME = '~/.rubygems'
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
|
||||
[Coding guidelines](new-guidelines.md)
|
||||
|
||||
[UI components coding guidelines](ui-guidelines.md)
|
||||
|
||||
[Release Checklist](release-checklist.md)
|
||||
|
||||
[Release Guide](release-guide.md)
|
||||
@@ -28,6 +30,8 @@
|
||||
|
||||
[Contributing to status-go](status-go-changes.md)
|
||||
|
||||
[Malli schemas (recorded demo)](https://www.youtube.com/watch?v=SlRio70aYVI) ([slides](files/forging-code-with-schemas-sep-2023-slides.pdf))
|
||||
|
||||
## Testing
|
||||
|
||||
[How to run local tests](testing.md)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 41 KiB |
+37
-22
@@ -4,21 +4,41 @@ This document provides information on how to start developing Status App.
|
||||
|
||||
# Getting Started
|
||||
|
||||
To start developing start a shell for the platform you are interested in.
|
||||
To start developing clone the status-mobile repo in the directory of your choice.
|
||||
```
|
||||
make shell TARGET=android
|
||||
git clone https://github.com/status-im/status-mobile.git
|
||||
```
|
||||
This step will take a while the first time as it will download all dependencies.
|
||||
|
||||
# Development
|
||||
Then open a terminal and cd into this directory.
|
||||
|
||||
There are three steps necessary to start development, in this case for Android:
|
||||
```
|
||||
cd status-mobile
|
||||
```
|
||||
|
||||
1. `make run-clojure` - Compiles Clojure into JavaScript, watches for changes on cljs files, and hot-reloads code in the app.
|
||||
2. `make run-android` or `make run-ios` - Builds the Android/iOS app, starts it on the device and starts metro bundler.
|
||||
Then build the clojure terminal
|
||||
|
||||
The first two will continue watching for changes and keep re-building the app. They need to be ready first.
|
||||
The last one will exit once the app is up and ready.
|
||||
```
|
||||
make run-clojure
|
||||
```
|
||||
|
||||
note: ⚠️ This might take a while if this is your first time.
|
||||
|
||||
This command installs `nix` and pulls in all the dependencies.
|
||||
Do answer with "Y" to all the prompts and press "Enter" when `nix` setup asks you to Acknowledge.
|
||||
This command builds the `jsbundle` and then compiles `Clojure` into `JavaScript`, watches for changes on `cljs` files, and hot-reloads code in the app.
|
||||
|
||||
wait till you see the following message :
|
||||
|
||||
```
|
||||
[:mobile] Build completed. (1801 files, 52 compiled, 0 warnings, 9.52s)
|
||||
```
|
||||
|
||||
Once the clojure terminal is running you need to run the appropriate command next for your platform in a separate terminal :
|
||||
|
||||
`make run-android` or `make run-ios`
|
||||
|
||||
These commands will build the app, start a metro bundler and deploy the app on your simulator OR connected device (android only). For building and deploying to connected iPhones use `make run-ios-device` instead of `make run-ios`
|
||||
Also check [developing on a physical iOS Device](#Additional-requirements-for-developing-on-physical-ios-device).
|
||||
|
||||
## Simulators and Devices
|
||||
### Android
|
||||
@@ -45,13 +65,9 @@ Running `make run-ios` will target `iPhone 13` by default.
|
||||
|
||||
If you need to run on any other simulator, you can specify the simulator type by adding the `SIMULATOR` flag:
|
||||
```sh
|
||||
make run-ios SIMULATOR="iPhone 13"
|
||||
make run-ios SIMULATOR="iPhone 15"
|
||||
```
|
||||
|
||||
#### Running on a physical device
|
||||
|
||||
Some manual steps are necessary for [developing on a physical iOS Device](#physical-ios-device).
|
||||
|
||||
# Build release
|
||||
|
||||
To build the app, you can simply run on of the following:
|
||||
@@ -101,16 +117,15 @@ Steps:
|
||||
3. [Setup Git to sign commits](https://help.github.com/en/github/authenticating-to-github/signing-commits)
|
||||
4. [Setup GitHub to validate commits](https://help.github.com/en/github/authenticating-to-github/adding-a-new-gpg-key-to-your-github-account)
|
||||
|
||||
## Physical iOS Device
|
||||
## Additional requirements for developing on Physical iOS Device
|
||||
|
||||
To use a physical iPhone your device UDID must be added to provisioning profiles and your Apple account invited as Developer to Status team.
|
||||
|
||||
1. [Get your UDID of your iPhone.](https://www.extentia.com/post/finding-the-udid-of-an-ios-device)
|
||||
2. Request from someone with access like @cammellos or @jakubgs to
|
||||
- Add the UDID to development devices on Apple Developer Portal.
|
||||
- Invite your Apple account to be Developer in Status team.
|
||||
3. Run a build in XCode using the project from `status-mobile/ios` directory.
|
||||
- You might see error: `Select a development team in the Signing & Capabilities editor`
|
||||
- Select `Status Research & Development GmbH` as the development team and rebuild again.
|
||||
|
||||
Once build finishes Status should start on your iPhone with its logs in terminal running `make run-metro`.
|
||||
- Add the UDID to development devices on Apple Developer Portal.
|
||||
- Invite your Apple account to be Developer in Status team.
|
||||
3. Open XCode using the project from `status-mobile/ios` directory.
|
||||
- You might see error: `Select a development team in the Signing & Capabilities editor`
|
||||
- Select `Status Research & Development GmbH` as the development team.
|
||||
4. In a new terminal execute `make clean` and then `make xcode-clean`
|
||||
|
||||
+32
-6
@@ -2,14 +2,12 @@
|
||||
|
||||
## Unit & integration tests
|
||||
|
||||
To run tests:
|
||||
To run all tests:
|
||||
|
||||
```
|
||||
make test
|
||||
```
|
||||
|
||||
|
||||
|
||||
Also test watcher can be launched. It will re-run the entire test suite when any file is modified
|
||||
|
||||
```
|
||||
@@ -51,18 +49,46 @@ Here I'm showing a terminal-only experience using Tmux (left pane Emacs, right p
|
||||
|
||||
[2022-12-19 13-17.webm](https://user-images.githubusercontent.com/46027/208471199-1909c446-c82d-42a0-9350-0c15ca562713.webm)
|
||||
|
||||
## Component tests
|
||||
## Component tests only
|
||||
|
||||
To run tests:
|
||||
|
||||
```
|
||||
make component-test
|
||||
make component-test
|
||||
```
|
||||
|
||||
Also test watcher can be launched. It will re-run the entire test suite when any file is modified
|
||||
|
||||
```
|
||||
make component-test-watch
|
||||
make component-test-watch
|
||||
```
|
||||
|
||||
Check [component tests doc](./component-tests-overview.md) for more.
|
||||
|
||||
## Unit tests only
|
||||
|
||||
To run unit tests:
|
||||
|
||||
```
|
||||
make test-unit
|
||||
```
|
||||
|
||||
Also test watcher can be launched. It will re-run the entire test suite when any file is modified
|
||||
|
||||
```
|
||||
make test-unit WATCH=true
|
||||
```
|
||||
|
||||
## Integration tests only
|
||||
|
||||
To run integration tests:
|
||||
|
||||
```
|
||||
make test-integration
|
||||
```
|
||||
|
||||
Also test watcher can be launched. It will re-run the entire test suite when any file is modified
|
||||
|
||||
```
|
||||
make test-integration WATCH=true
|
||||
```
|
||||
|
||||
+1
-20
@@ -88,6 +88,7 @@ info Visit https://yarnpkg.com/en/docs/cli/install for documentation about this
|
||||
Update yarn.lock file. In order to do this, perform the following steps on a clean `status-mobile` repo:
|
||||
```
|
||||
cd status-mobile
|
||||
make shell
|
||||
yarn install
|
||||
```
|
||||
and don't forget to commit updated `yarn.lock` together with `package.json`.
|
||||
@@ -127,23 +128,3 @@ Status-mobile uses `shadow-cljs` for hot reloading changes and uses its own [rel
|
||||
|
||||
### Solution
|
||||
Open react native's [In-App Developer Menu](https://reactnative.dev/docs/debugging#accessing-the-in-app-developer-menu) and press "Disable Fast Refresh" or "Disable Hot Reloading"
|
||||
|
||||
## App Crashes after few reloads
|
||||
|
||||
### Cause
|
||||
For x86 CPU architecture Android Devices, Hermes is creating the issue and the app crashes after a few reloads.
|
||||
([Original Issue](https://github.com/status-im/status-mobile/issues/14031))
|
||||
|
||||
<details>
|
||||
<summary>How to Find CPU architecture</summary>
|
||||
|
||||
CPU architecture of android device can be found using
|
||||
- `adb shell uname -m` or
|
||||
- `adb shell getprop ro.product.cpu.abilist`
|
||||
|
||||
</details>
|
||||
|
||||
### Solution
|
||||
Disable Hermes while building the app
|
||||
|
||||
`make run-android DISABLE_HERMES=true`
|
||||
|
||||
@@ -0,0 +1,254 @@
|
||||
# UI components coding guidelines
|
||||
|
||||
> [!IMPORTANT]
|
||||
> React apps are made out of components. A component is a piece of the UI (user interface) that has its own logic and appearance. A component can be as small as a button, or as large as an entire screen.
|
||||
> React components are JavaScript functions that return markup
|
||||
> This document will provide best practices on how to write efficient React components in ClojureScript
|
||||
|
||||
|
||||
At the time of creating the Status app, the Reagent library was a solid choice. Back then, hooks didn't exist, and there weren't any libraries providing effective global state management. After Reagent's emergence, another library called Re-frame built upon Reagent. Together, they offered powerful tools for developing React applications with ClojureScript. However, as React evolved, significant changes occurred. Class components, utilized in Reagent, became deprecated. Instead, functional components and hooks emerged for state management. In Status 2.0, we began incorporating more functional components and hooks, resulting in a blend of both approaches. To simplify matters and reduce confusion, we opted to transition to functional components and hooks for local state management.
|
||||
|
||||
BEFORE:
|
||||
```clojure
|
||||
(defn- view-internal
|
||||
[_ _]
|
||||
(let [pressed? (reagent/atom false)]
|
||||
(fn
|
||||
[{:keys [theme on-press on-long-press icon]}]
|
||||
[rn/pressable
|
||||
{:style (style/main @pressed? theme)
|
||||
:on-press on-press
|
||||
:on-press-in #(reset! pressed? true)
|
||||
:on-press-out #(reset! pressed? nil)
|
||||
:on-long-press on-long-press}
|
||||
[quo.icons/icon icon]])))
|
||||
|
||||
(def view (theme/with-theme view-internal))
|
||||
```
|
||||
|
||||
NOW:
|
||||
```clojure
|
||||
(defn view
|
||||
[{:keys [on-press on-long-press icon]}]
|
||||
(let [[pressed? set-pressed] (rn/use-state false)
|
||||
theme (theme/use-theme-value)
|
||||
on-press-in (rn/use-callback #(set-pressed true))
|
||||
on-press-out (rn/use-callback #(set-pressed nil))]
|
||||
[rn/pressable
|
||||
{:style (style/main pressed? theme)
|
||||
:on-press on-press
|
||||
:on-press-in on-press-in
|
||||
:on-press-out on-press-out
|
||||
:on-long-press on-long-press}
|
||||
[quo.icons/icon icon]]))
|
||||
```
|
||||
|
||||
|
||||
- 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
|
||||
- `:f>` not needed anymore, all components are functional by default
|
||||
- `rn/use-callback` hook should be used for anon callback functions
|
||||
|
||||
> [!IMPORTANT]
|
||||
> DO NOT USE anon functions directly in the props
|
||||
|
||||
BAD
|
||||
```clojure
|
||||
(defn view
|
||||
[]
|
||||
(let [[pressed? set-pressed] (rn/use-state false)]
|
||||
[rn/pressable
|
||||
{:style (style/main pressed?)
|
||||
:on-press-in #(set-pressed true)
|
||||
:on-press-out #(set-pressed nil)}]))
|
||||
```
|
||||
|
||||
GOOD:
|
||||
```clojure
|
||||
(defn view
|
||||
[]
|
||||
(let [[pressed? set-pressed] (rn/use-state false)
|
||||
on-press-in (rn/use-callback #(set-pressed true))
|
||||
on-press-out (rn/use-callback #(set-pressed nil))]
|
||||
[rn/pressable
|
||||
{:style (style/main pressed?)
|
||||
:on-press-in on-press-in
|
||||
:on-press-out on-press-out}]))
|
||||
```
|
||||
|
||||
## Global state and subscriptions
|
||||
|
||||
For global state management, we utilize Re-frame subscriptions. They can be likened to React state. To obtain the state, `(rf/sub [])` is employed, and to modify it, `(rf/dispatch [])` is utilized. However, they update components in a similar manner to React states.
|
||||
|
||||
```clojure
|
||||
(defn view
|
||||
[{:keys [selected-tab]}]
|
||||
(let [collectible-list (rf/sub [:wallet/all-collectibles])
|
||||
on-collectible-press (rn/use-callback
|
||||
(fn [{:keys [id]}]
|
||||
(rf/dispatch [:wallet/get-collectible-details id])))]
|
||||
[rn/view {:style style/container}
|
||||
(case selected-tab
|
||||
:assets [assets/view]
|
||||
:collectibles [collectibles/view {:collectibles collectible-list
|
||||
:on-collectible-press on-collectible-press}])
|
||||
[activity/view]]))
|
||||
```
|
||||
|
||||
## Regular atoms
|
||||
|
||||
In certain instances, components utilized regular atoms; however, they should now be used with `rn/use-ref-atom`
|
||||
|
||||
BEFORE:
|
||||
```clojure
|
||||
(defn view
|
||||
[]
|
||||
(let [focused? (atom false)]
|
||||
(fn []
|
||||
(let [on-clear #(reset! status (if @focused? :active :default))
|
||||
on-focus #(reset! focused? true)
|
||||
on-blur #(reset! focused? false)]))))
|
||||
```
|
||||
|
||||
NOW:
|
||||
```clojure
|
||||
(defn view
|
||||
[]
|
||||
(let [focused? (rn/use-ref-atom false)
|
||||
on-clear (rn/use-callback #(set-status (if @focused? :active :default)))
|
||||
on-focus (rn/use-callback #(reset! focused? true))
|
||||
on-blur (rn/use-callback #(reset! focused? false))]))
|
||||
```
|
||||
|
||||
## Effects
|
||||
|
||||
LIFECYCLE:
|
||||
|
||||
```clojure
|
||||
(defn view
|
||||
[{:keys []}]
|
||||
(let [opacity (reanimated/use-shared-value 0)]
|
||||
(rn/use-mount #(reanimated/animate opacity 1))
|
||||
[rn/view
|
||||
{:style (style/opacity opacity)}]))
|
||||
```
|
||||
|
||||
```clojure
|
||||
(defn view
|
||||
[{:keys []}]
|
||||
(let []
|
||||
(rn/use-unmount #(rn/dispatch [:unmounted]))
|
||||
[rn/view]))
|
||||
```
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Effects should NOT be utilized as a response to state changes for modifying logic. If you're unsure how to achieve this without using effects, please consult the team in the general chat. There may be instances where using effects is appropriate, so we can explore a solution together and enhance our guidelines.
|
||||
|
||||
BAD:
|
||||
```clojure
|
||||
(defn f-zoom-button
|
||||
[{:keys [selected? current-zoom]}]
|
||||
(let [size (reanimated/use-shared-value (if selected? 37 25))]
|
||||
(rn/use-effect #(reanimated/animate size (if selected? 37 25)) [current-zoom])
|
||||
[rn/touchable-opacity
|
||||
{:style (style/zoom-button-container size)}]))
|
||||
```
|
||||
|
||||
BAD:
|
||||
|
||||
```clojure
|
||||
(defn view
|
||||
[collectible-list (rf/sub [:wallet/all-collectibles])]
|
||||
(let []
|
||||
(rn/use-effect #(rn/dispatch [:all-collectibles-changed]) [collectible-list])
|
||||
[rn/view]))
|
||||
```
|
||||
|
||||
Instead `:all-collectibles-changed` should be used in the handler which changes `collectible-list` state
|
||||
|
||||
|
||||
|
||||
## Performance tips
|
||||
|
||||
To begin with, we need to understand that there are two distinct stages for a component: creation and update. React creates a render tree, a UI tree, composed of the rendered components.
|
||||
|
||||

|
||||
|
||||
### Component creation
|
||||
|
||||
For component creation, the most critical factor is the number of elements involved, so we should strive to minimize them. For instance, it's advisable to avoid using unnecessary wrappers or containers.
|
||||
|
||||
BAD:
|
||||
|
||||
```clojure
|
||||
(defn view
|
||||
[]
|
||||
(let []
|
||||
[rn/view {:style {:padding-top 20}}
|
||||
[quo/button]]))
|
||||
```
|
||||
|
||||
GOOD:
|
||||
```clojure
|
||||
(defn view
|
||||
[]
|
||||
(let []
|
||||
[quo/button {:container-style {:padding-top 20}}]))
|
||||
```
|
||||
|
||||
### Component updates
|
||||
|
||||
For component updates, it's crucial to recognize that React will invoke the function where state is utilized. Therefore, if you utilize state in the root component, React will execute the root function and re-render the entire root component along with all its children (unless optimizations like memoization are implemented).
|
||||
|
||||
BAD:
|
||||
|
||||
```clojure
|
||||
(defn component
|
||||
[{:keys [label]}]
|
||||
(let []
|
||||
[rn/text label]))
|
||||
|
||||
(defn component2
|
||||
[{:keys [label2]}]
|
||||
(let []
|
||||
[rn/text label2]))
|
||||
|
||||
(defn screen
|
||||
[]
|
||||
(let [screen-params (rf/sub [:screen-params])]
|
||||
[component screen-params]
|
||||
[component1]
|
||||
[component2 screen-params]
|
||||
[component3]
|
||||
[rn/view {:padding-top 20}
|
||||
[quo/button]]))
|
||||
```
|
||||
|
||||
Here, we have lost control over the `screen-params` map. It can contain any data, and if any field within this map changes, the entire screen function will be executed, resulting in the re-rendering of both `component` and `component2`.
|
||||
|
||||
GOOD:
|
||||
```clojure
|
||||
(defn component
|
||||
[]
|
||||
(let [label (rf/sub [:screen-params-label])]
|
||||
[rn/text label]))
|
||||
|
||||
(defn component2
|
||||
[]
|
||||
(let [label2 (rf/sub [:screen-params-label2])]
|
||||
[rn/text label2]))
|
||||
|
||||
(defn screen
|
||||
[]
|
||||
(let []
|
||||
[component]
|
||||
[component1]
|
||||
[component2]
|
||||
[component3]
|
||||
[rn/view {:padding-top 20}
|
||||
[quo/button]]))
|
||||
```
|
||||
|
||||
So, now the screen component function will never be invoked, and `component` and `component2` will be re-rendered only when `label` or `label2` have changed.
|
||||
+3
-2
@@ -1,4 +1,5 @@
|
||||
# This file contains the fastlane.tools configuration
|
||||
|
||||
# You can find the documentation at https://docs.fastlane.tools
|
||||
#
|
||||
# For a list of all available actions, check out
|
||||
@@ -96,7 +97,7 @@ end
|
||||
# if false - read list of devices from AppStoreConnect, and upgrade the provisioning profiles from it
|
||||
# `pr_build`:
|
||||
# if true - uses StatusImPR scheme and postfixed app id with `.pr` to build an app, which can be used in parallel with release
|
||||
# if false - uses StatusIm scheme to build the release app
|
||||
# if false - uses StatusIm scheme to build the release app
|
||||
|
||||
def build_ios_adhoc(readonly: false, pr_build: false)
|
||||
# PR builds should appear as a separate App on iOS
|
||||
@@ -123,7 +124,7 @@ def build_ios_adhoc(readonly: false, pr_build: false)
|
||||
export_method: 'ad-hoc',
|
||||
output_name: 'StatusIm',
|
||||
output_directory: 'status-ios',
|
||||
buildlog_path: 'ios/logs',
|
||||
buildlog_path: 'logs',
|
||||
export_options: {
|
||||
signingStyle: 'manual',
|
||||
provisioningProfiles: {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 52;
|
||||
objectVersion = 54;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
@@ -542,7 +542,7 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = "/usr/bin/env sh";
|
||||
shellScript = "set -o errexit\nexport NODE_BINARY=\"${NODE_BINARY:-node}\"\nexport NODE_ARGS=\"${NODE_ARGS:- --max-old-space-size=16384 }\"\n\nbash -x ../node_modules/react-native/scripts/react-native-xcode.sh > ./logs/react-native-xcode.log 2>&1";
|
||||
shellScript = "set -o errexit\nexport NODE_BINARY=\"${NODE_BINARY:-node}\"\nexport NODE_ARGS=\"${NODE_ARGS:- --max-old-space-size=16384 }\"\n\nbash -x ../node_modules/react-native/scripts/react-native-xcode.sh > ../logs/react-native-xcode.log 2>&1";
|
||||
};
|
||||
28606042DA81A750949525E4 /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
@@ -578,7 +578,7 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = "/usr/bin/env sh";
|
||||
shellScript = "set -o errexit\nexport NODE_BINARY=\"${NODE_BINARY:-node}\"\nexport NODE_ARGS=\"${NODE_ARGS:- --max-old-space-size=16384 }\"\n\nbash -x ../node_modules/react-native/scripts/react-native-xcode.sh > ./logs/react-native-xcode.log 2>&1";
|
||||
shellScript = "set -o errexit\nexport NODE_BINARY=\"${NODE_BINARY:-node}\"\nexport NODE_ARGS=\"${NODE_ARGS:- --max-old-space-size=16384 }\"\n\nbash -x ../node_modules/react-native/scripts/react-native-xcode.sh > ../logs/react-native-xcode.log 2>&1";
|
||||
};
|
||||
3AAD2AD724A3A60E0075D594 /* Run Script */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
@@ -592,7 +592,7 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 1;
|
||||
shellPath = "/usr/bin/env sh";
|
||||
shellScript = "\"${PROJECT_DIR}/scripts/set_xcode_version.sh\" > ./logs/set_xcode_version.log 2>&1";
|
||||
shellScript = "\"${PROJECT_DIR}/scripts/set_xcode_version.sh\" > ../logs/set_xcode_version.log 2>&1";
|
||||
};
|
||||
523CD6BCB20FD78FBF3564AD /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
@@ -716,7 +716,7 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 1;
|
||||
shellPath = "/usr/bin/env sh";
|
||||
shellScript = "\"${PROJECT_DIR}/scripts/set_xcode_version.sh\" > ./logs/set_xcode_version.log 2>&1";
|
||||
shellScript = "\"${PROJECT_DIR}/scripts/set_xcode_version.sh\" > ../logs/set_xcode_version.log 2>&1";
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
# Description
|
||||
|
||||
This directory is the destination of logs created by Fastlane and React Native Xcode script.
|
||||
|
||||
# Logs
|
||||
|
||||
* `react-native-xcode.log` - Output from `node_modules/react-native/scripts/react-native-xcode.sh`.
|
||||
- Created by redirecting output of `shellScript` in `ios/StatusIm.xcodeproj/project.pbxproj`.
|
||||
* `Status PR-StatusImPR.log - Created by [Fastlane Gym](https://docs.fastlane.tools/actions/gym/).
|
||||
- Configred via [`Fastfile`](../Fastfile) using `buildlog_path` argument for `build_ios_app`.
|
||||
|
||||
# CI
|
||||
|
||||
These log files are uploaded to Jenkins as CI job artifacts on failure using `archiveArtifacts`.
|
||||
@@ -0,0 +1,27 @@
|
||||
# Description
|
||||
|
||||
This directory is the destination of logs created during build time of debug builds and logs created by Fastlane on CI.
|
||||
|
||||
# Logs
|
||||
|
||||
* `xcrun_device_install.log` - Output from `status-mobile/scripts/run-ios-device.sh`.
|
||||
- Created by redirecting output of `xcrun simctl install "$UDID" "$APP_PATH"`.
|
||||
* `xcrun_device_process_launch.log` - Output from `status-mobile/scripts/run-ios-device.sh`.
|
||||
- Created by specifying `--json-output` flag for `xcrun devicectl device process launch --no-activate --verbose --device "${DEVICE_UUID}" "${INSTALLATION_URL}"`.
|
||||
* `xcrun_device_process_resume.log` - Output from `status-mobile/scripts/run-ios-device.sh`.
|
||||
- Created by redirecting output of `xcrun devicectl device process resume --device "${DEVICE_UUID}" --pid "${STATUS_PID}"`.
|
||||
* `adb_install.log` - Output from `scripts/run-android.sh`.
|
||||
- Created by redirecting output of `adb install -r ./result/app-debug.apk`.
|
||||
* `adb_shell_monkey.log` - Output from `status-mobile/scripts/run-android.sh`.
|
||||
- Created by redirecting output of `adb shell monkey -p im.status.ethereum.debug 1 >`.
|
||||
* `ios_simulators_list.log` - Output from `status-mobile/scripts/run-ios.sh`.
|
||||
- Created by redirecting output of `xcrun simctl list devices -j`.
|
||||
|
||||
# CI
|
||||
|
||||
These log files are uploaded to Jenkins as CI job artifacts on failure using `archiveArtifacts`.
|
||||
|
||||
* `react-native-xcode.log` - Output from `node_modules/react-native/scripts/react-native-xcode.sh`.
|
||||
- Created by redirecting output of `shellScript` in `ios/StatusIm.xcodeproj/project.pbxproj`.
|
||||
* `Status PR-StatusImPR.log - Created by [Fastlane Gym](https://docs.fastlane.tools/actions/gym/).
|
||||
- Configred via [`Fastfile`](../Fastfile) using `buildlog_path` argument for `build_ios_app`.
|
||||
+10
@@ -342,4 +342,14 @@ public class AccountManager extends ReactContextBaseJavaModule {
|
||||
final String keyStoreDir = this.utils.getKeyStorePath(keyUID);
|
||||
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.deleteMultiaccount(keyUID, keyStoreDir), callback);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void getRandomMnemonic(final Callback callback) throws JSONException {
|
||||
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.getRandomMnemonic(), callback);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void createAccountFromMnemonicAndDeriveAccountsForPaths(final String mnemonic, final Callback callback) throws JSONException {
|
||||
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.createAccountFromMnemonicAndDeriveAccountsForPaths(mnemonic), callback);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,4 +214,20 @@ RCT_EXPORT_METHOD(logout) {
|
||||
NSLog(@"%@", result);
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(getRandomMnemonic:(RCTResponseSenderBlock)callback) {
|
||||
#if DEBUG
|
||||
NSLog(@"GetRandomMnemonic() method called");
|
||||
#endif
|
||||
NSString *result = StatusgoGetRandomMnemonic();
|
||||
callback(@[result]);
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(createAccountFromMnemonicAndDeriveAccountsForPaths:(NSString *)mnemonic callback:(RCTResponseSenderBlock)callback) {
|
||||
#if DEBUG
|
||||
NSLog(@"createAccountFromMnemonicAndDeriveAccountsForPaths() method called");
|
||||
#endif
|
||||
NSString *result = StatusgoCreateAccountFromMnemonicAndDeriveAccountsForPaths(mnemonic);
|
||||
callback(@[result]);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -20,8 +20,8 @@ in {
|
||||
buildInputs = with pkgs; [
|
||||
xcodeWrapper watchman procps
|
||||
flock # used in nix/scripts/node_modules.sh
|
||||
ios-deploy # used in 'make run-ios-device'
|
||||
xcbeautify # used in 'make run-ios'
|
||||
libimobiledevice # used in `make run-ios-device`
|
||||
];
|
||||
|
||||
# WARNING: Executes shellHook in reverse order.
|
||||
|
||||
@@ -26,18 +26,6 @@ in {
|
||||
react-native = callPackage ./deps/react-native { };
|
||||
};
|
||||
|
||||
# Fix for missing libarclite_macosx.a in Xcode 14.3.
|
||||
# https://github.com/ios-control/ios-deploy/issues/580
|
||||
ios-deploy = super.darwin.ios-deploy.overrideAttrs (old: rec {
|
||||
version = "1.12.2";
|
||||
src = super.fetchFromGitHub {
|
||||
owner = "ios-control";
|
||||
repo = "ios-deploy";
|
||||
rev = version;
|
||||
sha256 = "sha256-TVGC+f+1ow3b93CK3PhIL70le5SZxxb2ug5OkIg8XCA";
|
||||
};
|
||||
});
|
||||
|
||||
# Clojure's linter receives frequent upgrades, and we want to take advantage
|
||||
# of the latest available rules.
|
||||
clj-kondo = super.clj-kondo.override rec {
|
||||
|
||||
+16
-39
@@ -1,37 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
set -m # needed to access jobs
|
||||
|
||||
GIT_ROOT=$(cd "${BASH_SOURCE%/*}" && git rev-parse --show-toplevel)
|
||||
|
||||
# We run Metro in background while calling adb.
|
||||
cleanupMetro() {
|
||||
pkill -f run-metro.sh
|
||||
rm -f metro-server-logs.log
|
||||
}
|
||||
|
||||
# Using function gives a neater jobspec name.
|
||||
runMetro() {
|
||||
nohup "${GIT_ROOT}/scripts/run-metro.sh" 2>&1 \
|
||||
| tee metro-server-logs.log
|
||||
}
|
||||
|
||||
waitForMetro() {
|
||||
set +e # Allow grep command to fail in the loop.
|
||||
TIMEOUT=5
|
||||
echo "Waiting for Metro server..." >&2
|
||||
while ! grep -q "Welcome to Metro" metro-server-logs.log; do
|
||||
echo -n "." >&2
|
||||
sleep 1
|
||||
if ((TIMEOUT == 0)); then
|
||||
echo -e "\nMetro server timed out, exiting" >&2
|
||||
set -e # Restore errexit for rest of script.
|
||||
return 1
|
||||
fi
|
||||
((TIMEOUT--))
|
||||
done
|
||||
set -e # Restore errexit for rest of script.
|
||||
}
|
||||
ADB_INSTALL_LOG_FILE="${GIT_ROOT}/logs/adb_install.log"
|
||||
ADB_SHELL_MONKEY_LOG_FILE="${GIT_ROOT}/logs/adb_shell_monkey.log"
|
||||
|
||||
# Generate android debug build.
|
||||
export ANDROID_ABI_INCLUDE=$("${GIT_ROOT}/scripts/adb_devices_abis.sh")
|
||||
@@ -40,14 +12,19 @@ export BUILD_TYPE=debug
|
||||
"${GIT_ROOT}/scripts/build-android.sh"
|
||||
|
||||
# Install the APK on running emulator or android device.
|
||||
adb install ./result/app-debug.apk
|
||||
installAndLaunchApp() {
|
||||
adb install -r ./result/app-debug.apk > "${ADB_INSTALL_LOG_FILE}" 2>&1
|
||||
"${GIT_ROOT}/scripts/wait-for-metro-port.sh" 2>&1
|
||||
# connected android devices need this port to be exposed for metro
|
||||
adb reverse "tcp:${RCT_METRO_PORT}" "tcp:${RCT_METRO_PORT}"
|
||||
adb shell monkey -p im.status.ethereum.debug 1 > "${ADB_SHELL_MONKEY_LOG_FILE}" 2>&1
|
||||
}
|
||||
|
||||
trap cleanupMetro EXIT ERR INT QUIT
|
||||
runMetro &
|
||||
waitForMetro
|
||||
showAdbLogs() {
|
||||
cat "${ADB_INSTALL_LOG_FILE}" >&2;
|
||||
cat "${ADB_SHELL_MONKEY_LOG_FILE}" >&2;
|
||||
}
|
||||
|
||||
# Start the installed app.
|
||||
adb shell monkey -p im.status.ethereum.debug 1
|
||||
|
||||
# bring metro job to foreground
|
||||
fg 'runMetro'
|
||||
trap showAdbLogs EXIT ERR INT QUIT
|
||||
installAndLaunchApp &
|
||||
exec "${GIT_ROOT}/scripts/run-metro.sh" 2>&1
|
||||
|
||||
Executable
+55
@@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
set -m # needed to access jobs
|
||||
|
||||
GIT_ROOT=$(cd "${BASH_SOURCE%/*}" && git rev-parse --show-toplevel)
|
||||
XCRUN_DEVICE_INSTALL_LOG_DIR="${GIT_ROOT}/logs/xcrun_device_install.log"
|
||||
XCRUN_DEVICE_PROCESS_LAUNCH_LOG_DIR="${GIT_ROOT}/logs/xcrun_device_process_launch.log"
|
||||
XCRUN_DEVICE_PROCESS_RESUME_LOG_DIR="${GIT_ROOT}/logs/xcrun_device_process_resume.log"
|
||||
|
||||
# Install on the connected device
|
||||
installAndLaunchApp() {
|
||||
xcrun devicectl device install app --device "${DEVICE_UUID}" "${APP_PATH}" --json-output "${XCRUN_DEVICE_INSTALL_LOG_DIR}" 2>&1
|
||||
|
||||
# Extract installationURL
|
||||
INSTALLATION_URL=$(jq -r '.result.installedApplications[0].installationURL' "${XCRUN_DEVICE_INSTALL_LOG_DIR}")
|
||||
|
||||
# launch the app and put it in background
|
||||
xcrun devicectl device process launch --no-activate --verbose --device "${DEVICE_UUID}" "${INSTALLATION_URL}" --json-output "${XCRUN_DEVICE_PROCESS_LAUNCH_LOG_DIR}"
|
||||
|
||||
# Extract background PID of status app
|
||||
STATUS_PID=$(jq -r '.result.process.processIdentifier' "${XCRUN_DEVICE_PROCESS_LAUNCH_LOG_DIR}")
|
||||
"${GIT_ROOT}/scripts/wait-for-metro-port.sh" 2>&1
|
||||
|
||||
# now that metro is ready, resume the app from background
|
||||
xcrun devicectl device process resume --device "${DEVICE_UUID}" --pid "${STATUS_PID}" > "${XCRUN_DEVICE_PROCESS_RESUME_LOG_DIR}" 2>&1
|
||||
}
|
||||
|
||||
showXcrunLogs() {
|
||||
cat "${XCRUN_DEVICE_INSTALL_LOG_DIR}" >&2;
|
||||
cat "${XCRUN_DEVICE_PROCESS_LAUNCH_LOG_DIR}" >&2;
|
||||
cat "${XCRUN_DEVICE_PROCESS_RESUME_LOG_DIR}" >&2;
|
||||
}
|
||||
|
||||
# find the first connected iPhone's UUID
|
||||
DEVICE_UUID=$(idevice_id -l)
|
||||
|
||||
# Check if any device is connected
|
||||
if [ -z "${DEVICE_UUID}" ]; then
|
||||
echo "No connected iPhone device detected."
|
||||
exit 1
|
||||
else
|
||||
echo "Connected iPhone UDID: ${DEVICE_UUID}"
|
||||
fi
|
||||
|
||||
BUILD_DIR="${GIT_ROOT}/build"
|
||||
|
||||
#iOS build of debug scheme
|
||||
xcodebuild -workspace "ios/StatusIm.xcworkspace" -configuration Debug -scheme StatusIm -destination id="${DEVICE_UUID}" -derivedDataPath "${BUILD_DIR}" -verbose | xcbeautify
|
||||
|
||||
APP_PATH="${BUILD_DIR}/Build/Products/Debug-iphoneos/StatusIm.app"
|
||||
|
||||
trap showXcrunLogs EXIT ERR INT QUIT
|
||||
installAndLaunchApp &
|
||||
exec "${GIT_ROOT}/scripts/run-metro.sh" 2>&1
|
||||
|
||||
+36
-46
@@ -3,34 +3,21 @@ set -euo pipefail
|
||||
set -m # needed to access jobs
|
||||
|
||||
GIT_ROOT=$(cd "${BASH_SOURCE%/*}" && git rev-parse --show-toplevel)
|
||||
XCRUN_INSTALL_LOG_FILE="${GIT_ROOT}/logs/xcrun_install.log"
|
||||
XCRUN_LAUNCH_LOG_FILE="${GIT_ROOT}/logs/xcrun_launch.log"
|
||||
XCRUN_SIMULATOR_JSON_FILE="${GIT_ROOT}/logs/ios_simulators_list.log"
|
||||
|
||||
# Install on the simulator
|
||||
installAndLaunchApp() {
|
||||
xcrun simctl install "$UDID" "$APP_PATH" > "${XCRUN_INSTALL_LOG_FILE}" 2>&1
|
||||
"${GIT_ROOT}/scripts/wait-for-metro-port.sh" 2>&1
|
||||
xcrun simctl launch "$UDID" im.status.ethereum.debug > "${XCRUN_LAUNCH_LOG_FILE}" 2>&1
|
||||
|
||||
# We run Metro in background while calling adb.
|
||||
cleanupMetro() {
|
||||
pkill -f run-metro.sh
|
||||
rm -f metro-server-logs.log
|
||||
}
|
||||
|
||||
# Using function gives a neater jobspec name.
|
||||
runMetro() {
|
||||
nohup "${GIT_ROOT}/scripts/run-metro.sh" 2>&1 \
|
||||
| tee metro-server-logs.log
|
||||
}
|
||||
|
||||
waitForMetro() {
|
||||
set +e # Allow grep command to fail in the loop.
|
||||
TIMEOUT=5
|
||||
echo "Waiting for Metro server..." >&2
|
||||
while ! grep -q "Welcome to Metro" metro-server-logs.log; do
|
||||
echo -n "." >&2
|
||||
sleep 1
|
||||
if ((TIMEOUT == 0)); then
|
||||
echo -e "\nMetro server timed out, exiting" >&2
|
||||
set -e # Restore errexit for rest of script.
|
||||
return 1
|
||||
fi
|
||||
((TIMEOUT--))
|
||||
done
|
||||
set -e # Restore errexit for rest of script.
|
||||
showXcrunLogs() {
|
||||
cat "${XCRUN_INSTALL_LOG_FILE}" >&2;
|
||||
cat "${XCRUN_LAUNCH_LOG_FILE}" >&2;
|
||||
}
|
||||
|
||||
# Check if the first argument is provided
|
||||
@@ -39,41 +26,44 @@ if [ -z "${1-}" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# fetch available iOS Simulators
|
||||
xcrun simctl list devices -j > "${XCRUN_SIMULATOR_JSON_FILE}"
|
||||
|
||||
SIMULATOR=${1}
|
||||
|
||||
# get our desired UUID
|
||||
UUID=$(xcrun simctl list devices | grep -E "$SIMULATOR \(" | head -n 1 | awk -F '[()]' '{print $2}')
|
||||
# get the first available UDID for Simulators that match the name
|
||||
read -r UDID SIMULATOR_STATE IS_AVAILABLE < <(jq --raw-output --arg simulator "${SIMULATOR}" '
|
||||
[ .devices[] | .[] | select(.name == $simulator) ] |
|
||||
map(select(.isAvailable)) + map(select(.isAvailable | not)) |
|
||||
first |
|
||||
"\(.udid) \(.state) \(.isAvailable)"
|
||||
' "${XCRUN_SIMULATOR_JSON_FILE}")
|
||||
|
||||
# get simulator status
|
||||
SIMULATOR_STATE=$(xcrun simctl list devices | grep -E "$SIMULATOR \(" | head -n 1 | awk '{print $NF}')
|
||||
if [ "${IS_AVAILABLE}" == false ] || [ "${UDID}" == null ]; then
|
||||
echo "Error: Simulator ${SIMULATOR} is not available, Please find and install them."
|
||||
echo "For help please refer"
|
||||
echo "https://developer.apple.com/documentation/safari-developer-tools/adding-additional-simulators#Add-and-remove-Simulators " >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# sometimes a simulator is already running, shut it down to avoid errors
|
||||
if [ "$SIMULATOR_STATE" != "(Shutdown)" ]; then
|
||||
xcrun simctl shutdown "$UUID"
|
||||
if [ "${SIMULATOR_STATE}" != "Shutdown" ]; then
|
||||
xcrun simctl shutdown "${UDID}"
|
||||
fi
|
||||
|
||||
# boot up iOS for simulator
|
||||
xcrun simctl boot "$UUID"
|
||||
xcrun simctl boot "${UDID}"
|
||||
|
||||
# start the simulator
|
||||
open -a Simulator --args -CurrentDeviceUDID "$UUID"
|
||||
open -a Simulator --args -CurrentDeviceUDID "${UDID}"
|
||||
|
||||
BUILD_DIR="${GIT_ROOT}/build"
|
||||
|
||||
#iOS build of debug scheme
|
||||
xcodebuild -workspace "ios/StatusIm.xcworkspace" -configuration Debug -scheme StatusIm -destination id="$UUID" -derivedDataPath "${BUILD_DIR}" | xcbeautify
|
||||
xcodebuild -workspace "ios/StatusIm.xcworkspace" -configuration Debug -scheme StatusIm -destination id="${UDID}" -derivedDataPath "${BUILD_DIR}" -verbose | xcbeautify
|
||||
|
||||
APP_PATH="${BUILD_DIR}/Build/Products/Debug-iphonesimulator/StatusIm.app"
|
||||
|
||||
# Install on the simulator
|
||||
xcrun simctl install "$UUID" "$APP_PATH"
|
||||
|
||||
trap cleanupMetro EXIT ERR INT QUIT
|
||||
runMetro &
|
||||
waitForMetro
|
||||
|
||||
# launch the app when metro is ready
|
||||
xcrun simctl launch "$UUID" im.status.ethereum.debug
|
||||
|
||||
# bring metro job to foreground
|
||||
fg 'runMetro'
|
||||
trap showXcrunLogs EXIT ERR INT QUIT
|
||||
installAndLaunchApp &
|
||||
exec "${GIT_ROOT}/scripts/run-metro.sh" 2>&1
|
||||
|
||||
Executable
+14
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
TIMEOUT=10 # Metro should not take this long to start.
|
||||
|
||||
while [ "${TIMEOUT}" -gt 0 ]; do
|
||||
if ! lsof -i:8081 &> /dev/null; then
|
||||
echo "."
|
||||
sleep 1
|
||||
((TIMEOUT--))
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
@@ -28,10 +28,10 @@
|
||||
|
||||
[:f>
|
||||
(fn []
|
||||
(rn/use-effect (fn []
|
||||
(rn/hw-back-add-listener dismiss-bottom-sheet-callback)
|
||||
(fn []
|
||||
(rn/hw-back-remove-listener dismiss-bottom-sheet-callback))))
|
||||
(rn/use-mount (fn []
|
||||
(rn/hw-back-add-listener dismiss-bottom-sheet-callback)
|
||||
(fn []
|
||||
(rn/hw-back-remove-listener dismiss-bottom-sheet-callback))))
|
||||
[theme/provider {:theme (or page-theme (theme/get-theme))}
|
||||
[bottom-sheet/bottom-sheet opts
|
||||
(when content
|
||||
|
||||
@@ -16,12 +16,14 @@
|
||||
:align-self :center})
|
||||
|
||||
(def backdrop
|
||||
{:position :absolute
|
||||
:left 0
|
||||
:right 0
|
||||
:bottom 0
|
||||
:top 0
|
||||
:background-color colors/neutral-100})
|
||||
{:position :absolute
|
||||
:left 0
|
||||
:right 0
|
||||
:bottom 0
|
||||
:top 0})
|
||||
|
||||
(def backdrop-color
|
||||
{:background-color colors/neutral-100})
|
||||
|
||||
(def container
|
||||
{:position :absolute
|
||||
|
||||
@@ -207,11 +207,13 @@
|
||||
[@show-bottom-sheet? @expanded? @gesture-running?])
|
||||
|
||||
[:<>
|
||||
[rn/touchable-without-feedback {:on-press (when backdrop-dismiss? close-bottom-sheet)}
|
||||
[rn/pressable
|
||||
{:on-press (when backdrop-dismiss? close-bottom-sheet)
|
||||
:style styles/backdrop}
|
||||
[reanimated/view
|
||||
{:style (reanimated/apply-animations-to-style
|
||||
{:opacity bg-opacity}
|
||||
styles/backdrop)}]]
|
||||
styles/backdrop-color)}]]
|
||||
(cond->> [reanimated/view
|
||||
{:style (reanimated/apply-animations-to-style
|
||||
{:transform [{:translateY translate-y}]}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns legacy.status-im.currency.core
|
||||
(:require
|
||||
[legacy.status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||
[legacy.status-im.wallet.prices :as prices]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn get-currency
|
||||
@@ -16,5 +15,4 @@
|
||||
:currency
|
||||
currency
|
||||
;; on changing currency, we should fetch tokens prices again
|
||||
{:on-success #(rf/dispatch [:wallet/get-wallet-token])})
|
||||
(prices/update-prices)))
|
||||
{:on-success #(rf/dispatch [:wallet/get-wallet-token])})))
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
[legacy.status-im.ethereum.ens :as ens]
|
||||
[legacy.status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||
[legacy.status-im.utils.random :as random]
|
||||
[legacy.status-im.wallet.utils :as wallet.utils]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.navigation.events :as navigation]
|
||||
@@ -126,7 +125,7 @@
|
||||
{:events [::set-pub-key]}
|
||||
[{:keys [db]}]
|
||||
(let [{:keys [username address custom-domain?]} (:ens/registration db)
|
||||
address (or address (wallet.utils/default-address db))
|
||||
address address
|
||||
{:keys [public-key]} (:profile/profile db)
|
||||
chain-id (chain/chain-id db)
|
||||
username (fullname custom-domain? username)]
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
[legacy.status-im.ethereum.decode :as decode]
|
||||
[legacy.status-im.ethereum.encode :as encode]
|
||||
[legacy.status-im.utils.mobile-sync :as utils.mobile-sync]
|
||||
[legacy.status-im.wallet.core :as wallet]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.common.json-rpc.events :as json-rpc]
|
||||
[taoensso.timbre :as log]
|
||||
@@ -256,24 +255,13 @@
|
||||
(let [checksum (eip55/address->checksum address)
|
||||
max-known-block (get-max-block-with-transfers db address)
|
||||
effects (cond-> [(when (seq transfers)
|
||||
(set-lowest-fetched-block checksum transfers))
|
||||
(wallet/set-max-block-with-transfers checksum transfers)]
|
||||
(set-lowest-fetched-block checksum transfers))]
|
||||
|
||||
(seq transfers)
|
||||
(concat
|
||||
[]
|
||||
(mapv add-transfer transfers))
|
||||
|
||||
(and max-known-block
|
||||
(some #(> (:block %) max-known-block) transfers))
|
||||
(conj (wallet/update-balances
|
||||
[address]
|
||||
(zero? max-known-block)))
|
||||
|
||||
(and (zero? max-known-block)
|
||||
(empty? transfers))
|
||||
(conj (wallet/set-zero-balances {:address address}))
|
||||
|
||||
(< (count transfers) limit)
|
||||
(conj (tx-history-end-reached checksum)))]
|
||||
(apply rf/merge cofx (tx-fetching-ended [checksum]) effects)))
|
||||
@@ -282,8 +270,7 @@
|
||||
{:events [::new-transfers]}
|
||||
[cofx transfers params]
|
||||
(rf/merge cofx
|
||||
(handle-new-transfer transfers params)
|
||||
(wallet/stop-fetching-on-empty-tx-history transfers)))
|
||||
(handle-new-transfer transfers params)))
|
||||
|
||||
(rf/defn tx-fetching-failed
|
||||
{:events [::tx-fetching-failed]}
|
||||
|
||||
@@ -32,10 +32,6 @@
|
||||
legacy.status-im.visibility-status-popover.core
|
||||
legacy.status-im.visibility-status-updates.core
|
||||
legacy.status-im.waku.core
|
||||
legacy.status-im.wallet.accounts.core
|
||||
legacy.status-im.wallet.choose-recipient.core
|
||||
[legacy.status-im.wallet.core :as wallet]
|
||||
legacy.status-im.wallet.custom-tokens.core
|
||||
[native-module.core :as native-module]
|
||||
[re-frame.core :as re-frame]
|
||||
[react-native.core :as rn]
|
||||
@@ -141,7 +137,6 @@
|
||||
(rf/merge cofx
|
||||
{:db (dissoc db :app-in-background-since)}
|
||||
(mailserver/process-next-messages-request)
|
||||
(wallet/restart-wallet-service-after-background app-in-background-since)
|
||||
(when-not new-account?
|
||||
(universal-links/process-stored-event))
|
||||
#(when-let [chat-id (:current-chat-id db)]
|
||||
@@ -198,10 +193,8 @@
|
||||
:reset-card (keycard/reset-card-screen-did-load %)
|
||||
:enter-pin-settings (keycard/enter-pin-screen-did-load %)
|
||||
:keycard-login-pin (keycard/login-pin-screen-did-load %)
|
||||
:add-new-account-pin (keycard/enter-pin-screen-did-load %)
|
||||
:keycard-authentication-method (keycard/authentication-method-screen-did-load %)
|
||||
:multiaccounts (keycard/multiaccounts-screen-did-load %)
|
||||
:wallet-legacy (wallet/wallet-will-focus %)
|
||||
nil)))
|
||||
|
||||
;;TODO :replace by named events
|
||||
|
||||
@@ -401,15 +401,12 @@
|
||||
(merge
|
||||
args
|
||||
{:on-success
|
||||
(fn [response]
|
||||
(fn [_response]
|
||||
(log/debug "[keycard response succ] export-key")
|
||||
(re-frame/dispatch [:keycard.callback/on-export-key-success
|
||||
response]))
|
||||
(js/alert "feature no longer supported"))
|
||||
:on-failure
|
||||
(fn [response]
|
||||
(log/debug "[keycard response fail] export-key")
|
||||
(re-frame/dispatch [:keycard.callback/on-export-key-error
|
||||
(error-object->map response)]))})))
|
||||
(fn [_response]
|
||||
(log/debug "[keycard response fail] export-key"))})))
|
||||
|
||||
(defn unpair-and-delete
|
||||
[args]
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
[legacy.status-im.keycard.recovery :as recovery]
|
||||
[legacy.status-im.keycard.sign :as sign]
|
||||
legacy.status-im.keycard.unpair
|
||||
[legacy.status-im.keycard.wallet :as wallet]
|
||||
[legacy.status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||
[re-frame.db]
|
||||
[status-im.navigation.events :as navigation]
|
||||
@@ -401,10 +400,6 @@
|
||||
(= pin-code-length numbers-entered))
|
||||
(common/verify-pin {:pin-step :current})
|
||||
|
||||
(and (= enter-step :export-key)
|
||||
(= pin-code-length numbers-entered))
|
||||
(wallet/verify-pin-with-delay)
|
||||
|
||||
(and (= enter-step :sign)
|
||||
(= pin-code-length numbers-entered))
|
||||
(sign/prepare-to-sign)
|
||||
|
||||
@@ -1,51 +1,13 @@
|
||||
(ns legacy.status-im.keycard.export-key
|
||||
(:require
|
||||
[legacy.status-im.keycard.common :as common]
|
||||
[legacy.status-im.keycard.wallet :as wallet]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/defn on-export-key-error
|
||||
{:events [:keycard.callback/on-export-key-error]}
|
||||
[{:keys [db] :as cofx} error]
|
||||
(log/debug "[keycard] export key error" error)
|
||||
(let [tag-was-lost? (common/tag-lost? (:error error))
|
||||
pin-retries (common/pin-retries (:error error))]
|
||||
(cond
|
||||
tag-was-lost?
|
||||
(rf/merge cofx
|
||||
{:db (assoc-in db [:keycard :pin :status] nil)}
|
||||
(common/set-on-card-connected :wallet-legacy.accounts/generate-new-keycard-account))
|
||||
|
||||
(not (nil? pin-retries))
|
||||
(rf/merge cofx
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :application-info :pin-retry-counter] pin-retries)
|
||||
(update-in [:keycard :pin]
|
||||
assoc
|
||||
:status :error
|
||||
:enter-step :export-key
|
||||
:puk []
|
||||
:current []
|
||||
:original []
|
||||
:confirmation []
|
||||
:sign []
|
||||
:export-key []
|
||||
:error-label :t/pin-mismatch))}
|
||||
(common/hide-connection-sheet)
|
||||
(when (zero? pin-retries) (common/frozen-keycard-popup)))
|
||||
:else
|
||||
(rf/merge cofx
|
||||
(common/show-wrong-keycard-alert)
|
||||
(common/clear-pin)
|
||||
(common/hide-connection-sheet)))))
|
||||
|
||||
(rf/defn on-export-key-success
|
||||
{:events [:keycard.callback/on-export-key-success]}
|
||||
[{:keys [db] :as cofx} pubkey]
|
||||
(let [callback-fn (get-in db [:keycard :on-export-success])]
|
||||
(rf/merge cofx
|
||||
{:dispatch (callback-fn pubkey)}
|
||||
(wallet/hide-pin-sheet)
|
||||
(common/clear-pin)
|
||||
(common/hide-connection-sheet))))
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.keycard.common :as common]
|
||||
[legacy.status-im.utils.deprecated-types :as types]
|
||||
[legacy.status-im.wallet.utils :as wallet.utils]
|
||||
[re-frame.core :as re-frame]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.address :as address]
|
||||
@@ -24,8 +23,7 @@
|
||||
typed? (get-in db [:keycard :typed?])
|
||||
pin (common/vector->string (get-in db [:keycard :pin :sign]))
|
||||
from (or (get-in db [:signing/tx :from :address])
|
||||
(get-in db [:signing/tx :message :from])
|
||||
(wallet.utils/default-address db))
|
||||
(get-in db [:signing/tx :message :from]))
|
||||
path (reduce
|
||||
(fn [_ {:keys [address path]}]
|
||||
(when (address/address= from address)
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
(ns legacy.status-im.keycard.wallet
|
||||
(:require
|
||||
[legacy.status-im.bottom-sheet.events :as bottom-sheet]
|
||||
[legacy.status-im.keycard.common :as common]
|
||||
[legacy.status-im.ui.screens.wallet.add-new.views :as add-new.views]
|
||||
[legacy.status-im.utils.hex :as utils.hex]
|
||||
[native-module.core :as native-module]
|
||||
[status-im.constants :as constants]
|
||||
[utils.ethereum.eip.eip55 :as eip55]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/defn show-pin-sheet
|
||||
{:events [:keycard/new-account-pin-sheet]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(rf/merge
|
||||
cofx
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :pin :enter-step] :export-key)
|
||||
(update-in [:keycard :pin] dissoc :export-key))
|
||||
:dismiss-keyboard nil}
|
||||
(bottom-sheet/show-bottom-sheet-old {:view {:content add-new.views/pin}})))
|
||||
|
||||
(rf/defn verify-pin-with-delay
|
||||
[cofx]
|
||||
{:utils/dispatch-later
|
||||
;; We need to give previous sheet some time to be fully hidden
|
||||
[{:ms 200
|
||||
:dispatch [:wallet-legacy.accounts/verify-pin]}]})
|
||||
|
||||
(rf/defn hide-pin-sheet
|
||||
{:events [:keycard/new-account-pin-sheet-hide]}
|
||||
[cofx]
|
||||
(bottom-sheet/hide-bottom-sheet-old cofx))
|
||||
|
||||
(defn public-key->address
|
||||
[public-key]
|
||||
(let [length (count public-key)
|
||||
normalized-key (case length
|
||||
132 (str "0x" (subs public-key 4))
|
||||
130 public-key
|
||||
128 (str "0x" public-key)
|
||||
nil)]
|
||||
(when normalized-key
|
||||
(subs (native-module/sha3 normalized-key) 26))))
|
||||
|
||||
(rf/defn generate-new-keycard-account
|
||||
{:events [:wallet-legacy.accounts/generate-new-keycard-account]}
|
||||
[{:keys [db]}]
|
||||
(let [path-num (inc (get-in db [:profile/profile :latest-derived-path]))
|
||||
path (str constants/path-wallet-root "/" path-num)
|
||||
pin (common/vector->string (get-in db [:keycard :pin :export-key]))]
|
||||
{:db
|
||||
(assoc-in
|
||||
db
|
||||
[:keycard :on-export-success]
|
||||
#(vector :wallet-legacy.accounts/account-stored
|
||||
(let [public-key (utils.hex/normalize-hex %)]
|
||||
{;; Strip leading 04 prefix denoting uncompressed key format
|
||||
:address (eip55/address->checksum
|
||||
(str "0x"
|
||||
(public-key->address
|
||||
(subs public-key 2))))
|
||||
:public-key (str "0x" public-key)
|
||||
:path path})))
|
||||
|
||||
:keycard/export-key {:pin pin :path path}}))
|
||||
|
||||
(rf/defn verify-pin
|
||||
{:events [:wallet-legacy.accounts/verify-pin]}
|
||||
[cofx]
|
||||
(common/verify-pin
|
||||
cofx
|
||||
{:pin-step :export-key
|
||||
:on-card-connected :wallet-legacy.accounts/verify-pin
|
||||
:on-success :wallet-legacy.accounts/generate-new-keycard-account
|
||||
:on-failure :keycard/new-account-pin-sheet}))
|
||||
@@ -5,7 +5,6 @@
|
||||
[legacy.status-im.multiaccounts.model :as multiaccounts.model]
|
||||
[legacy.status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||
[legacy.status-im.utils.mobile-sync :as utils]
|
||||
[legacy.status-im.wallet.core :as wallet]
|
||||
[status-im.contexts.chat.home.add-new-contact.events :as add-new-contact]
|
||||
[status-im.navigation.events :as navigation]
|
||||
[taoensso.timbre :as log]
|
||||
@@ -35,7 +34,6 @@
|
||||
(and logged-in? initialized?)
|
||||
[(mailserver/process-next-messages-request)
|
||||
(bottom-sheet/hide-bottom-sheet-old)
|
||||
(wallet/restart-wallet-service nil)
|
||||
#(add-new-contact/set-new-identity-reconnected %)]
|
||||
|
||||
logged-in?
|
||||
@@ -67,8 +65,7 @@
|
||||
(boolean remember-choice?)
|
||||
{})
|
||||
(when (and cellular? sync?)
|
||||
(mailserver/process-next-messages-request))
|
||||
(wallet/restart-wallet-service nil))))))
|
||||
(mailserver/process-next-messages-request)))))))
|
||||
|
||||
(rf/defn mobile-network-continue-syncing
|
||||
{:events [:mobile-network/continue-syncing]}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns legacy.status-im.multiaccounts.logout.core
|
||||
(:require
|
||||
[legacy.status-im.wallet.core :as wallet]
|
||||
[native-module.core :as native-module]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.common.keychain.events :as keychain]
|
||||
@@ -31,7 +30,6 @@
|
||||
(let [key-uid (get-in db [:profile/profile :key-uid])]
|
||||
(rf/merge cofx
|
||||
{:set-root :progress
|
||||
:chat.ui/clear-inputs nil
|
||||
:effects.shell/reset-state nil
|
||||
:hide-popover nil
|
||||
::logout nil
|
||||
@@ -40,7 +38,6 @@
|
||||
:profile/get-profiles-overview #(rf/dispatch
|
||||
[:profile/get-profiles-overview-success %])}
|
||||
(keychain/save-auth-method key-uid auth-method)
|
||||
(wallet/clear-timeouts)
|
||||
(initialize-app-db))))
|
||||
|
||||
(rf/defn logout
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
(:require
|
||||
["@react-native-community/netinfo" :default net-info]
|
||||
[legacy.status-im.mobile-sync-settings.core :as mobile-network]
|
||||
[legacy.status-im.wallet.core :as wallet]
|
||||
[native-module.core :as native-module]
|
||||
[re-frame.core :as re-frame]
|
||||
[taoensso.timbre :as log]
|
||||
@@ -11,12 +10,7 @@
|
||||
(rf/defn change-network-status
|
||||
[{:keys [db] :as cofx} is-connected?]
|
||||
(rf/merge cofx
|
||||
{:db (assoc db :network-status (if is-connected? :online :offline))}
|
||||
(when (and is-connected?
|
||||
(or (not= (count (get-in db [:wallet-legacy :accounts]))
|
||||
(count (get db :profile/wallet-accounts)))
|
||||
(wallet/has-empty-balances? db)))
|
||||
(wallet/update-balances nil nil))))
|
||||
{:db (assoc db :network-status (if is-connected? :online :offline))}))
|
||||
|
||||
(rf/defn change-network-type
|
||||
[{:keys [db] :as cofx} old-network-type network-type expensive?]
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
(ns legacy.status-im.search.core-test
|
||||
(:require
|
||||
[cljs.test :refer-macros [deftest testing is]]
|
||||
[legacy.status-im.subs.wallet.search :as search.subs]))
|
||||
|
||||
(defn extract-chat-attributes
|
||||
[chat]
|
||||
(let [{:keys [name alias tags]} (val chat)]
|
||||
(into [name alias] tags)))
|
||||
|
||||
(deftest filter-chats
|
||||
(let [chats {:chat-1 {:name "name1"
|
||||
:alias "alias1"
|
||||
:tags #{"tag1"}}
|
||||
:chat-2 {:name "name2"
|
||||
:alias "alias2"
|
||||
:tags #{"tag2" "tag3"}}
|
||||
:chat-3 {:name "name3"
|
||||
:alias "alias3"
|
||||
:tags #{}}
|
||||
:chat-4 {:name "name4"
|
||||
:alias "alias4"
|
||||
:tags #{"tag4"}}}]
|
||||
(testing "no search filter"
|
||||
(is (= (count chats)
|
||||
(count (search.subs/apply-filter ""
|
||||
chats
|
||||
extract-chat-attributes
|
||||
false)))))
|
||||
(testing "searching for a specific tag"
|
||||
(is (= 1
|
||||
(count (search.subs/apply-filter "tag2"
|
||||
chats
|
||||
extract-chat-attributes
|
||||
false)))))
|
||||
(testing "searching for a partial tag"
|
||||
(is (= 3
|
||||
(count (search.subs/apply-filter "tag"
|
||||
chats
|
||||
extract-chat-attributes
|
||||
false)))))
|
||||
(testing "searching for a specific alias"
|
||||
(is (= 1
|
||||
(count (search.subs/apply-filter "alias4"
|
||||
chats
|
||||
extract-chat-attributes
|
||||
false)))))
|
||||
(testing "searching for a partial alias"
|
||||
(is (= 4
|
||||
(count (search.subs/apply-filter "alias"
|
||||
chats
|
||||
extract-chat-attributes
|
||||
false)))))
|
||||
(testing "searching for a specific chat name"
|
||||
(is (= 1
|
||||
(count (search.subs/apply-filter "name4"
|
||||
chats
|
||||
extract-chat-attributes
|
||||
false)))))))
|
||||
@@ -10,9 +10,6 @@
|
||||
[legacy.status-im.utils.deprecated-types :as types]
|
||||
[legacy.status-im.utils.hex :as utils.hex]
|
||||
[legacy.status-im.utils.utils :as utils]
|
||||
[legacy.status-im.wallet.core :as wallet]
|
||||
[legacy.status-im.wallet.prices :as prices]
|
||||
[legacy.status-im.wallet.utils :as wallet.utils]
|
||||
[native-module.core :as native-module]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.common.json-rpc.events :as json-rpc]
|
||||
@@ -83,7 +80,7 @@
|
||||
[{{:signing/keys [sign tx] :as db} :db}]
|
||||
(let [{{:keys [data typed? from v4]} :message} tx
|
||||
{:keys [in-progress? password]} sign
|
||||
from (or from (wallet.utils/default-address db))
|
||||
from from
|
||||
hashed-password (native-module/sha3 (security/safe-unmask-data
|
||||
password))]
|
||||
(when-not in-progress?
|
||||
@@ -335,7 +332,7 @@
|
||||
:dismiss-keyboard nil}
|
||||
#(when-not wallet-set-up-passed?
|
||||
{:dispatch-later [{:dispatch [:show-popover {:view :signing-phrase}] :ms 200}]})
|
||||
(prices/update-prices)
|
||||
|
||||
#(when-not gas
|
||||
{:db (assoc-in (:db %) [:signing/edit-fee :gas-loading?] true)
|
||||
:signing/update-estimated-gas {:obj (-> tx-obj
|
||||
@@ -395,7 +392,6 @@
|
||||
:signing/show-transaction-result nil}
|
||||
(prepare-unconfirmed-transaction result tx-obj symbol amount)
|
||||
(check-queue)
|
||||
(wallet/watch-tx (get from :address) result)
|
||||
#(when on-result
|
||||
{:dispatch (conj on-result result)}))))
|
||||
|
||||
@@ -408,7 +404,6 @@
|
||||
(rf/merge
|
||||
cofx
|
||||
{:db (dissoc db :signing/tx :signing/sign)}
|
||||
(wallet/watch-tx (get from :address) transaction-hash)
|
||||
(if (keycard.common/keycard-multiaccount? db)
|
||||
(signing.keycard/hash-message
|
||||
{:data data
|
||||
@@ -511,8 +506,8 @@
|
||||
{:dispatch (conj on-error "transaction was cancelled by user")}))))
|
||||
|
||||
(defn normalize-tx-obj
|
||||
[db tx]
|
||||
(update-in tx [:tx-obj :from] #(eip55/address->checksum (or % (wallet.utils/default-address db)))))
|
||||
[_db tx]
|
||||
(update-in tx [:tx-obj :from] #(eip55/address->checksum %)))
|
||||
|
||||
(rf/defn sign
|
||||
"Signing transaction or message, shows signing sheet
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns legacy.status-im.stickers.core
|
||||
(:require
|
||||
[legacy.status-im.utils.utils :as utils]
|
||||
[legacy.status-im.wallet.utils :as wallet.utils]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.constants :as constants]
|
||||
[utils.ethereum.chain :as chain]
|
||||
@@ -39,15 +38,6 @@
|
||||
:params []
|
||||
:on-success #(re-frame/dispatch [:stickers/stickers-recent-success %])}]})
|
||||
|
||||
(rf/defn buy-pack
|
||||
{:events [:stickers/buy-pack]}
|
||||
[{db :db} pack-id]
|
||||
{:json-rpc/call [{:method "stickers_buyPrepareTx"
|
||||
:params [(chain/chain-id db) (wallet.utils/default-address db) (int pack-id)]
|
||||
:on-success #(re-frame/dispatch [:signing.ui/sign
|
||||
{:tx-obj %
|
||||
:on-result [:stickers/pending-pack pack-id]}])}]})
|
||||
|
||||
(rf/defn pending-pack
|
||||
{:events [:stickers/pending-pack]}
|
||||
[{db :db} id]
|
||||
|
||||
@@ -7,10 +7,6 @@
|
||||
legacy.status-im.subs.mailservers
|
||||
legacy.status-im.subs.networks
|
||||
legacy.status-im.subs.stickers
|
||||
legacy.status-im.subs.wallet.search
|
||||
legacy.status-im.subs.wallet.signing
|
||||
legacy.status-im.subs.wallet.transactions
|
||||
legacy.status-im.subs.wallet.wallet
|
||||
[re-frame.core :as re-frame]))
|
||||
|
||||
(defn reg-root-key-sub
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
(ns legacy.status-im.subs.wallet.search
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.utils.currency :as currency]
|
||||
[re-frame.core :as re-frame]))
|
||||
|
||||
(defn sort-by-timestamp
|
||||
[coll]
|
||||
(when (not-empty coll)
|
||||
(sort-by #(-> % second :timestamp)
|
||||
>
|
||||
(into {} coll))))
|
||||
|
||||
(defn apply-filter
|
||||
"extract-attributes-fn is a function that take an element from the collection
|
||||
and returns a vector of attributes which are strings
|
||||
apply-filter returns the elements for which at least one attribute includes
|
||||
the search-filter
|
||||
apply-filter returns nil if there is no element that match the filter
|
||||
apply-filter returns full collection if the search-filter is empty"
|
||||
[search-filter coll extract-attributes-fn sort?]
|
||||
(let [results (if (not-empty search-filter)
|
||||
(let [search-filter (string/lower-case search-filter)]
|
||||
(filter (fn [element]
|
||||
(some (fn [v]
|
||||
(let [s (cond (string? v) v
|
||||
(keyword? v) (name v))]
|
||||
(when (string? s)
|
||||
(string/includes? (string/lower-case s)
|
||||
search-filter))))
|
||||
(extract-attributes-fn element)))
|
||||
coll))
|
||||
coll)]
|
||||
(if sort?
|
||||
(sort-by-timestamp results)
|
||||
results)))
|
||||
|
||||
(defn extract-currency-attributes
|
||||
[currency]
|
||||
(let [{:keys [code display-name]} (val currency)]
|
||||
[code display-name]))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy/search-filtered-currencies
|
||||
:<- [:search/currency-filter]
|
||||
(fn [search-currency-filter]
|
||||
{:search-filter search-currency-filter
|
||||
:currencies (apply-filter search-currency-filter
|
||||
currency/currencies
|
||||
extract-currency-attributes
|
||||
false)}))
|
||||
|
||||
(defn extract-token-attributes
|
||||
[token]
|
||||
[(:symbol token) (:name token)])
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy/search-token-filter
|
||||
:<- [:ui/search]
|
||||
(fn [search]
|
||||
(get search :token-filter)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy/filtered-grouped-chain-tokens
|
||||
:<- [:wallet-legacy/grouped-chain-tokens]
|
||||
:<- [:wallet-legacy/search-token-filter]
|
||||
(fn [[{custom-tokens true default-tokens nil} search-token-filter]]
|
||||
{:search-filter search-token-filter
|
||||
:tokens {true (apply-filter search-token-filter custom-tokens extract-token-attributes false)
|
||||
nil (apply-filter search-token-filter
|
||||
default-tokens
|
||||
extract-token-attributes
|
||||
false)}}))
|
||||
@@ -1,235 +0,0 @@
|
||||
(ns legacy.status-im.subs.wallet.signing
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.ethereum.tokens :as tokens]
|
||||
[legacy.status-im.signing.gas :as signing.gas]
|
||||
[legacy.status-im.wallet.db :as wallet.db]
|
||||
[re-frame.core :as re-frame]
|
||||
[utils.ethereum.chain :as chain]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.money :as money]))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::send-transaction
|
||||
:<- [:wallet-legacy]
|
||||
(fn [wallet]
|
||||
(:send-transaction wallet)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy.send/symbol
|
||||
:<- [::send-transaction]
|
||||
(fn [send-transaction]
|
||||
(:symbol send-transaction)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy.send/camera-flashlight
|
||||
:<- [::send-transaction]
|
||||
(fn [send-transaction]
|
||||
(:camera-flashlight send-transaction)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy/settings
|
||||
:<- [:wallet-legacy]
|
||||
(fn [{:keys [settings]}]
|
||||
(reduce-kv #(conj %1 %3) [] settings)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy.request/transaction
|
||||
:<- [:wallet-legacy]
|
||||
:request-transaction)
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy/binance-chain?
|
||||
:<- [:current-network]
|
||||
(fn [network]
|
||||
(chain/binance-chain-id? (get-in network [:config :NetworkId]))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:signing/fee
|
||||
:<- [:signing/tx]
|
||||
(fn [{:keys [gas gasPrice maxFeePerGas]}]
|
||||
(signing.gas/calculate-max-fee gas (or maxFeePerGas gasPrice))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:signing/currencies
|
||||
:<- [:prices]
|
||||
:<- [:wallet-legacy/currency]
|
||||
:<- [:ethereum/native-currency]
|
||||
(fn [[prices {:keys [code]} {sym :symbol}]]
|
||||
[(name sym)
|
||||
code
|
||||
(get-in prices [sym (keyword code)])]))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:signing/priority-fee-suggestions-range
|
||||
:<- [:wallet-legacy/current-priority-fee]
|
||||
:<- [:wallet-legacy/slow-base-fee]
|
||||
:<- [:wallet-legacy/normal-base-fee]
|
||||
:<- [:wallet-legacy/fast-base-fee]
|
||||
(fn [[latest-tip slow normal fast]]
|
||||
(reduce
|
||||
(fn [acc [k fees]]
|
||||
(assoc acc
|
||||
k
|
||||
(reduce
|
||||
(fn [acc [k fee]]
|
||||
(assoc acc
|
||||
k
|
||||
(-> fee
|
||||
money/wei->gwei
|
||||
(money/to-fixed 2))))
|
||||
{}
|
||||
fees)))
|
||||
{}
|
||||
(signing.gas/get-fee-options latest-tip slow normal fast))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:signing/phrase
|
||||
:<- [:profile/profile]
|
||||
(fn [{:keys [signing-phrase]}]
|
||||
signing-phrase))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:signing/sign-message
|
||||
:<- [:signing/sign]
|
||||
:<- [:profile/wallet-accounts]
|
||||
:<- [:prices]
|
||||
(fn [[sign wallet-accounts prices]]
|
||||
(if (= :pinless (:type sign))
|
||||
(let [message (get-in sign [:formatted-data :message])
|
||||
wallet-acc (some #(when (= (:address %) (:receiver message)) %) wallet-accounts)]
|
||||
(cond-> sign
|
||||
(and (:amount message) (:currency message))
|
||||
(assoc :fiat-amount
|
||||
(money/fiat-amount-value (:amount message)
|
||||
(:currency message)
|
||||
:USD
|
||||
prices)
|
||||
:fiat-currency "USD")
|
||||
(and (:receiver message) wallet-acc)
|
||||
(assoc :account wallet-acc)))
|
||||
sign)))
|
||||
|
||||
(defn- too-precise-amount?
|
||||
"Checks if number has any extra digit beyond the allowed number of decimals.
|
||||
It does so by checking the number against its rounded value."
|
||||
[amount decimals]
|
||||
(let [^js bn (money/bignumber amount)]
|
||||
(not (.eq bn (.round bn decimals)))))
|
||||
|
||||
(defn get-amount-error
|
||||
[amount decimals]
|
||||
(when (and (seq amount) decimals)
|
||||
(let [normalized-amount (money/normalize amount)
|
||||
value (money/bignumber normalized-amount)]
|
||||
(cond
|
||||
(not (money/valid? value))
|
||||
{:amount-error (i18n/label :t/validation-amount-invalid-number)}
|
||||
|
||||
(too-precise-amount? normalized-amount decimals)
|
||||
{:amount-error (i18n/label :t/validation-amount-is-too-precise {:decimals decimals})}
|
||||
|
||||
:else nil))))
|
||||
|
||||
(defn get-sufficient-funds-error
|
||||
[balance sym amount]
|
||||
(when-not (money/sufficient-funds? amount (get balance sym))
|
||||
{:amount-error (i18n/label :t/wallet-insufficient-funds)}))
|
||||
|
||||
(defn gas-required-exceeds-allowance?
|
||||
[gas-error-message]
|
||||
(and gas-error-message
|
||||
(string/starts-with?
|
||||
gas-error-message
|
||||
"gas required exceeds allowance")))
|
||||
|
||||
(defn get-sufficient-gas-error
|
||||
[gas-error-message balance sym amount ^js gas ^js gasPrice]
|
||||
(if (and gas gasPrice)
|
||||
(let [^js fee (.times gas gasPrice)
|
||||
^js available-ether (money/bignumber (get balance :ETH 0))
|
||||
^js available-for-gas (if (= :ETH sym)
|
||||
(.minus available-ether (money/bignumber amount))
|
||||
available-ether)]
|
||||
(merge {:gas-error-state (when gas-error-message :gas-is-set)}
|
||||
(when-not (money/sufficient-funds? fee (money/bignumber available-for-gas))
|
||||
{:gas-error (i18n/label :t/wallet-insufficient-gas)})))
|
||||
(let [insufficient-balance? (gas-required-exceeds-allowance? gas-error-message)]
|
||||
{:gas-error-state (when gas-error-message :gas-isnt-set)
|
||||
:insufficient-balalce? insufficient-balance?
|
||||
:gas-error (if insufficient-balance?
|
||||
(i18n/label :t/insufficient-balance-to-cover-fee)
|
||||
(or gas-error-message
|
||||
(i18n/label :t/invalid-number)))})))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:signing/amount-errors
|
||||
(fn [[_ address] _]
|
||||
[(re-frame/subscribe [:signing/tx])
|
||||
(re-frame/subscribe [:balance address])])
|
||||
(fn [[{:keys [amount token gas gasPrice maxFeePerGas approve? gas-error-message]} balance]]
|
||||
(let [gas-price (or maxFeePerGas gasPrice)]
|
||||
(if (and amount token (not approve?))
|
||||
(let [amount-bn (money/formatted->internal (money/bignumber amount)
|
||||
(:symbol token)
|
||||
(:decimals token))
|
||||
amount-error (or (get-amount-error amount (:decimals token))
|
||||
(get-sufficient-funds-error balance (:symbol token) amount-bn))]
|
||||
(merge
|
||||
amount-error
|
||||
(get-sufficient-gas-error gas-error-message balance (:symbol token) amount-bn gas gas-price)))
|
||||
(get-sufficient-gas-error gas-error-message balance nil nil gas gas-price)))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy.send/prepare-transaction-with-balance
|
||||
:<- [:wallet-legacy/prepare-transaction]
|
||||
:<- [:wallet-legacy]
|
||||
:<- [:offline?]
|
||||
:<- [:wallet-legacy/all-tokens]
|
||||
:<- [:current-network]
|
||||
(fn [[{:keys [from to amount-text] :as transaction}
|
||||
wallet offline? all-tokens current-network]]
|
||||
(let [sym (:symbol transaction)
|
||||
balance (get-in wallet [:accounts (:address from) :balance])
|
||||
{:keys [decimals] :as token} (tokens/asset-for all-tokens current-network sym)
|
||||
{:keys [value error]} (wallet.db/parse-amount amount-text decimals)
|
||||
amount (money/formatted->internal value sym decimals)
|
||||
{:keys [amount-error] :as transaction-new}
|
||||
(merge transaction
|
||||
{:amount-error error}
|
||||
(when amount
|
||||
(get-sufficient-funds-error balance sym amount)))]
|
||||
(assoc transaction-new
|
||||
:amount amount
|
||||
:balance balance
|
||||
:token (assoc token :amount (get balance (:symbol token)))
|
||||
:sign-enabled? (and to
|
||||
(nil? amount-error)
|
||||
(not (nil? amount))
|
||||
(not offline?))))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy.request/prepare-transaction-with-balance
|
||||
:<- [:wallet-legacy/prepare-transaction]
|
||||
:<- [:wallet-legacy]
|
||||
:<- [:offline?]
|
||||
:<- [:wallet-legacy/all-tokens]
|
||||
:<- [:current-network]
|
||||
(fn [[{:keys [from to amount-text] :as transaction}
|
||||
wallet offline? all-tokens current-network]]
|
||||
(let [sym (:symbol transaction)
|
||||
balance (get-in wallet [:accounts (:address from) :balance])
|
||||
{:keys [decimals] :as token} (tokens/asset-for all-tokens current-network sym)
|
||||
{:keys [value error]} (wallet.db/parse-amount amount-text decimals)
|
||||
amount (money/formatted->internal value sym decimals)
|
||||
{:keys [amount-error] :as transaction-new}
|
||||
(assoc transaction :amount-error error)]
|
||||
(assoc transaction-new
|
||||
:amount amount
|
||||
:balance balance
|
||||
:token (assoc token :amount (get balance (:symbol token)))
|
||||
:sign-enabled? (and to
|
||||
from
|
||||
(nil? amount-error)
|
||||
(not (nil? amount))
|
||||
(not offline?))))))
|
||||
@@ -1,247 +0,0 @@
|
||||
(ns legacy.status-im.subs.wallet.transactions
|
||||
(:require
|
||||
[legacy.status-im.ethereum.transactions.core :as transactions]
|
||||
[legacy.status-im.notifications.wallet :as notifications.wallet]
|
||||
[legacy.status-im.wallet.db :as wallet.db]
|
||||
[legacy.status-im.wallet.utils :as wallet.utils]
|
||||
[re-frame.core :as re-frame]
|
||||
[utils.datetime :as datetime]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.money :as money]))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy/accounts
|
||||
:<- [:wallet-legacy]
|
||||
(fn [wallet]
|
||||
(get wallet :accounts)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy/account-by-transaction-hash
|
||||
:<- [:wallet-legacy/accounts]
|
||||
(fn [accounts [_ tx-hash]]
|
||||
(some (fn [[address account]]
|
||||
(when-let [transaction (get-in account [:transactions tx-hash])]
|
||||
(assoc transaction :address address)))
|
||||
accounts)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy/transactions
|
||||
:<- [:wallet-legacy]
|
||||
(fn [wallet [_ address]]
|
||||
(get-in wallet [:accounts address :transactions])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy/filters
|
||||
:<- [:wallet-legacy]
|
||||
(fn [wallet]
|
||||
(get wallet :filters)))
|
||||
|
||||
(defn enrich-transaction
|
||||
[{:keys [type to from value token] :as transaction}
|
||||
contacts native-currency]
|
||||
(let [[contact-address key-contact key-wallet]
|
||||
(if (= type :inbound)
|
||||
[from :from-contact :to-wallet]
|
||||
[to :to-contact :from-wallet])
|
||||
wallet (i18n/label :t/main-wallet)
|
||||
contact (get contacts contact-address)
|
||||
{:keys [symbol-display decimals] :as asset}
|
||||
(or token native-currency)
|
||||
amount-text (if value
|
||||
(wallet.utils/format-amount value decimals)
|
||||
"...")
|
||||
currency-text (when asset
|
||||
(clojure.core/name (or symbol-display
|
||||
(:symbol asset))))]
|
||||
(cond-> transaction
|
||||
contact (assoc key-contact (:name contact))
|
||||
:always (assoc key-wallet
|
||||
wallet
|
||||
:amount-text amount-text
|
||||
:currency-text currency-text))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy.transactions/transactions
|
||||
(fn [[_ address] _]
|
||||
[(re-frame/subscribe [:wallet-legacy/transactions address])
|
||||
(re-frame/subscribe [:contacts/contacts-by-address])
|
||||
(re-frame/subscribe [:ethereum/native-currency])])
|
||||
(fn [[transactions contacts native-currency]]
|
||||
(reduce (fn [acc [tx-hash transaction]]
|
||||
(assoc acc
|
||||
tx-hash
|
||||
(enrich-transaction transaction contacts native-currency))) ;;TODO this doesn't
|
||||
;;look good for performance, we need to calculate this only once for each transaction
|
||||
{}
|
||||
transactions)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy.transactions/all-filters?
|
||||
:<- [:wallet-legacy/filters]
|
||||
(fn [filters]
|
||||
(= wallet.db/default-wallet-filters
|
||||
filters)))
|
||||
|
||||
(def filters-labels
|
||||
{:inbound (i18n/label :t/incoming)
|
||||
:outbound (i18n/label :t/outgoing)
|
||||
:pending (i18n/label :t/pending)
|
||||
:failed (i18n/label :t/failed)})
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy.transactions/filters
|
||||
:<- [:wallet-legacy/filters]
|
||||
(fn [filters]
|
||||
(map (fn [id]
|
||||
(let [checked? (filters id)]
|
||||
{:id id
|
||||
:label (filters-labels id)
|
||||
:checked? checked?
|
||||
:on-touch #(if checked?
|
||||
(re-frame/dispatch [:wallet-legacy.transactions/remove-filter id])
|
||||
(re-frame/dispatch [:wallet-legacy.transactions/add-filter id]))}))
|
||||
wallet.db/default-wallet-filters)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy.transactions.filters/screen
|
||||
:<- [:wallet-legacy.transactions/filters]
|
||||
:<- [:wallet-legacy.transactions/all-filters?]
|
||||
(fn [[filters all-filters?]]
|
||||
{:all-filters? all-filters?
|
||||
:filters filters
|
||||
:on-touch-select-all (when-not all-filters?
|
||||
#(re-frame/dispatch
|
||||
[:wallet-legacy.transactions/add-all-filters]))}))
|
||||
|
||||
(defn- enrich-transaction-for-list
|
||||
[filters
|
||||
{:keys [type from-contact from to-contact to timestamp] :as transaction}
|
||||
address]
|
||||
(when (filters type)
|
||||
(assoc
|
||||
(case type
|
||||
:inbound
|
||||
(assoc transaction
|
||||
:label (i18n/label :t/from-capitalized)
|
||||
:contact-accessibility-label :sender-text
|
||||
:address-accessibility-label :sender-address-text
|
||||
:contact from-contact
|
||||
:address from)
|
||||
(assoc transaction
|
||||
:label (i18n/label :t/to-capitalized)
|
||||
:contact-accessibility-label :recipient-name-text
|
||||
:address-accessibility-label :recipient-address-text
|
||||
:contact to-contact
|
||||
:address to))
|
||||
:time-formatted (datetime/timestamp->time timestamp)
|
||||
:on-touch-fn #(re-frame/dispatch [:wallet-legacy.ui/show-transaction-details
|
||||
(:hash transaction)
|
||||
address]))))
|
||||
|
||||
(defn group-transactions-by-date
|
||||
[transactions]
|
||||
(->> transactions
|
||||
(group-by #(datetime/timestamp->date-key (:timestamp %)))
|
||||
(sort-by key >)
|
||||
(map (fn [[date-key transactions]]
|
||||
{:title (datetime/timestamp->mini-date (:timestamp (first transactions)))
|
||||
:key date-key
|
||||
:data (sort-by :timestamp > transactions)}))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy.transactions.history/screen
|
||||
(fn [[_ address] _]
|
||||
[(re-frame/subscribe [:wallet-legacy.transactions/transactions address])
|
||||
(re-frame/subscribe [:wallet-legacy/filters])
|
||||
(re-frame/subscribe [:wallet-legacy.transactions/all-filters?])])
|
||||
(fn [[transactions filters all-filters?] [_ address]]
|
||||
{:all-filters? all-filters?
|
||||
:total (count transactions)
|
||||
:transaction-history-sections
|
||||
(->> transactions
|
||||
vals
|
||||
(keep #(enrich-transaction-for-list filters % address))
|
||||
(group-transactions-by-date))}))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy/recipient-recent-txs
|
||||
(fn [[_ address] _]
|
||||
[(re-frame/subscribe [:wallet-legacy.transactions/transactions address])])
|
||||
(fn [[transactions] _]
|
||||
(->> transactions
|
||||
vals
|
||||
(sort-by :timestamp >)
|
||||
(remove #(= (:type %) :pending))
|
||||
(take 3))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy.transactions.details/current-transaction
|
||||
(fn [[_ _ address] _]
|
||||
[(re-frame/subscribe [:wallet-legacy.transactions/transactions address])
|
||||
(re-frame/subscribe [:ethereum/native-currency])
|
||||
(re-frame/subscribe [:chain-id])])
|
||||
(fn [[transactions native-currency chain-id] [_ tx-hash _]]
|
||||
(let [{:keys [gas-used gas-price fee-cap tip-cap timestamp type]
|
||||
:as transaction}
|
||||
(get transactions tx-hash)
|
||||
native-currency-text (name (or (:symbol-display native-currency)
|
||||
(:symbol native-currency)))]
|
||||
(when transaction
|
||||
(merge transaction
|
||||
{:gas-price-eth (if gas-price
|
||||
(money/wei->str :eth
|
||||
gas-price
|
||||
native-currency-text)
|
||||
"-")
|
||||
:gas-price-gwei (if gas-price
|
||||
(money/wei->str :gwei
|
||||
gas-price)
|
||||
"-")
|
||||
:fee-cap-gwei (if fee-cap
|
||||
(money/wei->str :gwei
|
||||
fee-cap)
|
||||
"-")
|
||||
:tip-cap-gwei (if tip-cap
|
||||
(money/wei->str :gwei
|
||||
tip-cap)
|
||||
"-")
|
||||
:date (datetime/timestamp->long-date timestamp)}
|
||||
(if (= type :unsigned)
|
||||
{:block (i18n/label :t/not-applicable)
|
||||
:cost (i18n/label :t/not-applicable)
|
||||
:gas-limit (i18n/label :t/not-applicable)
|
||||
:gas-used (i18n/label :t/not-applicable)
|
||||
:nonce (i18n/label :t/not-applicable)
|
||||
:hash (i18n/label :t/not-applicable)}
|
||||
{:cost (when gas-used
|
||||
(money/wei->str :eth
|
||||
(money/fee-value gas-used gas-price)
|
||||
native-currency-text))
|
||||
:url (transactions/get-transaction-details-url
|
||||
chain-id
|
||||
(:hash transaction))}))))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy.transactions.details/screen
|
||||
(fn [[_ tx-hash address] _]
|
||||
[(re-frame/subscribe [:wallet-legacy.transactions.details/current-transaction tx-hash address])
|
||||
(re-frame/subscribe [:ethereum/current-block])])
|
||||
(fn [[transaction current-block]]
|
||||
(let [confirmations (wallet.db/get-confirmations transaction
|
||||
current-block)]
|
||||
(assoc transaction
|
||||
:confirmations confirmations
|
||||
:confirmations-progress
|
||||
(if (>= confirmations transactions/confirmations-count-threshold)
|
||||
100
|
||||
(* 100 (/ confirmations transactions/confirmations-count-threshold)))))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:push-notifications/wallet-transactions
|
||||
:<- [:push-notifications/preferences]
|
||||
(fn [pref]
|
||||
(first (filter #(notifications.wallet/preference= %
|
||||
{:service "wallet"
|
||||
:event "transaction"
|
||||
:identifier "all"})
|
||||
pref))))
|
||||
@@ -1,295 +0,0 @@
|
||||
(ns legacy.status-im.subs.wallet.wallet
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.ethereum.tokens :as tokens]
|
||||
[legacy.status-im.utils.currency :as currency]
|
||||
[legacy.status-im.wallet.utils :as wallet.utils]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.config :as config]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.money :as money]))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:balance
|
||||
:<- [:wallet-legacy]
|
||||
(fn [wallet [_ address]]
|
||||
(get-in wallet [:accounts address :balance])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:balance-default
|
||||
:<- [:wallet-legacy]
|
||||
:<- [:profile/wallet-accounts]
|
||||
(fn [[wallet accounts]]
|
||||
(get-in wallet [:accounts (:address (wallet.utils/get-default-account accounts)) :balance])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:balances
|
||||
:<- [:wallet-legacy]
|
||||
:<- [:multiaccount/visible-accounts]
|
||||
(fn [[wallet accounts]]
|
||||
(let [accounts (map :address accounts)]
|
||||
(map :balance (vals (select-keys (:accounts wallet) accounts))))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:empty-balances?
|
||||
:<- [:balances]
|
||||
(fn [balances]
|
||||
(every?
|
||||
(fn [balance]
|
||||
(every?
|
||||
(fn [^js asset]
|
||||
(or (nil? asset) (.isZero asset)))
|
||||
(vals balance)))
|
||||
balances)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:price
|
||||
:<- [:prices]
|
||||
(fn [prices [_ fsym tsym]]
|
||||
(get-in prices [fsym tsym])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:last-day
|
||||
:<- [:prices]
|
||||
(fn [prices [_ fsym tsym]]
|
||||
(get-in prices [fsym tsym :last-day])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy/settings-currency
|
||||
:<- [:profile/profile]
|
||||
(fn [settings]
|
||||
(or (get settings :currency) :usd)))
|
||||
|
||||
(defn get-balance-total-value
|
||||
[balance prices currency token->decimals]
|
||||
(reduce-kv (fn [acc sym value]
|
||||
(if-let [price (get-in prices [sym currency])]
|
||||
(+ acc
|
||||
(or (some-> (money/internal->formatted value sym (token->decimals sym))
|
||||
^js (money/crypto->fiat price)
|
||||
.toNumber)
|
||||
0))
|
||||
acc))
|
||||
0
|
||||
balance))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy/token->decimals
|
||||
:<- [:wallet-legacy/all-tokens]
|
||||
(fn [all-tokens]
|
||||
(into {} (map #(vector (:symbol %) (:decimals %)) (vals all-tokens)))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:portfolio-value
|
||||
:<- [:balances]
|
||||
:<- [:prices]
|
||||
:<- [:wallet-legacy/currency]
|
||||
:<- [:wallet-legacy/token->decimals]
|
||||
(fn [[balances prices currency token->decimals]]
|
||||
(if (and balances prices)
|
||||
(let [currency-key (-> currency :code keyword)
|
||||
balance-total-value (apply
|
||||
+
|
||||
(map #(get-balance-total-value % prices currency-key token->decimals)
|
||||
balances))]
|
||||
(if (pos? balance-total-value)
|
||||
(-> balance-total-value
|
||||
(money/with-precision 2)
|
||||
str
|
||||
(i18n/format-currency (:code currency)))
|
||||
"0"))
|
||||
"...")))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:account-portfolio-value
|
||||
(fn [[_ address] _]
|
||||
[(re-frame/subscribe [:balance address])
|
||||
(re-frame/subscribe [:prices])
|
||||
(re-frame/subscribe [:wallet-legacy/currency])
|
||||
(re-frame/subscribe [:wallet-legacy/token->decimals])])
|
||||
(fn [[balance prices currency token->decimals]]
|
||||
(if (and balance prices)
|
||||
(let [currency-key (-> currency :code keyword)
|
||||
balance-total-value (get-balance-total-value balance prices currency-key token->decimals)]
|
||||
(if (pos? balance-total-value)
|
||||
(-> balance-total-value
|
||||
(money/with-precision 2)
|
||||
str
|
||||
(i18n/format-currency (:code currency)))
|
||||
"0"))
|
||||
"...")))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy/sorted-tokens
|
||||
:<- [:wallet-legacy/all-tokens]
|
||||
(fn [all-tokens]
|
||||
(tokens/sorted-tokens-for all-tokens)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy/grouped-chain-tokens
|
||||
:<- [:wallet-legacy/sorted-tokens]
|
||||
:<- [:wallet-legacy/visible-tokens-symbols]
|
||||
(fn [[all-tokens visible-tokens]]
|
||||
(let [vt-set (set visible-tokens)]
|
||||
(group-by :custom?
|
||||
(map #(assoc % :checked? (boolean (get vt-set (keyword (:symbol %))))) all-tokens)))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy/fetching-tx-history?
|
||||
:<- [:wallet-legacy]
|
||||
(fn [wallet [_ address]]
|
||||
(get-in wallet [:fetching address :history?])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy/fetching-recent-tx-history?
|
||||
:<- [:wallet-legacy]
|
||||
(fn [wallet [_ address]]
|
||||
(get-in wallet [:fetching address :recent?])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy/tx-history-fetched?
|
||||
:<- [:wallet-legacy]
|
||||
(fn [wallet [_ address]]
|
||||
(get-in wallet [:fetching address :all-fetched?])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy/chain-explorer-link
|
||||
(fn [db [_ address]]
|
||||
(let [network (:networks/current-network db)
|
||||
link (get-in config/default-networks-by-id
|
||||
[network :chain-explorer-link])]
|
||||
(when link
|
||||
(str link address)))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy/error-message
|
||||
:<- [:wallet-legacy]
|
||||
(fn [wallet]
|
||||
(or (get-in wallet [:errors :balance-update])
|
||||
(get-in wallet [:errors :prices-update]))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy/visible-tokens-symbols
|
||||
:<- [:ethereum/chain-keyword]
|
||||
:<- [:profile/profile]
|
||||
(fn [[chain current-multiaccount]]
|
||||
(get-in current-multiaccount [:wallet-legacy/visible-tokens chain])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy/visible-assets
|
||||
:<- [:current-network]
|
||||
:<- [:wallet-legacy/visible-tokens-symbols]
|
||||
:<- [:wallet-legacy/sorted-tokens]
|
||||
(fn [[network visible-tokens-symbols all-tokens-sorted]]
|
||||
(conj (filter #(contains? visible-tokens-symbols (:symbol %)) all-tokens-sorted)
|
||||
(tokens/native-currency network))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy/visible-assets-with-amount
|
||||
(fn [[_ address] _]
|
||||
[(re-frame/subscribe [:balance address])
|
||||
(re-frame/subscribe [:wallet-legacy/visible-assets])])
|
||||
(fn [[balance visible-assets]]
|
||||
(map #(assoc % :amount (get balance (:symbol %))) visible-assets)))
|
||||
|
||||
(defn update-value
|
||||
[prices currency]
|
||||
(fn [{:keys [decimals amount] :as token}]
|
||||
(let [sym (:symbol token)
|
||||
currency-kw (-> currency :code keyword)
|
||||
price (get-in prices [sym currency-kw])]
|
||||
(assoc token
|
||||
:price price
|
||||
:value (when (and amount price)
|
||||
(-> (money/internal->formatted amount sym decimals)
|
||||
(money/crypto->fiat price)
|
||||
(money/with-precision 2)
|
||||
str
|
||||
(i18n/format-currency (:code currency))))))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy/visible-assets-with-values
|
||||
(fn [[_ address] _]
|
||||
[(re-frame/subscribe [:wallet-legacy/visible-assets-with-amount address])
|
||||
(re-frame/subscribe [:prices])
|
||||
(re-frame/subscribe [:wallet-legacy/currency])])
|
||||
(fn [[assets prices currency]]
|
||||
(let [{:keys [tokens nfts]} (group-by #(if (:nft? %) :nfts :tokens) assets)
|
||||
tokens-with-values (map (update-value prices currency) tokens)]
|
||||
{:tokens tokens-with-values
|
||||
:nfts nfts})))
|
||||
|
||||
(defn get-asset-amount
|
||||
[balances sym]
|
||||
(reduce #(if-let [^js bl (get %2 sym)]
|
||||
(.plus ^js (or ^js %1 ^js (money/bignumber 0)) bl)
|
||||
%1)
|
||||
nil
|
||||
balances))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy/all-visible-assets-with-amount
|
||||
:<- [:balances]
|
||||
:<- [:wallet-legacy/visible-assets]
|
||||
(fn [[balances visible-assets]]
|
||||
(map #(assoc % :amount (get-asset-amount balances (:symbol %))) visible-assets)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy/all-visible-assets-with-values
|
||||
:<- [:wallet-legacy/all-visible-assets-with-amount]
|
||||
:<- [:prices]
|
||||
:<- [:wallet-legacy/currency]
|
||||
(fn [[assets prices currency]]
|
||||
(let [{:keys [tokens nfts]} (group-by #(if (:nft? %) :nfts :tokens) assets)
|
||||
tokens-with-values (map (update-value prices currency) tokens)]
|
||||
{:tokens tokens-with-values
|
||||
:nfts nfts})))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy/transferrable-assets-with-amount
|
||||
(fn [[_ address]]
|
||||
(re-frame/subscribe [:wallet-legacy/visible-assets-with-amount address]))
|
||||
(fn [all-assets]
|
||||
(filter #(not (:nft? %)) all-assets)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy/currency
|
||||
:<- [:wallet-legacy/settings-currency]
|
||||
(fn [currency-id]
|
||||
(get currency/currencies currency-id (get currency/currencies :usd))))
|
||||
|
||||
(defn filter-recipient-favs
|
||||
[search-filter {:keys [name]}]
|
||||
(string/includes? (string/lower-case (str name)) search-filter))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy/favourites-filtered
|
||||
:<- [:wallet-legacy/favourites]
|
||||
:<- [:wallet-legacy/search-recipient-filter]
|
||||
(fn [[favs search-filter]]
|
||||
(let [favs (vals favs)]
|
||||
(if (string/blank? search-filter)
|
||||
favs
|
||||
(filter (partial filter-recipient-favs
|
||||
(string/lower-case search-filter))
|
||||
favs)))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy/collectible-collection
|
||||
:<- [:wallet-legacy/collectible-collections]
|
||||
(fn [all-collections [_ address]]
|
||||
(when address
|
||||
(let [all-collections (get all-collections (string/lower-case address) [])]
|
||||
(sort-by :name all-collections)))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy/collectible-assets-by-collection-and-address
|
||||
:<- [:wallet-legacy/collectible-assets]
|
||||
(fn [all-assets [_ address collectible-slug]]
|
||||
(get-in all-assets [address collectible-slug] [])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet-legacy/fetching-assets-by-collectible-slug
|
||||
:<- [:wallet-legacy/fetching-collection-assets]
|
||||
(fn [fetching-collection-assets [_ collectible-slug]]
|
||||
(get fetching-collection-assets collectible-slug false)))
|
||||
@@ -1,152 +0,0 @@
|
||||
(ns legacy.status-im.subs.wallet.wallet-test
|
||||
(:require
|
||||
[cljs.test :refer [deftest is testing]]
|
||||
[legacy.status-im.subs.wallet.transactions :as wallet.transactions]
|
||||
[legacy.status-im.subs.wallet.wallet :as wallet]
|
||||
[re-frame.db :as rf-db]
|
||||
[test-helpers.unit :as h]
|
||||
[utils.money :as money]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(def money-zero (money/bignumber 0))
|
||||
(def money-eth (money/bignumber 8000000000000000000))
|
||||
(def money-snt (money/bignumber 756000000000000000000))
|
||||
(def main-account-id "0x0Fbd")
|
||||
|
||||
(def accounts
|
||||
[{:address "0x0Fbd"
|
||||
:name "Main account"
|
||||
:hidden false
|
||||
:removed false}
|
||||
{:address "0x5B03"
|
||||
:name "Secondary account"
|
||||
:hidden false
|
||||
:removed false}])
|
||||
|
||||
(def wallet
|
||||
{:accounts {main-account-id
|
||||
{:balance {:ETH money-eth :SNT money-snt}
|
||||
:transactions {}
|
||||
:max-block 0}
|
||||
"0x5B03"
|
||||
{:balance {:ETH money-eth :SNT money-snt}
|
||||
:transactions {}
|
||||
:max-block 10}}})
|
||||
|
||||
(def prices
|
||||
{:ETH {:USD 1282.23}
|
||||
:SNT {:USD 0.0232}})
|
||||
|
||||
(def tokens
|
||||
{"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
|
||||
{:address "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
|
||||
:name "Ether"
|
||||
:symbol :ETH
|
||||
:decimals 18
|
||||
:chainId 1}
|
||||
"0x744d70fdbe2ba4cf95131626614a1763df805b9e"
|
||||
{:address "0x744d70fdbe2ba4cf95131626614a1763df805b9e"
|
||||
:name "Status Network Token"
|
||||
:symbol :SNT
|
||||
:decimals 18
|
||||
:chainId 1}})
|
||||
|
||||
(h/deftest-sub :balances
|
||||
[sub-name]
|
||||
(swap! rf-db/app-db assoc
|
||||
:profile/wallet-accounts accounts
|
||||
:wallet-legacy wallet)
|
||||
(is (= [{:ETH money-eth
|
||||
:SNT money-snt}
|
||||
{:ETH money-eth
|
||||
:SNT money-snt}]
|
||||
(rf/sub [sub-name]))))
|
||||
|
||||
(h/deftest-sub :wallet-legacy/token->decimals
|
||||
[sub-name]
|
||||
(swap! rf-db/app-db assoc :wallet-legacy/all-tokens tokens)
|
||||
(is (= {:SNT 18 :ETH 18}
|
||||
(rf/sub [sub-name]))))
|
||||
|
||||
(deftest get-balance-total-value-test
|
||||
(is (= 697.53
|
||||
(wallet/get-balance-total-value
|
||||
{:ETH (money/bignumber 1000000000000000000)
|
||||
:SNT (money/bignumber 100000000000000000000)
|
||||
:AST (money/bignumber 10000)}
|
||||
{:ETH {:USD 677.91}
|
||||
:SNT {:USD 0.1562}
|
||||
:AST {:USD 4}}
|
||||
:USD
|
||||
{:ETH 18
|
||||
:SNT 18
|
||||
:AST 4}))))
|
||||
|
||||
(h/deftest-sub :portfolio-value
|
||||
[sub-name]
|
||||
(testing "returns fallback value when balances and prices are not available"
|
||||
(is (= "..." (rf/sub [sub-name]))))
|
||||
|
||||
(testing "returns zero when balance is not positive"
|
||||
(let [empty-wallet {:accounts {main-account-id
|
||||
{:balance {:ETH money-zero
|
||||
:SNT money-zero}}}}]
|
||||
(swap! rf-db/app-db assoc
|
||||
:profile/wallet-accounts accounts
|
||||
:prices prices
|
||||
:wallet-legacy empty-wallet
|
||||
:wallet-legacy/all-tokens tokens)
|
||||
(is (= "0" (rf/sub [sub-name])))))
|
||||
|
||||
(testing "returns formatted value in the default USD currency"
|
||||
(swap! rf-db/app-db assoc
|
||||
:profile/wallet-accounts accounts
|
||||
:prices prices
|
||||
:wallet-legacy wallet
|
||||
:wallet-legacy/all-tokens tokens)
|
||||
(is (= "20,550.76" (rf/sub [sub-name])))))
|
||||
|
||||
(h/deftest-sub :account-portfolio-value
|
||||
[sub-name]
|
||||
(testing "returns fallback value when balances and prices are not available"
|
||||
(is (= "..." (rf/sub [sub-name]))))
|
||||
|
||||
(testing "returns zero when balance is not positive"
|
||||
(let [empty-wallet {:accounts {main-account-id
|
||||
{:balance {:ETH money-zero
|
||||
:SNT money-zero}}}}]
|
||||
(swap! rf-db/app-db assoc
|
||||
:profile/wallet-accounts accounts
|
||||
:prices prices
|
||||
:wallet-legacy empty-wallet
|
||||
:wallet-legacy/all-tokens tokens)
|
||||
(is (= "0" (rf/sub [sub-name main-account-id])))))
|
||||
|
||||
(testing "returns formatted value in the default USD currency"
|
||||
(swap! rf-db/app-db assoc
|
||||
:profile/wallet-accounts accounts
|
||||
:prices prices
|
||||
:wallet-legacy wallet
|
||||
:wallet-legacy/all-tokens tokens)
|
||||
(is (= "10,275.38" (rf/sub [sub-name main-account-id])))))
|
||||
|
||||
(def transactions
|
||||
[{:timestamp "1505912551000"}
|
||||
{:timestamp "1505764322000"}
|
||||
{:timestamp "1505750000000"}])
|
||||
|
||||
(def grouped-transactions
|
||||
'({:title "20 Sep"
|
||||
:key :20170920
|
||||
:data
|
||||
({:timestamp "1505912551000"})}
|
||||
{:title "18 Sep"
|
||||
:key :20170918
|
||||
:data
|
||||
({:timestamp "1505764322000"}
|
||||
{:timestamp "1505750000000"})}))
|
||||
|
||||
(deftest group-transactions-by-date
|
||||
(testing "Check if transactions are sorted by date"
|
||||
(is (= (wallet.transactions/group-transactions-by-date transactions)
|
||||
grouped-transactions))))
|
||||
@@ -1,13 +1,12 @@
|
||||
(ns legacy.status-im.ui.components.keyboard-avoid-presentation
|
||||
(:require
|
||||
[legacy.status-im.ui.components.react :as react]
|
||||
[react-native.utils :as rn.utils]
|
||||
[reagent.core :as reagent]))
|
||||
|
||||
(defn keyboard-avoiding-view
|
||||
[]
|
||||
(let [this (reagent/current-component)
|
||||
props (reagent/props this)
|
||||
children (reagent/children this)]
|
||||
[& argv]
|
||||
(let [[props children] (rn.utils/get-props-and-children argv)]
|
||||
(reagent/as-element
|
||||
(into [react/keyboard-avoiding-view
|
||||
(update props
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
[legacy.status-im.ui.components.spacing :as spacing]
|
||||
[legacy.status-im.ui.components.text :as text]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]))
|
||||
[react-native.utils :as rn.utils]))
|
||||
|
||||
(defn footer
|
||||
[]
|
||||
(let [this (reagent/current-component)
|
||||
[& argv]
|
||||
(let [[props children] (rn.utils/get-props-and-children argv)
|
||||
{:keys [color]
|
||||
:or {color :secondary}}
|
||||
(reagent/props this)]
|
||||
props]
|
||||
[rn/view
|
||||
{:style (merge (:base spacing/padding-horizontal)
|
||||
(:small spacing/padding-vertical))}
|
||||
(into [text/text {:color color}]
|
||||
(reagent/children this))]))
|
||||
children)]))
|
||||
|
||||
@@ -3,18 +3,18 @@
|
||||
[legacy.status-im.ui.components.spacing :as spacing]
|
||||
[legacy.status-im.ui.components.text :as text]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]))
|
||||
[react-native.utils :as rn.utils]))
|
||||
|
||||
(defn header
|
||||
[]
|
||||
(let [this (reagent/current-component)
|
||||
[& argv]
|
||||
(let [[props children] (rn.utils/get-props-and-children argv)
|
||||
{:keys [color]
|
||||
:or {color :secondary}}
|
||||
(reagent/props this)]
|
||||
props]
|
||||
[rn/view
|
||||
{:style (merge (:base spacing/padding-horizontal)
|
||||
(:x-tiny spacing/padding-vertical))}
|
||||
(into [text/text
|
||||
{:color color
|
||||
:style {:margin-top 10}}]
|
||||
(reagent/children this))]))
|
||||
children)]))
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
[legacy.status-im.ui.components.colors :as colors]
|
||||
[legacy.status-im.ui.components.typography :as typography]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]))
|
||||
[react-native.utils :as rn.utils]))
|
||||
|
||||
(defn text-style
|
||||
[{:keys [size align weight monospace color style]}]
|
||||
@@ -40,11 +40,9 @@
|
||||
style))
|
||||
|
||||
(defn text
|
||||
[]
|
||||
(let [this (reagent/current-component)
|
||||
props (reagent/props this)
|
||||
component rn/text]
|
||||
(into [component
|
||||
[& argv]
|
||||
(let [[props children] (rn.utils/get-props-and-children argv)]
|
||||
(into [rn/text
|
||||
(merge {:style (text-style props)}
|
||||
(dissoc props
|
||||
:style
|
||||
@@ -53,4 +51,4 @@
|
||||
:color
|
||||
:align
|
||||
:animated?))]
|
||||
(reagent/children this))))
|
||||
children)))
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
current-fleet
|
||||
webview-debug
|
||||
test-networks-enabled?
|
||||
is-sepolia-enabled?]}]
|
||||
is-goerli-enabled?]}]
|
||||
(keep
|
||||
identity
|
||||
[{:size :small
|
||||
@@ -112,13 +112,13 @@
|
||||
:accessory :switch
|
||||
:active test-networks-enabled?}
|
||||
{:size :small
|
||||
:title "Enable Sepolia as test network"
|
||||
:title "Enable Goerli as test network"
|
||||
:accessibility-label :enable-sepolia-as-test-network
|
||||
:container-margin-bottom 8
|
||||
:on-press
|
||||
#(re-frame/dispatch [:profile.settings/toggle-sepolia-test-network])
|
||||
#(re-frame/dispatch [:profile.settings/toggle-goerli-test-network])
|
||||
:accessory :switch
|
||||
:active is-sepolia-enabled?}
|
||||
:active is-goerli-enabled?}
|
||||
{:size :small
|
||||
:title (i18n/label :t/set-currency)
|
||||
:accessibility-label :wallet-change-currency
|
||||
@@ -139,7 +139,7 @@
|
||||
(views/defview advanced-settings
|
||||
[]
|
||||
(views/letsubs [test-networks-enabled? [:profile/test-networks-enabled?]
|
||||
is-sepolia-enabled? [:profile/is-sepolia-enabled?]
|
||||
is-goerli-enabled? [:profile/is-goerli-enabled?]
|
||||
light-client-enabled? [:profile/light-client-enabled?]
|
||||
webview-debug [:profile/webview-debug]
|
||||
network-name [:network-name]
|
||||
@@ -156,6 +156,6 @@
|
||||
:dev-mode? false
|
||||
:webview-debug webview-debug
|
||||
:test-networks-enabled? test-networks-enabled?
|
||||
:is-sepolia-enabled? is-sepolia-enabled?})
|
||||
:is-goerli-enabled? is-goerli-enabled?})
|
||||
:key-fn (fn [_ i] (str i))
|
||||
:render-fn render-item}]))
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
[legacy.status-im.ui.screens.browser.accounts :as accounts]
|
||||
[legacy.status-im.ui.screens.browser.empty-tab.styles :as styles]
|
||||
[legacy.status-im.ui.screens.browser.views :as browser]
|
||||
[legacy.status-im.ui.screens.wallet.components.views :as components]
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as reagent]
|
||||
[utils.i18n :as i18n]
|
||||
@@ -144,7 +143,7 @@
|
||||
:container-style styles/input-container-style
|
||||
:accessibility-label :dapp-url-input
|
||||
:return-key-type :go}]
|
||||
[components/separator-dark]
|
||||
[react/view {:style {:height 1 :background-color (colors/alpha colors/black 0.1)}}]
|
||||
[list/flat-list
|
||||
{:header [list-header (empty? bookmarks)]
|
||||
:data bookmarks
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
[legacy.status-im.ui.components.icons.icons :as icons]
|
||||
[legacy.status-im.ui.components.list.item :as list.item]
|
||||
[legacy.status-im.ui.components.react :as react]
|
||||
[legacy.status-im.ui.screens.wallet.components.views :as components]
|
||||
[legacy.status-im.utils.utils :as utils]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.constants :as constants]
|
||||
@@ -32,7 +31,7 @@
|
||||
:subtitle (utils/get-shortened-checksum-address (:address account))
|
||||
:accessory [icons/icon :main-icons/check {:color colors/gray}]}]
|
||||
[react/view {:padding-vertical 8}
|
||||
[components/separator]]
|
||||
[react/view {:style {:height 1 :background-color (colors/alpha colors/black 0.1)}}]]
|
||||
[list.item/list-item
|
||||
{:theme :negative
|
||||
:title (i18n/label :t/revoke-access)
|
||||
@@ -86,7 +85,7 @@
|
||||
(js/setTimeout
|
||||
#(browser/share-link url)
|
||||
200))}]
|
||||
[components/separator]])
|
||||
[react/view {:style {:height 1 :background-color (colors/alpha colors/black 0.1)}}]])
|
||||
(if connected?
|
||||
[list.item/list-item
|
||||
{:icon [chat-icon/custom-icon-view-list (:name account) (:color account)]
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
[legacy.status-im.ui.components.plus-button :as components.plus-button]
|
||||
[legacy.status-im.ui.components.react :as react]
|
||||
[legacy.status-im.ui.components.topbar :as topbar]
|
||||
[legacy.status-im.ui.screens.wallet.components.views :as components]
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as reagent]
|
||||
[utils.i18n :as i18n]
|
||||
@@ -67,7 +66,7 @@
|
||||
:on-press #(do (re-frame/dispatch [:browser.ui/clear-all-browsers-pressed])
|
||||
(re-frame/dispatch [:browser.ui/open-empty-tab]))}]
|
||||
:title (i18n/label :t/tabs)}]
|
||||
[components/separator-dark]
|
||||
[react/view {:style {:height 1 :background-color (colors/alpha colors/black 0.1)}}]
|
||||
[list/flat-list
|
||||
{:data (conj browsers
|
||||
{:empty-tab true
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
[legacy.status-im.ui.screens.browser.permissions.views :as permissions.views]
|
||||
[legacy.status-im.ui.screens.browser.site-blocked.views :as site-blocked.views]
|
||||
[legacy.status-im.ui.screens.browser.styles :as styles]
|
||||
[legacy.status-im.ui.screens.wallet.components.views :as components]
|
||||
[legacy.status-im.utils.js-resources :as js-res]
|
||||
[re-frame.core :as re-frame]
|
||||
[react-native.permissions :as components.permissions]
|
||||
@@ -258,7 +257,7 @@
|
||||
url-original (browser/get-current-url current-browser)]
|
||||
[react/view {:style styles/browser}
|
||||
[toolbar-content url url-original secure? url-editing? unsafe?]
|
||||
[components/separator-dark]
|
||||
[react/view {:style {:height 1 :background-color (colors/alpha colors/black 0.1)}}]
|
||||
[react/view
|
||||
(when loading?
|
||||
[connectivity/loading-indicator-anim window-width])]
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
[legacy.status-im.ui.components.topbar :as topbar]
|
||||
[legacy.status-im.ui.screens.chat.utils :as chat.utils]
|
||||
[legacy.status-im.ui.screens.profile.components.views :as profile.components]
|
||||
[legacy.status-im.ui.screens.wallet.send.sheets :as sheets]
|
||||
[legacy.status-im.utils.utils :as utils]
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as reagent]
|
||||
@@ -292,9 +291,7 @@
|
||||
:title (:name account)
|
||||
:subtitle (utils/get-shortened-checksum-address (:address account))
|
||||
:chevron true
|
||||
:on-press #(re-frame/dispatch [:bottom-sheet/show-sheet-old
|
||||
{:content (fn [] [sheets/accounts-list :from
|
||||
::ens/change-address])}])}]))
|
||||
:on-press #(js/alert "funcitonality no longer supported")}]))
|
||||
|
||||
(defn- registration
|
||||
[checked contract address public-key]
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
[legacy.status-im.ui.screens.reset-password.views :as reset-password.views]
|
||||
[legacy.status-im.ui.screens.signing.sheets :as signing-sheets]
|
||||
[legacy.status-im.ui.screens.signing.views :as signing]
|
||||
[legacy.status-im.ui.screens.wallet.request.views :as request]
|
||||
[legacy.status-im.ui.screens.wallet.signing-phrase.views :as signing-phrase]
|
||||
[re-frame.core :as re-frame]
|
||||
[react-native.platform :as platform]
|
||||
[reagent.core :as reagent]))
|
||||
@@ -131,12 +129,6 @@
|
||||
(vector? view)
|
||||
view
|
||||
|
||||
(= :signing-phrase view)
|
||||
[signing-phrase/signing-phrase]
|
||||
|
||||
(= :share-account view)
|
||||
[request/share-address]
|
||||
|
||||
(= :share-chat-key view)
|
||||
[profile.user/share-chat-key]
|
||||
|
||||
|
||||
@@ -49,19 +49,6 @@
|
||||
[legacy.status-im.ui.screens.sync-settings.views :as sync-settings]
|
||||
[legacy.status-im.ui.screens.wakuv2-settings.edit-node.views :as edit-wakuv2-node]
|
||||
[legacy.status-im.ui.screens.wakuv2-settings.views :as wakuv2-settings]
|
||||
[legacy.status-im.ui.screens.wallet.account-settings.views :as account-settings]
|
||||
[legacy.status-im.ui.screens.wallet.account.views :as wallet.account]
|
||||
[legacy.status-im.ui.screens.wallet.accounts-manage.views :as accounts-manage]
|
||||
[legacy.status-im.ui.screens.wallet.accounts.views :as wallet.accounts]
|
||||
[legacy.status-im.ui.screens.wallet.add-new.views :as add-account]
|
||||
[legacy.status-im.ui.screens.wallet.buy-crypto.views :as wallet.buy-crypto]
|
||||
[legacy.status-im.ui.screens.wallet.collectibles.views :as wallet.collectibles]
|
||||
[legacy.status-im.ui.screens.wallet.custom-tokens.views :as custom-tokens]
|
||||
[legacy.status-im.ui.screens.wallet.recipient.views :as recipient]
|
||||
[legacy.status-im.ui.screens.wallet.send.views :as wallet.send]
|
||||
[legacy.status-im.ui.screens.wallet.settings.views :as wallet-settings]
|
||||
[legacy.status-im.ui.screens.wallet.swap.views :as wallet.swap]
|
||||
[legacy.status-im.ui.screens.wallet.transactions.views :as wallet-transactions]
|
||||
[status-im.contexts.chat.group-details.view :as group-details]
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
@@ -106,86 +93,11 @@
|
||||
;;TODO custom subtitle
|
||||
:component group-chat/new-group}
|
||||
|
||||
;;WALLET
|
||||
|
||||
{:name :wallet-legacy
|
||||
:on-focus [:wallet-legacy/tab-opened]
|
||||
;;TODO wallet redesign
|
||||
;;:options {:statusBar {:backgroundColor quo.colors/neutral-5}}
|
||||
:component wallet.accounts/accounts-overview-old}
|
||||
{:name :wallet-account
|
||||
;;TODO dynamic titleaccounts-overview
|
||||
:options {:insets {:top? true}}
|
||||
:component wallet.account/account}
|
||||
{:name :add-new-account
|
||||
;;TODO dynamic title
|
||||
:options {:insets {:top? true :bottom? true}}
|
||||
:component add-account/add-account-view}
|
||||
{:name :add-new-account-pin
|
||||
;;TODO dynamic title
|
||||
:options {:insets {:top? true}}
|
||||
:component add-account/pin}
|
||||
{:name :account-settings
|
||||
;;TODO dynamic title
|
||||
:options {:insets {:top? true}}
|
||||
:component account-settings/account-settings}
|
||||
{:name :wallet-transaction-details
|
||||
;;TODO dynamic title
|
||||
:options {:insets {:top? true}}
|
||||
:component wallet-transactions/transaction-details}
|
||||
{:name :wallet-settings-assets
|
||||
;;TODO dynamic title
|
||||
:options {:insets {:top? true}}
|
||||
:component wallet-settings/manage-assets}
|
||||
{:name :wallet-add-custom-token
|
||||
:on-focus [:wallet-legacy/wallet-add-custom-token]
|
||||
:options {:topBar {:title {:text (i18n/label :t/add-custom-token)}}
|
||||
:insets {:top? true}}
|
||||
:component custom-tokens/add-custom-token}
|
||||
{:name :wallet-custom-token-details
|
||||
;;TODO dynamic title
|
||||
:options {:insets {:top? true}}
|
||||
:component custom-tokens/custom-token-details}
|
||||
{:name :currency-settings
|
||||
:options {:topBar {:title {:text (i18n/label :t/main-currency)}}
|
||||
:insets {:top? true}}
|
||||
:component currency-settings/currency-settings}
|
||||
|
||||
{:name :manage-accounts
|
||||
:options {:topBar {:title {:text (i18n/label :t/wallet-manage-accounts)}}
|
||||
:insets {:top? true}}
|
||||
:component accounts-manage/manage}
|
||||
|
||||
{:name :token-swap
|
||||
;;TODO dynamic title
|
||||
:options {:insets {:top? true}}
|
||||
:component wallet.swap/swap}
|
||||
|
||||
{:name :token-swap-advanced-nonce
|
||||
:options {:topBar {:title {:text (i18n/label :t/nonce)}}
|
||||
:insets {:top? true}}
|
||||
:component wallet.swap/nonce-modal}
|
||||
|
||||
{:name :token-swap-advanced-approve-token
|
||||
:options {:topBar {:title {:text (i18n/label :t/approve-token)}}
|
||||
:insets {:top? true}}
|
||||
:component wallet.swap/approve-token-modal}
|
||||
|
||||
{:name :token-swap-advanced-transaction-fee
|
||||
:options {:topBar {:title {:text (i18n/label :t/transaction-fee)}}
|
||||
:insets {:top? true}}
|
||||
:component wallet.swap/transaction-fee-modal}
|
||||
|
||||
{:name :token-swap-advanced-swap-details
|
||||
:options {:topBar {:title {:text (i18n/label :t/swap-details)}}
|
||||
:insets {:top? true}}
|
||||
:component wallet.swap/swap-details-modal}
|
||||
|
||||
{:name :swap-asset-selector
|
||||
;;TODO dynamic title
|
||||
:options {:insets {:top? true}}
|
||||
:component wallet.swap/asset-selector}
|
||||
|
||||
;;PROFILE
|
||||
|
||||
{:name :my-profile
|
||||
@@ -404,20 +316,6 @@
|
||||
:top? true}}
|
||||
:component communities.invite/legacy-invite}
|
||||
|
||||
;[Wallet] Recipient
|
||||
{:name :recipient
|
||||
;;TODO accessories
|
||||
:options {:insets {:bottom? true
|
||||
:top? true}}
|
||||
:component recipient/recipient}
|
||||
|
||||
;[Wallet] New favourite
|
||||
{:name :new-favourite
|
||||
:options {:topBar {:title {:text (i18n/label :t/new-favourite)}}
|
||||
:insets {:bottom? true
|
||||
:top? true}}
|
||||
:component recipient/new-favourite}
|
||||
|
||||
;QR Scanner
|
||||
{:name :qr-scanner
|
||||
;;TODO custom topbar
|
||||
@@ -438,44 +336,6 @@
|
||||
:top? true}}
|
||||
:component notifications-settings/notifications-settings}
|
||||
|
||||
;[Wallet] Prepare Transaction
|
||||
{:name :prepare-send-transaction
|
||||
:on-dissmiss [:wallet-legacy/cancel-transaction-command]
|
||||
:options {:topBar {:title {:text (i18n/label :t/send-transaction)}}
|
||||
:swipeToDismiss false
|
||||
:hardwareBackButton {:dismissModalOnPress false}
|
||||
:insets {:bottom? true
|
||||
:top? true}}
|
||||
:component wallet.send/prepare-send-transaction}
|
||||
|
||||
;[Wallet] Request Transaction
|
||||
{:name :request-transaction
|
||||
:on-dissmiss [:wallet-legacy/cancel-transaction-command]
|
||||
:options {:topBar {:title {:text (i18n/label :t/request-transaction)}}
|
||||
:swipeToDismiss false
|
||||
:hardwareBackButton {:dismissModalOnPress false}
|
||||
:insets {:bottom? true
|
||||
:top? true}}
|
||||
:component wallet.send/request-transaction}
|
||||
|
||||
;[Wallet] Buy crypto
|
||||
{:name :buy-crypto
|
||||
:insets {:bottom? true}
|
||||
:component wallet.buy-crypto/container}
|
||||
|
||||
;[Wallet] Buy crypto website
|
||||
{:name :buy-crypto-website
|
||||
;;TODO subtitle
|
||||
:options {:insets {:bottom? true
|
||||
:top? true}}
|
||||
:component wallet.buy-crypto/website}
|
||||
|
||||
{:name :nft-details
|
||||
;;TODO dynamic title
|
||||
:options {:insets {:bottom? true
|
||||
:top? true}}
|
||||
:component wallet.collectibles/nft-details-modal}
|
||||
|
||||
;[Browser] New bookmark
|
||||
{:name :new-bookmark
|
||||
;;TODO dynamic title
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
(:require-macros [legacy.status-im.utils.views :as views])
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.ethereum.tokens :as tokens]
|
||||
[legacy.status-im.react-native.resources :as resources]
|
||||
[legacy.status-im.signing.eip1559 :as eip1559]
|
||||
[legacy.status-im.ui.components.bottom-panel.views :as bottom-panel]
|
||||
@@ -15,10 +14,8 @@
|
||||
[legacy.status-im.ui.components.react :as react]
|
||||
[legacy.status-im.ui.screens.signing.sheets :as sheets]
|
||||
[legacy.status-im.ui.screens.signing.styles :as styles]
|
||||
[legacy.status-im.ui.screens.wallet.components.views :as wallet.components]
|
||||
[legacy.status-im.utils.deprecated-types :as types]
|
||||
[legacy.status-im.utils.utils :as utils]
|
||||
[legacy.status-im.wallet.utils :as wallet.utils]
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.contexts.profile.utils :as profile.utils]
|
||||
@@ -57,11 +54,7 @@
|
||||
:style {:margin-right 8}}
|
||||
display-symbol]
|
||||
(if icon
|
||||
[wallet.components/token-icon
|
||||
(assoc icon
|
||||
:style {:background-color colors/gray-lighter
|
||||
:border-radius 16}
|
||||
:image-style {:width 24 :height 24})]
|
||||
[react/view]
|
||||
[chat-icon/custom-icon-view-list (:name token) color 32])]}]
|
||||
[separator]]))
|
||||
|
||||
@@ -328,7 +321,6 @@
|
||||
[{:keys [from contact amount token cancel?] :as tx}]
|
||||
(views/letsubs [fee [:signing/fee]
|
||||
sign [:signing/sign]
|
||||
chain [:current-network]
|
||||
{:keys [amount-error gas-error gas-error-state insufficient-balalce?]}
|
||||
[:signing/amount-errors (:address from)]
|
||||
keycard-multiaccount? [:keycard-multiaccount?]
|
||||
@@ -337,8 +329,8 @@
|
||||
mainnet? [:mainnet?]
|
||||
prices-loading? [:prices-loading?]
|
||||
management-enabled? [:wallet-legacy/transactions-management-enabled?]]
|
||||
(let [display-symbol (wallet.utils/display-symbol token)
|
||||
fee-display-symbol (wallet.utils/display-symbol (tokens/native-currency chain))]
|
||||
(let [display-symbol nil
|
||||
fee-display-symbol nil]
|
||||
[react/view (styles/sheet)
|
||||
[header sign tx display-symbol fee fee-display-symbol]
|
||||
[separator]
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
(or owned free)
|
||||
(re-frame/dispatch [:stickers/install-pack id])
|
||||
not-enough-snt? nil
|
||||
:else (re-frame/dispatch [:stickers/buy-pack id]))}
|
||||
:else (fn [] (js/alert "feature no longer supported")))}
|
||||
[react/view (styles/price-badge (and (not (or owned free)) not-enough-snt?))
|
||||
(when (and (not free) (not owned))
|
||||
[icons/tiny-icon :tiny-icons/tiny-snt
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.wallet.account.styles
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.ui.components.animation :as animation]
|
||||
[legacy.status-im.ui.components.colors :as colors]))
|
||||
|
||||
(defn card
|
||||
[window-width color]
|
||||
{:width (- window-width 30)
|
||||
:height 161
|
||||
:background-color (if (string/blank? color)
|
||||
colors/blue
|
||||
color)
|
||||
:shadow-offset {:width 0 :height 2}
|
||||
:shadow-radius 8
|
||||
:shadow-opacity 1
|
||||
:shadow-color (if (colors/dark?)
|
||||
"rgba(0, 0, 0, 0.75)"
|
||||
"rgba(0, 9, 26, 0.12)")
|
||||
:elevation 2
|
||||
:border-radius 8
|
||||
:justify-content :space-between})
|
||||
|
||||
(defn divider
|
||||
[]
|
||||
{:height 52
|
||||
:width 1
|
||||
:background-color colors/black-transparent-20
|
||||
:shadow-offset {:width 0 :height 2}
|
||||
:shadow-radius 8
|
||||
:shadow-opacity 1
|
||||
:shadow-color (if (colors/dark?)
|
||||
"rgba(0, 0, 0, 0.75)"
|
||||
"rgba(0, 9, 26, 0.12)")})
|
||||
|
||||
(defn bottom-send-recv-buttons-raise
|
||||
[anim-y]
|
||||
(animation/timing
|
||||
anim-y
|
||||
{:toValue 0
|
||||
:duration 200
|
||||
:easing (.-ease ^js animation/easing)
|
||||
:useNativeDriver true}))
|
||||
|
||||
(defn bottom-send-recv-buttons-lower
|
||||
[anim-y y]
|
||||
(animation/timing
|
||||
anim-y
|
||||
{:toValue y
|
||||
:duration 200
|
||||
:easing (.-ease ^js animation/easing)
|
||||
:useNativeDriver true}))
|
||||
|
||||
(def round-action-button
|
||||
{:background-color colors/blue
|
||||
:height 44
|
||||
:flex 1
|
||||
:justify-content :center
|
||||
:align-items :center
|
||||
:width 44
|
||||
:border-radius 44})
|
||||
|
||||
(def top-actions
|
||||
{:flex 1
|
||||
:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:width "60%"
|
||||
:align-self :center})
|
||||
@@ -1,363 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.wallet.account.views
|
||||
(:require
|
||||
[legacy.status-im.ui.components.animation :as animation]
|
||||
[legacy.status-im.ui.components.colors :as colors]
|
||||
[legacy.status-im.ui.components.core :as components.core]
|
||||
[legacy.status-im.ui.components.icons.icons :as icons]
|
||||
[legacy.status-im.ui.components.react :as react]
|
||||
[legacy.status-im.ui.components.spacing :as spacing]
|
||||
[legacy.status-im.ui.components.tabs :as tabs]
|
||||
[legacy.status-im.ui.components.topbar :as topbar]
|
||||
[legacy.status-im.ui.screens.wallet.account.styles :as styles]
|
||||
[legacy.status-im.ui.screens.wallet.accounts.common :as common]
|
||||
[legacy.status-im.ui.screens.wallet.accounts.sheets :as sheets]
|
||||
[legacy.status-im.ui.screens.wallet.buy-crypto.views :as buy-crypto]
|
||||
[legacy.status-im.ui.screens.wallet.collectibles.views :as collectibles.views]
|
||||
[legacy.status-im.ui.screens.wallet.transactions.views :as history]
|
||||
[quo.core :as quo]
|
||||
[quo.foundations.colors :as quo.colors]
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.config :as config]
|
||||
[utils.address :as address]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf])
|
||||
(:require-macros [legacy.status-im.utils.views :as views]))
|
||||
|
||||
(def state (reagent/atom {:tab :assets}))
|
||||
(def selected-tab (reagent/atom :tokens))
|
||||
|
||||
(defn button
|
||||
[label icon color handler]
|
||||
[react/touchable-highlight {:on-press handler :style {:flex 1}}
|
||||
[react/view {:flex 1 :align-items :center :justify-content :center}
|
||||
[react/view {:flex-direction :row :align-items :center}
|
||||
[icons/icon icon {:color color}]
|
||||
[react/text {:style {:margin-left 8 :color color}} label]]]])
|
||||
|
||||
(def button-group-height 52)
|
||||
|
||||
(views/defview account-card
|
||||
[{:keys [address color type] :as account}]
|
||||
(views/letsubs [currency [:wallet-legacy/currency]
|
||||
portfolio-value [:account-portfolio-value address]
|
||||
window-width [:dimensions/window-width]
|
||||
prices-loading? [:prices-loading?]]
|
||||
[react/view {:style (styles/card window-width color)}
|
||||
[react/view {:padding 16 :padding-bottom 12 :flex 1 :justify-content :space-between}
|
||||
[react/view {:style {:flex-direction :row}}
|
||||
(if prices-loading?
|
||||
[react/small-loading-indicator :colors/white-persist]
|
||||
[react/text {:style {:font-size 32 :color colors/white-persist :font-weight "600"}}
|
||||
portfolio-value])
|
||||
[react/text {:style {:font-size 32 :color colors/white-transparent-persist :font-weight "600"}}
|
||||
(str " " (:code currency))]]
|
||||
[components.core/text
|
||||
{:number-of-lines 1
|
||||
:ellipsize-mode :middle
|
||||
:monospace true
|
||||
:size :small
|
||||
:style {:width (/ window-width 3)
|
||||
:line-height 22
|
||||
:color colors/white-transparent-70-persist}}
|
||||
(address/normalized-hex address)]]
|
||||
[react/view {:position :absolute :top 12 :right 12}
|
||||
[react/touchable-highlight {:on-press #(re-frame/dispatch [:wallet-legacy/share-popover address])}
|
||||
[icons/icon :main-icons/share
|
||||
{:color colors/white-persist
|
||||
:accessibility-label :share-wallet-address-icon}]]]
|
||||
[react/view
|
||||
{:height button-group-height
|
||||
:background-color colors/black-transparent-20
|
||||
:border-bottom-right-radius 8
|
||||
:border-bottom-left-radius 8
|
||||
:flex-direction :row}
|
||||
(if (= type :watch)
|
||||
[react/view {:flex 1 :align-items :center :justify-content :center}
|
||||
[react/text {:style {:margin-left 8 :color colors/white-persist}}
|
||||
(i18n/label :t/watch-only)]]
|
||||
[button
|
||||
(i18n/label :t/wallet-send)
|
||||
:main-icons/send
|
||||
colors/white-persist
|
||||
#(re-frame/dispatch [:wallet-legacy/prepare-transaction-from-wallet account])])
|
||||
[react/view {:style (styles/divider)}]
|
||||
[button
|
||||
(i18n/label :t/receive)
|
||||
:main-icons/receive
|
||||
colors/white-persist
|
||||
#(re-frame/dispatch [:wallet-legacy/share-popover address])]]]))
|
||||
|
||||
(views/defview transactions
|
||||
[address]
|
||||
(views/letsubs [data [:wallet-legacy.transactions.history/screen address]]
|
||||
[history/history-list data address]))
|
||||
|
||||
(defn opensea-link
|
||||
[address]
|
||||
[react/touchable-highlight
|
||||
{:on-press #(re-frame/dispatch [:browser.ui/open-url (str "https://opensea.io/" address)])}
|
||||
[react/view
|
||||
{:style {:flex 1
|
||||
:padding-horizontal 14
|
||||
:flex-direction :row
|
||||
:align-items :center
|
||||
:background-color colors/blue-light
|
||||
:height 52}}
|
||||
[icons/tiny-icon
|
||||
:tiny-icons/tiny-external
|
||||
{:color colors/blue
|
||||
:container-style {:margin-right 5}}]
|
||||
[react/text
|
||||
{:style {:color colors/blue}}
|
||||
(i18n/label :t/check-on-opensea)]]])
|
||||
|
||||
(views/defview assets-and-collections-new
|
||||
[address]
|
||||
(views/letsubs [{:keys [tokens]} [:wallet-legacy/visible-assets-with-values address]
|
||||
currency [:wallet-legacy/currency]
|
||||
opensea-enabled? [:opensea-enabled?]
|
||||
collectible-collection [:wallet-legacy/collectible-collection address]]
|
||||
;ethereum-network? [:ethereum-network?]]
|
||||
(let [tab @selected-tab]
|
||||
[react/view {:flex 1}
|
||||
[react/view {:padding-horizontal 20 :padding-bottom 20}
|
||||
[quo/tabs
|
||||
{:size 24
|
||||
:on-change #(reset! selected-tab %)
|
||||
:default-active :tokens
|
||||
:data [{:id :tokens :label "Tokens"}
|
||||
{:id :nft :label "NFTs"}
|
||||
{:id :activity :label "Activity"}]}]]
|
||||
(cond
|
||||
(= tab :tokens)
|
||||
[react/scroll-view
|
||||
(for [item tokens]
|
||||
^{:key (:name item)}
|
||||
[common/render-asset-new item nil nil (:code currency)])]
|
||||
(= tab :nft)
|
||||
[:<>
|
||||
[opensea-link address]
|
||||
;; Hide collectibles behind a feature flag
|
||||
(when config/collectibles-enabled?
|
||||
(cond
|
||||
(not opensea-enabled?)
|
||||
[collectibles.views/enable-opensea-view]
|
||||
|
||||
(and opensea-enabled? (seq collectible-collection))
|
||||
[collectibles.views/nft-collections address]
|
||||
|
||||
:else
|
||||
[react/view {:align-items :center :margin-top 32}
|
||||
[react/text {:style {:color colors/gray}}
|
||||
(i18n/label :t/no-collectibles)]]))]
|
||||
(= tab :activity)
|
||||
[transactions address])])))
|
||||
|
||||
(views/defview bottom-send-recv-buttons
|
||||
[{:keys [address type] :as account} anim-y]
|
||||
[react/animated-view
|
||||
{:style {:background-color colors/white
|
||||
:bottom 0
|
||||
:flex-direction :row
|
||||
:height button-group-height
|
||||
:position :absolute
|
||||
:shadow-offset {:width 0 :height 1}
|
||||
:shadow-opacity 0.75
|
||||
:shadow-radius 1
|
||||
:transform [{:translateY anim-y}]
|
||||
:width "100%"}}
|
||||
(if (= type :watch)
|
||||
[react/view {:flex 1 :align-items :center :justify-content :center}
|
||||
[react/text {:style {:margin-left 8 :color colors/blue-persist}}
|
||||
(i18n/label :t/watch-only)]]
|
||||
[button
|
||||
(i18n/label :t/wallet-send)
|
||||
:main-icons/send
|
||||
colors/blue-persist
|
||||
#(re-frame/dispatch [:wallet-legacy/prepare-transaction-from-wallet account])])
|
||||
[button
|
||||
(i18n/label :t/receive)
|
||||
:main-icons/receive
|
||||
colors/blue-persist
|
||||
#(re-frame/dispatch [:wallet-legacy/share-popover address])]])
|
||||
|
||||
(defn anim-listener
|
||||
[anim-y scroll-y]
|
||||
(let [to-show (atom false)]
|
||||
(animation/add-listener
|
||||
scroll-y
|
||||
(fn [anim]
|
||||
(let [y-trigger 149]
|
||||
(cond
|
||||
(and (>= (.-value anim) y-trigger) (not @to-show))
|
||||
(animation/start
|
||||
(styles/bottom-send-recv-buttons-raise anim-y)
|
||||
#(reset! to-show true))
|
||||
|
||||
(and (< (.-value anim) y-trigger) @to-show)
|
||||
(animation/start
|
||||
(styles/bottom-send-recv-buttons-lower anim-y button-group-height)
|
||||
#(reset! to-show false))))))))
|
||||
|
||||
(defn round-action-button
|
||||
[{:keys [icon title on-press]}]
|
||||
[react/view
|
||||
{:style {:flex 1
|
||||
:align-items :center
|
||||
:margin-vertical (:large spacing/spacing)}}
|
||||
[react/touchable-opacity
|
||||
{:style styles/round-action-button
|
||||
:on-press on-press}
|
||||
(icons/icon icon {:color colors/white})]
|
||||
[components.core/text
|
||||
{:color :secondary
|
||||
:size :small
|
||||
:style {:margin-top (:tiny spacing/spacing)}}
|
||||
title]])
|
||||
|
||||
(defn top-actions
|
||||
[]
|
||||
[react/view {:style styles/top-actions}
|
||||
[round-action-button
|
||||
{:icon :main-icons/add
|
||||
:title (i18n/label :t/buy-crypto)
|
||||
:on-press #(re-frame/dispatch [:buy-crypto.ui/open-screen])}]
|
||||
[round-action-button
|
||||
{:icon :main-icons/change
|
||||
:title (i18n/label :t/swap)
|
||||
:on-press #(re-frame/dispatch [:open-modal :token-swap])}]])
|
||||
|
||||
(views/defview assets-and-collections
|
||||
[address]
|
||||
(views/letsubs [{:keys [tokens]} [:wallet-legacy/visible-assets-with-values address]
|
||||
currency [:wallet-legacy/currency]
|
||||
opensea-enabled? [:opensea-enabled?]
|
||||
collectible-collection [:wallet-legacy/collectible-collection address]
|
||||
ethereum-network? [:ethereum-network?]]
|
||||
(let [{:keys [tab]} @state]
|
||||
[react/view {:flex 1}
|
||||
[react/view {:flex-direction :row :margin-bottom 8 :padding-horizontal 4}
|
||||
[tabs/tab-title state :assets (i18n/label :t/wallet-assets) (= tab :assets)]
|
||||
(when ethereum-network?
|
||||
[tabs/tab-title state :nft (i18n/label :t/wallet-collectibles) (= tab :nft)])
|
||||
[tabs/tab-title state :history (i18n/label :t/history) (= tab :history)]]
|
||||
[quo/separator {:style {:margin-top -8}}]
|
||||
(cond
|
||||
(= tab :assets)
|
||||
[:<>
|
||||
(for [item tokens]
|
||||
^{:key (:name item)}
|
||||
[common/render-asset item nil nil (:code currency)])]
|
||||
(= tab :nft)
|
||||
[:<>
|
||||
[opensea-link address]
|
||||
;; Hide collectibles behind a feature flag
|
||||
(when config/collectibles-enabled?
|
||||
(cond
|
||||
(not opensea-enabled?)
|
||||
[collectibles.views/enable-opensea-view]
|
||||
|
||||
(and opensea-enabled? (seq collectible-collection))
|
||||
[collectibles.views/nft-collections address]
|
||||
|
||||
:else
|
||||
[react/view {:align-items :center :margin-top 32}
|
||||
[react/text {:style {:color colors/gray}}
|
||||
(i18n/label :t/no-collectibles)]]))]
|
||||
(= tab :history)
|
||||
[transactions address])])))
|
||||
|
||||
(defn account-new
|
||||
[selected-account]
|
||||
(let [;{:keys [name address] :as account} (rf/sub [:account-by-address selected-account])
|
||||
currency (rf/sub [:wallet-legacy/currency])
|
||||
portfolio-value (rf/sub [:account-portfolio-value selected-account])
|
||||
width (rf/sub [:dimensions/window-width])
|
||||
button-width (/ (- width 40 (* 2 12)) 3)]
|
||||
;fetching-error (rf/sub [:wallet-legacy/fetching-error])]
|
||||
[react/view
|
||||
{:flex 1
|
||||
:background-color (quo.colors/theme-colors quo.colors/white quo.colors/neutral-90)
|
||||
:border-top-left-radius 20
|
||||
:border-top-right-radius 20
|
||||
:elevation 4
|
||||
:shadow-opacity 1
|
||||
:shadow-radius 20
|
||||
:shadow-color (:shadow-01 @colors/theme)
|
||||
:shadow-offset {:width 0 :height 4}}
|
||||
[react/view {:padding 20}
|
||||
[quo/text {:size :heading-2 :weight :semi-bold} (str portfolio-value " " (:code currency))]]
|
||||
[react/view
|
||||
[react/scroll-view {:horizontal true :margin-bottom 32 :showsHorizontalScrollIndicator false}
|
||||
[react/view {:width 20}]
|
||||
[quo/button {:size 56 :width button-width :above :i/placeholder} "Buy"]
|
||||
[react/view {:width 12}]
|
||||
[quo/button {:size 56 :width button-width :type :secondary :above :i/placeholder} "Send"]
|
||||
[react/view {:width 12}]
|
||||
[quo/button {:size 56 :width button-width :type :secondary :above :i/placeholder}
|
||||
"Receive"]
|
||||
[react/view {:width 12}]
|
||||
[quo/button {:size 56 :width button-width :type :secondary :above :i/placeholder} "Swap"]
|
||||
[react/view {:width 20}]]]
|
||||
[assets-and-collections-new selected-account]]))
|
||||
|
||||
(views/defview account
|
||||
[]
|
||||
(views/letsubs [{:keys [name address] :as current-account} [:multiaccount/current-account]
|
||||
fetching-error [:wallet-legacy/fetching-error]]
|
||||
(let [anim-y (animation/create-value button-group-height)
|
||||
scroll-y (animation/create-value 0)]
|
||||
(anim-listener anim-y scroll-y)
|
||||
[:<>
|
||||
[topbar/topbar
|
||||
{:title name
|
||||
:right-accessories
|
||||
[{:icon :main-icons/more
|
||||
:on-press #(re-frame/dispatch [:bottom-sheet/show-sheet-old
|
||||
{:content sheets/account-settings
|
||||
:content-height 60}])}]}]
|
||||
[react/animated-scroll-view
|
||||
{:contentContainerStyle {:padding-bottom button-group-height}
|
||||
:on-scroll (animation/event
|
||||
[{:nativeEvent {:contentOffset {:y scroll-y}}}]
|
||||
{:useNativeDriver true})
|
||||
:scrollEventThrottle 1
|
||||
:refreshControl (common/refresh-control
|
||||
(and
|
||||
@common/updates-counter
|
||||
@(re-frame/subscribe [:wallet-legacy/refreshing-history?])))}
|
||||
(when fetching-error
|
||||
[react/view
|
||||
{:style {:flex 1
|
||||
:align-items :center
|
||||
:margin 8}}
|
||||
[icons/icon
|
||||
:main-icons/warning
|
||||
{:color :red
|
||||
:container-style {:background-color (colors/get-color :negative-02)
|
||||
:height 40
|
||||
:width 40
|
||||
:border-radius 20
|
||||
:align-items :center
|
||||
:justify-content :center}}]
|
||||
[react/view
|
||||
{:style {:justify-content :center
|
||||
:align-items :center
|
||||
:margin-top 8
|
||||
:margin-horizontal 67.5
|
||||
:text-align :center}}
|
||||
[components.core/text
|
||||
{:color :secondary
|
||||
:size :small
|
||||
:style {:text-align :center}}
|
||||
(i18n/label :t/transfers-fetching-failure)]]])
|
||||
[react/view {:padding-left 16}
|
||||
[react/scroll-view {:horizontal true}
|
||||
[react/view {:flex-direction :row :padding-top 8 :padding-bottom 12}
|
||||
[account-card current-account]]]]
|
||||
(if config/swap-enabled?
|
||||
[top-actions]
|
||||
[buy-crypto/banner])
|
||||
[assets-and-collections address]]
|
||||
[bottom-send-recv-buttons current-account anim-y]])))
|
||||
@@ -1,177 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.wallet.account-settings.views
|
||||
(:require-macros [legacy.status-im.utils.views :refer [defview letsubs]])
|
||||
(:require
|
||||
[legacy.status-im.ui.components.colors :as colors]
|
||||
[legacy.status-im.ui.components.copyable-text :as copyable-text]
|
||||
[legacy.status-im.ui.components.core :as quo]
|
||||
[legacy.status-im.ui.components.icons.icons :as icons]
|
||||
[legacy.status-im.ui.components.list.item :as list.item]
|
||||
[legacy.status-im.ui.components.react :as react]
|
||||
[legacy.status-im.ui.components.toolbar :as toolbar]
|
||||
[legacy.status-im.ui.components.topbar :as topbar]
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as reagent]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.security.core :as security]))
|
||||
|
||||
(defn not-valid-password?
|
||||
[password]
|
||||
(< (count (security/safe-unmask-data password)) 6))
|
||||
|
||||
(defn delete-account
|
||||
[_]
|
||||
(let [password (reagent/atom nil)
|
||||
text-input-ref (atom nil)
|
||||
error (reagent/atom nil)]
|
||||
(fn [account]
|
||||
(when (and @text-input-ref error (not @password))
|
||||
(.clear ^js @text-input-ref))
|
||||
[react/view {:padding 20 :width 300}
|
||||
[quo/text-input
|
||||
{:style {:margin-bottom 40}
|
||||
:label (i18n/label :t/password)
|
||||
:show-cancel false
|
||||
:secure-text-entry true
|
||||
:return-key-type :next
|
||||
:on-submit-editing nil
|
||||
:auto-focus true
|
||||
:on-change-text #(reset! password (security/mask-data %))
|
||||
:get-ref #(reset! text-input-ref %)
|
||||
:error (when (and @error (not @password))
|
||||
(if (= :wrong-password @error)
|
||||
(i18n/label :t/wrong-password)
|
||||
(str @error)))}]
|
||||
[quo/button
|
||||
{:on-press (fn []
|
||||
(re-frame/dispatch [:wallet-legacy.accounts/delete-key
|
||||
account
|
||||
@password
|
||||
#(reset! error :wrong-password)])
|
||||
(reset! password nil))
|
||||
:theme :negative
|
||||
:accessibility-label :delete-account-confirm
|
||||
:disabled (not-valid-password? @password)}
|
||||
(i18n/label :t/delete)]])))
|
||||
|
||||
(defview colors-popover
|
||||
[selected-color on-press]
|
||||
(letsubs [width [:dimensions/window-width]]
|
||||
[react/view {:flex 1 :padding-bottom 16}
|
||||
[react/scroll-view {:style {:margin 16}}
|
||||
(doall
|
||||
(for [color colors/account-colors]
|
||||
^{:key color}
|
||||
[react/touchable-highlight {:on-press #(on-press color)}
|
||||
[react/view
|
||||
{:height 52
|
||||
:background-color color
|
||||
:border-radius 8
|
||||
:width (* 0.7 width)
|
||||
:justify-content :center
|
||||
:padding-left 12
|
||||
:margin-bottom 16}
|
||||
[react/view
|
||||
{:height 32
|
||||
:width 32
|
||||
:border-radius 20
|
||||
:align-items :center
|
||||
:justify-content :center
|
||||
:background-color colors/black-transparent}
|
||||
(when (= selected-color color)
|
||||
[icons/icon :main-icons/check {:color colors/white}])]]]))]
|
||||
[toolbar/toolbar
|
||||
{:center
|
||||
[quo/button
|
||||
{:on-press #(re-frame/dispatch [:hide-popover])
|
||||
:type :secondary}
|
||||
(i18n/label :t/cancel)]}]]))
|
||||
|
||||
(defn property
|
||||
[label value]
|
||||
[react/view {:margin-top 28}
|
||||
[react/text {:style {:color colors/gray}} label]
|
||||
(if (string? value)
|
||||
[react/text {:style {:margin-top 6}} value]
|
||||
value)])
|
||||
|
||||
(defview account-settings
|
||||
[]
|
||||
(letsubs [{:keys [address color path type] :as account} [:multiaccount/current-account]
|
||||
new-account (reagent/atom nil)
|
||||
keycard? [:keycard-multiaccount?]]
|
||||
[react/keyboard-avoiding-view
|
||||
{:style {:flex 1}
|
||||
:ignore-offset true}
|
||||
[topbar/topbar
|
||||
(cond-> {:title (i18n/label :t/account-settings)}
|
||||
(and @new-account (not= "" (:name @new-account)))
|
||||
(assoc :right-accessories
|
||||
[{:label (i18n/label :t/apply)
|
||||
:on-press
|
||||
#(do
|
||||
(re-frame/dispatch [:wallet-legacy.accounts/save-account
|
||||
account
|
||||
@new-account])
|
||||
(reset! new-account nil))}]))]
|
||||
[react/scroll-view
|
||||
{:keyboard-should-persist-taps :handled
|
||||
:style {:flex 1}}
|
||||
[react/view {:padding-bottom 28 :padding-top 10}
|
||||
[react/view {:margin-horizontal 16}
|
||||
[quo/text-input
|
||||
{:label (i18n/label :t/account-name)
|
||||
:auto-focus false
|
||||
:default-value (:name account)
|
||||
:accessibility-label :enter-account-name
|
||||
:on-change-text #(swap! new-account assoc :name %)}]
|
||||
[react/text {:style {:margin-top 16 :color colors/gray}} (i18n/label :t/account-color)]
|
||||
[react/touchable-highlight
|
||||
{:on-press #(re-frame/dispatch [:show-popover
|
||||
{:view [colors-popover color
|
||||
(fn [new-color]
|
||||
(swap! new-account assoc :color new-color)
|
||||
(re-frame/dispatch [:hide-popover]))]
|
||||
:style {:max-height "60%"}}])}
|
||||
[react/view
|
||||
{:height 52
|
||||
:margin-top 12
|
||||
:background-color (or (:color @new-account) color)
|
||||
:border-radius 8
|
||||
:align-items :flex-end
|
||||
:justify-content :center
|
||||
:padding-right 12}
|
||||
[icons/icon :main-icons/dropdown {:color colors/white}]]]
|
||||
[property (i18n/label :t/type)
|
||||
(case type
|
||||
:watch (i18n/label :t/watch-only)
|
||||
(:key :seed) (i18n/label :t/off-status-tree)
|
||||
(i18n/label :t/on-status-tree))]
|
||||
[property (i18n/label :t/wallet-address)
|
||||
[copyable-text/copyable-text-view
|
||||
{:copied-text address}
|
||||
[quo/text
|
||||
{:style {:margin-top 6}
|
||||
:monospace true}
|
||||
address]]]
|
||||
(when-not (= type :watch)
|
||||
[property (i18n/label :t/derivation-path)
|
||||
[copyable-text/copyable-text-view
|
||||
{:copied-text path}
|
||||
[quo/text
|
||||
{:style {:margin-top 6}
|
||||
:monospace true} path]]])
|
||||
(when-not (= type :watch)
|
||||
[property (i18n/label :t/storage)
|
||||
(i18n/label (if keycard?
|
||||
:t/keycard
|
||||
:t/this-device))])]
|
||||
(when (#{:key :seed :watch} type)
|
||||
[react/view
|
||||
[react/view {:margin-bottom 8 :margin-top 28 :height 1 :background-color colors/gray-lighter}]
|
||||
[list.item/list-item
|
||||
{:theme :negative
|
||||
:title (i18n/label :t/delete-account)
|
||||
:on-press #(if (= :watch type)
|
||||
(re-frame/dispatch [:wallet-legacy.settings/show-delete-account-confirmation
|
||||
account])
|
||||
(re-frame/dispatch [:show-popover {:view [delete-account account]}]))}]])]]]))
|
||||
@@ -1,81 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.wallet.accounts.common
|
||||
(:require
|
||||
[legacy.status-im.ui.components.chat-icon.screen :as chat-icon]
|
||||
[legacy.status-im.ui.components.core :as components]
|
||||
[legacy.status-im.ui.components.list.item :as list.item]
|
||||
[legacy.status-im.ui.screens.wallet.components.views :as wallet.components]
|
||||
[legacy.status-im.utils.utils :as utils.utils]
|
||||
[legacy.status-im.wallet.utils :as wallet.utils]
|
||||
[quo.core :as quo]
|
||||
[quo.foundations.colors :as quo.colors]
|
||||
[re-frame.core :as re-frame]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]))
|
||||
|
||||
;; Note(rasom): sometimes `refreshing` might get stuck on iOS if action happened
|
||||
;; too fast. By updating this atom in 1s we ensure that `refreshing?` property
|
||||
;; is updated properly in this case.
|
||||
(def updates-counter (reagent/atom 0))
|
||||
|
||||
(defn schedule-counter-reset
|
||||
[]
|
||||
(utils.utils/set-timeout
|
||||
(fn []
|
||||
(swap! updates-counter inc)
|
||||
(when @(re-frame/subscribe [:wallet-legacy/refreshing-history?])
|
||||
(schedule-counter-reset)))
|
||||
1000))
|
||||
|
||||
(defn refresh-action
|
||||
[]
|
||||
(schedule-counter-reset)
|
||||
(re-frame/dispatch [:wallet-legacy.ui/pull-to-refresh-history]))
|
||||
|
||||
(defn refresh-control
|
||||
[refreshing?]
|
||||
(reagent/as-element
|
||||
[rn/refresh-control
|
||||
{:refreshing (boolean refreshing?)
|
||||
:onRefresh refresh-action}]))
|
||||
|
||||
(defn render-asset
|
||||
[{:keys [icon decimals amount color value] :as token} _ _ currency]
|
||||
[list.item/list-item
|
||||
{:title [components/text {:weight :medium}
|
||||
[components/text {:weight :inherit}
|
||||
(str (if amount
|
||||
(wallet.utils/format-amount amount decimals)
|
||||
"...")
|
||||
" ")]
|
||||
[components/text
|
||||
{:color :secondary
|
||||
:weight :inherit}
|
||||
(wallet.utils/display-symbol token)]]
|
||||
:subtitle (str (if value value "...") " " currency)
|
||||
:accessibility-label (str (:symbol token) "-asset-value")
|
||||
:icon (if icon
|
||||
[wallet.components/token-icon icon]
|
||||
[chat-icon/custom-icon-view-list (:name token) color])}])
|
||||
|
||||
(defn render-asset-new
|
||||
[{:keys [icon decimals amount color value name] :as token} _ _ currency]
|
||||
[rn/view {:height 56 :margin-horizontal 8 :margin-top 4}
|
||||
[rn/view {:position :absolute :left 12 :top 12}
|
||||
(if icon
|
||||
[wallet.components/token-icon (merge icon {:width 32 :height 32})]
|
||||
[chat-icon/custom-icon-view-list (:name token) color])]
|
||||
[rn/view {:position :absolute :left 52 :top 8 :right 12}
|
||||
[rn/view {:flex-direction :row :justify-content :space-between :align-items :center}
|
||||
[quo/text {:weight :semi-bold :style {:height 22}}
|
||||
name]
|
||||
[quo/text {:size :paragraph-2 :weight :medium}
|
||||
(str (if value value "...") " " currency)]]
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:weight :medium
|
||||
:style {:color (quo.colors/theme-colors quo.colors/neutral-50 quo.colors/neutral-40)}}
|
||||
(str (if amount
|
||||
(wallet.utils/format-amount amount decimals)
|
||||
"...")
|
||||
" "
|
||||
(wallet.utils/display-symbol token))]]])
|
||||
@@ -1,135 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.wallet.accounts.sheets
|
||||
(:require
|
||||
[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]))
|
||||
|
||||
(defn hide-sheet-and-dispatch
|
||||
[event]
|
||||
(re-frame/dispatch [:bottom-sheet/hide-old])
|
||||
(re-frame/dispatch event))
|
||||
|
||||
(defn accounts-options
|
||||
[mnemonic]
|
||||
(fn []
|
||||
[:<>
|
||||
[list.item/list-item
|
||||
{:theme :accent
|
||||
:title (i18n/label :t/wallet-manage-accounts)
|
||||
:icon :main-icons/account
|
||||
:accessibility-label :wallet-manage-accounts
|
||||
:on-press #(hide-sheet-and-dispatch
|
||||
[:navigate-to :manage-accounts])}]
|
||||
[list.item/list-item
|
||||
{:theme :accent
|
||||
:title (i18n/label :t/wallet-manage-assets)
|
||||
:icon :main-icons/token
|
||||
:accessibility-label :wallet-manage-assets
|
||||
:on-press #(hide-sheet-and-dispatch
|
||||
[:navigate-to :wallet-settings-assets])}]
|
||||
[list.item/list-item
|
||||
{:theme :accent
|
||||
:title (i18n/label :t/scan-tokens)
|
||||
:icon :main-icons/refresh
|
||||
:accessibility-label :wallet-scan-token
|
||||
:on-press #(hide-sheet-and-dispatch
|
||||
[:wallet-legacy/update-balances nil true])}]
|
||||
[list.item/list-item
|
||||
{:theme :accent
|
||||
:title (i18n/label :t/set-currency)
|
||||
:icon :main-icons/language
|
||||
:accessibility-label :wallet-set-currency
|
||||
:on-press #(hide-sheet-and-dispatch
|
||||
[:navigate-to :currency-settings])}]
|
||||
[list.item/list-item
|
||||
{:theme :accent
|
||||
:title (i18n/label :t/view-signing)
|
||||
:icon :main-icons/info
|
||||
:on-press #(hide-sheet-and-dispatch
|
||||
[:show-popover {:view :signing-phrase}])}]
|
||||
(when mnemonic
|
||||
[list.item/list-item
|
||||
{:theme :negative
|
||||
:title (i18n/label :t/wallet-backup-recovery-title)
|
||||
:icon :main-icons/security
|
||||
:accessibility-label :wallet-backup-recovery-title
|
||||
:on-press #(hide-sheet-and-dispatch
|
||||
[:navigate-to :backup-seed])}])]))
|
||||
|
||||
(defn account-card-actions
|
||||
[account type wallet]
|
||||
[react/view
|
||||
(when-not (= type :watch)
|
||||
[list.item/list-item
|
||||
{:theme :accent
|
||||
:title (i18n/label :t/wallet-send)
|
||||
:icon :main-icons/send
|
||||
:accessibility-label :send-transaction-button
|
||||
:on-press #(hide-sheet-and-dispatch
|
||||
[:wallet-legacy/prepare-transaction-from-wallet account])}])
|
||||
[list.item/list-item
|
||||
{:theme :accent
|
||||
:title (i18n/label :t/share)
|
||||
:icon :main-icons/share
|
||||
:accessibility-label :share-account-button
|
||||
:on-press #(hide-sheet-and-dispatch
|
||||
[:wallet-legacy/share-popover (:address account)])}]
|
||||
(when-not wallet
|
||||
[list.item/list-item
|
||||
{:theme :accent
|
||||
:title (i18n/label :t/hide)
|
||||
:icon :main-icons/hide
|
||||
:accessibility-label :hide-account-button
|
||||
:on-press #(hide-sheet-and-dispatch
|
||||
[:wallet-legacy.accounts/save-account account {:hidden true}])}])])
|
||||
|
||||
(defn add-account
|
||||
[]
|
||||
(let [keycard? @(re-frame/subscribe [:keycard-multiaccount?])]
|
||||
[react/view
|
||||
[list.item/list-item
|
||||
{:title (i18n/label :t/generate-a-new-account)
|
||||
:theme :accent
|
||||
:icon :main-icons/add
|
||||
:accessibility-label :add-account-sheet-generate
|
||||
:on-press #(hide-sheet-and-dispatch
|
||||
[:wallet-legacy.accounts/start-adding-new-account
|
||||
{:type :generate}])}]
|
||||
[list.item/list-item
|
||||
{:theme :accent
|
||||
:title (i18n/label :t/add-a-watch-account)
|
||||
:icon :main-icons/show
|
||||
:accessibility-label :add-account-sheet-watch
|
||||
:on-press #(hide-sheet-and-dispatch
|
||||
[:wallet-legacy.accounts/start-adding-new-account
|
||||
{:type :watch}])}]
|
||||
(when-not keycard?
|
||||
[list.item/list-item
|
||||
{:title (i18n/label :t/enter-a-seed-phrase)
|
||||
:theme :accent
|
||||
:icon :main-icons/text
|
||||
:accessibility-label :add-account-sheet-seed
|
||||
:on-press #(hide-sheet-and-dispatch
|
||||
[:wallet-legacy.accounts/start-adding-new-account
|
||||
{:type :seed}])}])
|
||||
(when-not keycard?
|
||||
[list.item/list-item
|
||||
{:title (i18n/label :t/enter-a-private-key)
|
||||
:theme :accent
|
||||
:icon :main-icons/address
|
||||
:accessibility-label :add-account-sheet-private-key
|
||||
:on-press #(hide-sheet-and-dispatch
|
||||
[:wallet-legacy.accounts/start-adding-new-account
|
||||
{:type :key}])}])]))
|
||||
|
||||
(defn account-settings
|
||||
[]
|
||||
[react/view
|
||||
[list.item/list-item
|
||||
{:theme :accent
|
||||
:title (i18n/label :t/account-settings)
|
||||
:accessibility-label :account-settings-bottom-sheet
|
||||
:icon :main-icons/info
|
||||
:on-press #(hide-sheet-and-dispatch
|
||||
[:navigate-to :account-settings])}]])
|
||||
@@ -1,165 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.wallet.accounts.styles
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.ui.components.colors :as colors]))
|
||||
|
||||
(def dot-size 6)
|
||||
|
||||
(def dot-container
|
||||
{:height 200
|
||||
:flex-direction :column
|
||||
:flex-wrap :wrap
|
||||
:padding-horizontal 8})
|
||||
|
||||
(defn dot-selector
|
||||
[]
|
||||
{:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:align-items :center})
|
||||
|
||||
(defn dot-style
|
||||
[selected]
|
||||
{:background-color (if selected colors/blue colors/blue-light)
|
||||
:overflow :hidden
|
||||
:opacity 1
|
||||
:margin-horizontal 3
|
||||
:width dot-size
|
||||
:height dot-size
|
||||
:border-radius 3})
|
||||
|
||||
(defn container
|
||||
[{:keys [minimized]}]
|
||||
(when-not minimized
|
||||
{:padding-bottom 8
|
||||
:padding-horizontal 16}))
|
||||
|
||||
(defn value-container
|
||||
[{:keys [minimized animation]}]
|
||||
(when minimized
|
||||
{:opacity animation}))
|
||||
|
||||
(defn value-text
|
||||
[{:keys [minimized]}]
|
||||
{:font-size (if minimized 20 32)
|
||||
:line-height 40
|
||||
:color colors/black})
|
||||
|
||||
(defn accounts-mnemonic
|
||||
[{:keys [animation]}]
|
||||
{:opacity (if animation 1 0)
|
||||
:flex 1
|
||||
:justify-content :center
|
||||
:position :absolute
|
||||
:top 0
|
||||
:bottom 0
|
||||
:left 0})
|
||||
|
||||
(def card-margin 8)
|
||||
(defn page-width
|
||||
[card-width]
|
||||
(+ card-width (* card-margin 2)))
|
||||
|
||||
(defn card-common
|
||||
[card-width]
|
||||
{:margin card-margin
|
||||
:width card-width
|
||||
:height 82
|
||||
:border-radius 16})
|
||||
|
||||
(defn card
|
||||
[color card-width]
|
||||
(merge (card-common card-width)
|
||||
{:background-color (if (string/blank? color)
|
||||
colors/blue
|
||||
color)
|
||||
:justify-content :space-between
|
||||
:padding-horizontal 12
|
||||
:padding-top 12
|
||||
:padding-bottom 10}))
|
||||
|
||||
(defn add-card
|
||||
[card-width]
|
||||
(merge (card-common card-width)
|
||||
{:background-color colors/white
|
||||
:flex-direction :row
|
||||
:border-width 1
|
||||
:border-color colors/gray-lighter
|
||||
:justify-content :center
|
||||
:align-items :center}))
|
||||
|
||||
(def add-text
|
||||
{:color colors/blue
|
||||
:margin-left 8
|
||||
:font-weight "500"
|
||||
:font-size 15
|
||||
:line-height 22})
|
||||
|
||||
(def card-name
|
||||
{:color colors/white-persist
|
||||
:font-weight "500"
|
||||
:font-size 15
|
||||
:line-height 22})
|
||||
|
||||
(def card-address
|
||||
{:number-of-lines 1
|
||||
:ellipsize-mode :middle
|
||||
:size :small
|
||||
:monospace true
|
||||
:style {:width 110
|
||||
:font-size 15
|
||||
:line-height 22
|
||||
:color colors/white-transparent-70-persist}})
|
||||
|
||||
(def card-value
|
||||
{:color colors/white-persist
|
||||
:font-size 22
|
||||
:font-weight "500"})
|
||||
|
||||
(def card-value-currency
|
||||
{:color colors/white-persist
|
||||
:font-size 22
|
||||
:font-weight "500"})
|
||||
|
||||
(def card-icon-more
|
||||
{:border-radius 32
|
||||
:width 36
|
||||
:height 36
|
||||
:justify-content :center
|
||||
:align-items :center
|
||||
:background-color colors/black-transparent})
|
||||
|
||||
(def card-icon-type
|
||||
{:border-radius 32
|
||||
:width 36
|
||||
:height 36
|
||||
:justify-content :center
|
||||
:align-items :center
|
||||
:margin-left :auto
|
||||
:margin-right 12
|
||||
:background-color colors/white-persist})
|
||||
|
||||
(def send-button-container
|
||||
{:position :absolute
|
||||
:z-index 2
|
||||
:align-items :center
|
||||
:justify-content :center
|
||||
:left 0
|
||||
:right 0
|
||||
:bottom 56
|
||||
:height 40})
|
||||
|
||||
(defn send-button
|
||||
[]
|
||||
{:width 40
|
||||
:height 40
|
||||
:background-color colors/blue
|
||||
:border-radius 20
|
||||
:align-items :center
|
||||
:justify-content :center
|
||||
:shadow-offset {:width 0 :height 1}
|
||||
:shadow-radius 6
|
||||
:shadow-opacity 1
|
||||
:shadow-color (if (colors/dark?)
|
||||
"rgba(0, 0, 0, 0.75)"
|
||||
"rgba(0, 12, 63, 0.2)")
|
||||
:elevation 2})
|
||||
@@ -1,302 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.wallet.accounts.views
|
||||
(:require
|
||||
[legacy.status-im.keycard.login :as keycard.login]
|
||||
[legacy.status-im.qr-scanner.core :as qr-scanner]
|
||||
[legacy.status-im.ui.components.colors :as colors]
|
||||
[legacy.status-im.ui.components.core :as components.core]
|
||||
[legacy.status-im.ui.components.icons.icons :as icons]
|
||||
[legacy.status-im.ui.components.react :as react]
|
||||
[legacy.status-im.ui.screens.wallet.account.views :as account.views]
|
||||
[legacy.status-im.ui.screens.wallet.accounts.common :as common]
|
||||
[legacy.status-im.ui.screens.wallet.accounts.sheets :as sheets]
|
||||
[legacy.status-im.ui.screens.wallet.accounts.styles :as styles]
|
||||
[legacy.status-im.ui.screens.wallet.buy-crypto.views :as buy-crypto]
|
||||
[quo.core :as quo]
|
||||
[quo.foundations.colors :as quo.colors]
|
||||
[re-frame.core :as re-frame]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[reagent.core :as reagent]
|
||||
[utils.i18n :as i18n])
|
||||
(:require-macros [legacy.status-im.utils.views :as views]))
|
||||
|
||||
(views/defview account-card
|
||||
[{:keys [name color address type wallet] :as account} keycard? card-width]
|
||||
(views/letsubs [currency [:wallet-legacy/currency]
|
||||
portfolio-value [:account-portfolio-value address]
|
||||
prices-loading? [:prices-loading?]]
|
||||
[react/touchable-highlight
|
||||
{:on-press #(re-frame/dispatch [:navigate-to :wallet-account account])
|
||||
:accessibility-label (str "accountcard" name)}
|
||||
[react/view {:style (styles/card color card-width)}
|
||||
[react/view {:flex-direction :row :align-items :center :justify-content :space-between}
|
||||
[react/text {:style styles/card-name} name]
|
||||
[components.core/text styles/card-address
|
||||
address]]
|
||||
[react/view {:flex-direction :row :align-items :center :justify-content :space-between}
|
||||
[react/view {:style {:flex-direction :row}}
|
||||
(if prices-loading?
|
||||
[react/small-loading-indicator :colors/white-persist]
|
||||
[react/text
|
||||
{:style styles/card-value
|
||||
:accessibility-label "account-total-value"} portfolio-value])
|
||||
[react/text {:style styles/card-value-currency} (str " " (:code currency))]]
|
||||
(let [icon (cond
|
||||
(= type :watch)
|
||||
:main-icons/show
|
||||
|
||||
(and (not= type :watch) keycard?)
|
||||
:main-icons/keycard-account)]
|
||||
(when icon
|
||||
[icons/icon icon
|
||||
{:container-style styles/card-icon-type
|
||||
:color color}]))
|
||||
[react/touchable-highlight
|
||||
{:style styles/card-icon-more
|
||||
:on-press #(re-frame/dispatch
|
||||
[:bottom-sheet/show-sheet-old
|
||||
{:content (fn [] [sheets/account-card-actions account type wallet])
|
||||
:content-height 130}])}
|
||||
[icons/icon :main-icons/more {:color colors/white-persist}]]]]]))
|
||||
|
||||
(defn add-card
|
||||
[card-width]
|
||||
[react/touchable-highlight
|
||||
{:on-press #(re-frame/dispatch [:bottom-sheet/show-sheet-old
|
||||
{:content sheets/add-account
|
||||
:content-height 260}])
|
||||
:accessibility-label "add-new-account"}
|
||||
[react/view {:style (styles/add-card card-width)}
|
||||
[icons/icon :main-icons/add-circle {:color colors/blue}]
|
||||
[react/text {:style styles/add-text} (i18n/label :t/add-account)]]])
|
||||
|
||||
(views/defview assets
|
||||
[]
|
||||
(views/letsubs [{:keys [tokens]} [:wallet-legacy/all-visible-assets-with-values]
|
||||
currency [:wallet-legacy/currency]]
|
||||
[:<>
|
||||
(for [item tokens]
|
||||
^{:key (:name item)}
|
||||
[common/render-asset item nil nil (:code currency)])]))
|
||||
|
||||
(views/defview send-button
|
||||
[]
|
||||
(views/letsubs [account [:multiaccount/default-account]]
|
||||
[react/view styles/send-button-container
|
||||
[components.core/button
|
||||
{:accessibility-label :send-transaction-button
|
||||
:type :scale
|
||||
:on-press #(re-frame/dispatch [:wallet-legacy/prepare-transaction-from-wallet
|
||||
account])}
|
||||
[react/view (styles/send-button)
|
||||
[icons/icon :main-icons/send {:color colors/white-persist}]]]]))
|
||||
|
||||
(defn dot
|
||||
[]
|
||||
(fn [{:keys [selected]}]
|
||||
[react/view {:style (styles/dot-style selected)}]))
|
||||
|
||||
(defn dots-selector
|
||||
[{:keys [n selected]}]
|
||||
[react/view {:style (styles/dot-selector)}
|
||||
(for [i (range n)]
|
||||
^{:key i}
|
||||
[dot {:selected (= selected i)}])])
|
||||
|
||||
;;ACCOUNTS OLD
|
||||
(views/defview accounts-old
|
||||
[]
|
||||
(views/letsubs [accounts [:multiaccount/visible-accounts]
|
||||
keycard? [:keycard-multiaccount?]
|
||||
window-width [:dimensions/window-width]
|
||||
index (reagent/atom 0)]
|
||||
(let [card-width (quot window-width 1.1)
|
||||
page-width (styles/page-width card-width)]
|
||||
[react/view
|
||||
{:style {:align-items :center
|
||||
:flex 1
|
||||
:justify-content :flex-end}}
|
||||
[react/scroll-view
|
||||
{:horizontal true
|
||||
:deceleration-rate "fast"
|
||||
:snap-to-interval page-width
|
||||
:shows-horizontal-scroll-indicator false
|
||||
:scroll-event-throttle 64
|
||||
:on-scroll #(let [x (.-nativeEvent.contentOffset.x ^js %)]
|
||||
(reset! index (Math/max (Math/round (/ x page-width))
|
||||
0)))}
|
||||
[react/view styles/dot-container
|
||||
(doall
|
||||
(for [account accounts]
|
||||
^{:key account}
|
||||
[account-card account keycard? card-width]))
|
||||
[add-card card-width]]]
|
||||
(let [columns (Math/ceil (/ (inc (count accounts)) 2))
|
||||
totalwidth (* (styles/page-width card-width) columns)
|
||||
n (Math/ceil (/ totalwidth window-width))]
|
||||
(when (> n 1)
|
||||
[dots-selector
|
||||
{:selected @index
|
||||
:n n}]))])))
|
||||
|
||||
;;TOTAL VALUE OLD
|
||||
(views/defview total-value-old
|
||||
[{:keys [animation minimized]}]
|
||||
(views/letsubs [currency [:wallet-legacy/currency]
|
||||
portfolio-value [:portfolio-value]
|
||||
empty-balances? [:empty-balances?]
|
||||
frozen-card? [:keycard/frozen-card?]
|
||||
{:keys [mnemonic]} [:profile/profile]]
|
||||
[reanimated/view {:style (styles/container {:minimized minimized})}
|
||||
(when (or
|
||||
(and frozen-card? minimized)
|
||||
(and mnemonic minimized (not empty-balances?)))
|
||||
[reanimated/view {:style (styles/accounts-mnemonic {:animation animation})}
|
||||
[react/touchable-highlight
|
||||
{:on-press #(re-frame/dispatch
|
||||
(if frozen-card?
|
||||
[::keycard.login/reset-pin]
|
||||
[:navigate-to :backup-seed]))}
|
||||
[react/view
|
||||
{:flex-direction :row
|
||||
:align-items :center}
|
||||
[react/view
|
||||
{:width 14
|
||||
:height 14
|
||||
:background-color colors/gray
|
||||
:border-radius 7
|
||||
:align-items :center
|
||||
:justify-content :center
|
||||
:margin-right 9}
|
||||
[react/text
|
||||
{:style {:color colors/white
|
||||
:font-size 13
|
||||
:font-weight "700"}}
|
||||
"!"]]
|
||||
[react/text
|
||||
{:style {:color colors/gray}
|
||||
:accessibility-label :back-up-your-seed-phrase-warning}
|
||||
(if frozen-card?
|
||||
(i18n/label :t/your-card-is-frozen)
|
||||
(i18n/label :t/back-up-your-seed-phrase))]]]])
|
||||
|
||||
[reanimated/view
|
||||
{:style (styles/value-container {:minimized minimized
|
||||
:animation animation})
|
||||
:pointer-events :none}
|
||||
[reanimated/view {:style {:justify-content :center}}
|
||||
[components.core/text
|
||||
{:animated? true
|
||||
:weight :semi-bold
|
||||
:style (styles/value-text {:minimized minimized})}
|
||||
portfolio-value
|
||||
[components.core/text
|
||||
{:animated? true
|
||||
:size :inherit
|
||||
:weight :inherit
|
||||
:color :secondary}
|
||||
(str " " (:code currency))]]]]
|
||||
(when-not minimized
|
||||
[reanimated/view
|
||||
[components.core/text {:color :secondary}
|
||||
(i18n/label :t/wallet-total-value)]])]))
|
||||
|
||||
(views/defview total-value
|
||||
[]
|
||||
(views/letsubs [currency [:wallet-legacy/currency]
|
||||
portfolio-value [:portfolio-value]]
|
||||
[react/view {:padding-vertical 12}
|
||||
[quo/text (i18n/label :t/wallet-total-value)]
|
||||
[quo/text {:size :heading-1 :weight :semi-bold}
|
||||
(str portfolio-value " " (:code currency))]
|
||||
[react/scroll-view {:horizontal true}]]))
|
||||
|
||||
(views/defview accounts
|
||||
[selected-account-atom]
|
||||
(views/letsubs [visible-accounts [:multiaccount/visible-accounts]]
|
||||
(do
|
||||
(reset! selected-account-atom (:address (first visible-accounts)))
|
||||
(let [accounts-data (for [account visible-accounts]
|
||||
{:label (:name account)
|
||||
:id (:address account)})]
|
||||
[react/scroll-view
|
||||
{:horizontal true
|
||||
:shows-horizontal-scroll-indicator false
|
||||
:scroll-event-throttle 64
|
||||
:margin-top 12
|
||||
:margin-bottom 20}
|
||||
[react/view {:flex-direction :row}
|
||||
[quo/tabs
|
||||
{:default-active (:address (first visible-accounts))
|
||||
:on-change #(reset! selected-account-atom %)
|
||||
:data accounts-data}]
|
||||
[quo/button
|
||||
{:type :grey
|
||||
:size 32
|
||||
:on-press #(re-frame/dispatch [:bottom-sheet/show-sheet-old
|
||||
{:content sheets/add-account
|
||||
:content-height 260}])}
|
||||
"Add account"]]]))))
|
||||
|
||||
(defn accounts-overview
|
||||
[]
|
||||
(let [mnemonic @(re-frame/subscribe [:mnemonic])
|
||||
selected-account-atom (reagent/atom nil)]
|
||||
(fn []
|
||||
[react/view
|
||||
{:style {:flex 1
|
||||
:padding-top (safe-area/get-top)
|
||||
:background-color (quo.colors/theme-colors quo.colors/neutral-5
|
||||
quo.colors/neutral-95)}}
|
||||
[react/view {:padding-horizontal 20}
|
||||
[react/view {:flex-direction :row :height 56 :align-items :center :justify-content :flex-end}
|
||||
[quo/button
|
||||
{:icon true
|
||||
:size 32
|
||||
:type :grey
|
||||
:accessibility-label :accounts-qr-code
|
||||
:on-press #(re-frame/dispatch
|
||||
[::qr-scanner/scan-code
|
||||
{:handler :wallet-legacy.send/qr-scanner-result}])}
|
||||
:i/placeholder]
|
||||
[react/view {:width 12}]
|
||||
[quo/button
|
||||
{:icon true
|
||||
:size 32
|
||||
:type :grey
|
||||
:on-press #(re-frame/dispatch [:bottom-sheet/show-sheet-old
|
||||
{:content (sheets/accounts-options mnemonic)}])
|
||||
:accessibility-label :accounts-more-options}
|
||||
:i/placeholder]]
|
||||
[total-value]
|
||||
[accounts selected-account-atom]]
|
||||
[account.views/account-new @selected-account-atom]])))
|
||||
|
||||
(defn accounts-overview-old
|
||||
[]
|
||||
(let [mnemonic @(re-frame/subscribe [:mnemonic])
|
||||
mainnet? @(re-frame/subscribe [:mainnet?])]
|
||||
[react/view
|
||||
{:style {:flex 1}}
|
||||
[components.core/animated-header
|
||||
{:extended-header total-value-old
|
||||
:refresh-control common/refresh-control
|
||||
:refreshing-sub (re-frame/subscribe [:wallet-legacy/refreshing-history?])
|
||||
:refreshing-counter common/updates-counter
|
||||
:use-insets true
|
||||
:right-accessories [{:on-press #(re-frame/dispatch
|
||||
[::qr-scanner/scan-code
|
||||
{:handler :wallet-legacy.send/qr-scanner-result}])
|
||||
:icon :main-icons/qr
|
||||
:accessibility-label :accounts-qr-code}
|
||||
{:on-press #(re-frame/dispatch [:bottom-sheet/show-sheet-old
|
||||
{:content (sheets/accounts-options
|
||||
mnemonic)}])
|
||||
:icon :main-icons/more
|
||||
:accessibility-label :accounts-more-options}]}
|
||||
[accounts-old]
|
||||
(when mainnet?
|
||||
[buy-crypto/banner])
|
||||
[assets]
|
||||
[react/view {:height 68}]]
|
||||
[send-button]]))
|
||||
@@ -1,38 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.wallet.accounts-manage.views
|
||||
(:require
|
||||
[legacy.status-im.ui.components.colors :as colors]
|
||||
[legacy.status-im.ui.components.icons.icons :as icons]
|
||||
[legacy.status-im.ui.components.list.item :as list.item]
|
||||
[legacy.status-im.ui.components.list.views :as list]
|
||||
[legacy.status-im.utils.utils :as utils]
|
||||
[reagent.core :as reagent]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn render-account
|
||||
[_]
|
||||
(reagent/create-class
|
||||
{:should-component-update
|
||||
(fn [_ [_ old-item] [_ new-item]]
|
||||
(not= (:hidden old-item) (:hidden new-item)))
|
||||
:reagent-render
|
||||
(fn [{:keys [hidden name address wallet] :as account}]
|
||||
[list.item/list-item
|
||||
{:accessory [icons/icon
|
||||
(if hidden :main-icos/hide :main-icos/show)
|
||||
(merge {:accessibility-label (if hidden :hide-icon :show-icon)}
|
||||
(when wallet {:color colors/gray}))]
|
||||
:animated-accessory? false
|
||||
:animated false
|
||||
:disabled wallet
|
||||
:title name
|
||||
:subtitle (utils/get-shortened-checksum-address address)
|
||||
:on-press #(rf/dispatch [:wallet-legacy.accounts/save-account account
|
||||
{:hidden (not hidden)}])}])}))
|
||||
|
||||
(defn manage
|
||||
[]
|
||||
(let [accounts (rf/sub [:profile/wallet-accounts])]
|
||||
[list/flat-list
|
||||
{:key-fn :address
|
||||
:data accounts
|
||||
:render-fn render-account}]))
|
||||
@@ -1,173 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.wallet.add-new.views
|
||||
(:require-macros [legacy.status-im.utils.views :refer [defview letsubs]])
|
||||
(:require
|
||||
[cljs.spec.alpha :as spec]
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.multiaccounts.db :as multiaccounts.db]
|
||||
[legacy.status-im.ui.components.colors :as colors]
|
||||
[legacy.status-im.ui.components.core :as quo]
|
||||
[legacy.status-im.ui.components.icons.icons :as icons]
|
||||
[legacy.status-im.ui.components.react :as react]
|
||||
[legacy.status-im.ui.components.toolbar :as toolbar]
|
||||
[legacy.status-im.ui.components.topbar :as topbar]
|
||||
[legacy.status-im.ui.screens.wallet.account-settings.views :as account-settings]
|
||||
[native-module.core :as native-module]
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as reagent]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.security.core :as security]))
|
||||
|
||||
(defn add-account-topbar
|
||||
[type]
|
||||
(let [title (case type
|
||||
:generate :t/generate-an-account
|
||||
:watch :t/add-watch-account
|
||||
:seed :t/add-seed-account
|
||||
:key :t/add-private-key-account
|
||||
"")]
|
||||
[topbar/topbar
|
||||
(merge {:title (i18n/label title)}
|
||||
(when (= type :watch)
|
||||
{:right-accessories
|
||||
[{:icon :qr
|
||||
:on-press #(re-frame/dispatch [:wallet-legacy.add-new/qr-scanner
|
||||
{:handler
|
||||
:wallet-legacy.add-new/qr-scanner-result}])}]}))]))
|
||||
|
||||
(defn common-settings
|
||||
[account]
|
||||
[react/view {:margin-horizontal 16}
|
||||
[quo/text-input
|
||||
{:label (i18n/label :t/account-name)
|
||||
:auto-focus false
|
||||
:default-value (:name account)
|
||||
:accessibility-label :enter-account-name
|
||||
:placeholder (i18n/label :t/account-name)
|
||||
:on-change-text #(re-frame/dispatch [:set-in [:add-account :account :name] %])}]
|
||||
[react/text {:style {:margin-top 30}} (i18n/label :t/account-color)]
|
||||
[react/touchable-highlight
|
||||
{:on-press #(re-frame/dispatch
|
||||
[:show-popover
|
||||
{:view [account-settings/colors-popover (:color account)
|
||||
(fn [new-color]
|
||||
(re-frame/dispatch [:set-in [:add-account :account :color] new-color])
|
||||
(re-frame/dispatch [:hide-popover]))]
|
||||
:style {:max-height "60%"}}])}
|
||||
[react/view
|
||||
{:height 52
|
||||
:margin-top 12
|
||||
:background-color (:color account)
|
||||
:border-radius 8
|
||||
:align-items :flex-end
|
||||
:justify-content :center
|
||||
:padding-right 12}
|
||||
[icons/icon :main-icons/dropdown {:color colors/white}]]]])
|
||||
|
||||
(defn settings
|
||||
[{:keys [type scanned-address password-error account-error]}
|
||||
entered-password]
|
||||
[react/view
|
||||
{:padding-horizontal 16
|
||||
:padding-vertical 16}
|
||||
(if (= type :watch)
|
||||
[quo/text-input
|
||||
{:label (i18n/label :t/wallet-key-title)
|
||||
:auto-focus false
|
||||
:default-value scanned-address
|
||||
:monospace true
|
||||
:placeholder (i18n/label :t/enter-address)
|
||||
:accessibility-label :add-account-enter-watch-address
|
||||
:on-change-text #(re-frame/dispatch [:wallet-legacy.accounts/set-account-to-watch %])}]
|
||||
[quo/text-input
|
||||
{:label (i18n/label :t/password)
|
||||
:show-cancel false
|
||||
:auto-focus false
|
||||
:placeholder (i18n/label :t/enter-your-password)
|
||||
:secure-text-entry true
|
||||
:text-content-type :none
|
||||
:accessibility-label :add-account-enter-password
|
||||
:bottom-value 0
|
||||
:error (when password-error (i18n/label :t/add-account-incorrect-password))
|
||||
:on-change-text #(do
|
||||
(re-frame/dispatch [:set-in [:add-account :password-error] nil])
|
||||
(reset! entered-password %))}])
|
||||
(when (= type :seed)
|
||||
[react/view {:padding-top 16}
|
||||
[quo/text-input
|
||||
{:label (i18n/label :t/recovery-phrase)
|
||||
:auto-focus false
|
||||
:placeholder (i18n/label :t/multiaccounts-recover-enter-phrase-title)
|
||||
:auto-correct false
|
||||
:keyboard-type :visible-password
|
||||
:multiline true
|
||||
:height 95
|
||||
:error account-error
|
||||
:accessibility-label :add-account-enter-seed
|
||||
:monospace true
|
||||
:on-change-text
|
||||
#(do
|
||||
(re-frame/dispatch [:set-in [:add-account :account-error] nil])
|
||||
(re-frame/dispatch [:set-in [:add-account :seed]
|
||||
(security/mask-data (string/lower-case %))]))}]])
|
||||
(when (= type :key)
|
||||
[react/view {:margin-top 30}
|
||||
[quo/text-input
|
||||
{:label (i18n/label :t/private-key)
|
||||
:auto-focus false
|
||||
:placeholder (i18n/label :t/enter-a-private-key)
|
||||
:auto-correct false
|
||||
:keyboard-type :visible-password
|
||||
:error account-error
|
||||
:secure-text-entry true
|
||||
:accessibility-label :add-account-enter-private-key
|
||||
:text-content-type :none
|
||||
:on-change-text
|
||||
#(do
|
||||
(re-frame/dispatch [:set-in [:add-account :account-error] nil])
|
||||
(re-frame/dispatch [:set-in [:add-account :private-key] (security/mask-data %)]))}]])])
|
||||
|
||||
(defn pin
|
||||
[]
|
||||
[react/view])
|
||||
|
||||
(defview add-account-view
|
||||
[]
|
||||
(letsubs [{:keys [type account] :as add-account} [:add-account]
|
||||
add-account-disabled? [:add-account-disabled?]
|
||||
entered-password (reagent/atom "")
|
||||
keycard? [:keycard-multiaccount?]]
|
||||
[react/keyboard-avoiding-view
|
||||
{:style {:flex 1}
|
||||
:ignore-offset true}
|
||||
[add-account-topbar type]
|
||||
[react/scroll-view
|
||||
{:keyboard-should-persist-taps :handled
|
||||
:style {:flex 1 :padding-top 20}}
|
||||
(when (or (not keycard?)
|
||||
(= type :watch))
|
||||
[settings add-account entered-password])
|
||||
[common-settings account]]
|
||||
[toolbar/toolbar
|
||||
{:show-border? true
|
||||
:right
|
||||
[quo/button
|
||||
{:type :secondary
|
||||
:after :main-icon/next
|
||||
:accessibility-label :add-account-add-account-button
|
||||
:on-press
|
||||
(if (and keycard?
|
||||
(not= type :watch))
|
||||
#(re-frame/dispatch [:keycard/new-account-pin-sheet
|
||||
{:view {:content pin
|
||||
:height 256}}])
|
||||
#(re-frame/dispatch [:wallet-legacy.accounts/add-new-account
|
||||
(native-module/sha3 @entered-password)]))
|
||||
:disabled
|
||||
(or add-account-disabled?
|
||||
(and
|
||||
(not (= type :watch))
|
||||
(and
|
||||
(not keycard?)
|
||||
(not (spec/valid? ::multiaccounts.db/password
|
||||
@entered-password)))))}
|
||||
(i18n/label :t/add-account)]}]]))
|
||||
@@ -1,34 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.wallet.buy-crypto.sheets
|
||||
(:require
|
||||
[legacy.status-im.ui.components.colors :as colors]))
|
||||
|
||||
;; This needs to be a function because `colors/x` is a mutable reference
|
||||
;; and changes dynamically based on the appearance settings
|
||||
(defn banner-container
|
||||
[]
|
||||
{:margin-horizontal 16
|
||||
:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:align-items :center
|
||||
:flex 1
|
||||
:margin-top 16
|
||||
:border-radius 16
|
||||
:margin-bottom 8
|
||||
:padding-horizontal 12
|
||||
:padding-vertical 5
|
||||
:background-color colors/blue-light})
|
||||
|
||||
(defn highlight-container
|
||||
[]
|
||||
{:padding 4
|
||||
:justify-content :center
|
||||
:border-radius 4
|
||||
:background-color colors/blue})
|
||||
|
||||
(def highlight-text
|
||||
{:text-transform :uppercase
|
||||
:color "#FFFFFF"})
|
||||
|
||||
(def icon
|
||||
{:width 68
|
||||
:height 36})
|
||||
@@ -1,167 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.wallet.buy-crypto.views
|
||||
(:require
|
||||
[legacy.status-im.ui.components.core :as quo]
|
||||
[legacy.status-im.ui.components.icons.icons :as icons]
|
||||
[legacy.status-im.ui.components.list.item :as list.item]
|
||||
[legacy.status-im.ui.components.list.views :as list]
|
||||
[legacy.status-im.ui.components.react :as react]
|
||||
[legacy.status-im.ui.components.topbar :as topbar]
|
||||
[legacy.status-im.ui.components.webview :as components.webview]
|
||||
[legacy.status-im.ui.screens.browser.views :as browser.views]
|
||||
[legacy.status-im.ui.screens.chat.photos :as photos]
|
||||
[legacy.status-im.ui.screens.wallet.buy-crypto.sheets :as sheets]
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as reagent]
|
||||
[utils.i18n :as i18n])
|
||||
(:require-macros [legacy.status-im.utils.views :as views]))
|
||||
|
||||
(def learn-more-url "")
|
||||
|
||||
(def webview-ref (atom nil))
|
||||
|
||||
(defn on-buy-crypto-pressed
|
||||
[]
|
||||
(re-frame/dispatch [:buy-crypto.ui/open-screen]))
|
||||
|
||||
(defn render-on-ramp
|
||||
[{:keys [name fees logo-url description] :as on-ramp}]
|
||||
[react/touchable-highlight
|
||||
{:on-press #(re-frame/dispatch [:open-modal :buy-crypto-website on-ramp])
|
||||
:style {:flex 1}}
|
||||
[list.item/list-item
|
||||
{:title [react/view {:style {:flex 1}}
|
||||
[quo/text
|
||||
{:size :large
|
||||
:weight :bold}
|
||||
name]
|
||||
[quo/text {} description]]
|
||||
:subtitle [react/view {:style {:flex 1}}
|
||||
[quo/text
|
||||
{:size :small
|
||||
:color :secondary} fees]]
|
||||
:icon [photos/photo logo-url {:size 40}]
|
||||
:left-side-alignment :flex-start
|
||||
:accessory :text}]])
|
||||
|
||||
(defn buy-crypto-header
|
||||
[]
|
||||
[react/view
|
||||
{:padding-bottom 16
|
||||
:align-items :center}
|
||||
[react/view
|
||||
{:padding-top 16
|
||||
:padding-bottom 8}
|
||||
[quo/text
|
||||
{:weight :bold
|
||||
:size :x-large}
|
||||
(i18n/label :t/buy-crypto)]]
|
||||
[quo/text {:color :secondary}
|
||||
(i18n/label :t/buy-crypto-choose-a-service)]
|
||||
(when (seq learn-more-url)
|
||||
[react/touchable-highlight {:on-press #(re-frame/dispatch [:browser.ui/open-url learn-more-url])}
|
||||
[react/view {:padding-vertical 11}
|
||||
[quo/text {:color :link} (i18n/label :t/learn-more)]]])])
|
||||
|
||||
(views/defview buy-crypto
|
||||
[]
|
||||
(views/letsubs [on-ramps [:buy-crypto/on-ramps]]
|
||||
[list/flat-list
|
||||
{:data on-ramps
|
||||
:key-fn :site-url
|
||||
:header [buy-crypto-header]
|
||||
:render-fn render-on-ramp}]))
|
||||
|
||||
(defn website
|
||||
[]
|
||||
(let [has-loaded? (reagent/atom false)
|
||||
initialized? (reagent/atom false)
|
||||
{:keys [name
|
||||
hostname
|
||||
logo-url
|
||||
site-url]}
|
||||
@(re-frame/subscribe [:get-screen-params])]
|
||||
;;it crashes on android , probably because of modal animation
|
||||
(js/setTimeout #(reset! initialized? true) 500)
|
||||
(fn []
|
||||
;; overflow hidden needed for the crash on android
|
||||
[react/view {:flex 1 :overflow :hidden}
|
||||
[topbar/topbar
|
||||
{:content [react/view
|
||||
{:flex 1
|
||||
:align-items :center
|
||||
:justify-content :center}
|
||||
[quo/text
|
||||
{:weight :semi-bold}
|
||||
(i18n/label :t/buy-crypto)]
|
||||
[quo/text {:color :secondary}
|
||||
hostname]]
|
||||
:modal? true}]
|
||||
(when-not @has-loaded?
|
||||
[react/view
|
||||
{:style {:flex 1
|
||||
:position :absolute
|
||||
:top 56
|
||||
:left 0
|
||||
:right 0
|
||||
:z-index 1
|
||||
:background-color "#ffffff"
|
||||
:bottom 0
|
||||
:align-items :center
|
||||
:justify-content :center}}
|
||||
[photos/photo logo-url {:size 40}]
|
||||
[quo/text
|
||||
{:size :x-large}
|
||||
(i18n/label :t/opening-buy-crypto {:site name})]
|
||||
[react/view {:style {:padding-horizontal 32}}
|
||||
[quo/text
|
||||
{:align :center
|
||||
:color :secondary}
|
||||
(i18n/label :t/buy-crypto-leaving)]]])
|
||||
(when @initialized?
|
||||
[components.webview/webview
|
||||
{:onLoadEnd #(reset! has-loaded? true)
|
||||
:ref #(reset! webview-ref %)
|
||||
:on-permission-request #(browser.views/request-resources-access-for-page
|
||||
(-> ^js % .-nativeEvent .-resources)
|
||||
site-url
|
||||
@webview-ref)
|
||||
:java-script-enabled true
|
||||
;; This is to avoid crashes on android devices due to
|
||||
;; https://github.com/react-native-webview/react-native-webview/issues/1838
|
||||
;; We can't disable hardware acceleration as we need to use camera
|
||||
:style {:opacity 0.99}
|
||||
:local-storage-enabled true
|
||||
:source {:uri site-url}}])])))
|
||||
|
||||
(defn container
|
||||
[]
|
||||
(reagent/create-class
|
||||
{:component-did-mount #(re-frame/dispatch [:buy-crypto.ui/loaded])
|
||||
:reagent-render buy-crypto}))
|
||||
|
||||
(defn banner
|
||||
[]
|
||||
(fn []
|
||||
[react/touchable-highlight {:on-press on-buy-crypto-pressed}
|
||||
[react/view {:style (sheets/banner-container)}
|
||||
[react/view {:flex-direction :row}
|
||||
[react/view {:style (sheets/highlight-container)}
|
||||
[quo/text
|
||||
{:weight :bold
|
||||
:size :tiny
|
||||
:style sheets/highlight-text}
|
||||
(i18n/label :t/new)]]
|
||||
[react/view
|
||||
{:style {:justify-content :center
|
||||
:align-items :center
|
||||
:padding-left 8}}
|
||||
[quo/text
|
||||
{:size :large
|
||||
:weight :medium
|
||||
:color :link} (i18n/label :t/buy-crypto)]]]
|
||||
[react/view
|
||||
{:style {:align-content :flex-end
|
||||
:align-self :flex-end}}
|
||||
[react/image
|
||||
{:source (icons/icon-source :buy-crypto)
|
||||
:style sheets/icon}]]]]))
|
||||
@@ -1,314 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.wallet.collectibles.views
|
||||
(:require
|
||||
["react-native-svg" :refer (SvgUri)]
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||
[legacy.status-im.react-native.resources :as resources]
|
||||
[legacy.status-im.ui.components.accordion :as accordion]
|
||||
[legacy.status-im.ui.components.colors :as colors]
|
||||
[legacy.status-im.ui.components.core :as quo]
|
||||
[legacy.status-im.ui.components.icons.icons :as icons]
|
||||
[legacy.status-im.ui.components.list.item :as list.item]
|
||||
[legacy.status-im.ui.components.react :as react]
|
||||
[legacy.status-im.ui.components.toastable-highlight :refer [toastable-highlight-view]]
|
||||
[legacy.status-im.ui.components.topbar :as topbar]
|
||||
[legacy.status-im.ui.screens.wallet.components.views :as wallet.components]
|
||||
[legacy.status-im.wallet.core :as wallet-legacy]
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as reagent]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(def svg-uri (reagent/adapt-react-class SvgUri))
|
||||
|
||||
(defn is-image?
|
||||
[nft]
|
||||
(and (seq (:image_url nft))
|
||||
(not (string/ends-with? (:image_url nft) ".svg"))
|
||||
(not (string/ends-with? (:image_url nft) ".mp4"))))
|
||||
|
||||
(defn is-vector?
|
||||
[nft]
|
||||
(and (seq (:image_url nft))
|
||||
(string/ends-with? (:image_url nft) ".svg")))
|
||||
|
||||
(defn missing-image-placeholder
|
||||
[]
|
||||
[react/view
|
||||
{:style {:width "100%"
|
||||
:flex 1
|
||||
:align-items :center
|
||||
:border-radius 16
|
||||
:background-color colors/gray-lighter
|
||||
:justify-content :center
|
||||
:aspect-ratio 1}}
|
||||
[icons/icon :photo {:color colors/gray}]])
|
||||
|
||||
(defn nft-assets-skeleton
|
||||
[num-assets]
|
||||
[:<>
|
||||
(for [i (range num-assets)]
|
||||
^{:key i}
|
||||
[react/view
|
||||
{:style {:width "48%"
|
||||
:margin-bottom 16}}
|
||||
[react/view
|
||||
{:style {:flex 1
|
||||
:aspect-ratio 1
|
||||
:border-width 1
|
||||
:background-color colors/gray-transparent-10
|
||||
:border-color colors/gray-lighter
|
||||
:border-radius 16}}]])])
|
||||
|
||||
(defn nft-trait-card
|
||||
[trait]
|
||||
[react/view
|
||||
{:style {:border-width 1
|
||||
:border-radius 12
|
||||
:margin-right 8
|
||||
:padding-vertical 4
|
||||
:padding-horizontal 8
|
||||
:border-color colors/gray-lighter}}
|
||||
[quo/text
|
||||
{:size :small
|
||||
:color :secondary}
|
||||
(:trait_type trait)]
|
||||
[quo/text {}
|
||||
(:value trait)]])
|
||||
|
||||
(defn nft-traits-scroller
|
||||
[traits]
|
||||
[react/scroll-view
|
||||
{:horizontal true
|
||||
:deceleration-rate "fast"
|
||||
:snap-to-alignment "start"
|
||||
:shows-horizontal-scroll-indicator
|
||||
false
|
||||
:scroll-event-throttle 64
|
||||
:style {:padding-left 16
|
||||
:margin-vertical 16
|
||||
:padding-bottom 8}}
|
||||
(for [trait traits]
|
||||
^{:key (:trait_type trait)}
|
||||
[nft-trait-card trait])
|
||||
|
||||
;; spacer
|
||||
[react/view
|
||||
{:style {:height 40
|
||||
:width 40}}]])
|
||||
|
||||
(defn no-assets-error
|
||||
[]
|
||||
[react/view
|
||||
{:style {:flex 1
|
||||
:justify-content :center
|
||||
:padding 16
|
||||
:margin-vertical 16
|
||||
:align-items :center
|
||||
:border-radius 16}}
|
||||
[icons/icon :photo {:color colors/red}]
|
||||
[quo/text
|
||||
{:color :secondary
|
||||
:style {:magin-top 8}}
|
||||
(i18n/label :t/no-collectibles)]])
|
||||
|
||||
(defn render-asset
|
||||
[{:keys [asset width clickable?]}]
|
||||
[(if clickable? react/touchable-opacity react/view)
|
||||
{:style
|
||||
{:width width
|
||||
:border-radius 16
|
||||
:margin-bottom 16}
|
||||
:on-press (when clickable? #(re-frame/dispatch [::wallet-legacy/show-nft-details asset]))
|
||||
:accessibility-label
|
||||
:nft-asset}
|
||||
(cond
|
||||
;; pngs and jpegs
|
||||
(is-image? asset)
|
||||
[react/image
|
||||
{:style {:flex 1
|
||||
:aspect-ratio 1
|
||||
:border-width 1
|
||||
:border-color colors/gray-lighter
|
||||
:border-radius 16}
|
||||
:source {:uri (:image_url asset)}}]
|
||||
|
||||
;; vectors
|
||||
(is-vector? asset)
|
||||
[react/view
|
||||
{:style {:flex 1
|
||||
:aspect-ratio 1
|
||||
:border-width 1
|
||||
:border-color colors/gray-lighter
|
||||
:border-radius 16}}
|
||||
[svg-uri
|
||||
{:uri (:image_url asset)
|
||||
:width "100%"
|
||||
:height "100%"}]]
|
||||
|
||||
;; ¯\_(ツ)_/¯
|
||||
:else [missing-image-placeholder])])
|
||||
|
||||
(defn nft-assets
|
||||
[{:keys [num-assets address collectible-slug]}]
|
||||
(let [assets (rf/sub [:wallet-legacy/collectible-assets-by-collection-and-address address
|
||||
collectible-slug])
|
||||
fetching? (rf/sub [:wallet-legacy/fetching-assets-by-collectible-slug collectible-slug])]
|
||||
[react/view
|
||||
{:flex 1
|
||||
:flex-wrap :wrap
|
||||
:justify-content :space-between
|
||||
:flex-direction :row
|
||||
:style {:padding-horizontal 16}}
|
||||
(cond
|
||||
fetching? [nft-assets-skeleton num-assets]
|
||||
|
||||
;; <shivekkhurana> OpenSea sometimes doesn't return an asset. This condition handles it
|
||||
(and (not fetching?)
|
||||
(not (seq assets)))
|
||||
[no-assets-error]
|
||||
|
||||
(seq assets)
|
||||
(for [asset assets]
|
||||
^{:key (:id asset)}
|
||||
[render-asset
|
||||
{:asset asset
|
||||
:clickable? true
|
||||
:width "48%"}]))]))
|
||||
|
||||
(defn nft-collections
|
||||
[address]
|
||||
(let [collection (rf/sub [:wallet-legacy/collectible-collection address])]
|
||||
[:<>
|
||||
(for [[index collectible] (map-indexed vector collection)]
|
||||
^{:key (:slug collectible)}
|
||||
[accordion/section
|
||||
{:title
|
||||
[react/view {:flex 1}
|
||||
[list.item/list-item
|
||||
{:title (:name collectible)
|
||||
:text-size :large
|
||||
:accessibility-label
|
||||
(keyword (str "collection-" index))
|
||||
:icon (if (seq (:image_url collectible))
|
||||
[wallet.components/token-icon
|
||||
{:style {:border-radius 40
|
||||
:overflow :hidden
|
||||
:border-width 1
|
||||
:border-color colors/gray-lighter}
|
||||
:source {:uri (:image_url collectible)}}]
|
||||
:main-icons/photo)
|
||||
:accessory :text
|
||||
:accessory-text (:owned_asset_count collectible)}]]
|
||||
:padding-vertical 0
|
||||
:dropdown-margin-left -12
|
||||
:open-container-style {:border-top-width 8
|
||||
:border-bottom-width 8
|
||||
:border-color colors/gray-lighter}
|
||||
:on-open #(re-frame/dispatch
|
||||
[::wallet-legacy/fetch-collectible-assets-by-owner-and-collection
|
||||
address
|
||||
(:slug collectible)
|
||||
(:owned_asset_count collectible)])
|
||||
:content [nft-assets
|
||||
{:address address
|
||||
:num-assets (:owned_asset_count collectible)
|
||||
:collectible-slug (:slug collectible)}]}])]))
|
||||
|
||||
(defn enable-opensea-view
|
||||
[]
|
||||
[react/view {:style {:padding 16}}
|
||||
[react/view
|
||||
{:style {:border-color colors/gray-lighter
|
||||
:border-width 1
|
||||
:align-self :center
|
||||
:padding 4
|
||||
:border-radius 12}}
|
||||
[react/image
|
||||
{:source (resources/get-theme-image :collectible)
|
||||
:style {:align-self :center
|
||||
:resize-mode :contain}}]]
|
||||
[quo/text
|
||||
{:align :center
|
||||
:style {:margin-vertical 16}}
|
||||
(i18n/label :t/collectibles-leak-metadata)]
|
||||
[react/view {:align-items :center}
|
||||
[quo/button
|
||||
{:accessibility-label :enable-opensea-nft-visibility
|
||||
:on-press
|
||||
#(re-frame/dispatch
|
||||
[::multiaccounts.update/toggle-opensea-nfts-visiblity true])
|
||||
:theme :main
|
||||
:type :primary}
|
||||
(i18n/label :t/display-collectibles)]]
|
||||
[quo/text
|
||||
{:size :small
|
||||
:color :secondary
|
||||
:align :center
|
||||
:style {:margin-top 10}}
|
||||
(i18n/label :t/disable-later-in-settings)]])
|
||||
|
||||
(defn nft-details-modal
|
||||
[]
|
||||
(let [nft (rf/sub [:wallet-legacy/selected-collectible])]
|
||||
[react/scroll-view
|
||||
[topbar/topbar
|
||||
{:navigation {:icon :main-icons/close}
|
||||
:border-bottom false}]
|
||||
[react/view {:padding-horizontal 16}
|
||||
[quo/text
|
||||
{:size :large
|
||||
:weight :bold}
|
||||
(:name nft)]
|
||||
[quo/text
|
||||
{:size :small
|
||||
:color :secondary
|
||||
:style {:margin-top 4}}
|
||||
(-> nft :collection :name)]
|
||||
|
||||
[render-asset
|
||||
{:asset nft
|
||||
:clickable? false
|
||||
:width "100%"}]
|
||||
|
||||
[quo/text {:style {:margin-top 12}}
|
||||
(:description nft)]]
|
||||
|
||||
(when (seq (:traits nft))
|
||||
[nft-traits-scroller (:traits nft)])
|
||||
|
||||
;; seperator
|
||||
[react/view
|
||||
{:style {:border-bottom-width 1
|
||||
:padding-top 8
|
||||
:border-color colors/gray-lighter}}]
|
||||
|
||||
;; TODO <shivekkhurana>: Enable txns
|
||||
;; [list/list-item {:title (i18n/label :t/wallet-send)
|
||||
;; :icon :main-icons/send :accessibility-label :nft-send :theme :accent
|
||||
;; :on-press #()}]
|
||||
|
||||
;; TODO <shivekkhurana>: What to do with share? Share links or share image?
|
||||
;; [list/list-item {:title (i18n/label :t/share)
|
||||
;; :theme :accent
|
||||
;; :accessibility-label
|
||||
;; :nft-share
|
||||
;; :on-press #()
|
||||
;; :icon :main-icons/share}]
|
||||
[list.item/list-item
|
||||
{:title (i18n/label :t/view-on-opensea)
|
||||
:theme :accent
|
||||
:icon :main-icons/browser
|
||||
:on-press #(re-frame/dispatch [:browser.ui/open-url (:permalink nft)])}]
|
||||
(when (is-image? nft)
|
||||
[toastable-highlight-view
|
||||
;; the last string is an emoji. It might not show up in all editors but its there
|
||||
{:toast-label (str (i18n/label :t/profile-picture-updated)) " " "😎"}
|
||||
[list.item/list-item
|
||||
{:title (i18n/label :t/use-as-profile-picture)
|
||||
:theme :accent
|
||||
:on-press #(re-frame/dispatch [:profile.settings/save-profile-picture-from-url
|
||||
(:image_url nft)])
|
||||
:icon :main-icons/profile
|
||||
:accessibility-label
|
||||
:set-nft-as-pfp}]])]))
|
||||
@@ -1,13 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.wallet.components.styles
|
||||
(:require
|
||||
[legacy.status-im.ui.components.colors :as colors]))
|
||||
|
||||
(defn separator
|
||||
[]
|
||||
{:height 1
|
||||
:background-color colors/gray-lighter})
|
||||
|
||||
(defn separator-dark
|
||||
[]
|
||||
{:height 1
|
||||
:background-color colors/black-transparent})
|
||||
@@ -1,22 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.wallet.components.views
|
||||
(:require
|
||||
[legacy.status-im.ui.components.react :as react]
|
||||
[legacy.status-im.ui.screens.wallet.components.styles :as styles]))
|
||||
|
||||
(defn separator
|
||||
[]
|
||||
[react/view (styles/separator)])
|
||||
|
||||
(defn separator-dark
|
||||
[]
|
||||
[react/view (styles/separator-dark)])
|
||||
|
||||
(defn token-icon
|
||||
[{:keys [style source image-style width height]}]
|
||||
[react/view {:style style}
|
||||
[react/image
|
||||
{:source (if (fn? source) (source) source)
|
||||
:style (merge
|
||||
{:width (or width 40)
|
||||
:height (or height 40)}
|
||||
image-style)}]])
|
||||
@@ -1,171 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.wallet.custom-tokens.views
|
||||
(:require-macros [legacy.status-im.utils.views :refer [defview letsubs]])
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[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]
|
||||
[legacy.status-im.ui.components.toolbar :as toolbar]
|
||||
[legacy.status-im.ui.components.topbar :as topbar]
|
||||
[re-frame.core :as re-frame]
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
(def debounce-timers (atom {}))
|
||||
|
||||
(defn debounce-and-save
|
||||
[field-key value]
|
||||
(let [timeout (get @debounce-timers field-key)]
|
||||
(when timeout (js/clearTimeout timeout))
|
||||
(swap! debounce-timers assoc
|
||||
field-key
|
||||
(js/setTimeout
|
||||
#(re-frame/dispatch [:wallet-legacy.custom-token.ui/field-is-edited field-key
|
||||
(string/trim value)])
|
||||
500))))
|
||||
|
||||
(defview add-custom-token
|
||||
[]
|
||||
(letsubs [{:keys [contract name decimals in-progress? error error-name error-symbol]
|
||||
:as m}
|
||||
[:wallet-legacy/custom-token-screen]]
|
||||
(let [sym (:symbol m)]
|
||||
[react/keyboard-avoiding-view {:flex 1 :background-color colors/white}
|
||||
[react/scroll-view
|
||||
{:keyboard-should-persist-taps :handled
|
||||
:style {:flex 1
|
||||
:padding-horizontal 16}}
|
||||
[react/view {:padding-vertical 8}
|
||||
[react/view
|
||||
{:style {:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:padding-vertical 10}}
|
||||
[react/text (i18n/label :t/contract-address)]
|
||||
(when in-progress?
|
||||
[react/view {:flex-direction :row :justify-content :center}
|
||||
[react/view {:height 20}
|
||||
[react/activity-indicator {:width 24 :height 24 :animating true}]]
|
||||
[react/text {:style {:color colors/gray :margin-left 5}}
|
||||
(i18n/label :t/processing)]])]
|
||||
(when-not in-progress?
|
||||
;;tooltip covers button
|
||||
[react/view {:position :absolute :z-index 1000 :right 0 :top 10}
|
||||
[react/touchable-highlight
|
||||
{:on-press #(re-frame/dispatch [:wallet-legacy.custom-token.ui/contract-address-paste])}
|
||||
[react/text {:style {:color colors/blue}}
|
||||
(i18n/label :t/paste)]]])
|
||||
[quo/text-input
|
||||
{:on-change-text #(debounce-and-save :contract %)
|
||||
:error error
|
||||
:default-value contract
|
||||
:monospace true
|
||||
:multiline true
|
||||
:height 78
|
||||
:auto-focus false
|
||||
:placeholder (i18n/label :t/specify-address)}]]
|
||||
[react/view {:padding-vertical 8}
|
||||
[quo/text-input
|
||||
{:on-change-text #(debounce-and-save :name %)
|
||||
:label (i18n/label :t/name)
|
||||
:default-value name
|
||||
:error error-name
|
||||
:auto-focus false
|
||||
:placeholder (i18n/label :t/name-of-token)}]]
|
||||
[react/view {:padding-vertical 8}
|
||||
[react/view {:style {:flex-direction :row}}
|
||||
[react/view
|
||||
{:flex 1
|
||||
:padding-right 8}
|
||||
[quo/text-input
|
||||
{:on-change-text #(debounce-and-save :symbol %)
|
||||
:label (i18n/label :t/symbol)
|
||||
:error error-symbol
|
||||
:default-value sym
|
||||
:auto-focus false
|
||||
:show-cancel false
|
||||
:placeholder "ABC"}]]
|
||||
[react/view
|
||||
{:flex 1
|
||||
:padding-left 8}
|
||||
[quo/text-input
|
||||
{:label (i18n/label :t/decimals)
|
||||
:on-change-text #(debounce-and-save :decimals %)
|
||||
:default-value decimals
|
||||
:keyboard-type :number-pad
|
||||
:max-length 2
|
||||
:auto-focus false
|
||||
:show-cancel false
|
||||
:placeholder "18"}]]]]
|
||||
#_[quo/text-input
|
||||
{:label (i18n/label :t/balance)
|
||||
:default-value (when (and balance decimals)
|
||||
(wallet.utils/format-amount balance decimals))
|
||||
:editable false
|
||||
:placeholder (i18n/label :t/no-tokens-found)}]]
|
||||
|
||||
[toolbar/toolbar
|
||||
{:show-border? true
|
||||
:right
|
||||
[quo/button
|
||||
{:type :secondary
|
||||
:after :main-icon/next
|
||||
:disabled (boolean
|
||||
(or in-progress?
|
||||
error
|
||||
error-name
|
||||
error-symbol
|
||||
(string/blank? contract)
|
||||
(string/blank? name)
|
||||
(string/blank? sym)
|
||||
(string/blank? decimals)))
|
||||
:on-press #(re-frame/dispatch [:wallet-legacy.custom-token.ui/add-pressed])}
|
||||
(i18n/label :t/add)]}]])))
|
||||
|
||||
(defview custom-token-details
|
||||
[]
|
||||
(letsubs [{:keys [address name decimals custom?] :as token}
|
||||
[:get-screen-params]]
|
||||
[react/keyboard-avoiding-view
|
||||
{:style {:flex 1}
|
||||
:ignore-offset true}
|
||||
[topbar/topbar {:title name}]
|
||||
[react/scroll-view
|
||||
{:keyboard-should-persist-taps :handled
|
||||
:style {:flex 1}}
|
||||
[react/view {:padding-horizontal 16}
|
||||
[react/view {:padding-vertical 8}
|
||||
[quo/text-input
|
||||
{:label (i18n/label :t/contract-address)
|
||||
:default-value address
|
||||
:multiline true
|
||||
:height 78
|
||||
:editable false}]]
|
||||
[react/view {:padding-vertical 8}
|
||||
[quo/text-input
|
||||
{:label (i18n/label :t/name)
|
||||
:default-value name
|
||||
:editable false}]]
|
||||
[react/view {:padding-vertical 8}
|
||||
[react/view {:style {:flex-direction :row}}
|
||||
[react/view
|
||||
{:flex 1
|
||||
:padding-right 8}
|
||||
[quo/text-input
|
||||
{:label (i18n/label :t/symbol)
|
||||
:editable false
|
||||
:show-cancel false
|
||||
:default-value (:symbol token)}]]
|
||||
[react/view {:flex 1 :padding-left 8}
|
||||
[quo/text-input
|
||||
{:label (i18n/label :t/decimals)
|
||||
:show-cancel false
|
||||
:default-value (str decimals)
|
||||
:editable false}]]]]]
|
||||
[react/view {:height 24}]
|
||||
(when custom?
|
||||
[list.item/list-item
|
||||
{:theme :negative
|
||||
:title (i18n/label :t/remove-token)
|
||||
:icon :main-icons/delete
|
||||
:on-press #(re-frame/dispatch [:wallet-legacy.custom-token.ui/remove-pressed token
|
||||
true])}])]]))
|
||||
@@ -1,350 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.wallet.recipient.views
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.ui.components.chat-icon.screen :as chat-icon]
|
||||
[legacy.status-im.ui.components.colors :as colors]
|
||||
[legacy.status-im.ui.components.core :as quo]
|
||||
[legacy.status-im.ui.components.icons.icons :as icons]
|
||||
[legacy.status-im.ui.components.keyboard-avoid-presentation :as kb-presentation]
|
||||
[legacy.status-im.ui.components.list.item :as list.item]
|
||||
[legacy.status-im.ui.components.react :as react]
|
||||
[legacy.status-im.ui.components.search-input.view :as search-input]
|
||||
[legacy.status-im.ui.components.toolbar :as toolbar]
|
||||
[legacy.status-im.ui.components.topbar :as topbar]
|
||||
[legacy.status-im.ui.screens.wallet.components.views :as components]
|
||||
[legacy.status-im.utils.utils :as utils]
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as reagent]
|
||||
[utils.address :as address]
|
||||
[utils.debounce :as debounce]
|
||||
[utils.ens.stateofus :as stateofus]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.string :as utils.string])
|
||||
(:require-macros [legacy.status-im.utils.views :as views]))
|
||||
|
||||
(defn- recipient-topbar
|
||||
[]
|
||||
[topbar/topbar
|
||||
{:navigation {:on-press
|
||||
#(do
|
||||
(re-frame/dispatch [:wallet-legacy/recipient-modal-closed])
|
||||
(re-frame/dispatch [:wallet-legacy/search-recipient-filter-changed nil])
|
||||
(re-frame/dispatch [:navigate-back]))}
|
||||
:modal? true
|
||||
:border-bottom false
|
||||
:title (i18n/label :t/recipient)
|
||||
:right-accessories
|
||||
[{:icon :qr
|
||||
:accessibility-label :scan-contact-code-button
|
||||
:on-press #(re-frame/dispatch [:wallet-legacy.send/qr-scanner
|
||||
{:ignore-url true
|
||||
:handler :wallet-legacy.send/qr-scanner-result}])}]}])
|
||||
|
||||
(defonce search-active? (reagent/atom false))
|
||||
|
||||
(defn search-input-wrapper
|
||||
[]
|
||||
(let [search-filter @(re-frame/subscribe [:wallet-legacy/search-recipient-filter])]
|
||||
[react/view
|
||||
{:padding-horizontal 16
|
||||
:padding-vertical 10}
|
||||
[search-input/search-input-old
|
||||
{:search-active? search-active?
|
||||
:search-filter search-filter
|
||||
:on-cancel #(re-frame/dispatch [:wallet-legacy/search-recipient-filter-changed nil])
|
||||
:on-change (fn [text]
|
||||
(re-frame/dispatch [:wallet-legacy/search-recipient-filter-changed text])
|
||||
(re-frame/dispatch [:set-in [:contacts/new-identity :state] :searching])
|
||||
(debounce/debounce-and-dispatch [:contacts/set-new-identity {:input text}]
|
||||
300))}]]))
|
||||
|
||||
(defn section
|
||||
[_ _ _]
|
||||
(let [opened? (reagent/atom false)]
|
||||
(fn [title cnt content]
|
||||
[react/view {:padding-vertical 8}
|
||||
[list.item/list-item
|
||||
{:title title
|
||||
:on-press #(swap! opened? not)
|
||||
:accessory
|
||||
[react/view {:flex-direction :row :align-items :center}
|
||||
(when (pos? cnt)
|
||||
[react/text {:style {:color colors/gray}} cnt])
|
||||
[icons/icon (if @opened? :main-icons/dropdown :main-icons/next)
|
||||
{:container-style {:align-items :center
|
||||
:margin-left 8
|
||||
:justify-content :center}
|
||||
:resize-mode :center
|
||||
:color colors/black}]]}]
|
||||
(when @opened?
|
||||
content)])))
|
||||
|
||||
(defn render-account
|
||||
[account]
|
||||
[list.item/list-item
|
||||
{:icon [chat-icon/custom-icon-view-list (:name account) (:color account)]
|
||||
:title (:name account)
|
||||
:on-press #(re-frame/dispatch [:wallet-legacy.send/set-recipient (:address account)])
|
||||
:subtitle [quo/text
|
||||
{:monospace true
|
||||
:color :secondary}
|
||||
(utils/get-shortened-checksum-address (:address account))]}])
|
||||
|
||||
(def scroll-view-ref (atom nil))
|
||||
|
||||
(defn contacts-list-item
|
||||
[{:keys [name] :as contact}]
|
||||
[list.item/list-item
|
||||
{:title (:primary-name contact)
|
||||
:subtitle (:secondary-name contact)
|
||||
:on-press #(do
|
||||
(some-> ^js @scroll-view-ref
|
||||
(.scrollTo #js {:x 0 :animated true}))
|
||||
(re-frame/dispatch [:wallet-legacy.recipient/address-changed name]))
|
||||
:icon [chat-icon/contact-icon-contacts-tab contact]}])
|
||||
|
||||
(defn empty-items
|
||||
[icon title]
|
||||
[react/view {:height 94 :align-items :center :justify-content :center}
|
||||
[icons/icon icon
|
||||
{:color colors/gray}]
|
||||
[react/text {:style {:color colors/gray :margin-top 8}}
|
||||
title]])
|
||||
|
||||
(views/defview accounts-section
|
||||
[]
|
||||
(views/letsubs [accounts [:accounts-for-recipient]]
|
||||
(let [cnt (count accounts)]
|
||||
[section
|
||||
(i18n/label :t/my-accounts)
|
||||
cnt
|
||||
(if (> cnt 0)
|
||||
[react/view
|
||||
(for [account accounts]
|
||||
[render-account account])]
|
||||
[empty-items :main-icons/address (i18n/label :t/my-accounts-empty)])])))
|
||||
|
||||
(defn render-recent
|
||||
[{:keys [from to type amount-text currency-text]}]
|
||||
(let [inbound? (= type :inbound)
|
||||
address (if inbound? from to)]
|
||||
[list.item/list-item
|
||||
{:title [quo/text {:monospace true}
|
||||
(utils/get-shortened-checksum-address address)]
|
||||
:on-press #(re-frame/dispatch [:wallet-legacy.recipient/address-changed address])
|
||||
:size :small
|
||||
:accessory [react/text
|
||||
{:style {:flex-shrink 1
|
||||
:color colors/gray}}
|
||||
(str (if inbound? "↓ " "↑ ") amount-text " " currency-text)]}]))
|
||||
|
||||
(defn recent-section
|
||||
[]
|
||||
(let [{:keys [from]} @(re-frame/subscribe [:wallet-legacy/prepare-transaction])
|
||||
txs @(re-frame/subscribe [:wallet-legacy/recipient-recent-txs (:address from)])
|
||||
cnt (count txs)]
|
||||
[section
|
||||
(i18n/label :t/recent)
|
||||
cnt
|
||||
(if (> cnt 0)
|
||||
[react/view
|
||||
(for [tx txs]
|
||||
[render-recent tx])]
|
||||
[empty-items :main-icons/history (i18n/label :t/recent-empty)])]))
|
||||
|
||||
(defn render-fav
|
||||
[{:keys [address name]}]
|
||||
(let [noname? (string/blank? name)
|
||||
short-address (utils/get-shortened-checksum-address address)]
|
||||
[list.item/list-item
|
||||
{:icon [chat-icon/custom-icon-view-list
|
||||
(if noname? " 2" name)
|
||||
(rand-nth colors/chat-colors)]
|
||||
:title (if noname?
|
||||
[quo/text {:monospace true}
|
||||
short-address]
|
||||
name)
|
||||
:subtitle (when-not noname?
|
||||
[quo/text
|
||||
{:monospace true
|
||||
:color :secondary}
|
||||
short-address])
|
||||
:on-press #(re-frame/dispatch [:wallet-legacy.send/set-recipient address])
|
||||
:size (when noname? :small)}]))
|
||||
|
||||
(views/defview fav-section
|
||||
[]
|
||||
(views/letsubs [favourites [:wallet-legacy/favourites-filtered]]
|
||||
(let [cnt (count favourites)]
|
||||
[section
|
||||
(i18n/label :t/favourites)
|
||||
cnt
|
||||
[react/view
|
||||
;;TODO implement later
|
||||
#_[list/list-item
|
||||
{:title "Add favourite"
|
||||
:icon :main-icons/add
|
||||
:theme :accent}]
|
||||
(if (> cnt 0)
|
||||
[react/view
|
||||
(for [data favourites]
|
||||
[render-fav data])]
|
||||
[empty-items :main-icons/favourite (i18n/label :t/favourites-empty)])]])))
|
||||
|
||||
(views/defview contacts-section
|
||||
[]
|
||||
(views/letsubs [contacts [:contacts/active-with-ens-names]]
|
||||
(let [cnt (count contacts)]
|
||||
[section
|
||||
(i18n/label :t/contacts)
|
||||
cnt
|
||||
(if (> cnt 0)
|
||||
[react/view
|
||||
(for [contact contacts]
|
||||
[contacts-list-item contact])]
|
||||
[empty-items :main-icons/username (i18n/label :t/contacts-empty)])])))
|
||||
|
||||
(views/defview search-results
|
||||
[]
|
||||
(views/letsubs [contacts [:contacts/active-with-ens-names]
|
||||
favourites [:wallet-legacy/favourites-filtered]
|
||||
accounts [:accounts-for-recipient]]
|
||||
[react/view
|
||||
(for [account accounts]
|
||||
[render-account account])
|
||||
(for [data favourites]
|
||||
[render-fav data])
|
||||
(for [contact contacts]
|
||||
[contacts-list-item contact])]))
|
||||
|
||||
(defn accordion
|
||||
[search-filter]
|
||||
(if (not (string/blank? search-filter))
|
||||
[search-results]
|
||||
[react/view
|
||||
[components/separator]
|
||||
[accounts-section]
|
||||
[components/separator]
|
||||
[recent-section]
|
||||
[components/separator]
|
||||
[fav-section]
|
||||
[components/separator]
|
||||
[contacts-section]
|
||||
[components/separator]]))
|
||||
|
||||
(views/defview new-favourite
|
||||
[]
|
||||
(views/letsubs [{:keys [resolved-address]} [:wallet-legacy/recipient]
|
||||
fav-name (atom "")]
|
||||
[kb-presentation/keyboard-avoiding-view {:style {:flex 1}}
|
||||
[react/view {:flex 1}
|
||||
[react/scroll-view {:style {:flex 1}}
|
||||
[react/view {:padding-horizontal 16}
|
||||
[react/view
|
||||
{:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:align-items :center
|
||||
:height 40
|
||||
:margin-vertical 8}
|
||||
[quo/text (i18n/label :t/address-or-ens-name)]]
|
||||
[quo/text-input
|
||||
{:multiline true
|
||||
:default-value resolved-address
|
||||
:height 70
|
||||
:editable false
|
||||
:accessibility-label :fav-address}]]
|
||||
[react/view {:height 16}]
|
||||
[quo/list-header (i18n/label :t/name-optional)]
|
||||
[react/view {:padding-horizontal 16}
|
||||
[quo/text-input
|
||||
{:show-cancel false
|
||||
:accessibility-label :fav-name
|
||||
:on-change-text #(reset! fav-name %)}]]]
|
||||
[toolbar/toolbar
|
||||
{:show-border? true
|
||||
:center
|
||||
[quo/button
|
||||
{:accessibility-label :add-fav
|
||||
:type :secondary
|
||||
:on-press #(re-frame/dispatch [:wallet-legacy/add-favourite resolved-address
|
||||
@fav-name])}
|
||||
(i18n/label :t/add)]}]]]))
|
||||
|
||||
(views/defview recipient
|
||||
[]
|
||||
(views/letsubs [{:keys [address resolved-address searching]} [:wallet-legacy/recipient]
|
||||
search-filter [:wallet-legacy/search-recipient-filter]]
|
||||
(let [disabled? (or searching (not resolved-address))]
|
||||
[kb-presentation/keyboard-avoiding-view
|
||||
{:style {:flex 1}
|
||||
:ignore-offset true}
|
||||
[react/view {:flex 1}
|
||||
[recipient-topbar]
|
||||
[search-input-wrapper]
|
||||
[react/scroll-view
|
||||
{:style {:flex 1}
|
||||
:keyboard-should-persist-taps :handled
|
||||
:ref #(reset! scroll-view-ref %)}
|
||||
[react/view
|
||||
[components/separator]
|
||||
[react/view {:padding-horizontal 16 :margin-bottom 16}
|
||||
[react/view
|
||||
{:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:align-items :center
|
||||
:height 40
|
||||
:margin-vertical 8}
|
||||
[quo/text (i18n/label :t/address-or-ens-name)]
|
||||
[quo/button
|
||||
{:type :secondary
|
||||
:on-press #(re-frame/dispatch [:wallet-legacy.recipient/address-paste-pressed])}
|
||||
(i18n/label :t/paste)]]
|
||||
[quo/text-input
|
||||
{:multiline true
|
||||
:default-value address
|
||||
:height 70
|
||||
:placeholder (i18n/label :t/recipient-code-placeholder)
|
||||
:text-align-vertical :top
|
||||
:on-change-text #(do
|
||||
(re-frame/dispatch [:set-in [:wallet-legacy/recipient :searching]
|
||||
:searching])
|
||||
(debounce/debounce-and-dispatch
|
||||
[:wallet-legacy.recipient/address-changed
|
||||
(utils.string/safe-trim %)]
|
||||
600))
|
||||
:accessibility-label :recipient-address-input}]]
|
||||
[react/view {:align-items :center :height 30 :padding-bottom 8}
|
||||
(if searching
|
||||
[react/small-loading-indicator]
|
||||
(when resolved-address
|
||||
[quo/text
|
||||
{:style {:margin-horizontal 16}
|
||||
:size :small
|
||||
:align :center
|
||||
:color :secondary}
|
||||
(when-not (address/address? address)
|
||||
(str (stateofus/username-with-domain address) " • "))
|
||||
[quo/text
|
||||
{:monospace true
|
||||
:size :inherit
|
||||
:color :inherit}
|
||||
(utils/get-shortened-address resolved-address)]]))]
|
||||
[accordion search-filter]]]
|
||||
[toolbar/toolbar
|
||||
{:show-border? true
|
||||
:left
|
||||
[quo/button
|
||||
{:accessibility-label :participant-add-to-favs
|
||||
:type :secondary
|
||||
:disabled disabled?
|
||||
:on-press #(re-frame/dispatch [:open-modal :new-favourite])}
|
||||
(i18n/label :t/add-to-favourites)]
|
||||
:right
|
||||
[quo/button
|
||||
{:accessibility-label :participant-done
|
||||
:type :secondary
|
||||
:after :main-icons/next
|
||||
:disabled disabled?
|
||||
:on-press #(re-frame/dispatch [:wallet-legacy.send/set-recipient
|
||||
resolved-address])}
|
||||
(i18n/label :t/done)]}]]])))
|
||||
@@ -1,42 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.wallet.request.views
|
||||
(:require
|
||||
[legacy.status-im.ui.components.copyable-text :as copyable-text]
|
||||
[legacy.status-im.ui.components.core :as quo]
|
||||
[legacy.status-im.ui.components.react :as react]
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.common.qr-codes.view :as qr-codes]
|
||||
[utils.ethereum.eip.eip55 :as eip55]
|
||||
[utils.ethereum.eip.eip681 :as eip681]
|
||||
[utils.i18n :as i18n])
|
||||
(:require-macros [legacy.status-im.utils.views :as views]))
|
||||
|
||||
(views/defview share-address
|
||||
[]
|
||||
(views/letsubs [{:keys [address]} [:popover/popover]
|
||||
chain-id [:chain-id]
|
||||
width (reagent/atom nil)]
|
||||
[react/view {:on-layout #(reset! width (-> ^js % .-nativeEvent .-layout .-width))}
|
||||
[react/view {:style {:padding-top 16 :padding-horizontal 16}}
|
||||
(when @width
|
||||
[qr-codes/qr-code
|
||||
{:url (eip681/generate-uri address {:chain-id chain-id})
|
||||
:size (- @width 32)}])
|
||||
[copyable-text/copyable-text-view
|
||||
{:label :t/ethereum-address
|
||||
:container-style {:margin-top 12 :margin-bottom 4}
|
||||
:copied-text (eip55/address->checksum address)}
|
||||
[quo/text
|
||||
{:number-of-lines 1
|
||||
:ellipsize-mode :middle
|
||||
:accessibility-label :address-text
|
||||
:monospace true}
|
||||
(eip55/address->checksum address)]]]
|
||||
[react/view
|
||||
{:padding-top 12
|
||||
:padding-horizontal 16
|
||||
:padding-bottom 16}
|
||||
[quo/button
|
||||
{:on-press #(re-frame/dispatch [:wallet-legacy.accounts/share address])
|
||||
:accessibility-label :share-address-button}
|
||||
(i18n/label :t/share-address)]]]))
|
||||
@@ -1,53 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.wallet.send.sheets
|
||||
(:require-macros [legacy.status-im.utils.views :as views])
|
||||
(:require
|
||||
[legacy.status-im.ui.components.chat-icon.screen :as chat-icon]
|
||||
[legacy.status-im.ui.components.list.item :as list.item]
|
||||
[legacy.status-im.ui.components.list.views :as list]
|
||||
[legacy.status-im.ui.components.react :as react]
|
||||
[legacy.status-im.ui.screens.wallet.accounts.common :as common]
|
||||
[re-frame.core :as re-frame]))
|
||||
|
||||
(defn asset
|
||||
[currency token]
|
||||
[react/touchable-highlight
|
||||
{:on-press #(re-frame/dispatch [:wallet-legacy.send/set-symbol (:symbol token)])}
|
||||
[common/render-asset token nil nil (:code currency)]])
|
||||
|
||||
(views/defview assets
|
||||
[address]
|
||||
(views/letsubs [{:keys [tokens]} [:wallet-legacy/visible-assets-with-values address]
|
||||
currency [:wallet-legacy/currency]]
|
||||
[react/view
|
||||
{:style {:height 300}}
|
||||
[list/flat-list
|
||||
{:data tokens
|
||||
:key-fn :symbol
|
||||
:render-fn (partial asset currency)}]]))
|
||||
|
||||
(defn render-account
|
||||
[account _ _ {:keys [field event]}]
|
||||
[list.item/list-item
|
||||
{:icon [chat-icon/custom-icon-view-list (:name account) (:color account)]
|
||||
:title (:name account)
|
||||
:on-press #(re-frame/dispatch [event field account])}])
|
||||
|
||||
(views/defview accounts-list
|
||||
[field event]
|
||||
(views/letsubs [accounts [:multiaccount/visible-accounts]
|
||||
accounts-whithout-watch [:visible-accounts-without-watch-only]]
|
||||
[list/flat-list
|
||||
{:data (if (= :to field) accounts accounts-whithout-watch)
|
||||
:key-fn :address
|
||||
:render-data {:field field
|
||||
:event event}
|
||||
:render-fn render-account}]))
|
||||
|
||||
(defn show-accounts-list
|
||||
[]
|
||||
(re-frame/dispatch [:bottom-sheet/hide-old])
|
||||
(js/setTimeout #(re-frame/dispatch [:bottom-sheet/show-sheet-old
|
||||
{:content (fn [] [accounts-list :to
|
||||
:wallet-legacy.send/set-field])
|
||||
:content-height 300}])
|
||||
400))
|
||||
@@ -1,34 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.wallet.send.styles
|
||||
(:require
|
||||
[legacy.status-im.ui.components.colors :as colors]))
|
||||
|
||||
(defn sheet
|
||||
[]
|
||||
{:flex 1})
|
||||
|
||||
(defn acc-sheet
|
||||
[]
|
||||
{:background-color colors/white
|
||||
:border-top-right-radius 16
|
||||
:border-top-left-radius 16
|
||||
:padding-bottom 60})
|
||||
|
||||
(defn header
|
||||
[small-screen?]
|
||||
{:flex-direction :row
|
||||
:align-items :center
|
||||
:justify-content :space-between
|
||||
:padding-top (when-not small-screen? 16)
|
||||
:padding-left 16})
|
||||
|
||||
(defn set-max-button
|
||||
[]
|
||||
{:height 35
|
||||
:border-radius 40
|
||||
:background-color colors/blue-light
|
||||
:margin-horizontal 12
|
||||
:align-self :flex-start
|
||||
:margin-bottom 12
|
||||
:align-items :center
|
||||
:justify-content :center
|
||||
:padding-horizontal 12})
|
||||
@@ -1,271 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.wallet.send.views
|
||||
(:require-macros [legacy.status-im.utils.views :as views])
|
||||
(:require
|
||||
[legacy.status-im.ui.components.chat-icon.screen :as chat-icon]
|
||||
[legacy.status-im.ui.components.colors :as colors]
|
||||
[legacy.status-im.ui.components.core :as components.core]
|
||||
[legacy.status-im.ui.components.icons.icons :as icons]
|
||||
[legacy.status-im.ui.components.keyboard-avoid-presentation :as kb-presentation]
|
||||
[legacy.status-im.ui.components.list.item :as list.item]
|
||||
[legacy.status-im.ui.components.react :as react]
|
||||
[legacy.status-im.ui.components.toolbar :as toolbar]
|
||||
[legacy.status-im.ui.components.tooltip.views :as tooltip]
|
||||
[legacy.status-im.ui.screens.wallet.components.views :as components]
|
||||
[legacy.status-im.ui.screens.wallet.send.sheets :as sheets]
|
||||
[legacy.status-im.ui.screens.wallet.send.styles :as styles]
|
||||
[legacy.status-im.utils.utils :as utils]
|
||||
[legacy.status-im.wallet.utils :as wallet.utils]
|
||||
[quo.core :as quo]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.contexts.profile.utils :as profile.utils]
|
||||
[utils.address :as address]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.money :as money]))
|
||||
|
||||
(defn header
|
||||
[{:keys [label small-screen?]}]
|
||||
[react/view (styles/header small-screen?)
|
||||
[react/view {:flex 1}
|
||||
[react/text {:style (merge {:typography :title-bold} (when small-screen? {:font-size 15}))}
|
||||
(i18n/label (or label :t/send-transaction))]]])
|
||||
|
||||
(defn asset-selector
|
||||
[{:keys [request? token from]} window-width]
|
||||
(let [{:keys [name icon color]} token]
|
||||
[react/touchable-highlight
|
||||
{:on-press (when-not request?
|
||||
#(do
|
||||
(re-frame/dispatch [:dismiss-keyboard])
|
||||
(re-frame/dispatch [:bottom-sheet/show-sheet-old
|
||||
{:content (fn [] [sheets/assets (:address from)])
|
||||
:content-height 300}])))}
|
||||
[react/view
|
||||
{:style {:flex-direction :row
|
||||
:align-items :center
|
||||
:margin-left 16}
|
||||
:accessibility-label :choose-asset-button}
|
||||
(if icon
|
||||
[components/token-icon
|
||||
(assoc icon
|
||||
:style {:background-color colors/gray-lighter
|
||||
:border-radius 50}
|
||||
:image-style {:width 32 :height 32})]
|
||||
[chat-icon/custom-icon-view-list name color 32])
|
||||
[react/text
|
||||
{:style {:margin-left 8
|
||||
:max-width (/ window-width 4)}
|
||||
:number-of-lines 2}
|
||||
(wallet.utils/display-symbol token)]
|
||||
(when-not request?
|
||||
[icons/icon :main-icons/dropdown {:color colors/gray}])]]))
|
||||
|
||||
(defn render-account
|
||||
[account {:keys [amount decimals] :as token} event]
|
||||
[list.item/list-item
|
||||
{:icon [chat-icon/custom-icon-view-list (:name account) (:color account)]
|
||||
:title (:name account)
|
||||
:subtitle (when token
|
||||
(str (wallet.utils/format-amount amount decimals)
|
||||
" "
|
||||
(wallet.utils/display-symbol token)))
|
||||
:chevron true
|
||||
:on-press #(do
|
||||
(re-frame/dispatch [:dismiss-keyboard])
|
||||
(re-frame/dispatch [:bottom-sheet/show-sheet-old
|
||||
{:content (fn [] [sheets/accounts-list :from event])
|
||||
:content-height 300}]))}])
|
||||
|
||||
(defn render-contact
|
||||
[{:keys [address] :as contact} from-chat?]
|
||||
(if from-chat?
|
||||
[list.item/list-item
|
||||
{:title (profile.utils/displayed-name contact)
|
||||
:subtitle [components.core/text
|
||||
{:monospace true
|
||||
:color :secondary}
|
||||
(utils/get-shortened-checksum-address address)]
|
||||
:icon [chat-icon/contact-icon-contacts-tab contact]}]
|
||||
[list.item/list-item
|
||||
(merge {:title (if-not contact
|
||||
(i18n/label :t/wallet-choose-recipient)
|
||||
[components.core/text
|
||||
{:size :large
|
||||
:monospace true}
|
||||
(utils/get-shortened-checksum-address
|
||||
(if (string? contact) contact address))])
|
||||
:accessibility-label :choose-recipient-button
|
||||
:on-press #(do
|
||||
(re-frame/dispatch [:dismiss-keyboard])
|
||||
(re-frame/dispatch
|
||||
[:wallet-legacy.send/navigate-to-recipient-code]))
|
||||
:chevron true}
|
||||
(when-not contact
|
||||
{:icon :main-icons/add
|
||||
:theme :accent}))]))
|
||||
|
||||
(defn set-max
|
||||
[token]
|
||||
[react/touchable-highlight
|
||||
{:on-press
|
||||
#(when token
|
||||
(re-frame/dispatch [:wallet-legacy.send/set-max-amount token]))}
|
||||
[react/view {:style (styles/set-max-button)}
|
||||
[react/text {:style {:color colors/blue}} (i18n/label :t/set-max)]]])
|
||||
|
||||
(defn fiat-value
|
||||
[amount {sym :symbol} prices wallet-currency]
|
||||
(when-let [price (get-in prices [(keyword sym) (keyword (:code wallet-currency)) :price])]
|
||||
(let [norm-amount (js/parseFloat (money/normalize amount))
|
||||
amount (if (js/isNaN norm-amount) 0 norm-amount)]
|
||||
[react/text
|
||||
{:style {:color colors/gray
|
||||
:margin-left 16
|
||||
:margin-bottom 8
|
||||
:font-size 15
|
||||
:line-height 22}}
|
||||
(str (i18n/format-currency (* amount price) (:code wallet-currency))
|
||||
" "
|
||||
(:code wallet-currency))])))
|
||||
|
||||
(views/defview request-transaction
|
||||
[_]
|
||||
(views/letsubs [{:keys [amount-error amount-text from token sign-enabled?] :as tx}
|
||||
[:wallet-legacy.request/prepare-transaction-with-balance]
|
||||
window-width [:dimensions/window-width]
|
||||
prices [:prices]
|
||||
wallet-currency [:wallet-legacy/currency]]
|
||||
[kb-presentation/keyboard-avoiding-view {:style {:flex 1}}
|
||||
[:<>
|
||||
[react/scroll-view
|
||||
{:style {:flex 1}
|
||||
:keyboard-should-persist-taps :handled}
|
||||
[react/view {:style (styles/sheet)}
|
||||
[react/view
|
||||
{:flex-direction :row
|
||||
:padding-horizontal 24
|
||||
:align-items :center
|
||||
:margin-vertical 16}
|
||||
[react/text-input
|
||||
{:style {:font-size 38
|
||||
:color (if amount-error colors/red colors/black)
|
||||
:flex-shrink 1}
|
||||
:keyboard-type :decimal-pad
|
||||
:auto-capitalize :words
|
||||
:accessibility-label :amount-input
|
||||
:default-value amount-text
|
||||
:auto-focus true
|
||||
:on-change-text #(re-frame/dispatch [:wallet-legacy.request/set-amount-text %])
|
||||
:placeholder "0.0 "}]
|
||||
[asset-selector tx window-width]
|
||||
(when amount-error
|
||||
[tooltip/tooltip amount-error
|
||||
{:bottom-value 2
|
||||
:font-size 12}])]
|
||||
[fiat-value amount-text token prices wallet-currency]
|
||||
[components/separator]
|
||||
[components.core/list-header
|
||||
(i18n/label :t/to-capitalized)]
|
||||
[react/view {:flex-direction :row :flex 1 :align-items :center}
|
||||
[react/view {:flex 1}
|
||||
[render-account from token :wallet-legacy.request/set-field]]]]]
|
||||
[toolbar/toolbar
|
||||
{:show-border? true
|
||||
:right
|
||||
[components.core/button
|
||||
{:type :secondary
|
||||
:after :main-icon/next
|
||||
:accessibility-label :request-transaction-bottom-sheet
|
||||
:disabled (not sign-enabled?)
|
||||
:on-press #(do
|
||||
(re-frame/dispatch
|
||||
[:wallet-legacy.ui/request-transaction-button-clicked tx])
|
||||
(re-frame/dispatch [:navigate-back]))}
|
||||
(i18n/label :t/wallet-request)]}]]]))
|
||||
|
||||
(views/defview prepare-send-transaction
|
||||
[_]
|
||||
(views/letsubs [{:keys [amount-error amount-text
|
||||
request?
|
||||
from token to sign-enabled? from-chat?]
|
||||
:as tx}
|
||||
[:wallet-legacy.send/prepare-transaction-with-balance]
|
||||
prices [:prices]
|
||||
wallet-currency [:wallet-legacy/currency]
|
||||
window-width [:dimensions/window-width]]
|
||||
(let [to-norm (address/normalized-hex (if (string? to) to (:address to)))]
|
||||
[kb-presentation/keyboard-avoiding-view {:style {:flex 1}}
|
||||
[:<>
|
||||
[quo/page-nav
|
||||
{:type :title
|
||||
:text-align :left
|
||||
:title (i18n/label :t/send-transaction)
|
||||
:icon-name :i/arrow-left
|
||||
:on-press (fn []
|
||||
(re-frame/dispatch [:navigate-back])
|
||||
(re-frame/dispatch [:wallet-legacy/cancel-transaction-command]))
|
||||
:accessibility-label :back-button}]
|
||||
[react/scroll-view
|
||||
{:style {:flex 1}
|
||||
:keyboard-should-persist-taps :handled}
|
||||
[react/view {:style (styles/sheet)}
|
||||
[react/view
|
||||
{:flex-direction :row
|
||||
:padding-horizontal 16
|
||||
:align-items :center
|
||||
:margin-top 12
|
||||
:margin-bottom 4}
|
||||
[react/text-input
|
||||
{:style {:font-size 38
|
||||
:max-width (- (* (/ window-width 4) 3) 106)
|
||||
:color (if amount-error colors/red colors/black)}
|
||||
:keyboard-type :decimal-pad
|
||||
:auto-capitalize :words
|
||||
:accessibility-label :amount-input
|
||||
:default-value amount-text
|
||||
:editable (not request?)
|
||||
:auto-focus true
|
||||
:on-change-text #(re-frame/dispatch [:wallet-legacy.send/set-amount-text %])
|
||||
:placeholder "0.0 "}]
|
||||
[asset-selector tx window-width]
|
||||
(when amount-error
|
||||
[tooltip/tooltip
|
||||
(if from
|
||||
amount-error
|
||||
(i18n/label :t/select-account-first))
|
||||
{:bottom-value 2
|
||||
:font-size 12}])]
|
||||
[fiat-value amount-text token prices wallet-currency]
|
||||
(when-not (or request? from-chat?)
|
||||
[set-max token])
|
||||
[components/separator]
|
||||
[components.core/list-header (i18n/label :t/from-capitalized)]
|
||||
[react/view {:flex-direction :row :flex 1 :align-items :center}
|
||||
[react/view {:flex 1}
|
||||
[render-account from token :wallet-legacy.send/set-field]]]
|
||||
[components.core/list-header
|
||||
(i18n/label :t/to-capitalized)]
|
||||
[react/view {:flex-direction :row :flex 1 :align-items :center}
|
||||
[react/view {:flex 1}
|
||||
[render-contact to from-chat?]]]]]
|
||||
[toolbar/toolbar
|
||||
{:show-border? true
|
||||
:right
|
||||
[quo/button
|
||||
{:accessibility-label :send-transaction-bottom-sheet
|
||||
:type :secondary
|
||||
:after :main-icon/next
|
||||
:disabled (not sign-enabled?)
|
||||
:on-press #(do
|
||||
(re-frame/dispatch [:navigate-back])
|
||||
(re-frame/dispatch
|
||||
[(cond
|
||||
request?
|
||||
:wallet-legacy.ui/sign-transaction-button-clicked-from-request
|
||||
from-chat?
|
||||
:wallet-legacy.ui/sign-transaction-button-clicked-from-chat
|
||||
:else
|
||||
:wallet-legacy.ui/sign-transaction-button-clicked) tx]))}
|
||||
|
||||
(if (and (not request?) from-chat? (not to-norm))
|
||||
(i18n/label :t/wallet-send)
|
||||
(i18n/label :t/next))]}]]])))
|
||||
@@ -1,125 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.wallet.settings.views
|
||||
(:require
|
||||
[legacy.status-im.ui.components.chat-icon.screen :as chat-icon]
|
||||
[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.list.views :as list]
|
||||
[legacy.status-im.ui.components.react :as react]
|
||||
[legacy.status-im.ui.components.search-input.view :as search-input]
|
||||
[legacy.status-im.ui.components.topbar :as topbar]
|
||||
[legacy.status-im.ui.screens.wallet.components.views :as wallet.components]
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as reagent]
|
||||
[utils.i18n :as i18n])
|
||||
(:require-macros [legacy.status-im.utils.views :refer [defview letsubs]]))
|
||||
|
||||
(defonce search-active? (reagent/atom false))
|
||||
|
||||
(defn toolbar
|
||||
[]
|
||||
[topbar/topbar
|
||||
{:title (i18n/label :t/wallet-assets)
|
||||
:navigation
|
||||
{:on-press #(re-frame/dispatch [:wallet-legacy.settings.ui/navigate-back-pressed])}}])
|
||||
|
||||
(defn hide-sheet-and-dispatch
|
||||
[event]
|
||||
(re-frame/dispatch [:bottom-sheet/hide-old])
|
||||
(re-frame/dispatch event))
|
||||
|
||||
(defn custom-token-actions-view
|
||||
[{:keys [custom?] :as token}]
|
||||
(fn []
|
||||
[react/view
|
||||
[list.item/list-item
|
||||
{:theme :accent
|
||||
:title (i18n/label :t/token-details)
|
||||
:icon :main-icons/warning
|
||||
:on-press #(hide-sheet-and-dispatch
|
||||
[:navigate-to :wallet-custom-token-details token])}]
|
||||
(when custom?
|
||||
[list.item/list-item
|
||||
{:theme :negative
|
||||
:title (i18n/label :t/remove-token)
|
||||
:icon :main-icons/delete
|
||||
:on-press #(hide-sheet-and-dispatch
|
||||
[:wallet-legacy.custom-token.ui/remove-pressed token])}])]))
|
||||
|
||||
(defn render-token
|
||||
[_]
|
||||
(reagent/create-class
|
||||
{:should-component-update
|
||||
(fn [_ [_ old-token] [_ new-token]]
|
||||
(not= (:checked? old-token) (:checked? new-token)))
|
||||
:reagent-render
|
||||
(fn [{sym :symbol
|
||||
title :name
|
||||
icon :icon
|
||||
color :color
|
||||
checked? :checked?
|
||||
:as token}]
|
||||
[list.item/list-item
|
||||
{:active checked?
|
||||
:accessory :checkbox
|
||||
:animated-accessory? false
|
||||
:animated false
|
||||
:icon (if icon
|
||||
[wallet.components/token-icon icon]
|
||||
[chat-icon/custom-icon-view-list title color])
|
||||
:title title
|
||||
:subtitle (name sym)
|
||||
:on-press #(re-frame/dispatch [:wallet-legacy.settings/toggle-visible-token
|
||||
(keyword sym)
|
||||
(not checked?)])
|
||||
:on-long-press #(re-frame/dispatch [:bottom-sheet/show-sheet-old
|
||||
{:content (custom-token-actions-view token)}])}])}))
|
||||
|
||||
(defn- render-token-wrapper
|
||||
[token]
|
||||
[render-token token])
|
||||
|
||||
(defview manage-assets
|
||||
[]
|
||||
(letsubs [{search-filter :search-filter
|
||||
{custom-tokens true default-tokens nil} :tokens}
|
||||
[:wallet-legacy/filtered-grouped-chain-tokens]]
|
||||
{:component-will-unmount #(do
|
||||
(re-frame/dispatch [:wallet-legacy/search-token-filter-changed nil])
|
||||
(reset! search-active? false))}
|
||||
[react/view {:flex 1 :background-color colors/white}
|
||||
[toolbar]
|
||||
[react/view {:flex 1}
|
||||
[react/view
|
||||
{:padding-horizontal 16
|
||||
:padding-vertical 10}
|
||||
[search-input/search-input-old
|
||||
{:search-active? search-active?
|
||||
:search-filter search-filter
|
||||
:on-cancel #(re-frame/dispatch [:wallet-legacy/search-token-filter-changed nil])
|
||||
:on-focus (fn [search-filter]
|
||||
(when-not search-filter
|
||||
(re-frame/dispatch [:wallet-legacy/search-token-filter-changed ""])))
|
||||
:on-change (fn [text]
|
||||
(re-frame/dispatch [:wallet-legacy/search-token-filter-changed text]))}]]
|
||||
[list/section-list
|
||||
{:header
|
||||
[react/view {:margin-top 16}
|
||||
[list.item/list-item
|
||||
{:theme :accent
|
||||
:title (i18n/label :t/add-custom-token)
|
||||
:icon :main-icons/add
|
||||
:on-press
|
||||
#(re-frame/dispatch [:navigate-to :wallet-add-custom-token])}]]
|
||||
:sections (concat
|
||||
(when (seq custom-tokens)
|
||||
[{:title (i18n/label :t/custom)
|
||||
:data custom-tokens}])
|
||||
[{:title (i18n/label :t/default-assets)
|
||||
:data default-tokens}])
|
||||
:key-fn :address
|
||||
:stickySectionHeadersEnabled false
|
||||
:render-section-header-fn
|
||||
(fn [{:keys [title]}]
|
||||
[quo/list-header title])
|
||||
:render-fn render-token-wrapper}]]]))
|
||||
@@ -1,54 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.wallet.signing-phrase.views
|
||||
(:require-macros [legacy.status-im.utils.views :as views])
|
||||
(:require
|
||||
[legacy.status-im.ui.components.colors :as colors]
|
||||
[legacy.status-im.ui.components.core :as quo]
|
||||
[legacy.status-im.ui.components.icons.icons :as icons]
|
||||
[legacy.status-im.ui.components.react :as react]
|
||||
[re-frame.core :as re-frame]
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
(views/defview signing-phrase
|
||||
[]
|
||||
(views/letsubs [phrase [:signing/phrase]
|
||||
{:keys [wallet-set-up-passed?]} [:profile/profile]]
|
||||
[react/view
|
||||
[react/view {:margin-top 24 :margin-horizontal 24 :align-items :center}
|
||||
[react/view
|
||||
{:background-color colors/blue-light
|
||||
:width 32
|
||||
:height 32
|
||||
:border-radius 16
|
||||
:align-items :center
|
||||
:justify-content :center}
|
||||
[icons/icon :main-icons/security {:color colors/blue}]]
|
||||
[react/text {:style {:typography :title-bold :margin-top 16 :margin-bottom 8}}
|
||||
(i18n/label :t/this-is-you-signing)]
|
||||
[react/text {:style {:color colors/gray :text-align :center}}
|
||||
(i18n/label :t/three-words-description)]]
|
||||
[react/view
|
||||
{:margin-vertical 16
|
||||
:height 52
|
||||
:background-color colors/gray-lighter
|
||||
:align-items :center
|
||||
:justify-content :center}
|
||||
[react/text phrase]]
|
||||
[react/view
|
||||
{:padding-bottom 8
|
||||
:padding-horizontal 24
|
||||
:align-items :center}
|
||||
[react/text {:style {:color colors/gray :text-align :center}}
|
||||
(i18n/label :t/three-words-description-2)]
|
||||
(when-not wallet-set-up-passed?
|
||||
[react/view {:style {:margin-top 16}}
|
||||
[quo/button {:on-press #(re-frame/dispatch [:hide-popover])}
|
||||
(i18n/label :t/remind-me-later)]])
|
||||
[react/view {:style {:padding-vertical 8}}
|
||||
[quo/button
|
||||
{:on-press #(do
|
||||
(when-not wallet-set-up-passed?
|
||||
(re-frame/dispatch [:profile.settings/update-value
|
||||
:wallet-set-up-passed? true]))
|
||||
(re-frame/dispatch [:hide-popover]))
|
||||
:type :secondary}
|
||||
(i18n/label :t/ok-got-it)]]]]))
|
||||
@@ -1,505 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.wallet.swap.views
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.ethereum.tokens :as tokens]
|
||||
[legacy.status-im.ui.components.chat-icon.screen :as chat-icon]
|
||||
[legacy.status-im.ui.components.colors :as colors]
|
||||
[legacy.status-im.ui.components.core :as quo]
|
||||
[legacy.status-im.ui.components.icons.icons :as icons]
|
||||
[legacy.status-im.ui.components.keyboard-avoid-presentation :as kb-presentation]
|
||||
[legacy.status-im.ui.components.list.item :as list.item]
|
||||
[legacy.status-im.ui.components.react :as react]
|
||||
[legacy.status-im.ui.components.search-input.view :as search-input]
|
||||
[legacy.status-im.ui.components.slider :as slider]
|
||||
[legacy.status-im.ui.components.toolbar :as toolbar]
|
||||
[legacy.status-im.ui.components.topbar :as topbar]
|
||||
[legacy.status-im.ui.screens.wallet.components.views :as wallet.components]
|
||||
[legacy.status-im.wallet.swap.core :as wallet-legacy.swap]
|
||||
[legacy.status-im.wallet.utils :as wallet.utils]
|
||||
[re-frame.core :as re-frame]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn render-asset
|
||||
[{{:keys
|
||||
[icon decimals amount color value]
|
||||
:as token}
|
||||
:token
|
||||
currency :currency
|
||||
on-press :on-press}]
|
||||
[list.item/list-item
|
||||
{:title [quo/text {:weight :medium}
|
||||
[quo/text {:weight :inherit}
|
||||
(str (if amount
|
||||
(wallet.utils/format-amount amount decimals)
|
||||
"...")
|
||||
" ")]
|
||||
[quo/text
|
||||
{:color :secondary
|
||||
:weight :inherit}
|
||||
(wallet.utils/display-symbol token)]]
|
||||
:on-press on-press
|
||||
:subtitle (str (if value value "...") " " currency)
|
||||
:accessibility-label
|
||||
(str (:symbol token) "-asset-value")
|
||||
:icon (if icon
|
||||
[wallet.components/token-icon icon]
|
||||
[chat-icon/custom-icon-view-list (:name token) color])}])
|
||||
|
||||
(defn asset-selector
|
||||
[]
|
||||
(let [{:keys [address]} (rf/sub [:multiaccount/current-account])
|
||||
{:keys [tokens]} (rf/sub [:wallet-legacy/visible-assets-with-values address])
|
||||
source? (rf/sub [:wallet-legacy/modal-selecting-source-token?])
|
||||
currency (rf/sub [:wallet-legacy/currency])]
|
||||
[:<>
|
||||
[topbar/topbar
|
||||
{:title (if source?
|
||||
(i18n/label :t/select-token-to-swap)
|
||||
(i18n/label :t/select-token-to-receive))
|
||||
:modal? true}]
|
||||
|
||||
[search-input/search-input-old
|
||||
{:search-active? true}]
|
||||
|
||||
[react/scroll-view
|
||||
(for [token tokens]
|
||||
^{:key (:name token)}
|
||||
[render-asset
|
||||
{:token token
|
||||
:on-press #(re-frame/dispatch
|
||||
[(if source?
|
||||
::wallet-legacy.swap/set-from-token
|
||||
::wallet-legacy.swap/set-to-token)
|
||||
(:symbol token)])
|
||||
:currency (:code currency)}])]]))
|
||||
|
||||
(defn pill-button
|
||||
[{:keys [on-press label margin-left]}]
|
||||
[react/touchable-opacity
|
||||
{:on-press on-press
|
||||
:style {:background-color colors/blue-light
|
||||
:padding-horizontal 12
|
||||
:padding-vertical 2
|
||||
:border-radius 24
|
||||
:margin-left (or margin-left 8)}}
|
||||
[quo/text
|
||||
{:color :link
|
||||
:weight :medium} label]])
|
||||
|
||||
(defn token-display
|
||||
"Show token and act as an anchor to open selector."
|
||||
[{:keys [token source?]}]
|
||||
(let [token-icon-source (-> token :icon :source)]
|
||||
[react/touchable-highlight
|
||||
{:on-press #(re-frame/dispatch [::wallet-legacy.swap/open-asset-selector-modal source?])}
|
||||
[react/view
|
||||
{:style {:flex-direction :row
|
||||
:align-items :center
|
||||
:border-width 1
|
||||
:border-color colors/gray-lighter
|
||||
:border-radius 8
|
||||
:margin-left 16
|
||||
:padding-horizontal 8
|
||||
:padding-vertical 2}
|
||||
:accessibility-label
|
||||
:choose-asset-button}
|
||||
[quo/text {:style {:margin-right 8}}
|
||||
(-> token :symbol name)]
|
||||
[react/image
|
||||
{:source (if (fn? token-icon-source)
|
||||
(token-icon-source)
|
||||
token-icon-source)}]]]))
|
||||
|
||||
(defn token-input
|
||||
"Component to get the amount and type of tokens"
|
||||
[{:keys [amount error label token max-from source?]}]
|
||||
(let [window-width (rf/sub [:dimensions/window-width])]
|
||||
[react/view
|
||||
{:style {:justify-content :space-between
|
||||
:flex-direction :row
|
||||
:align-items :center}}
|
||||
[react/view {:flex 2}
|
||||
[react/view
|
||||
{:flex-direction :row
|
||||
:align-items :center}
|
||||
[quo/text label]
|
||||
(when max-from
|
||||
[pill-button
|
||||
{:on-press #()
|
||||
:label "Max 0.043"}])]
|
||||
[react/text-input
|
||||
{:style {:font-size 38
|
||||
:max-width (- (* (/ window-width 4) 3) 106)
|
||||
:color (if error colors/red colors/black)}
|
||||
:keyboard-type :decimal-pad
|
||||
:auto-capitalize :words
|
||||
:accessibility-label :amount-input
|
||||
:default-value amount
|
||||
:editable true
|
||||
:auto-focus true
|
||||
:on-change-text #(re-frame/dispatch [(when source?
|
||||
::wallet-legacy.swap/set-from-token-amount)
|
||||
%])
|
||||
:placeholder "0.0"}]]
|
||||
[token-display
|
||||
{:token token
|
||||
:source? source?}]]))
|
||||
|
||||
(defn separator-with-icon
|
||||
[]
|
||||
[react/view
|
||||
{:margin-vertical 8}
|
||||
[quo/separator]
|
||||
[react/touchable-opacity
|
||||
{:on-press #(re-frame/dispatch [::wallet-legacy.swap/switch-from-token-with-to])}
|
||||
[react/view
|
||||
{:style {:background-color colors/gray-lighter
|
||||
:width 40
|
||||
:height 40
|
||||
:border-radius 40
|
||||
:border-width 4
|
||||
:border-color colors/white
|
||||
:margin-top -20
|
||||
:margin-bottom -20
|
||||
:align-self :center
|
||||
:align-items :center
|
||||
:justify-content :center}}
|
||||
[react/image
|
||||
{:source (icons/icon-source :main-icons/change)
|
||||
:style {:tint-color colors/gray
|
||||
:transform [{:rotate "90deg"}]}}]]]])
|
||||
|
||||
(defn floating-card
|
||||
[{:keys [icon title body on-press]}]
|
||||
[react/view
|
||||
{:style {:border-width 1
|
||||
:padding 2 ;; need a padding because border breaks otherwise
|
||||
:border-radius 12
|
||||
:margin-top 12
|
||||
:border-color colors/gray-lighter}}
|
||||
[list.item/list-item
|
||||
{:title title
|
||||
:subtitle body
|
||||
:active-background-enabled
|
||||
false
|
||||
:on-press on-press
|
||||
:theme :main
|
||||
:chevron true
|
||||
:icon [react/view
|
||||
{:style {:background-color colors/blue-light
|
||||
:padding 8
|
||||
:border-radius 4}}
|
||||
(icons/icon icon {:color :dark})]}]])
|
||||
|
||||
(defn card-body-row
|
||||
[k value primary?]
|
||||
[react/view {:flex-direction :row}
|
||||
[quo/text {:color (when-not primary? :secondary)} k]
|
||||
[quo/text
|
||||
{:style {:margin-right 4}
|
||||
:color (when-not primary? :secondary)} ":"]
|
||||
[quo/text
|
||||
{:ellipsize-mode :middle
|
||||
:number-of-lines 1
|
||||
:style {:width "50%"}
|
||||
:color (when-not primary? :secondary)
|
||||
:weight :semi-bold} value]])
|
||||
|
||||
(defn transaction-fee-card
|
||||
[{:keys [gas-amount price-limit tip-limit gas-in-eth gas-in-usd]}]
|
||||
[floating-card
|
||||
{:title (i18n/label :t/transaction-fee)
|
||||
:icon :main-icons/gas
|
||||
:on-press #(re-frame/dispatch [:open-modal :token-swap-advanced-transaction-fee])
|
||||
:body [react/view
|
||||
[card-body-row (i18n/label :t/gas-amount-limit) gas-amount]
|
||||
[card-body-row (i18n/label :t/per-gas-price-limit) price-limit]
|
||||
[card-body-row (i18n/label :t/per-gas-tip-limit) tip-limit]
|
||||
[card-body-row (i18n/label :t/total-gas)
|
||||
(str gas-in-eth " • $" gas-in-usd)
|
||||
true]]}])
|
||||
|
||||
(defn swap-details-card
|
||||
[{:keys [slippage price-impact]}]
|
||||
[floating-card
|
||||
{:title (i18n/label :t/swap-details)
|
||||
:icon :main-icons/change
|
||||
:on-press #(re-frame/dispatch [:open-modal :token-swap-advanced-swap-details])
|
||||
:body [react/view
|
||||
[card-body-row (i18n/label :t/slippage) (str slippage " %")]
|
||||
[card-body-row (i18n/label :t/price-impact) (str price-impact " %")]]}])
|
||||
|
||||
(defn nonce-card
|
||||
[{:keys [nonce]}]
|
||||
[floating-card
|
||||
{:title (i18n/label :t/nonce)
|
||||
:icon :main-icons/channel
|
||||
:on-press #(re-frame/dispatch [:open-modal :token-swap-advanced-nonce])
|
||||
:body [react/view
|
||||
[card-body-row (i18n/label :t/nonce) nonce]]}])
|
||||
|
||||
(defn approve-token-card
|
||||
[{:keys [token contract-address approve-limit]}]
|
||||
[floating-card
|
||||
{:title (i18n/label :t/approve)
|
||||
:icon :main-icons/check
|
||||
:on-press #(re-frame/dispatch [:open-modal :token-swap-advanced-approve-token])
|
||||
:body [react/view
|
||||
[card-body-row (i18n/label :t/token) token]
|
||||
[card-body-row (i18n/label :t/contract-address) contract-address]
|
||||
[card-body-row (i18n/label :t/approve-limit) approve-limit]]}])
|
||||
|
||||
(defn advanced-input
|
||||
[{:keys [label label-help value on-change after]}]
|
||||
[react/view
|
||||
{:style {:padding-horizontal 16
|
||||
:margin-bottom 16}}
|
||||
[react/view
|
||||
{:style {:flex-direction :row
|
||||
:justify-content :space-between}}
|
||||
[quo/text {} label]
|
||||
label-help]
|
||||
|
||||
[quo/text-input
|
||||
{:default-value (str value)
|
||||
:show-cancel false
|
||||
:style {:margin-top 12
|
||||
:border-radius 8}
|
||||
:after {:component after}
|
||||
:on-change-text on-change}]])
|
||||
|
||||
(defn help-label-kv
|
||||
[{k :key v :value}]
|
||||
[react/view {:style {:flex-direction :row}}
|
||||
[quo/text {:color :secondary} k]
|
||||
[quo/text
|
||||
{:color :secondary
|
||||
:style {:margin-right 4}} ":"]
|
||||
[quo/text {:color :secondary} v]])
|
||||
|
||||
(defn nonce-modal
|
||||
[]
|
||||
(let [last-txn-nonce 22
|
||||
nonce 23]
|
||||
[kb-presentation/keyboard-avoiding-view
|
||||
{:style {:flex 1
|
||||
:margin-top 16}
|
||||
:ignore-offset true}
|
||||
[advanced-input
|
||||
{:label (i18n/label :t/nonce)
|
||||
:label-help [help-label-kv
|
||||
{:key (i18n/label :t/last-transaction)
|
||||
:value last-txn-nonce}]
|
||||
:value nonce
|
||||
:on-change #()
|
||||
:on-save #()}]
|
||||
[toolbar/toolbar
|
||||
{:show-border? true
|
||||
:left [quo/button {:type :secondary}
|
||||
(i18n/label :t/cancel)]
|
||||
:right [quo/button {:theme :accent}
|
||||
(i18n/label :t/save)]}]]))
|
||||
|
||||
(defn approve-token-modal
|
||||
[]
|
||||
[quo/text "modal"])
|
||||
|
||||
(defn transaction-fee-modal
|
||||
[]
|
||||
(let [gas-amount-limit 21000
|
||||
gas-amount 21000
|
||||
per-gas-price-limit 7.3
|
||||
current-avg-per-gas-price-limit 7.3
|
||||
per-gas-tip-limit 150
|
||||
current-avg-per-gas-tip-limit 150]
|
||||
[kb-presentation/keyboard-avoiding-view
|
||||
{:style {:flex 1
|
||||
:margin-top 16}
|
||||
:ignore-offset true}
|
||||
[react/view {:flex 1}
|
||||
[advanced-input
|
||||
{:label (i18n/label :t/gas-amount-limit)
|
||||
:label-help [help-label-kv
|
||||
{:key (i18n/label :t/limit)
|
||||
:value gas-amount-limit}]
|
||||
:value gas-amount
|
||||
:after [quo/text {:color :secondary} (i18n/label :t/gwei)]
|
||||
:on-change #()
|
||||
:on-save #()}]
|
||||
|
||||
[advanced-input
|
||||
{:label (i18n/label :t/per-gas-price-limit)
|
||||
:label-help [help-label-kv
|
||||
{:key (i18n/label :t/current-average)
|
||||
:value current-avg-per-gas-price-limit}]
|
||||
:value per-gas-price-limit
|
||||
:after [quo/text {:color :secondary} (i18n/label :t/gwei)]
|
||||
:on-change #()
|
||||
:on-save #()}]
|
||||
|
||||
[advanced-input
|
||||
{:label (i18n/label :t/per-gas-price-limit)
|
||||
:label-help [help-label-kv
|
||||
{:key (i18n/label :t/current-average)
|
||||
:value current-avg-per-gas-tip-limit}]
|
||||
:value per-gas-tip-limit
|
||||
:after [quo/text {:color :secondary} (i18n/label :t/gwei)]
|
||||
:on-change #()
|
||||
:on-save #()}]
|
||||
|
||||
[list.item/list-item
|
||||
{:title (i18n/label :t/maximum-fee)
|
||||
:text-size :base
|
||||
:title-text-weight :regular
|
||||
:accessory :text
|
||||
:accessory-text [quo/text "0.3 ETH"]
|
||||
:container-style {:margin-top 16}}]
|
||||
[quo/text
|
||||
{:color :secondary
|
||||
:style {:padding-horizontal 16}}
|
||||
(i18n/label :t/maximum-fee-desc)]]
|
||||
[toolbar/toolbar
|
||||
{:show-border? true
|
||||
:left [quo/button {:type :secondary}
|
||||
(i18n/label :t/cancel)]
|
||||
:right [quo/button {:theme :accent}
|
||||
(i18n/label :t/save)]}]]))
|
||||
|
||||
(defn swap-details-modal
|
||||
[]
|
||||
(let [slippage-limit 20
|
||||
slippage 0.5
|
||||
price-impact 4]
|
||||
[kb-presentation/keyboard-avoiding-view
|
||||
{:style {:flex 1
|
||||
:margin-top 16}
|
||||
:ignore-offset true}
|
||||
[react/view {:flex 1}
|
||||
[advanced-input
|
||||
{:label (str (i18n/label :t/slippage) " %")
|
||||
:label-help [help-label-kv
|
||||
{:key (i18n/label :t/limit)
|
||||
:value (str slippage-limit "%")}]
|
||||
:value slippage
|
||||
:on-change #()
|
||||
:on-save #()}]
|
||||
|
||||
[list.item/list-item
|
||||
{:title (i18n/label :t/price-impact)
|
||||
:text-size :base
|
||||
:title-text-weight :regular
|
||||
:accessory :text
|
||||
:accessory-text (str price-impact "%")
|
||||
:container-style {:margin-top 16}}]
|
||||
[quo/text
|
||||
{:color :secondary
|
||||
:style {:padding-horizontal 16}}
|
||||
(i18n/label :t/price-impact-desc)]]
|
||||
[toolbar/toolbar
|
||||
{:show-border? true
|
||||
:left [quo/button {:type :secondary}
|
||||
(i18n/label :t/cancel)]
|
||||
:right [quo/button {:theme :accent}
|
||||
(i18n/label :t/save)]}]]))
|
||||
|
||||
(defn advanced-settings
|
||||
[]
|
||||
[react/view
|
||||
{:style {:flex 1
|
||||
:padding-horizontal 16}}
|
||||
[react/view {:align-self :flex-start}
|
||||
[pill-button
|
||||
{:label (i18n/label :t/switch-to-simple-interface)
|
||||
:margin-left 0
|
||||
:on-press #(re-frame/dispatch [::wallet-legacy.swap/set-advanced-mode false])}]]
|
||||
[transaction-fee-card
|
||||
{:gas-amount 21000
|
||||
:price-limit 74
|
||||
:tip-limit 21
|
||||
:gas-in-eth 0.0031
|
||||
:gas-in-usd 34.28}]
|
||||
[swap-details-card
|
||||
{:slippage 0.5
|
||||
:price-impact 4}]
|
||||
[approve-token-card
|
||||
{:token "USDC"
|
||||
:contract-address "0x9f8f72aa9304c8b593d555f12ef6589cc3a579a2"
|
||||
:approve-limit "unlimited"}]
|
||||
[nonce-card {:nonce 22}]])
|
||||
|
||||
(defn swap
|
||||
[]
|
||||
(let [{:keys [name]}
|
||||
(rf/sub [:multiaccount/current-account])
|
||||
all-tokens (rf/sub [:wallet-legacy/all-tokens])
|
||||
from-symbol (rf/sub [:wallet-legacy/swap-from-token])
|
||||
to-symbol (rf/sub [:wallet-legacy/swap-to-token])
|
||||
advanced-mode? (rf/sub [:wallet-legacy/swap-advanced-mode?])
|
||||
amount "0.02"
|
||||
from-token (tokens/symbol->token all-tokens (or from-symbol :DGX))
|
||||
to-token (tokens/symbol->token all-tokens (or to-symbol :SNT))]
|
||||
|
||||
[kb-presentation/keyboard-avoiding-view
|
||||
{:style (merge
|
||||
{:flex 1})
|
||||
:ignore-offset true}
|
||||
[topbar/topbar
|
||||
{:title name
|
||||
:subtitle (string/upper-case (i18n/label :t/powered-by-paraswap))
|
||||
:modal? true}]
|
||||
|
||||
[react/view
|
||||
(merge {:padding-horizontal 16
|
||||
:margin-vertical 32}
|
||||
(when-not advanced-mode?
|
||||
{:flex 1}))
|
||||
[token-input
|
||||
{:amount amount
|
||||
:error nil
|
||||
:label (i18n/label :t/amount)
|
||||
:token from-token
|
||||
:source? true
|
||||
:max-from 67.28}]
|
||||
|
||||
[separator-with-icon]
|
||||
|
||||
[token-input
|
||||
{:amount "0.01"
|
||||
:error nil
|
||||
:label (i18n/label :t/minimum-received)
|
||||
:source? false
|
||||
:token to-token}]]
|
||||
|
||||
(when-not advanced-mode?
|
||||
[react/view
|
||||
{:style {:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:padding-horizontal 16
|
||||
:align-items :center}}
|
||||
[react/view {:style {:flex-direction :row}}
|
||||
[quo/text {} (i18n/label :t/priority)]
|
||||
[pill-button
|
||||
{:label (i18n/label :t/advanced)
|
||||
:on-press #(re-frame/dispatch [::wallet-legacy.swap/set-advanced-mode true])}]]
|
||||
|
||||
[quo/text {:color :secondary} "0.0034 ETH/ $ 8.09"]])
|
||||
|
||||
(comment
|
||||
(re-frame/dispatch [::wallet-legacy.swap/set-advanced-mode false]))
|
||||
|
||||
(when-not advanced-mode?
|
||||
[react/view {:style {:padding-horizontal 16}}
|
||||
[slider/animated-slider
|
||||
{:minimum-value 0
|
||||
:maximum-value 100
|
||||
:style {:margin-vertical 8}}]])
|
||||
|
||||
(when advanced-mode?
|
||||
[quo/text "here"]
|
||||
[advanced-settings])
|
||||
|
||||
[toolbar/toolbar
|
||||
{:show-border? true
|
||||
:right [quo/button {:theme :accent}
|
||||
(i18n/label :t/swap)]}]]))
|
||||
@@ -1,141 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.wallet.transactions.styles
|
||||
(:require
|
||||
[legacy.status-im.ui.components.colors :as colors]
|
||||
[legacy.status-im.utils.styles :as styles]))
|
||||
|
||||
(def forward
|
||||
{:color colors/gray})
|
||||
|
||||
(def empty-text
|
||||
{:text-align :center
|
||||
:color colors/gray
|
||||
:margin-top 22
|
||||
:margin-horizontal 92})
|
||||
|
||||
(styles/def amount-time
|
||||
{:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:padding-right 22
|
||||
:padding-left 17
|
||||
:ios {:padding-top 13}
|
||||
:android {:padding-top 14}})
|
||||
|
||||
(def tx-amount
|
||||
{:flex-grow 1
|
||||
:flex-shrink 1
|
||||
:margin-right 10
|
||||
:font-size 17})
|
||||
|
||||
(def tx-time
|
||||
{:flex-grow 1
|
||||
:font-size 14
|
||||
:text-align :right
|
||||
:color colors/blue})
|
||||
|
||||
(def address-row
|
||||
{:flex-direction :row
|
||||
:padding-right 22
|
||||
:padding-left 17
|
||||
:padding-top 4})
|
||||
|
||||
(def address-label
|
||||
{:margin-right 5
|
||||
:font-size 16
|
||||
:color colors/gray})
|
||||
|
||||
(def address-contact
|
||||
{:margin-right 5
|
||||
:font-size 16})
|
||||
|
||||
(def address-hash
|
||||
{:flex-shrink 1})
|
||||
|
||||
(defn transaction-icon-background
|
||||
[color]
|
||||
{:justify-content :center
|
||||
:align-items :center
|
||||
:width 40
|
||||
:height 40
|
||||
:border-radius 32
|
||||
:background-color color})
|
||||
|
||||
;; transaction details
|
||||
|
||||
(def details-row
|
||||
{:flex-direction :row
|
||||
:margin-vertical 5})
|
||||
|
||||
(def details-item-label
|
||||
{:flex 1
|
||||
:margin-right 10
|
||||
:color colors/gray})
|
||||
|
||||
(def details-item-value-wrapper
|
||||
{:flex 5})
|
||||
|
||||
(def details-item-value
|
||||
{:font-size 14})
|
||||
|
||||
(def details-item-extra-value
|
||||
{:font-size 14
|
||||
:color colors/gray})
|
||||
|
||||
(def details-header
|
||||
{:margin-horizontal 16
|
||||
:margin-top 10
|
||||
:flex-direction :row})
|
||||
|
||||
(def details-header-icon
|
||||
{:margin-vertical 7})
|
||||
|
||||
(def details-header-infos
|
||||
{:flex 1
|
||||
:flex-direction :column
|
||||
:margin-left 12
|
||||
:margin-vertical 7})
|
||||
|
||||
(def details-header-value
|
||||
{:font-size 16})
|
||||
|
||||
(def details-header-date
|
||||
{:font-size 14
|
||||
:color colors/gray})
|
||||
|
||||
(def details-block
|
||||
{:margin-horizontal 16})
|
||||
|
||||
(def progress-bar
|
||||
{:flex-direction :row
|
||||
:margin-vertical 10
|
||||
:height 2})
|
||||
|
||||
(defn progress-bar-done
|
||||
[done failed?]
|
||||
{:flex done
|
||||
:background-color (if failed?
|
||||
colors/red
|
||||
colors/blue)})
|
||||
|
||||
(defn progress-bar-todo
|
||||
[todo failed?]
|
||||
{:flex todo
|
||||
:background-color (if failed?
|
||||
colors/red
|
||||
colors/blue)
|
||||
:opacity 0.30})
|
||||
|
||||
(def details-confirmations-count
|
||||
{:margin-vertical 2})
|
||||
|
||||
(def details-failed
|
||||
{:color colors/red
|
||||
:margin-vertical 2})
|
||||
|
||||
(def details-confirmations-helper-text
|
||||
{:color colors/gray
|
||||
:margin-vertical 2})
|
||||
|
||||
(def details-separator
|
||||
{:background-color colors/black-transparent
|
||||
:height 1
|
||||
:margin-vertical 10})
|
||||
@@ -1,304 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.wallet.transactions.views
|
||||
(:require
|
||||
[legacy.status-im.ui.components.colors :as colors]
|
||||
[legacy.status-im.ui.components.core :as quo]
|
||||
[legacy.status-im.ui.components.icons.icons :as icons]
|
||||
[legacy.status-im.ui.components.list-selection :as list-selection]
|
||||
[legacy.status-im.ui.components.list.item :as list.item]
|
||||
[legacy.status-im.ui.components.list.views :as list]
|
||||
[legacy.status-im.ui.components.react :as react]
|
||||
[legacy.status-im.ui.components.toolbar :as toolbar]
|
||||
[legacy.status-im.ui.components.topbar :as topbar]
|
||||
[legacy.status-im.ui.screens.wallet.transactions.styles :as styles]
|
||||
[legacy.status-im.utils.utils :as utils]
|
||||
[re-frame.core :as re-frame]
|
||||
[utils.i18n :as i18n])
|
||||
(:require-macros [legacy.status-im.utils.views :refer [defview letsubs]]))
|
||||
|
||||
(defn- transaction-icon
|
||||
[icon-key background-color color]
|
||||
{:icon icon-key
|
||||
:icon-color color
|
||||
:icon-bg-color background-color})
|
||||
|
||||
(defn- transaction-type->icon
|
||||
[k]
|
||||
(case k
|
||||
:inbound (transaction-icon :main-icons/arrow-left
|
||||
colors/green-transparent-10
|
||||
colors/green)
|
||||
:outbound (transaction-icon :main-icons/arrow-right
|
||||
colors/blue-transparent-10
|
||||
colors/blue)
|
||||
:failed (transaction-icon :main-icons/warning
|
||||
colors/black-transparent
|
||||
colors/red)
|
||||
:pending (transaction-icon :main-icons/arrow-right
|
||||
colors/black-transparent
|
||||
colors/gray)
|
||||
(throw (js/Error. (str "Unknown transaction type: " k)))))
|
||||
|
||||
(defn render-transaction
|
||||
[{:keys [label contact address contact-accessibility-label
|
||||
currency-text amount-text
|
||||
time-formatted on-touch-fn type]
|
||||
:as transaction}
|
||||
_ _ {:keys [keycard-account?]}]
|
||||
[:<>
|
||||
[list.item/list-item
|
||||
(merge
|
||||
{:on-press on-touch-fn
|
||||
:accessibility-label :transaction-item
|
||||
:title (str amount-text " " currency-text)
|
||||
:subtitle (str label
|
||||
" "
|
||||
(when contact
|
||||
[react/text
|
||||
{:style styles/address-contact
|
||||
:accessibility-label contact-accessibility-label}
|
||||
contact])
|
||||
" "
|
||||
(utils/get-shortened-address address)
|
||||
" "
|
||||
(i18n/label :t/at)
|
||||
" "
|
||||
time-formatted)
|
||||
:chevron true}
|
||||
(when type (transaction-type->icon (keyword type))))]
|
||||
;; Disabling for now as we have added nonce which is more reliable, until we address the ux
|
||||
;; issues
|
||||
(when (and false
|
||||
(not keycard-account?)
|
||||
(= type :pending))
|
||||
[react/view {:flex-direction :row :padding 16 :justify-content :space-between}
|
||||
[quo/button
|
||||
{:on-press #(re-frame/dispatch [:signing.ui/increase-gas-pressed (:hash transaction)])}
|
||||
(i18n/label :t/increase-gas)]
|
||||
[quo/button
|
||||
{:on-press #(re-frame/dispatch [:signing.ui/cancel-transaction-pressed (:hash transaction)])}
|
||||
(i18n/label :t/cancel)]])])
|
||||
|
||||
(defn chain-explorer-link
|
||||
[address]
|
||||
(let [link @(re-frame/subscribe [:wallet-legacy/chain-explorer-link address])]
|
||||
[react/touchable-highlight
|
||||
{:on-press #(when link
|
||||
(.openURL ^js react/linking link))}
|
||||
[react/view
|
||||
{:style {:flex 1
|
||||
:padding-horizontal 14
|
||||
:flex-direction :row
|
||||
:align-items :center
|
||||
:background-color colors/blue-light
|
||||
:height 52}}
|
||||
[icons/tiny-icon
|
||||
:tiny-icons/tiny-external
|
||||
{:color colors/blue
|
||||
:container-style {:margin-right 5}}]
|
||||
[react/text
|
||||
{:style {:color colors/blue}}
|
||||
(i18n/label :t/check-on-block-explorer)]]]))
|
||||
|
||||
(defn custom-node
|
||||
[]
|
||||
[react/view
|
||||
{:style {:flex 1
|
||||
:padding-horizontal 14
|
||||
:flex-direction :row
|
||||
:align-items :center
|
||||
:background-color (colors/get-color :warning-02)
|
||||
:height 52}}
|
||||
[react/text
|
||||
{:style {:color (colors/get-color :warning-01)}}
|
||||
(i18n/label :t/custom-node)]])
|
||||
|
||||
(defn non-archival-node
|
||||
[]
|
||||
[react/view
|
||||
{:style {:flex 1
|
||||
:padding-horizontal 14
|
||||
:flex-direction :row
|
||||
:align-items :center
|
||||
:background-color (colors/get-color :negative-02)
|
||||
:height 52}}
|
||||
[react/text
|
||||
{:style {:color (colors/get-color :negative-01)}}
|
||||
(i18n/label :t/non-archival-node)]])
|
||||
|
||||
(defn history-list
|
||||
[{:keys [transaction-history-sections total]} address]
|
||||
(let [fetching-recent-history? @(re-frame/subscribe [:wallet-legacy/fetching-recent-tx-history?
|
||||
address])
|
||||
fetching-more-history? @(re-frame/subscribe [:wallet-legacy/fetching-tx-history? address])
|
||||
keycard-account? @(re-frame/subscribe [:multiaccounts/keycard-account?])
|
||||
custom-rpc-node? @(re-frame/subscribe [:custom-rpc-node])
|
||||
non-archival-rpc-node? @(re-frame/subscribe [:wallet-legacy/non-archival-node])
|
||||
binance-chain? @(re-frame/subscribe [:wallet-legacy/binance-chain?])
|
||||
all-fetched? @(re-frame/subscribe [:wallet-legacy/tx-history-fetched? address])
|
||||
syncing-allowed? @(re-frame/subscribe [:mobile-network/syncing-allowed?])]
|
||||
[react/view {:flex 1}
|
||||
[chain-explorer-link address]
|
||||
(cond (or non-archival-rpc-node? binance-chain?)
|
||||
[non-archival-node]
|
||||
custom-rpc-node?
|
||||
[custom-node])
|
||||
(when fetching-recent-history?
|
||||
[react/view
|
||||
{:style {:flex 1
|
||||
:height 40
|
||||
:margin-vertical 16}}
|
||||
[react/activity-indicator
|
||||
{:size :large
|
||||
:animating true}]])
|
||||
[list/section-list
|
||||
{:sections transaction-history-sections
|
||||
:key-fn :hash
|
||||
:render-data {:keycard-account? keycard-account?}
|
||||
:render-fn render-transaction
|
||||
:empty-component
|
||||
[react/i18n-text
|
||||
{:style styles/empty-text
|
||||
:key (if (or fetching-recent-history? fetching-more-history?)
|
||||
:transactions-history-loading
|
||||
:transactions-history-empty)}]}]
|
||||
(when (and (not fetching-recent-history?)
|
||||
(not= all-fetched? :all))
|
||||
(if fetching-more-history?
|
||||
[react/view
|
||||
{:style {:flex 1
|
||||
:height 40
|
||||
:margin-vertical 8}}
|
||||
[react/activity-indicator
|
||||
{:size :large
|
||||
:animating true}]]
|
||||
[toolbar/toolbar
|
||||
{:center
|
||||
[quo/button
|
||||
{:type :secondary
|
||||
:disabled (and (not syncing-allowed?)
|
||||
(or (= all-fetched? :all-preloaded)
|
||||
(zero? total)))
|
||||
:on-press (when-not fetching-more-history?
|
||||
#(re-frame/dispatch
|
||||
[:transactions/fetch-more address]))}
|
||||
(i18n/label :t/transactions-load-more)]}]))]))
|
||||
|
||||
(defn details-header
|
||||
[date type amount-text currency-text]
|
||||
[list.item/list-item
|
||||
(merge
|
||||
{:title [react/nested-text {:style styles/details-header-value}
|
||||
[{:accessibility-label :amount-text} amount-text]
|
||||
" "
|
||||
[{:accessibility-label :currency-text} currency-text]]
|
||||
:subtitle date}
|
||||
(transaction-type->icon type))])
|
||||
|
||||
(defn progress-bar
|
||||
[progress failed?]
|
||||
[react/view {:style styles/progress-bar}
|
||||
[react/view {:style (styles/progress-bar-done progress failed?)}]
|
||||
[react/view {:style (styles/progress-bar-todo (- 100 progress) failed?)}]])
|
||||
|
||||
(defn details-confirmations
|
||||
[confirmations confirmations-progress failed?]
|
||||
[react/view {:style styles/details-block}
|
||||
[progress-bar confirmations-progress failed?]
|
||||
(if failed?
|
||||
[react/i18n-text
|
||||
{:style styles/details-failed
|
||||
:key :failed}]
|
||||
[react/text {:style styles/details-confirmations-count}
|
||||
(str confirmations " " (i18n/label :t/confirmations))])
|
||||
[react/i18n-text
|
||||
{:style styles/details-confirmations-helper-text
|
||||
:key :confirmations-helper-text}]])
|
||||
|
||||
(defn details-list-row
|
||||
([label props-value]
|
||||
(details-list-row label props-value nil))
|
||||
([label props-value extra-props-value]
|
||||
(let [[props value] (if (string? props-value)
|
||||
[nil props-value]
|
||||
props-value)
|
||||
[extra-props extra-value] (if (string? extra-props-value)
|
||||
[nil extra-props-value]
|
||||
extra-props-value)]
|
||||
[react/view {:style styles/details-row}
|
||||
[react/i18n-text {:style styles/details-item-label :key label}]
|
||||
[react/view {:style styles/details-item-value-wrapper}
|
||||
[quo/text
|
||||
(merge {:size :small
|
||||
:monospace true}
|
||||
props)
|
||||
(str (or value "-"))]
|
||||
[quo/text
|
||||
(merge {:size :small
|
||||
:color :secondary
|
||||
:monospace true}
|
||||
extra-props)
|
||||
(str extra-value)]]])))
|
||||
|
||||
(defn details-list
|
||||
[{:keys [block from from-wallet from-contact
|
||||
to to-wallet to-contact
|
||||
gas-limit gas-price-gwei gas-price-eth gas-used
|
||||
fee-cap-gwei tip-cap-gwei
|
||||
cost nonce data]
|
||||
:as tx}]
|
||||
[react/view {:style styles/details-block}
|
||||
[details-list-row :t/block block]
|
||||
[details-list-row :t/hash (:hash tx)]
|
||||
[details-list-row :t/from-capitalized
|
||||
[{:accessibility-label (if from-wallet :sender-name-text :sender-address-text)}
|
||||
(or from-wallet from-contact from)]
|
||||
(when (or from-wallet from-contact)
|
||||
[{:accessibility-label :sender-address-text}
|
||||
from])]
|
||||
[details-list-row :t/to-capitalized
|
||||
[{:accessibility-label (if to-wallet :recipient-name-text :recipient-address-text)}
|
||||
(or to-wallet to-contact to)]
|
||||
(when (or to-wallet to-contact)
|
||||
[{:accessibility-label :recipient-address-text}
|
||||
to])]
|
||||
[details-list-row :t/gas-limit [{:monospace true} gas-limit]]
|
||||
[details-list-row :t/gas-price gas-price-gwei [{:monospace false} gas-price-eth]]
|
||||
[details-list-row :t/fee-cap fee-cap-gwei]
|
||||
[details-list-row :t/tip-cap tip-cap-gwei]
|
||||
[details-list-row :t/gas-used gas-used]
|
||||
[details-list-row :t/cost-fee [{:monospace false} cost]]
|
||||
[details-list-row :t/nonce nonce]
|
||||
[details-list-row :t/data data]])
|
||||
|
||||
(defn details-action
|
||||
[tx-hash url]
|
||||
[{:label (i18n/label :t/copy-transaction-hash)
|
||||
:action #(react/copy-to-clipboard tx-hash)}
|
||||
{:label (i18n/label :t/open-on-block-explorer)
|
||||
:action #(.openURL ^js react/linking url)}])
|
||||
|
||||
(defview transaction-details-view
|
||||
[tx-hash address]
|
||||
(letsubs [{:keys [url type confirmations confirmations-progress
|
||||
date amount-text currency-text]
|
||||
:as transaction}
|
||||
[:wallet-legacy.transactions.details/screen tx-hash address]]
|
||||
[react/view {:flex 1}
|
||||
;;TODO options should be replaced by bottom sheet ,and topbar should be used here
|
||||
[topbar/topbar
|
||||
{:title (i18n/label :t/transaction-details)
|
||||
:right-accessories (when transaction
|
||||
[{:icon :main-icons/more
|
||||
:on-press #(list-selection/show {:options
|
||||
(details-action tx-hash url)})}])}]
|
||||
[react/scroll-view {:flex 1}
|
||||
[details-header date type amount-text currency-text]
|
||||
[details-confirmations confirmations confirmations-progress (= :failed type)]
|
||||
[react/view {:style styles/details-separator}]
|
||||
[details-list transaction]]]))
|
||||
|
||||
(defview transaction-details
|
||||
[]
|
||||
(letsubs [{tx-hash :hash address :address} [:get-screen-params]]
|
||||
(when (and tx-hash address)
|
||||
[transaction-details-view tx-hash address])))
|
||||
@@ -1,394 +0,0 @@
|
||||
(ns legacy.status-im.wallet.accounts.core
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.ens.core :as ens.core]
|
||||
[legacy.status-im.ethereum.mnemonic :as mnemonic]
|
||||
[legacy.status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||
[legacy.status-im.ui.components.colors :as colors]
|
||||
[legacy.status-im.ui.components.list-selection :as list-selection]
|
||||
[legacy.status-im.utils.deprecated-types :as types]
|
||||
[legacy.status-im.utils.hex :as hex]
|
||||
[legacy.status-im.utils.mobile-sync :as utils.mobile-sync]
|
||||
[legacy.status-im.wallet.core :as wallet-legacy]
|
||||
[legacy.status-im.wallet.prices :as prices]
|
||||
[native-module.core :as native-module]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.navigation.events :as navigation]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.address :as address]
|
||||
[utils.ens.stateofus :as stateofus]
|
||||
[utils.ethereum.chain :as chain]
|
||||
[utils.ethereum.eip.eip55 :as eip55]
|
||||
[utils.ethereum.eip.eip681 :as eip681]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
|
||||
(rf/defn start-adding-new-account
|
||||
{:events [:wallet-legacy.accounts/start-adding-new-account]}
|
||||
[{:keys [db] :as cofx} {:keys [type] :as add-account}]
|
||||
(let [{:keys [latest-derived-path]} (:profile/profile db)
|
||||
path-num (inc latest-derived-path)
|
||||
account (merge
|
||||
{:color (rand-nth colors/account-colors)}
|
||||
(when (= type :generate)
|
||||
{:name (str "Account " path-num)}))]
|
||||
(rf/merge cofx
|
||||
{:db (assoc db :add-account (assoc add-account :account account))}
|
||||
(navigation/navigate-to :add-new-account nil))))
|
||||
|
||||
(rf/defn new-account-error
|
||||
{:events [::new-account-error]}
|
||||
[{:keys [db]} error-key error]
|
||||
{:db (update db
|
||||
:add-account
|
||||
merge
|
||||
{error-key error
|
||||
:step nil})})
|
||||
|
||||
(defn account-stored
|
||||
[path type]
|
||||
(fn [result]
|
||||
(let [{:keys [error publicKey address]} (types/json->clj result)]
|
||||
(if error
|
||||
(re-frame/dispatch [::new-account-error :account-error error])
|
||||
(re-frame/dispatch [:wallet-legacy.accounts/account-stored
|
||||
{:address address
|
||||
:public-key publicKey
|
||||
:type type
|
||||
:path path}])))))
|
||||
|
||||
(defn normalize-path
|
||||
[path]
|
||||
(if (string/starts-with? path "m/")
|
||||
(str constants/path-wallet-root
|
||||
"/"
|
||||
(last (string/split path "/")))
|
||||
path))
|
||||
|
||||
(defn derive-and-store-account
|
||||
[key-uid path hashed-password type accounts]
|
||||
(fn [value]
|
||||
(let [{:keys [id error keyUid]} (types/json->clj value)]
|
||||
(if error
|
||||
(re-frame/dispatch [::new-account-error :password-error error])
|
||||
(native-module/multiaccount-derive-addresses
|
||||
id
|
||||
[path]
|
||||
(fn [derived]
|
||||
(let [derived-address (get-in (types/json->clj derived) [(keyword path) :address])]
|
||||
(if (some #(= derived-address (get % :address)) accounts)
|
||||
(re-frame/dispatch [::new-account-error :account-error
|
||||
(i18n/label :t/account-exists-title)])
|
||||
(native-module/multiaccount-store-derived
|
||||
id
|
||||
key-uid
|
||||
[path]
|
||||
hashed-password
|
||||
(fn [result]
|
||||
(let [{:keys [error] :as result} (types/json->clj result)
|
||||
{:keys [publicKey address]} (get result (keyword path))]
|
||||
(if error
|
||||
(re-frame/dispatch [::new-account-error :account-error error])
|
||||
(re-frame/dispatch
|
||||
[:wallet-legacy.accounts/account-stored
|
||||
{:address address
|
||||
:public-key publicKey
|
||||
:key-uid keyUid
|
||||
:type type
|
||||
:path (normalize-path path)}])))))))))))))
|
||||
|
||||
(def pass-error
|
||||
"cannot retrieve a valid key for a given account: could not decrypt key with given password")
|
||||
|
||||
(defn store-account
|
||||
[key-uid path hashed-password type]
|
||||
(fn [value]
|
||||
(let [{:keys [id error]} (types/json->clj value)]
|
||||
(if error
|
||||
(re-frame/dispatch [::new-account-error
|
||||
(if (= error pass-error) :password-error :account-error)
|
||||
error])
|
||||
(native-module/multiaccount-store-account
|
||||
id
|
||||
key-uid
|
||||
hashed-password
|
||||
(account-stored path type))))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::verify-password
|
||||
(fn [{:keys [address hashed-password]}]
|
||||
(native-module/verify
|
||||
address
|
||||
hashed-password
|
||||
#(re-frame/dispatch [:wallet-legacy.accounts/add-new-account-password-verified %
|
||||
hashed-password]))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::generate-account
|
||||
(fn [{:keys [derivation-info hashed-password accounts key-uid]}]
|
||||
(let [{:keys [address path]} derivation-info]
|
||||
(native-module/multiaccount-load-account
|
||||
address
|
||||
hashed-password
|
||||
(derive-and-store-account key-uid path hashed-password :generated accounts)))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::import-account-seed
|
||||
(fn [{:keys [passphrase hashed-password accounts key-uid]}]
|
||||
(native-module/multiaccount-import-mnemonic
|
||||
(mnemonic/sanitize-passphrase (security/unmask passphrase))
|
||||
""
|
||||
(derive-and-store-account key-uid constants/path-default-wallet hashed-password :seed accounts))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::import-account-private-key
|
||||
(fn [{:keys [private-key hashed-password key-uid]}]
|
||||
(native-module/multiaccount-import-private-key
|
||||
(string/trim (security/unmask private-key))
|
||||
(store-account key-uid constants/path-default-wallet hashed-password :key))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::validate-mnemonic
|
||||
(fn [[passphrase callback]]
|
||||
(native-module/validate-mnemonic passphrase callback)))
|
||||
|
||||
(rf/defn generate-new-account
|
||||
[{:keys [db]} hashed-password]
|
||||
(let [{:keys [key-uid wallet-root-address]}
|
||||
(get db :profile/profile)
|
||||
path-num (inc (get-in db [:profile/profile :latest-derived-path]))
|
||||
accounts (:profile/wallet-accounts db)]
|
||||
{:db (assoc-in db [:add-account :step] :generating)
|
||||
::generate-account {:derivation-info {:path (str "m/" path-num)
|
||||
:address wallet-root-address}
|
||||
:hashed-password hashed-password
|
||||
:accounts accounts
|
||||
:key-uid key-uid}}))
|
||||
|
||||
(rf/defn import-new-account-seed
|
||||
[{:keys [db]} passphrase hashed-password]
|
||||
{:db (assoc-in db [:add-account :step] :generating)
|
||||
::validate-mnemonic [(security/safe-unmask-data passphrase)
|
||||
#(re-frame/dispatch [:wallet-legacy.accounts/seed-validated % passphrase
|
||||
hashed-password])]})
|
||||
|
||||
(rf/defn new-account-seed-validated
|
||||
{:events [:wallet-legacy.accounts/seed-validated]}
|
||||
[{:keys [db] :as cofx} phrase-warnings passphrase hashed-password]
|
||||
(let [error (:error (types/json->clj phrase-warnings))
|
||||
{:keys [key-uid]} (:profile/profile db)]
|
||||
(if-not (string/blank? error)
|
||||
(new-account-error cofx :account-error error)
|
||||
(let [accounts (:profile/wallet-accounts db)]
|
||||
{::import-account-seed {:passphrase passphrase
|
||||
:hashed-password hashed-password
|
||||
:accounts accounts
|
||||
:key-uid key-uid}}))))
|
||||
|
||||
(rf/defn import-new-account-private-key
|
||||
[{:keys [db]} private-key hashed-password]
|
||||
(let [{:keys [key-uid]} (:profile/profile db)]
|
||||
{:db (assoc-in db [:add-account :step] :generating)
|
||||
::import-account-private-key {:private-key private-key
|
||||
:hashed-password hashed-password
|
||||
:key-uid key-uid}}))
|
||||
|
||||
(rf/defn save-new-account
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [{:keys [latest-derived-path]} (:profile/profile db)
|
||||
{:keys [account type]} (:add-account db)
|
||||
{:keys [address name key-uid]} account
|
||||
main-key-uid (or key-uid (get-in db [:profile/profile :key-uid]))
|
||||
accounts (:profile/wallet-accounts db)
|
||||
new-accounts (conj accounts account)
|
||||
;; Note(rasom): in case if a new account is created using a mnemonic or
|
||||
;; a private key we add a new keypair to the database, otherwise we just
|
||||
;; keep using "profile" keypair
|
||||
[method params]
|
||||
(if key-uid
|
||||
["accounts_saveKeypair"
|
||||
[{:key-uid main-key-uid
|
||||
:name name
|
||||
:type (if (= type :seed)
|
||||
"seed"
|
||||
"key")
|
||||
:derived-from address
|
||||
:last-used-derivation-index 0
|
||||
:synced-from ""
|
||||
:clock 0
|
||||
:accounts [account]}]]
|
||||
["accounts_saveAccount"
|
||||
[(assoc account :key-uid key-uid)]])]
|
||||
(when account
|
||||
(rf/merge cofx
|
||||
{:json-rpc/call [{:method method
|
||||
:params params
|
||||
:on-success #(re-frame/dispatch [::wallet-legacy/restart])}]
|
||||
:db (-> db
|
||||
(assoc :profile/wallet-accounts new-accounts)
|
||||
(dissoc :add-account))}
|
||||
(when (= type :generate)
|
||||
(multiaccounts.update/multiaccount-update
|
||||
:latest-derived-path
|
||||
(inc latest-derived-path)
|
||||
{}))))))
|
||||
|
||||
(rf/defn account-generated
|
||||
{:events [:wallet-legacy.accounts/account-stored]}
|
||||
[{:keys [db] :as cofx} {:keys [address] :as account}]
|
||||
(let [accounts (:profile/wallet-accounts db)]
|
||||
(if (some #(when (= (:address %) address) %) accounts)
|
||||
(new-account-error cofx :account-error (i18n/label :t/account-exists-title))
|
||||
(rf/merge cofx
|
||||
{:db (update-in db [:add-account :account] merge account)}
|
||||
(save-new-account)
|
||||
(if (utils.mobile-sync/syncing-allowed? cofx)
|
||||
(wallet-legacy/set-max-block address 0)
|
||||
(wallet-legacy/update-balances nil true))
|
||||
(wallet-legacy/fetch-collectibles-collection)
|
||||
(prices/update-prices)
|
||||
(navigation/navigate-back)))))
|
||||
|
||||
(rf/defn add-watch-account
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [address (get-in db [:add-account :address])]
|
||||
(account-generated cofx
|
||||
{:address (eip55/address->checksum (address/normalized-hex address))
|
||||
:type :watch})))
|
||||
|
||||
(rf/defn add-new-account-password-verified
|
||||
{:events [:wallet-legacy.accounts/add-new-account-password-verified]}
|
||||
[{:keys [db] :as cofx} result hashed-password]
|
||||
(let [{:keys [error]} (types/json->clj result)]
|
||||
(if (not (string/blank? error))
|
||||
(new-account-error cofx :password-error error)
|
||||
(let [{:keys [type seed private-key]} (:add-account db)]
|
||||
(case type
|
||||
:seed
|
||||
(import-new-account-seed cofx seed hashed-password)
|
||||
:key
|
||||
(import-new-account-private-key cofx private-key hashed-password)
|
||||
nil)))))
|
||||
|
||||
(rf/defn add-new-account-verify-password
|
||||
[{:keys [db]} hashed-password]
|
||||
{:db (assoc-in db [:add-account :step] :generating)
|
||||
::verify-password {:address (get-in db [:profile/profile :wallet-root-address])
|
||||
:hashed-password hashed-password}})
|
||||
|
||||
(rf/defn set-account-to-watch
|
||||
{:events [:wallet-legacy.accounts/set-account-to-watch]}
|
||||
[{:keys [db]} account]
|
||||
(let [name? (and (>= (count account) 3)
|
||||
(not (hex/valid-hex? account)))]
|
||||
(log/debug "[wallet] set-account-to-watch" account
|
||||
"name?" name?)
|
||||
(cond-> {:db (assoc-in db [:add-account :address] account)}
|
||||
name?
|
||||
(assoc ::ens.core/resolve-address
|
||||
[(chain/chain-id db)
|
||||
(stateofus/ens-name-parse account)
|
||||
#(re-frame/dispatch
|
||||
[:wallet-legacy.accounts/set-account-to-watch %])]))))
|
||||
|
||||
(rf/defn add-new-account
|
||||
{:events [:wallet-legacy.accounts/add-new-account]}
|
||||
[{:keys [db] :as cofx} hashed-password]
|
||||
(let [{:keys [type step]} (:add-account db)]
|
||||
(log/debug "[wallet] add-new-account"
|
||||
"type" type
|
||||
"step" step)
|
||||
(when-not step
|
||||
(case type
|
||||
:watch
|
||||
(add-watch-account cofx)
|
||||
:generate
|
||||
(generate-new-account cofx hashed-password)
|
||||
(:seed :key)
|
||||
(add-new-account-verify-password cofx hashed-password)
|
||||
nil))))
|
||||
|
||||
(rf/defn save-account
|
||||
{:events [:wallet-legacy.accounts/save-account]}
|
||||
[{:keys [db]} account {:keys [name color hidden]}]
|
||||
(let [accounts (:profile/wallet-accounts db)
|
||||
new-account (cond-> account
|
||||
name (assoc :name name)
|
||||
color (assoc :color color)
|
||||
(not (nil? hidden)) (assoc :hidden hidden))
|
||||
new-accounts (replace {account new-account} accounts)]
|
||||
{:json-rpc/call [{:method "accounts_saveAccount"
|
||||
:params [new-account]
|
||||
:on-success #()}]
|
||||
:db (assoc db :profile/wallet-accounts new-accounts)}))
|
||||
|
||||
(rf/defn delete-account
|
||||
{:events [:wallet-legacy.accounts/delete-account]}
|
||||
[{:keys [db] :as cofx} account]
|
||||
(let [accounts (:profile/wallet-accounts db)
|
||||
new-accounts (vec (remove #(= account %) accounts))
|
||||
deleted-address (:address account)]
|
||||
(rf/merge cofx
|
||||
{:json-rpc/call [{:method "accounts_deleteAccount"
|
||||
:params [(:address account)]
|
||||
:on-success #()}]
|
||||
:db (-> db
|
||||
(assoc :profile/wallet-accounts new-accounts)
|
||||
(update-in [:wallet-legacy :accounts] dissoc deleted-address))}
|
||||
(navigation/pop-to-root :shell-stack))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:key-storage/delete-imported-key
|
||||
(fn [{:keys [key-uid address password on-success on-error]}]
|
||||
(let [hashed-pass (native-module/sha3 (security/safe-unmask-data password))]
|
||||
(native-module/delete-imported-key
|
||||
key-uid
|
||||
(string/lower-case (subs address 2))
|
||||
hashed-pass
|
||||
(fn [result]
|
||||
(let [{:keys [error]} (types/json->clj result)]
|
||||
(if-not (string/blank? error)
|
||||
(on-error error)
|
||||
(on-success))))))))
|
||||
|
||||
(rf/defn delete-account-key
|
||||
{:events [:wallet-legacy.accounts/delete-key]}
|
||||
[{:keys [db] :as cofx} account password on-error]
|
||||
(let [deleted-address (:address account)
|
||||
dapps-address (get-in cofx [:db :profile/profile :dapps-address])]
|
||||
(if (= (string/lower-case dapps-address) (string/lower-case deleted-address))
|
||||
{:effects.utils/show-popup {:title (i18n/label :t/warning)
|
||||
:content (i18n/label :t/account-is-used)}}
|
||||
{:key-storage/delete-imported-key
|
||||
{:key-uid (get-in db [:profile/profile :key-uid])
|
||||
:address (:address account)
|
||||
:password password
|
||||
:on-success #(do
|
||||
(re-frame/dispatch [:hide-popover])
|
||||
(re-frame/dispatch [:wallet-legacy.accounts/delete-account account]))
|
||||
:on-error on-error}})))
|
||||
|
||||
(rf/defn view-only-qr-scanner-result
|
||||
{:events [:wallet-legacy.add-new/qr-scanner-result]}
|
||||
[{db :db :as cofx} data _]
|
||||
(let [address (:address (eip681/parse-uri data))]
|
||||
(rf/merge cofx
|
||||
(merge {:db (-> db
|
||||
(assoc-in [:add-account :scanned-address] address)
|
||||
(assoc-in [:add-account :address] address))}
|
||||
(when-not address
|
||||
{:effects.utils/show-popup {:title (i18n/label :t/error)
|
||||
:content (i18n/label :t/invalid-address-qr-code)}}))
|
||||
(navigation/navigate-back))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:list.selection/open-share
|
||||
(fn [obj]
|
||||
(list-selection/open-share obj)))
|
||||
|
||||
(rf/defn wallet-accounts-share
|
||||
{:events [:wallet-legacy.accounts/share]}
|
||||
[_ address]
|
||||
{:list.selection/open-share {:message (eip55/address->checksum address)}})
|
||||
@@ -1,182 +0,0 @@
|
||||
(ns legacy.status-im.wallet.choose-recipient.core
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.bottom-sheet.events :as bottom-sheet]
|
||||
[legacy.status-im.contact.db :as contact.db]
|
||||
[legacy.status-im.ethereum.ens :as ens]
|
||||
[legacy.status-im.ethereum.tokens :as tokens]
|
||||
[legacy.status-im.qr-scanner.core :as qr-scaner]
|
||||
[legacy.status-im.wallet.utils :as wallet.utils]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.common.router :as router]
|
||||
[status-im.common.universal-links :as links]
|
||||
[status-im.navigation.events :as navigation]
|
||||
[utils.ethereum.chain :as chain]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.money :as money]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.url :as url]))
|
||||
|
||||
;; FIXME(Ferossgp): Should be part of QR scanner not wallet
|
||||
(rf/defn toggle-flashlight
|
||||
{:events [:wallet-legacy/toggle-flashlight]}
|
||||
[{:keys [db]}]
|
||||
(let [flashlight-state (get-in db [:wallet-legacy :send-transaction :camera-flashlight])
|
||||
toggled-state (if (= :on flashlight-state) :off :on)]
|
||||
{:db (assoc-in db [:wallet-legacy :send-transaction :camera-flashlight] toggled-state)}))
|
||||
|
||||
(defn- find-address-name
|
||||
[db address]
|
||||
(:name (contact.db/find-contact-by-address (:contacts/contacts db) address)))
|
||||
|
||||
(rf/defn set-recipient
|
||||
{:events [:wallet-legacy.send/set-recipient]}
|
||||
[{:keys [db]} address]
|
||||
{:db (-> db
|
||||
(dissoc :wallet-legacy/recipient)
|
||||
(assoc-in [:ui/search :recipient-filter] nil)
|
||||
(assoc-in [:wallet-legacy/prepare-transaction :to] address))
|
||||
:dispatch [:navigate-back]})
|
||||
|
||||
(re-frame/reg-fx
|
||||
::resolve-addresses
|
||||
(fn [{:keys [chain-id ens-names callback]}]
|
||||
;; resolve all addresses then call the callback function with the array of
|
||||
;;addresses as parameter
|
||||
(-> (js/Promise.all
|
||||
(clj->js (mapv (fn [ens-name]
|
||||
(js/Promise.
|
||||
(fn [resolve-fn _]
|
||||
(ens/address chain-id ens-name resolve-fn))))
|
||||
ens-names)))
|
||||
(.then callback)
|
||||
(.catch (fn [error]
|
||||
(js/console.log error))))))
|
||||
|
||||
(defn- fill-prepare-transaction-details
|
||||
[db
|
||||
{address :address
|
||||
name :name
|
||||
value :value
|
||||
sym :symbol
|
||||
gas :gas
|
||||
gas-price :gasPrice
|
||||
gas-limit :gasLimit
|
||||
:or {sym :ETH}}
|
||||
all-tokens]
|
||||
(assoc db
|
||||
:wallet-legacy/prepare-transaction
|
||||
(cond-> {:to address
|
||||
:to-name (or name (find-address-name db address))
|
||||
:from (wallet.utils/get-default-account
|
||||
(get db :profile/wallet-accounts))}
|
||||
gas (assoc :gas (money/bignumber gas))
|
||||
gas-limit (assoc :gas (money/bignumber gas-limit))
|
||||
gas-price (assoc :gasPrice (money/bignumber gas-price))
|
||||
value (assoc :amount-text
|
||||
(if (= :ETH sym)
|
||||
(str (money/internal->formatted value sym (get all-tokens sym)))
|
||||
(str value)))
|
||||
sym (assoc :symbol sym))))
|
||||
|
||||
(defn parse-eth-value
|
||||
"Takes a map as returned by `parse-uri` and returns value as BigNumber"
|
||||
[s]
|
||||
(when (string? s)
|
||||
(let [eth? (string/ends-with? s "ETH")
|
||||
^js n (money/bignumber (string/replace s "ETH" ""))]
|
||||
(if eth? (.times n 1e18) n))))
|
||||
|
||||
(defn extract-request-details
|
||||
"Return a map encapsulating request details (with keys `value`, `address` and `symbol`) from a parsed URI.
|
||||
Supports ethereum and erc20 token."
|
||||
[{:keys [value address function-name function-arguments] :as details} all-tokens]
|
||||
(when address
|
||||
(merge details
|
||||
(case function-name
|
||||
nil
|
||||
{:value (parse-eth-value value)
|
||||
:symbol :ETH
|
||||
:address address}
|
||||
"transfer"
|
||||
{:value (money/bignumber (:uint256 function-arguments))
|
||||
:symbol (:symbol (tokens/address->token all-tokens address))
|
||||
:address (:address function-arguments)}
|
||||
nil))))
|
||||
|
||||
(rf/defn request-uri-parsed
|
||||
{:events [:wallet-legacy/request-uri-parsed]}
|
||||
[{{:networks/keys [networks current-network]
|
||||
:wallet-legacy/keys [all-tokens]
|
||||
:as db}
|
||||
:db}
|
||||
{:keys [chain-id] :as data}
|
||||
uri]
|
||||
(let [{:keys [address gasPrice] :as details}
|
||||
(extract-request-details data all-tokens)]
|
||||
(if address
|
||||
(if (:wallet-legacy/recipient db)
|
||||
{:db (update db
|
||||
:wallet-legacy/recipient assoc
|
||||
:resolved-address address
|
||||
:address address)}
|
||||
(if (:wallet-legacy/prepare-transaction db)
|
||||
{:db (update db
|
||||
:wallet-legacy/prepare-transaction assoc
|
||||
:to address
|
||||
:to-name (find-address-name db address))}
|
||||
(let [current-chain-id (get-in networks [current-network :config :NetworkId])]
|
||||
(merge {:db (fill-prepare-transaction-details db details all-tokens)
|
||||
:dispatch [:open-modal :prepare-send-transaction]}
|
||||
(when-not gasPrice
|
||||
{:signing/update-gas-price
|
||||
{:success-callback
|
||||
#(re-frame/dispatch
|
||||
[:wallet-legacy.send/update-gas-price-success :wallet-legacy/prepare-transaction
|
||||
%])
|
||||
:network-id (get-in (chain/current-network db)
|
||||
[:config :NetworkId])}})
|
||||
(when (and chain-id (not= current-chain-id chain-id))
|
||||
{:ui/show-error (i18n/label :t/wallet-invalid-chain-id
|
||||
{:data uri :chain current-chain-id})})))))
|
||||
{:ui/show-error (i18n/label :t/wallet-invalid-address {:data uri})})))
|
||||
|
||||
(rf/defn qr-scanner-allowed
|
||||
{:events [:wallet-legacy.send/qr-scanner]}
|
||||
[{:keys [db] :as cofx} options]
|
||||
(rf/merge cofx
|
||||
(bottom-sheet/hide-bottom-sheet-old)
|
||||
(qr-scaner/scan-qr-code options)))
|
||||
|
||||
(rf/defn parse-eip681-uri-and-resolve-ens
|
||||
{:events [:wallet-legacy/parse-eip681-uri-and-resolve-ens]}
|
||||
[{db :db :as cofx} {:keys [message uri paths ens-names error]} ignore-url]
|
||||
(if-not error
|
||||
;; first we get a vector of ens-names to resolve and a vector of paths of these names
|
||||
(if (empty? ens-names)
|
||||
;; if there are no ens-names, we dispatch request-uri-parsed immediately
|
||||
(request-uri-parsed cofx message uri)
|
||||
{::resolve-addresses
|
||||
{:chain-id (chain/chain-id db)
|
||||
:ens-names ens-names
|
||||
:callback
|
||||
(fn [addresses]
|
||||
(re-frame/dispatch
|
||||
[:wallet-legacy/request-uri-parsed
|
||||
;; we replace ens-names at their path in the message by their actual address
|
||||
(reduce (fn [message [path address]]
|
||||
(assoc-in message path address))
|
||||
message
|
||||
(map vector paths addresses)) uri]))}})
|
||||
(if (and (url/url? uri) (not ignore-url))
|
||||
(if (links/universal-link? uri)
|
||||
{:dispatch [:universal-links/handle-url uri]}
|
||||
{:browser/show-browser-selection uri})
|
||||
{:ui/show-error (i18n/label :t/wallet-invalid-address {:data uri})})))
|
||||
|
||||
(rf/defn qr-scanner-result
|
||||
{:events [:wallet-legacy.send/qr-scanner-result]}
|
||||
[cofx data {:keys [ignore-url]}]
|
||||
(rf/merge cofx
|
||||
(navigation/navigate-back)
|
||||
(parse-eip681-uri-and-resolve-ens (router/match-eip681 data) ignore-url)))
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,128 +0,0 @@
|
||||
(ns legacy.status-im.wallet.custom-tokens.core
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.ui.components.colors :as colors]
|
||||
[legacy.status-im.ui.components.react :as react]
|
||||
[legacy.status-im.wallet.core :as wallet]
|
||||
[legacy.status-im.wallet.prices :as prices]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.navigation.events :as navigation]
|
||||
[utils.address :as address]
|
||||
[utils.ethereum.chain :as chain]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:wallet-legacy.custom-token/contract-address-paste
|
||||
(fn []
|
||||
(react/get-from-clipboard
|
||||
#(re-frame/dispatch [:wallet-legacy.custom-token/contract-address-is-pasted (string/trim %)]))))
|
||||
|
||||
(defn field-exists?
|
||||
[{:wallet-legacy/keys [all-tokens]} field-key field-value]
|
||||
(some #(= field-value (get % field-key))
|
||||
(vals all-tokens)))
|
||||
|
||||
(defn token-in-list?
|
||||
[{:wallet-legacy/keys [all-tokens]} contract]
|
||||
(not (nil? (get all-tokens (string/lower-case contract)))))
|
||||
|
||||
(rf/defn contract-address-is-changed
|
||||
{:events [:wallet-legacy.custom-token/contract-address-is-pasted]}
|
||||
[{:keys [db]} contract]
|
||||
(if (address/address? contract)
|
||||
(if (token-in-list? db contract)
|
||||
{:db (assoc db
|
||||
:wallet-legacy/custom-token-screen
|
||||
{:contract contract :error (i18n/label :t/already-have-asset)})}
|
||||
{:db (assoc db
|
||||
:wallet-legacy/custom-token-screen
|
||||
{:contract contract :in-progress? true})
|
||||
:json-rpc/call [{:method "wallet_discoverToken"
|
||||
:params [(chain/chain-id db) contract]
|
||||
:on-success #(re-frame/dispatch
|
||||
[:wallet-legacy.custom-token/token-discover-result %])
|
||||
:on-error #(re-frame/dispatch [:wallet-legacy.custom-token/not-supported])}]})
|
||||
{:db (assoc db
|
||||
:wallet-legacy/custom-token-screen
|
||||
{:contract contract
|
||||
:error (i18n/label :t/wrong-address)})}))
|
||||
|
||||
(rf/defn token-discover-result
|
||||
{:events [:wallet-legacy.custom-token/token-discover-result]}
|
||||
[{:keys [db]} {:keys [name symbol decimals]}]
|
||||
(let [symbol-exists? (field-exists? db :symbol (keyword symbol))]
|
||||
{:db (update db
|
||||
:wallet-legacy/custom-token-screen
|
||||
merge
|
||||
{:name name
|
||||
:symbol symbol
|
||||
:error-symbol (when symbol-exists?
|
||||
(i18n/label :t/you-already-have-an-asset {:value symbol}))
|
||||
:decimals (str decimals)
|
||||
:in-progress? nil})}))
|
||||
|
||||
(rf/defn not-supported
|
||||
{:events [:wallet-legacy.custom-token/not-supported]}
|
||||
[{:keys [db]}]
|
||||
{:db (assoc-in db [:wallet-legacy/custom-token-screen :in-progress?] nil)
|
||||
:effects.utils/show-popup {:content (i18n/label :t/contract-isnt-supported)}})
|
||||
|
||||
(rf/defn add-custom-token
|
||||
{:events [:wallet-legacy.custom-token.ui/add-pressed]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [{:keys [contract name symbol decimals]} (get db :wallet-legacy/custom-token-screen)
|
||||
symbol (keyword symbol)
|
||||
new-token {:address contract
|
||||
:name name
|
||||
:symbol symbol
|
||||
:decimals (int decimals)
|
||||
:color (rand-nth colors/chat-colors)}]
|
||||
(rf/merge cofx
|
||||
{:db (assoc-in db
|
||||
[:wallet-legacy/all-tokens contract]
|
||||
(assoc new-token :custom? true))
|
||||
:json-rpc/call [{:method "wallet_addCustomToken"
|
||||
:params [new-token]
|
||||
:on-success #()}]}
|
||||
(wallet/add-custom-token new-token)
|
||||
(prices/update-prices)
|
||||
(navigation/navigate-back))))
|
||||
|
||||
(rf/defn remove-custom-token
|
||||
{:events [:wallet-legacy.custom-token.ui/remove-pressed]}
|
||||
[{:keys [db] :as cofx} {:keys [address] :as token} navigate-back?]
|
||||
(rf/merge cofx
|
||||
{:db (update db :wallet-legacy/all-tokens dissoc address)
|
||||
:json-rpc/call [{:method "wallet_deleteCustomToken"
|
||||
:params [address]
|
||||
:on-success #()}]}
|
||||
(wallet/remove-custom-token token)
|
||||
(when navigate-back?
|
||||
(navigation/navigate-back))))
|
||||
|
||||
(rf/defn field-is-edited
|
||||
{:events [:wallet-legacy.custom-token.ui/field-is-edited]}
|
||||
[{:keys [db] :as cofx} field-key value]
|
||||
(case field-key
|
||||
:contract (contract-address-is-changed cofx value)
|
||||
:name {:db (update db
|
||||
:wallet-legacy/custom-token-screen
|
||||
merge
|
||||
{field-key
|
||||
value
|
||||
:error-name
|
||||
(when (field-exists? db field-key value)
|
||||
(i18n/label :t/you-already-have-an-asset
|
||||
{:value value}))})}
|
||||
:symbol {:db (update db
|
||||
:wallet-legacy/custom-token-screen
|
||||
merge
|
||||
{field-key
|
||||
value
|
||||
:error-symbol
|
||||
(when (field-exists? db field-key (keyword value))
|
||||
(i18n/label :t/you-already-have-an-asset {:value value}))})}
|
||||
:decimals {:db (assoc-in db
|
||||
[:wallet-legacy/custom-token-screen :decimals]
|
||||
value)}))
|
||||
@@ -1,55 +0,0 @@
|
||||
(ns legacy.status-im.wallet.db
|
||||
(:require
|
||||
[legacy.status-im.utils.priority-map :refer [empty-transaction-map]]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.money :as money]))
|
||||
|
||||
(defn- too-precise-amount?
|
||||
"Checks if number has any extra digit beyond the allowed number of decimals.
|
||||
It does so by checking the number against its rounded value."
|
||||
[amount decimals]
|
||||
(let [^js bn (money/bignumber amount)]
|
||||
(not (.eq bn
|
||||
(.round bn decimals)))))
|
||||
|
||||
(defn parse-amount
|
||||
[amount decimals]
|
||||
(when-not (empty? amount)
|
||||
(let [normalized-amount (money/normalize amount)
|
||||
value (money/bignumber normalized-amount)]
|
||||
(cond
|
||||
(not (money/valid? value))
|
||||
{:error (i18n/label :t/validation-amount-invalid-number) :value value}
|
||||
|
||||
(too-precise-amount? normalized-amount decimals)
|
||||
{:error (i18n/label :t/validation-amount-is-too-precise {:decimals decimals}) :value value}
|
||||
|
||||
:else
|
||||
{:value value}))))
|
||||
|
||||
(def default-wallet-filters
|
||||
#{:inbound :outbound :pending :failed})
|
||||
|
||||
(def default-wallet
|
||||
{:filters default-wallet-filters})
|
||||
|
||||
(defn get-confirmations
|
||||
[{:keys [block]} current-block]
|
||||
(if (and current-block block)
|
||||
(inc (- current-block block))
|
||||
0))
|
||||
|
||||
(defn remove-transactions-since-block
|
||||
[accounts block]
|
||||
(reduce-kv (fn [acc account-address account]
|
||||
(assoc acc
|
||||
account-address
|
||||
(update account
|
||||
:transactions
|
||||
(fn [transactions]
|
||||
(into empty-transaction-map
|
||||
(drop-while (fn [[_ v]]
|
||||
(>= (int (:block v)) block))
|
||||
transactions))))))
|
||||
{}
|
||||
accounts))
|
||||
@@ -1,59 +0,0 @@
|
||||
(ns legacy.status-im.wallet.db-test
|
||||
(:require
|
||||
[cljs.test :refer-macros [deftest is testing]]
|
||||
[legacy.status-im.wallet.db :as wallet.db]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.money :as money]))
|
||||
|
||||
(deftest test-too-precise-amount?
|
||||
(testing "try both decimal and scientific or hex format"
|
||||
(is (false? (#'legacy.status-im.wallet.db/too-precise-amount? "100" 2)))
|
||||
(is (false? (#'legacy.status-im.wallet.db/too-precise-amount? "100" 0)))
|
||||
(is (true? (#'legacy.status-im.wallet.db/too-precise-amount? "100.1" 0)))
|
||||
(is (false? (#'legacy.status-im.wallet.db/too-precise-amount? "100.23" 2)))
|
||||
(is (true? (#'legacy.status-im.wallet.db/too-precise-amount? "100.233" 2)))
|
||||
(is (true? (#'legacy.status-im.wallet.db/too-precise-amount? "100.0000000000000000001" 18)))
|
||||
(is (false? (#'legacy.status-im.wallet.db/too-precise-amount? "100.000000000000000001" 18)))
|
||||
(is (false? (#'legacy.status-im.wallet.db/too-precise-amount? "1e-18" 18)))
|
||||
(is (true? (#'legacy.status-im.wallet.db/too-precise-amount? "1e-19" 18)))
|
||||
(is (true? (#'legacy.status-im.wallet.db/too-precise-amount? "0xa.a" 2))) ;; 0xa.a is 10.625
|
||||
(is (false? (#'legacy.status-im.wallet.db/too-precise-amount? "0xa.a" 3)))
|
||||
(is (false? (#'legacy.status-im.wallet.db/too-precise-amount? "1000" 3)))))
|
||||
|
||||
(defn- equal-results?
|
||||
[a b]
|
||||
(and (= (:error a) (:error b))
|
||||
(or (and (nil? (:amount a))
|
||||
(nil? (:amount b)))
|
||||
(.eq ^js (:amount a) (:amount b)))))
|
||||
|
||||
(deftest test-parse-amount
|
||||
(testing "test amount parsing"
|
||||
(is (equal-results? {:value (money/bignumber "100")} (wallet.db/parse-amount "100" 2)))
|
||||
(is (equal-results? {:value (money/bignumber "100")} (wallet.db/parse-amount "100" 0)))
|
||||
(is (equal-results? {:error (i18n/label :t/validation-amount-is-too-precise {:decimals 0})
|
||||
:value (money/bignumber "100.1")}
|
||||
(wallet.db/parse-amount "100.1" 0)))
|
||||
(is (equal-results? {:value (money/bignumber "100.23")} (wallet.db/parse-amount "100.23" 2)))
|
||||
(is (equal-results? {:error (i18n/label :t/validation-amount-is-too-precise {:decimals 2})
|
||||
:value (money/bignumber "100.233")}
|
||||
(wallet.db/parse-amount "100.233" 2)))
|
||||
(is (equal-results? {:error (i18n/label :t/validation-amount-is-too-precise {:decimals 18})
|
||||
:value (money/bignumber "100.0000000000000000001")}
|
||||
(wallet.db/parse-amount "100.0000000000000000001" 18)))
|
||||
(is (equal-results? {:value (money/bignumber "100.000000000000000001")}
|
||||
(wallet.db/parse-amount "100.000000000000000001" 18)))
|
||||
(is (equal-results? {:value (money/bignumber "1e-18")} (wallet.db/parse-amount "1e-18" 18)))
|
||||
(is (equal-results? {:error (i18n/label :t/validation-amount-is-too-precise {:decimals 18})
|
||||
:value (money/bignumber "1e-19")}
|
||||
(wallet.db/parse-amount "1e-19" 18)))
|
||||
(is (equal-results? {:error (i18n/label :t/validation-amount-is-too-precise {:decimals 2})
|
||||
:value (money/bignumber "10.625")}
|
||||
(wallet.db/parse-amount "0xa.a" 2)))
|
||||
(is (equal-results? {:value (money/bignumber "10.625")} (wallet.db/parse-amount "0xa.a" 3)))
|
||||
(is (equal-results? {:error (i18n/label :t/validation-amount-invalid-number)
|
||||
:value nil}
|
||||
(wallet.db/parse-amount "SOMETHING" 5)))
|
||||
(is (nil? (wallet.db/parse-amount nil 5)))
|
||||
(is (nil? (wallet.db/parse-amount "" 5)))
|
||||
(is (equal-results? {:value (money/bignumber "1000")} (wallet.db/parse-amount "1000" 3)))))
|
||||
@@ -1,77 +0,0 @@
|
||||
(ns legacy.status-im.wallet.prices
|
||||
(:require
|
||||
[clojure.set :as set]
|
||||
[legacy.status-im.ethereum.tokens :as tokens]
|
||||
[legacy.status-im.utils.currency :as currency]
|
||||
[legacy.status-im.utils.prices :as prices]
|
||||
[legacy.status-im.wallet.utils :as wallet.utils]
|
||||
[re-frame.core :as re-frame]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.ethereum.chain :as chain]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn assoc-error-message
|
||||
[db error-type err]
|
||||
(assoc-in db [:wallet-legacy :errors error-type] (or err :unknown-error)))
|
||||
|
||||
(defn clear-error-message
|
||||
[db error-type]
|
||||
(update-in db [:wallet-legacy :errors] dissoc error-type))
|
||||
|
||||
(defn tokens-symbols
|
||||
[visible-token-symbols all-tokens]
|
||||
(set/difference (set visible-token-symbols)
|
||||
(set (map :symbol (tokens/nfts-for all-tokens)))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:wallet-legacy/get-prices
|
||||
(fn [{:keys [from to mainnet? success-event error-event]}]
|
||||
(prices/get-prices from
|
||||
to
|
||||
mainnet?
|
||||
#(re-frame/dispatch [success-event %])
|
||||
#(re-frame/dispatch [error-event %]))))
|
||||
|
||||
(rf/defn on-update-prices-success
|
||||
{:events [::update-prices-success]}
|
||||
[{:keys [db]} prices]
|
||||
{:db (assoc db
|
||||
:prices prices
|
||||
:prices-loading? false)})
|
||||
|
||||
(rf/defn on-update-prices-fail
|
||||
{:events [::update-prices-fail]}
|
||||
[{:keys [db]} err]
|
||||
(log/debug "Unable to get prices: " err)
|
||||
{:db (-> db
|
||||
(assoc-error-message :prices-update :error-unable-to-get-prices)
|
||||
(assoc :prices-loading? false))})
|
||||
|
||||
(rf/defn update-prices
|
||||
{:events [:wallet-legacy.ui/pull-to-refresh]}
|
||||
[{{:keys [network-status :wallet-legacy/all-tokens]
|
||||
{:keys [currency :wallet-legacy/visible-tokens]
|
||||
:or {currency :usd}}
|
||||
:profile/profile
|
||||
:as db}
|
||||
:db}]
|
||||
(let [chain (chain/chain-keyword db)
|
||||
mainnet? (= :mainnet chain)
|
||||
assets (get visible-tokens chain #{})
|
||||
tokens (tokens-symbols assets all-tokens)
|
||||
currency (get currency/currencies currency)]
|
||||
(when (not= network-status :offline)
|
||||
{:wallet-legacy/get-prices
|
||||
{:from (if mainnet?
|
||||
(conj tokens "ETH")
|
||||
[(-> (tokens/native-currency (chain/get-current-network db))
|
||||
(wallet.utils/exchange-symbol))])
|
||||
:to [(:code currency)]
|
||||
:mainnet? mainnet?
|
||||
:success-event ::update-prices-success
|
||||
:error-event ::update-prices-fail}
|
||||
|
||||
:db
|
||||
(-> db
|
||||
(clear-error-message :prices-update)
|
||||
(assoc :prices-loading? true))})))
|
||||
@@ -1,107 +0,0 @@
|
||||
(ns legacy.status-im.wallet.recipient.core
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.ethereum.ens :as ens]
|
||||
[legacy.status-im.ui.components.react :as react]
|
||||
[legacy.status-im.utils.random :as random]
|
||||
[legacy.status-im.utils.utils :as utils]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.common.json-rpc.events :as json-rpc]
|
||||
[status-im.navigation.events :as navigation]
|
||||
[utils.address :as address]
|
||||
[utils.ens.core :as utils.ens]
|
||||
[utils.ens.stateofus :as stateofus]
|
||||
[utils.ethereum.chain :as chain]
|
||||
[utils.ethereum.eip.eip55 :as eip55]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.string :as utils.string]))
|
||||
|
||||
;;NOTE we want to handle only last resolve
|
||||
(def resolve-last-id (atom nil))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::resolve-address
|
||||
(fn [{:keys [chain-id ens-name cb]}]
|
||||
(ens/address chain-id ens-name cb)))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:wallet-legacy.recipient/address-paste
|
||||
(fn []
|
||||
(react/get-from-clipboard
|
||||
#(re-frame/dispatch [:wallet-legacy.recipient/address-changed (string/trim %)]))))
|
||||
|
||||
(rf/defn address-paste-pressed
|
||||
{:events [:wallet-legacy.recipient/address-paste-pressed]}
|
||||
[_]
|
||||
{:wallet-legacy.recipient/address-paste nil})
|
||||
|
||||
(rf/defn set-recipient
|
||||
{:events [::recipient-address-resolved]}
|
||||
[{:keys [db] :as cofx} raw-recipient id]
|
||||
(when (or (not id) (= id @resolve-last-id))
|
||||
(reset! resolve-last-id nil)
|
||||
(let [recipient (utils.string/safe-trim raw-recipient)]
|
||||
(cond
|
||||
(address/address? recipient)
|
||||
(let [checksum (eip55/address->checksum recipient)]
|
||||
(if (eip55/valid-address-checksum? checksum)
|
||||
(rf/merge cofx
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet-legacy/recipient :searching] false)
|
||||
(assoc-in [:wallet-legacy/recipient :resolved-address] checksum))}
|
||||
(json-rpc/call
|
||||
{:method "eth_getCode"
|
||||
:params [checksum "latest"]
|
||||
:on-success #(when (not= "0x" %)
|
||||
(utils/show-popup (i18n/label :t/warning)
|
||||
(i18n/label
|
||||
:t/warning-sending-to-contract-descr)))
|
||||
:number-of-retries 3}))
|
||||
{:ui/show-error (i18n/label :t/wallet-invalid-address-checksum {:data recipient})
|
||||
:db (assoc-in db [:wallet-legacy/recipient :searching] false)}))
|
||||
(and (not (string/blank? recipient))
|
||||
(not (string/starts-with? recipient "0x"))
|
||||
(utils.ens/valid-eth-name-prefix? recipient))
|
||||
(let [ens-name (if (= (.indexOf ^js recipient ".") -1)
|
||||
(stateofus/subdomain recipient)
|
||||
recipient)]
|
||||
(if (utils.ens/is-valid-eth-name? ens-name)
|
||||
(do
|
||||
(reset! resolve-last-id (random/id))
|
||||
{::resolve-address
|
||||
{:chain-id (chain/chain-id db)
|
||||
:ens-name ens-name
|
||||
:cb #(re-frame/dispatch [::recipient-address-resolved % @resolve-last-id])}})
|
||||
{:db (assoc-in db [:wallet-legacy/recipient :searching] false)}))
|
||||
:else
|
||||
{:db (assoc-in db [:wallet-legacy/recipient :searching] false)}))))
|
||||
|
||||
(rf/defn address-changed
|
||||
{:events [:wallet-legacy.recipient/address-changed]}
|
||||
[{:keys [db] :as cofx} new-identity]
|
||||
(rf/merge cofx
|
||||
{:db (update db
|
||||
:wallet-legacy/recipient assoc
|
||||
:address new-identity
|
||||
:resolved-address nil
|
||||
:searching true)}
|
||||
(set-recipient new-identity nil)))
|
||||
|
||||
(rf/defn recipient-modal-closed
|
||||
{:events [:wallet-legacy/recipient-modal-closed]}
|
||||
[{:keys [db]}]
|
||||
{:db (dissoc db :wallet-legacy/recipient)})
|
||||
|
||||
(rf/defn add-favourite
|
||||
{:events [:wallet-legacy/add-favourite]}
|
||||
[{:keys [db] :as cofx} address name]
|
||||
(let [new-favourite {:address address
|
||||
:name (or name "")
|
||||
:favourite true}]
|
||||
(rf/merge cofx
|
||||
{:db (assoc-in db [:wallet-legacy/favourites address] new-favourite)
|
||||
:json-rpc/call [{:method "wallet_addSavedAddress"
|
||||
:params [new-favourite]
|
||||
:on-success #()}]}
|
||||
(navigation/navigate-back))))
|
||||
@@ -1,52 +0,0 @@
|
||||
(ns legacy.status-im.wallet.swap.core
|
||||
(:require
|
||||
[re-frame.core :as re-frame]
|
||||
[re-frame.db :as re-frame.db]
|
||||
[status-im.navigation.events :as navigation]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
;; "source? true" means we are selecting the source asset. false implies
|
||||
;; selection of sink asset."
|
||||
(re-frame/reg-event-fx ::open-asset-selector-modal
|
||||
(fn [{:keys [db]} [source?]]
|
||||
{:db (assoc db :wallet-legacy/modal-selecting-source-token? source?)
|
||||
:fx [[:dispatch [:open-modal :swap-asset-selector {}]]]}))
|
||||
|
||||
(rf/defn set-from-token
|
||||
{:events [::set-from-token]}
|
||||
[{:keys [db]} from-symbol]
|
||||
(rf/merge {:db (assoc db :wallet-legacy/swap-from-token from-symbol)}
|
||||
(navigation/navigate-back)))
|
||||
|
||||
(rf/defn set-to-token
|
||||
{:events [::set-to-token]}
|
||||
[{:keys [db]} to-symbol]
|
||||
(rf/merge {:db (assoc db :wallet-legacy/swap-to-token to-symbol)}
|
||||
(navigation/navigate-back)))
|
||||
|
||||
(rf/defn set-from-token-amount
|
||||
[{:keys [db]} from-amount]
|
||||
{:db (assoc db :wallet-legacy/swap-from-token-amount from-amount)})
|
||||
|
||||
(rf/defn set-max-from-token-amount
|
||||
[{:keys [db]} _]
|
||||
{:db (assoc db :wallet-legacy/swap-from-token-amount 0)})
|
||||
|
||||
(rf/defn switch-from-token-with-to
|
||||
{:events [::switch-from-token-with-to]}
|
||||
[{:keys [db]}]
|
||||
{:db (assoc db
|
||||
:wallet-legacy/swap-from-token (:wallet-legacy/swap-to-token db)
|
||||
:wallet-legacy/swap-to-token (:wallet-legacy/swap-from-token db))})
|
||||
|
||||
(rf/defn set-advanced-mode
|
||||
{:events [::set-advanced-mode]}
|
||||
[{:keys [db]} mode]
|
||||
{:db (assoc db :wallet-legacy/swap-advanced-mode? mode)})
|
||||
|
||||
(comment
|
||||
(->> re-frame.db/app-db
|
||||
deref
|
||||
:wallet-legacy/all-tokens
|
||||
vals
|
||||
(map #(str (:name %) "-" (:symbol %)))))
|
||||
@@ -1,11 +0,0 @@
|
||||
(ns legacy.status-im.wallet.transactions-test
|
||||
(:require
|
||||
[cljs.test :refer-macros [deftest is]]
|
||||
[legacy.status-im.ethereum.transactions.core :as transactions]))
|
||||
|
||||
(deftest get-transaction-details-url
|
||||
(is (= "https://etherscan.io/tx/asdfasdf"
|
||||
(transactions/get-transaction-details-url 1 "asdfasdf")))
|
||||
(is (nil? (transactions/get-transaction-details-url 7787878 "asdfasdfg")))
|
||||
(is (thrown? js/Error (transactions/get-transaction-details-url nil "asdfasdfg")))
|
||||
(is (thrown? js/Error (transactions/get-transaction-details-url 676868 1))))
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user