[#18458] Token input fixes (#18520)

* Add custom keyboard to token-input preview
* Fix token input flickering
This commit is contained in:
Ulises Manuel 2024-01-22 20:01:00 -06:00 committed by GitHub
parent 97d1b3faa1
commit dcbb080217
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 174 additions and 94 deletions

View File

@ -1,8 +1,7 @@
(ns quo.components.wallet.token-input.style (ns quo.components.wallet.token-input.style
(:require (:require
[quo.foundations.colors :as colors] [quo.foundations.colors :as colors]
[quo.foundations.typography :as typography] [quo.foundations.typography :as typography]))
[react-native.platform :as platform]))
(defn main-container (defn main-container
[width] [width]
@ -16,23 +15,51 @@
:flex-direction :row :flex-direction :row
:justify-content :space-between}) :justify-content :space-between})
(defn token-name
[theme]
{:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)
:margin-right 8
:padding-bottom 2})
(def token-label-container
{:position :absolute
:left 40 ; token image size + margin
:right 0
:bottom 0
:top 0
:flex-direction :row
:align-items :flex-end})
(def text-input-container
{:position :absolute
:top 0
:bottom 0
:left 40 ; token image size + margin
:right 0})
(def text-input-dimensions
(-> typography/heading-1
(dissoc :letter-spacing)
(assoc :font-weight "600"
:margin-right 5
:padding-left 0
:padding-right 0
:padding-top 0
:padding-bottom 0
:height "100%")))
(defn text-input (defn text-input
[theme] [theme]
(merge typography/heading-1 (assoc text-input-dimensions :color (colors/theme-colors colors/neutral-100 colors/white theme)))
{:font-weight "600"
:margin-left 8 (defn placeholder-text
:margin-right (if platform/ios? 6 4) [theme]
:color (colors/theme-colors colors/neutral-100 colors/white theme) (colors/theme-colors colors/neutral-40 colors/neutral-50 theme))
:padding 0
:text-align :center
:height "100%"}))
(defn divider (defn divider
[width theme] [theme]
{:height 1 {:margin-vertical 8
:width width :background-color (colors/theme-colors colors/neutral-10 colors/neutral-90 theme)})
:background-color (colors/theme-colors colors/neutral-10 colors/neutral-90 theme)
:margin-vertical 8})
(def data-container (def data-container
{:padding-top 4 {:padding-top 4
@ -40,3 +67,7 @@
:flex-direction :row :flex-direction :row
:justify-content :space-between :justify-content :space-between
:align-items :center}) :align-items :center})
(defn fiat-amount
[theme]
{:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)})

View File

