Compare commits

..
Author SHA1 Message Date
alwx 7376ae1509 Updates for unread messages indicator 2023-10-02 17:30:58 +02:00
Mohsen ee85d6d596 [#17288] refactor: migrate previews to new api (#17470) 2023-10-02 16:28:35 +03:00
Omar Basem d8d8a6c7a0 Quo2: Token Input followup (#17419)
* Quo2: token input followup
2023-10-02 09:01:39 +04:00
jakub f5f1e6302d ci: use new OpenSea API keys
They are split by both platform and build type.

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

Signed-off-by: Jakub Sokołowski <jakub@status.im>
2023-09-29 16:32:45 +02:00
Mohamed Javid 9c26a54006 Add network-dropdown to wallet-overview component (#17440)
This commit adds the "network-dropdown" component to the "wallet-overview" component.

Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com>
2023-09-29 18:53:06 +05:30
codemaster ab868a6ae5 Implement switcher group messaging card (#16802) 2023-09-29 23:11:21 +10:00
Parvesh Monu 695bbcbe81 fix bottom tabs unread badge for group chats (#17454) 2023-09-29 17:59:35 +05:30
Mohamed Javid bf76ca167a Implement dropdown component and update it's usage across the codebase (#17412)
This commit: 

- Removes the existing dropdown component which uses the old button component under the hood
- Implements the Dropdown component
- Updates the usage in the page-nav component for types dropdown, token and wallet-networks
- Updates the usage in the photo selector bottom sheet
- Updates the usage in the Quo2 preview main screen

---------

Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com>
2023-09-29 17:37:27 +05:30
Ulises Manuel af1942dff3 [#17220] - New 64 avatars size (#17283)
* Add 64 size for user-avatar

* Add 64 size for channel-avatar

* Add 64 size for account-avatar

* Add 64 size for wallet-avatar
2023-09-29 03:48:02 -06:00
yqrashawn 1c31127a6f fix: missing/empty user-avatar in component previews (#17430) 2023-09-29 15:30:04 +08:00
Ajay Sivan fe404ab005 Remove old quo code from status_im2 namespace (#17404) 2023-09-28 09:27:31 -07:00
Brian Sztamfater 8869271054 feat: implement account list item component (#17303)
Signed-off-by: Brian Sztamfater <brian@status.im>
2023-09-28 12:27:36 -03:00
Brian Sztamfater 5ea78084d1 feat: implement saved address component (#17398)
Signed-off-by: Brian Sztamfater <brian@status.im>
2023-09-28 12:13:49 -03:00
Mohsen ba57ab9ae4 [#17288] refactor: migrate previews to new api (#17420) 2023-09-28 15:26:15 +03:00
0522120c66 Standardized in-app authentication (#16916)
* chore: move password input to connected component
---------

Co-authored-by: Jamie Caprani <jamiecaprani@gmail.com>
Co-authored-by: frank <lovefree103@gmail.com>
2023-09-28 04:23:15 -07:00
Parvesh Monu 6b9b5fa300 Only use animated loading skeleton for ios (#17432) 2023-09-27 20:43:21 +05:30
Omar Basem 77733b3a65 Quo2: Color picker (#17405)
* Quo2: color picker
2023-09-27 15:34:16 +04:00
Volodymyr Kozieiev 79f7b6c6ba Transaction summary design followup fixes (#17360) 2023-09-27 11:54:41 +01:00
flexsurfer db787f9d4b remove status-im.utils.clocks (#17434) 2023-09-27 12:04:40 +02:00
flexsurfer a847f508f9 [#17410] migrate status-im.ethereum.core (#17422) 2023-09-27 11:57:51 +02:00
Lungu Cristian 4152b9318b Quo2: section label (#17219)
* feat: added section-label to quo2

* fix: addressed review comments

* ref: reorder and small change

* fix: blur only for dark and adjusted styling
2023-09-27 12:07:10 +03:00
220 changed files with 3510 additions and 2310 deletions
-5
View File
@@ -136,11 +136,6 @@ quo.animated/re-timing
quo.design-system.colors/white
quo.design-system.colors/black
status-im.transport.core-test/messages
status-im.ethereum.core/sidechain?
status-im.ethereum.core/network-with-upstream-rpc?
status-im.ethereum.core/current-address
status-im.ethereum.core/network->network-name
status-im.ethereum.core/estimate-gas
quo.core/animated-header
quo.core/safe-area-provider
quo.core/safe-area-consumer
+1
View File
@@ -311,6 +311,7 @@ endef
lint: export TARGET := clojure
lint: ##@test Run code style checks
@sh scripts/lint-re-frame-in-quo-components.sh && \
sh scripts/lint-old-quo-usage.sh \
clj-kondo --config .clj-kondo/config.edn --cache false --fail-level error --lint src && \
ALL_CLOJURE_FILES=$(call find_all_clojure_files) && \
zprint '{:search-config? true}' -sfc $$ALL_CLOJURE_FILES && \
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.7.14'
library 'status-jenkins-lib@v1.7.15'
/* Options section can't access functions in objects. */
def isPRBuild = utils.isPRBuild()
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.7.14'
library 'status-jenkins-lib@v1.7.15'
pipeline {
agent { label 'linux' }
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.7.14'
library 'status-jenkins-lib@v1.7.15'
pipeline {
agent { label 'linux' }
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@set_ios_status_go_targets'
library 'status-jenkins-lib@v1.7.15'
/* Options section can't access functions in objects. */
def isPRBuild = utils.isPRBuild()
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.7.14'
library 'status-jenkins-lib@v1.7.15'
/* Options section can't access functions in objects. */
def isPRBuild = utils.isPRBuild()
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.7.14'
library 'status-jenkins-lib@v1.7.15'
pipeline {
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.7.14'
library 'status-jenkins-lib@v1.7.15'
pipeline {
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.7.14'
library 'status-jenkins-lib@v1.7.15'
pipeline {
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.7.14'
library 'status-jenkins-lib@v1.7.15'
pipeline {
agent { label 'macos' }
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.7.14'
library 'status-jenkins-lib@v1.7.15'
pipeline {
agent { label params.AGENT_LABEL }
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.7.14'
library 'status-jenkins-lib@v1.7.15'
pipeline {
agent { label 'linux' }
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.7.14'
library 'status-jenkins-lib@v1.7.15'
pipeline {
agent {
+1 -1
View File
@@ -707,7 +707,7 @@ SPEC CHECKSUMS:
FBLazyVector: a8af91c2b5a0029d12ff6b32e428863d63c48991
FBReactNativeSpec: 1b2309b096448a1dc9d0c43999216f8fda809ae8
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
glog: d93527a855523adb8c113837db4be68fb00e230d
glog: 166d178815c300e8126de9a7900101814eb16253
HMSegmentedControl: 34c1f54d822d8308e7b24f5d901ec674dfa31352
Keycard: ac6df4d91525c3c82635ac24d4ddd9a80aca5fc8
libwebp: f62cb61d0a484ba548448a4bd52aabf150ff6eef
Binary file not shown.

Before

Width:  |  Height:  |  Size: 725 B

After

Width:  |  Height:  |  Size: 673 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1007 B

After

Width:  |  Height:  |  Size: 1001 B

+13
View File
@@ -0,0 +1,13 @@
#!/usr/bin/env sh
set -euo pipefail
QUO_USAGES=$(grep -r -E '\[quo\.[^ ]* :(?:as|refer)|\[quo\.[^ ]*\]' --include '*.cljs' --include '*.clj' './src/status_im2' --exclude='./src/status_im2/common/theme/core.cljs' || true)
echo -e "\nChecking 'status_im2' namespace for 'quo' namespace usage."
if [ -n "$QUO_USAGES" ]; then
echo -e "\033[0;31mERROR: Usage of the old 'quo' namespace detected in 'status_im2' code. Please update to 'quo2'. \n"
echo -e "$QUO_USAGES \033[0m"
exit 1
fi
+5 -3
View File
@@ -470,7 +470,8 @@
(defn sha3
[s]
(log/debug "[native-module] sha3")
(.sha3 ^js (status) s))
(when s
(.sha3 ^js (status) (str s))))
(defn utf8-to-hex
[s]
@@ -491,8 +492,9 @@
(defn address?
[address]
(log/debug "[native-module] address?")
(let [result (.isAddress ^js (status) address)]
(types/json->clj result)))
(when address
(let [result (.isAddress ^js (status) address)]
(types/json->clj result))))
(defn to-checksum-address
[address]
@@ -6,16 +6,20 @@
(def default-padding 16)
(def default-emoji-size 36)
(def ^:private container-size
{:size-64 64})
(defn get-border-radius
[size]
(case size
80 16
48 12
32 10
28 8
24 8
20 6
16 4
80 16
:size-64 16
48 12
32 10
28 8
24 8
20 6
16 4
default-border-radius))
(defn get-padding
@@ -33,29 +37,32 @@
(defn get-emoji-size
[size]
(case size
80 36
48 24
32 15
28 12
24 11
20 11
16 11
80 36
:size-64 30
48 24
32 15
28 12
24 11
20 11
16 11
default-emoji-size))
(defn get-border-width
[size]
(case size
16 0.8 ;; 0.8 px is for only size 16
;; Rest of the size will have 1 px
1))
(if (= size 16)
0.8 ;; 0.8 px is for only size 16
1)) ;; Rest of the size will have 1 px
(defn root-container
[{:keys [type size theme customization-color]
:or {size default-size
customization-color :blue}}]
(let [watch-only? (= type :watch-only)]
(cond-> {:width size
:height size
(let [watch-only? (= type :watch-only)
width (cond-> size
(keyword? size) (container-size size))]
(cond-> {:width width
:height width
:background-color (colors/custom-color-by-theme customization-color 50 60 nil nil theme)
:border-radius (get-border-radius size)
:border-color (if (= theme :light) colors/neutral-80-opa-5 colors/white-opa-5)
@@ -11,7 +11,7 @@
(h/test "with emoji, no lock set, large size"
(let [emoji "🍓"]
(h/render [component/view {:emoji emoji :size :size/l}])
(h/render [component/view {:emoji emoji :size :size-32}])
(h/is-null (h/query-by-label-text :initials))
(h/is-truthy (h/query-by-text emoji))
(h/is-null (h/query-by-label-text :lock))))
@@ -31,5 +31,5 @@
(h/test "no emoji, large size"
(h/render [component/view
{:full-name "Status Mobile"
:size :size/l}])
:size :size-32}])
(h/is-truthy (h/query-by-text "SM"))))
@@ -5,17 +5,27 @@
(defn outer-container
[{:keys [size color]}]
(let [size (if (= size :size/l) 32 24)]
{:width size
:height size
:border-radius size
(let [container-size (case size
:size-64 64
:size-32 32
24)]
{:width container-size
:height container-size
:border-radius container-size
:justify-content :center
:align-items :center
:background-color (colors/theme-alpha color 0.1 0.1)}))
(defn emoji-size
[size]
{:font-size (case size
:size-64 24
:size-32 15
11)})
(defn lock-container
[size]
(let [distance (if (= size :size/l) 20 12)]
(let [distance (if (= size :size-32) 20 12)]
{:position :absolute
:left distance
:top distance
@@ -5,17 +5,19 @@
[quo2.components.markdown.text :as text]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
utils.string))
[utils.string]))
(defn- initials
[full-name size color]
(let [amount-initials (if (= size :size/l) 2 1)
(let [amount-initials (if (#{:size-32 :size-64} size) 2 1)
channel-name (string/replace full-name "#" "")]
[text/text
{:accessibility-label :initials
:size :paragraph-2
:weight :semi-bold
:style {:color color}}
(cond-> {:accessibility-label :initials
:style {:color color}
:size :paragraph-2
:weight :semi-bold}
(= size :size-64) (assoc :size :heading-1
:weight :medium))
(utils.string/get-initials channel-name amount-initials)]))
(defn- lock
@@ -54,8 +56,8 @@
:style (style/outer-container {:size size :color customization-color})}
(if (string/blank? emoji)
[initials full-name size customization-color]
[text/text
{:accessibility-label :emoji
:size (if (= size :size/l) :paragraph-1 :label)}
[rn/text
{:style (style/emoji-size size)
:accessibility-label :emoji}
(string/trim emoji)])
[lock locked? size]])
@@ -28,9 +28,10 @@
(let [container-size (get-in sizes [size :container])
icon-size (get-in sizes [size :icon])]
[rn/view
{:style (style/container {:container-size container-size
:customization-color customization-color
:theme theme})}
{:accessibility-label :group-avatar
:style (style/container {:container-size container-size
:customization-color customization-color
:theme theme})}
(if picture
[fast-image/fast-image
{:source picture
@@ -2,48 +2,54 @@
(:require [quo2.foundations.colors :as colors]))
(def sizes
{:big {:dimensions 80
:status-indicator 12
:status-indicator-border 4
:status-indicator-center-to-edge 12
:font-size :heading-1
:ring-width 4}
:medium {:dimensions 48
:status-indicator 8
:status-indicator-border 2
:status-indicator-center-to-edge 6
:font-size :heading-2
:ring-width 2}
:small {:dimensions 32
:status-indicator 8
:status-indicator-border 2
:status-indicator-center-to-edge 4
:font-size :paragraph-2
:ring-width 2}
28 {:dimensions 28
:status-indicator 0
:status-indicator-border 0
:status-indicator-center-to-edge 0
:font-size :paragraph-2
:ring-width 0}
:xs {:dimensions 24
:status-indicator 0
:status-indicator-border 0
:status-indicator-center-to-edge 0
:font-size :paragraph-2
:ring-width 2}
:xxs {:dimensions 20
:status-indicator 0
:status-indicator-border 0
:status-indicator-center-to-edge 0
:font-size :label
:ring-width 2}
:xxxs {:dimensions 16
:status-indicator 0
:status-indicator-border 0
:status-indicator-center-to-edge 0
:font-size :label
:ring-width 2}})
{:big {:dimensions 80
:status-indicator 12
:status-indicator-border 4
:status-indicator-center-to-edge 12
:font-size :heading-1
:ring-width 4}
:size-64 {:dimensions 64
:status-indicator 8
:status-indicator-border 2
:status-indicator-center-to-edge 6
:font-size :heading-1
:ring-width 2}
:medium {:dimensions 48
:status-indicator 8
:status-indicator-border 2
:status-indicator-center-to-edge 6
:font-size :heading-2
:ring-width 2}
:small {:dimensions 32
:status-indicator 8
:status-indicator-border 2
:status-indicator-center-to-edge 4
:font-size :paragraph-2
:ring-width 2}
28 {:dimensions 28
:status-indicator 0
:status-indicator-border 0
:status-indicator-center-to-edge 0
:font-size :paragraph-2
:ring-width 0}
:xs {:dimensions 24
:status-indicator 0
:status-indicator-border 0
:status-indicator-center-to-edge 0
:font-size :paragraph-2
:ring-width 2}
:xxs {:dimensions 20
:status-indicator 0
:status-indicator-border 0
:status-indicator-center-to-edge 0
:font-size :label
:ring-width 2}
:xxxs {:dimensions 16
:status-indicator 0
:status-indicator-border 0
:status-indicator-center-to-edge 0
:font-size :label
:ring-width 2}})
(defn initials-avatar
[size customization-color theme]
@@ -8,18 +8,21 @@
{:small 20
:medium 32
:large 48
:size-64 64
:x-large 80})
(def font-sizes
{:small :label
:medium :paragraph-2
:large :paragraph-1
:size-64 :heading-1
:x-large :heading-1})
(def font-weights
{:small :medium
:medium :semi-bold
:large :semi-bold
:size-64 :medium
:x-large :medium})
(defn wallet-user-avatar
@@ -1,6 +1,8 @@
(ns quo2.components.buttons.button.properties
(:require [quo2.foundations.colors :as colors]))
(def backgrounds #{:photo :blur})
(defn custom-color-type
[customization-color icon-only?]
{:icon-color colors/white-opa-70
@@ -70,7 +70,7 @@
[sliding-complete?]
(reset! sliding-complete? true))
(defn- reset-track-position
(defn reset-track-position
[x-pos]
(animate-spring x-pos 0))
@@ -1,7 +1,6 @@
(ns quo2.components.buttons.slide-button.component-spec
(:require [quo2.components.buttons.slide-button.view :as slide-button]
[quo2.components.buttons.slide-button.constants :as constants]
[quo2.components.buttons.slide-button.utils :as utils]
["@testing-library/react-native" :as rtl]
["react-native-gesture-handler/jest-utils" :as gestures-jest]
[reagent.core :as r]
@@ -82,17 +81,11 @@
(h/has-style track-mock {:opacity constants/disable-opacity})))
(h/test "render the small button"
(h/render [slide-button/view (assoc default-props :size :small)])
(h/render [slide-button/view (assoc default-props :size :size/s-40)])
(let [mock (h/get-by-test-id :slide-button-track)
small-height (:track-height constants/small-dimensions)]
(h/has-style mock {:height small-height})))
(h/test "render with the correct customization-color"
(h/render [slide-button/view (assoc default-props :customization-color :purple)])
(let [track-mock (h/get-by-test-id :slide-button-track)
purple-color (utils/slider-color :track :purple)]
(h/has-style track-mock {:backgroundColor purple-color})))
(h/test
"calls on-complete when dragged"
(let [props (merge default-props {:on-complete (h/mock-fn)})
@@ -13,10 +13,10 @@
:right 0})
(defn thumb-container
[interpolate-track thumb-size customization-color]
[{:keys [interpolate-track thumb-size customization-color theme]}]
(reanimated/apply-animations-to-style
{:transform [{:translate-x (interpolate-track :track-clamp)}]}
{:background-color (utils/slider-color :main customization-color)
{:background-color (utils/slider-color :main customization-color theme)
:border-radius 12
:height thumb-size
:width thumb-size
@@ -46,7 +46,7 @@
:justify-content :space-around}))
(defn track
[disabled? customization-color height]
[{:keys [disabled? customization-color height theme]}]
{:align-items :flex-start
:justify-content :center
:border-radius 14
@@ -54,7 +54,7 @@
:align-self :stretch
:padding constants/track-padding
:opacity (if disabled? 0.3 1)
:background-color (utils/slider-color :track customization-color)})
:background-color (utils/slider-color :track customization-color theme)})
(defn track-cover
[interpolate-track]
@@ -74,7 +74,7 @@
:width track-width})
(defn track-text
[customization-color]
[customization-color theme]
(-> typography/paragraph-1
(merge typography/font-medium)
(assoc :color (utils/slider-color :main customization-color))))
(assoc :color (utils/slider-color :main customization-color theme))))
@@ -6,9 +6,15 @@
(defn slider-color
"- `color-key` `:main`/`:track`
- `customization-color` Customization color"
[color-key customization-color]
(let [colors-by-key {:main (colors/custom-color-by-theme customization-color 50 60)
:track (colors/custom-color-by-theme customization-color 50 60 10 10)}]
[color-key customization-color theme]
(let [colors-by-key {:main (colors/theme-colors
(colors/custom-color customization-color 50)
(colors/custom-color customization-color 60)
theme)
:track (colors/theme-colors
(colors/custom-color customization-color 50 10)
(colors/custom-color customization-color 60 10)
theme)}]
(color-key colors-by-key)))
(defn clamp-value
@@ -28,8 +34,8 @@
(defn get-dimensions
[track-width size dimension-key]
(let [default-dimensions (case size
:small constants/small-dimensions
:large constants/large-dimensions
:size/s-40 constants/small-dimensions
:size/s-48 constants/large-dimensions
constants/large-dimensions)]
(-> default-dimensions
(merge {:usable-track (calc-usable-track
@@ -10,7 +10,8 @@
[reagent.core :as reagent]
[oops.core :as oops]
[react-native.reanimated :as reanimated]
[quo2.components.buttons.slide-button.constants :as constants]))
[quo2.components.buttons.slide-button.constants :as constants]
[quo2.theme :as quo.theme]))
(defn- f-slider
[{:keys [disabled?]}]
@@ -20,14 +21,15 @@
on-track-layout (fn [evt]
(let [width (oops/oget evt "nativeEvent.layout.width")]
(reset! track-width width)))]
(fn [{:keys [on-complete
(fn [{:keys [on-reset
on-complete
track-text
track-icon
disabled?
customization-color
size
container-style]}]
container-style
theme]}]
(let [x-pos (reanimated/use-shared-value 0)
dimensions (partial utils/get-dimensions
(or @track-width constants/default-width)
@@ -36,12 +38,19 @@
x-pos
(dimensions :usable-track)
(dimensions :thumb))]
(rn/use-effect (fn []
(when @sliding-complete?
(on-complete)))
[@sliding-complete?])
(rn/use-effect (fn []
(when on-reset
(reset! sliding-complete? false)
(reset! gestures-disabled? false)
(animations/reset-track-position x-pos)
(on-reset)))
[on-reset])
[gesture/gesture-detector
{:gesture (animations/drag-gesture x-pos
gestures-disabled?
@@ -50,21 +59,25 @@
sliding-complete?)}
[reanimated/view
{:test-ID :slide-button-track
:style (merge (style/track disabled? customization-color (dimensions :track-height))
:style (merge (style/track {:disabled? disabled?
:customization-color customization-color
:height (dimensions :track-height)
:theme theme})
container-style)
:on-layout (when-not (some? @track-width)
on-track-layout)}
[reanimated/view {:style (style/track-cover interpolate-track)}
[rn/view {:style (style/track-cover-text-container @track-width)}
[icon/icon track-icon
{:color (utils/slider-color :main customization-color)
{:color (utils/slider-color :main customization-color theme)
:size 20}]
[rn/view {:width 4}]
[rn/text {:style (style/track-text customization-color)} track-text]]]
[rn/text {:style (style/track-text customization-color theme)} track-text]]]
[reanimated/view
{:style (style/thumb-container interpolate-track
(dimensions :thumb)
customization-color)}
{:style (style/thumb-container {:interpolate-track interpolate-track
:thumb-size (dimensions :thumb)
:customization-color customization-color
:theme theme})}
[reanimated/view {:style (style/arrow-icon-container interpolate-track)}
[icon/icon :arrow-right
{:color colors/white
@@ -76,16 +89,19 @@
{:color colors/white
:size 20}]]]]]))))
(defn view
(defn- view-internal
"Options
- `on-complete` Callback called when the sliding is complete
- `disabled?` Boolean that disables the button
(_and gestures_)
- `size` `:small`/`:large`
- `size` :size/s-40`/`:size/s-48`
- `track-text` Text that is shown on the track
- `track-icon` Key of the icon shown on the track
(e.g. `:face-id`)
- `customization-color` Customization color
- `on-reset` A callback which can be used to reset the component and run required functionality
"
[props]
[:f> f-slider props])
(def view (quo.theme/with-theme view-internal))
@@ -0,0 +1,54 @@
(ns quo2.components.colors.color.style
(:require [quo2.foundations.colors :as colors]))
(def color-button-common
{:width 48
:height 48
:border-width 4
:border-radius 24
:margin-horizontal 4
:transform [{:rotate "45deg"}]
:border-color :transparent})
(defn color-button
[color selected?]
(merge color-button-common
(when selected?
{:border-top-color (colors/alpha color 0.4)
:border-end-color (colors/alpha color 0.4)
:border-bottom-color (colors/alpha color 0.2)
:border-start-color (colors/alpha color 0.2)})))
(defn color-circle
[color border?]
{:width 40
:height 40
:transform [{:rotate "-45deg"}]
:background-color color
:justify-content :center
:align-items :center
:border-color color
:border-width (if border? 2 0)
:overflow :hidden
:border-radius 20})
(defn feng-shui
[theme]
{:width 40
:height 40
:transform [{:rotate "45deg"}]
:overflow :hidden
:border-color (colors/theme-colors colors/neutral-100 colors/white theme)
:border-width 2
:background-color (colors/theme-colors colors/neutral-100 colors/white theme)
:border-radius 20})
(defn left-half
[theme]
{:flex 1
:background-color (colors/theme-colors colors/white colors/neutral-100 theme)})
(defn right-half
[theme]
{:flex 1
:background-color (colors/theme-colors colors/neutral-100 colors/white theme)})
@@ -0,0 +1,50 @@
(ns quo2.components.colors.color.view
(:require
[quo2.components.icon :as icon]
[quo2.foundations.colors :as colors]
[quo2.theme :as quo.theme]
[react-native.core :as rn]
[quo2.components.colors.color.style :as style]))
(defn- feng-shui
[{:keys [color theme]}]
[rn/view
{:accessibility-label color
:style (style/feng-shui theme)}
[rn/view {:style (style/left-half theme)}]
[rn/view {:style (style/right-half theme)}]])
(defn- view-internal
[{:keys [color
selected?
on-press
blur?
theme]
:as props}]
(let [border? (and (not blur?) (not selected?))
hex-color (if (= :feng-shui color)
(colors/theme-colors colors/neutral-100 colors/white theme)
(colors/theme-colors (colors/custom-color color 50)
(colors/custom-color color 60)
theme))]
[rn/pressable
{:style (style/color-button hex-color selected?)
:accessibility-label :color-picker-item
:on-press #(on-press color)}
(if (and (= :feng-shui color) (not selected?))
[feng-shui
(assoc props
:hex-color hex-color
:border? border?)]
[rn/view
{:accessibility-label color
:style (style/color-circle hex-color border?)}
(when selected?
[icon/icon :i/check
{:size 20
:color (if (= :feng-shui color)
(colors/theme-colors colors/white colors/neutral-100 theme)
colors/white)}])])]))
(def view (quo.theme/with-theme view-internal))
@@ -3,8 +3,6 @@
[reagent.core :as reagent]
[test-helpers.component :as h]))
(def color-list [:blue :yellow :turquoise :copper :sky :camel :orange :army :pink :purple :magenta])
(h/describe "color-picker"
(h/test "color picker rendered"
(h/render [color-picker/view])
@@ -26,6 +24,6 @@
(h/render [color-picker/view])
(js/Promise.all (map (fn [color]
(h/is-truthy (h/get-all-by-label-text color)))
color-list))))
color-picker/color-list))))
@@ -1,50 +0,0 @@
(ns quo2.components.colors.color-picker.style
(:require [quo2.foundations.colors :as colors]))
(def color-picker-container
{:flex-direction :row
:flex-wrap :wrap
:justify-content :space-between})
(def flex-break
{:flex-basis "100%"
:height 10})
(def color-button-common
{:width 48
:height 48
:border-width 4
:border-radius 24
:transform [{:rotate "45deg"}]
:border-color :transparent})
(defn color-button
[color selected?]
(merge color-button-common
(when selected?
{:border-top-color (colors/alpha color 0.4)
:border-end-color (colors/alpha color 0.4)
:border-bottom-color (colors/alpha color 0.2)
:border-start-color (colors/alpha color 0.2)})))
(defn color-circle
[color border?]
{:width 40
:height 40
:transform [{:rotate "-45deg"}]
:background-color color
:justify-content :center
:align-items :center
:border-color color
:border-width (if border? 2 0)
:overflow :hidden
:border-radius 20})
(defn secondary-overlay
[secondary-color border?]
{:width (if border? 18 20)
:height 40
:position :absolute
:right 0
:background-color secondary-color})
@@ -1,77 +1,34 @@
(ns quo2.components.colors.color-picker.view
(:require [react-native.core :as rn]
[quo2.foundations.colors :as colors]
[quo2.components.icon :as icon]
[reagent.core :as reagent]
[quo2.components.colors.color-picker.style :as style]))
[quo2.components.colors.color.view :as color]))
;; TODO: using :no-color this to keep alignment of colors correct while b & w is being developed.
;; https://github.com/status-im/status-mobile/issues/15442
(def color-list
[:blue :yellow :turquoise :copper :sky :camel :orange :army :pink :purple :magenta :no-color])
(defn picker-colors
[blur?]
(map (fn [color]
{:name color
:color (colors/custom-color-by-theme color (if blur? 60 50) 60)})
color-list))
[:blue :yellow :purple :turquoise :magenta :sky :orange :army :flamingo :camel :copper])
(defn- on-change-handler
[selected color-name on-change]
(reset! selected color-name)
(when on-change (on-change color-name)))
(defn empty-color-item
[]
[rn/view {:style style/color-button-common}])
(defn- color-item
[{:keys [name
color
secondary-color
selected?
on-press
blur?]}]
(let [border? (and (not blur?) (and secondary-color (not selected?)))]
(if (= :no-color name)
[empty-color-item]
[rn/touchable-opacity
{:style (style/color-button color selected?)
:accessibility-label :color-picker-item
:on-press #(on-press name)}
[rn/view
{:accessibile true
:accessibility-label name
:style (style/color-circle color border?)}
(when (and secondary-color (not selected?))
[rn/view
{:style (style/secondary-overlay secondary-color border?)}])
(when selected?
[icon/icon :i/check
{:size 20
:color (or secondary-color
colors/white)}])]])))
(defn view
"Options
- `default-selected?` Default selected color name.
- `selected` Selected color name.
- `default-selected` Default selected color name.
- `on-change` Callback called when a color is selected `(fn [color-name])`.
- `blur?` Boolean to enable blur background support.}"
[{:keys [default-selected?]}]
(let [internal-selected (reagent/atom default-selected?)]
(fn [{:keys [blur? on-change selected]}]
(when (and (not (nil? selected)) (not= @internal-selected selected))
(reset! internal-selected selected))
[rn/view {:style style/color-picker-container}
(doall (map-indexed (fn [index color]
[:<> {:key (color :name)}
[color-item
(merge color
{:selected? (= (color :name) @internal-selected)
:on-press #(on-change-handler internal-selected % on-change)
:blur? blur?})]
(when (= index 5) [rn/view {:style style/flex-break}])])
(picker-colors blur?)))])))
[{:keys [default-selected]}]
(let [selected (reagent/atom default-selected)]
(fn [{:keys [blur? on-change feng-shui?]}]
[rn/scroll-view
{:horizontal true
:shows-horizontal-scroll-indicator false}
(doall (map (fn [color]
[color/view
{:selected? (= color @selected)
:on-press #(on-change-handler selected % on-change)
:blur? blur?
:key color
:color color}])
;; TODO: using :feng-shui? temporarily while b & w is being developed.
;; https://github.com/status-im/status-mobile/discussions/16676
(if feng-shui? (conj color-list :feng-shui) color-list)))])))
@@ -4,7 +4,9 @@
(defn get-color
[type customization-color theme]
(case type
:default (colors/custom-color customization-color 50)
:default (colors/theme-colors (colors/custom-color customization-color 50)
(colors/custom-color customization-color 60)
theme)
:secondary (colors/theme-colors colors/neutral-80-opa-5 colors/white-opa-5 theme)
:grey (colors/theme-colors colors/neutral-10 colors/neutral-80 theme)
:outline (colors/theme-colors colors/neutral-20 colors/neutral-80 theme)
@@ -1,20 +0,0 @@
(ns quo2.components.dropdowns.dropdown
(:require [quo2.components.dropdowns.old-button-view :as old-button]))
(defn dropdown
[_ _]
(fn [{:keys [on-change selected] :as opts} children]
;TODO: Dropdown needs to be implemented/refactored to be its own component -
;https://github.com/status-im/status-mobile/issues/16456
[old-button/button
(merge
opts
{:after (if selected :i/chevron-top :i/chevron-down)
:icon-size 12
:icon-container-size 14
:icon-container-rounded? true
:override-after-margins {:left 7
:right 9}
:pressed selected
:on-press #(when on-change (on-change selected))})
children]))
@@ -0,0 +1,35 @@
(ns quo2.components.dropdowns.dropdown.component-spec
(:require [quo2.components.dropdowns.dropdown.view :as dropdown]
[test-helpers.component :as h]))
(h/describe "Dropdown"
(h/test "default render"
(let [label "Recent"]
(h/render [dropdown/view {} label])
(h/is-truthy (h/get-by-label-text :dropdown))
(h/is-null (h/query-by-label-text :left-icon))
(h/is-truthy (h/get-by-text label))
(h/is-truthy (h/get-by-label-text :right-icon))))
(h/test "render with icon"
(let [label "Recent"]
(h/render [dropdown/view {:icon? true} label])
(h/is-truthy (h/get-by-label-text :dropdown))
(h/is-truthy (h/get-by-label-text :left-icon))
(h/is-truthy (h/get-by-text label))
(h/is-truthy (h/get-by-label-text :right-icon))))
(h/test "render only emoji"
(let [label "🍑"]
(h/render [dropdown/view {:emoji? true} label])
(h/is-truthy (h/get-by-label-text :dropdown))
(h/is-null (h/query-by-label-text :left-icon))
(h/is-truthy (h/get-by-text label))
(h/is-null (h/query-by-label-text :right-icon))))
(h/test "on-press"
(let [event (h/mock-fn)
label "Recent"]
(h/render [dropdown/view {:on-press event} label])
(h/fire-event :press (h/get-by-text label))
(h/was-called event))))
@@ -0,0 +1,120 @@
(ns quo2.components.dropdowns.dropdown.properties
(:require [quo2.foundations.colors :as colors]))
(def backgrounds #{:photo :blur})
(def sizes
{:size-40 {:size 40
:icon-size 20
:emoji-size 20
:emoji-padding 10
:padding-vertical 9
:padding-left {:default 16 :icon 12}
:padding-right 12
:border-radius 12
:text-size :paragraph-1}
:size-32 {:size 32
:icon-size 20
:emoji-size 20
:emoji-padding 6
:padding-vertical 5
:padding-left {:default 12 :icon 8}
:padding-right 8
:border-radius 10
:text-size :paragraph-1}
:size-24 {:size 24
:icon-size 12
:emoji-size 12
:emoji-padding 6
:padding-vertical 3
:padding-left {:default 8 :icon 8}
:padding-right 8
:border-radius 8
:text-size :paragraph-2}})
(defn- custom-color-type
[customization-color]
{:left-icon-color colors/white-opa-70
:right-icon-color colors/white-opa-20
:right-icon-color-2 colors/white
:label-color colors/white
:background-color (colors/custom-color customization-color 50)})
(def sizes-to-exclude-blur-in-photo-bg #{:size-40})
(defn- grey-photo
[theme active? size]
{:left-icon-color (colors/theme-colors colors/neutral-80-opa-40 colors/white-opa-40 theme)
:right-icon-color (colors/theme-colors colors/neutral-80-opa-10 colors/white-opa-10 theme)
:right-icon-color-2 (colors/theme-colors colors/neutral-100 colors/white theme)
:label-color (colors/theme-colors colors/neutral-100 colors/white theme)
:blur-overlay-color (when (and (= theme :dark) (nil? (sizes-to-exclude-blur-in-photo-bg size)))
(if active? colors/neutral-80-opa-50 colors/neutral-80-opa-40))
:blur-type (if (= theme :light) :light :dark)
:background-color (cond
(= theme :light)
(if active? colors/white-opa-50 colors/white-opa-40)
(and (= theme :dark) (sizes-to-exclude-blur-in-photo-bg size))
(if active? colors/neutral-80-opa-50 colors/neutral-80-opa-40))})
(defn- grey-blur
[theme active?]
{:left-icon-color (colors/theme-colors colors/neutral-80-opa-40 colors/white-opa-70 theme)
:right-icon-color (colors/theme-colors colors/neutral-80-opa-10 colors/white-opa-10 theme)
:right-icon-color-2 (colors/theme-colors colors/neutral-100 colors/white theme)
:label-color (colors/theme-colors colors/neutral-100 colors/white theme)
:background-color (if active?
(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
[theme active?]
{:left-icon-color (colors/theme-colors colors/neutral-80-opa-40 colors/white-opa-40 theme)
:right-icon-color (colors/theme-colors colors/neutral-80-opa-10 colors/white-opa-10 theme)
:right-icon-color-2 (colors/theme-colors colors/neutral-100 colors/white theme)
:label-color (colors/theme-colors colors/neutral-100 colors/white theme)
:border-color (if active?
(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- outline
[theme active?]
{:left-icon-color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)
:right-icon-color (colors/theme-colors colors/neutral-20 colors/neutral-80 theme)
:right-icon-color-2 (colors/theme-colors colors/neutral-100 colors/white theme)
:label-color (colors/theme-colors colors/neutral-100 colors/white theme)
:border-color (if active?
(colors/theme-colors colors/neutral-40 colors/neutral-60 theme)
(colors/theme-colors colors/neutral-30 colors/neutral-70 theme))})
(defn- grey
[theme active?]
{:left-icon-color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)
:right-icon-color (colors/theme-colors colors/neutral-20 colors/neutral-80 theme)
:right-icon-color-2 (colors/theme-colors colors/neutral-100 colors/white theme)
:label-color (colors/theme-colors colors/neutral-100 colors/white theme)
:background-color (if active?
(colors/theme-colors colors/neutral-20 colors/neutral-80 theme)
(colors/theme-colors colors/neutral-5 colors/neutral-90 theme))})
(defn- ghost
[theme active?]
{:left-icon-color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)
:right-icon-color (colors/theme-colors colors/neutral-20 colors/neutral-80 theme)
:right-icon-color-2 (colors/theme-colors colors/neutral-100 colors/white theme)
:label-color (colors/theme-colors colors/neutral-100 colors/white theme)
:background-color (when active?
(colors/theme-colors colors/neutral-10 colors/neutral-80 theme))})
(defn get-colors
[{:keys [customization-color theme type state background size]}]
(let [active? (= state :active)]
(cond
(and (= background :photo) (= type :grey)) (grey-photo theme active? size)
(and (= background :blur) (= type :grey)) (grey-blur theme active?)
(and (= background :blur) (= type :outline)) (outline-blur theme active?)
(= type :outline) (outline theme active?)
(= type :grey) (grey theme active?)
(= type :ghost) (ghost theme active?)
(= type :customization) (custom-color-type customization-color))))
@@ -0,0 +1,53 @@
(ns quo2.components.dropdowns.dropdown.style)
(def gap 4)
(def blur-view
{:position :absolute
:top 0
:left 0
:right 0
:bottom 0})
(def left-icon
{:margin-right gap})
(defn right-icon
[label-color]
{:color label-color
:margin-right gap})
(defn- add-styles-for-emoji
[style size emoji-padding]
(-> style
(dissoc :padding-vertical :padding-left :padding-right)
(assoc :width size
:padding emoji-padding)))
(defn root-container
[{:keys [size border-radius padding-vertical padding-right padding-left emoji-padding]}
{:keys [background-color border-color]}
{:keys [icon? emoji? state]}]
(cond-> {:height size
:align-items :center
:justify-content :center
:flex-direction :row
:padding-vertical padding-vertical
:padding-left (:default padding-left)
:padding-right padding-right
:overflow :hidden
:background-color background-color
:border-radius border-radius}
icon?
(assoc :padding-left (:icon padding-left))
emoji?
(add-styles-for-emoji size emoji-padding)
border-color
(assoc :border-color border-color
:border-width 1)
(= state :disabled)
(assoc :opacity 0.3)))
@@ -0,0 +1,87 @@
(ns quo2.components.dropdowns.dropdown.view
(:require [quo2.components.dropdowns.dropdown.properties :as properties]
[quo2.components.dropdowns.dropdown.style :as style]
[quo2.components.icon :as icon]
[quo2.components.markdown.text :as text]
[quo2.foundations.customization-colors :as customization-colors]
[quo2.theme :as theme]
[react-native.blur :as blur]
[react-native.core :as rn]))
(defn- view-internal
[{:keys [type size state background customization-color theme on-press icon-name icon? emoji?
accessibility-label]
:or {type :grey
size :size-40
state :default
icon? false
emoji? false
icon-name :i/placeholder}
:as props}
text]
(let [{:keys [icon-size text-size emoji-size border-radius]
:as size-properties} (properties/sizes size)
{:keys [left-icon-color right-icon-color right-icon-color-2 label-color blur-type
blur-overlay-color]
:as colors} (properties/get-colors props)
right-icon (if (= state :active) :i/pullup :i/dropdown)
customization-type? (= type :customization)
show-blur-background? (and (= background :photo)
(= type :grey)
(nil? (properties/sizes-to-exclude-blur-in-photo-bg size)))]
[rn/pressable
{:accessibility-label (or accessibility-label :dropdown)
:disabled (= state :disabled)
:on-press on-press
:style (style/root-container size-properties colors props)}
(when show-blur-background?
[blur/view
{:blur-radius 20
:blur-type blur-type
:overlay-color blur-overlay-color
:style style/blur-view}])
(when customization-type?
[customization-colors/overlay
{:customization-color customization-color
:theme theme
:pressed? (= state :active)
:border-radius border-radius}])
(if emoji?
[rn/text
{:adjusts-font-size-to-fit true
:style {:font-size emoji-size}}
text]
[:<>
(when icon?
[icon/icon
icon-name
{:accessibility-label :left-icon
:color left-icon-color
:size icon-size
:container-style style/left-icon}])
[text/text
{:size text-size
:weight :medium
:number-of-lines 1
:style (style/right-icon label-color)}
text]
[icon/icon
right-icon
{:size icon-size
:accessibility-label :right-icon
:color right-icon-color
:color-2 right-icon-color-2}]])]))
(def view
"Props:
- type: :outline |:grey (default) | :ghost | :customization
- size: :size-40 (default) | :size-32 | :size-24
- state: :default (default) | :active | :disabled
- emoji?: boolean
- icon?: boolean
- background: :blur | :photo (optional)
- icon-name: keyword
- on-press: function
Child: string - used as label or emoji (for emoji only)"
(theme/with-theme view-internal))
@@ -4,10 +4,10 @@
(defn container-border-color
[{:keys [state blur? theme pressed?]}]
(let [default-color (if blur?
colors/neutral-80-opa-5
(colors/theme-colors colors/neutral-80-opa-5 colors/white-opa-5 theme)
(colors/theme-colors colors/neutral-30 colors/neutral-70 theme))
active-color (if blur?
colors/neutral-80-opa-10
(colors/theme-colors colors/neutral-80-opa-10 colors/white-opa-10 theme)
(colors/theme-colors colors/neutral-40 colors/neutral-60 theme))]
(condp = state
:disabled default-color
@@ -1,264 +0,0 @@
(ns quo2.components.dropdowns.old-button-style
(:require [quo2.foundations.colors :as colors]))
(def blur-view
{:position :absolute
:top 0
:left 0
:right 0
:bottom 0})
(defn before-icon-style
[{:keys [override-margins size icon-container-size icon-background-color icon-container-rounded?
icon-size]}]
(merge
{:margin-left (or (get override-margins :left)
(if (= size 40) 12 8))
:margin-right (or (get override-margins :right) 4)
:align-items :center
:justify-content :center}
(when icon-container-size
{:width icon-container-size
:height icon-container-size})
(when icon-background-color
{:background-color icon-background-color})
(when icon-container-rounded?
{:border-radius (/ (or icon-container-size icon-size) 2)})))
(defn after-icon-style
[{:keys [override-margins size icon-container-size icon-background-color icon-container-rounded?
icon-size]}]
(merge
{:margin-left (or (get override-margins :left) 4)
:margin-right (or (get override-margins :right)
(if (= size 40) 12 8))
:align-items :center
:justify-content :center}
(when icon-container-size
{:width icon-container-size
:height icon-container-size})
(when icon-background-color
{:background-color icon-background-color})
(when icon-container-rounded?
{:border-radius (/ (or icon-container-size icon-size) 2)})))
(defn themes
[customization-color]
{:light
{:primary {:icon-color colors/white
:icon-secondary-color colors/white-opa-70
:label-color colors/white
:background-color {:default (colors/custom-color customization-color 50)
:pressed (colors/custom-color customization-color 60)
:disabled (colors/custom-color customization-color 50)}}
:secondary {:icon-color colors/primary-50
:label-color colors/primary-50
:background-color {:default colors/primary-50-opa-20
:pressed colors/primary-50-opa-40
:disabled colors/primary-50-opa-20}}
:grey {:icon-color colors/neutral-100
:icon-secondary-color colors/neutral-50
:label-color colors/neutral-100
:background-color {:default colors/neutral-10
:pressed colors/neutral-20
:disabled colors/neutral-10}}
:dark-grey {:icon-color colors/neutral-100
:icon-secondary-color colors/neutral-50
:label-color colors/neutral-100
:background-color {:default colors/neutral-20
:pressed colors/neutral-30
:disabled colors/neutral-20}}
:outline {:icon-color colors/neutral-50
:icon-secondary-color colors/neutral-50
:label-color colors/neutral-100
:border-color {:default colors/neutral-30
:pressed colors/neutral-40
:disabled colors/neutral-30}}
:ghost {:icon-color colors/neutral-50
:icon-secondary-color colors/neutral-50
:label-color colors/neutral-100
:background-color {:pressed colors/neutral-10}}
:danger {:icon-color colors/white
:icon-secondary-color colors/white-opa-70
:label-color colors/white
:background-color {:default colors/danger-50
:pressed colors/danger-60
:disabled colors/danger-50}}
:positive {:icon-color colors/white
:icon-secondary-color colors/white-opa-70
:label-color colors/white
:background-color {:default colors/success-50
:pressed colors/success-60
:disabled colors/success-50-opa-30}}
:photo-bg {:icon-color colors/neutral-100
:icon-secondary-color colors/neutral-80-opa-40
:label-color colors/neutral-100
:background-color {:default colors/white-opa-40
:pressed colors/white-opa-50
:disabled colors/white-opa-40}}
:blur-bg {:icon-color colors/neutral-100
:icon-secondary-color colors/neutral-80-opa-40
:label-color colors/neutral-100
:background-color {:default colors/neutral-80-opa-5
:pressed colors/neutral-80-opa-10
:disabled colors/neutral-80-opa-5}}
:blurred {:icon-color colors/neutral-100
:icon-secondary-color colors/neutral-100
:icon-background-color {:default colors/neutral-20
:blurred colors/neutral-80-opa-10}
:label-color colors/neutral-100
:background-color {:default colors/neutral-10
:pressed colors/neutral-10
:disabled colors/neutral-10-opa-10-blur}
:blur-overlay-color colors/neutral-10-opa-40-blur
:blur-type :light}
:blur-bg-outline {:icon-color colors/neutral-100
:icon-secondary-color colors/neutral-80-opa-40
:label-color colors/neutral-100
:border-color {:default colors/neutral-80-opa-10
:pressed colors/neutral-80-opa-20
:disabled colors/neutral-80-opa-10}}
:shell {:icon-color colors/white
:label-color colors/white
:background-color {:default colors/neutral-95
:pressed colors/neutral-95
:disabled colors/neutral-95}}}
:dark
{:primary {:icon-color colors/white
:icon-secondary-color colors/white-opa-70
:label-color colors/white
:background-color {:default (colors/custom-color customization-color 60)
:pressed (colors/custom-color customization-color 50)
:disabled (colors/custom-color customization-color 60)}}
:secondary {:icon-color colors/primary-50
:label-color colors/primary-50
:background-color {:default colors/primary-50-opa-20
:pressed colors/primary-50-opa-30
:disabled colors/primary-50-opa-20}}
:grey {:icon-color colors/white
:icon-secondary-color colors/neutral-40
:label-color colors/white
:background-color {:default colors/neutral-90
:pressed colors/neutral-60
:disabled colors/neutral-90}}
:dark-grey {:icon-color colors/white
:icon-secondary-color colors/neutral-40
:label-color colors/white
:background-color {:default colors/neutral-70
:pressed colors/neutral-60
:disabled colors/neutral-70}}
:outline {:icon-color colors/neutral-40
:icon-secondary-color colors/neutral-40
:label-color colors/white
:border-color {:default colors/neutral-70
:pressed colors/neutral-60
:disabled colors/neutral-70}}
:ghost {:icon-color colors/neutral-40
:icon-secondary-color colors/neutral-40
:label-color colors/white
:background-color {:pressed colors/neutral-80}}
:danger {:icon-color colors/white
:icon-secondary-color colors/white-opa-70
:label-color colors/white
:background-color {:default colors/danger-60
:pressed colors/danger-50
:disabled colors/danger-60}}
:positive {:icon-color colors/white
:icon-secondary-color colors/white-opa-70
:label-color colors/white
:background-color {:default colors/success-60
:pressed colors/success-50
:disabled colors/success-60-opa-30}}
:photo-bg {:icon-color colors/white
:icon-secondary-color colors/neutral-30
:label-color colors/white
:background-color {:default colors/neutral-80-opa-40
:pressed colors/neutral-80-opa-50
:disabled colors/neutral-80-opa-40}}
:blur-bg {:icon-color colors/white
:icon-secondary-color colors/white-opa-70
:label-color colors/white
:background-color {:default colors/white-opa-5
:pressed colors/white-opa-10
:disabled colors/white-opa-5}}
:blurred {:icon-color colors/white
:icon-secondary-color colors/white
:icon-background-color {:default colors/neutral-80
:blurred colors/white-opa-10}
:label-color colors/white
:background-color {:default colors/neutral-90
:pressed colors/neutral-90
:disabled colors/neutral-90-opa-10-blur}
:blur-overlay-color colors/neutral-80-opa-40
:blur-type :dark}
:blur-bg-outline {:icon-color colors/white
:icon-secondary-color colors/white-opa-40
:label-color colors/white
:border-color {:default colors/white-opa-10
:pressed colors/white-opa-20
:disabled colors/white-opa-5}}
:shell {:icon-color colors/white
:label-color colors/white
:background-color {:default colors/neutral-95}}}})
(defn shape-style-container
[type icon size]
{:height size
:border-radius (if (and icon (#{:primary :secondary :danger} type))
24
(case size
56 12
40 12
32 10
24 8))})
(defn style-container
[{:keys [type size disabled background-color border-color icon above width before after blur-active?]}]
(merge {:height size
:align-items :center
:justify-content :center
:flex-direction (if above :column :row)
:padding-horizontal (when-not (or icon before after)
(case size
56 16
40 16
32 12
24 8))
:padding-left (when-not (or icon before)
(case size
56 16
40 16
32 12
24 8))
:padding-right (when-not (or icon after)
(case size
56 16
40 16
32 12
24 8))
:padding-top (when-not (or icon before after)
(case size
56 0
40 9
32 5
24 3))
:padding-bottom (when-not (or icon before after)
(case size
56 0
40 9
32 5
24 4))
:overflow :hidden}
(when (or (and (= type :blurred) (not blur-active?))
(not= type :blurred))
{:background-color background-color})
(shape-style-container type icon size)
(when width
{:width width})
(when icon
{:width size})
(when border-color
{:border-color border-color
:border-width 1})
(when disabled
{:opacity 0.3})))
@@ -1,138 +0,0 @@
(ns quo2.components.dropdowns.old-button-view
(:require [quo2.components.icon :as quo2.icons]
[quo2.components.markdown.text :as text]
[quo2.theme :as theme]
[react-native.core :as rn]
[react-native.blur :as blur]
[reagent.core :as reagent]
[quo2.components.dropdowns.old-button-style :as style]))
(defn- button-internal
"with label
[button opts \"label\"]
opts
{:type :primary/:secondary/:grey/:dark-grey/:outline/:ghost/
:danger/:photo-bg/:blur-bg/:blur-bg-outline/:shell/:community
:size 40 [default] /32/24
:icon true/false
:community-color '#FFFFFF'
:community-text-color '#000000'
:before :icon-keyword
:after :icon-keyword}
only icon
[button {:icon true} :i/close-circle]"
[_ _]
(let [pressed-in (reagent/atom false)]
(fn
[{:keys [on-press disabled type size before after above icon-secondary-no-color
width customization-color theme override-background-color pressed
on-long-press accessibility-label icon icon-no-color style inner-style test-ID
blur-active? override-before-margins override-after-margins icon-size icon-container-size
icon-container-rounded?]
:or {type :primary
size 40
customization-color :primary
blur-active? true}}
children]
(let [{:keys [icon-color icon-secondary-color background-color label-color border-color blur-type
blur-overlay-color icon-background-color]}
(get-in (style/themes customization-color)
[theme type])
state (cond disabled :disabled
(or @pressed-in pressed) :pressed
:else :default)
blur-state (if blur-active? :blurred :default)
icon-size (or icon-size (when (= 24 size) 12))
icon-secondary-color (or icon-secondary-color icon-color)]
[rn/touchable-without-feedback
(merge {:test-ID test-ID
:disabled disabled
:accessibility-label accessibility-label
:on-press-in #(reset! pressed-in true)
:on-press-out #(reset! pressed-in nil)}
(when on-press
{:on-press on-press})
(when on-long-press
{:on-long-press on-long-press}))
[rn/view
{:style (merge
(style/shape-style-container type icon size)
{:width width}
style)}
[rn/view
{:style (merge
(style/style-container {:type type
:size size
:disabled disabled
:background-color
(or override-background-color (get background-color state))
:border-color
(get border-color state)
:icon icon
:above above
:width width
:before before
:after after
:blur-active? blur-active?})
(when (= state :pressed) {:opacity 0.9})
inner-style)}
(when (and (= type :blurred)
blur-active?)
[blur/view
{:blur-radius 20
:blur-type blur-type
:overlay-color blur-overlay-color
:style style/blur-view}])
(when above
[rn/view
[quo2.icons/icon above
{:container-style {:margin-bottom 2}
:color icon-secondary-color
:size icon-size}]])
(when before
[rn/view
{:style (style/before-icon-style
{:override-margins override-before-margins
:size size
:icon-container-size icon-container-size
:icon-background-color (get icon-background-color blur-state)
:icon-container-rounded? icon-container-rounded?
:icon-size icon-size})}
[quo2.icons/icon before
{:color icon-secondary-color
:size icon-size}]])
[rn/view
(cond
(or icon icon-no-color)
[quo2.icons/icon children
{:color icon-color
:no-color icon-no-color
:size icon-size}]
(string? children)
[text/text
{:size (when (#{56 24} size) :paragraph-2)
:weight :medium
:number-of-lines 1
:style {:color label-color}}
children]
(vector? children)
children)]
(when after
[rn/view
{:style (style/after-icon-style
{:override-margins override-after-margins
:size size
:icon-container-size icon-container-size
:icon-background-color (get icon-background-color blur-state)
:icon-container-rounded? icon-container-rounded?
:icon-size icon-size})}
[quo2.icons/icon after
{:no-color icon-secondary-no-color
:color icon-secondary-color
:size icon-size}]])]]]))))
(def button (theme/with-theme button-internal))
+84 -13
View File
@@ -21,21 +21,92 @@
children))
(defn- clear-20
[{:keys [color color-2] :as props}]
(let [color (or color colors/neutral-100)
color-2 (or color-2 colors/white)]
[container props
[svg/path
{:d
"M3 10C3 6.13401 6.13401 3 10 3C13.866 3 17 6.13401 17 10C17 13.866 13.866 17 10 17C6.13401 17 3 13.866 3 10Z"
:fill color}]
[svg/path
{:d
"M9.15142 9.99998L7.07566 12.0757L7.9242 12.9243L9.99994 10.8485L12.0757 12.9242L12.9242 12.0757L10.8485 9.99998L12.9242 7.92421L12.0757 7.07568L9.99994 9.15145L7.92421 7.07572L7.07568 7.92425L9.15142 9.99998Z"
:fill color-2}]]))
[{:keys [color color-2]
:or {color colors/neutral-100
color-2 colors/white}
:as props}]
[container props
[svg/path
{:d
"M3 10C3 6.13401 6.13401 3 10 3C13.866 3 17 6.13401 17 10C17 13.866 13.866 17 10 17C6.13401 17 3 13.866 3 10Z"
:fill color}]
[svg/path
{:d
"M9.15142 9.99998L7.07566 12.0757L7.9242 12.9243L9.99994 10.8485L12.0757 12.9242L12.9242 12.0757L10.8485 9.99998L12.9242 7.92421L12.0757 7.07568L9.99994 9.15145L7.92421 7.07572L7.07568 7.92425L9.15142 9.99998Z"
:fill color-2}]])
(defn- dropdown-20
[{:keys [color color-2]
:or {color colors/neutral-100
color-2 colors/white}
:as props}]
[container props
[svg/path
{:d
"M3 10C3 6.13401 6.13401 3 10 3C13.866 3 17 6.13401 17 10C17 13.866 13.866 17 10 17C6.13401 17 3 13.866 3 10Z"
:fill color}]
[svg/path
{:d
"M7 8.5L10 11.5L13 8.5"
:stroke color-2
:stroke-width 1.2}]])
(defn- pullup-20
[{:keys [color color-2]
:or {color colors/neutral-100
color-2 colors/white}
:as props}]
[container props
[svg/path
{:d
"M3 10C3 6.13401 6.13401 3 10 3C13.866 3 17 6.13401 17 10C17 13.866 13.866 17 10 17C6.13401 17 3 13.866 3 10Z"
:fill color}]
[svg/path
{:d
"M7 11.5L10 8.5L13 11.5"
:stroke color-2
:stroke-width 1.2}]])
(defn- dropdown-12
[{:keys [color color-2]
:or {color colors/neutral-100
color-2 colors/white}
:as props}]
[container props
[svg/circle
{:cx 6
:cy 6
:r 6
:fill color}]
[svg/path
{:d
"M3.5 5L6 7.5L8.5 5"
:stroke color-2
:stroke-width 1.1}]])
(defn- pullup-12
[{:keys [color color-2]
:or {color colors/neutral-100
color-2 colors/white}
:as props}]
[container props
[svg/circle
{:cx 6
:cy 6
:r 6
:fill color}]
[svg/path
{:d
"M3.5 7L6 4.5L8.5 7"
:stroke color-2
:stroke-width 1.1}]])
(def ^:private icons
{:i/clear-20 clear-20})
{:i/clear-20 clear-20
:i/dropdown-20 dropdown-20
:i/pullup-20 pullup-20
:i/dropdown-12 dropdown-12
:i/pullup-12 pullup-12})
(defn- append-to-keyword
[k & xs]
@@ -0,0 +1,86 @@
(ns quo2.components.list-items.account.component-spec
(:require [test-helpers.component :as h]
[quo2.components.list-items.account.view :as account]
[quo2.foundations.colors :as colors]))
(h/describe "List items: account"
(h/test "default render'"
(h/render [account/view])
(h/is-truthy (h/query-by-label-text :container)))
(h/test "on-press-in changes state to :pressed"
(h/render [account/view])
(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/custom-color :blue 50 5)})))
(h/test "on-press-in changes state to :pressed with blur? enabled"
(h/render [account/view {:blur? true}])
(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 "on-press-out changes state to :active"
(h/render [account/view])
(h/fire-event :on-press-in (h/get-by-label-text :container))
(h/fire-event :on-press-out (h/get-by-label-text :container))
(h/wait-for #(h/has-style (h/query-by-label-text :container)
{:backgroundColor (colors/custom-color :blue 50 10)})))
(h/test "on-press-out changes state to :active with blur? enabled"
(h/render [account/view {:blur? true}])
(h/fire-event :on-press-in (h/get-by-label-text :container))
(h/fire-event :on-press-out (h/get-by-label-text :container))
(h/wait-for #(h/has-style (h/query-by-label-text :container)
{:backgroundColor colors/white-opa-10})))
(h/test "on-press-out changes state to :selected"
(h/render [account/view {:selectable? true}])
(h/fire-event :on-press-in (h/get-by-label-text :container))
(h/fire-event :on-press-out (h/get-by-label-text :container))
(h/wait-for #(h/is-truthy (h/query-by-label-text :check-icon))))
(h/test "on-press-out calls on-press"
(let [on-press (h/mock-fn)]
(h/render [account/view {:on-press on-press}])
(h/fire-event :on-press-in (h/get-by-label-text :container))
(h/fire-event :on-press-out (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/is-truthy (h/query-by-label-text :tag-container)))
(h/test "renders keycard icon if title-icon? is true"
(h/render [account/view {:title-icon? true}])
(h/is-truthy (h/query-by-label-text :keycard-icon)))
(h/test "doesn't render keycard icon if title-icon? is false"
(h/render [account/view])
(h/is-falsy (h/query-by-label-text :keycard-icon)))
(h/test "renders balance container but not arrow icon if type :balance-neutral"
(h/render [account/view {:type :balance-neutral}])
(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/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/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/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))))
@@ -0,0 +1,110 @@
(ns quo2.components.list-items.account.style
(:require [quo2.foundations.colors :as colors]))
(defn- background-color
[{:keys [state blur? customization-color]}]
(cond (or (= state :pressed) (= state :selected))
(if blur? colors/white-opa-5 (colors/custom-color customization-color 50 5))
(= state :active)
(if blur? colors/white-opa-10 (colors/custom-color customization-color 50 10))
(and (= state :pressed) blur?) colors/white-opa-10
:else :transparent))
(defn container
[props]
{:height 56
:border-radius 12
:background-color (background-color props)
:flex-direction :row
:align-items :center
:padding-horizontal 12
:padding-vertical 6
:justify-content :space-between})
(def left-container
{:flex-direction :row
:align-items :center})
(defn metric-text
[type theme]
{:color (case type
:balance-positive (colors/theme-colors colors/success-50 colors/success-60 theme)
:balance-negative (colors/theme-colors colors/danger-50 colors/danger-60 theme)
(colors/theme-colors colors/neutral-50 colors/neutral-40 theme))})
(defn dot-divider
[type theme]
{:width 2
:height 2
:border-radius 2
:margin-horizontal 4
:background-color (case type
:balance-positive (colors/theme-colors colors/success-50-opa-40
colors/success-60-opa-40
theme)
:balance-negative (colors/theme-colors colors/danger-50-opa-40
colors/danger-50-opa-40
theme)
(colors/theme-colors colors/neutral-80-opa-40 colors/neutral-50-opa-40 theme))})
(defn arrow-icon
[type theme]
{:size 16
:color (if (= type :balance-positive)
(colors/theme-colors colors/success-50 colors/success-60 theme)
(colors/theme-colors colors/danger-50 colors/danger-60 theme))})
(def arrow-icon-container
{:margin-left 4})
(def account-container
{:margin-left 8})
(def account-title-container
{:flex-direction :row
:height 22
:align-items :center})
(defn account-address
[blur? theme]
{:height 18
:color (if blur?
colors/white-opa-40
(colors/theme-colors colors/neutral-50 colors/neutral-40 theme))})
(def keycard-icon-container
{:margin-left 4})
(def token-tag-container
{:height 40
:padding-top 4})
(defn token-tag-text-container
[blur? theme]
{:flex-direction :row
:align-items :center
:height 16
:padding-horizontal 3
:border-width 1
:border-radius 6
:border-color (if blur?
colors/white-opa-10
(colors/theme-colors colors/neutral-20
colors/neutral-80
theme))})
(defn token-tag-text
[blur? theme]
{:margin-top -1
:color (if blur?
colors/white-opa-70
(colors/theme-colors colors/neutral-50 colors/neutral-40 theme))})
(def balance-container
{:align-items :flex-end
:justify-content :space-between})
(def metrics-container
{:flex-direction :row
:align-items :center
:margin-top 2})
@@ -0,0 +1,155 @@
(ns quo2.components.list-items.account.view
(:require [quo2.components.avatars.account-avatar.view :as account-avatar]
[quo2.components.markdown.text :as text]
[quo2.foundations.colors :as colors]
[quo2.theme :as quo.theme]
[react-native.core :as rn]
[quo2.components.list-items.account.style :as style]
[reagent.core :as reagent]
[quo2.components.icon :as icon]))
(defn- account-view
[{:keys [account-props title-icon? blur? theme]
:or {title-icon? false}}]
[rn/view {:style style/left-container}
[account-avatar/view (assoc account-props :size 32)]
[rn/view {:style style/account-container}
[rn/view
{:style style/account-title-container}
[text/text
{:weight :semi-bold
:size :paragraph-1}
(:name account-props)]
(when title-icon?
[rn/view
{:style style/keycard-icon-container
:accessibility-label :keycard-icon}
[icon/icon :i/keycard
{:size 20
:color (if blur?
colors/white-opa-40
(colors/theme-colors colors/neutral-50 colors/neutral-40 theme))}]])]
[text/text {:size :paragraph-2}
[text/text
{:size :paragraph-2
:weight :monospace
:style (style/account-address blur? theme)}
(:address account-props)]]]])
(defn- balance-view
[{:keys [balance-props type theme]}]
[rn/view
{:style style/balance-container
:accessibility-label :balance-container}
[text/text
{:weight :medium
:size :paragraph-2}
(:fiat-value balance-props)]
[rn/view
{:style style/metrics-container}
[text/text
{:size :paragraph-2
:style (style/metric-text type theme)}
(str (:percentage-change balance-props) "%")]
[rn/view {:style (style/dot-divider type theme)}]
[text/text
{:size :paragraph-2
:style (style/metric-text type theme)}
(:fiat-change balance-props)]
(when (not= type :balance-neutral)
[rn/view
{:style style/arrow-icon-container
:accessibility-label :arrow-icon}
[icon/icon (if (= type :balance-positive) :i/positive :i/negative)
(assoc (style/arrow-icon type theme)
:accessibility-label
(if (= type :balance-positive) :icon-positive :icon-negative))]])]])
(defn- token-tag
[{:keys [token-props blur? theme]}]
;; TODO: Use Tiny tag component when available (issue #17341)
[rn/view
{:style (style/token-tag-text-container blur? theme)
:accessibility-label :tag-container}
[text/text
{:size :label
:weight :medium
:style (style/token-tag-text blur? theme)}
(str (:value token-props) " " (:symbol token-props))]])
(defn- options-button
[{:keys [on-options-press blur? theme]}]
[rn/pressable
{:accessibility-label :options-button
:on-press #(when on-options-press
(on-options-press))}
[icon/icon :i/options
{:color (if blur?
colors/white-opa-70
(colors/theme-colors colors/neutral-50 colors/neutral-40 theme))}]])
(defn- check-icon
[{:keys [blur? customization-color theme]}]
[rn/view {:accessibility-label :check-icon}
[icon/icon :i/check
{:color (if blur?
colors/white
(colors/theme-colors (colors/custom-color customization-color 50)
(colors/custom-color customization-color 60)
theme))}]])
(defn- f-internal-view
[]
(let [state (reagent/atom :default)
active-or-selected? (atom false)
timer (atom nil)
on-press-in (fn []
(when-not (= @state :selected)
(reset! timer (js/setTimeout #(reset! state :pressed) 100))))]
(fn [{:keys [type selectable? blur? customization-color on-press]
:or {customization-color :blue
type :default
blur? false}
:as props}]
(let [on-press-out (fn []
(let [new-state (if @active-or-selected?
:default
(if (and (= type :default) selectable?)
:selected
:active))]
(when @timer (js/clearTimeout @timer))
(reset! timer nil)
(reset! active-or-selected? (or (= new-state :active)
(= new-state :selected)))
(reset! state new-state)
(when on-press
(on-press))))]
(rn/use-effect
#(cond (and selectable? (= type :default) (= @state :active)) (reset! state :selected)
(and (not selectable?) (= type :default) (= @state :selected)) (reset! state :active))
[selectable?])
[rn/pressable
{:style (style/container
{:state @state :blur? blur? :customization-color customization-color})
:on-press-in on-press-in
:on-press-out on-press-out
:accessibility-label :container}
[account-view props]
[rn/view {:style (when (= type :tag) style/token-tag-container)}
(when (or (= type :balance-neutral)
(= type :balance-negative)
(= type :balance-positive))
[balance-view props])
(when (= type :tag)
[token-tag props])
(when (= type :action)
[options-button props])
(when (and (= type :default)
(= @state :selected))
[check-icon props])]]))))
(defn- internal-view
[props]
[:f> f-internal-view props])
(def view (quo.theme/with-theme internal-view))
@@ -38,7 +38,7 @@
:on-press-in #(reset! pressed? true)
:on-press-out #(reset! pressed? false)}
[channel-avatar/view
{:size :size/l
{:size :size-32
:locked? locked?
:full-name name
:customization-color customization-color
@@ -0,0 +1,51 @@
(ns quo2.components.list-items.saved-address.component-spec
(:require [test-helpers.component :as h]
[quo2.components.list-items.saved-address.view :as saved-address]
[quo2.foundations.colors :as colors]))
(h/describe "List items: saved address"
(h/test "default render"
(h/render [saved-address/view])
(h/is-truthy (h/query-by-label-text :container)))
(h/test "on-press-in changes state to :pressed"
(h/render [saved-address/view])
(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/custom-color :blue 50 5)})))
(h/test "on-press-in changes state to :pressed with blur? enabled"
(h/render [saved-address/view {:blur? true}])
(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 "on-press-out changes state to :active"
(h/render [saved-address/view])
(h/fire-event :on-press-in (h/get-by-label-text :container))
(h/fire-event :on-press-out (h/get-by-label-text :container))
(h/wait-for #(h/has-style (h/query-by-label-text :container)
{:backgroundColor (colors/custom-color :blue 50 10)})))
(h/test "on-press-out changes state to :active with blur? enabled"
(h/render [saved-address/view {:blur? true}])
(h/fire-event :on-press-in (h/get-by-label-text :container))
(h/fire-event :on-press-out (h/get-by-label-text :container))
(h/wait-for #(h/has-style (h/query-by-label-text :container)
{:backgroundColor colors/white-opa-10})))
(h/test "on-press-out calls on-press"
(let [on-press (h/mock-fn)]
(h/render [saved-address/view {:on-press on-press}])
(h/fire-event :on-press-in (h/get-by-label-text :container))
(h/fire-event :on-press-out (h/get-by-label-text :container))
(h/was-called on-press)))
(h/test "renders options button if type :action"
(let [on-options-press (h/mock-fn)]
(h/render [saved-address/view
{:type :action
:on-options-press on-options-press}])
(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))))
@@ -0,0 +1,42 @@
(ns quo2.components.list-items.saved-address.style
(:require [quo2.foundations.colors :as colors]))
(defn- background-color
[{:keys [state blur? customization-color]}]
(cond (and (or (= state :pressed) (= state :selected)) (not blur?))
(colors/custom-color customization-color 50 5)
(and (or (= state :pressed) (= state :selected)) blur?)
colors/white-opa-5
(and (= state :active) (not blur?))
(colors/custom-color customization-color 50 10)
(and (= state :active) blur?)
colors/white-opa-10
(and (= state :pressed) blur?) colors/white-opa-10
:else :transparent))
(defn container
[props]
{:height 56
:border-radius 12
:background-color (background-color props)
:flex-direction :row
:align-items :center
:padding-horizontal 12
:padding-vertical 6
:justify-content :space-between})
(def left-container
{:flex-direction :row
:align-items :center})
(def name-text
{:height 22})
(def account-container
{:margin-left 8})
(defn account-address
[blur? theme]
{:color (if blur?
colors/white-opa-40
(colors/theme-colors colors/neutral-50 colors/neutral-40 theme))})
@@ -0,0 +1,79 @@
(ns quo2.components.list-items.saved-address.view
(:require [quo2.components.avatars.wallet-user-avatar :as wallet-user-avatar]
[quo2.components.markdown.text :as text]
[quo2.foundations.colors :as colors]
[quo2.theme :as quo.theme]
[react-native.core :as rn]
[quo2.components.list-items.saved-address.style :as style]
[reagent.core :as reagent]
[quo2.components.icon :as icon]
[clojure.string :as string]))
(defn- left-container
[{:keys [blur? theme name address customization-color]}]
(let [names (remove string/blank? (string/split name " "))
first-name (if (> (count names) 0) (first names) "")
last-name (if (> (count names) 1) (last names) "")]
[rn/view {:style style/left-container}
[wallet-user-avatar/wallet-user-avatar
{:size :medium
:f-name first-name
:l-name last-name
:color customization-color}]
[rn/view {:style style/account-container}
[text/text
{:weight :semi-bold
:size :paragraph-1
:style style/name-text}
name]
[text/text {:size :paragraph-2}
[text/text
{:size :paragraph-2
:weight :monospace
:style (style/account-address blur? theme)}
address]]]]))
(defn- internal-view
[]
(let [state (reagent/atom :default)
active? (atom false)
timer (atom nil)
on-press-in (fn []
(when-not (= @state :selected)
(reset! timer (js/setTimeout #(reset! state :pressed) 100))))]
(fn [{:keys [blur? user-props customization-color
on-press
on-options-press
theme]
:or {customization-color :blue
blur? false}}]
(let [on-press-out (fn []
(let [new-state (if @active? :default :active)]
(when @timer (js/clearTimeout @timer))
(reset! timer nil)
(reset! active? (= new-state :active))
(reset! state new-state)
(when on-press
(on-press))))]
[rn/pressable
{:style (style/container
{:state @state :blur? blur? :customization-color customization-color})
:on-press-in on-press-in
:on-press-out on-press-out
:accessibility-label :container}
[left-container
{:blur? blur?
:theme theme
:name (:name user-props)
:address (:address user-props)
:customization-color (:customization-color user-props)}]
[rn/pressable
{:accessibility-label :options-button
:on-press #(when on-options-press
(on-options-press))}
[icon/icon :i/options
{:color (if blur?
colors/white-opa-70
(colors/theme-colors colors/neutral-50 colors/neutral-40 theme))}]]]))))
(def view (quo.theme/with-theme internal-view))
@@ -19,12 +19,6 @@
:align-items :center
:justify-content (if centered? :center :flex-start)})
(def account-switcher-placeholder
{:width 32
:height 32
:border-radius 10
:background-color (colors/custom-color :purple 50)})
(def right-actions-container
{:flex-direction :row})
@@ -1,7 +1,9 @@
(ns quo2.components.navigation.page-nav.view
(:require [quo2.components.avatars.group-avatar.view :as group-avatar]
[quo2.components.buttons.button.view :as button]
[quo2.components.dropdowns.dropdown :as dropdown]
[quo2.components.buttons.button.properties :as button-properties]
[quo2.components.dropdowns.dropdown.view :as dropdown]
[quo2.components.dropdowns.dropdown.properties :as dropdown-properties]
[quo2.components.icon :as icons]
[quo2.components.markdown.text :as text]
[quo2.components.navigation.page-nav.style :as style]
@@ -28,6 +30,7 @@
:icon-only? true
:size 32
:on-press on-press
:background (when (button-properties/backgrounds background) background)
:accessibility-label accessibility-label}
icon-name])]
children))
@@ -45,20 +48,28 @@
:icon-only? icon-name
:size 32
:accessible true
:background (when (#{:photo :blur} background) background))
:background (when (button-properties/backgrounds background) background))
(or label icon-name)]))
(interpose [right-section-spacing])))
(defn- account-switcher-content
[{:keys [customization-color on-press emoji state]}]
[dropdown/view
{:type :customization
:customization-color customization-color
:state (or state :default)
:size :size-32
:on-press on-press
:emoji? true}
emoji])
(defn- right-content
[{:keys [background content max-actions min-size? support-account-switcher?]
[{:keys [background content max-actions min-size? support-account-switcher? account-switcher]
:or {support-account-switcher? true}}]
[rn/view (when min-size? {:style style/right-content-min-size})
(cond
;; TODO: use account-switcher when available (issue #16456)
(and support-account-switcher? (= content :account-switcher))
[rn/pressable
{:style style/account-switcher-placeholder
:on-press #(js/alert "Not implemented yet")}]
[account-switcher-content account-switcher]
(coll? content)
(into [rn/view {:style style/right-actions-container}]
@@ -78,17 +89,19 @@
title]])
(defn- dropdown-center
[{:keys [theme background dropdown-on-change dropdown-selected? dropdown-text]}]
(let [dropdown-type (cond
(= background :photo) :grey
(and (= theme :dark) (= background :blur)) :grey
:else :ghost)]
[{:keys [theme background dropdown-on-press dropdown-selected? dropdown-text]}]
(let [dropdown-type (cond
(= background :photo) :grey
(and (= theme :dark) (= background :blur)) :grey
:else :ghost)
dropdown-state (if dropdown-selected? :active :default)]
[rn/view {:style (style/center-content-container true)}
[dropdown/dropdown
{:type dropdown-type
:size 32
:on-change dropdown-on-change
:selected dropdown-selected?}
[dropdown/view
{:type dropdown-type
:state dropdown-state
:size :size-32
:background (when (dropdown-properties/backgrounds background) background)
:on-press dropdown-on-press}
dropdown-text]]))
(defn- token-center
@@ -157,7 +170,7 @@
shown-name]]))
(defn- view-internal
[{:keys [type right-side background text-align]
[{:keys [type right-side background text-align account-switcher]
:or {type :no-title
text-align :center
right-side :none
@@ -173,28 +186,29 @@
[page-nav-base props
[title-center (assoc props :centered? centered?)]
[right-content
{:background background
:content right-side
:max-actions (if centered? 1 3)
:min-size? centered?}]])
{:background background
:content right-side
:max-actions (if centered? 1 3)
:min-size? centered?
:account-switcher account-switcher}]])
:dropdown
[page-nav-base props
[dropdown-center props]
[rn/view {:style style/right-actions-container}
(let [{button-icon :icon-name :as button-props} (first right-side)]
[button/button
(assoc button-props
:type (button-type background)
:icon-only? true
:size 32
:accessible true)
button-icon])]]
[right-content
{:background background
:content right-side
:max-actions 1
:support-account-switcher? false}]]
:token
[page-nav-base props
[token-center props]
[right-content {:background background :content right-side :max-actions 3}]]
[right-content
{:background background
:content right-side
:max-actions 3
:account-switcher account-switcher}]]
:channel
[page-nav-base props
@@ -224,10 +238,11 @@
:number-of-lines 1}
"NETWORK DROPDOWN"]]
[right-content
{:background background
:content right-side
:max-actions 1
:min-size? true}]]
{:background background
:content right-side
:max-actions 1
:min-size? true
:account-switcher account-switcher}]]
(:community :network)
[page-nav-base props
@@ -255,12 +270,19 @@
:on-press (fn callback [] nil)
:accessibility-label \"an optional label\"}
- account-switcher (optional)
- props to render dropdown component (emoji only) e.g.:
{:customization-color :purple
:on-press (fn [] nil)
:state :default (inherit dropdown states)
:emoji \"🍑\"}
Depending on the `type` selected, different properties are accepted:
`:title`
- title
- text-align: `:center` or `:left`
`:dropdown`
- dropdown-on-change: a callback
- dropdown-on-press: a callback
- dropdown-selected?: a boolean
- dropdown-text
`:token`
@@ -0,0 +1,43 @@
(ns quo2.components.settings.section-label.view
(:require
[quo2.theme :as quo.theme]
[quo2.components.markdown.text :as text]
[quo2.foundations.colors :as colors]))
(defn- get-text-color
[theme blur?]
(if blur?
colors/white-opa-40
(colors/theme-colors colors/neutral-50
colors/neutral-40
theme)))
(defn label-style
[color]
{:color color
:margin-bottom 2})
(defn- view-internal
"Props:
- section - the label of the section
- description (optional) - description of the section
- blur? (optional) - use blurred styling
- theme - light or dark"
[{:keys [section description blur? theme]}]
(let [color (get-text-color theme (or blur? false))
description? (not (nil? description))]
[:<>
[text/text
{:number-of-lines 1
:size (if description? :paragraph-1 :paragraph-2)
:weight :medium
:style (label-style color)}
section]
(when description?
[text/text
{:size :paragraph-1
:weight :regular
:style {:color color}}
description])]))
(def view (quo.theme/with-theme view-internal))
@@ -0,0 +1,18 @@
(ns quo2.components.switchers.base-card.component-spec
(:require [test-helpers.component :as h]
[quo2.components.switchers.base-card.view :as base-card]
[quo2.foundations.colors :as colors]))
(h/describe "Switcher: Base card"
(h/test "Default render"
(h/render [base-card/base-card {}])
(h/is-truthy (h/query-by-label-text :base-card)))
(h/test "Banner render"
(h/render [base-card/base-card {:banner {:source "banner"}}])
(h/is-truthy (h/query-by-label-text :base-card))
(h/is-truthy (h/query-by-label-text :banner)))
(h/test "Customization color"
(h/render [base-card/base-card {:customization-color :blue}])
(h/has-style
(h/query-by-label-text :base-card)
{:backgroundColor (colors/custom-color :blue 50 40)})))
@@ -0,0 +1,23 @@
(ns quo2.components.switchers.base-card.style
(:require [quo2.foundations.colors :as colors]))
(defn base-container
[customization-color]
{:width 160
:height 160
:border-radius 16
:background-color (colors/custom-color customization-color 50 40)})
(def thumb-card
{:width 160
:height 120
:border-radius 16
:bottom 0
:position :absolute
:background-color colors/neutral-95
:padding 12})
(def close-button
{:position :absolute
:right 8
:top 8})
@@ -0,0 +1,31 @@
(ns quo2.components.switchers.base-card.view
(:require [quo.react-native :as rn]
[quo2.components.buttons.button.view :as button]
[quo2.components.switchers.base-card.style :as style]))
(defn base-card
[]
(let [card-ref (atom nil)
set-ref #(reset! card-ref %)]
(fn [{:keys [banner on-press on-close customization-color]} & children]
[rn/touchable-opacity
{:on-press on-press
:ref set-ref
:active-opacity 1}
[rn/view
{:accessibility-label :base-card
:style (style/base-container customization-color)}
(when banner
[rn/image
{:accessibility-label :banner
:source (:source banner)
:style {:width 160}}])
[button/button
{:size 24
:type :grey
:icon-only? true
:on-press on-close
:background :photo
:container-style style/close-button}
:i/close]
(into [rn/view {:style style/thumb-card}] children)]])))
@@ -0,0 +1,27 @@
(ns quo2.components.switchers.card-content.style
(:require [quo2.foundations.colors :as colors]))
(defn content-container
[status]
{:flex-direction :row
:justify-content :space-between
:align-items (if (= status :mention) :center :flex-end)})
(def notification-container
{:width 20
:height 20
:justify-content :center
:align-items :center
:margin-left 8})
(def message-text
{:color colors/white})
(def sticker
{:width 24
:height 24})
(def gif
{:width 24
:height 24
:border-radius 8})
@@ -0,0 +1,98 @@
(ns quo2.components.switchers.card-content.view
(:require [react-native.core :as rn]
[react-native.fast-image :as fast-image]
[quo2.components.switchers.card-content.style :as style]
[quo2.components.common.notification-dot.view :as notification-dot]
[quo2.components.counter.counter.view :as counter]
[quo2.components.markdown.text :as text]
[quo2.components.list-items.preview-list.view :as preview-list]
[quo2.components.tags.context-tag.view :as tag]
[quo2.components.code.snippet-preview.view :as snippet-preview]
[utils.i18n :as i18n]))
(defn content-view
[{:keys [type content customization-color]
{:keys [text duration photos community-avatar
community-name source]} :content}]
[rn/view {:style {:max-width 108}}
(case type
:message
[text/text
{:size :paragraph-2
:weight :regular
:number-of-lines 1
:ellipsize-mode :tail
:style style/message-text}
text]
:photo
[preview-list/view
{:type :collectibles
:more-than-99-label (i18n/label :t/counter-99-plus)
:size :size/s-24}
photos]
:sticker
[fast-image/fast-image
{:accessibility-label :sticker
:source source
:style style/sticker}]
:gif
[fast-image/fast-image
{:accessibility-label :gif
:source source
:style style/gif}]
:audio
[tag/view
{:type :audio
:duration duration
:customization-color customization-color}]
:community
[tag/view
{:type :community
:community-name community-name
:community-logo community-avatar
:size 24}]
:link
[tag/view
{:type :icon
:icon (:icon content)
:context (:text content)
:size 24}]
:code
[snippet-preview/view
{:language (:language content)}
content]
nil)])
(defn notification-indicator
[{:keys [status mention-count customization-color]}]
(when (not= status :read)
[rn/view {:style style/notification-container}
(case status
:unread
[notification-dot/view
{:customization-color customization-color}]
:mention
[counter/view
{:outline false
:customization-color customization-color}
mention-count]
nil)]))
(defn view
[type status customization-color content]
[rn/view {:style (style/content-container status)}
[content-view {:type type :content content :customization-color customization-color}]
[notification-indicator
{:status status
:customization-color customization-color
:mention-count (:mention-count content)}]])
@@ -0,0 +1,5 @@
(ns quo2.components.switchers.card-main-info.style
(:require [quo2.foundations.colors :as colors]))
(def subtitle
{:color colors/neutral-40})
@@ -0,0 +1,21 @@
(ns quo2.components.switchers.card-main-info.view
(:require [quo2.components.markdown.text :as text]
[quo2.components.switchers.card-main-info.style :as style]
[quo.react-native :as rn]))
(defn view
[{:keys [title subtitle]}]
[rn/view
[text/text
{:accessibility-label :title
:size :paragraph-1
:weight :semi-bold
:number-of-lines 1
:ellipsize-mode :tail}
title]
[text/text
{:accessibility-label :subtitle
:size :paragraph-2
:weight :medium
:style style/subtitle}
subtitle]])
@@ -0,0 +1,116 @@
(ns quo2.components.switchers.group-messaging-card.component-spec
(:require [test-helpers.component :as h]
[quo2.components.switchers.group-messaging-card.view :as group-messaging-card]
[quo2.components.switchers.utils :as utils]))
(def photos-list
[{:source (js/require "../resources/images/mock2/photo1.png")}
{:source (js/require "../resources/images/mock2/photo2.png")}
{:source (js/require "../resources/images/mock2/photo3.png")}
{:source (js/require "../resources/images/mock2/photo1.png")}
{:source (js/require "../resources/images/mock2/photo2.png")}
{:source (js/require "../resources/images/mock2/photo3.png")}])
(def sticker {:source (js/require "../resources/images/mock2/sticker.png")})
(def gif {:source (js/require "../resources/images/mock2/gif.png")})
(def coinbase-community (js/require "../resources/images/mock2/coinbase.png"))
(def link-icon (js/require "../resources/images/mock2/status-logo.png"))
(h/describe "Switcher: Group Messaging Card"
(h/test "Default render"
(h/render [group-messaging-card/view {}])
(h/is-truthy (h/query-by-label-text :base-card)))
(h/test "Avatar render"
(h/render [group-messaging-card/view {:avatar true}])
(h/is-truthy (h/query-by-label-text :group-avatar)))
(h/test "Status: Read, Type: Message, Avatar: true"
(h/render [group-messaging-card/view
{:avatar true
:status :read
:type :message
:title "Title"
:content {:text "Last message"}}])
(h/is-truthy (h/get-by-text "Title"))
(h/is-truthy (h/get-by-text (utils/subtitle :message nil)))
(h/is-truthy (h/get-by-text "Last message")))
(h/test "Status: Unread, Type: Message, Avatar: true"
(h/render [group-messaging-card/view
{:avatar true
:status :unread
:type :message
:title "Title"}])
(h/is-truthy (h/query-by-label-text :notification-dot)))
(h/test "Status: Mention, Type: Message, Avatar: true"
(h/render [group-messaging-card/view
{:avatar true
:status :mention
:type :message
:title "Title"
:content {:mention-count 5}}])
(h/is-truthy (h/get-by-test-id :counter-component)))
(h/test "Status: Read, Type: Photo, Avatar: true"
(h/render [group-messaging-card/view
{:avatar true
:status :read
:type :photo
:title "Title"
:content {:photos photos-list}}])
(h/is-truthy (h/get-by-text (utils/subtitle :photo {:photos photos-list}))))
(h/test "Status: Read, Type: Stciker, Avatar: true"
(h/render [group-messaging-card/view
{:avatar true
:status :read
:type :sticker
:title "Title"
:content sticker}])
(h/is-truthy (h/get-by-text (utils/subtitle :sticker nil)))
(h/is-truthy (h/get-by-label-text :sticker)))
(h/test "Status: Read, Type: Gif, Avatar: true"
(h/render [group-messaging-card/view
{:avatar true
:status :read
:type :gif
:title "Title"
:content gif}])
(h/is-truthy (h/get-by-text (utils/subtitle :gif nil)))
(h/is-truthy (h/get-by-label-text :gif)))
(h/test "Status: Read, Type: Audio, Avatar: true"
(h/render [group-messaging-card/view
{:avatar true
:status :read
:type :audio
:title "Title"
:content {:duration "00:32"}}])
(h/is-truthy (h/get-by-text (utils/subtitle :audio nil)))
(h/is-truthy (h/get-by-text "00:32")))
(h/test "Status: Read, Type: Community, Avatar: true"
(h/render [group-messaging-card/view
{:avatar true
:status :read
:type :community
:title "Title"
:content {:community-avatar coinbase-community
:community-name "Coinbase"}}])
(h/is-truthy (h/get-by-text (utils/subtitle :community nil)))
(h/is-truthy (h/get-by-label-text :group-avatar))
(h/is-truthy (h/get-by-text "Coinbase")))
(h/test "Status: Read, Type: Link, Avatar: true"
(h/render [group-messaging-card/view
{:avatar true
:status :read
:type :link
:title "Title"
:content {:icon :placeholder
:text "Rolling St..."}}])
(h/is-truthy (h/get-by-text (utils/subtitle :link nil)))
(h/is-truthy (h/get-by-label-text :group-avatar))
(h/is-truthy (h/get-by-text "Rolling St..."))))
@@ -0,0 +1,16 @@
(ns quo2.components.switchers.group-messaging-card.style
(:require [quo2.foundations.colors :as colors]))
(def avatar-container
{:left 10
:top -30
:border-radius 48
:border-width 2
:border-color colors/neutral-95
:position :absolute})
(def content-container
{:flex 1
:flex-direction :column
:justify-content :space-between
:margin-top 16})
@@ -0,0 +1,32 @@
(ns quo2.components.switchers.group-messaging-card.view
(:require
[react-native.core :as rn]
[quo2.components.avatars.group-avatar.view :as group-avatar]
[quo2.components.switchers.base-card.view :as base-card]
[quo2.components.switchers.card-main-info.view :as card-main-info]
[quo2.components.switchers.card-content.view :as card-content]
[quo2.components.switchers.group-messaging-card.style :as style]
[quo2.components.switchers.utils :as utils]))
(defn view
"Opts:
:type - keyword -> :message/:photo/:sticker/:gif/:audio/:community/:link/:code
:status - keyword -> :read/:unread/:mention
:profile-color -> keyword or hexstring -> :blue/:army/... or #ABCEDF
:customization-color -> keyword or hexstring -> :blue/:army/... or #ABCEDF"
[{:keys [avatar type status title profile-color customization-color on-close content]
:or {profile-color :blue avatar nil}}]
[base-card/base-card
{:customization-color customization-color
:on-close on-close}
[rn/view {:style style/avatar-container}
[group-avatar/view
{:customization-color customization-color
:picture avatar
:icon-name :i/members
:size :size-48}]]
[rn/view {:style style/content-container}
[card-main-info/view
{:title title
:subtitle (utils/subtitle type content)}]
[card-content/view type status profile-color content]]])
+35
View File
@@ -0,0 +1,35 @@
(ns quo2.components.switchers.utils
(:require [utils.i18n :as i18n]))
(defn subtitle
[type {:keys [photos]}]
(case type
:message
(i18n/label :t/message)
:photo
(i18n/label
(if (= (count photos) 1)
:t/one-photo
:t/n-photos)
{:count (count photos)})
:sticker
(i18n/label :t/sticker)
:gif
(i18n/label :t/gif)
:audio
(i18n/label :t/audio-message)
:community
(i18n/label :t/link-to-community)
:link
(i18n/label :t/external-link)
:code
(i18n/label :t/code-snippet)
""))
@@ -7,13 +7,17 @@
(colors/theme-colors colors/neutral-80-opa-40 colors/white-opa-40 theme)
(colors/theme-colors colors/neutral-50 colors/neutral-40 theme)))
(def audio-tag-icon-container
(defn audio-tag-icon-container
[customization-color theme]
{:width 20
:height 20
:border-radius 10
:align-items :center
:justify-content :center
:background-color colors/primary-50})
:background-color (colors/theme-colors
(colors/custom-color customization-color 50)
(colors/custom-color customization-color 60)
theme)})
(def audio-tag-icon-color colors/white)
@@ -108,7 +108,7 @@
:audio
[tag-skeleton {:theme theme :text (str duration)}
[rn/view {:style style/audio-tag-icon-container}
[rn/view {:style (style/audio-tag-icon-container customization-color theme)}
[icons/icon :i/play {:color style/audio-tag-icon-color :size 12}]]]
:group
@@ -20,11 +20,13 @@
{:width 32
:height 32})
(def text-input
(defn text-input
[theme]
(merge typography/heading-1
{:font-weight "600"
:margin-left 4
:margin-left 8
:margin-right (if platform/ios? 6 4)
:color (colors/theme-colors colors/neutral-100 colors/white theme)
:padding 0
:text-align :center
:height "100%"}))
@@ -39,6 +41,6 @@
(def data-container
{:padding-top 4
:padding-horizontal 20
:height 28
:flex-direction :row
:justify-content :space-between})
:justify-content :space-between
:align-items :center})
@@ -9,7 +9,9 @@
[react-native.core :as rn]
[reagent.core :as reagent]
[quo2.foundations.common :as common]
[quo2.components.wallet.token-input.style :as style]))
[quo2.components.wallet.token-input.style :as style]
[quo2.components.tags.network-tags.view :as network-tag]
[quo2.components.dividers.divider-line.view :as divider-line]))
(defn calc-value
[crypto? currency token value conversion]
@@ -23,7 +25,7 @@
value (reagent/atom 0)
crypto? (reagent/atom true)
input-ref (atom nil)]
(fn [{:keys [theme token currency conversion]}]
(fn [{:keys [theme token currency conversion networks title customization-color]}]
[rn/view {:style (style/main-container width)}
[rn/view {:style style/amount-container}
[rn/pressable
@@ -42,22 +44,26 @@
:max-length 12
:default-value @value
:on-change-text #(reset! value %)
:style style/text-input}]
:style (style/text-input theme)
:selection-color customization-color}]
[text/text
{:size :paragraph-2
:weight :semi-bold
:style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)}}
:style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)
:margin-right 8
:padding-bottom 2}}
(string/upper-case (clj->js (if @crypto? token currency)))]]
[button/button
{:icon true
:icon-only? true
:size 32
:on-press #(swap! crypto? not)
:type :outline
:accessibility-label :reorder}
:i/reorder]]
[rn/view {:style (style/divider width theme)}]
[divider-line/view {:container-style {:margin-vertical 8}}]
[rn/view {:style style/data-container}
[text/text "[WIP] NETWORK TAG"]
[network-tag/view {:networks networks :title title}]
[text/text
{:size :paragraph-2
:weight :medium
@@ -50,7 +50,8 @@
(defn divider
[theme]
{:height 1
:margin-vertical 4
:margin-top 4
:margin-bottom 3
:background-color (colors/theme-colors colors/neutral-10 colors/neutral-80 theme)})
(defn extra-info-header
@@ -16,13 +16,6 @@
{:flex-direction :row
:padding-top 4})
(def network-dropdown
{:border-color colors/neutral-50
:border-width 1
:border-radius 10
:width 68
:height 32})
(defn color-metrics
[metrics theme]
(if (= metrics :positive)
@@ -1,10 +1,11 @@
(ns quo2.components.wallet.wallet-overview.view
(:require [quo2.components.icon :as icons]
(:require [quo2.components.dropdowns.network-dropdown.view :as network-dropdown]
[quo2.components.icon :as icon]
[quo2.components.markdown.text :as text]
[react-native.core :as rn]
[utils.i18n :as i18n]
[quo2.components.wallet.wallet-overview.style :as style]
[quo2.theme :as quo.theme]))
[quo2.theme :as quo.theme]
[react-native.core :as rn]
[utils.i18n :as i18n]))
(def ^:private time-frames
{:one-week (i18n/label :t/one-week-int)
@@ -15,22 +16,13 @@
(defn- loading-bars
[bars theme]
(map (fn [{:keys [width height margin]}]
[rn/view {:style (style/loading-bar width height margin theme)}])
bars))
;; temporary placeholder for network dropdown component
(defn- network-dropdown-temporary
[]
[:<>
[rn/view
{:style (merge style/network-dropdown
{:justify-content :center
:align-items :center})}
[text/text "[WIP]"]]])
(map-indexed (fn [index {:keys [width height margin]}]
^{:key index}
[rn/view {:style (style/loading-bar width height margin theme)}])
bars))
(defn- view-info-top
[{:keys [state balance theme]}]
[{:keys [state balance theme networks dropdown-on-press dropdown-state]}]
[rn/view {:style style/container-info-top}
(if (= state :loading)
(loading-bars [{:width 201 :height 20 :margin 0}] theme)
@@ -39,7 +31,11 @@
:size :heading-1
:style (style/style-text-heading theme)}
balance])
[network-dropdown-temporary]])
[network-dropdown/view
{:state (or dropdown-state :default)
:blur? true
:on-press dropdown-on-press}
networks]])
(defn- view-metrics
[{:keys [metrics currency-change percentage-change theme]}]
@@ -59,7 +55,7 @@
:style {:color (style/color-metrics metrics theme)
:margin-right 4}}
currency-change]
[icons/icon
[icon/icon
(if (= metrics :positive) :i/positive :i/negative)
{:color (style/color-metrics metrics theme)
:size 16}]])
@@ -90,7 +86,7 @@
:size :paragraph-2
:style (style/style-text-paragraph theme)}
begin-date]
[icons/icon :i/positive-right
[icon/icon :i/positive-right
{:color (style/color-text-paragraph theme)
:size 16}]
[text/text
+22 -6
View File
@@ -21,6 +21,7 @@
quo2.components.calendar.calendar-year.view
quo2.components.code.snippet.view
quo2.components.code.snippet-preview.view
quo2.components.colors.color.view
quo2.components.colors.color-picker.view
quo2.components.common.notification-dot.view
quo2.components.common.separator.view
@@ -43,7 +44,7 @@
quo2.components.drawers.drawer-buttons.view
quo2.components.drawers.drawer-top.view
quo2.components.drawers.permission-context.view
quo2.components.dropdowns.dropdown
quo2.components.dropdowns.dropdown.view
quo2.components.dropdowns.network-dropdown.view
quo2.components.empty-state.empty-state.view
quo2.components.gradient.gradient-cover.view
@@ -63,12 +64,14 @@
quo2.components.links.link-preview.view
quo2.components.links.url-preview-list.view
quo2.components.links.url-preview.view
quo2.components.list-items.account.view
quo2.components.list-items.account-list-card.view
quo2.components.list-items.channel.view
quo2.components.list-items.community.view
quo2.components.list-items.dapp.view
quo2.components.list-items.menu-item
quo2.components.list-items.preview-list.view
quo2.components.list-items.saved-address.view
quo2.components.list-items.token-value.view
quo2.components.list-items.user-list
quo2.components.loaders.skeleton-list.view
@@ -90,6 +93,7 @@
quo2.components.numbered-keyboard.numbered-keyboard.view
quo2.components.onboarding.small-option-card.view
quo2.components.password.tips.view
quo2.components.profile.collectible.view
quo2.components.profile.profile-card.view
quo2.components.profile.select-profile.view
quo2.components.profile.showcase-nav.view
@@ -106,8 +110,10 @@
quo2.components.settings.reorder-item.view
quo2.components.settings.settings-item.view
quo2.components.settings.category.view
quo2.components.settings.section-label.view
quo2.components.share.qr-code.view
quo2.components.share.share-qr-code.view
quo2.components.switchers.group-messaging-card.view
quo2.components.tabs.account-selector
quo2.components.tabs.segmented-tab
quo2.components.tabs.tabs.view
@@ -175,7 +181,7 @@
;;;; Colors
(def color-picker quo2.components.colors.color-picker.view/view)
(def picker-colors quo2.components.colors.color-picker.view/picker-colors)
(def color quo2.components.colors.color.view/view)
;;;; Community
(def community-card-view-item quo2.components.community.community-card-view/view)
@@ -210,7 +216,7 @@
(def permission-context quo2.components.drawers.permission-context.view/view)
;;;; Dropdowns
(def dropdown quo2.components.dropdowns.dropdown/dropdown)
(def dropdown quo2.components.dropdowns.dropdown.view/view)
(def network-dropdown quo2.components.dropdowns.network-dropdown.view/view)
;;;; Empty State
@@ -252,6 +258,7 @@
(def url-preview-list quo2.components.links.url-preview-list.view/view)
;;;; List items
(def account-item quo2.components.list-items.account.view/view)
(def account-list-card quo2.components.list-items.account-list-card.view/view)
(def channel quo2.components.list-items.channel.view/view)
(def dapp quo2.components.list-items.dapp.view/view)
@@ -259,6 +266,7 @@
(def preview-list quo2.components.list-items.preview-list.view/view)
(def user-list quo2.components.list-items.user-list/user-list)
(def community-list-item quo2.components.list-items.community.view/view)
(def saved-address quo2.components.list-items.saved-address.view/view)
(def token-value quo2.components.list-items.token-value.view/view)
;;;; Loaders
@@ -290,6 +298,7 @@
(def tips quo2.components.password.tips.view/view)
;;;; Profile
(def collectible quo2.components.profile.collectible.view/collectible)
(def profile-card quo2.components.profile.profile-card.view/profile-card)
(def select-profile quo2.components.profile.select-profile.view/view)
(def showcase-nav quo2.components.profile.showcase-nav.view/view)
@@ -308,19 +317,26 @@
(def filter quo2.components.selectors.filter.view/view)
(def reactions quo2.components.selectors.reactions.view/view)
(def checkbox quo2.components.selectors.selectors.view/checkbox)
(def toggle quo2.components.selectors.selectors.view/toggle)
(def radio quo2.components.selectors.selectors.view/radio)
(def checkbox-prefill quo2.components.selectors.selectors.view/checkbox-prefill)
;;;; Settings
(def privacy-option quo2.components.settings.privacy-option.view/view)
(def account quo2.components.settings.accounts.view/account)
(def settings-item quo2.components.settings.settings-item.view/view)
(def reorder-item quo2.components.settings.reorder-item.view/reorder-item)
(def category quo2.components.settings.category.view/category)
(def data-item quo2.components.settings.data-item.view/view)
(def privacy-option quo2.components.settings.privacy-option.view/view)
(def reorder-item quo2.components.settings.reorder-item.view/reorder-item)
(def section-label quo2.components.settings.section-label.view/view)
(def settings-item quo2.components.settings.settings-item.view/view)
;;;; Share
(def qr-code quo2.components.share.qr-code.view/qr-code)
(def share-qr-code quo2.components.share.share-qr-code.view/view)
;;;; SWITCHER
(def group-messaging-card quo2.components.switchers.group-messaging-card.view/view)
;;;; Tabs
(def tabs quo2.components.tabs.tabs.view/view)
(def segmented-control quo2.components.tabs.segmented-tab/segmented-control)
+5
View File
@@ -24,6 +24,7 @@
[quo2.components.drawers.drawer-buttons.component-spec]
[quo2.components.drawers.drawer-top.component-spec]
[quo2.components.drawers.permission-context.component-spec]
[quo2.components.dropdowns.dropdown.component-spec]
[quo2.components.dropdowns.network-dropdown.component-spec]
[quo2.components.gradient.gradient-cover.component-spec]
[quo2.components.graph.wallet-graph.component-spec]
@@ -37,9 +38,11 @@
[quo2.components.links.link-preview.component-spec]
[quo2.components.links.url-preview-list.component-spec]
[quo2.components.links.url-preview.component-spec]
[quo2.components.list-items.account.component-spec]
[quo2.components.list-items.channel.component-spec]
[quo2.components.list-items.community.component-spec]
[quo2.components.list-items.dapp.component-spec]
[quo2.components.list-items.saved-address.component-spec]
[quo2.components.list-items.token-value.component-spec]
[quo2.components.loaders.skeleton-list.component-spec]
[quo2.components.markdown.text-component-spec]
@@ -62,6 +65,8 @@
[quo2.components.settings.category.component-spec]
[quo2.components.settings.data-item.component-spec]
[quo2.components.share.share-qr-code.component-spec]
[quo2.components.switchers.base-card.component-spec]
[quo2.components.switchers.group-messaging-card.component-spec]
[quo2.components.tags.network-tags.component-spec]
[quo2.components.tags.status-tags-component-spec]
[quo2.components.wallet.account-card.component-spec]
+2 -2
View File
@@ -68,7 +68,7 @@
(def neutral-80-opa-20 (alpha neutral-80 0.2))
(def neutral-80-opa-30 (alpha neutral-80 0.3))
(def neutral-80-opa-40 (alpha neutral-80 0.4))
(def neutral-80-opa-50 (alpha neutral-80 0.4))
(def neutral-80-opa-50 (alpha neutral-80 0.5))
(def neutral-80-opa-60 (alpha neutral-80 0.6))
(def neutral-80-opa-70 (alpha neutral-80 0.7))
(def neutral-80-opa-80 (alpha neutral-80 0.8))
@@ -215,7 +215,7 @@
60 "#CC6438"}
:army {50 "#216266"
60 "#1A4E52"}
:pink {50 "#F66F8F"
:flamingo {50 "#F66F8F"
60 "#C55972"}
:purple {50 "#7140FD"
60 "#5A33CA"}
+1 -1
View File
@@ -15,5 +15,5 @@
(defn authenticate
[{:keys [on-success on-fail reason options]}]
(-> (.authenticate ^js touchid reason (clj->js options))
(.then #(when on-success (on-success)))
(.then #(when on-success (on-success %)))
(.catch #(when on-fail (on-fail (aget % "code"))))))
+14 -6
View File
@@ -9,7 +9,6 @@
[status-im.browser.permissions :as browser.permissions]
[status-im.browser.webview-ref :as webview-ref]
[status-im2.constants :as constants]
[status-im.ethereum.core :as ethereum]
[status-im.ethereum.ens :as ens]
[utils.i18n :as i18n]
[status-im.multiaccounts.update.core :as multiaccounts.update]
@@ -25,7 +24,9 @@
[status-im2.navigation.events :as navigation]
[taoensso.timbre :as log]
[utils.debounce :as debounce]
[utils.security.core :as security]))
[utils.security.core :as security]
[utils.ethereum.chain :as chain]
[utils.address :as address]))
(rf/defn update-browser-option
[{:keys [db]} option-key option-value]
@@ -91,7 +92,7 @@
host (url/url-host current-url)]
(if (and (not resolved-url) (ens/is-valid-eth-name? host))
{:db (update db :browser/options assoc :resolving? true)
:browser/resolve-ens-contenthash {:chain-id (ethereum/chain-id db)
:browser/resolve-ens-contenthash {:chain-id (chain/chain-id db)
:ens-name host
:cb resolve-ens-contenthash-callback}}
{:db (update db :browser/options assoc :url (or resolved-url current-url) :resolving? false)}))))
@@ -352,12 +353,19 @@
:id (int id)
:result result}}})
(defn utf8-to-hex
[s]
(let [hex (native-module/utf8-to-hex (str s))]
(if (empty? hex)
nil
hex)))
(defn normalize-message
"NOTE (andrey) there is no spec for this, so this implementation just to be compatible with MM"
[message]
(if (string/starts-with? message "0x")
message
(ethereum/utf8-to-hex message)))
(utf8-to-hex message)))
(defn normalize-sign-message-params
"NOTE (andrey) we need this function, because params may be mixed up"
@@ -365,9 +373,9 @@
(let [[first-param second-param] params]
(when (and (string? first-param) (string? second-param))
(cond
(ethereum/address? first-param)
(address/address? first-param)
[first-param (if typed? second-param (normalize-message second-param))]
(ethereum/address? second-param)
(address/address? second-param)
[second-param (if typed? first-param (normalize-message first-param))]))))
(rf/defn send-to-bridge
+6 -6
View File
@@ -2,9 +2,9 @@
;(`wallet_switchEthereumChain`)
(ns status-im.browser.eip3326
(:require [status-im2.constants :as constants]
[status-im.ethereum.core :as ethereum]
[status-im.ui.screens.browser.eip3326.sheet :as sheet]
[utils.re-frame :as rf]))
[utils.re-frame :as rf]
[utils.ethereum.chain :as chain]))
(rf/defn deny-permission
{:events [:eip3326.ui/dapp-permission-denied]}
@@ -20,8 +20,8 @@
[{:keys [db] :as cofx} dapp-name id message-id {:keys [chainId] :as params}]
(let [target-chain-id (js/parseInt chainId 16)
networks (vals (get-in db [:networks/networks]))
exist-chain-ids (set (map ethereum/network->chain-id networks))
current-chain-id (ethereum/chain-id db)]
exist-chain-ids (set (map chain/network->chain-id networks))
current-chain-id (chain/chain-id db)]
(if (exist-chain-ids target-chain-id)
(if (= current-chain-id target-chain-id)
{:browser/send-to-bridge {:type constants/web3-send-async-callback
@@ -29,10 +29,10 @@
:result {:jsonrpc "2.0"
:id (int id)
:result nil}}}
(let [target-network (first (filter #(= (ethereum/network->chain-id %1) target-chain-id)
(let [target-network (first (filter #(= (chain/network->chain-id %1) target-chain-id)
networks))
target-network-id (:id target-network)
current-network (ethereum/current-network db)
current-network (chain/current-network db)
network-from (:name current-network)
network-to (:name target-network)
params (assoc params
+4 -3
View File
@@ -1,7 +1,7 @@
(ns status-im.commands.core
(:require [re-frame.core :as re-frame]
[status-im.ethereum.core :as ethereum]
[utils.re-frame :as rf]))
[utils.re-frame :as rf]
[status-im.wallet.utils :as wallet.utils]))
(rf/defn handle-prepare-accept-request-address-for-transaction
{:events [::prepare-accept-request-address-for-transaction]}
@@ -9,7 +9,8 @@
{:db (assoc db
:commands/select-account
{:message message
:from (ethereum/get-default-account (:profile/wallet-accounts db))})
:from (wallet.utils/get-default-account (:profile/wallet-accounts
db))})
:show-select-acc-sheet nil})
(rf/defn set-selected-account
+3 -3
View File
@@ -2,8 +2,8 @@
(:require [clojure.set :as set]
[clojure.string :as string]
[status-im2.constants :as constants]
[status-im.ethereum.core :as ethereum]
[status-im.utils.gfycat.core :as gfycat]))
[status-im.utils.gfycat.core :as gfycat]
[utils.address :as address]))
(defn public-key->new-contact
[public-key]
@@ -31,7 +31,7 @@
(defn- contact-by-address
[[addr contact] address]
(when (ethereum/address= addr address)
(when (address/address= addr address)
contact))
(defn find-contact-by-address
+1 -1
View File
@@ -1,6 +1,6 @@
(ns status-im.data-store.settings
(:require [status-im.data-store.visibility-status-updates :as visibility-status-updates]
[status-im.ethereum.eip55 :as eip55]
[utils.ethereum.eip.eip55 :as eip55]
[status-im2.config :as config]
[clojure.set :as set]))
+19 -12
View File
@@ -5,8 +5,7 @@
[clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.bottom-sheet.events :as bottom-sheet]
[status-im.ethereum.core :as ethereum]
[status-im.ethereum.eip55 :as eip55]
[utils.ethereum.eip.eip55 :as eip55]
[status-im.ethereum.ens :as ens]
[status-im.ethereum.stateofus :as stateofus]
[status-im.multiaccounts.update.core :as multiaccounts.update]
@@ -15,7 +14,9 @@
[status-im.utils.random :as random]
[status-im2.navigation.events :as navigation]
[status-im2.constants :as constants]
[taoensso.timbre :as log]))
[taoensso.timbre :as log]
[utils.ethereum.chain :as chain]
[status-im.wallet.utils :as wallet.utils]))
(defn fullname
[custom-domain? username]
@@ -102,7 +103,7 @@
[{:keys [db] :as cofx} custom-domain? username redirect-to-summary? connected?]
(let [name (fullname custom-domain? username)
names (get-in db [:ens/names] [])
chain-id (ethereum/chain-id db)]
chain-id (chain/chain-id db)]
(rf/merge cofx
(cond-> {:dispatch-n [[:ens/update-usernames [{:username name :chain-id chain-id}]]]}
connected? (assoc :json-rpc/call
@@ -124,9 +125,9 @@
{:events [::set-pub-key]}
[{:keys [db]}]
(let [{:keys [username address custom-domain?]} (:ens/registration db)
address (or address (ethereum/default-address db))
address (or address (wallet.utils/default-address db))
{:keys [public-key]} (:profile/profile db)
chain-id (ethereum/chain-id db)
chain-id (chain/chain-id db)
username (fullname custom-domain? username)]
{:db (assoc-in db [:ens/registration :action] constants/ens-action-type-set-pub-key)
:json-rpc/call [{:method "ens_setPubKeyPrepareTx"
@@ -192,7 +193,7 @@
(let [{:keys [username]}
(:ens/registration db)
{:keys [public-key]} (:profile/profile db)
chain-id (ethereum/chain-id db)]
chain-id (chain/chain-id db)]
{:db (assoc-in db [:ens/registration :action] constants/ens-action-type-register)
:json-rpc/call [{:method "ens_registerPrepareTx"
:params [chain-id {:from address} username public-key]
@@ -225,6 +226,12 @@
:searching)
:else :invalid))
(defn addresses-without-watch
[db]
(into #{}
(remove #(= (:type %) :watch)
(map #(eip55/address->checksum (:address %)) (get db :profile/wallet-accounts)))))
;;NOTE we want to handle only last resolve
(def resolve-last-id (atom nil))
@@ -243,8 +250,8 @@
(when (= state :searching)
(let [{:profile/keys [profile]} db
{:keys [public-key]} profile
addresses (ethereum/addresses-without-watch db)
chain-id (ethereum/chain-id db)]
addresses (addresses-without-watch db)
chain-id (chain/chain-id db)]
{::resolve-owner [chain-id
(fullname custom-domain? username)
#(on-resolve-owner
@@ -266,8 +273,8 @@
;; we reset navigation so that navigate back doesn't return
;; into the registration flow
(navigation/navigate-back-to :my-profile)
(navigation/navigate-to :ens-main {})
))
(navigation/navigate-to :ens-main {})))
(rf/defn switch-domain-type
{:events [::switch-domain-type]}
@@ -320,7 +327,7 @@
(rf/defn navigate-to-name
{:events [::navigate-to-name]}
[{:keys [db] :as cofx} username]
(let [chain-id (ethereum/chain-id db)]
(let [chain-id (chain/chain-id db)]
(rf/merge cofx
{::get-expiration-time
[chain-id
-21
View File
@@ -1,21 +0,0 @@
(ns status-im.ethereum.contracts
(:require [status-im.ethereum.core :as ethereum]))
(def contracts
{:status/snt
{:mainnet "0x744d70fdbe2ba4cf95131626614a1763df805b9e"
:goerli "0x3D6AFAA395C31FCd391fE3D562E75fe9E8ec7E6a"}
:status/stickers
{:mainnet "0x0577215622f43a39f4bc9640806dfea9b10d2a36"
:goerli "0x07f7CB0C0a4ab3e0999AfE8b3997Da34880f05d0"}
:status/sticker-market
{:mainnet "0x12824271339304d3a9f7e096e62a2a7e73b4a7e7"
:goerli "0xf1E149A7DF70D5Ff1E265daAa738d785D3274717"}
:status/sticker-pack
{:mainnet "0x110101156e8F0743948B2A61aFcf3994A8Fb172e"
:goerli "0x8D3fD2EA24bD53a8Bd2b1026727db8bbe9A8C8Af"}})
(defn get-address
[db contract]
(let [chain-keyword (ethereum/chain-keyword db)]
(get-in contracts [contract chain-keyword])))
-202
View File
@@ -1,202 +0,0 @@
(ns status-im.ethereum.core
(:require [clojure.string :as string]
[status-im.ethereum.eip55 :as eip55]
[native-module.core :as native-module]))
(defn sha3
[s]
(when s
(native-module/sha3 (str s))))
(defn utf8-to-hex
[s]
(let [hex (native-module/utf8-to-hex (str s))]
(if (empty? hex)
nil
hex)))
(defn hex-to-utf8
[s]
(let [utf8 (native-module/hex-to-utf8 s)]
(if (empty? utf8)
nil
utf8)))
(def BSC-mainnet-chain-id 56)
(def BSC-testnet-chain-id 97)
;; IDs standardized in https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md#list-of-chain-ids
(def chains
{:mainnet {:id 1 :name "Mainnet"}
:xdai {:id 100 :name "xDai"}
:goerli {:id 5 :name "Goerli"}
:bsc {:id BSC-mainnet-chain-id
:name "BSC"}
:bsc-testnet {:id BSC-testnet-chain-id
:name "BSC tetnet"}})
(defn chain-id->chain-keyword
[i]
(or (some #(when (= i (:id (val %))) (key %)) chains)
:custom))
(defn chain-id->chain-name
[i]
(or (some #(when (= i (:id (val %))) (:name (val %))) chains)
:custom))
(defn chain-keyword->chain-id
[k]
(get-in chains [k :id]))
(defn chain-keyword->snt-symbol
[k]
(case k
:mainnet :SNT
:STT))
(defn testnet?
[id]
(contains? #{(chain-keyword->chain-id :goerli)
(chain-keyword->chain-id :bsc-testnet)}
id))
(defn sidechain?
[id]
(contains? #{(chain-keyword->chain-id :xdai)
(chain-keyword->chain-id :bsc)}
id))
(defn network-with-upstream-rpc?
[network]
(get-in network [:config :UpstreamConfig :Enabled]))
(def hex-prefix "0x")
(defn normalized-hex
[hex]
(when hex
(if (string/starts-with? hex hex-prefix)
hex
(str hex-prefix hex))))
(defn current-address
[db]
(-> (get-in db [:profile/profile :address])
normalized-hex))
(defn get-default-account
[accounts]
(some #(when (:wallet %) %) accounts))
(defn default-address
[db]
(-> (get db :profile/wallet-accounts)
get-default-account
:address))
(defn addresses-without-watch
[db]
(into #{}
(remove #(= (:type %) :watch)
(map #(eip55/address->checksum (:address %)) (get db :profile/wallet-accounts)))))
(defn naked-address
[s]
(when s
(string/replace s hex-prefix "")))
(def public-key-length 128)
(defn coordinates
[public-key]
(when-let [hex (naked-address public-key)]
(when (= public-key-length (count (subs hex 2)))
{:x (normalized-hex (subs hex 2 66))
:y (normalized-hex (subs hex 66))})))
(defn address?
[s]
(when s
(native-module/address? s)))
(defn network->chain-id
[network]
(get-in network [:config :NetworkId]))
(defn network->chain-keyword
[network]
(chain-id->chain-keyword (network->chain-id network)))
(defn current-network
[db]
(let [networks (get db :networks/networks)
network-id (get db :networks/current-network)]
(get networks network-id)))
(defn binance-chain-id?
[chain-id]
(or (= BSC-mainnet-chain-id chain-id)
(= BSC-testnet-chain-id chain-id)))
(defn binance-chain?
[db]
(-> db
current-network
network->chain-id
binance-chain-id?))
(def custom-rpc-node-id-len 45)
(defn custom-rpc-node?
[{:keys [id]}]
(= custom-rpc-node-id-len (count id)))
(defn network->network-name
[network]
(chain-id->chain-name (network->chain-id network)))
(defn network->chain-name
[network]
(-> network
network->chain-keyword
name))
(defn get-current-network
[m]
(get (:networks/networks m) (:networks/current-network m)))
(defn chain-keyword
[db]
(network->chain-keyword (get-current-network db)))
(defn chain-id
[db]
(network->chain-id (get-current-network db)))
(defn snt-symbol
[db]
(chain-keyword->snt-symbol (chain-keyword db)))
(defn address=
[address1 address2]
(and address1
address2
(= (string/lower-case (normalized-hex address1))
(string/lower-case (normalized-hex address2)))))
(defn public-key->address
[public-key]
(let [length (count public-key)
normalized-key (case length
132 (str "0x" (subs public-key 4))
130 public-key
128 (str "0x" public-key)
nil)]
(when normalized-key
(subs (sha3 normalized-key) 26))))
(defn hex->text
"Converts a hexstring to UTF8 text."
[data]
(or (hex-to-utf8 data) data))
-16
View File
@@ -1,16 +0,0 @@
(ns status-im.ethereum.core-test
(:require [cljs.test :refer-macros [deftest is]]
[status-im.ethereum.core :as ethereum]))
(deftest chain-id->chain-keyword
(is (= (ethereum/chain-id->chain-keyword 1) :mainnet))
(is (= (ethereum/chain-id->chain-keyword 5) :goerli))
(is (= (ethereum/chain-id->chain-keyword 5777) :custom)))
(deftest coordinates
(is
(=
{:x "0x46fa4851f3cccd01e3b8d96c130c00bf812502354939eacf06a68fa519ebcbd1"
:y "0xeb08bebe7403856c0d9686210b9b2e324aa0179747bbba56d53f304a002f31c3"}
(ethereum/coordinates
"0x0446fa4851f3cccd01e3b8d96c130c00bf812502354939eacf06a68fa519ebcbd1eb08bebe7403856c0d9686210b9b2e324aa0179747bbba56d53f304a002f31c3"))))
+10 -9
View File
@@ -5,10 +5,11 @@
e.g. ethereum:0x1234@1/transfer?to=0x5678&value=1e18&gas=5000"
(:require [clojure.string :as string]
[status-im.ethereum.core :as ethereum]
[status-im.ethereum.ens :as ens]
[status-im.ethereum.tokens :as tokens]
[utils.money :as money]))
[utils.money :as money]
[utils.ethereum.chain :as chain]
[utils.address :as address]))
(def scheme "ethereum")
(def scheme-separator ":")
@@ -64,16 +65,16 @@
Invalid URI will be parsed as `nil`."
[s]
(when (string? s)
(if (ethereum/address? s)
(if (address/address? s)
{:address s}
(let [[_ authority-path query] (re-find uri-pattern s)]
(when authority-path
(let [[_ raw-address chain-id function-name] (re-find authority-path-pattern authority-path)]
(when (or (or (ens/is-valid-eth-name? raw-address) (ethereum/address? raw-address))
(when (or (or (ens/is-valid-eth-name? raw-address) (address/address? raw-address))
(when (string/starts-with? raw-address "pay-")
(let [pay-address (string/replace-first raw-address "pay-" "")]
(or (ens/is-valid-eth-name? pay-address)
(ethereum/address? pay-address)))))
(address/address? pay-address)))))
(let [address (if (string/starts-with? raw-address "pay-")
(string/replace-first raw-address "pay-" "")
raw-address)]
@@ -81,12 +82,12 @@
(let [contract-address (get-in arguments [:function-arguments :address])]
(if-not (or (not contract-address)
(or (ens/is-valid-eth-name? contract-address)
(ethereum/address? contract-address)))
(address/address? contract-address)))
nil
(merge {:address address
:chain-id (if chain-id
(js/parseInt chain-id)
(ethereum/chain-keyword->chain-id :mainnet))}
(chain/chain-keyword->chain-id :mainnet))}
arguments))))))))))))
(defn parse-eth-value
@@ -124,12 +125,12 @@
"Generate a EIP 681 URI based on `address` and a map (keywords / {bignumbers/strings} ) of extra properties.
No validation of address format is performed."
[address {:keys [chain-id function-name function-arguments] :as m}]
(when (ethereum/address? address)
(when (address/address? address)
(let [parameters (dissoc (into {} (filter second m)) :chain-id)] ;; filter nil values
(str scheme
scheme-separator
address
(when (and chain-id (not= chain-id (ethereum/chain-keyword->chain-id :mainnet)))
(when (and chain-id (not= chain-id (chain/chain-keyword->chain-id :mainnet)))
;; Add chain-id if specified and is not main-net
(str chain-id-separator chain-id))
(when-not (empty? parameters)
+1 -1
View File
@@ -1,5 +1,5 @@
(ns status-im.ethereum.eip681-test
(:require [cljs.test :refer-macros [deftest is] :as test]
(:require [cljs.test :refer-macros [deftest is]]
[status-im.ethereum.eip681 :as eip681]
[utils.money :as money]))
-4
View File
@@ -189,10 +189,6 @@
(-> (sanitize-passphrase s)
(string/split #" "))))
(defn words->passphrase
[v]
(string/join " " v))
(def valid-word-counts #{12 15 18 21 24})
(defn valid-word-counts?
+1 -16
View File
@@ -1,6 +1,5 @@
(ns status-im.ethereum.stateofus
(:require [clojure.string :as string]
[status-im.ethereum.core :as ethereum]
[status-im.ethereum.ens :as ens]
[status-im2.config :as config]))
@@ -33,23 +32,9 @@
(when config/test-stateofus?
{:goerli "0xD1f7416F91E7Eb93dD96A61F12FC092aD6B67B11"})))
(def registrars-cache (atom {}))
(defn get-registrar
[chain callback]
(if-let [contract (get @registrars-cache chain)]
(callback contract)
(ens/owner
(ethereum/chain-keyword->chain-id chain)
domain
(fn [addr]
(let [addr (or addr (get old-registrars chain))]
(swap! registrars-cache assoc chain addr)
(callback addr))))))
(defn get-cached-registrar
[chain]
(get @registrars-cache chain (get old-registrars chain)))
(get old-registrars chain))
(defn lower-case?
[s]
+1 -1
View File
@@ -1,5 +1,5 @@
(ns status-im.ethereum.subscriptions
(:require [status-im.ethereum.eip55 :as eip55]
(:require [utils.ethereum.eip.eip55 :as eip55]
[status-im.ethereum.transactions.core :as transactions]
[utils.re-frame :as rf]
[status-im.wallet.core :as wallet.core]
+2 -2
View File
@@ -1,6 +1,6 @@
(ns status-im.ethereum.tokens
(:require [clojure.string :as string]
[status-im.ethereum.core :as ethereum])
[utils.ethereum.chain :as chain])
(:require-macros [status-im.ethereum.macros :as ethereum.macros :refer [resolve-icons]]))
(def default-native-currency
@@ -42,7 +42,7 @@
(defn native-currency
[{sym :symbol :as current-network}]
(let [chain (ethereum/network->chain-keyword current-network)]
(let [chain (chain/network->chain-keyword current-network)]
(get all-native-currencies chain (default-native-currency sym))))
(defn ethereum?
@@ -1,24 +1,24 @@
(ns status-im.ethereum.transactions.core
(:require [cljs.spec.alpha :as spec]
[re-frame.core :as re-frame]
[status-im.ethereum.core :as ethereum]
[status-im.ethereum.decode :as decode]
[status-im.ethereum.eip55 :as eip55]
[utils.ethereum.eip.eip55 :as eip55]
[status-im.ethereum.encode :as encode]
[utils.re-frame :as rf]
[status-im.utils.mobile-sync :as utils.mobile-sync]
[status-im.wallet.core :as wallet]
[status-im2.common.json-rpc.events :as json-rpc]
[taoensso.timbre :as log]))
[taoensso.timbre :as log]
[utils.ethereum.chain :as chain]))
(def confirmations-count-threshold 12)
(def etherscan-supported?
#{(ethereum/chain-keyword->chain-id :mainnet)
(ethereum/chain-keyword->chain-id :goerli)})
#{(chain/chain-keyword->chain-id :mainnet)
(chain/chain-keyword->chain-id :goerli)})
(def binance-mainnet-chain-id (ethereum/chain-keyword->chain-id :bsc))
(def binance-testnet-chain-id (ethereum/chain-keyword->chain-id :bsc-testnet))
(def binance-mainnet-chain-id (chain/chain-keyword->chain-id :bsc))
(def binance-testnet-chain-id (chain/chain-keyword->chain-id :bsc-testnet))
(def network->subdomain {5 "goerli"})
+3 -3
View File
@@ -3,7 +3,6 @@
[clojure.string :as string]
[day8.re-frame.test :as rf-test]
[re-frame.core :as rf]
[status-im.ethereum.core :as ethereum]
status-im.events
status-im2.events
[status-im.multiaccounts.logout.core :as logout]
@@ -12,7 +11,8 @@
status-im2.navigation.core
status-im2.subs.root ; so integration tests can run independently
[taoensso.timbre :as log]
[status-im2.constants :as constants]))
[status-im2.constants :as constants]
[native-module.core :as native-module]))
(def password "testabc")
@@ -52,7 +52,7 @@
[]
(rf/dispatch-sync [:wallet.accounts/start-adding-new-account {:type :generate}])
(rf/dispatch-sync [:set-in [:add-account :account :name] account-name])
(rf/dispatch [:wallet.accounts/add-new-account (ethereum/sha3 password)]))
(rf/dispatch [:wallet.accounts/add-new-account (native-module/sha3 password)]))
(defn assert-new-account-created
[]
+4 -4
View File
@@ -2,7 +2,6 @@
(:require [clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.bottom-sheet.events :as bottom-sheet]
[status-im.ethereum.core :as ethereum]
[utils.i18n :as i18n]
[status-im.keycard.nfc :as nfc]
[status-im.popover.core :as popover]
@@ -13,7 +12,8 @@
[react-native.platform :as platform]
[status-im.utils.deprecated-types :as types]
[status-im2.navigation.events :as navigation]
[taoensso.timbre :as log]))
[taoensso.timbre :as log]
[utils.address :as address]))
(def default-pin "000000")
@@ -78,7 +78,7 @@
(when key-uid
(->> (:profile/profiles-overview db)
vals
(filter #(= (ethereum/normalized-hex key-uid) (:key-uid %)))
(filter #(= (address/normalized-hex key-uid) (:key-uid %)))
first)))
(defn get-pairing
@@ -354,7 +354,7 @@
:puk-retry-counter 5
:pin-retry-counter 3)
(assoc-in [:keycard :profile/profile]
(update account-data :whisper-public-key ethereum/normalized-hex))
(update account-data :whisper-public-key address/normalized-hex))
(assoc-in [:keycard :flow] nil)
(update :profile/login assoc
:password encryption-public-key
+3 -3
View File
@@ -1,6 +1,5 @@
(ns status-im.keycard.login
(:require [status-im.bottom-sheet.events :as bottom-sheet]
[status-im.ethereum.core :as ethereum]
[status-im.keycard.common :as common]
status-im.keycard.fx
[status-im.keycard.onboarding :as onboarding]
@@ -9,7 +8,8 @@
[utils.re-frame :as rf]
[status-im.utils.deprecated-types :as types]
[status-im2.navigation.events :as navigation]
[taoensso.timbre :as log]))
[taoensso.timbre :as log]
[utils.address :as address]))
(rf/defn login-got-it-pressed
{:events [:keycard.login.pin.ui/got-it-pressed
@@ -162,7 +162,7 @@
(assoc-in [:keycard :pin :status] nil)
(assoc-in [:keycard :pin :login] [])
(assoc-in [:keycard :profile/profile]
(update account-data :whisper-public-key ethereum/normalized-hex))
(update account-data :whisper-public-key address/normalized-hex))
(assoc-in [:keycard :flow] nil)
(update :profile/login assoc
:password encryption-public-key
+4 -4
View File
@@ -2,12 +2,12 @@
(:require ["react-native" :as rn]
["react-native-status-keycard" :default status-keycard]
[clojure.string :as string]
[status-im.ethereum.core :as ethereum]
[status-im.keycard.keycard :as keycard]
[native-module.core :as native-module]
[react-native.platform :as platform]
[status-im.utils.deprecated-types :as types]
[taoensso.timbre :as log]))
[taoensso.timbre :as log]
[utils.address :as address]))
(defonce event-emitter
(if platform/ios?
@@ -114,7 +114,7 @@
(then (fn [response]
(let [info (-> response
(js->clj :keywordize-keys true)
(update :key-uid ethereum/normalized-hex))]
(update :key-uid address/normalized-hex))]
(on-success info))))
(catch on-failure)))
@@ -125,7 +125,7 @@
(then (fn [response]
(let [info (-> response
(js->clj :keywordize-keys true)
(update :key-uid ethereum/normalized-hex))]
(update :key-uid address/normalized-hex))]
(on-success info))))
(catch on-failure)))
+16 -16
View File
@@ -3,8 +3,7 @@
[re-frame.core :as re-frame]
[status-im.bottom-sheet.events :as bottom-sheet]
[status-im2.constants :as constants]
[status-im.ethereum.core :as ethereum]
[status-im.ethereum.eip55 :as eip55]
[utils.ethereum.eip.eip55 :as eip55]
[utils.i18n :as i18n]
[status-im.keycard.common :as common]
status-im.keycard.fx
@@ -19,7 +18,8 @@
[status-im.utils.deprecated-types :as types]
[status-im2.navigation.events :as navigation]
[taoensso.timbre :as log]
[utils.security.core :as security]))
[utils.security.core :as security]
[utils.address :as address]))
(rf/defn pair*
[_ password]
@@ -203,7 +203,7 @@
:address address
:public-key public-key
:keycard-instance-uid instance-uid
:key-uid (ethereum/normalized-hex key-uid)
:key-uid (address/normalized-hex key-uid)
:keycard-pairing pairing
:keycard-paired-on paired-on
:chat-key whisper-private-key}
@@ -272,9 +272,9 @@
settings {:keycard-instance-uid instance-uid
:keycard-paired-on paired-on
:keycard-pairing pairing}
password (ethereum/sha3 (security/safe-unmask-data (get-in db
[:keycard
:migration-password])))
password (native-module/sha3 (security/safe-unmask-data (get-in db
[:keycard
:migration-password])))
encryption-pass (get-in db [:keycard :profile/profile :encryption-public-key])
login-params {:key-uid key-uid
:multiaccount-data (types/clj->json account)
@@ -316,20 +316,20 @@
(assoc-in
[:keycard :profile/profile]
(-> account-data
(update :address ethereum/normalized-hex)
(update :whisper-address ethereum/normalized-hex)
(update :wallet-address ethereum/normalized-hex)
(update :wallet-root-address ethereum/normalized-hex)
(update :public-key ethereum/normalized-hex)
(update :whisper-public-key ethereum/normalized-hex)
(update :wallet-public-key ethereum/normalized-hex)
(update :wallet-root-public-key ethereum/normalized-hex)
(update :address address/normalized-hex)
(update :whisper-address address/normalized-hex)
(update :wallet-address address/normalized-hex)
(update :wallet-root-address address/normalized-hex)
(update :public-key address/normalized-hex)
(update :whisper-public-key address/normalized-hex)
(update :wallet-public-key address/normalized-hex)
(update :wallet-root-public-key address/normalized-hex)
(update :instance-uid #(get-in db [:keycard :profile/profile :instance-uid] %))))
(assoc-in [:keycard :multiaccount-wallet-address] (:wallet-address account-data))
(assoc-in [:keycard :multiaccount-whisper-public-key] (:whisper-public-key account-data))
(assoc-in [:keycard :pin :status] nil)
(assoc-in [:keycard :application-info :key-uid]
(ethereum/normalized-hex (:key-uid account-data)))
(address/normalized-hex (:key-uid account-data)))
(update :keycard dissoc :recovery-phrase :creating-backup? :converting-account?)
(update-in [:keycard :secrets] dissoc :pin :puk :password :mnemonic)
(assoc :multiaccounts/new-installation-id (random-guid-generator)))}

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