Compare commits

...
Author SHA1 Message Date
codemaster115 d944b15f16 feat: initial quo/messages/message component 2023-11-02 10:36:51 -07:00
Ajay Sivan abbf29d4ca Remove all status-im.ui.components.react usages in status-im2 (#17750) 2023-10-30 06:37:28 -07:00
Parvesh Monu cebec10aa5 fix bottom message in the chat history is hidden behind the composer with an image in it (#17757) 2023-10-30 15:46:16 +05:30
Smoothieewastaken 55b233c528 docs: Fixed typos (#17749) 2023-10-30 08:06:52 +01:00
Omar Basem 68ad4fe086 Wallet: Address Text (#17732)
* Wallet: address text
2023-10-30 09:40:39 +04:00
Jamie Caprani 06c31f3a12 chore: add sub to get network info (#17650) 2023-10-27 03:54:58 -07:00
Lungu Cristian 954373105d Visual debugging of components (#17729)
* feat: debug/show components from the REPL

* ref: some renames and cleanup

* chore: removed comments/imports

* feat: added remount on every eval & small changes

* doc: added tip to debugging doc

* doc: formatting

* doc: more formatting

* fix: fixed docs and other review comments

* fix: moved & renamed into the dev.component-preview ns

* style: adjusted debugging readme spacing

* fix: removed trailing line
2023-10-27 13:14:01 +03:00
Mohsen 2aeafa30bd [#17423] fix: update sync flow (#17731) 2023-10-27 11:16:56 +03:00
Parvesh Monu 5920c35677 Fixed Some Grammatical Errors in README.md (#17716)
Author: Janumala Akhilendra <82641474+JanumalaAkhilendra@users.noreply.github.com>
2023-10-27 13:17:16 +05:30
Ulises Manuel 1f71883fa4 [#16755] - Network routing component (#17457)
* Add network routing component & animations
* Add basic tests and accessibility labels
2023-10-26 16:07:44 -06:00
Siddarth Kumar c9b3196203 improve make component-test robustness (#17743)
Many times devs run
`make component-test` or `make component-test-watch` when there is already a metro or clojure terminal running on their system.

This causes weird behaviour and it is advised to not run these commands together.

This commit prevents that and shows a warning.
2023-10-26 23:24:23 +05:30
mmilad75 6ebd5b421c Fix account-card component UI (#17589)
* add new type

* fix lint issues

* add tests

* refactor get-test-data function

* resolve comments

* fix imports

* resolve comments

* fix lint issues

* remove extra code

* fix height
2023-10-26 16:46:24 +03:30
Ibrahem Khalil 901644e023 Make color selector take full 0device width to match Figma and add dynamic width (#17465) 2023-10-26 13:20:40 +03:00
Mohsen df256bf2b4 [#17534] fix: Add contact scan QR screen back handler issue (#17694) 2023-10-26 12:38:47 +03:00
Jamie Caprani 56492949f1 feat (wallet): add ability to create new account (#17496) 2023-10-26 01:45:33 -07:00
frank ab2ad0ec12 Don't sync AC notifications, only decisions/state (#17600)
* fix outgoing contact request state not show correctly

* update status-go-version.json
2023-10-26 14:44:06 +08:00
Ibrahem Khalil fe2272b703 Fix Composer not focusing on edit/reply (#17640) 2023-10-26 05:43:49 +03:00
Icaro Motta c0b21aa315 Document how to auto-format Clojure files in VSCode with zprint (#17719)
Document how a VSCode user can configure their editor to auto-format
Clojure(Script) files that respect all the formatter (zprint) settings specified
in status-mobile/.zprintrc.

The result should be that on every file save, the file should be identically
formatted as if you used make lint-fix, at least the part about zprint. If
lint-fix does other things now or in the future that are outside the scope of
zprint, those won't be covered by the VSCode extension.
2023-10-25 23:19:56 -03:00
Nikolay 876b020a32 Token network component (#17667) 2023-10-25 13:35:42 -07:00
Mohsen 8ed7059aa9 [#17230] fix: fetch group member info (#17726) 2023-10-25 21:26:34 +03:00
Omar Basem 125c117bac wallet: token value drawer (#17730)
* wallet: token value drawer
2023-10-25 15:45:45 +04:00
Parvesh Monu 078976806a Don't display "Add Unknown as contact to send a Message" if chat is not loaded (#17704) 2023-10-25 16:38:01 +05:30
100 changed files with 1932 additions and 427 deletions
+12
View File
@@ -0,0 +1,12 @@
{
"editor.formatOnSave": true,
"clojure.format.enable": false,
"[clojure]": {
"editor.defaultFormatter": "rflagreca.vscode-clj-zprint"
},
"vscode-clj-zprint.IgnoreExternalFiles": false,
"vscode-clj-zprint.CommunityFormatting": false,
"vscode-clj-zprint.OptionsMap": "",
"vscode-clj-zprint.width": "",
"vscode-clj-zprint.Styles.UseOnlyTheseStyles": false
}
+2
View File
@@ -362,6 +362,7 @@ component-test-watch: export TARGET := clojure
component-test-watch: export COMPONENT_TEST := true
component-test-watch: export BABEL_ENV := test
component-test-watch: ##@ Watch tests and re-run no changes to cljs files
@@scripts/check-metro-shadow-process.sh
rm -rf ./component-spec
yarn install
nodemon --exec 'yarn shadow-cljs compile component-test && jest --config=test/jest/jest.config.js' -e cljs
@@ -370,6 +371,7 @@ component-test: export TARGET := clojure
component-test: export COMPONENT_TEST := true
component-test: export BABEL_ENV := test
component-test: ##@test Run component tests once in NodeJS
@scripts/check-metro-shadow-process.sh
rm -rf ./component-spec
yarn install
yarn shadow-cljs compile component-test && \
+8 -8
View File
@@ -6,7 +6,7 @@
[Get it on Github](https://github.com/status-im/status-mobile/releases)
Join us in creating a browser, messenger, and gateway to a decentralized world. Status is a free (libre) open source mobile client targeting Android & iOS built entirely on [Ethereum](https://ethereum.org/) technologies. That's right, no middle men and `go-ethereum` running directly on your device.
Join us in creating a browser, messenger, and gateway to a decentralized world. Status is a free (libre) open source mobile client targeting Android & iOS built entirely on [Ethereum](https://ethereum.org/) technologies. That's right, no middlemen and `go-ethereum` running directly on your device.
[![Getting started with Status](https://i.imgur.com/C0aZZEL.jpg)](https://www.youtube.com/watch?v=oDCSEmS9c3o "Getting started with Status")
@@ -14,9 +14,9 @@ Join us in creating a browser, messenger, and gateway to a decentralized world.
We believe in a medium of pure free trade, economies with fair, permission-less access and a world without intermediaries. We want to create policies that can exist between friends or scale globally, we want to communicate securely and be uninhibited by legacy systems.
We want to take responsibility for our data, the way we conduct ourselves privately and promote this way of life to a mass audience.
We want to take responsibility for our data, and the way we conduct ourselves privately and promote this way of life to a mass audience.
We want deep insights into our own economies so we can make informed, data-driven decisions on how to make our lives better. The Ethereum blockchain, Smart Contracts, Swarm and Whisper provide us a path forward.
We want deep insights into our own economies so we can make informed, data-driven decisions on how to make our lives better. The Ethereum blockchain, Smart Contracts, Swarm and Whisper provide us with a path forward.
If this interests you, **help us make Status a reality** - anyone can contribute and we need everyone at any skill level to participate.
@@ -37,26 +37,26 @@ 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 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.im/about)
- **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.
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.
- **Blog Writing**
Content is King, keeping our blog up to date and informing the community of news helps keep everyone on the same page.
- **Testers**
It's bug hunting season! Status is currently under active development and there is sure to be a bunch of learning, [build status from scratch](doc/starting-guide.md) or if an android user check out our [nightly builds](https://status.im/nightly). You can shake your phone to submit bug reports, or start browsing our [Github Issues](https://github.com/status-im/status-mobile/issues). Every bug you find brings Status closer to stable, usable software for everyone to enjoy!
It's bug-hunting season! Status is currently under active development and there is sure to be a bunch of learning, [build status from scratch](doc/starting-guide.md) or if an android user checks out our [nightly builds](https://status.im/nightly). You can shake your phone to submit bug reports, or start browsing our [Github Issues](https://github.com/status-im/status-mobile/issues). Every bug you find brings Status closer to stable, usable software for everyone to enjoy!
- **Security**
Status is a visual interface to make permanent changes on the Blockchain, it handles crypto-tokens that have real value and allows 3rd party code execution. Security is paramount to its success. You are given permission to break Status as hard as you can, as long as you share your findings with the community!
- **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)
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.im), through our [nightly builds](https://status.im/nightly/), or by [building it yourself](https://status.im/technical/build_status/).
## Core Contributors
+35
View File
@@ -99,3 +99,38 @@ Also to inspect logs in a more flexible manner, instead of the strict output fro
adb logcat | grep 'ReactNativeJS\|StatusModule\|GoLog'
```
### From @clauxx (visual debugging):
When building/fixing/refactoring components, it can be annoying to set-up the component for instant visual feedback (i.e. finding it in the UI when fixing/refactoring; finding a place for it when building from scratch). Very often if the location of the screen containing your component nested deeply in the app, you might have to do a lot of repeated navigation, nevermind logging in every time the app reloads (even with fast refresh disabled this happens quite often).
To alleviate this discomfort and make the development cycle more *pleasant*, you can use one of the following options (*_both of which involve the ... REPL ༼ つ ╹ ╹ ༽つ, so make sure you have that set-up with your IDE/editor_*)
#### REPL-ing to a screen
This one is straightforward, just evaluate a navigation dispatch form from anywhere:
```cljs
(comment (rf/dispatch [:navigate-to :your-favorite-buggy-screen]))
```
> TIP: you can run this from an untracked user namespace `(ns user)`, from which you can experiment or interact with the REPL. This is where I usually keep my development navigation forms.
#### REPL-ing a component
This is also straighforward, but there are some small differences. Just like above, we only have to evaluate a dispatch form, as follows:
```cljs
;; example debugging a quo component, although it could be any other component e.g. from the `status-im2` ns.
(comment (re-frame/dispatch [:dev/preview-component
[quo/slide-button
{:track-icon :face-id
:track-text "preview component example"
:customization-color :blue
:on-complete identity}]]))
```
When evaluated, a full-screen bottom sheet will appear with your component inside. You can make changes to the props or the component internals and re-evaluate the changed forms, after which the component will be re-mounted without running a reload (unless you save the file). Other times it's quicker to just hit save and the component will be reloaded as usual (except for the props you evaluated, which have to be re-evaluated when changed).
> TIP: You can have multiple versions of the component as separate comments to check for the component variations
> TIP: You can leave `comment` blocks at the end of component files (other than quo, since can be previewed in other ways) with usages of components, which other developers can use for visualisation/testing.
@@ -18,7 +18,7 @@ While neat in theory, it has some serious downsides:
As a result of that, more dynamic/state requiring things (like the live tx detail in `/send` command messages) were very hard to do,
so instead of "eating our own dogfood", we decided to side-step the API and implement such things as hard-coded logic in the app, while partly
retaining the js code for "easier" things (like parameter declaration).
Needles to say, such efforts produced code of very poor quality, riddling our app with hard-coded "magic" everywhere in the codebase, completly
Needles to say, such efforts produced code of very poor quality, riddling our app with hard-coded "magic" everywhere in the codebase, completely
defeating the point of "dogfooding" while still requiring more effort and being much more error prone (no way to unit test jail logic) because
of the need to asynchronously communicate with jail for leftover logic in command messages (the parts not hardcoded in app).
+1 -1
View File
@@ -13,7 +13,7 @@ accepted
There was a generally dissatisfaction with our PR flow process from multiple stakeholders, including devs, QA and design. These largely centered around size, speed of integration and quality of PRs.
For more details, please see pain points in the meeting notes held end of February here: https://notes.status.im/C5pj8g7gQOu9Wo8PtDZsMw?edit# as well as the preceeding Discuss thread: https://discuss.status.im/t/better-pull-requests-process/1044
For more details, please see pain points in the meeting notes held end of February here: https://notes.status.im/C5pj8g7gQOu9Wo8PtDZsMw?edit# as well as the preceding Discuss thread: https://discuss.status.im/t/better-pull-requests-process/1044
Also see conversations in Core Dev Call #12 and #13: https://github.com/status-im/pm/
+3 -3
View File
@@ -18,7 +18,7 @@ The whitepaper also proposes that the deposit is only forfeited to the recipient
Considering:
- the absence of efficient ways to perform anonymous transactions (zk-snarks could be used in the future for that)
- the impossibility to prove that a recipient has made an actual reply and not some kind of automated reply (captcha solution was proposed, but wouldn't be pratical until we can use a solution such as swarm feeds that allow users to make free updates to their captcha without on-chain transactions)
- the impossibility to prove that a recipient has made an actual reply and not some kind of automated reply (captcha solution was proposed, but wouldn't be practical until we can use a solution such as swarm feeds that allow users to make free updates to their captcha without on-chain transactions)
- the limited time to develop the feature
We opted for a solution that:
@@ -28,8 +28,8 @@ We opted for a solution that:
## Manifests
Since TtT related informations aren't stored on chain, they need to be stored somewhere else.
For the first iteration of TtT we opted for IPFS, which is already used accross the app for other forms of content, through Infura IPFS gateway.
Since TtT related information aren't stored on chain, they need to be stored somewhere else.
For the first iteration of TtT we opted for IPFS, which is already used across the app for other forms of content, through Infura IPFS gateway.
On IPFS we store what we call a ttt manifest, which is a json file with the following format:
+1 -1
View File
@@ -64,7 +64,7 @@ tests (otherwise some PRs could wait their turn of the scheduled Jenkins job til
## Analysing test results (and why test fails to pass)
After automated test run finished test results could be found in GH comment (if the test suite ran agaist PR) and TestRail. There are two states of the test: Passed and Failed. Test failure happens when certain condition of test step has not met or automated test can not proceed execution because it can not find the respective element on screen it expects should be there.
After automated test run finished test results could be found in GH comment (if the test suite ran against PR) and TestRail. There are two states of the test: Passed and Failed. Test failure happens when certain condition of test step has not met or automated test can not proceed execution because it can not find the respective element on screen it expects should be there.
Several examples of when test fails to succeed:
+47 -22
View File
@@ -17,9 +17,10 @@ You can use any Clojure enabled editor. Here are instructions for developing the
- [REPL!](#repl)
- [Connecting to REPL to IntelliJ](#connecting-to-repl-to-intellij)
- [Connecting REPL and IntelliJ to `status-mobile`](#connecting-repl-and-intellij-to-status-mobile)
- [Using Calva](#using-calva)
- [Start and connect the REPL](#start-and-connect-the-repl)
- [Use the REPL](#use-the-repl)
- [Visual Studio Code](#visual-studio-code)
- [Set up the REPL](#set-up-the-repl)
- [Auto-format files on save](#auto-format-files-on-save)
- [Using Emacs with CIDER](#using-emacs-with-cider)
## Using Cursive
@@ -160,24 +161,24 @@ Following the above should give you the below result:
For additional details on issues you may face when setting up REPL with Cursive [see this document](https://notes.status.im/9Gr7kqF8SzC_SmYK0eB7uQ?view#Connecting-Cursive--IntelliJ-IDEA-to-REPL-Problems)
## Using Calva
## Visual Studio Code
For VS Code users.
### Set up the REPL
0. Install Calva.
1. Install Calva extension.
2. Open the `status-mobile` folder.
3. Start [Status development](starting-guide.md#development) (Starting the
`run-clojure` and `run-metro` jobs in split view in the VS Code integrated
terminal works great).
4. Run the VS Code command: **Calva: Connect to a running REPL Server in the
project**.
- Select the project type `shadow-cljs`.
- Accept the suggested connection `host:port`.
- Select to connect to the `:mobile` build.
### Start and connect the REPL
1. Open the `status-mobile` folder.
1. Start [Status development](starting-guide.md#development) (Starting the `run-clojure` and `run-metro` jobs in split view in the VS Code integrated terminal works great.)
1. Run the VS Code command: **Calva: Connect to a running REPL Server in the project**
1. Select the project type `shadow-cljs`
1. Accept the suggested connection `host:port`
1. Select to connect to the `:mobile` build
### Use the REPL
Open any `.cljs` file in the project and evaluate forms in it. See https://calva.io/try-first/ for some starter tips and links. Confirm that your REPL is connected to the app by evaluating:
Open any `.cljs` file in the project and evaluate forms in it. See
https://calva.io/try-first/ for some starter tips and links. Confirm that your
REPL is connected to the app by evaluating:
```clojure
(js/alert "Hello from Status App!")
@@ -185,9 +186,35 @@ Open any `.cljs` file in the project and evaluate forms in it. See https://calva
🎉 Tada! You are ready to use the REPL to improve Status.im! 🎉
Please consider bookmarking [calva.io](https://calva.io/) for quick access to the Calva documentation.
Consider bookmarking [calva.io](https://calva.io/) for quick access to the Calva
documentation.
## Using Emacs/Cider
### Auto-format files on save
We format Clojure code with [zprint](https://github.com/kkinnear/zprint). We
recommend configuring VSCode to auto-format Clojure files on every save,
otherwise you'll need to constantly rely on the much slower `make lint-fix`
command.
1. Create a file `~/.zprintrc` and enable the `:search-config?` option. This is
necessary so the VSCode extension finds the project's `.zprintrc`.
```bash
echo "{:search-config? true}" > ~/.zprintrc
```
2. Install the extension
[vscode-clj-zprint](https://github.com/rflagreca/vscode-clj-zprint). By the
way, did you know this extension is written in ClojureScript?
3. Copy the recommended settings from our repository in
[.vscode/settings.example.json](/.vscode/settings.example.json) and merge it
with your workspace settings in `.vscode/settings.json`.
The extension `vscode-clj-zprint` is only available for VSCode. If you are using
VSCodium, you'll need to build the `vsix` (extension) yourself (it's easy, only
`yarn` and `vsce` are required).
## Using Emacs with CIDER
1. Install Emacs/Cider/etc. (there is a lot of variability in how to manage things in emacs, so please google for help with this)
2. Add a local ~/.shadow-cljs/config.edn file like below (corresponding to the version numbers of the packages you are using):
@@ -198,5 +225,3 @@ Please consider bookmarking [calva.io](https://calva.io/) for quick access to th
[cider/cider-nrepl "0.28.4"]
[cider/piggieback "0.5.2"]]}
```
+1 -1
View File
@@ -1,7 +1,7 @@
# Patching
## Libraries
If 3rd party library has an issue and fix is not yet released (or we can't switch to a new release), we use forks. Fix should be commited to the fork, tagged and referenced from package.json.
If 3rd party library has an issue and fix is not yet released (or we can't switch to a new release), we use forks. Fix should be committed to the fork, tagged and referenced from package.json.
Example: [`react-native-hole-view`](https://github.com/status-im/react-native-hole-view#refs/tags/v2.1.1-status)
+1 -1
View File
@@ -13,7 +13,7 @@ QA process was focused on account creation and login with keycard, and this bug
## Resolution process
- the commit was reverted locally by the developer which fixed the issue localy and confirmed the faulty commit
- the commit was reverted locally by the developer which fixed the issue locally and confirmed the faulty commit
- the bug was only reproducible on iOS which strongly hinted at a potential issue with native code
- the missing method was not the origin of the problem but was found at this point and further analysis lead to the shadowing error
+2 -2
View File
@@ -765,7 +765,7 @@ SPEC CHECKSUMS:
RNLanguages: 962e562af0d34ab1958d89bcfdb64fafc37c513e
RNPermissions: ad71dd4f767ec254f2cd57592fbee02afee75467
RNReactNativeHapticFeedback: 2566b468cc8d0e7bb2f84b23adc0f4614594d071
RNReanimated: b2dc21e263319892469d656dc58fc26fb03eadab
RNReanimated: 62e43ee6baafb9ba3d3af1857d7fd23a1d41bff0
RNShare: d82e10f6b7677f4b0048c23709bd04098d5aee6c
RNStaticSafeAreaInsets: 055ddbf5e476321720457cdaeec0ff2ba40ec1b8
RNSVG: 80584470ff1ffc7994923ea135a3e5ad825546b9
@@ -777,6 +777,6 @@ SPEC CHECKSUMS:
TouchID: ba4c656d849cceabc2e4eef722dea5e55959ecf4
Yoga: d24d6184b6b85f742536bd93bd07d69d7b9bb4c1
PODFILE CHECKSUM: 6a5f0e6776ce4ef6193032d077947117ace77a87
PODFILE CHECKSUM: 84b749023e1c988c133d7a6ec09d125536e4a4fd
COCOAPODS: 1.12.0
Binary file not shown.

After

Width:  |  Height:  |  Size: 615 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 930 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 615 B

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 930 B

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 967 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

+15
View File
@@ -0,0 +1,15 @@
#!/usr/bin/env bash
if pgrep -f 'shadow-cljs watch mobile' > /dev/null; then
echo "Error: make run-clojure is already running in another terminal" >&2
echo "Please close that terminal before running this command." >&2
exit 1
fi
if pgrep -f 'react-native start' > /dev/null; then
echo "Error: make run-metro is already running in another terminal" >&2
echo "Please close that terminal before running this command." >&2
exit 1
fi
exit 0
+25
View File
@@ -0,0 +1,25 @@
(ns dev.component-preview.events
(:require
[quo.core :as quo]
[re-frame.core :as re-frame]))
(def preview-screen-name :dev-component-preview)
(when js/goog.DEBUG
(re-frame/reg-event-fx :dev/preview-component
(fn [{:keys [db]} [[component-tag props & args]]]
(let [view-id (:view-id db)
;; NOTE: re-render on every evaluation e.g. reset component state without changes
component (into [component-tag (assoc props :key (random-uuid))] args)
navigate? (not= view-id preview-screen-name)]
(cond-> {:db (assoc db :dev/previewed-component component)}
navigate? (assoc :fx [[:dispatch [:navigate-to preview-screen-name]]]))))))
;; Usage example
(comment
(re-frame/dispatch [:dev/preview-component
[quo/slide-button
{:track-icon :face-id
:track-text ":debug-component example"
:customization-color :blue
:on-complete identity}]]))
+16
View File
@@ -0,0 +1,16 @@
(ns dev.component-preview.view
(:require
[react-native.core :as rn]
[utils.re-frame :as rf]))
(def ^:private container-style
{:flex 1
:padding-horizontal 20
:padding-top 80
:align-items :center})
(defn view
[]
(let [component (rf/sub [:dev/previewed-component])]
[rn/view {:style container-style}
(when component component)]))
@@ -0,0 +1,3 @@
(ns quo.components.colors.color.constants)
(def ^:const IPHONE_11_PRO_VIEWPORT_WIDTH 375)
+29 -15
View File
@@ -1,24 +1,38 @@
(ns quo.components.colors.color.style
(:require
[quo.components.colors.color.constants :as constants]
[quo.foundations.colors :as colors]))
(def color-button-common
{:width 48
:height 48
:border-width 4
:border-radius 24
:margin-horizontal 4
:transform [{:rotate "45deg"}]
:border-color :transparent})
(defn color-button-common
[window-width]
{:width 48
:height 48
:border-width 4
:border-radius 24
:margin-right (-> window-width
(- constants/IPHONE_11_PRO_VIEWPORT_WIDTH) ;We want the design to be 100%
;identical to Figma on iPhone 11
;Pro, So we're using it's VW here.
(/ 6) ;Dividing by an appropriate factor to get a reasonable value for each VW
;on other devices (This will yield 0 on iPhone 11 Pro, Which is what we
;want)
(+ 8)) ;Add same margin that's on Figma for 11 Pro, This value will increase
;based on the device VW because of the division above.
:transform [{:rotate "45deg"}]
:border-color :transparent})
(defn color-button
[color selected?]
(merge color-button-common
(when selected?
{:border-top-color (colors/alpha color 0.4)
:border-end-color (colors/alpha color 0.4)
:border-bottom-color (colors/alpha color 0.2)
:border-start-color (colors/alpha color 0.2)})))
([color selected?]
(color-button color selected? nil nil))
([color selected? idx window-width]
(merge (color-button-common window-width)
(when selected?
{:border-top-color (colors/alpha color 0.4)
:border-end-color (colors/alpha color 0.4)
:border-bottom-color (colors/alpha color 0.2)
:border-start-color (colors/alpha color 0.2)}
(when (zero? idx)
{:margin-left -4})))))
(defn color-circle
[color border?]
+4 -2
View File
@@ -19,7 +19,9 @@
selected?
on-press
blur?
theme]
theme
idx
window-width]
:as props}]
(let [border? (and (not blur?) (not selected?))
hex-color (if (= :feng-shui color)
@@ -29,7 +31,7 @@
theme))]
[rn/pressable
{:style (style/color-button hex-color selected?)
{:style (style/color-button hex-color selected? idx window-width)
:accessibility-label :color-picker-item
:on-press #(on-press color)}
(if (and (= :feng-shui color) (not selected?))
@@ -17,20 +17,22 @@
- `default-selected` Default selected color name.
- `on-change` Callback called when a color is selected `(fn [color-name])`.
- `blur?` Boolean to enable blur background support.}"
[{:keys [default-selected]}]
[{:keys [default-selected window-width]}]
(let [selected (reagent/atom default-selected)]
(fn [{:keys [blur? on-change feng-shui? container-style]}]
[rn/scroll-view
{:horizontal true
:shows-horizontal-scroll-indicator false
:content-container-style container-style}
(doall (map (fn [color]
[color/view
{:selected? (= color @selected)
:on-press #(on-change-handler selected % on-change)
:blur? blur?
:key color
:color color}])
;; TODO: using :feng-shui? temporarily while b & w is being developed.
;; https://github.com/status-im/status-mobile/discussions/16676
(if feng-shui? (conj color-list :feng-shui) color-list)))])))
(doall (map-indexed (fn [idx color]
[color/view
{:selected? (= color @selected)
:on-press #(on-change-handler selected % on-change)
:blur? blur?
:key color
:color color
:idx idx
:window-width window-width}])
;; TODO: using :feng-shui? temporarily while b & w is being developed.
;; https://github.com/status-im/status-mobile/discussions/16676
(if feng-shui? (conj color-list :feng-shui) color-list)))])))
@@ -57,7 +57,7 @@
{:title "Title"
:type :account
:account-avatar-emoji "🍿"
:networks [{:name :ethereum :short :eth}]
:networks [{:name :ethereum :short-name "eth"}]
:description "0x62b...0a5"
:customization-color :purple}])
(h/is-truthy (h/get-by-text "Title"))
+11 -17
View File
@@ -8,6 +8,7 @@
[quo.components.icon :as icons]
[quo.components.markdown.text :as text]
[quo.components.tags.context-tag.view :as context-tag]
[quo.components.wallet.address-text.view :as address-text]
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]
@@ -32,14 +33,6 @@
:profile-picture profile-picture}]
nil))
(defn- network-view
[network]
[text/text
{:size :paragraph-2
:weight :regular
:style (style/network-text-color (:name network))}
(str (name (:short network)) ":")])
(defn- keypair-subtitle
[{:keys [theme blur? keycard?]}]
[rn/view {:style style/row}
@@ -59,15 +52,16 @@
(defn- account-subtitle
[{:keys [networks theme blur? description]}]
[rn/view {:style style/row}
(for [network networks]
^{:key (str network)}
[network-view network])
[text/text
{:size :paragraph-2
:weight :regular
:style (style/description theme blur?)}
description]])
(if networks
[address-text/view
{:networks networks
:address description
:format :short}]
[text/text
{:size :paragraph-2
:weight :regular
:style (style/description theme blur?)}
description]))
(defn- default-keypair-subtitle
[{:keys [description theme blur?]}]
+1 -1
View File
@@ -150,7 +150,7 @@
:auto-complete :password
:secure-text-entry (not @password-shown?)
:right-icon {:style-fn style/password-icon
:icon-name (if @password-shown? :i/hide :i/reveal)
:icon-name (if @password-shown? :i/hide-password :i/reveal)
:on-press #(swap! password-shown? not)})])))
(defn input-internal
@@ -4,19 +4,12 @@
[quo.components.icon :as icon]
[quo.components.list-items.account.style :as style]
[quo.components.markdown.text :as text]
[quo.components.wallet.address-text.view :as address-text]
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[reagent.core :as reagent]))
(defn- network-view
[network]
[text/text
{:size :paragraph-2
:weight :regular
:style {:color (colors/custom-color (:name network))}}
(str (name (:short network)) ":")])
(defn- account-view
[{:keys [account-props title-icon? blur? theme]
:or {title-icon? false}}]
@@ -38,15 +31,10 @@
:color (if blur?
colors/white-opa-40
(colors/theme-colors colors/neutral-50 colors/neutral-40 theme))}]])]
[text/text {:size :paragraph-2}
(for [network (:networks account-props)]
^{:key (str network)}
[network-view network])
[text/text
{:size :paragraph-2
:weight :monospace
:style (style/account-address blur? theme)}
(:address account-props)]]]])
[address-text/view
{:networks (:networks account-props)
:address (:address account-props)
:format :short}]]])
(defn- balance-view
[{:keys [balance-props type theme]}]
@@ -4,6 +4,7 @@
[quo.components.icon :as icon]
[quo.components.list-items.account-list-card.style :as style]
[quo.components.markdown.text :as text]
[quo.components.wallet.address-text.view :as address-text]
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]
@@ -26,20 +27,10 @@
{:weight :semi-bold
:size :paragraph-2}
(:name account-props)]
[text/text {:size :paragraph-2}
(map (fn [network]
^{:key (str network)}
[text/text
{:size :paragraph-2
:style {:color (colors/resolve-color network theme)}}
(str (subs (name network) 0 3) ":")])
networks)
[text/text
{:size :paragraph-2
:style {:color (if blur?
colors/white-opa-40
(colors/theme-colors colors/neutral-50 colors/neutral-40 theme))}}
(:address account-props)]]]]
[address-text/view
{:networks networks
:address (:address account-props)
:format :short}]]]
(when (= action :icon)
[rn/pressable {:on-press on-options-press}
[icon/icon :i/options
@@ -0,0 +1,47 @@
(ns quo.components.list-items.token-network.component-spec
(:require [quo.components.list-items.token-network.view :as token-network]
[quo.foundations.colors :as colors]
[quo.foundations.resources :as resources]
[test-helpers.component :as h]))
(def props
{:token (resources/get-token :snt)
:state :default
:label "Status"
:networks [(resources/get-network :ethereum)]
:token-value "100.00 SNT"
:fiat-value "€0.00"})
(h/describe "List items: Token network"
(h/test "default state"
(h/render [token-network/view (dissoc props :state)])
(h/is-truthy (h/get-by-text "Status")))
(h/test "default state explicit"
(h/render [token-network/view props])
(h/is-truthy (h/get-by-text "Status")))
(h/test "Pressed state"
(h/render [token-network/view props])
(h/fire-event :on-press-in (h/get-by-label-text :token-network))
(h/wait-for #(h/has-style (h/query-by-label-text :token-network)
{:backgroundColor (colors/resolve-color :blue :light 5)})))
(h/test "Active state"
(h/render [token-network/view (assoc props :state :active)])
(h/has-style (h/query-by-label-text :token-network)
{:backgroundColor (colors/resolve-color :blue :light 10)}))
(h/test "Selected state"
(h/render [token-network/view (assoc props :state :selected)])
(h/is-truthy (h/query-by-label-text :check-icon)))
(h/test "Call on-press"
(let [on-press (h/mock-fn)]
(h/render [token-network/view (assoc props :on-press on-press)])
(h/fire-event :on-press (h/get-by-label-text :token-network))
(h/was-called on-press)))
(h/test "Empty props"
(h/render [token-network/view {}])
(h/is-truthy (h/get-by-label-text :token-network))))
@@ -0,0 +1,47 @@
(ns quo.components.list-items.token-network.style
(:require [quo.foundations.colors :as colors]))
(defn- background-color
[state customization-color theme]
(cond
(= state :pressed) (colors/resolve-color customization-color theme 5)
(= state :active) (colors/resolve-color customization-color theme 10)
(= state :selected) (colors/resolve-color customization-color theme 5)
:else :transparent))
(defn container
[state customization-color theme]
{:flex-direction :row
:justify-content :space-between
:align-items :center
:padding-horizontal 12
:padding-vertical 8
:border-radius 12
:height 56
:background-color (background-color state customization-color theme)})
(defn check-color
[customization-color theme]
(colors/resolve-color customization-color theme))
(def info
{:flex-direction :row
:align-items :center})
(def token-info
{:height 40})
(def token-image
{:width 32
:height 32
:border-width 1
:border-radius 16
:border-color colors/neutral-80-opa-5
:margin-right 8})
(def values-container
{:align-items :flex-end})
(defn fiat-value
[theme]
{:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)})
@@ -0,0 +1,62 @@
(ns quo.components.list-items.token-network.view
(:require
[quo.components.icon :as icon]
[quo.components.list-items.preview-list.view :as preview-list]
[quo.components.list-items.token-network.style :as style]
[quo.components.markdown.text :as text]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[reagent.core :as reagent]))
(defn- info
[{:keys [token label networks]}]
[rn/view {:style style/info}
[rn/image
{:source (or (:source token) token)
:style style/token-image}]
[rn/view {:style style/token-info}
[text/text {:weight :semi-bold} label]
[preview-list/view
{:type :network
:size :size-14
:number 3}
networks]]])
(defn- values
[{:keys [state token-value fiat-value customization-color theme]}]
(if (= state :selected)
[icon/icon :i/check
{:color (style/check-color customization-color theme)
:accessibility-label :check-icon}]
[rn/view {:style style/values-container}
[text/text
{:weight :medium
:size :paragraph-2}
token-value]
[text/text
{:style (style/fiat-value theme)
:size :paragraph-2}
fiat-value]]))
(defn- view-internal
[]
(let [pressed? (reagent/atom false)
on-press-in #(reset! pressed? true)
on-press-out #(reset! pressed? false)]
(fn [{:keys [on-press state customization-color
_token _networks _token-value _fiat-value theme]
:as props
:or {customization-color :blue}}]
(let [internal-state (if @pressed?
:pressed
state)]
[rn/pressable
{:style (style/container internal-state customization-color theme)
:on-press-in on-press-in
:on-press-out on-press-out
:on-press on-press
:accessibility-label :token-network}
[info props]
[values props]]))))
(def view (quo.theme/with-theme view-internal))
@@ -14,7 +14,7 @@
(defn- internal-view
[]
(let [state (reagent/atom :default)]
(fn [{:keys [theme customization-color status token metrics? values on-press]}]
(fn [{:keys [theme customization-color status token metrics? values on-press on-long-press]}]
(let [bg-opacity (case @state
:active 10
:pressed 5
@@ -28,6 +28,7 @@
(reset! state :active)
(js/setTimeout #(reset! state :default) 300)
on-press)
:on-long-press on-long-press
:accessibility-label :container}
[rn/view
{:style {:flex-direction :row
@@ -0,0 +1,31 @@
(ns quo.components.messages.message.style
(:require [quo.foundations.colors :as colors]))
(defn container
[theme header? reacted? state pinned-by customization-color]
{:padding-horizontal 12
:padding-vertical (if header? 8 4)
:padding-bottom (when reacted? (if header? 12 8))
:border-radius 16
:background-color (cond
pinned-by (colors/resolve-color customization-color theme 5)
(= state :default) (colors/theme-colors colors/white colors/neutral-5 theme)
:else (colors/theme-colors colors/neutral-5
colors/neutral-90
theme))
}
)
(def avatar-container
{:padding-vertical 4
:margin-right 8
})
(def pin-indicator-container
{:flex-direction :row
:align-items :center
:padding-left 40
:margin-bottom 2
})
(def message-content {})
@@ -0,0 +1,103 @@
(ns quo.components.messages.message.view
(:require [quo.components.avatars.user-avatar.view :as user-avatar]
[quo.components.icon :as icon]
[quo.components.info.info-message :as info-message]
[quo.components.markdown.text :as text]
[quo.components.messages.author.view :as author]
[quo.components.messages.message.style :as style]
[quo.components.selectors.react.view :as react]
[quo.foundations.colors :as colors]
[quo.theme :as theme]
[react-native.core :as rn]
[reagent.core :as reagent]
[utils.i18n :as i18n]))
(defn- pin-indicator
[{:keys [theme pinned-by customization-color]}]
[rn/view {:style style/pin-indicator-container}
[icon/icon :i/pin
{:color (colors/resolve-color customization-color theme)
:size 16}]
[text/text
{:size :label
:weight :medium
:style {:margin-left 2 :color (colors/resolve-color customization-color theme)}}
pinned-by]]
)
(defn- internal-view
[]
(let [state (reagent/atom :default)]
(fn [{:keys [theme header? reacted? delivered? avatar-props author-props on-press context
customization-color]}]
(println context)
(let [{:keys [content-type pinned-by reactions]} context]
[rn/pressable
{:style (style/container theme header? reacted? @state (seq pinned-by) customization-color)
:on-press-in #(reset! state :pressed)
:on-press-out #(reset! state :default)
:on-press on-press
}
(when (seq pinned-by)
[pin-indicator
{:theme theme
:header? header?
:pinned-by pinned-by
:customization-color customization-color}])
[rn/view {:style {:flex-direction :row :margin-left (when-not header? 40)}}
(when header?
[rn/view {:style style/avatar-container}
[user-avatar/user-avatar
(merge avatar-props {:size :small})]
])
[rn/view
(when header? [author/view (merge author-props {:size 13})])
[rn/view {:style style/message-content}
(condp = content-type
:text
[text/text "This is a simple message"]
:image
[text/text "image"]
:text-and-image
[text/text "image with text"]
:audio
[text/text "audio"]
:gif
[text/text "gif"]
:sticker
[text/text "sticker"]
:text-and-code
[text/text "code with text"]
:code
[text/text "code"]
:text-and-link-preview
[text/text "link preview with text"]
:text-and-internal-link
[text/text "internal link with text"]
:internal-link
[text/text "internal link"]
:text-and-forward-message
[text/text "forward message with text"]
:forward-message
[text/text "forward message"]
[text/text "not implemented"])]
(when (seq reactions)
[react/view
{:reactions reactions
:use-case :pinned
:add-reaction? true
:container-style {:margin-top 8}}])
(when delivered?
[info-message/info-message
{:type :default
:size :tiny
:icon :i/sent
:style {:margin-top 2}
} (i18n/label :t/sent)])
]]
])
))
)
(def view (theme/with-theme internal-view))
@@ -7,7 +7,7 @@
(def empty-username "Account 1")
(defn get-test-data
[type watch-only? empty-type? loading? metrics?]
[{:keys [type watch-only? empty-type? loading? no-metrics?]}]
{:name (if empty-type? empty-username username)
:balance "€1,000.00"
:percentage-value "50%"
@@ -15,17 +15,18 @@
:customization-color :blue
:watch-only? watch-only?
:loading? loading?
:metrics? metrics?
:metrics? (not no-metrics?)
:type type})
(h/describe "Account_card tests"
(h/test "Renders Default"
(let [data (get-test-data :default false false false true)]
(let [data (get-test-data {:type :default})]
(h/render [account-card/view data])
(h/is-truthy (h/get-by-text username))))
(h/test "Renders Watch-Only"
(let [data (get-test-data :watch-only true false false true)]
(let [data (get-test-data {:type :watch-only
:watch-only? true})]
(h/render [account-card/view data])
(h/is-truthy (h/get-by-text username))))
@@ -35,10 +36,16 @@
(h/is-truthy (h/get-by-label-text :add-account))))
(h/test "Renders Empty"
(let [data (get-test-data :empty false true false true)]
(let [data (get-test-data {:type :empty
:empty-type? true})]
(h/render [account-card/view data])
(h/is-truthy (h/get-by-text empty-username))))
(h/test "Renders Missing Keypair"
(let [data (get-test-data {:type :missing-keypair})]
(h/render [account-card/view data])
(h/is-truthy (h/get-by-text username))))
(h/test "Add account on press fires correctly"
(let [on-press (h/mock-fn)
data {:type :add-account
@@ -48,16 +55,20 @@
(h/was-called on-press)))
(h/test "Renders component without metrics"
(let [data (get-test-data :default false false false false)]
(let [data (get-test-data {:type :default
:no-metrics? true})]
(h/render [account-card/view data])
(h/is-falsy (h/query-by-label-text :metrics))))
(h/test "Renders loading state"
(let [data (get-test-data :default false false true true)]
(let [data (get-test-data {:type :default
:loading? true})]
(h/render [account-card/view data])
(h/is-truthy (h/get-by-label-text :loading))))
(h/test "Renders loading state without metrics"
(let [data (get-test-data :default false false true false)]
(let [data (get-test-data {:type :default
:no-metrics? true
:loading? true})]
(h/render [account-card/view data])
(h/is-falsy (h/query-by-label-text :metrics)))))
@@ -0,0 +1,20 @@
(ns quo.components.wallet.account-card.properties
(:require [quo.foundations.colors :as colors]))
(defn gradient-start-color
[theme customization-color]
(colors/theme-colors
(colors/resolve-color customization-color theme 0)
colors/neutral-95
theme))
(defn gradient-end-color
[theme customization-color]
(colors/theme-colors
(colors/resolve-color customization-color theme 6)
colors/neutral-95
theme))
(defn alert-icon-color
[theme]
(colors/theme-colors colors/neutral-50 colors/white theme))
@@ -3,24 +3,29 @@
[quo.foundations.colors :as colors]))
(defn text-color
[watch-only? theme]
(if (and watch-only? (= :light theme))
[type theme]
(if (and (or (= :missing-keypair type)
(= :watch-only type))
(= :light theme))
colors/neutral-100
colors/white))
(defn card
[{:keys [customization-color watch-only? metrics? theme pressed?]}]
[{:keys [customization-color type theme pressed?]}]
{:width 162
:height (if metrics? 88 68)
:background-color (if watch-only?
(colors/theme-colors colors/neutral-80-opa-5 colors/neutral-95 theme)
:background-color (when (not= :watch-only type)
(colors/theme-colors
(colors/custom-color customization-color 50)
(colors/custom-color customization-color 60)
(colors/resolve-color customization-color
theme
(when (= :missing-keypair type) (if pressed? 20 10)))
(colors/resolve-color customization-color
theme
(when (= :missing-keypair type) (if pressed? 30 20)))
theme))
:border-radius 16
:border-width 1
:border-color (if watch-only?
:border-color (if (or (= :missing-keypair type)
(= :watch-only type))
(colors/theme-colors
(if pressed? colors/neutral-80-opa-10 colors/neutral-80-opa-5)
(if pressed? colors/white-opa-10 colors/white-opa-5)
@@ -28,10 +33,10 @@
colors/neutral-80-opa-10)
:padding-horizontal 12
:padding-top 6
:padding-bottom 10})
:padding-bottom 9})
(def profile-container
{:margin-bottom 6
{:margin-bottom 8
:flex-direction :row})
(def metrics-container
@@ -39,8 +44,8 @@
:align-items :center})
(defn account-name
[watch-only? theme]
{:color (text-color watch-only? theme)
[type theme]
{:color (text-color type theme)
:margin-left 2})
(def watch-only-container
@@ -50,21 +55,25 @@
:flex 1})
(defn account-value
[watch-only? theme]
{:color (text-color watch-only? theme)})
[type theme]
{:color (text-color type theme)})
(defn metrics
[watch-only? theme]
{:color (if (and watch-only? (= :light theme))
[type theme]
{:color (if (and (or (= :missing-keypair type)
(= :watch-only type))
(= :light theme))
colors/neutral-80-opa-60
colors/white-opa-70)})
(defn separator
[watch-only? theme]
[type theme]
{:width 2
:height 2
:border-radius 20
:background-color (if (and watch-only? (= :light theme))
:background-color (if (and (or (= :missing-keypair type)
(= :watch-only type))
(= :light theme))
colors/neutral-80-opa-20
colors/white-opa-40)
:margin-horizontal 4})
@@ -102,3 +111,12 @@
(def metrics-icon-container
{:margin-left 4})
(def gradient-view
{:position :absolute
:bottom 0
:top 0
:left 0
:right 0
:border-radius 16
:z-index -1})
@@ -3,11 +3,13 @@
[quo.components.buttons.button.view :as button]
[quo.components.icon :as icon]
[quo.components.markdown.text :as text]
[quo.components.wallet.account-card.properties :as properties]
[quo.components.wallet.account-card.style :as style]
[quo.foundations.colors :as colors]
[quo.foundations.customization-colors :as customization-colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[react-native.linear-gradient :as linear-gradient]
[reagent.core :as reagent]))
(defn- loading-view
@@ -17,8 +19,7 @@
[rn/view
{:accessibility-label :loading
:style (style/card {:customization-color customization-color
:watch-only? watch-only?
:metrics? metrics?
:type type
:theme theme
:pressed? false})}
[rn/view {:style style/loader-container}
@@ -54,31 +55,43 @@
10)}])]))
(defn- metrics-percentage
[watch-only? theme account-percentage]
[type theme account-percentage]
[text/text
{:weight :semi-bold
{:weight :medium
:size :paragraph-2
:accessibility-label :metrics
:style (style/metrics watch-only? theme)}
:style (style/metrics type theme)}
account-percentage])
(defn- metrics-info
[watch-only? theme account-amount]
[type theme account-amount]
[:<>
[rn/view (style/separator watch-only? theme)]
[rn/view (style/separator type theme)]
[text/text
{:weight :semi-bold
{:weight :medium
:size :paragraph-2
:style (style/metrics watch-only? theme)}
:style (style/metrics type theme)}
account-amount]
[rn/view {:style style/metrics-icon-container}
[icon/icon
:i/positive
{:color (colors/theme-colors (if watch-only? colors/neutral-50 colors/white-opa-70)
{:color (colors/theme-colors (if (or (= :missing-keypair type)
(= :watch-only type))
colors/neutral-50
colors/white-opa-70)
colors/white-opa-70
theme)
:size 16}]]])
(defn- gradient-overview
[theme customization-color]
[linear-gradient/linear-gradient
{:colors [(properties/gradient-start-color theme customization-color)
(properties/gradient-end-color theme customization-color)]
:style style/gradient-view
:start {:x 0 :y 0}
:end {:x 1 :y 0}}])
(defn- user-account
[]
(let [pressed? (reagent/atom false)
@@ -86,7 +99,8 @@
on-press-out #(reset! pressed? false)]
(fn [{:keys [name balance percentage-value loading? amount customization-color type emoji metrics?
theme on-press]}]
(let [watch-only? (= :watch-only type)]
(let [watch-only? (= :watch-only type)
missing-keypair? (= :missing-keypair type)]
(if loading?
[loading-view
{:customization-color customization-color
@@ -97,12 +111,11 @@
{:on-press-in on-press-in
:on-press-out on-press-out
:style (style/card {:customization-color customization-color
:watch-only? watch-only?
:metrics? metrics?
:type type
:theme theme
:pressed? @pressed?})
:on-press on-press}
(when (and customization-color (not watch-only?))
(when (and customization-color (and (not watch-only?) (not missing-keypair?)))
[customization-colors/overlay
{:customization-color customization-color
:border-radius 16
@@ -115,19 +128,23 @@
[text/text
{:size :paragraph-2
:weight :medium
:style (style/account-name watch-only? theme)}
:style (style/account-name type theme)}
name]
(when watch-only? [icon/icon :i/reveal {:color colors/neutral-50 :size 12}])]]
(when watch-only? [icon/icon :i/reveal {:color colors/neutral-50 :size 12}])
(when missing-keypair?
[icon/icon :i/alert {:color (properties/alert-icon-color theme) :size 12}])]]
[text/text
{:size :heading-2
:weight :semi-bold
:style (style/account-value watch-only? theme)}
:style (style/account-value type theme)}
balance]
(when metrics?
[rn/view {:style style/metrics-container}
[metrics-percentage watch-only? theme percentage-value]
[metrics-percentage type theme percentage-value]
(when (not= :empty type)
[metrics-info watch-only? theme amount])])])))))
[metrics-info type theme amount])])
(when watch-only?
[gradient-overview theme customization-color])])))))
(defn- add-account-view
[]
@@ -156,10 +173,8 @@
(defn- view-internal
[{:keys [type] :as props}]
(case type
:watch-only [user-account props]
:add-account [add-account-view props]
:default [user-account props]
:empty [user-account props]
(:watch-only :default :empty :missing-keypair) [user-account props]
:add-account [add-account-view props]
nil))
(def view (quo.theme/with-theme view-internal))
@@ -0,0 +1,9 @@
(ns quo.components.wallet.address-text.style
(:require [quo.foundations.colors :as colors]))
(defn address-text
[format blur? theme]
(when (= format :short)
{:color (if blur?
colors/white-opa-40
(colors/theme-colors colors/neutral-50 colors/neutral-40 theme))}))
@@ -0,0 +1,31 @@
(ns quo.components.wallet.address-text.view
(:require [quo.components.markdown.text :as text]
[quo.components.wallet.address-text.style :as style]
[quo.foundations.colors :as colors]
[quo.theme]
[utils.address :as utils]))
(defn- colored-network-text
[theme network]
(let [{:keys [name short-name]} network]
[text/text
{:size :paragraph-2
:style {:color (colors/resolve-color name theme)}}
(str short-name ":")]))
(defn- view-internal
[{:keys [networks address blur? theme format]}]
(let [network-text-xf (map #(colored-network-text theme %))
address-text [text/text
{:size :paragraph-2
;; TODO: monospace font https://github.com/status-im/status-mobile/issues/17009
:weight :monospace
:style (style/address-text format blur? theme)}
(if (= format :short)
(utils/get-short-wallet-address address)
address)]]
(as-> networks $
(into [text/text] network-text-xf $)
(conj $ address-text))))
(def view (quo.theme/with-theme view-internal))
@@ -10,7 +10,8 @@
:type :default
:name "Trip to Vegas"
:address "0x0ah...71a"}
:networks [:ethereum :optimism]
:networks [{:name :ethereum :short-name "eth"}
{:name :optimism :short-name "opt"}]
:state :default
:action :none}])
@@ -0,0 +1,115 @@
(ns quo.components.wallet.network-routing.animation
(:require [react-native.reanimated :as reanimated]))
(def ^:private slider-timing 300)
(defn show-slider
[opacity-shared-value]
(reanimated/animate opacity-shared-value 1 slider-timing))
(defn hide-slider
[opacity-shared-value]
(reanimated/animate opacity-shared-value 0 slider-timing))
(defn increase-slider
[width-shared-value height-shared-value]
(reanimated/animate width-shared-value 8 slider-timing)
(reanimated/animate height-shared-value 40 slider-timing))
(defn decrease-slider
[width-shared-value height-shared-value]
(reanimated/animate width-shared-value 4 slider-timing)
(reanimated/animate height-shared-value 32 slider-timing))
(def ^:private pressed-bar-timing 600)
(defn move-previous-bars
[{:keys [bars bars-widths-negative]}]
(doseq [[bar-idx bar] (map-indexed vector bars)
:let [new-translation-x (->> (take (inc bar-idx) bars-widths-negative)
(reduce +)
(dec))]]
(reanimated/animate (:translate-x-shared-value bar)
new-translation-x
pressed-bar-timing)))
(defn move-pressed-bar
[{:keys [bars-widths-negative number-previous-bars]
{:keys [translate-x-shared-value]} :bar}]
(let [new-translation-x (reduce + (take number-previous-bars bars-widths-negative))]
(reanimated/animate translate-x-shared-value
new-translation-x
(- pressed-bar-timing 20))))
(defn move-next-bars
[{:keys [bars bars-widths-negative number-previous-bars extra-offset add-new-timeout]}]
(doseq [[bar-idx bar] (map-indexed vector bars)
:let [number-bars-before (+ number-previous-bars
(inc bar-idx))
new-translation-x (->> (take number-bars-before bars-widths-negative)
(reduce +)
(* 1.05))]]
(reanimated/animate (:translate-x-shared-value bar) new-translation-x pressed-bar-timing)
(add-new-timeout
(keyword (str "fix-next-bars-position-" bar-idx))
(fn []
(let [translate-x-value (reanimated/get-shared-value (:translate-x-shared-value bar))
hidden-position (- translate-x-value extra-offset)]
(reanimated/set-shared-value (:translate-x-shared-value bar) hidden-position)))
pressed-bar-timing)))
(def ^:private max-limit-bar-timing 300)
(defn show-max-limit-bar
[max-limit-bar-opacity]
(reanimated/animate max-limit-bar-opacity 1 max-limit-bar-timing))
(defn hide-max-limit-bar
[max-limit-bar-opacity]
(reanimated/animate max-limit-bar-opacity 0 max-limit-bar-timing))
(defn reset-bars-positions
[bars unlock-press-fn add-new-timeout]
(let [bars-reset-timing 500]
(doseq [{:keys [translate-x-shared-value]} bars]
(reanimated/animate translate-x-shared-value 0 bars-reset-timing))
(add-new-timeout :unlock-press unlock-press-fn bars-reset-timing)))
(defn align-bars-off-screen
[{:keys [new-network-values network-bars amount->width add-new-timeout]}]
(let [width-to-off-screen (->> new-network-values
(reduce #(- %1 (:amount %2)) 0)
(amount->width))]
(doseq [[bar-idx {new-amount :amount} bar] (map vector (range) new-network-values network-bars)]
(reanimated/set-shared-value (:amount-shared-value bar) new-amount)
(reanimated/set-shared-value (:translate-x-shared-value bar) (* 2 width-to-off-screen))
(add-new-timeout
(keyword (str "align-bar-" bar-idx))
#(reanimated/set-shared-value (:translate-x-shared-value bar) width-to-off-screen)
1))))
(def ^:private hide-bar-timing 400)
(defn hide-pressed-bar
[{:keys [translate-x-shared-value amount-shared-value]} amount->width]
(let [bar-width (amount->width (reanimated/get-shared-value amount-shared-value))
new-translation-x (- (reanimated/get-shared-value translate-x-shared-value)
bar-width)]
(reanimated/animate translate-x-shared-value new-translation-x hide-bar-timing)))
(defn update-bar-values-and-reset-animations
[{:keys [new-network-values network-bars amount->width reset-values-fn add-new-timeout
lock-press-fn unlock-press-fn]}]
(lock-press-fn)
(add-new-timeout
:update-bars-values
(fn []
(align-bars-off-screen {:new-network-values new-network-values
:network-bars network-bars
:amount->width amount->width
:add-new-timeout add-new-timeout})
(reset-values-fn)
(add-new-timeout :reset-bars
#(reset-bars-positions network-bars unlock-press-fn add-new-timeout)
100))
hide-bar-timing))
@@ -0,0 +1,79 @@
(ns quo.components.wallet.network-routing.style
(:require [quo.foundations.colors :as colors]
[react-native.reanimated :as reanimated]))
(defn container
[container-style theme]
(assoc container-style
:flex-direction :row
:height 64
:background-color (colors/theme-colors colors/neutral-100-opa-5 colors/neutral-90 theme)
:border-radius 20
:overflow :hidden))
(defn max-limit-bar
[{:keys [opacity-shared-value width]}]
(reanimated/apply-animations-to-style
{:opacity opacity-shared-value}
{:position :absolute
:top 0
:bottom 0
:left 0
:width width
:z-index -1
:flex-direction :row}))
(defn max-limit-bar-background
[network-name]
{:flex 1
:background-color (colors/resolve-color network-name nil 10)})
(defn network-bar
[{:keys [max-width on-top? bar-division? theme]
{:keys [network-name translate-x-shared-value]} :bar}
width-shared-value]
(reanimated/apply-animations-to-style
{:width width-shared-value
:transform [{:translate-x translate-x-shared-value}]}
{:max-width max-width
:flex-direction :row
:justify-content :flex-end
:background-color (colors/resolve-color network-name nil)
:z-index (if on-top? 1 0)
:border-right-width (if bar-division? 0 1)
:border-color (colors/theme-colors colors/white colors/neutral-95 theme)}))
(def slider-container
{:width 40
:background-color :transparent
:justify-content :center
:align-items :center
:right -20})
(def ^:private slider-fixed-styles
{:background-color colors/white
:height 32
:width 4
:border-radius 4})
(defn slider
[{:keys [width-shared-value height-shared-value opacity-shared-value]}]
(reanimated/apply-animations-to-style
{:width width-shared-value
:height height-shared-value
:opacity opacity-shared-value}
slider-fixed-styles))
(def dashed-line
{:width 1
:height "100%"
:margin-left -1
:margin-top -1.5})
(defn dashed-line-line
[network-name]
{:background-color (colors/resolve-color network-name nil)
:height 3
:width 1})
(def dashed-line-space {:height 4 :width 1})
@@ -0,0 +1,189 @@
(ns quo.components.wallet.network-routing.view
(:require
[oops.core :as oops]
[quo.components.wallet.network-routing.animation :as animation]
[quo.components.wallet.network-routing.style :as style]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[react-native.gesture :as gesture]
[react-native.reanimated :as reanimated]
[reagent.core :as reagent]
[utils.number]))
(def ^:private timeouts (atom {}))
(defn- add-new-timeout
[k f ms]
(letfn [(exec-fn-and-remove-timeout []
(f)
(swap! timeouts dissoc k))]
(js/clearTimeout (k @timeouts))
(swap! timeouts assoc k (js/setTimeout exec-fn-and-remove-timeout ms))))
(defn- f-slider
[slider-shared-values]
[rn/view {:style style/slider-container}
[reanimated/view {:style (style/slider slider-shared-values)}]])
(defn f-network-bar
[_]
(let [detecting-gesture? (reagent/atom false)
amount-on-gesture-start (atom 0)]
(fn [{:keys [total-width total-amount on-press on-new-amount allow-press?]
{:keys [amount-shared-value
max-amount]} :bar
:as props}]
(let [slider-width-shared-value (reanimated/use-shared-value 4)
slider-height-shared-value (reanimated/use-shared-value 32)
slider-opacity-shared-value (reanimated/use-shared-value 0)
network-bar-shared-value (reanimated/interpolate amount-shared-value
[0 total-amount]
[0 total-width])
width->amount #(/ (* % total-amount) total-width)]
[rn/touchable-without-feedback
{:on-press (fn []
(when (and (not @detecting-gesture?) allow-press?)
(on-press)
(reset! detecting-gesture? true)
(animation/show-slider slider-opacity-shared-value)))}
[reanimated/view
{:style (style/network-bar props network-bar-shared-value)
:accessibility-label :network-routing-bar}
[gesture/gesture-detector
{:gesture
(-> (gesture/gesture-pan)
(gesture/enabled @detecting-gesture?)
(gesture/on-begin
(fn [_]
(animation/increase-slider slider-width-shared-value slider-height-shared-value)
(reset! amount-on-gesture-start (reanimated/get-shared-value amount-shared-value))))
(gesture/on-update
(fn [event]
(let [new-amount (-> (oops/oget event "translationX")
(width->amount)
(+ @amount-on-gesture-start)
(utils.number/value-in-range 1 max-amount))]
(reanimated/set-shared-value amount-shared-value new-amount))))
(gesture/on-finalize
(fn [_]
(animation/decrease-slider slider-width-shared-value slider-height-shared-value)
(animation/hide-slider slider-opacity-shared-value)
(on-new-amount (reanimated/get-shared-value amount-shared-value))
(add-new-timeout :turn-off-gesture #(reset! detecting-gesture? false) 20))))}
[:f> f-slider
{:width-shared-value slider-width-shared-value
:height-shared-value slider-height-shared-value
:opacity-shared-value slider-opacity-shared-value}]]]]))))
(defn- add-bar-shared-values
[{:keys [amount] :as network}]
(assoc network
:amount-shared-value (reanimated/use-shared-value amount)
:translate-x-shared-value (reanimated/use-shared-value 0)))
(def ^:private get-negative-amount
(comp - reanimated/get-shared-value :amount-shared-value))
(defn- dashed-line
[network-name]
[rn/view {:style style/dashed-line}
(take 19
(interleave (repeat [rn/view {:style (style/dashed-line-line network-name)}])
(repeat [rn/view {:style style/dashed-line-space}])))])
(defn f-network-routing-bars
[_]
(let [selected-network-idx (reagent/atom nil)
press-locked? (reagent/atom false)
lock-press #(reset! press-locked? true)
unlock-press #(reset! press-locked? false)
reset-state-values #(reset! selected-network-idx nil)]
(fn [{:keys [networks total-width total-amount requesting-data? on-amount-selected]}]
(let [bar-opacity-shared-value (reanimated/use-shared-value 0)
network-bars (map add-bar-shared-values networks)
amount->width #(* % (/ total-width total-amount))
bars-widths-negative (map #(-> % get-negative-amount amount->width)
network-bars)
last-bar-idx (dec (count network-bars))]
(rn/use-effect
#(when (and (not requesting-data?) @selected-network-idx)
(let [bar (nth network-bars @selected-network-idx)]
(animation/hide-pressed-bar bar amount->width))
(animation/update-bar-values-and-reset-animations
{:new-network-values networks
:network-bars network-bars
:amount->width amount->width
:reset-values-fn reset-state-values
:lock-press-fn lock-press
:unlock-press-fn unlock-press
:add-new-timeout add-new-timeout}))
[requesting-data?])
[:<>
(doall
(for [[bar-idx bar] (map-indexed vector network-bars)
:let [bar-max-width (amount->width (:max-amount bar))
bar-width (-> (:amount-shared-value bar)
(reanimated/get-shared-value)
(amount->width))
hide-division? (or (= last-bar-idx bar-idx) @selected-network-idx)
this-bar-selected? (= @selected-network-idx bar-idx)]]
^{:key (str "network-bar-" bar-idx)}
[:f> f-network-bar
{:bar bar
:max-width bar-max-width
:total-width total-width
:total-amount total-amount
:bar-division? hide-division?
:on-top? this-bar-selected?
:allow-press? (and (or (not @selected-network-idx) this-bar-selected?)
(not requesting-data?)
(not @press-locked?))
:on-press (fn []
(when-not @selected-network-idx
(let [[previous-bars [_ & next-bars]] (split-at bar-idx network-bars)
number-previous-bars bar-idx]
(animation/move-previous-bars
{:bars previous-bars
:bars-widths-negative bars-widths-negative})
(animation/move-pressed-bar
{:bar bar
:bars-widths-negative bars-widths-negative
:number-previous-bars number-previous-bars})
(animation/move-next-bars
{:bars next-bars
:bars-widths-negative bars-widths-negative
:number-previous-bars (inc number-previous-bars)
:extra-offset (max 0 (- bar-max-width bar-width))
:add-new-timeout add-new-timeout}))
(animation/show-max-limit-bar bar-opacity-shared-value)
(reset! selected-network-idx bar-idx)))
:on-new-amount (fn [new-amount]
(animation/hide-max-limit-bar bar-opacity-shared-value)
(when on-amount-selected
(on-amount-selected new-amount @selected-network-idx)))}]))
(let [{:keys [max-amount network-name]} (some->> @selected-network-idx
(nth network-bars))
limit-bar-width (amount->width max-amount)]
[reanimated/view
{:style (style/max-limit-bar
{:opacity-shared-value bar-opacity-shared-value
:width limit-bar-width})}
[rn/view {:style (style/max-limit-bar-background network-name)}]
[dashed-line network-name]])]))))
(defn view-internal
[{:keys [networks container-style theme] :as params}]
(reagent/with-let [total-width (reagent/atom nil)]
[rn/view
{:accessibility-label :network-routing
:style (style/container container-style theme)
:on-layout #(reset! total-width (oops/oget % "nativeEvent.layout.width"))}
(when @total-width
^{:key (str "network-routing-" (count networks))}
[:f> f-network-routing-bars (assoc params :total-width @total-width)])]
(finally
(doseq [[_ living-timeout] @timeouts]
(js/clearTimeout living-timeout)))))
(def view (quo.theme/with-theme view-internal))
+8 -1
View File
@@ -77,6 +77,7 @@
quo.components.list-items.preview-list.view
quo.components.list-items.saved-address.view
quo.components.list-items.saved-contact-address.view
quo.components.list-items.token-network.view
quo.components.list-items.token-value.view
quo.components.list-items.user-list
quo.components.loaders.skeleton-list.view
@@ -84,6 +85,7 @@
quo.components.markdown.text
quo.components.messages.author.view
quo.components.messages.gap
quo.components.messages.message.view
quo.components.messages.system-message.view
quo.components.navigation.bottom-nav-tab.view
quo.components.navigation.floating-shell-button.view
@@ -112,7 +114,6 @@
quo.components.selectors.selectors.view
quo.components.settings.accounts.view
quo.components.settings.category.view
quo.components.settings.category.view
quo.components.settings.data-item.view
quo.components.settings.privacy-option.view
quo.components.settings.reorder-item.view
@@ -137,10 +138,12 @@
quo.components.wallet.account-card.view
quo.components.wallet.account-origin.view
quo.components.wallet.account-overview.view
quo.components.wallet.address-text.view
quo.components.wallet.keypair.view
quo.components.wallet.network-amount.view
quo.components.wallet.network-bridge.view
quo.components.wallet.network-link.view
quo.components.wallet.network-routing.view
quo.components.wallet.progress-bar.view
quo.components.wallet.summary-info.view
quo.components.wallet.token-input.view
@@ -278,6 +281,7 @@
(def community-list-item quo.components.list-items.community.view/view)
(def saved-address quo.components.list-items.saved-address.view/view)
(def saved-contact-address quo.components.list-items.saved-contact-address.view/view)
(def token-network quo.components.list-items.token-network.view/view)
(def token-value quo.components.list-items.token-value.view/view)
;;;; Loaders
@@ -296,6 +300,7 @@
;;;; Messages
(def author quo.components.messages.author.view/view)
(def gap quo.components.messages.gap/gap)
(def message quo.components.messages.message.view/view)
(def system-message quo.components.messages.system-message.view/system-message)
;;;; Notifications
@@ -369,9 +374,11 @@
(def account-card quo.components.wallet.account-card.view/view)
(def account-origin quo.components.wallet.account-origin.view/view)
(def account-overview quo.components.wallet.account-overview.view/view)
(def address-text quo.components.wallet.address-text.view/view)
(def keypair quo.components.wallet.keypair.view/view)
(def network-amount quo.components.wallet.network-amount.view/view)
(def network-bridge quo.components.wallet.network-bridge.view/view)
(def network-routing quo.components.wallet.network-routing.view/view)
(def progress-bar quo.components.wallet.progress-bar.view/view)
(def summary-info quo.components.wallet.summary-info.view/view)
(def network-link quo.components.wallet.network-link.view/view)
+2 -1
View File
@@ -32,7 +32,6 @@
[quo.components.inputs.address-input.component-spec]
[quo.components.inputs.input.component-spec]
[quo.components.inputs.locked-input.component-spec]
[quo.components.inputs.locked-input.component-spec]
[quo.components.inputs.profile-input.component-spec]
[quo.components.inputs.recovery-phrase.component-spec]
[quo.components.inputs.title-input.component-spec]
@@ -46,6 +45,7 @@
[quo.components.list-items.dapp.component-spec]
[quo.components.list-items.saved-address.component-spec]
[quo.components.list-items.saved-contact-address.component-spec]
[quo.components.list-items.token-network.component-spec]
[quo.components.list-items.token-value.component-spec]
[quo.components.loaders.skeleton-list.component-spec]
[quo.components.markdown.list.component-spec]
@@ -72,6 +72,7 @@
[quo.components.switchers.group-messaging-card.component-spec]
[quo.components.tags.network-tags.component-spec]
[quo.components.tags.status-tags-component-spec]
[quo.components.tags.tiny-tag.component-spec]
[quo.components.wallet.account-card.component-spec]
[quo.components.wallet.account-origin.component-spec]
[quo.components.wallet.account-overview.component-spec]
+1 -1
View File
@@ -37,7 +37,7 @@
[k]
(get tokens k))
(def networks
(def ^:private networks
{:arbitrum (js/require "../resources/images/networks/Arbitrum.png")
:ethereum (js/require "../resources/images/networks/Ethereum.png")
:gnosis (js/require "../resources/images/networks/Gnosis.png")
@@ -0,0 +1,28 @@
(ns quo2.components.wallet.network-routing.component-spec
(:require [oops.core :as oops]
[quo2.components.wallet.network-routing.view :as network-routing]
[reagent.core :as reagent]
[test-helpers.component :as h]))
(h/describe "Network-routing tests"
(let [network {:amount 250 :max-amount 300 :network-name :unknown}
default-props {:networks [network network network]
:total-amount 500
:requesting-data? false
:on-amount-selected (fn [_new-amount _network-idx] nil)}]
(h/test "Renders Default"
(h/render [network-routing/view default-props])
(h/is-truthy (h/get-by-label-text :network-routing)))
(h/test "Renders bars inside"
(let [component (h/render [network-routing/view default-props])
rerender-fn #((oops/oget component "rerender") (reagent/as-element %))
component (h/get-by-label-text :network-routing)]
;; Fires on-layout callback since the total width is required
(h/fire-event :layout component #js {:nativeEvent #js {:layout #js {:width 1000}}})
;; Update props to trigger rerender, otherwise it won't be updated
(rerender-fn [network-routing/view (assoc default-props :requesting-data? true)])
;; Check number of networks rendered
(->> (js->clj (h/query-all-by-label-text :network-routing-bar))
(count)
(h/is-equal 3))))))
+23 -8
View File
@@ -1,16 +1,18 @@
(ns status-im.ui.screens.qr-scanner.views
(:require-macros [status-im.utils.views :refer [defview letsubs]])
(:require
[clojure.string :as string]
[re-frame.core :as re-frame]
[react-native.camera-kit :as camera-kit]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im.ui.components.colors :as colors]
[status-im.ui.components.core :as quo]
[status-im.ui.components.react :as react]
[status-im.ui.components.topbar :as topbar]
[status-im.ui.screens.qr-scanner.styles :as styles]
[status-im2.config :as config]
[utils.i18n :as i18n]))
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn get-qr-code-data
[^js event]
@@ -85,13 +87,18 @@
[opts data]
(re-frame/dispatch [:qr-scanner.callback/scan-qr-code-success opts (get-qr-code-data data)]))
(defview qr-scanner
(defn- navigate-back-handler
[]
(letsubs [read-once? (atom false)
{:keys [height width]} [:dimensions/window]
camera-flashlight [:wallet-legacy.send/camera-flashlight]
opts [:get-screen-params]
camera-ref (atom nil)]
(re-frame/dispatch [:navigate-back])
true)
(defn f-qr-scanner
[]
(let [read-once? (reagent/atom false)
{:keys [height width]} (rf/sub [:dimensions/window])
camera-flashlight (rf/sub [:wallet-legacy.send/camera-flashlight])
opts (rf/sub [:get-screen-params])
camera-ref (reagent/atom nil)]
[react/view
{:flex 1
:background-color colors/black-persist}
@@ -111,3 +118,11 @@
(reset! read-once? true)
(on-barcode-read opts %))}]]
[viewfinder (int (* 2 (/ (min height width) 3)))]])]))
(defn qr-scanner
[]
(reagent/create-class
{:display-name "qr-scanner"
:component-did-mount #(rn/hw-back-add-listener navigate-back-handler)
:component-will-unmount #(rn/hw-back-remove-listener navigate-back-handler)
:reagent-render f-qr-scanner}))
+2 -1
View File
@@ -46,7 +46,8 @@
:no-contacts-to-invite-light (js/require "../resources/images/ui2/no-contacts-to-invite-light.png")
:no-contacts-to-invite-dark (js/require "../resources/images/ui2/no-contacts-to-invite-dark.png")
:no-notifications-light (js/require "../resources/images/ui2/no-notifications-light.png")
:no-notifications-dark (js/require "../resources/images/ui2/no-notifications-dark.png")})
:no-notifications-dark (js/require "../resources/images/ui2/no-notifications-dark.png")
:welcome-illustration (js/require "../resources/images/ui2/welcome_illustration.png")})
(def ui-themed
{:no-messages
@@ -9,13 +9,11 @@
[utils.re-frame :as rf]))
(defn view
[{:keys [on-enter-password button-label]}]
(let [{:keys [key-uid display-name
customization-color]
:as account} (rf/sub [:profile/multiaccount])
{:keys [error processing password]} (rf/sub [:profile/login])
sign-in-enabled? (rf/sub [:sign-in-enabled?])
profile-picture (multiaccounts/displayed-photo account)]
[{:keys [on-enter-password button-label button-icon-left customization-color]}]
(let [{:keys [key-uid display-name] :as account} (rf/sub [:profile/multiaccount])
{:keys [error processing password]} (rf/sub [:profile/login])
sign-in-enabled? (rf/sub [:sign-in-enabled?])
profile-picture (multiaccounts/displayed-photo account)]
[:<>
[rn/view {:style style/enter-password-container}
[rn/view
@@ -45,7 +43,7 @@
:type :primary
:customization-color (or customization-color :primary)
:accessibility-label :login-button
:icon-left :i/reveal
:icon-left button-icon-left
:disabled? (or (not sign-in-enabled?) processing)
:on-press (fn []
(rf/dispatch [:set-in [:profile/login :key-uid] key-uid])
@@ -17,7 +17,7 @@
(defn authorize
[{:keys [on-enter-password biometric-auth? on-auth-success on-auth-fail on-close
fallback-button-label theme blur?]}]
auth-button-label theme blur? customization-color auth-button-icon-left]}]
(biometric/get-supported-type
(fn [biometric-type]
(if (and biometric-auth? biometric-type)
@@ -43,8 +43,10 @@
:shell? blur?
:content (fn []
[enter-password/view
{:on-enter-password on-enter-password
:button-label fallback-button-label}])}]))))))
{:customization-color customization-color
:on-enter-password on-enter-password
:button-icon-left auth-button-icon-left
:button-label auth-button-label}])}]))))))
(defn- view-internal
[_]
@@ -53,26 +55,31 @@
(fn [{:keys [biometric-auth?
track-text
customization-color
fallback-button-label
auth-button-label
on-enter-password
on-auth-success
on-auth-fail
auth-button-icon-left
size
theme
blur?]}]
blur?
container-style]}]
[rn/view {:style {:flex 1}}
[quo/slide-button
{:size size
:container-style container-style
:customization-color customization-color
:on-reset (when @reset-slider? #(reset! reset-slider? false))
:on-complete #(authorize {:on-close on-close
:auth-button-icon-left auth-button-icon-left
:theme theme
:blur? blur?
:customization-color customization-color
:on-enter-password on-enter-password
:biometric-auth? biometric-auth?
:on-auth-success on-auth-success
:on-auth-fail on-auth-fail
:fallback-button-label fallback-button-label})
:auth-button-label auth-button-label})
:track-icon (if biometric-auth? :i/face-id :password)
:track-text track-text}]])))
+14
View File
@@ -358,3 +358,17 @@
(def ^:const ens-action-type-register 1)
(def ^:const ens-action-type-set-pub-key 2)
;; wallet
(def ^:const mainnet-chain-id 1)
(def ^:const optimism-chain-id 10)
(def ^:const arbitrum-chain-id 42161)
(def ^:const goerli-chain-id 5)
(def ^:const mainnet-short-name "eth")
(def ^:const optimism-short-name "opt")
(def ^:const arbitrum-short-name "arb1")
(def ^:const mainnet-network-name :ethereum)
(def ^:const optimism-network-name :optimism)
(def ^:const arbitrum-network-name :arbitrum)
@@ -112,7 +112,10 @@
(let [edit-text (get-in edit [:content :text])
text-value-count (count @text-value)]
(when (and edit @input-ref)
(.focus ^js @input-ref)
;; A small setTimeout is necessary to ensure the statement is enqueued and will get executed
;; ASAP.
;; https://github.com/software-mansion/react-native-screens/issues/472
(js/setTimeout #(.focus ^js @input-ref) 250)
(.setNativeProps ^js @input-ref (clj->js {:text edit-text}))
(reset! text-value edit-text)
(reset! saved-cursor-position (if (zero? text-value-count)
@@ -129,7 +132,7 @@
(when reply
(reanimated/animate container-opacity 1))
(when (and reply @input-ref)
(.focus ^js @input-ref)))
(js/setTimeout #(.focus ^js @input-ref) 250)))
[(:message-id reply)]))
(defn edit-mentions
@@ -181,7 +184,7 @@
(+ (reanimated/get-shared-value last-height) value))))
(let [curr-text @text-value]
(reset! text-value (str @text-value " "))
(js/setTimeout #(reset! text-value curr-text) 10)))
(js/setTimeout #(reset! text-value curr-text) 100)))
(reset! sending-links? link-previews?))
[link-previews?]))
@@ -208,7 +211,7 @@
(+ (reanimated/get-shared-value last-height) value))))
(let [curr-text @text-value]
(reset! text-value (str @text-value " "))
(js/setTimeout #(reset! text-value curr-text) 10)))
(js/setTimeout #(reset! text-value curr-text) 100)))
(reset! sending-images? (boolean (seq images))))
[(boolean (seq images))]))
@@ -2,10 +2,10 @@
(:require
[quo.components.selectors.reaction-resource :as reactions.resource]
[quo.core :as quo]
[react-native.clipboard :as clipboard]
[react-native.core :as rn]
[react-native.gesture :as gesture]
[reagent.core :as reagent]
[status-im.ui.components.react :as react]
[status-im2.common.contact-list-item.view :as contact-list-item]
[status-im2.constants :as constants]
[status-im2.contexts.chat.composer.reply.view :as reply]
@@ -119,7 +119,7 @@
(when (and (not (or deleted? deleted-for-me?))
(not= content-type constants/content-type-audio))
[{:type :main
:on-press #(react/copy-to-clipboard
:on-press #(clipboard/set-string
(reply/get-quoted-text-with-mentions
(get content :parsed-text)))
:label (i18n/label :t/copy-text)
@@ -2,12 +2,9 @@
(:require
[quo.foundations.colors :as colors]
[quo.foundations.typography :as typography]
[status-im.ui.components.react :as react]))
[react-native.core :as rn]))
(def screen-width
(-> "window"
react/get-dimensions
:width))
(def screen-width (:width (rn/get-window)))
(defn scale-dimensions
"Scale a given height and width to be maximum percentage allowed of the screen width"
@@ -82,4 +79,3 @@
{:height 170})
{:overflow :hidden
:border-radius 12}))
@@ -130,13 +130,15 @@
(defn list-header
[insets able-to-send-message? theme]
[rn/view
{:background-color (colors/theme-colors colors/white colors/neutral-95 theme)
:height (+ (if able-to-send-message?
(+ composer.constants/composer-default-height
jump-to.constants/floating-shell-button-height
(:bottom insets))
(- 70 (:bottom insets))))}])
(let [images (rf/sub [:chats/sending-image])]
[rn/view
{:background-color (colors/theme-colors colors/white colors/neutral-95 theme)
:height (if able-to-send-message?
(+ composer.constants/composer-default-height
jump-to.constants/floating-shell-button-height
(if (seq images) composer.constants/images-container-height 0)
(:bottom insets))
(- 70 (:bottom insets)))}]))
(defn f-list-footer-avatar
[{:keys [scroll-y display-name online? profile-picture]}]
@@ -318,10 +320,10 @@
:render-fn render-fn
:on-viewable-items-changed on-viewable-items-changed
:on-content-size-change (fn [_ y]
;; NOTE(alwx): here we set the initial value of `scroll-y`
;; which is needed because by default the chat is
;; scrolled to the bottom and no initial `on-scroll`
;; event is getting triggered
;; NOTE(alwx): here we set the initial value of
;; `scroll-y` which is needed because by default the
;; chat is scrolled to the bottom and no initial
;; `on-scroll` event is getting triggered
(let [scroll-y-shared (reanimated/get-shared-value
scroll-y)
content-height-shared (reanimated/get-shared-value
@@ -82,12 +82,13 @@
:online? online?
:photo-path photo-path}]
(if able-to-send-message?
[:f> composer.view/composer
{:insets insets
:scroll-to-bottom-fn list.view/scroll-to-bottom
:show-floating-scroll-down-button? show-floating-scroll-down-button?}]
[contact-requests.bottom-drawer/view chat-id contact-request-state group-chat])]))
(when (seq chat)
(if able-to-send-message?
[:f> composer.view/composer
{:insets insets
:scroll-to-bottom-fn list.view/scroll-to-bottom
:show-floating-scroll-down-button? show-floating-scroll-down-button?}]
[contact-requests.bottom-drawer/view chat-id contact-request-state group-chat]))]))
(defn chat
[]
@@ -6,7 +6,6 @@
[quo.theme :as quo.theme]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im.ui.components.react :as react]
[status-im2.common.scroll-page.view :as scroll-page]
[status-im2.contexts.communities.actions.community-options.view :as options]
[status-im2.contexts.communities.discover.style :as style]
@@ -117,7 +116,7 @@
featured-communities
view-type
selected-tab]}]
[react/animated-view
[rn/view
[screen-title]
(when (pos? featured-communities-count)
[:<>
@@ -14,6 +14,7 @@
[status-im2.contexts.communities.actions.community-options.view :as options]
[status-im2.contexts.communities.overview.style :as style]
[status-im2.contexts.communities.overview.utils :as utils]
[utils.debounce :as debounce]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
@@ -210,7 +211,7 @@
(when (and (not locked?) id)
{:on-press (fn []
(rf/dispatch [:dismiss-keyboard])
(rf/dispatch [:chat/navigate-to-chat (str community-id id)]))
(debounce/dispatch-and-chill [:chat/navigate-to-chat (str community-id id)] 1000))
:on-long-press #(rf/dispatch
[:show-bottom-sheet
{:content (fn []
@@ -2,6 +2,7 @@
(:require
[clojure.string :as string]
[oops.core :as oops]
[quo.components.colors.color.constants :as constants]
[quo.core :as quo]
[quo.foundations.colors :as colors]
[react-native.blur :as blur]
@@ -33,6 +34,12 @@
(defn length-not-valid [s] (< (count (string/trim (str s))) min-length))
(def scroll-view-height (reagent/atom 0))
(def content-container-height (reagent/atom 0))
(defn iphone-11-Pro-20-pixel-from-width
[window-width]
;; Divide iPhone 11 Pro VW by the desired value
(let [calculate-ratio (/ constants/IPHONE_11_PRO_VIEWPORT_WIDTH 20)]
;; Divide window width by the ratio to get a dynamic value. Based on the VW width
(int (/ window-width calculate-ratio))))
(defn validation-message
[s]
@@ -131,7 +138,8 @@
{:keys [keyboard-shown keyboard-height]} (hooks/use-keyboard)
show-background? (show-button-background keyboard-height
keyboard-shown
@content-scroll-y)]
@content-scroll-y)
{window-width :width} (rn/get-window)]
[rn/view {:style style/page-container}
[quo/page-nav
{:margin-top navigation-bar-top
@@ -194,11 +202,13 @@
{:size :paragraph-2
:weight :medium
:style style/color-title}
(i18n/label :t/accent-colour)]
[quo/color-picker
{:blur? true
:default-selected :blue
:on-change on-change}]]]]]
(i18n/label :t/accent-colour)]]]
[quo/color-picker
{:blur? true
:default-selected :blue
:on-change on-change
:window-width window-width
:container-style {:padding-left (iphone-11-Pro-20-pixel-from-width window-width)}}]]]
[rn/keyboard-avoiding-view
{:style {:position :absolute
@@ -1,6 +1,4 @@
(ns status-im2.contexts.onboarding.welcome.style
(:require
[quo.foundations.colors :as colors]))
(ns status-im2.contexts.onboarding.welcome.style)
(def default-margin 20)
@@ -9,16 +7,27 @@
{:flex 1
:padding-top (:top insets)})
(def page-illustration
{:flex 1
:background-color colors/danger-50
:align-items :center
:margin-horizontal default-margin
:border-radius 20
:margin-top default-margin
:justify-content :center})
(defn page-illustration
[width]
{:resize-mode :stretch
:resize-method :scale
:width width
:margin-top 12
:margin-bottom 4})
(defn buttons
[insets]
{:margin default-margin
:margin-bottom (+ 14 (:bottom insets))})
{:position :absolute
:left 0
:right 0
:padding-left default-margin
:padding-right default-margin
:bottom (+ 12 (:bottom insets))})
(def bottom-shadow
{:position :absolute
:height 64
:top 0
:bottom 0
:left 0
:right 0})
@@ -1,9 +1,12 @@
(ns status-im2.contexts.onboarding.welcome.view
(:require
[quo.core :as quo]
[quo.foundations.colors :as colors]
[re-frame.core :as re-frame]
[react-native.core :as rn]
[react-native.linear-gradient :as linear-gradient]
[react-native.safe-area :as safe-area]
[status-im2.common.resources :as resources]
[status-im2.constants :as constants]
[status-im2.contexts.onboarding.welcome.style :as style]
[utils.i18n :as i18n]
@@ -30,6 +33,7 @@
[]
(let [profile-color (rf/sub [:onboarding-2/customization-color])
{:keys [status-type]} (rf/sub [:multiaccount/current-user-visibility-status])
window (rf/sub [:dimensions/window])
insets (safe-area/get-insets)]
[rn/view {:style (style/page-container insets)}
(when (nil? status-type)
@@ -40,10 +44,14 @@
:icon-name :i/arrow-left
:on-press #(rf/dispatch [:navigate-back-within-stack :enable-notifications])}]
[page-title]
[rn/view {:style style/page-illustration}
[quo/text
"Illustration here"]]
[rn/image
{:style (style/page-illustration (:width window))
:source (resources/get-image :welcome-illustration)}]
[rn/view {:style (style/buttons insets)}
(when rn/small-screen?
[linear-gradient/linear-gradient
{:style style/bottom-shadow
:colors [colors/neutral-100-opa-0 colors/neutral-100-opa-80]}])
[quo/button
{:on-press (fn []
(rf/dispatch [:init-root :shell-stack])
@@ -22,6 +22,7 @@
[status-im2.contexts.profile.rpc :as profile.rpc]
[status-im2.contexts.push-notifications.events :as notifications]
[status-im2.contexts.shell.activity-center.events :as activity-center]
[status-im2.contexts.wallet.events :as wallet]
[status-im2.navigation.events :as navigation]
[taoensso.timbre :as log]
[utils.re-frame :as rf]
@@ -91,6 +92,7 @@
(activity-center/notifications-fetch-pending-contact-requests)
(activity-center/update-seen-state)
(activity-center/notifications-fetch-unread-count)
(wallet/get-ethereum-chains)
(redirect-to-root))))
;; login phase 2, we want to load and show chats faster so we split login into 2 phases
@@ -188,14 +190,16 @@
native-module/sha3)]
{:json-rpc/call [{:method "accounts_verifyPassword"
:params [hashed-password]
:on-success #(do (rf/dispatch [:profile.login/verified-database-password %]) (cb))
:on-success #(rf/dispatch [:profile.login/verified-database-password % cb])
:on-error #(log/error "accounts_verifyPassword error" %)}]}))
(rf/defn verify-database-password-success
{:events [:profile.login/verified-database-password]}
[{:keys [db] :as cofx} valid?]
[{:keys [db] :as cofx} valid? callback]
(if valid?
(do
(when (fn? callback)
(callback))
{:db (update db
:profile/login
dissoc
@@ -45,7 +45,7 @@
:type :default
:label "Drawer label"
:keycard? true
:networks [:ethereum]
:networks [{:name :ethereum :short-name "eth"}]
:description "0x62b...0a5"
:button-icon :i/placeholder
:community-name "Coinbase"
@@ -16,7 +16,8 @@
{:type :account
:blur? false
:title "Collectibles vault"
:networks [:ethereum :optimism]
:networks [{:name :ethereum :short-name "eth"}
{:name :optimism :short-name "opt"}]
:description "0x0ah...78b"
:account-avatar-emoji "🍿"
:customization-color (or customization-color :blue)}]
@@ -20,7 +20,8 @@
:type :default
:name "Trip to Vegas"
:address "0x0ah...78b"}
:networks [:ethereum :optimism]
:networks [{:name :ethereum :short-name "eth"}
{:name :optimism :short-name "opt"}]
:action :none
:on-press (fn [] (js/alert "Item pressed"))
:on-options-press (fn [] (js/alert "Options pressed"))
@@ -13,7 +13,8 @@
(defn view
[]
(let [state (reagent/atom {:address "0x0ah...78b"
:networks [:ethereum :optimism]})]
:networks [{:name :ethereum :short-name "eth"}
{:name :optimism :short-name "opt"}]})]
(fn []
[preview/preview-container
{:state state
@@ -0,0 +1,55 @@
(ns status-im2.contexts.quo-preview.list-items.token-network
(:require
[quo.core :as quo]
[quo.foundations.resources :as quo.resources]
[reagent.core :as reagent]
[status-im2.contexts.quo-preview.preview :as preview]))
(def networks-list
[{:source (quo.resources/get-network :ethereum)}
{:source (quo.resources/get-network :optimism)}
{:source (quo.resources/get-network :arbitrum)}
{:source (quo.resources/get-network :zksync)}
{:source (quo.resources/get-network :polygon)}])
(def descriptor
[{:key :state
:type :select
:options [{:key :default}
{:key :active}
{:key :selected}]}
{:key :token
:type :select
:options [{:value :eth
:key (quo.resources/get-token :eth)}
{:value :snt
:key (quo.resources/get-token :snt)}
{:value :dai
:key (quo.resources/get-token :dai)}]}
{:key :label
:type :text}
{:key :token-value
:type :text}
{:key :fiat-value
:type :text}
(preview/customization-color-option)
{:key :show-alert-on-press?
:type :boolean}])
(defn preview-token-network
[]
(let [state (reagent/atom {:token (quo.resources/get-token :snt)
:label "Status"
:token-value "0.00 SNT"
:fiat-value "€0.00"
:networks networks-list
:state :default
:customization-color :blue})]
(fn []
[preview/preview-container
{:state state
:descriptor descriptor}
[quo/token-network
(merge @state
(when (:show-alert-on-press? @state)
{:on-press #(js/alert "Pressed!")}))]])))
@@ -92,6 +92,7 @@
[status-im2.contexts.quo-preview.list-items.preview-lists :as preview-lists]
[status-im2.contexts.quo-preview.list-items.saved-address :as saved-address]
[status-im2.contexts.quo-preview.list-items.saved-contact-address :as saved-contact-address]
[status-im2.contexts.quo-preview.list-items.token-network :as token-network]
[status-im2.contexts.quo-preview.list-items.token-value :as token-value]
[status-im2.contexts.quo-preview.list-items.user-list :as user-list]
[status-im2.contexts.quo-preview.loaders.skeleton-list :as skeleton-list]
@@ -99,6 +100,7 @@
[status-im2.contexts.quo-preview.markdown.text :as text]
[status-im2.contexts.quo-preview.messages.author :as messages-author]
[status-im2.contexts.quo-preview.messages.gap :as messages-gap]
[status-im2.contexts.quo-preview.messages.message :as message]
[status-im2.contexts.quo-preview.messages.system-message :as system-message]
[status-im2.contexts.quo-preview.navigation.bottom-nav-tab :as
bottom-nav-tab]
@@ -165,6 +167,7 @@
[status-im2.contexts.quo-preview.wallet.network-amount :as network-amount]
[status-im2.contexts.quo-preview.wallet.network-bridge :as network-bridge]
[status-im2.contexts.quo-preview.wallet.network-link :as network-link]
[status-im2.contexts.quo-preview.wallet.network-routing :as network-routing]
[status-im2.contexts.quo-preview.wallet.progress-bar :as progress-bar]
[status-im2.contexts.quo-preview.wallet.summary-info :as summary-info]
[status-im2.contexts.quo-preview.wallet.token-input :as token-input]
@@ -328,6 +331,8 @@
:component saved-address/view}
{:name :saved-contact-address
:component saved-contact-address/view}
{:name :token-network
:component token-network/preview-token-network}
{:name :token-value
:component token-value/view}
{:name :user-list
@@ -344,6 +349,8 @@
:component messages-author/view}
{:name :gap
:component messages-gap/view}
{:name :message
:component message/view}
{:name :system-messages
:component system-message/view}]
:navigation [{:name :bottom-nav-tab
@@ -444,6 +451,7 @@
{:name :network-amount :component network-amount/preview}
{:name :network-bridge :component network-bridge/preview}
{:name :network-link :component network-link/preview}
{:name :network-routing :component network-routing/preview}
{:name :progress-bar :component progress-bar/preview}
{:name :summary-info :component summary-info/preview}
{:name :token-input :component token-input/preview}
@@ -0,0 +1,59 @@
(ns status-im2.contexts.quo-preview.messages.message
(:require [quo.core :as quo]
[reagent.core :as reagent]
[status-im2.common.resources :as resources]
[status-im2.constants :as constants]
[status-im2.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:key :header? :type :boolean}
{:key :reacted? :type :boolean}
{:key :delivered? :type :boolean}
{:key :pinned-by :type :text}
(preview/customization-color-option)])
(defn- gen-quantity
[max-count _]
(rand-int max-count))
(def ^:private memo-gen-quantity (memoize gen-quantity))
(defn- normalize-state
[state]
(merge @state
{:context {:pinned-by (:pinned-by @state)
:reactions (when (:reacted? @state)
(mapv (fn [reaction-id]
{:emoji-reaction-id reaction-id
:emoji-id reaction-id
:emoji (get constants/reactions reaction-id)
:quantity (memo-gen-quantity 10 reaction-id)
;; :own (contains? @pressed-reactions
;; reaction-id)
})
[1 2]))}
})
)
(defn view
[]
(let [state (reagent/atom {:avatar-props {:full-name "Alisher Yakupov"
:ring? true
:status-indicator? true
:online? true
:profile-picture (resources/get-mock-image
:user-picture-male5)
:customization-color :blue}
:author-props {:primary-name "Alisher Yakupov"
:secondary-name "zQ3...9d4Gs0"
:time-str "09:30"}
:customization-color :blue
:pinned-by "Steve"
}
)]
(fn []
[preview/preview-container
{:state state
:descriptor descriptor
:component-container-style {:padding-vertical 50
:padding-horizontal 20}}
[quo/message (normalize-state state)]])))
@@ -20,7 +20,9 @@
{:key :add-account
:value "Add Account"}
{:key :empty
:value "Empty"}]}
:value "Empty"}
{:key :missing-keypair
:value "Missing Keypair"}]}
{:label "Customization color:"
:key :customization-color
:type :select
@@ -73,13 +75,24 @@
:emoji "🍑"}
:watch-only
{:name "Alisher account"
:balance "€2,269.12"
:percentage-value "16.9%"
:amount "€570.24"
:metrics? true
:type :watch-only
:emoji "💸"}
{:name "Bens fortune"
:balance "€2,269.12"
:percentage-value "16.9%"
:amount "€570.24"
:metrics? true
:type :watch-only
:customization-color :army
:emoji "💸"}
:missing-keypair
{:name "Trip to Vegas"
:balance "€2,269.12"
:percentage-value "16.9%"
:amount "€570.24"
:metrics? true
:customization-color :turquoise
:type :missing-keypair
:emoji "🎲"}
:add-account
{:customization-color :blue
@@ -12,7 +12,8 @@
:type :default
:name "Trip to Vegas"
:address "0x0ah...71a"}
:networks [:ethereum :optimism]
:networks [{:name :ethereum :short-name "eth"}
{:name :optimism :short-name "opt"}]
:state :default
:action :none}
{:account-props {:customization-color :purple
@@ -21,7 +22,8 @@
:type :default
:name "My savings"
:address "0x0ah...72b"}
:networks [:ethereum :optimism]
:networks [{:name :ethereum :short-name "eth"}
{:name :optimism :short-name "opt"}]
:state :default
:action :none}
{:account-props {:customization-color :army
@@ -30,7 +32,8 @@
:type :default
:name "Coin vault"
:address "0x0ah...73c"}
:networks [:ethereum :optimism]
:networks [{:name :ethereum :short-name "eth"}
{:name :optimism :short-name "opt"}]
:state :default
:action :none}
{:account-props {:customization-color :orange
@@ -39,7 +42,8 @@
:type :default
:name "Crypto fortress"
:address "0x0ah...74e"}
:networks [:ethereum :optimism]
:networks [{:name :ethereum :short-name "eth"}
{:name :optimism :short-name "opt"}]
:state :default
:action :none}
{:account-props {:customization-color :yellow
@@ -48,7 +52,8 @@
:type :default
:name "Block treasure"
:address "0x0ah...75f"}
:networks [:ethereum :optimism]
:networks [{:name :ethereum :short-name "eth"}
{:name :optimism :short-name "opt"}]
:state :default
:action :none}])
@@ -0,0 +1,94 @@
(ns status-im2.contexts.quo-preview.wallet.network-routing
(:require [quo.core :as quo]
[quo.foundations.colors :as colors]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im2.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:label "Number of networks"
:key :number-networks
:type :select
:options [{:key 2} {:key 3} {:key 4} {:key 5}]}])
(defn- fake-call-to-get-amounts
[{:keys [new-amount fixed-index current-values on-success]}]
(let [number-networks (count current-values)
amount-difference (- (get current-values fixed-index) new-amount)
difference-distributed (/ amount-difference (dec number-networks))
new-values (assoc (mapv #(+ % difference-distributed) current-values)
fixed-index
new-amount)]
(js/setTimeout #(on-success new-values) (rand-nth (range 700 5000 250)))))
(defn preview-internal
[{:keys [total-amount number-networks] :as descriptor-state}]
(let [initial-amount (/ total-amount number-networks)
networks (reagent/atom
[{:amount initial-amount
:max-amount (descriptor-state :max-amount-0)
:network-name :ethereum}
{:amount initial-amount
:max-amount (descriptor-state :max-amount-1)
:network-name :arbitrum}
{:amount initial-amount
:max-amount (descriptor-state :max-amount-2)
:network-name :xDai}
{:amount initial-amount
:max-amount (descriptor-state :max-amount-3)
:network-name :optimism}
{:amount initial-amount
:max-amount (descriptor-state :max-amount-4)
:network-name :polygon}])
requesting-data? (reagent/atom false)]
(fn [_]
(let [asked-networks (vec (take number-networks @networks))
on-success-fn (fn [new-network-amounts]
(reset! requesting-data? false)
(swap! networks
#(map (fn [network new-amount]
(assoc network :amount new-amount))
%
new-network-amounts)))]
[rn/view
[quo/network-routing
{:total-amount total-amount
:networks asked-networks
:requesting-data? @requesting-data?
:on-amount-selected (fn [new-amount selected-idx]
(reset! requesting-data? true)
(fake-call-to-get-amounts
{:new-amount new-amount
:fixed-index selected-idx
:current-values (mapv :amount asked-networks)
:on-success on-success-fn}))}]
(reduce (fn [acc {:keys [amount max-amount network-name]}]
(conj acc
[rn/view
{:style {:flex-direction :row
:margin-vertical 12}}
[rn/view
{:style {:background-color (colors/custom-color network-name)
:width 24
:height 24
:margin-right 12}}]
[quo/text
"Max limit: " max-amount " Amount: " (subs (str amount) 0 6)]]))
[rn/view {:style {:margin-vertical 12}}
[quo/text "Total amount: " (reduce + (map :amount asked-networks))]]
asked-networks)]))))
(defn preview
[]
(let [descriptor-state (reagent/atom {:total-amount 400
:number-networks 4
:max-amount-0 350
:max-amount-1 350
:max-amount-2 300
:max-amount-3 250
:max-amount-4 200})]
(fn []
[preview/preview-container {:state descriptor-state :descriptor descriptor}
[rn/view {:style {:flex 1 :margin-vertical 28}}
^{:key (str "preview-network-routing-" (:number-networks @descriptor-state))}
[preview-internal @descriptor-state]]])))
@@ -59,9 +59,9 @@
(defn- outgoing-contact-request-view
[{:keys [notification set-swipeable-height customization-color]}]
(let [{:keys [chat-id message last-message]} notification
{:keys [contact-request-state] :as message} (or message last-message)]
(if (= contact-request-state constants/contact-request-message-state-accepted)
(let [{:keys [chat-id message last-message accepted]} notification
{:keys [contact-request-state] :as message} (or message last-message)]
(if accepted
[quo/activity-log
{:title (i18n/label :t/contact-request-was-accepted)
:customization-color customization-color
@@ -191,7 +191,7 @@
{:size :paragraph-2
:weight :regular
:style style/viewfinder-text}
(i18n/label :t/ensure-qr-code-is-in-focus-to-scan)]]))
(i18n/label :t/ensure-both-devices-are-on-the-same-network)]]))
(defn- scan-qr-code-tab
[qr-view-finder]
@@ -126,7 +126,8 @@
:customization-color customization-color
:on-enter-password on-enter-password
:biometric-auth? false
:fallback-button-label (i18n/label :t/reveal-sync-code)}]])]]
:auth-button-label (i18n/label :t/reveal-sync-code)
:auth-button-icon-left :i/reveal}]])]]
[rn/view {:style style/sync-code}
[quo/divider-label {:tight? false} (i18n/label :t/have-a-sync-code?)]
[quo/action-drawer
@@ -2,6 +2,7 @@
(:require
[quo.core :as quo]
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[status-im2.contexts.wallet.account.tabs.about.style :as style]
[status-im2.contexts.wallet.common.temp :as temp]
@@ -9,20 +10,21 @@
[utils.re-frame :as rf]))
(defn description
[{:keys [address]}]
[quo/text {:size :paragraph-2}
(map (fn [network]
^{:key (str network)}
[quo/text
{:size :paragraph-2
:weight :medium
:style {:color (colors/custom-color network)}}
(str (subs (name network) 0 3) (when (= network :arbitrum) "1") ":")])
temp/network-names)
[quo/text
{:size :paragraph-2
:weight :monospace}
address]])
[{:keys [address theme]}]
(let [networks-list (rf/sub [:wallet/network-details])]
[quo/text {:size :paragraph-2}
(map (fn [{:keys [chain-id short-name network-name]}]
^{:key (str chain-id short-name)}
[quo/text
{:size :paragraph-2
:weight :medium
:style {:color (colors/resolve-color network-name theme)}}
(str short-name ":")])
networks-list)
[quo/text
{:size :paragraph-2
:weight :monospace}
address]]))
(defn about-options
[]
@@ -49,12 +51,19 @@
:accessibility-label :share-address
:label (i18n/label :t/share-address)}]]])
(defn view
(defn- view-internal
[]
[rn/view {:style style/about-tab}
[quo/data-item
(merge temp/data-item-state
{:custom-subtitle (fn [] [description {:address temp/address}])
{:custom-subtitle (fn [] [quo/address-text
{:networks [{:name :ethereum :short-name "eth"}
{:name :optimism :short-name "opt"}
{:name :arbitrum :short-name "arb1"}]
:address temp/address
:format :long}])
:container-style {:margin-bottom 12}
:on-press #(rf/dispatch [:show-bottom-sheet {:content about-options}])})]
[quo/account-origin temp/account-origin-state]])
(def view (quo.theme/with-theme view-internal))
@@ -1,6 +1,5 @@
(ns status-im2.contexts.wallet.account.tabs.view
(:require
[quo.core :as quo]
[react-native.core :as rn]
[status-im2.contexts.wallet.account.tabs.about.view :as about]
[status-im2.contexts.wallet.account.tabs.dapps.view :as dapps]
@@ -8,13 +7,14 @@
[status-im2.contexts.wallet.common.collectibles-tab.view :as collectibles]
[status-im2.contexts.wallet.common.empty-tab.view :as empty-tab]
[status-im2.contexts.wallet.common.temp :as temp]
[status-im2.contexts.wallet.common.token-value.view :as token-value]
[utils.i18n :as i18n]))
(defn view
[{:keys [selected-tab]}]
(case selected-tab
:assets [rn/flat-list
{:render-fn quo/token-value
{:render-fn token-value/view
:data temp/tokens
:content-container-style {:padding-horizontal 8}}]
:collectibles [collectibles/view]
@@ -1,7 +1,6 @@
(ns status-im2.contexts.wallet.account.view
(:require
[quo.core :as quo]
[quo.foundations.resources :as quo.resources]
[react-native.core :as rn]
[react-native.safe-area :as safe-area]
[reagent.core :as reagent]
@@ -49,11 +48,6 @@
:padding-bottom 8}
:render-fn quo/settings-item}]])
(def ^:private networks-list
[{:source (quo.resources/get-network :ethereum)}
{:source (quo.resources/get-network :optimism)}
{:source (quo.resources/get-network :arbitrum)}])
(def tabs-data
[{:id :assets :label (i18n/label :t/assets) :accessibility-label :assets-tab}
{:id :collectibles :label (i18n/label :t/collectibles) :accessibility-label :collectibles-tab}
@@ -67,34 +61,35 @@
(let [top (safe-area/get-top)
selected-tab (reagent/atom (:id (first tabs-data)))]
(fn []
[rn/view
{:style {:flex 1
:margin-top top}}
[quo/page-nav
{:type :wallet-networks
:background :blur
:icon-name :i/close
:on-press #(rf/dispatch [:navigate-back])
:networks networks-list
:networks-on-press #(js/alert "Pressed Networks")
:right-side :account-switcher
:account-switcher {:customization-color :purple
:on-press #(rf/dispatch [:show-bottom-sheet
{:content account-options
:gradient-cover? true
:customization-color :purple}])
:emoji "🍑"}}]
[quo/account-overview temp/account-overview-state]
[quo/wallet-graph {:time-frame :empty}]
[quo/wallet-ctas
{:send-action #(rf/dispatch [:open-modal :wallet-select-address])
:buy-action #(rf/dispatch [:show-bottom-sheet
{:content buy-drawer}])}]
[quo/tabs
{:style style/tabs
:size 32
:default-active @selected-tab
:data tabs-data
:on-change #(reset! selected-tab %)
:scrollable? true}]
[tabs/view {:selected-tab @selected-tab}]])))
(let [networks (rf/sub [:wallet/network-details])]
[rn/view
{:style {:flex 1
:margin-top top}}
[quo/page-nav
{:type :wallet-networks
:background :blur
:icon-name :i/close
:on-press #(rf/dispatch [:navigate-back])
:networks networks
:networks-on-press #(js/alert "Pressed Networks")
:right-side :account-switcher
:account-switcher {:customization-color :purple
:on-press #(rf/dispatch [:show-bottom-sheet
{:content account-options
:gradient-cover? true
:customization-color :purple}])
:emoji "🍑"}}]
[quo/account-overview temp/account-overview-state]
[quo/wallet-graph {:time-frame :empty}]
[quo/wallet-ctas
{:send-action #(rf/dispatch [:open-modal :wallet-select-address])
:buy-action #(rf/dispatch [:show-bottom-sheet
{:content buy-drawer}])}]
[quo/tabs
{:style style/tabs
:size 32
:default-active @selected-tab
:data tabs-data
:on-change #(reset! selected-tab %)
:scrollable? true}]
[tabs/view {:selected-tab @selected-tab}]]))))
+15 -45
View File
@@ -6,14 +6,9 @@
[react-native.core :as rn]
[status-im2.common.resources :as status.resources]
[status-im2.constants :as constants]
[status-im2.contexts.wallet.common.utils :as utils]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(def networks
[{:source (quo.resources/get-network :ethereum)}
{:source (quo.resources/get-network :optimism)}
{:source (quo.resources/get-network :arbitrum)}])
(defn wallet-temporary-navigation
[]
@@ -29,7 +24,8 @@
[quo/button {:on-press #(rf/dispatch [:navigate-to :wallet-saved-addresses])}
"Saved Addresses"]])
(def wallet-overview-state
(defn wallet-overview-state
[networks]
{:state :default
:time-frame :none
:metrics :none
@@ -112,36 +108,10 @@
:account :default
:customization-color :blue})
(defn keypair-string
[full-name]
(let [first-name (utils/get-first-name full-name)]
(i18n/label :t/keypair-title {:name first-name})))
(defn create-account-state
[name]
[{:title (keypair-string name)
:image :avatar
:image-props {:full-name "A Y"
:size :xxs
:customization-color :blue}
:action :button
:action-props {:on-press #(js/alert "Button pressed!")
:button-text (i18n/label :t/edit)
:alignment :flex-start}
:description :text
:description-props {:text (i18n/label :t/on-device)}}
{:title (i18n/label :t/derivation-path)
:image :icon
:image-props :i/derivated-path
:action :button
:action-props {:on-press #(js/alert "Button pressed!")
:button-text (i18n/label :t/edit)
:icon-left :i/placeholder
:alignment :flex-start}
:description :text
:description-props {:text (string/replace constants/path-default-wallet #"/" " / ")}}])
(def network-names [:ethereum :optimism :arbitrum])
(def network-names
[{:name :ethereum :short-name "eth"}
{:name :optimism :short-name "opt"}
{:name :arbitrum :short-name "arb1"}])
(def address "0x39cf6E0Ba4C4530735616e1Ee7ff5FbCB726fBd4")
@@ -182,10 +152,10 @@
(def account-data
{:title "Trip to Vegas"
:type :account
:networks [{:name :ethereum :short :eth}
{:name :optimism :short :opt}
{:name :arbitrum :short :arb1}]
:description "0x62b...0a5"
:networks [{:name :ethereum :short-name "eth"}
{:name :optimism :short-name "opt"}
{:name :arbitrum :short-name "arb1"}]
:description "0x39cf6E0Ba4C4530735616e1Ee7ff5FbCB726fBd4"
:account-avatar-emoji "🍑"
:customization-color :purple})
@@ -193,14 +163,14 @@
[{:customization-color :flamingo
:emoji "🍿"
:name "New House"
:address "0x21a...49e"
:networks [{:name :ethereum :short :eth}
{:name :optimism :short :opt}]}
:address "0x21af6E0Ba4C4530735616e1Ee7ff5FbCB726f493"
:networks [{:name :ethereum :short-name "eth"}
{:name :optimism :short-name "opt"}]}
{:customization-color :blue
:emoji "🎮"
:name "My savings"
:address "0x43c...98d"
:networks [{:name :ethereum :short :eth}]}])
:address "0x43cf6E0Ba4C4530735616e1Ee7ff5FbCB726f98d"
:networks [{:name :ethereum :short-name "eth"}]}])
(def asset-snt
{:size 24
@@ -0,0 +1,40 @@
(ns status-im2.contexts.wallet.common.token-value.view
(:require [quo.core :as quo]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn token-value-drawer
[]
[:<>
[quo/action-drawer
[[{:icon :i/buy
:accessibility-label :buy
:label (i18n/label :t/buy)
:on-press #(js/alert "to be implemented")
:right-icon :i/external}
{:icon :i/send
:accessibility-label :send
:label (i18n/label :t/send)}
{:icon :i/receive
:accessibility-label :receive
:label (i18n/label :t/receive)}
{:icon :i/bridge
:accessibility-label :bridge
:label (i18n/label :t/bridge)}
{:icon :i/settings
:accessibility-label :settings
:label (i18n/label :t/manage-tokens)
:add-divider? true}
{:icon :i/hide
:accessibility-label :hide
:label (i18n/label :t/hide)}]]]])
(defn view
[item]
[quo/token-value
(merge item
{:on-long-press
#(rf/dispatch
[:show-bottom-sheet
{:content token-value-drawer
:selected-item (fn [] [quo/token-value item])}])})])
@@ -1,7 +1,11 @@
(ns status-im2.contexts.wallet.common.utils
(:require
[clojure.string :as string]))
(:require [clojure.string :as string]
[status-im2.constants :as constants]))
(defn get-first-name
[full-name]
(first (string/split full-name #" ")))
(defn get-derivation-path
[number-of-accounts]
(str constants/path-wallet-root "/" number-of-accounts))
@@ -5,20 +5,44 @@
[react-native.core :as rn]
[react-native.safe-area :as safe-area]
[reagent.core :as reagent]
[status-im2.contexts.wallet.common.temp :as temp]
[status-im2.common.standard-authentication.standard-auth.view :as standard-auth]
[status-im2.contexts.wallet.common.utils :as utils]
[status-im2.contexts.wallet.create-account.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(def diamond-emoji "\uD83D\uDC8E")
(defn keypair-string
[full-name]
(let [first-name (utils/get-first-name full-name)]
(i18n/label :t/keypair-title {:name first-name})))
(defn get-keypair-data
[name derivation-path]
[{:title (keypair-string name)
:button-props {:title (i18n/label :t/edit)}
:left-icon :i/placeholder
:description :text
:description-props {:text (i18n/label :t/on-device)}}
{:title (i18n/label :t/derivation-path)
:button-props {:title (i18n/label :t/edit)}
:left-icon :i/derivated-path
:description :text
:description-props {:text derivation-path}}])
(defn- view-internal
[]
(let [top (safe-area/get-top)
bottom (safe-area/get-bottom)
account-color (reagent/atom :blue)
emoji (reagent/atom diamond-emoji)
number-of-accounts (count (rf/sub [:profile/wallet-accounts]))
account-name (reagent/atom (i18n/label :t/default-account-name
{:number (inc number-of-accounts)}))
derivation-path (reagent/atom (utils/get-derivation-path number-of-accounts))
{:keys [public-key]} (rf/sub [:profile/profile])
on-change-text #(reset! account-name %)
display-name (first (rf/sub [:contacts/contact-two-names-by-identity public-key]))]
(fn [{:keys [theme]}]
[rn/view
@@ -50,13 +74,14 @@
(reset! emoji selected-emoji))}])
:container-style style/reaction-button-container} :i/reaction]]
[quo/title-input
{:color :red
:placeholder "Type something here"
:max-length 24
:blur? true
:disabled? false
:default-value "Account 2"
:container-style style/title-input-container}]
{:customization-color @account-color
:placeholder "Type something here"
:on-change-text on-change-text
:max-length 24
:blur? true
:disabled? false
:default-value @account-name
:container-style style/title-input-container}]
[quo/divider-line]
[rn/view
{:style style/color-picker-container}
@@ -74,13 +99,20 @@
[quo/category
{:list-type :settings
:label (i18n/label :t/origin)
:data (temp/create-account-state display-name)}]
[quo/slide-button
{:track-text (i18n/label :t/slide-to-sign)
:track-icon :face-id
:data (get-keypair-data display-name @derivation-path)}]
[standard-auth/view
{:size :size-48
:track-text (i18n/label :t/slide-to-create-account)
:customization-color @account-color
:on-complete (fn []
(js/alert "Functionality not implemented"))
:on-enter-password (fn [entered-password]
(rf/dispatch [:wallet/derive-address-and-add-account
entered-password
{:emoji @emoji
:color @account-color
:path @derivation-path
:account-name @account-name}]))
:biometric-auth? false
:auth-button-label (i18n/label :t/confirm)
:container-style (style/slide-button-container bottom)}]])))
(def view (quo.theme/with-theme view-internal))
@@ -39,7 +39,12 @@
:right-icon :i/advanced
:card? true
:title (i18n/label :t/address)
:subtitle account-address
:custom-subtitle (fn [] [quo/address-text
{:networks [{:name :ethereum :short-name "eth"}
{:name :optimism :short-name "opt"}
{:name :arbitrum :short-name "arb1"}]
:address account-address
:format :long}])
:on-press (fn []
(rf/dispatch [:show-bottom-sheet
{:content (fn [] [network-preferences/view
+66 -1
View File
@@ -1,5 +1,10 @@
(ns status-im2.contexts.wallet.events
(:require [utils.re-frame :as rf]))
(:require
[native-module.core :as native-module]
[status-im2.data-store.wallet :as data-store]
[taoensso.timbre :as log]
[utils.re-frame :as rf]
[utils.security.core :as security]))
(rf/defn scan-address-success
{:events [:wallet/scan-address-success]}
@@ -10,3 +15,63 @@
{:events [:wallet/clean-scanned-address]}
[{:keys [db]}]
{:db (dissoc db :wallet/scanned-address)})
(rf/reg-event-fx :wallet/create-derived-addresses
(fn [{:keys [db]} [password {:keys [path]} on-success]]
(let [{:keys [wallet-root-address]} (:profile/profile db)
sha3-pwd (native-module/sha3 (str (security/safe-unmask-data password)))]
{:fx [[:json-rpc/call
[{:method "wallet_getDerivedAddresses"
:params [sha3-pwd wallet-root-address [path]]
:on-success on-success
:on-error #(log/info "failed to derive address " %)}]]]})))
(rf/reg-event-fx :wallet/add-account
(fn [{:keys [db]} [password {:keys [emoji account-name color]} {:keys [public-key address path]}]]
(let [key-uid (get-in db [:profile/profile :key-uid])
sha3-pwd (native-module/sha3 (security/safe-unmask-data password))
account-config {:key-uid key-uid
:wallet false
:chat false
:type :generated
:name account-name
:emoji emoji
:path path
:address address
:public-key public-key
:colorID color}]
{:fx [[:json-rpc/call
[{:method "accounts_addAccount"
:params [sha3-pwd account-config]
:on-success #(rf/dispatch [:navigate-to :wallet-accounts])
:on-error #(log/info "failed to create account " %)}]]]})))
(rf/reg-event-fx :wallet/derive-address-and-add-account
(fn [_ [password account-details]]
(let [on-success (fn [derived-adress-details]
(rf/dispatch [:wallet/add-account password account-details
(first derived-adress-details)]))]
{:fx [[:dispatch [:wallet/create-derived-addresses password account-details on-success]]]})))
(rf/defn get-ethereum-chains
{:events [:wallet/get-ethereum-chains]}
[{:keys [db]}]
{:fx [[:json-rpc/call
[{:method "wallet_getEthereumChains"
:params []
:on-success [:wallet/get-ethereum-chains-success]
:on-error #(log/info "failed to get networks " %)}]]]})
(rf/reg-event-fx
:wallet/get-ethereum-chains-success
(fn [{:keys [db]} [data]]
(let [network-data
{:test (map #(->> %
:Test
data-store/<-rpc)
data)
:prod (map #(->> %
:Prod
data-store/<-rpc)
data)}]
{:db (assoc db :wallet/networks network-data)})))
+33 -30
View File
@@ -8,6 +8,7 @@
[status-im2.contexts.wallet.common.activity-tab.view :as activity]
[status-im2.contexts.wallet.common.collectibles-tab.view :as collectibles]
[status-im2.contexts.wallet.common.temp :as temp]
[status-im2.contexts.wallet.common.token-value.view :as token-value]
[status-im2.contexts.wallet.home.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
@@ -50,33 +51,35 @@
(let [top (safe-area/get-top)
selected-tab (reagent/atom (:id (first tabs-data)))]
(fn []
[rn/view
{:style {:margin-top top
:flex 1}}
[common.top-nav/view]
[rn/view {:style style/overview-container}
[quo/wallet-overview temp/wallet-overview-state]]
[rn/pressable
{:on-long-press #(rf/dispatch [:show-bottom-sheet {:content temp/wallet-temporary-navigation}])}
[quo/wallet-graph {:time-frame :empty}]]
[rn/view {:style style/accounts-container}
[rn/flat-list
{:style style/accounts-list
:data account-cards
:horizontal true
:separator [rn/view {:style {:width 12}}]
:render-fn quo/account-card}]]
[quo/tabs
{:style style/tabs
:size 32
:default-active @selected-tab
:data tabs-data
:on-change #(reset! selected-tab %)}]
(case @selected-tab
:assets [rn/flat-list
{:render-fn quo/token-value
:data temp/tokens
:key :assets-list
:content-container-style {:padding-horizontal 8}}]
:collectibles [collectibles/view]
[activity/view])])))
(let [networks (rf/sub [:wallet/network-details])]
[rn/view
{:style {:margin-top top
:flex 1}}
[common.top-nav/view]
[rn/view {:style style/overview-container}
[quo/wallet-overview (temp/wallet-overview-state networks)]]
[rn/pressable
{:on-long-press #(rf/dispatch [:show-bottom-sheet
{:content temp/wallet-temporary-navigation}])}
[quo/wallet-graph {:time-frame :empty}]]
[rn/view {:style style/accounts-container}
[rn/flat-list
{:style style/accounts-list
:data account-cards
:horizontal true
:separator [rn/view {:style {:width 12}}]
:render-fn quo/account-card}]]
[quo/tabs
{:style style/tabs
:size 32
:default-active @selected-tab
:data tabs-data
:on-change #(reset! selected-tab %)}]
(case @selected-tab
:assets [rn/flat-list
{:render-fn token-value/view
:data temp/tokens
:key :assets-list
:content-container-style {:padding-horizontal 8}}]
:collectibles [collectibles/view]
[activity/view])]))))
+25
View File
@@ -0,0 +1,25 @@
(ns status-im2.data-store.wallet
(:require
clojure.set))
(defn <-rpc
[network]
(-> network
(clojure.set/rename-keys
{:Prod :prod
:Test :test
:isTest :test?
:tokenOverrides :token-overrides
:rpcUrl :rpc-url
:chainColor :chain-color
:chainName :chain-name
:nativeCurrencyDecimals :native-currency-decimals
:relatedChainId :related-chain-id
:shortName :short-name
:chainId :chain-id
:originalFallbackURL :original-fallback-url
:originalRpcUrl :original-rpc-url
:fallbackURL :fallback-url
:blockExplorerUrl :block-explorer-url
:nativeCurrencySymbol :native-currency-symbol
:nativeCurrencyName :native-currency-symbol})))
+6
View File
@@ -1,5 +1,6 @@
(ns status-im2.navigation.screens
(:require
[dev.component-preview.view :as component-preview]
[status-im.ui.screens.screens :as old-screens]
[status-im2.config :as config]
[status-im2.contexts.add-new-contact.views :as add-new-contact]
@@ -272,6 +273,11 @@
{:modalPresentationStyle :overCurrentContext})
:component scan-address/view}]
(when js/goog.DEBUG
[{:name :dev-component-preview
:options {:sheet? true}
:component component-preview/view}])
(when config/quo-preview-enabled?
quo.preview/screens)
+8 -1
View File
@@ -10,7 +10,8 @@
status-im2.subs.onboarding
status-im2.subs.pairing
status-im2.subs.profile
status-im2.subs.shell))
status-im2.subs.shell
status-im2.subs.wallet.networks))
(defn reg-root-key-sub
[sub-name db-key]
@@ -146,3 +147,9 @@
;;wallet
(reg-root-key-sub :wallet/scanned-address :wallet/scanned-address)
(reg-root-key-sub :wallet/create-account :wallet/create-account)
(reg-root-key-sub :wallet/networks :wallet/networks)
;;debug
(when js/goog.DEBUG
(reg-root-key-sub :dev/previewed-component :dev/previewed-component))
+43
View File
@@ -0,0 +1,43 @@
(ns status-im2.subs.wallet.networks
(:require [quo.foundations.resources :as resources]
[re-frame.core :as re-frame]
[status-im2.constants :as constants]))
(re-frame/reg-sub
:wallet/filtered-networks-by-mode
:<- [:wallet/networks]
(fn [networks [_ test?]]
(get networks (if test? :test :prod))))
(def mainnet-network-details
{:source (resources/get-network constants/mainnet-network-name)
:short-name constants/mainnet-short-name
:network-name constants/mainnet-network-name})
(def arbitrum-network-details
{:source (resources/get-network constants/arbitrum-network-name)
:short-name constants/arbitrum-short-name
:network-name constants/arbitrum-network-name})
(def optimism-network-details
{:source (resources/get-network constants/optimism-network-name)
:short-name constants/optimism-short-name
:network-name constants/optimism-network-name})
(def network-list
{constants/mainnet-chain-id mainnet-network-details
constants/goerli-chain-id mainnet-network-details
constants/arbitrum-chain-id arbitrum-network-details
constants/optimism-chain-id optimism-network-details})
(re-frame/reg-sub
:wallet/network-details
:<- [:wallet/filtered-networks-by-mode false]
(fn [networks]
(keep
(fn [{:keys [chain-id related-chain-id test?]}]
(let [network-details (get network-list (if test? related-chain-id chain-id))]
(assoc network-details
:chain-id chain-id
:related-chain-id related-chain-id)))
networks)))
@@ -0,0 +1,44 @@
(ns status-im2.subs.wallet.networks-test
(:require
[cljs.test :refer [is testing]]
[re-frame.db :as rf-db]
status-im2.subs.root
status-im2.subs.wallet.networks
[test-helpers.unit :as h]
[utils.re-frame :as rf]))
(def network-data
{:test [{:test? true
:short-name "eth"
:network-name :ethereum
:related-chain-id 1}
{:test? true
:short-name "arb1"
:related-chain-id 42161}
{:test? true
:short-name "opt"
:related-chain-id 10}]
:prod [{:test? false
:short-name "eth"
:chain-id 1}
{:test? false
:short-name "arb1"
:chain-id 42161}
{:test? false
:short-name "opt"
:chain-id 10}]})
(h/deftest-sub :wallet/network-details
[sub-name]
(testing "returns data with prod"
(swap! rf-db/app-db assoc :wallet/networks network-data)
(is (= [{:network-name :ethereum
:short-name "eth"
:chain-id 1}
{:network-name :arbitrum
:short-name "arb1"
:chain-id 42161}
{:network-name :optimism
:short-name "opt"
:chain-id 10}]
(map #(dissoc % :source :related-chain-id) (rf/sub [sub-name]))))))
+5
View File
@@ -72,3 +72,8 @@
abbreviated-public-key (str first-part-of-public-key ellipsis last-part-of-public-key)]
abbreviated-public-key)
nil))
(defn get-short-wallet-address
[value]
(when value
(str (subs value 0 5) "..." (subs value (- (count value) 3) (count value)))))
+2
View File
@@ -83,3 +83,5 @@
(def reg-fx re-frame/reg-fx)
(def dispatch-sync re-frame/dispatch-sync)
(def reg-event-fx re-frame/reg-event-fx)
+3 -3
View File
@@ -3,7 +3,7 @@
"_comment": "Instead use: scripts/update-status-go.sh <rev>",
"owner": "status-im",
"repo": "status-go",
"version": "v0.171.1",
"commit-sha1": "3326362b90ba3b853118ac0aa3be8502fc1aed4f",
"src-sha256": "1npjwhvckmldjy1p7mc6rml8i21mb23409mgl13dzysmlqkppqb1"
"version": "v0.171.7",
"commit-sha1": "74396b461df0c18593262a67c9fd79d706287f7a",
"src-sha256": "1d46lav3g6m1f6ifpypjlsp2qm82c6yk4478awb8f68azpdkvcg5"
}
+6 -1
View File
@@ -433,6 +433,7 @@
"decline": "Decline",
"decryption-failed-content": "An error occured decrypting your data. You might need to erase your old data and generate a new account. Tap “Apply” to erase or “Cancel” to try again",
"default": "Default",
"default-account-name": "Account {{number}}",
"delete": "Delete",
"delete-and-leave-group": "Delete and leave group",
"delete-bootnode": "Delete bootnode",
@@ -1893,6 +1894,7 @@
"select-token-to-swap": "Select token to Swap",
"select-token-to-receive": "Select token to receive",
"slide-to-reveal-code": "Slide to reveal code",
"slide-to-create-account": "Slide to create account",
"minimum-received": "Minimum received",
"powered-by-paraswap": "Powered by Paraswap",
"priority": "Priority",
@@ -2126,6 +2128,7 @@
"ensure-qr-code-in-focus-to-scan": "Ensure that the QR code is in focus to scan",
"i-dont-have-status-on-another-device": "I dont have Status on another device",
"ensure-qr-code-is-in-focus-to-scan": "Ensure that the QR code is in focus to scan",
"ensure-both-devices-are-on-the-same-network": "Ensure both devices are on the same network",
"error-this-is-not-a-sync-qr-code": "Oops! This is not a sync QR code",
"error-syncing-connection-failed": "Oops! Connection failed. Try again",
"camera-permission-denied": "Permission denied",
@@ -2359,5 +2362,7 @@
"account-name-input-placeholder": "Account name",
"network-preferences": "Network preferences",
"network-preferences-desc": "Select which network this address is happy to receive funds on",
"layer-2": "Layer 2"
"layer-2": "Layer 2",
"manage-tokens": "Manage tokens",
"sign transactions": "sign transactions"
}