Compare commits

...
Author SHA1 Message Date
Ulises M 747d6bb128 WIP: debugging 2024-02-13 13:30:46 -06:00
Ulises M a29264a1a1 Reimplement avatar animations using new worklet approach 2024-02-12 15:06:35 -06:00
Ulises M 1386bd4777 Add worklet translation to shadow-cljs 2024-02-12 15:06:03 -06:00
e86faa0767 feat(quo): implement wallet - input amount component (#18687)
Co-authored-by: Siddarth Kumar <siddarthkay@gmail.com>
Co-authored-by: Jamie Caprani <jamiecaprani@gmail.com>
2024-02-12 07:36:23 -08:00
Shivek Khurana abe0342be0 🚟 Add schema batch 2 (#18696)
* 🚟 Add schema batch 2

*  Add maybe and optionals

* 🧑‍⚖️ Make theme a required prop

* 🍙 Fix misplaced square brackets that broke spec

* 🎨 Assume default theme and fix tests

- Fixes #18734

* ⬆️ Update schema and rebase

* 🧪 Update tests

* 🆙 Update progress bar value to be string or int

* 🔩 Tighten schema
2024-02-12 14:44:40 +00:00
Mohamed Javid 6669c33e33 [Fix] Edited wallet account name persists in other edit account screens (#18729)
This commit fixes the edited wallet account name that persists in other account edit screens.

Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com>
2024-02-12 19:11:17 +05:30
Ajay Sivan 1351a54fd1 fix - Button colors have become darker (#18776) 2024-02-12 05:06:18 -08:00
Ibrahem Khalil da192dcdb3 Dismiss keyboard when opening mute chat drawer (#18486) 2024-02-12 13:05:56 +02:00
Flavio Fraschetti 6e22e63158 [Communities] Add quo Collectible Tag (#18748)
* register and basic imports for collectible tag component

* implement variations and design for collectible tag component

* Refined based on review feedback and implemented schema enhancements
2024-02-12 07:40:12 -03:00
Mohamed Javid d1f22cd2b8 Wallet - Clear input on long press delete (#18732)
This commit allows clearing the amount input (in the send flow) by long-pressing the delete key.

---------

Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com>
2024-02-10 00:09:15 +05:30
Parvesh Monu 9dacc9e8af error and app freezing when deselecting account (#18759) 2024-02-09 23:32:58 +05:30
Jamie Caprani 9acf67dd5b feat: add basic infrastructure for contract tests (#18665) 2024-02-09 09:10:09 -08:00
Brian Sztamfater ab73c7e56a feat: show estimated fees when calculating route (#18309)
Signed-off-by: Brian Sztamfater <brian@status.im>
2024-02-09 13:43:14 -03:00
Yevheniia Berdnyk f1db73d149 e2e: updated deep/universal links tests 2024-02-09 15:51:14 +02:00
Ajay Sivan d78d7719cd Account permissions component malli schema fix (#18770) 2024-02-09 05:44:11 -08:00
Alexander e381998b19 Toast notification design fixes (#18468)
* Toast notification design fixes

* Code style fix

* Smaller fix

* Style fix

* Fixes

* Style fixes

* Fixes

* Fixes
2024-02-09 09:54:14 +01:00
Brian Sztamfater 025c38ae88 fix: address is lost on re-render (#18593)
Signed-off-by: Brian Sztamfater <brian@status.im>
2024-02-08 16:29:05 -03:00
mmilad75 523a5809d0 Wallet - Add malli spec to Quo Wallet components (batch 1) #18354 (#18707)
* draft

* add account_card

* add account-origin

* add account_overview

* add account_permission

* add address_text

* add confirmation_progress

* wrapping up

* resolve comments and fix ci issues

* fix ci issues

* fix transaction_progress tests

* fix all tests

* fix lint issues
2024-02-08 20:31:57 +03:30
Icaro Motta 505f2fe624 Communities: Show relevant tokens (#18636)
Show "relevant tokens" in account selection step. Related status-go PR
https://github.com/status-im/status-go/pull/4631.

- Balances are fetched on the account selection screen. Assuming most users
  won't care about selecting addresses, this eliminates unnecessary calls to get
  balances, at the expense of refetching them every time the component is
  mounted. I think for now this is acceptable.
- Relevant tokens is a terminology used in Figma, but more specifically, it
  means "balances for all assets that have at least one Token Criteria
  associated, and for a given address". Or, as I tried to give it a more
  distinct name, "permissioned balances".

Areas that may be impacted: None because all affected code is behind a disabled
feature flag.

Fixes https://github.com/status-im/status-mobile/issues/18126
2024-02-08 11:17:15 -03:00
Ajay Sivan ac32de89f9 Update drawer/bottom-actions component with top & top error variants (#18513) 2024-02-08 02:31:50 -08:00
Mohamed Javid 52a82fffab Bump status-go version to 0.174.2 (#18745)
This commit updates the status-go version to use v0.174.2

Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com>
2024-02-08 15:19:27 +05:30
Mohamed Javid d1c8f6411d [Feature] Wallet - Display token price (#18438)
This commit adds a feature to display token prices for each token in the Wallet home and Account screens.

Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com>
2024-02-08 13:31:42 +05:30
Mohsen 7b639f2ffe [#18453] feat: implement change accent colour screen (#18517) 2024-02-07 19:49:21 +03:00
Brian Sztamfater ae7ee33f00 fix: ENS regex not being used to detect an ENS on address input (#18626)
Signed-off-by: Brian Sztamfater <brian@status.im>
2024-02-07 12:39:49 -03:00
Mohamed Javid c70646bd5c [Fix] Scanned address not populated in send flow (#18727)
This commit fixes the scanned address not pasted/populated in the "Send to" input field.

---

Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com>
2024-02-07 19:56:42 +05:30
mmilad75andLungu Cristian 484ab919b1 Update Wallet: Share QR Code #18454 (#18479)
* add icon

* fix lint issues

* fix preview props and header icon

* fix watched-address icon condition

* fix header tabs

* draft

* fix network name in multichain mode

* fix lint issues

* update tests

* update comments

* add background color

* update preview file

* update usages

* feat: add schema to quo/share-qr-code component

* test: fixed & re-factored tests after adding schema

* bring back gradient structure

* fix scrolling issue

* fix lint issues

* fix usage

---------

Co-authored-by: Lungu Cristian <lungucristian95@gmail.com>
2024-02-07 17:08:41 +03:30
Omar Basem 052d88b531 Wallet: bridging - assets list (#18713)
Wallet: bridging - assets list
2024-02-07 16:55:14 +04:00
Omar Basem 0aba789b5c feat: new keypair - check your backup (#18667)
* feat: new keypair - check your backup
2024-02-07 15:53:29 +04:00
Omar Basem 73450d736a Wallet: fix nested scrollviews warning (#18714)
Wallet: fix nested scrollviews warning (#18714)
2024-02-07 09:32:53 +04:00
Siddarth Kumar cc63c8fff5 init: maestro dev automation (#18712)
The purpose of this commit is to allow running `maestro` automations to enhance productivity by **automating** mundane tasks.

Other flows like
- send contact request
- sync devices
- join a community
etc will be a part of follow ups.

In this commit we provide a `make` command to run a very common task like creating account & login :
`make auto-login`

We also allow another `make` command to run any other custom flow :
`make auto-custom FLOW="maestro/create-account-or-login.yaml"`

A `maestro` folder has been added with 3 `yaml` files which are very easy to understand
ref : https://maestro.mobile.dev/api-reference/commands
2024-02-06 23:29:35 +05:30
Jamie Caprani ef6027575f Add a UI for toggling developer feature flags (#18602) 2024-02-06 08:24:45 -08:00
165 changed files with 3352 additions and 1293 deletions
+13 -12
View File
@@ -16,18 +16,19 @@
:clj-kondo-config {:level :error}
:cond-else {:level :error}
:consistent-alias {:level :error
:aliases {clojure.set set
clojure.string string
clojure.walk walk
malli.core malli
malli.dev.pretty malli.pretty
malli.dev.virhe malli.virhe
malli.error malli.error
malli.generator malli.generator
malli.transform malli.transform
malli.util malli.util
schema.core schema
taoensso.timbre log}}
:aliases {clojure.set set
clojure.string string
clojure.walk walk
malli.core malli
malli.dev.pretty malli.pretty
malli.dev.virhe malli.virhe
malli.error malli.error
malli.generator malli.generator
malli.transform malli.transform
malli.util malli.util
schema.core schema
status-im.feature-flags ff
taoensso.timbre log}}
:deprecated-namespace {:level :warning}
:docstring-blank {:level :error}
:equals-true {:level :error}
+22 -2
View File
@@ -373,15 +373,20 @@ test-watch-for-repl: ##@test Watch all Clojure tests and support REPL connection
"until [ -f $$SHADOW_OUTPUT_TO ] ; do sleep 1 ; done ; node --require ./test-resources/override.js $$SHADOW_OUTPUT_TO --repl"
test-unit: export SHADOW_OUTPUT_TO := target/unit_test/test.js
test-unit: export SHADOW_NS_REGEXP := ^(?!status-im\.integration-test).*-test$$
test-unit: export SHADOW_NS_REGEXP := ^(?!tests\.integration-test)(?!tests-im\.contract-test).*-test$$
test-unit: ##@test Run unit tests
test-unit: _test-clojure
test-integration: export SHADOW_OUTPUT_TO := target/integration_test/test.js
test-integration: export SHADOW_NS_REGEXP := ^status-im\.integration-test.*$$
test-integration: export SHADOW_NS_REGEXP := ^tests\.integration-test.*$$
test-integration: ##@test Run integration tests
test-integration: _test-clojure
test-contract: export SHADOW_OUTPUT_TO := target/contract_test/test.js
test-contract: export SHADOW_NS_REGEXP := ^tests\.contract-test.*$$
test-contract: ##@test Run contract tests
test-contract: _test-clojure
android-test: jsbundle
android-test: export TARGET := android
android-test:
@@ -457,3 +462,18 @@ repl-clojure: ##@repl Start Clojure repl for mobile App
yarn shadow-cljs cljs-repl mobile
repl-nix: nix-repl ##@repl Start an interactive Nix REPL
#--------------
# Dev Automation Flows
#--------------
auto-login: export TARGET := default
auto-login: ##@auto runs flow for login or onboarding app on simulator/emulator
maestro test "maestro/create-account-or-login.yaml"
auto-custom: export TARGET := default
auto-custom: ##@auto runs any custom maestro automation flow on simulator/emulator
ifndef FLOW
$(error Usage: make automate FLOW=your-maestro-flow-file.yaml)
endif
maestro test "$(FLOW)"
+11
View File
@@ -0,0 +1,11 @@
appId: im.status.ethereum.debug
---
- runFlow: # to run onboarding flow only when device is in onboarding state
when:
visible: "Im new to Status"
file: onboarding.yaml
- runFlow: # to run login flow only when device is on login screen
when:
visible: "Profile password"
file: login.yaml
+5
View File
@@ -0,0 +1,5 @@
appId: im.status.ethereum.debug
---
- tapOn: "password-input"
- inputText: "password123" # update your account password here
- tapOn: login-button
+15
View File
@@ -0,0 +1,15 @@
appId: im.status.ethereum.debug
---
- tapOn: "Im new to Status"
- tapOn: "small-option-card"
- tapOn: "Your name"
- inputText: "DeviceA"
- tapOn: "submit-create-profile-button"
- inputText: "password123"
- tapOn: "Repeat password"
- inputText: "password123"
- tapOn: "disclaimer-touchable-opacity"
- tapOn: "Confirm password"
- tapOn: "skip-identifiers"
- tapOn: "enable-notifications-later-button"
- tapOn: "welcome-button"
+1
View File
@@ -97,4 +97,5 @@ in {
patchMavenSources = callPackage ./pkgs/patch-maven-srcs { };
goMavenResolver = callPackage ./pkgs/go-maven-resolver { };
xcbeautify = callPackage ./pkgs/xcbeautify { };
idb-companion = callPackage ./pkgs/idb-companion { };
}
+29
View File
@@ -0,0 +1,29 @@
{ stdenv, fetchurl, lib }:
stdenv.mkDerivation rec {
pname = "idb-companion";
version = "1.1.8";
src = fetchurl {
url = "https://github.com/facebook/idb/releases/download/v${version}/idb-companion.universal.tar.gz";
sha256 = "sha256-O3LMappbGiKhiCBahAkNOilDR6hGGA79dVzxo8hI4+c=";
};
buildInputs = [ ];
unpackPhase = ''
tar -xzf $src
'';
installPhase = ''
mkdir -p $out/bin
cp -r ./* $out/bin/
'';
meta = with lib; {
description = "A powerful command line tool for automating iOS simulators and devices";
homepage = "https://github.com/facebook/idb";
license = licenses.mit;
platforms = platforms.darwin;
};
}
+2 -2
View File
@@ -23,9 +23,9 @@ in mkShell {
# build specific utilities
clojure maven watchman
# other nice to have stuff
yarn nodejs python310
yarn nodejs python310 maestro
] # and some special cases
++ lib.optionals stdenv.isDarwin ([ cocoapods clang tcl ] ++ appleSDKFrameworks)
++ lib.optionals stdenv.isDarwin ([ cocoapods clang tcl idb-companion ] ++ appleSDKFrameworks)
++ lib.optionals (!stdenv.isDarwin) [ gcc8 ]
);
Binary file not shown.

After

Width:  |  Height:  |  Size: 695 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 B

+3 -1
View File
@@ -45,6 +45,9 @@
;; To match the folder created by Nix build of JSBundle.
:output-dir "result"
:init-fn status-im.core/init
:build-hooks [(status-im.setup.build-hooks.worklets/transform-output)
(status-im.setup.build-hooks.worklets/optimize-start)
(status-im.setup.build-hooks.worklets/optimize-output)]
;; When false, the Shadow-CLJS watcher won't automatically refresh
;; the target files (a.k.a hot reload). When false, you can manually
;; reload by calling `shadow.cljs.devtools.api/watch-compile-all!`.
@@ -176,7 +179,6 @@
;; option setupFilesAfterEnv.
test-helpers.component-tests-preload
status-im.setup.schema-preload
quo.core-spec
status-im.core-spec]
:ns-regexp "component-spec$"
@@ -4,14 +4,19 @@
(def backgrounds #{:photo :blur})
(defn custom-color-type
;; Note: We hardcode the :light theme for the background-color and apply an overlay when necessary, such
;; as for dark themes and pressed states. This approach is taken because, for communities, we only have
;; one color available, which is the light theme version.
;; For more information, see the related issue: https://github.com/status-im/status-mobile/issues/16396
(defn- custom-color-type
[customization-color icon-only?]
{:icon-color colors/white-opa-70
:label-color colors/white
:background-color (colors/custom-color customization-color 50)
:border-radius (when icon-only? 24)})
{:icon-color colors/white-opa-70
:label-color colors/white
:background-color (colors/resolve-color customization-color :light)
:border-radius (when icon-only? 24)
:overlay-customization-color customization-color})
(defn grey-photo
(defn- grey-photo
[theme pressed?]
{:icon-color (colors/theme-colors colors/neutral-80-opa-40 colors/white-opa-70 theme)
:label-color (colors/theme-colors colors/neutral-100 colors/white theme)
@@ -24,7 +29,7 @@
theme))
:blur-type (if (= theme :light) :light :dark)})
(defn grey-blur
(defn- grey-blur
[theme pressed?]
{:icon-color (colors/theme-colors colors/neutral-80-opa-40 colors/white-opa-70 theme)
:label-color (colors/theme-colors colors/neutral-100 colors/white theme)
@@ -32,7 +37,7 @@
(colors/theme-colors colors/neutral-80-opa-10 colors/white-opa-10 theme)
(colors/theme-colors colors/neutral-80-opa-5 colors/white-opa-5 theme))})
(defn outline-blur
(defn- outline-blur
[theme pressed?]
{:icon-color (colors/theme-colors colors/neutral-80-opa-40 colors/white-opa-40 theme)
:label-color (colors/theme-colors colors/neutral-100 colors/white theme)
@@ -40,7 +45,7 @@
(colors/theme-colors colors/neutral-80-opa-20 colors/white-opa-20 theme)
(colors/theme-colors colors/neutral-80-opa-10 colors/white-opa-10 theme))})
(defn grey
(defn- grey
[theme pressed?]
{:icon-color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)
:label-color (colors/theme-colors colors/neutral-100 colors/white theme)
@@ -50,7 +55,7 @@
colors/neutral-90
theme))})
(defn dark-grey
(defn- dark-grey
[theme pressed?]
{:icon-color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)
:label-color (colors/theme-colors colors/neutral-100 colors/white theme)
@@ -58,7 +63,7 @@
(colors/theme-colors colors/neutral-30 colors/neutral-60 theme)
(colors/theme-colors colors/neutral-20 colors/neutral-90 theme))})
(defn outline
(defn- outline
[theme pressed?]
{:icon-color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)
:label-color (colors/theme-colors colors/neutral-100 colors/white theme)
@@ -66,29 +71,32 @@
(colors/theme-colors colors/neutral-40 colors/neutral-60 theme)
(colors/theme-colors colors/neutral-30 colors/neutral-70 theme))})
(defn ghost
(defn- ghost
[theme pressed?]
{:icon-color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)
:label-color (colors/theme-colors colors/neutral-100 colors/white theme)
:background-color (when pressed?
(colors/theme-colors colors/neutral-10 colors/neutral-80 theme))})
(defn black
(defn- black
[pressed?]
{:label-color colors/white
:background-color (if pressed? colors/neutral-80 colors/neutral-95)})
(defn get-values
[{:keys [customization-color theme type background pressed? icon-only?]}]
(cond
(= type :primary) (custom-color-type customization-color icon-only?)
(= type :positive) (custom-color-type customization-color icon-only?)
(= type :danger) (custom-color-type customization-color icon-only?)
(and (= :photo background) (= type :grey)) (grey-photo theme pressed?)
(and (= :blur background) (= type :grey)) (grey-blur theme pressed?)
(and (= :blur background) (= type :outline)) (outline-blur theme pressed?)
(= type :grey) (grey theme pressed?)
(= type :dark-grey) (dark-grey theme pressed?)
(= type :outline) (outline theme pressed?)
(= type :ghost) (ghost theme pressed?)
(= type :black) (black pressed?)))
(let [customization-color (get {:primary customization-color
:positive :success
:danger :danger}
type)]
(cond
(contains? #{:primary :positive :danger} type) (custom-color-type customization-color
icon-only?)
(and (= :photo background) (= type :grey)) (grey-photo theme pressed?)
(and (= :blur background) (= type :grey)) (grey-blur theme pressed?)
(and (= :blur background) (= type :outline)) (outline-blur theme pressed?)
(= type :grey) (grey theme pressed?)
(= type :dark-grey) (dark-grey theme pressed?)
(= type :outline) (outline theme pressed?)
(= type :ghost) (ghost theme pressed?)
(= type :black) (black pressed?))))
+4 -7
View File
@@ -37,13 +37,10 @@
pressed? on-press-in on-press-out allow-multiple-presses?]
:or {type :primary
size 40
customization-color (cond (= type :primary) :blue
(= type :positive) :success
(= type :danger) :danger
:else nil)}}
customization-color (if (= type :primary) :blue nil)}}
children]
(let [{:keys [icon-color background-color label-color border-color blur-type
blur-overlay-color border-radius]}
blur-overlay-color border-radius overlay-customization-color]}
(button-properties/get-values {:customization-color customization-color
:background background
:type type
@@ -79,9 +76,9 @@
:icon-left icon-left
:icon-right icon-right})
inner-style)}
(when customization-color
(when overlay-customization-color
[customization-colors/overlay
{:customization-color customization-color
{:customization-color overlay-customization-color
:theme theme
:pressed? (if pressed? pressed? @pressed-state?)}])
(when (= background :photo)
@@ -35,7 +35,7 @@
(when (and @ref (>= index 0))
(some-> ^js @ref
(.scrollToIndex #js
{:animated true
{:animated false
:index index
:viewPosition 0.5})))))
50)))
@@ -3,34 +3,60 @@
[quo.components.drawers.bottom-actions.view :as bottom-actions]
[test-helpers.component :as h]))
(defn- render
[component]
(h/render-with-theme-provider component :light))
(h/describe "bottom actions tests"
(h/test "default render with no description and single action button"
(h/render [bottom-actions/view {:button-one-label "Request to join"}])
(render [bottom-actions/view {:actions :one-action :button-one-label "Request to join"}])
(h/is-truthy (h/get-by-text "Request to join")))
(h/test "render with description"
(h/render [bottom-actions/view {:description "Sample description"}])
(h/is-truthy (h/get-by-text "Sample description")))
(h/test "render with description & 1 action"
(render [bottom-actions/view
{:description :bottom
:description-text "Sample description"
:actions :one-action
:button-one-label "Request to join"}])
(h/is-truthy (h/get-by-text "Sample description"))
(h/is-truthy (h/get-by-text "Request to join")))
(h/test "render with 2 actions"
(let [button-one "Button One"
button-two "Button Two"]
(h/render [bottom-actions/view
{:actions :2-actions
:button-one-label button-one
:button-one-props {:icon-left :i/arrow-left}
:button-two-label button-two}])
(render [bottom-actions/view
{:actions :two-actions
:button-one-label button-one
:button-one-props {:icon-left :i/arrow-left}
:button-two-label button-two}])
(h/is-truthy (h/get-by-text button-one))
(h/is-truthy (h/get-by-label-text :icon))
(h/is-truthy (h/get-by-text button-two))))
(h/test "render disabled button"
(h/render [bottom-actions/view
{:description "Sample description"
:button-one-props {:disabled? true}
:button-one-label "button"}])
(render [bottom-actions/view
{:description :bottom
:actions :one-action
:description-text "Sample description"
:button-one-props {:disabled? true}
:button-one-label "button"}])
(h/is-disabled (h/get-by-label-text :button-one)))
(h/test "sane defaults"
(h/render [bottom-actions/view {}])
(h/is-truthy (h/get-by-label-text :button-one))))
(h/test "render with error & 1 action"
(render [bottom-actions/view
{:description :top-error
:error-message "Sample error"
:actions :one-action
:button-one-label "Request to join"}])
(h/is-truthy (h/get-by-text "Sample error"))
(h/is-truthy (h/get-by-text "Request to join")))
(h/test "render with top description & 1 action"
(render [bottom-actions/view
{:description :top
:role :admin
:actions :one-action
:button-one-label "Request to join"}])
(h/is-truthy (h/get-by-text "Eligible to join as"))
(h/is-truthy (h/get-by-text "Admin"))
(h/is-truthy (h/get-by-text "Request to join"))))
@@ -2,34 +2,58 @@
(:require
[quo.foundations.colors :as colors]))
(defn- text-color
[scroll? blur? theme]
(cond
scroll? (if blur?
colors/white-70-blur
(colors/theme-colors colors/neutral-80-opa-70
colors/white-opa-70
theme))
blur? colors/white-opa-40
:else (colors/theme-colors colors/neutral-50
colors/neutral-40
theme)))
(defn container
[scroll? blur? theme]
{:background-color (when-not (or scroll? blur?)
(colors/theme-colors colors/white colors/neutral-95 theme))})
(def buttons-container
{:flex-direction :row
:justify-content :space-around
:padding-vertical 12
:gap 12
:padding-horizontal 20})
(def button-container
{:flex 1})
(def button-container-2-actions
(assoc button-container :margin-right 12))
(def description-top
{:flex-direction :row
:align-items :center
:gap 5
:padding-top 12
:padding-bottom 4
:justify-content :center})
(defn description
[theme scroll?]
{:color (colors/theme-colors
(if scroll?
(colors/custom-color colors/neutral-80 70)
colors/neutral-50)
(if scroll?
colors/white-opa-70
colors/neutral-40)
theme)
(defn description-top-text
[scroll? blur? theme]
{:color (text-color scroll? blur? theme)})
(defn description-bottom
[scroll? blur? theme]
{:color (text-color scroll? blur? theme)
:text-align :center
:padding-bottom 12
:padding-horizontal 40})
(def scroll
{:margin-top 21
:margin-horizontal 120
:margin-bottom 8
:width 134
:height 5})
(def error-message
{:flex-direction :row
:gap 4
:justify-content :center
:align-items :center
:padding-top 15
:padding-horizontal 20
:padding-bottom 7})
@@ -2,55 +2,96 @@
(:require
[quo.components.buttons.button.view :as button]
[quo.components.drawers.bottom-actions.style :as style]
[quo.components.icon :as icon]
[quo.components.markdown.text :as text]
[quo.components.tags.context-tag.view :as context-tag]
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]))
[react-native.core :as rn]
[schema.core :as schema]
[utils.i18n :as i18n]))
(def default-props
{:button-one-type :primary
:button-two-type :grey
:customization-color :blue})
(def ?schema
[:=>
[:catn
[:props
[:map {:closed true}
[:actions [:maybe [:enum :one-action :two-actions]]]
[:description {:optional true} [:maybe [:enum :top :bottom :top-error]]]
[:description-text {:optional true} [:maybe :string]]
[:error-message {:optional true} [:maybe :string]]
[:role {:optional true} [:maybe [:enum :admin :member :token-master :owner]]]
[:button-one-label {:optional true} [:maybe :string]]
[:button-two-label {:optional true} [:maybe :string]]
[:button-one-props {:optional true} [:maybe :map]]
[:button-two-props {:optional true} [:maybe :map]]
[:theme :schema.common/theme]
[:scroll? {:optional true} [:maybe :boolean]]
[:blur? {:optional true} [:maybe :boolean]]
[:container-style {:optional true} [:maybe :map]]]]]
:any])
(def ^:private role-icon
{:admin :i/gavel
:member :i/members
:token-master :i/token-master
:owner :i/crown})
(defn- view-internal
"Options:
[{:keys [actions description description-text error-message role button-one-label button-two-label
blur? button-one-props button-two-props theme scroll? container-style]}]
[rn/view
{:style (merge (style/container scroll? blur? theme) container-style)}
(when (= description :top-error)
[rn/view {:style style/error-message}
[icon/icon
:i/alert
{:color (colors/theme-colors colors/danger-50 colors/danger-60 theme)
:size 16}]
[text/text
{:size :paragraph-2
:style {:color (colors/theme-colors colors/danger-50 colors/danger-60 theme)}}
error-message]])
:actions - keyword (default nil) - :1-action/:2-actions
:description - string (default nil) - Description to display below the title
:button-one-label - string (default nil) - Label for the first button
:button-two-label - string (default nil) - Label for the second button
:button-one-props - map with props for button one
:button-two-props - map with props for button two
:theme - :light/:dark
:scroll? - bool (default false) - Whether the iOS Home Indicator should be rendered"
[props]
(let [{:keys [actions description button-one-label button-two-label
button-one-props button-two-props theme scroll? customization-color container-style]}
(merge default-props props)]
[rn/view {:style container-style}
[rn/view {:style style/buttons-container}
(when (= actions :2-actions)
[button/button
(merge
{:size 40
:background (when scroll? :blur)
:container-style style/button-container-2-actions
:theme theme
:accessibility-label :button-two}
button-two-props)
button-two-label])
(when (= description :top)
[rn/view
{:style style/description-top}
[text/text
{:size :paragraph-2
:style (style/description-top-text scroll? blur? theme)}
(i18n/label :t/eligible-to-join-as)]
[context-tag/view
{:type :icon
:size 24
:icon (role role-icon)
:blur? blur?
:context (i18n/label (keyword "t" role))}]])
[rn/view {:style style/buttons-container}
(when (= actions :two-actions)
[button/button
(merge
{:size 40
:background (when (or blur? scroll?) :blur)
:container-style style/button-container
:background (when scroll? :blur)
:theme theme
:accessibility-label :button-one
:customization-color customization-color}
button-one-props)
button-one-label]]
(when description
[text/text
{:size :paragraph-2
:style (style/description theme scroll?)} description])]))
:accessibility-label :button-two}
button-two-props)
button-two-label])
[button/button
(merge
{:size 40
:container-style style/button-container
:background (when (or blur? scroll?) :blur)
:theme theme
:accessibility-label :button-one}
button-one-props)
button-one-label]]
(when (= description :bottom)
[text/text
{:size :paragraph-2
:style (style/description-bottom scroll? blur? theme)} description-text])])
(def view (quo.theme/with-theme view-internal))
(def view
(quo.theme/with-theme
(schema/instrument #'view-internal ?schema)))
@@ -3,97 +3,110 @@
[quo.core :as quo]
[test-helpers.component :as h]))
(def ^:private theme :light)
(h/describe "drawer top tests"
(h/test "component renders in default type"
(h/render [quo/drawer-top
{:title "Title"
:type :default}])
(h/render-with-theme-provider [quo/drawer-top
{:title "Title"
:type :default}]
theme)
(h/is-truthy (h/get-by-text "Title")))
(h/test "component renders in default + description type"
(h/render [quo/drawer-top
{:title "Title"
:type :default
:description "Description"}])
(h/render-with-theme-provider [quo/drawer-top
{:title "Title"
:type :default
:description "Description"}]
theme)
(h/is-truthy (h/get-by-text "Title"))
(h/is-truthy (h/get-by-text "Description")))
(h/test "component renders in info type"
(h/render [quo/drawer-top
{:title "Title"
:type :info}])
(h/render-with-theme-provider [quo/drawer-top
{:title "Title"
:type :info}]
theme)
(h/is-truthy (h/get-by-text "Title"))
(h/is-truthy (h/get-by-label-text :info-icon)))
(h/test "component renders in info + description type"
(h/render [quo/drawer-top
{:title "Title"
:description "Description"
:type :info}])
(h/render-with-theme-provider [quo/drawer-top
{:title "Title"
:description "Description"
:type :info}]
theme)
(h/is-truthy (h/get-by-text "Title"))
(h/is-truthy (h/get-by-text "Description"))
(h/is-truthy (h/get-by-label-text :info-icon)))
(h/test "component renders in context-tag type"
(h/render [quo/drawer-top
{:title "Title"
:type :context-tag
:community-name "Coinbase"}])
(h/render-with-theme-provider [quo/drawer-top
{:title "Title"
:type :context-tag
:community-name "Coinbase"}]
theme)
(h/is-truthy (h/get-by-text "Title"))
(h/is-truthy (h/get-by-label-text :context-tag-wrapper)))
(h/test "component renders in context-tag + button type"
(h/render [quo/drawer-top
{:title "Title"
:type :context-tag
:button-icon :i/placeholder
:community-name "Coinbase"}])
(h/render-with-theme-provider [quo/drawer-top
{:title "Title"
:type :context-tag
:button-icon :i/placeholder
:community-name "Coinbase"}]
theme)
(h/is-truthy (h/get-by-text "Title"))
(h/is-truthy (h/get-by-label-text :button-icon))
(h/is-truthy (h/get-by-label-text :context-tag-wrapper)))
(h/test "component renders in account type"
(h/render [quo/drawer-top
{:title "Title"
:type :account
:account-avatar-emoji "🍿"
:networks [{:name :ethereum :short-name "eth"}]
:description "0x62b...0a5"
:customization-color :purple}])
(h/render-with-theme-provider [quo/drawer-top
{:title "Title"
:type :account
:account-avatar-emoji "🍿"
:networks [{:name :ethereum :short-name "eth"}]
:description "0x62b...0a5"
:customization-color :purple}]
theme)
(h/is-truthy (h/get-by-text "Title"))
(h/is-truthy (h/get-by-text "0x62b...0a5"))
(h/is-truthy (h/get-by-label-text :account-avatar)))
(h/test "component renders in keypair type when keycard? is false"
(h/render [quo/drawer-top
{:title "Title"
:keycard? false
:icon-avatar :i/placeholder
:type :keypair}])
(h/render-with-theme-provider [quo/drawer-top
{:title "Title"
:keycard? false
:icon-avatar :i/placeholder
:type :keypair}]
theme)
(h/is-truthy (h/get-by-text "Title"))
(-> (h/expect (h/get-by-translation-text :t/on-device))
(.toBeTruthy)))
(h/test "component renders in keypair type when keycard? is true"
(h/render [quo/drawer-top
{:title "Title"
:keycard? true
:icon-avatar :i/placeholder
:type :keypair}])
(h/render-with-theme-provider [quo/drawer-top
{:title "Title"
:keycard? true
:icon-avatar :i/placeholder
:type :keypair}]
theme)
(h/is-truthy (h/get-by-text "Title"))
(-> (h/expect (h/get-by-translation-text :t/on-keycard))
(.toBeTruthy)))
(h/test "component renders in default-keypair type"
(h/render [quo/drawer-top
{:title "Title"
:description "0x62b...0a5"
:type :default-keypair}])
(h/render-with-theme-provider [quo/drawer-top
{:title "Title"
:description "0x62b...0a5"
:type :default-keypair}]
theme)
(h/is-truthy (h/get-by-text "Title"))
(h/is-truthy (h/get-by-label-text :default-keypair-text)))
(h/test "component renders in label type"
(h/render [quo/drawer-top
{:label "label"
:type :label}])
(h/render-with-theme-provider [quo/drawer-top
{:label "label"
:type :label}]
theme)
(h/is-truthy (h/get-by-text "label"))))
@@ -61,24 +61,30 @@
value (reagent/atom "")
focused? (atom false)]
(fn [{:keys [scanned-value theme blur? on-change-text on-blur on-focus on-clear on-scan
on-detect-ens on-detect-address address-regex valid-ens-or-address?
container-style]}]
on-detect-ens on-detect-address on-detect-unclassified address-regex ens-regex
valid-ens-or-address? container-style]}]
(let [on-change (fn [text]
(when (not= @value text)
(let [address? (when address-regex
(boolean (re-matches address-regex text)))]
(boolean (re-matches address-regex text)))
ens? (when ens-regex
(boolean (re-matches ens-regex text)))]
(if (> (count text) 0)
(reset! status :typing)
(reset! status :active))
(reset! value text)
(when on-change-text
(on-change-text text))
(when (and on-detect-ens (> (count text) 0))
(when (and on-detect-ens ens?)
(reset! status :loading)
(on-detect-ens text #(reset! status :typing)))
(when (and address? on-detect-address)
(reset! status :loading)
(on-detect-address text)))))
(on-detect-address text))
(when (and (not address?)
(not ens?)
on-detect-unclassified)
(on-detect-unclassified text)))))
on-paste (fn []
(clipboard/get-string
(fn [clipboard]
@@ -4,79 +4,83 @@
[quo.foundations.colors :as colors]
[test-helpers.component :as h]))
(def ^:private theme :light)
(h/describe "List items: account"
(h/test "default render'"
(h/render [account/view])
(h/render-with-theme-provider [account/view] theme)
(h/is-truthy (h/query-by-label-text :container)))
(h/test "on-press-in changes state to :pressed"
(h/render [account/view])
(h/render-with-theme-provider [account/view] theme)
(h/fire-event :on-press-in (h/get-by-label-text :container))
(h/wait-for #(h/has-style (h/query-by-label-text :container)
{:backgroundColor (colors/resolve-color :blue :light 5)})))
(h/test "on-press-in changes state to :pressed with blur? enabled"
(h/render [account/view {:blur? true}])
(h/render-with-theme-provider [account/view {:blur? true}] theme)
(h/fire-event :on-press-in (h/get-by-label-text :container))
(h/wait-for #(h/has-style (h/query-by-label-text :container)
{:backgroundColor colors/white-opa-5})))
(h/test "render with state :active"
(h/render [account/view {:state :active}])
(h/render-with-theme-provider [account/view {:state :active}] theme)
(h/has-style (h/query-by-label-text :container)
{:backgroundColor (colors/resolve-color :blue :light 10)}))
(h/test "render with state :active and blur? enabled"
(h/render [account/view
{:blur? true
:state :active}])
(h/render-with-theme-provider [account/view
{:blur? true
:state :active}]
theme)
(h/has-style (h/query-by-label-text :container)
{:backgroundColor colors/white-opa-10}))
(h/test "render with state :selected"
(h/render [account/view {:state :selected}])
(h/render-with-theme-provider [account/view {:state :selected}] theme)
(h/is-truthy (h/query-by-label-text :check-icon)))
(h/test "calls on-press"
(let [on-press (h/mock-fn)]
(h/render [account/view {:on-press on-press}])
(h/render-with-theme-provider [account/view {:on-press on-press}] theme)
(h/fire-event :on-press (h/get-by-label-text :container))
(h/was-called on-press)))
(h/test "renders token props if type :tag"
(h/render [account/view {:type :tag}])
(h/render-with-theme-provider [account/view {:type :tag}] theme)
(h/is-truthy (h/query-by-label-text :tag-container)))
(h/test "renders keycard icon if title-icon is present"
(h/render [account/view {:title-icon :i/placeholder}])
(h/render-with-theme-provider [account/view {:title-icon :i/placeholder}] theme)
(h/is-truthy (h/query-by-label-text :title-icon)))
(h/test "doesn't render keycard icon if title-icon is missing"
(h/render [account/view])
(h/render-with-theme-provider [account/view] theme)
(h/is-falsy (h/query-by-label-text :title-icon)))
(h/test "renders balance container but not arrow icon if type :balance-neutral"
(h/render [account/view {:type :balance-neutral}])
(h/render-with-theme-provider [account/view {:type :balance-neutral}] theme)
(h/is-truthy (h/query-by-label-text :balance-container))
(h/is-falsy (h/query-by-label-text :arrow-icon)))
(h/test "renders balance container and negative arrow icon if type :balance-negative"
(h/render [account/view {:type :balance-negative}])
(h/render-with-theme-provider [account/view {:type :balance-negative}] theme)
(h/is-truthy (h/query-by-label-text :balance-container))
(h/is-truthy (h/query-by-label-text :icon-negative))
(h/is-falsy (h/query-by-label-text :icon-positive)))
(h/test "renders balance container and positive arrow icon if type :balance-positive"
(h/render [account/view {:type :balance-positive}])
(h/render-with-theme-provider [account/view {:type :balance-positive}] theme)
(h/is-truthy (h/query-by-label-text :balance-container))
(h/is-falsy (h/query-by-label-text :icon-negative))
(h/is-truthy (h/query-by-label-text :icon-positive)))
(h/test "renders options button if type :action"
(let [on-options-press (h/mock-fn)]
(h/render [account/view
{:type :action
:on-options-press on-options-press}])
(h/render-with-theme-provider [account/view
{:type :action
:on-options-press on-options-press}]
theme)
(h/is-truthy (h/query-by-label-text :options-button))
(h/fire-event :on-press (h/get-by-label-text :options-button))
(h/was-called on-options-press))))
@@ -9,8 +9,10 @@
[utils.i18n :as i18n]))
(defn- view-internal
[{:keys [state theme number word] :as props}]
[rn/view {:style (style/container props)}
[{:keys [state theme number word on-press] :as props}]
[rn/pressable
{:style (style/container props)
:on-press on-press}
(if (or (= state :empty) (= state :disabled))
[rn/view
{:style (style/num-container props)
@@ -24,9 +24,7 @@
{:background-color (colors/theme-colors colors/neutral-80-opa-70 colors/white-opa-70 theme)
:flex-direction :row
:justify-content :space-between
:padding-vertical 8
:padding-left 10
:padding-right 8
:padding 8
:border-radius 12})
(defn title
@@ -47,8 +45,13 @@
theme))
:container-style {:width 20 :height 20}})
(def left-side-container {:padding 2})
(def right-side-container {:padding 4 :flex 1})
(def left-side-container
{:padding 2
:padding-top 3})
(def right-side-container
{:padding 4
:flex 1})
(defn action-container
[theme]
@@ -45,7 +45,6 @@
:blur-radius 10
:blur-type :transparent
:overlay-color :transparent}]
[rn/view {:style (style/content-container theme)}
[rn/view {:style style/left-side-container}
left]
@@ -77,16 +76,19 @@
:or {type :neutral icon :i/placeholder}}]
(let [context-theme (or theme (quo.theme/get-theme))
icon-name (case type
:positive :i/correct
:negative :i/incorrect
:positive (if (= theme :light)
:i/correct
:i/correct-dark)
:negative (if (= theme :light)
:i/incorrect
:i/incorrect-dark)
:neutral icon)]
[quo.theme/provider {:theme context-theme}
[toast-container
{:left (cond user
[user-avatar/user-avatar user]
icon-name
[icon/icon icon-name (style/icon type context-theme)]
)
[icon/icon icon-name (style/icon type context-theme)])
:title title
:text text
:right (if undo-duration
@@ -15,7 +15,7 @@
(defn- view-internal
[]
(let [pressed? (reagent/atom false)]
(fn [{:keys [disabled? theme blur? on-press type]} label]
(fn [{:keys [disabled? theme blur? on-press on-long-press type]} label]
(let [label-color (style/get-label-color disabled? theme blur?)
background-color (style/toggle-background-color @pressed? blur? theme)]
[rn/pressable
@@ -24,6 +24,9 @@
:on-press (fn []
(when on-press
(on-press label)))
:on-long-press (fn []
(when (fn? on-long-press)
(on-long-press label)))
:allow-multiple-presses? true
:on-press-in #(reset! pressed? true)
:on-press-out #(reset! pressed? false)
@@ -6,18 +6,19 @@
[react-native.core :as rn]))
(defn keyboard-item
[{:keys [item type disabled? on-press blur? theme]}]
[{:keys [item type disabled? on-press on-long-press blur? theme]}]
[keyboard-key/view
{:disabled? disabled?
:on-press on-press
:blur? blur?
:theme theme
:type type}
{:disabled? disabled?
:on-press on-press
:on-long-press on-long-press
:blur? blur?
:theme theme
:type type}
item])
(defn- view-internal
[]
(fn [{:keys [disabled? theme blur? left-action delete-key? on-press on-delete
(fn [{:keys [disabled? theme blur? left-action delete-key? on-press on-delete on-long-press-delete
container-style]
:or {left-action :none}}]
[rn/view
@@ -62,12 +63,13 @@
:theme theme}]
(if delete-key?
[keyboard-item
{:item :i/backspace
:type :key
:disabled? disabled?
:on-press on-delete
:blur? blur?
:theme theme}]
{:item :i/backspace
:type :key
:disabled? disabled?
:on-press on-delete
:on-long-press on-long-press-delete
:blur? blur?
:theme theme}]
[keyboard-item])]]))
(def view (quo.theme/with-theme view-internal))
@@ -121,7 +121,7 @@
{:accessibility-label :data-item
:disabled (not icon-right?)
:on-press on-press
:style (merge container-style (style/container size card? blur? theme))}
:style (merge (style/container size card? blur? theme) container-style)}
[left-side props]
(when (and (= :default status) (not= :small size))
[right-side
@@ -2,9 +2,64 @@
(:require [quo.components.share.share-qr-code.view :as share-qr-code]
[test-helpers.component :as h]))
(def qr-label "Text shown below QR")
(def default-props
{:qr-data qr-label
:qr-image-uri "test-uri"
:full-name "Default name"})
(def profile-props
{:type :profile
:profile-picture 123})
(def wallet-props {:networks '(:ethereum)})
(def text-press-event
{:test-name "Text pressed"
:accessibility-label :share-qr-code-info-text
:event-name :press
:callback-prop-key :on-text-press})
(def text-long-press-event
{:test-name "Text long pressed"
:accessibility-label :share-qr-code-info-text
:event-name :long-press
:callback-prop-key :on-text-long-press})
(def share-press-event
{:test-name "Share button"
:accessibility-label :link-to-profile
:event-name :press
:callback-prop-key :on-share-press})
(def multichain-press-event
{:test-name "Multichain tab pressed"
:accessibility-label :share-qr-code-multichain-tab
:event-name :press
:callback-prop-key :on-multichain-press})
(def legacy-press-event
{:test-name "Legacy tab pressed"
:accessibility-label :share-qr-code-legacy-tab
:event-name :press
:callback-prop-key :on-legacy-press})
(def settings-press-event
{:test-name "Settings pressed"
:accessibility-label :share-qr-code-settings
:event-name :press
:callback-prop-key :on-settings-press})
(defn render-share-qr-code
[{share-qr-type :type :as props}]
(let [component-rendered (h/render [share-qr-code/view {:type share-qr-type}])
[props]
;; NOTE: rendering the profile type first, so that the re-render is triggered.
;; Passing a :key breaks it for some reason.
(let [component-rendered (h/render [share-qr-code/view
(merge
default-props
profile-props
{:qr-data "initial-render"})])
rerender-fn (h/get-rerender-fn component-rendered)
share-qr-code (h/get-by-label-text :share-qr-code)]
;; Fires on-layout since it's needed to render the content
@@ -13,23 +68,52 @@
(h/describe "Share QR Code component"
(h/describe "Renders share-qr-code component in all types"
(let [qr-label "Text shown below QR"]
(h/test "Profile"
(render-share-qr-code {:type :profile
:qr-data qr-label})
(h/is-truthy (h/get-by-text qr-label)))
(h/test "Profile"
(render-share-qr-code (merge default-props
profile-props))
(h/is-truthy (h/get-by-text qr-label)))
(h/test "Wallet Legacy"
(render-share-qr-code {:type :wallet-legacy
:qr-data qr-label
:emoji "👻"})
(h/is-truthy (h/get-by-text qr-label)))
(h/test "Wallet Legacy"
(render-share-qr-code (merge default-props
wallet-props
{:type :wallet
:address :legacy}))
(h/is-truthy (h/get-by-text qr-label)))
(h/test "Wallet Multichain"
(render-share-qr-code {:type :wallet-multichain
:qr-data qr-label
:emoji "👻"})
(h/is-truthy (h/get-by-text qr-label)))))
(h/test "Wallet multichain"
(render-share-qr-code (merge default-props
wallet-props
{:type :wallet
:address :multichain}))
(h/is-truthy (h/get-by-text qr-label)))
(h/test "Saved address legacy"
(render-share-qr-code (merge default-props
wallet-props
{:type :saved-address
:address :legacy}))
(h/is-truthy (h/get-by-text qr-label)))
(h/test "Saved address multichain"
(render-share-qr-code (merge default-props
wallet-props
{:type :saved-address
:address :multichain}))
(h/is-truthy (h/get-by-text qr-label)))
(h/test "Watched address legacy"
(render-share-qr-code (merge default-props
wallet-props
{:type :watched-address
:address :legacy}))
(h/is-truthy (h/get-by-text qr-label)))
(h/test "Watched address multichain"
(render-share-qr-code (merge default-props
wallet-props
{:type :watched-address
:address :multichain}))
(h/is-truthy (h/get-by-text qr-label))))
(h/describe "Fires all events for all types"
(letfn [(test-fire-events [props test-seq]
@@ -44,68 +128,86 @@
(h/describe "Profile"
(test-fire-events
{:type :profile}
[{:test-name "Text pressed"
:accessibility-label :share-qr-code-info-text
:event-name :press
:callback-prop-key :on-text-press}
{:test-name "Text long pressed"
:accessibility-label :share-qr-code-info-text
:event-name :long-press
:callback-prop-key :on-text-long-press}
{:test-name "Share button"
:accessibility-label :link-to-profile
:event-name :press
:callback-prop-key :on-share-press}]))
(merge default-props
profile-props)
[text-press-event
text-long-press-event
share-press-event]))
(h/describe "Wallet Legacy"
(test-fire-events
{:type :wallet-legacy :emoji "👽"}
[{:test-name "Text pressed"
:accessibility-label :share-qr-code-info-text
:event-name :press
:callback-prop-key :on-text-press}
{:test-name "Text long pressed"
:accessibility-label :share-qr-code-info-text
:event-name :long-press
:callback-prop-key :on-text-long-press}
{:test-name "Share button pressed"
:accessibility-label :link-to-profile
:event-name :press
:callback-prop-key :on-share-press}
{:test-name "Legacy tab pressed"
:accessibility-label :share-qr-code-legacy-tab
:event-name :press
:callback-prop-key :on-legacy-press}
{:test-name "Multichain tab pressed"
:accessibility-label :share-qr-code-multichain-tab
:event-name :press
:callback-prop-key :on-multichain-press}]))
(merge default-props
wallet-props
{:type :wallet
:address :legacy
:emoji "👻"})
[text-press-event
text-long-press-event
share-press-event
multichain-press-event
legacy-press-event]))
(h/describe "Wallet Multichain"
(test-fire-events
{:type :wallet-multichain :emoji "👽"}
[{:test-name "Text pressed"
:accessibility-label :share-qr-code-info-text
:event-name :press
:callback-prop-key :on-text-press}
{:test-name "Text long pressed"
:accessibility-label :share-qr-code-info-text
:event-name :long-press
:callback-prop-key :on-text-long-press}
{:test-name "Share button pressed"
:accessibility-label :link-to-profile
:event-name :press
:callback-prop-key :on-share-press}
{:test-name "Legacy tab pressed"
:accessibility-label :share-qr-code-legacy-tab
:event-name :press
:callback-prop-key :on-legacy-press}
{:test-name "Multichain tab pressed"
:accessibility-label :share-qr-code-multichain-tab
:event-name :press
:callback-prop-key :on-multichain-press}
{:test-name "Settings pressed"
:accessibility-label :share-qr-code-settings
:event-name :press
:callback-prop-key :on-settings-press}])))))
(merge default-props
wallet-props
{:type :wallet
:address :multichain
:emoji "👻"})
[text-press-event
text-long-press-event
share-press-event
legacy-press-event
multichain-press-event
settings-press-event]))
(h/describe "Saved Address Legacy"
(test-fire-events
(merge default-props
wallet-props
{:type :saved-address
:address :legacy})
[text-press-event
text-long-press-event
share-press-event
legacy-press-event
multichain-press-event]))
(h/describe "Saved Address Multichain"
(test-fire-events
(merge default-props
wallet-props
{:type :saved-address :address :multichain})
[text-press-event
text-long-press-event
share-press-event
legacy-press-event
multichain-press-event
settings-press-event]))
(h/describe "Watched Address Legacy"
(test-fire-events
(merge default-props
wallet-props
{:type :watched-address
:address :legacy
:emoji "👽"})
[text-press-event
text-long-press-event
share-press-event
legacy-press-event
multichain-press-event]))
(h/describe "Watched Address Multichain"
(test-fire-events
(merge default-props
wallet-props
{:type :watched-address
:address :multichain
:emoji "👽"})
[text-press-event
text-long-press-event
share-press-event
legacy-press-event
multichain-press-event
settings-press-event])))))
@@ -0,0 +1,68 @@
(ns quo.components.share.share-qr-code.schema
(:require
[quo.foundations.resources :as resources]))
(defn- valid-network?
[network]
(-> network resources/get-network boolean))
(def ?base
[:map
[:type [:enum :profile :wallet :saved-address :watched-address]]
[:full-name :string]
[:qr-image-uri :string]
[:qr-data :string]
[:on-text-press {:optional true} [:maybe fn?]]
[:on-text-long-press {:optional true} [:maybe fn?]]
[:on-share-press {:optional true} [:maybe fn?]]
[:customization-color {:optional true} [:maybe :schema.common/customization-color]]
[:unblur-on-android? {:optional true} [:maybe :boolean]]])
(def ?emoji :string)
(def ?profile
[:map
[:type [:= :profile]]
[:profile-picture :schema.common/image-source]])
(def ?wallet
[:map
[:type [:= :wallet]]
[:emoji {:optional true} [:maybe ?emoji]]])
(def ?address-multichain
[:map
[:address [:= :multichain]]
[:on-settings-press {:optional true} fn?]])
(def ?address-base
[:merge
[:map
[:networks [:sequential [:fn valid-network?]]]
[:on-legacy-press {:optional true} [:maybe fn?]]
[:on-multichain-press {:optional true} [:maybe fn?]]
[:address [:enum :legacy :multichain]]]
[:multi {:dispatch :address}
[:multichain ?address-multichain]]])
(def ?saved-address
[:map
[:type [:= :saved-address]]
[:on-settings-press {:optional true} fn?]])
(def ?watched-address
[:map
[:type [:= :watched-address]]
[:emoji {:optional true} [:maybe ?emoji]]])
(def ?schema
[:=>
[:catn
[:props
[:multi {:dispatch :type}
[:profile [:merge ?base ?profile]]
[:wallet [:merge ?base ?address-base ?wallet]]
[:saved-address [:merge ?base ?address-base ?saved-address]]
[:watched-address [:merge ?base ?address-base ?watched-address]]]]]
:any])
@@ -106,3 +106,6 @@
{:color (-> network-short-name
(get-network-full-name :unknown)
(colors/resolve-color nil))})
(def watched-account-icon
{:margin-left 4})
@@ -3,19 +3,25 @@
[clojure.string :as string]
[oops.core :as oops]
[quo.components.avatars.account-avatar.view :as account-avatar]
[quo.components.avatars.user-avatar.view :as user-avatar]
[quo.components.avatars.wallet-user-avatar.view :as wallet-user-avatar]
[quo.components.buttons.button.view :as button]
[quo.components.gradient.gradient-cover.view :as gradient-cover]
[quo.components.icon :as icons]
[quo.components.markdown.text :as text]
[quo.components.share.qr-code.view :as qr-code]
[quo.components.share.share-qr-code.schema :as component-schema]
[quo.components.share.share-qr-code.style :as style]
[quo.components.tabs.tab.view :as tab]
[quo.foundations.colors :as colors]
[quo.theme]
[react-native.core :as rn]
[reagent.core :as reagent]
[schema.core :as schema]
[utils.i18n :as i18n]))
(defn- header
[{:keys [share-qr-type on-legacy-press on-multichain-press]}]
[{:keys [on-legacy-press on-multichain-press address]}]
[rn/view {:style style/header-container}
[tab/view
{:accessibility-label :share-qr-code-legacy-tab
@@ -23,7 +29,7 @@
:active-item-container-style style/header-tab-active
:item-container-style style/header-tab-inactive
:size 24
:active (= :wallet-legacy share-qr-type)
:active (= :legacy address)
:on-press on-legacy-press}
(i18n/label :t/legacy)]
[rn/view {:style style/space-between-tabs}]
@@ -33,7 +39,7 @@
:active-item-container-style style/header-tab-active
:item-container-style style/header-tab-inactive
:size 24
:active (= :wallet-multichain share-qr-type)
:active (= :multichain address)
:on-press on-multichain-press}
(i18n/label :t/multichain)]])
@@ -121,77 +127,69 @@
:on-press on-settings-press}
:i/advanced]])
(defn- header-icon
[{:keys [share-qr-type customization-color emoji profile-picture full-name]}]
(case share-qr-type
:profile [user-avatar/user-avatar
{:size :small
:status-indicator? false
:profile-picture profile-picture
:customization-color customization-color}]
(:wallet :watched-address) [account-avatar/view
{:customization-color customization-color
:emoji emoji
:size 32}]
:saved-address [wallet-user-avatar/wallet-user-avatar
{:size :size-32
:customization-color customization-color
:full-name full-name}]
nil))
(defn- share-qr-code
[{:keys [share-qr-type qr-image-uri component-width customization-color full-name
profile-picture emoji on-share-press]
profile-picture emoji on-share-press address]
:as props}]
[:<>
[rn/view {:style style/gradient-bg}
[gradient-cover/view {:customization-color customization-color :height 463}]]
[rn/view {:style style/content-container}
[rn/view
{:style style/share-qr-container}
[rn/view
{:style style/share-qr-inner-container}
[account-avatar/view
{:customization-color customization-color
:emoji emoji
:size 32}]
[rn/view {:style style/share-qr-container}
[rn/view {:style style/share-qr-inner-container}
[header-icon props]
[text/text
{:size :heading-2
:weight :semi-bold
:style {:margin-left 8}} full-name]]
:style {:margin-left 8}} full-name]
(when (= share-qr-type :watched-address)
[icons/icon
:i/reveal
{:color colors/white-opa-40
:container-style style/watched-account-icon}])]
[share-button {:on-press on-share-press}]]
(when (#{:wallet-legacy :wallet-multichain} share-qr-type)
(when (not= share-qr-type :profile)
[header props])
[quo.theme/provider {:theme :light}
[qr-code/view
{:qr-image-uri qr-image-uri
:size (style/qr-code-size component-width)
:avatar (if (= share-qr-type :profile)
:profile
:wallet-account)
:avatar (case share-qr-type
:profile :profile
(:watched-address :wallet) :wallet-account
:saved-address :saved-address
nil)
:customization-color customization-color
:full-name full-name
:profile-picture profile-picture
:emoji emoji}]]
[rn/view {:style style/bottom-container}
(case share-qr-type
:profile [profile-bottom props]
:wallet-legacy [wallet-legacy-bottom props]
:wallet-multichain [wallet-multichain-bottom props]
nil)]]])
(if (= share-qr-type :profile)
[profile-bottom props]
(case address
:legacy [wallet-legacy-bottom props]
:multichain [wallet-multichain-bottom props]
nil))]]])
(defn- view-internal
"Receives the following properties:
- type: :profile | :wallet-legacy | :wallet-multichain
- qr-image-uri: Image source value.
- qr-data: Text to show below the QR code.
- on-text-press: Callback for the `qr-data` text.
- on-text-long-press: Callback for the `qr-data` text.
- on-share-press: Callback for the share button.
- customization-color: Custom color for the QR code component.
- unblur-on-android?: [Android only] disables blur for this component.
Depending on the `type`, different properties are accepted:
`:profile`
- full-name: User full name.
- profile-picture: map ({:source image-source}) or any image source.
`:wallet-legacy`
- emoji: Emoji in a string to show in the QR code.
- on-legacy-press: Callback for the legacy tab.
- on-multichain-press: Callback for the multichain tab.
`:wallet-multichain`
- networks: A vector of network names as keywords (`[:ethereum, :my-net, ...]`).
- on-settings-press: Callback for the settings button.
- emoji: Emoji in a string to show in the QR code.
- on-legacy-press: Callback for the legacy tab.
- on-multichain-press: Callback for the multichain tab.
WARNING on Android:
Sometimes while using a blur layer on top of another on Android, this component looks
bad because of the `blur/view`, so we can set `unblur-on-android? true` to fix it.
"
[props]
(reagent/with-let [component-width (reagent/atom nil)
container-component [rn/view {:background-color style/overlay-color}]]
@@ -207,5 +205,6 @@
(assoc :component-width @component-width)
(clojure.set/rename-keys {:type :share-qr-type}))]))]]))
(def view (quo.theme/with-theme view-internal))
(def view
(quo.theme/with-theme
(schema/instrument #'view-internal component-schema/?schema)))
@@ -0,0 +1,50 @@
(ns quo.components.tags.collectible-tag.style
(:require
[quo.foundations.colors :as colors]))
(defn container
[size options blur? theme]
(let [hold? (= options :hold)]
(merge {:background-color (if blur?
(colors/theme-colors colors/neutral-80-opa-5 colors/white-opa-5 theme)
(colors/theme-colors colors/neutral-10 colors/neutral-90 theme))
:flex-direction :row
:align-items :center
:padding-left 2
:border-width (if hold? 1 0)
:border-radius 0
:border-color (colors/resolve-color :success theme)}
(condp = size
:size-24 {:height (if hold? 26 24)
:padding-right 10
:border-radius 8}
:size-32 {:height (if hold? 34 32)
:padding-right 12
:border-radius 10}))))
(defn options-icon
[size]
(assoc
(condp = size
:size-24 {:right -8
:top -8}
:size-32 {:right -6
:top -6})
:position
:absolute))
(defn collectible-img
[size]
(condp = size
:size-24 {:width 20
:height 20
:margin-right 6
:border-radius 6}
:size-32 {:width 28
:height 28
:margin-right 8
:border-radius 8}))
(defn label
[theme]
{:color (colors/theme-colors colors/neutral-100 colors/white theme)})
@@ -0,0 +1,70 @@
(ns quo.components.tags.collectible-tag.view
(:require
[quo.components.icon :as icons]
[quo.components.markdown.text :as text]
[quo.components.tags.collectible-tag.style :as style]
[quo.theme]
[react-native.core :as rn]
[react-native.hole-view :as hole-view]
[schema.core :as schema]))
(def ?schema
[:=>
[:catn
[:props
[:map {:closed true}
[:options {:optional true} [:maybe [:enum false :add :hold]]]
[:size {:optional true} [:enum :size-24 :size-32]]
[:blur? {:optional true} :boolean]
[:theme :schema.common/theme]
[:collectible-img-src [:or :int :string]]
[:collectible-name :string]
[:collectible-id :string]
[:container-width :number]
[:on-layout {:optional true} [:maybe fn?]]]]]
:any])
(defn- view-internal
[]
(fn [{:keys [options size blur? theme collectible-img-src collectible-name collectible-id
container-width on-layout]
:or {size :size-24}}]
[rn/view
{:on-layout on-layout}
[hole-view/hole-view
{:holes (if options
[{:x (- container-width
(case size
:size-24 10
:size-32 12
nil))
:y (case size
:size-24 -6
:size-32 -4
nil)
:width 16
:height 16
:borderRadius 8}]
[])}
[rn/view {:style (style/container size options blur? theme)}
[rn/image {:style (style/collectible-img size) :source collectible-img-src}]
[text/text
{:size :paragraph-2
:weight :medium
:style (style/label theme)}
collectible-name]
[text/text
{:size :paragraph-2
:weight :medium
:margin-left 5
:style (style/label theme)}
collectible-id]]]
(when options
[rn/view {:style (style/options-icon size)}
[icons/icon (if (= options :hold) :i/hold :i/add-token)
{:size 20
:no-color true}]])]))
(def view
(quo.theme/with-theme
(schema/instrument #'view-internal ?schema)))
@@ -5,6 +5,7 @@
(def username "Alisher account")
(def empty-username "Account 1")
(def ^:private theme :light)
(defn get-test-data
[{:keys [type watch-only? empty-type? loading? no-metrics?]}]
@@ -21,54 +22,54 @@
(h/describe "Account_card tests"
(h/test "Renders Default"
(let [data (get-test-data {:type :default})]
(h/render [account-card/view data])
(h/render-with-theme-provider [account-card/view data] theme)
(h/is-truthy (h/get-by-text username))))
(h/test "Renders Watch-Only"
(let [data (get-test-data {:type :watch-only
:watch-only? true})]
(h/render [account-card/view data])
(h/render-with-theme-provider [account-card/view data] theme)
(h/is-truthy (h/get-by-text username))))
(h/test "Renders Add-Account"
(let [data {:type :add-account}]
(h/render [account-card/view data])
(h/render-with-theme-provider [account-card/view data] theme)
(h/is-truthy (h/get-by-label-text :add-account))))
(h/test "Renders Empty"
(let [data (get-test-data {:type :empty
:empty-type? true})]
(h/render [account-card/view data])
(h/render-with-theme-provider [account-card/view data] theme)
(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/render-with-theme-provider [account-card/view data] theme)
(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
:on-press on-press}]
(h/render [account-card/view data])
(h/render-with-theme-provider [account-card/view data] theme)
(h/fire-event :on-press (h/get-by-label-text :add-account))
(h/was-called on-press)))
(h/test "Renders component without metrics"
(let [data (get-test-data {:type :default
:no-metrics? true})]
(h/render [account-card/view data])
(h/render-with-theme-provider [account-card/view data] theme)
(h/is-falsy (h/query-by-label-text :metrics))))
(h/test "Renders loading state"
(let [data (get-test-data {:type :default
:loading? true})]
(h/render [account-card/view data])
(h/render-with-theme-provider [account-card/view data] theme)
(h/is-truthy (h/get-by-label-text :loading))))
(h/test "Renders loading state without metrics"
(let [data (get-test-data {:type :default
:no-metrics? true
:loading? true})]
(h/render [account-card/view data])
(h/render-with-theme-provider [account-card/view data] theme)
(h/is-falsy (h/query-by-label-text :metrics)))))
@@ -0,0 +1,33 @@
(ns quo.components.wallet.account-card.schema)
(def ^:private ?base
[:map
[:type {:optional true} [:enum :default :watch-only :add-account :empty :missing-keypair]]
[:customization-color {:optional true} [:maybe :schema.common/customization-color]]
[:theme :schema.common/theme]
[:metrics? {:optional true} [:maybe :boolean]]
[:on-press {:optional true} [:maybe fn?]]])
(def ^:private ?amount
[:map
[:amount {:optional true} [:maybe :string]]])
(def ^:private ?card
[:map
[:balance {:optional true} [:maybe :string]]
[:loading? {:optional true} [:maybe :boolean]]
[:name {:optional true} [:maybe :string]]
[:percentage-value {:optional true} [:maybe :string]]
[:emoji {:optional true} [:maybe :string]]])
(def ?schema
[:=>
[:catn
[:props
[:multi {:dispatch :type}
[:default [:merge ?base ?amount ?card]]
[:watch-only [:merge ?base ?amount ?card]]
[:missing-keypair [:merge ?base ?amount ?card]]
[:empty [:merge ?base ?card]]
[:add-account ?base]]]]
:any])
@@ -4,13 +4,15 @@
[quo.components.icon :as icon]
[quo.components.markdown.text :as text]
[quo.components.wallet.account-card.properties :as properties]
[quo.components.wallet.account-card.schema :as component-schema]
[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]))
[reagent.core :as reagent]
[schema.core :as schema]))
(defn- loading-view
[{:keys [customization-color type theme metrics?]}]
@@ -183,4 +185,6 @@
:add-account [add-account-view props]
nil))
(def view (quo.theme/with-theme view-internal))
(def view
(quo.theme/with-theme
(schema/instrument #'view-internal component-schema/?schema)))
@@ -3,92 +3,104 @@
[quo.core :as quo]
[test-helpers.component :as h]))
(def ^:private theme :light)
(h/describe "account origin tests"
(h/test "component renders"
(h/render [quo/account-origin
{:type :recovery-phrase
:stored :on-keycard
:derivation-path "m / 44 / 60 / 0 / 0 / 2"
:user-name "Test Name"}])
(h/render-with-theme-provider [quo/account-origin
{:type :recovery-phrase
:stored :on-keycard
:derivation-path "m / 44 / 60 / 0 / 0 / 2"
:user-name "Test Name"}]
theme)
(-> (h/expect (h/get-by-translation-text :t/origin))
(.toBeTruthy)))
(h/test "recovery phrase icon is visible when :type is :recovery-phrase"
(h/render [quo/account-origin
{:type :recovery-phrase
:stored :on-keycard
:derivation-path "m / 44 / 60 / 0 / 0 / 2"
:user-name "Test Name"}])
(h/render-with-theme-provider [quo/account-origin
{:type :recovery-phrase
:stored :on-keycard
:derivation-path "m / 44 / 60 / 0 / 0 / 2"
:user-name "Test Name"}]
theme)
(h/is-truthy (h/get-by-label-text :recovery-phrase-icon)))
(h/test "recovery phrase icon is visible when :type is :recovery-phrase"
(h/render [quo/account-origin
{:type :recovery-phrase
:stored :on-keycard
:derivation-path "m / 44 / 60 / 0 / 0 / 2"
:user-name "Test Name"}])
(h/render-with-theme-provider [quo/account-origin
{:type :recovery-phrase
:stored :on-keycard
:derivation-path "m / 44 / 60 / 0 / 0 / 2"
:user-name "Test Name"}]
theme)
(h/is-truthy (h/get-by-label-text :recovery-phrase-icon)))
(h/test "private-key-icon is visible when :type is :private-key"
(h/render [quo/account-origin
{:type :private-key
:stored :on-keycard
:derivation-path "m / 44 / 60 / 0 / 0 / 2"
:user-name "Test Name"}])
(h/render-with-theme-provider [quo/account-origin
{:type :private-key
:stored :on-keycard
:derivation-path "m / 44 / 60 / 0 / 0 / 2"
:user-name "Test Name"}]
theme)
(h/is-truthy (h/get-by-label-text :private-key-icon)))
(h/test "derivation-path-icon is visible when :type is :default-keypair"
(h/render [quo/account-origin
{:type :default-keypair
:stored :on-keycard
:derivation-path "m / 44 / 60 / 0 / 0 / 2"
:user-name "Test Name"}])
(h/render-with-theme-provider [quo/account-origin
{:type :default-keypair
:stored :on-keycard
:derivation-path "m / 44 / 60 / 0 / 0 / 2"
:user-name "Test Name"}]
theme)
(h/is-truthy (h/get-by-label-text :derivation-path-icon)))
(h/test "derivation-path-icon is visible when :type is :recovery-phrase"
(h/render [quo/account-origin
{:type :recovery-phrase
:stored :on-keycard
:derivation-path "m / 44 / 60 / 0 / 0 / 2"
:user-name "Test Name"}])
(h/render-with-theme-provider [quo/account-origin
{:type :recovery-phrase
:stored :on-keycard
:derivation-path "m / 44 / 60 / 0 / 0 / 2"
:user-name "Test Name"}]
theme)
(h/is-truthy (h/get-by-label-text :derivation-path-icon)))
(h/test "on-device text is visible when :stored is :on-device"
(h/render [quo/account-origin
{:type :recovery-phrase
:stored :on-device
:derivation-path "m / 44 / 60 / 0 / 0 / 2"
:user-name "Test Name"}])
(h/render-with-theme-provider [quo/account-origin
{:type :recovery-phrase
:stored :on-device
:derivation-path "m / 44 / 60 / 0 / 0 / 2"
:user-name "Test Name"}]
theme)
(-> (h/expect (h/get-by-translation-text :t/on-device))
(.toBeTruthy)))
(h/test "on-keycard text is visible when :stored is :on-keycard"
(h/render [quo/account-origin
{:type :recovery-phrase
:stored :on-keycard
:derivation-path "m / 44 / 60 / 0 / 0 / 2"
:user-name "Test Name"}])
(h/render-with-theme-provider [quo/account-origin
{:type :recovery-phrase
:stored :on-keycard
:derivation-path "m / 44 / 60 / 0 / 0 / 2"
:user-name "Test Name"}]
theme)
(-> (h/expect (h/get-by-translation-text :t/on-keycard))
(.toBeTruthy)))
(h/test "on-press is called when :type is :recovery-phrase"
(let [on-press (h/mock-fn)]
(h/render [quo/account-origin
{:type :recovery-phrase
:stored :on-keycard
:derivation-path "m / 44 / 60 / 0 / 0 / 2"
:user-name "Test Name"
:on-press on-press}])
(h/render-with-theme-provider [quo/account-origin
{:type :recovery-phrase
:stored :on-keycard
:derivation-path "m / 44 / 60 / 0 / 0 / 2"
:user-name "Test Name"
:on-press on-press}]
theme)
(h/fire-event :press (h/query-by-label-text :derivation-path-button))
(h/was-called on-press)))
(h/test "on-press is called when :type is :default-keypair"
(let [on-press (h/mock-fn)]
(h/render [quo/account-origin
{:type :default-keypair
:stored :on-keycard
:derivation-path "m / 44 / 60 / 0 / 0 / 2"
:user-name "Test Name"
:on-press on-press}])
(h/render-with-theme-provider [quo/account-origin
{:type :default-keypair
:stored :on-keycard
:derivation-path "m / 44 / 60 / 0 / 0 / 2"
:user-name "Test Name"
:on-press on-press}]
theme)
(h/fire-event :press (h/query-by-label-text :derivation-path-button))
(h/was-called on-press))))
@@ -0,0 +1,30 @@
(ns quo.components.wallet.account-origin.schema)
(def ^:private ?base
[:map
[:type {:optional true} [:enum :default-keypair :recovery-phrase :private-key]]
[:stored {:optional true} [:enum :on-device :on-keycard]]
[:theme :schema.common/theme]])
(def ^:private ?default-keypair
[:map
[:user-name {:optional true} [:maybe :string]]
[:profile-picture {:optional true} [:maybe [:or :schema.common/image-source :string]]]
[:derivation-path {:optional true} [:maybe :string]]
[:on-press {:optional true} [:maybe fn?]]
[:customization-color {:optional true} [:maybe :schema.common/customization-color]]])
(def ^:private ?recovery-phrase
[:map
[:derivation-path {:optional true} [:maybe :string]]
[:on-press {:optional true} [:maybe fn?]]])
(def ?schema
[:=>
[:catn
[:props
[:multi {:dispatch :type}
[:default-keypair [:merge ?base ?default-keypair]]
[:recovery-phrase [:merge ?base ?recovery-phrase]]
[:private-key ?base]]]]
:any])
@@ -3,10 +3,12 @@
[quo.components.avatars.user-avatar.view :as user-avatar]
[quo.components.icon :as icons]
[quo.components.markdown.text :as text]
[quo.components.wallet.account-origin.schema :as component-schema]
[quo.components.wallet.account-origin.style :as style]
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[schema.core :as schema]
[utils.i18n :as i18n]))
(defn- row-title
@@ -107,14 +109,5 @@
[card-view theme derivation-path secondary-color on-press])]))
(def view
"Create an account-origin UI component.
| key | values |
| ----------------------|------------------------------------------------|
| :type | :default-keypair :recovery-phrase :private-key
| :stored | :on-device :on-keycard
| :profile-picture | image source
| :customization-color | profile color
| :derivation-path | string
| :user-name | string
| :on-press | function"
(quo.theme/with-theme view-internal))
(quo.theme/with-theme
(schema/instrument #'view-internal component-schema/?schema)))
@@ -0,0 +1,20 @@
(ns quo.components.wallet.account-overview.schema)
(def ?schema
[:=>
[:catn
[:props
[:map
[:account-name {:optional true} [:maybe :string]]
[:currency-change {:optional true} [:maybe :string]]
[:current-value {:optional true} [:maybe :string]]
[:percentage-change {:optional true} [:maybe :string]]
[:time-frame-string {:optional true} [:maybe :string]]
[:time-frame-to-string {:optional true} [:maybe :string]]
[:state {:optional true} [:enum :default :loading]]
[:metrics {:optional true} [:enum :negative :positive]]
[:customization-color {:optional true} [:maybe :schema.common/customization-color]]
[:account {:optional true} [:enum :default :watched-address]]
[:time-frame {:optional true}
[:enum :one-week :one-month :three-months :one-year :all-time :custom]]]]]
:any])
@@ -2,10 +2,12 @@
(:require
[quo.components.icon :as icons]
[quo.components.markdown.text :as text]
[quo.components.wallet.account-overview.schema :as component-schema]
[quo.components.wallet.account-overview.style :as style]
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[schema.core :as schema]
[utils.i18n :as i18n]))
(defn- loading-state
@@ -129,16 +131,5 @@
[numeric-changes percentage-change currency-change customization-color theme up?])]])]))
(def view
"Create a account-overview UI component.
| key | description |
| -------------|-------------|
| `:account-name` | A value representing the account name (default `nil`)
| `:account` | A value that represents if the account is a `:watched-address` or a `:default` account. (default `nil`)
| `:time-frame` | A value that represents the type of the timeframe, Can be from a preset of time frames. `[:1-week :1-month :3-months :1-year :custom]` (default `nil`) if custom is set, We expect a start time and if there's a space between two times that are in `time-frame-string` we'll split them with an arrow to the right icon
| `:loading?` | A value that indicates that component is loading data. (default `nil`)
| `:metrics` | A value that indicates if the account value have increased can be `:positive` or `:negative` (default `nil`)
| `:time-frame-string` | A value representing time frame string. (default `nil`)
| `:current-value` | A value representing the current value of the selected account. (default `nil`)
| `:currency-change` | A value representing the change of the value of the selected account in the selected currency. (default `nil`)
| `:percentage-change` | A value representing the change of the value of the selected account in percentage relative to it's previous value. (default `nil`)"
(quo.theme/with-theme view-internal))
(quo.theme/with-theme
(schema/instrument #'view-internal component-schema/?schema)))
@@ -42,18 +42,22 @@
(render [account-permissions/view
{:account account
:token-details [{:token "SNT"
:amount "100"}]}])
:amount "100"
:type :token}]}])
(h/is-truthy (h/get-by-text "100 SNT")))
(h/test "render with multiple token details"
(render [account-permissions/view
{:account account
:token-details [{:token "SNT"
:amount "100"}
:amount "100"
:type :token}
{:token "ETH"
:amount "18"}
:amount "18"
:type :token}
{:token "BTM"
:amount "1000"}]}])
:amount "1000"
:type :token}]}])
(h/is-truthy (h/get-by-text "100 SNT"))
(h/is-truthy (h/get-by-text "18 ETH"))
(h/is-truthy (h/get-by-text "1000 BTM")))
@@ -0,0 +1,22 @@
(ns quo.components.wallet.account-permissions.schema
(:require [quo.components.wallet.required-tokens.view :as required-tokens]))
(def ?schema
[:=>
[:catn
[:props
[:map
[:account
[:map
[:name [:maybe :string]]
[:address [:maybe :string]]
[:emoji [:maybe :string]]
[:customization-color {:optional true} [:maybe :schema.common/customization-color]]]]
[:token-details {:optional true} [:maybe [:sequential required-tokens/?schema]]]
[:keycard? {:optional true} [:maybe :boolean]]
[:checked? {:optional true} [:maybe :boolean]]
[:disabled? {:optional true} [:maybe :boolean]]
[:on-change {:optional true} [:maybe fn?]]
[:container-style {:optional true} [:maybe :map]]
[:theme :schema.common/theme]]]]
:any])
@@ -4,6 +4,7 @@
[quo.components.icon :as icons]
[quo.components.markdown.text :as text]
[quo.components.selectors.selectors.view :as selectors]
[quo.components.wallet.account-permissions.schema :as component-schema]
[quo.components.wallet.account-permissions.style :as style]
[quo.components.wallet.address-text.view :as address-text]
[quo.components.wallet.required-tokens.view :as required-tokens]
@@ -13,26 +14,6 @@
[schema.core :as schema]
[utils.i18n :as i18n]))
(def ?schema
[:=>
[:catn
[:props
[:map {:closed true}
[:account
[:map {:closed true}
[:name [:maybe :string]]
[:address [:maybe :string]]
[:emoji [:maybe :string]]
[:customization-color [:maybe [:or :string :keyword]]]]]
[:token-details {:optional true} [:maybe [:vector required-tokens/?schema]]]
[:keycard? {:optional true} [:maybe :boolean]]
[:checked? {:optional true} [:maybe :boolean]]
[:disabled? {:optional true} [:maybe :boolean]]
[:on-change {:optional true} [:maybe fn?]]
[:container-style {:optional true} [:maybe :map]]
[:theme :schema.common/theme]]]]
:any])
(defn- token-details-section
[tokens]
(when tokens
@@ -47,14 +28,16 @@
(i18n/label :t/no-relevant-tokens)]
(let [token-length (dec (count tokens))]
(map-indexed (fn [idx {:keys [token amount]}]
(map-indexed (fn [idx {:keys [type token amount collectible-name collectible-img-src]}]
^{:key idx}
[required-tokens/view
{:container-style style/token-and-text
:type :token
:amount amount
:token token
:divider? (not= token-length idx)}])
{:container-style style/token-and-text
:type type
:amount amount
:token token
:collectible-img-src collectible-img-src
:collectible-name collectible-name
:divider? (not= token-length idx)}])
tokens)))]]))
(defn- view-internal
@@ -93,4 +76,4 @@
(def view
(quo.theme/with-theme
(schema/instrument #'view-internal ?schema)))
(schema/instrument #'view-internal component-schema/?schema)))
@@ -0,0 +1,14 @@
(ns quo.components.wallet.address-text.schema)
(def ?schema
[:=>
[:catn
[:props
[:map
[:address {:optional true} [:maybe :string]]
[:blur? {:optional true} [:maybe :boolean]]
[:format {:optional true} [:enum :short :long]]
[:theme :schema.common/theme]
[:networks {:optional true}
[:maybe [:sequential [:map [:name :keyword] [:short-name :string]]]]]]]]
:any])
@@ -1,8 +1,10 @@
(ns quo.components.wallet.address-text.view
(:require [quo.components.markdown.text :as text]
[quo.components.wallet.address-text.schema :as component-schema]
[quo.components.wallet.address-text.style :as style]
[quo.foundations.colors :as colors]
[quo.theme]
[schema.core :as schema]
[utils.address :as utils]))
(defn- colored-network-text
@@ -28,4 +30,6 @@
(into [text/text] network-text-xf $)
(conj $ address-text))))
(def view (quo.theme/with-theme view-internal))
(def view
(quo.theme/with-theme
(schema/instrument #'view-internal component-schema/?schema)))
@@ -0,0 +1,43 @@
(ns quo.components.wallet.amount-input.component-spec
(:require
[oops.core :as oops]
[quo.components.wallet.amount-input.view :as amount-input]
[quo.foundations.colors :as colors]
[test-helpers.component :as h]))
(defn- render
[component]
(h/render-with-theme-provider component :light))
(h/describe "Amount input component"
(h/test "Renders with default value"
(let [text-expected 0]
(render [amount-input/view {:init-value text-expected}])
(h/is-truthy (h/query-by-label-text :amount-input))
(h/is-equal (oops/oget (h/get-by-label-text :amount-input) "props" "value")
(str text-expected))))
(h/test "When the value = minimum dec button is disabled"
(render [amount-input/view
{:init-value 0
:min-value 0}])
(h/is-truthy
(oops/oget (h/get-by-label-text :amount-input-dec-button) "props" "accessibilityState" "disabled")))
(h/test "When the value = maximum inc button is disabled"
(render [amount-input/view
{:init-value 100
:max-value 100}])
(h/is-truthy
(oops/oget (h/get-by-label-text :amount-input-inc-button) "props" "accessibilityState" "disabled")))
(h/test "Renders the error state"
(render [amount-input/view {:status :error}])
(h/is-equal (colors/resolve-color :danger :light)
(oops/oget (h/get-by-label-text :amount-input) "props" "style" "color")))
(h/test "on-change-text function is fired"
(let [on-change-text (h/mock-fn)]
(render [amount-input/view {:on-change-text on-change-text}])
(h/fire-event :change-text (h/get-by-label-text :amount-input) "100")
(h/was-called on-change-text))))
@@ -0,0 +1,21 @@
(ns quo.components.wallet.amount-input.schema)
(def return-key-types
[:enum :done :go :next :search :send :none :previous :default
:emergency-call :google :join :route :yahoo])
(def ?schema
[:=>
[:catn
[:props
[:map {:closed true}
[:status {:optional true} [:maybe [:enum :default :error]]]
[:theme :schema.common/theme]
[:on-change-text {:optional true} [:maybe fn?]]
[:container-style {:optional true} [:maybe :map]]
[:auto-focus? {:optional true} [:maybe :boolean]]
[:min-value {:optional true} [:maybe :int]]
[:max-value {:optional true} [:maybe :int]]
[:return-key-type {:optional true} [:maybe return-key-types]]
[:init-value {:optional true} [:maybe :int]]]]]
:any])
@@ -0,0 +1,17 @@
(ns quo.components.wallet.amount-input.style
(:require
[quo.foundations.colors :as colors]))
(def container
{:flex-direction :row
:justify-content :center
:align-items :center})
(def input-container {:flex 1})
(defn input-text
[theme type]
{:padding 0
:color (if (= type :error)
(colors/resolve-color :danger theme)
(colors/theme-colors colors/neutral-100 colors/white theme))})
@@ -0,0 +1,81 @@
(ns quo.components.wallet.amount-input.view
(:require
[quo.components.buttons.button.view :as button]
[quo.components.markdown.text :as text]
[quo.components.wallet.amount-input.schema :as amount-input.schema]
[quo.components.wallet.amount-input.style :as style]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[reagent.core :as reagent]
[schema.core :as schema]))
(defn- amount-button
[{:keys [theme accessibility-label disabled? icon on-press]}]
[button/button
{:icon-only? true
:theme theme
:disabled? disabled?
:type :outline
:accessibility-label accessibility-label
:size 32
:on-press on-press}
icon])
(defn- process-amount
[input-value min-value max-value]
(let [parsed-input-value (parse-double input-value)]
(cond
(nil? parsed-input-value) min-value
(>= input-value max-value) max-value
(<= input-value min-value) min-value
:else parsed-input-value)))
(defn- view-internal
[{:keys [init-value]}]
(let [init-value (or init-value 0)
value (reagent/atom init-value)
on-dec-press #(swap! value dec)
on-inc-press #(swap! value inc)]
(fn [{:keys [theme status min-value max-value auto-focus?
return-key-type container-style on-change-text]}]
(let [min-value (or min-value 0)
max-value (or max-value 999999999)]
[rn/view
{:style (merge style/container container-style)}
[amount-button
{:theme theme
:accessibility-label :amount-input-dec-button
:icon :i/remove
:on-press on-dec-press
:disabled? (>= min-value @value)}]
[rn/view {:style style/input-container}
[rn/text-input
{:style
(text/text-style
{:size :heading-1
:weight :semi-bold
:align :center
:style (style/input-text theme (or status :default))})
:accessibility-label :amount-input
:editable true
:auto-focus (or auto-focus? false)
:value (str @value)
:keyboard-appearance (quo.theme/theme-value :light :dark theme)
:return-key-type (or return-key-type :done)
:input-mode :numeric
:on-change-text (fn [input-value]
(let [processed-amount (process-amount input-value min-value max-value)]
(reset! value processed-amount)
(when on-change-text
(on-change-text processed-amount))
(reagent/flush)))}]] ; Fixes the input flickering issue when typing.
[amount-button
{:theme theme
:icon :i/add
:accessibility-label :amount-input-inc-button
:on-press on-inc-press
:disabled? (>= @value max-value)}]]))))
(def view
(quo.theme/with-theme
(schema/instrument #'view-internal amount-input.schema/?schema)))
@@ -1,99 +1,115 @@
(ns quo.components.wallet.confirmation-progress.component-spec
(:require [quo.core :as quo]
[reagent.core :as reagent]
[test-helpers.component :as h]))
(defn- get-test-data
[{:keys [state network]
:or {state :pending network :mainnet}}]
{:counter (reagent/atom 0)
{:counter 0
:total-box 85
:progress-value "10"
:progress-value 10
:network network
:state state
:customization-color :blue})
(h/describe "Confirmation Progress"
(h/test "component renders when state is sending and network is optimism"
(h/render [quo/confirmation-propgress
(get-test-data {:state :sending
:network :optimism})])
(h/is-truthy (h/get-by-label-text :progress-box)))
(h/render-with-theme-provider [quo/confirmation-propgress
(get-test-data {:state :sending
:network :optimism})])
(h/is-truthy (h/get-by-label-text :progress-box))))
(h/test "component renders when state is confirmed and network is optimism"
(h/render [quo/confirmation-propgress
(get-test-data {:state :confirmed
:network :optimism})])
(h/is-truthy (h/get-by-label-text :progress-box)))
(h/test "component renders when state is confirmed and network is optimism"
(h/render-with-theme-provider
[quo/confirmation-propgress
(get-test-data {:state :confirmed
:network :optimism})])
(h/is-truthy (h/get-by-label-text :progress-box)))
(h/test "component renders when state is finalising and network is optimism"
(h/render [quo/confirmation-propgress
(get-test-data {:state :finalising
:network :optimism})])
(h/is-truthy (h/get-by-label-text :progress-box)))
(h/test "component renders when state is finalising and network is optimism"
(h/render-with-theme-provider
[quo/confirmation-propgress
(get-test-data {:state :finalising
:network :optimism})])
(h/is-truthy (h/get-by-label-text :progress-box)))
(h/test "component renders when state is finalized and network is optimism"
(h/render [quo/confirmation-propgress
(get-test-data {:state :finalized
:network :optimism})])
(h/is-truthy (h/get-by-label-text :progress-box)))
(h/test "component renders when state is finalized and network is optimism"
(h/render-with-theme-provider
[quo/confirmation-propgress
(get-test-data {:state :finalized
:network :optimism})])
(h/is-truthy (h/get-by-label-text :progress-box)))
(h/test "component renders when state is error and network is optimism"
(h/render [quo/confirmation-propgress
(get-test-data {:state :error
:network :optimism})])
(h/is-truthy (h/get-by-label-text :progress-box)))
(h/test "component renders when state is error and network is optimism"
(h/render-with-theme-provider
[quo/confirmation-propgress
(get-test-data {:state :error
:network :optimism})])
(h/is-truthy (h/get-by-label-text :progress-box)))
(h/test "component renders when state is sending and network is arbitrum"
(h/render [quo/confirmation-propgress
(get-test-data {:state :sending
:network :arbitrum})])
(h/is-truthy (h/get-by-label-text :progress-box)))
(h/test "component renders when state is sending and network is arbitrum"
(h/render-with-theme-provider
[quo/confirmation-propgress
(get-test-data {:state :sending
:network :arbitrum})])
(h/is-truthy (h/get-by-label-text :progress-box)))
(h/test "component renders when state is confirmed and network is arbitrum"
(h/render [quo/confirmation-propgress
(get-test-data {:state :confirmed
:network :arbitrum})])
(h/is-truthy (h/get-by-label-text :progress-box)))
(h/test "component renders when state is confirmed and network is arbitrum"
(h/render-with-theme-provider
[quo/confirmation-propgress
(get-test-data {:state :confirmed
:network :arbitrum})])
(h/is-truthy (h/get-by-label-text :progress-box)))
(h/test "component renders when state is finalising and network is arbitrum"
(h/render [quo/confirmation-propgress
(get-test-data {:state :finalising
:network :arbitrum})])
(h/is-truthy (h/get-by-label-text :progress-box)))
(h/test "component renders when state is finalising and network is arbitrum"
(h/render-with-theme-provider
[quo/confirmation-propgress
(get-test-data {:state :finalising
:network :arbitrum})])
(h/is-truthy (h/get-by-label-text :progress-box)))
(h/test "component renders when state is finalized and network is arbitrum"
(h/render [quo/confirmation-propgress
(get-test-data {:state :finalized
:network :arbitrum})])
(h/is-truthy (h/get-by-label-text :progress-box)))
(h/test "component renders when state is finalized and network is arbitrum"
(h/render-with-theme-provider
[quo/confirmation-propgress
(get-test-data {:state :finalized
:network :arbitrum})])
(h/is-truthy (h/get-by-label-text :progress-box)))
(h/test "component renders when state is error and network is arbitrum"
(h/render [quo/confirmation-propgress
(get-test-data {:state :error
:network :arbitrum})])
(h/is-truthy (h/get-by-label-text :progress-box)))
(h/test "component renders when state is error and network is arbitrum"
(h/render-with-theme-provider
[quo/confirmation-propgress
(get-test-data {:state :error
:network :arbitrum})])
(h/is-truthy (h/get-by-label-text :progress-box)))
(h/test "component renders when state is pending and network is mainnet"
(h/render [quo/confirmation-propgress (get-test-data {})])
(h/is-truthy (h/get-by-label-text :mainnet-progress-box)))
(h/test "component renders when state is pending and network is mainnet"
(h/render-with-theme-provider
[quo/confirmation-propgress (get-test-data {})])
(h/is-truthy (h/get-by-label-text :mainnet-progress-box)))
(h/test "component renders when state is sending and network is mainnet"
(h/render [quo/confirmation-propgress (get-test-data {:state :sending})])
(h/is-truthy (h/get-by-label-text :mainnet-progress-box)))
(h/test "component renders when state is sending and network is mainnet"
(h/render-with-theme-provider
[quo/confirmation-propgress (get-test-data {:state :sending})])
(h/is-truthy (h/get-by-label-text :mainnet-progress-box)))
(h/test "component renders when state is confirmed and network is mainnet"
(h/render [quo/confirmation-propgress (get-test-data {:state :confirmed})])
(h/is-truthy (h/get-by-label-text :mainnet-progress-box)))
(h/test "component renders when state is confirmed and network is mainnet"
(h/render-with-theme-provider
[quo/confirmation-propgress (get-test-data {:state :confirmed})])
(h/is-truthy (h/get-by-label-text :mainnet-progress-box)))
(h/test "component renders when state is finalising and network is mainnet"
(h/render [quo/confirmation-propgress (get-test-data {:state :finalising})])
(h/is-truthy (h/get-by-label-text :mainnet-progress-box)))
(h/test "component renders when state is finalising and network is mainnet"
(h/render-with-theme-provider
[quo/confirmation-propgress (get-test-data {:state :finalising})])
(h/is-truthy (h/get-by-label-text :mainnet-progress-box)))
(h/test "component renders when state is finalized and network is mainnet"
(h/render [quo/confirmation-propgress (get-test-data {:state :finalized})])
(h/is-truthy (h/get-by-label-text :mainnet-progress-box)))
(h/test "component renders when state is finalized and network is mainnet"
(h/render-with-theme-provider
[quo/confirmation-propgress (get-test-data {:state :finalized})])
(h/is-truthy (h/get-by-label-text :mainnet-progress-box)))
(h/test "component renders when state is error and network is mainnet"
(h/render [quo/confirmation-propgress (get-test-data {:state :error})])
(h/is-truthy (h/get-by-label-text :mainnet-progress-box))))
(h/test "component renders when state is error and network is mainnet"
(h/render-with-theme-provider
[quo/confirmation-propgress
(get-test-data {:state :error})])
(h/is-truthy (h/get-by-label-text :mainnet-progress-box)))
@@ -0,0 +1,15 @@
(ns quo.components.wallet.confirmation-progress.schema)
(def ?schema
[:=>
[:catn
[:props
[:map
[:total-box {:optional true} [:maybe :int]]
[:counter {:optional true} [:maybe :int]]
[:progress-value {:optional true} [:maybe :int]]
[:network {:optional true} [:enum :mainnet :optimism :arbitrum]]
[:state {:optional true} [:enum :pending :sending :confirmed :finalising :finalized :error]]
[:customization-color {:optional true} [:maybe :schema.common/customization-color]]
[:theme :schema.common/theme]]]]
:any])
@@ -1,8 +1,10 @@
(ns quo.components.wallet.confirmation-progress.view
(:require [quo.components.wallet.confirmation-progress.style :as style]
(:require [quo.components.wallet.confirmation-progress.schema :as component-schema]
[quo.components.wallet.confirmation-progress.style :as style]
[quo.components.wallet.progress-bar.view :as progress-box]
[quo.theme :as quo.theme]
[react-native.core :as rn]))
[react-native.core :as rn]
[schema.core :as schema]))
(def ^:private max-progress 100)
(def ^:private min-progress 0)
@@ -66,4 +68,6 @@
(:arbitrum :optimism) [progress-boxes-sidenet props]
nil))
(def view (quo.theme/with-theme view-internal))
(def view
(quo.theme/with-theme
(schema/instrument #'view-internal component-schema/?schema)))
@@ -3,6 +3,8 @@
[quo.components.wallet.keypair.view :as keypair]
[test-helpers.component :as h]))
(def ^:private theme :light)
(def accounts
[{:account-props {:customization-color :turquoise
:size 32
@@ -23,41 +25,45 @@
(h/describe "Wallet: Keypair"
(h/test "Default keypair title renders"
(h/render [keypair/view
{:accounts accounts
:customization-color :blue
:type :default-keypair
:stored :on-device
:action :selector
:details default-details}])
(h/render-with-theme-provider [keypair/view
{:accounts accounts
:customization-color :blue
:type :default-keypair
:stored :on-device
:action :selector
:details default-details}]
theme)
(h/is-truthy (h/get-by-label-text :title)))
(h/test "On device renders"
(h/render [keypair/view
{:accounts accounts
:customization-color :blue
:type :other
:stored :on-device
:action :selector
:details other-details}])
(h/render-with-theme-provider [keypair/view
{:accounts accounts
:customization-color :blue
:type :other
:stored :on-device
:action :selector
:details other-details}]
theme)
(h/is-truthy (h/get-by-label-text :details)))
(h/test "Selector action renders"
(h/render [keypair/view
{:accounts accounts
:customization-color :blue
:type :other
:stored :on-keycard
:action :selector
:details other-details}])
(h/render-with-theme-provider [keypair/view
{:accounts accounts
:customization-color :blue
:type :other
:stored :on-keycard
:action :selector
:details other-details}]
theme)
(h/is-truthy (h/get-by-label-text :radio-on)))
(h/test "Options action renders"
(h/render [keypair/view
{:accounts accounts
:customization-color :blue
:type :other
:stored :on-keycard
:action :options
:details other-details}])
(h/render-with-theme-provider [keypair/view
{:accounts accounts
:customization-color :blue
:type :other
:stored :on-keycard
:action :options
:details other-details}]
theme)
(h/is-truthy (h/get-by-label-text :options-button))))
@@ -5,7 +5,8 @@
(h/describe "Wallet: Network Amount"
(h/test "Amount renders"
(h/render [network-amount/view
{:amount "5.123"
:token :eth}])
(h/render-with-theme-provider
[network-amount/view
{:amount "5.123"
:token :eth}])
(h/is-truthy (h/get-by-text "5.123 ETH"))))
@@ -5,7 +5,18 @@
[quo.components.utilities.token.view :as token]
[quo.components.wallet.network-amount.style :as style]
[quo.theme :as quo.theme]
[react-native.core :as rn]))
[react-native.core :as rn]
[schema.core :as schema]))
(def ?schema
[:=>
[:catn
[:props
[:map {:closed true}
[:amount {:optional true} [:maybe :string]]
[:token {:optional true} [:or :keyword :string]]
[:theme :schema.common/theme]]]]
:any])
(defn- view-internal
[{:keys [amount token theme]}]
@@ -19,4 +30,4 @@
[rn/view
{:style (style/divider theme)}]])
(def view (quo.theme/with-theme view-internal))
(def view (quo.theme/with-theme (schema/instrument #'view-internal ?schema)))
@@ -4,37 +4,37 @@
[test-helpers.component :as h]))
(h/describe "Wallet: Network Bridge"
(h/test "Amount renders"
(h/render [network-bridge/view
{:amount "50 SNT"
:network :ethereum
:status :default}])
(h/test "Amount render-with-theme-providers"
(h/render-with-theme-provider [network-bridge/view
{:amount "50 SNT"
:network :ethereum
:status :default}])
(h/is-truthy (h/get-by-text "50 SNT")))
(h/test "Network label renders"
(h/render [network-bridge/view
{:amount "50 SNT"
:network :optimism
:status :default}])
(h/test "Network label render"
(h/render-with-theme-provider [network-bridge/view
{:amount "50 SNT"
:network :optimism
:status :default}])
(h/is-truthy (h/get-by-text "Optimism")))
(h/test "Locked state"
(h/render [network-bridge/view
{:amount "50 SNT"
:network :optimism
:status :locked}])
(h/render-with-theme-provider [network-bridge/view
{:amount "50 SNT"
:network :optimism
:status :locked}])
(h/is-truthy (h/get-by-label-text :lock)))
(h/test "Loading state"
(h/render [network-bridge/view
{:amount "50 SNT"
:network :optimism
:status :loading}])
(h/render-with-theme-provider [network-bridge/view
{:amount "50 SNT"
:network :optimism
:status :loading}])
(h/is-truthy (h/get-by-label-text :loading)))
(h/test "Disabled state"
(h/render [network-bridge/view
{:amount "50 SNT"
:network :optimism
:status :disabled}])
(h/render-with-theme-provider [network-bridge/view
{:amount "50 SNT"
:network :optimism
:status :disabled}])
(h/has-style (h/get-by-label-text :container) {:opacity 0.3})))
@@ -7,7 +7,8 @@
[quo.foundations.colors :as colors]
[quo.foundations.resources :as resources]
[quo.theme :as quo.theme]
[react-native.core :as rn]))
[react-native.core :as rn]
[schema.core :as schema]))
(defn network-bridge-add
[{:keys [network state theme container-style on-press]}]
@@ -24,6 +25,22 @@
(= network :ethereum) "Mainnet"
:else (string/capitalize (name network))))
(def ^:private ?network-bridge-status
[:enum :add :loading :locked :disabled :default])
(def ?schema
[:=>
[:catn
[:props
[:map
[:theme :schema.common/theme]
[:network {:optional true} [:maybe :keyword]]
[:status {:optional true} [:maybe ?network-bridge-status]]
[:amount {:optional true} [:maybe :string]]
[:container-style {:optional true} [:maybe :map]]
[:on-press {:optional true} [:maybe fn?]]]]]
:any])
(defn view-internal
[{:keys [theme network status amount container-style on-press] :as args}]
(if (= status :add)
@@ -62,4 +79,6 @@
:style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)}}
(network->text network)]]]))
(def view (quo.theme/with-theme view-internal))
(def view
(quo.theme/with-theme
(schema/instrument #'view-internal ?schema)))
@@ -1,6 +1,7 @@
(ns quo.components.wallet.network-routing.component-spec
(:require [oops.core :as oops]
[quo.components.wallet.network-routing.view :as network-routing]
quo.theme
[reagent.core :as reagent]
[test-helpers.component :as h]))
@@ -11,17 +12,18 @@
:requesting-data? false
:on-amount-selected (fn [_new-amount _network-idx] nil)}]
(h/test "Renders Default"
(h/render [network-routing/view default-props])
(h/render-with-theme-provider [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])
(let [component (h/render-with-theme-provider [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)])
(rerender-fn [quo.theme/provider {:theme :light}
[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)
@@ -8,6 +8,7 @@
[react-native.gesture :as gesture]
[react-native.reanimated :as reanimated]
[reagent.core :as reagent]
[schema.core :as schema]
[utils.number]))
(def ^:private timeouts (atom {}))
@@ -172,6 +173,22 @@
[rn/view {:style (style/max-limit-bar-background network-name)}]
[dashed-line network-name]])]))))
(def ?schema
[:=>
[:catn
[:props
[:map
[:networks {:optional true}
[:maybe
[:sequential
[:map
[:amount :int]
[:max-amount :int]
[:network-name [:or :string :keyword]]]]]]
[:container-style {:optional true} [:maybe :map]]
[:theme :schema.common/theme]]]]
:any])
(defn view-internal
[{:keys [networks container-style theme] :as params}]
(reagent/with-let [total-width (reagent/atom nil)]
@@ -186,4 +203,6 @@
(doseq [[_ living-timeout] @timeouts]
(js/clearTimeout living-timeout)))))
(def view (quo.theme/with-theme view-internal))
(def view
(quo.theme/with-theme
(schema/instrument #'view-internal ?schema)))
@@ -2,7 +2,19 @@
(:require
[quo.components.wallet.progress-bar.style :as style]
[quo.theme :as quo.theme]
[react-native.core :as rn]))
[react-native.core :as rn]
[schema.core :as schema]))
(def ?schema
[:=>
[:catn
[:props
[:map
[:customization-color {:optional true} [:maybe :schema.common/customization-color]]
[:theme :schema.common/theme]
[:progressed-value {:optional true} [:maybe [:or :string :int]]]
[:full-width? {:optional true} [:maybe :boolean]]]]]
:any])
(defn- view-internal
[{:keys [full-width?] :as props}]
@@ -12,4 +24,6 @@
(when full-width?
[rn/view {:style (style/progressed-bar props)}])])
(def view (quo.theme/with-theme view-internal))
(def view
(quo.theme/with-theme
(schema/instrument #'view-internal ?schema)))
@@ -15,7 +15,7 @@
[:amount {:optional true} [:maybe [:or :string :int]]]
[:token {:optional true} [:maybe :string]]
[:token-img-src {:optional true} [:maybe :schema.common/image-source]]
[:collectible-img-src {:optional true} :schema.common/image-source]
[:collectible-img-src {:optional true} [:maybe :schema.common/image-source]]
[:collectible-name {:optional true} [:maybe :string]]
[:divider? {:optional true} [:maybe :boolean]]
[:theme :schema.common/theme]
@@ -13,48 +13,49 @@
(h/describe "Wallet: Summary Info"
(h/test "Type of `status-account` title renders"
(h/render [summary-info/view
{:type :status-account
:networks? true
:values {:ethereum 150
:optimism 50
:arbitrum 25}
:account-props status-account-props}])
(h/render-with-theme-provider [summary-info/view
{:type :status-account
:networks? true
:values {:ethereum 150
:optimism 50
:arbitrum 25}
:account-props status-account-props}])
(h/is-truthy (h/get-by-text "Collectibles vault")))
(h/test "Type of `user` title renders"
(h/render [summary-info/view
{:type :user
:networks? true
:values {:ethereum 150
:optimism 50
:arbitrum 25}
:account-props {:full-name "M L"
:status-indicator? false
:size :small
:customization-color :blue
:name "Mark Libot"
:address "0x0ah...78b"
:status-account (merge status-account-props {:size 16})}}])
(h/render-with-theme-provider [summary-info/view
{:type :user
:networks? true
:values {:ethereum 150
:optimism 50
:arbitrum 25}
:account-props {:full-name "M L"
:status-indicator? false
:size :small
:customization-color :blue
:name "Mark Libot"
:address "0x0ah...78b"
:status-account (merge status-account-props
{:size 16})}}])
(h/is-truthy (h/get-by-text "Mark Libot"))
(h/is-truthy (h/get-by-text "Collectibles vault")))
(h/test "Networks true render"
(h/render [summary-info/view
{:type :status-account
:networks? true
:values {:ethereum 150
:optimism 50
:arbitrum 25}
:account-props status-account-props}])
(h/render-with-theme-provider [summary-info/view
{:type :status-account
:networks? true
:values {:ethereum 150
:optimism 50
:arbitrum 25}
:account-props status-account-props}])
(h/is-truthy (h/get-by-label-text :networks)))
(h/test "Networks false render"
(h/render [summary-info/view
{:type :status-account
:networks? false
:values {:ethereum 150
:optimism 50
:arbitrum 25}
:account-props status-account-props}])
(h/render-with-theme-provider [summary-info/view
{:type :status-account
:networks? false
:values {:ethereum 150
:optimism 50
:arbitrum 25}
:account-props status-account-props}])
(h/is-null (h/query-by-label-text :networks))))
@@ -8,7 +8,8 @@
[quo.foundations.colors :as colors]
[quo.foundations.resources :as resources]
[quo.theme :as quo.theme]
[react-native.core :as rn]))
[react-native.core :as rn]
[schema.core :as schema]))
(defn- network-amount
[{:keys [network amount divider? theme]}]
@@ -51,6 +52,18 @@
:amount (str (:amount arbitrum) " " (or (:token-symbol arbitrum) "ARB"))
:theme theme}])]))
(def ?schema
[:=>
[:catn
[:props
[:map
[:theme :schema.common/theme]
[:type [:enum :status-account :saved-account :account :user]]
[:account-props {:optional true} [:maybe :map]]
[:networks? {:optional true} [:maybe :boolean]]
[:values {:optional true} [:maybe :map]]]]]
:any])
(defn- view-internal
[{:keys [theme type account-props networks? values]}]
[rn/view
@@ -91,4 +104,6 @@
{:style (style/line-divider theme)}]
[networks values theme]])])
(def view (quo.theme/with-theme view-internal))
(def view
(quo.theme/with-theme
(schema/instrument #'view-internal ?schema)))
@@ -1,6 +1,5 @@
(ns quo.components.wallet.transaction-progress.component-spec
(:require [quo.core :as quo]
[reagent.core :as reagent]
[test-helpers.component :as h]))
(defn- get-test-data
@@ -8,193 +7,228 @@
:or {state :pending network :mainnet}}]
{:title "Title"
:tag-name "Doodle"
:tag-number "120"
:tag-number 120
:network network
:customization-color :blue
:networks [{:network :mainnet
:state state
:counter (reagent/atom 0)
:counter 0
:total-box 85
:progress 30
:epoch-number "123"}
{:network :optimism
:state state
:progress "50"
:progress 50
:epoch-number "123"}
{:network :arbitrum
:state state
:progress "30"
:progress 30
:epoch-number "123"}]
:on-press (fn []
(js/alert "Transaction progress item pressed"))})
(h/describe "Transaction Progress"
(h/test "component renders without props"
(h/render [quo/transaction-progress])
(h/render-with-theme-provider
[quo/transaction-progress])
(h/is-truthy (h/get-by-label-text :transaction-progress)))
(h/test "component renders when state is pending and network is mainnet"
(h/render [quo/transaction-progress (get-test-data {:network :optimism-arbitrum})])
(h/render-with-theme-provider
[quo/transaction-progress (get-test-data {:network :optimism-arbitrum})])
(h/is-truthy (h/get-by-label-text :transaction-progress)))
(h/test "component renders when state is sending and network is optimism-arbitrum"
(h/render [quo/transaction-progress
(get-test-data {:state :sending
:network :optimism-arbitrum})])
(h/render-with-theme-provider
[quo/transaction-progress
(get-test-data {:state :sending
:network :optimism-arbitrum})])
(h/is-truthy (h/get-by-label-text :transaction-progress)))
(h/test "component renders when state is confirmed and network is optimism-arbitrum"
(h/render [quo/transaction-progress
(get-test-data {:state :confirmed
:network :optimism-arbitrum})])
(h/render-with-theme-provider
[quo/transaction-progress
(get-test-data {:state :confirmed
:network :optimism-arbitrum})])
(h/is-truthy (h/get-by-label-text :transaction-progress)))
(h/test "component renders when state is finalising and network is optimism-arbitrum"
(h/render [quo/transaction-progress
(get-test-data {:state :finalising
:network :optimism-arbitrum})])
(h/render-with-theme-provider
[quo/transaction-progress
(get-test-data {:state :finalising
:network :optimism-arbitrum})])
(h/is-truthy (h/get-by-label-text :transaction-progress)))
(h/test "component renders when state is finalized and network is optimism-arbitrum"
(h/render [quo/transaction-progress
(get-test-data {:state :finalized
:network :optimism-arbitrum})])
(h/render-with-theme-provider
[quo/transaction-progress
(get-test-data {:state :finalized
:network :optimism-arbitrum})])
(h/is-truthy (h/get-by-label-text :transaction-progress)))
(h/test "component renders when state is error and network is optimism-arbitrum"
(h/render [quo/transaction-progress
(get-test-data {:state :error
:network :optimism-arbitrum})])
(h/render-with-theme-provider
[quo/transaction-progress
(get-test-data {:state :error
:network :optimism-arbitrum})])
(h/is-truthy (h/get-by-label-text :transaction-progress)))
(h/test "component renders when state is sending and network is optimism"
(h/render [quo/transaction-progress
(get-test-data {:state :sending
:network :optimism})])
(h/render-with-theme-provider
[quo/transaction-progress
(get-test-data {:state :sending
:network :optimism})])
(h/is-truthy (h/get-by-label-text :transaction-progress)))
(h/test "component renders when state is confirmed and network is optimism"
(h/render [quo/transaction-progress
(get-test-data {:state :confirmed
:network :optimism})])
(h/render-with-theme-provider
[quo/transaction-progress
(get-test-data {:state :confirmed
:network :optimism})])
(h/is-truthy (h/get-by-label-text :transaction-progress)))
(h/test "component renders when state is finalising and network is optimism"
(h/render [quo/transaction-progress
(get-test-data {:state :finalising
:network :optimism})])
(h/render-with-theme-provider
[quo/transaction-progress
(get-test-data {:state :finalising
:network :optimism})])
(h/is-truthy (h/get-by-label-text :transaction-progress)))
(h/test "component renders when state is finalized and network is optimism"
(h/render [quo/transaction-progress
(get-test-data {:state :finalized
:network :optimism})])
(h/render-with-theme-provider
[quo/transaction-progress
(get-test-data {:state :finalized
:network :optimism})])
(h/is-truthy (h/get-by-label-text :transaction-progress)))
(h/test "component renders when state is error and network is optimism"
(h/render [quo/transaction-progress
(get-test-data {:state :error
:network :optimism})])
(h/render-with-theme-provider
[quo/transaction-progress
(get-test-data {:state :error
:network :optimism})])
(h/is-truthy (h/get-by-label-text :transaction-progress)))
(h/test "component renders when state is sending and network is arbitrum"
(h/render [quo/transaction-progress
(get-test-data {:state :sending
:network :arbitrum})])
(h/render-with-theme-provider
[quo/transaction-progress
(get-test-data {:state :sending
:network :arbitrum})])
(h/is-truthy (h/get-by-label-text :transaction-progress)))
(h/test "component renders when state is confirmed and network is arbitrum"
(h/render [quo/transaction-progress
(get-test-data {:state :confirmed
:network :arbitrum})])
(h/render-with-theme-provider
[quo/transaction-progress
(get-test-data {:state :confirmed
:network :arbitrum})])
(h/is-truthy (h/get-by-label-text :transaction-progress)))
(h/test "component renders when state is finalising and network is arbitrum"
(h/render [quo/transaction-progress
(get-test-data {:state :finalising
:network :arbitrum})])
(h/render-with-theme-provider
[quo/transaction-progress
(get-test-data {:state :finalising
:network :arbitrum})])
(h/is-truthy (h/get-by-label-text :transaction-progress)))
(h/test "component renders when state is finalized and network is arbitrum"
(h/render [quo/transaction-progress
(get-test-data {:state :finalized
:network :arbitrum})])
(h/render-with-theme-provider
[quo/transaction-progress
(get-test-data {:state :finalized
:network :arbitrum})])
(h/is-truthy (h/get-by-label-text :transaction-progress)))
(h/test "component renders when state is error and network is arbitrum"
(h/render [quo/transaction-progress
(get-test-data {:state :error
:network :arbitrum})])
(h/render-with-theme-provider
[quo/transaction-progress
(get-test-data {:state :error
:network :arbitrum})])
(h/is-truthy (h/get-by-label-text :transaction-progress)))
(h/test "component renders when state is pending and network is mainnet"
(h/render [quo/transaction-progress (get-test-data {})])
(h/render-with-theme-provider
[quo/transaction-progress (get-test-data {})])
(h/is-truthy (h/get-by-label-text :transaction-progress)))
(h/test "component renders when state is sending and network is mainnet"
(h/render [quo/transaction-progress (get-test-data {:state :sending})])
(h/render-with-theme-provider
[quo/transaction-progress (get-test-data {:state :sending})])
(h/is-truthy (h/get-by-label-text :transaction-progress)))
(h/test "component renders when state is confirmed and network is mainnet"
(h/render [quo/transaction-progress (get-test-data {:state :confirmed})])
(h/render-with-theme-provider
[quo/transaction-progress (get-test-data {:state :confirmed})])
(h/is-truthy (h/get-by-label-text :transaction-progress)))
(h/test "component renders when state is finalising and network is mainnet"
(h/render [quo/transaction-progress (get-test-data {:state :finalising})])
(h/render-with-theme-provider
[quo/transaction-progress (get-test-data {:state :finalising})])
(h/is-truthy (h/get-by-label-text :transaction-progress)))
(h/test "component renders when state is finalized and network is mainnet"
(h/render [quo/transaction-progress (get-test-data {:state :finalized})])
(h/render-with-theme-provider
[quo/transaction-progress (get-test-data {:state :finalized})])
(h/is-truthy (h/get-by-label-text :transaction-progress)))
(h/test "component renders when state is error and network is mainnet"
(h/render [quo/transaction-progress (get-test-data {:state :error})])
(h/render-with-theme-provider
[quo/transaction-progress (get-test-data {:state :error})])
(h/is-truthy (h/get-by-label-text :transaction-progress)))
(h/test "mainnet progress box is visible network is mainnet"
(h/render [quo/transaction-progress (get-test-data {})])
(h/render-with-theme-provider
[quo/transaction-progress (get-test-data {})])
(h/is-truthy (h/get-by-label-text :mainnet-progress-box)))
(h/test "arbitrum-optimism progress box is visible network is optimism-arbitrum"
(h/render [quo/transaction-progress (get-test-data {:network :optimism-arbitrum})])
(h/render-with-theme-provider
[quo/transaction-progress (get-test-data {:network :optimism-arbitrum})])
(h/is-truthy (h/get-all-by-label-text :progress-box)))
(h/test "arbitrum progress box is visible network is arbitrum"
(h/render [quo/transaction-progress (get-test-data {:network :arbitrum})])
(h/render-with-theme-provider
[quo/transaction-progress (get-test-data {:network :arbitrum})])
(h/is-truthy (h/get-all-by-label-text :progress-box)))
(h/test "optimism progress box is visible network is optimism"
(h/render [quo/transaction-progress (get-test-data {:network :optimism})])
(h/render-with-theme-provider
[quo/transaction-progress (get-test-data {:network :optimism})])
(h/is-truthy (h/get-all-by-label-text :progress-box)))
(h/test "title is visible network is optimism-arbitrum"
(h/render [quo/transaction-progress (get-test-data {:network :optimism-arbitrum})])
(h/render-with-theme-provider
[quo/transaction-progress (get-test-data {:network :optimism-arbitrum})])
(h/is-truthy (h/get-by-text "Title")))
(h/test "title is visible network is mainnet"
(h/render [quo/transaction-progress (get-test-data {})])
(h/render-with-theme-provider
[quo/transaction-progress (get-test-data {})])
(h/is-truthy (h/get-by-text "Title")))
(h/test "title is visible network is optimism"
(h/render [quo/transaction-progress (get-test-data {:network :optimism})])
(h/render-with-theme-provider
[quo/transaction-progress (get-test-data {:network :optimism})])
(h/is-truthy (h/get-by-text "Title")))
(h/test "title is visible network is arbitrum"
(h/render [quo/transaction-progress (get-test-data {:network :arbitrum})])
(h/render-with-theme-provider
[quo/transaction-progress (get-test-data {:network :arbitrum})])
(h/is-truthy (h/get-by-text "Title")))
(h/test "context tag is visible network is optimism-arbitrum"
(h/render [quo/transaction-progress (get-test-data {:network :optimism-arbitrum})])
(h/render-with-theme-provider
[quo/transaction-progress (get-test-data {:network :optimism-arbitrum})])
(h/is-truthy (h/get-by-label-text :context-tag)))
(h/test "context tag is visible network is mainnet"
(h/render [quo/transaction-progress (get-test-data {})])
(h/render-with-theme-provider
[quo/transaction-progress (get-test-data {})])
(h/is-truthy (h/get-by-label-text :context-tag)))
(h/test "context tag is visible network is optimism"
(h/render [quo/transaction-progress (get-test-data {:network :optimism})])
(h/render-with-theme-provider
[quo/transaction-progress (get-test-data {:network :optimism})])
(h/is-truthy (h/get-by-label-text :context-tag)))
(h/test "context tag is visible network is optimism"
(h/render [quo/transaction-progress (get-test-data {:network :arbitrum})])
(h/render-with-theme-provider
[quo/transaction-progress (get-test-data {:network :arbitrum})])
(h/is-truthy (h/get-by-label-text :context-tag))))
+4
View File
@@ -135,6 +135,7 @@
quo.components.tabs.account-selector
quo.components.tabs.segmented-tab
quo.components.tabs.tabs.view
quo.components.tags.collectible-tag.view
quo.components.tags.context-tag.view
quo.components.tags.network-tags.view
quo.components.tags.number-tag.view
@@ -156,6 +157,7 @@
quo.components.wallet.account-overview.view
quo.components.wallet.account-permissions.view
quo.components.wallet.address-text.view
quo.components.wallet.amount-input.view
quo.components.wallet.confirmation-progress.view
quo.components.wallet.keypair.view
quo.components.wallet.network-amount.view
@@ -387,6 +389,7 @@
(def account-selector quo.components.tabs.account-selector/account-selector)
;;;; Tags
(def collectible-tag quo.components.tags.collectible-tag.view/view)
(def context-tag quo.components.tags.context-tag.view/view)
(def network-tags quo.components.tags.network-tags.view/view)
(def number-tag quo.components.tags.number-tag.view/view)
@@ -414,6 +417,7 @@
(def account-overview quo.components.wallet.account-overview.view/view)
(def account-permissions quo.components.wallet.account-permissions.view/view)
(def address-text quo.components.wallet.address-text.view/view)
(def amount-input quo.components.wallet.amount-input.view/view)
(def confirmation-propgress quo.components.wallet.confirmation-progress.view/view)
(def keypair quo.components.wallet.keypair.view/view)
(def network-amount quo.components.wallet.network-amount.view/view)
+1
View File
@@ -90,6 +90,7 @@
quo.components.wallet.account-origin.component-spec
quo.components.wallet.account-overview.component-spec
quo.components.wallet.account-permissions.component-spec
quo.components.wallet.amount-input.component-spec
quo.components.wallet.confirmation-progress.component-spec
quo.components.wallet.keypair.component-spec
quo.components.wallet.network-amount.component-spec
+4 -1
View File
@@ -20,7 +20,8 @@
LinearTransition
enableLayoutAnimations
useAnimatedScrollHandler
runOnJS)]
runOnJS)
:as reanimated*]
["react-native-redash" :refer (withPause)]
[oops.core :as oops]
[react-native.flat-list :as rn-flat-list]
@@ -113,6 +114,8 @@
(when (and anim (some? v))
(set! (.-value anim) v)))
(def interpolate* reanimated*/interpolate)
(defn interpolate
([shared-value input-range output-range]
(interpolate shared-value input-range output-range nil))
+1 -1
View File
@@ -22,7 +22,7 @@
{:min 1}
[:map
{:closed true}
[:method :string]
[:method [:or :keyword :string]]
[:params [:sequential :any]]
[:js-response {:optional true} :any]
[:on-success [:or fn? [:cat keyword? [:* :any]]]]
+34 -29
View File
@@ -54,38 +54,43 @@
(defn share-qr-code
"Receives the following properties:
- type: :profile | :wallet-legacy | :wallet-multichain
- qr-data: Text to encode in the QR code
- qr-data-label-shown: Text to show below the QR code
- on-text-press: Callback for the `qr-data-label-shown` text.
- on-text-long-press: Callback for the `qr-data-label-shown` text.
- on-share-press: Callback for the share button.
- customization-color: Custom color for the QR code component.
- unblur-on-android?: [Android only] disables blur for this component.
Depending on the `type`, different properties are accepted:
`:profile`
- full-name: User full name.
- profile-picture: map ({:source image-source}) or any image source.
`:wallet-legacy`
- emoji: Emoji in a string to show in the QR code.
- on-info-press: Callback for the info icon.
- on-legacy-press: Callback for the legacy tab.
- on-multichain-press: Callback for the multichain tab.
`:wallet-multichain`
- networks: A vector of network names (`[:ethereum, :optimism, :my-net, ,,,]`)
they will add network prefixes to the address in
`qr-data-label-shown` and the QR code generated.
- on-settings-press: Callback for the settings button.
- emoji: Emoji in a string to show in the QR code.
- on-info-press: Callback for the info icon.
- on-legacy-press: Callback for the legacy tab.
- on-multichain-press: Callback for the multichain tab."
[{:keys [qr-data qr-data-label-shown networks]
- type: :profile | :wallet | :saved-address | :watched-address
- qr-image-uri: Image source value.
- qr-data: Text to show below the QR code.
- on-text-press: Callback for the `qr-data` text.
- on-text-long-press: Callback for the `qr-data` text.
- on-share-press: Callback for the share button.
- customization-color: Custom color for the QR code component.
- unblur-on-android?: [Android only] disables blur for this component.
- full-name: User full name.
Depending on the `type`, different properties are accepted:
`:profile`
- profile-picture: map ({:source image-source}) or any image source.
`:wallet`
- networks: A vector of network names as keywords (`[:ethereum, :my-net, ...]`).
- emoji: Emoji in a string to show in the QR code.
- on-legacy-press: Callback for the legacy tab.
- on-multichain-press: Callback for the multichain tab.
- address: :legacy | :multichain
`:saved-address`
- networks: A vector of network names as keywords (`[:ethereum, :my-net, ...]`).
- on-settings-press: Callback for the settings button.
- on-legacy-press: Callback for the legacy tab.
- address: :legacy | :multichain
- on-multichain-press: Callback for the multichain tab.
`:watched-address`
- networks: A vector of network names as keywords (`[:ethereum, :my-net, ...]`).
- on-settings-press: Callback for the settings button.
- emoji: Emoji in a string to show in the QR code.
- on-legacy-press: Callback for the legacy tab.
- address: :legacy | :multichain
- on-multichain-press: Callback for the multichain tab."
[{:keys [qr-data qr-data-label-shown networks address]
share-qr-type :type
:as props}]
(let [label (or qr-data-label-shown qr-data)
string-to-encode (if (= share-qr-type :wallet-multichain)
string-to-encode (if (and (= share-qr-type :wallet) (= address :multichain))
(get-qr-data-for-wallet-multichain qr-data networks)
qr-data)
qr-media-server-uri (image-server/get-qr-image-uri-for-any-url
+5 -3
View File
@@ -1,9 +1,11 @@
(ns status-im.common.toasts.style)
(ns status-im.common.toasts.style
(:require [react-native.safe-area :as safe-area]))
(def outmost-transparent-container
(defn outmost-transparent-container
[]
{:elevation 2
:pointer-events :box-none
:padding-top 52
:padding-top (+ (safe-area/get-top) 6)
:flex-direction :column
:justify-content :center
:align-items :center})
+1 -1
View File
@@ -60,5 +60,5 @@
[]
(->> (rf/sub [:toasts])
:ordered
(into [rn/view {:style style/outmost-transparent-container}]
(into [rn/view {:style (style/outmost-transparent-container)}]
(map #(with-meta [:f> f-container %] {:key %})))))
-5
View File
@@ -169,8 +169,3 @@
(def community-accounts-selection-enabled? (enabled? (get-config :ACCOUNT_SELECTION_ENABLED "0")))
(def fetch-messages-enabled? (enabled? (get-config :FETCH_MESSAGES_ENABLED "1")))
(def wallet-feature-flags
{:edit-default-keypair false
:bridge-token false
:remove-account false})
+3
View File
@@ -159,6 +159,9 @@
community-token-permission-become-token-master
community-token-permission-become-token-owner})
(def ^:const community-token-type-erc20 1)
(def ^:const community-token-type-erc721 2)
;; Community rules for joining
(def ^:const community-rule-ens-only "ens-only")
@@ -153,19 +153,19 @@
50)}]))
:max-duration-ms constants/audio-max-duration-ms}]]))
(defn images-limit-toast
(defn photo-limit-toast
[]
(rf/dispatch [:toasts/upsert
{:id :random-id
:type :negative
:container-style {:top (when platform/ios? 20)}
:text (i18n/label :t/only-6-images)}]))
{:id :random-id
:type :negative
:text (i18n/label :t/hit-photos-limit
{:max-photos constants/max-album-photos})}]))
(defn go-to-camera
[images-count]
(device-permissions/camera #(if (>= images-count constants/max-album-photos)
(images-limit-toast)
(photo-limit-toast)
(rf/dispatch [:navigate-to :camera-screen]))))
(defn camera-button
@@ -151,7 +151,6 @@
:icon :i/pin
:counter-value pins-count
:on-press (fn []
(rf/dispatch [:dismiss-keyboard])
(rf/dispatch [:pin-message/show-pins-bottom-sheet
chat-id]))}
{:accessibility-label :action-button-mute
@@ -55,6 +55,7 @@
^js identity-images (.-identityImages response-js)
^js accounts (.-accounts response-js)
^js ens-username-details-js (.-ensUsernameDetails response-js)
^js customization-color-js (.-customizationColor response-js)
sync-handler (when-not process-async process-response)]
(cond
@@ -204,7 +205,14 @@
(js-delete response-js "ensUsernameDetails")
(rf/merge cofx
(process-next response-js sync-handler)
(rf/dispatch [:ens/update-usernames ens-username-details-clj]))))))
(rf/dispatch [:ens/update-usernames ens-username-details-clj])))
(seq customization-color-js)
(let [customization-color (types/js->clj customization-color-js)]
(js-delete response-js "customizationColor")
(rf/merge cofx
(process-next response-js sync-handler)
(rf/dispatch [:profile/save-local-accent-color (keyword customization-color)]))))))
(defn group-by-and-update-unviewed-counts
"group messages by current chat, profile updates, transactions and update unviewed counters in db for not curent chats"
@@ -75,3 +75,6 @@
{:position :absolute
:top 8
:right 8})
(def photo-limit-toast-container
{:top (if platform/ios? 6 16)})
@@ -4,7 +4,6 @@
[react-native.core :as rn]
[react-native.gesture :as gesture]
[react-native.linear-gradient :as linear-gradient]
[react-native.platform :as platform]
[react-native.reanimated :as reanimated]
[react-native.safe-area :as safe-area]
[reagent.core :as reagent]
@@ -17,13 +16,14 @@
(def min-scroll-to-blur 5)
(defn show-toast
(defn show-photo-limit-toast
[]
(rf/dispatch [:toasts/upsert
{:id :random-id
:type :negative
:container-style {:top (when platform/ios? 20)}
:text (i18n/label :t/only-6-images)}]))
:container-style style/photo-limit-toast-container
:text (i18n/label :t/hit-photos-limit
{:max-photos constants/max-album-photos})}]))
(defn on-press-confirm-selection
[selected close]
@@ -74,7 +74,7 @@
(if item-selected?
(swap! selected remove-selected item)
(if (>= (count @selected) constants/max-album-photos)
(show-toast)
(show-photo-limit-toast)
(swap! selected conj item))))
:accessibility-label (str "image-" index)}
[rn/image
@@ -18,7 +18,7 @@
{:community-id id :password %}])}])
(rf/dispatch [:navigate-back]))
(defn f-view-internal
(defn view
[]
(let [{id :community-id} (rf/sub [:get-screen-params])
{:keys [name color images]} (rf/sub [:communities/community id])
@@ -83,7 +83,3 @@
:track-icon :i/face-id
:customization-color color
:on-complete #(join-community-and-navigate-back id)}]]]))
(defn view
[]
[:f> f-view-internal])
@@ -0,0 +1,58 @@
(ns status-im.contexts.communities.actions.addresses-for-permissions.events
(:require
[schema.core :as schema]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(defn get-permissioned-balances
[{[event-id _] :original-event} [community-id]]
{:fx [[:json-rpc/call
[{:method :wakuext_getCommunityPermissionedBalances
:params [{:communityId community-id}]
:on-success [:communities/get-permissioned-balances-success community-id]
:on-error (fn [error]
(log/error "failed to get balances"
{:community-id community-id
:event event-id
:error error}))}]]]})
(schema/=> get-permissioned-balances
[:=>
[:catn
[:cofx :schema.re-frame/cofx]
[:args [:schema [:catn [:community-id :string]]]]]
[:map {:closed true}
[:fx
[:tuple
[:tuple [:= :json-rpc/call] :schema.common/rpc-call]]]]])
(rf/reg-event-fx :communities/get-permissioned-balances get-permissioned-balances)
(defn get-permissioned-balances-success
[{:keys [db]} [community-id response]]
{:db (assoc-in db [:communities/permissioned-balances community-id] response)})
(def ^:private ?account-address keyword?)
(def ^:private ?permissioned-balances-response
[:map-of
?account-address
[:sequential
[:map
[:type int?]
[:symbol string?]
[:decimals int?]
[:amount string?]]]])
(schema/=> get-permissioned-balances-success
[:=>
[:catn
[:cofx :schema.re-frame/cofx]
[:args
[:schema
[:catn
[:community-id string?]
[:response ?permissioned-balances-response]]]]]
map?])
(rf/reg-event-fx :communities/get-permissioned-balances-success get-permissioned-balances-success)
@@ -0,0 +1,15 @@
(ns status-im.contexts.communities.actions.addresses-for-permissions.events-test
(:require
[cljs.test :refer [deftest is]]
[status-im.contexts.communities.actions.addresses-for-permissions.events :as sut]))
(def community-id "0x1")
(deftest get-permissioned-balances-test
(let [cofx {:db {}}]
(is (match? {:fx [[:json-rpc/call
[{:method :wakuext_getCommunityPermissionedBalances
:params [{:communityId community-id}]
:on-success [:communities/get-permissioned-balances-success community-id]
:on-error fn?}]]]}
(sut/get-permissioned-balances cofx [community-id])))))
@@ -8,12 +8,6 @@
:padding-horizontal 20
:padding-vertical 12})
(def error-message
{:flex-direction :row
:gap 4
:justify-content :center
:margin-bottom 8})
(def highest-role
{:flex-direction :row
:gap 4
@@ -3,90 +3,111 @@
[quo.foundations.colors :as colors]
[react-native.core :as rn]
[status-im.common.not-implemented :as not-implemented]
[status-im.common.resources :as resources]
[status-im.constants :as constants]
[status-im.contexts.communities.actions.addresses-for-permissions.style :as style]
[status-im.contexts.communities.utils :as communities.utils]
[utils.i18n :as i18n]
[utils.money :as money]
[utils.re-frame :as rf]))
(defn- balances->components-props
[balances]
(for [{:keys [amount decimals type name] :as balance} balances]
(cond-> balance
true
(assoc :type
(condp = type
constants/community-token-type-erc20 :token
constants/community-token-type-erc721 :collectible
:token))
(= type constants/community-token-type-erc721)
(assoc :collectible-name name
:collectible-img-src (resources/get-mock-image :collectible))
(= type constants/community-token-type-erc20)
(assoc :amount (str (money/with-precision (money/token->unit amount decimals) 3))
:token (:symbol balance)))))
(defn- account-item
[item _ _ [selected-addresses community-id]]
[quo/account-permissions
{:account {:name (:name item)
:address (:address item)
:emoji (:emoji item)
:customization-color (:customization-color item)}
:token-details []
:checked? (contains? selected-addresses (:address item))
:on-change #(rf/dispatch [:communities/toggle-selected-permission-address
(:address item) community-id])
:container-style {:margin-bottom 8}}])
[{:keys [customization-color address name emoji]} _ _ [selected-addresses community-id]]
(let [balances (rf/sub [:communities/permissioned-balances-by-address community-id address])]
[quo/account-permissions
{:account {:name name
:address address
:emoji emoji
:customization-color customization-color}
:token-details (balances->components-props balances)
:checked? (contains? selected-addresses address)
:on-change #(rf/dispatch [:communities/toggle-selected-permission-address
address community-id])
:container-style {:margin-bottom 8}}]))
(defn view
[]
(let [{id :community-id} (rf/sub [:get-screen-params])
{:keys [name color images]} (rf/sub [:communities/community id])
{:keys [highest-permission-role]} (rf/sub [:community/token-gated-overview id])
accounts (rf/sub [:wallet/accounts-with-customization-color])
selected-addresses (rf/sub [:communities/selected-permission-addresses id])
highest-role-text
(i18n/label
(communities.utils/role->translation-key highest-permission-role))]
[rn/safe-area-view {:style style/container}
[quo/drawer-top
{:type :context-tag
:title (i18n/label :t/addresses-for-permissions)
:context-tag-type :community
:community-name name
:button-icon :i/info
:on-button-press not-implemented/alert
:community-logo (get-in images [:thumbnail :uri])
:customization-color color}]
(let [{id :community-id} (rf/sub [:get-screen-params])]
(rf/dispatch [:communities/get-permissioned-balances id])
(fn []
(let [{:keys [name color images]} (rf/sub [:communities/community id])
{:keys [highest-permission-role]} (rf/sub [:community/token-gated-overview id])
accounts (rf/sub [:wallet/accounts-with-customization-color])
selected-addresses (rf/sub [:communities/selected-permission-addresses id])
highest-role-text (when highest-permission-role
(i18n/label (communities.utils/role->translation-key
highest-permission-role)))]
[rn/safe-area-view {:style style/container}
[quo/drawer-top
{:type :context-tag
:title (i18n/label :t/addresses-for-permissions)
:context-tag-type :community
:community-name name
:button-icon :i/info
:on-button-press not-implemented/alert
:community-logo (get-in images [:thumbnail :uri])
:customization-color color}]
[rn/flat-list
{:render-fn account-item
:render-data [selected-addresses id]
:content-container-style {:padding 20}
:key-fn :address
:data accounts}]
[rn/flat-list
{:render-fn account-item
:render-data [selected-addresses id]
:content-container-style {:padding 20}
:key-fn :address
:data accounts}]
(when (and highest-permission-role (seq selected-addresses))
[rn/view
{:style style/highest-role}
[quo/text
{:size :paragraph-2
:style {:color colors/neutral-50}}
(i18n/label :t/eligible-to-join-as {:role ""})]
[quo/context-tag
{:type :icon
:icon :i/members
:size 24
:context highest-role-text}]])
(if (and highest-permission-role (seq selected-addresses))
[rn/view
{:style style/highest-role}
[quo/text
{:size :paragraph-2
:style {:color colors/neutral-50}}
(i18n/label :t/eligible-to-join-as)]
[quo/context-tag
{:type :icon
:icon :i/members
:size 24
:context highest-role-text}]]
[quo/info-message
{:type :error
:size :default
:icon :i/info
:style {:justify-content :center}}
(if (empty? selected-addresses)
(i18n/label :t/no-addresses-selected)
(i18n/label :t/addresses-dont-contain-tokens-needed))])
(when (empty? selected-addresses)
[rn/view
{:style style/error-message}
[quo/icon
:i/info
{:color colors/danger-50
:size 16}]
[quo/text
{:size :paragraph-2
:style {:color colors/danger-50}}
(i18n/label :t/no-addresses-selected)]])
[rn/view {:style style/buttons}
[quo/button
{:type :grey
:container-style {:flex 1}
:on-press (fn []
(rf/dispatch [:communities/reset-selected-permission-addresses id])
(rf/dispatch [:navigate-back]))}
(i18n/label :t/cancel)]
[quo/button
{:container-style {:flex 1}
:customization-color color
:disabled? (empty? selected-addresses)
:on-press (fn []
(rf/dispatch [:communities/update-previous-permission-addresses id])
[rn/view {:style style/buttons}
[quo/button
{:type :grey
:container-style {:flex 1}
:on-press (fn []
(rf/dispatch [:communities/reset-selected-permission-addresses id])
(rf/dispatch [:navigate-back]))}
(i18n/label :t/confirm-changes)]]]))
(i18n/label :t/cancel)]
[quo/button
{:container-style {:flex 1}
:customization-color color
:disabled? (empty? selected-addresses)
:on-press (fn []
(rf/dispatch [:communities/update-previous-permission-addresses id])
(rf/dispatch [:navigate-back]))}
(i18n/label :t/confirm-changes)]]]))))
@@ -9,6 +9,7 @@
[schema.core :as schema]
[status-im.constants :as constants]
[status-im.contexts.chat.messenger.messages.link-preview.events :as link-preview.events]
status-im.contexts.communities.actions.addresses-for-permissions.events
status-im.contexts.communities.actions.community-options.events
status-im.contexts.communities.actions.leave.events
[status-im.navigation.events :as navigation]
@@ -0,0 +1,5 @@
(ns status-im.contexts.preview.feature-flags.style)
(def container
{:flex 1
:margin-left 20})
@@ -0,0 +1,39 @@
(ns status-im.contexts.preview.feature-flags.view
(:require
[clojure.string :as string]
[quo.core :as quo]
[re-frame.core :as rf]
[react-native.core :as rn]
[status-im.contexts.preview.feature-flags.style :as style]
[status-im.feature-flags :as ff]))
(defn view
[]
[rn/view {:style {:flex 1}}
[quo/page-nav
{:type :title
:text-align :left
:title "Features Flags"
:icon-name :i/arrow-left
:on-press #(rf/dispatch [:navigate-back])}]
(doall
(for [context-name ff/feature-flags-categories
:let [context-flags (filter (fn [[k]]
(string/includes? (str k) context-name))
(ff/feature-flags))]]
^{:key (str context-name)}
[rn/view {:style style/container}
[quo/text
context-name]
(doall
(for [i (range (count context-flags))
:let [[flag] (nth context-flags i)]]
^{:key (str context-name flag i)}
[rn/view {:style {:flex-direction :row}}
[quo/selectors
{:type :toggle
:checked? (ff/enabled? flag)
:container-style {:margin-right 8}
:on-change #(ff/toggle flag)}]
[quo/text (second (string/split (name flag) "."))]]))]))])
@@ -19,8 +19,10 @@
(def descriptor
[{:type :select
:key :actions
:options [{:key :1-action}
{:key :2-actions}]}
:options [{:key :one-action}
{:key :two-actions}]}
{:key :button-one-label
:type :text}
{:label "Button 1 type"
:type :select
:key :type
@@ -30,6 +32,8 @@
:type :boolean
:key :disabled?
:path [:button-one-props]}
{:key :button-two-label
:type :text}
{:label "Button 2 type"
:type :select
:key :type
@@ -39,32 +43,59 @@
:type :boolean
:key :disabled?
:path [:button-two-props]}
{:key :description
:type :text}
{:key :button-one-label
:type :text}
{:key :button-two-label
:type :text}
{:key :blur?
:type :boolean}
{:key :scroll?
:type :boolean}])
:type :boolean}
{:key :description
:type :select
:options [{:key nil
:value :none}
{:key :top}
{:key :bottom}
{:key :top-error}]}])
(def role-descriptor
{:key :role
:type :select
:options [{:key :owner}
{:key :token-master}
{:key :admin}
{:key :member}]})
(def description-descriptor
{:key :description-text
:type :text})
(def error-descriptor
{:key :error-message
:type :text})
(defn view
[]
(let [state (reagent/atom {:actions :2-actions
:description description
(let [state (reagent/atom {:actions :two-actions
:description :bottom
:description-text description
:error-message "Error message"
:button-one-label button-one
:button-two-label button-two
:button-one-props {:on-press (button-press 1)
:type :primary
:icon-left :i/arrow-up}
:button-one-props {:on-press (button-press 1)
:type :primary}
:button-two-props {:on-press (button-press 2)
:type :grey}
:blur? false
:role :owner
:scroll? false})]
(fn []
[preview/preview-container
{:state state
:descriptor descriptor
:blur? (:scroll? @state)
:descriptor (merge descriptor
(case (:description @state)
:top role-descriptor
:bottom description-descriptor
:top-error error-descriptor
nil))
:blur? (:blur? @state)
:show-blur-background? true
:blur-dark-only? true
:component-container-style {:margin-top 40
+7 -1
View File
@@ -158,6 +158,7 @@
[status-im.contexts.preview.quo.tabs.account-selector :as account-selector]
[status-im.contexts.preview.quo.tabs.segmented-tab :as segmented]
[status-im.contexts.preview.quo.tabs.tabs :as tabs]
[status-im.contexts.preview.quo.tags.collectible-tag :as collectible-tag]
[status-im.contexts.preview.quo.tags.context-tags :as context-tags]
[status-im.contexts.preview.quo.tags.network-tags :as network-tags]
[status-im.contexts.preview.quo.tags.number-tag :as number-tag]
@@ -178,6 +179,7 @@
[status-im.contexts.preview.quo.wallet.account-overview :as
account-overview]
[status-im.contexts.preview.quo.wallet.account-permissions :as account-permissions]
[status-im.contexts.preview.quo.wallet.amount-input :as amount-input]
[status-im.contexts.preview.quo.wallet.confirmation-progress :as
confirmation-progress]
[status-im.contexts.preview.quo.wallet.keypair :as keypair]
@@ -457,7 +459,9 @@
:component tabs/view}
{:name :account-selector
:component account-selector/view}]
:tags [{:name :context-tags
:tags [{:name :collectible-tag
:component collectible-tag/view}
{:name :context-tags
:component context-tags/view}
{:name :network-tags
:component network-tags/view}
@@ -493,6 +497,8 @@
:component account-overview/view}
{:name :account-permissions
:component account-permissions/view}
{:name :amount-input
:component amount-input/view}
{:name :confirmation-progress
:component confirmation-progress/view}
{:name :keypair :component keypair/view}
@@ -1,7 +1,6 @@
(ns status-im.contexts.preview.quo.share.share-qr-code
(:require
[quo.core :as quo]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im.common.resources :as resources]
[status-im.contexts.preview.quo.preview :as preview]
@@ -15,8 +14,23 @@
{:key :type
:type :select
:options [{:key :profile}
{:key :wallet-legacy}
{:key :wallet-multichain}]}])
{:key :wallet}
{:key :saved-address}
{:key :watched-address}]}])
(def possible-networks [:ethereum :optimism :arbitrum :myNet])
(def networks-selector
{:key :networks
:type :select
:options [{:key (take 1 possible-networks)
:value "Ethereum"}
{:key (take 2 possible-networks)
:value "Ethereum and Optimism"}
{:key (take 3 possible-networks)
:value "Ethereum, Optimism and Arbitrum"}
{:key (take 4 possible-networks)
:value "Ethereum, Optimism, Arbitrum and unknown"}]})
(def profile-descriptor
[{:key :profile-picture
@@ -24,40 +38,44 @@
:options [{:key (resources/get-mock-image :user-picture-female2)
:value "User 1"}
{:key (resources/get-mock-image :user-picture-male4)
:value "User 2"}
{:key nil
:value "No picture"}]}
:value "User 2"}]}
{:key :full-name
:type :text}
(preview/customization-color-option)])
(def wallet-legacy-descriptor
[{:key :emoji
(def wallet-descriptor
[{:key :address
:type :select
:options [{:key :legacy}
{:key :multichain}]}
{:key :emoji
:type :select
:options [{:key "🐈"}
{:key "👻"}
{:key "🐧"}]}
networks-selector
(preview/customization-color-option)])
(def possible-networks [:ethereum :optimism :arbitrum :myNet])
(def saved-address-descriptor
[{:key :address
:type :select
:options [{:key :legacy}
{:key :multichain}]}
networks-selector
(preview/customization-color-option)])
(def wallet-multichain-descriptor
[{:key :emoji
(def watched-address-descriptor
[{:key :address
:type :select
:options [{:key :legacy}
{:key :multichain}]}
{:key :emoji
:type :select
:options [{:key "🐈"}
{:key "👻"}
{:key "🐧"}]}
(preview/customization-color-option)
{:key :networks
:type :select
:options [{:key (take 1 possible-networks)
:value "Ethereum"}
{:key (take 2 possible-networks)
:value "Ethereum and Optimism"}
{:key (take 3 possible-networks)
:value "Ethereum, Optimism and Arbitrum"}
{:key (take 4 possible-networks)
:value "Ethereum, Optimism, Arbitrum and unknown"}]}])
networks-selector
(preview/customization-color-option)])
(defn- get-network-short-name-url
[network]
@@ -84,22 +102,23 @@
(defn view
[]
(let [state (reagent/atom {:type :profile
:address :legacy
:qr-data profile-link
:on-share-press #(js/alert "share pressed")
:on-text-press #(js/alert "text pressed")
:on-text-long-press #(js/alert "text long press")
:profile-picture nil
:profile-picture (resources/get-mock-image :user-picture-female2)
:full-name "My User"
:customization-color :purple
:emoji "🐈"
:on-info-press #(js/alert "Info pressed")
:on-legacy-press #(js/alert (str "Tab " % " pressed"))
:on-multichain-press #(js/alert (str "Tab " % " pressed"))
:networks (take 2 possible-networks)
:on-settings-press #(js/alert "Settings pressed")})
_ (add-watch state :change set-qr-data-based-on-type)]
(fn []
(let [qr-url (if (= (:type @state) :wallet-multichain)
(let [qr-url (if (and (= (:address @state) :multichain)
(not= (:type @state) :profile))
(as-> (:networks @state) $
(map get-network-short-name-url $)
(apply str $)
@@ -112,31 +131,20 @@
:error-level :highest})
typed-descriptor (concat descriptor
(case (:type @state)
:profile profile-descriptor
:wallet-legacy wallet-legacy-descriptor
:wallet-multichain wallet-multichain-descriptor
:profile profile-descriptor
:wallet wallet-descriptor
:saved-address saved-address-descriptor
:watched-address watched-address-descriptor
nil))]
[preview/preview-container
{:state state
:descriptor typed-descriptor
:component-container-style {:padding-horizontal 0}}
[rn/view
{:style {:flex 1
:justify-content :flex-end
:align-items :center
:padding-horizontal 20
:padding-vertical 30}}
[rn/view
{:style {:position :absolute
:top 0
:bottom 0
:left 0
:right 0}}
[rn/image
{:style {:flex 1
:resize-mode :stretch}
:source (resources/get-mock-image :dark-blur-bg)}]]
[quo/share-qr-code
(assoc @state
:qr-image-uri qr-media-server-uri
:qr-data qr-url)]]]))))
:blur? true
:blur-height 500
:component-container-style {:padding-horizontal 0}
:show-blur-background? true
:blur-dark-only? true}
[quo/share-qr-code
(assoc @state
:qr-image-uri qr-media-server-uri
:qr-data qr-url)]]))))
@@ -0,0 +1,51 @@
(ns status-im.contexts.preview.quo.tags.collectible-tag
(:require
[oops.core :refer [oget]]
[quo.core :as quo]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im.common.resources :as resources]
[status-im.contexts.preview.quo.preview :as preview]))
(def descriptor
[{:key :size
:type :select
:options [{:key :size-24
:value "Size 24"}
{:key :size-32
:value "Size 32"}]}
{:key :options
:type :select
:options [{:key false
:value false}
{:key :add
:value :add}
{:key :hold
:value :hold}]}
{:key :blur?
:type :boolean}
{:key :collectible-name
:type :text}
{:key :collectible-id
:type :text}])
(defn view
[]
(let [state (reagent/atom {:size :size-24
:collectible-name "Collectible"
:collectible-id "#123"
:collectible-img-src (resources/mock-images :collectible)
:options false
:blur? false
:container-width 0})
on-layout #(swap! state assoc
:container-width
(oget % :nativeEvent :layout :width))]
(fn []
[preview/preview-container
{:state state
:blur? (:blur? @state)
:show-blur-background? true
:descriptor descriptor}
[rn/view {:style {:align-items :center}}
[quo/collectible-tag (assoc @state :on-layout on-layout)]]])))
@@ -0,0 +1,29 @@
(ns status-im.contexts.preview.quo.wallet.amount-input
(:require
[quo.core :as quo]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]))
(def descriptor
[{:key :max-value
:type :number}
{:key :min-value
:type :number}
{:key :init-value
:type :number}
{:type :select
:key :status
:options [{:key :default}
{:key :error}]}])
(defn view
[]
(let [state (reagent/atom {:max-value 10000
:min-value 0
:init-value 1
:status :default})]
(fn []
[preview/preview-container
{:state state
:descriptor descriptor}
[quo/amount-input @state]])))
@@ -6,7 +6,7 @@
[status-im.contexts.preview.quo.preview :as preview]))
(def descriptor
[{:type :text
[{:type :number
:key :progress-value}
{:type :select
:key :network
@@ -78,7 +78,7 @@
[]
(let [state (reagent/atom
{:total-box total-box
:progress-value "10"
:progress-value 10
:network :mainnet
:state :pending
:customization-color :blue})]
@@ -19,9 +19,9 @@
:key :epoch-number-arbitrum}
{:type :text
:key :tag-number}
{:type :text
{:type :number
:key :optimism-progress-percentage}
{:type :text
{:type :number
:key :arbitrum-progress-percentage}
{:type :select
:key :network
@@ -142,8 +142,8 @@
:epoch-number-mainnet "181,329"
:epoch-number-optimism "181,329"
:epoch-number-arbitrum "181,329"
:optimism-progress-percentage "10"
:arbitrum-progress-percentage "10"
:optimism-progress-percentage 10
:arbitrum-progress-percentage 10
:network :mainnet
:state-mainnet :pending
:state-arbitrum :pending
@@ -0,0 +1,30 @@
(ns status-im.contexts.profile.edit.accent-colour.events
(:require [taoensso.timbre :as log]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(rf/reg-event-fx :profile/edit-accent-colour-success
(fn [_ [customization-color]]
{:fx [[:dispatch [:profile/save-local-accent-color customization-color]]
[:dispatch [:navigate-back]]
[:dispatch
[:toasts/upsert
{:type :positive
:theme :dark
:text (i18n/label :t/accent-colour-updated)}]]]}))
(rf/reg-event-fx :profile/save-local-accent-color
(fn [{:keys [db]} [customization-color]]
{:db (assoc-in db [:profile/profile :customization-color] customization-color)}))
(defn edit-accent-colour
[{:keys [db]} [customization-color]]
(let [key-uid (get-in db [:profile/profile :key-uid])]
{:fx [[:json-rpc/call
[{:method "wakuext_setCustomizationColor"
:params [{:customizationColor customization-color
:keyUid key-uid}]
:on-success [:profile/edit-accent-colour-success customization-color]
:on-error #(log/error "failed to edit accent color." {:error %})}]]]}))
(rf/reg-event-fx :profile/edit-accent-colour edit-accent-colour)

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