diff --git a/resources/images/icons2/16x16/keycard-card@2x.png b/resources/images/icons2/16x16/keycard-card@2x.png new file mode 100644 index 0000000000..6f2baf3ab0 Binary files /dev/null and b/resources/images/icons2/16x16/keycard-card@2x.png differ diff --git a/resources/images/icons2/16x16/keycard-card@3x.png b/resources/images/icons2/16x16/keycard-card@3x.png new file mode 100644 index 0000000000..8f5881ff0c Binary files /dev/null and b/resources/images/icons2/16x16/keycard-card@3x.png differ diff --git a/src/quo2/components/avatars/icon_avatar.cljs b/src/quo2/components/avatars/icon_avatar.cljs index e62b5fa60f..9c151206aa 100644 --- a/src/quo2/components/avatars/icon_avatar.cljs +++ b/src/quo2/components/avatars/icon_avatar.cljs @@ -1,6 +1,7 @@ (ns quo2.components.avatars.icon-avatar (:require [quo2.components.icon :as icons] [quo2.foundations.colors :as colors] + [quo2.theme :as quo.theme] [react-native.core :as rn])) (def sizes @@ -8,8 +9,8 @@ :medium 32 :small 20}) -(defn icon-avatar - [{:keys [size icon color opacity] +(defn icon-avatar-internal + [{:keys [size icon color opacity border? theme] :or {opacity 20}}] (let [component-size (size sizes) circle-color (colors/custom-color color 50 opacity) @@ -22,9 +23,13 @@ {:style {:width component-size :height component-size :border-radius component-size + :border-width (when border? 1) + :border-color (colors/theme-colors colors/neutral-20 colors/neutral-80 theme) :background-color circle-color :justify-content :center :align-items :center}} [icons/icon icon {:size icon-size :color icon-color}]])) + +(def icon-avatar (quo.theme/with-theme icon-avatar-internal)) diff --git a/src/quo2/components/wallet/keypair/component_spec.cljs b/src/quo2/components/wallet/keypair/component_spec.cljs new file mode 100644 index 0000000000..a2de6b90b2 --- /dev/null +++ b/src/quo2/components/wallet/keypair/component_spec.cljs @@ -0,0 +1,61 @@ +(ns quo2.components.wallet.keypair.component-spec + (:require [test-helpers.component :as h] + [quo2.components.wallet.keypair.view :as keypair])) + +(def accounts + [{:account-props {:customization-color :turquoise + :size 32 + :emoji "\uD83C\uDFB2" + :type :default + :name "Trip to Vegas" + :address "0x0ah...71a"} + :networks [:ethereum :optimism] + :state :default + :action :none}]) + +(def default-details + {:full-name "John Doe" + :address "zQ3...6fBd2"}) + +(def other-details {:full-name "Metamask"}) + +(h/describe "Wallet: Keypair" + (h/test "Default keypair title renders" + (h/render [keypair/view + {:accounts accounts + :customization-color :blue + :type :default-keypair + :stored :on-device + :action :selector + :details default-details}]) + (h/is-truthy (h/get-by-label-text :title))) + + (h/test "On device renders" + (h/render [keypair/view + {:accounts accounts + :customization-color :blue + :type :other + :stored :on-device + :action :selector + :details other-details}]) + (h/is-truthy (h/get-by-label-text :details))) + + (h/test "Selector action renders" + (h/render [keypair/view + {:accounts accounts + :customization-color :blue + :type :other + :stored :on-keycard + :action :selector + :details other-details}]) + (h/is-truthy (h/get-by-label-text :radio-on))) + + (h/test "Options action renders" + (h/render [keypair/view + {:accounts accounts + :customization-color :blue + :type :other + :stored :on-keycard + :action :options + :details other-details}]) + (h/is-truthy (h/get-by-label-text :options-button)))) diff --git a/src/quo2/components/wallet/keypair/style.cljs b/src/quo2/components/wallet/keypair/style.cljs new file mode 100644 index 0000000000..b87bd76e97 --- /dev/null +++ b/src/quo2/components/wallet/keypair/style.cljs @@ -0,0 +1,26 @@ +(ns quo2.components.wallet.keypair.style + (:require [quo2.foundations.colors :as colors])) + +(defn container + [selected? customization-color theme] + {:border-radius 20 + :border-width 1 + :border-color (if selected? + (colors/theme-colors (colors/custom-color customization-color 50) + (colors/custom-color customization-color 60) + theme) + (colors/theme-colors colors/neutral-10 colors/neutral-80 theme)) + :padding-bottom 8}) + +(def header-container + {:padding-horizontal 12 + :padding-top 8 + :padding-bottom 12 + :flex-direction :row + :align-items :center}) + +(def title-container + {:flex-direction :row + :align-items :center + :justify-content :space-between + :flex 1}) diff --git a/src/quo2/components/wallet/keypair/view.cljs b/src/quo2/components/wallet/keypair/view.cljs new file mode 100644 index 0000000000..abb09c1108 --- /dev/null +++ b/src/quo2/components/wallet/keypair/view.cljs @@ -0,0 +1,93 @@ +(ns quo2.components.wallet.keypair.view + (:require + [quo2.components.avatars.icon-avatar :as icon-avatar] + [quo2.components.avatars.user-avatar.view :as user-avatar] + [quo2.components.icon :as icon] + [quo2.components.list-items.account-list-card.view :as account-list-card] + [quo2.components.markdown.text :as text] + [quo2.foundations.colors :as colors] + [quo2.theme :as quo.theme] + [react-native.core :as rn] + [quo2.components.selectors.selectors.view :as selectors] + [reagent.core :as reagent] + [utils.i18n :as i18n] + [quo2.components.wallet.keypair.style :as style] + [clojure.string :as string])) + +(defn keypair-string + [full-name] + (let [first-name (first (string/split full-name #" "))] + (i18n/label :t/keypair-title {:name first-name}))) + +(defn details-string + [address stored] + (str (when address (str address " ∙ ")) + (if (= stored :on-device) (i18n/label :t/on-device) (i18n/label :t/on-keycard)))) + +(defn avatar + [type full-name customization-color] + (if (= type :default-keypair) + [user-avatar/user-avatar + {:full-name full-name + :ring? true + :size :small + :customization-color customization-color}] + [icon-avatar/icon-avatar + {:size :medium + :icon :i/placeholder + :border? true}])) + +(defn title-view + [full-name action selected? type customization-color on-options-press theme] + [rn/view + {:style style/title-container + :accessibility-label :title} + [text/text {:weight :semi-bold} + (if (= type :default-keypair) (keypair-string full-name) full-name)] + (if (= action :selector) + [selectors/radio + {:checked? selected? + :customization-color customization-color}] + [rn/pressable {:on-press on-options-press} + [icon/icon :i/options + {:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme) + :accessibility-label :options-button}]])]) + +(defn details-view + [address stored theme] + [rn/view + {:style {:flex-direction :row + :align-items :center}} + [text/text + {:size :paragraph-2 + :accessibility-label :details + :style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)}} + (details-string address stored)] + (when (= stored :on-keycard) + [rn/view {:style {:margin-left 4}} + [icon/icon :i/keycard-card + {:size 16 + :color (colors/theme-colors colors/neutral-50 colors/neutral-40)}]])]) + +(defn- view-internal + [] + (let [selected? (reagent/atom true)] + (fn [{:keys [theme accounts customization-color type details stored action on-options-press]}] + (let [{:keys [address full-name]} details] + [rn/pressable + {:style (style/container @selected? customization-color theme) + :on-press #(when (= action :selector) (reset! selected? (not @selected?)))} + [rn/view {:style style/header-container} + [avatar type full-name customization-color] + [rn/view + {:style {:margin-left 8 + :flex 1}} + [title-view full-name action @selected? type customization-color on-options-press theme] + [details-view address stored theme]]] + [rn/flat-list + {:data accounts + :render-fn account-list-card/view + :separator [rn/view {:style {:height 8}}] + :style {:padding-horizontal 8}}]])))) + +(def view (quo.theme/with-theme view-internal)) diff --git a/src/quo2/core.cljs b/src/quo2/core.cljs index 83cb739d32..ffd615eff8 100644 --- a/src/quo2/core.cljs +++ b/src/quo2/core.cljs @@ -111,6 +111,7 @@ quo2.components.text-combinations.title.view quo2.components.wallet.account-overview.view quo2.components.wallet.account-card.view + quo2.components.wallet.keypair.view quo2.components.wallet.network-amount.view quo2.components.wallet.network-bridge.view quo2.components.wallet.progress-bar.view @@ -317,6 +318,7 @@ ;;;; Wallet (def account-card quo2.components.wallet.account-card.view/view) (def account-overview quo2.components.wallet.account-overview.view/view) +(def keypair quo2.components.wallet.keypair.view/view) (def network-amount quo2.components.wallet.network-amount.view/view) (def network-bridge quo2.components.wallet.network-bridge.view/view) (def progress-bar quo2.components.wallet.progress-bar.view/view) diff --git a/src/quo2/core_spec.cljs b/src/quo2/core_spec.cljs index ce612dcbb9..0e03f9b542 100644 --- a/src/quo2/core_spec.cljs +++ b/src/quo2/core_spec.cljs @@ -56,6 +56,7 @@ [quo2.components.tags.status-tags-component-spec] [quo2.components.wallet.account-overview.component-spec] [quo2.components.wallet.account-card.component-spec] + [quo2.components.wallet.keypair.component-spec] [quo2.components.wallet.network-amount.component-spec] [quo2.components.wallet.network-bridge.component-spec] [quo2.components.wallet.progress-bar.component-spec] diff --git a/src/status_im2/contexts/quo_preview/main.cljs b/src/status_im2/contexts/quo_preview/main.cljs index fdc52a7e15..cc46901f08 100644 --- a/src/status_im2/contexts/quo_preview/main.cljs +++ b/src/status_im2/contexts/quo_preview/main.cljs @@ -112,6 +112,7 @@ [status-im2.contexts.quo-preview.gradient.gradient-cover :as gradient-cover] [status-im2.contexts.quo-preview.wallet.account-overview :as account-overview] [status-im2.contexts.quo-preview.wallet.account-card :as account-card] + [status-im2.contexts.quo-preview.wallet.keypair :as keypair] [status-im2.contexts.quo-preview.wallet.network-amount :as network-amount] [status-im2.contexts.quo-preview.wallet.network-bridge :as network-bridge] [status-im2.contexts.quo-preview.wallet.progress-bar :as progress-bar] @@ -337,6 +338,9 @@ :component account-card/preview-account-card} {:name :account-overview :component account-overview/preview-account-overview} + {:name :keypair + :options {:topBar {:visible true}} + :component keypair/preview} {:name :network-amount :component network-amount/preview} {:name :network-bridge diff --git a/src/status_im2/contexts/quo_preview/wallet/keypair.cljs b/src/status_im2/contexts/quo_preview/wallet/keypair.cljs new file mode 100644 index 0000000000..fb5b898324 --- /dev/null +++ b/src/status_im2/contexts/quo_preview/wallet/keypair.cljs @@ -0,0 +1,115 @@ +(ns status-im2.contexts.quo-preview.wallet.keypair + (:require + [quo2.core :as quo] + [react-native.core :as rn] + [reagent.core :as reagent] + [status-im2.contexts.quo-preview.preview :as preview])) + +(def accounts + [{:account-props {:customization-color :turquoise + :size 32 + :emoji "\uD83C\uDFB2" + :type :default + :name "Trip to Vegas" + :address "0x0ah...71a"} + :networks [:ethereum :optimism] + :state :default + :action :none} + {:account-props {:customization-color :purple + :size 32 + :emoji "\uD83C\uDF7F" + :type :default + :name "My savings" + :address "0x0ah...72b"} + :networks [:ethereum :optimism] + :state :default + :action :none} + {:account-props {:customization-color :army + :size 32 + :emoji "\uD83D\uDCC8" + :type :default + :name "Coin vault" + :address "0x0ah...73c"} + :networks [:ethereum :optimism] + :state :default + :action :none} + {:account-props {:customization-color :orange + :size 32 + :emoji "\uD83C\uDFF0" + :type :default + :name "Crypto fortress" + :address "0x0ah...74e"} + :networks [:ethereum :optimism] + :state :default + :action :none} + {:account-props {:customization-color :yellow + :size 32 + :emoji "\uD83C\uDFDD️" + :type :default + :name "Block treasure" + :address "0x0ah...75f"} + :networks [:ethereum :optimism] + :state :default + :action :none}]) + +(def descriptor + [{:label "Stored:" + :key :stored + :type :select + :options [{:key :on-device + :value "On device"} + {:key :on-keycard + :value "On Keycard"}]} + {:label "Action:" + :key :action + :type :select + :options [{:key :selector + :value "Selector"} + {:key :options + :value "Options"}]} + {:label "Type:" + :key :type + :type :select + :options [{:key :default-keypair + :value "Default keypair"} + {:key :other + :value "Other"}]} + (preview/customization-color-option)]) + +(def default-details + {:full-name "John Doe" + :address "zQ3...6fBd2"}) + +(def other-details {:full-name "Metamask"}) + +(defn cool-preview + [] + (let [state (reagent/atom {:accounts accounts + :customization-color :blue + :type :default-keypair + :stored :on-device + :on-options-press #(js/alert "Options pressed") + :action :selector})] + (fn [] + [rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!} + [rn/view {:style {:padding-bottom 150}} + [rn/view {:style {:flex 1}} + [preview/customizer state descriptor]] + [rn/view + {:style {:padding-vertical 30 + :flex-direction :row + :justify-content :center}} + [quo/keypair + (merge + @state + {:details (if (= (:type @state) :default-keypair) default-details other-details)})]]]]))) + +(defn preview + [] + [rn/view + {:style {:flex 1}} + [rn/flat-list + {:flex 1 + :keyboard-should-persist-taps :always + :header [cool-preview] + :key-fn str}]]) diff --git a/translations/en.json b/translations/en.json index 2a71a64e43..f7cc1ec435 100644 --- a/translations/en.json +++ b/translations/en.json @@ -2282,5 +2282,8 @@ "no-activity": "No activity", "no-activity-description": "C'mon do something...", "buy": "Buy", - "bridge": "Bridge" + "bridge": "Bridge", + "on-device": "On device", + "on-keycard": "On Keycard", + "keypair-title": "{{name}}'s default keypair" }