@ -7,7 +7,6 @@
[quo.components.tags.network-tags.view :as network-tag] [quo.components.tags.network-tags.view :as network-tag]
[quo.components.utilities.token.view :as token] [quo.components.utilities.token.view :as token]
[quo.components.wallet.token-input.style :as style] [quo.components.wallet.token-input.style :as style]
[quo.foundations.colors :as colors]
[quo.foundations.common :as common] [quo.foundations.common :as common]
[quo.theme :as quo.theme] [quo.theme :as quo.theme]
[react-native.core :as rn] [react-native.core :as rn]
@ -25,83 +24,117 @@
(defn calc-value (defn calc-value
[{:keys [crypto? currency token value conversion crypto-decimals]}] [{:keys [crypto? currency token value conversion crypto-decimals]}]
(let [num-value (if (string? value) (parse-double (or value "0")) value)] (let [num-value (if (string? value)
(or (parse-double value) 0)
value)]
(if crypto? (if crypto?
(fiat-format currency num-value conversion) (fiat-format currency num-value conversion)
(crypto-format num-value conversion crypto-decimals token)))) (crypto-format num-value conversion crypto-decimals token))))
(defn- data-info
[{:keys [theme token crypto-decimals conversion networks title crypto? currency amount]}]
[rn/view {:style style/data-container}
[network-tag/view {:networks networks :title title}]
[text/text
{:size :paragraph-2
:weight :medium
:style (style/fiat-amount theme)}
(calc-value {:crypto? crypto?
:currency currency
:token token
:value amount
:conversion conversion
:crypto-decimals crypto-decimals})]])
(defn- token-name-text
[theme text]
[text/text
{:style (style/token-name theme)
:size :paragraph-2
:weight :semi-bold}
(string/upper-case (or (clj->js text) ""))])
(defn- token-label
[{:keys [theme value text]}]
[rn/view
{:style style/token-label-container
:pointer-events :none}
[rn/text-input
{:max-length 12
:style style/text-input-dimensions
:editable false
:placeholder "0"
:opacity 0
:value value}]
[token-name-text theme text]])
(defn input-section
[{:keys [on-change-text value value-atom]}]
(let [input-ref (atom nil)
set-ref #(reset! input-ref %)
focus-input #(when-let [ref ^js @input-ref]
(.focus ref))
controlled-input? (some? value)
handle-on-change-text (fn [v]
(when-not controlled-input?
(reset! value-atom v))
(when on-change-text
(on-change-text v)))]
(fn [{:keys [theme token customization-color show-keyboard? crypto? currency value]
:or {show-keyboard? true}}]
[rn/pressable
{:on-press focus-input
:style {:flex 1}}
[token/view
{:token token
:size :size-32}]
[rn/view {:style style/text-input-container}
[rn/text-input
(cond-> {:style (style/text-input theme)
:placeholder-text-color (style/placeholder-text theme)
:auto-focus true
:ref set-ref
:placeholder "0"
:keyboard-type :numeric
:max-length 12
:on-change-text handle-on-change-text
:selection-color customization-color
:show-soft-input-on-focus show-keyboard?}
controlled-input? (assoc :value value)
(not controlled-input?) (assoc :default-value @value-atom))]]
[token-label
{:theme theme
:text (if crypto? token currency)
:value (if controlled-input? value @value-atom)}]])))
(defn- view-internal (defn- view-internal
[{external-value :value}] [{:keys [on-swap]}]
(let [width (:width (rn/get-window)) (let [width (:width (rn/get-window))
value (reagent/atom nil) value-atom (reagent/atom nil)
crypto? (reagent/atom true) crypto? (reagent/atom true)
input-ref (atom nil) handle-on-swap (fn []
controlled-input? (some? external-value)] (swap! crypto? not)
(fn [{:keys [theme token currency crypto-decimals conversion networks title (when on-swap
customization-color (on-swap @crypto?)))]
on-change-text on-swap container-style show-keyboard?] (fn [{:keys [theme container-style value] :as props}]
:or {show-keyboard? true} [rn/view {:style (merge (style/main-container width) container-style)}
external-value :value}]
[rn/view
{:style (merge
(style/main-container width)
container-style)}
[rn/view {:style style/amount-container} [rn/view {:style style/amount-container}
[rn/pressable [input-section
{:on-press #(when @input-ref (.focus ^js @input-ref)) (assoc props
:style {:flex-direction :row :value-atom value-atom
:flex-grow 1 :crypto? @crypto?)]
:align-items :flex-end}}
[token/view {:token token :size :size-32}]
[rn/text-input
(cond-> {:auto-focus true
:ref #(reset! input-ref %)
:placeholder "0"
:placeholder-text-color (colors/theme-colors colors/neutral-40
colors/neutral-50
theme)
:keyboard-type :numeric
:max-length 12
:on-change-text (fn [v]
(when-not controlled-input?
(reset! value v))
(when on-change-text
(on-change-text v)))
:style (style/text-input theme)
:selection-color customization-color
:show-soft-input-on-focus show-keyboard?}
controlled-input? (assoc :value external-value)
(not controlled-input?) (assoc :default-value @value))]
[text/text
{:size :paragraph-2
:weight :semi-bold
:style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)
:margin-right 8
:padding-bottom 2}}
(string/upper-case (or (clj->js (if @crypto? token currency)) ""))]]
[button/button [button/button
{:icon true {:icon true
:icon-only? true :icon-only? true
:size 32 :size 32
:on-press (fn [] :on-press handle-on-swap
(swap! crypto? not)
(when on-swap
(on-swap @crypto?)))
:type :outline :type :outline
:accessibility-label :reorder} :accessibility-label :reorder}
:i/reorder]] :i/reorder]]
[divider-line/view {:container-style {:margin-vertical 8}}] [divider-line/view {:container-style (style/divider theme)}]
[rn/view {:style style/data-container} [data-info
[network-tag/view {:networks networks :title title}] (assoc props
[text/text :crypto? @crypto?
{:size :paragraph-2 :amount (or value @value-atom))]])))
:weight :medium
:style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)}}
(calc-value {:crypto? @crypto?
:currency currency
:token token
:value (or external-value @value)
:conversion conversion
:crypto-decimals crypto-decimals})]]])))
(def view (quo.theme/with-theme view-internal)) (def view (quo.theme/with-theme view-internal))

View File

@ -320,7 +320,7 @@
(defn- f-preview-container (defn- f-preview-container
[{:keys [title state descriptor blur? blur-dark-only? [{:keys [title state descriptor blur? blur-dark-only?
component-container-style component-container-style
blur-container-style blur-view-props blur-height show-blur-background?] blur-container-style blur-view-props blur-height show-blur-background? full-screen?]
:or {blur-height 200}} :or {blur-height 200}}
& children] & children]
(let [theme (quo.theme/use-theme-value) (let [theme (quo.theme/use-theme-value)
@ -337,8 +337,11 @@
[common/navigation-bar {:title title}] [common/navigation-bar {:title title}]
[rn/scroll-view [rn/scroll-view
{:style (style/panel-basic) {:style (style/panel-basic)
:shows-vertical-scroll-indicator false} :shows-vertical-scroll-indicator false
[rn/pressable {:on-press rn/dismiss-keyboard!} :content-container-style (when full-screen? {:flex 1})}
[rn/pressable
{:style (when full-screen? {:flex 1})
:on-press rn/dismiss-keyboard!}
(when descriptor (when descriptor
[rn/view {:style style/customizer-container} [rn/view {:style style/customizer-container}
[customizer state descriptor]]) [customizer state descriptor]])

View File

@ -2,6 +2,7 @@
(:require (:require
[quo.core :as quo] [quo.core :as quo]
[quo.foundations.resources :as resources] [quo.foundations.resources :as resources]
[react-native.safe-area :as safe-area]
[reagent.core :as reagent] [reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview])) [status-im.contexts.preview.quo.preview :as preview]))
@ -24,17 +25,29 @@
(defn view (defn view
[] []
(let [state (reagent/atom {:token :eth (let [state (reagent/atom {:token :eth
:currency :usd :currency :usd
:conversion 0.02 :conversion 0.02
:networks networks :networks networks
:title title :title title
:customization-color :blue})] :customization-color :blue
:show-keyboard? false})
value (reagent/atom "")
set-value (fn [v]
(swap! value str v))
delete (fn [_]
(swap! value #(subs % 0 (dec (count %)))))]
(fn [] (fn []
[preview/preview-container [preview/preview-container
{:state state {:state state
:descriptor descriptor :descriptor descriptor
:component-container-style {:padding-horizontal 20 :full-screen? true
:margin-top 50 :component-container-style {:flex 1
:align-items :center}} :justify-content :space-between}}
[quo/token-input @state]]))) [quo/token-input (assoc @state :value @value)]
[quo/numbered-keyboard
{:container-style {:padding-bottom (safe-area/get-top)}
:left-action :dot
:delete-key? true
:on-press set-value
:on-delete delete}]])))